settings = new Content_Refresher_Settings( $this->options ); $this->refresher = new Content_Refresher_Refresher( $this->options ); if ( ! empty( $this->options['allow_cloning'] ) || ! empty( $this->options['allow_content_refresh'] ) ) { add_action( 'init', [ $this, 'register_row_actions' ] ); } if ( ! empty( $this->options['allow_cloning'] ) ) { add_action( 'admin_action_adminoptim-clone-post', [ $this, 'handle_clone_post' ] ); } if ( ! empty( $this->options['allow_content_refresh'] ) ) { add_action( 'admin_action_adminoptim-clone-republish', [ $this, 'handle_refresh_clone' ] ); add_action( 'admin_action_adminoptim-republisher-delete-post', [ $this, 'handle_refresh_cleanup_redirect' ] ); add_action( 'transition_post_status', [ $this, 'schedule_or_refresh' ], 8, 3 ); add_action( 'adminoptim_republish_post', [ $this, 'run_scheduled_refresh' ] ); add_action( 'adminoptim_deactivate_plugin', [ $this, 'remove_scheduled_actions' ] ); add_filter( 'display_post_states', [ $this, 'display_refresh_state' ], 10, 2 ); add_action( 'admin_notices', [ $this, 'display_refresh_notice' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_editor_assets' ] ); new Content_Refresher_Post_Status( $this->refresher ); new Content_Refresher_Cleaner( $this->options ); new Content_Refresher_Metaboxes( $this->options, $this->refresher ); } } /** * Use the old module toggles as initial values when this module has no saved option yet. * * @return array */ protected function get_default_options() { $module_options = get_option( 'adminoptim-modules', [] ); $module_options = is_array( $module_options ) ? $module_options : []; $clone_options = get_option( 'adminoptim_post_cloner', [] ); $clone_options = is_array( $clone_options ) ? $clone_options : []; $refresh_options = get_option( 'adminoptim_post_republisher', [] ); $refresh_options = is_array( $refresh_options ) ? $refresh_options : []; $has_legacy = array_key_exists( 'enable_post_cloner', $module_options ) || array_key_exists( 'enable_post_republisher', $module_options ); return [ 'allow_cloning' => $has_legacy ? ( ! empty( $module_options['enable_post_cloner'] ) ? 1 : 0 ) : 1, 'clone_post_types' => isset( $clone_options['post_types'] ) ? (array) $clone_options['post_types'] : [ 'post', 'page' ], 'clone_roles' => isset( $clone_options['clone_roles'] ) ? (array) $clone_options['clone_roles'] : [ 'administrator' ], 'after_cloning' => isset( $clone_options['after_cloning'] ) ? $clone_options['after_cloning'] : 'return', 'allow_content_refresh' => $has_legacy ? ( ! empty( $module_options['enable_post_republisher'] ) ? 1 : 0 ) : 1, 'refresh_post_types' => isset( $refresh_options['post_types'] ) ? (array) $refresh_options['post_types'] : [ 'post', 'page' ], 'refresh_roles' => isset( $refresh_options['republish_roles'] ) ? (array) $refresh_options['republish_roles'] : [ 'administrator' ], 'replace_author' => ! empty( $refresh_options['replace_author'] ) ? 1 : 0, 'replace_publish_date' => ! empty( $refresh_options['replace_publish_date'] ) ? 1 : 0, 'replace_modified_date' => ! empty( $refresh_options['replace_modified_date'] ) ? 1 : 0, 'replace_tax' => ! empty( $refresh_options['replace_tax'] ) ? 1 : 0, 'replace_post_metas' => ! empty( $refresh_options['replace_post_metas'] ) ? 1 : 0, 'update_guid' => ! empty( $refresh_options['update_guid'] ) ? 1 : 0, 'delete_comments' => ! empty( $refresh_options['delete_comments'] ) ? 1 : 0, 'after_republish_action' => isset( $refresh_options['after_republish_action'] ) ? $refresh_options['after_republish_action'] : 'trash', ]; } /** * Register one row-action filter for both features. * * @return void */ public function register_row_actions(): void { if ( is_admin() ) { add_filter( 'post_row_actions', [ $this, 'add_row_actions' ], 10, 2 ); add_filter( 'page_row_actions', [ $this, 'add_row_actions' ], 10, 2 ); } } /** * Add the enabled operations to a post row. * * @param array $actions Existing actions. * @param \WP_Post $post Post object. * @return array */ public function add_row_actions( $actions, $post ): array { if ( ! $post instanceof \WP_Post || $this->refresher->is_refresh_copy( $post->ID ) ) { return $actions; } if ( ! empty( $this->options['allow_cloning'] ) && $this->post_type_enabled( $post->post_type, 'clone_post_types' ) && $this->refresher->can_clone( wp_get_current_user(), $post ) ) { $url = wp_nonce_url( admin_url( 'admin.php?action=adminoptim-clone-post&post=' . $post->ID ), 'adminoptim-clone-post-' . $post->ID ); $actions['clone_post'] = '' . esc_html__( 'Clone', 'admin-optimizer' ) . ''; } if ( ! empty( $this->options['allow_content_refresh'] ) && $this->post_type_enabled( $post->post_type, 'refresh_post_types' ) && $this->refresher->can_refresh( wp_get_current_user(), $post ) ) { $url = wp_nonce_url( admin_url( 'admin.php?action=adminoptim-clone-republish&post=' . $post->ID ), 'adminoptim-refresh-post-' . $post->ID ); $actions['clone_republish'] = '' . esc_html__( 'Create Refresh Copy', 'admin-optimizer' ) . ''; } return $actions; } /** * Handle ordinary cloning. * * @return void */ public function handle_clone_post(): void { $source_id = isset( $_GET['post'] ) ? absint( $_GET['post'] ) : 0; check_admin_referer( 'adminoptim-clone-post-' . $source_id ); $source = get_post( $source_id ); if ( ! $source instanceof \WP_Post || ! $this->post_type_enabled( $source->post_type, 'clone_post_types' ) || ! $this->refresher->can_clone( wp_get_current_user(), $source ) ) { wp_die( esc_html__( 'You are not allowed to clone this post.', 'admin-optimizer' ) ); } $clone_id = $this->refresher->clone_post( $source_id ); if ( is_wp_error( $clone_id ) ) { wp_die( esc_html( $clone_id->get_error_message() ) ); } $redirect = 'edit' === ( $this->options['after_cloning'] ?? 'return' ) ? get_edit_post_link( $clone_id, 'raw' ) : admin_url( 'edit.php?post_type=' . $source->post_type ); wp_safe_redirect( $redirect ?: admin_url( 'edit.php' ) ); exit; } /** * Handle creation of a refresh working copy. * * @return void */ public function handle_refresh_clone(): void { $source_id = isset( $_GET['post'] ) ? absint( $_GET['post'] ) : 0; check_admin_referer( 'adminoptim-refresh-post-' . $source_id ); $source = get_post( $source_id ); if ( ! $source instanceof \WP_Post || ! $this->post_type_enabled( $source->post_type, 'refresh_post_types' ) || ! $this->refresher->can_refresh( wp_get_current_user(), $source ) ) { wp_die( esc_html__( 'You are not allowed to create a refresh copy of this post.', 'admin-optimizer' ) ); } $clone_id = $this->refresher->clone_for_refresh( $source_id ); if ( is_wp_error( $clone_id ) ) { wp_die( esc_html( $clone_id->get_error_message() ) ); } wp_safe_redirect( get_edit_post_link( $clone_id, 'raw' ) ?: admin_url( 'edit.php' ) ); exit; } /** * Refresh immediately or manage a scheduled refresh. * * @param string $new_status New post status. * @param string $old_status Previous post status. * @param \WP_Post $post Post being transitioned. * * @return void */ public function schedule_or_refresh( $new_status, $old_status, $post ): void { if ( ! $post instanceof \WP_Post || ! $this->refresher->is_refresh_copy( $post->ID ) ) { return; } if ( 'republish' === $new_status && 'republish' !== $old_status ) { $parent_id = $this->refresher->get_refresh_parent( $post->ID ); $result = $this->refresher->refresh_original( $post ); if ( is_wp_error( $result ) ) { return; } if ( ! $this->is_rest_request() && ! wp_doing_ajax() ) { wp_safe_redirect( $this->cleanup_redirect_url( $post->ID, $parent_id ) ); exit; } } elseif ( 'future-republish' === $new_status ) { $timestamp = get_post_timestamp( $post ); if ( ! as_has_scheduled_action( 'adminoptim_republish_post', [ $post->ID ], 'admin-optimizer' ) ) { as_schedule_single_action( $timestamp, 'adminoptim_republish_post', [ $post->ID ], 'admin-optimizer', true ); } else { $scheduled = as_next_scheduled_action( 'adminoptim_republish_post', [ $post->ID ], 'admin-optimizer' ); if ( $scheduled !== $timestamp ) { as_unschedule_action( 'adminoptim_republish_post', [ $post->ID ], 'admin-optimizer' ); as_schedule_single_action( $timestamp, 'adminoptim_republish_post', [ $post->ID ], 'admin-optimizer', true ); } } } elseif ( 'future-republish' === $old_status ) { as_unschedule_action( 'adminoptim_republish_post', [ $post->ID ], 'admin-optimizer' ); } } /** * Run a scheduled refresh. * * @param int $refresh_id Refresh-copy post ID. * * @return void */ public function run_scheduled_refresh( $refresh_id ): void { $result = $this->refresher->refresh_original( absint( $refresh_id ) ); if ( ! is_wp_error( $result ) ) { $this->refresher->delete_refresh_copy( absint( $refresh_id ) ); } } /** * Finish deletion after a synchronous refresh and redirect to the original. * * @return void */ public function handle_refresh_cleanup_redirect(): void { check_admin_referer( 'adminoptim-republisher-delete-post', 'republish_nonce' ); $refresh_id = isset( $_GET['republish_id'] ) ? absint( $_GET['republish_id'] ) : 0; $parent_id = isset( $_GET['parent_id'] ) ? absint( $_GET['parent_id'] ) : 0; if ( $refresh_id && 'pending-delete' === get_post_meta( $refresh_id, '_republish_status', true ) ) { $this->refresher->delete_refresh_copy( $refresh_id ); } wp_safe_redirect( $parent_id ? get_edit_post_link( $parent_id, 'raw' ) : admin_url( 'edit.php' ) ); exit; } /** * Display the parent relationship in post lists. * * @param array $states Existing post display states. * @param \WP_Post $post Post being listed. * * @return array */ public function display_refresh_state( $states, $post ) { if ( $post instanceof \WP_Post && $this->refresher->is_refresh_copy( $post->ID ) ) { $parent_id = $this->refresher->get_refresh_parent( $post->ID ); $states['adminoptim_refresh_copy'] = sprintf( /* translators: %s: Original post title. */ esc_html__( 'Refresh copy of %s', 'admin-optimizer' ), esc_html( get_the_title( $parent_id ) ) ); } return $states; } /** * Display classic-editor context for refresh copies. * * @return void */ public function display_refresh_notice(): void { global $post; $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; if ( ! $post instanceof \WP_Post || ! $screen || 'post' !== $screen->base || ! $this->refresher->is_refresh_copy( $post->ID ) ) { return; } $parent_id = $this->refresher->get_refresh_parent( $post->ID ); ?>