WordPress.org

Make WordPress Core


Ignore:
Timestamp:
10/18/2016 08:04:36 PM (3 years ago)
Author:
westonruter
Message:

Customize: Implement customized state persistence with changesets.

Includes infrastructure developed in the Customize Snapshots feature plugin.

See https://make.wordpress.org/core/2016/10/12/customize-changesets-technical-design-decisions/

Props westonruter, valendesigns, utkarshpatel, stubgo, lgedeon, ocean90, ryankienstra, mihai2u, dlh, aaroncampbell, jonathanbardo, jorbin.
See #28721.
See #31089.
Fixes #30937.
Fixes #31517.
Fixes #30028.
Fixes #23225.
Fixes #34142.
Fixes #36485.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/customize/manager.php

    r38765 r38810  
    2828
    2929    /**
     30     * Admin user ID.
     31     *
     32     * @var int
     33     */
     34    protected static $admin_user_id;
     35
     36    /**
     37     * Subscriber user ID.
     38     *
     39     * @var int
     40     */
     41    protected static $subscriber_user_id;
     42
     43    /**
     44     * Set up before class.
     45     *
     46     * @param WP_UnitTest_Factory $factory Factory.
     47     */
     48    public static function wpSetUpBeforeClass( $factory ) {
     49        self::$subscriber_user_id = $factory->user->create( array( 'role' => 'subscriber' ) );
     50        self::$admin_user_id = $factory->user->create( array( 'role' => 'administrator' ) );
     51    }
     52
     53    /**
    3054     * Set up test.
    3155     */
     
    4367        $this->manager = null;
    4468        unset( $GLOBALS['wp_customize'] );
     69        $_REQUEST = array();
    4570        parent::tearDown();
    4671    }
     
    5479        $GLOBALS['wp_customize'] = new WP_Customize_Manager();
    5580        return $GLOBALS['wp_customize'];
     81    }
     82
     83    /**
     84     * Test WP_Customize_Manager::__construct().
     85     *
     86     * @covers WP_Customize_Manager::__construct()
     87     */
     88    function test_constructor() {
     89        $uuid = wp_generate_uuid4();
     90        $theme = 'twentyfifteen';
     91        $messenger_channel = 'preview-123';
     92        $wp_customize = new WP_Customize_Manager( array(
     93            'changeset_uuid' => $uuid,
     94            'theme' => $theme,
     95            'messenger_channel' => $messenger_channel,
     96        ) );
     97        $this->assertEquals( $uuid, $wp_customize->changeset_uuid() );
     98        $this->assertEquals( $theme, $wp_customize->get_stylesheet() );
     99        $this->assertEquals( $messenger_channel, $wp_customize->get_messenger_channel() );
     100
     101        $theme = 'twentyfourteen';
     102        $messenger_channel = 'preview-456';
     103        $_REQUEST['theme'] = $theme;
     104        $_REQUEST['customize_messenger_channel'] = $messenger_channel;
     105        $wp_customize = new WP_Customize_Manager( array( 'changeset_uuid' => $uuid ) );
     106        $this->assertEquals( $theme, $wp_customize->get_stylesheet() );
     107        $this->assertEquals( $messenger_channel, $wp_customize->get_messenger_channel() );
     108
     109        $theme = 'twentyfourteen';
     110        $_REQUEST['customize_theme'] = $theme;
     111        $wp_customize = new WP_Customize_Manager();
     112        $this->assertEquals( $theme, $wp_customize->get_stylesheet() );
     113        $this->assertNotEmpty( $wp_customize->changeset_uuid() );
     114    }
     115
     116    /**
     117     * Test WP_Customize_Manager::setup_theme() for admin screen.
     118     *
     119     * @covers WP_Customize_Manager::setup_theme()
     120     */
     121    function test_setup_theme_in_customize_admin() {
     122        global $pagenow, $wp_customize;
     123        $pagenow = 'customize.php';
     124        set_current_screen( 'customize' );
     125
     126        // Unauthorized.
     127        $exception = null;
     128        $wp_customize = new WP_Customize_Manager();
     129        wp_set_current_user( self::$subscriber_user_id );
     130        try {
     131            $wp_customize->setup_theme();
     132        } catch ( Exception $e ) {
     133            $exception = $e;
     134        }
     135        $this->assertInstanceOf( 'WPDieException', $exception );
     136        $this->assertContains( 'you are not allowed to customize this site', $exception->getMessage() );
     137
     138        // Bad changeset.
     139        $exception = null;
     140        wp_set_current_user( self::$admin_user_id );
     141        $wp_customize = new WP_Customize_Manager( array( 'changeset_uuid' => 'bad' ) );
     142        try {
     143            $wp_customize->setup_theme();
     144        } catch ( Exception $e ) {
     145            $exception = $e;
     146        }
     147        $this->assertInstanceOf( 'WPDieException', $exception );
     148        $this->assertContains( 'Invalid changeset UUID', $exception->getMessage() );
     149
     150        $wp_customize = new WP_Customize_Manager();
     151        $wp_customize->setup_theme();
     152    }
     153
     154    /**
     155     * Test WP_Customize_Manager::setup_theme() for frontend.
     156     *
     157     * @covers WP_Customize_Manager::setup_theme()
     158     */
     159    function test_setup_theme_in_frontend() {
     160        global $wp_customize, $pagenow, $show_admin_bar;
     161        $pagenow = 'front';
     162        set_current_screen( 'front' );
     163
     164        wp_set_current_user( 0 );
     165        $exception = null;
     166        $wp_customize = new WP_Customize_Manager();
     167        wp_set_current_user( self::$subscriber_user_id );
     168        try {
     169            $wp_customize->setup_theme();
     170        } catch ( Exception $e ) {
     171            $exception = $e;
     172        }
     173        $this->assertInstanceOf( 'WPDieException', $exception );
     174        $this->assertContains( 'Non-existent changeset UUID', $exception->getMessage() );
     175
     176        wp_set_current_user( self::$admin_user_id );
     177        $wp_customize = new WP_Customize_Manager( array( 'messenger_channel' => 'preview-1' ) );
     178        $wp_customize->setup_theme();
     179        $this->assertFalse( $show_admin_bar );
     180
     181        show_admin_bar( true );
     182        wp_set_current_user( self::$admin_user_id );
     183        $wp_customize = new WP_Customize_Manager( array( 'messenger_channel' => null ) );
     184        $wp_customize->setup_theme();
     185        $this->assertTrue( $show_admin_bar );
     186    }
     187
     188    /**
     189     * Test WP_Customize_Manager::changeset_uuid().
     190     *
     191     * @ticket 30937
     192     * @covers WP_Customize_Manager::changeset_uuid()
     193     */
     194    function test_changeset_uuid() {
     195        $uuid = wp_generate_uuid4();
     196        $wp_customize = new WP_Customize_Manager( array( 'changeset_uuid' => $uuid ) );
     197        $this->assertEquals( $uuid, $wp_customize->changeset_uuid() );
     198    }
     199
     200    /**
     201     * Test WP_Customize_Manager::wp_loaded().
     202     *
     203     * Ensure that post values are previewed even without being in preview.
     204     *
     205     * @ticket 30937
     206     * @covers WP_Customize_Manager::wp_loaded()
     207     */
     208    function test_wp_loaded() {
     209        wp_set_current_user( self::$admin_user_id );
     210        $wp_customize = new WP_Customize_Manager();
     211        $title = 'Hello World';
     212        $wp_customize->set_post_value( 'blogname', $title );
     213        $this->assertNotEquals( $title, get_option( 'blogname' ) );
     214        $wp_customize->wp_loaded();
     215        $this->assertFalse( $wp_customize->is_preview() );
     216        $this->assertEquals( $title, $wp_customize->get_setting( 'blogname' )->value() );
     217        $this->assertEquals( $title, get_option( 'blogname' ) );
     218    }
     219
     220    /**
     221     * Test WP_Customize_Manager::find_changeset_post_id().
     222     *
     223     * @ticket 30937
     224     * @covers WP_Customize_Manager::find_changeset_post_id()
     225     */
     226    function test_find_changeset_post_id() {
     227        $uuid = wp_generate_uuid4();
     228        $post_id = $this->factory()->post->create( array(
     229            'post_name' => $uuid,
     230            'post_type' => 'customize_changeset',
     231            'post_status' => 'auto-draft',
     232            'post_content' => '{}',
     233        ) );
     234
     235        $wp_customize = new WP_Customize_Manager();
     236        $this->assertNull( $wp_customize->find_changeset_post_id( wp_generate_uuid4() ) );
     237        $this->assertEquals( $post_id, $wp_customize->find_changeset_post_id( $uuid ) );
     238    }
     239
     240    /**
     241     * Test WP_Customize_Manager::changeset_post_id().
     242     *
     243     * @ticket 30937
     244     * @covers WP_Customize_Manager::changeset_post_id()
     245     */
     246    function test_changeset_post_id() {
     247        $uuid = wp_generate_uuid4();
     248        $wp_customize = new WP_Customize_Manager( array( 'changeset_uuid' => $uuid ) );
     249        $this->assertNull( $wp_customize->changeset_post_id() );
     250
     251        $uuid = wp_generate_uuid4();
     252        $wp_customize = new WP_Customize_Manager( array( 'changeset_uuid' => $uuid ) );
     253        $post_id = $this->factory()->post->create( array(
     254            'post_name' => $uuid,
     255            'post_type' => 'customize_changeset',
     256            'post_status' => 'auto-draft',
     257            'post_content' => '{}',
     258        ) );
     259        $this->assertEquals( $post_id, $wp_customize->changeset_post_id() );
     260    }
     261
     262    /**
     263     * Test WP_Customize_Manager::changeset_data().
     264     *
     265     * @ticket 30937
     266     * @covers WP_Customize_Manager::changeset_data()
     267     */
     268    function test_changeset_data() {
     269        $uuid = wp_generate_uuid4();
     270        $wp_customize = new WP_Customize_Manager( array( 'changeset_uuid' => $uuid ) );
     271        $this->assertEquals( array(), $wp_customize->changeset_data() );
     272
     273        $uuid = wp_generate_uuid4();
     274        $data = array( 'blogname' => array( 'value' => 'Hello World' ) );
     275        $this->factory()->post->create( array(
     276            'post_name' => $uuid,
     277            'post_type' => 'customize_changeset',
     278            'post_status' => 'auto-draft',
     279            'post_content' => wp_json_encode( $data ),
     280        ) );
     281        $wp_customize = new WP_Customize_Manager( array( 'changeset_uuid' => $uuid ) );
     282        $this->assertEquals( $data, $wp_customize->changeset_data() );
     283    }
     284
     285    /**
     286     * Test WP_Customize_Manager::customize_preview_init().
     287     *
     288     * @ticket 30937
     289     * @covers WP_Customize_Manager::customize_preview_init()
     290     */
     291    function test_customize_preview_init() {
     292
     293        // Test authorized admin user.
     294        wp_set_current_user( self::$admin_user_id );
     295        $did_action_customize_preview_init = did_action( 'customize_preview_init' );
     296        $wp_customize = new WP_Customize_Manager();
     297        $wp_customize->customize_preview_init();
     298        $this->assertEquals( $did_action_customize_preview_init + 1, did_action( 'customize_preview_init' ) );
     299
     300        $this->assertEquals( 10, has_action( 'wp_head', 'wp_no_robots' ) );
     301        $this->assertEquals( 10, has_filter( 'wp_headers', array( $wp_customize, 'filter_iframe_security_headers' ) ) );
     302        $this->assertEquals( 10, has_filter( 'wp_redirect', array( $wp_customize, 'add_state_query_params' ) ) );
     303        $this->assertTrue( wp_script_is( 'customize-preview', 'enqueued' ) );
     304        $this->assertEquals( 10, has_action( 'wp_head', array( $wp_customize, 'customize_preview_loading_style' ) ) );
     305        $this->assertEquals( 20, has_action( 'wp_footer', array( $wp_customize, 'customize_preview_settings' ) ) );
     306
     307        // Test unauthorized user outside preview (no messenger_channel).
     308        wp_set_current_user( self::$subscriber_user_id );
     309        $wp_customize = new WP_Customize_Manager();
     310        $wp_customize->register_controls();
     311        $this->assertNotEmpty( $wp_customize->controls() );
     312        $wp_customize->customize_preview_init();
     313        $this->assertEmpty( $wp_customize->controls() );
     314
     315        // Test unauthorized user inside preview (with messenger_channel).
     316        wp_set_current_user( self::$subscriber_user_id );
     317        $wp_customize = new WP_Customize_Manager( array( 'messenger_channel' => 'preview-0' ) );
     318        $exception = null;
     319        try {
     320            $wp_customize->customize_preview_init();
     321        } catch ( WPDieException $e ) {
     322            $exception = $e;
     323        }
     324        $this->assertNotNull( $exception );
     325        $this->assertContains( 'Unauthorized', $exception->getMessage() );
     326    }
     327
     328    /**
     329     * Test WP_Customize_Manager::filter_iframe_security_headers().
     330     *
     331     * @ticket 30937
     332     * @covers WP_Customize_Manager::filter_iframe_security_headers()
     333     */
     334    function test_filter_iframe_security_headers() {
     335        $customize_url = admin_url( 'customize.php' );
     336        $wp_customize = new WP_Customize_Manager();
     337        $headers = $wp_customize->filter_iframe_security_headers( array() );
     338        $this->assertArrayHasKey( 'X-Frame-Options', $headers );
     339        $this->assertArrayHasKey( 'Content-Security-Policy', $headers );
     340        $this->assertEquals( "ALLOW-FROM $customize_url", $headers['X-Frame-Options'] );
     341    }
     342
     343    /**
     344     * Test WP_Customize_Manager::add_state_query_params().
     345     *
     346     * @ticket 30937
     347     * @covers WP_Customize_Manager::add_state_query_params()
     348     */
     349    function test_add_state_query_params() {
     350        $uuid = wp_generate_uuid4();
     351        $messenger_channel = 'preview-0';
     352        $wp_customize = new WP_Customize_Manager( array(
     353            'changeset_uuid' => $uuid,
     354            'messenger_channel' => $messenger_channel,
     355        ) );
     356        $url = $wp_customize->add_state_query_params( home_url( '/' ) );
     357        $parsed_url = wp_parse_url( $url );
     358        parse_str( $parsed_url['query'], $query_params );
     359        $this->assertArrayHasKey( 'customize_messenger_channel', $query_params );
     360        $this->assertArrayHasKey( 'customize_changeset_uuid', $query_params );
     361        $this->assertArrayNotHasKey( 'customize_theme', $query_params );
     362        $this->assertEquals( $uuid, $query_params['customize_changeset_uuid'] );
     363        $this->assertEquals( $messenger_channel, $query_params['customize_messenger_channel'] );
     364
     365        $uuid = wp_generate_uuid4();
     366        $wp_customize = new WP_Customize_Manager( array(
     367            'changeset_uuid' => $uuid,
     368            'messenger_channel' => null,
     369            'theme' => 'twentyfifteen',
     370        ) );
     371        $url = $wp_customize->add_state_query_params( home_url( '/' ) );
     372        $parsed_url = wp_parse_url( $url );
     373        parse_str( $parsed_url['query'], $query_params );
     374        $this->assertArrayNotHasKey( 'customize_messenger_channel', $query_params );
     375        $this->assertArrayHasKey( 'customize_changeset_uuid', $query_params );
     376        $this->assertArrayHasKey( 'customize_theme', $query_params );
     377        $this->assertEquals( $uuid, $query_params['customize_changeset_uuid'] );
     378        $this->assertEquals( 'twentyfifteen', $query_params['customize_theme'] );
     379
     380        $uuid = wp_generate_uuid4();
     381        $wp_customize = new WP_Customize_Manager( array(
     382            'changeset_uuid' => $uuid,
     383            'messenger_channel' => null,
     384            'theme' => 'twentyfifteen',
     385        ) );
     386        $url = $wp_customize->add_state_query_params( 'http://not-allowed.example.com/?q=1' );
     387        $parsed_url = wp_parse_url( $url );
     388        parse_str( $parsed_url['query'], $query_params );
     389        $this->assertArrayNotHasKey( 'customize_messenger_channel', $query_params );
     390        $this->assertArrayNotHasKey( 'customize_changeset_uuid', $query_params );
     391        $this->assertArrayNotHasKey( 'customize_theme', $query_params );
     392    }
     393
     394    /**
     395     * Test WP_Customize_Manager::save_changeset_post().
     396     *
     397     * @ticket 30937
     398     * @covers WP_Customize_Manager::save_changeset_post()
     399     */
     400    function test_save_changeset_post_without_theme_activation() {
     401        wp_set_current_user( self::$admin_user_id );
     402
     403        $did_action = array(
     404            'customize_save_validation_before' => did_action( 'customize_save_validation_before' ),
     405            'customize_save' => did_action( 'customize_save' ),
     406            'customize_save_after' => did_action( 'customize_save_after' ),
     407        );
     408        $uuid = wp_generate_uuid4();
     409
     410        $manager = new WP_Customize_Manager( array(
     411            'changeset_uuid' => $uuid,
     412        ) );
     413        $manager->register_controls();
     414        $manager->set_post_value( 'blogname', 'Changeset Title' );
     415        $manager->set_post_value( 'blogdescription', 'Changeset Tagline' );
     416
     417        $r = $manager->save_changeset_post( array(
     418            'status' => 'auto-draft',
     419            'title' => 'Auto Draft',
     420            'date_gmt' => '2010-01-01 00:00:00',
     421            'data' => array(
     422                'blogname' => array(
     423                    'value' => 'Overridden Changeset Title',
     424                ),
     425                'blogdescription' => array(
     426                    'custom' => 'something',
     427                ),
     428            ),
     429        ) );
     430        $this->assertInternalType( 'array', $r );
     431
     432        $this->assertEquals( $did_action['customize_save_validation_before'] + 1, did_action( 'customize_save_validation_before' ) );
     433
     434        $post_id = $manager->find_changeset_post_id( $uuid );
     435        $this->assertNotNull( $post_id );
     436        $saved_data = json_decode( get_post( $post_id )->post_content, true );
     437        $this->assertEquals( $manager->unsanitized_post_values(), wp_list_pluck( $saved_data, 'value' ) );
     438        $this->assertEquals( 'Overridden Changeset Title', $saved_data['blogname']['value'] );
     439        $this->assertEquals( 'something', $saved_data['blogdescription']['custom'] );
     440        $this->assertEquals( 'Auto Draft', get_post( $post_id )->post_title );
     441        $this->assertEquals( 'auto-draft', get_post( $post_id )->post_status );
     442        $this->assertEquals( '2010-01-01 00:00:00', get_post( $post_id )->post_date_gmt );
     443        $this->assertNotEquals( 'Changeset Title', get_option( 'blogname' ) );
     444        $this->assertArrayHasKey( 'setting_validities', $r );
     445
     446        // Test saving with invalid settings, ensuring transaction blocked.
     447        $previous_saved_data = $saved_data;
     448        $manager->add_setting( 'foo_unauthorized', array(
     449            'capability' => 'do_not_allow',
     450        ) );
     451        $manager->add_setting( 'baz_illegal', array(
     452            'validate_callback' => array( $this, 'return_illegal_error' ),
     453        ) );
     454        $r = $manager->save_changeset_post( array(
     455            'status' => 'auto-draft',
     456            'data' => array(
     457                'blogname' => array(
     458                    'value' => 'OK',
     459                ),
     460                'foo_unauthorized' => array(
     461                    'value' => 'No',
     462                ),
     463                'bar_unknown' => array(
     464                    'value' => 'No',
     465                ),
     466                'baz_illegal' => array(
     467                    'value' => 'No',
     468                ),
     469            ),
     470        ) );
     471        $this->assertInstanceOf( 'WP_Error', $r );
     472        $this->assertEquals( 'transaction_fail', $r->get_error_code() );
     473        $this->assertInternalType( 'array', $r->get_error_data() );
     474        $this->assertArrayHasKey( 'setting_validities', $r->get_error_data() );
     475        $error_data = $r->get_error_data();
     476        $this->assertArrayHasKey( 'blogname', $error_data['setting_validities'] );
     477        $this->assertTrue( $error_data['setting_validities']['blogname'] );
     478        $this->assertArrayHasKey( 'foo_unauthorized', $error_data['setting_validities'] );
     479        $this->assertInstanceOf( 'WP_Error', $error_data['setting_validities']['foo_unauthorized'] );
     480        $this->assertEquals( 'unauthorized', $error_data['setting_validities']['foo_unauthorized']->get_error_code() );
     481        $this->assertArrayHasKey( 'bar_unknown', $error_data['setting_validities'] );
     482        $this->assertInstanceOf( 'WP_Error', $error_data['setting_validities']['bar_unknown'] );
     483        $this->assertEquals( 'unrecognized', $error_data['setting_validities']['bar_unknown']->get_error_code() );
     484        $this->assertArrayHasKey( 'baz_illegal', $error_data['setting_validities'] );
     485        $this->assertInstanceOf( 'WP_Error', $error_data['setting_validities']['baz_illegal'] );
     486        $this->assertEquals( 'illegal', $error_data['setting_validities']['baz_illegal']->get_error_code() );
     487
     488        // Since transactional, ensure no changes have been made.
     489        $this->assertEquals( $previous_saved_data, json_decode( get_post( $post_id )->post_content, true ) );
     490
     491        // Attempt a non-transactional/incremental update.
     492        $manager = new WP_Customize_Manager( array(
     493            'changeset_uuid' => $uuid,
     494        ) );
     495        $manager->register_controls(); // That is, register settings.
     496        $r = $manager->save_changeset_post( array(
     497            'status' => null,
     498            'data' => array(
     499                'blogname' => array(
     500                    'value' => 'Non-Transactional \o/ <script>unsanitized</script>',
     501                ),
     502                'bar_unknown' => array(
     503                    'value' => 'No',
     504                ),
     505            ),
     506        ) );
     507        $this->assertInternalType( 'array', $r );
     508        $this->assertArrayHasKey( 'setting_validities', $r );
     509        $this->assertTrue( $r['setting_validities']['blogname'] );
     510        $this->assertInstanceOf( 'WP_Error', $r['setting_validities']['bar_unknown'] );
     511        $saved_data = json_decode( get_post( $post_id )->post_content, true );
     512        $this->assertNotEquals( $previous_saved_data, $saved_data );
     513        $this->assertEquals( 'Non-Transactional \o/ <script>unsanitized</script>', $saved_data['blogname']['value'] );
     514
     515        // Ensure the filter applies.
     516        $customize_changeset_save_data_call_count = $this->customize_changeset_save_data_call_count;
     517        add_filter( 'customize_changeset_save_data', array( $this, 'filter_customize_changeset_save_data' ), 10, 2 );
     518        $manager->save_changeset_post( array(
     519            'status' => null,
     520            'data' => array(
     521                'blogname' => array(
     522                    'value' => 'Filtered',
     523                ),
     524            ),
     525        ) );
     526        $this->assertEquals( $customize_changeset_save_data_call_count + 1, $this->customize_changeset_save_data_call_count );
     527
     528        // Publish the changeset.
     529        $manager = new WP_Customize_Manager( array( 'changeset_uuid' => $uuid ) );
     530        $manager->register_controls();
     531        $GLOBALS['wp_customize'] = $manager;
     532        $r = $manager->save_changeset_post( array(
     533            'status' => 'publish',
     534            'data' => array(
     535                'blogname' => array(
     536                    'value' => 'Do it live \o/',
     537                ),
     538            ),
     539        ) );
     540        $this->assertInternalType( 'array', $r );
     541        $this->assertEquals( 'Do it live \o/', get_option( 'blogname' ) );
     542        $this->assertEquals( 'trash', get_post_status( $post_id ) ); // Auto-trashed.
     543
     544        // Test revisions.
     545        add_post_type_support( 'customize_changeset', 'revisions' );
     546        $uuid = wp_generate_uuid4();
     547        $manager = new WP_Customize_Manager( array( 'changeset_uuid' => $uuid ) );
     548        $manager->register_controls();
     549        $GLOBALS['wp_customize'] = $manager;
     550
     551        $manager->set_post_value( 'blogname', 'Hello Surface' );
     552        $manager->save_changeset_post( array( 'status' => 'auto-draft' ) );
     553
     554        $manager->set_post_value( 'blogname', 'Hello World' );
     555        $manager->save_changeset_post( array( 'status' => 'draft' ) );
     556        $this->assertTrue( wp_revisions_enabled( get_post( $manager->changeset_post_id() ) ) );
     557
     558        $manager->set_post_value( 'blogname', 'Hello Solar System' );
     559        $manager->save_changeset_post( array( 'status' => 'draft' ) );
     560
     561        $manager->set_post_value( 'blogname', 'Hello Galaxy' );
     562        $manager->save_changeset_post( array( 'status' => 'draft' ) );
     563        $this->assertCount( 3, wp_get_post_revisions( $manager->changeset_post_id() ) );
     564    }
     565
     566    /**
     567     * Call count for customize_changeset_save_data filter.
     568     *
     569     * @var int
     570     */
     571    protected $customize_changeset_save_data_call_count = 0;
     572
     573    /**
     574     * Filter customize_changeset_save_data.
     575     *
     576     * @param array $data    Data.
     577     * @param array $context Context.
     578     * @returns array Data.
     579     */
     580    function filter_customize_changeset_save_data( $data, $context ) {
     581        $this->customize_changeset_save_data_call_count += 1;
     582        $this->assertInternalType( 'array', $data );
     583        $this->assertInternalType( 'array', $context );
     584        $this->assertArrayHasKey( 'uuid', $context );
     585        $this->assertArrayHasKey( 'title', $context );
     586        $this->assertArrayHasKey( 'status', $context );
     587        $this->assertArrayHasKey( 'date_gmt', $context );
     588        $this->assertArrayHasKey( 'post_id', $context );
     589        $this->assertArrayHasKey( 'previous_data', $context );
     590        $this->assertArrayHasKey( 'manager', $context );
     591        return $data;
     592    }
     593
     594    /**
     595     * Return illegal error.
     596     *
     597     * @return WP_Error Error.
     598     */
     599    function return_illegal_error() {
     600        return new WP_Error( 'illegal' );
     601    }
     602
     603    /**
     604     * Test WP_Customize_Manager::save_changeset_post().
     605     *
     606     * @ticket 30937
     607     * @covers WP_Customize_Manager::save_changeset_post()
     608     * @covers WP_Customize_Manager::update_stashed_theme_mod_settings()
     609     */
     610    function test_save_changeset_post_with_theme_activation() {
     611        wp_set_current_user( self::$admin_user_id );
     612
     613        $stashed_theme_mods = array(
     614            'twentyfifteen' => array(
     615                'background_color' => array(
     616                    'value' => '#123456',
     617                ),
     618            ),
     619        );
     620        update_option( 'customize_stashed_theme_mods', $stashed_theme_mods );
     621        $uuid = wp_generate_uuid4();
     622        $manager = new WP_Customize_Manager( array(
     623            'changeset_uuid' => $uuid,
     624            'theme' => 'twentyfifteen',
     625        ) );
     626        $manager->register_controls();
     627        $GLOBALS['wp_customize'] = $manager;
     628
     629        $manager->set_post_value( 'blogname', 'Hello 2015' );
     630        $post_values = $manager->unsanitized_post_values();
     631        $manager->save_changeset_post( array( 'status' => 'publish' ) ); // Activate.
     632
     633        $this->assertEquals( '#123456', $post_values['background_color'] );
     634        $this->assertEquals( 'twentyfifteen', get_stylesheet() );
     635        $this->assertEquals( 'Hello 2015', get_option( 'blogname' ) );
     636    }
     637
     638    /**
     639     * Test WP_Customize_Manager::is_cross_domain().
     640     *
     641     * @ticket 30937
     642     * @covers WP_Customize_Manager::is_cross_domain()
     643     */
     644    function test_is_cross_domain() {
     645        $wp_customize = new WP_Customize_Manager();
     646
     647        update_option( 'home', 'http://example.com' );
     648        update_option( 'siteurl', 'http://example.com' );
     649        $this->assertFalse( $wp_customize->is_cross_domain() );
     650
     651        update_option( 'home', 'http://example.com' );
     652        update_option( 'siteurl', 'https://admin.example.com' );
     653        $this->assertTrue( $wp_customize->is_cross_domain() );
     654    }
     655
     656    /**
     657     * Test WP_Customize_Manager::get_allowed_urls().
     658     *
     659     * @ticket 30937
     660     * @covers WP_Customize_Manager::get_allowed_urls()
     661     */
     662    function test_get_allowed_urls() {
     663        $wp_customize = new WP_Customize_Manager();
     664        $this->assertFalse( is_ssl() );
     665        $this->assertFalse( $wp_customize->is_cross_domain() );
     666        $allowed = $wp_customize->get_allowed_urls();
     667        $this->assertEquals( $allowed, array( home_url( '/', 'http' ) ) );
     668
     669        add_filter( 'customize_allowed_urls', array( $this, 'filter_customize_allowed_urls' ) );
     670        $allowed = $wp_customize->get_allowed_urls();
     671        $this->assertEqualSets( $allowed, array( 'http://headless.example.com/', home_url( '/', 'http' ) ) );
     672    }
     673
     674    /**
     675     * Callback for customize_allowed_urls filter.
     676     *
     677     * @param array $urls URLs.
     678     * @return array URLs.
     679     */
     680    function filter_customize_allowed_urls( $urls ) {
     681        $urls[] = 'http://headless.example.com/';
     682        return $urls;
    56683    }
    57684
     
    91718     * @ticket 30988
    92719     */
    93     function test_unsanitized_post_values() {
     720    function test_unsanitized_post_values_from_input() {
     721        wp_set_current_user( self::$admin_user_id );
    94722        $manager = $this->manager;
    95723
     
    101729        $post_values = $manager->unsanitized_post_values();
    102730        $this->assertEquals( $customized, $post_values );
     731        $this->assertEmpty( $manager->unsanitized_post_values( array( 'exclude_post_data' => true ) ) );
     732
     733        $manager->set_post_value( 'foo', 'BAR' );
     734        $post_values = $manager->unsanitized_post_values();
     735        $this->assertEquals( 'BAR', $post_values['foo'] );
     736        $this->assertEmpty( $manager->unsanitized_post_values( array( 'exclude_post_data' => true ) ) );
     737
     738        // If user is unprivileged, the post data is ignored.
     739        wp_set_current_user( 0 );
     740        $this->assertEmpty( $manager->unsanitized_post_values() );
     741    }
     742
     743    /**
     744     * Test WP_Customize_Manager::unsanitized_post_values().
     745     *
     746     * @ticket 30937
     747     * @covers WP_Customize_Manager::unsanitized_post_values()
     748     */
     749    function test_unsanitized_post_values_with_changeset_and_stashed_theme_mods() {
     750        wp_set_current_user( self::$admin_user_id );
     751
     752        $stashed_theme_mods = array(
     753            'twentyfifteen' => array(
     754                'background_color' => array(
     755                    'value' => '#000000',
     756                ),
     757            ),
     758        );
     759        $stashed_theme_mods[ get_stylesheet() ] = array(
     760            'background_color' => array(
     761                'value' => '#FFFFFF',
     762            ),
     763        );
     764        update_option( 'customize_stashed_theme_mods', $stashed_theme_mods );
     765
     766        $post_values = array(
     767            'blogdescription' => 'Post Input Tagline',
     768        );
     769        $_POST['customized'] = wp_slash( wp_json_encode( $post_values ) );
     770
     771        $uuid = wp_generate_uuid4();
     772        $changeset_data = array(
     773            'blogname' => array(
     774                'value' => 'Changeset Title',
     775            ),
     776            'blogdescription' => array(
     777                'value' => 'Changeset Tagline',
     778            ),
     779        );
     780        $this->factory()->post->create( array(
     781            'post_type' => 'customize_changeset',
     782            'post_status' => 'auto-draft',
     783            'post_name' => $uuid,
     784            'post_content' => wp_json_encode( $changeset_data ),
     785        ) );
     786
     787        $manager = new WP_Customize_Manager( array(
     788            'changeset_uuid' => $uuid,
     789        ) );
     790        $this->assertTrue( $manager->is_theme_active() );
     791
     792        $this->assertArrayNotHasKey( 'background_color', $manager->unsanitized_post_values() );
     793
     794        $this->assertEquals(
     795            array(
     796                'blogname' => 'Changeset Title',
     797                'blogdescription' => 'Post Input Tagline',
     798            ),
     799            $manager->unsanitized_post_values()
     800        );
     801        $this->assertEquals(
     802            array(
     803                'blogdescription' => 'Post Input Tagline',
     804            ),
     805            $manager->unsanitized_post_values( array( 'exclude_changeset' => true ) )
     806        );
     807
     808        $manager->set_post_value( 'blogdescription', 'Post Override Tagline' );
     809        $this->assertEquals(
     810            array(
     811                'blogname' => 'Changeset Title',
     812                'blogdescription' => 'Post Override Tagline',
     813            ),
     814            $manager->unsanitized_post_values()
     815        );
     816
     817        $this->assertEquals(
     818            array(
     819                'blogname' => 'Changeset Title',
     820                'blogdescription' => 'Changeset Tagline',
     821            ),
     822            $manager->unsanitized_post_values( array( 'exclude_post_data' => true ) )
     823        );
     824
     825        $this->assertEmpty( $manager->unsanitized_post_values( array( 'exclude_post_data' => true, 'exclude_changeset' => true ) ) );
     826
     827        // Test unstashing theme mods.
     828        $manager = new WP_Customize_Manager( array(
     829            'changeset_uuid' => $uuid,
     830            'theme' => 'twentyfifteen',
     831        ) );
     832        $this->assertFalse( $manager->is_theme_active() );
     833        $values = $manager->unsanitized_post_values( array( 'exclude_post_data' => true, 'exclude_changeset' => true ) );
     834        $this->assertNotEmpty( $values );
     835        $this->assertArrayHasKey( 'background_color', $values );
     836        $this->assertEquals( '#000000', $values['background_color'] );
     837
     838        $values = $manager->unsanitized_post_values( array( 'exclude_post_data' => false, 'exclude_changeset' => false ) );
     839        $this->assertArrayHasKey( 'background_color', $values );
     840        $this->assertArrayHasKey( 'blogname', $values );
     841        $this->assertArrayHasKey( 'blogdescription', $values );
    103842    }
    104843
     
    109848     */
    110849    function test_post_value() {
     850        wp_set_current_user( self::$admin_user_id );
    111851        $posted_settings = array(
    112852            'foo' => 'OOF',
     
    132872     */
    133873    function test_invalid_post_value() {
     874        wp_set_current_user( self::$admin_user_id );
    134875        $default_value = 'foo_default';
    135876        $setting = $this->manager->add_setting( 'foo', array(
     
    197938     */
    198939    function test_post_value_validation_sanitization_order() {
     940        wp_set_current_user( self::$admin_user_id );
    199941        $default_value = '0';
    200942        $setting = $this->manager->add_setting( 'numeric', array(
     
    241983     */
    242984    function test_validate_setting_values() {
     985        wp_set_current_user( self::$admin_user_id );
    243986        $setting = $this->manager->add_setting( 'foo', array(
    244987            'validate_callback' => array( $this, 'filter_customize_validate_foo' ),
     
    3061049
    3071050    /**
     1051     * Test WP_Customize_Manager::validate_setting_values().
     1052     *
     1053     * @ticket 30937
     1054     * @covers WP_Customize_Manager::validate_setting_values()
     1055     */
     1056    function test_validate_setting_values_args() {
     1057        wp_set_current_user( self::$admin_user_id );
     1058        $this->manager->register_controls();
     1059
     1060        $validities = $this->manager->validate_setting_values( array( 'unknown' => 'X' ) );
     1061        $this->assertEmpty( $validities );
     1062
     1063        $validities = $this->manager->validate_setting_values( array( 'unknown' => 'X' ), array( 'validate_existence' => false ) );
     1064        $this->assertEmpty( $validities );
     1065
     1066        $validities = $this->manager->validate_setting_values( array( 'unknown' => 'X' ), array( 'validate_existence' => true ) );
     1067        $this->assertNotEmpty( $validities );
     1068        $this->assertArrayHasKey( 'unknown', $validities );
     1069        $error = $validities['unknown'];
     1070        $this->assertInstanceOf( 'WP_Error', $error );
     1071        $this->assertEquals( 'unrecognized', $error->get_error_code() );
     1072
     1073        $this->manager->get_setting( 'blogname' )->capability = 'do_not_allow';
     1074        $validities = $this->manager->validate_setting_values( array( 'blogname' => 'X' ), array( 'validate_capability' => false ) );
     1075        $this->assertArrayHasKey( 'blogname', $validities );
     1076        $this->assertTrue( $validities['blogname'] );
     1077        $validities = $this->manager->validate_setting_values( array( 'blogname' => 'X' ), array( 'validate_capability' => true ) );
     1078        $this->assertArrayHasKey( 'blogname', $validities );
     1079        $error = $validities['blogname'];
     1080        $this->assertInstanceOf( 'WP_Error', $error );
     1081        $this->assertEquals( 'unauthorized', $error->get_error_code() );
     1082    }
     1083
     1084    /**
    3081085     * Add a length constraint to a setting.
    3091086     *
     
    3291106     */
    3301107    function test_validate_setting_values_validation_sanitization_order() {
     1108        wp_set_current_user( self::$admin_user_id );
    3311109        $setting = $this->manager->add_setting( 'numeric', array(
    3321110            'validate_callback' => array( $this, 'filter_customize_validate_numeric' ),
     
    3701148     */
    3711149    function test_set_post_value() {
     1150        wp_set_current_user( self::$admin_user_id );
    3721151        $this->manager->add_setting( 'foo', array(
    3731152            'sanitize_callback' => array( $this, 'sanitize_foo_for_test_set_post_value' ),
     
    4741253        $this->assertFalse( $this->manager->has_published_pages() );
    4751254
    476         wp_set_current_user( $this->factory()->user->create( array( 'role' => 'editor' ) ) );
     1255        wp_set_current_user( self::$admin_user_id );
    4771256        $this->manager->nav_menus->customize_register();
    4781257        $setting_id = 'nav_menus_created_posts';
     
    4931272     */
    4941273    function test_register_dynamic_settings() {
     1274        wp_set_current_user( self::$admin_user_id );
    4951275        $posted_settings = array(
    4961276            'foo' => 'OOF',
     
    5921372        $this->assertEquals( home_url( '/' ), $this->manager->get_return_url() );
    5931373
    594         wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
     1374        wp_set_current_user( self::$admin_user_id );
    5951375        $this->assertTrue( current_user_can( 'edit_theme_options' ) );
    5961376        $this->assertEquals( home_url( '/' ), $this->manager->get_return_url() );
     
    6851465     */
    6861466    function test_customize_pane_settings() {
    687         wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
     1467        wp_set_current_user( self::$admin_user_id );
    6881468        $this->manager->register_controls();
    6891469        $this->manager->prepare_controls();
     
    7071487        $this->assertNotEmpty( $data );
    7081488
    709         $this->assertEqualSets( array( 'theme', 'url', 'browser', 'panels', 'sections', 'nonce', 'autofocus', 'documentTitleTmpl', 'previewableDevices' ), array_keys( $data ) );
     1489        $this->assertEqualSets( array( 'theme', 'url', 'browser', 'panels', 'sections', 'nonce', 'autofocus', 'documentTitleTmpl', 'previewableDevices', 'changeset', 'timeouts' ), array_keys( $data ) );
    7101490        $this->assertEquals( $autofocus, $data['autofocus'] );
    7111491        $this->assertArrayHasKey( 'save', $data['nonce'] );
     
    7191499     */
    7201500    function test_customize_preview_settings() {
    721         wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
     1501        wp_set_current_user( self::$admin_user_id );
    7221502        $this->manager->register_controls();
    7231503        $this->manager->prepare_controls();
     
    7411521        $this->assertArrayHasKey( 'nonce', $settings );
    7421522        $this->assertArrayHasKey( '_dirty', $settings );
     1523        $this->assertArrayHasKey( 'timeouts', $settings );
     1524        $this->assertArrayHasKey( 'changeset', $settings );
    7431525
    7441526        $this->assertArrayHasKey( 'preview', $settings['nonce'] );
    745         $this->assertEquals( array( 'foo' ), $settings['_dirty'] );
    7461527    }
    7471528
     
    8151596        $manager->register_controls();
    8161597        $section_id = 'foo-section';
    817         wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
     1598        wp_set_current_user( self::$admin_user_id );
    8181599        $manager->add_section( $section_id, array(
    8191600            'title'      => 'Section',
     
    8461627    function test_add_section_return_instance() {
    8471628        $manager = new WP_Customize_Manager();
    848         wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
     1629        wp_set_current_user( self::$admin_user_id );
    8491630
    8501631        $section_id = 'foo-section';
     
    8731654    function test_add_setting_return_instance() {
    8741655        $manager = new WP_Customize_Manager();
    875         wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
     1656        wp_set_current_user( self::$admin_user_id );
    8761657
    8771658        $setting_id = 'foo-setting';
     
    9441725    function test_add_panel_return_instance() {
    9451726        $manager = new WP_Customize_Manager();
    946         wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
     1727        wp_set_current_user( self::$admin_user_id );
    9471728
    9481729        $panel_id = 'foo-panel';
     
    9711752        $manager = new WP_Customize_Manager();
    9721753        $section_id = 'foo-section';
    973         wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
     1754        wp_set_current_user( self::$admin_user_id );
    9741755        $manager->add_section( $section_id, array(
    9751756            'title'    => 'Section',
Note: See TracChangeset for help on using the changeset viewer.