diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5b6e9ba --- /dev/null +++ b/.gitattributes @@ -0,0 +1,34 @@ +# +# Exclude these files from release archives. +# This will also make them unavailable when using Composer with `--prefer-dist`. +# If you develop using Composer, use `--prefer-source`. +# https://www.reddit.com/r/PHP/comments/2jzp6k/i_dont_need_your_tests_in_my_production +# https://blog.madewithlove.be/post/gitattributes/ +# +.gitattributes export-ignore +.gitignore export-ignore +.phpcs.xml export-ignore +.phpcs.xml.dist export-ignore +.travis.yml export-ignore +composer.json export-ignore +deploy.sh export-ignore +phpcs.xml export-ignore +phpcs.xml.dist export-ignore +phpunit.xml export-ignore +phpunit.xml.dist export-ignore +README.md export-ignore +assets export-ignore +bin export-ignore +tests export-ignore + +# +# Auto detect text files and perform LF normalization +# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/ +# +* text=auto + +# +# The above will handle all files NOT found below +# +*.md text +*.php text diff --git a/.gitignore b/.gitignore index 22d0d82..e3bc916 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ -vendor +composer.lock +vendor/* +.phpcs.xml +phpcs.xml +phpunit.xml diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist new file mode 100644 index 0000000..470a4dd --- /dev/null +++ b/.phpcs.xml.dist @@ -0,0 +1,81 @@ + + + + The coding standard for the WP-Post-Meta-Revisions plugin. + + + + . + + */vendor/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /tests/*\.php$ + + + + + /wp-post-meta-revisions\.php$ + + + diff --git a/.travis.yml b/.travis.yml index a43b6f1..513c2db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,49 +1,62 @@ -language: php +cache: + apt: true + directories: + # Cache directory for older Composer versions. + - $HOME/.composer/cache/files + # Cache directory for more recent Composer versions. + - $HOME/.cache/composer/files language: php -sudo: false +services: + - mysql + +# Declare versions of PHP to use. +php: + - 5.6 + - 7.0 + - 7.1 + - 7.2 + - "7.4snapshot" + +env: + global: + - WP_VERSION=master # Git equivalent of SVN /trunk matrix: include: - - php: 7.1 - env: PHPUNIT_VERSION="^7" - env: WP_TRAVISCI=travis:js - php: 7.3 - env: PHPUNIT_VERSION="^7" - - php: 7.2 - env: PHPUNIT_VERSION="^7" - - php: 7.1 - env: PHPUNIT_VERSION="^7" - - php: 7.0 - - php: 5.6 - - php: 5.6 - env: WP_TRAVIS_OBJECT_CACHE=true - services: memcached - - php: 5.5 - - php: 5.3 - dist: precise - - php: 5.2 - dist: precise - - php: nightly + env: PHPCS=1 + allow_failures: - - php: nightly + - php: "7.4snapshot" + fast_finish: true -env: - global: - - WP_VERSION=master # Git equivalent of SVN /trunk - - PHPUNIT_VERSION="travis" + +# Before install, failures in this section will result in build status 'errored' +before_install: + # Speed up build time by disabling Xdebug when its not needed. + - phpenv config-rm xdebug.ini || echo 'No xdebug config.' + # clone the WordPress develop repo + - WP_DEVELOP_DIR=/tmp/wordpress + - git clone --depth=1 --branch="master" git://develop.git.wordpress.org/ $WP_DEVELOP_DIR + # Install the dependencies. + - composer install before_script: - bash bin/install-wp-tests.sh wordpress_test root '' localhost master -# Before install, failures in this section will result in build status 'errored' -before_install: - # setup WP_DEVELOP_DIR (needed for bbPress to bootstrap WP PHPUnit tests) - - WP_DEVELOP_DIR=/tmp/wordpress - # clone the WordPress develop repo - - git clone --depth=1 --branch="master" git://develop.git.wordpress.org/ $WP_DEVELOP_DIR - - WP_DEVELOP_DIR=/tmp/wordpress/src - - if [[ $PHPUNIT_VERSION != "travis" ]]; then composer require phpunit/phpunit:${PHPUNIT_VERSION}; fi +script: + # Run the unit tests. + - vendor/bin/phpunit + + # Lint the PHP files against parse errors. + - find -L . -path ./vendor -prune -o -name '*.php' -print0 | xargs -0 -n 1 -P 4 php -l + + # Validate the composer.json file. + # @link https://getcomposer.org/doc/03-cli.md#validate + - if [[ $TRAVIS_PHP_VERSION == "5.6" || $TRAVIS_PHP_VERSION == "7.3" ]]; then composer validate --no-check-all; fi + # Check for code style violations, best practices and PHP cross-version compatibility. + - if [[ "$PHPCS" == "1" ]]; then vendor/bin/phpcs --report=full,summary; fi diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..66f6fb6 --- /dev/null +++ b/composer.json @@ -0,0 +1,30 @@ +{ + "name": "adamsilverstein/wp-post-meta-revisions", + "description": "A WordPress plugin which implements a post meta revisioning feature as arrived at in https://core.trac.wordpress.org/ticket/20564.", + "homepage" : "https://wordpress.org/plugins/wp-post-meta-revisions/", + "keywords" : ["wordpress", "plugin" ], + "type" : "wordpress-plugin", + "license" : "GPL-2.0-or-later", + "authors": [ + { + "name": "Adam Silverstein", + "email": "adam@10up.com" + } + ], + "support": { + "forum" : "https://wordpress.org/support/plugin/wp-post-meta-revisions", + "issues": "https://github.com/adamsilverstein/wp-post-meta-revisions/issues", + "source": "https://github.com/adamsilverstein/wp-post-meta-revisions" + }, + "require": { + "php" : ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^4 | ^5 | ^6 | ^7", + "wp-coding-standards/wpcs": "^2.0", + "phpcompatibility/phpcompatibility-wp": "^2.0", + "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0" + }, + "minimum-stability" : "RC", + "prefer-stable": true +} \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml.dist similarity index 67% rename from phpunit.xml rename to phpunit.xml.dist index 73ca3a8..117aea8 100644 --- a/phpunit.xml +++ b/phpunit.xml.dist @@ -1,4 +1,7 @@ + - + ./tests/ diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 5b11274..bee5632 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -15,6 +15,9 @@ require_once $_tests_dir . '/includes/functions.php'; +/** + * Load the plugin for testing. + */ function _manually_load_plugin() { require dirname( __FILE__ ) . '/../wp-post-meta-revisions.php'; } diff --git a/tests/test-meta-revisions.php b/tests/test-meta-revisions.php index 2626d91..dcabebf 100644 --- a/tests/test-meta-revisions.php +++ b/tests/test-meta-revisions.php @@ -14,6 +14,10 @@ class MetaRevisionTests extends WP_UnitTestCase { /** * Callback function to add the revisioned keys. + * + * @param array $keys The passed array of keys to revision. + * + * @return array The filtered array of keys to revision, including the key 'meta_revision_test'. */ public function add_revisioned_keys( $keys ) { $keys[] = 'meta_revision_test'; @@ -23,6 +27,9 @@ public function add_revisioned_keys( $keys ) { /** * Test the revisions system for storage of meta values with slashes. * + * @param string $passed The passed data for testing. + * @param string $expected The expected value after storing & retrieving. + * * @group revision * @group slashed * @dataProvider slashed_data_provider @@ -77,6 +84,9 @@ public function test_revisions_stores_meta_values_with_slashes( $passed, $expect remove_filter( 'wp_post_revision_meta_keys', array( $this, 'add_revisioned_keys' ) ); } + /** + * Provide data for the slashed data tests. + */ public function slashed_data_provider() { return array( array( diff --git a/wp-post-meta-revisions.php b/wp-post-meta-revisions.php index f5d7e2c..919f248 100644 --- a/wp-post-meta-revisions.php +++ b/wp-post-meta-revisions.php @@ -29,18 +29,18 @@ public function __construct() { // Actions. // // When restoring a revision, also restore that revisions's revisioned meta. - add_action( 'wp_restore_post_revision', array( $this, '_wp_restore_post_revision_meta' ), 10, 2 ); + add_action( 'wp_restore_post_revision', array( $this, 'wp_restore_post_revision_meta' ), 10, 2 ); // When creating or updating an autosave, save any revisioned meta fields. - add_action( 'wp_creating_autosave', array( $this, '_wp_autosave_post_revisioned_meta_fields' ) ); - add_action( 'wp_before_creating_autosave', array( $this, '_wp_autosave_post_revisioned_meta_fields' ) ); + add_action( 'wp_creating_autosave', array( $this, 'wp_autosave_post_revisioned_meta_fields' ) ); + add_action( 'wp_before_creating_autosave', array( $this, 'wp_autosave_post_revisioned_meta_fields' ) ); // When creating a revision, also save any revisioned meta. - add_action( '_wp_put_post_revision', array( $this, '_wp_save_revisioned_meta_fields' ) ); + add_action( '_wp_put_post_revision', array( $this, 'wp_save_revisioned_meta_fields' ) ); // Filters. // When revisioned post meta has changed, trigger a revision save. - add_filter( 'wp_save_post_revision_post_has_changed', array( $this, '_wp_check_revisioned_meta_fields_have_changed' ), 10, 3 ); + add_filter( 'wp_save_post_revision_post_has_changed', array( $this, 'wp_check_revisioned_meta_fields_have_changed' ), 10, 3 ); } @@ -49,8 +49,8 @@ public function __construct() { * * @since 4.5.0 */ - public function _add_metadata_preview_filter() { - add_filter( 'get_post_metadata', array( $this, '_wp_preview_meta_filter' ), 10, 4 ); + public function add_metadata_preview_filter() { + add_filter( 'get_post_metadata', array( $this, 'wp_preview_meta_filter' ), 10, 4 ); } /** @@ -63,19 +63,25 @@ public function _add_metadata_preview_filter() { * * @param Post object $new_autosave The new post being autosaved. */ - public function _wp_autosave_post_revisioned_meta_fields( $new_autosave ) { + public function wp_autosave_post_revisioned_meta_fields( $new_autosave ) { /* * The post data arrives as either $_POST['data']['wp_autosave'] or the $_POST * itself. This sets $posted_data to the correct variable. + * + * Ignoring sanitization to avoid altering meta. Ignoring the nonce check because + * this is hooked on inner core hooks where a valid nonce was already checked. + * + * @phpcs:disable WordPress.Security */ - $posted_data = isset( $_POST['data']['wp_autosave'] ) ? $_POST['data']['wp_autosave'] : $_POST; // WPCS: CSRF ok. input var ok. sanitization ok. + $posted_data = isset( $_POST['data']['wp_autosave'] ) ? $_POST['data']['wp_autosave'] : $_POST; + // phpcs:enable /* * Go thru the revisioned meta keys and save them as part of the autosave, if * the meta key is part of the posted data, the meta value is not blank and * the the meta value has changes from the last autosaved value. */ - foreach ( $this->_wp_post_revision_meta_keys() as $meta_key ) { + foreach ( $this->wp_post_revision_meta_keys() as $meta_key ) { if ( isset( $posted_data[ $meta_key ] ) && @@ -109,7 +115,7 @@ public function _wp_autosave_post_revisioned_meta_fields( $new_autosave ) { * * @return array An array of meta keys to be revisioned. */ - public function _wp_post_revision_meta_keys() { + public function wp_post_revision_meta_keys() { /** * Filter the list of post meta keys to be revisioned. * @@ -117,16 +123,20 @@ public function _wp_post_revision_meta_keys() { * * @param array $keys An array of default meta fields to be revisioned. */ - return apply_filters( 'wp_post_revision_meta_keys', array() ); + return apply_filters( 'wp_post_revision_meta_keys', array() ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals } /** * Check whether revisioned post meta fields have changed. * + * @param bool $post_has_changed Whether the post has changed. + * @param WP_Post $last_revision The last revision post object. + * @param WP_Post $post The post object. + * * @since 4.5.0 */ - public function _wp_check_revisioned_meta_fields_have_changed( $post_has_changed, WP_Post $last_revision, WP_Post $post ) { - foreach ( $this->_wp_post_revision_meta_keys() as $meta_key ) { + public function wp_check_revisioned_meta_fields_have_changed( $post_has_changed, WP_Post $last_revision, WP_Post $post ) { + foreach ( $this->wp_post_revision_meta_keys() as $meta_key ) { if ( get_post_meta( $post->ID, $meta_key ) !== get_post_meta( $last_revision->ID, $meta_key ) ) { $post_has_changed = true; break; @@ -138,14 +148,16 @@ public function _wp_check_revisioned_meta_fields_have_changed( $post_has_changed /** * Save the revisioned meta fields. * + * @param int $revision_id The ID of the revision to save the meta to. + * * @since 4.5.0 */ - public function _wp_save_revisioned_meta_fields( $revision_id ) { + public function wp_save_revisioned_meta_fields( $revision_id ) { $revision = get_post( $revision_id ); $post_id = $revision->post_parent; // Save revisioned meta fields. - foreach ( $this->_wp_post_revision_meta_keys() as $meta_key ) { + foreach ( $this->wp_post_revision_meta_keys() as $meta_key ) { $meta_value = get_post_meta( $post_id, $meta_key ); /* @@ -159,11 +171,14 @@ public function _wp_save_revisioned_meta_fields( $revision_id ) { /** * Restore the revisioned meta values for a post. * + * @param int $post_id The ID of the post to restore the meta to. + * @param int $revision_id The ID of the revision to restore the meta from. + * * @since 4.5.0 */ - public function _wp_restore_post_revision_meta( $post_id, $revision_id ) { + public function wp_restore_post_revision_meta( $post_id, $revision_id ) { // Restore revisioned meta fields. - $metas_revisioned = $this->_wp_post_revision_meta_keys(); + $metas_revisioned = $this->wp_post_revision_meta_keys(); if ( isset( $metas_revisioned ) && 0 !== count( $metas_revisioned ) ) { foreach ( $metas_revisioned as $meta_key ) { // Clear any existing metas. @@ -196,13 +211,13 @@ public function _wp_restore_post_revision_meta( $post_id, $revision_id ) { * the post type is a revision or the post ID doesn't match the object ID. * Otherwise, the revisioned meta value is returned for the preview. */ - public function _wp_preview_meta_filter( $value, $object_id, $meta_key, $single ) { + public function wp_preview_meta_filter( $value, $object_id, $meta_key, $single ) { $post = get_post(); if ( empty( $post ) || $post->ID !== $object_id || - ! in_array( $meta_key, $this->_wp_post_revision_meta_keys(), true ) || + ! in_array( $meta_key, $this->wp_post_revision_meta_keys(), true ) || 'revision' === $post->post_type ) { return $value;