From ea59b4366a439ea93b85bc048fe08a52dc5a8f75 Mon Sep 17 00:00:00 2001 From: Beda Schmid Date: Wed, 29 May 2024 16:12:10 +0700 Subject: [PATCH] Updated plugin requirements and refactored codebase - [Added]: New paths in the release workflow file - [Added]: Additional properties and methods to Base_Metabox class for better flexibility - [Changed]: Updated minimum PHP version requirement to 8.0.0 - [Changed]: Updated minimum WordPress version requirement to 4.0 - [Changed]: Refactored how metaboxes are registered and saved, improving code clarity - [Changed]: Renamed keys for shortcodes, taxonomies, and custom post types using a configurable slug - [Changed]: Replaced specific metabox class with a more generic example - [Fixed]: Incorrect author information in several files - [Removed]: Unused function imports across multiple files --- .github/workflows/release.yml | 1 + CHANGELOG.md | 11 ++ src/plugin-name.php | 19 +-- src/readme.txt | 2 +- src/src/admin/class-admin-notifications.php | 2 +- src/src/bootstrap.php | 4 +- src/src/core/class-lifecycle.php | 1 - src/src/core/class-requirements.php | 7 - src/src/registerables/cpt/class-item-cpt.php | 4 +- .../metaboxes/class-base-metabox.php | 147 ++++++++++++++++-- .../metaboxes/class-example-metabox.php | 144 +++++++++++++++++ .../metaboxes/class-image-upload-metabox.php | 97 ------------ .../shortcodes/class-example-shortcode.php | 3 +- .../taxonomies/class-collection-taxonomy.php | 5 +- .../utilities/class-wp-filesystem-utility.php | 6 +- 15 files changed, 311 insertions(+), 142 deletions(-) create mode 100644 src/src/registerables/metaboxes/class-example-metabox.php delete mode 100644 src/src/registerables/metaboxes/class-image-upload-metabox.php diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 58e317d..fc49e56 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,6 +26,7 @@ jobs: cp -R src/* $REPO_NAME/ sed -i 's|/src/src/|/src/|g' $REPO_NAME/vendor/composer/autoload_classmap.php sed -i 's|/src/src/|/src/|g' $REPO_NAME/vendor/composer/autoload_static.php + sed -i 's|/../../..|/../..|g' $REPO_NAME/vendor/composer/autoload_static.php zip -r $REPO_NAME.zip $REPO_NAME/ - name: Get the version diff --git a/CHANGELOG.md b/CHANGELOG.md index d387f47..89d08e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## 2024-05-29 +- [Added]: New paths in the release workflow file +- [Added]: Additional properties and methods to Base_Metabox class for better flexibility +- [Changed]: Updated minimum PHP version requirement to 8.0.0 +- [Changed]: Updated minimum WordPress version requirement to 4.0 +- [Changed]: Refactored how metaboxes are registered and saved, improving code clarity +- [Changed]: Renamed keys for shortcodes, taxonomies, and custom post types using a configurable slug +- [Changed]: Replaced specific metabox class with a more generic example +- [Fixed]: Incorrect author information in several files +- [Removed]: Unused function imports across multiple files + ## ## 2024-05-26 - [Fixed] Properly initialise WP_Filesystem - [Fixed] Use HTML file extension for resouurce files diff --git a/src/plugin-name.php b/src/plugin-name.php index 9a19841..fc90b1e 100644 --- a/src/plugin-name.php +++ b/src/plugin-name.php @@ -30,8 +30,8 @@ * Description: This is a short description of what the plugin does. It's displayed in the WordPress admin area. * Version: 1.0.0 * Author: Ideally, your WordPress forum username. - * Requires at least: X.X - * Requires PHP: X.X + * Requires at least: 4.0 + * Requires PHP: 8.0.0 * Tested up to: X.X * Author URI: https://site.tld/author-name-uri/ * License: GPL-3.0-or-later @@ -56,13 +56,6 @@ namespace Company\Plugins\PluginName; use Company\Plugins\PluginName\Core\{Config, Requirements, Lifecycle}; -use function add_action; -use function deactivate_plugins; -use function current_user_can; -use function plugin_basename; -use function register_activation_hook; -use function register_deactivation_hook; -use function register_uninstall_hook; /** * Exit the code if this file is accessed directly @@ -98,7 +91,7 @@ Config::init( array( 'version' => '1.0.0', - 'requires_php' => '7.4.0', + 'requires_php' => '8.0.0', 'requires_os' => array( 'wp' => '6.0.0', 'cp' => '1.0.0', @@ -134,8 +127,8 @@ if ( ! $requirements->met() ) { - require_once \ABSPATH . 'wp-includes/capabilities.php'; - require_once \ABSPATH . 'wp-includes/pluggable.php'; + require_once ABSPATH . 'wp-includes/capabilities.php'; + require_once ABSPATH . 'wp-includes/pluggable.php'; if ( current_user_can( 'deactivate_plugins' ) ) { unset( $_GET['activate'] ); @@ -147,7 +140,7 @@ ) ); - require_once \ABSPATH . 'wp-admin/includes/plugin.php'; + require_once ABSPATH . 'wp-admin/includes/plugin.php'; deactivate_plugins( array( Config::get( 'base_name' ) ), true ); } diff --git a/src/readme.txt b/src/readme.txt index 78bc04b..e22e4c9 100644 --- a/src/readme.txt +++ b/src/readme.txt @@ -2,7 +2,7 @@ Contributors: user.a,user.b Donate link: https://domain.tld/donate Tags: tag-1,tag-2 -Requires at least: X.X +Requires at least: 4.0 Tested up to: X.X Stable tag: 1.0.0 License: GPL-3.0-or-later diff --git a/src/src/admin/class-admin-notifications.php b/src/src/admin/class-admin-notifications.php index ec57e3f..73a06d4 100644 --- a/src/src/admin/class-admin-notifications.php +++ b/src/src/admin/class-admin-notifications.php @@ -64,7 +64,7 @@ class Admin_Notifications { * reviewers: phpcs:ignore is used deterministically because GitHub WPCS Workflow fails otherwise. * * @since 1.0.0 Introduced on 2023-08-02 15:14 - * @author Beda Schmid + * @author Your Name * @return void */ public static function print_requirement_notice(): void { diff --git a/src/src/bootstrap.php b/src/src/bootstrap.php index 979c855..0310d3b 100644 --- a/src/src/bootstrap.php +++ b/src/src/bootstrap.php @@ -26,7 +26,7 @@ namespace Company\Plugins\PluginName; use Company\Plugins\PluginName\Registerables\CPT\Item_CPT; -use Company\Plugins\PluginName\Registerables\MetaBoxes\Image_Upload_Metabox; +use Company\Plugins\PluginName\Registerables\MetaBoxes\Example_Metabox; use Company\Plugins\PluginName\Registerables\Taxonomies\Collection_Taxonomy; use Company\Plugins\PluginName\Registerables\Shortcodes\Example_Shortcode; @@ -41,6 +41,6 @@ * Initialise all services */ ( new Item_CPT() )->register(); -( new Image_Upload_Metabox() )->register(); +( new Example_Metabox() )->register(); ( new Collection_Taxonomy() )->register(); ( new Example_Shortcode() )->register(); diff --git a/src/src/core/class-lifecycle.php b/src/src/core/class-lifecycle.php index 0ae03d0..79f41de 100644 --- a/src/src/core/class-lifecycle.php +++ b/src/src/core/class-lifecycle.php @@ -32,7 +32,6 @@ namespace Company\Plugins\PluginName\Core; use Company\Plugins\PluginName\Core\Config; -use function current_user_can; /** * Exit the code if this file is accessed directly diff --git a/src/src/core/class-requirements.php b/src/src/core/class-requirements.php index 20d2511..c082d23 100644 --- a/src/src/core/class-requirements.php +++ b/src/src/core/class-requirements.php @@ -31,13 +31,6 @@ */ namespace Company\Plugins\PluginName\Core; -use function get_bloginfo; -use function get_option; -use function get_site_option; -use function get_template; -use function is_multisite; -use function is_plugin_active; - /** * Exit the code if this file is accessed directly */ diff --git a/src/src/registerables/cpt/class-item-cpt.php b/src/src/registerables/cpt/class-item-cpt.php index 29be954..ba9583f 100644 --- a/src/src/registerables/cpt/class-item-cpt.php +++ b/src/src/registerables/cpt/class-item-cpt.php @@ -62,7 +62,7 @@ final class Item_CPT extends Base_CPT { * @return void */ protected function set_key(): void { - $this->key = 'item'; + $this->key = Config::get( 'slug' ) . '-item'; } /** @@ -78,7 +78,7 @@ protected function set_key(): void { protected function set_specific_args(): array { return array( 'menu_position' => 1, - 'taxonomies' => array( 'collection' ), + 'taxonomies' => array( Config::get( 'slug' ) . '-collection' ), 'menu_icon' => 'data:image/svg+xml;base64,' . ( new WP_Filesystem_Utility() ) ->get_base64_encoded_contents( Config::get( 'plugin_dir' ) . 'public/icons/cpt-icon.svg' ), ); diff --git a/src/src/registerables/metaboxes/class-base-metabox.php b/src/src/registerables/metaboxes/class-base-metabox.php index ba32b4e..efa7d27 100644 --- a/src/src/registerables/metaboxes/class-base-metabox.php +++ b/src/src/registerables/metaboxes/class-base-metabox.php @@ -31,6 +31,7 @@ namespace Company\Plugins\PluginName\Registerables\Metaboxes; use Company\Plugins\PluginName\Registerables\Base_WP_Registerable; +use Company\Plugins\PluginName\Core\Config; /** * Exit the code if this file is accessed directly @@ -60,6 +61,32 @@ abstract class Base_Metabox extends Base_WP_Registerable { */ protected array $post_types = array(); + /** + * Context to add metabox + * + * Possible values are 'normal', 'side', and 'advanced' + * + * @see https://developer.wordpress.org/reference/functions/add_meta_box/ + * @since 1.0.0 Introduced on 2023-08-02 14:14 + * @author Your Name + * @access private + * @var array $context Associativ array of the context to add the metabox to, keyed by post type, value the context. + */ + protected array $context = array(); + + /** + * Priority to add metabox + * + * Possible values are 'high', 'core', 'default', or 'low' + * + * @see https://developer.wordpress.org/reference/functions/add_meta_box/ + * @since 1.0.0 Introduced on 2023-08-02 14:14 + * @author Your Name + * @access private + * @var array $priority Associativ array of the context to add the metabox to, keyed by post type, value the context. + */ + protected array $priority = array(); + /** * User Roles to assign metabox * @@ -80,6 +107,40 @@ abstract class Base_Metabox extends Base_WP_Registerable { */ protected array $taxonomies = array(); + /** + * Abstract method to initialise properties. + * + * Provides an abstract method to initialise meta box properties. + * + * @since 1.0.0 Introduced 2024-05-28 17:37 + * @author Your Name + * @return void + */ + abstract protected function initialize_properties(): void; + + /** + * Abstract method to sanitize the POSTed data. + * + * Provides an abstract method to sanitize the posted data before saving it. + * + * @since 1.0.0 Introduced 2024-05-28 17:37 + * @author Your Name + * @param int|string|array $data The POSTed data. + * @return int|array|string + */ + abstract protected function sanitize_meta_box_data( int|string|array $data ): int|array|string; + + /** + * Abstract method to set callback args. + * + * Provides an abstract method to set the add_meta_box() second argument data array. + * + * @since 1.0.0 Introduced 2024-05-28 17:37 + * @author Your Name + * @return array + */ + abstract protected function set_args(): array; + /** * Abstract method to render metabox * @@ -87,10 +148,12 @@ abstract class Base_Metabox extends Base_WP_Registerable { * * @since 1.0.0 Introduced on 2023-10-08 17:09 * @see https://developer.wordpress.org/reference/functions/add_meta_box/#parameters - * @author Beda Schmid + * @author Your Name + * @param object $obj The Current object to which the metabox is added. + * @param array $args The Arguments passed to the callback. * @return array */ - abstract public function render(): void; + abstract public function render( object $obj = new \stdClass(), array $args = array() ): void; /** * Validate the key @@ -98,7 +161,7 @@ abstract public function render(): void; * Validate $key for get_key(). * * @since 1.0.0 Introduced on 2023-10-08 16:30 - * @author Beda Schmid + * @author Your Name * @throws \LengthException If the key length validation fails. * @throws \UnexpectedValueException If the key sanitization fails. * @return string The validated string. @@ -119,11 +182,23 @@ protected function validate_key(): string { * * @since 1.0.0 Introduced on 2023-10-08 17:09 * @see https://developer.wordpress.org/reference/functions/add_meta_box/ - * @author Beda Schmid + * @author Your Name * @return void */ public function register(): void { + $this->initialize_properties(); + $this->register_metaboxes(); + $this->register_save_hooks(); + } + /** + * Register the metaboxes with WordPress + * + * @since 1.0.0 Introduced 2024-05-29 14:54 + * @author Your Name + * @return void + */ + protected function register_metaboxes(): void { /** * Register for Post types if any */ @@ -149,26 +224,78 @@ public function register(): void { } /** - * Callback for Post Types + * Register the saving hooks with WordPress + * + * @since 1.0.0 Introduced 2024-05-29 14:55 + * @author Your Name + * @return void + */ + protected function register_save_hooks(): void { + /** + * Register for Post types if any + */ + if ( ! empty( $this->post_types ) ) { + add_action( 'save_post', array( $this, 'save_custom_post_meta_box_data' ) ); + } + } + + /** + * Callback for Post Types metabox add action * * True metaboxes are only available on Post Types. * * @since 1.0.0 Introduced on 2023-10-08 17:09 * @see https://developer.wordpress.org/reference/functions/add_meta_box/#parameters - * @author Beda Schmid + * @author Your Name * @return void */ public function register_metaboxes_for_post_types(): void { foreach ( $this->post_types as $post_type ) { add_meta_box( $this->get_key() . '_' . $post_type, - ucwords( str_replace( '_', ' ', $this->get_key() ) ), + ucwords( str_replace( '-', ' ', str_replace( Config::get( 'slug' ), '', $this->get_key() ) ) ), array( $this, 'render' ), $post_type, - 'side', - 'high', - null + array_key_exists( $post_type, $this->context ) ? $this->context[ $post_type ] : 'advanced', + array_key_exists( $post_type, $this->priority ) ? $this->context[ $post_type ] : 'default', + $this->set_args() ); } } + + /** + * Callback for Post Types saving action + * + * Saves the post metabox value to the database. + * + * @since 1.0.0 Introduced 2024-05-28 17:14 + * @author Your Name + * @param int $post_id The Post ID being saved. + * @return void + */ + public function save_custom_post_meta_box_data( int $post_id = 0 ): void { + + foreach ( $this->post_types as $post_type ) { + + if ( ! isset( $_POST['_wpnonce'] ) + || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['_wpnonce'] ) ), 'update-post_' . $post_id ) + || ( defined( 'DOING_AUTOSAVE' ) + && DOING_AUTOSAVE + ) + || ! isset( $_POST['post_type'] ) + || $post_type !== $_POST['post_type'] + || ! current_user_can( 'edit_post', $post_id ) + ) { + return; + } + + if ( isset( $_POST[ $this->get_key() ] ) ) { + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + $sanitized_data = $this->sanitize_meta_box_data( wp_unslash( $_POST[ $this->get_key() ] ) ); + update_post_meta( $post_id, $this->get_key(), $sanitized_data ); + } else { + delete_post_meta( $post_id, $this->get_key() ); + } + } + } } diff --git a/src/src/registerables/metaboxes/class-example-metabox.php b/src/src/registerables/metaboxes/class-example-metabox.php new file mode 100644 index 0000000..9df71a0 --- /dev/null +++ b/src/src/registerables/metaboxes/class-example-metabox.php @@ -0,0 +1,144 @@ + + */ + +/** + * Declare strict typing + * + * @see https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.strict + */ +declare( strict_types = 1 ); + +/** + * Declare the namespace + * + * @see https://www.php.net/manual/en/language.namespaces.php + */ +namespace Company\Plugins\PluginName\Registerables\MetaBoxes; + +use Company\Plugins\PluginName\Registerables\Metaboxes\Base_Metabox; +use Company\Plugins\PluginName\Core\Config; + +/** + * Exit the code if this file is accessed directly + */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + +/** + * The Example Metabox Class + * + * Example Metabox class registers a Number metabox for: + * - posts, pages, items, + * - administrators, editors, + * - categories, tags, collections. + * + * @since 1.0.0 Introduced on 2023-08-01 15:30 + * @package Plugins\PluginName\Registerables\Metaboxes + * @author Your Name + */ +class Example_Metabox extends Base_Metabox { + + + /** + * Initiate class properties + * + * Defines object types to which the metebox will be assigned + * + * @since 1.0.0 Introduced on 2023-10-08 17:09 + * @author Your Name + * @return void + */ + protected function initialize_properties(): void { + + $this->post_types = array( 'post', 'page', 'item' ); + $this->context = array( + 'post' => 'side', + 'page' => 'normal', + 'item' => 'advanced', + ); + $this->priority = array( + 'post' => 'high', + 'page' => 'core', + 'item' => 'low', + ); + $this->user_roles = array( 'administrator', 'editor' ); + $this->taxonomies = array( 'category', 'post_tag', 'collection' ); + } + + /** + * Set registerable key + * + * Sets the metabox unique key. + * + * @since 1.0.0 Introduced on 2023-10-08 17:09 + * @author Your Name + * @return void + */ + protected function set_key(): void { + + $this->key = Config::get( 'slug' ) . '-example'; + } + + /** + * Sanitize the POSTed data. + * + * The parent class already unslashes the POSTed data. + * + * @since 1.0.0 Introduced 2024-05-28 17:38 + * @author Your Name + * @param int|string|array $data The POSTed data, unslashed. + * @return int|string|array $data The Sanized data. + */ + protected function sanitize_meta_box_data( int|string|array $data ): int|string|array { + + return absint( $data ); + } + + /** + * The array of data passed to the second argument of add_meta_box callback + * + * The add_meta_box callback takes a second argument, an array of data, that is made available to the callback. + * + * @since 1.0.0 Introduced 2024-05-29 14:39 + * @author Your Name + * @return array + */ + protected function set_args(): array { + + return array(); + } + + /** + * Render the metabox + * + * A metabox needs to be rendered. This can be as simple or as complex as required. + * + * @since 1.0.0 Introduced on 2023-10-08 17:09 + * @author Your Name + * @param object $post The Currently edited WordPress Post Object. + * @param array $args The Arguments passed to the callback. + * @return void + */ + public function render( object $post = new \WP_Post(), array $args = array() ): void { + + $saved_value = get_post_meta( $post->ID, $this->key, true ); + $value = $saved_value ? esc_attr( $saved_value ) : ''; + echo ''; + } +} diff --git a/src/src/registerables/metaboxes/class-image-upload-metabox.php b/src/src/registerables/metaboxes/class-image-upload-metabox.php deleted file mode 100644 index bf3ed12..0000000 --- a/src/src/registerables/metaboxes/class-image-upload-metabox.php +++ /dev/null @@ -1,97 +0,0 @@ - - */ - -/** - * Declare strict typing - * - * @see https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.strict - */ -declare( strict_types = 1 ); - -/** - * Declare the namespace - * - * @see https://www.php.net/manual/en/language.namespaces.php - */ -namespace Company\Plugins\PluginName\Registerables\MetaBoxes; - -use Company\Plugins\PluginName\Registerables\Metaboxes\Base_Metabox; - -/** - * Exit the code if this file is accessed directly - */ -if ( ! defined( 'ABSPATH' ) ) { - exit; -} - -/** - * The Image Upload Metabox Class - * - * Image Upload Metabox class registers a Media Upload metabox for: - * - posts, pages, items, - * - administrators, editors, - * - categories, tags, collections. - * - * @since 1.0.0 Introduced on 2023-08-01 15:30 - * @package Plugins\PluginName\Registerables\Metaboxes - * @author Your Name - */ -class Image_Upload_Metabox extends Base_Metabox { - - - /** - * Initiate class properties - * - * Defines object types to which the metebox will be assigned - * - * @since 1.0.0 Introduced on 2023-10-08 17:09 - * @author Beda Schmid - * @return void - */ - public function __construct() { - $this->post_types = array( 'post', 'page', 'item' ); - $this->user_roles = array( 'administrator', 'editor' ); - $this->taxonomies = array( 'category', 'post_tag', 'collection' ); - } - - /** - * Set registerable key - * - * Sets the metabox unique key. - * - * @since 1.0.0 Introduced on 2023-10-08 17:09 - * @author Beda Schmid - * @return void - */ - protected function set_key(): void { - $this->key = 'my-box'; - } - - /** - * Render the metabox - * - * A metabox needs to be rendered. This can be as simple or as complex as required. - * - * @since 1.0.0 Introduced on 2023-10-08 17:09 - * @author Beda Schmid - * @return void - */ - public function render(): void { - echo ''; - } -} diff --git a/src/src/registerables/shortcodes/class-example-shortcode.php b/src/src/registerables/shortcodes/class-example-shortcode.php index 43dbf54..5488044 100644 --- a/src/src/registerables/shortcodes/class-example-shortcode.php +++ b/src/src/registerables/shortcodes/class-example-shortcode.php @@ -21,6 +21,7 @@ namespace Company\Plugins\PluginName\Registerables\Shortcodes; use Company\Plugins\PluginName\Registerables\Shortcodes\Base_Shortcode; +use Company\Plugins\PluginName\Core\Config; if ( ! defined( 'ABSPATH' ) ) { exit; @@ -63,7 +64,7 @@ protected function set_shortcode_atts(): array { * @return void */ protected function set_key(): void { - $this->key = 'example'; + $this->key = Config::get( 'slug' ) . '-example'; } /** diff --git a/src/src/registerables/taxonomies/class-collection-taxonomy.php b/src/src/registerables/taxonomies/class-collection-taxonomy.php index e5c8dc2..8337431 100644 --- a/src/src/registerables/taxonomies/class-collection-taxonomy.php +++ b/src/src/registerables/taxonomies/class-collection-taxonomy.php @@ -31,6 +31,7 @@ namespace Company\Plugins\PluginName\Registerables\Taxonomies; use Company\Plugins\PluginName\Registerables\Taxonomies\Base_Taxonomy; +use Company\Plugins\PluginName\Core\Config; /** * Exit the code if this file is accessed directly @@ -60,7 +61,7 @@ final class Collection_Taxonomy extends Base_Taxonomy { * @return void */ protected function set_key(): void { - $this->key = 'collection'; + $this->key = Config::get( 'slug' ) . '-collection'; } /** @@ -105,7 +106,7 @@ protected function set_specific_labels(): array { */ protected function set_object_types(): array { return array( - 'item', + Config::get( 'slug' ) . '-item', ); } } diff --git a/src/src/utilities/class-wp-filesystem-utility.php b/src/src/utilities/class-wp-filesystem-utility.php index 3318e6f..c2aa67f 100644 --- a/src/src/utilities/class-wp-filesystem-utility.php +++ b/src/src/utilities/class-wp-filesystem-utility.php @@ -30,9 +30,6 @@ */ namespace Company\Plugins\PluginName\Utilities; -use WP_Filesystem_Direct; -use base64_encode; - /** * Exit the code if this file is accessed directly */ @@ -75,8 +72,7 @@ public static function get_filesystem(): object { if ( null === self::$filesystem ) { - require_once \ABSPATH . 'wp-admin/includes/file.php'; - \WP_Filesystem(); + WP_Filesystem(); self::$filesystem = new \WP_Filesystem_Direct( true ); }