From 6321341b09053800306604bbe63652e3586ecb5e Mon Sep 17 00:00:00 2001 From: Muhammed ogunsanya Date: Thu, 18 Apr 2024 11:52:46 +0100 Subject: [PATCH 01/11] chore: deleted old files --- on-demand-revalidation.php | 227 --------- src/Admin/Settings.php | 148 ------ src/Admin/SettingsRegistry.php | 895 --------------------------------- src/Helpers.php | 68 --- src/Revalidation.php | 182 ------- 5 files changed, 1520 deletions(-) delete mode 100644 on-demand-revalidation.php delete mode 100644 src/Admin/Settings.php delete mode 100644 src/Admin/SettingsRegistry.php delete mode 100644 src/Helpers.php delete mode 100644 src/Revalidation.php diff --git a/on-demand-revalidation.php b/on-demand-revalidation.php deleted file mode 100644 index 2a37ab5..0000000 --- a/on-demand-revalidation.php +++ /dev/null @@ -1,227 +0,0 @@ -setup_constants(); - if ( self::$instance->includes() ) { - self::$instance->settings(); - self::$instance->revalidation(); - self::$instance->pluginLinks(); - - \OnDemandRevalidation\Helpers::preventWrongApiUrl(); - } - } - - /** - * Fire off init action. - * - * @param OnDemandRevalidation $instance The instance of the OnDemandRevalidation class - */ - do_action( 'on_demand_revalidation_init', self::$instance ); - - // Return the OnDemandRevalidation Instance. - return self::$instance; - } - - /** - * Throw error on object clone. - * The whole idea of the singleton design pattern is that there is a single object - * therefore, we don't want the object to be cloned. - * - * @since 0.0.1 - */ - public function __clone() { - - // Cloning instances of the class is forbidden. - _doing_it_wrong( - __FUNCTION__, - esc_html__( - 'The OnDemandRevalidation class should not be cloned.', - 'on-demand-revalidation' - ), - '0.0.1' - ); - } - - /** - * Disable unserializing of the class. - * - * @since 0.0.1 - */ - public function __wakeup() { - - // De-serializing instances of the class is forbidden. - _doing_it_wrong( - __FUNCTION__, - esc_html__( - 'De-serializing instances of the OnDemandRevalidation class is not allowed.', - 'on-demand-revalidation' - ), - '0.0.1' - ); - } - - /** - * Setup plugin constants. - * - * @since 0.0.1 - */ - private function setup_constants(): void { - - if ( ! function_exists( 'get_plugin_data' ) ) { - require_once( ABSPATH . 'wp-admin/includes/plugin.php' ); - } - - // Plugin version. - if ( ! defined( 'ON_DEMAND_REVALIDATION_VERSION' ) ) { - define( 'ON_DEMAND_REVALIDATION_VERSION', get_plugin_data( __FILE__ )['Version'] ); - } - - // Plugin Folder Path. - if ( ! defined( 'ON_DEMAND_REVALIDATION_PLUGIN_DIR' ) ) { - define( 'ON_DEMAND_REVALIDATION_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); - } - - // Plugin Folder URL. - if ( ! defined( 'ON_DEMAND_REVALIDATION_PLUGIN_URL' ) ) { - define( 'ON_DEMAND_REVALIDATION_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); - } - - // Plugin Root File. - if ( ! defined( 'ON_DEMAND_REVALIDATION_PLUGIN_FILE' ) ) { - define( 'ON_DEMAND_REVALIDATION_PLUGIN_FILE', __FILE__ ); - } - - // Whether to autoload the files or not. - if ( ! defined( 'ON_DEMAND_REVALIDATION_AUTOLOAD' ) ) { - define( 'ON_DEMAND_REVALIDATION_AUTOLOAD', true ); - } - } - - /** - * Uses composer's autoload to include required files. - * - * @since 0.0.1 - * - * @return bool - */ - private function includes(): bool { - - // Autoload Required Classes. - if ( defined( 'ON_DEMAND_REVALIDATION_AUTOLOAD' ) && false !== ON_DEMAND_REVALIDATION_AUTOLOAD ) { - if ( file_exists( ON_DEMAND_REVALIDATION_PLUGIN_DIR . 'vendor/autoload.php' ) ) { - require_once ON_DEMAND_REVALIDATION_PLUGIN_DIR . 'vendor/autoload.php'; - } - - // Bail if installed incorrectly. - if ( ! class_exists( '\OnDemandRevalidation\Admin\Settings' ) ) { - add_action( 'admin_notices', [ $this, 'missing_notice' ] ); - return false; - } - } - - return true; - } - - /** - * Composer dependencies missing notice. - * - * @since 0.0.1 - */ - public function missing_notice(): void { - if ( ! current_user_can( 'manage_options' ) ) { - return; - } ?> -
-

- -

