', esc_html( static::encode_json( $setting_args['value'] ) ) );
echo '';
diff --git a/readme.md b/readme.md
index f79b64c4..46966301 100644
--- a/readme.md
+++ b/readme.md
@@ -17,8 +17,6 @@ Allow Customizer states to be drafted, and previewed with a private URL.
Customize Snapshots save the state of a Customizer session so it can be shared or even publish at a future date. A snapshot can be shared with a private URL to both authenticated and non authenticated users. This means anyone can preview a snapshot's settings on the front-end without loading the Customizer, and authenticated users can load the snapshot into the Customizer and publish or amend the settings at any time.
-Snapshots are saved with a `scope` of `full` or `dirty`, which tells the preview how to playback the settings stored in the snapshot. A `full` snapshot will playback all the settings during preview, while the `dirty` snapshot will only playback the ones that were marked `dirty` when the snapshot was taken.
-
Requires PHP 5.3+.
**Development of this plugin is done [on GitHub](https://github.com/xwp/wp-customize-snapshots). Pull requests welcome. Please see [issues](https://github.com/xwp/wp-customize-snapshots) reported there before going to the [plugin forum](https://wordpress.org/support/plugin/customize-snapshots).**
@@ -27,6 +25,7 @@ Requires PHP 5.3+.
### 0.4.0 ###
* Update the UX by removing most modal dialogs and the need to set the snapshot scope.
+* Eliminate the storage of non-dirty settings in a Snapshot, which eliminates the `scope` feature.
* Ensure that widget actions and filters get added when previewing snapshots on the front-end.
* Use `wp_slash()` instead of `add_magic_quotes()` when loading the snapshot post vars.
* Update `dev-lib`.
diff --git a/readme.txt b/readme.txt
index 97e608d0..de0a9440 100644
--- a/readme.txt
+++ b/readme.txt
@@ -13,8 +13,6 @@ Allow Customizer states to be drafted, and previewed with a private URL.
Customize Snapshots save the state of a Customizer session so it can be shared or even publish at a future date. A snapshot can be shared with a private URL to both authenticated and non authenticated users. This means anyone can preview a snapshot's settings on the front-end without loading the Customizer, and authenticated users can load the snapshot into the Customizer and publish or amend the settings at any time.
-Snapshots are saved with a `scope` of `full` or `dirty`, which tells the preview how to playback the settings stored in the snapshot. A `full` snapshot will playback all the settings during preview, while the `dirty` snapshot will only playback the ones that were marked `dirty` when the snapshot was taken.
-
Requires PHP 5.3+.
**Development of this plugin is done [on GitHub](https://github.com/xwp/wp-customize-snapshots). Pull requests welcome. Please see [issues](https://github.com/xwp/wp-customize-snapshots) reported there before going to the [plugin forum](https://wordpress.org/support/plugin/customize-snapshots).**
@@ -23,6 +21,7 @@ Requires PHP 5.3+.
= 0.4.0 =
* Update the UX by removing most modal dialogs and the need to set the snapshot scope.
+* Eliminate the storage of non-dirty settings in a Snapshot, which eliminates the `scope` feature.
* Ensure that widget actions and filters get added when previewing snapshots on the front-end.
* Use `wp_slash()` instead of `add_magic_quotes()` when loading the snapshot post vars.
* Update `dev-lib`.
From d61af4d84722f6f4715a1a99a03838c9aca09614 Mon Sep 17 00:00:00 2001
From: Derek Herman
Date: Fri, 10 Jun 2016 20:55:17 -0700
Subject: [PATCH 47/69] Add coverage for
Customize_Snapshot_Manager::filter_post_row_actions()
---
php/class-customize-snapshot-manager.php | 14 ++--
.../test-class-customize-snapshot-manager.php | 70 +++++++++++++++++++
2 files changed, 77 insertions(+), 7 deletions(-)
diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php
index 10ef2455..9f600470 100644
--- a/php/class-customize-snapshot-manager.php
+++ b/php/class-customize-snapshot-manager.php
@@ -292,7 +292,7 @@ public function create_post_type() {
* @param array $actions Actions.
* @return array Actions.
*/
- function filter_bulk_actions( $actions ) {
+ public function filter_bulk_actions( $actions ) {
unset( $actions['edit'] );
return $actions;
}
@@ -304,7 +304,7 @@ function filter_bulk_actions( $actions ) {
* @param \WP_Post $post Post.
* @return array Actions.
*/
- function filter_post_row_actions( $actions, $post ) {
+ public function filter_post_row_actions( $actions, $post ) {
if ( self::POST_TYPE !== $post->post_type ) {
return $actions;
}
@@ -337,7 +337,7 @@ function filter_post_row_actions( $actions, $post ) {
/**
* Add the metabox.
*/
- function setup_metaboxes() {
+ public function setup_metaboxes() {
$id = self::POST_TYPE;
$title = __( 'Data', 'customize-snapshots' );
$callback = array( $this, 'render_data_metabox' );
@@ -350,7 +350,7 @@ function setup_metaboxes() {
/**
* Remove publish metabox for published posts, since they should be immutable once published.
*/
- function remove_publish_metabox() {
+ public function remove_publish_metabox() {
remove_meta_box( 'slugdiv', self::POST_TYPE, 'normal' );
remove_meta_box( 'submitdiv', self::POST_TYPE, 'side' );
remove_meta_box( 'authordiv', self::POST_TYPE, 'normal' );
@@ -361,7 +361,7 @@ function remove_publish_metabox() {
*
* @param \WP_Post $post Post object.
*/
- function render_data_metabox( $post ) {
+ public function render_data_metabox( $post ) {
$snapshot_content = static::get_post_content( $post );
$post_status_obj = get_post_status_object( $post->post_status );
@@ -408,7 +408,7 @@ function render_data_metabox( $post ) {
* @param \WP_Post $post A customize_snapshot post or a revision post.
* @return array
*/
- static function get_post_content( \WP_Post $post ) {
+ static public function get_post_content( \WP_Post $post ) {
if ( self::POST_TYPE !== $post->post_type ) {
$parent_post = null;
if ( 'revision' === $post->post_type ) {
@@ -434,7 +434,7 @@ static function get_post_content( \WP_Post $post ) {
* @param array $value The snapshot value.
* @return string
*/
- static function encode_json( $value ) {
+ static public function encode_json( $value ) {
$flags = 0;
if ( defined( '\JSON_PRETTY_PRINT' ) ) {
$flags |= \JSON_PRETTY_PRINT;
diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php
index df0b499d..61c74da7 100644
--- a/tests/php/test-class-customize-snapshot-manager.php
+++ b/tests/php/test-class-customize-snapshot-manager.php
@@ -176,6 +176,76 @@ function test_filter_bulk_actions() {
$this->assertEquals( array(), $this->manager->filter_bulk_actions( array( 'edit' => 'link markup' ) ) );
}
+ /**
+ * @see Customize_Snapshot_Manager::filter_post_row_actions()
+ */
+ function test_filter_post_row_actions_return() {
+ $manager = new Customize_Snapshot_Manager( $this->plugin );
+ $actions = array( 'inline hide-if-no-js' );
+ $args = array(
+ 'post_title' => 'Some Title',
+ 'post_status' => 'publish',
+ );
+ $post = get_post( self::factory()->post->create( $args ) );
+ $filtered = $manager->filter_post_row_actions( $actions, $post );
+
+ $this->assertEquals( $actions, $filtered );
+ }
+
+ /**
+ * @see Customize_Snapshot_Manager::filter_post_row_actions()
+ */
+ function test_filter_post_row_actions_draft() {
+ wp_set_current_user( $this->user_id );
+ $this->do_customize_boot_actions( true );
+ $_POST = array(
+ 'nonce' => wp_create_nonce( 'save-customize_' . $this->wp_customize->get_stylesheet() ),
+ 'snapshot_uuid' => self::UUID,
+ 'snapshot_customized' => '{"foo":{"value":"foo_default","dirty":true},"bar":{"value":"bar_default","dirty":true}}',
+ );
+
+ $manager = new Customize_Snapshot_Manager( $this->plugin );
+ $manager->capture_unsanitized_snapshot_post_data();
+ $foo = $manager->customize_manager->get_setting( 'foo' );
+ $manager->snapshot()->set( $foo, 'foo_custom', true );
+ $manager->snapshot()->save();
+ $actions = array(
+ 'inline hide-if-no-js' => true,
+ );
+ $post = $manager->snapshot()->post();
+ $filtered = $manager->filter_post_row_actions( $actions, $post );
+ $extected = array(
+ 'customize' => 'Customize',
+ );
+ $this->assertEquals( $extected, $filtered );
+ }
+
+ /**
+ * @see Customize_Snapshot_Manager::filter_post_row_actions()
+ */
+ function test_filter_post_row_actions_publish() {
+ wp_set_current_user( $this->user_id );
+ $this->do_customize_boot_actions( true );
+ $_POST = array(
+ 'nonce' => wp_create_nonce( 'save-customize_' . $this->wp_customize->get_stylesheet() ),
+ 'snapshot_uuid' => self::UUID,
+ 'snapshot_customized' => '{"foo":{"value":"foo_default","dirty":true},"bar":{"value":"bar_default","dirty":true}}',
+ );
+ $manager = new Customize_Snapshot_Manager( $this->plugin );
+ $manager->set_snapshot_uuid();
+ $manager->save_snapshot();
+ $actions = array(
+ 'inline hide-if-no-js' => true,
+ 'edit' => '',
+ );
+ $post = $manager->snapshot()->post();
+ $filtered = $manager->filter_post_row_actions( $actions, $post );
+ $extected = array(
+ 'edit' => 'View',
+ );
+ $this->assertEquals( $extected, $filtered );
+ }
+
/**
* @see Customize_Snapshot_Manager::enqueue_scripts()
*/
From 74011ecfbcf3b659f41a33e5437e78f3de14f3e0 Mon Sep 17 00:00:00 2001
From: Derek Herman
Date: Fri, 10 Jun 2016 21:21:16 -0700
Subject: [PATCH 48/69] Add coverage for
Customize_Snapshot_Manager::setup_metaboxes()
---
php/class-customize-snapshot-manager.php | 2 ++
.../test-class-customize-snapshot-manager.php | 32 ++++++++-----------
2 files changed, 16 insertions(+), 18 deletions(-)
diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php
index 9f600470..8cf2fe88 100644
--- a/php/class-customize-snapshot-manager.php
+++ b/php/class-customize-snapshot-manager.php
@@ -349,6 +349,8 @@ public function setup_metaboxes() {
/**
* Remove publish metabox for published posts, since they should be immutable once published.
+ *
+ * @codeCoverageIgnore
*/
public function remove_publish_metabox() {
remove_meta_box( 'slugdiv', self::POST_TYPE, 'normal' );
diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php
index 61c74da7..edb95f00 100644
--- a/tests/php/test-class-customize-snapshot-manager.php
+++ b/tests/php/test-class-customize-snapshot-manager.php
@@ -74,6 +74,7 @@ function tearDown() {
unset( $GLOBALS['wp_customize'] );
unset( $GLOBALS['wp_scripts'] );
unset( $_REQUEST['customize_snapshot_uuid'] );
+ unset( $GLOBALS['screen'] );
parent::tearDown();
}
@@ -246,6 +247,17 @@ function test_filter_post_row_actions_publish() {
$this->assertEquals( $extected, $filtered );
}
+ /**
+ * @see Customize_Snapshot_Manager::setup_metaboxes()
+ */
+ function test_setup_metaboxes() {
+ global $wp_meta_boxes;
+ $screen = Customize_Snapshot_Manager::POST_TYPE;
+ set_current_screen( $screen );
+ $this->manager->setup_metaboxes();
+ $this->assertArrayHasKey( $screen, $wp_meta_boxes[ $screen ]['normal']['high'] );
+ }
+
/**
* @see Customize_Snapshot_Manager::enqueue_scripts()
*/
@@ -319,7 +331,8 @@ function test_save_snapshot() {
/**
* @see Customize_Snapshot_Manager::customize_menu()
*/
- public function test_customize_menu_dirty() {
+ public function test_customize_menu() {
+ set_current_screen( 'front' );
$customize_url = admin_url( 'customize.php' ) . '?customize_snapshot_uuid=' . self::UUID . '&url=' . urlencode( esc_url( home_url( '/' ) ) );
require_once( ABSPATH . WPINC . '/class-wp-admin-bar.php' );
@@ -332,23 +345,6 @@ public function test_customize_menu_dirty() {
do_action_ref_array( 'admin_bar_menu', array( &$wp_admin_bar ) );
$this->assertEquals( $customize_url, $wp_admin_bar->get_node( 'customize' )->href );
}
-
- /**
- * @see Customize_Snapshot_Manager::customize_menu()
- */
- public function test_customize_menu_full() {
- $customize_url = admin_url( 'customize.php' ) . '?customize_snapshot_uuid=' . self::UUID . '&url=' . urlencode( esc_url( home_url( '/' ) ) );
-
- require_once( ABSPATH . WPINC . '/class-wp-admin-bar.php' );
- $wp_admin_bar = new \WP_Admin_Bar;
- $this->assertInstanceOf( 'WP_Admin_Bar', $wp_admin_bar );
-
- wp_set_current_user( $this->user_id );
- $this->go_to( home_url( '?customize_snapshot_uuid=' . self::UUID ) );
-
- do_action_ref_array( 'admin_bar_menu', array( &$wp_admin_bar ) );
- $this->assertEquals( $customize_url, $wp_admin_bar->get_node( 'customize' )->href );
- }
/**
* @see Customize_Snapshot_Manager::customize_menu()
From aef8101d5fb2f71694a383f5e2b2bc28cc09ed14 Mon Sep 17 00:00:00 2001
From: Derek Herman
Date: Fri, 10 Jun 2016 21:40:51 -0700
Subject: [PATCH 49/69] Add coverage for
Customize_Snapshot_Manager::encode_json()
---
.../test-class-customize-snapshot-manager.php | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php
index edb95f00..f81cf092 100644
--- a/tests/php/test-class-customize-snapshot-manager.php
+++ b/tests/php/test-class-customize-snapshot-manager.php
@@ -258,6 +258,27 @@ function test_setup_metaboxes() {
$this->assertArrayHasKey( $screen, $wp_meta_boxes[ $screen ]['normal']['high'] );
}
+ /**
+ * @see Customize_Snapshot_Manager::encode_json()
+ */
+ function test_encode_json() {
+ $array = array(
+ 'foo' => array(
+ 'value' => 'foo_value',
+ 'dirty' => true,
+ 'sanitized' => false,
+ ),
+ );
+ $json = '{
+ "foo": {
+ "value": "foo_value",
+ "dirty": true,
+ "sanitized": false
+ }
+}';
+ $this->assertEquals( $json, Customize_Snapshot_Manager::encode_json( $array ) );
+ }
+
/**
* @see Customize_Snapshot_Manager::enqueue_scripts()
*/
From e3d626ff4be30db8db1b7bd835b2929348797d82 Mon Sep 17 00:00:00 2001
From: Derek Herman
Date: Fri, 10 Jun 2016 22:33:37 -0700
Subject: [PATCH 50/69] Add coverage for
Customize_Snapshot_Manager::get_post_content()
---
.../test-class-customize-snapshot-manager.php | 43 +++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php
index f81cf092..437ec66a 100644
--- a/tests/php/test-class-customize-snapshot-manager.php
+++ b/tests/php/test-class-customize-snapshot-manager.php
@@ -258,6 +258,49 @@ function test_setup_metaboxes() {
$this->assertArrayHasKey( $screen, $wp_meta_boxes[ $screen ]['normal']['high'] );
}
+ /**
+ * @see Customize_Snapshot_Manager::get_post_content()
+ */
+ function test_get_post_content() {
+ wp_set_current_user( $this->user_id );
+ $this->do_customize_boot_actions( true );
+ $snapshot_json = '{"foo":{"value":"foo_value","dirty":true,"sanitized":false}}';
+ $_POST = array(
+ 'nonce' => wp_create_nonce( 'save-customize_' . $this->wp_customize->get_stylesheet() ),
+ 'snapshot_uuid' => self::UUID,
+ 'snapshot_customized' => $snapshot_json,
+ );
+ $manager = new Customize_Snapshot_Manager( $this->plugin );
+ $manager->capture_unsanitized_snapshot_post_data();
+ $foo = $manager->customize_manager->get_setting( 'foo' );
+ $manager->snapshot()->set( $foo, 'foo_value', true );
+ $manager->snapshot()->save();
+ $post = $manager->snapshot()->post();
+ $snapshot_content = Customize_Snapshot_Manager::get_post_content( $post );
+ $this->assertEquals( json_decode( $snapshot_json, true ), $snapshot_content );
+
+ // Get the revision post.
+ $manager->snapshot()->set( $foo, 'foo_revision_value', true );
+ $manager->snapshot()->save();
+ $revisions = wp_get_post_revisions( $post->ID );
+ $revision = array_shift( $revisions );
+ $revision_content = Customize_Snapshot_Manager::get_post_content( $revision );
+ $this->assertEquals( 'foo_revision_value', $revision_content['foo']['value'] );
+ }
+
+ /**
+ * @see Customize_Snapshot_Manager::get_post_content()
+ */
+ function test_get_post_content_empty() {
+ $args = array(
+ 'post_name' => self::UUID,
+ 'post_type' => Customize_Snapshot_Manager::POST_TYPE,
+ );
+ $post = get_post( self::factory()->post->create( $args ) );
+ $snapshot_content = Customize_Snapshot_Manager::get_post_content( $post );
+ $this->assertEquals( array(), $snapshot_content );
+ }
+
/**
* @see Customize_Snapshot_Manager::encode_json()
*/
From fe7fbe3ddb56316b610c0ab6d533d5124a079cd4 Mon Sep 17 00:00:00 2001
From: Derek Herman
Date: Sat, 11 Jun 2016 01:05:12 -0700
Subject: [PATCH 51/69] Fix Customize_Snapshot_Manager::encode_json() for PHP
5.3
---
tests/php/test-class-customize-snapshot-manager.php | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php
index 437ec66a..a938210d 100644
--- a/tests/php/test-class-customize-snapshot-manager.php
+++ b/tests/php/test-class-customize-snapshot-manager.php
@@ -312,14 +312,8 @@ function test_encode_json() {
'sanitized' => false,
),
);
- $json = '{
- "foo": {
- "value": "foo_value",
- "dirty": true,
- "sanitized": false
- }
-}';
- $this->assertEquals( $json, Customize_Snapshot_Manager::encode_json( $array ) );
+ $json = '{"foo":{"value":"foo_value","dirty":true,"sanitized":false}}';
+ $this->assertEquals( $json, preg_replace( '/\s+/', '', Customize_Snapshot_Manager::encode_json( $array ) ) );
}
/**
From 0cd511188b67757d99830536ecd9bcb8a1644c7a Mon Sep 17 00:00:00 2001
From: Derek Herman
Date: Sat, 11 Jun 2016 02:16:55 -0700
Subject: [PATCH 52/69] Add coverage for
Customize_Snapshot_Manager::render_data_metabox()
---
.../test-class-customize-snapshot-manager.php | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php
index a938210d..4a0375eb 100644
--- a/tests/php/test-class-customize-snapshot-manager.php
+++ b/tests/php/test-class-customize-snapshot-manager.php
@@ -258,6 +258,32 @@ function test_setup_metaboxes() {
$this->assertArrayHasKey( $screen, $wp_meta_boxes[ $screen ]['normal']['high'] );
}
+ /**
+ * @see Customize_Snapshot_Manager::render_data_metabox()
+ */
+ function test_render_data_metabox() {
+ wp_set_current_user( $this->user_id );
+ $this->do_customize_boot_actions( true );
+ $snapshot_json = '{"foo":{"value":"foo_value","dirty":true,"sanitized":false}}';
+ $_POST = array(
+ 'nonce' => wp_create_nonce( 'save-customize_' . $this->wp_customize->get_stylesheet() ),
+ 'snapshot_uuid' => self::UUID,
+ 'snapshot_customized' => $snapshot_json,
+ );
+ $manager = new Customize_Snapshot_Manager( $this->plugin );
+ $manager->capture_unsanitized_snapshot_post_data();
+ $foo = $manager->customize_manager->get_setting( 'foo' );
+ $manager->snapshot()->set( $foo, 'foo_value', true );
+ $manager->snapshot()->save();
+ $post = $manager->snapshot()->post();
+ ob_start();
+ $manager->render_data_metabox( $post );
+ $metabox = ob_get_clean();
+ $this->assertContains( $post->post_name, $metabox );
+ $this->assertContains( 'Edit in Customizer', $metabox );
+ $this->assertContains( 'foo_value', $metabox );
+ }
+
/**
* @see Customize_Snapshot_Manager::get_post_content()
*/
From 0ab440819ea2c0c6c3ce3f589049c4de5587c44d Mon Sep 17 00:00:00 2001
From: Derek Herman
Date: Sat, 11 Jun 2016 02:17:44 -0700
Subject: [PATCH 53/69] Add coverage for
Customize_Snapshot_Manager::get_snapshot_uuid()
---
...-class-ajax-customize-snapshot-manager.php | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/tests/php/test-class-ajax-customize-snapshot-manager.php b/tests/php/test-class-ajax-customize-snapshot-manager.php
index e39089da..05f530e3 100644
--- a/tests/php/test-class-ajax-customize-snapshot-manager.php
+++ b/tests/php/test-class-ajax-customize-snapshot-manager.php
@@ -339,4 +339,41 @@ function test_ajax_save_snapshot_post_data_check() {
$this->assertEquals( array( 'missing_snapshot_customized' => 'The Snapshots customized data was missing from the request.' ), $response );
}
+ /**
+ * Nonce check for the get_snapshot_uuid method
+ */
+ function test_ajax_get_snapshot_uuid_nonce_check() {
+ $_POST = array(
+ 'action' => Customize_Snapshot_Manager::AJAX_ACTION,
+ 'nonce' => 'bad-nonce-12345',
+ );
+
+ $this->make_ajax_call( 'customize_get_snapshot_uuid' );
+
+ // Get the results.
+ $response = json_decode( $this->_last_response, true );
+ $expected_results = array(
+ 'success' => false,
+ 'data' => 'bad_nonce',
+ );
+
+ $this->assertSame( $expected_results, $response );
+ }
+
+ /**
+ * Successful reponse from the update_snapshot method
+ */
+ function test_ajax_get_snapshot_uuid_success() {
+ $_POST = array(
+ 'action' => Customize_Snapshot_Manager::AJAX_ACTION,
+ 'nonce' => wp_create_nonce( Customize_Snapshot_Manager::AJAX_ACTION ),
+ );
+
+ $this->make_ajax_call( 'customize_get_snapshot_uuid' );
+
+ // Get the results.
+ $response = json_decode( $this->_last_response, true );
+
+ $this->assertNotEmpty( $response['data']['uuid'] );
+ }
}
From 164815c488b1fe10298a2c401e9e41ed68d5c625 Mon Sep 17 00:00:00 2001
From: Derek Herman
Date: Sat, 11 Jun 2016 03:21:38 -0700
Subject: [PATCH 54/69] Add coverage to Plugin_Base & fix
Plugin_Base::remove_doc_hooks
---
php/class-plugin-base.php | 42 +++++++++------
tests/php/test-class-plugin-base.php | 78 ++++++++++++++++++++++++++++
2 files changed, 103 insertions(+), 17 deletions(-)
diff --git a/php/class-plugin-base.php b/php/class-plugin-base.php
index cb9ff481..2d1618e7 100644
--- a/php/class-plugin-base.php
+++ b/php/class-plugin-base.php
@@ -56,13 +56,6 @@ abstract class Plugin_Base {
*/
protected $autoload_matches_cache = array();
- /**
- * All DocBlock added hooks.
- *
- * @var array
- */
- protected $added_doc_hooks = array();
-
/**
* Required instead of a static variable inside the add_doc_hooks method
* for the sake of unit testing.
@@ -140,7 +133,7 @@ public function autoload( $class ) {
* Version of plugin_dir_url() which works for plugins installed in the plugins directory,
* and for plugins bundled with themes.
*
- * @throws \Exception If the plugin is not located in the expected location.
+ * @throws Exception If the plugin is not located in the expected location.
* @return array
*/
public function locate_plugin() {
@@ -150,13 +143,13 @@ public function locate_plugin() {
}
$plugin_dir = preg_replace( '#(.*plugins[^/]*/[^/]+)(/.*)?#', '$1', $file_name, 1, $count );
if ( 0 === $count ) {
- throw new \Exception( "Class not located within a directory tree containing 'plugins': $file_name" );
+ throw new Exception( "Class not located within a directory tree containing 'plugins': $file_name" );
}
// Make sure that we can reliably get the relative path inside of the content directory.
$plugin_path = $this->relative_path( $plugin_dir, 'wp-content', \DIRECTORY_SEPARATOR );
if ( '' === $plugin_path ) {
- throw new \Exception( 'Plugin dir is not inside of the `wp-content` directory' );
+ throw new Exception( 'Plugin dir is not inside of the `wp-content` directory' );
}
$dir_url = content_url( trailingslashit( $plugin_path ) );
@@ -251,7 +244,6 @@ protected function _add_hook( $type, $name, $callback, $args = array() ) {
$arg_count = isset( $args['arg_count'] ) ? $args['arg_count'] : PHP_INT_MAX;
$fn = sprintf( '\add_%s', $type );
$retval = \call_user_func( $fn, $name, $callback, $priority, $arg_count );
- $this->added_doc_hooks[] = compact( 'type', 'name', 'callback', 'priority' );
return $retval;
}
@@ -268,7 +260,7 @@ public function add_doc_hooks( $object = null ) {
if ( isset( $this->_called_doc_hooks[ $class_name ] ) ) {
$notice = sprintf( 'The add_doc_hooks method was already called on %s. Note that the Plugin_Base constructor automatically calls this method.', $class_name );
if ( ! $this->is_wpcom_vip_prod() ) {
- trigger_error( esc_html( $notice ), E_USER_NOTICE );
+ trigger_error( esc_html( $notice ), \E_USER_NOTICE );
}
return;
}
@@ -292,12 +284,28 @@ public function add_doc_hooks( $object = null ) {
/**
* Removes the added DocBlock hooks.
+ *
+ * @param object $object The class object.
*/
- public function remove_doc_hooks() {
- foreach ( $this->added_doc_hooks as $added_hook ) {
- $fn = sprintf( 'remove_%s', $added_hook['type'] );
- call_user_func( $fn, $added_hook['name'], $added_hook['callback'], $added_hook['priority'] );
+ public function remove_doc_hooks( $object = null ) {
+ if ( is_null( $object ) ) {
+ $object = $this;
+ }
+ $class_name = get_class( $object );
+
+ $reflector = new \ReflectionObject( $object );
+ foreach ( $reflector->getMethods() as $method ) {
+ $doc = $method->getDocComment();
+ if ( preg_match_all( '#\* @(?Pfilter|action)\s+(?P[a-z0-9\-\._]+)(?:,\s+(?P\d+))?#', $doc, $matches, PREG_SET_ORDER ) ) {
+ foreach ( $matches as $match ) {
+ $type = $match['type'];
+ $name = $match['name'];
+ $priority = empty( $match['priority'] ) ? 10 : intval( $match['priority'] );
+ $callback = array( $object, $method->getName() );
+ call_user_func( "remove_{$type}", $name, $callback, $priority );
+ }
+ }
}
- $this->_called_doc_hooks = array();
+ unset( $this->_called_doc_hooks[ $class_name ] );
}
}
diff --git a/tests/php/test-class-plugin-base.php b/tests/php/test-class-plugin-base.php
index 9ab59f3c..4332e4d9 100644
--- a/tests/php/test-class-plugin-base.php
+++ b/tests/php/test-class-plugin-base.php
@@ -9,6 +9,7 @@
/**
* Tests for Plugin_Base.
+ * @group plugin
*/
class Test_Plugin_Base extends \WP_UnitTestCase {
@@ -78,4 +79,81 @@ public function test_is_wpcom_vip_prod() {
}
$this->assertEquals( WPCOM_IS_VIP_ENV, $this->plugin->is_wpcom_vip_prod() );
}
+
+ /**
+ * Test add_doc_hooks().
+ *
+ * @see Plugin_Base::add_doc_hooks()
+ */
+ public function test_add_doc_hooks() {
+ $object = new Test_Doc_hooks();
+ $this->assertFalse( has_action( 'init', array( $object, 'init_action' ) ) );
+ $this->assertFalse( has_action( 'the_content', array( $object, 'the_content_filter' ) ) );
+ $this->plugin->add_doc_hooks( $object );
+ $this->assertEquals( 10, has_action( 'init', array( $object, 'init_action' ) ) );
+ $this->assertEquals( 10, has_action( 'the_content', array( $object, 'the_content_filter' ) ) );
+ $this->plugin->remove_doc_hooks( $object );
+ }
+
+ /**
+ * Test add_doc_hooks().
+ *
+ * @see Plugin_Base::add_doc_hooks()
+ */
+ public function test_add_doc_hooks_error() {
+ $mock = $this->getMockBuilder( 'CustomizeSnapshots\Plugin' )
+ ->setMethods( [ 'is_wpcom_vip_prod' ] )
+ ->getMock();
+
+ $mock->method( 'is_wpcom_vip_prod' )
+ ->willReturn( false );
+
+ $this->assertFalse( $mock->is_wpcom_vip_prod() );
+
+ $obj = $this;
+ set_error_handler( function ( $errno, $errstr ) use ( $obj, $mock ) {
+ $obj->assertEquals( sprintf( 'The add_doc_hooks method was already called on %s. Note that the Plugin_Base constructor automatically calls this method.', get_class( $mock ) ), $errstr );
+ $obj->assertEquals( \E_USER_NOTICE, $errno );
+ } );
+ $mock->add_doc_hooks();
+ restore_error_handler();
+
+ $mock->remove_doc_hooks();
+ }
+
+ /**
+ * Test remove_doc_hooks().
+ *
+ * @see Plugin_Base::remove_doc_hooks()
+ */
+ public function test_remove_doc_hooks() {
+ $object = new Test_Doc_hooks();
+ $this->plugin->add_doc_hooks( $object );
+ $this->assertEquals( 10, has_action( 'init', array( $object, 'init_action' ) ) );
+ $this->assertEquals( 10, has_action( 'the_content', array( $object, 'the_content_filter' ) ) );
+ $this->plugin->remove_doc_hooks( $object );
+ $this->assertFalse( has_action( 'init', array( $object, 'init_action' ) ) );
+ $this->assertFalse( has_action( 'the_content', array( $object, 'the_content_filter' ) ) );
+ }
+}
+
+class Test_Doc_hooks {
+
+ /**
+ * Load this on the init action hook.
+ *
+ * @action init
+ */
+ public function init_action() {
+ // Do something.
+ }
+
+ /**
+ * Load this on the the_content filter hook.
+ *
+ * @filter the_content
+ */
+ public function the_content_filter( $content ) {
+ // Do something.
+ }
}
From f462605d29c15d78bd2fa98fa29311b50911d552 Mon Sep 17 00:00:00 2001
From: Derek Herman
Date: Sat, 11 Jun 2016 03:24:40 -0700
Subject: [PATCH 55/69] Make tests PHP 5.3 compatible
---
tests/php/test-class-plugin-base.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/php/test-class-plugin-base.php b/tests/php/test-class-plugin-base.php
index 4332e4d9..1f671603 100644
--- a/tests/php/test-class-plugin-base.php
+++ b/tests/php/test-class-plugin-base.php
@@ -102,7 +102,7 @@ public function test_add_doc_hooks() {
*/
public function test_add_doc_hooks_error() {
$mock = $this->getMockBuilder( 'CustomizeSnapshots\Plugin' )
- ->setMethods( [ 'is_wpcom_vip_prod' ] )
+ ->setMethods( array( 'is_wpcom_vip_prod' ) )
->getMock();
$mock->method( 'is_wpcom_vip_prod' )
From aa7497267654fe43b9b2ad4eb745505f0f3edd66 Mon Sep 17 00:00:00 2001
From: Weston Ruter
Date: Sat, 11 Jun 2016 15:12:02 -0700
Subject: [PATCH 56/69] Show list of (dirty) settings in a snapshot excerpt
---
php/class-customize-snapshot-manager.php | 21 +++++++++++++++++++
.../test-class-customize-snapshot-manager.php | 21 +++++++++++++++++++
2 files changed, 42 insertions(+)
diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php
index 8cf2fe88..8555e645 100644
--- a/php/class-customize-snapshot-manager.php
+++ b/php/class-customize-snapshot-manager.php
@@ -284,6 +284,7 @@ public function create_post_type() {
add_action( 'add_meta_boxes_' . self::POST_TYPE, array( $this, 'remove_publish_metabox' ), 100 );
add_filter( 'wp_insert_post_data', array( $this, 'preserve_post_name_in_insert_data' ), 10, 2 );
add_filter( 'bulk_actions-edit-' . self::POST_TYPE, array( $this, 'filter_bulk_actions' ) );
+ add_filter( 'get_the_excerpt', array( $this, 'filter_snapshot_excerpt' ), 10, 2 );
}
/**
@@ -297,6 +298,26 @@ public function filter_bulk_actions( $actions ) {
return $actions;
}
+ /**
+ * Include the setting IDs in the excerpt.
+ *
+ * @param string $excerpt The post excerpt.
+ * @param \WP_Post $post Post object.
+ * @return string Excerpt.
+ */
+ public function filter_snapshot_excerpt( $excerpt, $post ) {
+ if ( self::POST_TYPE === $post->post_type ) {
+ $excerpt = '';
+ foreach ( static::get_post_content( $post ) as $setting_id => $setting_params ) {
+ if ( ! isset( $setting_params['dirty'] ) || true === $setting_params['dirty'] ) {
+ $excerpt .= sprintf( '
%s
', esc_attr( $setting_id ) );
+ }
+ }
+ $excerpt .= '';
+ }
+ return $excerpt;
+ }
+
/**
* Add Customize link to quick edit links.
*
diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php
index 4a0375eb..42b28e40 100644
--- a/tests/php/test-class-customize-snapshot-manager.php
+++ b/tests/php/test-class-customize-snapshot-manager.php
@@ -540,4 +540,25 @@ public function test_preview() {
$this->manager->preview();
$this->assertTrue( $foo->dirty );
}
+
+ /**
+ * @see Customize_Snapshot_Manager::filter_snapshot_excerpt()
+ */
+ public function test_excerpt() {
+ global $post;
+ wp_set_current_user( $this->user_id );
+ $this->manager->customize_manager = $this->wp_customize;
+ $this->manager->snapshot = new Customize_Snapshot( $this->manager, null );
+ $foo = $this->manager->customize_manager->get_setting( 'foo' );
+ $bar = $this->manager->customize_manager->get_setting( 'bar' );
+ $this->manager->snapshot()->set( $foo, 'foo_custom', true );
+ $this->manager->snapshot()->set( $bar, 'bar_custom', true );
+ $this->manager->snapshot()->save();
+
+ $post = $this->manager->snapshot()->post();
+ $excerpt = get_the_excerpt( $post );
+ $this->assertContains( '', $excerpt );
+ $this->assertContains( 'foo', $excerpt );
+ $this->assertContains( 'bar', $excerpt );
+ }
}
From 29f63177624b93d4c9373908590063fe0cf1e688 Mon Sep 17 00:00:00 2001
From: Weston Ruter
Date: Sat, 11 Jun 2016 15:12:16 -0700
Subject: [PATCH 57/69] Fix test_preview
---
tests/php/test-class-customize-snapshot-manager.php | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php
index 42b28e40..c80a68a9 100644
--- a/tests/php/test-class-customize-snapshot-manager.php
+++ b/tests/php/test-class-customize-snapshot-manager.php
@@ -532,6 +532,8 @@ public function test_set_post_values() {
*/
public function test_preview() {
wp_set_current_user( $this->user_id );
+ $this->manager->customize_manager = $this->wp_customize;
+ $this->manager->snapshot = new Customize_Snapshot( $this->manager, null );
$foo = $this->manager->customize_manager->get_setting( 'foo' );
$this->manager->snapshot()->set( $foo, 'foo_custom', true );
$this->assertFalse( $foo->dirty );
From 182c8c87f8729c58636cb6e6ef63bf360b2ab283 Mon Sep 17 00:00:00 2001
From: Weston Ruter
Date: Sat, 11 Jun 2016 15:12:37 -0700
Subject: [PATCH 58/69] Bump minimum wp version to 4.5
---
readme.md | 4 ++--
readme.txt | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/readme.md b/readme.md
index 46966301..5c51c6ba 100644
--- a/readme.md
+++ b/readme.md
@@ -6,12 +6,12 @@ Allow Customizer states to be drafted, and previewed with a private URL.
**Contributors:** [westonruter](https://profiles.wordpress.org/westonruter), [valendesigns](https://profiles.wordpress.org/valendesigns), [xwp](https://profiles.wordpress.org/xwp), [newscorpau](https://profiles.wordpress.org/newscorpau)
**Tags:** [customizer](https://wordpress.org/plugins/tags/customizer), [customize](https://wordpress.org/plugins/tags/customize), [snapshots](https://wordpress.org/plugins/tags/snapshots)
-**Requires at least:** 4.3
+**Requires at least:** 4.5
**Tested up to:** trunk
**Stable tag:** 0.4.0
**License:** [GPLv2 or later](http://www.gnu.org/licenses/gpl-2.0.html)
-[![Build Status](https://travis-ci.org/xwp/wp-customize-snapshots.svg?branch=master)](https://travis-ci.org/xwp/wp-customize-snapshots) [![Coverage Status](https://coveralls.io/repos/xwp/wp-customize-snapshots/badge.svg?branch=master)](https://coveralls.io/github/xwp/wp-customize-snapshots) [![Built with Grunt](https://cdn.gruntjs.com/builtwith.svg)](http://gruntjs.com) [![devDependency Status](https://david-dm.org/xwp/wp-customize-snapshots/dev-status.svg)](https://david-dm.org/xwp/wp-customize-snapshots#info=devDependencies)
+[![Build Status](https://travis-ci.org/xwp/wp-customize-snapshots.svg?branch=master)](https://travis-ci.org/xwp/wp-customize-snapshots) [![Coverage Status](https://coveralls.io/repos/xwp/wp-customize-snapshots/badge.svg?branch=master)](https://coveralls.io/github/xwp/wp-customize-snapshots) [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com) [![devDependency Status](https://david-dm.org/xwp/wp-customize-snapshots/dev-status.svg)](https://david-dm.org/xwp/wp-customize-snapshots#info=devDependencies)
## Description ##
diff --git a/readme.txt b/readme.txt
index de0a9440..69392a98 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,6 +1,6 @@
=== Customize Snapshots ===
Contributors: westonruter, valendesigns, xwp, newscorpau
-Requires at least: 4.3
+Requires at least: 4.5
Tested up to: trunk
Stable tag: 0.4.0
License: GPLv2 or later
From 31602e061b6950df3ec3a5864d116b6e6281b8e2 Mon Sep 17 00:00:00 2001
From: Weston Ruter
Date: Sat, 11 Jun 2016 15:44:45 -0700
Subject: [PATCH 59/69] Remove dirty from codebase and deprecate when used in
set method
---
php/class-customize-snapshot-manager.php | 2 +-
php/class-customize-snapshot.php | 26 ++++++++-----
...-class-ajax-customize-snapshot-manager.php | 8 ++--
.../test-class-customize-snapshot-manager.php | 37 +++++++++----------
tests/php/test-class-customize-snapshot.php | 33 ++++++-----------
5 files changed, 51 insertions(+), 55 deletions(-)
diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php
index 8555e645..f760c2bd 100644
--- a/php/class-customize-snapshot-manager.php
+++ b/php/class-customize-snapshot-manager.php
@@ -567,7 +567,7 @@ public function save( $status = 'draft' ) {
foreach ( $this->customize_manager->settings() as $setting ) {
if ( $this->can_preview( $setting, $this->unsanitized_snapshot_post_data ) ) {
$post_data = $this->unsanitized_snapshot_post_data[ $setting->id ];
- $this->snapshot->set( $setting, $post_data['value'], $post_data['dirty'] );
+ $this->snapshot->set( $setting, $post_data['value'] );
}
}
diff --git a/php/class-customize-snapshot.php b/php/class-customize-snapshot.php
index 59e452bd..168547f9 100644
--- a/php/class-customize-snapshot.php
+++ b/php/class-customize-snapshot.php
@@ -336,18 +336,24 @@ public function status() {
/**
* Store a setting's value in the snapshot's data.
*
- * @param \WP_Customize_Setting $setting Setting.
- * @param mixed $value Must be JSON-serializable.
- * @param bool $dirty Whether the setting is dirty or not.
+ * @since 0.4.0 Removed support for `$dirty` argument.
+ *
+ * @param \WP_Customize_Setting $setting Setting.
+ * @param mixed $value Must be JSON-serializable.
+ * @param bool $deprecated Whether the setting is dirty or not.
*/
- public function set( \WP_Customize_Setting $setting, $value, $dirty ) {
- if ( $dirty ) {
- $this->data[ $setting->id ] = array(
- 'value' => $value,
- 'dirty' => $dirty,
- 'sanitized' => false,
- );
+ public function set( \WP_Customize_Setting $setting, $value, $deprecated = null ) {
+ if ( ! is_null( $deprecated ) ) {
+ _doing_it_wrong( __METHOD__, 'The $dirty argument has been removed.', '0.4.0' );
+ if ( false === $deprecated ) {
+ return;
+ }
}
+
+ $this->data[ $setting->id ] = array(
+ 'value' => $value,
+ 'sanitized' => false,
+ );
}
/**
diff --git a/tests/php/test-class-ajax-customize-snapshot-manager.php b/tests/php/test-class-ajax-customize-snapshot-manager.php
index 05f530e3..cdc6391f 100644
--- a/tests/php/test-class-ajax-customize-snapshot-manager.php
+++ b/tests/php/test-class-ajax-customize-snapshot-manager.php
@@ -236,7 +236,7 @@ function test_ajax_update_snapshot_preview_check() {
'action' => Customize_Snapshot_Manager::AJAX_ACTION,
'nonce' => wp_create_nonce( Customize_Snapshot_Manager::AJAX_ACTION ),
'customize_snapshot_uuid' => self::UUID,
- 'snapshot_customized' => '{"header_background_color":{"value":"#ffffff","dirty":false}}',
+ 'snapshot_customized' => '{"header_background_color":{"value":"#ffffff"}}',
);
$this->manager->capture_unsanitized_snapshot_post_data();
@@ -260,7 +260,7 @@ function test_ajax_update_snapshot_success() {
'action' => Customize_Snapshot_Manager::AJAX_ACTION,
'nonce' => wp_create_nonce( Customize_Snapshot_Manager::AJAX_ACTION ),
'customize_snapshot_uuid' => self::UUID,
- 'snapshot_customized' => '{"foo":{"value":"foo_default","dirty":true},"bar":{"value":"bar_default","dirty":true}}',
+ 'snapshot_customized' => '{"foo":{"value":"foo_default"},"bar":{"value":"bar_default"}}',
'preview' => 'off',
);
@@ -289,7 +289,7 @@ function test_ajax_update_snapshot_success_preview() {
'action' => Customize_Snapshot_Manager::AJAX_ACTION,
'nonce' => wp_create_nonce( Customize_Snapshot_Manager::AJAX_ACTION ),
'customize_snapshot_uuid' => self::UUID,
- 'snapshot_customized' => '{"foo":{"value":"foo_default","dirty":false},"bar":{"value":"bar_default","dirty":false}}',
+ 'snapshot_customized' => '{"foo":{"value":"foo_default"},"bar":{"value":"bar_default"}}',
'preview' => 'on',
);
@@ -303,7 +303,7 @@ function test_ajax_update_snapshot_success_preview() {
// Get the results.
$response = json_decode( $this->_last_response, true );
$this->assertSame( self::UUID, $response['data']['customize_snapshot_uuid'] );
- $this->assertEmpty( $response['data']['customize_snapshot_settings'] );
+ $this->assertNotEmpty( $response['data']['customize_snapshot_settings'] );
}
/**
diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php
index c80a68a9..095f9a3a 100644
--- a/tests/php/test-class-customize-snapshot-manager.php
+++ b/tests/php/test-class-customize-snapshot-manager.php
@@ -202,13 +202,13 @@ function test_filter_post_row_actions_draft() {
$_POST = array(
'nonce' => wp_create_nonce( 'save-customize_' . $this->wp_customize->get_stylesheet() ),
'snapshot_uuid' => self::UUID,
- 'snapshot_customized' => '{"foo":{"value":"foo_default","dirty":true},"bar":{"value":"bar_default","dirty":true}}',
+ 'snapshot_customized' => '{"foo":{"value":"foo_default"},"bar":{"value":"bar_default"}}',
);
$manager = new Customize_Snapshot_Manager( $this->plugin );
$manager->capture_unsanitized_snapshot_post_data();
$foo = $manager->customize_manager->get_setting( 'foo' );
- $manager->snapshot()->set( $foo, 'foo_custom', true );
+ $manager->snapshot()->set( $foo, 'foo_custom' );
$manager->snapshot()->save();
$actions = array(
'inline hide-if-no-js' => true,
@@ -230,7 +230,7 @@ function test_filter_post_row_actions_publish() {
$_POST = array(
'nonce' => wp_create_nonce( 'save-customize_' . $this->wp_customize->get_stylesheet() ),
'snapshot_uuid' => self::UUID,
- 'snapshot_customized' => '{"foo":{"value":"foo_default","dirty":true},"bar":{"value":"bar_default","dirty":true}}',
+ 'snapshot_customized' => '{"foo":{"value":"foo_default"},"bar":{"value":"bar_default"}}',
);
$manager = new Customize_Snapshot_Manager( $this->plugin );
$manager->set_snapshot_uuid();
@@ -264,7 +264,7 @@ function test_setup_metaboxes() {
function test_render_data_metabox() {
wp_set_current_user( $this->user_id );
$this->do_customize_boot_actions( true );
- $snapshot_json = '{"foo":{"value":"foo_value","dirty":true,"sanitized":false}}';
+ $snapshot_json = '{"foo":{"value":"foo_value","sanitized":false}}';
$_POST = array(
'nonce' => wp_create_nonce( 'save-customize_' . $this->wp_customize->get_stylesheet() ),
'snapshot_uuid' => self::UUID,
@@ -273,7 +273,7 @@ function test_render_data_metabox() {
$manager = new Customize_Snapshot_Manager( $this->plugin );
$manager->capture_unsanitized_snapshot_post_data();
$foo = $manager->customize_manager->get_setting( 'foo' );
- $manager->snapshot()->set( $foo, 'foo_value', true );
+ $manager->snapshot()->set( $foo, 'foo_value' );
$manager->snapshot()->save();
$post = $manager->snapshot()->post();
ob_start();
@@ -290,7 +290,7 @@ function test_render_data_metabox() {
function test_get_post_content() {
wp_set_current_user( $this->user_id );
$this->do_customize_boot_actions( true );
- $snapshot_json = '{"foo":{"value":"foo_value","dirty":true,"sanitized":false}}';
+ $snapshot_json = '{"foo":{"value":"foo_value","sanitized":false}}';
$_POST = array(
'nonce' => wp_create_nonce( 'save-customize_' . $this->wp_customize->get_stylesheet() ),
'snapshot_uuid' => self::UUID,
@@ -299,14 +299,14 @@ function test_get_post_content() {
$manager = new Customize_Snapshot_Manager( $this->plugin );
$manager->capture_unsanitized_snapshot_post_data();
$foo = $manager->customize_manager->get_setting( 'foo' );
- $manager->snapshot()->set( $foo, 'foo_value', true );
+ $manager->snapshot()->set( $foo, 'foo_value' );
$manager->snapshot()->save();
$post = $manager->snapshot()->post();
$snapshot_content = Customize_Snapshot_Manager::get_post_content( $post );
$this->assertEquals( json_decode( $snapshot_json, true ), $snapshot_content );
// Get the revision post.
- $manager->snapshot()->set( $foo, 'foo_revision_value', true );
+ $manager->snapshot()->set( $foo, 'foo_revision_value' );
$manager->snapshot()->save();
$revisions = wp_get_post_revisions( $post->ID );
$revision = array_shift( $revisions );
@@ -334,11 +334,10 @@ function test_encode_json() {
$array = array(
'foo' => array(
'value' => 'foo_value',
- 'dirty' => true,
'sanitized' => false,
),
);
- $json = '{"foo":{"value":"foo_value","dirty":true,"sanitized":false}}';
+ $json = '{"foo":{"value":"foo_value","sanitized":false}}';
$this->assertEquals( $json, preg_replace( '/\s+/', '', Customize_Snapshot_Manager::encode_json( $array ) ) );
}
@@ -353,7 +352,7 @@ function test_enqueue_scripts() {
$_POST = array(
'nonce' => wp_create_nonce( 'save-customize_' . $this->wp_customize->get_stylesheet() ),
'snapshot_uuid' => self::UUID,
- 'snapshot_customized' => '{"foo":{"value":"foo_default","dirty":false},"bar":{"value":"bar_default","dirty":false}}',
+ 'snapshot_customized' => '{"foo":{"value":"foo_default"},"bar":{"value":"bar_default"}}',
);
$manager = new Customize_Snapshot_Manager( $this->plugin );
$manager->set_snapshot_uuid();
@@ -387,7 +386,7 @@ function test_save_error() {
$_POST = array(
'nonce' => wp_create_nonce( 'save-customize_' . $this->wp_customize->get_stylesheet() ),
'snapshot_uuid' => self::UUID,
- 'snapshot_customized' => '{"baz":{"value":"","dirty":true}}',
+ 'snapshot_customized' => '{"baz":{"value":""}}',
);
$manager = new Customize_Snapshot_Manager( $this->plugin );
$manager->save();
@@ -403,7 +402,7 @@ function test_save_snapshot() {
$_POST = array(
'nonce' => wp_create_nonce( 'save-customize_' . $this->wp_customize->get_stylesheet() ),
'snapshot_uuid' => self::UUID,
- 'snapshot_customized' => '{"foo":{"value":"foo_default","dirty":false},"bar":{"value":"bar_default","dirty":false}}',
+ 'snapshot_customized' => '{"foo":{"value":"foo_default"},"bar":{"value":"bar_default"}}',
);
$manager = new Customize_Snapshot_Manager( $this->plugin );
$manager->set_snapshot_uuid();
@@ -465,7 +464,7 @@ public function test_can_preview() {
$_POST = wp_slash( array(
'nonce' => wp_create_nonce( 'save-customize_' . $this->wp_customize->get_stylesheet() ),
'snapshot_uuid' => self::UUID,
- 'snapshot_customized' => '{"foo":{"value":"foo_custom","dirty":true},"bar":{"value":"bar_default","dirty":false}}',
+ 'snapshot_customized' => '{"foo":{"value":"foo_custom"},"bar":{"value":"bar_default"}}',
) );
$this->do_customize_boot_actions( true );
$foo = $this->wp_customize->get_setting( 'foo' );
@@ -503,7 +502,7 @@ public function test_can_preview_array_key_exists() {
$_POST = array(
'nonce' => wp_create_nonce( 'save-customize_' . $this->wp_customize->get_stylesheet() ),
'snapshot_uuid' => self::UUID,
- 'snapshot_customized' => '{"bar":{"value":"bar_default","dirty":false}}',
+ 'snapshot_customized' => '{"bar":{"value":"bar_default"}}',
);
$manager = new Customize_Snapshot_Manager( $this->plugin );
$manager->save_snapshot();
@@ -520,7 +519,7 @@ public function test_can_preview_array_key_exists() {
public function test_set_post_values() {
wp_set_current_user( $this->user_id );
$foo = $this->manager->customize_manager->get_setting( 'foo' );
- $this->manager->snapshot()->set( $foo, 'foo_custom', true );
+ $this->manager->snapshot()->set( $foo, 'foo_custom' );
$this->manager->snapshot()->save();
$this->manager->snapshot()->is_preview = true;
$this->manager->set_post_values();
@@ -535,7 +534,7 @@ public function test_preview() {
$this->manager->customize_manager = $this->wp_customize;
$this->manager->snapshot = new Customize_Snapshot( $this->manager, null );
$foo = $this->manager->customize_manager->get_setting( 'foo' );
- $this->manager->snapshot()->set( $foo, 'foo_custom', true );
+ $this->manager->snapshot()->set( $foo, 'foo_custom' );
$this->assertFalse( $foo->dirty );
$this->manager->snapshot()->save();
$this->manager->snapshot()->is_preview = true;
@@ -553,8 +552,8 @@ public function test_excerpt() {
$this->manager->snapshot = new Customize_Snapshot( $this->manager, null );
$foo = $this->manager->customize_manager->get_setting( 'foo' );
$bar = $this->manager->customize_manager->get_setting( 'bar' );
- $this->manager->snapshot()->set( $foo, 'foo_custom', true );
- $this->manager->snapshot()->set( $bar, 'bar_custom', true );
+ $this->manager->snapshot()->set( $foo, 'foo_custom' );
+ $this->manager->snapshot()->set( $bar, 'bar_custom' );
$this->manager->snapshot()->save();
$post = $this->manager->snapshot()->post();
diff --git a/tests/php/test-class-customize-snapshot.php b/tests/php/test-class-customize-snapshot.php
index 0e396736..a33af3ff 100644
--- a/tests/php/test-class-customize-snapshot.php
+++ b/tests/php/test-class-customize-snapshot.php
@@ -187,17 +187,9 @@ function test_values() {
$_POST['customized'] = 'on';
$this->wp_customize->setup_theme();
- // Has no no dirty values.
- $snapshot = new Customize_Snapshot( $this->snapshot_manager, null );
- $snapshot->set( $this->foo, 'foo_default', false );
- $snapshot->set( $this->bar, 'bar_default', false );
- $this->assertEmpty( $snapshot->values() );
- $snapshot->save();
- $uuid = $snapshot->uuid();
-
// Has dirty values.
- $snapshot = new Customize_Snapshot( $this->snapshot_manager, $uuid );
- $snapshot->set( $this->bar, 'bar_custom', true );
+ $snapshot = new Customize_Snapshot( $this->snapshot_manager, null );
+ $snapshot->set( $this->bar, 'bar_custom' );
$this->assertNotEmpty( $snapshot->values() );
}
@@ -210,13 +202,12 @@ function test_data() {
$this->wp_customize->setup_theme();
$snapshot = new Customize_Snapshot( $this->snapshot_manager, null );
- $snapshot->set( $this->foo, 'foo_default', false );
- $this->assertEmpty( $snapshot->data() );
- $snapshot->set( $this->foo, 'foo_custom', true );
+ $snapshot->set( $this->foo, 'foo_default' );
+ $this->assertNotEmpty( $snapshot->data() );
+ $snapshot->set( $this->foo, 'foo_custom' );
$expected = array(
'foo' => array(
'value' => 'foo_custom',
- 'dirty' => true,
'sanitized' => false,
),
);
@@ -229,7 +220,7 @@ function test_data() {
function test_settings() {
$snapshot = new Customize_Snapshot( $this->snapshot_manager, null );
$this->assertEmpty( $snapshot->settings() );
- $snapshot->set( $this->foo, 'foo_default', true );
+ $snapshot->set( $this->foo, 'foo_default' );
$this->assertNotEmpty( $snapshot->settings() );
}
@@ -242,12 +233,12 @@ function test_set_and_get() {
$this->wp_customize->add_setting( 'biz' );
$this->assertEmpty( $snapshot->get( $this->wp_customize->get_setting( 'biz' ) ) );
- $snapshot->set( $this->foo, 'foo_default', false );
+ $snapshot->set( $this->foo, 'foo_default' );
$this->assertNotEmpty( $snapshot->get( $this->foo ) );
$this->assertNotEmpty( $snapshot->get( 'foo' ) );
$this->assertEquals( 'bar_default', $snapshot->get( 'bar' ) );
$this->assertEquals( 'default', $snapshot->get( 'bar', 'default' ) );
- $this->assertNull( $snapshot->get( 'baz' ) );
+ $this->assertNull( $snapshot->get( 'baz' ) );
}
/**
@@ -256,8 +247,8 @@ function test_set_and_get() {
function test_save() {
$snapshot = new Customize_Snapshot( $this->snapshot_manager, null );
- $snapshot->set( $this->foo, 'foo_default', true );
- $snapshot->set( $this->bar, 'bar_default', true );
+ $snapshot->set( $this->foo, 'foo_default' );
+ $snapshot->set( $this->bar, 'bar_default' );
$this->assertFalse( $snapshot->saved() );
$snapshot->save();
@@ -270,7 +261,7 @@ function test_save() {
// Update the Snapshot content
$snapshot = new Customize_Snapshot( $this->snapshot_manager, $snapshot->uuid() );
- $snapshot->set( $this->bar, 'bar_custom', true );
+ $snapshot->set( $this->bar, 'bar_custom' );
$snapshot->save( 'publish' );
$decoded = json_decode( $snapshot->post()->post_content, true );
@@ -298,7 +289,7 @@ function test_save_pending() {
wp_set_current_user( $contributor_id );
$this->snapshot_manager->customize_manager = $wp_customize;
$snapshot = new Customize_Snapshot( $this->snapshot_manager, null );
- $snapshot->set( $this->foo, 'foo', true );
+ $snapshot->set( $this->foo, 'foo' );
$uuid = $snapshot->uuid();
$this->assertNotInstanceOf( 'WP_Error', $snapshot->save( 'pending' ) );
$post = get_post( $snapshot->post() );
From deb0ddd99b96e280bf924758c3dd31a6365e1069 Mon Sep 17 00:00:00 2001
From: Weston Ruter
Date: Sat, 11 Jun 2016 17:40:47 -0700
Subject: [PATCH 60/69] Only send dirty settings to be saved into the snapshot
---
js/customize-snapshots.js | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js
index 7ee372aa..c1ebd2fa 100644
--- a/js/customize-snapshots.js
+++ b/js/customize-snapshots.js
@@ -136,10 +136,11 @@
if ( component.data.isPreview ) {
api.each( function( value, key ) {
- allCustomized[ key ] = {
- 'value': value(),
- 'dirty': value._dirty
- };
+ if ( value._dirty ) {
+ allCustomized[ key ] = {
+ 'value': value()
+ };
+ }
} );
retval.snapshot_customized = JSON.stringify( allCustomized );
retval.snapshot_uuid = component.data.uuid;
@@ -248,10 +249,11 @@
customized = {};
api.each( function( value, key ) {
- customized[ key ] = {
- 'value': value(),
- 'dirty': value._dirty
- };
+ if ( value._dirty ) {
+ customized[ key ] = {
+ 'value': value()
+ };
+ }
} );
request = wp.ajax.post( 'customize_update_snapshot', {
From 314e829c9797112d5a699b95ef1a72fe211d11d5 Mon Sep 17 00:00:00 2001
From: Derek Herman
Date: Sat, 11 Jun 2016 19:04:31 -0700
Subject: [PATCH 61/69] Suspend kses filters when restoring a revision &
organize methods
---
php/class-customize-snapshot-manager.php | 151 +++++++++++++++++------
php/class-customize-snapshot.php | 35 +-----
2 files changed, 112 insertions(+), 74 deletions(-)
diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php
index f760c2bd..d6996f6c 100644
--- a/php/class-customize-snapshot-manager.php
+++ b/php/class-customize-snapshot-manager.php
@@ -67,6 +67,13 @@ class Customize_Snapshot_Manager {
*/
protected $snapshot_uuid;
+ /**
+ * Whether kses filters on content_save_pre are added.
+ *
+ * @var bool
+ */
+ protected $kses_suspended = false;
+
/**
* Constructor.
*
@@ -229,6 +236,30 @@ public function capture_unsanitized_snapshot_post_data() {
}
}
+ /**
+ * Suspend kses which runs on content_save_pre and can corrupt JSON in post_content.
+ *
+ * @see \sanitize_post()
+ */
+ function suspend_kses() {
+ if ( false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' ) ) {
+ $this->kses_suspended = true;
+ kses_remove_filters();
+ }
+ }
+
+ /**
+ * Restore kses which runs on content_save_pre and can corrupt JSON in post_content.
+ *
+ * @see \sanitize_post()
+ */
+ function restore_kses() {
+ if ( $this->kses_suspended ) {
+ kses_init_filters();
+ $this->kses_suspended = false;
+ }
+ }
+
/**
* Create the custom post type.
*
@@ -280,11 +311,73 @@ public function create_post_type() {
register_post_type( self::POST_TYPE, $args );
- add_filter( 'post_row_actions', array( $this, 'filter_post_row_actions' ), 10, 2 );
add_action( 'add_meta_boxes_' . self::POST_TYPE, array( $this, 'remove_publish_metabox' ), 100 );
- add_filter( 'wp_insert_post_data', array( $this, 'preserve_post_name_in_insert_data' ), 10, 2 );
+ add_action( 'load-revision.php', array( $this, 'suspend_kses_for_snapshot_revision_restore' ) );
add_filter( 'bulk_actions-edit-' . self::POST_TYPE, array( $this, 'filter_bulk_actions' ) );
add_filter( 'get_the_excerpt', array( $this, 'filter_snapshot_excerpt' ), 10, 2 );
+ add_filter( 'post_row_actions', array( $this, 'filter_post_row_actions' ), 10, 2 );
+ add_filter( 'wp_insert_post_data', array( $this, 'preserve_post_name_in_insert_data' ), 10, 2 );
+ }
+
+ /**
+ * Add the metabox.
+ */
+ public function setup_metaboxes() {
+ $id = self::POST_TYPE;
+ $title = __( 'Data', 'customize-snapshots' );
+ $callback = array( $this, 'render_data_metabox' );
+ $screen = self::POST_TYPE;
+ $context = 'normal';
+ $priority = 'high';
+ add_meta_box( $id, $title, $callback, $screen, $context, $priority );
+ }
+
+ /**
+ * Remove publish metabox for published posts, since they should be immutable once published.
+ *
+ * @codeCoverageIgnore
+ */
+ public function remove_publish_metabox() {
+ remove_meta_box( 'slugdiv', self::POST_TYPE, 'normal' );
+ remove_meta_box( 'submitdiv', self::POST_TYPE, 'side' );
+ remove_meta_box( 'authordiv', self::POST_TYPE, 'normal' );
+ }
+
+ /**
+ * Make sure that restoring snapshot revisions doesn't involve kses corrupting the post_content.
+ *
+ * Ideally there would be an action like pre_wp_restore_post_revision instead
+ * of having to hack into the load-revision.php action. But even more ideally
+ * we should be able to disable such content_save_pre filters from even applying
+ * for certain post types, such as those which store JSON in post_content.
+ *
+ * @action load-revision.php
+ */
+ function suspend_kses_for_snapshot_revision_restore() {
+ if ( ! isset( $_GET['revision'] ) ) { // WPCS: input var ok.
+ return;
+ }
+ if ( ! isset( $_GET['action'] ) || 'restore' !== $_GET['action'] ) { // WPCS: input var ok, sanitization ok.
+ return;
+ }
+ $revision_post_id = intval( $_GET['revision'] ); // WPCS: input var ok.
+ if ( $revision_post_id <= 0 ) {
+ return;
+ }
+ $revision_post = wp_get_post_revision( $revision_post_id );
+ if ( empty( $revision_post ) ) {
+ return;
+ }
+ $post = get_post( $revision_post->post_parent );
+ if ( empty( $post ) || self::POST_TYPE !== $post->post_type ) {
+ return;
+ }
+
+ $this->suspend_kses();
+ $that = $this;
+ add_action( 'wp_restore_post_revision', function() use ( $that ) {
+ $that->restore_kses();
+ } );
}
/**
@@ -356,27 +449,23 @@ public function filter_post_row_actions( $actions, $post ) {
}
/**
- * Add the metabox.
- */
- public function setup_metaboxes() {
- $id = self::POST_TYPE;
- $title = __( 'Data', 'customize-snapshots' );
- $callback = array( $this, 'render_data_metabox' );
- $screen = self::POST_TYPE;
- $context = 'normal';
- $priority = 'high';
- add_meta_box( $id, $title, $callback, $screen, $context, $priority );
- }
-
- /**
- * Remove publish metabox for published posts, since they should be immutable once published.
+ * Preserve the post_name when submitting a snapshot for review.
*
- * @codeCoverageIgnore
+ * @see wp_insert_post()
+ * @link https://github.com/xwp/wordpress-develop/blob/831a186108983ade4d647124d4e56e09aa254704/src/wp-includes/post.php#L3134-L3137
+ *
+ * @param array $post_data Post data.
+ * @param array $original_post_data Original post data.
+ * @return array Post data.
*/
- public function remove_publish_metabox() {
- remove_meta_box( 'slugdiv', self::POST_TYPE, 'normal' );
- remove_meta_box( 'submitdiv', self::POST_TYPE, 'side' );
- remove_meta_box( 'authordiv', self::POST_TYPE, 'normal' );
+ public function preserve_post_name_in_insert_data( $post_data, $original_post_data ) {
+ if ( empty( $post_data['post_type'] ) || self::POST_TYPE !== $post_data['post_type'] ) {
+ return $post_data;
+ }
+ if ( empty( $post_data['post_name'] ) && 'pending' === $post_data['post_status'] ) {
+ $post_data['post_name'] = $original_post_data['post_name'];
+ }
+ return $post_data;
}
/**
@@ -527,26 +616,6 @@ public function snapshot() {
return $this->snapshot;
}
- /**
- * Preserve the post_name when submitting a snapshot for review.
- *
- * @see wp_insert_post()
- * @link https://github.com/xwp/wordpress-develop/blob/831a186108983ade4d647124d4e56e09aa254704/src/wp-includes/post.php#L3134-L3137
- *
- * @param array $post_data Post data.
- * @param array $original_post_data Original post data.
- * @return array Post data.
- */
- public function preserve_post_name_in_insert_data( $post_data, $original_post_data ) {
- if ( empty( $post_data['post_type'] ) || self::POST_TYPE !== $post_data['post_type'] ) {
- return $post_data;
- }
- if ( empty( $post_data['post_name'] ) && 'pending' === $post_data['post_status'] ) {
- $post_data['post_name'] = $original_post_data['post_name'];
- }
- return $post_data;
- }
-
/**
* Save a snapshot.
*
diff --git a/php/class-customize-snapshot.php b/php/class-customize-snapshot.php
index 168547f9..f849d3c4 100644
--- a/php/class-customize-snapshot.php
+++ b/php/class-customize-snapshot.php
@@ -56,13 +56,6 @@ class Customize_Snapshot {
*/
public $is_preview = false;
- /**
- * Whether kses filters on content_save_pre are added.
- *
- * @var bool
- */
- protected $kses_suspended = false;
-
/**
* Initial loader.
*
@@ -396,7 +389,7 @@ public function save( $status = 'draft' ) {
// JSON encoded snapshot data.
$post_content = wp_json_encode( $this->data, $options );
- $this->suspend_kses();
+ $this->snapshot_manager->suspend_kses();
if ( ! $this->post ) {
$postarr = array(
'post_type' => Customize_Snapshot_Manager::POST_TYPE,
@@ -424,32 +417,8 @@ public function save( $status = 'draft' ) {
}
$this->post = get_post( $r );
}
- $this->restore_kses();
+ $this->snapshot_manager->restore_kses();
return null;
}
-
- /**
- * Suspend kses which runs on content_save_pre and can corrupt JSON in post_content.
- *
- * @see \sanitize_post()
- */
- function suspend_kses() {
- if ( false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' ) ) {
- $this->kses_suspended = true;
- kses_remove_filters();
- }
- }
-
- /**
- * Restore kses which runs on content_save_pre and can corrupt JSON in post_content.
- *
- * @see \sanitize_post()
- */
- function restore_kses() {
- if ( $this->kses_suspended ) {
- kses_init_filters();
- $this->kses_suspended = false;
- }
- }
}
From 40b3e79155efacfa9cb10ce29cc66083459d3696 Mon Sep 17 00:00:00 2001
From: Derek Herman
Date: Sat, 11 Jun 2016 19:13:37 -0700
Subject: [PATCH 62/69] Remove action from the docblock & ignore coverage
---
php/class-customize-snapshot-manager.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php
index d6996f6c..d30204e7 100644
--- a/php/class-customize-snapshot-manager.php
+++ b/php/class-customize-snapshot-manager.php
@@ -351,7 +351,7 @@ public function remove_publish_metabox() {
* we should be able to disable such content_save_pre filters from even applying
* for certain post types, such as those which store JSON in post_content.
*
- * @action load-revision.php
+ * @codeCoverageIgnore
*/
function suspend_kses_for_snapshot_revision_restore() {
if ( ! isset( $_GET['revision'] ) ) { // WPCS: input var ok.
From c740f037287d643692842d32e58f41363f3b97b4 Mon Sep 17 00:00:00 2001
From: Derek Herman
Date: Sat, 11 Jun 2016 20:29:02 -0700
Subject: [PATCH 63/69] Grunt minified JS
---
js/customize-snapshots.min.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/customize-snapshots.min.js b/js/customize-snapshots.min.js
index 73bfd966..82b39514 100644
--- a/js/customize-snapshots.min.js
+++ b/js/customize-snapshots.min.js
@@ -1 +1 @@
-!function(a,b){"use strict";var c;a.Snapshots||(a.Snapshots={}),c=a.Snapshots,c.data={},"undefined"!=typeof _customizeSnapshots&&_.extend(c.data,_customizeSnapshots),c.init=function(){window._wpCustomizeControlsL10n.save=c.data.i18n.publish,window._wpCustomizeControlsL10n.saved=c.data.i18n.published,a.bind("ready",function(){!a.settings.theme.active||c.data.theme&&c.data.theme!==a.settings.theme.stylesheet||(a.state.create("snapshot-saved",!0),a.state.create("snapshot-submitted",!0),a.bind("change",function(){a.state("snapshot-saved").set(!1),a.state("snapshot-submitted").set(!1)}),c.previewerQuery(),c.addButtons(),b("#snapshot-save").on("click",function(a){a.preventDefault(),c.sendUpdateSnapshotRequest({status:"draft",openNewWindow:a.shiftKey})}),b("#snapshot-submit").on("click",function(a){a.preventDefault(),c.sendUpdateSnapshotRequest({status:"pending",openNewWindow:a.shiftKey})}),c.data.isPreview&&(a.state("saved").set(!1),c.resetSavedStateQuietly()))}),a.bind("save",function(d){return a.state("saved").set(!1),d.fail(function(a){var d="snapshot-dialog-error",e=wp.template(d);a.responseText&&(0===b("#"+d).length&&b("body").append(e({title:c.data.i18n.publish,message:c.data.isPreview?c.data.i18n.permsMsg.update:c.data.i18n.permsMsg.save})),b("#customize-header-actions .spinner").removeClass("is-active"),b("#"+d).dialog({autoOpen:!0,modal:!0}))}),d}),a.bind("saved",function(){var a,b,d,e=window.location.href;c.changeButton(c.data.i18n.saveButton,c.data.i18n.permsMsg.save),a=wp.ajax.post("customize_get_snapshot_uuid",{nonce:c.data.nonce,wp_customize:"on"}),a.done(function(a){c.data.uuid=a.uuid}),d=e.split("?"),history.replaceState&&d[1]&&(b=d[0]+"?"+_.filter(d[1].split("&"),function(a){return!/^(customize_snapshot_uuid)=/.test(a)}).join("&"),b=b.replace(/\?$/,""),b!==e&&history.replaceState({},document.title,b))})},c.previewerQuery=function(){var b=a.previewer.query;a.previewer.query=function(){var d,e={};return d=b.apply(this,arguments),c.data.isPreview&&(a.each(function(a,b){e[b]={value:a(),dirty:a._dirty}}),d.snapshot_customized=JSON.stringify(e),d.snapshot_uuid=c.data.uuid),d}},c.addButtons=function(){var d,e,f,g=b("#customize-header-actions"),h=g.find("#save");d=wp.template("snapshot-save"),f={buttonText:c.data.isPreview?c.data.i18n.updateButton:c.data.i18n.saveButton},d=b(b.trim(d(f))),c.data.currentUserCanPublish||d.attr("title",c.data.isPreview?c.data.i18n.permsMsg.update:c.data.i18n.permsMsg.save),d.prop("disabled",!0),d.insertAfter(h),a.state("snapshot-saved").bind(function(a){d.prop("disabled",a)}),c.data.currentUserCanPublish||(h.hide(),e=wp.template("snapshot-submit"),e=b(b.trim(e({buttonText:c.data.i18n.submit}))),e.prop("disabled",!0),e.insertBefore(d),a.state("snapshot-submitted").bind(function(a){e.prop("disabled",a)})),g.addClass("button-added")},c.changeButton=function(a,d){var e=b("#customize-header-actions").find("#snapshot-save");e.length&&(e.text(a),c.data.currentUserCanPublish||e.attr("title",d))},c.resetSavedStateQuietly=function(){a.state("saved")._value=!0},c.sendUpdateSnapshotRequest=function(d){var e,f,g,h=b("#customize-header-actions .spinner");g=_.extend({status:"draft",openNewWindow:!1},d),h.addClass("is-active"),f={},a.each(function(a,b){f[b]={value:a(),dirty:a._dirty}}),e=wp.ajax.post("customize_update_snapshot",{nonce:c.data.nonce,wp_customize:"on",snapshot_customized:JSON.stringify(f),customize_snapshot_uuid:c.data.uuid,status:g.status,preview:c.data.isPreview?"on":"off"}),e.done(function(b){var d=a.previewer.previewUrl(),e=new RegExp("([?&])customize_snapshot_uuid=.*?(&|$)","i"),f=-1!==d.indexOf("?")?"&":"?",i=window.location.href,j=-1!==i.indexOf("?")?"&":"?";c.data.uuid||(c.data.uuid=b.customize_snapshot_uuid),d=d.match(e)?d.replace(e,"$1customize_snapshot_uuid="+encodeURIComponent(c.data.uuid)+"$2"):d+f+"customize_snapshot_uuid="+encodeURIComponent(c.data.uuid),c.changeButton(c.data.i18n.updateButton,c.data.i18n.permsMsg.update),c.data.isPreview=!0,h.removeClass("is-active"),c.resetSavedStateQuietly(),history.replaceState&&!i.match(e)&&(i+=j+"customize_snapshot_uuid="+encodeURIComponent(c.data.uuid),history.replaceState({},document.title,i)),a.state("snapshot-saved").set(!0),"pending"===g.status&&a.state("snapshot-submitted").set(!0),g.openNewWindow&&window.open(d,"_blank"),a.trigger("customize-snapshots-update",{previewUrl:d,customizeUrl:i,uuid:c.data.uuid})}),e.fail(function(){var a="snapshot-dialog-error",d=wp.template(a);0===b("#"+a).length&&b("body").append(d({title:c.data.i18n.errorTitle,message:c.data.i18n.errorMsg})),b("#"+a).dialog({autoOpen:!0,modal:!0}),h.removeClass("is-active")})},c.init()}(wp.customize,jQuery);
\ No newline at end of file
+!function(a,b){"use strict";var c;a.Snapshots||(a.Snapshots={}),c=a.Snapshots,c.data={},"undefined"!=typeof _customizeSnapshots&&_.extend(c.data,_customizeSnapshots),c.init=function(){window._wpCustomizeControlsL10n.save=c.data.i18n.publish,window._wpCustomizeControlsL10n.saved=c.data.i18n.published,a.bind("ready",function(){!a.settings.theme.active||c.data.theme&&c.data.theme!==a.settings.theme.stylesheet||(a.state.create("snapshot-saved",!0),a.state.create("snapshot-submitted",!0),a.bind("change",function(){a.state("snapshot-saved").set(!1),a.state("snapshot-submitted").set(!1)}),c.previewerQuery(),c.addButtons(),b("#snapshot-save").on("click",function(a){a.preventDefault(),c.sendUpdateSnapshotRequest({status:"draft",openNewWindow:a.shiftKey})}),b("#snapshot-submit").on("click",function(a){a.preventDefault(),c.sendUpdateSnapshotRequest({status:"pending",openNewWindow:a.shiftKey})}),c.data.isPreview&&(a.state("saved").set(!1),c.resetSavedStateQuietly()))}),a.bind("save",function(d){return a.state("saved").set(!1),d.fail(function(a){var d="snapshot-dialog-error",e=wp.template(d);a.responseText&&(0===b("#"+d).length&&b("body").append(e({title:c.data.i18n.publish,message:c.data.isPreview?c.data.i18n.permsMsg.update:c.data.i18n.permsMsg.save})),b("#customize-header-actions .spinner").removeClass("is-active"),b("#"+d).dialog({autoOpen:!0,modal:!0}))}),d}),a.bind("saved",function(){var a,b,d,e=window.location.href;c.changeButton(c.data.i18n.saveButton,c.data.i18n.permsMsg.save),a=wp.ajax.post("customize_get_snapshot_uuid",{nonce:c.data.nonce,wp_customize:"on"}),a.done(function(a){c.data.uuid=a.uuid}),d=e.split("?"),history.replaceState&&d[1]&&(b=d[0]+"?"+_.filter(d[1].split("&"),function(a){return!/^(customize_snapshot_uuid)=/.test(a)}).join("&"),b=b.replace(/\?$/,""),b!==e&&history.replaceState({},document.title,b))})},c.previewerQuery=function(){var b=a.previewer.query;a.previewer.query=function(){var d,e={};return d=b.apply(this,arguments),c.data.isPreview&&(a.each(function(a,b){a._dirty&&(e[b]={value:a()})}),d.snapshot_customized=JSON.stringify(e),d.snapshot_uuid=c.data.uuid),d}},c.addButtons=function(){var d,e,f,g=b("#customize-header-actions"),h=g.find("#save");d=wp.template("snapshot-save"),f={buttonText:c.data.isPreview?c.data.i18n.updateButton:c.data.i18n.saveButton},d=b(b.trim(d(f))),c.data.currentUserCanPublish||d.attr("title",c.data.isPreview?c.data.i18n.permsMsg.update:c.data.i18n.permsMsg.save),d.prop("disabled",!0),d.insertAfter(h),a.state("snapshot-saved").bind(function(a){d.prop("disabled",a)}),c.data.currentUserCanPublish||(h.hide(),e=wp.template("snapshot-submit"),e=b(b.trim(e({buttonText:c.data.i18n.submit}))),e.prop("disabled",!0),e.insertBefore(d),a.state("snapshot-submitted").bind(function(a){e.prop("disabled",a)})),g.addClass("button-added")},c.changeButton=function(a,d){var e=b("#customize-header-actions").find("#snapshot-save");e.length&&(e.text(a),c.data.currentUserCanPublish||e.attr("title",d))},c.resetSavedStateQuietly=function(){a.state("saved")._value=!0},c.sendUpdateSnapshotRequest=function(d){var e,f,g,h=b("#customize-header-actions .spinner");g=_.extend({status:"draft",openNewWindow:!1},d),h.addClass("is-active"),f={},a.each(function(a,b){a._dirty&&(f[b]={value:a()})}),e=wp.ajax.post("customize_update_snapshot",{nonce:c.data.nonce,wp_customize:"on",snapshot_customized:JSON.stringify(f),customize_snapshot_uuid:c.data.uuid,status:g.status,preview:c.data.isPreview?"on":"off"}),e.done(function(b){var d=a.previewer.previewUrl(),e=new RegExp("([?&])customize_snapshot_uuid=.*?(&|$)","i"),f=-1!==d.indexOf("?")?"&":"?",i=window.location.href,j=-1!==i.indexOf("?")?"&":"?";c.data.uuid||(c.data.uuid=b.customize_snapshot_uuid),d=d.match(e)?d.replace(e,"$1customize_snapshot_uuid="+encodeURIComponent(c.data.uuid)+"$2"):d+f+"customize_snapshot_uuid="+encodeURIComponent(c.data.uuid),c.changeButton(c.data.i18n.updateButton,c.data.i18n.permsMsg.update),c.data.isPreview=!0,h.removeClass("is-active"),c.resetSavedStateQuietly(),history.replaceState&&!i.match(e)&&(i+=j+"customize_snapshot_uuid="+encodeURIComponent(c.data.uuid),history.replaceState({},document.title,i)),a.state("snapshot-saved").set(!0),"pending"===g.status&&a.state("snapshot-submitted").set(!0),g.openNewWindow&&window.open(d,"_blank"),a.trigger("customize-snapshots-update",{previewUrl:d,customizeUrl:i,uuid:c.data.uuid})}),e.fail(function(){var a="snapshot-dialog-error",d=wp.template(a);0===b("#"+a).length&&b("body").append(d({title:c.data.i18n.errorTitle,message:c.data.i18n.errorMsg})),b("#"+a).dialog({autoOpen:!0,modal:!0}),h.removeClass("is-active")})},c.init()}(wp.customize,jQuery);
\ No newline at end of file
From 2f2124b25e2ac56b8f5aba38bdbf25042cf77a63 Mon Sep 17 00:00:00 2001
From: Weston Ruter
Date: Sat, 11 Jun 2016 21:44:06 -0700
Subject: [PATCH 64/69] Update readme for 0.4.0
---
php/class-customize-snapshot-manager.php | 2 +-
readme.md | 32 ++++++++++++++++++------
readme.txt | 31 ++++++++++++++++++-----
3 files changed, 51 insertions(+), 14 deletions(-)
diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php
index d30204e7..836b1b94 100644
--- a/php/class-customize-snapshot-manager.php
+++ b/php/class-customize-snapshot-manager.php
@@ -478,7 +478,7 @@ public function render_data_metabox( $post ) {
$post_status_obj = get_post_status_object( $post->post_status );
echo '
';
- echo esc_html__( 'UUID:', 'customize-snapshots' ) . '' . esc_html( $post->post_name ) . ' ';
+ echo esc_html__( 'UUID:', 'customize-snapshots' ) . ' ' . esc_html( $post->post_name ) . ' ';
echo sprintf( '%1$s %2$s', esc_html__( 'Status:', 'customize-snapshots' ), esc_html( $post_status_obj->label ) ) . ' ';
echo sprintf( '%1$s %2$s %3$s', esc_html__( 'Publish Date:', 'customize-snapshots' ), esc_html( get_the_date( '', $post->ID ) ), esc_html( get_the_time( '', $post->ID ) ) ) . ' ';
echo sprintf( '%1$s %2$s %3$s', esc_html__( 'Modified:', 'customize-snapshots' ), esc_html( get_the_modified_date( '' ) ), esc_html( get_the_modified_time( '' ) ) ) . ' ';
diff --git a/readme.md b/readme.md
index 5c51c6ba..562bba19 100644
--- a/readme.md
+++ b/readme.md
@@ -11,7 +11,7 @@ Allow Customizer states to be drafted, and previewed with a private URL.
**Stable tag:** 0.4.0
**License:** [GPLv2 or later](http://www.gnu.org/licenses/gpl-2.0.html)
-[![Build Status](https://travis-ci.org/xwp/wp-customize-snapshots.svg?branch=master)](https://travis-ci.org/xwp/wp-customize-snapshots) [![Coverage Status](https://coveralls.io/repos/xwp/wp-customize-snapshots/badge.svg?branch=master)](https://coveralls.io/github/xwp/wp-customize-snapshots) [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com) [![devDependency Status](https://david-dm.org/xwp/wp-customize-snapshots/dev-status.svg)](https://david-dm.org/xwp/wp-customize-snapshots#info=devDependencies)
+[![Build Status](https://travis-ci.org/xwp/wp-customize-snapshots.svg?branch=master)](https://travis-ci.org/xwp/wp-customize-snapshots) [![Coverage Status](https://coveralls.io/repos/xwp/wp-customize-snapshots/badge.svg?branch=master)](https://coveralls.io/github/xwp/wp-customize-snapshots) [![Built with Grunt](https://cdn.gruntjs.com/builtwith.svg)](http://gruntjs.com) [![devDependency Status](https://david-dm.org/xwp/wp-customize-snapshots/dev-status.svg)](https://david-dm.org/xwp/wp-customize-snapshots#info=devDependencies)
## Description ##
@@ -23,12 +23,30 @@ Requires PHP 5.3+.
## Changelog ##
-### 0.4.0 ###
-* Update the UX by removing most modal dialogs and the need to set the snapshot scope.
-* Eliminate the storage of non-dirty settings in a Snapshot, which eliminates the `scope` feature.
-* Ensure that widget actions and filters get added when previewing snapshots on the front-end.
-* Use `wp_slash()` instead of `add_magic_quotes()` when loading the snapshot post vars.
-* Update `dev-lib`.
+### 0.4.0 - 2016-06-11 ###
+Added:
+
+* Improved UX by removing save/update dialogs, changing the Snapshot button text to “Save” & “Update” for a more streamlined experience by removing the “full” snapshot option. (Issues #13, #42, PR #30)
+* Snapshot UUID is dynamically added to the Customizer URL when a snapshot is first saved and it is stripped from the URL once the settings are published (and the snapshot is published), at which point the snapshot is “frozen”. (Issue #37, PR #40).
+* Update button can now be shift-clicked to open the snapshot on the frontend in a new window.
+* Eliminate the storage of non-dirty settings in a Snapshot, which deprecates the scope feature (Issue #42)
+* Support listing snapshots in the admin and inspecting their contents WP Admin UI, with shortcuts to open snapshot in Customizer, viewing list of settings contained in snapshot from excerpt in post list view (Issue #45, PRs #38, #46).
+* Introduce pending snapshots for users who are not administrators (who lack the customize_publish capability) to be able to make snapshots and save them, and then submit them for review once ready (PR #38).
+* Added revisions for snapshots so that changes to a snapshot made before the time it is published can be tracked.
+* New banner image and icon (Issue #24, PR #27).
+* Bumped minimum WordPress version to 4.5.
+
+Fixed:
+
+* Store content in post_content instead of post_content_filtered (Issue #25, PRs #36, #43). This breaks backwards compatibility with existing snapshots.
+* Replace customize-snapshots JS dependency from customize-widgets to customize-controls (PR #14).
+* Ensure that widget actions and filters are added when previewing snapshots from the front-end (Issue #34, PR #33).
+* Use wp_slash() instead of add_magic_quotes() when loading the snapshot post vars (PR #23).
+* Update dev-lib.
+
+See full commit log: 0.3.1...0.4.0
+Issues/PRs in release: milestone:0.4.0
+Props: Weston Ruter (@westonruter), Derek Herman (@valendesigns), Luke Carbis (@lukecarbis)
### 0.3.1 ###
* Fix additional WordPress VIP issues.
diff --git a/readme.txt b/readme.txt
index 69392a98..a974939c 100644
--- a/readme.txt
+++ b/readme.txt
@@ -19,12 +19,31 @@ Requires PHP 5.3+.
== Changelog ==
-= 0.4.0 =
-* Update the UX by removing most modal dialogs and the need to set the snapshot scope.
-* Eliminate the storage of non-dirty settings in a Snapshot, which eliminates the `scope` feature.
-* Ensure that widget actions and filters get added when previewing snapshots on the front-end.
-* Use `wp_slash()` instead of `add_magic_quotes()` when loading the snapshot post vars.
-* Update `dev-lib`.
+= 0.4.0 - 2016-06-11 =
+
+Added:
+
+* Improved UX by removing save/update dialogs, changing the Snapshot button text to “Save” & “Update” for a more streamlined experience by removing the “full” snapshot option. (Issues #13, #42, PR #30)
+* Snapshot UUID is dynamically added to the Customizer URL when a snapshot is first saved and it is stripped from the URL once the settings are published (and the snapshot is published), at which point the snapshot is “frozen”. (Issue #37, PR #40).
+* Update button can now be shift-clicked to open the snapshot on the frontend in a new window.
+* Eliminate the storage of non-dirty settings in a Snapshot, which deprecates the scope feature (Issue #42)
+* Support listing snapshots in the admin and inspecting their contents WP Admin UI, with shortcuts to open snapshot in Customizer, viewing list of settings contained in snapshot from excerpt in post list view (Issue #45, PRs #38, #46).
+* Introduce pending snapshots for users who are not administrators (who lack the customize_publish capability) to be able to make snapshots and save them, and then submit them for review once ready (PR #38).
+* Added revisions for snapshots so that changes to a snapshot made before the time it is published can be tracked.
+* New banner image and icon (Issue #24, PR #27).
+* Bumped minimum WordPress version to 4.5.
+
+Fixed:
+
+* Store content in post_content instead of post_content_filtered (Issue #25, PRs #36, #43). This breaks backwards compatibility with existing snapshots.
+* Replace customize-snapshots JS dependency from customize-widgets to customize-controls (PR #14).
+* Ensure that widget actions and filters are added when previewing snapshots from the front-end (Issue #34, PR #33).
+* Use wp_slash() instead of add_magic_quotes() when loading the snapshot post vars (PR #23).
+* Update dev-lib.
+
+See full commit log: 0.3.1...0.4.0
+Issues/PRs in release: milestone:0.4.0
+Props: Weston Ruter (@westonruter), Derek Herman (@valendesigns), Luke Carbis (@lukecarbis)
= 0.3.1 =
* Fix additional WordPress VIP issues.
From 6d84772cdbb87e2ca81cb2e5129896c9af106eda Mon Sep 17 00:00:00 2001
From: Derek Herman
Date: Sat, 11 Jun 2016 22:18:18 -0700
Subject: [PATCH 65/69] Minor copy changes
---
readme.md | 4 ++--
readme.txt | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/readme.md b/readme.md
index 562bba19..9b6a2d79 100644
--- a/readme.md
+++ b/readme.md
@@ -30,7 +30,7 @@ Added:
* Snapshot UUID is dynamically added to the Customizer URL when a snapshot is first saved and it is stripped from the URL once the settings are published (and the snapshot is published), at which point the snapshot is “frozen”. (Issue #37, PR #40).
* Update button can now be shift-clicked to open the snapshot on the frontend in a new window.
* Eliminate the storage of non-dirty settings in a Snapshot, which deprecates the scope feature (Issue #42)
-* Support listing snapshots in the admin and inspecting their contents WP Admin UI, with shortcuts to open snapshot in Customizer, viewing list of settings contained in snapshot from excerpt in post list view (Issue #45, PRs #38, #46).
+* Support listing snapshots in the admin and inspecting their contents WP Admin UI, with shortcuts to open snapshot in Customizer, viewing the list of settings contained in a snapshot from the excerpt in post list view (Issue #45, PRs #38, #46).
* Introduce pending snapshots for users who are not administrators (who lack the customize_publish capability) to be able to make snapshots and save them, and then submit them for review once ready (PR #38).
* Added revisions for snapshots so that changes to a snapshot made before the time it is published can be tracked.
* New banner image and icon (Issue #24, PR #27).
@@ -38,7 +38,7 @@ Added:
Fixed:
-* Store content in post_content instead of post_content_filtered (Issue #25, PRs #36, #43). This breaks backwards compatibility with existing snapshots.
+* Store content in `post_content` instead of `post_content_filtered` (Issue #25, PRs #36, #43). This breaks backwards compatibility with existing snapshots.
* Replace customize-snapshots JS dependency from customize-widgets to customize-controls (PR #14).
* Ensure that widget actions and filters are added when previewing snapshots from the front-end (Issue #34, PR #33).
* Use wp_slash() instead of add_magic_quotes() when loading the snapshot post vars (PR #23).
diff --git a/readme.txt b/readme.txt
index a974939c..04c0dd85 100644
--- a/readme.txt
+++ b/readme.txt
@@ -27,7 +27,7 @@ Added:
* Snapshot UUID is dynamically added to the Customizer URL when a snapshot is first saved and it is stripped from the URL once the settings are published (and the snapshot is published), at which point the snapshot is “frozen”. (Issue #37, PR #40).
* Update button can now be shift-clicked to open the snapshot on the frontend in a new window.
* Eliminate the storage of non-dirty settings in a Snapshot, which deprecates the scope feature (Issue #42)
-* Support listing snapshots in the admin and inspecting their contents WP Admin UI, with shortcuts to open snapshot in Customizer, viewing list of settings contained in snapshot from excerpt in post list view (Issue #45, PRs #38, #46).
+* Support listing snapshots in the admin and inspecting their contents WP Admin UI, with shortcuts to open snapshot in Customizer, viewing the list of settings contained in a snapshot from the excerpt in post list view (Issue #45, PRs #38, #46).
* Introduce pending snapshots for users who are not administrators (who lack the customize_publish capability) to be able to make snapshots and save them, and then submit them for review once ready (PR #38).
* Added revisions for snapshots so that changes to a snapshot made before the time it is published can be tracked.
* New banner image and icon (Issue #24, PR #27).
@@ -35,7 +35,7 @@ Added:
Fixed:
-* Store content in post_content instead of post_content_filtered (Issue #25, PRs #36, #43). This breaks backwards compatibility with existing snapshots.
+* Store content in `post_content` instead of `post_content_filtered` (Issue #25, PRs #36, #43). This breaks backwards compatibility with existing snapshots.
* Replace customize-snapshots JS dependency from customize-widgets to customize-controls (PR #14).
* Ensure that widget actions and filters are added when previewing snapshots from the front-end (Issue #34, PR #33).
* Use wp_slash() instead of add_magic_quotes() when loading the snapshot post vars (PR #23).
From b2871ea7aa904e742eef1a2e03b752c6ec19aaf4 Mon Sep 17 00:00:00 2001
From: Weston Ruter
Date: Sat, 11 Jun 2016 22:24:01 -0700
Subject: [PATCH 66/69] Add screenshots
[ci skip]
---
readme.md | 30 ++++++++++++++++++++++++++++++
readme.txt | 11 +++++++++++
wp-assets/screenshot-1.png | Bin 0 -> 28654 bytes
wp-assets/screenshot-2.png | Bin 0 -> 42368 bytes
wp-assets/screenshot-3.png | Bin 0 -> 97918 bytes
wp-assets/screenshot-4.png | Bin 0 -> 251913 bytes
wp-assets/screenshot-5.png | Bin 0 -> 134660 bytes
wp-assets/screenshot-6.png | Bin 0 -> 129375 bytes
wp-assets/screenshot-7.png | Bin 0 -> 189440 bytes
9 files changed, 41 insertions(+)
create mode 100644 wp-assets/screenshot-1.png
create mode 100644 wp-assets/screenshot-2.png
create mode 100644 wp-assets/screenshot-3.png
create mode 100644 wp-assets/screenshot-4.png
create mode 100644 wp-assets/screenshot-5.png
create mode 100644 wp-assets/screenshot-6.png
create mode 100644 wp-assets/screenshot-7.png
diff --git a/readme.md b/readme.md
index 9b6a2d79..9bcca55a 100644
--- a/readme.md
+++ b/readme.md
@@ -21,6 +21,36 @@ Requires PHP 5.3+.
**Development of this plugin is done [on GitHub](https://github.com/xwp/wp-customize-snapshots). Pull requests welcome. Please see [issues](https://github.com/xwp/wp-customize-snapshots) reported there before going to the [plugin forum](https://wordpress.org/support/plugin/customize-snapshots).**
+## Screenshots ##
+
+### The “Save & Publish” button is broken up into separate “Save” and “Publish” buttons. The “Save” button creates a snapshot and turns into “Update” to save a new snapshot.
+
+![The “Save & Publish” button is broken up into separate “Save” and “Publish” buttons. The “Save” button creates a snapshot and turns into “Update” to save a new snapshot.](wp-assets/screenshot-1.png)
+
+### For non-administrator users (who lack the new `customize_publish` capability) the “Publish” button is replaced with a “Submit” button. This takes the snapshot and puts it into a pending status.
+
+![For non-administrator users (who lack the new `customize_publish` capability) the “Publish” button is replaced with a “Submit” button. This takes the snapshot and puts it into a pending status.](wp-assets/screenshot-2.png)
+
+### Saving snapshot causes the snapshot UUID to appear in the URL, allowing it to be bookmarked to easily come back to later. Upon publishing, the UUID will be removed from the URL so a new snapshot can be started made.
+
+![Saving snapshot causes the snapshot UUID to appear in the URL, allowing it to be bookmarked to easily come back to later. Upon publishing, the UUID will be removed from the URL so a new snapshot can be started made.](wp-assets/screenshot-3.png)
+
+### The Snapshots admin page lists out all of the snapshots in the system. When the excerpt view is turned on, a list of the settings modified in the snapshot can be seen.
+
+![The Snapshots admin page lists out all of the snapshots in the system. When the excerpt view is turned on, a list of the settings modified in the snapshot can be seen.](wp-assets/screenshot-4.png)
+
+### Viewing a snapshot post in the admin shows all of the modified settings contained within it. A link is provided to open the snapshot in the Customizer to continue making changes.
+
+![Viewing a snapshot post in the admin shows all of the modified settings contained within it. A link is provided to open the snapshot in the Customizer to continue making changes.](wp-assets/screenshot-5.png)
+
+### Published snapshots are shown in the admin screen but lack the ability to open in the Customizer, as they are intended to be frozen revisions for when the Customizer was saved.
+
+![Published snapshots are shown in the admin screen but lack the ability to open in the Customizer, as they are intended to be frozen revisions for when the Customizer was saved.](wp-assets/screenshot-6.png)
+
+### Changes to snapshots are captured in revisions.
+
+![Changes to snapshots are captured in revisions.](wp-assets/screenshot-7.png)
+
## Changelog ##
### 0.4.0 - 2016-06-11 ###
diff --git a/readme.txt b/readme.txt
index 04c0dd85..b6191db9 100644
--- a/readme.txt
+++ b/readme.txt
@@ -17,6 +17,17 @@ Requires PHP 5.3+.
**Development of this plugin is done [on GitHub](https://github.com/xwp/wp-customize-snapshots). Pull requests welcome. Please see [issues](https://github.com/xwp/wp-customize-snapshots) reported there before going to the [plugin forum](https://wordpress.org/support/plugin/customize-snapshots).**
+
+== Screenshots ==
+
+1. The “Save & Publish” button is broken up into separate “Save” and “Publish” buttons. The “Save” button creates a snapshot and turns into “Update” to save a new snapshot.
+2. For non-administrator users (who lack the new `customize_publish` capability) the “Publish” button is replaced with a “Submit” button. This takes the snapshot and puts it into a pending status.
+3. Saving snapshot causes the snapshot UUID to appear in the URL, allowing it to be bookmarked to easily come back to later. Upon publishing, the UUID will be removed from the URL so a new snapshot can be started made.
+4. The Snapshots admin page lists out all of the snapshots in the system. When the excerpt view is turned on, a list of the settings modified in the snapshot can be seen.
+5. Viewing a snapshot post in the admin shows all of the modified settings contained within it. A link is provided to open the snapshot in the Customizer to continue making changes.
+6. Published snapshots are shown in the admin screen but lack the ability to open in the Customizer, as they are intended to be frozen revisions for when the Customizer was saved.
+7. Changes to snapshots are captured in revisions.
+
== Changelog ==
= 0.4.0 - 2016-06-11 =
diff --git a/wp-assets/screenshot-1.png b/wp-assets/screenshot-1.png
new file mode 100644
index 0000000000000000000000000000000000000000..88060c1f27fc5082b40f8c836142a7c7afd0f55e
GIT binary patch
literal 28654
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