From ce642fd8d5d33f2004163b2276ae9b801e67e360 Mon Sep 17 00:00:00 2001 From: Erick Hitter <git-contrib@ethitter.com> Date: Sun, 5 Jun 2022 14:09:54 -0700 Subject: [PATCH] Separate block-editor bits from existing classes --- .gitignore | 1 + .phpcs.xml.dist | 4 +- assets/src/gutenberg.js | 4 +- inc/class-block-editor.php | 173 ++++++++++++ ...lass-wp-revisions-control-bulk-actions.php | 43 +-- inc/class-wp-revisions-control.php | 259 +----------------- inc/trait-singleton.php | 45 +++ readme.txt | 2 +- wp-revisions-control.php | 12 +- 9 files changed, 251 insertions(+), 292 deletions(-) create mode 100644 inc/class-block-editor.php create mode 100644 inc/trait-singleton.php diff --git a/.gitignore b/.gitignore index 6f68bc7..bb41fbf 100755 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ phpunit.xml Thumbs.db wp-cli.local.yml node_modules/ +*.map *.sql *.tar.gz *.zip diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index 121c174..1c2181c 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -4,7 +4,7 @@ <!-- What to scan --> <file>.</file> - <exclude-pattern>/vendor/</exclude-pattern> + <exclude-pattern>/assets/build/</exclude-pattern> <exclude-pattern>/node_modules/</exclude-pattern> <!-- How to scan --> @@ -18,7 +18,7 @@ <!-- Rules: Check PHP version compatibility --> <!-- https://github.com/PHPCompatibility/PHPCompatibility#sniffing-your-code-for-compatibility-with-specific-php-versions --> - <config name="testVersion" value="5.3-"/> + <config name="testVersion" value="5.6-"/> <!-- https://github.com/PHPCompatibility/PHPCompatibilityWP --> <rule ref="PHPCompatibilityWP"/> diff --git a/assets/src/gutenberg.js b/assets/src/gutenberg.js index fe7f599..b1a6c60 100644 --- a/assets/src/gutenberg.js +++ b/assets/src/gutenberg.js @@ -74,8 +74,8 @@ const PurgeModal = ( limit, manualPurge ) => { </Modal> ) } </> - ) -} + ); +}; // TODO: switch to `useSelect` and `useDispatch`. const RevisionsControl = compose( diff --git a/inc/class-block-editor.php b/inc/class-block-editor.php new file mode 100644 index 0000000..58ba02b --- /dev/null +++ b/inc/class-block-editor.php @@ -0,0 +1,173 @@ +<?php +/** + * Support block editor (Gutenberg). + * + * @package WP_Revisions_Control + */ + +namespace WP_Revisions_Control; + +use WP_REST_Response; +use WP_REST_Request; +use WP_Revisions_Control; + +/** + * Class Block_Editor. + */ +class Block_Editor { + use Singleton; + + /** + * Name of action used to clean up post's revisions via cron. + * + * @var string + */ + private $cron_action = 'wp_revisions_control_cron_purge'; + + /** + * Prepare class. + * + * This is called at `init`, so cannot use that hook unless priority is + * greater than 10. + */ + private function setup() { + add_action( 'rest_api_init', array( $this, 'action_rest_api_init' ) ); + add_filter( 'is_protected_meta', array( $this, 'filter_is_protected_meta' ), 10, 2 ); + add_action( $this->cron_action, array( $this, 'do_purge_excess' ) ); + add_action( 'admin_init', array( $this, 'action_admin_init' ) ); + } + + /** + * Register admin-only hooks. + * + * @return void + */ + public function action_admin_init() { + if ( ! function_exists( 'use_block_editor_for_post' ) ) { + return; + } + + add_action( 'enqueue_block_editor_assets', array( $this, 'action_enqueue_block_editor_assets' ) ); + } + + /** + * Register REST API components for Gutenberg UI. + */ + public function action_rest_api_init() { + if ( + ! function_exists( 'register_meta' ) + || ! function_exists( 'register_rest_route' ) + ) { + return; + } + + foreach ( array_keys( WP_Revisions_Control::get_instance()->get_post_types() ) as $post_type ) { + register_meta( + 'post', + WP_REVISIONS_CONTROL_LIMIT_META_KEY, + array( + 'object_subtype' => $post_type, + 'type' => 'string', // Can be empty, so must be string. + 'default' => '', + 'single' => true, + 'show_in_rest' => true, + 'description' => __( + 'Number of revisions to retain.', + 'wp_revisions_control' + ), + ) + ); + } + + register_rest_route( + 'wp-revisions-control/v1', + 'schedule/(?P<id>[\d]+)', + array( + 'methods' => 'PUT', + 'callback' => array( $this, 'rest_api_schedule_purge' ), + 'permission_callback' => array( $this, 'rest_api_permission_callback' ), + 'args' => array( + 'id' => array( + 'required' => true, + 'type' => 'integer', + 'validate_callback' => array( $this, 'rest_api_validate_id' ), + ), + ), + 'show_in_index' => false, + ) + ); + } + + /** + * Permissions callback for REST endpoint. + * + * @param WP_REST_Request $request Request object. + * @return bool + */ + public function rest_api_permission_callback( $request ) { + return current_user_can( + 'edit_post', + $request->get_param( 'id' ) + ); + } + + /** + * Validate post ID. + * + * @param int $input Post ID. + * @return bool + */ + public function rest_api_validate_id( $input ) { + return is_numeric( $input ); + } + + /** + * Schedule cleanup of post's excess revisions. + * + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response + */ + public function rest_api_schedule_purge( $request ) { + $result = wp_schedule_single_event( + time() + 3, + $this->cron_action, + array( + $request->get_param( 'id' ), + ) + ); + + return rest_ensure_response( $result ); + } + + /** + * Allow our meta to be edited from Gutenberg. + * + * @param bool $protected If meta is protected. + * @param string $meta_key Meta key being checked. + * @return false + */ + public function filter_is_protected_meta( $protected, $meta_key ) { + if ( $meta_key === WP_REVISIONS_CONTROL_LIMIT_META_KEY ) { + return false; + } + + return $protected; + } + + /** + * Register Gutenberg script. + */ + public function action_enqueue_block_editor_assets() { + $asset_data = require_once dirname( __DIR__ ) . '/assets/build/gutenberg.asset.php'; + + wp_enqueue_script( + 'wp-revisions-control-block-editor', + plugins_url( + 'assets/build/gutenberg.js', + __DIR__ + ), + $asset_data['dependencies'], + $asset_data['version'], + ); + } +} diff --git a/inc/class-wp-revisions-control-bulk-actions.php b/inc/class-wp-revisions-control-bulk-actions.php index 14402e6..f7e74c8 100644 --- a/inc/class-wp-revisions-control-bulk-actions.php +++ b/inc/class-wp-revisions-control-bulk-actions.php @@ -5,23 +5,20 @@ * @package WP_Revisions_Control */ +use WP_Revisions_Control\Singleton; + /** * Class WP_Revisions_Control_Bulk_Actions. */ class WP_Revisions_Control_Bulk_Actions { - /** - * Singleton. - * - * @var static - */ - private static $__instance; + use Singleton; /** * Supported post types. * * @var array */ - protected $post_types; + public static $post_types; /** * Base for bulk action names. @@ -37,38 +34,14 @@ class WP_Revisions_Control_Bulk_Actions { */ protected $actions; - /** - * Silence is golden! - */ - private function __construct() {} - - /** - * Singleton implementation. - * - * @param array $post_types Supported post types, used only on instantiation. - * @return static - */ - public static function get_instance( $post_types = array() ) { - if ( ! is_a( static::$__instance, __CLASS__ ) ) { - static::$__instance = new self(); - - static::$__instance->setup( $post_types ); - } - - return static::$__instance; - } - /** * One-time actions. - * - * @param array $post_types Supported post types. */ - public function setup( $post_types ) { - if ( empty( $post_types ) || ! is_array( $post_types ) ) { + public function setup() { + if ( empty( static::$post_types ) || ! is_array( static::$post_types ) ) { return; } - $this->post_types = $post_types; $this->register_actions(); add_action( 'load-edit.php', array( $this, 'register_admin_hooks' ) ); @@ -104,9 +77,7 @@ class WP_Revisions_Control_Bulk_Actions { return; } - $post_types = array_keys( $this->post_types ); - - if ( ! in_array( $screen->post_type, $post_types, true ) ) { + if ( ! array_key_exists( $screen->post_type, static::$post_types ) ) { return; } diff --git a/inc/class-wp-revisions-control.php b/inc/class-wp-revisions-control.php index c77ce87..b5a5ebe 100644 --- a/inc/class-wp-revisions-control.php +++ b/inc/class-wp-revisions-control.php @@ -5,16 +5,14 @@ * @package WP_Revisions_Control */ +use WP_Revisions_Control\Block_Editor; +use WP_Revisions_Control\Singleton; + /** * Class WP_Revisions_Control. */ class WP_Revisions_Control { - /** - * Singleton. - * - * @var static - */ - private static $__instance; + use Singleton; /** * Filter priority. @@ -64,13 +62,6 @@ class WP_Revisions_Control { */ private $settings_section = 'wp_revisions_control'; - /** - * Name of setting to disable native Gutenberg component. - * - * @var string - */ - private $setting_native_gutenberg; - /** * Meta key holding post's revisions limit. * @@ -78,41 +69,14 @@ class WP_Revisions_Control { */ private $meta_key_limit = '_wp_rev_ctl_limit'; - /** - * Name of action used to clean up post's revisions via cron. - * - * @var string - */ - private $cron_action = 'wp_revisions_control_cron_purge'; - - /** - * Silence is golden! - */ - private function __construct() {} - - /** - * Singleton implementation. - * - * @return static - */ - public static function get_instance() { - if ( ! is_a( static::$__instance, __CLASS__ ) ) { - static::$__instance = new self(); - - static::$__instance->setup(); - } - - return static::$__instance; - } - /** * Register actions and filters at `init` so others can interact, if desired. */ private function setup() { - $this->setting_native_gutenberg = $this->settings_section . '_gutenberg'; - add_action( 'plugins_loaded', array( $this, 'action_plugins_loaded' ) ); add_action( 'init', array( $this, 'action_init' ) ); + + Block_Editor::get_instance(); } /** @@ -133,13 +97,6 @@ class WP_Revisions_Control { add_action( 'admin_init', array( $this, 'action_admin_init' ) ); add_filter( 'wp_revisions_to_keep', array( $this, 'filter_wp_revisions_to_keep' ), $this->plugin_priority(), 2 ); - - if ( $this->use_gutenberg_component() ) { - add_action( 'rest_api_init', array( $this, 'action_rest_api_init' ) ); - add_filter( 'is_protected_meta', array( $this, 'filter_is_protected_meta' ), 10, 2 ); - add_action( 'enqueue_block_editor_assets', array( $this, 'action_enqueue_block_editor_assets' ) ); - add_action( $this->cron_action, array( $this, 'do_purge_excess' ) ); - } } /** @@ -152,7 +109,6 @@ class WP_Revisions_Control { // Plugin setting section. register_setting( $this->settings_page, $this->settings_section, array( $this, 'sanitize_options' ) ); - register_setting( $this->settings_page, $this->setting_native_gutenberg, array( $this, 'sanitize_gutenberg_option' ) ); add_settings_section( $this->settings_section, 'WP Revisions Control', array( $this, 'settings_section_intro' ), $this->settings_page ); @@ -160,26 +116,14 @@ class WP_Revisions_Control { add_settings_field( $this->settings_section . '-' . $post_type, $name, array( $this, 'field_post_type' ), $this->settings_page, $this->settings_section, array( 'post_type' => $post_type ) ); } - if ( function_exists( 'use_block_editor_for_post' ) ) { - add_settings_field( - $this->settings_section . '-gutenberg', - __( - 'Gutenberg', - 'wp_revisions_control' - ), - array( $this, 'field_gutenberg' ), - $this->settings_page, - $this->settings_section - ); - } - // Post-level functionality. add_action( 'add_meta_boxes', array( $this, 'action_add_meta_boxes' ), 10, 2 ); add_action( 'wp_ajax_' . $this->settings_section . '_purge', array( $this, 'ajax_purge' ) ); add_action( 'save_post', array( $this, 'action_save_post' ) ); // Bulk actions. - WP_Revisions_Control_Bulk_Actions::get_instance( $post_types ); + WP_Revisions_Control_Bulk_Actions::$post_types = $post_types; + WP_Revisions_Control_Bulk_Actions::get_instance(); } /** @@ -228,42 +172,6 @@ class WP_Revisions_Control { <?php } - /** - * Render field to disable Gutenberg component. - */ - public function field_gutenberg() { - $setting_id = $this->settings_section . '_gutenberg'; - - $checked = (bool) get_option( $this->setting_native_gutenberg, false ); - - ?> - <input - type="checkbox" - id="<?php echo esc_attr( $setting_id ); ?>" - name="<?php echo esc_attr( $this->setting_native_gutenberg ); ?>" - value="1" - <?php checked( $checked ); ?> - /> - <label for="<?php echo esc_attr( $setting_id ); ?>"> - <?php - esc_html_e( - 'Disable Gutenberg sidebar component', - 'wp_revisions_control' - ); - ?> - </label> - - <p class="description"> - <?php - esc_html_e( - 'If checked, the plugin\'s previous interface will appear below the post content in Gutenberg, rather than appearing in the sidebar.', - 'wp_revisions_control' - ); - ?> - </p> - <?php - } - /** * Sanitize plugin settings. * @@ -295,16 +203,6 @@ class WP_Revisions_Control { return $options_sanitized; } - /** - * Convert Gutenberg checkbox to a boolean. - * - * @param mixed $option Value to sanitize. - * @return bool - */ - public function sanitize_gutenberg_option( $option ) { - return (bool) $option; - } - /** * REVISIONS QUANTITY OVERRIDES. */ @@ -335,7 +233,7 @@ class WP_Revisions_Control { * @return int */ public function filter_wp_revisions_to_keep( $qty, $post ) { - $post_limit = get_post_meta( $post->ID, $this->meta_key_limit, true ); + $post_limit = get_post_meta( $post->ID, WP_REVISIONS_CONTROL_LIMIT_META_KEY, true ); if ( 0 < strlen( $post_limit ) ) { $qty = $post_limit; @@ -363,13 +261,11 @@ class WP_Revisions_Control { */ public function action_add_meta_boxes( $post_type, $post ) { if ( - $this->use_gutenberg_component() - || ! post_type_supports( $post_type, 'revisions' ) + ! post_type_supports( $post_type, 'revisions' ) || 'auto-draft' === get_post_status() || ( function_exists( 'use_block_editor_for_post' ) && use_block_editor_for_post( $post ) - && $this->use_gutenberg_component() ) || count( wp_get_post_revisions( $post ) ) < 1 ) { @@ -572,9 +468,9 @@ class WP_Revisions_Control { $limit = (int) $_POST[ $qty ]; if ( -1 === $limit || empty( $limit ) ) { - delete_post_meta( $post_id, $this->meta_key_limit ); + delete_post_meta( $post_id, WP_REVISIONS_CONTROL_LIMIT_META_KEY ); } else { - update_post_meta( $post_id, $this->meta_key_limit, absint( $limit ) ); + update_post_meta( $post_id, WP_REVISIONS_CONTROL_LIMIT_META_KEY, absint( $limit ) ); } } } @@ -600,124 +496,6 @@ class WP_Revisions_Control { <?php } - /** - * GUTENBERG SUPPORT. - */ - - /** - * Register REST API components for Gutenberg UI. - */ - public function action_rest_api_init() { - foreach ( array_keys( $this->get_post_types() ) as $post_type ) { - register_meta( - 'post', - $this->meta_key_limit, - array( - 'object_subtype' => $post_type, - 'type' => 'string', // Can be empty, so must be string. - 'default' => '', - 'single' => true, - 'show_in_rest' => true, - 'description' => __( - 'Number of revisions to retain.', - 'wp_revisions_control' - ), - ) - ); - } - - register_rest_route( - 'wp-revisions-control/v1', - 'schedule/(?P<id>[\d]+)', - array( - 'methods' => 'PUT', - 'callback' => array( $this, 'rest_api_schedule_purge' ), - 'permission_callback' => array( $this, 'rest_api_permission_callback' ), - 'args' => array( - 'id' => array( - 'required' => true, - 'type' => 'integer', - 'validate_callback' => array( $this, 'rest_api_validate_id' ), - ), - ), - 'show_in_index' => false, - ) - ); - } - - /** - * Permissions callback for REST endpoint. - * - * @param WP_REST_Request $request Request object. - * @return bool - */ - public function rest_api_permission_callback( $request ) { - return current_user_can( - 'edit_post', - $request->get_param( 'id' ) - ); - } - - /** - * Validate post ID. - * - * @param int $input Post ID. - * @return bool - */ - public function rest_api_validate_id( $input ) { - return is_numeric( $input ); - } - - /** - * Schedule cleanup of post's excess revisions. - * - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response - */ - public function rest_api_schedule_purge( $request ) { - $result = wp_schedule_single_event( - time() + 3, - $this->cron_action, - array( - $request->get_param( 'id' ), - ) - ); - - return rest_ensure_response( $result ); - } - - /** - * Allow our meta to be edited from Gutenberg. - * - * @param bool $protected If meta is protected. - * @param string $meta_key Meta key being checked. - * @return false - */ - public function filter_is_protected_meta( $protected, $meta_key ) { - if ( $meta_key === $this->meta_key_limit ) { - return false; - } - - return $protected; - } - - /** - * Register Gutenberg script. - */ - public function action_enqueue_block_editor_assets() { - $asset_data = require_once dirname( __DIR__ ) . '/assets/build/gutenberg.asset.php'; - - wp_enqueue_script( - $this->settings_section, - plugins_url( - 'assets/build/gutenberg.js', - __DIR__ - ), - $asset_data['dependencies'], - $asset_data['version'], - ); - } - /** * PLUGIN UTILITIES. */ @@ -772,7 +550,7 @@ class WP_Revisions_Control { * * @return array */ - private function get_post_types() { + public function get_post_types() { if ( empty( self::$post_types ) ) { foreach ( get_post_types() as $type ) { if ( post_type_supports( $type, 'revisions' ) ) { @@ -823,7 +601,7 @@ class WP_Revisions_Control { * @return int|string */ private function get_post_revisions_to_keep( $post_id ) { - $to_keep = get_post_meta( $post_id, $this->meta_key_limit, true ); + $to_keep = get_post_meta( $post_id, WP_REVISIONS_CONTROL_LIMIT_META_KEY, true ); if ( empty( $to_keep ) || -1 === $to_keep || '-1' === $to_keep ) { $to_keep = ''; @@ -833,15 +611,6 @@ class WP_Revisions_Control { return $to_keep; } - - /** - * Is the Gutenberg component enabled? - * - * @return bool - */ - private function use_gutenberg_component() { - return ! (bool) get_option( $this->setting_native_gutenberg, false ); - } } WP_Revisions_Control::get_instance(); diff --git a/inc/trait-singleton.php b/inc/trait-singleton.php new file mode 100644 index 0000000..ca89deb --- /dev/null +++ b/inc/trait-singleton.php @@ -0,0 +1,45 @@ +<?php +/** + * Reusable singleton. + * + * @package WP_Revisions_Control + */ + +namespace WP_Revisions_Control; + +/** + * Trait Singleton. + */ +trait Singleton { + /** + * Singleton. + * + * @var static + */ + private static $__instance; + + /** + * Silence is golden! + */ + final private function __construct() {} + + /** + * Singleton implementation. + * + * @return static + */ + final public static function get_instance() { + if ( ! is_a( static::$__instance, __CLASS__ ) ) { + static::$__instance = new self(); + + static::$__instance->setup(); + } + + return static::$__instance; + } + + /** + * Prepare class. + */ + abstract public function setup(); +} diff --git a/readme.txt b/readme.txt index cd74432..cb13f17 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: ethitter Donate link: https://ethitter.com/donate/ Tags: revision, revisions, admin Requires at least: 3.6 -Tested up to: 5.9 +Tested up to: 6.0 Stable tag: 1.4 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html diff --git a/wp-revisions-control.php b/wp-revisions-control.php index c830379..94ac7a3 100644 --- a/wp-revisions-control.php +++ b/wp-revisions-control.php @@ -1,10 +1,4 @@ <?php -/** - * Load plugin. - * - * @package WP_Revisions_Control - */ - /** * Plugin Name: WP Revisions Control * Plugin URI: https://ethitter.com/plugins/wp-revisions-control/ @@ -15,6 +9,8 @@ * Text Domain: wp_revisions_control * Domain Path: /languages/ * + * @package WP_Revisions_Control + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -30,5 +26,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +define( 'WP_REVISIONS_CONTROL_LIMIT_META_KEY', '_wp_rev_ctl_limit' ); + +require_once __DIR__ . '/inc/trait-singleton.php'; +require_once __DIR__ . '/inc/class-block-editor.php'; require_once __DIR__ . '/inc/class-wp-revisions-control-bulk-actions.php'; require_once __DIR__ . '/inc/class-wp-revisions-control.php'; -- GitLab