-
- init(); - } - - /** - * Set up Purge. - * - * @since 0.0.1 - */ - private function revalidation(): void { - \OnDemandRevalidation\Revalidation::init(); - } - - - /** - * Set up Action Links. - * - * @since 0.0.1 - */ - private function pluginLinks(): void { - - // Setup Settings link. - add_filter('plugin_action_links_' . plugin_basename( __FILE__ ), function ( $links ) { - $links[] = 'Settings'; - - return $links; - }); - } - } - -endif; - -\OnDemandRevalidation::instance(); diff --git a/src/Admin/Settings.php b/src/Admin/Settings.php deleted file mode 100644 index f609f85..0000000 --- a/src/Admin/Settings.php +++ /dev/null @@ -1,148 +0,0 @@ -settings_api = new SettingsRegistry(); - add_action( 'admin_menu', [ $this, 'add_options_page' ] ); - add_action( 'init', [ $this, 'register_settings' ] ); - add_action( 'admin_init', [ $this, 'initialize_settings_page' ] ); - - if ( is_admin() ) { - Revalidation::testRevalidationButton(); - } - } - - - /** - * Add the options page to the WP Admin - * - * @return void - */ - public function add_options_page() { - - add_options_page( - __( 'Next.js On-Demand Revalidation', 'on-demand-revalidation' ), - __( 'Next.js On-Demand Revalidation', 'on-demand-revalidation' ), - 'manage_options', - 'on-demand-revalidation', - [ $this, 'render_settings_page' ] - ); - - } - - /** - * Registers the settings fields - * - * @return void - */ - public function register_settings() { - - $this->settings_api->register_section( 'on_demand_revalidation_default_settings', [ - 'title' => __( 'General', 'on-demand-revalidation' ), - ] ); - - $this->settings_api->register_fields( 'on_demand_revalidation_default_settings', [ - [ - 'name' => 'frontend_url', - 'label' => __( 'Next.js URL', 'on-demand-revalidation' ), - 'type' => 'text', - ], - [ - 'name' => 'revalidate_secret_key', - 'label' => __( 'Revalidate Secret Key', 'on-demand-revalidation' ), - 'type' => 'password', - ], - ] ); - - $this->settings_api->register_section( 'on_demand_revalidation_post_update_settings', [ - 'title' => __( 'On post update', 'on-demand-revalidation' ), - 'desc' => __( 'On post update is current page revalidated automatically.', 'on-demand-revalidation' ), - ] ); - - $this->settings_api->register_fields( 'on_demand_revalidation_post_update_settings', [ - [ - 'name' => 'revalidate_homepage', - 'desc' => __( 'Revalidate Homepage on post update', 'on-demand-revalidation' ), - 'type' => 'checkbox', - 'default' => 'on', - ], - [ - 'name' => 'disable_cron', - 'desc' => __( "Disable scheduled revalidation. Revalidation triggered immediately without using WP-Cron. It'll slow down post update.", 'on-demand-revalidation' ), - 'type' => 'checkbox', - ], - [ - 'name' => 'revalidate_paths', - 'label' => __( 'Additional paths to revalidate on Post update', 'on-demand-revalidation' ), - 'desc' => 'One path per row.

Available current Post placeholders:
%slug% %author_nicename% %author_username% %category% %post_tag% %custom_taxonomy%

Note: Replace %custom_taxonomy% with your custom taxonomy name.', - 'placeholder' => '/category/%category%', - 'type' => 'textarea', - ], - [ - 'name' => 'test-config', - 'label' => __( 'Test your config:', 'on-demand-revalidation' ), - 'desc' => 'Revalidate Latest Post', - 'type' => 'html', - ], - ] ); - - } - - /** - * Initialize the settings admin page - * - * @return void - */ - public function initialize_settings_page() { - $this->settings_api->admin_init(); - } - - /** - * Render the settings page in the admin - * - * @return void - */ - public function render_settings_page() { - if ( ! current_user_can( 'manage_options' ) ) { - wp_die( esc_html__( 'You do not have sufficient permissions to access this page.' ) ); - } - - ?> -
- Next.js On-Demand Revalidation'; - $this->settings_api->show_navigation(); - $this->settings_api->show_forms(); - ?> -
- - * @link https://tareq.co Tareq Hasan - * - * @see https://github.com/wp-graphql/wp-graphql/blob/develop/src/Admin/Settings/SettingsRegistry.php - */ -class SettingsRegistry { - - /** - * Settings sections array - * - * @var array - */ - protected $settings_sections = []; - - /** - * Settings fields array - * - * @var array - */ - protected $settings_fields = []; - - /** - * SettingsRegistry constructor. - * - * @return void - */ - public function __construct() { - add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] ); - } - - /** - * @return array - */ - public function get_settings_sections() { - return $this->settings_sections; - } - - /** - * @return array - */ - public function get_settings_fields() { - return $this->settings_fields; - } - - /** - * Enqueue scripts and styles - * - * @return void - */ - function admin_enqueue_scripts() { - wp_enqueue_style( 'wp-color-picker' ); - - wp_enqueue_media(); - wp_enqueue_script( 'wp-color-picker' ); - wp_enqueue_script( 'jquery' ); - } - - /** - * Set settings sections - * - * @param string $slug Setting Section Slug - * @param array $section setting section config - * - * @return SettingsRegistry - */ - function register_section( string $slug, array $section ) { - $section['id'] = $slug; - $this->settings_sections[ $slug ] = $section; - - return $this; - } - - /** - * Register fields to a section - * - * @param string $section The slug of the section to register a field to - * @param array $fields settings fields array - * - * @return SettingsRegistry - */ - function register_fields( string $section, array $fields ) { - foreach ( $fields as $field ) { - $this->register_field( $section, $field ); - } - - return $this; - } - - /** - * Register a field to a section - * - * @param string $section The slug of the section to register a field to - * @param array $field The config for the field being registered - * - * @return SettingsRegistry - */ - function register_field( string $section, array $field ) { - $defaults = [ - 'name' => '', - 'label' => '', - 'desc' => '', - 'type' => 'text', - ]; - - $field_config = wp_parse_args( $field, $defaults ); - - // Get the field name before the filter is passed. - $field_name = $field_config['name']; - - // Unset it, as we don't want it to be filterable - unset( $field_config['name'] ); - - /** - * Filter the setting field config - * - * @param array $field_config The field config for the setting - * @param string $field_name The name of the field (unfilterable in the config) - * @param string $section The slug of the section the field is registered to - */ - $field = apply_filters( 'on_demand_revalidation_setting_field_config', $field_config, $field_name, $section ); - - // Add the field name back after the filter has been applied - $field['name'] = $field_name; - - // Add the field to the section - $this->settings_fields[ $section ][] = $field; - - return $this; - } - - /** - * Initialize and registers the settings sections and fileds to WordPress - * - * Usually this should be called at `admin_init` hook. - * - * This function gets the initiated settings sections and fields. Then - * registers them to WordPress and ready for use. - * - * @return void - */ - function admin_init() { - - // Action that fires when settings are being initialized - do_action( 'on_demand_revalidation_init_settings', $this ); - - /** - * Filter the settings sections - * - * @param array $setting_sections The registered settings sections - */ - $setting_sections = apply_filters( 'on_demand_revalidation_settings_sections', $this->settings_sections ); - - foreach ( $setting_sections as $id => $section ) { - if ( false === get_option( $id ) ) { - add_option( $id ); - } - - if ( isset( $section['desc'] ) && ! empty( $section['desc'] ) ) { - $section['desc'] = '
' . $section['desc'] . '
'; - $callback = function () use ( $section ) { - echo wp_kses( str_replace( '"', '\"', $section['desc'] ), $this->get_allowed_wp_kses_html() ); - }; - } elseif ( isset( $section['callback'] ) ) { - $callback = $section['callback']; - } else { - $callback = null; - } - - add_settings_section( $id, $section['title'], $callback, $id ); - } - - //register settings fields - foreach ( $this->settings_fields as $section => $field ) { - foreach ( $field as $option ) { - - $name = $option['name']; - $type = isset( $option['type'] ) ? $option['type'] : 'text'; - $label = isset( $option['label'] ) ? $option['label'] : ''; - $callback = isset( $option['callback'] ) ? $option['callback'] : [ - $this, - 'callback_' . $type, - ]; - - $args = [ - 'id' => $name, - 'class' => isset( $option['class'] ) ? $option['class'] : $name, - 'label_for' => "{$section}[{$name}]", - 'desc' => isset( $option['desc'] ) ? $option['desc'] : '', - 'name' => $label, - 'section' => $section, - 'size' => isset( $option['size'] ) ? $option['size'] : null, - 'options' => isset( $option['options'] ) ? $option['options'] : '', - 'std' => isset( $option['default'] ) ? $option['default'] : '', - 'sanitize_callback' => isset( $option['sanitize_callback'] ) ? $option['sanitize_callback'] : '', - 'type' => $type, - 'placeholder' => isset( $option['placeholder'] ) ? $option['placeholder'] : '', - 'min' => isset( $option['min'] ) ? $option['min'] : '', - 'max' => isset( $option['max'] ) ? $option['max'] : '', - 'step' => isset( $option['step'] ) ? $option['step'] : '', - 'disabled' => isset( $option['disabled'] ) ? (bool) $option['disabled'] : false, - 'value' => isset( $option['value'] ) ? $option['value'] : null, - ]; - - add_settings_field( "{$section}[{$name}]", $label, $callback, $section, $section, $args ); - } - } - - // creates our settings in the options table - foreach ( $this->settings_sections as $id => $section ) { - register_setting( $id, $id, [ $this, 'sanitize_options' ] ); - } - } - - /** - * Get field description for display - * - * @param array $args settings field args - * - * @return string - */ - public function get_field_description( array $args ): string { - if ( ! empty( $args['desc'] ) ) { - $desc = sprintf( '

%s

', $args['desc'] ); - } else { - $desc = ''; - } - - return $desc; - } - - /** - * Displays a text field for a settings field - * - * @param array $args settings field args - * - * @return void - */ - function callback_text( array $args ) { - $value = isset( $args['value'] ) && ! empty( $args['value'] ) ? esc_attr( $args['value'] ) : esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); - $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; - $type = isset( $args['type'] ) ? $args['type'] : 'text'; - $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"'; - $disabled = isset( $args['disabled'] ) && true === $args['disabled'] ? 'disabled' : null; - $html = sprintf( '', $type, $size, $args['section'], $args['id'], $value, $placeholder, $disabled ); - $html .= $this->get_field_description( $args ); - - echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); - } - - /** - * Displays a url field for a settings field - * - * @param array $args settings field args - * - * @return void - */ - function callback_url( array $args ) { - $this->callback_text( $args ); - } - - /** - * Displays a number field for a settings field - * - * @param array $args settings field args - * - * @return void - */ - function callback_number( array $args ) { - $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); - $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; - $type = isset( $args['type'] ) ? $args['type'] : 'number'; - $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"'; - $min = ( '' === $args['min'] ) ? '' : ' min="' . $args['min'] . '"'; - $max = ( '' === $args['max'] ) ? '' : ' max="' . $args['max'] . '"'; - $step = ( '' === $args['step'] ) ? '' : ' step="' . $args['step'] . '"'; - - $html = sprintf( '', $type, $size, $args['section'], $args['id'], $value, $placeholder, $min, $max, $step ); - $html .= $this->get_field_description( $args ); - - echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); - } - - /** - * Displays a checkbox for a settings field - * - * @param array $args settings field args - * - * @return void - */ - function callback_checkbox( array $args ) { - - $value = isset( $args['value'] ) && ! empty( $args['value'] ) ? esc_attr( $args['value'] ) : esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); - $disabled = isset( $args['disabled'] ) && true === $args['disabled'] ? 'disabled' : null; - - $html = '
'; - $html .= sprintf( '', $args['desc'] ); - $html .= '
'; - - echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); - } - - /** - * Displays a multicheckbox for a settings field - * - * @param array $args settings field args - * - * @return void - */ - function callback_multicheck( array $args ) { - - $value = $this->get_option( $args['id'], $args['section'], $args['std'] ); - $html = '
'; - $html .= sprintf( '', $args['section'], $args['id'] ); - foreach ( $args['options'] as $key => $label ) { - $checked = isset( $value[ $key ] ) ? $value[ $key ] : '0'; - $html .= sprintf( '
', $label ); - } - - $html .= $this->get_field_description( $args ); - $html .= '
'; - - echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); - } - - /** - * Displays a radio button for a settings field - * - * @param array $args settings field args - * - * @return void - */ - function callback_radio( array $args ) { - - $value = $this->get_option( $args['id'], $args['section'], $args['std'] ); - $html = '
'; - - foreach ( $args['options'] as $key => $label ) { - $html .= sprintf( '
', $label ); - } - - $html .= $this->get_field_description( $args ); - $html .= '
'; - - echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); - } - - /** - * Displays a selectbox for a settings field - * - * @param array $args settings field args - * - * @return void - */ - function callback_select( array $args ) { - - $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); - $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; - $html = sprintf( '' ); - $html .= $this->get_field_description( $args ); - - echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); - } - - /** - * Displays a textarea for a settings field - * - * @param array $args settings field args - * - * @return void - */ - function callback_textarea( array $args ) { - - $value = esc_textarea( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); - $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; - $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"'; - - $html = sprintf( '', $size, $args['section'], $args['id'], $placeholder, $value ); - $html .= $this->get_field_description( $args ); - - echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); - } - - /** - * Displays the html for a settings field - * - * @param array $args settings field args - * - * @return void - */ - function callback_html( array $args ) { - echo wp_kses( $this->get_field_description( $args ), $this->get_allowed_wp_kses_html() ); - } - - /** - * Displays a rich text textarea for a settings field - * - * @param array $args settings field args - * - * @return void - */ - function callback_wysiwyg( array $args ) { - - $value = $this->get_option( $args['id'], $args['section'], $args['std'] ); - $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : '500px'; - - echo '
'; - - $editor_settings = [ - 'teeny' => true, - 'textarea_name' => $args['section'] . '[' . $args['id'] . ']', - 'textarea_rows' => 10, - ]; - - if ( isset( $args['options'] ) && is_array( $args['options'] ) ) { - $editor_settings = array_merge( $editor_settings, $args['options'] ); - } - - wp_editor( $value, $args['section'] . '-' . $args['id'], $editor_settings ); - - echo '
'; - - echo wp_kses( $this->get_field_description( $args ), $this->get_allowed_wp_kses_html() ); - } - - /** - * Displays a file upload field for a settings field - * - * @param array $args settings field args - * - * @return void - */ - function callback_file( array $args ) { - - $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); - $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; - $id = $args['section'] . '[' . $args['id'] . ']'; - $label = isset( $args['options']['button_label'] ) ? $args['options']['button_label'] : __( 'Choose File' ); - - $html = sprintf( '', $size, $args['section'], $args['id'], $value ); - $html .= ''; - $html .= $this->get_field_description( $args ); - - echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); - } - - /** - * Displays a password field for a settings field - * - * @param array $args settings field args - * - * @return void - */ - function callback_password( array $args ) { - - $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); - $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; - - $html = sprintf( '', $size, $args['section'], $args['id'], $value ); - $html .= $this->get_field_description( $args ); - - echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); - } - - /** - * Displays a color picker field for a settings field - * - * @param array $args settings field args - * - * @return void - */ - function callback_color( $args ) { - - $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); - $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; - - $html = sprintf( '', $size, $args['section'], $args['id'], $value, $args['std'] ); - $html .= $this->get_field_description( $args ); - - echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); - } - - - /** - * Displays a select box for creating the pages select box - * - * @param array $args settings field args - * - * @return void - */ - function callback_pages( array $args ) { - - $dropdown_args = array_merge( [ - 'selected' => esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ), - 'name' => $args['section'] . '[' . $args['id'] . ']', - 'id' => $args['section'] . '[' . $args['id'] . ']', - 'echo' => 0, - ], $args ); - - $clean_args = []; - foreach ( $dropdown_args as $key => $arg ) { - $clean_args[ $key ] = wp_kses( $arg, $this->get_allowed_wp_kses_html() ); - } - - // Ignore phpstan as this is providing an array as expected - // @phpstan-ignore-next-line - // phpcs:ignore - echo wp_dropdown_pages( $clean_args ); - } - - /** - * Displays a select box for user roles - * - * @param array $args settings field args - * - * @return void - */ - function callback_user_role_select( array $args ) { - $selected = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); - - if ( empty( $selected ) ) { - $selected = isset( $args['defualt'] ) ? $args['defualt'] : null; - } - - $name = $args['section'] . '[' . $args['id'] . ']'; - $id = $args['section'] . '[' . $args['id'] . ']'; - - echo ''; - echo wp_kses( $this->get_field_description( $args ), $this->get_allowed_wp_kses_html() ); - } - - /** - * Sanitize callback for Settings API - * - * @param array $options - * - * @return mixed - */ - function sanitize_options( array $options ) { - - if ( ! $options ) { - return $options; - } - - foreach ( $options as $option_slug => $option_value ) { - $sanitize_callback = $this->get_sanitize_callback( $option_slug ); - - // If callback is set, call it - if ( $sanitize_callback ) { - $options[ $option_slug ] = call_user_func( $sanitize_callback, $option_value ); - continue; - } - } - - return $options; - } - - /** - * Get sanitization callback for given option slug - * - * @param string $slug option slug - * - * @return mixed string or bool false - */ - function get_sanitize_callback( $slug = '' ) { - if ( empty( $slug ) ) { - return false; - } - - // Iterate over registered fields and see if we can find proper callback - foreach ( $this->settings_fields as $section => $options ) { - foreach ( $options as $option ) { - if ( $slug !== $option['name'] ) { - continue; - } - - // Return the callback name - return isset( $option['sanitize_callback'] ) && is_callable( $option['sanitize_callback'] ) ? $option['sanitize_callback'] : false; - } - } - - return false; - } - - /** - * Get the value of a settings field - * - * @param string $option settings field name - * @param string $section the section name this field belongs to - * @param string $default default text if it's not found - * - * @return string - */ - function get_option( $option, $section, $default = '' ) { - - $options = get_option( $section ); - - if ( isset( $options[ $option ] ) ) { - return $options[ $option ]; - } - - return $default; - } - - /** - * Show navigations as tab - * - * Shows all the settings section labels as tab - * - * @return void - */ - function show_navigation() { - $html = ''; - - echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); - } - - /** - * Show the section settings forms - * - * This function displays every sections in a different form - * - * @return void - */ - function show_forms() { - ?> -
- settings_sections as $id => $form ) { ?> - - -
- script(); - } - - /** - * Tabbable JavaScript codes & Initiate Color Picker - * - * This code uses localstorage for displaying active tabs - * - * @return void - */ - function script() { - ?> - - _style_fix(); - } - - /** - * Add styles to adjust some settings - * - * @return void - */ - function _style_fix() { - global $wp_version; - - if ( version_compare( $wp_version, '3.8', '<=' ) ) : - ?> - - [], - 'class' => [], - 'type' => [], - 'id' => [], - 'dir' => [], - 'lang' => [], - 'style' => [], - 'xml:lang' => [], - 'src' => [], - 'alt' => [], - 'href' => [], - 'rel' => [], - 'rev' => [], - 'target' => [], - 'novalidate' => [], - 'value' => [], - 'name' => [], - 'tabindex' => [], - 'action' => [], - 'method' => [], - 'for' => [], - 'width' => [], - 'height' => [], - 'data' => [], - 'title' => [], - 'checked' => [], - 'disabled' => [], - 'selected' => [], - 'placeholder' => [], - 'rows' => [], - ]; - - return [ - 'form' => $allowed_atts, - 'label' => $allowed_atts, - 'input' => $allowed_atts, - 'textarea' => $allowed_atts, - 'iframe' => $allowed_atts, - 'script' => $allowed_atts, - 'select' => $allowed_atts, - 'option' => $allowed_atts, - 'style' => $allowed_atts, - 'strong' => $allowed_atts, - 'small' => $allowed_atts, - 'table' => $allowed_atts, - 'span' => $allowed_atts, - 'abbr' => $allowed_atts, - 'code' => $allowed_atts, - 'pre' => $allowed_atts, - 'div' => $allowed_atts, - 'img' => $allowed_atts, - 'h1' => $allowed_atts, - 'h2' => $allowed_atts, - 'h3' => $allowed_atts, - 'h4' => $allowed_atts, - 'h5' => $allowed_atts, - 'h6' => $allowed_atts, - 'ol' => $allowed_atts, - 'ul' => $allowed_atts, - 'li' => $allowed_atts, - 'em' => $allowed_atts, - 'hr' => $allowed_atts, - 'br' => $allowed_atts, - 'tr' => $allowed_atts, - 'td' => $allowed_atts, - 'p' => $allowed_atts, - 'a' => $allowed_atts, - 'b' => $allowed_atts, - 'i' => $allowed_atts, - ]; - } - -} diff --git a/src/Helpers.php b/src/Helpers.php deleted file mode 100644 index 595ae58..0000000 --- a/src/Helpers.php +++ /dev/null @@ -1,68 +0,0 @@ -post_name, $current_path ); - } elseif ( 'author_nicename' === $placeholder ) { - $new_paths[] = str_replace( '%author_nicename%', get_the_author_meta( 'user_nicename', $post->post_author ), $current_path ); - } elseif ( 'author_username' === $placeholder ) { - $new_paths[] = str_replace( '%author_username%', get_the_author_meta( 'user_login', $post->post_author ), $current_path ); - } elseif ( 'categories' === $placeholder ) { - $terms = wp_get_post_terms( $post->ID, 'category', [ 'fields' => 'slugs' ] ) ?? []; - foreach ( $terms as $term ) { - $new_paths[] = str_replace( '%categories%', $term, $current_path ); - } - } elseif ( 'tags' === $placeholder ) { - $terms = wp_get_post_terms( $post->ID, 'post_tag', [ 'fields' => 'slugs' ] ) ?? []; - foreach ( $terms as $term ) { - $new_paths[] = str_replace( '%tags%', $term, $current_path ); - } - } elseif ( in_array( $placeholder, get_post_taxonomies( $post ), true ) ) { - $terms = wp_get_post_terms( $post->ID, $placeholder, [ 'fields' => 'slugs' ] ) ?? []; - foreach ( $terms as $term ) { - $new_paths[] = str_replace( '%' . $placeholder . '%', $term, $current_path ); - } - } else { - $new_paths[] = $current_path; - } - } - - $current_paths = $new_paths; - } - - // Add the paths to the final array - $final_paths = array_merge( $final_paths, $current_paths ); - } - - return $final_paths; - } -} diff --git a/src/Revalidation.php b/src/Revalidation.php deleted file mode 100644 index 666d71d..0000000 --- a/src/Revalidation.php +++ /dev/null @@ -1,182 +0,0 @@ -post_status ) && in_array( $post->post_status, $excluded_statuses, true ) ) { - return; - } - - if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) { - return; - } - - if ( false !== wp_is_post_revision( $post_id ) ) { - return; - } - - self::revalidatePost( $post ); - } - - public static function handleTransitionPostStatus( $new_status, $old_status, $post ) { - if ( ( ( 'draft' !== $old_status && 'trash' !== $old_status ) && 'trash' === $new_status ) || - ( 'publish' === $old_status && 'draft' === $new_status ) ) { - - self::revalidatePost( $post ); - } - } - - static function revalidatePost( $post ) { - if ( Settings::get( 'disable_cron', 'on', 'on_demand_revalidation_post_update_settings' ) === 'on' ) { - self::revalidate( $post ); - } else { - wp_schedule_single_event( time(), 'on_demand_revalidation_on_post_update', [ $post ] ); - } - } - - public static function revalidate( $post ) { - $frontend_url = Settings::get( 'frontend_url' ); - $revalidate_secret_key = Settings::get( 'revalidate_secret_key' ); - - if ( ! ( $frontend_url || $revalidate_secret_key ) ) { - return new WP_Error( 'rest_forbidden', __( 'Fill Next.js URL and Revalidate Secret Key first.', 'on-demand-revalidation' ), [ 'status' => 401 ] ); - } - - $paths = []; - - if ( Settings::get( 'revalidate_homepage', 'on', 'on_demand_revalidation_post_update_settings' ) === 'on' ) { - $paths[] = '/'; - } - - $post_permalink = get_permalink( $post ); - $parse_permalink = parse_url( $post_permalink ); - $page_path = '/'; - - if ( isset( $parse_permalink['path'] ) && '/' !== $parse_permalink['path'] ) { - $page_path = substr( $parse_permalink['path'], -1 ) === '/' ? substr( $parse_permalink['path'], 0, -1 ) : $parse_permalink['path']; - $paths[] = $page_path; - } - - $old_permalink = get_post_meta( $post->ID, '_old_permalink', true ); - - if ( ! empty( $old_permalink ) ) { - $parse_old_permalink = parse_url( $old_permalink ); - - if ( isset( $parse_old_permalink['path'] ) && '/' !== $parse_old_permalink['path'] ) { - $old_page_path = substr( $parse_old_permalink['path'], -1 ) === '/' ? substr( $parse_old_permalink['path'], 0, -1 ) : $parse_old_permalink['path']; - $paths[] = $old_page_path; - } - } - - $paths = array_unique( $paths ); - - $revalidate_paths = trim( Settings::get( 'revalidate_paths', '', 'on_demand_revalidation_post_update_settings' ) ); - $revalidate_paths = preg_split( '/\r\n|\n|\r/', $revalidate_paths ); - $revalidate_paths = Helpers::rewritePaths( $revalidate_paths, $post ); - - if ( $revalidate_paths ) { - foreach ( $revalidate_paths as $path ) { - if ( str_starts_with( $path, '/' ) ) { - $paths[] = $path; - } - } - } - - $paths = apply_filters( 'on_demand_revalidation_paths', $paths, $post ); - - $data = json_encode( [ - 'paths' => $paths, - 'postId' => $post->ID, - ] ); - - $response = wp_remote_request( "$frontend_url/api/revalidate", [ - 'method' => 'PUT', - 'body' => $data, - 'headers' => [ - 'Authorization' => "Bearer $revalidate_secret_key", - 'Content-Type' => 'application/json', - ], - ]); - - $body = json_decode( wp_remote_retrieve_body( $response ), true ); - - $response_data = ( ! is_wp_error( $response ) ) ? $body : $response; - - - if ( class_exists( 'CPurgeCache' ) ) { - \CPurgeCache\Purge::purge( $post ); - } - - return $response_data; - - if ( ! $response_data['revalidated'] ) { - return new WP_Error( 'revalidate_error', $response['message'], [ 'status' => 403 ] ); - } - - $revalidated = implode( ', ', $paths ); - - return (object) [ - 'success' => $response_data['revalidated'], - 'message' => "Next.js revalidated $revalidated successfully.", - ]; - } - - public static function testRevalidationButton() { - add_action('admin_footer', function () { ?> - - 401 ] ); - } - - $latest_post = get_posts([ - 'numberposts' => 1, - 'post_status' => 'publish', - ])[0]; - $response = self::revalidate( $latest_post ); - - wp_send_json( $response ); - wp_die(); - }); - } -} From 105d4e2405f9ed3aa2d687938fcec87c45837a70 Mon Sep 17 00:00:00 2001 From: Muhammed ogunsanya Date: Thu, 18 Apr 2024 11:58:37 +0100 Subject: [PATCH 02/11] chore: deploy to wp on github release --- .github/workflows/deploy-to-wp-on-release.yml | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/deploy-to-wp-on-release.yml diff --git a/.github/workflows/deploy-to-wp-on-release.yml b/.github/workflows/deploy-to-wp-on-release.yml new file mode 100644 index 0000000..c7e1340 --- /dev/null +++ b/.github/workflows/deploy-to-wp-on-release.yml @@ -0,0 +1,31 @@ +name: Deploy to WordPress.org + +on: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + extensions: mbstring, intl + tools: composer + + - name: Install PHP dependencies + run: | + composer install --no-dev --optimize-autoloader + + - name: WordPress Plugin Deploy + uses: 10up/action-wordpress-plugin-deploy@stable + env: + SVN_USERNAME: ${{ secrets.SVN_USERNAME }} + SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} + SLUG: on-demand-revalidation + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 5c6c19ebacf11ebd49b13d43366d2333cb029057 Mon Sep 17 00:00:00 2001 From: Muhammed ogunsanya Date: Thu, 18 Apr 2024 11:59:04 +0100 Subject: [PATCH 03/11] chore: updated phpcs rules --- phpcs.xml.dist | 88 +++++++++++--------------------------------------- 1 file changed, 18 insertions(+), 70 deletions(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index d8d8e04..e1cb527 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -1,71 +1,19 @@ - - Wordpress Coding Standards - - - - - - - - - - - - - ./on-demand-revalidation.php - ./uninstall.php - ./src - - */node_modules/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + . + + + vendor/* + node_modules/* + + + + + + + + + + + \ No newline at end of file From d8426783606463be57a0b13319f68657fc5d05bf Mon Sep 17 00:00:00 2001 From: Muhammed ogunsanya Date: Thu, 18 Apr 2024 11:59:43 +0100 Subject: [PATCH 04/11] chore: updated the required packages --- composer.json | 6 +- composer.lock | 373 ++++++++++++++++++++++++++++---------------------- 2 files changed, 211 insertions(+), 168 deletions(-) diff --git a/composer.json b/composer.json index 46a480b..59aa8a5 100644 --- a/composer.json +++ b/composer.json @@ -19,9 +19,9 @@ } }, "require-dev": { - "automattic/vipwpcs": "^2.3", - "dealerdirect/phpcodesniffer-composer-installer": "^0.7", - "phpcompatibility/phpcompatibility-wp": "*" + "squizlabs/php_codesniffer": "^3.9", + "automattic/vipwpcs": "^3.0", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0" }, "scripts": { "phpcs": [ diff --git a/composer.lock b/composer.lock index 011656b..cbb058b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,33 +4,34 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "73dd93049347a923592fffa3f95e8779", + "content-hash": "abe7fdb289c442ae5244023b8c11b676", "packages": [], "packages-dev": [ { "name": "automattic/vipwpcs", - "version": "2.3.3", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/Automattic/VIP-Coding-Standards.git", - "reference": "6cd0a6a82bc0ac988dbf9d6a7c2e293dc8ac640b" + "reference": "1b8960ebff9ea3eb482258a906ece4d1ee1e25fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Automattic/VIP-Coding-Standards/zipball/6cd0a6a82bc0ac988dbf9d6a7c2e293dc8ac640b", - "reference": "6cd0a6a82bc0ac988dbf9d6a7c2e293dc8ac640b", + "url": "https://api.github.com/repos/Automattic/VIP-Coding-Standards/zipball/1b8960ebff9ea3eb482258a906ece4d1ee1e25fd", + "reference": "1b8960ebff9ea3eb482258a906ece4d1ee1e25fd", "shasum": "" }, "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7", "php": ">=5.4", - "sirbrillig/phpcs-variable-analysis": "^2.11.1", - "squizlabs/php_codesniffer": "^3.5.5", - "wp-coding-standards/wpcs": "^2.3" + "phpcsstandards/phpcsextra": "^1.1.0", + "phpcsstandards/phpcsutils": "^1.0.8", + "sirbrillig/phpcs-variable-analysis": "^2.11.17", + "squizlabs/php_codesniffer": "^3.7.2", + "wp-coding-standards/wpcs": "^3.0" }, "require-dev": { - "php-parallel-lint/php-console-highlighter": "^0.5", - "php-parallel-lint/php-parallel-lint": "^1.0", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", "phpcompatibility/php-compatibility": "^9", "phpcsstandards/phpcsdevtools": "^1.0", "phpunit/phpunit": "^4 || ^5 || ^6 || ^7" @@ -50,6 +51,7 @@ "keywords": [ "phpcs", "standards", + "static analysis", "wordpress" ], "support": { @@ -57,39 +59,42 @@ "source": "https://github.com/Automattic/VIP-Coding-Standards", "wiki": "https://github.com/Automattic/VIP-Coding-Standards/wiki" }, - "time": "2021-09-29T16:20:23+00:00" + "time": "2023-09-05T11:01:05+00:00" }, { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v0.7.2", + "version": "v1.0.0", "source": { "type": "git", - "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", - "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db" + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", - "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", "shasum": "" }, "require": { "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.3", + "php": ">=5.4", "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" }, "require-dev": { "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", "php-parallel-lint/php-parallel-lint": "^1.3.1", - "phpcompatibility/php-compatibility": "^9.0" + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" }, "type": "composer-plugin", "extra": { - "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" }, "autoload": { "psr-4": { - "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -105,7 +110,7 @@ }, { "name": "Contributors", - "homepage": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer/graphs/contributors" + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" } ], "description": "PHP_CodeSniffer Standards Composer Installer Plugin", @@ -129,50 +134,49 @@ "tests" ], "support": { - "issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues", - "source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer" + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "source": "https://github.com/PHPCSStandards/composer-installer" }, - "time": "2022-02-04T12:51:07+00:00" + "time": "2023-01-05T11:28:13+00:00" }, { - "name": "phpcompatibility/php-compatibility", - "version": "9.3.5", + "name": "phpcsstandards/phpcsextra", + "version": "1.2.1", "source": { "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", - "reference": "9fb324479acf6f39452e0655d2429cc0d3914243" + "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", + "reference": "11d387c6642b6e4acaf0bd9bf5203b8cca1ec489" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243", - "reference": "9fb324479acf6f39452e0655d2429cc0d3914243", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/11d387c6642b6e4acaf0bd9bf5203b8cca1ec489", + "reference": "11d387c6642b6e4acaf0bd9bf5203b8cca1ec489", "shasum": "" }, "require": { - "php": ">=5.3", - "squizlabs/php_codesniffer": "^2.3 || ^3.0.2" - }, - "conflict": { - "squizlabs/php_codesniffer": "2.6.2" + "php": ">=5.4", + "phpcsstandards/phpcsutils": "^1.0.9", + "squizlabs/php_codesniffer": "^3.8.0" }, "require-dev": { - "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcsstandards/phpcsdevcs": "^1.1.6", + "phpcsstandards/phpcsdevtools": "^1.2.1", + "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-stable": "1.x-dev", + "dev-develop": "1.x-dev" + } + }, "notification-url": "https://packagist.org/downloads/", "license": [ "LGPL-3.0-or-later" ], "authors": [ - { - "name": "Wim Godden", - "homepage": "https://github.com/wimg", - "role": "lead" - }, { "name": "Juliette Reinders Folmer", "homepage": "https://github.com/jrfnl", @@ -180,156 +184,152 @@ }, { "name": "Contributors", - "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" + "homepage": "https://github.com/PHPCSStandards/PHPCSExtra/graphs/contributors" } ], - "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", - "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", + "description": "A collection of sniffs and standards for use with PHP_CodeSniffer.", "keywords": [ - "compatibility", + "PHP_CodeSniffer", + "phpcbf", + "phpcodesniffer-standard", "phpcs", - "standards" + "standards", + "static analysis" ], "support": { - "issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues", - "source": "https://github.com/PHPCompatibility/PHPCompatibility" - }, - "time": "2019-12-27T09:44:58+00:00" - }, - { - "name": "phpcompatibility/phpcompatibility-paragonie", - "version": "1.3.1", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git", - "reference": "ddabec839cc003651f2ce695c938686d1086cf43" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/ddabec839cc003651f2ce695c938686d1086cf43", - "reference": "ddabec839cc003651f2ce695c938686d1086cf43", - "shasum": "" - }, - "require": { - "phpcompatibility/php-compatibility": "^9.0" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7", - "paragonie/random_compat": "dev-master", - "paragonie/sodium_compat": "dev-master" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." + "issues": "https://github.com/PHPCSStandards/PHPCSExtra/issues", + "security": "https://github.com/PHPCSStandards/PHPCSExtra/security/policy", + "source": "https://github.com/PHPCSStandards/PHPCSExtra" }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ + "funding": [ { - "name": "Wim Godden", - "role": "lead" + "url": "https://github.com/PHPCSStandards", + "type": "github" }, { - "name": "Juliette Reinders Folmer", - "role": "lead" + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" } ], - "description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.", - "homepage": "http://phpcompatibility.com/", - "keywords": [ - "compatibility", - "paragonie", - "phpcs", - "polyfill", - "standards" - ], - "support": { - "issues": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie/issues", - "source": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie" - }, - "time": "2021-02-15T10:24:51+00:00" + "time": "2023-12-08T16:49:07+00:00" }, { - "name": "phpcompatibility/phpcompatibility-wp", - "version": "2.1.3", + "name": "phpcsstandards/phpcsutils", + "version": "1.0.10", "source": { "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git", - "reference": "d55de55f88697b9cdb94bccf04f14eb3b11cf308" + "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", + "reference": "51609a5b89f928e0c463d6df80eb38eff1eaf544" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/d55de55f88697b9cdb94bccf04f14eb3b11cf308", - "reference": "d55de55f88697b9cdb94bccf04f14eb3b11cf308", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/51609a5b89f928e0c463d6df80eb38eff1eaf544", + "reference": "51609a5b89f928e0c463d6df80eb38eff1eaf544", "shasum": "" }, "require": { - "phpcompatibility/php-compatibility": "^9.0", - "phpcompatibility/phpcompatibility-paragonie": "^1.0" + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^3.9.0 || 4.0.x-dev@dev" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." + "ext-filter": "*", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcsstandards/phpcsdevcs": "^1.1.6", + "yoast/phpunit-polyfills": "^1.1.0 || ^2.0.0" }, "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-stable": "1.x-dev", + "dev-develop": "1.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPCSUtils/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "LGPL-3.0-or-later" ], "authors": [ { - "name": "Wim Godden", + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", "role": "lead" }, { - "name": "Juliette Reinders Folmer", - "role": "lead" + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHPCSUtils/graphs/contributors" } ], - "description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.", - "homepage": "http://phpcompatibility.com/", + "description": "A suite of utility functions for use with PHP_CodeSniffer", + "homepage": "https://phpcsutils.com/", "keywords": [ - "compatibility", + "PHP_CodeSniffer", + "phpcbf", + "phpcodesniffer-standard", "phpcs", + "phpcs3", "standards", - "wordpress" + "static analysis", + "tokens", + "utility" ], "support": { - "issues": "https://github.com/PHPCompatibility/PHPCompatibilityWP/issues", - "source": "https://github.com/PHPCompatibility/PHPCompatibilityWP" + "docs": "https://phpcsutils.com/", + "issues": "https://github.com/PHPCSStandards/PHPCSUtils/issues", + "security": "https://github.com/PHPCSStandards/PHPCSUtils/security/policy", + "source": "https://github.com/PHPCSStandards/PHPCSUtils" }, - "time": "2021-12-30T16:37:40+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-03-17T23:44:50+00:00" }, { "name": "sirbrillig/phpcs-variable-analysis", - "version": "v2.11.3", + "version": "v2.11.17", "source": { "type": "git", "url": "https://github.com/sirbrillig/phpcs-variable-analysis.git", - "reference": "c921498b474212fe4552928bbeb68d70250ce5e8" + "reference": "3b71162a6bf0cde2bff1752e40a1788d8273d049" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/c921498b474212fe4552928bbeb68d70250ce5e8", - "reference": "c921498b474212fe4552928bbeb68d70250ce5e8", + "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/3b71162a6bf0cde2bff1752e40a1788d8273d049", + "reference": "3b71162a6bf0cde2bff1752e40a1788d8273d049", "shasum": "" }, "require": { "php": ">=5.4.0", - "squizlabs/php_codesniffer": "^3.5" + "squizlabs/php_codesniffer": "^3.5.6" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", - "limedeck/phpunit-detailed-printer": "^3.1 || ^4.0 || ^5.0", - "phpstan/phpstan": "^0.11.8", - "phpunit/phpunit": "^5.0 || ^6.5 || ^7.0 || ^8.0", - "sirbrillig/phpcs-import-detection": "^1.1" + "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || ^1.0", + "phpcsstandards/phpcsdevcs": "^1.1", + "phpstan/phpstan": "^1.7", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.5 || ^7.0 || ^8.0 || ^9.0", + "sirbrillig/phpcs-import-detection": "^1.1", + "vimeo/psalm": "^0.2 || ^0.3 || ^1.1 || ^4.24 || ^5.0@beta" }, "type": "phpcodesniffer-standard", "autoload": { @@ -352,25 +352,29 @@ } ], "description": "A PHPCS sniff to detect problems with variables.", + "keywords": [ + "phpcs", + "static analysis" + ], "support": { "issues": "https://github.com/sirbrillig/phpcs-variable-analysis/issues", "source": "https://github.com/sirbrillig/phpcs-variable-analysis", "wiki": "https://github.com/sirbrillig/phpcs-variable-analysis/wiki" }, - "time": "2022-02-21T17:01:13+00:00" + "time": "2023-08-05T23:46:11+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.7.0", + "version": "3.9.1", "source": { "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "a2cd51b45bcaef9c1f2a4bda48f2dd2fa2b95563" + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "267a4405fff1d9c847134db3a3c92f1ab7f77909" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/a2cd51b45bcaef9c1f2a4bda48f2dd2fa2b95563", - "reference": "a2cd51b45bcaef9c1f2a4bda48f2dd2fa2b95563", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/267a4405fff1d9c847134db3a3c92f1ab7f77909", + "reference": "267a4405fff1d9c847134db3a3c92f1ab7f77909", "shasum": "" }, "require": { @@ -380,11 +384,11 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", "extra": { @@ -399,48 +403,80 @@ "authors": [ { "name": "Greg Sherwood", - "role": "lead" + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", "keywords": [ "phpcs", - "standards" + "standards", + "static analysis" ], "support": { - "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", - "source": "https://github.com/squizlabs/PHP_CodeSniffer", - "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" }, - "time": "2022-06-13T06:31:38+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-03-31T21:03:09+00:00" }, { "name": "wp-coding-standards/wpcs", - "version": "2.3.0", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "7da1894633f168fe244afc6de00d141f27517b62" + "reference": "9333efcbff231f10dfd9c56bb7b65818b4733ca7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62", - "reference": "7da1894633f168fe244afc6de00d141f27517b62", + "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/9333efcbff231f10dfd9c56bb7b65818b4733ca7", + "reference": "9333efcbff231f10dfd9c56bb7b65818b4733ca7", "shasum": "" }, "require": { + "ext-filter": "*", + "ext-libxml": "*", + "ext-tokenizer": "*", + "ext-xmlreader": "*", "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.3.1" + "phpcsstandards/phpcsextra": "^1.2.1", + "phpcsstandards/phpcsutils": "^1.0.10", + "squizlabs/php_codesniffer": "^3.9.0" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", "phpcompatibility/php-compatibility": "^9.0", - "phpcsstandards/phpcsdevtools": "^1.0", - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + "phpcsstandards/phpcsdevtools": "^1.2.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." + "ext-iconv": "For improved results", + "ext-mbstring": "For improved results" }, "type": "phpcodesniffer-standard", "notification-url": "https://packagist.org/downloads/", @@ -457,6 +493,7 @@ "keywords": [ "phpcs", "standards", + "static analysis", "wordpress" ], "support": { @@ -464,7 +501,13 @@ "source": "https://github.com/WordPress/WordPress-Coding-Standards", "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki" }, - "time": "2020-05-13T23:57:56+00:00" + "funding": [ + { + "url": "https://opencollective.com/php_codesniffer", + "type": "custom" + } + ], + "time": "2024-03-25T16:39:00+00:00" } ], "aliases": [], @@ -474,5 +517,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.6.0" } From 684d7ef4946ebbab023ef86a40647cdaa3b38ab6 Mon Sep 17 00:00:00 2001 From: Muhammed ogunsanya Date: Thu, 18 Apr 2024 12:00:23 +0100 Subject: [PATCH 05/11] chore: add doc comments to uninstall.php file --- uninstall.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/uninstall.php b/uninstall.php index d11c090..f75b470 100644 --- a/uninstall.php +++ b/uninstall.php @@ -1,4 +1,12 @@ Date: Thu, 18 Apr 2024 12:02:16 +0100 Subject: [PATCH 06/11] chore: renamed file per phpcs rule, added doc comments and added new rewrite_tags fn --- src/class-helpers.php | 174 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 src/class-helpers.php diff --git a/src/class-helpers.php b/src/class-helpers.php new file mode 100644 index 0000000..7a1bf1d --- /dev/null +++ b/src/class-helpers.php @@ -0,0 +1,174 @@ +post_name, $current_path ); + } elseif ( 'author_nicename' === $placeholder ) { + $new_paths[] = str_replace( '%author_nicename%', get_the_author_meta( 'user_nicename', $post->post_author ), $current_path ); + } elseif ( 'author_username' === $placeholder ) { + $new_paths[] = str_replace( '%author_username%', get_the_author_meta( 'user_login', $post->post_author ), $current_path ); + } elseif ( 'categories' === $placeholder ) { + $terms = wp_get_post_terms( $post->ID, 'category', array( 'fields' => 'slugs' ) ) ?? array(); + foreach ( $terms as $term ) { + $new_paths[] = str_replace( '%categories%', $term, $current_path ); + } + } elseif ( 'tags' === $placeholder ) { + $terms = wp_get_post_terms( $post->ID, 'post_tag', array( 'fields' => 'slugs' ) ) ?? array(); + foreach ( $terms as $term ) { + $new_paths[] = str_replace( '%tags%', $term, $current_path ); + } + } elseif ( in_array( $placeholder, get_post_taxonomies( $post ), true ) ) { + $terms = wp_get_post_terms( $post->ID, $placeholder, array( 'fields' => 'slugs' ) ) ?? array(); + foreach ( $terms as $term ) { + $new_paths[] = str_replace( '%' . $placeholder . '%', $term, $current_path ); + } + } else { + $new_paths[] = $current_path; + } + } + + $current_paths = $new_paths; + } + + // Add the paths to the final array. + $final_paths = array_merge( $final_paths, $current_paths ); + } + + return $final_paths; + } + + + /** + * Rewrites tags. + * + * This method rewrites tags based on post placeholders and returns the final tags array. + * + * @param array $tags An array of tags to rewrite. + * @param object $post The post object. + * @return array The final array of rewritten tags. + */ + public static function rewrite_tags( $tags, $post ) { + $final_tags = array(); + + foreach ( $tags as $tag ) { + $tag = trim( $tag ); + + // Match all placeholders within the tag template. + preg_match_all( '/{(.+?)}/', $tag, $matches ); + $placeholders = $matches[1]; + + $current_tags = array( $tag ); + + foreach ( $placeholders as $placeholder ) { + $new_tags = array(); + + foreach ( $current_tags as $current_tag ) { + switch ( $placeholder ) { + case 'databaseId': + case 'id': + $new_tags[] = str_replace( '{' . $placeholder . '}', $post->ID, $current_tag ); + break; + case 'category': + $terms = wp_get_post_terms( $post->ID, 'category', array( 'fields' => 'slugs' ) ); + if ( ! empty( $terms ) ) { + foreach ( $terms as $term ) { + $new_tags[] = str_replace( '{category}', $term, $current_tag ); + } + } else { + // Ensure at least one tag remains even if there are no terms. + $new_tags[] = str_replace( '{category}', 'uncategorized', $current_tag ); + } + break; + case 'tag': + $terms = wp_get_post_terms( $post->ID, 'post_tag', array( 'fields' => 'slugs' ) ); + if ( ! empty( $terms ) ) { + foreach ( $terms as $term ) { + $new_tags[] = str_replace( '{tag}', $term, $current_tag ); + } + } else { + // Ensure at least one tag remains even if there are no terms. + $new_tags[] = str_replace( '{tag}', 'notag', $current_tag ); + } + break; + default: + $terms = wp_get_post_terms( $post->ID, $placeholder, array( 'fields' => 'slugs' ) ); + if ( ! empty( $terms ) ) { + foreach ( $terms as $term ) { + $new_tags[] = str_replace( '{' . $placeholder . '}', $term, $current_tag ); + } + } else { + // Preserve the tag without replacement if no terms found. + $new_tags[] = $current_tag; + } + break; + } + } + + // Update the current tags for the next round of replacements. + $current_tags = $new_tags; + } + + // Merge all fully processed tags into the final list. + $final_tags = array_merge( $final_tags, $current_tags ); + } + + return $final_tags; + } +} From 16877e82f3049c0b75bc013ae86726f32388d14d Mon Sep 17 00:00:00 2001 From: Muhammed ogunsanya Date: Thu, 18 Apr 2024 12:02:52 +0100 Subject: [PATCH 07/11] chore: renamed file per phpcs rule, added doc comments and added visibility to various functions --- src/Admin/class-settingsregistry.php | 896 +++++++++++++++++++++++++++ 1 file changed, 896 insertions(+) create mode 100644 src/Admin/class-settingsregistry.php diff --git a/src/Admin/class-settingsregistry.php b/src/Admin/class-settingsregistry.php new file mode 100644 index 0000000..674716c --- /dev/null +++ b/src/Admin/class-settingsregistry.php @@ -0,0 +1,896 @@ + + * @link https://tareq.co Tareq Hasan + * + * @see https://github.com/wp-graphql/wp-graphql/blob/develop/src/Admin/Settings/SettingsRegistry.php + */ +class SettingsRegistry { + + /** + * Settings sections array + * + * @var array + */ + protected $settings_sections = array(); + + /** + * Settings fields array + * + * @var array + */ + protected $settings_fields = array(); + + /** + * SettingsRegistry constructor. + * + * @return void + */ + public function __construct() { + add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); + } + + /** + * Get_settings_sections + * + * @return array + */ + public function get_settings_sections() { + return $this->settings_sections; + } + + /** + * Get_settings_fields + * + * @return array + */ + public function get_settings_fields() { + return $this->settings_fields; + } + + /** + * Enqueue scripts and styles + * + * @return void + */ + public function admin_enqueue_scripts() { + wp_enqueue_style( 'wp-color-picker' ); + + wp_enqueue_media(); + wp_enqueue_script( 'wp-color-picker' ); + wp_enqueue_script( 'jquery' ); + } + + /** + * Set settings sections + * + * @param string $slug Setting Section Slug. + * @param array $section setting section config. + * + * @return SettingsRegistry + */ + public function register_section( string $slug, array $section ) { + $section['id'] = $slug; + $this->settings_sections[ $slug ] = $section; + + return $this; + } + + /** + * Register fields to a section + * + * @param string $section The slug of the section to register a field to. + * @param array $fields settings fields array. + * + * @return SettingsRegistry + */ + public function register_fields( string $section, array $fields ) { + foreach ( $fields as $field ) { + $this->register_field( $section, $field ); + } + + return $this; + } + + /** + * Register a field to a section + * + * @param string $section The slug of the section to register a field to. + * @param array $field The config for the field being registered. + * + * @return SettingsRegistry + */ + public function register_field( string $section, array $field ) { + $defaults = array( + 'name' => '', + 'label' => '', + 'desc' => '', + 'type' => 'text', + ); + + $field_config = wp_parse_args( $field, $defaults ); + + // Get the field name before the filter is passed. + $field_name = $field_config['name']; + + // Unset it, as we don't want it to be filterable. + unset( $field_config['name'] ); + + /** + * Filter the setting field config + * + * @param array $field_config The field config for the setting + * @param string $field_name The name of the field (unfilterable in the config) + * @param string $section The slug of the section the field is registered to + */ + $field = apply_filters( 'on_demand_revalidation_setting_field_config', $field_config, $field_name, $section ); + + // Add the field name back after the filter has been applied. + $field['name'] = $field_name; + + // Add the field to the section. + $this->settings_fields[ $section ][] = $field; + + return $this; + } + + /** + * Initialize and registers the settings sections and fileds to WordPress + * + * Usually this should be called at `admin_init` hook. + * + * This function gets the initiated settings sections and fields. Then + * registers them to WordPress and ready for use. + * + * @return void + */ + public function admin_init() { + + // Action that fires when settings are being initialized. + do_action( 'on_demand_revalidation_init_settings', $this ); + + /** + * Filter the settings sections + * + * @param array $setting_sections The registered settings sections + */ + $setting_sections = apply_filters( 'on_demand_revalidation_settings_sections', $this->settings_sections ); + + foreach ( $setting_sections as $id => $section ) { + if ( false === get_option( $id ) ) { + add_option( $id ); + } + + if ( isset( $section['desc'] ) && ! empty( $section['desc'] ) ) { + $section['desc'] = '
' . $section['desc'] . '
'; + $callback = function () use ( $section ) { + echo wp_kses( str_replace( '"', '\"', $section['desc'] ), $this->get_allowed_wp_kses_html() ); + }; + } elseif ( isset( $section['callback'] ) ) { + $callback = $section['callback']; + } else { + $callback = null; + } + + add_settings_section( $id, $section['title'], $callback, $id ); + } + + // register settings fields. + foreach ( $this->settings_fields as $section => $field ) { + foreach ( $field as $option ) { + + $name = $option['name']; + $type = isset( $option['type'] ) ? $option['type'] : 'text'; + $label = isset( $option['label'] ) ? $option['label'] : ''; + $callback = isset( $option['callback'] ) ? $option['callback'] : array( + $this, + 'callback_' . $type, + ); + + $args = array( + 'id' => $name, + 'class' => isset( $option['class'] ) ? $option['class'] : $name, + 'label_for' => "{$section}[{$name}]", + 'desc' => isset( $option['desc'] ) ? $option['desc'] : '', + 'name' => $label, + 'section' => $section, + 'size' => isset( $option['size'] ) ? $option['size'] : null, + 'options' => isset( $option['options'] ) ? $option['options'] : '', + 'std' => isset( $option['default'] ) ? $option['default'] : '', + 'sanitize_callback' => isset( $option['sanitize_callback'] ) ? $option['sanitize_callback'] : '', + 'type' => $type, + 'placeholder' => isset( $option['placeholder'] ) ? $option['placeholder'] : '', + 'min' => isset( $option['min'] ) ? $option['min'] : '', + 'max' => isset( $option['max'] ) ? $option['max'] : '', + 'step' => isset( $option['step'] ) ? $option['step'] : '', + 'disabled' => isset( $option['disabled'] ) ? (bool) $option['disabled'] : false, + 'value' => isset( $option['value'] ) ? $option['value'] : null, + ); + + add_settings_field( "{$section}[{$name}]", $label, $callback, $section, $section, $args ); + } + } + + // creates our settings in the options table. + foreach ( $this->settings_sections as $id => $section ) { + register_setting( $id, $id, array( $this, 'sanitize_options' ) ); + } + } + + /** + * Get field description for display + * + * @param array $args settings field args. + * + * @return string + */ + public function get_field_description( array $args ): string { + if ( ! empty( $args['desc'] ) ) { + $desc = sprintf( '

