: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
button.element.on( 'mouseenter', function() {
if ( control.setting() ) {
button( button.element.data( 'copy-text' ) );
updatePreviewLink: function updatePreviewLink() {
var control = this, unsavedDirtyValues;
unsavedDirtyValues = ! api.state( 'saved' ).get() || '' === api.state( 'changesetStatus' ).get() || 'auto-draft' === api.state( 'changesetStatus' ).get();
control.toggleSaveNotification( unsavedDirtyValues );
control.previewElements.url.element.parent().toggleClass( 'disabled', unsavedDirtyValues );
control.previewElements.button.element.prop( 'disabled', unsavedDirtyValues );
control.setting.set( api.previewer.getFrontendPreviewUrl() );
* Toggles save notification.
* @param {boolean} notify Add or remove notification.
toggleSaveNotification: function toggleSaveNotification( notify ) {
var control = this, notificationCode, notification;
notificationCode = 'changes_not_saved';
notification = new api.Notification( notificationCode, {
message: api.l10n.saveBeforeShare
control.notifications.add( notification );
control.notifications.remove( notificationCode );
* Change objects contained within the main customize object to Settings.
* @alias wp.customize.defaultConstructor
api.defaultConstructor = api.Setting;
* Callback for resolved controls.
* @callback wp.customize.deferredControlsCallback
* @param {wp.customize.Control[]} controls Resolved controls.
* Collection of all registered controls.
* @alias wp.customize.control
* @param {...string} ids - One or more ids for controls to obtain.
* @param {deferredControlsCallback} [callback] - Function called when all supplied controls exist.
* @return {wp.customize.Control|undefined|jQuery.promise} Control instance or undefined (if function called with one id param),
* or promise resolving to requested controls.
* @example <caption>Loop over all registered controls.</caption>
* wp.customize.control.each( function( control ) { ... } );
* @example <caption>Getting `background_color` control instance.</caption>
* control = wp.customize.control( 'background_color' );
* @example <caption>Check if control exists.</caption>
* hasControl = wp.customize.control.has( 'background_color' );
* @example <caption>Deferred getting of `background_color` control until it exists, using callback.</caption>
* wp.customize.control( 'background_color', function( control ) { ... } );
* @example <caption>Get title and tagline controls when they both exist, using promise (only available when multiple IDs are present).</caption>
* promise = wp.customize.control( 'blogname', 'blogdescription' );
* promise.done( function( titleControl, taglineControl ) { ... } );
* @example <caption>Get title and tagline controls when they both exist, using callback.</caption>
* wp.customize.control( 'blogname', 'blogdescription', function( titleControl, taglineControl ) { ... } );
* @example <caption>Getting setting value for `background_color` control.</caption>
* value = wp.customize.control( 'background_color ').setting.get();
* value = wp.customize( 'background_color' ).get(); // Same as above, since setting ID and control ID are the same.
* @example <caption>Add new control for site title.</caption>
* wp.customize.control.add( new wp.customize.Control( 'other_blogname', {
* section: 'other_site_identify'
* @example <caption>Remove control.</caption>
* wp.customize.control.remove( 'other_blogname' );
* @example <caption>Listen for control being added.</caption>
* wp.customize.control.bind( 'add', function( addedControl ) { ... } )
* @example <caption>Listen for control being removed.</caption>
* wp.customize.control.bind( 'removed', function( removedControl ) { ... } )
api.control = new api.Values({ defaultConstructor: api.Control });
* Callback for resolved sections.
* @callback wp.customize.deferredSectionsCallback
* @param {wp.customize.Section[]} sections Resolved sections.
* Collection of all registered sections.
* @alias wp.customize.section
* @param {...string} ids - One or more ids for sections to obtain.
* @param {deferredSectionsCallback} [callback] - Function called when all supplied sections exist.
* @return {wp.customize.Section|undefined|jQuery.promise} Section instance or undefined (if function called with one id param),
* or promise resolving to requested sections.
* @example <caption>Loop over all registered sections.</caption>
* wp.customize.section.each( function( section ) { ... } )
* @example <caption>Getting `title_tagline` section instance.</caption>
* section = wp.customize.section( 'title_tagline' )
* @example <caption>Expand dynamically-created section when it exists.</caption>
* wp.customize.section( 'dynamically_created', function( section ) {
* @see {@link wp.customize.control} for further examples of how to interact with {@link wp.customize.Values} instances.
api.section = new api.Values({ defaultConstructor: api.Section });
* Callback for resolved panels.
* @callback wp.customize.deferredPanelsCallback
* @param {wp.customize.Panel[]} panels Resolved panels.
* Collection of all registered panels.
* @alias wp.customize.panel
* @param {...string} ids - One or more ids for panels to obtain.
* @param {deferredPanelsCallback} [callback] - Function called when all supplied panels exist.
* @return {wp.customize.Panel|undefined|jQuery.promise} Panel instance or undefined (if function called with one id param),
* or promise resolving to requested panels.
* @example <caption>Loop over all registered panels.</caption>
* wp.customize.panel.each( function( panel ) { ... } )
* @example <caption>Getting nav_menus panel instance.</caption>
* panel = wp.customize.panel( 'nav_menus' );
* @example <caption>Expand dynamically-created panel when it exists.</caption>
* wp.customize.panel( 'dynamically_created', function( panel ) {
* @see {@link wp.customize.control} for further examples of how to interact with {@link wp.customize.Values} instances.
api.panel = new api.Values({ defaultConstructor: api.Panel });
* Callback for resolved notifications.
* @callback wp.customize.deferredNotificationsCallback
* @param {wp.customize.Notification[]} notifications Resolved notifications.
* Collection of all global notifications.
* @alias wp.customize.notifications
* @param {...string} codes - One or more codes for notifications to obtain.
* @param {deferredNotificationsCallback} [callback] - Function called when all supplied notifications exist.
* @return {wp.customize.Notification|undefined|jQuery.promise} Notification instance or undefined (if function called with one code param),
* or promise resolving to requested notifications.
* @example <caption>Check if existing notification</caption>
* exists = wp.customize.notifications.has( 'a_new_day_arrived' );
* @example <caption>Obtain existing notification</caption>
* notification = wp.customize.notifications( 'a_new_day_arrived' );
* @example <caption>Obtain notification that may not exist yet.</caption>
* wp.customize.notifications( 'a_new_day_arrived', function( notification ) { ... } );
* @example <caption>Add a warning notification.</caption>
* wp.customize.notifications.add( new wp.customize.Notification( 'midnight_almost_here', {
* message: 'Midnight has almost arrived!',
* @example <caption>Remove a notification.</caption>
* wp.customize.notifications.remove( 'a_new_day_arrived' );
* @see {@link wp.customize.control} for further examples of how to interact with {@link wp.customize.Values} instances.
api.notifications = new api.Notifications();
api.PreviewFrame = api.Messenger.extend(/** @lends wp.customize.PreviewFrame.prototype */{
sensitivity: null, // Will get set to api.settings.timeouts.previewFrameSensitivity.
* An object that fetches a preview in the background of the document, which
* allows for seamless replacement of an existing preview.
* @constructs wp.customize.PreviewFrame
* @augments wp.customize.Messenger
* @param {Object} params.container
* @param {Object} params.previewUrl
* @param {Object} params.query
* @param {Object} options
initialize: function( params, options ) {
var deferred = $.Deferred();
* Make the instance of the PreviewFrame the promise object
* so other objects can easily interact with it.
deferred.promise( this );
this.container = params.container;
$.extend( params, { channel: api.PreviewFrame.uuid() });
api.Messenger.prototype.initialize.call( this, params, options );
this.add( 'previewUrl', params.previewUrl );
this.query = $.extend( params.query || {}, { customize_messenger_channel: this.channel() });
* Run the preview request.
* @param {Object} deferred jQuery Deferred object to be resolved with
run: function( deferred ) {
hasPendingChangesetUpdate = '{}' !== previewFrame.query.customized,
if ( previewFrame._ready ) {
previewFrame.unbind( 'ready', previewFrame._ready );
previewFrame._ready = function( data ) {
previewFrame.container.addClass( 'iframe-ready' );
deferred.resolveWith( previewFrame, [ data ] );
previewFrame.bind( 'ready', previewFrame._ready );
urlParser = document.createElement( 'a' );
urlParser.href = previewFrame.previewUrl();
api.utils.parseQueryString( urlParser.search.substr( 1 ) ),
customize_changeset_uuid: previewFrame.query.customize_changeset_uuid,
customize_theme: previewFrame.query.customize_theme,
customize_messenger_channel: previewFrame.query.customize_messenger_channel
if ( api.settings.changeset.autosaved || ! api.state( 'saved' ).get() ) {
params.customize_autosaved = 'on';
urlParser.search = $.param( params );
previewFrame.iframe = $( '<iframe />', {
title: api.l10n.previewIframeTitle,
name: 'customize-' + previewFrame.channel()
previewFrame.iframe.attr( 'onmousewheel', '' ); // Workaround for Safari bug. See WP Trac #38149.
previewFrame.iframe.attr( 'sandbox', 'allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts' );
if ( ! hasPendingChangesetUpdate ) {
previewFrame.iframe.attr( 'src', urlParser.href );
previewFrame.iframe.attr( 'data-src', urlParser.href ); // For debugging purposes.
previewFrame.iframe.appendTo( previewFrame.container );
previewFrame.targetWindow( previewFrame.iframe[0].contentWindow );
* Submit customized data in POST request to preview frame window since
* there are setting value changes not yet written to changeset.
if ( hasPendingChangesetUpdate ) {
target: previewFrame.iframe.attr( 'name' ),
form.append( $( '<input>', {
_.each( previewFrame.query, function( value, key ) {
form.append( $( '<input>', {
previewFrame.container.append( form );
form.trigger( 'submit' );
form.remove(); // No need to keep the form around after submitted.
previewFrame.bind( 'iframe-loading-error', function( error ) {
previewFrame.iframe.remove();
// Check if the user is not logged in.
previewFrame.login( deferred );
deferred.rejectWith( previewFrame, [ 'cheatin' ] );
deferred.rejectWith( previewFrame, [ 'request failure' ] );
previewFrame.iframe.one( 'load', function() {
deferred.resolveWith( previewFrame, [ readyData ] );
deferred.rejectWith( previewFrame, [ 'ready timeout' ] );
}, previewFrame.sensitivity );
login: function( deferred ) {
deferred.rejectWith( self, [ 'logged out' ] );
// Check if we have an admin cookie.
$.get( api.settings.url.ajax, {
}).fail( reject ).done( function( response ) {
if ( '1' !== response ) {
iframe = $( '<iframe />', { 'src': self.previewUrl(), 'title': api.l10n.previewIframeTitle } ).hide();
iframe.appendTo( self.container );
iframe.on( 'load', function() {
api.Messenger.prototype.destroy.call( this );
delete this.targetWindow;
* Return an incremented ID for a preview messenger channel.
* This function is named "uuid" for historical reasons, but it is a
* misnomer as it is not an actual UUID, and it is not universally unique.
* This is not to be confused with `api.settings.changeset.uuid`.
api.PreviewFrame.uuid = function() {
return 'preview-' + String( id++ );
* Set the document title of the customizer.
* @alias wp.customize.setDocumentTitle
* @param {string} documentTitle
api.setDocumentTitle = function ( documentTitle ) {
tmpl = api.settings.documentTitleTmpl;
title = tmpl.replace( '%s', documentTitle );
api.trigger( 'title', title );
api.Previewer = api.Messenger.extend(/** @lends wp.customize.Previewer.prototype */{
refreshBuffer: null, // Will get set to api.settings.timeouts.windowRefresh.
* @constructs wp.customize.Previewer
* @augments wp.customize.Messenger
* @param {Array} params.allowedUrls
* @param {string} params.container A selector or jQuery element for the preview
* @param {string} params.form
* @param {string} params.previewUrl The URL to preview.
* @param {Object} options
initialize: function( params, options ) {
urlParser = document.createElement( 'a' );
$.extend( previewer, options || {} );
// Debounce to prevent hammering server and then wait for any pending update requests.
previewer.refresh = _.debounce(
( function( originalRefresh ) {
var isProcessingComplete, refreshOnceProcessingComplete;