diff --git a/php/class-post-type.php b/php/class-post-type.php index 5da9c524..cb23b731 100644 --- a/php/class-post-type.php +++ b/php/class-post-type.php @@ -79,6 +79,13 @@ public function hooks() { add_filter( 'content_save_pre', array( $this, 'filter_out_settings_if_removed_in_metabox' ), 10 ); add_action( 'admin_print_scripts-revision.php', array( $this, 'disable_revision_ui_for_published_posts' ) ); add_action( 'admin_notices', array( $this, 'admin_show_merge_error' ) ); + + // Add workaround for failure to save changes to option settings when publishing changeset outside of customizer. See https://core.trac.wordpress.org/ticket/39221#comment:14 + if ( function_exists( '_wp_customize_publish_changeset' ) && function_exists( 'wp_doing_ajax' ) ) { // Workaround only works in WP 4.7. + $priority = has_action( 'transition_post_status', '_wp_customize_publish_changeset' ); + add_action( 'transition_post_status', array( $this, 'start_pretending_customize_save_ajax_action' ), $priority - 1, 3 ); + add_action( 'transition_post_status', array( $this, 'finish_pretending_customize_save_ajax_action' ), $priority + 1, 3 ); + } } /** @@ -588,6 +595,59 @@ public function save( array $args ) { return $r; } + /** + * Remember whether customize_save is being pretended. + * + * @link https://core.trac.wordpress.org/ticket/39221#comment:14 + * + * @var bool + */ + protected $is_pretending_customize_save_ajax_action = false; + + /** + * Start pretending customize_save Ajax action. + * + * Add workaround for failure to save changes to option settings when publishing changeset outside of customizer. + * + * @link https://core.trac.wordpress.org/ticket/39221#comment:14 + * @see \WP_Customize_Manager::doing_ajax() + * + * @param string $new_status New post status. + * @param string $old_status Old post status. + * @param \WP_Post $changeset_post Changeset post object. + */ + function start_pretending_customize_save_ajax_action( $new_status, $old_status, $changeset_post ) { + $is_publishing_changeset = ( 'customize_changeset' === $changeset_post->post_type && 'publish' === $new_status && 'publish' !== $old_status ); + if ( ! $is_publishing_changeset || isset( $_REQUEST['action'] ) ) { + return; + } + $this->is_pretending_customize_save_ajax_action = true; + add_filter( 'wp_doing_ajax', '__return_true' ); + $_REQUEST['action'] = 'customize_save'; + } + + /** + * Finish pretending customize_save Ajax action. + * + * Clean up workaround for failure to save changes to option settings when publishing changeset outside of customizer. + * + * @link https://core.trac.wordpress.org/ticket/39221#comment:14 + * @see \WP_Customize_Manager::doing_ajax() + * + * @param string $new_status New post status. + * @param string $old_status Old post status. + * @param \WP_Post $changeset_post Changeset post object. + */ + function finish_pretending_customize_save_ajax_action( $new_status, $old_status, $changeset_post ) { + $is_publishing_changeset = ( 'customize_changeset' === $changeset_post->post_type && 'publish' === $new_status && 'publish' !== $old_status ); + if ( ! $is_publishing_changeset || ! $this->is_pretending_customize_save_ajax_action ) { + return; + } + remove_filter( 'wp_doing_ajax', '__return_true' ); + unset( $_REQUEST['action'] ); + $this->is_pretending_customize_save_ajax_action = false; + } + /** * Re-map customize meta cap to edit_theme_options primitive cap. * diff --git a/tests/php/test-class-post-type.php b/tests/php/test-class-post-type.php index fcdff6b7..c6f26248 100644 --- a/tests/php/test-class-post-type.php +++ b/tests/php/test-class-post-type.php @@ -663,6 +663,49 @@ public function test_save() { $this->assertEquals( 'future', get_post_status( $post_id ) ); } + /** + * Test that changes to options can be saved by publishing the changeset. + * + * @covers \CustomizeSnapshots\Post_Type::start_pretending_customize_save_ajax_action() + * @covers \CustomizeSnapshots\Post_Type::finish_pretending_customize_save_ajax_action() + */ + function test_pretending_customize_save_ajax_action() { + if ( ! function_exists( 'wp_generate_uuid4' ) ) { + $this->markTestSkipped( 'Only relevant to WordPress 4.7 and greater.' ); + } + + set_current_screen( 'edit' ); + $this->assertTrue( is_admin() ); + $post_type = $this->get_new_post_type_instance( $this->plugin->customize_snapshot_manager ); + $post_type->init(); + + $old_sidebars_widgets = get_option( 'sidebars_widgets' ); + $new_sidebars_widgets = $old_sidebars_widgets; + $new_sidebar_1 = array_reverse( $new_sidebars_widgets['sidebar-1'] ); + + $post_id = $this->factory()->post->create( array( + 'post_type' => 'customize_changeset', + 'post_status' => 'draft', + 'post_name' => wp_generate_uuid4(), + 'post_content' => wp_json_encode( array( + 'sidebars_widgets[sidebar-1]' => array( + 'value' => $new_sidebar_1, + ), + ) ), + ) ); + + // Save the updated sidebar widgets into the options table. + wp_publish_post( $post_id ); + + // Make sure previewing filters are removed. + remove_all_filters( 'option_sidebars_widgets' ); + remove_all_filters( 'default_option_sidebars_widgets' ); + + // Ensure that the value has actually been written to the DB. + $updated_sidebars_widgets = get_option( 'sidebars_widgets' ); + $this->assertEquals( $new_sidebar_1, $updated_sidebars_widgets['sidebar-1'] ); + } + /** * Test granting customize capability. *