%s

', $args['desc'] ); + } else { + $desc = ''; + } + + return $desc; + } + + /** + * Displays a text field for a settings field + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_text( array $args ) { + $value = isset( $args['value'] ) && ! empty( $args['value'] ) ? esc_attr( $args['value'] ) : esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); + $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; + $type = isset( $args['type'] ) ? $args['type'] : 'text'; + $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"'; + $disabled = isset( $args['disabled'] ) && true === $args['disabled'] ? 'disabled' : null; + $html = sprintf( '', $type, $size, $args['section'], $args['id'], $value, $placeholder, $disabled ); + $html .= $this->get_field_description( $args ); + + echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); + } + + /** + * Displays a url field for a settings field + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_url( array $args ) { + $this->callback_text( $args ); + } + + /** + * Displays a number field for a settings field + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_number( array $args ) { + $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); + $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; + $type = isset( $args['type'] ) ? $args['type'] : 'number'; + $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"'; + $min = ( '' === $args['min'] ) ? '' : ' min="' . $args['min'] . '"'; + $max = ( '' === $args['max'] ) ? '' : ' max="' . $args['max'] . '"'; + $step = ( '' === $args['step'] ) ? '' : ' step="' . $args['step'] . '"'; + + $html = sprintf( '', $type, $size, $args['section'], $args['id'], $value, $placeholder, $min, $max, $step ); + $html .= $this->get_field_description( $args ); + + echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); + } + + /** + * Displays a checkbox for a settings field + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_checkbox( array $args ) { + + $value = isset( $args['value'] ) && ! empty( $args['value'] ) ? esc_attr( $args['value'] ) : esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); + $disabled = isset( $args['disabled'] ) && true === $args['disabled'] ? 'disabled' : null; + + $html = '
'; + $html .= sprintf( '', $args['desc'] ); + $html .= '
'; + + echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); + } + + /** + * Displays a multicheckbox for a settings field + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_multicheck( array $args ) { + + $value = $this->get_option( $args['id'], $args['section'], $args['std'] ); + $html = '
'; + $html .= sprintf( '', $args['section'], $args['id'] ); + foreach ( $args['options'] as $key => $label ) { + $checked = isset( $value[ $key ] ) ? $value[ $key ] : '0'; + $html .= sprintf( '
', $label ); + } + + $html .= $this->get_field_description( $args ); + $html .= '
'; + + echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); + } + + /** + * Displays a radio button for a settings field + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_radio( array $args ) { + + $value = $this->get_option( $args['id'], $args['section'], $args['std'] ); + $html = '
'; + + foreach ( $args['options'] as $key => $label ) { + $html .= sprintf( '
', $label ); + } + + $html .= $this->get_field_description( $args ); + $html .= '
'; + + echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); + } + + /** + * Displays a selectbox for a settings field + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_select( array $args ) { + + $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); + $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; + $html = sprintf( '' ); + $html .= $this->get_field_description( $args ); + + echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); + } + + /** + * Displays a textarea for a settings field + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_textarea( array $args ) { + + $value = esc_textarea( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); + $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; + $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"'; + + $html = sprintf( '', $size, $args['section'], $args['id'], $placeholder, $value ); + $html .= $this->get_field_description( $args ); + + echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); + } + + /** + * Displays the html for a settings field + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_html( array $args ) { + echo wp_kses( $this->get_field_description( $args ), $this->get_allowed_wp_kses_html() ); + } + + /** + * Displays a rich text textarea for a settings field + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_wysiwyg( array $args ) { + + $value = $this->get_option( $args['id'], $args['section'], $args['std'] ); + $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : '500px'; + + echo '
'; + + $editor_settings = array( + 'teeny' => true, + 'textarea_name' => $args['section'] . '[' . $args['id'] . ']', + 'textarea_rows' => 10, + ); + + if ( isset( $args['options'] ) && is_array( $args['options'] ) ) { + $editor_settings = array_merge( $editor_settings, $args['options'] ); + } + + wp_editor( $value, $args['section'] . '-' . $args['id'], $editor_settings ); + + echo '
'; + + echo wp_kses( $this->get_field_description( $args ), $this->get_allowed_wp_kses_html() ); + } + + /** + * Displays a file upload field for a settings field + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_file( array $args ) { + + $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); + $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; + $id = $args['section'] . '[' . $args['id'] . ']'; + unset( $id ); + $label = isset( $args['options']['button_label'] ) ? $args['options']['button_label'] : __( 'Choose File' ); + + $html = sprintf( '', $size, $args['section'], $args['id'], $value ); + $html .= ''; + $html .= $this->get_field_description( $args ); + + echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); + } + + /** + * Displays a password field for a settings field + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_password( array $args ) { + + $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); + $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; + + $html = sprintf( '', $size, $args['section'], $args['id'], $value ); + $html .= $this->get_field_description( $args ); + + echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); + } + + /** + * Displays a color picker field for a settings field + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_color( $args ) { + + $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); + $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; + + $html = sprintf( '', $size, $args['section'], $args['id'], $value, $args['std'] ); + $html .= $this->get_field_description( $args ); + + echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); + } + + + /** + * Displays a select box for creating the pages select box + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_pages( array $args ) { + + $dropdown_args = array_merge( + array( + 'selected' => esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ), + 'name' => $args['section'] . '[' . $args['id'] . ']', + 'id' => $args['section'] . '[' . $args['id'] . ']', + 'echo' => 0, + ), + $args + ); + + $clean_args = array(); + foreach ( $dropdown_args as $key => $arg ) { + $clean_args[ $key ] = wp_kses( $arg, $this->get_allowed_wp_kses_html() ); + } + + // Ignore phpstan as this is providing an array as expected + // @phpstan-ignore-next-line. + // phpcs:ignore + echo wp_dropdown_pages( $clean_args ); + } + + /** + * Displays a select box for user roles + * + * @param array $args settings field args. + * + * @return void + */ + public function callback_user_role_select( array $args ) { + $selected = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); + + if ( empty( $selected ) ) { + $selected = isset( $args['defualt'] ) ? $args['defualt'] : null; + } + + $name = $args['section'] . '[' . $args['id'] . ']'; + $id = $args['section'] . '[' . $args['id'] . ']'; + + echo ''; + echo wp_kses( $this->get_field_description( $args ), $this->get_allowed_wp_kses_html() ); + } + + /** + * Sanitize callback for Settings API + * + * @param array $options array options. + * + * @return mixed + */ + public function sanitize_options( array $options ) { + + if ( ! $options ) { + return $options; + } + + foreach ( $options as $option_slug => $option_value ) { + $sanitize_callback = $this->get_sanitize_callback( $option_slug ); + + // If callback is set, call it. + if ( $sanitize_callback ) { + $options[ $option_slug ] = call_user_func( $sanitize_callback, $option_value ); + continue; + } + } + + return $options; + } + + /** + * Get sanitization callback for given option slug + * + * @param string $slug option slug. + * + * @return mixed string or bool false. + */ + public function get_sanitize_callback( $slug = '' ) { + if ( empty( $slug ) ) { + return false; + } + + // Iterate over registered fields and see if we can find proper callback. + foreach ( $this->settings_fields as $section => $options ) { + unset( $section ); + foreach ( $options as $option ) { + if ( $slug !== $option['name'] ) { + continue; + } + + // Return the callback name. + return isset( $option['sanitize_callback'] ) && is_callable( $option['sanitize_callback'] ) ? $option['sanitize_callback'] : false; + } + } + + return false; + } + + /** + * Get the value of a settings field + * + * @param string $option settings field name. + * @param string $section the section name this field belongs to. + * @param string $default_value default text if it's not found. + * + * @return string + */ + public function get_option( $option, $section, $default_value = '' ) { + + $options = get_option( $section ); + + if ( isset( $options[ $option ] ) ) { + return $options[ $option ]; + } + + return $default_value; + } + + /** + * Show navigations as tab + * + * Shows all the settings section labels as tab + * + * @return void + */ + public function show_navigation() { + $html = ''; + + echo wp_kses( $html, $this->get_allowed_wp_kses_html() ); + } + + /** + * Show the section settings forms + * + * This function displays every sections in a different form + * + * @return void + */ + public function show_forms() { + ?> +
+ settings_sections as $id => $form ) { ?> + + +
+ script(); + } + + /** + * Tabbable JavaScript codes & Initiate Color Picker + * + * This code uses localstorage for displaying active tabs + * + * @return void + */ + public function script() { + ?> + + style_fix(); + } + + /** + * Add styles to adjust some settings + * + * @return void + */ + public function style_fix() { + global $wp_version; + + if ( version_compare( $wp_version, '3.8', '<=' ) ) : + ?> + + array(), + 'class' => array(), + 'type' => array(), + 'id' => array(), + 'dir' => array(), + 'lang' => array(), + 'style' => array(), + 'xml:lang' => array(), + 'src' => array(), + 'alt' => array(), + 'href' => array(), + 'rel' => array(), + 'rev' => array(), + 'target' => array(), + 'novalidate' => array(), + 'value' => array(), + 'name' => array(), + 'tabindex' => array(), + 'action' => array(), + 'method' => array(), + 'for' => array(), + 'width' => array(), + 'height' => array(), + 'data' => array(), + 'title' => array(), + 'checked' => array(), + 'disabled' => array(), + 'selected' => array(), + 'placeholder' => array(), + 'rows' => array(), + ); + + return array( + 'form' => $allowed_atts, + 'label' => $allowed_atts, + 'input' => $allowed_atts, + 'textarea' => $allowed_atts, + 'iframe' => $allowed_atts, + 'script' => $allowed_atts, + 'select' => $allowed_atts, + 'option' => $allowed_atts, + 'style' => $allowed_atts, + 'strong' => $allowed_atts, + 'small' => $allowed_atts, + 'table' => $allowed_atts, + 'span' => $allowed_atts, + 'abbr' => $allowed_atts, + 'code' => $allowed_atts, + 'pre' => $allowed_atts, + 'div' => $allowed_atts, + 'img' => $allowed_atts, + 'h1' => $allowed_atts, + 'h2' => $allowed_atts, + 'h3' => $allowed_atts, + 'h4' => $allowed_atts, + 'h5' => $allowed_atts, + 'h6' => $allowed_atts, + 'ol' => $allowed_atts, + 'ul' => $allowed_atts, + 'li' => $allowed_atts, + 'em' => $allowed_atts, + 'hr' => $allowed_atts, + 'br' => $allowed_atts, + 'tr' => $allowed_atts, + 'td' => $allowed_atts, + 'p' => $allowed_atts, + 'a' => $allowed_atts, + 'b' => $allowed_atts, + 'i' => $allowed_atts, + ); + } +} From 3ef507b5d14792ebe5b1fc430652a4117b30439a Mon Sep 17 00:00:00 2001 From: Muhammed ogunsanya Date: Thu, 18 Apr 2024 12:03:46 +0100 Subject: [PATCH 08/11] chore: renamed file per phpcs rule, added doc comments --- class-ondemandrevalidation.php | 232 +++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 class-ondemandrevalidation.php diff --git a/class-ondemandrevalidation.php b/class-ondemandrevalidation.php new file mode 100644 index 0000000..335d846 --- /dev/null +++ b/class-ondemandrevalidation.php @@ -0,0 +1,232 @@ +setup_constants(); + if ( self::$instance->includes() ) { + self::$instance->settings(); + self::$instance->revalidation(); + self::$instance->plugin_links(); + + \OnDemandRevalidation\Helpers::prevent_wrong_api_url(); + } + } + + /** + * Fire off init action. + * + * @param OnDemandRevalidation $instance The instance of the OnDemandRevalidation class + */ + do_action( 'on_demand_revalidation_init', self::$instance ); + + // Return the OnDemandRevalidation Instance. + return self::$instance; + } + + /** + * Throw error on object clone. + * The whole idea of the singleton design pattern is that there is a single object + * therefore, we don't want the object to be cloned. + * + * @since 0.0.1 + */ + public function __clone() { + + // Cloning instances of the class is forbidden. + _doing_it_wrong( + __FUNCTION__, + esc_html__( + 'The OnDemandRevalidation class should not be cloned.', + 'on-demand-revalidation' + ), + '0.0.1' + ); + } + + /** + * Disable unserializing of the class. + * + * @since 0.0.1 + */ + public function __wakeup() { + + // De-serializing instances of the class is forbidden. + _doing_it_wrong( + __FUNCTION__, + esc_html__( + 'De-serializing instances of the OnDemandRevalidation class is not allowed.', + 'on-demand-revalidation' + ), + '0.0.1' + ); + } + + /** + * Setup plugin constants. + * + * @since 0.0.1 + */ + private function setup_constants(): void { + + if ( ! function_exists( 'get_plugin_data' ) ) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + + // Plugin version. + if ( ! defined( 'ON_DEMAND_REVALIDATION_VERSION' ) ) { + define( 'ON_DEMAND_REVALIDATION_VERSION', get_plugin_data( __FILE__ )['Version'] ); + } + + // Plugin Folder Path. + if ( ! defined( 'ON_DEMAND_REVALIDATION_PLUGIN_DIR' ) ) { + define( 'ON_DEMAND_REVALIDATION_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); + } + + // Plugin Folder URL. + if ( ! defined( 'ON_DEMAND_REVALIDATION_PLUGIN_URL' ) ) { + define( 'ON_DEMAND_REVALIDATION_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); + } + + // Plugin Root File. + if ( ! defined( 'ON_DEMAND_REVALIDATION_PLUGIN_FILE' ) ) { + define( 'ON_DEMAND_REVALIDATION_PLUGIN_FILE', __FILE__ ); + } + + // Whether to autoload the files or not. + if ( ! defined( 'ON_DEMAND_REVALIDATION_AUTOLOAD' ) ) { + define( 'ON_DEMAND_REVALIDATION_AUTOLOAD', true ); + } + } + + /** + * Uses composer's autoload to include required files. + * + * @since 0.0.1 + * + * @return bool + */ + private function includes(): bool { + + // Autoload Required Classes. + if ( defined( 'ON_DEMAND_REVALIDATION_AUTOLOAD' ) && false !== ON_DEMAND_REVALIDATION_AUTOLOAD ) { + if ( file_exists( ON_DEMAND_REVALIDATION_PLUGIN_DIR . 'vendor/autoload.php' ) ) { + require_once ON_DEMAND_REVALIDATION_PLUGIN_DIR . 'vendor/autoload.php'; + } + + // Bail if installed incorrectly. + if ( ! class_exists( '\OnDemandRevalidation\Admin\Settings' ) ) { + add_action( 'admin_notices', array( $this, 'missing_notice' ) ); + return false; + } + } + + return true; + } + + /** + * Composer dependencies missing notice. + * + * @since 0.0.1 + */ + public function missing_notice(): void { + if ( ! current_user_can( 'manage_options' ) ) { + return; + } ?> +
+

