Changeset 1430660
- Timestamp:
- 06/05/2016 03:10:19 AM (10 years ago)
- Location:
- customize-posts/trunk
- Files:
-
- 4 added
- 1 deleted
- 29 edited
-
css/customize-posts.css (modified) (7 diffs)
-
css/customize-posts.min.css (modified) (1 diff)
-
customize-posts.php (modified) (1 diff)
-
js/customize-base-extensions.min.js (deleted)
-
js/customize-dynamic-control.js (modified) (1 diff)
-
js/customize-dynamic-control.min.js (modified) (1 diff)
-
js/customize-post-field-partial.js (modified) (2 diffs)
-
js/customize-post-field-partial.min.js (modified) (1 diff)
-
js/customize-post-section.js (modified) (29 diffs)
-
js/customize-post-section.min.js (modified) (1 diff)
-
js/customize-posts-panel.js (modified) (3 diffs)
-
js/customize-posts-panel.min.js (modified) (1 diff)
-
js/customize-posts.js (modified) (9 diffs)
-
js/customize-posts.min.js (modified) (1 diff)
-
js/customize-preview-posts.js (modified) (3 diffs)
-
js/customize-preview-posts.min.js (modified) (1 diff)
-
js/edit-post-preview-admin.js (modified) (1 diff)
-
php/class-customize-posts-plugin-support.php (added)
-
php/class-customize-posts-plugin.php (modified) (18 diffs)
-
php/class-customize-posts-support.php (added)
-
php/class-customize-posts-theme-support.php (added)
-
php/class-edit-post-preview.php (modified) (2 diffs)
-
php/class-wp-customize-dynamic-control.php (modified) (1 diff)
-
php/class-wp-customize-featured-image-controller.php (modified) (2 diffs)
-
php/class-wp-customize-page-template-controller.php (modified) (1 diff)
-
php/class-wp-customize-post-discussion-fields-control.php (modified) (1 diff)
-
php/class-wp-customize-post-field-partial.php (modified) (5 diffs)
-
php/class-wp-customize-post-setting.php (modified) (9 diffs)
-
php/class-wp-customize-postmeta-controller.php (modified) (5 diffs)
-
php/class-wp-customize-postmeta-setting.php (modified) (4 diffs)
-
php/class-wp-customize-posts-preview.php (modified) (10 diffs)
-
php/class-wp-customize-posts.php (modified) (13 diffs)
-
php/theme-support (added)
-
readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
customize-posts/trunk/css/customize-posts.css
r1406933 r1430660 1 /* In case Customize Setting Validation is not active */2 div.customize-setting-validation-message.error {3 display: none;4 }5 1 6 2 .customize-posts-panel-notice { … … 11 7 } 12 8 9 .customize-posts-trashed { 10 font-weight: normal; 11 } 12 13 #customize-controls .accordion-section.is-trashed .accordion-section-title { 14 opacity: .5; 15 } 16 13 17 .customize-section-title > div.customize-setting-validation-message { 14 18 border-top: 1px solid #ddd; … … 16 20 margin-bottom: 0; 17 21 } 18 .customize-setting-validation-message .override-post-conflict { 22 23 .customize-control-notifications-container .override-post-conflict { 19 24 margin-left: 1ex; 20 25 float: right; 26 } 27 28 #customize-controls .control-panel-posts .customize-info { 29 margin-bottom: 0; 30 } 31 32 #customize-controls .customize-posts-navigation { 33 position: absolute; 34 top: 4px; 35 right: 1px; 36 padding: 20px; 37 width: 20px; 38 height: 20px; 39 cursor: pointer; 40 -webkit-appearance: none; 41 background: transparent; 42 color: #555; 43 border: none; 44 } 45 46 #customize-controls .customize-posts-navigation:before { 47 padding: 4px; 48 position: absolute; 49 top: 6px; 50 left: 6px; 51 -webkit-border-radius: 100%; 52 border-radius: 100%; 53 } 54 55 #customize-controls .customize-posts-navigation:focus:before { 56 -webkit-box-shadow: 57 0 0 0 1px #5b9dd9, 58 0 0 2px 1px rgba(30, 140, 190, .8); 59 box-shadow: 60 0 0 0 1px #5b9dd9, 61 0 0 2px 1px rgba(30, 140, 190, .8); 62 } 63 64 #customize-controls .customize-posts-navigation:focus, 65 #customize-controls .customize-posts-navigation:hover { 66 color: #0073aa; 67 } 68 69 #customize-controls .customize-posts-navigation:focus { 70 outline: none; 71 } 72 73 .customize-posts-add-new { 74 padding: 15px 12px; 75 margin: 0; 76 overflow: hidden; 77 } 78 79 .customize-posts-add-new .add-new-post-stub { 80 float: right; 81 } 82 83 .customize-posts-add-new .add-new-post-stub:before { 84 content: "\f132"; 85 display: inline-block; 86 position: relative; 87 left: -2px; 88 top: -1px; 89 font: normal 20px/1 dashicons; 90 vertical-align: middle; 91 -webkit-transition: all 0.2s; 92 transition: all 0.2s; 93 -webkit-font-smoothing: antialiased; 94 -moz-osx-font-smoothing: grayscale; 21 95 } 22 96 … … 31 105 background: #f1f1f1; 32 106 display: block; 33 -webkit-transition: bottom 0.2s; 34 transition: bottom 0.2s; 35 36 /* @todo This should have visibility:hidden to ensure accessible when closed. */ 107 -webkit-transition: all 0.2s; 108 transition: all 0.2s; 109 visibility: hidden; 110 } 111 112 body.customize-posts-content-editor-pane-resize #customize-preview, 113 body.customize-posts-content-editor-pane-resize #customize-posts-content-editor-pane { 114 -webkit-transition: none; 115 transition: none; 37 116 } 38 117 … … 43 122 body.customize-posts-content-editor-pane-open #customize-posts-content-editor-pane { 44 123 bottom: 0; 124 visibility: inherit; 45 125 } 46 126 … … 75 155 } 76 156 157 /* vertical resize bar */ 158 #customize-posts-content-editor-dragbar { 159 top: 0; 160 cursor: row-resize; 161 display: block; 162 height: 4px; 163 position: absolute; 164 width: 100%; 165 z-index: 21; 166 } 167 168 body.customize-posts-content-editor-pane-resize #customize-preview:before { 169 top: 0; 170 right: 0; 171 bottom: 0; 172 left: 0; 173 position: absolute; 174 height: 100%; 175 width: 100%; 176 z-index: 999999; 177 } 178 77 179 /* @todo Mobile support for rich text editor */ 78 180 … … 96 198 } 97 199 98 @media screen and ( max-width: 782px ) { 99 body.customize-posts-content-editor-pane-open #customize-theme-controls [id^=accordion-panel-posts] ul.accordion-section-content { 100 padding-bottom: 300px; 101 } 102 } 200 .customize-posts-content-editor-pane-open .wp-full-overlay.collapsed .wp-full-overlay-sidebar { 201 z-index: 30; 202 } 203 .customize-posts-content-editor-pane-open .wp-full-overlay.collapsed .collapse-sidebar { 204 bottom: 308px; 205 } 206 .customize-posts-content-editor-pane-open .wp-full-overlay.expanded .collapse-sidebar { 207 bottom: 0 !important; 208 } 209 .customize-posts-content-editor-pane-resize .wp-full-overlay.collapsed .collapse-sidebar { 210 -webkit-transition: none; 211 transition: none; 212 } 213 .customize-posts-content-editor-pane-open.mce-fullscreen .wp-full-overlay.collapsed .collapse-sidebar { 214 bottom: 8px !important; 215 } -
customize-posts/trunk/css/customize-posts.min.css
r1406933 r1430660 1 div.customize-setting-validation-message.error{display:none}.customize-posts-panel-notice{color:#555;background:#fff;padding:12px 15px;border-top:1px solid #ddd}.customize-section-title>div.customize-setting-validation-message{border-top:1px solid #ddd;margin-top:0;margin-bottom:0}.customize-setting-validation-message .override-post-conflict{margin-left:1ex;float:right}#customize-posts-content-editor-pane{border-top:solid 1px #ddd;position:absolute;height:300px;bottom:-301px;right:0;left:0;z-index:20;background:#f1f1f1;display:block;-webkit-transition:bottom .2s;transition:bottom .2s}body.mce-fullscreen.customize-posts-content-editor-pane-open #customize-posts-content-editor-pane{top:0}body.customize-posts-content-editor-pane-open #customize-posts-content-editor-pane{bottom:0}#customize-posts-content-editor-pane .wp-editor-tools{padding-top:5px;padding-right:10px}#customize-posts-content-editor-pane .wp-media-buttons{padding-left:5px}#customize-preview{height:auto}body.customize-posts-content-editor-pane-open #customize-preview{bottom:300px}body.mce-fullscreen #customize-preview{bottom:0}body.mce-fullscreen.customize-posts-content-editor-pane-open div.mce-fullscreen{position:relative;left:0}#wp-customize-posts-content-editor-container{border-left:0}.wp-customizer .ui-autocomplete.wplink-autocomplete{z-index:500110}.wp-customizer #wp-link-wrap{z-index:500105}.wp-customizer #wp_editbtns,.wp-customizer #wp_gallerybtns{z-index:500020}.wp-customizer #TB_overlay,.wp-customizer #TB_window{z-index:500050}.wp-customizer .mce-panel,.wp-customizer .mce-tooltip{z-index:500100!important}@media screen and (max-width:782px){body.customize-posts-content-editor-pane-open #customize-theme-controls [id^=accordion-panel-posts] ul.accordion-section-content{padding-bottom:300px}}1 .customize-posts-panel-notice{color:#555;background:#fff;padding:12px 15px;border-top:1px solid #ddd}.customize-posts-trashed{font-weight:400}#customize-controls .accordion-section.is-trashed .accordion-section-title{opacity:.5}.customize-section-title>div.customize-setting-validation-message{border-top:1px solid #ddd;margin-top:0;margin-bottom:0}.customize-control-notifications-container .override-post-conflict{margin-left:1ex;float:right}#customize-controls .control-panel-posts .customize-info{margin-bottom:0}#customize-controls .customize-posts-navigation{position:absolute;top:4px;right:1px;padding:20px;width:20px;height:20px;cursor:pointer;-webkit-appearance:none;background:0 0;color:#555;border:none}#customize-controls .customize-posts-navigation:before{padding:4px;position:absolute;top:6px;left:6px;-webkit-border-radius:100%;border-radius:100%}#customize-controls .customize-posts-navigation:focus:before{-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}#customize-controls .customize-posts-navigation:focus,#customize-controls .customize-posts-navigation:hover{color:#0073aa}#customize-controls .customize-posts-navigation:focus{outline:0}.customize-posts-add-new{padding:15px 12px;margin:0;overflow:hidden}.customize-posts-add-new .add-new-post-stub{float:right}.customize-posts-add-new .add-new-post-stub:before{content:"\f132";display:inline-block;position:relative;left:-2px;top:-1px;font:400 20px/1 dashicons;vertical-align:middle;-webkit-transition:all .2s;transition:all .2s;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#customize-posts-content-editor-pane{border-top:solid 1px #ddd;position:absolute;height:300px;bottom:-301px;right:0;left:0;z-index:20;background:#f1f1f1;display:block;-webkit-transition:all .2s;transition:all .2s;visibility:hidden}body.customize-posts-content-editor-pane-resize #customize-posts-content-editor-pane,body.customize-posts-content-editor-pane-resize #customize-preview{-webkit-transition:none;transition:none}body.mce-fullscreen.customize-posts-content-editor-pane-open #customize-posts-content-editor-pane{top:0}body.customize-posts-content-editor-pane-open #customize-posts-content-editor-pane{bottom:0;visibility:inherit}#customize-posts-content-editor-pane .wp-editor-tools{padding-top:5px;padding-right:10px}#customize-posts-content-editor-pane .wp-media-buttons{padding-left:5px}#customize-preview{height:auto}body.customize-posts-content-editor-pane-open #customize-preview{bottom:300px}body.mce-fullscreen #customize-preview{bottom:0}body.mce-fullscreen.customize-posts-content-editor-pane-open div.mce-fullscreen{position:relative;left:0}#wp-customize-posts-content-editor-container{border-left:0}#customize-posts-content-editor-dragbar{top:0;cursor:row-resize;display:block;height:4px;position:absolute;width:100%;z-index:21}body.customize-posts-content-editor-pane-resize #customize-preview:before{top:0;right:0;bottom:0;left:0;position:absolute;height:100%;width:100%;z-index:999999}.wp-customizer .ui-autocomplete.wplink-autocomplete{z-index:500110}.wp-customizer #wp-link-wrap{z-index:500105}.wp-customizer #wp_editbtns,.wp-customizer #wp_gallerybtns{z-index:500020}.wp-customizer #TB_overlay,.wp-customizer #TB_window{z-index:500050}.wp-customizer .mce-panel,.wp-customizer .mce-tooltip{z-index:500100!important}.customize-posts-content-editor-pane-open .wp-full-overlay.collapsed .wp-full-overlay-sidebar{z-index:30}.customize-posts-content-editor-pane-open .wp-full-overlay.collapsed .collapse-sidebar{bottom:308px}.customize-posts-content-editor-pane-open .wp-full-overlay.expanded .collapse-sidebar{bottom:0!important}.customize-posts-content-editor-pane-resize .wp-full-overlay.collapsed .collapse-sidebar{-webkit-transition:none;transition:none}.customize-posts-content-editor-pane-open.mce-fullscreen .wp-full-overlay.collapsed .collapse-sidebar{bottom:8px!important} -
customize-posts/trunk/customize-posts.php
r1406933 r1430660 4 4 * Description: Manage posts and postmeta via the Customizer. Works best in conjunction with the <a href="https://wordpress.org/plugins/customize-setting-validation/">Customize Setting Validation</a> plugin. 5 5 * Plugin URI: https://github.com/xwp/wp-customize-posts/ 6 * Version: 0. 5.06 * Version: 0.6.0 7 7 * Author: XWP 8 8 * Author URI: https://make.xwp.co/ -
customize-posts/trunk/js/customize-dynamic-control.js
r1406933 r1430660 28 28 } 29 29 30 control.propertyElements = []; 30 31 api.Control.prototype.initialize.call( control, id, args ); 31 control.propertyElements = [];32 32 }, 33 33 -
customize-posts/trunk/js/customize-dynamic-control.min.js
r1406933 r1430660 1 !function(a,b){"use strict";a.DynamicControl=a.Control.extend({initialize:function(c,d){var e,f=this;e=d||{},e.params=e.params||{},e.params.type||(e.params.type="dynamic"),e.params.content||(e.params.content=b("<li></li>"),e.params.content.attr("id","customize-control-"+c.replace(/]/g,"").replace(/\[/g,"-")),e.params.content.attr("class","customize-control customize-control-"+e.params.type)), a.Control.prototype.initialize.call(f,c,e),f.propertyElements=[]},_setUpSettingRootLinks:function(){var c,d,e;c=this,d=c.container.find("[data-customize-setting-link]"),e={},d.each(function(){var f,g=b(this);if(g.is(":radio")){if(f=g.prop("name"),e[f])return;e[f]=!0,g=d.filter('[name="'+f+'"]')}a(g.data("customizeSettingLink"),function(b){var d=new a.Element(g);c.elements.push(d),d.sync(b),d.set(b())})})},_setUpSettingPropertyLinks:function(){var c,d,e=this;e.setting&&(c=e.container.find("[data-customize-setting-property-link]"),d={},c.each(function(){var f,g,h=b(this),i=h.data("customizeSettingPropertyLink");if(h.is(":radio")){if(f=h.prop("name"),d[f])return;d[f]=!0,h=c.filter('[name="'+f+'"]')}g=new a.Element(h),e.propertyElements.push(g),g.set(e.setting()[i]),g.bind(function(a){var b=e.setting();a!==b[i]&&(b=_.clone(b),b[i]=a,e.setting.set(b))}),e.setting.bind(function(a){a[i]!==g.get()&&g.set(a[i])})}))},ready:function(){var b=this;b._setUpSettingRootLinks(),b._setUpSettingPropertyLinks(),a.Control.prototype.ready.call(b),b.deferred.embedded.done(function(){})},embed:function(){var b=this,c=b.section();c&&a.section(c,function(c){c.expanded()||a.settings.autofocus.control===b.id?b.actuallyEmbed():c.expanded.bind(function(a){a&&b.actuallyEmbed()})})},actuallyEmbed:function(){var a=this;"resolved"!==a.deferred.embedded.state()&&(a.renderContent(),a.deferred.embedded.resolve())},focus:function(b){var c=this;c.actuallyEmbed(),a.Control.prototype.focus.call(c,b)}}),a.controlConstructor.dynamic=a.DynamicControl}(wp.customize,jQuery);1 !function(a,b){"use strict";a.DynamicControl=a.Control.extend({initialize:function(c,d){var e,f=this;e=d||{},e.params=e.params||{},e.params.type||(e.params.type="dynamic"),e.params.content||(e.params.content=b("<li></li>"),e.params.content.attr("id","customize-control-"+c.replace(/]/g,"").replace(/\[/g,"-")),e.params.content.attr("class","customize-control customize-control-"+e.params.type)),f.propertyElements=[],a.Control.prototype.initialize.call(f,c,e)},_setUpSettingRootLinks:function(){var c,d,e;c=this,d=c.container.find("[data-customize-setting-link]"),e={},d.each(function(){var f,g=b(this);if(g.is(":radio")){if(f=g.prop("name"),e[f])return;e[f]=!0,g=d.filter('[name="'+f+'"]')}a(g.data("customizeSettingLink"),function(b){var d=new a.Element(g);c.elements.push(d),d.sync(b),d.set(b())})})},_setUpSettingPropertyLinks:function(){var c,d,e=this;e.setting&&(c=e.container.find("[data-customize-setting-property-link]"),d={},c.each(function(){var f,g,h=b(this),i=h.data("customizeSettingPropertyLink");if(h.is(":radio")){if(f=h.prop("name"),d[f])return;d[f]=!0,h=c.filter('[name="'+f+'"]')}g=new a.Element(h),e.propertyElements.push(g),g.set(e.setting()[i]),g.bind(function(a){var b=e.setting();a!==b[i]&&(b=_.clone(b),b[i]=a,e.setting.set(b))}),e.setting.bind(function(a){a[i]!==g.get()&&g.set(a[i])})}))},ready:function(){var b=this;b._setUpSettingRootLinks(),b._setUpSettingPropertyLinks(),a.Control.prototype.ready.call(b),b.deferred.embedded.done(function(){})},embed:function(){var b=this,c=b.section();c&&a.section(c,function(c){c.expanded()||a.settings.autofocus.control===b.id?b.actuallyEmbed():c.expanded.bind(function(a){a&&b.actuallyEmbed()})})},actuallyEmbed:function(){var a=this;"resolved"!==a.deferred.embedded.state()&&(a.renderContent(),a.deferred.embedded.resolve())},focus:function(b){var c=this;c.actuallyEmbed(),a.Control.prototype.focus.call(c,b)}}),a.controlConstructor.dynamic=a.DynamicControl}(wp.customize,jQuery); -
customize-posts/trunk/js/customize-post-field-partial.js
r1406933 r1430660 22 22 */ 23 23 initialize: function( id, options ) { 24 var partial = this, args, matches, baseSelector, singularSelector,idPattern = /^post\[(.+?)]\[(-?\d+)]\[(.+?)](?:\[(.+?)])?$/;24 var partial = this, args, matches, idPattern = /^post\[(.+?)]\[(-?\d+)]\[(.+?)](?:\[(.+?)])?$/; 25 25 26 26 args = options || {}; … … 35 35 args.params.placement = matches[4] || ''; 36 36 37 if ( ! args.params.selector ) {38 baseSelector = '.hentry.post-' + String( args.params.post_id ) + '.type-' + args.params.post_type;39 singularSelector = '.postid-' + String( args.params.post_id ) + '.single-' + args.params.post_type;40 if ( 'post_title' === args.params.field_id ) {41 args.params.selector = baseSelector + ' .entry-title';42 } else if ( 'post_content' === args.params.field_id ) {43 args.params.selector = baseSelector + ' .entry-content';44 } else if ( 'post_excerpt' === args.params.field_id ) {45 args.params.selector = baseSelector + ' .entry-summary';46 } else if ( 'comment_status' === args.params.field_id ) {47 if ( 'comments-area' === args.params.placement ) {48 args.params.selector = singularSelector + ' .comments-area';49 } else if ( 'comments-link' === args.params.placement ) {50 args.params.selector = baseSelector + ' .comments-link';51 }52 } else if ( 'ping_status' === args.params.field_id ) {53 args.params.selector = singularSelector + ' .comments-area';54 } else if ( 'post_author' === args.params.field_id ) {55 if ( 'author-bio' === args.params.placement ) {56 args.params.selector = baseSelector + ' .author-info';57 } else if ( 'byline' === args.params.placement ) {58 args.params.selector = baseSelector + ' .vcard a.fn';59 } else if ( 'avatar' === args.params.placement ) {60 args.params.selector = baseSelector + ' .vcard img.avatar';61 }62 }63 }64 37 api.selectiveRefresh.Partial.prototype.initialize.call( partial, id, args ); 65 38 }, -
customize-posts/trunk/js/customize-post-field-partial.min.js
r1406933 r1430660 1 !function(a){"use strict";a.previewPosts||(a.previewPosts={}),a.previewPosts.PostFieldPartial=a.selectiveRefresh.Partial.extend({initialize:function(b,c){var d,e,f ,g,h=this,i=/^post\[(.+?)]\[(-?\d+)]\[(.+?)](?:\[(.+?)])?$/;if(d=c||{},d.params=d.params||{},e=b.match(i),!e)throw new Error("Bad PostFieldPartial id. Expected post[:post_type][:post_id][:field_id]");d.params.post_type=e[1],d.params.post_id=parseInt(e[2],10),d.params.field_id=e[3],d.params.placement=e[4]||"",d.params.selector||(f=".hentry.post-"+String(d.params.post_id)+".type-"+d.params.post_type,g=".postid-"+String(d.params.post_id)+".single-"+d.params.post_type,"post_title"===d.params.field_id?d.params.selector=f+" .entry-title":"post_content"===d.params.field_id?d.params.selector=f+" .entry-content":"post_excerpt"===d.params.field_id?d.params.selector=f+" .entry-summary":"comment_status"===d.params.field_id?"comments-area"===d.params.placement?d.params.selector=g+" .comments-area":"comments-link"===d.params.placement&&(d.params.selector=f+" .comments-link"):"ping_status"===d.params.field_id?d.params.selector=g+" .comments-area":"post_author"===d.params.field_id&&("author-bio"===d.params.placement?d.params.selector=f+" .author-info":"byline"===d.params.placement?d.params.selector=f+" .vcard a.fn":"avatar"===d.params.placement&&(d.params.selector=f+" .vcard img.avatar"))),a.selectiveRefresh.Partial.prototype.initialize.call(h,b,d)},showControl:function(){var b=this,c=b.params.primarySetting;c||(c=_.first(b.settings())),a.preview.send("focus-control",c+"["+b.params.field_id+"]")},isRelatedSetting:function(b,c,d){var e=this;return _.isObject(c)&&_.isObject(d)&&e.params.field_id&&c[e.params.field_id]===d[e.params.field_id]?!1:a.selectiveRefresh.Partial.prototype.isRelatedSetting.call(e,b)}}),a.selectiveRefresh.partialConstructor.post_field=a.previewPosts.PostFieldPartial}(wp.customize);1 !function(a){"use strict";a.previewPosts||(a.previewPosts={}),a.previewPosts.PostFieldPartial=a.selectiveRefresh.Partial.extend({initialize:function(b,c){var d,e,f=this,g=/^post\[(.+?)]\[(-?\d+)]\[(.+?)](?:\[(.+?)])?$/;if(d=c||{},d.params=d.params||{},e=b.match(g),!e)throw new Error("Bad PostFieldPartial id. Expected post[:post_type][:post_id][:field_id]");d.params.post_type=e[1],d.params.post_id=parseInt(e[2],10),d.params.field_id=e[3],d.params.placement=e[4]||"",a.selectiveRefresh.Partial.prototype.initialize.call(f,b,d)},showControl:function(){var b=this,c=b.params.primarySetting;c||(c=_.first(b.settings())),a.preview.send("focus-control",c+"["+b.params.field_id+"]")},isRelatedSetting:function(b,c,d){var e=this;return _.isObject(c)&&_.isObject(d)&&e.params.field_id&&c[e.params.field_id]===d[e.params.field_id]?!1:a.selectiveRefresh.Partial.prototype.isRelatedSetting.call(e,b)}}),a.selectiveRefresh.partialConstructor.post_field=a.previewPosts.PostFieldPartial}(wp.customize); -
customize-posts/trunk/js/customize-post-section.js
r1406933 r1430660 1 1 /* global wp, tinyMCE */ 2 /* eslint consistent-this: [ "error", "section" ] */2 /* eslint consistent-this: [ "error", "section" ], no-magic-numbers: [ "error", { "ignore": [-1,0,1] } ] */ 3 3 4 4 (function( api, $ ) { … … 75 75 76 76 api.Section.prototype.initialize.call( section, id, args ); 77 }, 78 79 /** 77 78 section.active.validate = function( active ) { 79 var setting = api( section.id ); 80 if ( setting ) { 81 return setting._dirty || active; 82 } else { 83 return true; 84 } 85 }; 86 }, 87 88 /** 89 * Ready. 90 * 80 91 * @todo Defer embedding section until panel is expanded? 92 * 93 * @returns {void} 81 94 */ 82 95 ready: function() { … … 85 98 section.setupTitleUpdating(); 86 99 section.setupSettingValidation(); 100 section.setupPostNavigation(); 87 101 section.setupControls(); 88 102 … … 95 109 /** 96 110 * Keep the title updated in the UI when the title updates in the setting. 111 * 112 * @returns {void} 97 113 */ 98 114 setupTitleUpdating: function() { … … 106 122 setting.bind( function( newPostData, oldPostData ) { 107 123 var title; 108 if ( newPostData.post_title !== oldPostData.post_title ) {124 if ( newPostData.post_title !== oldPostData.post_title && 'trash' !== newPostData.post_status ) { 109 125 title = newPostData.post_title || api.Posts.data.l10n.noTitle; 110 126 sectionOuterTitleElement.text( title ); … … 116 132 117 133 /** 134 * Reload the pane based on the current posts preview url. 135 * 136 * @returns {void} 137 */ 138 setupPostNavigation: function() { 139 var section = this, 140 sectionNavigationButton, 141 sectionContainer = section.container.closest( '.accordion-section' ), 142 sectionTitle = sectionContainer.find( '.customize-section-title:first' ), 143 sectionNavigationButtonTemplate = wp.template( 'customize-posts-navigation' ), 144 postTypeObj = api.Posts.data.postTypes[ section.params.post_type ]; 145 146 // Short-circuit showing a link if the post type is not publicly queryable anyway. 147 if ( ! postTypeObj['public'] ) { 148 return; 149 } 150 151 sectionNavigationButton = $( sectionNavigationButtonTemplate( { 152 label: postTypeObj.labels.singular_name 153 } ) ); 154 sectionTitle.append( sectionNavigationButton ); 155 156 // Hide the link when the post is currently in the preview. 157 api.previewer.bind( 'customized-posts', function( data ) { 158 sectionNavigationButton.toggle( section.params.post_id !== data.queriedPostId ); 159 } ); 160 161 sectionNavigationButton.on( 'click', function( event ) { 162 event.preventDefault(); 163 api.previewer.previewUrl( api.Posts.getPreviewUrl( section.params ) ); 164 } ); 165 }, 166 167 /** 118 168 * Set up the post field controls. 169 * 170 * @returns {void} 119 171 */ 120 172 setupControls: function() { … … 125 177 section.addTitleControl(); 126 178 } 179 if ( postTypeObj.supports.title || postTypeObj.supports.slug ) { 180 section.addSlugControl(); 181 } 182 if ( 'undefined' === typeof EditPostPreviewCustomize ) { 183 section.addPostStatusControl(); 184 } 127 185 if ( postTypeObj.supports.editor ) { 128 186 section.addContentControl(); … … 140 198 141 199 /** 200 * Prevent notifications for settings from being added to post field control notifications. 201 * 202 * @param {string} code Notification code. 203 * @param {wp.customize.Notification} notification Notification object. 204 * @returns {wp.customize.Notification|null} Notification if not bypassed. 205 */ 206 addPostFieldControlNotification: function( code, notification ) { 207 if ( -1 !== code.indexOf( ':' ) ) { 208 return null; 209 } else { 210 return api.Values.prototype.add.call( this, code, notification ); 211 } 212 }, 213 214 /** 142 215 * Add post title control. 143 216 * 144 * @returns {wp.customize.Control} 217 * @returns {wp.customize.Control} Added control. 145 218 */ 146 219 addTitleControl: function() { … … 169 242 api.control.add( control.id, control ); 170 243 171 // Remove the setting from the settingValidationMessages since it is not specific to this field. 172 if ( control.settingValidationMessages ) { 173 control.settingValidationMessages.remove( setting.id ); 174 control.settingValidationMessages.add( control.id, new api.Value( '' ) ); 244 if ( control.notifications ) { 245 control.notifications.add = section.addPostFieldControlNotification; 175 246 } 176 247 return control; … … 178 249 179 250 /** 251 * Add post slug control. 252 * 253 * @returns {wp.customize.Control} Added control. 254 */ 255 addSlugControl: function() { 256 var section = this, control, setting = api( section.id ); 257 control = new api.controlConstructor.dynamic( section.id + '[post_name]', { 258 params: { 259 section: section.id, 260 priority: 15, 261 label: api.Posts.data.l10n.fieldSlugLabel, 262 active: true, 263 settings: { 264 'default': setting.id 265 }, 266 field_type: 'text', 267 setting_property: 'post_name' 268 } 269 } ); 270 271 // Supply a placeholder for the input field to approximate how an empty slug will be derived from the title. 272 control.deferred.embedded.done( function() { 273 var input = control.container.find( 'input' ); 274 function setPlaceholder() { 275 var slug = api.Posts.sanitizeTitleWithDashes( setting.get().post_title ); 276 input.prop( 'placeholder', slug ); 277 } 278 setPlaceholder(); 279 setting.bind( setPlaceholder ); 280 } ); 281 282 // Override preview trying to de-activate control not present in preview context. 283 control.active.validate = function() { 284 return true; 285 }; 286 287 // Register. 288 section.postFieldControls.post_name = control; 289 api.control.add( control.id, control ); 290 291 if ( control.notifications ) { 292 control.notifications.add = section.addPostFieldControlNotification; 293 } 294 return control; 295 }, 296 297 /** 298 * Add post status control. 299 * 300 * @returns {wp.customize.Control} Added control. 301 */ 302 addPostStatusControl: function() { 303 var section = this, control, setting = api( section.id ), sectionContainer, sectionTitle; 304 305 sectionContainer = section.container.closest( '.accordion-section' ); 306 sectionTitle = sectionContainer.find( '.accordion-section-title:first' ); 307 308 control = new api.controlConstructor.dynamic( section.id + '[post_status]', { 309 params: { 310 section: section.id, 311 priority: 20, 312 label: api.Posts.data.l10n.fieldPostStatusLabel, 313 active: true, 314 settings: { 315 'default': setting.id 316 }, 317 field_type: 'select', 318 setting_property: 'post_status', 319 choices: api.Posts.data.postStatusChoices 320 } 321 } ); 322 323 /** 324 * Update the UI when a post is transitioned from/to trash. 325 * 326 * @param {boolean} trashed - Whether or not the post_status is 'trash'. 327 * @returns {void} 328 */ 329 control.toggleTrash = function( trashed ) { 330 sectionContainer.toggleClass( 'is-trashed', trashed ); 331 if ( true === trashed ) { 332 if ( 0 === sectionTitle.find( '.customize-posts-trashed' ).length ) { 333 sectionTitle.append( wp.template( 'customize-posts-trashed' )() ); 334 } 335 } else { 336 sectionContainer.find( '.customize-posts-trashed' ).remove(); 337 } 338 }; 339 340 /** 341 * Update the status UI when the setting changes its state. 342 */ 343 setting.bind( function( newPostData, oldPostData ) { 344 if ( newPostData.post_status !== oldPostData.post_status ) { 345 control.toggleTrash( 'trash' === newPostData.post_status ); 346 } 347 } ); 348 349 // Override preview trying to de-activate control not present in preview context. 350 control.active.validate = function() { 351 return true; 352 }; 353 354 // Register. 355 section.postFieldControls.post_status = control; 356 api.control.add( control.id, control ); 357 358 // Initialize the trashed UI. 359 api.panel( 'posts[' + section.params.post_type + ']' ).expanded.bind( function() { 360 control.toggleTrash( 'trash' === setting.get().post_status ); 361 } ); 362 363 control.deferred.embedded.done( function() { 364 var embeddedDelay = 50; 365 366 _.delay( function() { 367 control.toggleTrash( 'trash' === setting.get().post_status ); 368 }, embeddedDelay ); 369 } ); 370 371 if ( control.notifications ) { 372 control.notifications.add = section.addPostFieldControlNotification; 373 } 374 return control; 375 }, 376 377 /** 180 378 * Add post content control. 181 379 * 182 380 * @todo It is hacky how the dynamic control is overloaded to connect to the shared TinyMCE editor. 183 381 * 184 * @returns {wp.customize.Control} 382 * @returns {wp.customize.Control} Added control. 185 383 */ 186 384 addContentControl: function() { 187 var section = this, control, setting = api( section.id ); 385 var section = this, 386 control, 387 setting = api( section.id ), 388 preview = $( '#customize-preview' ), 389 editorPane = $( '#customize-posts-content-editor-pane' ), 390 editorFrame = $( '#customize-posts-content_ifr' ), 391 mceTools = $( '#wp-customize-posts-content-editor-tools' ), 392 mceToolbar = $( '.mce-toolbar-grp' ), 393 mceStatusbar = $( '.mce-statusbar' ), 394 dragbar = $( '#customize-posts-content-editor-dragbar' ), 395 collapse = $( '.collapse-sidebar' ), 396 resizeHeight; 188 397 189 398 control = new api.controlConstructor.dynamic( section.id + '[post_content]', { 190 399 params: { 191 400 section: section.id, 192 priority: 2 0,401 priority: 25, 193 402 label: api.Posts.data.l10n.fieldContentLabel, 194 403 active: true, … … 209 418 /** 210 419 * Update the setting value when the editor changes its state. 420 * 421 * @returns {void} 211 422 */ 212 423 control.onVisualEditorChange = function() { … … 224 435 /** 225 436 * Update the setting value when the editor changes its state. 437 * 438 * @returns {void} 226 439 */ 227 440 control.onTextEditorChange = function() { … … 262 475 editor.on( 'input change keyup', control.onVisualEditorChange ); 263 476 textarea.on( 'input', control.onTextEditorChange ); 477 control.resizeEditor( window.innerHeight - editorPane.height() ); 264 478 } else { 265 479 editor.off( 'input change keyup', control.onVisualEditorChange ); … … 269 483 editor.execCommand( 'wp_link_cancel' ); 270 484 $( '.mce-active' ).click(); 485 preview.css( 'bottom', '' ); 486 collapse.css( 'bottom', '' ); 271 487 } 272 488 } ); … … 298 514 * Expand the editor and focus on it when the post content control is focused. 299 515 * 300 * @param args 516 * @param {object} args Focus args. 517 * @returns {void} 301 518 */ 302 519 control.focus = function( args ) { … … 306 523 editor.focus(); 307 524 }; 525 526 /** 527 * Vertically Resize Expanded Post Editor. 528 * 529 * @param {int} position - The position of the post editor from the top of the browser window. 530 * @returns {void} 531 */ 532 control.resizeEditor = function( position ) { 533 var windowHeight = window.innerHeight, 534 windowWidth = window.innerWidth, 535 sectionContent = $( '[id^=accordion-panel-posts] ul.accordion-section-content' ), 536 minScroll = 40, 537 maxScroll = 1, 538 mobileWidth = 782, 539 collapseMinSpacing = 56, 540 collapseBottomOutsideEditor = 8, 541 collapseBottomInsideEditor = 4, 542 args = {}; 543 544 if ( ! $( document.body ).hasClass( 'customize-posts-content-editor-pane-open' ) ) { 545 return; 546 } 547 548 if ( ! _.isNaN( position ) ) { 549 resizeHeight = windowHeight - position; 550 } 551 552 args.height = resizeHeight; 553 args.components = mceTools.outerHeight() + mceToolbar.outerHeight() + mceStatusbar.outerHeight(); 554 555 if ( resizeHeight < minScroll ) { 556 args.height = minScroll; 557 } 558 559 if ( resizeHeight > windowHeight - maxScroll ) { 560 args.height = windowHeight - maxScroll; 561 } 562 563 if ( windowHeight < editorPane.outerHeight() ) { 564 args.height = windowHeight; 565 } 566 567 preview.css( 'bottom', args.height ); 568 editorPane.css( 'height', args.height ); 569 editorFrame.css( 'height', args.height - args.components ); 570 collapse.css( 'bottom', args.height + collapseBottomOutsideEditor ); 571 572 if ( collapseMinSpacing > windowHeight - args.height ) { 573 collapse.css( 'bottom', mceStatusbar.outerHeight() + collapseBottomInsideEditor ); 574 } 575 576 if ( windowWidth <= mobileWidth ) { 577 sectionContent.css( 'padding-bottom', args.height ); 578 } else { 579 sectionContent.css( 'padding-bottom', '' ); 580 } 581 }; 582 583 // Resize the editor. 584 dragbar.on( 'mousedown', function() { 585 if ( ! section.expanded() ) { 586 return; 587 } 588 $( document ).on( 'mousemove.customize-posts-editor', function( event ) { 589 event.preventDefault(); 590 $( document.body ).addClass( 'customize-posts-content-editor-pane-resize' ); 591 editorFrame.css( 'pointer-events', 'none' ); 592 control.resizeEditor( event.pageY ); 593 } ); 594 } ); 595 596 // Remove editor resize. 597 dragbar.on( 'mouseup', function() { 598 if ( ! section.expanded() ) { 599 return; 600 } 601 $( document ).off( 'mousemove.customize-posts-editor' ); 602 $( document.body ).removeClass( 'customize-posts-content-editor-pane-resize' ); 603 editorFrame.css( 'pointer-events', '' ); 604 } ); 605 606 // Resize the editor when the viewport changes. 607 $( window ).on( 'resize', function() { 608 var resizeDelay = 50; 609 if ( ! section.expanded() ) { 610 return; 611 } 612 _.delay( function() { 613 control.resizeEditor( window.innerHeight - editorPane.height() ); 614 }, resizeDelay ); 615 } ); 308 616 309 617 // Override preview trying to de-activate control not present in preview context. … … 325 633 } ); 326 634 327 // Remove the setting from the settingValidationMessages since it is not specific to this field. 328 if ( control.settingValidationMessages ) { 329 control.settingValidationMessages.remove( setting.id ); 330 control.settingValidationMessages.add( control.id, new api.Value( '' ) ); 635 if ( control.notifications ) { 636 control.notifications.add = section.addPostFieldControlNotification; 331 637 } 332 638 return control; … … 336 642 * Add post excerpt control. 337 643 * 338 * @returns {wp.customize.Control} 644 * @returns {wp.customize.Control} Added control. 339 645 */ 340 646 addExcerptControl: function() { … … 363 669 api.control.add( control.id, control ); 364 670 365 // Remove the setting from the settingValidationMessages since it is not specific to this field. 366 if ( control.settingValidationMessages ) { 367 control.settingValidationMessages.remove( setting.id ); 368 control.settingValidationMessages.add( control.id, new api.Value( '' ) ); 671 if ( control.notifications ) { 672 control.notifications.add = section.addPostFieldControlNotification; 369 673 } 370 674 return control; … … 374 678 * Add discussion fields (comments and ping status fields) control. 375 679 * 376 * @returns {wp.customize.Control} 680 * @returns {wp.customize.Control} Added control. 377 681 */ 378 682 addDiscussionFieldsControl: function() { … … 401 705 api.control.add( control.id, control ); 402 706 403 // Remove the setting from the settingValidationMessages since it is not specific to this field. 404 if ( control.settingValidationMessages ) { 405 control.settingValidationMessages.remove( setting.id ); 406 control.settingValidationMessages.add( control.id, new api.Value( '' ) ); 707 if ( control.notifications ) { 708 control.notifications.add = section.addPostFieldControlNotification; 407 709 } 408 710 return control; … … 412 714 * Add post author control. 413 715 * 414 * @returns {wp.customize.Control} 716 * @returns {wp.customize.Control} Added control. 415 717 */ 416 718 addAuthorControl: function() { … … 440 742 api.control.add( control.id, control ); 441 743 442 // Remove the setting from the settingValidationMessages since it is not specific to this field. 443 if ( control.settingValidationMessages ) { 444 control.settingValidationMessages.remove( setting.id ); 445 control.settingValidationMessages.add( control.id, new api.Value( '' ) ); 744 if ( control.notifications ) { 745 control.notifications.add = section.addPostFieldControlNotification; 446 746 } 447 747 return control; … … 450 750 /** 451 751 * Set up setting validation. 752 * 753 * @returns {void} 452 754 */ 453 755 setupSettingValidation: function() { 454 var section = this, setting = api( section.id ) ;455 if ( ! setting. validationMessage) {756 var section = this, setting = api( section.id ), debouncedRenderNotifications; 757 if ( ! setting.notifications ) { 456 758 return; 457 759 } 458 760 459 section.validationMessageElement = $( '<div class="customize-setting-validation-message error" aria-live="assertive"></div>' ); 460 section.container.find( '.customize-section-title' ).append( section.validationMessageElement ); 461 setting.validationMessage.bind( function( message ) { 462 var template = wp.template( 'customize-setting-validation-message' ); 463 section.validationMessageElement.empty().append( $.trim( 464 template( { messages: [ message ] } ) 465 ) ); 466 if ( message ) { 467 section.validationMessageElement.slideDown( 'fast' ); 468 } else { 469 section.validationMessageElement.slideUp( 'fast' ); 470 } 471 section.container.toggleClass( 'customize-setting-invalid', '' !== message ); 472 } ); 761 // Add the notifications API. 762 section.notifications = new api.Values({ defaultConstructor: api.Notification }); 763 section.notificationsContainer = $( '<div class="customize-control-notifications-container"></div>' ); 764 section.notificationsTemplate = wp.template( 'customize-post-section-notifications' ); 765 section.container.find( '.customize-section-title' ).after( section.notificationsContainer ); 766 section.getNotificationsContainerElement = function() { 767 return section.notificationsContainer; 768 }; 769 section.renderNotifications = api.Control.prototype.renderNotifications; 770 771 // Sync setting notifications into the section notifications 772 setting.notifications.bind( 'add', function( settingNotification ) { 773 var notification = new api.Notification( setting.id + ':' + settingNotification.code, settingNotification ); 774 section.notifications.add( notification.code, notification ); 775 } ); 776 setting.notifications.bind( 'remove', function( settingNotification ) { 777 section.notifications.remove( setting.id + ':' + settingNotification.code ); 778 } ); 779 780 /* 781 * Render notifications when the collection is updated. 782 * Note that this debounced/deferred rendering is needed for two reasons: 783 * 1) The 'remove' event is triggered just _before_ the notification is actually removed. 784 * 2) Improve performance when adding/removing multiple notifications at a time. 785 */ 786 debouncedRenderNotifications = _.debounce( function renderNotifications() { 787 section.renderNotifications(); 788 } ); 789 section.notifications.bind( 'add', function( notification ) { 790 wp.a11y.speak( notification.message, 'assertive' ); 791 debouncedRenderNotifications(); 792 } ); 793 section.notifications.bind( 'remove', debouncedRenderNotifications ); 794 section.renderNotifications(); 473 795 474 796 // Dismiss conflict block when clicking on button. 475 section. validationMessageElement.on( 'click', '.override-post-conflict', function( e ) {797 section.notificationsContainer.on( 'click', '.override-post-conflict', function( e ) { 476 798 var ourValue; 477 799 e.preventDefault(); … … 479 801 ourValue.post_modified_gmt = ''; 480 802 setting.set( ourValue ); 481 section.resetPostFieldControlSettingValidationMessages(); 803 804 _.each( section.postFieldControls, function( control ) { 805 if ( control.notifications ) { 806 control.notifications.remove( 'post_update_conflict' ); 807 } 808 } ); 809 setting.notifications.remove( 'post_update_conflict' ); 482 810 } ); 483 811 484 812 // Detect conflict errors. 485 813 api.bind( 'error', function( response ) { 486 var theirValue, ourValue , overrideButton, wasOverrideButtonAdded = false;814 var theirValue, ourValue; 487 815 if ( ! response.update_conflicted_setting_values ) { 488 816 return; … … 494 822 ourValue = setting.get(); 495 823 _.each( theirValue, function( theirFieldValue, fieldId ) { 496 var control, validationMessage;824 var control, notification; 497 825 if ( 'post_modified' === fieldId || 'post_modified_gmt' === fieldId || theirFieldValue === ourValue[ fieldId ] ) { 498 826 return; 499 827 } 500 828 control = api.control( setting.id + '[' + fieldId + ']' ); 501 if ( control && control.settingValidationMessages && control.settingValidationMessages.has( control.id ) ) { 502 validationMessage = api.Posts.data.l10n.theirChange.replace( '%s', String( theirFieldValue ) ); 503 control.settingValidationMessages( control.id ).set( validationMessage ); 504 505 if ( ! wasOverrideButtonAdded ) { 506 overrideButton = $( '<button class="button override-post-conflict" type="button"></button>' ); 507 overrideButton.text( api.Posts.data.l10n.overrideButtonText ); 508 section.validationMessageElement.find( 'li:first' ).prepend( overrideButton ); 509 wasOverrideButtonAdded = true; 510 } 829 if ( control && control.notifications ) { 830 notification = new api.Notification( 'post_update_conflict', { 831 message: api.Posts.data.l10n.theirChange.replace( '%s', String( theirFieldValue ) ) 832 } ); 833 control.notifications.remove( notification.code ); 834 control.notifications.add( notification.code, notification ); 511 835 } 512 836 } ); … … 514 838 515 839 api.bind( 'save', function() { 516 section.resetPostFieldControl SettingValidationMessages();840 section.resetPostFieldControlErrorNotifications(); 517 841 } ); 518 842 }, … … 520 844 /** 521 845 * Reset all of the validation messages for all of the post fields in the section. 522 */ 523 resetPostFieldControlSettingValidationMessages: function() { 846 * 847 * @returns {void} 848 */ 849 resetPostFieldControlErrorNotifications: function() { 524 850 var section = this; 525 851 _.each( section.postFieldControls, function( postFieldControl ) { 526 if ( postFieldControl.settingValidationMessages ) { 527 postFieldControl.settingValidationMessages.each( function( validationMessage ) { 528 validationMessage.set( '' ); 852 if ( postFieldControl.notifications ) { 853 postFieldControl.notifications.each( function( notification ) { 854 if ( 'error' === notification.type ) { 855 postFieldControl.notifications.remove( notification.code ); 856 } 529 857 } ); 530 858 } … … 535 863 * Allow an active section to be contextually active even when it has no active controls. 536 864 * 537 * @returns {boolean} 865 * @returns {boolean} Active. 538 866 */ 539 867 isContextuallyActive: function() { -
customize-posts/trunk/js/customize-post-section.min.js
r1406933 r1430660 1 !function(a,b){"use strict";var c,d,e={};a.Posts||(a.Posts={}),c=a.Element.synchronizer.checkbox.update,d=a.Element.synchronizer.checkbox.refresh,_.extend(a.Element.synchronizer.checkbox,{update:function(a){var b;b=_.isUndefined(this.element.data("on-value"))||_.isUndefined(this.element.data("off-value"))?a:a===this.element.data("on-value"),c.call(this,b)},refresh:function(){return _.isUndefined(this.element.data("on-value"))||_.isUndefined(this.element.data("off-value"))?d.call(this):this.element.prop("checked")?this.element.data("on-value"):this.element.data("off-value")}}),a.Posts.PostSection=a.Section.extend({initialize:function(b,c){var d,f=this;if(d=c||{},d.params=d.params||{},!d.params.post_type||!a.Posts.data.postTypes[d.params.post_type])throw new Error("Missing post_type");if(_.isNaN(d.params.post_id))throw new Error("Missing post_id");if(!a.has(b))throw new Error("No setting id");d.params.title||(d.params.title=a(b).get().post_title),d.params.title||(d.params.title=a.Posts.data.l10n.noTitle),f.postFieldControls={},d.params.priority||(e[d.params.post_type]||(e[d.params.post_type]=a.Section.prototype.defaults.priority),e[d.params.post_type]+=1,d.params.priority=e[d.params.post_type]),a.Section.prototype.initialize.call(f,b,d) },ready:function(){var b=this;b.setupTitleUpdating(),b.setupSettingValidation(),b.setupControls(),a.Section.prototype.ready.call(b)},setupTitleUpdating:function(){var b,c,d,e,f=this,g=a(f.id);b=f.container.closest(".accordion-section"),c=b.find(".accordion-section-title:first"),d=b.find(".customize-section-title h3").first(),e=d.find(".customize-action").first(),g.bind(function(b,f){var g;b.post_title!==f.post_title&&(g=b.post_title||a.Posts.data.l10n.noTitle,c.text(g),d.text(g),d.prepend(e))})},setupControls:function(){var b,c=this;b=a.Posts.data.postTypes[c.params.post_type],b.supports.title&&c.addTitleControl(),b.supports.editor&&c.addContentControl(),b.supports.excerpt&&c.addExcerptControl(),(b.supports.comments||b.supports.trackbacks)&&c.addDiscussionFieldsControl(),b.supports.author&&c.addAuthorControl()},addTitleControl:function(){var b,c=this,d=a(c.id);return b=new a.controlConstructor.dynamic(c.id+"[post_title]",{params:{section:c.id,priority:10,label:a.Posts.data.l10n.fieldTitleLabel,active:!0,settings:{"default":d.id},field_type:"text",setting_property:"post_title"}}),b.active.validate=function(){return!0},c.postFieldControls.post_title=b,a.control.add(b.id,b),b.settingValidationMessages&&(b.settingValidationMessages.remove(d.id),b.settingValidationMessages.add(b.id,new a.Value(""))),b},addContentControl:function(){var c,d=this,e=a(d.id);return c=new a.controlConstructor.dynamic(d.id+"[post_content]",{params:{section:d.id,priority:20,label:a.Posts.data.l10n.fieldContentLabel,active:!0,settings:{"default":e.id},field_type:"textarea",setting_property:"post_content"}}),c.editorExpanded=new a.Value(!1),c.editorToggleExpandButton=b('<button type="button" class="button"></button>'),c.updateEditorToggleExpandButtonLabel=function(b){c.editorToggleExpandButton.text(b?a.Posts.data.l10n.closeEditor:a.Posts.data.l10n.openEditor)},c.updateEditorToggleExpandButtonLabel(c.editorExpanded.get()),c.onVisualEditorChange=function(){var a,b;c.editorSyncSuspended||(b=tinyMCE.get("customize-posts-content"),a=wp.editor.removep(b.getContent()),c.editorSyncSuspended=!0,c.propertyElements[0].set(a),c.editorSyncSuspended=!1)},c.onTextEditorChange=function(){c.editorSyncSuspended||(c.editorSyncSuspended=!0,c.propertyElements[0].set(b(this).val()),c.editorSyncSuspended=!1)},e.bind(function(a,b){var d;c.editorExpanded.get()&&!c.editorSyncSuspended&&a.post_content!==b.post_content&&(c.editorSyncSuspended=!0,d=tinyMCE.get("customize-posts-content"),d.setContent(wp.editor.autop(a.post_content)),c.editorSyncSuspended=!1)}),c.editorExpanded.bind(function(a){var d,f=b("#customize-posts-content");d=tinyMCE.get("customize-posts-content"),c.updateEditorToggleExpandButtonLabel(a),b(document.body).toggleClass("customize-posts-content-editor-pane-open",a),a?(d.setContent(wp.editor.autop(e().post_content)),d.on("input change keyup",c.onVisualEditorChange),f.on("input",c.onTextEditorChange)):(d.off("input change keyup",c.onVisualEditorChange),f.off("input",c.onTextEditorChange),d.execCommand("wp_link_cancel"),b(".mce-active").click())}),d.expanded.bind(function(b){b?a.Posts.postIdInput.val(d.params.post_id):(a.Posts.postIdInput.val(""),c.editorExpanded.set(!1))}),c.editorToggleExpandButton.on("click",function(){var a=tinyMCE.get("customize-posts-content");c.editorExpanded.set(!c.editorExpanded()),c.editorExpanded()&&a.focus()}),c.focus=function(b){var d=tinyMCE.get("customize-posts-content");a.controlConstructor.dynamic.prototype.focus.call(c,b),c.editorExpanded.set(!0),d.focus()},c.active.validate=function(){return!0},d.postFieldControls.post_content=c,a.control.add(c.id,c),c.deferred.embedded.done(function(){var a=c.container.find("textarea:first");a.hide(),c.editorToggleExpandButton.attr("id",a.attr("id")),a.attr("id",""),c.container.append(c.editorToggleExpandButton)}),c.settingValidationMessages&&(c.settingValidationMessages.remove(e.id),c.settingValidationMessages.add(c.id,new a.Value(""))),c},addExcerptControl:function(){var b,c=this,d=a(c.id);return b=new a.controlConstructor.dynamic(c.id+"[post_excerpt]",{params:{section:c.id,priority:30,label:a.Posts.data.l10n.fieldExcerptLabel,active:!0,settings:{"default":d.id},field_type:"textarea",setting_property:"post_excerpt"}}),b.active.validate=function(){return!0},c.postFieldControls.post_excerpt=b,a.control.add(b.id,b),b.settingValidationMessages&&(b.settingValidationMessages.remove(d.id),b.settingValidationMessages.add(b.id,new a.Value(""))),b},addDiscussionFieldsControl:function(){var b,c,d=this,e=a(d.id);return b=a.Posts.data.postTypes[d.params.post_type],c=new a.controlConstructor.post_discussion_fields(d.id+"[discussion_fields]",{params:{section:d.id,priority:60,label:a.Posts.data.l10n.fieldDiscussionLabel,active:!0,settings:{"default":e.id},post_type_supports:b.supports}}),c.active.validate=function(){return!0},d.postFieldControls.post_discussion_fields=c,a.control.add(c.id,c),c.settingValidationMessages&&(c.settingValidationMessages.remove(e.id),c.settingValidationMessages.add(c.id,new a.Value(""))),c},addAuthorControl:function(){var b,c=this,d=a(c.id);return b=new a.controlConstructor.dynamic(c.id+"[post_author]",{params:{section:c.id,priority:70,label:a.Posts.data.l10n.fieldAuthorLabel,active:!0,settings:{"default":d.id},field_type:"select",setting_property:"post_author",choices:a.Posts.data.authorChoices}}),b.active.validate=function(){return!0},c.postFieldControls.post_author=b,a.control.add(b.id,b),b.settingValidationMessages&&(b.settingValidationMessages.remove(d.id),b.settingValidationMessages.add(b.id,new a.Value(""))),b},setupSettingValidation:function(){var c=this,d=a(c.id);d.validationMessage&&(c.validationMessageElement=b('<div class="customize-setting-validation-message error" aria-live="assertive"></div>'),c.container.find(".customize-section-title").append(c.validationMessageElement),d.validationMessage.bind(function(a){var d=wp.template("customize-setting-validation-message");c.validationMessageElement.empty().append(b.trim(d({messages:[a]}))),a?c.validationMessageElement.slideDown("fast"):c.validationMessageElement.slideUp("fast"),c.container.toggleClass("customize-setting-invalid",""!==a)}),c.validationMessageElement.on("click",".override-post-conflict",function(a){var b;a.preventDefault(),b=_.clone(d.get()),b.post_modified_gmt="",d.set(b),c.resetPostFieldControlSettingValidationMessages()}),a.bind("error",function(e){var f,g,h,i=!1;e.update_conflicted_setting_values&&(f=e.update_conflicted_setting_values[d.id],f&&(g=d.get(),_.each(f,function(e,f){var j,k;"post_modified"!==f&&"post_modified_gmt"!==f&&e!==g[f]&&(j=a.control(d.id+"["+f+"]"),j&&j.settingValidationMessages&&j.settingValidationMessages.has(j.id)&&(k=a.Posts.data.l10n.theirChange.replace("%s",String(e)),j.settingValidationMessages(j.id).set(k),i||(h=b('<button class="button override-post-conflict" type="button"></button>'),h.text(a.Posts.data.l10n.overrideButtonText),c.validationMessageElement.find("li:first").prepend(h),i=!0)))})))}),a.bind("save",function(){c.resetPostFieldControlSettingValidationMessages()}))},resetPostFieldControlSettingValidationMessages:function(){var a=this;_.each(a.postFieldControls,function(a){a.settingValidationMessages&&a.settingValidationMessages.each(function(a){a.set("")})})},isContextuallyActive:function(){var a=this;return a.active()}})}(wp.customize,jQuery);1 !function(a,b){"use strict";var c,d,e={};a.Posts||(a.Posts={}),c=a.Element.synchronizer.checkbox.update,d=a.Element.synchronizer.checkbox.refresh,_.extend(a.Element.synchronizer.checkbox,{update:function(a){var b;b=_.isUndefined(this.element.data("on-value"))||_.isUndefined(this.element.data("off-value"))?a:a===this.element.data("on-value"),c.call(this,b)},refresh:function(){return _.isUndefined(this.element.data("on-value"))||_.isUndefined(this.element.data("off-value"))?d.call(this):this.element.prop("checked")?this.element.data("on-value"):this.element.data("off-value")}}),a.Posts.PostSection=a.Section.extend({initialize:function(b,c){var d,f=this;if(d=c||{},d.params=d.params||{},!d.params.post_type||!a.Posts.data.postTypes[d.params.post_type])throw new Error("Missing post_type");if(_.isNaN(d.params.post_id))throw new Error("Missing post_id");if(!a.has(b))throw new Error("No setting id");d.params.title||(d.params.title=a(b).get().post_title),d.params.title||(d.params.title=a.Posts.data.l10n.noTitle),f.postFieldControls={},d.params.priority||(e[d.params.post_type]||(e[d.params.post_type]=a.Section.prototype.defaults.priority),e[d.params.post_type]+=1,d.params.priority=e[d.params.post_type]),a.Section.prototype.initialize.call(f,b,d),f.active.validate=function(b){var c=a(f.id);return c?c._dirty||b:!0}},ready:function(){var b=this;b.setupTitleUpdating(),b.setupSettingValidation(),b.setupPostNavigation(),b.setupControls(),a.Section.prototype.ready.call(b)},setupTitleUpdating:function(){var b,c,d,e,f=this,g=a(f.id);b=f.container.closest(".accordion-section"),c=b.find(".accordion-section-title:first"),d=b.find(".customize-section-title h3").first(),e=d.find(".customize-action").first(),g.bind(function(b,f){var g;b.post_title!==f.post_title&&"trash"!==b.post_status&&(g=b.post_title||a.Posts.data.l10n.noTitle,c.text(g),d.text(g),d.prepend(e))})},setupPostNavigation:function(){var c,d=this,e=d.container.closest(".accordion-section"),f=e.find(".customize-section-title:first"),g=wp.template("customize-posts-navigation"),h=a.Posts.data.postTypes[d.params.post_type];h["public"]&&(c=b(g({label:h.labels.singular_name})),f.append(c),a.previewer.bind("customized-posts",function(a){c.toggle(d.params.post_id!==a.queriedPostId)}),c.on("click",function(b){b.preventDefault(),a.previewer.previewUrl(a.Posts.getPreviewUrl(d.params))}))},setupControls:function(){var b,c=this;b=a.Posts.data.postTypes[c.params.post_type],b.supports.title&&c.addTitleControl(),(b.supports.title||b.supports.slug)&&c.addSlugControl(),"undefined"==typeof EditPostPreviewCustomize&&c.addPostStatusControl(),b.supports.editor&&c.addContentControl(),b.supports.excerpt&&c.addExcerptControl(),(b.supports.comments||b.supports.trackbacks)&&c.addDiscussionFieldsControl(),b.supports.author&&c.addAuthorControl()},addPostFieldControlNotification:function(b,c){return-1!==b.indexOf(":")?null:a.Values.prototype.add.call(this,b,c)},addTitleControl:function(){var b,c=this,d=a(c.id);return b=new a.controlConstructor.dynamic(c.id+"[post_title]",{params:{section:c.id,priority:10,label:a.Posts.data.l10n.fieldTitleLabel,active:!0,settings:{"default":d.id},field_type:"text",setting_property:"post_title"}}),b.active.validate=function(){return!0},c.postFieldControls.post_title=b,a.control.add(b.id,b),b.notifications&&(b.notifications.add=c.addPostFieldControlNotification),b},addSlugControl:function(){var b,c=this,d=a(c.id);return b=new a.controlConstructor.dynamic(c.id+"[post_name]",{params:{section:c.id,priority:15,label:a.Posts.data.l10n.fieldSlugLabel,active:!0,settings:{"default":d.id},field_type:"text",setting_property:"post_name"}}),b.deferred.embedded.done(function(){function c(){var b=a.Posts.sanitizeTitleWithDashes(d.get().post_title);e.prop("placeholder",b)}var e=b.container.find("input");c(),d.bind(c)}),b.active.validate=function(){return!0},c.postFieldControls.post_name=b,a.control.add(b.id,b),b.notifications&&(b.notifications.add=c.addPostFieldControlNotification),b},addPostStatusControl:function(){var b,c,d,e=this,f=a(e.id);return c=e.container.closest(".accordion-section"),d=c.find(".accordion-section-title:first"),b=new a.controlConstructor.dynamic(e.id+"[post_status]",{params:{section:e.id,priority:20,label:a.Posts.data.l10n.fieldPostStatusLabel,active:!0,settings:{"default":f.id},field_type:"select",setting_property:"post_status",choices:a.Posts.data.postStatusChoices}}),b.toggleTrash=function(a){c.toggleClass("is-trashed",a),!0===a?0===d.find(".customize-posts-trashed").length&&d.append(wp.template("customize-posts-trashed")()):c.find(".customize-posts-trashed").remove()},f.bind(function(a,c){a.post_status!==c.post_status&&b.toggleTrash("trash"===a.post_status)}),b.active.validate=function(){return!0},e.postFieldControls.post_status=b,a.control.add(b.id,b),a.panel("posts["+e.params.post_type+"]").expanded.bind(function(){b.toggleTrash("trash"===f.get().post_status)}),b.deferred.embedded.done(function(){var a=50;_.delay(function(){b.toggleTrash("trash"===f.get().post_status)},a)}),b.notifications&&(b.notifications.add=e.addPostFieldControlNotification),b},addContentControl:function(){var c,d,e=this,f=a(e.id),g=b("#customize-preview"),h=b("#customize-posts-content-editor-pane"),i=b("#customize-posts-content_ifr"),j=b("#wp-customize-posts-content-editor-tools"),k=b(".mce-toolbar-grp"),l=b(".mce-statusbar"),m=b("#customize-posts-content-editor-dragbar"),n=b(".collapse-sidebar");return c=new a.controlConstructor.dynamic(e.id+"[post_content]",{params:{section:e.id,priority:25,label:a.Posts.data.l10n.fieldContentLabel,active:!0,settings:{"default":f.id},field_type:"textarea",setting_property:"post_content"}}),c.editorExpanded=new a.Value(!1),c.editorToggleExpandButton=b('<button type="button" class="button"></button>'),c.updateEditorToggleExpandButtonLabel=function(b){c.editorToggleExpandButton.text(b?a.Posts.data.l10n.closeEditor:a.Posts.data.l10n.openEditor)},c.updateEditorToggleExpandButtonLabel(c.editorExpanded.get()),c.onVisualEditorChange=function(){var a,b;c.editorSyncSuspended||(b=tinyMCE.get("customize-posts-content"),a=wp.editor.removep(b.getContent()),c.editorSyncSuspended=!0,c.propertyElements[0].set(a),c.editorSyncSuspended=!1)},c.onTextEditorChange=function(){c.editorSyncSuspended||(c.editorSyncSuspended=!0,c.propertyElements[0].set(b(this).val()),c.editorSyncSuspended=!1)},f.bind(function(a,b){var d;c.editorExpanded.get()&&!c.editorSyncSuspended&&a.post_content!==b.post_content&&(c.editorSyncSuspended=!0,d=tinyMCE.get("customize-posts-content"),d.setContent(wp.editor.autop(a.post_content)),c.editorSyncSuspended=!1)}),c.editorExpanded.bind(function(a){var d,e=b("#customize-posts-content");d=tinyMCE.get("customize-posts-content"),c.updateEditorToggleExpandButtonLabel(a),b(document.body).toggleClass("customize-posts-content-editor-pane-open",a),a?(d.setContent(wp.editor.autop(f().post_content)),d.on("input change keyup",c.onVisualEditorChange),e.on("input",c.onTextEditorChange),c.resizeEditor(window.innerHeight-h.height())):(d.off("input change keyup",c.onVisualEditorChange),e.off("input",c.onTextEditorChange),d.execCommand("wp_link_cancel"),b(".mce-active").click(),g.css("bottom",""),n.css("bottom",""))}),e.expanded.bind(function(b){b?a.Posts.postIdInput.val(e.params.post_id):(a.Posts.postIdInput.val(""),c.editorExpanded.set(!1))}),c.editorToggleExpandButton.on("click",function(){var a=tinyMCE.get("customize-posts-content");c.editorExpanded.set(!c.editorExpanded()),c.editorExpanded()&&a.focus()}),c.focus=function(b){var d=tinyMCE.get("customize-posts-content");a.controlConstructor.dynamic.prototype.focus.call(c,b),c.editorExpanded.set(!0),d.focus()},c.resizeEditor=function(a){var c=window.innerHeight,e=window.innerWidth,f=b("[id^=accordion-panel-posts] ul.accordion-section-content"),m=40,o=1,p=782,q=56,r=8,s=4,t={};b(document.body).hasClass("customize-posts-content-editor-pane-open")&&(_.isNaN(a)||(d=c-a),t.height=d,t.components=j.outerHeight()+k.outerHeight()+l.outerHeight(),m>d&&(t.height=m),d>c-o&&(t.height=c-o),c<h.outerHeight()&&(t.height=c),g.css("bottom",t.height),h.css("height",t.height),i.css("height",t.height-t.components),n.css("bottom",t.height+r),q>c-t.height&&n.css("bottom",l.outerHeight()+s),p>=e?f.css("padding-bottom",t.height):f.css("padding-bottom",""))},m.on("mousedown",function(){e.expanded()&&b(document).on("mousemove.customize-posts-editor",function(a){a.preventDefault(),b(document.body).addClass("customize-posts-content-editor-pane-resize"),i.css("pointer-events","none"),c.resizeEditor(a.pageY)})}),m.on("mouseup",function(){e.expanded()&&(b(document).off("mousemove.customize-posts-editor"),b(document.body).removeClass("customize-posts-content-editor-pane-resize"),i.css("pointer-events",""))}),b(window).on("resize",function(){var a=50;e.expanded()&&_.delay(function(){c.resizeEditor(window.innerHeight-h.height())},a)}),c.active.validate=function(){return!0},e.postFieldControls.post_content=c,a.control.add(c.id,c),c.deferred.embedded.done(function(){var a=c.container.find("textarea:first");a.hide(),c.editorToggleExpandButton.attr("id",a.attr("id")),a.attr("id",""),c.container.append(c.editorToggleExpandButton)}),c.notifications&&(c.notifications.add=e.addPostFieldControlNotification),c},addExcerptControl:function(){var b,c=this,d=a(c.id);return b=new a.controlConstructor.dynamic(c.id+"[post_excerpt]",{params:{section:c.id,priority:30,label:a.Posts.data.l10n.fieldExcerptLabel,active:!0,settings:{"default":d.id},field_type:"textarea",setting_property:"post_excerpt"}}),b.active.validate=function(){return!0},c.postFieldControls.post_excerpt=b,a.control.add(b.id,b),b.notifications&&(b.notifications.add=c.addPostFieldControlNotification),b},addDiscussionFieldsControl:function(){var b,c,d=this,e=a(d.id);return b=a.Posts.data.postTypes[d.params.post_type],c=new a.controlConstructor.post_discussion_fields(d.id+"[discussion_fields]",{params:{section:d.id,priority:60,label:a.Posts.data.l10n.fieldDiscussionLabel,active:!0,settings:{"default":e.id},post_type_supports:b.supports}}),c.active.validate=function(){return!0},d.postFieldControls.post_discussion_fields=c,a.control.add(c.id,c),c.notifications&&(c.notifications.add=d.addPostFieldControlNotification),c},addAuthorControl:function(){var b,c=this,d=a(c.id);return b=new a.controlConstructor.dynamic(c.id+"[post_author]",{params:{section:c.id,priority:70,label:a.Posts.data.l10n.fieldAuthorLabel,active:!0,settings:{"default":d.id},field_type:"select",setting_property:"post_author",choices:a.Posts.data.authorChoices}}),b.active.validate=function(){return!0},c.postFieldControls.post_author=b,a.control.add(b.id,b),b.notifications&&(b.notifications.add=c.addPostFieldControlNotification),b},setupSettingValidation:function(){var c,d=this,e=a(d.id);e.notifications&&(d.notifications=new a.Values({defaultConstructor:a.Notification}),d.notificationsContainer=b('<div class="customize-control-notifications-container"></div>'),d.notificationsTemplate=wp.template("customize-post-section-notifications"),d.container.find(".customize-section-title").after(d.notificationsContainer),d.getNotificationsContainerElement=function(){return d.notificationsContainer},d.renderNotifications=a.Control.prototype.renderNotifications,e.notifications.bind("add",function(b){var c=new a.Notification(e.id+":"+b.code,b);d.notifications.add(c.code,c)}),e.notifications.bind("remove",function(a){d.notifications.remove(e.id+":"+a.code)}),c=_.debounce(function(){d.renderNotifications()}),d.notifications.bind("add",function(a){wp.a11y.speak(a.message,"assertive"),c()}),d.notifications.bind("remove",c),d.renderNotifications(),d.notificationsContainer.on("click",".override-post-conflict",function(a){var b;a.preventDefault(),b=_.clone(e.get()),b.post_modified_gmt="",e.set(b),_.each(d.postFieldControls,function(a){a.notifications&&a.notifications.remove("post_update_conflict")}),e.notifications.remove("post_update_conflict")}),a.bind("error",function(b){var c,d;b.update_conflicted_setting_values&&(c=b.update_conflicted_setting_values[e.id],c&&(d=e.get(),_.each(c,function(b,c){var f,g;"post_modified"!==c&&"post_modified_gmt"!==c&&b!==d[c]&&(f=a.control(e.id+"["+c+"]"),f&&f.notifications&&(g=new a.Notification("post_update_conflict",{message:a.Posts.data.l10n.theirChange.replace("%s",String(b))}),f.notifications.remove(g.code),f.notifications.add(g.code,g)))})))}),a.bind("save",function(){d.resetPostFieldControlErrorNotifications()}))},resetPostFieldControlErrorNotifications:function(){var a=this;_.each(a.postFieldControls,function(a){a.notifications&&a.notifications.each(function(b){"error"===b.type&&a.notifications.remove(b.code)})})},isContextuallyActive:function(){var a=this;return a.active()}})}(wp.customize,jQuery); -
customize-posts/trunk/js/customize-posts-panel.js
r1406933 r1430660 1 1 /* global wp, jQuery */ 2 /* eslint consistent-this: [ "error", "panel" ] */2 /* eslint consistent-this: [ "error", "panel" ], no-magic-numbers: [ "error", { "ignore": [0,500] } ] */ 3 3 4 4 (function( api, $ ) { … … 45 45 }; 46 46 47 panel.setupPostAddition(); 48 47 49 /* 48 50 * Set the initial visibility state for rendered notice. … … 65 67 66 68 /** 69 * Add new post stub, which builds the UI & listens for click events. 70 * 71 * @return {void} 72 */ 73 setupPostAddition: function() { 74 var panel = this, descriptionContainer, addNewButton, postObj; 75 76 descriptionContainer = panel.container.find( '.panel-meta:first' ); 77 addNewButton = wp.template( 'customize-posts-add-new' ); 78 postObj = api.Posts.data.postTypes[ panel.postType ]; 79 80 if ( postObj.current_user_can.create_posts ) { 81 descriptionContainer.after( addNewButton( { 82 label: postObj.labels.singular_name 83 } ) ); 84 85 panel.container.find( '.add-new-post-stub' ).on( 'click', function( event ) { 86 var postData, button = $( this ), promise; 87 event.preventDefault(); 88 button.prop( 'disabled', true ); 89 90 postData = { 91 post_status: 'publish' 92 }; 93 if ( postObj.supports.title ) { 94 postData.post_title = api.Posts.data.l10n.noTitle; 95 } 96 97 promise = api.Posts.insertAutoDraftPost( panel.postType ); 98 promise.done( function( data ) { 99 data.setting.set( _.extend( 100 {}, 101 data.setting.get(), 102 postData 103 ) ); 104 105 // Navigate to the newly-created post if it is public; otherwise, refresh the preview. 106 if ( postObj['public'] && data.url ) { 107 api.previewer.previewUrl( data.url ); 108 } else { 109 api.previewer.refresh(); 110 } 111 112 /** 113 * Perform a dance to focus on the first control in the section. 114 * 115 * There is a race condition where focusing on a control too 116 * early can result in the focus logic not being able to see 117 * any visible inputs to focus on. 118 * 119 * @returns {void} 120 */ 121 function focusControlOnceFocusable() { 122 var firstControl = data.section.controls()[0]; 123 function onChangeActive( isActive ) { 124 if ( isActive ) { 125 data.section.active.unbind( onChangeActive ); 126 _.defer( function() { 127 firstControl.focus( { 128 completeCallback: function() { 129 firstControl.container.find( 'input:first' ).select(); 130 } 131 } ); 132 } ); 133 } 134 } 135 if ( firstControl ) { 136 data.section.active.bind( onChangeActive ); 137 } 138 } 139 140 data.section.focus( { 141 completeCallback: focusControlOnceFocusable 142 } ); 143 } ); 144 promise.always( function() { 145 button.prop( 'disabled', false ); 146 } ); 147 } ); 148 } 149 }, 150 151 /** 67 152 * Allow an active panel to be contextually active even when it has no active controls. 68 153 * 69 * @returns {boolean} 154 * @returns {boolean} Whether contextually active. 70 155 */ 71 156 isContextuallyActive: function() { -
customize-posts/trunk/js/customize-posts-panel.min.js
r1381641 r1430660 1 !function(a,b){"use strict";a.Posts||(a.Posts={}),a.Posts.PostsPanel=a.Panel.extend({postType:"post",ready:function(){var c=this;a.Panel.prototype.ready.call(c),c.params.post_type&&(c.postType=c.params.post_type),c.deferred.embedded.done(function(){var d,e,f;d=c.container.find(".panel-meta:first"),e=b(b.trim(wp.template("customize-panel-posts-"+c.postType+"-notice")({message:c.params.noPostsLoadedMessage}))),d.append(e),f=function(){return 0===_.filter(c.sections(),function(a){return a.active()}).length}, e.toggle(f()),a.previewer.deferred.active.done(function(){e.toggle(f())}),a.bind("pane-contents-reflowed",function(){var b="resolved"===a.previewer.deferred.active.state()?"fast":0;f()?e.slideDown(b):e.slideUp(b)})})},isContextuallyActive:function(){var a=this;return a.active()}})}(wp.customize,jQuery);1 !function(a,b){"use strict";a.Posts||(a.Posts={}),a.Posts.PostsPanel=a.Panel.extend({postType:"post",ready:function(){var c=this;a.Panel.prototype.ready.call(c),c.params.post_type&&(c.postType=c.params.post_type),c.deferred.embedded.done(function(){var d,e,f;d=c.container.find(".panel-meta:first"),e=b(b.trim(wp.template("customize-panel-posts-"+c.postType+"-notice")({message:c.params.noPostsLoadedMessage}))),d.append(e),f=function(){return 0===_.filter(c.sections(),function(a){return a.active()}).length},c.setupPostAddition(),e.toggle(f()),a.previewer.deferred.active.done(function(){e.toggle(f())}),a.bind("pane-contents-reflowed",function(){var b="resolved"===a.previewer.deferred.active.state()?"fast":0;f()?e.slideDown(b):e.slideUp(b)})})},setupPostAddition:function(){var c,d,e,f=this;c=f.container.find(".panel-meta:first"),d=wp.template("customize-posts-add-new"),e=a.Posts.data.postTypes[f.postType],e.current_user_can.create_posts&&(c.after(d({label:e.labels.singular_name})),f.container.find(".add-new-post-stub").on("click",function(c){var d,g,h=b(this);c.preventDefault(),h.prop("disabled",!0),d={post_status:"publish"},e.supports.title&&(d.post_title=a.Posts.data.l10n.noTitle),g=a.Posts.insertAutoDraftPost(f.postType),g.done(function(b){function c(){function a(d){d&&(b.section.active.unbind(a),_.defer(function(){c.focus({completeCallback:function(){c.container.find("input:first").select()}})}))}var c=b.section.controls()[0];c&&b.section.active.bind(a)}b.setting.set(_.extend({},b.setting.get(),d)),e["public"]&&b.url?a.previewer.previewUrl(b.url):a.previewer.refresh(),b.section.focus({completeCallback:c})}),g.always(function(){h.prop("disabled",!1)})}))},isContextuallyActive:function(){var a=this;return a.active()}})}(wp.customize,jQuery); -
customize-posts/trunk/js/customize-posts.js
r1406933 r1430660 1 /* global jQuery, wp, _, _wpCustomizePostsExports, console */1 /* global jQuery, wp, _, _wpCustomizePostsExports, console */ 2 2 3 3 (function( api, $ ) { … … 58 58 59 59 /** 60 * Get the post preview URL. 61 * 62 * @param {object} params - Parameters to configure the preview URL. 63 * @param {number} params.post_id - Post ID to preview. 64 * @param {string} [params.post_type] - Post type to preview. 65 * @return {string} Preview URL. 66 */ 67 component.getPreviewUrl = function( params ) { 68 var url = api.settings.url.home, 69 args = {}; 70 71 if ( ! params || ! params.post_id ) { 72 throw new Error( 'Missing params' ); 73 } 74 75 args.preview = true; 76 if ( 'page' === params.post_type ) { 77 args.page_id = params.post_id; 78 } else { 79 args.p = params.post_id; 80 if ( params.post_type && 'post' !== params.post_type ) { 81 args.post_type = params.post_type; 82 } 83 } 84 85 return url + '?' + $.param( args ); 86 }; 87 88 /** 89 * Insert a new stubbed `auto-draft` post. 90 * 91 * @param {string} postType Post type to create. 92 * @return {jQuery.promise} Promise resolved with the added section. 93 */ 94 component.insertAutoDraftPost = function( postType ) { 95 var request, deferred = $.Deferred(); 96 97 request = wp.ajax.post( 'customize-posts-insert-auto-draft', { 98 'customize-posts-nonce': api.Posts.data.nonce, 99 'wp_customize': 'on', 100 'post_type': postType 101 } ); 102 103 request.done( function( response ) { 104 var sections = component.receivePreviewData( response ); 105 if ( 0 === sections.length ) { 106 deferred.rejectWith( 'no_sections' ); 107 } else { 108 deferred.resolve( _.extend( 109 { 110 section: sections[0], 111 setting: api( sections[0].id ) 112 }, 113 response 114 ) ); 115 } 116 } ); 117 118 request.fail( function( response ) { 119 var error = response || ''; 120 121 if ( 'undefined' !== typeof response.message ) { 122 error = response.message; 123 } 124 125 console.error( error ); 126 deferred.rejectWith( error ); 127 } ); 128 129 return deferred.promise(); 130 }; 131 132 /** 60 133 * Handle receiving customized-posts messages from the preview. 61 134 * 62 * @param {object} data 135 * @param {object} data Data from preview. 136 * @return {wp.customize.Section[]} Sections added. 63 137 */ 64 138 component.receivePreviewData = function( data ) { 65 _.each( data.settings, function( setting, id ) { 139 var sections = [], section, setting; 140 141 _.each( data.settings, function( settingArgs, id ) { 66 142 67 143 if ( ! api.has( id ) ) { 68 api.create( id, id, setting.value, {69 transport: setting .transport,144 setting = api.create( id, id, settingArgs.value, { 145 transport: settingArgs.transport, 70 146 previewer: api.previewer, 71 dirty: setting .dirty147 dirty: settingArgs.dirty 72 148 } ); 73 } 74 75 if ( 'post' === setting.type ) { 76 component.addPostSection( id ); 77 } 78 } ); 149 if ( settingArgs.dirty ) { 150 setting.callbacks.fireWith( setting, [ setting.get(), {} ] ); 151 } 152 } 153 154 if ( 'post' === settingArgs.type ) { 155 section = component.addPostSection( id ); 156 if ( section ) { 157 sections.push( section ); 158 } 159 } 160 } ); 161 162 return sections; 79 163 }; 80 164 … … 82 166 * Handle adding post setting. 83 167 * 84 * @param {string} id 168 * @param {string} id - Section ID (same as post setting ID). 169 * @return {wp.customize.Section|null} Added (or existing) section, or null if not able to be added. 85 170 */ 86 171 component.addPostSection = function( id ) { … … 92 177 console.error( 'Unrecognized post type: ' + postType ); 93 178 } 94 return; 179 return null; 180 } 181 if ( ! component.data.postTypes[ postType ].show_in_customizer ) { 182 return null; 95 183 } 96 184 postId = parseInt( idParts[2], 10 ); … … 99 187 console.error( 'Bad post id: ' + idParts[2] ); 100 188 } 101 return ;189 return null; 102 190 } 103 191 … … 107 195 108 196 if ( api.section.has( sectionId ) ) { 109 return ;197 return api.section( sectionId ); 110 198 } 111 199 … … 124 212 }); 125 213 api.section.add( sectionId, section ); 214 215 return section; 216 }; 217 218 /** 219 * Emulate sanitize_title_with_dashes(). 220 * 221 * @todo This can be more verbose, supporting Unicode. 222 * 223 * @param {string} title Title 224 * @returns {string} slug 225 */ 226 component.sanitizeTitleWithDashes = function sanitizeTitleWithDashes( title ) { 227 var slug = $.trim( title ).toLowerCase(); 228 slug = slug.replace( /[^a-z0-9\-_]+/g, '-' ); 229 slug = slug.replace( /--+/g, '-' ); 230 slug = slug.replace( /^-+|-+$/g, '' ); 231 return slug; 232 }; 233 234 /** 235 * Handle purging the trash after Customize `saved`. 236 * 237 * @returns {void} 238 */ 239 component.purgeTrash = function purgeTrash() { 240 api.section.each( function( section ) { 241 if ( section.extended( component.PostSection ) && 'trash' === api( section.id ).get().post_status ) { 242 api.section.remove( section.id ); 243 section.collapse(); 244 section.panel.set( false ); 245 if ( ! _.isUndefined( component.previewedQuery ) && true === component.previewedQuery.get().isSingular ) { 246 api.previewer.previewUrl( api.settings.url.home ); 247 } 248 } 249 } ); 250 }; 251 252 /** 253 * Update settings quietly. 254 * 255 * Update all of the settings without causing the overall dirty state to change. 256 * 257 * This was originally part of the Customize Setting Validation plugin. 258 * 259 * @link https://github.com/xwp/wp-customize-setting-validation/blob/2e5ddc66a870ad7b1aee5f8e414bad4b78e120d2/js/customize-setting-validation.js#L186-L209 260 * 261 * @param {object} settingValues Setting IDs mapped to values. 262 * @return {void} 263 */ 264 component.updateSettingsQuietly = function updateSettingsQuietly( settingValues ) { 265 var wasSaved = api.state( 'saved' ).get(); 266 _.each( settingValues, function( value, settingId ) { 267 var setting = api( settingId ), wasDirty; 268 if ( setting && ! _.isEqual( setting.get(), value ) ) { 269 wasDirty = setting._dirty; 270 setting.set( value ); 271 setting._dirty = wasDirty; 272 } 273 } ); 274 api.state( 'saved' ).set( wasSaved ); 126 275 }; 127 276 … … 133 282 134 283 api.previewer.bind( 'customized-posts', component.receivePreviewData ); 284 285 // Track some of the recieved preview data from `customized-posts`. 286 component.previewedQuery = new api.Value( {} ); 287 api.previewer.bind( 'customized-posts', function( data ) { 288 var query = {}; 289 _.each( [ 'isSingular', 'isPostPreview', 'queriedPostId' ], function( key ) { 290 if ( ! _.isUndefined( data[ key ] ) ) { 291 query[ key ] = data[ key ]; 292 } 293 } ); 294 component.previewedQuery.set( query ); 295 } ); 296 297 // Purge trashed posts and update client settings with saved values from server. 298 api.bind( 'saved', function( data ) { 299 if ( data.saved_post_setting_values ) { 300 component.updateSettingsQuietly( data.saved_post_setting_values ); 301 } 302 303 component.purgeTrash(); 304 } ); 135 305 136 306 /** … … 147 317 148 318 /** 149 * Focus on the sectionrequested from the preview.319 * Focus on the control requested from the preview. 150 320 * 151 321 * @todo This can be merged into Core to correspond with focus-control-for-setting. -
customize-posts/trunk/js/customize-posts.min.js
r1406933 r1430660 1 !function(a,b){"use strict";var c;a.Posts||(a.Posts={}),c=a.Posts,c.data={postTypes:{},l10n:{sectionCustomizeActionTpl:"",fieldTitleLabel:"",fieldContentLabel:"",fieldExcerptLabel:""},postIdInput:null},"undefined"!=typeof _wpCustomizePostsExports&&_.extend(c.data,_wpCustomizePostsExports),a.panelConstructor.posts=c.PostsPanel,a.sectionConstructor.post=c.PostSection,a.controlConstructor.post_discussion_fields=a.controlConstructor.dynamic.extend({initialize:function(b,c){c.params.type="post_discussion_fields",c.params.field_type="checkbox",a.controlConstructor.dynamic.prototype.initialize.call(this,b,c)}}),_.each(c.data.postTypes,function(b){var c,d;c="posts["+b.name+"]",a.panelConstructor[c]||(a.panelConstructor[c]=a.panelConstructor.posts.extend({postType:b})),d="post["+b.name+"]",a.sectionConstructor[d]||(a.sectionConstructor[d]=a.sectionConstructor.post.extend({postType:b}))}),c. receivePreviewData=function(b){_.each(b.settings,function(b,d){a.has(d)||a.create(d,d,b.value,{transport:b.transport,previewer:a.previewer,dirty:b.dirty}),"post"===b.type&&c.addPostSection(d)})},c.addPostSection=function(d){var e,f,g,h,i,j,k,l,m;return k=d.replace(/]/g,"").split("["),j=k[1],c.data.postTypes[j]?(i=parseInt(k[2],10))?(h="post["+j+"]",g="posts["+j+"]",f=d,void(a.section.has(f)||(l=a.sectionConstructor[h]||a.sectionConstructor.post,m=b("<div>").html(c.data.l10n.sectionCustomizeActionTpl.replace("%s",a.panel(g).params.title)),e=new l(f,{params:{id:f,panel:g,post_type:j,post_id:i,active:!0,customizeAction:m.text()}}),a.section.add(f,e)))):void("undefined"!=typeof console&&console.error&&console.error("Bad post id: "+k[2])):void("undefined"!=typeof console&&console.error&&console.error("Unrecognized post type: "+j))},a.bind("ready",function(){c.postIdInput=b('<input type="hidden" id="post_ID" name="post_ID">'),b("body").append(c.postIdInput),a.previewer.bind("customized-posts",c.receivePreviewData),a.previewer.bind("focus-section",function(b){var c=a.section(b);c&&c.focus()}),a.previewer.bind("focus-control",function(b){var c=a.control(b);c&&c.focus()})})}(wp.customize,jQuery);1 !function(a,b){"use strict";var c;a.Posts||(a.Posts={}),c=a.Posts,c.data={postTypes:{},l10n:{sectionCustomizeActionTpl:"",fieldTitleLabel:"",fieldContentLabel:"",fieldExcerptLabel:""},postIdInput:null},"undefined"!=typeof _wpCustomizePostsExports&&_.extend(c.data,_wpCustomizePostsExports),a.panelConstructor.posts=c.PostsPanel,a.sectionConstructor.post=c.PostSection,a.controlConstructor.post_discussion_fields=a.controlConstructor.dynamic.extend({initialize:function(b,c){c.params.type="post_discussion_fields",c.params.field_type="checkbox",a.controlConstructor.dynamic.prototype.initialize.call(this,b,c)}}),_.each(c.data.postTypes,function(b){var c,d;c="posts["+b.name+"]",a.panelConstructor[c]||(a.panelConstructor[c]=a.panelConstructor.posts.extend({postType:b})),d="post["+b.name+"]",a.sectionConstructor[d]||(a.sectionConstructor[d]=a.sectionConstructor.post.extend({postType:b}))}),c.getPreviewUrl=function(c){var d=a.settings.url.home,e={};if(!c||!c.post_id)throw new Error("Missing params");return e.preview=!0,"page"===c.post_type?e.page_id=c.post_id:(e.p=c.post_id,c.post_type&&"post"!==c.post_type&&(e.post_type=c.post_type)),d+"?"+b.param(e)},c.insertAutoDraftPost=function(d){var e,f=b.Deferred();return e=wp.ajax.post("customize-posts-insert-auto-draft",{"customize-posts-nonce":a.Posts.data.nonce,wp_customize:"on",post_type:d}),e.done(function(b){var d=c.receivePreviewData(b);0===d.length?f.rejectWith("no_sections"):f.resolve(_.extend({section:d[0],setting:a(d[0].id)},b))}),e.fail(function(a){var b=a||"";"undefined"!=typeof a.message&&(b=a.message),console.error(b),f.rejectWith(b)}),f.promise()},c.receivePreviewData=function(b){var d,e,f=[];return _.each(b.settings,function(b,g){a.has(g)||(e=a.create(g,g,b.value,{transport:b.transport,previewer:a.previewer,dirty:b.dirty}),b.dirty&&e.callbacks.fireWith(e,[e.get(),{}])),"post"===b.type&&(d=c.addPostSection(g),d&&f.push(d))}),f},c.addPostSection=function(d){var e,f,g,h,i,j,k,l,m;return k=d.replace(/]/g,"").split("["),j=k[1],c.data.postTypes[j]?c.data.postTypes[j].show_in_customizer?(i=parseInt(k[2],10))?(h="post["+j+"]",g="posts["+j+"]",f=d,a.section.has(f)?a.section(f):(l=a.sectionConstructor[h]||a.sectionConstructor.post,m=b("<div>").html(c.data.l10n.sectionCustomizeActionTpl.replace("%s",a.panel(g).params.title)),e=new l(f,{params:{id:f,panel:g,post_type:j,post_id:i,active:!0,customizeAction:m.text()}}),a.section.add(f,e),e)):("undefined"!=typeof console&&console.error&&console.error("Bad post id: "+k[2]),null):null:("undefined"!=typeof console&&console.error&&console.error("Unrecognized post type: "+j),null)},c.sanitizeTitleWithDashes=function(a){var c=b.trim(a).toLowerCase();return c=c.replace(/[^a-z0-9\-_]+/g,"-"),c=c.replace(/--+/g,"-"),c=c.replace(/^-+|-+$/g,"")},c.purgeTrash=function(){a.section.each(function(b){b.extended(c.PostSection)&&"trash"===a(b.id).get().post_status&&(a.section.remove(b.id),b.collapse(),b.panel.set(!1),_.isUndefined(c.previewedQuery)||!0!==c.previewedQuery.get().isSingular||a.previewer.previewUrl(a.settings.url.home))})},c.updateSettingsQuietly=function(b){var c=a.state("saved").get();_.each(b,function(b,c){var d,e=a(c);e&&!_.isEqual(e.get(),b)&&(d=e._dirty,e.set(b),e._dirty=d)}),a.state("saved").set(c)},a.bind("ready",function(){c.postIdInput=b('<input type="hidden" id="post_ID" name="post_ID">'),b("body").append(c.postIdInput),a.previewer.bind("customized-posts",c.receivePreviewData),c.previewedQuery=new a.Value({}),a.previewer.bind("customized-posts",function(a){var b={};_.each(["isSingular","isPostPreview","queriedPostId"],function(c){_.isUndefined(a[c])||(b[c]=a[c])}),c.previewedQuery.set(b)}),a.bind("saved",function(a){a.saved_post_setting_values&&c.updateSettingsQuietly(a.saved_post_setting_values),c.purgeTrash()}),a.previewer.bind("focus-section",function(b){var c=a.section(b);c&&c.focus()}),a.previewer.bind("focus-control",function(b){var c=a.control(b);c&&c.focus()})})}(wp.customize,jQuery); -
customize-posts/trunk/js/customize-preview-posts.js
r1406933 r1430660 1 /*global wp, _wpCustomizePreviewPostsData, JSON */ 1 /* global wp, _wpCustomizePreviewPostsData, JSON */ 2 2 3 ( function( api, $ ) { 3 4 'use strict'; … … 27 28 28 29 _.each( settings, function( setting, id ) { 29 var partial;30 30 31 31 if ( ! api.has( id ) ) { … … 37 37 if ( 'post' === setting.type ) { 38 38 39 // Post field partial for post_title. 40 partial = new api.previewPosts.PostFieldPartial( id + '[post_title]', { 41 params: { 42 settings: [ id ] 39 // Add the partials. 40 _.each( api.previewPosts.partialSchema( id ), function( schema ) { 41 var partial, addPartial, matches, baseSelector, idPattern = /^post\[(.+?)]\[(-?\d+)]\[(.+?)](?:\[(.+?)])?$/; 42 43 matches = schema.id.match( idPattern ); 44 if ( ! matches ) { 45 throw new Error( 'Bad PostFieldPartial id. Expected post[:post_type][:post_id][:field_id]' ); 46 } 47 48 if ( schema.params.selector ) { 49 if ( ! schema.params.bodySelector ) { 50 baseSelector = '.hentry.post-' + String( parseInt( matches[2], 10 ) ) + '.type-' + matches[1]; 51 } else { 52 baseSelector = '.postid-' + String( parseInt( matches[2], 10 ) ) + '.single-' + matches[1]; 53 } 54 schema.params.selector = baseSelector + ' ' + schema.params.selector; 55 56 addPartial = 57 ! schema.params.singularOnly && ! schema.params.archiveOnly || 58 schema.params.singularOnly && api.previewPosts.data.isSingular || 59 schema.params.archiveOnly && ! api.previewPosts.data.isSingular; 60 61 if ( addPartial ) { 62 partial = new api.previewPosts.PostFieldPartial( schema.id, { params: schema.params } ); 63 api.selectiveRefresh.partial.add( partial.id, partial ); 64 } 65 } else { 66 partial = new api.previewPosts.PostFieldPartial( schema.id, { params: schema.params } ); 67 68 /** 69 * Suppress wasted partial refreshes for partials that lack selectors. 70 * 71 * For example, since the post_name field is not normally 72 * displayed, suppress refreshing changes. 73 * 74 * @returns {jQuery.promise} Promise. 75 */ 76 partial.refresh = function refreshWithoutSelector() { 77 var deferred = $.Deferred(); 78 if ( this.params.fallbackRefresh ) { 79 api.selectiveRefresh.requestFullRefresh(); 80 deferred.resolve(); 81 } else { 82 deferred.reject(); 83 } 84 return deferred.promise(); 85 }; 86 api.selectiveRefresh.partial.add( partial.id, partial ); 43 87 } 44 88 } ); 45 api.selectiveRefresh.partial.add( partial.id, partial );46 47 // Post field partial for post_content.48 partial = new api.previewPosts.PostFieldPartial( id + '[post_content]', {49 params: {50 settings: [ id ]51 }52 } );53 api.selectiveRefresh.partial.add( partial.id, partial );54 55 // Post field partial for post_excerpt.56 partial = new api.previewPosts.PostFieldPartial( id + '[post_excerpt]', {57 params: {58 settings: [ id ]59 }60 } );61 api.selectiveRefresh.partial.add( partial.id, partial );62 63 // Post field partial for comment_status comments-area.64 if ( api.previewPosts.data.isSingular ) {65 partial = new api.previewPosts.PostFieldPartial( id + '[comment_status][comments-area]', {66 params: {67 settings: [ id ],68 containerInclusive: true,69 fallbackRefresh: true70 }71 } );72 api.selectiveRefresh.partial.add( partial.id, partial );73 }74 75 // Post field partial for comment_status comments-link.76 partial = new api.previewPosts.PostFieldPartial( id + '[comment_status][comments-link]', {77 params: {78 settings: [ id ],79 containerInclusive: true,80 fallbackRefresh: false81 }82 } );83 partial.fallback = function() {84 if ( ! this.params.fallbackRefresh && 0 === this.placements().length && ! api.previewPosts.data.isSingular ) {85 api.selectiveRefresh.requestFullRefresh();86 } else {87 api.previewPosts.PostFieldPartial.prototype.refresh.call( this );88 }89 };90 api.selectiveRefresh.partial.add( partial.id, partial );91 92 // Post field partial for ping_status.93 partial = new api.previewPosts.PostFieldPartial( id + '[ping_status]', {94 params: {95 settings: [ id ],96 containerInclusive: true,97 fallbackRefresh: false98 }99 } );100 api.selectiveRefresh.partial.add( partial.id, partial );101 102 // Post field partial for post_author author-bio.103 partial = new api.previewPosts.PostFieldPartial( id + '[post_author][author-bio]', {104 params: {105 settings: [ id ],106 containerInclusive: true,107 fallbackRefresh: true108 }109 } );110 api.selectiveRefresh.partial.add( partial.id, partial );111 112 // Post field partial for post_author byline.113 partial = new api.previewPosts.PostFieldPartial( id + '[post_author][byline]', {114 params: {115 settings: [ id ],116 containerInclusive: true,117 fallbackRefresh: false118 }119 } );120 api.selectiveRefresh.partial.add( partial.id, partial );121 122 // Post field partial for post_author avatar.123 partial = new api.previewPosts.PostFieldPartial( id + '[post_author][avatar]', {124 params: {125 settings: [ id ],126 containerInclusive: true,127 fallbackRefresh: false128 }129 } );130 api.selectiveRefresh.partial.add( partial.id, partial );131 89 } 132 90 133 91 // @todo Trigger event for plugins and postmeta controllers. 134 92 } ); 93 }; 94 95 /** 96 * Geneate the partial schema. 97 * 98 * @param {string} id 99 */ 100 api.previewPosts.partialSchema = function( id ) { 101 var partialSchema = []; 102 103 _.each( api.previewPosts.data.partialSchema, function( params, key ) { 104 var partialId, idParts; 105 106 idParts = key.replace( /]/g, '' ).split( /\[/ ); 107 partialId = id + '[' + idParts.join( '][' ) + ']'; 108 109 params.settings = [ id ]; 110 partialSchema.push( { 111 id: partialId, 112 params: api.previewPosts.snakeToCamel( params ) 113 } ); 114 } ); 115 116 return partialSchema; 117 }; 118 119 /** 120 * Convert the schema snakecase params to camelcase. 121 * 122 * @param {object} params 123 */ 124 api.previewPosts.snakeToCamel = function( params ) { 125 var newParams = {}; 126 127 _.each( params, function( value, key ) { 128 var i = key.replace( /_\w/g, function( str ) { 129 return str[1].toUpperCase(); 130 } ); 131 newParams[ i ] = value; 132 } ); 133 134 return newParams; 135 135 }; 136 136 -
customize-posts/trunk/js/customize-preview-posts.min.js
r1406933 r1430660 1 !function(a,b){"use strict";a.previewPosts||(a.previewPosts={}),a.previewPosts.data||(a.previewPosts.data={}),b(document.body).on("mousedown",function(a){a.shiftKey&&a.preventDefault()}),a.previewPosts.addPartials=function( b){_.each(b,function(b,c){var d;a.has(c)||a.create(c,b.value,{id:c}),"post"===b.type&&(d=new a.previewPosts.PostFieldPartial(c+"[post_title]",{params:{settings:[c]}}),a.selectiveRefresh.partial.add(d.id,d),d=new a.previewPosts.PostFieldPartial(c+"[post_content]",{params:{settings:[c]}}),a.selectiveRefresh.partial.add(d.id,d),d=new a.previewPosts.PostFieldPartial(c+"[post_excerpt]",{params:{settings:[c]}}),a.selectiveRefresh.partial.add(d.id,d),a.previewPosts.data.isSingular&&(d=new a.previewPosts.PostFieldPartial(c+"[comment_status][comments-area]",{params:{settings:[c],containerInclusive:!0,fallbackRefresh:!0}}),a.selectiveRefresh.partial.add(d.id,d)),d=new a.previewPosts.PostFieldPartial(c+"[comment_status][comments-link]",{params:{settings:[c],containerInclusive:!0,fallbackRefresh:!1}}),d.fallback=function(){this.params.fallbackRefresh||0!==this.placements().length||a.previewPosts.data.isSingular?a.previewPosts.PostFieldPartial.prototype.refresh.call(this):a.selectiveRefresh.requestFullRefresh()},a.selectiveRefresh.partial.add(d.id,d),d=new a.previewPosts.PostFieldPartial(c+"[ping_status]",{params:{settings:[c],containerInclusive:!0,fallbackRefresh:!1}}),a.selectiveRefresh.partial.add(d.id,d),d=new a.previewPosts.PostFieldPartial(c+"[post_author][author-bio]",{params:{settings:[c],containerInclusive:!0,fallbackRefresh:!0}}),a.selectiveRefresh.partial.add(d.id,d),d=new a.previewPosts.PostFieldPartial(c+"[post_author][byline]",{params:{settings:[c],containerInclusive:!0,fallbackRefresh:!1}}),a.selectiveRefresh.partial.add(d.id,d),d=new a.previewPosts.PostFieldPartial(c+"[post_author][avatar]",{params:{settings:[c],containerInclusive:!0,fallbackRefresh:!1}}),a.selectiveRefresh.partial.add(d.id,d))})},a.previewPosts.addSettings=function(b){a.previewPosts.addPartials(b),a.preview.send("customized-posts",{settings:b})},a.bind("preview-ready",function(){a.preview.bind("active",function(){var c={};_.extend(a.previewPosts.data,_wpCustomizePreviewPostsData),a.each(function(b){var d=a.previewPosts.data.settingProperties[b.id];d&&(c[b.id]={value:b.get(),dirty:Boolean(a.settings._dirty[b.id]),type:d.type,transport:d.transport})}),a.previewPosts.addPartials(c),a.preview.send("customized-posts",{isPostPreview:a.previewPosts.data.isPostPreview,isSingular:a.previewPosts.data.isSingular,queriedPostId:a.previewPosts.data.queriedPostId,settings:c}),b(document.body).on("click",".post-edit-link",function(c){var d,e=b(this);d=e.data("customize-post-setting-id"),c.preventDefault(),d&&a.preview.send("focus-section",d)})}),a.selectiveRefresh.bind("render-partials-response",function(b){b.customize_post_settings&&a.previewPosts.addSettings(b.customize_post_settings)}),b(document).ajaxSuccess(function(b,c,d,e){var f,g="POST"===d.type&&-1!==d.url.indexOf("infinity=scrolling");g&&(f="string"==typeof e?JSON.parse(e):e,f.customize_post_settings&&a.previewPosts.addSettings(f.customize_post_settings))})})}(wp.customize,jQuery);1 !function(a,b){"use strict";a.previewPosts||(a.previewPosts={}),a.previewPosts.data||(a.previewPosts.data={}),b(document.body).on("mousedown",function(a){a.shiftKey&&a.preventDefault()}),a.previewPosts.addPartials=function(c){_.each(c,function(c,d){a.has(d)||a.create(d,c.value,{id:d}),"post"===c.type&&_.each(a.previewPosts.partialSchema(d),function(c){var d,e,f,g,h=/^post\[(.+?)]\[(-?\d+)]\[(.+?)](?:\[(.+?)])?$/;if(f=c.id.match(h),!f)throw new Error("Bad PostFieldPartial id. Expected post[:post_type][:post_id][:field_id]");c.params.selector?(g=c.params.bodySelector?".postid-"+String(parseInt(f[2],10))+".single-"+f[1]:".hentry.post-"+String(parseInt(f[2],10))+".type-"+f[1],c.params.selector=g+" "+c.params.selector,e=!c.params.singularOnly&&!c.params.archiveOnly||c.params.singularOnly&&a.previewPosts.data.isSingular||c.params.archiveOnly&&!a.previewPosts.data.isSingular,e&&(d=new a.previewPosts.PostFieldPartial(c.id,{params:c.params}),a.selectiveRefresh.partial.add(d.id,d))):(d=new a.previewPosts.PostFieldPartial(c.id,{params:c.params}),d.refresh=function(){var c=b.Deferred();return this.params.fallbackRefresh?(a.selectiveRefresh.requestFullRefresh(),c.resolve()):c.reject(),c.promise()},a.selectiveRefresh.partial.add(d.id,d))})})},a.previewPosts.partialSchema=function(b){var c=[];return _.each(a.previewPosts.data.partialSchema,function(d,e){var f,g;g=e.replace(/]/g,"").split(/\[/),f=b+"["+g.join("][")+"]",d.settings=[b],c.push({id:f,params:a.previewPosts.snakeToCamel(d)})}),c},a.previewPosts.snakeToCamel=function(a){var b={};return _.each(a,function(a,c){var d=c.replace(/_\w/g,function(a){return a[1].toUpperCase()});b[d]=a}),b},a.previewPosts.addSettings=function(b){a.previewPosts.addPartials(b),a.preview.send("customized-posts",{settings:b})},a.bind("preview-ready",function(){a.preview.bind("active",function(){var c={};_.extend(a.previewPosts.data,_wpCustomizePreviewPostsData),a.each(function(b){var d=a.previewPosts.data.settingProperties[b.id];d&&(c[b.id]={value:b.get(),dirty:Boolean(a.settings._dirty[b.id]),type:d.type,transport:d.transport})}),a.previewPosts.addPartials(c),a.preview.send("customized-posts",{isPostPreview:a.previewPosts.data.isPostPreview,isSingular:a.previewPosts.data.isSingular,queriedPostId:a.previewPosts.data.queriedPostId,settings:c}),b(document.body).on("click",".post-edit-link",function(c){var d,e=b(this);d=e.data("customize-post-setting-id"),c.preventDefault(),d&&a.preview.send("focus-section",d)})}),a.selectiveRefresh.bind("render-partials-response",function(b){b.customize_post_settings&&a.previewPosts.addSettings(b.customize_post_settings)}),b(document).ajaxSuccess(function(b,c,d,e){var f,g="POST"===d.type&&-1!==d.url.indexOf("infinity=scrolling");g&&(f="string"==typeof e?JSON.parse(e):e,f.customize_post_settings&&a.previewPosts.addSettings(f.customize_post_settings))})})}(wp.customize,jQuery); -
customize-posts/trunk/js/edit-post-preview-admin.js
r1406933 r1430660 71 71 editor.setContent( wp.editor.autop( data[ postSettingId ].post_content ) ); 72 72 } 73 // @todo Handle post-status sync. 73 74 $( '#content' ).val( data[ postSettingId ].post_content ).trigger( 'change' ); 74 75 $( '#excerpt' ).val( data[ postSettingId ].post_excerpt ).trigger( 'change' ); -
customize-posts/trunk/php/class-customize-posts-plugin.php
r1406933 r1430660 65 65 add_filter( 'user_has_cap', array( $this, 'grant_customize_capability' ), 10, 3 ); 66 66 add_filter( 'customize_loaded_components', array( $this, 'filter_customize_loaded_components' ), 100, 2 ); 67 add_action( 'customize_register', array( $this, 'load_support_classes' ) ); 67 68 68 69 require_once dirname( __FILE__ ) . '/class-wp-customize-postmeta-controller.php'; … … 113 114 114 115 return $components; 116 } 117 118 /** 119 * Load theme and plugin compatibility classes. 120 * 121 * @codeCoverageIgnore 122 * 123 * @param WP_Customize_Manager $wp_customize Manager. 124 */ 125 function load_support_classes( $wp_customize ) { 126 127 // Theme & Plugin Support. 128 require_once dirname( __FILE__ ) . '/class-customize-posts-support.php'; 129 require_once dirname( __FILE__ ) . '/class-customize-posts-plugin-support.php'; 130 require_once dirname( __FILE__ ) . '/class-customize-posts-theme-support.php'; 131 132 foreach ( array( 'theme', 'plugin' ) as $type ) { 133 foreach ( glob( dirname( __FILE__ ) . '/' . $type . '-support/class-*.php' ) as $file_path ) { 134 require_once $file_path; 135 136 $class_name = str_replace( '-', '_', preg_replace( '/^class-(.+)\.php$/', '$1', basename( $file_path ) ) ); 137 if ( class_exists( $class_name ) ) { 138 $wp_customize->posts->add_support( new $class_name( $wp_customize->posts ) ); 139 } 140 } 141 } 115 142 } 116 143 … … 133 160 public function register_scripts( WP_Scripts $wp_scripts ) { 134 161 $suffix = ( SCRIPT_DEBUG ? '' : '.min' ) . '.js'; 135 $plugin_dir_url = plugin_dir_url( dirname( __FILE__ ) );136 162 137 163 $handle = 'customize-controls-patched-36521'; 138 $src = $plugin_dir_url . 'js/customize-controls-patched-36521' . $suffix;164 $src = plugins_url( 'js/customize-controls-patched-36521' . $suffix, dirname( __FILE__ ) ); 139 165 $deps = array( 'customize-controls' ); 140 166 $in_footer = 1; … … 142 168 143 169 $handle = 'customize-posts-panel'; 144 $src = $plugin_dir_url . 'js/customize-posts-panel' . $suffix;170 $src = plugins_url( 'js/customize-posts-panel' . $suffix, dirname( __FILE__ ) ); 145 171 $deps = array( 'customize-controls' ); 146 172 $in_footer = 1; … … 148 174 149 175 $handle = 'customize-post-section'; 150 $src = $plugin_dir_url . 'js/customize-post-section' . $suffix;176 $src = plugins_url( 'js/customize-post-section' . $suffix, dirname( __FILE__ ) ); 151 177 $deps = array( 'customize-controls' ); 152 178 $in_footer = 1; … … 154 180 155 181 $handle = 'customize-dynamic-control'; 156 $src = $plugin_dir_url . 'js/customize-dynamic-control' . $suffix;182 $src = plugins_url( 'js/customize-dynamic-control' . $suffix, dirname( __FILE__ ) ); 157 183 $deps = array( 'customize-controls' ); 158 184 $in_footer = 1; … … 160 186 161 187 $handle = 'customize-posts'; 162 $src = $plugin_dir_url . 'js/customize-posts' . $suffix;188 $src = plugins_url( 'js/customize-posts' . $suffix, dirname( __FILE__ ) ); 163 189 $deps = array( 164 190 'jquery', … … 177 203 178 204 $handle = 'customize-post-field-partial'; 179 $src = $plugin_dir_url . 'js/customize-post-field-partial' . $suffix;205 $src = plugins_url( 'js/customize-post-field-partial' . $suffix, dirname( __FILE__ ) ); 180 206 $deps = array( 'customize-selective-refresh' ); 181 207 $in_footer = 1; … … 183 209 184 210 $handle = 'customize-preview-posts'; 185 $src = $plugin_dir_url . 'js/customize-preview-posts' . $suffix;211 $src = plugins_url( 'js/customize-preview-posts' . $suffix, dirname( __FILE__ ) ); 186 212 $deps = array( 'jquery', 'customize-preview', 'customize-post-field-partial' ); 187 213 $in_footer = 1; … … 189 215 190 216 $handle = 'edit-post-preview-admin'; 191 $src = $plugin_dir_url . 'js/edit-post-preview-admin' . $suffix;217 $src = plugins_url( 'js/edit-post-preview-admin' . $suffix, dirname( __FILE__ ) ); 192 218 $deps = array( 'post' ); 193 219 $in_footer = 1; … … 195 221 196 222 $handle = 'edit-post-preview-customize'; 197 $src = $plugin_dir_url . 'js/edit-post-preview-customize' . $suffix;223 $src = plugins_url( 'js/edit-post-preview-customize' . $suffix, dirname( __FILE__ ) ); 198 224 $deps = array( 'customize-controls' ); 199 225 $in_footer = 1; … … 202 228 // Page templates. 203 229 $handle = 'customize-page-template'; 204 $src = $plugin_dir_url . 'js/customize-page-template' . $suffix;230 $src = plugins_url( 'js/customize-page-template' . $suffix, dirname( __FILE__ ) ); 205 231 $deps = array( 'customize-controls', 'customize-posts' ); 206 232 $in_footer = 1; … … 208 234 209 235 $handle = 'edit-post-preview-admin-page-template'; 210 $src = $plugin_dir_url . 'js/edit-post-preview-admin-page-template' . $suffix;236 $src = plugins_url( 'js/edit-post-preview-admin-page-template' . $suffix, dirname( __FILE__ ) ); 211 237 $deps = array( 'edit-post-preview-admin' ); 212 238 $in_footer = 1; … … 215 241 // Featured images. 216 242 $handle = 'customize-featured-image'; 217 $src = $plugin_dir_url . 'js/customize-featured-image' . $suffix;243 $src = plugins_url( 'js/customize-featured-image' . $suffix, dirname( __FILE__ ) ); 218 244 $deps = array( 'customize-controls', 'customize-posts' ); 219 245 $in_footer = 1; … … 221 247 222 248 $handle = 'edit-post-preview-admin-featured-image'; 223 $src = $plugin_dir_url . 'js/edit-post-preview-admin-featured-image' . $suffix;249 $src = plugins_url( 'js/edit-post-preview-admin-featured-image' . $suffix, dirname( __FILE__ ) ); 224 250 $deps = array( 'edit-post-preview-admin' ); 225 251 $in_footer = 1; … … 227 253 228 254 $handle = 'customize-preview-featured-image'; 229 $src = $plugin_dir_url . 'js/customize-preview-featured-image' . $suffix;255 $src = plugins_url( 'js/customize-preview-featured-image' . $suffix, dirname( __FILE__ ) ); 230 256 $deps = array( 'customize-preview', 'customize-selective-refresh' ); 231 257 $in_footer = 1; … … 240 266 public function register_styles( WP_Styles $wp_styles ) { 241 267 $suffix = ( SCRIPT_DEBUG ? '' : '.min' ) . '.css'; 242 $plugin_dir_url = plugin_dir_url( dirname( __FILE__ ) );243 268 244 269 $handle = 'customize-posts'; 245 $src = $plugin_dir_url . 'css/customize-posts' . $suffix;270 $src = plugins_url( 'css/customize-posts' . $suffix, dirname( __FILE__ ) ); 246 271 $deps = array( 'wp-admin' ); 247 272 $version = $this->version; … … 249 274 250 275 $handle = 'edit-post-preview-customize'; 251 $src = $plugin_dir_url . 'css/edit-post-preview-customize' . $suffix;276 $src = plugins_url( 'css/edit-post-preview-customize' . $suffix, dirname( __FILE__ ) ); 252 277 $deps = array( 'customize-controls' ); 253 278 $wp_styles->add( $handle, $src, $deps, $this->version ); -
customize-posts/trunk/php/class-edit-post-preview.php
r1406933 r1430660 95 95 96 96 /** 97 * Generate a preview permalink for a post/page. 98 * 99 * @access public 100 * 101 * @param WP_Post $post The post in question. 102 * @return string Edit post link. 103 */ 104 public static function get_preview_post_link( $post ) { 105 $permalink = ''; 106 107 if ( $post instanceof WP_Post ) { 108 $id_param = ( 'page' === $post->post_type ) ? 'page_id' : 'p'; 109 $args = array(); 110 $args['preview'] = true; 111 $args[ $id_param ] = $post->ID; 112 if ( 'page_id' !== $id_param && 'post' !== $post->post_type ) { 113 $args['post_type'] = $post->post_type; 114 } 115 $permalink = get_preview_post_link( $post, $args, home_url( '/' ) ); 116 } 117 118 return $permalink; 119 } 120 121 /** 97 122 * Enqueue scripts for post edit screen. 98 123 */ … … 104 129 $post = $this->get_previewed_post(); 105 130 106 $id_param = ( 'page' === $post->post_type ) ? 'page_id' : 'p';107 $url = get_preview_post_link( $post, array(), home_url( '?preview=true&' . $id_param . '=' . $post->ID ) );108 131 $customize_url = add_query_arg( 109 132 array( 110 'url' => urlencode( $url),133 'url' => urlencode( self::get_preview_post_link( $post ) ), 111 134 'previewed_post' => $post->ID, 112 135 'autofocus[section]' => sprintf( 'post[%s][%d]', $post->post_type, $post->ID ), -
customize-posts/trunk/php/class-wp-customize-dynamic-control.php
r1406933 r1430660 144 144 <# } #> 145 145 <# } #> 146 <div class="customize-setting-validation-message error" aria-live="assertive"></div>147 146 <?php 148 147 } -
customize-posts/trunk/php/class-wp-customize-featured-image-controller.php
r1406933 r1430660 379 379 * @param string $attachment_id The value to sanitize. 380 380 * @param WP_Customize_Postmeta_Setting $setting Setting. 381 * @param bool $strict Whether validation is being done. This is part of the proposed patch in in #34893. 382 * @return mixed|null Null if an input isn't valid, otherwise the sanitized value. 383 */ 384 public function sanitize_setting( $attachment_id, WP_Customize_Postmeta_Setting $setting, $strict = false ) { 381 * @return mixed|WP_Error Sanitized value or `WP_Error` if invalid. 382 */ 383 public function sanitize_setting( $attachment_id, WP_Customize_Postmeta_Setting $setting ) { 385 384 unset( $setting ); 385 $has_setting_validation = method_exists( 'WP_Customize_Setting', 'validate' ); 386 386 387 387 $is_valid = ( … … 398 398 * So $attachment_id is either a valid attachment ID, -1, or false. 399 399 */ 400 if ( $strict && ! $is_valid ) { 401 if ( $strict ) { 402 return new WP_Error( 'invalid_attachment_id', __( 'The attachment is invalid.', 'customize-posts' ) ); 403 } else { 404 return null; 405 } 400 if ( ! $is_valid ) { 401 return $has_setting_validation ? new WP_Error( 'invalid_attachment_id', __( 'The attachment is invalid.', 'customize-posts' ) ) : null; 406 402 } 407 403 -
customize-posts/trunk/php/class-wp-customize-page-template-controller.php
r1406933 r1430660 105 105 * @param string $page_template The value to sanitize. 106 106 * @param WP_Customize_Postmeta_Setting $setting Setting. 107 * @param bool $strict Whether validation is being done. This is part of the proposed patch in in #34893. 108 * @return mixed|null Null if an input isn't valid, otherwise the sanitized value. 107 * @return mixed|WP_Error Sanitized value or WP_Error if invalid valid. 109 108 */ 110 public function sanitize_setting( $page_template, WP_Customize_Postmeta_Setting $setting , $strict = false) {109 public function sanitize_setting( $page_template, WP_Customize_Postmeta_Setting $setting ) { 111 110 $post = get_post( $setting->post_id ); 112 111 $page_templates = wp_get_theme()->get_page_templates( $post ); 112 $has_setting_validation = method_exists( 'WP_Customize_Setting', 'validate' ); 113 113 114 114 if ( 'default' !== $page_template && ! isset( $page_templates[ $page_template ] ) ) { 115 if ( $strict ) { 116 return new WP_Error( 'invalid_page_template', __( 'The page template is invalid.', 'customize-posts' ) ); 117 } else { 118 return null; 119 } 115 return $has_setting_validation ? new WP_Error( 'invalid_page_template', __( 'The page template is invalid.', 'customize-posts' ) ) : null; 120 116 } 121 117 return $page_template; -
customize-posts/trunk/php/class-wp-customize-post-discussion-fields-control.php
r1406933 r1430660 74 74 </p> 75 75 <# } #> 76 77 <div class="customize-setting-validation-message error" aria-live="assertive"></div>78 76 <?php 79 77 } -
customize-posts/trunk/php/class-wp-customize-post-field-partial.php
r1406933 r1430660 43 43 * Setting that this section is related to. 44 44 * 45 * @var WP_Customize_Post_Setting45 * @var string 46 46 */ 47 47 public $field_id; … … 84 84 $args['field_id'] = $matches['field_id']; 85 85 $args['placement'] = isset( $matches['placement'] ) ? $matches['placement'] : ''; 86 87 if ( ! empty( $args['placement'] ) ) {88 if ( ! isset( $args['container_inclusive'] ) ) {89 $args['container_inclusive'] = true;90 }91 if ( ! isset( $args['fallback_refresh'] ) ) {92 $args['fallback_refresh'] = false;93 }94 }95 86 96 87 parent::__construct( $component, $id, $args ); … … 112 103 } 113 104 114 /**115 * Partial.116 *117 * @var WP_Customize_Post_Field_Partial $partial118 */119 120 105 $GLOBALS['post'] = $post; // WPCS: override global ok. 121 106 setup_postdata( $post ); 122 if ( 'post_title' === $this->field_id ) { 123 $rendered = $post->post_title; 124 125 if ( ! empty( $post->post_password ) ) { 126 /** This filter is documented in wp-includes/post-template.php */ 127 $protected_title_format = apply_filters( 'protected_title_format', __( 'Protected: %s', 'customize-posts' ), $post ); 128 $rendered = sprintf( $protected_title_format, $rendered ); 129 } elseif ( isset( $post->post_status ) && 'private' === $post->post_status ) { 130 /** This filter is documented in wp-includes/post-template.php */ 131 $private_title_format = apply_filters( 'private_title_format', __( 'Private: %s', 'customize-posts' ), $post ); 132 $rendered = sprintf( $private_title_format, $rendered ); 133 } 134 107 108 $method = 'render_' . $this->field_id; 109 if ( method_exists( $this, $method ) ) { 110 $rendered = $this->$method( $partial, $context, $post ); 111 } 112 113 wp_reset_postdata(); 114 return $rendered; 115 } 116 117 /** 118 * Export data to JS. 119 * 120 * @return array 121 */ 122 public function json() { 123 $data = parent::json(); 124 $data['post_type'] = $this->post_type; 125 $data['post_id'] = $this->post_id; 126 $data['field_id'] = $this->field_id; 127 $data['placement'] = $this->placement; 128 return $data; 129 } 130 131 /** 132 * Render the post title. 133 * 134 * @param WP_Customize_Partial $partial Partial. 135 * @param array $context Context. 136 * @param WP_Post $post Post object. 137 * @return string 138 */ 139 public function render_post_title( $partial, $context, $post ) { 140 unset( $partial, $context ); 141 $rendered = $post->post_title; 142 143 if ( ! empty( $post->post_password ) ) { 135 144 /** This filter is documented in wp-includes/post-template.php */ 136 $rendered = apply_filters( 'the_title', $rendered, $post->ID ); 137 138 // @todo We need to pass whether a link is present as placement context. 139 if ( ! is_single() ) { 140 $rendered = sprintf( '<a href="%s" rel="bookmark">%s</a>', esc_url( get_permalink( $post->ID ) ), $rendered ); 141 } 142 } elseif ( 'post_content' === $this->field_id ) { 143 $rendered = get_the_content(); 144 145 $protected_title_format = apply_filters( 'protected_title_format', __( 'Protected: %s', 'customize-posts' ), $post ); 146 $rendered = sprintf( $protected_title_format, $rendered ); 147 } elseif ( isset( $post->post_status ) && 'private' === $post->post_status ) { 145 148 /** This filter is documented in wp-includes/post-template.php */ 146 $rendered = apply_filters( 'the_content', $rendered ); 147 $rendered = str_replace( ']]>', ']]>', $rendered ); 148 } elseif ( 'post_excerpt' === $partial->field_id ) { 149 $rendered = get_the_excerpt(); 150 151 /** This filter is documented in wp-includes/post-template.php */ 152 $rendered = apply_filters( 'the_excerpt', $rendered ); 153 } elseif ( ( 'comment_status' === $partial->field_id && 'comments-area' === $this->placement ) || ( 'ping_status' === $partial->field_id ) && is_singular() ) { 149 $private_title_format = apply_filters( 'private_title_format', __( 'Private: %s', 'customize-posts' ), $post ); 150 $rendered = sprintf( $private_title_format, $rendered ); 151 } 152 153 /** This filter is documented in wp-includes/post-template.php */ 154 $rendered = apply_filters( 'the_title', $rendered, $post->ID ); 155 156 // @todo We need to pass whether a link is present as placement context. 157 if ( ! is_single() ) { 158 $rendered = sprintf( '<a href="%s" rel="bookmark">%s</a>', esc_url( get_permalink( $post->ID ) ), $rendered ); 159 } 160 161 return $rendered; 162 } 163 164 /** 165 * Render the post content. 166 * 167 * @param WP_Customize_Partial $partial Partial. 168 * @param array $context Context. 169 * @param WP_Post $post Post object. 170 * @return string 171 */ 172 public function render_post_content( $partial, $context, $post ) { 173 unset( $partial, $context, $post ); 174 $rendered = get_the_content(); 175 176 /** This filter is documented in wp-includes/post-template.php */ 177 $rendered = apply_filters( 'the_content', $rendered ); 178 $rendered = str_replace( ']]>', ']]>', $rendered ); 179 180 return $rendered; 181 } 182 183 /** 184 * Render the post excerpt. 185 * 186 * @param WP_Customize_Partial $partial Partial. 187 * @param array $context Context. 188 * @param WP_Post $post Post object. 189 * @return string 190 */ 191 public function render_post_excerpt( $partial, $context, $post ) { 192 unset( $partial, $context, $post ); 193 $rendered = get_the_excerpt(); 194 195 /** This filter is documented in wp-includes/post-template.php */ 196 $rendered = apply_filters( 'the_excerpt', $rendered ); 197 198 return $rendered; 199 } 200 201 /** 202 * Render comments area & link. 203 * 204 * @param WP_Customize_Partial $partial Partial. 205 * @param array $context Context. 206 * @param WP_Post $post Post object. 207 * @return string|null 208 */ 209 public function render_comment_status( $partial, $context, $post ) { 210 unset( $partial, $context, $post ); 211 $rendered = null; 212 213 if ( 'comments-area' === $this->placement && is_singular() ) { 154 214 if ( comments_open() || get_comments_number() ) { 155 215 ob_start(); … … 160 220 $rendered = ''; 161 221 } 162 } elseif ( 'comment _status' === $partial->field_id && 'comments-link' === $this->placement && ! is_single() && ! post_password_required() && ( comments_open() || get_comments_number() ) ) {222 } elseif ( 'comments-link' === $this->placement && ! is_single() && ! post_password_required() && ( comments_open() || get_comments_number() ) ) { 163 223 ob_start(); 164 224 /* translators: %s: post title */ … … 169 229 $rendered = '<span class="comments-link">' . $link . '</span>'; 170 230 } 171 } elseif ( 'post_author' === $this->field_id ) { 172 if ( 'author-bio' === $this->placement && is_singular() && get_the_author_meta( 'description' ) ) { 173 174 $rendered = false; 175 $template_parts = array( 176 'template-parts/biography', 177 'author-bio', 178 ); 179 foreach ( $template_parts as $template_part ) { 180 if ( '' !== locate_template( $template_part . '.php' ) ) { 181 ob_start(); 182 get_template_part( $template_part ); 183 $rendered = ob_get_contents(); 184 ob_end_clean(); 185 break; 186 } 187 } 188 } elseif ( 'byline' === $this->placement && ( is_singular() || is_multi_author() ) ) { 189 $rendered = sprintf( '<a class="url fn n" href="%1$s">%2$s</a>', 190 esc_url( get_author_posts_url( get_the_author_meta( 'ID', $post->post_author ) ) ), 191 get_the_author_meta( 'display_name', $post->post_author ) 192 ); 193 } elseif ( 'avatar' === $this->placement ) { 194 $size = isset( $context['size'] ) ? $context['size'] : 96; 195 $default = isset( $context['default'] ) ? $context['default'] : ''; 196 $alt = isset( $context['alt'] ) ? $context['alt'] : ''; 197 $rendered = get_avatar( get_the_author_meta( 'user_email' ), $size, $default, $alt, $context ); 198 } 199 } 200 201 wp_reset_postdata(); 202 return $rendered; 203 } 204 205 /** 206 * Export data to JS. 207 * 208 * @return array 209 */ 210 public function json() { 211 $data = parent::json(); 212 $data['post_type'] = $this->post_type; 213 $data['post_id'] = $this->post_id; 214 $data['field_id'] = $this->field_id; 215 $data['placement'] = $this->placement; 216 return $data; 231 } 232 233 return $rendered; 234 } 235 236 /** 237 * Render pings. 238 * 239 * @param WP_Customize_Partial $partial Partial. 240 * @param array $context Context. 241 * @param WP_Post $post Post object. 242 * @return string 243 */ 244 public function render_ping_status( $partial, $context, $post ) { 245 unset( $partial, $context, $post ); 246 if ( is_singular() && ( comments_open() || get_comments_number() ) ) { 247 ob_start(); 248 comments_template(); 249 $rendered = ob_get_contents(); 250 ob_end_clean(); 251 } else { 252 $rendered = ''; 253 } 254 255 return $rendered; 256 } 257 258 /** 259 * Render post author. 260 * 261 * @param WP_Customize_Partial $partial Partial. 262 * @param array $context Context. 263 * @param WP_Post $post Post object. 264 * @return string|bool 265 */ 266 public function render_post_author( $partial, $context, $post ) { 267 unset( $partial ); 268 $rendered = null; 269 270 if ( 'byline' === $this->placement && ( is_singular() || is_multi_author() ) ) { 271 $rendered = sprintf( '<a class="url fn n" href="%1$s">%2$s</a>', 272 esc_url( get_author_posts_url( get_the_author_meta( 'ID', $post->post_author ) ) ), 273 get_the_author_meta( 'display_name', $post->post_author ) 274 ); 275 } elseif ( 'avatar' === $this->placement ) { 276 $size = isset( $context['size'] ) ? $context['size'] : 96; 277 $default = isset( $context['default'] ) ? $context['default'] : ''; 278 $alt = isset( $context['alt'] ) ? $context['alt'] : ''; 279 $rendered = get_avatar( get_the_author_meta( 'user_email' ), $size, $default, $alt, $context ); 280 } 281 282 return $rendered; 217 283 } 218 284 } -
customize-posts/trunk/php/class-wp-customize-post-setting.php
r1406933 r1430660 183 183 } 184 184 185 $post_data = wp_array_slice_assoc( 186 $post_data, 187 array_keys( $this->default ) 188 ); 189 190 if ( 'customize-draft' === $post_data['post_status'] || 'auto-draft' === $post_data['post_status'] ) { 191 $post_data['post_status'] = 'publish'; 192 } 193 185 194 return $post_data; 186 195 } … … 200 209 201 210 if ( $this->is_previewed ) { 202 $post_data = array_merge( $post_data, $this->post_value( array() ) ); 211 $input_value = $this->post_value( array() ); 212 if ( null !== $input_value ) { 213 $post_data = array_merge( $post_data, $input_value ); 214 } 203 215 } 204 216 … … 214 226 */ 215 227 public function get_post_data( WP_Post $post ) { 216 $post_data = wp_array_slice_assoc( 217 $post->to_array(), 218 array_keys( $this->default ) 219 ); 220 $post_data = $this->normalize_post_data( $post_data ); 228 $post_data = $this->normalize_post_data( $post->to_array() ); 221 229 return $post_data; 222 230 } … … 248 256 * 249 257 * @param array $post_data The value to sanitize. 250 * @param bool $strict Whether validation is being done. This is part of the proposed patch in in #34893. 251 * @return string|array|null|WP_Error Null if an input isn't valid, otherwise the sanitized value. WP_Error returned if `$strict`. 252 */ 253 public function sanitize( $post_data, $strict = false ) { 258 * @return array|WP_Error|null Sanitized post array or WP_Error if invalid (or null if not WP 4.6-alpha). 259 */ 260 public function sanitize( $post_data ) { 254 261 global $wpdb; 262 $has_setting_validation = method_exists( 'WP_Customize_Setting', 'validate' ); 255 263 256 264 $post_data = array_merge( $this->default, $post_data ); 257 258 // The customize_validate_settings action is part of the Customize Setting Validation plugin.259 if ( ! $strict && doing_action( 'customize_validate_settings' ) ) {260 $strict = true;261 }262 265 263 266 $update = ( $this->post_id > 0 ); 264 267 $post_type_obj = get_post_type_object( $this->post_type ); 265 268 266 if ( $strict &&! empty( $post_data['post_type'] ) && $post_data['post_type'] !== $this->post_type ) {267 return new WP_Error( 'bad_post_type' );269 if ( ! empty( $post_data['post_type'] ) && $post_data['post_type'] !== $this->post_type ) { 270 return $has_setting_validation ? new WP_Error( 'bad_post_type' ) : null; 268 271 } 269 272 $post_data['post_type'] = $this->post_type; 270 273 271 if ( $ strict && $update) {274 if ( $update && did_action( 'customize_save_validation_before' ) ) { 272 275 // Check post lock. 276 require_once ABSPATH . 'wp-admin/includes/post.php'; 273 277 $locked_user = wp_check_post_lock( $this->post_id ); 274 278 if ( $locked_user ) { … … 278 282 $user ? $user->display_name : __( '(unknown user)', 'customize-posts' ) 279 283 ); 280 return new WP_Error( 'post_locked', $error_message );284 return $has_setting_validation ? new WP_Error( 'post_locked', $error_message ) : null; 281 285 } 282 286 … … 299 303 ); 300 304 $this->posts_component->update_conflicted_settings[ $this->id ] = $this; 301 return new WP_Error( 'post_update_conflict', $error_message );305 return $has_setting_validation ? new WP_Error( 'post_update_conflict', $error_message ) : null; 302 306 } 303 307 } … … 315 319 316 320 /** This filter is documented in wp-includes/post.php */ 317 if ( $strict&& apply_filters( 'wp_insert_post_empty_content', $maybe_empty, $post_data ) ) {318 return new WP_Error( 'empty_content', __( 'Content, title, and excerpt are empty.', 'customize-posts' ) );321 if ( 'trash' !== $post_data['post_status'] && apply_filters( 'wp_insert_post_empty_content', $maybe_empty, $post_data ) ) { 322 return $has_setting_validation ? new WP_Error( 'empty_content', __( 'Content, title, and excerpt are empty.', 'customize-posts' ) ) : null; 319 323 } 320 324 … … 368 372 $valid_date = wp_checkdate( $mm, $jj, $aa, $post_data['post_date'] ); 369 373 if ( ! $valid_date ) { 370 if ( $strict ) { 371 return new WP_Error( 'invalid_date', __( 'Whoops, the provided date is invalid.', 'customize-posts' ) ); 372 } else { 373 $post_data['post_date'] = ''; 374 } 374 return $has_setting_validation ? new WP_Error( 'invalid_date', __( 'Whoops, the provided date is invalid.', 'customize-posts' ) ) : null; 375 375 } 376 376 … … 505 505 $data['post_type'] = $this->post_type; 506 506 507 $result = wp_update_post( wp_slash( $data ), true ); 508 509 if ( is_wp_error( $result ) ) { 510 // @todo Amend customize_save_response 511 return false; 512 } 513 return true; 507 $is_trashed = 'trash' === $data['post_status']; 508 if ( $is_trashed ) { 509 add_filter( 'wp_insert_post_empty_content', '__return_false', 100 ); 510 511 /* 512 * Do not transition the post_status to trash, use the current value. 513 * 514 * If we were to unset `$data['post_status']`, the post would not be 515 * properly purged from the Customizer pane. And if we transitioned the 516 * status in `wp_update_post()` then `wp_trash_post()` would return false. 517 */ 518 $data['post_status'] = get_post_status( $this->post_id ); 519 } 520 521 $r = wp_update_post( wp_slash( $data ), true ); 522 $result = ! is_wp_error( $r ); 523 524 if ( $is_trashed ) { 525 $result = wp_trash_post( $this->post_id ); 526 remove_filter( 'wp_insert_post_empty_content', '__return_false', 100 ); 527 } 528 529 return $result; 514 530 } 515 531 } -
customize-posts/trunk/php/class-wp-customize-postmeta-controller.php
r1406933 r1430660 57 57 58 58 /** 59 * Setting validate callback. 60 * 61 * @var callable 62 */ 63 public $validate_callback; 64 65 /** 59 66 * Setting transport. 60 67 * … … 95 102 $this->sanitize_js_callback = array( $this, 'js_value' ); 96 103 } 104 if ( ! isset( $this->validate_callback ) ) { 105 $this->validate_callback = array( $this, 'validate_setting' ); 106 } 97 107 98 108 add_action( 'customize_posts_register_meta', array( $this, 'register_meta' ) ); … … 130 140 'sanitize_callback' => $this->sanitize_callback, 131 141 'sanitize_js_callback' => $this->sanitize_js_callback, 142 'validate_callback' => $this->validate_callback, 132 143 'transport' => $this->setting_transport, 133 144 'theme_supports' => $this->theme_supports, … … 192 203 193 204 /** 194 * Sanitize (and validate)an input.205 * Sanitize an input. 195 206 * 196 207 * Callback for `customize_sanitize_post_meta_{$meta_key}` filter. … … 200 211 * @param string $meta_value The value to sanitize. 201 212 * @param WP_Customize_Postmeta_Setting $setting Setting. 202 * @param bool $strict Whether validation is being done. This is part of the proposed patch in in #34893. 203 * @return mixed|null Null if an input isn't valid, otherwise the sanitized value. 204 */ 205 public function sanitize_setting( $meta_value, WP_Customize_Postmeta_Setting $setting, $strict = false ) { 206 unset( $setting, $strict ); 213 * @return mixed|null Sanitized value or `null` if invalid. 214 */ 215 public function sanitize_setting( $meta_value, WP_Customize_Postmeta_Setting $setting ) { 216 unset( $setting ); 207 217 return $meta_value; 218 } 219 220 /** 221 * Validate an input. 222 * 223 * Callback for `customize_validate_post_meta_{$meta_key}` filter. 224 * 225 * @see update_metadata() 226 * 227 * @param WP_Error $validity Validity. 228 * @param string $meta_value The value to sanitize. 229 * @param WP_Customize_Postmeta_Setting $setting Setting. 230 * @return WP_Error Validity. 231 */ 232 public function validate_setting( $validity, $meta_value, WP_Customize_Postmeta_Setting $setting ) { 233 unset( $setting, $meta_value ); 234 return $validity; 208 235 } 209 236 -
customize-posts/trunk/php/class-wp-customize-postmeta-setting.php
r1406933 r1430660 125 125 $meta_key = $this->meta_key; 126 126 $object_id = $this->post_id; 127 $single = true; 128 $value = get_post_meta( $object_id, $meta_key, $single ); 129 if ( '' === $value ) { 127 $single = false; 128 $values = get_post_meta( $object_id, $meta_key, $single ); 129 $value = array_shift( $values ); 130 if ( ! isset( $value ) ) { 130 131 $value = $this->default; 131 132 } … … 140 141 * 141 142 * @param string $meta_value The value to sanitize. 142 * @param bool $strict Whether validation is being done. This is part of the proposed patch in in #34893. 143 * @return mixed|null Null if an input isn't valid, otherwise the sanitized value. 144 */ 145 public function sanitize( $meta_value, $strict = false ) { 146 147 // The customize_validate_settings action is part of the Customize Setting Validation plugin. 148 if ( ! $strict && doing_action( 'customize_validate_settings' ) ) { 149 $strict = true; 150 } 143 * @return mixed|WP_Error|null Sanitized post array or WP_Error if invalid (or null if not WP 4.6-alpha). 144 */ 145 public function sanitize( $meta_value ) { 146 $has_setting_validation = method_exists( 'WP_Customize_Setting', 'validate' ); 151 147 152 148 $meta_type = 'post'; … … 160 156 * @param mixed $meta_value Value of the setting. 161 157 * @param WP_Customize_Setting $this WP_Customize_Setting instance. 162 * @param bool $strict Whether validation is being done. This is part of the proposed patch in in #34893.163 158 */ 164 $meta_value = apply_filters( "customize_sanitize_{$this->id}", $meta_value, $this , $strict);159 $meta_value = apply_filters( "customize_sanitize_{$this->id}", $meta_value, $this ); 165 160 166 161 // Apply sanitization if value didn't fail validation. … … 168 163 $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type ); 169 164 } 165 if ( is_wp_error( $meta_value ) ) { 166 return $has_setting_validation ? $meta_value : null; 167 } 170 168 171 169 /** This filter is documented in wp-includes/meta.php */ 172 170 $check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value ); 173 171 if ( null !== $check ) { 174 if ( $strict ) { 175 return new WP_Error( 'not_allowed', sprintf( __( 'Update to post meta "%s" blocked.', 'customize-posts' ), $meta_key ) ); 176 } else { 177 return null; 178 } 172 return $has_setting_validation ? new WP_Error( 'not_allowed', sprintf( __( 'Update to post meta "%s" blocked.', 'customize-posts' ), $meta_key ) ) : null; 179 173 } 180 174 -
customize-posts/trunk/php/class-wp-customize-posts-preview.php
r1406933 r1430660 67 67 add_filter( 'comments_open', array( $this, 'filter_preview_comments_open' ), 10, 2 ); 68 68 add_filter( 'pings_open', array( $this, 'filter_preview_pings_open' ), 10, 2 ); 69 add_filter( 'get_post_metadata', array( $this, 'filter_get_post_meta_to_add_dynamic_postmeta_settings' ), 1000, 4);69 add_filter( 'get_post_metadata', array( $this, 'filter_get_post_meta_to_add_dynamic_postmeta_settings' ), 1000, 2 ); 70 70 add_action( 'wp_footer', array( $this, 'export_preview_data' ), 10 ); 71 71 add_filter( 'edit_post_link', array( $this, 'filter_edit_post_link' ), 10, 2 ); … … 85 85 add_filter( 'the_posts', array( $this, 'filter_the_posts_to_preview_settings' ), 1000 ); 86 86 add_action( 'the_post', array( $this, 'preview_setup_postdata' ) ); 87 add_filter( 'the_title', array( $this, 'filter_the_title' ), 1, 2 ); 87 88 add_filter( 'get_post_metadata', array( $this, 'filter_get_post_meta_to_preview' ), 1000, 4 ); 89 add_filter( 'posts_where', array( $this, 'filter_posts_where_to_include_previewed_posts' ), 10, 2 ); 90 add_filter( 'wp_setup_nav_menu_item', array( $this, 'filter_nav_menu_item_to_set_url' ) ); 88 91 $this->has_preview_filters = true; 89 92 return true; … … 126 129 127 130 /** 128 * Create dynamic post settings and sections for posts queried in the page. 131 * Retrieve post title and filter according to the current Customizer state. 132 * 133 * This is necessary because the is currently no filter yet in WP to mutate 134 * the underling post object. This specifically was noticed in the `get_the_title()` 135 * call in `WP_REST_Posts_Controller::prepare_item_for_response()`. 136 * 137 * @link https://github.com/xwp/wp-customize-posts/issues/96 138 * @link https://core.trac.wordpress.org/ticket/12955 139 * 140 * @param string $title Filtered title. 141 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. 142 * @return string Title. 143 */ 144 public function filter_the_title( $title, $post ) { 145 if ( empty( $post ) ) { 146 return $title; 147 } 148 $post = get_post( $post ); 149 if ( empty( $post ) ) { 150 return $title; 151 } 152 153 $setting_id = WP_Customize_Post_Setting::get_post_setting_id( $post ); 154 $setting = $this->component->manager->get_setting( $setting_id ); 155 156 if ( ! ( $setting instanceof WP_Customize_Post_Setting ) ) { 157 return $title; 158 } 159 $post_data = $setting->post_value(); 160 if ( ! is_array( $post_data ) || ! isset( $post_data['post_title'] ) ) { 161 return $title; 162 } 163 164 $title = $post_data['post_title']; 165 166 /* 167 * Begin code modified from get_the_title(): 168 * https://github.com/xwp/wordpress-develop/blob/6792df6fab87063e0564148c6634aaa0ed3156b4/src/wp-includes/post-template.php#L113-L148 169 */ 170 171 if ( ! is_admin() ) { 172 $mock_post = new WP_Post( (object) array_merge( 173 $post->to_array(), 174 $post_data 175 ) ); 176 177 if ( ! empty( $post_data['post_password'] ) ) { 178 179 /** This filter is documented in wp-includes/post-template.php */ 180 $protected_title_format = apply_filters( 'protected_title_format', __( 'Protected: %s', 'customize-posts' ), $mock_post ); 181 $title = sprintf( $protected_title_format, $title ); 182 } elseif ( isset( $post_data['post_status'] ) && 'private' === $post_data['post_status'] ) { 183 184 /** This filter is documented in wp-includes/post-template.php */ 185 $private_title_format = apply_filters( 'private_title_format', __( 'Private: %s', 'customize-posts' ), $mock_post ); 186 $title = sprintf( $private_title_format, $title ); 187 } 188 } 189 190 return $title; 191 } 192 193 /** 194 * Create dynamic post/postmeta settings and sections for posts queried in the page. 129 195 * 130 196 * @param array $posts Posts. … … 143 209 $this->component->manager->add_section( $section ); 144 210 } 211 $this->component->register_post_type_meta_settings( $post->ID ); 145 212 } 146 213 return $posts; … … 165 232 166 233 /** 234 * Get current posts being previewed which should be included in the given query. 235 * 236 * @access public 237 * 238 * @param \WP_Query $query The query. 239 * @param boolean $published Whether to return the published posts. Default 'true'. 240 * @return array 241 */ 242 public function get_previewed_posts_for_query( WP_Query $query, $published = true ) { 243 $query_vars = $query->query_vars; 244 245 if ( empty( $query_vars['post_type'] ) ) { 246 $query_vars['post_type'] = array( 'post' ); 247 } elseif ( is_string( $query_vars['post_type'] ) ) { 248 $query_vars['post_type'] = explode( ',', $query_vars['post_type'] ); 249 } 250 251 if ( empty( $query_vars['post_status'] ) ) { 252 $query_vars['post_status'] = array( 'publish' ); 253 } elseif ( is_string( $query_vars['post_status'] ) ) { 254 $query_vars['post_status'] = explode( ',', $query_vars['post_status'] ); 255 } 256 257 $post_ids = array(); 258 $settings = $this->component->manager->unsanitized_post_values(); 259 if ( ! empty( $settings ) ) { 260 foreach ( (array) $settings as $id => $post_data ) { 261 if ( ! preg_match( WP_Customize_Post_Setting::SETTING_ID_PATTERN, $id, $matches ) ) { 262 continue; 263 } 264 $post_id = intval( $matches['post_id'] ); 265 $statuses = $query_vars['post_status']; 266 267 $post_type_match = ( 268 empty( $query_vars['post_type'] ) 269 || 270 in_array( $matches['post_type'], $query_vars['post_type'], true ) 271 || 272 ( 273 in_array( 'any', $query_vars['post_type'], true ) 274 && 275 in_array( $matches['post_type'], get_post_types( array( 'exclude_from_search' => false ) ), true ) 276 ) 277 ); 278 279 $post_type_obj = get_post_type_object( $matches['post_type'] ); 280 if ( $post_type_obj && current_user_can( $post_type_obj->cap->read_private_posts, $post_id ) ) { 281 $statuses[] = 'private'; 282 } 283 284 if ( empty( $query_vars['post_status'] ) ) { 285 $post_status_match = true; 286 } elseif ( false === $published ) { 287 $post_status_match = ! in_array( $post_data['post_status'], array( 'publish', 'private' ), true ); 288 } else { 289 $post_status_match = in_array( $post_data['post_status'], $statuses, true ); 290 } 291 292 $post__in_match = empty( $query_vars['post__in'] ) || in_array( $post_id, $query_vars['post__in'], true ); 293 if ( $post_status_match && $post_type_match && $post__in_match ) { 294 $post_ids[] = $post_id; 295 } 296 } 297 } 298 299 return $post_ids; 300 } 301 302 /** 303 * Include stubbed posts that are being previewed. 304 * 305 * @filter posts_where 306 * @access public 307 * 308 * @param string $where The WHERE clause of the query. 309 * @param WP_Query $query The WP_Query instance (passed by reference). 310 * @return string 311 */ 312 public function filter_posts_where_to_include_previewed_posts( $where, $query ) { 313 global $wpdb; 314 315 if ( ! $query->is_singular() ) { 316 $post__not_in = implode( ',', array_map( 'absint', $this->get_previewed_posts_for_query( $query, false ) ) ); 317 if ( ! empty( $post__not_in ) ) { 318 $where .= " AND {$wpdb->posts}.ID NOT IN ($post__not_in)"; 319 } 320 $post__in = implode( ',', array_map( 'absint', $this->get_previewed_posts_for_query( $query, true ) ) ); 321 if ( ! empty( $post__in ) ) { 322 $where .= " OR {$wpdb->posts}.ID IN ($post__in)"; 323 } 324 } 325 326 return $where; 327 } 328 329 /** 330 * Filter a nav menu item for an added post to supply a URL field. 331 * 332 * This is probably a bug in Core where the `value_as_wp_post_nav_menu_item` 333 * should be setting the url property. 334 * 335 * @access public 336 * @see WP_Customize_Nav_Menu_Item_Setting::value_as_wp_post_nav_menu_item() 337 * 338 * @param WP_Post $nav_menu_item Nav menu item. 339 * @return WP_Post Nav menu item. 340 */ 341 public function filter_nav_menu_item_to_set_url( $nav_menu_item ) { 342 if ( 'post_type' !== $nav_menu_item->type || $nav_menu_item->url || ! $nav_menu_item->object_id ) { 343 return $nav_menu_item; 344 } 345 346 $post = get_post( $nav_menu_item->object_id ); 347 if ( ! $post ) { 348 return $nav_menu_item; 349 } 350 $setting_id = WP_Customize_Post_Setting::get_post_setting_id( $post ); 351 $setting = $this->component->manager->get_setting( $setting_id ); 352 if ( $setting ) { 353 $nav_menu_item->url = get_permalink( $post->ID ); 354 } 355 return $nav_menu_item; 356 } 357 358 /** 167 359 * Filter the comments open for a previewed post. 168 360 * … … 205 397 * @param null|array|string $value The value get_metadata() should return - a single metadata value, or an array of values. 206 398 * @param int $object_id Object ID. 207 * @param string $meta_key Meta key.208 399 * @return mixed Value. 209 400 */ 210 public function filter_get_post_meta_to_add_dynamic_postmeta_settings( $value, $object_id, $meta_key ) { 211 $post = get_post( $object_id ); 212 if ( ! $post || ! isset( $this->component->registered_post_meta[ $post->post_type ] ) ) { 213 return $value; 214 } 215 216 if ( '' === $meta_key ) { 217 if ( null !== $value ) { 218 $meta_keys = array_keys( $value ); 219 } else { 220 $meta_keys = array(); 221 } 222 } else { 223 $meta_keys = array( $meta_key ); 224 } 225 226 $setting_ids = array(); 227 if ( ! empty( $meta_keys ) ) { 228 foreach ( $meta_keys as $key ) { 229 if ( isset( $this->component->registered_post_meta[ $post->post_type ][ $key ] ) ) { 230 $setting_ids[] = WP_Customize_Postmeta_Setting::get_post_meta_setting_id( $post, $key ); 231 } 232 } 233 } 234 $this->component->manager->add_dynamic_settings( $setting_ids ); 235 401 public function filter_get_post_meta_to_add_dynamic_postmeta_settings( $value, $object_id ) { 402 $this->component->register_post_type_meta_settings( $object_id ); 236 403 return $value; 237 404 } … … 327 494 } 328 495 $args['type'] = WP_Customize_Post_Field_Partial::TYPE; 496 497 $field_id = $matches['field_id']; 498 if ( ! empty( $matches['placement'] ) ) { 499 $field_id .= '[' . $matches['placement'] . ']'; 500 } 501 $schema = $this->get_post_field_partial_schema( $field_id ); 502 if ( ! empty( $schema ) ) { 503 $args = array_merge( $args, $schema ); 504 } 329 505 } 330 506 return $args; … … 420 596 421 597 /** 598 * Get the schema for dynamically registered partials. 599 * 600 * @param string $field_id The partial field ID. 601 * @return array 602 */ 603 public function get_post_field_partial_schema( $field_id = '' ) { 604 $schema = array( 605 'post_title' => array( 606 'selector' => '.entry-title', 607 ), 608 'post_name' => array( 609 'fallback_refresh' => false, 610 ), 611 'post_status' => array( 612 'fallback_refresh' => true, 613 ), 614 'post_content' => array( 615 'selector' => '.entry-content', 616 ), 617 'post_excerpt' => array( 618 'selector' => '.entry-summary', 619 ), 620 'comment_status[comments-area]' => array( 621 'selector' => '.comments-area', 622 'body_selector' => true, 623 'singular_only' => true, 624 'container_inclusive' => true, 625 ), 626 'comment_status[comments-link]' => array( 627 'selector' => '.comments-link', 628 'archive_only' => true, 629 'container_inclusive' => true, 630 ), 631 'ping_status' => array( 632 'selector' => '.comments-area', 633 'body_selector' => true, 634 'singular_only' => true, 635 'container_inclusive' => true, 636 ), 637 'post_author[byline]' => array( 638 'selector' => '.vcard a.fn', 639 'container_inclusive' => true, 640 'fallback_refresh' => false, 641 ), 642 'post_author[avatar]' => array( 643 'selector' => '.vcard img.avatar', 644 'container_inclusive' => true, 645 'fallback_refresh' => false, 646 ), 647 ); 648 649 /** 650 * Filter the schema for dynamically registered partials. 651 * 652 * @param array $schema Partial schema. 653 * @return array 654 */ 655 $schema = apply_filters( 'customize_posts_partial_schema', $schema ); 656 657 // Return specific schema based on the field_id & placement. 658 if ( ! empty( $field_id ) ) { 659 if ( isset( $schema[ $field_id ] ) ) { 660 return $schema[ $field_id ]; 661 } else { 662 return array(); 663 } 664 } 665 666 return $schema; 667 } 668 669 /** 422 670 * Export data into the customize preview. 423 671 */ … … 443 691 } 444 692 693 $exported_partial_schema = array(); 694 foreach ( $this->get_post_field_partial_schema() as $key => $schema ) { 695 unset( $schema['render_callback'] ); // PHP callbacks are generally not JSON-serializable. 696 $exported_partial_schema[ $key ] = $schema; 697 } 698 445 699 $exported = array( 446 700 'isPostPreview' => is_preview(), … … 448 702 'queriedPostId' => $queried_post_id, 449 703 'settingProperties' => $setting_properties, 704 'partialSchema' => $exported_partial_schema, 450 705 ); 451 706 -
customize-posts/trunk/php/class-wp-customize-posts.php
r1406933 r1430660 44 44 45 45 /** 46 * Registered support classes. 47 * 48 * @var array 49 */ 50 public $supports = array(); 51 52 /** 53 * Whether the post link filters are being suppressed. 54 * 55 * @var bool 56 */ 57 public $suppress_post_link_filters = false; 58 59 /** 60 * Customize draft post IDs. 61 * 62 * @var array 63 */ 64 public $customize_draft_post_ids = array(); 65 66 /** 46 67 * Initial loader. 47 68 * … … 71 92 add_filter( 'customize_dynamic_setting_class', array( $this, 'filter_customize_dynamic_setting_class' ), 5, 3 ); 72 93 add_filter( 'customize_save_response', array( $this, 'filter_customize_save_response_for_conflicts' ), 10, 2 ); 94 add_filter( 'customize_save_response', array( $this, 'filter_customize_save_response_to_export_saved_values' ), 10, 2 ); 95 add_action( 'customize_controls_print_footer_scripts', array( $this, 'render_templates' ) ); 96 add_action( 'init', array( $this, 'register_customize_draft' ) ); 97 add_filter( 'customize_snapshot_save', array( $this, 'transition_customize_draft' ) ); 98 add_action( 'after_setup_theme', array( $this, 'preview_customize_draft_post_ids' ) ); 99 add_action( 'pre_get_posts', array( $this, 'preview_customize_draft' ) ); 100 add_filter( 'post_link', array( $this, 'post_link_draft' ), 10, 2 ); 101 add_filter( 'post_type_link', array( $this, 'post_link_draft' ), 10, 2 ); 102 add_filter( 'page_link', array( $this, 'post_link_draft' ), 10, 2 ); 103 add_action( 'wp_ajax_customize-posts-insert-auto-draft', array( $this, 'ajax_insert_auto_draft_post' ) ); 73 104 74 105 $this->preview = new WP_Customize_Posts_Preview( $this ); 106 } 107 108 /** 109 * Instantiate a Customize Posts support class. 110 * 111 * The support class must extend `Customize_Posts_Support` or one of it's subclasses. 112 * 113 * @param string|Customize_Posts_Support $support The support class name or object. 114 */ 115 function add_support( $support ) { 116 if ( is_string( $support ) && class_exists( $support, false ) ) { 117 $support = new $support( $this ); 118 } 119 120 if ( $support instanceof Customize_Posts_Support ) { 121 $class_name = get_class( $support ); 122 if ( ! isset( $this->supports[ $class_name ] ) ) { 123 $this->supports[ $class_name ] = $support; 124 $support->init(); 125 } 126 } 75 127 } 76 128 … … 88 140 $post_type_objects = get_post_types( array(), 'objects' ); 89 141 foreach ( $post_type_objects as $post_type_object ) { 90 $is_included = $post_type_object->show_ui; 91 if ( isset( $post_type_object->show_in_customizer ) ) { 92 $is_included = $post_type_object->show_in_customizer; 93 } 94 95 if ( $is_included ) { 96 $post_type_object = clone $post_type_object; 97 $post_type_object->supports = get_all_post_type_supports( $post_type_object->name ); 98 99 // Remove unnecessary properties. 100 unset( $post_type_object->register_meta_box_cb ); 101 102 $post_types[ $post_type_object->name ] = $post_type_object; 103 } 142 $post_type_object = clone $post_type_object; 143 if ( ! isset( $post_type_object->show_in_customizer ) ) { 144 $post_type_object->show_in_customizer = $post_type_object->show_ui; 145 } 146 $post_type_object->supports = get_all_post_type_supports( $post_type_object->name ); 147 148 // Remove unnecessary properties. 149 unset( $post_type_object->register_meta_box_cb ); 150 151 $post_types[ $post_type_object->name ] = $post_type_object; 104 152 } 105 153 … … 145 193 'sanitize_callback' => null, 146 194 'sanitize_js_callback' => null, 195 'validate_callback' => null, 147 196 'setting_class' => 'WP_Customize_Postmeta_Setting', 148 197 ), … … 229 278 $this->set_builtin_post_type_descriptions(); 230 279 foreach ( $this->get_post_types() as $post_type_object ) { 280 if ( empty( $post_type_object->show_in_customizer ) ) { 281 continue; 282 } 283 231 284 $panel_id = sprintf( 'posts[%s]', $post_type_object->name ); 232 285 … … 339 392 340 393 /** 394 * Add all postmeta settings for all registered postmeta for a given post type instance. 395 * 396 * @param int $post_id Post ID. 397 * @return array 398 */ 399 public function register_post_type_meta_settings( $post_id ) { 400 $post = get_post( $post_id ); 401 $setting_ids = array(); 402 if ( ! empty( $post ) && isset( $this->registered_post_meta[ $post->post_type ] ) ) { 403 foreach ( array_keys( $this->registered_post_meta[ $post->post_type ] ) as $key ) { 404 $setting_ids[] = WP_Customize_Postmeta_Setting::get_post_meta_setting_id( $post, $key ); 405 } 406 } 407 $this->manager->add_dynamic_settings( $setting_ids ); 408 409 return $setting_ids; 410 } 411 412 /** 341 413 * When loading the customizer from a post, get the post. 342 414 * … … 350 422 $post = get_post( $post_id ); 351 423 return $post; 424 } 425 426 /** 427 * Get the post status choices array. 428 * 429 * @return array 430 */ 431 public function get_post_status_choices() { 432 $choices = array( 433 array( 434 'value' => 'draft', 435 'text' => __( 'Draft', 'customize-posts' ), 436 ), 437 array( 438 'value' => 'pending', 439 'text' => __( 'Pending Review', 'customize-posts' ), 440 ), 441 array( 442 'value' => 'private', 443 'text' => __( 'Private', 'customize-posts' ), 444 ), 445 array( 446 'value' => 'publish', 447 'text' => __( 'Published', 'customize-posts' ), 448 ), 449 array( 450 'value' => 'trash', 451 'text' => __( 'Trash', 'customize-posts' ), 452 ), 453 ); 454 455 return $choices; 352 456 } 353 457 … … 420 524 421 525 /** 526 * Return the saved sanitized values for posts and postmeta to update in the client. 527 * 528 * This was originally in the Customize Setting Validation plugin. 529 * 530 * @link https://github.com/xwp/wp-customize-setting-validation/blob/2e5ddc66a870ad7b1aee5f8e414bad4b78e120d2/php/class-plugin.php#L283-L317 531 * 532 * @param array $response Response. 533 * @return array 534 */ 535 public function filter_customize_save_response_to_export_saved_values( $response ) { 536 $response['saved_post_setting_values'] = array(); 537 foreach ( array_keys( $this->manager->unsanitized_post_values() ) as $setting_id ) { 538 $setting = $this->manager->get_setting( $setting_id ); 539 if ( $setting instanceof WP_Customize_Post_Setting || $setting instanceof WP_Customize_Postmeta_Setting ) { 540 $response['saved_post_setting_values'][ $setting->id ] = $setting->value(); 541 } 542 } 543 return $response; 544 } 545 546 /** 422 547 * Enqueue scripts and styles for Customize Posts. 423 548 */ … … 432 557 } 433 558 434 $post_types[ $post_type ] = wp_array_slice_assoc( (array) $post_type_obj, array( 435 'name', 436 'supports', 437 'labels', 438 'has_archive', 439 'menu_icon', 440 'description', 441 'hierarchical', 442 ) ); 559 $post_types[ $post_type ] = array_merge( 560 wp_array_slice_assoc( (array) $post_type_obj, array( 561 'name', 562 'supports', 563 'labels', 564 'has_archive', 565 'menu_icon', 566 'description', 567 'hierarchical', 568 'show_in_customizer', 569 'publicly_queryable', 570 'public', 571 ) ), 572 array( 573 'current_user_can' => array( 574 'create_posts' => current_user_can( $post_type_obj->cap->create_posts ), 575 'delete_posts' => current_user_can( $post_type_obj->cap->delete_posts ), 576 ), 577 ) 578 ); 443 579 } 444 580 445 581 $exports = array( 582 'nonce' => wp_create_nonce( 'customize-posts' ), 446 583 'postTypes' => $post_types, 584 'postStatusChoices' => $this->get_post_status_choices(), 447 585 'authorChoices' => $this->get_author_choices(), 448 586 'l10n' => array( … … 450 588 'sectionCustomizeActionTpl' => __( 'Customizing ▸ %s', 'customize-posts' ), 451 589 'fieldTitleLabel' => __( 'Title', 'customize-posts' ), 590 'fieldSlugLabel' => __( 'Slug', 'customize-posts' ), 591 'fieldPostStatusLabel' => __( 'Post Status', 'customize-posts' ), 452 592 'fieldContentLabel' => __( 'Content', 'customize-posts' ), 453 593 'fieldExcerptLabel' => __( 'Excerpt', 'customize-posts' ), … … 456 596 'noTitle' => __( '(no title)', 'customize-posts' ), 457 597 'theirChange' => __( 'Their change: %s', 'customize-posts' ), 458 'overrideButtonText' => __( 'Override', 'customize-posts' ),459 598 'openEditor' => __( 'Open Editor', 'customize-posts' ), 460 599 'closeEditor' => __( 'Close Editor', 'customize-posts' ), … … 484 623 */ 485 624 public function render_editor() { 486 echo '<div id="customize-posts-content-editor-pane">'; 487 488 // The settings passed in here are derived from those used in edit-form-advanced.php. 489 wp_editor( '', 'customize-posts-content', array( 490 '_content_editor_dfw' => false, 491 'drag_drop_upload' => true, 492 'tabfocus_elements' => 'content-html,save-post', 493 'editor_height' => 200, 494 'default_editor' => 'tinymce', 495 'tinymce' => array( 496 'resize' => false, 497 'wp_autoresize_on' => false, 498 'add_unload_trigger' => false, 499 ), 500 ) ); 501 502 echo '</div>'; 625 ?> 626 <div id="customize-posts-content-editor-pane"> 627 <div id="customize-posts-content-editor-dragbar"> 628 <span class="screen-reader-text"><?php _e( 'Resize Editor', 'customize-posts' ); ?></span> 629 </div> 630 631 <?php 632 // The settings passed in here are derived from those used in edit-form-advanced.php. 633 wp_editor( '', 'customize-posts-content', array( 634 '_content_editor_dfw' => false, 635 'drag_drop_upload' => true, 636 'tabfocus_elements' => 'content-html,save-post', 637 'editor_height' => 200, 638 'default_editor' => 'tinymce', 639 'tinymce' => array( 640 'resize' => false, 641 'wp_autoresize_on' => false, 642 'add_unload_trigger' => false, 643 ), 644 ) ); 645 ?> 646 647 </div> 648 <?php 503 649 } 504 650 … … 539 685 return $value; 540 686 } 687 688 /** 689 * Underscore (JS) templates. 690 */ 691 public function render_templates() { 692 ?> 693 <script type="text/html" id="tmpl-customize-posts-add-new"> 694 <li class="customize-posts-add-new"> 695 <button class="button-secondary add-new-post-stub"> 696 <?php esc_html_e( 'Add New', 'customize-posts' ); ?> {{ data.label }} 697 </button> 698 </li> 699 </script> 700 701 <script id="tmpl-customize-posts-navigation" type="text/html"> 702 <button class="customize-posts-navigation dashicons dashicons-visibility" tabindex="0"> 703 <span class="screen-reader-text"><?php esc_html_e( 'Preview', 'customize-posts' ); ?> {{ data.label }}</span> 704 </button> 705 </script> 706 707 <script id="tmpl-customize-posts-trashed" type="text/html"> 708 <span class="customize-posts-trashed">(<?php esc_html_e( 'Trashed', 'customize-posts' ); ?>)</span> 709 </script> 710 711 <script type="text/html" id="tmpl-customize-post-section-notifications"> 712 <ul> 713 <# _.each( data.notifications, function( notification ) { #> 714 <li class="notice notice-{{ notification.type || 'info' }} {{ data.altNotice ? 'notice-alt' : '' }}" data-code="{{ notification.code }}" data-type="{{ notification.type }}"> 715 <# if ( /post_update_conflict/.test( notification.code ) ) { #> 716 <button class="button override-post-conflict" type="button"><?php esc_html_e( 'Override', 'customize-posts' ); ?></button> 717 <# } #> 718 {{ notification.message || notification.code }} 719 </li> 720 <# } ); #> 721 </ul> 722 </script> 723 <?php 724 } 725 726 /** 727 * Register the `customize-draft` post status. 728 * 729 * @action init 730 * @access public 731 */ 732 public function register_customize_draft() { 733 register_post_status( 'customize-draft', array( 734 'label' => 'customize-draft', 735 'public' => false, 736 'internal' => true, 737 'protected' => true, 738 'exclude_from_search' => true, 739 'show_in_admin_all_list' => false, 740 'show_in_admin_status_list' => false, 741 ) ); 742 } 743 744 /** 745 * Transition the post status. 746 * 747 * This ensures unpublished new posts, which are added to a snapshot, are not 748 * garbage collected during the `wp_scheduled_auto_draft_delete` action by 749 * changing the default `auto-draft` post status to `customize-draft`. 750 * 751 * @filter customize_snapshot_save 752 * @access public 753 * 754 * @param array $data Customizer settings and values. 755 * @return array 756 */ 757 public function transition_customize_draft( $data ) { 758 foreach ( $data as $id => $setting ) { 759 if ( ! preg_match( WP_Customize_Post_Setting::SETTING_ID_PATTERN, $id, $matches ) ) { 760 continue; 761 } 762 if ( 'auto-draft' === get_post_status( $matches['post_id'] ) ) { 763 add_filter( 'wp_insert_post_empty_content', '__return_false', 100 ); 764 $result = wp_update_post( array( 765 'ID' => intval( $matches['post_id'] ), 766 'post_status' => 'customize-draft', 767 ), true ); 768 remove_filter( 'wp_insert_post_empty_content', '__return_false', 100 ); 769 770 // @todo Amend customize_save_response if error. 771 } 772 } 773 774 return $data; 775 } 776 777 /** 778 * Set the previewed `customize-draft` post IDs within a Snapshot. 779 * 780 * @action after_setup_theme 781 * @access public 782 */ 783 public function preview_customize_draft_post_ids() { 784 if ( isset( $_REQUEST['preview'] ) ) { 785 $this->customize_draft_post_ids = array(); 786 foreach ( $this->manager->unsanitized_post_values() as $id => $post_data ) { 787 if ( ! preg_match( WP_Customize_Post_Setting::SETTING_ID_PATTERN, $id, $matches ) ) { 788 continue; 789 } 790 $post_id = intval( $matches['post_id'] ); 791 if ( 'customize-draft' === get_post_status( $post_id ) ) { 792 $this->customize_draft_post_ids[] = $post_id; 793 } 794 } 795 } 796 } 797 798 /** 799 * Allow the `customize-draft` status to be previewed in a Snapshot by all users. 800 * 801 * @action pre_get_posts 802 * @access public 803 * 804 * @param WP_Query $query The WP_Query instance (passed by reference). 805 */ 806 public function preview_customize_draft( $query ) { 807 if ( $query->is_preview ) { 808 $query_vars = $query->query_vars; 809 $post_id = 0; 810 811 if ( ! empty( $query_vars['p'] ) ) { 812 $post_id = $query_vars['p']; 813 } elseif ( ! empty( $query_vars['page_id'] ) ) { 814 $post_id = $query_vars['page_id']; 815 } 816 817 if ( in_array( $post_id, $this->customize_draft_post_ids, true ) ) { 818 $query->set( 'post_status', 'customize-draft' ); 819 } 820 } 821 } 822 823 /** 824 * Filter the preview permalink for a post. 825 * 826 * @access public 827 * 828 * @param string $permalink The post's permalink. 829 * @param int|WP_Post $post The post in question. 830 * @return string 831 */ 832 public function post_link_draft( $permalink, $post ) { 833 if ( is_customize_preview() && ! $this->suppress_post_link_filters ) { 834 $permalink = Edit_Post_Preview::get_preview_post_link( get_post( $post ) ); 835 } 836 return $permalink; 837 } 838 839 /** 840 * Add a new `auto-draft` post. 841 * 842 * @access public 843 * 844 * @param string $post_type The post type. 845 * @return WP_Post|WP_Error 846 */ 847 public function insert_auto_draft_post( $post_type ) { 848 849 $post_type_obj = get_post_type_object( $post_type ); 850 if ( ! $post_type_obj ) { 851 return new WP_Error( 'unknown_post_type', __( 'Unknown post type', 'customize-posts' ) ); 852 } 853 854 add_filter( 'wp_insert_post_empty_content', '__return_false', 100 ); 855 $this->suppress_post_link_filters = true; 856 $date_local = current_time( 'mysql', 0 ); 857 $date_gmt = current_time( 'mysql', 1 ); 858 $args = array( 859 'post_status' => 'auto-draft', 860 'post_type' => $post_type, 861 'post_date' => $date_local, 862 'post_date_gmt' => $date_gmt, 863 'post_modified' => $date_local, 864 'post_modified_gmt' => $date_gmt, 865 ); 866 $r = wp_insert_post( wp_slash( $args ), true ); 867 remove_filter( 'wp_insert_post_empty_content', '__return_false', 100 ); 868 $this->suppress_post_link_filters = false; 869 870 if ( is_wp_error( $r ) ) { 871 return $r; 872 } else { 873 return get_post( $r ); 874 } 875 } 876 877 /** 878 * Ajax handler for adding a new post. 879 * 880 * @action wp_ajax_customize-posts-insert-auto-draft 881 * @access public 882 */ 883 public function ajax_insert_auto_draft_post() { 884 if ( ! check_ajax_referer( 'customize-posts', 'customize-posts-nonce', false ) ) { 885 status_header( 400 ); 886 wp_send_json_error( 'bad_nonce' ); 887 } 888 889 if ( ! current_user_can( 'customize' ) ) { 890 status_header( 403 ); 891 wp_send_json_error( 'customize_not_allowed' ); 892 } 893 894 if ( empty( $_POST['post_type'] ) ) { 895 status_header( 400 ); 896 wp_send_json_error( 'missing_post_type' ); 897 } 898 899 $post_type_object = get_post_type_object( wp_unslash( $_POST['post_type'] ) ); 900 if ( ! $post_type_object || ! current_user_can( $post_type_object->cap->create_posts ) ) { 901 status_header( 403 ); 902 wp_send_json_error( 'insufficient_post_permissions' ); 903 } 904 if ( ! empty( $post_type_object->labels->singular_name ) ) { 905 $singular_name = $post_type_object->labels->singular_name; 906 } else { 907 $singular_name = __( 'Post', 'customize-posts' ); 908 } 909 910 $r = $this->insert_auto_draft_post( $post_type_object->name ); 911 if ( is_wp_error( $r ) ) { 912 $error = $r; 913 $data = array( 914 'message' => sprintf( __( '%1$s could not be created: %2$s', 'customize-posts' ), $singular_name, $error->get_error_message() ), 915 ); 916 wp_send_json_error( $data ); 917 } else { 918 $post = $r; 919 $exported_settings = array(); 920 921 $post_setting_id = WP_Customize_Post_Setting::get_post_setting_id( $post ); 922 $setting_ids = array( $post_setting_id ); 923 $this->manager->add_dynamic_settings( $setting_ids ); 924 $post_setting = $this->manager->get_setting( $post_setting_id ); 925 if ( ! $post_setting ) { 926 wp_send_json_error( array( 'message' => __( 'Failed to create setting', 'customize-posts' ) ) ); 927 } 928 929 $setting_ids = array_merge( $setting_ids, $this->register_post_type_meta_settings( $post->ID ) ); 930 foreach ( $setting_ids as $setting_id ) { 931 $setting = $this->manager->get_setting( $setting_id ); 932 if ( ! $setting ) { 933 continue; 934 } 935 if ( preg_match( WP_Customize_Postmeta_Setting::SETTING_ID_PATTERN, $setting->id, $matches ) ) { 936 if ( isset( $matches['meta_key'] ) && isset( $params[ $matches['meta_key'] ] ) ) { 937 $this->manager->set_post_value( $setting_id, $params[ $matches['meta_key'] ] ); 938 $setting->preview(); 939 } 940 } 941 if ( method_exists( $setting, 'json' ) ) { // New in 4.6-alpha. 942 $exported_settings[ $setting->id ] = $setting->json(); 943 } else { 944 $exported_settings[ $setting->id ] = array( 945 'value' => $setting->js_value(), 946 'transport' => $setting->transport, 947 'dirty' => $setting->dirty, 948 'type' => $setting->type, 949 ); 950 } 951 $exported_settings[ $setting->id ]['dirty'] = true; 952 } 953 $data = array( 954 'postId' => $post->ID, 955 'postSettingId' => $post_setting_id, 956 'settings' => $exported_settings, 957 'sectionId' => WP_Customize_Post_Setting::get_post_setting_id( $post ), 958 'url' => Edit_Post_Preview::get_preview_post_link( $post ), 959 ); 960 wp_send_json_success( $data ); 961 } 962 } 541 963 } -
customize-posts/trunk/readme.txt
r1406933 r1430660 4 4 Requires at least: 4.5-beta2 5 5 Tested up to: 4.6-alpha 6 Stable tag: 0. 5.06 Stable tag: 0.6.0 7 7 License: GPLv2 or later 8 8 License URI: http://www.gnu.org/licenses/gpl-2.0.html 9 Text Domain: customize-posts 9 10 10 11 Edit posts and postmeta in the Customizer. Stop editing your posts/postmeta blind! … … 58 59 == Changelog == 59 60 61 = 0.6.0 - 2016-06-02 = 62 63 Added: 64 65 * Add the ability to create new posts and pages in the Customizer. Created posts get <code>auto-draft</code> status in the DB so they will be garbage-collected if the Customizer is never saved. A new view link appears in the post section allowing a newly-created post to be navigated to easily without having to find the created post linked to in the preview. (Issues <a href="https://github.com/xwp/wp-customize-posts/issues/48" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/48" data-id="139489948" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#48</a>, <a href="https://github.com/xwp/wp-customize-posts/issues/50" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/50" data-id="139490828" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#50</a>, PR <a href="https://github.com/xwp/wp-customize-posts/pull/134" class="issue-link js-issue-link" data-id="154290445" data-error-text="Failed to load issue title" data-permission-text="Issue title is private" title="Post Creation">#134</a>) 66 * Add post status control and preview, with <code>trash</code> status support (Issues <a href="https://github.com/xwp/wp-customize-posts/issues/40" class="issue-link js-issue-link" data-id="138757986" data-error-text="Failed to load issue title" data-permission-text="Issue title is private" title="Add post status dropdown selection control and preview">#40</a>, <a href="https://github.com/xwp/wp-customize-posts/issues/137" class="issue-link js-issue-link" data-id="154582644" data-error-text="Failed to load issue title" data-permission-text="Issue title is private" title="Delete a post whilst in the Customizer">#137</a>, PR <a href="https://github.com/xwp/wp-customize-posts/pull/152" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/152" data-id="157317131" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#152</a>) 67 * Add support for setting validation in WordPress 4.6-alpha, showing notifications if attempting to save when a post is locked or a conflicting update was previously made. (Issue <a href="https://github.com/xwp/wp-customize-posts/issues/142" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/142" data-id="156058078" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#142</a>, PR <a href="https://github.com/xwp/wp-customize-posts/pull/150" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/150" data-id="156916244" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#150</a>) 68 * Add the ability to vertically resize the post editor (Issue <a href="https://github.com/xwp/wp-customize-posts/issues/136" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/136" data-id="154541791" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#136</a>, PR <a href="https://github.com/xwp/wp-customize-posts/pull/149" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/149" data-id="156898366" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#149</a>) 69 * Add post slug control, wherein changes do not cause the preview to refresh by default since there is nothing to see (Issue <a href="https://github.com/xwp/wp-customize-posts/issues/63" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/63" data-id="140028525" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#63</a>, PR <a href="https://github.com/xwp/wp-customize-posts/pull/148" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/148" data-id="156877309" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#148</a>) 70 * Posts data as saved will now be synced back into the Customizer interface, ensuring that if a post slug gets the infamous <code>-2</code> added, you’ll see that in the Control. Likewise, if a <code>wp_insert_post_data</code> filter or <code>content_save_pre</code> changes your data in some way, these will be shown in the post’s Customizer controls upon saving. 71 * Add extendable theme & plugin compatibility classes that can configure partial rendering. All Core themes & Jetpack are currently supported. (Issues <a href="https://github.com/xwp/wp-customize-posts/issues/82" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/82" data-id="145302561" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#82</a>, <a href="https://github.com/xwp/wp-customize-posts/issues/103" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/103" data-id="150771094" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#103</a>, PR <a href="https://github.com/xwp/wp-customize-posts/pull/123" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/123" data-id="151805533" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#123</a>) 72 * Use <code>plugins_url()</code> for each asset URL so that the plugin can be installed as a submodule without <code>SCRIPT_DEBUG</code> (Issue <a href="https://github.com/xwp/wp-customize-posts/pull/133" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/133" data-id="154007394" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#133</a>) 73 74 Fixed: 75 76 * Add all postmeta settings for registered types not just the ones actually referenced (Issues <a href="https://github.com/xwp/wp-customize-posts/pull/141" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/141" data-id="155671511" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#141</a>, <a href="https://github.com/xwp/wp-customize-posts/issues/145" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/145" data-id="156801928" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#145</a>) 77 * Export all registered post types to client, but only register panels if <code>show_in_customizer</code> (PR <a href="https://github.com/xwp/wp-customize-posts/pull/130" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/130" data-id="152866156" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#130</a>) 78 * Ensure that control pane expand button is visible when editor is open and the Customizer pane is collapsed (Issue <a href="https://github.com/xwp/wp-customize-posts/issues/44" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/44" data-id="139484076" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#44</a>, PR <a href="https://github.com/xwp/wp-customize-posts/pull/126" class="issue-link js-issue-link" data-url="https://github.com/xwp/wp-customize-posts/issues/126" data-id="152710123" data-error-text="Failed to load issue title" data-permission-text="Issue title is private">#126</a>) 79 * Improve compatibility with the Customize Snapshots plugin. 80 * Improve compatibility with the WP REST API plugin. 81 * Supply a default <code>(no title)</code> placeholder to the post title control for new posts. 82 * Filter post and page links in the Customizer to return the preview URL. 83 84 See full commit log: [`0.5.0...0.6.0`](https://github.com/xwp/wp-customize-posts/compare/0.5.0...0.6.0) 85 86 Issues in milestone: [`milestone:0.6`](https://github.com/xwp/wp-customize-posts/issues?q=milestone%3A0.6) 87 88 Props: Weston Ruter (<a href="https://github.com/westonruter" class="user-mention">@westonruter</a>), Derek Herman (<a href="https://github.com/valendesigns" class="user-mention">@valendesigns</a>), Philip Ingram (<a href="https://github.com/pingram3541" class="user-mention">@pingram3541</a>), Daniel Bachhuber (<a href="https://github.com/danielbachhuber" class="user-mention">@danielbachhuber</a>), Stuart Shields (<a href="https://github.com/stuartshields" class="user-mention">@stuartshields</a>) 89 60 90 = 0.5.0 - 2016-04-27 = 61 91 … … 79 109 * Export post/postmeta settings during selective refresh requests so that new posts added will appear in the panel, such as when adding the number of posts to show in the Recent Posts widget. (Issue #97, PR #99) 80 110 * Improve compatibility with Customize Snapshots (PR #95) 111 112 See [v0.5 release post](https://make.xwp.co/2016/04/29/customize-posts-v0-5-released/) on Make XWP. 81 113 82 114 See full commit log: [`0.4.2...0.5.0`](https://github.com/xwp/wp-customize-posts/compare/0.4.2...0.5.0)
Note: See TracChangeset
for help on using the changeset viewer.