diff --git a/.gitattributes b/.gitattributes index b9a594aa8..f82b3a0de 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9,6 +9,8 @@ # They are also used when pushing to WordPress.org SVN using the # https://github.com/10up/action-wordpress-plugin-deploy GitHub Action. +# Likewise, anything marked `export-ignore` will be excluded by `bin/export-plugin.sh` + # Directories /.github export-ignore /.wordpress-org export-ignore @@ -22,10 +24,12 @@ /.gitignore export-ignore /.phpcs.xml.dist export-ignore /.prettierrc export-ignore +/.nvmrc export-ignore /.travis.yml export-ignore /CHANGELOG.md export-ignore /CODE_OF_CONDUCT.md export-ignore /CONTRIBUTING.md export-ignore /composer.json export-ignore /composer.lock export-ignore +/package-lock.json export-ignore /phpunit.xml.dist export-ignore diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..caf1ec4e1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,28 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +## Describe the bug + + +## To Reproduce + + +## Expected behaviour + + +## Screenshots + + +## Environment + + + +## Additional context + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..8ffb70296 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +## Is your feature request related to a problem? + + +## Describe the solution you'd like + + +## Describe alternatives you've considered + + +## Additional context + diff --git a/.github/ISSUE_TEMPLATE/release-template.md b/.github/ISSUE_TEMPLATE/release-template.md new file mode 100644 index 000000000..f9728f39b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/release-template.md @@ -0,0 +1,24 @@ +--- +name: Release template +about: Internally used for new releases +title: Release x.y.z +labels: 'Type: Maintenance' + +--- + +:warning: DO NOT MERGE (YET) :warning: + +[Remaining work for this Milestone](https://github.com/Parsely/wp-parsely/milestone/14) + +PR for tracking changes for the X.Y.Z release. Target release date: DOW DD MMMM YYYY. + +- [ ] Merge any outstanding PRs due for this release. +- [ ] Add/Update changelog for this release: PR #XXX +- [ ] Add commit/PR which increases version numbers in the README, plugin bootstrap file, and in the `test_class_version` test in `tests/class-all-test.php`. +- [ ] Merge this PR. +- [ ] Add signed release tag against `trunk`. +- [ ] Close the current milestone. +- [ ] Open a new milestone for the next release. +- [ ] If any open PRs/issues which were milestoned for this release do not make it into the release, update their milestone. +- [ ] Write a Lobby post. +- [ ] Write an internal P2 post. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..cba58d981 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + - package-ecosystem: 'npm' + reviewers: + - 'Parsely/wp-parsely' + directory: '/' + schedule: + interval: 'daily' + + - package-ecosystem: 'composer' + directory: '/' + schedule: + interval: 'daily' diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..40593db51 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,21 @@ + + +## Description + + +## Motivation and Context + + + +## How Has This Been Tested? + + + + +## Screenshots (if appropriate): + +## Types of changes + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a18037d79..cacbaac12 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -8,7 +8,7 @@ jobs: name: New tag runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v2 - name: Build # Remove or modify this step as needed run: | npm install diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 759ce25ce..ac700495b 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -13,55 +13,71 @@ on: jobs: test: name: PHP ${{ matrix.php }} - runs-on: ubuntu-latest - continue-on-error: ${{ matrix.allowed_failure }} + # ubuntu-20.04 / ubuntu-latest includes MySQL 8, which has issues with older versions of PHP. + # ubuntu-18.04 includes PHP versions 7.1-8.0, but 5.6-7.1 are cached, so setup is about 5 seconds. + # See https://setup-php.com/i/452 + runs-on: ubuntu-18.04 env: WP_VERSION: latest strategy: matrix: - php: [ '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0' ] - allowed_failure: [ false ] + php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4'] include: - # PHP nightly. - - php: '8.1' - allowed_failure: true + - php: '8.0' + # Ignore platform requirements, so that PHPUnit 7.5 can be installed on PHP 8.0 (and above). + composer-options: '--ignore-platform-reqs' + extensions: pcov + ini-values: pcov.directory=., "pcov.exclude=\"~(vendor|tests)~\"" + coverage: pcov + # There is no PHP nightly. Due to https://github.com/sebastianbergmann/phpunit/issues/4575 this is never + # going to succeed as WordPress is hard-coded to only support PHPUnit 7.5, and then fix only appears + # in PHPUnit 8.5.14. + fail-fast: false steps: - name: Checkout code - uses: actions/checkout@master + uses: actions/checkout@v2 - - name: Setup PHP 7.4 + - name: Setup PHP ${{ matrix.php }} uses: shivammathur/setup-php@v2 with: - php-version: '7.4' - coverage: pcov - # https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions - extensions: curl, dom, exif, fileinfo, hash, json, mbstring, mysqli, libsodium, openssl, pcre, imagick, xml, zip + php-version: ${{ matrix.php }} + extensions: ${{ matrix.extensions }} + ini-values: ${{ matrix.ini-values }} + coverage: ${{ matrix.coverage }} - - name: Install Composer dependencies (PHP < 8.0 ) - if: ${{ matrix.php < 8.0 }} - uses: ramsey/composer-install@v1 + - name: Setup problem matchers for PHP + run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" - - name: Install Composer dependencies (PHP >= 8.0) - if: ${{ matrix.php >= 8.0 }} - uses: ramsey/composer-install@v1 - with: - composer-options: --ignore-platform-reqs + # Setup PCOV since we're using PHPUnit < 8 which has it integrated. Requires PHP 7.1. + # Ignore platform reqs to make it install on PHP 8. + # https://github.com/krakjoe/pcov-clobber + - name: Setup PCOV + if: ${{ matrix.php == 8.0 }} + run: | + composer require pcov/clobber --ignore-platform-reqs + vendor/bin/pcov clobber - name: Setup Problem Matchers for PHPUnit run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" -# - name: Run unit tests -# run: composer unit + - name: Install Composer dependencies + uses: ramsey/composer-install@v1 + with: + composer-options: '${{ matrix.composer-options }}' - name: Start MySQL Service run: sudo systemctl start mysql.service - name: Prepare environment for integration tests - run: composer prepare + run: composer prepare-ci - name: Run integration tests (single site) - run: composer integration + if: ${{ matrix.php != 8.0 }} + run: composer test + - name: Run integration tests (single site with code coverage) + if: ${{ matrix.php == 8.0 }} + run: composer coverage-ci - name: Run integration tests (multisite) - run: composer integration-ms + run: composer test-ms diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml new file mode 100644 index 000000000..175427c65 --- /dev/null +++ b/.github/workflows/node.js.yml @@ -0,0 +1,57 @@ +# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: Node.js CI + +on: + pull_request: + paths: + - .github/workflows/*.js.yml + - '**/*[tj]sx?' + - package*.json + push: + paths: + - .github/workflows/*.js.yml + - '**/*[tj]sx?' + - package*.json + # Allow manually triggering the workflow. + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x, 16.x] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - uses: actions/checkout@v2 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + + # See: https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows + - name: Cache node modules + uses: actions/cache@v2 + env: + cache-name: cache-node-modules + with: + path: ~/.npm + key: "${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}" + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: Install JavaScript dependencies + run: npm ci + + - name: Build application + run: npm run build + + - name: Run tests + run: npm test diff --git a/.gitignore b/.gitignore index 759038a1e..7e5c00be3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ /composer.lock /vendor +/build/*.map .DS_Store .idea node_modules +/build/logs/ +/build/coverage-html/ + diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..8351c1939 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +14 diff --git a/.wordpress-org/screenshot-1.png b/.wordpress-org/screenshot-1.png index 6d045a0d7..e75d56c0b 100644 Binary files a/.wordpress-org/screenshot-1.png and b/.wordpress-org/screenshot-1.png differ diff --git a/.wordpress-org/screenshot-2.png b/.wordpress-org/screenshot-2.png index dc0168ab6..6b92f4b6b 100644 Binary files a/.wordpress-org/screenshot-2.png and b/.wordpress-org/screenshot-2.png differ diff --git a/.wordpress-org/screenshot-3.png b/.wordpress-org/screenshot-3.png index 8246caf74..4cb87edf0 100644 Binary files a/.wordpress-org/screenshot-3.png and b/.wordpress-org/screenshot-3.png differ diff --git a/.wordpress-org/screenshot-4.png b/.wordpress-org/screenshot-4.png deleted file mode 100644 index c4df2ccf9..000000000 Binary files a/.wordpress-org/screenshot-4.png and /dev/null differ diff --git a/CHANGELOG.md b/CHANGELOG.md index ea94b5347..4e775b66d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,60 @@ # Changelog for the Parsely WordPress plugin + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.5.0] - 2021-05-17 + +### Added + +- Refreshed contributor documentation into a new [CONTRIBUTING.md](CONTRIBUTING.md) file. +- Introduce a build step for front-end and admin page JavaScript assets which leverages the [`@wordpress/scripts` package](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/). Scripts are now separately enqueued and browser-cacheable. +- Allow for select HTML tags and attributes in the Recommended Content widget title. +- Add a "No boost" option for scores in the widget. +- Add filter `wp_parsely_post_type` to override the [type of content Parse.ly attributes to an article](https://www.parse.ly/help/integration/jsonld#distinguishing-between-posts-and-pages). +- Add support for custom post status slugs via the `wp_parsely_trackable_statuses` filter (to allow for those other than `publish` to be tracked). +- Make `$post_id` available to the `wp_parsely_permalink` filter. + +### Changed + +- Refactor printed markup into template "views." +- Refactor plugin entry file to perform minimal initialization and separately load the `Parsely` class file. +- Improve the README file (which populates the copy in the plugin repository page). +- Expand test coverage (PHP and JavaScript). +- Expanded string localization and consolidate into a single text domain. +- Adjust HTML heading levels for improved usability and accessibility. +- Improve accessibility of radio inputs on the admin page. +- Improve the widget user interface to make it more consistent with core styles. +- Better load Widget CSS and use plugin version for cache busting. +- Replace widget form and hide front-end output when API values are missing. +- Prevent printing of admin page CSS outside the specific admin page for this plugin. +- Switch to XHRs for `/profile` calls (instead of using JSONP). +- Remove jQuery dependency from the API and Admin scripts. +- Stop using protocol-relative URL for the tracking script. +- Register the [package at Packagist](https://packagist.org/packages/parsely/wp-parsely) for easier install via Composer. + +### Fixed + +- Fix the "requires a recrawl" notices to limit to specific admin page settings. +- Fix inconsistent ports in canonical URLs. + +### Deprecated + +- Deprecate filter `after_set_parsely_page` -- use new name `wp_parsely_metadata` instead. +- Deprecate filter `parsely_filter_insert_javascript` -- use new name `wp_parsely_load_js_tracker` instead. + ## [2.4.1] - 2021-04-13 ### Fixed + - Fix the version number set in the main plugin file. ## [2.4.0] - 2021-04-13 ### Added + - Structured data integration tests for posts, pages, category and author archives, and home/front pages. - License, `.editorconfig`, `.gitattributes`, `CODEOWNERS`, `CHANGELOG.md`, and other development files. - Documentation for hooks. @@ -19,6 +62,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - JS Build environment entrypoint. ### Changed + - Improve WordPress.org assets (screenshots, icons, readme). - Switch to using GitHub Actions workflow for CI and WordPress.org deployment. - Update scaffolded integration test files. @@ -26,36 +70,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Separate multisite and single-site tests in CI workflow. ### Fixed + - Fix metadata for home pages, including pages of older posts. -- Fix metadata for category archives. +- Fix metadata for category archives. ### Removed + - Remove Parse.ly metadata from search result pages. ## [2.3.0] - 2021-03-24 + - Fix and improve Travis configuration. - Small maintenance items: merge isset() calls, remove unnecessary typecasting, remove is_null() in favour of null comparison, un-nest nested functions, simplify ternary operators, remove unnecessary local variable, etc. - Improve tests: split utility methods to custom test case, use more specific assertions, etc. - Update WordPress plugin Tested Up To version. ## [2.2.1] - 2020-12-18 + - Add logo to JSON LD publisher object. ## [2.2] - 2020-09-14 + - Fix metadata being inserted on a 404 page. - Add `parsely_filter_insert_javascript` filter hook. ## [2.1.3] - 2020-09-11 + - Add defaults for API Secret and Wipe settings. ## [2.1.2] - 2020-07-02 + - Cleanup code to conform to WordPress VIP standards. - Add a guard against null values. ## [2.1.1] - 2020-06-08 + - Fix incorrect variable name. ## [2.1] - 2020-06-05 + - Update documentation. - Extract logic for metadata construction and updating into their own methods. - Add API Secret setting. @@ -63,12 +116,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add 10-minute cron job schedule. - Add Wipe Parsely Metadata Info setting. - ## [2.0] - 2019-04-29 + - Change JavaScript integration to directly load tracker bundles that are customized for your specific site ID. See https://www.parse.ly/help/integration/basic/. NOTE: Sites that have custom Parse.ly video tracking configured (outside the Parse.ly WordPress plugin) for a player listed at https://www.parse.ly/help/integration/video_v2/#supported-players should contact support@parsely.com before upgrading. ## [1.14] - 2019-01-15 + - Update AMP analytics implementation. - Add ability to use a horizontal layout of the widget (for page footers). - Add `itm` campaign parameters to widget links for tracking performance. @@ -78,23 +132,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Cleanup code to conform to WordPress VIP standards. ## [1.13.1] - 2018-06-18 + - Cleanup code to conform to WordPress VIP standards. ## [1.13] - 2018-05-24 + - Make AMP integration optional. - Add support for publisher logo information. - Fix minor bugs. ## [1.12.5] - 2018-05-16 + - Fix kissing close bracket for select tags on settings page. ## [1.12.4] - 2018-05-15 + - No net changes from 1.12.3 ## [1.12.3] - 2018-05-01 + - Cleanup code to conform to WordPress VIP standards. ## [1.12.2] - 2018-04-27 + - Cleanup code to conform to WordPress VIP standards. - Add security fixes. - Add Author data when on author archive. @@ -103,55 +163,67 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove broken or un-needed CSS rules. ## [1.12.1] - 2018-01-30 + - Fix archive pages having post canonicals. ## [1.12] - 2018-01-26 + - Add ability to use repeated meta tags instead of ld+json tags for metadata. - Cleanup code to conform to WordPress VIP standards. - Fix minor bugs. ## [1.11.2] - 2017-12-19 + - No net changes from 1.11. ## [1.11] - 2017-12-18 + - Add ability to use Parsely API with widget. - Add ability to track or not track custom page and post types. - Add ability to disable JavaScript tracking. - Fix minor bugs. ## [1.10.3] - 2017-09-21 + - Update documentation. - Amend logic for allowing logged users not to be tracked. ## [1.10.2] - 2016-10-25 + - Validate `force_https_canonicals` value. - Improve setting help text. - Add security fix. ## [v1.10.1] - 2016-09-22 + - Update documentation. - Add conditional in case there are no custom taxonomies. ## [v1.10] - 2016-09-20 + - Add ability to filter final JSON-LD output. - Add the ability to use a custom taxonomy as tags. - Add AMP / Facebook Instant integration with official AMP / FBIA plugins from Automattic. - Fix bug related to HTTPS canonicals. ## [v1.9] - 2016-06-23 + - Add ability to assign custom taxonomies as section. - Fix bug related to adding section to tag field. ## [v1.8] - 2016-01-13 + - Update documentation for installation and local development. - Allow developers to adjust the tag list and the category reported for a post. - Add support for themes to extend the reported authors. ## [v1.7] - 2014-11-19 + - Use JSON-LD / schema.org for parsely-page data instead of proprietary format. -- Add support for multiple authors if using the [Co-Authors Plus plugin](https://wordpress.org/plugins/co-authors-plus/). +- Add support for multiple authors if using the [Co-Authors Plus plugin](https://wordpress.org/plugins/co-authors-plus/). ## [v1.6] - 2014-04-30 + - Maintenance release with multiple changes needed for WordPress VIP inclusion. - Migrate to WP Settings API. - Various syntax changes in line with Automattic's guidelines. @@ -160,17 +232,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Update screenshots. ## [v1.5] - 2013-06-17 + - Add support for new option - "Use Categories as Tags". - Fix bug that caused wp-admin bar to be hidden when "Do not track authenticated in users" was selected. - Fix WP category logic bug that failed on users with custom post types. ## [v1.4] - 2012-11-09 + - Add early support for post tags. - Fix permalink errors on category/author/tag pages. - Add version output to both templates and settings pages. - Rename API key to Site ID to avoid confusion. ## [v1.3] - 2012-10-03 + - Add option to not track or not track authenticated users (default is to not track authenticated users). - Remove async implementation option. - Update API key retrieval instructions. @@ -178,11 +253,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - null categories are now set to "Uncategorized". ## [v1.2] - 2012-08-31 + - Add support for using top-level categories for posts instead of the first active post the plugin finds. - parsely-page meta tag now outputs its value using 'content' attribute instead of 'value'. - Minor fixes to outputting to use proper WordPress functions. ## [v1.1] - 2012-07-19 + - Add ability to add a prefix to content IDs. - Ensured the plugin only uses long tags ` [db-host] [wp-version] [skip-database-creation]" + ``` + +Then, you can use Composer to run the tests from your terminal. + +To run the single-site tests: + +``` +composer test +``` + +To run the multisite tests: + +``` +composer test-ms +``` + +To run with code coverage: + +``` +composer coverage +``` + +## Building Included Assets + +JavaScript files that are included in the released plugin are built with the +[wp-scripts tool](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/). + +Here's how to get started making changes to them: + +1. Install the dependencies: `npm i` +1. Start the build tool: `npm run start` +1. Make and test your changes -- assets are rebuilt automatically +1. Create a branch / PR with all applicable changes to: + - Source files (in the `src` directory) + - Build tooling (including an updated `package-lock.json` if you've altered dependencies) + - Built files (in the `build` directory) + - When you're ready to do this, stop your `start` script and run `npm run build` instead diff --git a/DEVELOP.md b/DEVELOP.md deleted file mode 100644 index 145bef0aa..000000000 --- a/DEVELOP.md +++ /dev/null @@ -1,39 +0,0 @@ -# Getting Started - -Plugin development is a little tricky given that we host on github, but have to -publish to SVN. - -### Get added as a committer to wp-parsely - -Ask one of the owners of the plugin (currently, Mike Sukmanowsky) to add you as -a committer which provides you with write access to the SVN repo. You will need -to provide your wordpress.org username. - -### Run init.py - -Run `python init.py` which will pull the wp-parsely repo and configure git so -that you will be able to eventually run `git svn dcommit` to push changes to -wordpress.org. - -# Making Changes - -If you hit merge conflicts when you try to `dcommit`, you can try creating a -local tracking branch of `svn/trunk`, rebasing your local working branch with -it, and then merging that back onto local `trunk` before trying to `dcommit` -again. Otherwise, you may end up taking over every conflict and wrecking the -commit history. - -1. Make changes and commit locally to master branch -2. Test all changes and ensure no bugs have been introduced -3. Validate `readme.txt` with https://wordpress.org/plugins/about/validator/ -4. Run `git svn dcommit` to push changes to WordPress.org SVN repo -5. Tag any releases as needed `git tag -a vx.x ` -6. `git push -f origin master` to update GitHub repo - -**WARNING**: Unfortunately, `git push -f origin master` is required because -running `git svn dcommit` will usually modify commit history to change the -author of each commit to that of the user you use for wordpress.org (and often -that author does not match that of `git config --get user.name`). - -Be very careful to not overwrite commits that you have not yet pulled from -github. diff --git a/README.md b/README.md index 406b59612..52ea9f576 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ # Parse.ly -Stable tag: 2.4.1 +Stable tag: 2.5.0 Requires at least: 4.0 Tested up to: 5.6 Requires PHP: 5.6 License: GPLv2 or later -Tags: analytics, post, page +Tags: analytics, parse.ly, parsely, parsley Contributors: parsely, hbbtstar, jblz, mikeyarce, GaryJ, parsely_mike -The Parse.ly plugin real-time and historical analytics to your content through a platform designed and built for digital publishing. +The Parse.ly plugin facilitates real-time and historical analytics to your content through a platform designed and built for digital publishing. ## Description @@ -20,58 +20,71 @@ Join industry leaders -- like Mashable, Slate, News Corp, and Conde Nast -- who ### Features -- Get started with Parse.ly right away: the plugin automatically inserts the required parsely-page tag and JavaScript on all your published pages and posts. -- Allows you to specify the JavaScript implementation to use: standard, DOM free or asynchronous. -- If you've purchased access to the Parse.ly API, add a widget to your site with story recommendations personalized to individual users. +- Get started with Parse.ly right away: the plugin automatically inserts the required metadata and JavaScript on all your published pages and posts. +- Choose what format the metadata takes, and whether logged-in users should be included in the analytics. +- If you've purchased access to the Parse.ly API, add a widget to your site with article recommendations personalized to individual users. -Feedback, suggestions, questions or concerns? E-mail us at [support@parsely.com](mailto:support@parsely.com) we always want to hear from you. +Feedback, suggestions, questions or concerns? Open a new [GitHub issue](https://github.com/Parsely/wp-parsely/issues) or email us at [support@parsely.com](mailto:support@parsely.com). We always want to hear from you! ## Installation -1. This plug-in requires an active version of Parse.ly. We offer a free trial, [sign up here](http://www.parsely.com/trial/?utm_medium=referral&utm_source=wordpress.org&utm_content=wp-parsely) -1. If you haven't already done so, [sign up for a trial of Parse.ly](http://www.parsely.com/trial/?utm_medium=referral&utm_source=wordpress.org&utm_content=wp-parsely) -1. Download the plugin -1. Upload the entire `wp-parsely` folder to your `/wp-content/plugins` directory -1. Activate the plugin through the 'Plugins' menu in WordPress (look for "Parse.ly") -1. Head to the settings page for the plugin (should be /wp-admin/options-general.php?page=parsely) -1. Set your Site ID, which is your own site domain name (e.g., `mysite.com`) -1. Save your changes and enjoy your data! +The plugin requires an active Parse.ly account. Parse.ly gives creators, marketers, and developers the tools to understand content performance, prove content value, and deliver tailored content experiences that drive meaningful results. +[Sign up for a free trial of Parse.ly](http://www.parsely.com/trial/?utm_medium=referral&utm_source=wordpress.org&utm_content=wp-parsely). -**NOTE:** This plugin does not currently support dynamic tracking (the tracking of multiple pageviews on a single page). Some common use-cases for dynamic tracking are slideshows or articles loaded via AJAX calls in single-page applications -- situations in which new content is loaded without a full page refresh. Tracking these events requires manually implementing additional JavaScript above [the standard Parse.ly include](http://www.parsely.com/help/integration/basic/) that the plugin injects into your page source. Please consult [the Parse.ly documentation on dynamic tracking](https://www.parsely.com/help/integration/dynamic/) for instructions on implementing dynamic tracking, or contact Parse.ly support for additional assistance. +### Install the plugin from within WordPress -Feedback, suggestions, questions or concerns? E-mail us at [support@parsely.com](mailto:support@parsely.com) -- we always want to hear from you. +1. Visit the Plugins page from your WordPress dashboard and click "Add New" at the top of the page. +1. Search for "parse.ly" using the search bar on the right side. +1. Click "Install Now" to install the plugin. +1. After it's installed, click "Activate" to activate the plugin on your site. + +### Install the plugin manually + +1. Download the plugin from WordPress.org or get the latest release from our [Github Releases page](https://github.com/Parsely/wp-parsely/releases). +1. Unzip the downloaded archive. +1. Upload the entire `wp-parsely` folder to your `/wp-content/plugins` directory. +1. Visit the Plugins page from your WordPress dashboard and look for the newly installed Parse.ly plugin. +1. Click "Activate" to activate the plugin on your site. ## Frequently Asked Questions ### Where do I find my Site ID? -Your Site ID is your own site domain name (e.g., `mysite.com`). +Your Site ID is likely your own site domain name (e.g., `mysite.com`). You can find this in your Parse.ly account. -### Why can't I see Dash code on my post when I preview? +### Why can't I see Parse.ly code on my post when I preview? -Dash code will only be placed on pages and posts which have been published in WordPress to ensure we don't track traffic generated while you're still writing a post/page. +The code will only be placed on posts and pages which have been published in WordPress to ensure we don't track traffic generated while you're still writing a post or page. + +You may also be not tracking logged-in users, via one of the settings. ### How can I edit the values passed to the JSON-LD metadata? -You can use the `after_set_parsely_page` filter, which sends three arguments: the array of metadata, the post object, and the `parselyOptions` array: +You can use the `wp_parsely_metadata` filter, which sends three arguments: the array of metadata, the post object, and the `parsely_options` array: + + add_filter( 'wp_parsely_metadata', 'filter_parsely_metadata', 10, 3 ); + function filter_parsely_page( $parsely_metadata, $post, $parsely_options ) { + $parsely_metadata['articleSection'] = '...'; // Whatever values you want Parse.ly's Section to be. + return $parsely_metadata; + } + +This filter can go anywhere in your codebase, provided it always gets loaded. + +### Is the plugin compatible with AMP and Facebook Instant Articles? + +It is! The plugin hooks into Automattic's official plugins for [AMP](https://wordpress.org/plugins/amp/) and [Facebook Instant Articles](https://wordpress.org/plugins/fb-instant-articles/). -``` -function filter_parsely_page($parselyPage, $post, $parselyOptions ) { - $parselyPage['articleSection'] = ; // whatever values you want Parse.ly's Section to be - return $parselyPage; -} +AMP support is enabled automatically if the Automattic AMP plugin is installed -add_filter( 'after_set_parsely_page', 'filter_parsely_page', 10, 3); -``` +For Facebook Instant Articles support, enable "Parsely Analytics" in the "Advanced Settings" menu of the Facebook Instant Articles plugin. -This filter can go anywhere in your codebase, provided it always gets loaded. We recommend putting it in your header file, so that it gets loaded with wp_head. +### Does the plugin support dynamic tracking? -### Is the plugin Google AMP/Facebook Instant ready? +This plugin does not currently support dynamic tracking (the tracking of multiple pageviews on a single page). -It is! We are hooked into Automattic's official plugins for AMP and Facebook Instant. AMP support is enabled automatically if the Automattic AMP plugin is installed, and for Facebook Instant you just have to enable "Parsely Analytics" in the "Advanced Settings" menu of the Facebook Instant Articles plugin. +Some common use-cases for dynamic tracking are slideshows or articles loaded via AJAX calls in single-page applications -- situations in which new content is loaded without a full page refresh. -Official AMP plugin: https://wordpress.org/plugins/amp/ -Official FB Instant plugin: https://wordpress.org/plugins/fb-instant-articles/ +Tracking these events requires manually implementing additional JavaScript above [the standard Parse.ly include](http://www.parsely.com/help/integration/basic/) that the plugin injects into your page source. Please consult [the Parse.ly documentation on dynamic tracking](https://www.parsely.com/help/integration/dynamic/) for instructions on implementing dynamic tracking, or contact Parse.ly support for additional assistance. ### How do I create a local dev environment to make changes to the `wp-parsely` code? @@ -79,18 +92,40 @@ See [the wiki](https://github.com/Parsely/wp-parsely/wiki/Setting-up-a-WP-plugin ## Screenshots -1. The main settings screen of the wp-parsely plugin -![The main settings screen of the wp-parsely plugin](.wordpress-org/screenshot-1.png) +1. The main admin screen of the Parse.ly plugin, showing some of the settings. + ![The main settings screen of the wp-parsely plugin](.wordpress-org/screenshot-1.png) + +2. The settings for the Parse.ly Recommended Widget. Engage your visitors with predictive and personalized recommendations from Parse.ly. + ![The settings for the Parse.ly Recommended Widget](.wordpress-org/screenshot-2.png) +3. A view of the Parse.ly Dashboard Overview. Parse.ly offers analytics that empowers you to better understand how your content is peforming. + ![The Parsely Dashboard Overview](.wordpress-org/screenshot-3.png) + +## Sample Parse.ly metadata + +The standard Parse.ly JavaScript tracker inserted before the closing `body` tag: + + + + + + + +A sample `JSON-LD` structured data for a home page or section page: -2. The standard JavaScript include being inserted before `` -![2. The standard JavaScript include being inserted before body tag](.wordpress-org/screenshot-2.png) + + + -3. A sample `JSON-LD` meta tag for a home page or section page -![3. A sample `JSON-LD` meta tag for a home page or section page](.wordpress-org/screenshot-3.png) +A sample `JSON-LD` meta tag and structured data for an article or post: -4. A sample `JSON-LD` meta tag for an article or post -![4. A sample `JSON-LD` meta tag for an article or post](.wordpress-org/screenshot-4.png) + + + ## Changelog -See the [change log](https://github.com/parsely/wp-parsely/blob/master/CHANGELOG.md). +See the [change log](https://github.com/parsely/wp-parsely/blob/trunk/CHANGELOG.md). diff --git a/bin/export-plugin.sh b/bin/export-plugin.sh new file mode 100755 index 000000000..d8016f677 --- /dev/null +++ b/bin/export-plugin.sh @@ -0,0 +1,137 @@ +#!/bin/bash + +usage () { + echo "Usage $0 " + echo "Supported values for are: ZIP, DIR" + echo "IMPORTANT! Files in the output directory will be OVERWRITTEN!" +} + +OUTPUT_DIRECTORY="$1" +OUTPUT_FORMAT="${2:-ZIP}" +OUTPUT_FORMAT=$(echo "$OUTPUT_FORMAT" | tr '[:lower:]' '[:upper:]') + +if [ ! -d "$OUTPUT_DIRECTORY" ]; then + usage + echo " is not a dir. Your input was: \"$OUTPUT_DIRECTORY\"" + exit 1 +fi + +if [ ! -w "$OUTPUT_DIRECTORY" ]; then + usage + echo "Cannot write to : $OUTPUT_DIRECTORY" + exit 2 +fi + +BRANCH=$(git branch --show-current) +REMOTE="origin" +REMOTEBRANCH="$REMOTE/$BRANCH" +LOCALHASH=$(git rev-parse --short $BRANCH) + +echo "Attempting to package..." +echo " branch: $BRANCH" +echo " hash: $LOCALHASH" +echo " format: $OUTPUT_FORMAT" +echo " output dir: $OUTPUT_DIRECTORY"; + +if [[ "$(git status -sb | wc -l | xargs)" != "1" && -z "$DEBUG" ]]; then + echo "ERROR: Local branch contains uncommitted changes" + exit 10 +fi + +echo "Fetching remote branch: $REMOTE $BRANCH..." +git fetch "$REMOTE" "$BRANCH" + +if [[ "$?" != "0" && -z "$DEBUG" ]]; then + echo "Unable to continue without remote branch: $REMOTEBRANCH" + exit 11 +fi + +REMOTEHASH=$(git rev-parse --short $REMOTEBRANCH) + +echo "Local Branch \`$BRANCH\` is at hash: \`$LOCALHASH\`" +echo "Remote Branch \`$REMOTE $BRANCH\` is at hash: \`$REMOTEHASH\`" + +if [[ "$LOCALHASH" != "$REMOTEHASH" && -z "$DEBUG" ]]; then + echo "ERROR: Local hash does not match remote" + exit 12 +fi + +git diff --exit-code --quiet "$REMOTEBRANCH"..HEAD 2>/dev/null +if [[ "$?" != "0" && -z "$DEBUG" ]]; then + echo "ERROR: Local branch called $REMOTEBRANCH & actual remote branch do not match" + exit 13 +fi + +git diff --exit-code --quiet "$REMOTEBRANCH" 2>/dev/null +if [[ "$?" != "0" && -z "$DEBUG" ]]; then + echo "ERROR: Local files don't match branch: $REMOTEBRANCH" + exit 14 +fi + +confirm() { + read -p "Are you sure? (y/n) " -n1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "bailed" + exit + fi +} + +writezip() { + TIDYBRANCH=$(echo $BRANCH | sed 's/[^a-zA-Z0-9_.]/-/g') + OUTFILE="$OUTPUT_DIRECTORY/wp-parsely-$LOCALHASH-$TIDYBRANCH.zip" + echo "Preparing to export plugin to: $OUTFILE" + + if [[ -f $OUTFILE ]]; then + echo "WARNING: $OUTFILE already exists and will be overwritten." + confirm + fi + + git archive --format zip --output "$OUTFILE" "$REMOTEBRANCH" + if [[ "$?" != "0" ]]; then + echo "Error running git archive command"; + exit 20 + fi + echo "Successfully wrote plugin to: $OUTFILE" +} + +# `git archive` does not support writing directly to a directory, so tar, then extract +# Inspired by: https://github.com/10up/action-wordpress-plugin-deploy/blob/b3f8b3c0d73bf0af43aea9a0c2cb398d12d46b25/entrypoint.sh#L93-L100 +writedir() { + if [ "$(ls -A "$OUTPUT_DIRECTORY")" ]; then + echo "WARNING: $OUTPUT_DIRECTORY is NOT EMPTY!" + echo "If you continue, its contents will be completely replaced." + confirm + fi + + TMPDIR=$(mktemp -d) + + echo "Preparing to export plugin to temporary dir: $TMPDIR" + + git archive HEAD | tar -x --directory "$TMPDIR" + if [[ "$?" != "0" ]]; then + echo "Error running git archive command"; + exit 30 + fi + + rsync -a "$TMPDIR"/ "$OUTPUT_DIRECTORY"/ --delete --delete-excluded + if [[ "$?" != "0" ]]; then + echo "Error running rsync command"; + exit 31 + fi + + echo "Successfully wrote plugin to dir: $OUTPUT_DIRECTORY" +} + +if [[ "$OUTPUT_FORMAT" == "ZIP" ]]; then + writezip + exit +fi + +if [[ "$OUTPUT_FORMAT" == "DIR" ]]; then + writedir + exit +fi + +echo "Unsupported : $OUTPUT_FORMAT" +exit 99 diff --git a/build/admin-page.asset.php b/build/admin-page.asset.php new file mode 100644 index 000000000..add67bff9 --- /dev/null +++ b/build/admin-page.asset.php @@ -0,0 +1 @@ + array('wp-dom-ready', 'wp-i18n', 'wp-polyfill'), 'version' => '06021ec5bceb7a09784311ae923f5404'); \ No newline at end of file diff --git a/build/admin-page.js b/build/admin-page.js new file mode 100644 index 000000000..4c96fe15b --- /dev/null +++ b/build/admin-page.js @@ -0,0 +1,3 @@ +!function(e){var r={};function t(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=r,t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:n})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,r){if(1&r&&(e=t(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(t.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var o in e)t.d(n,o,function(r){return e[r]}.bind(null,o));return n},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},t.p="",t(t.s=9)}({0:function(e,r){e.exports=window.wp.domReady},3:function(e,r){e.exports=window.wp.i18n},9:function(e,r,t){"use strict";t.r(r);var n=t(0),o=t.n(n),a=t(3);o()((function(){var e=document.querySelector("#apikey"),r=document.querySelectorAll('.parsely-form-controls[data-requires-recrawl="true"] .help-text');if(e&&r.length){var t=Object(a.sprintf)( +/* translators: %s: The API Key that will be used to request a recrawl */ +Object(a.__)('Important: changing this value on a site currently tracked with Parse.ly will require reprocessing of your Parse.ly data. Once you have changed this value, please contact support@parsely.com'),e.value,"wp-parsely");[].forEach.call(r,(function(e){var r=document.createElement("p");r.className="description",r.innerHTML=t,e.appendChild(r)}))}}))}}); \ No newline at end of file diff --git a/build/init-api.asset.php b/build/init-api.asset.php new file mode 100644 index 000000000..9e7bdf5ee --- /dev/null +++ b/build/init-api.asset.php @@ -0,0 +1 @@ + array('wp-polyfill'), 'version' => '700f35bca2ccd41db5214814eb890235'); \ No newline at end of file diff --git a/build/init-api.js b/build/init-api.js new file mode 100644 index 000000000..9dba2b9db --- /dev/null +++ b/build/init-api.js @@ -0,0 +1 @@ +!function(t){var e={};function n(o){if(e[o])return e[o].exports;var r=e[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=t,n.c=e,n.d=function(t,e,o){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:o})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)n.d(o,r,function(e){return t[e]}.bind(null,r));return o},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=8)}([,function(t,e){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e){t.exports=window.regeneratorRuntime},,function(t,e){function n(e){return"function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?(t.exports=n=function(t){return typeof t},t.exports.default=t.exports,t.exports.__esModule=!0):(t.exports=n=function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t.exports.default=t.exports,t.exports.__esModule=!0),n(e)}t.exports=n,t.exports.default=t.exports,t.exports.__esModule=!0},function(t,e){function n(t,e,n,o,r,u,i){try{var c=t[u](i),f=c.value}catch(t){return void n(t)}c.done?e(f):Promise.resolve(f).then(o,r)}t.exports=function(t){return function(){var e=this,o=arguments;return new Promise((function(r,u){var i=t.apply(e,o);function c(t){n(i,r,u,c,f,"next",t)}function f(t){n(i,r,u,c,f,"throw",t)}c(void 0)}))}},t.exports.default=t.exports,t.exports.__esModule=!0},,,function(t,e,n){"use strict";n.r(e),function(t){n.d(e,"initApi",(function(){return l}));var o=n(4),r=n.n(o),u=n(5),i=n.n(u),c=n(2),f=n.n(c);function a(){return p.apply(this,arguments)}function p(){return(p=i()(f.a.mark((function e(){var n,o,r,u,i,c;return f.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(u=null===(n=t.wpParsely)||void 0===n?void 0:n.apikey,i=null===(o=t.PARSELY)||void 0===o||null===(r=o.config)||void 0===r?void 0:r.parsely_site_uuid,u&&i){e.next=4;break}return e.abrupt("return");case 4:return c="https://api.parsely.com/v2/profile?apikey=".concat(encodeURIComponent(u),"&uuid=").concat(encodeURIComponent(i),"&url=").concat(window.location.href),e.abrupt("return",fetch(c));case 6:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function l(){if("object"!==r()(t.PARSELY))t.PARSELY={onload:a};else{if("function"!=typeof t.PARSELY.onload)return void(t.PARSELY.onload=a);var e=t.PARSELY.onload;t.PARSELY.onload=function(){e&&e(),a()}}}l()}.call(this,n(1))}]); \ No newline at end of file diff --git a/build/recommended-widget.asset.php b/build/recommended-widget.asset.php new file mode 100644 index 000000000..2712c0a29 --- /dev/null +++ b/build/recommended-widget.asset.php @@ -0,0 +1 @@ + array('wp-dom-ready', 'wp-polyfill'), 'version' => 'f3bcdeb624be02da652e81d20b364165'); \ No newline at end of file diff --git a/build/recommended-widget.js b/build/recommended-widget.js new file mode 100644 index 000000000..9045d6435 --- /dev/null +++ b/build/recommended-widget.js @@ -0,0 +1 @@ +!function(e){var t={};function r(n){if(t[n])return t[n].exports;var i=t[n]={i:n,l:!1,exports:{}};return e[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)r.d(n,i,function(t){return e[t]}.bind(null,i));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=10)}([function(e,t){e.exports=window.wp.domReady},function(e,t){var r;r=function(){return this}();try{r=r||new Function("return this")()}catch(e){"object"==typeof window&&(r=window)}e.exports=r},,,,,function(e,t){e.exports=function(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t,r){"use strict";r.d(t,"a",(function(){return n}));var n=function(e){var t,r,n=(null!==(t=null===(r=document)||void 0===r?void 0:r.cookie)&&void 0!==t?t:"").split("; ").find((function(t){return t.startsWith("".concat(e,"="))}));return null==n?void 0:n.split("=")[1]}},,,function(e,t,r){"use strict";r.r(t),function(e){var t=r(6),n=r.n(t),i=r(0),o=r.n(i),a=r(7);function d(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t0)){var m=c("
").addClass("parsely-recommendation-widget").appendTo(f);"none"!==i&&m.addClass("display-thumbnail"),r&&m.addClass("list-"+r);var y=c("