+ +

+
+ init(); + } + + /** + * Set up Purge. + * + * @since 0.0.1 + */ + private function revalidation(): void { + \OnDemandRevalidation\Revalidation::init(); + } + + + /** + * Set up Action Links. + * + * @since 0.0.1 + */ + private function plugin_links(): void { + + // Setup Settings link. + add_filter( + 'plugin_action_links_' . plugin_basename( __FILE__ ), + function ( $links ) { + $links[] = 'Settings'; + + return $links; + } + ); + } + } + +endif; + +\OnDemandRevalidation::instance(); From 4b9610012a99fe9101f0e2449e4ca3c6a0f49b58 Mon Sep 17 00:00:00 2001 From: Muhammed ogunsanya Date: Thu, 18 Apr 2024 12:04:35 +0100 Subject: [PATCH 09/11] chore: renamed file per phpcs rule, added new revalidate_tag settings field --- src/Admin/class-settings.php | 186 +++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 src/Admin/class-settings.php diff --git a/src/Admin/class-settings.php b/src/Admin/class-settings.php new file mode 100644 index 0000000..3f0163e --- /dev/null +++ b/src/Admin/class-settings.php @@ -0,0 +1,186 @@ +settings_api = new SettingsRegistry(); + add_action( 'admin_menu', array( $this, 'add_options_page' ) ); + add_action( 'init', array( $this, 'register_settings' ) ); + add_action( 'admin_init', array( $this, 'initialize_settings_page' ) ); + + if ( is_admin() ) { + Revalidation::test_revalidation_button(); + } + } + + + /** + * Add the options page to the WP Admin + * + * @return void + */ + public function add_options_page() { + + add_options_page( + __( 'Next.js On-Demand Revalidation', 'on-demand-revalidation' ), + __( 'Next.js On-Demand Revalidation', 'on-demand-revalidation' ), + 'manage_options', + 'on-demand-revalidation', + array( $this, 'render_settings_page' ) + ); + } + + /** + * Registers the settings fields + * + * @return void + */ + public function register_settings() { + + $this->settings_api->register_section( + 'on_demand_revalidation_default_settings', + array( + 'title' => __( 'General', 'on-demand-revalidation' ), + ) + ); + + $this->settings_api->register_fields( + 'on_demand_revalidation_default_settings', + array( + array( + 'name' => 'frontend_url', + 'label' => __( 'Next.js URL', 'on-demand-revalidation' ), + 'type' => 'text', + ), + array( + 'name' => 'revalidate_secret_key', + 'label' => __( 'Revalidate Secret Key', 'on-demand-revalidation' ), + 'type' => 'password', + ), + ) + ); + + $this->settings_api->register_section( + 'on_demand_revalidation_post_update_settings', + array( + 'title' => __( 'On post update', 'on-demand-revalidation' ), + 'desc' => __( 'On post update is current page revalidated automatically.', 'on-demand-revalidation' ), + ) + ); + + $this->settings_api->register_fields( + 'on_demand_revalidation_post_update_settings', + array( + array( + 'name' => 'revalidate_homepage', + 'desc' => __( 'Revalidate Homepage on post update', 'on-demand-revalidation' ), + 'type' => 'checkbox', + 'default' => 'on', + ), + array( + 'name' => 'disable_cron', + 'desc' => __( "Disable scheduled revalidation. Revalidation triggered immediately without using WP-Cron. It'll slow down post update.", 'on-demand-revalidation' ), + 'type' => 'checkbox', + ), + array( + 'name' => 'revalidate_paths', + 'label' => __( 'Additional paths to revalidate on Post update', 'on-demand-revalidation' ), + 'desc' => 'One path per row.

Available current Post placeholders:
%slug% %author_nicename% %author_username% %category% %post_tag% %custom_taxonomy%

Note: Replace %custom_taxonomy% with your custom taxonomy name.', + 'placeholder' => '/category/%category%', + 'type' => 'textarea', + ), + + array( + 'name' => 'revalidate_tags', + 'label' => __( 'Tags to revalidate on Post update', 'on-demand-revalidation' ), + 'desc' => 'Enter each tag on a new line, using placeholders like {databaseId}, {id}, {category}. Placeholders will be replaced with actual values from the post during revalidation.', + 'type' => 'textarea', + ), + + array( + 'name' => 'test-config', + 'label' => __( 'Test your config:', 'on-demand-revalidation' ), + 'desc' => 'Revalidate Latest Post', + 'type' => 'html', + ), + ) + ); + } + + /** + * Initialize the settings admin page + * + * @return void + */ + public function initialize_settings_page() { + $this->settings_api->admin_init(); + } + + /** + * Render the settings page in the admin + * + * @return void + */ + public function render_settings_page() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( esc_html__( 'You do not have sufficient permissions to access this page.' ) ); + } + + ?> +
+ Next.js On-Demand Revalidation'; + $this->settings_api->show_navigation(); + $this->settings_api->show_forms(); + ?> +
+ Date: Thu, 18 Apr 2024 12:13:38 +0100 Subject: [PATCH 10/11] chore: renamed file per phpcs rule, added doc comments and updated the revalidate function to include tags --- src/class-revalidation.php | 255 +++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 src/class-revalidation.php diff --git a/src/class-revalidation.php b/src/class-revalidation.php new file mode 100644 index 0000000..5b2025e --- /dev/null +++ b/src/class-revalidation.php @@ -0,0 +1,255 @@ +post_status ) && in_array( $post->post_status, $excluded_statuses, true ) ) { + return; + } + + if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) { + return; + } + + if ( false !== wp_is_post_revision( $post_id ) ) { + return; + } + + self::revalidate_post( $post ); + } + + /** + * Handles the transition of post status. + * + * @param string $new_status The new status of the post. + * @param string $old_status The old status of the post. + * @param object $post The post object. + */ + public static function handle_transition_post_status( $new_status, $old_status, $post ) { + if ( ( ( 'draft' !== $old_status && 'trash' !== $old_status ) && 'trash' === $new_status ) || + ( 'publish' === $old_status && 'draft' === $new_status ) ) { + + self::revalidate_post( $post ); + } + } + + /** + * Revalidates a post. + * + * @param object $post The post object to be revalidated. + * @return mixed the response data or WP_Error if revalidation fails. + */ + public static function revalidate_post( $post ) { + if ( Settings::get( 'disable_cron', 'on', 'on_demand_revalidation_post_update_settings' ) === 'on' ) { + self::revalidate( $post ); + } else { + wp_schedule_single_event( time(), 'on_demand_revalidation_on_post_update', array( $post ) ); + } + } + + /** + * Revalidates a post. + * + * @param object $post The post object to be revalidated. + * @return mixed the response data or WP_Error if revalidation fails. + */ + public static function revalidate( $post ) { + $frontend_url = Settings::get( 'frontend_url' ); + $revalidate_secret_key = Settings::get( 'revalidate_secret_key' ); + + if ( ! ( $frontend_url || $revalidate_secret_key ) ) { + return new WP_Error( 'rest_forbidden', __( 'Fill Next.js URL and Revalidate Secret Key first.', 'on-demand-revalidation' ), array( 'status' => 401 ) ); + } + + $paths = array(); + + if ( Settings::get( 'revalidate_homepage', 'on', 'on_demand_revalidation_post_update_settings' ) === 'on' ) { + $paths[] = '/'; + } + + $post_permalink = get_permalink( $post ); + $parse_permalink = wp_parse_url( $post_permalink ); + $page_path = '/'; + + if ( isset( $parse_permalink['path'] ) && '/' !== $parse_permalink['path'] ) { + $page_path = substr( $parse_permalink['path'], -1 ) === '/' ? substr( $parse_permalink['path'], 0, -1 ) : $parse_permalink['path']; + $paths[] = $page_path; + } + + $old_permalink = get_post_meta( $post->ID, '_old_permalink', true ); + + if ( ! empty( $old_permalink ) ) { + $parse_old_permalink = wp_parse_url( $old_permalink ); + + if ( isset( $parse_old_permalink['path'] ) && '/' !== $parse_old_permalink['path'] ) { + $old_page_path = substr( $parse_old_permalink['path'], -1 ) === '/' ? substr( $parse_old_permalink['path'], 0, -1 ) : $parse_old_permalink['path']; + $paths[] = $old_page_path; + } + } + + $paths = array_unique( $paths ); + + $revalidate_paths = trim( Settings::get( 'revalidate_paths', '', 'on_demand_revalidation_post_update_settings' ) ); + $revalidate_paths = preg_split( '/\r\n|\n|\r/', $revalidate_paths ); + $revalidate_paths = Helpers::rewrite_paths( $revalidate_paths, $post ); + + // Process and prepare tags. + $tag_templates = Settings::get( 'revalidate_tags', '', 'on_demand_revalidation_post_update_settings' ); + $tags = Helpers::rewrite_tags( preg_split( '/\r\n|\n|\r/', $tag_templates ), $post ); + + if ( $revalidate_paths ) { + foreach ( $revalidate_paths as $path ) { + if ( str_starts_with( $path, '/' ) ) { + $paths[] = $path; + } + } + } + + $paths = apply_filters( 'on_demand_revalidation_paths', $paths, $post ); + + $data = wp_json_encode( + array( + 'paths' => $paths, + 'tags' => $tags, + 'postId' => $post->ID, + ) + ); + + $response = wp_remote_request( + "$frontend_url/api/revalidate", + array( + 'method' => 'PUT', + 'body' => $data, + 'headers' => array( + 'Authorization' => "Bearer $revalidate_secret_key", + 'Content-Type' => 'application/json', + ), + ) + ); + + $body = json_decode( wp_remote_retrieve_body( $response ), true ); + + $response_data = ( ! is_wp_error( $response ) ) ? $body : $response; + + + if ( class_exists( 'CPurgeCache' ) ) { + \CPurgeCache\Purge::purge( $post ); + } + + + if ( ! $response_data['revalidated'] ) { + return new WP_Error( 'revalidate_error', $response['message'], array( 'status' => 403 ) ); + } + + $revalidated = implode( ', ', $paths ); + + return (object) array( + 'success' => $response_data['revalidated'], + 'message' => "Next.js revalidated $revalidated successfully.", + ); + } + + /** + * Adds a test revalidation button to the admin interface. + */ + public static function test_revalidation_button() { + add_action( + 'admin_footer', + function () { ?> + + 401 ) ); + } + + $latest_post = get_posts( + array( + 'numberposts' => 1, + 'post_status' => 'publish', + 'suppress_filters' => false, + ) + )[0]; + $response = self::revalidate( $latest_post ); + + wp_send_json( $response ); + wp_die(); + } + ); + } +} From 3f95423cb509998eede21f2bc39cb9daa6df555e Mon Sep 17 00:00:00 2001 From: Muhammed ogunsanya Date: Thu, 18 Apr 2024 13:17:28 +0100 Subject: [PATCH 11/11] chore: update plugin details --- class-ondemandrevalidation.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/class-ondemandrevalidation.php b/class-ondemandrevalidation.php index 335d846..158cf18 100644 --- a/class-ondemandrevalidation.php +++ b/class-ondemandrevalidation.php @@ -4,11 +4,11 @@ * * Plugin Name: On-Demand Revalidation * Plugin URI: https://wordpress.org/plugins/on-demand-revalidation - * GitHub Plugin URI: https://github.com/gdidentity/on-demand-revalidation - * Description: Next.js On-Demand Revalidation on the post update, revalidate specific paths on the post update. - * Version: 1.1.3 - * Author: GD IDENTITY - * Author URI: https://gdidentity.sk + * GitHub Plugin URI: https://github.com/dexerto/on-demand-revalidation + * Description: Next.js On-Demand Revalidation on the post update, revalidate specific paths, tags on the post update. + * Version: 1.2.0 + * Author: Dexerto + * Author URI: https://dexerto.com * Text Domain: on-demand-revalidation * License: GPL-3 * License URI: https://www.gnu.org/licenses/gpl-3.0.html