diff --git a/.travis.yml b/.travis.yml index 003dcbac..1dbd3883 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,7 @@ env: - WP_VERSION=latest WP_MULTISITE=1 install: + - nvm install 4 && nvm use 4 - export DEV_LIB_PATH=dev-lib - if [ ! -e "$DEV_LIB_PATH" ] && [ -L .travis.yml ]; then export DEV_LIB_PATH=$( dirname $( readlink .travis.yml ) ); fi - source $DEV_LIB_PATH/travis.install.sh diff --git a/css/customize-snapshots.css b/css/customize-snapshots.css index 53c8ee3a..ddb771d6 100644 --- a/css/customize-snapshots.css +++ b/css/customize-snapshots.css @@ -1,10 +1,12 @@ -#snapshot-preview-link, #snapshot-edit-link { +#snapshot-preview-link, +#snapshot-schedule-button { float: right; margin-top: 13px; margin-right: 4px; color: #656a6f; } -#snapshot-edit-link{ + +#snapshot-schedule-button { display: block; } @@ -13,11 +15,13 @@ #snapshot-preview-link:active { color: #191e23; } + #snapshot-save { float: right; margin-top: 9px; margin-right: 9px; } + #customize-header-actions:not(.button-added) .button#save { visibility: hidden; } @@ -53,4 +57,107 @@ margin-top: 6px; margin-right: 6px; } -} \ No newline at end of file +} + +#snapshot-schedule { + background: #fff !important; + border-bottom: 1px solid #ddd; + line-height: 1.5; + left: 0; + top: 46px; + position: absolute; + width: 100%; + box-shadow: 0 5px 0 0 rgba(0,0,0,0.05); +} + +#snapshot-schedule .snapshot-schedule-title { + color: #555; + padding: 10px 10px 0; +} + +#snapshot-schedule .snapshot-schedule-title h3 { + margin: .2em 2em .75em 0; +} + +#snapshot-schedule a.snapshot-edit-link { + position: absolute; + top: 4px; + right: 1px; + width: 20px; + height: 20px; + cursor: pointer; + -webkit-box-shadow: none; + box-shadow: none; + -webkit-appearance: none; + background: transparent; + color: #555; + border: none; + padding: 10px; +} + +#snapshot-schedule a.snapshot-edit-link:focus, +#snapshot-schedule a.snapshot-edit-link:hover { + color: #0073aa; + +} + +#snapshot-schedule a.snapshot-edit-link:before { + padding: 4px; + position: absolute; + top: 5px; + left: 6px; + -webkit-border-radius: 100%; + border-radius: 100%; +} + +#snapshot-schedule a.snapshot-edit-link: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); +} + +#snapshot-schedule .snapshot-schedule-control { + padding: 10px; +} + +#snapshot-schedule .accordion-section-title { + padding: 10px; +} + +#snapshot-schedule .reset-time { + font-weight: normal; + font-size: 80%; + display: none; +} + +.snapshot-schedule-control select.date-input { + height: 28px; +} + +.snapshot-schedule-control select, +.snapshot-schedule-control input.date-input { + min-width: 10%; + width: auto; +} + +.snapshot-schedule-control input.date-input { + -moz-appearance: textfield; +} + +.snapshot-schedule-control input.date-input::-webkit-outer-spin-button, +.snapshot-schedule-control input.date-input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +.wp-full-overlay .wp-full-overlay-sidebar .wp-full-overlay-header { + padding-left: 15px; + z-index: 500101; +} + +.select2-container { + z-index: 500100 !important; +} diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 946b2430..3934d407 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -1,5 +1,4 @@ /* global jQuery, _customizeSnapshots */ -/* eslint-disable no-extra-parens */ ( function( api, $ ) { 'use strict'; @@ -12,7 +11,21 @@ component = api.Snapshots; - component.data = {}; + component.schedule = {}; + + component.data = { + action: '', + uuid: '', + editLink: '', + publishDate: '', + postStatus: '', + currentUserCanPublish: '', + initialServerDate: '', + initialServerTimestamp: 0, + initialClientTimestamp: 0, + i18n: {}, + dirty: false + }; if ( 'undefined' !== typeof _customizeSnapshots ) { _.extend( component.data, _customizeSnapshots ); @@ -27,6 +40,9 @@ window._wpCustomizeControlsL10n.save = component.data.i18n.publish; window._wpCustomizeControlsL10n.saved = component.data.i18n.published; + // Set the initial client timestamp. + component.data.initialClientTimestamp = component.dateValueOf(); + api.bind( 'ready', function() { api.state.create( 'snapshot-exists', component.data.snapshotExists ); api.state.create( 'snapshot-saved', true ); @@ -40,10 +56,20 @@ component.extendPreviewerQuery(); component.addButtons(); + component.addSchedule(); $( '#snapshot-save' ).on( 'click', function( event ) { + var scheduleDate; event.preventDefault(); - component.sendUpdateSnapshotRequest( { status: 'draft' } ); + if ( ! _.isEmpty( component.schedule.template ) && component.isFutureDate() ) { + scheduleDate = component.getDateFromInputs(); + component.sendUpdateSnapshotRequest( { + status: 'future', + publish_date: component.formatDate( scheduleDate ) + } ); + } else { + component.sendUpdateSnapshotRequest( { status: 'draft' } ); + } } ); $( '#snapshot-submit' ).on( 'click', function( event ) { event.preventDefault(); @@ -159,13 +185,21 @@ component.addButtons = function() { var header = $( '#customize-header-actions' ), publishButton = header.find( '#save' ), - snapshotEditLinkTemplate = wp.template( 'snapshot-edit-link' ), - snapshotButton, submitButton, data, setPreviewLinkHref, snapshotEditLinkEl; + snapshotButton, scheduleButton, submitButton, data, setPreviewLinkHref, snapshotButtonText; // Save/update button. snapshotButton = wp.template( 'snapshot-save' ); + if ( api.state( 'snapshot-exists' ).get() ) { + if ( 'future' === component.data.postStatus ) { + snapshotButtonText = component.data.i18n.scheduleButton; + } else { + snapshotButtonText = component.data.i18n.updateButton; + } + } else { + snapshotButtonText = component.data.i18n.saveButton; + } data = { - buttonText: api.state( 'snapshot-exists' ).get() ? component.data.i18n.updateButton : component.data.i18n.saveButton + buttonText: snapshotButtonText }; snapshotButton = $( $.trim( snapshotButton( data ) ) ); if ( ! component.data.currentUserCanPublish ) { @@ -174,20 +208,25 @@ snapshotButton.prop( 'disabled', true ); snapshotButton.insertAfter( publishButton ); - snapshotEditLinkEl = $( $.trim( snapshotEditLinkTemplate( component.data ) ) ); - snapshotEditLinkEl.insertAfter( snapshotButton ); + // Schedule button. + scheduleButton = wp.template( 'snapshot-schedule-button' ); + scheduleButton = $( $.trim( scheduleButton( {} ) ) ); + scheduleButton.insertAfter( snapshotButton ); + if ( ! component.data.editLink ) { - snapshotEditLinkEl.hide(); + scheduleButton.hide(); } - api.state.bind( 'change', function() { - snapshotEditLinkEl.toggle( api.state( 'snapshot-saved' ).get() && api.state( 'snapshot-exists' ).get() ); + + api.state( 'change', function() { + scheduleButton.toggle( api.state( 'snapshot-saved' ).get() && api.state( 'snapshot-exists' ).get() ); + } ); + + api.state( 'snapshot-exists' ).bind( function( exist ) { + scheduleButton.toggle( exist ); } ); api.state( 'snapshot-saved' ).bind( function( saved ) { snapshotButton.prop( 'disabled', saved ); - if ( saved ) { - snapshotEditLinkEl.attr( 'href', component.data.editLink ); - } } ); api.state( 'saved' ).bind( function( saved ) { @@ -204,9 +243,6 @@ if ( exists ) { buttonText = component.data.i18n.updateButton; permsMsg = component.data.i18n.permsMsg.update; - if ( component.data.editLink ) { - snapshotEditLinkEl.attr( 'href', component.data.editLink ); - } } else { buttonText = component.data.i18n.saveButton; permsMsg = component.data.i18n.permsMsg.save; @@ -255,6 +291,158 @@ header.addClass( 'button-added' ); }; + /** + * Renders snapshot schedule and handles it's events. + * + * @returns {void} + */ + component.addSchedule = function addSchedule() { + var sliceBegin = 0, + sliceEnd = -2; + + // Inject the UI. + if ( _.isEmpty( component.schedule.template ) ) { + if ( '0000-00-00 00:00:00' === component.data.publishDate ) { + component.data.publishDate = component.getCurrentTime(); + } + + // Normalize date with secs set as zeros removed. + component.data.publishDate = component.data.publishDate.slice( sliceBegin, sliceEnd ) + '00'; + + // Extend the components data object and add the parsed datetime strings. + component.data = _.extend( component.data, component.parseDateTime( component.data.publishDate ) ); + + // Add the template to the DOM. + component.schedule.template = $( $.trim( wp.template( 'snapshot-schedule' )( component.data ) ) ); + component.schedule.template.hide().appendTo( $( '#customize-header-actions' ) ); + + // Store the date inputs. + component.schedule.inputs = component.schedule.template.find( '.date-input' ); + + component.schedule.inputs.on( 'input', function() { + component.populateSetting(); + } ); + + component.schedule.inputs.on( 'blur', function() { + component.populateInputs(); + component.populateSetting(); + } ); + + component.updateCountdown(); + + component.schedule.template.find( '.reset-time a' ).on( 'click', function( event ) { + event.preventDefault(); + component.updateSchedule(); + } ); + } + + // Listen for click events. + $( '#snapshot-schedule-button' ).on( 'click', function( event ) { + event.preventDefault(); + component.schedule.template.toggle(); + } ); + + api.state( 'snapshot-saved' ).bind( function( saved ) { + if ( saved ) { + component.updateSchedule(); + } + } ); + + api.bind( 'change', function() { + component.data.dirty = true; + component.schedule.template.find( 'a.snapshot-edit-link' ).hide(); + } ); + + api.state( 'saved' ).bind( function( saved ) { + if ( saved && ! _.isEmpty( component.schedule.template ) ) { + component.data.publishDate = component.getCurrentTime(); + component.updateSchedule(); + component.schedule.template.hide(); + component.data.dirty = false; + } + } ); + + api.state( 'snapshot-exists' ).bind( function( exists ) { + if ( exists && ! _.isEmpty( component.schedule.template ) ) { + component.updateSchedule(); + } else { + component.schedule.template.hide(); + } + } ); + }; + + /** + * Updates snapshot schedule with `component.data`. + * + * @return {void} + */ + component.updateSchedule = function updateSchedule() { + var parsed, + sliceBegin = 0, + sliceEnd = -2; + + if ( _.isEmpty( component.schedule.template ) ) { + return; + } + + if ( '0000-00-00 00:00:00' === component.data.publishDate ) { + component.data.publishDate = component.getCurrentTime(); + } + + // Normalize date with seconds removed. + component.data.publishDate = component.data.publishDate.slice( sliceBegin, sliceEnd ) + '00'; + + // Update date controls. + component.schedule.template.find( 'a.snapshot-edit-link' ) + .attr( 'href', component.data.editLink ) + .show(); + parsed = component.parseDateTime( component.data.publishDate ); + + component.schedule.inputs.each( function() { + var input = $( this ), + fieldName = input.data( 'date-input' ); + + $( this ).val( parsed[fieldName] ); + } ); + + component.populateSetting(); + }; + + /** + * Update the scheduled countdown text. + * + * Hides countdown if post_status is not already future. + * Toggles the countdown if there is no remaining time. + * + * @returns {boolean} True if date inputs are valid. + */ + component.updateCountdown = function updateCountdown() { + var countdown = component.schedule.template.find( '.snapshot-scheduled-countdown' ), + countdownTemplate = wp.template( 'snapshot-scheduled-countdown' ), + dateTimeFromInput = component.getDateFromInputs(), + millisecondsDivider = 1000, + remainingTime; + + if ( ! dateTimeFromInput ) { + return false; + } + + remainingTime = dateTimeFromInput.valueOf(); + remainingTime -= component.dateValueOf( component.getCurrentTime() ); + remainingTime = Math.ceil( remainingTime / millisecondsDivider ); + + if ( 0 < remainingTime ) { + countdown.text( countdownTemplate( { + remainingTime: remainingTime + } ) ); + countdown.show(); + } else { + countdown.hide(); + } + + return true; + }; + /** * Silently update the saved state to be true without triggering the * changed event so that the AYS beforeunload dialog won't appear @@ -281,22 +469,17 @@ */ component.sendUpdateSnapshotRequest = function( options ) { var spinner = $( '#customize-header-actions .spinner' ), - request, data, args; + request, data; - args = _.extend( + data = _.extend( { status: 'draft' }, - options - ); - - data = _.extend( - {}, api.previewer.query(), + options, { nonce: api.settings.nonce.snapshot, - customize_snapshot_uuid: component.data.uuid, - status: args.status + customize_snapshot_uuid: component.data.uuid } ); request = wp.ajax.post( 'customize_update_snapshot', data ); @@ -307,6 +490,11 @@ if ( response.edit_link ) { component.data.editLink = response.edit_link; } + if ( response.snapshot_publish_date ) { + component.data.publishDate = response.snapshot_publish_date; + } + component.updateSchedule(); + component.data.dirty = false; // @todo Remove privateness from _handleSettingValidities in Core. if ( api._handleSettingValidities && response.setting_validities ) { @@ -320,9 +508,10 @@ request.done( function() { var url = api.previewer.previewUrl(), regex = new RegExp( '([?&])customize_snapshot_uuid=.*?(&|$)', 'i' ), - separator = url.indexOf( '?' ) !== -1 ? '&' : '?', + notFound = -1, + separator = url.indexOf( '?' ) !== notFound ? '&' : '?', customizeUrl = window.location.href, - customizeSeparator = customizeUrl.indexOf( '?' ) !== -1 ? '&' : '?'; + customizeSeparator = customizeUrl.indexOf( '?' ) !== notFound ? '&' : '?'; if ( url.match( regex ) ) { url = url.replace( regex, '$1customize_snapshot_uuid=' + encodeURIComponent( component.data.uuid ) + '$2' ); @@ -340,7 +529,7 @@ } api.state( 'snapshot-saved' ).set( true ); - if ( 'pending' === args.status ) { + if ( 'pending' === data.status ) { api.state( 'snapshot-submitted' ).set( true ); } component.resetSavedStateQuietly(); @@ -399,6 +588,209 @@ } ); }; + /** + * Get date from inputs. + * + * @returns {Date|null} Date created from inputs or null if invalid date. + */ + component.getDateFromInputs = function getDateFromInputs() { + var template = component.schedule.template, + monthOffset = 1, + date; + + date = new Date( + parseInt( template.find( '[data-date-input="year"]' ).val(), 10 ), + parseInt( template.find( '[data-date-input="month"]' ).val(), 10 ) - monthOffset, + parseInt( template.find( '[data-date-input="day"]' ).val(), 10 ), + parseInt( template.find( '[data-date-input="hour"]' ).val(), 10 ), + parseInt( template.find( '[data-date-input="minute"]' ).val(), 10 ) + ); + + if ( isNaN( date.valueOf() ) ) { + return null; + } + + date.setSeconds( 0 ); + + return date; + }; + + /** + * Parse datetime string. + * + * @param {string} datetime Date/Time string. + * @returns {object|null} Returns object containing date components or null if parse error. + */ + component.parseDateTime = function parseDateTime( datetime ) { + var matches = datetime.match( /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)$/ ); + + if ( ! matches ) { + return null; + } + + matches.shift(); + + return { + year: matches.shift(), + month: matches.shift(), + day: matches.shift(), + hour: matches.shift(), + minute: matches.shift(), + second: matches.shift() + }; + }; + + /** + * Format a Date Object. Returns 'Y-m-d H:i:s' format. + * + * @props http://stackoverflow.com/questions/10073699/pad-a-number-with-leading-zeros-in-javascript#comment33639551_10073699 + * + * @param {Date} date A Date object. + * @returns {string} A formatted date String. + */ + component.formatDate = function formatDate( date ) { + var formattedDate, + yearLength = 4, + nonYearLength = 2, + monthOffset = 1; + + formattedDate = ( '0000' + date.getFullYear() ).substr( -yearLength, yearLength ); + formattedDate += '-' + ( '00' + ( date.getMonth() + monthOffset ) ).substr( -nonYearLength, nonYearLength ); + formattedDate += '-' + ( '00' + date.getDate() ).substr( -nonYearLength, nonYearLength ); + formattedDate += ' ' + ( '00' + date.getHours() ).substr( -nonYearLength, nonYearLength ); + formattedDate += ':' + ( '00' + date.getMinutes() ).substr( -nonYearLength, nonYearLength ); + formattedDate += ':' + ( '00' + date.getSeconds() ).substr( -nonYearLength, nonYearLength ); + + return formattedDate; + }; + + /** + * Populate inputs from the setting value, if none of them are currently focused. + * + * @returns {boolean} Whether the inputs were populated. + */ + component.populateInputs = function populateInputs() { + var parsed; + + if ( component.schedule.inputs.is( ':focus' ) || '0000-00-00 00:00:00' === component.data.publishDate ) { + return false; + } + + parsed = component.parseDateTime( component.data.publishDate ); + if ( ! parsed ) { + return false; + } + + component.schedule.inputs.each( function() { + var input = $( this ), + fieldName = input.data( 'date-input' ); + + if ( ! $( this ).is( 'select' ) && '' === $( this ).val() ) { + $( this ).val( parsed[fieldName] ); + } + } ); + return true; + }; + + /** + * Populate setting value from the inputs. + * + * @returns {boolean} Whether the date inputs currently represent a valid date. + */ + component.populateSetting = function populateSetting() { + var date = component.getDateFromInputs(), + save = $( '#snapshot-save' ), + scheduled; + + if ( ! date ) { + return false; + } + + date.setSeconds( 0 ); + scheduled = component.formatDate( date ) !== component.data.publishDate; + + if ( save.length ) { + + // Change update button to schedule. + if ( component.isFutureDate() ) { + save.html( component.data.i18n.scheduleButton ); + } else { + save.html( component.data.i18n.updateButton ); + } + + if ( scheduled || component.data.dirty ) { + save.prop( 'disabled', false ); + } else { + save.prop( 'disabled', true ); + } + } + + component.updateCountdown(); + component.schedule.template.find( '.reset-time' ).toggle( scheduled ); + + return true; + }; + + /** + * Check if the schedule date is in the future. + * + * @returns {boolean} True if future date. + */ + component.isFutureDate = function isFutureDate() { + var date = component.getDateFromInputs(), + millisecondsDivider = 1000, + remainingTime; + + if ( ! date ) { + return false; + } + + remainingTime = component.dateValueOf( date ); + remainingTime -= component.dateValueOf( component.getCurrentTime() ); + remainingTime = Math.ceil( remainingTime / millisecondsDivider ); + + return 0 < remainingTime; + }; + + /** + * Get current date/time in the site's timezone. + * + * Same functionality as the `current_time( 'mysql', false )` function in PHP. + * + * @returns {string} Current datetime string. + */ + component.getCurrentTime = function getCurrentTime() { + var currentDate = new Date( component.data.initialServerDate ), + currentTimestamp = component.dateValueOf(), + timestampDifferential; + + timestampDifferential = currentTimestamp - component.data.initialClientTimestamp; + timestampDifferential += component.data.initialClientTimestamp - component.data.initialServerTimestamp; + currentDate.setTime( currentDate.getTime() + timestampDifferential ); + + return component.formatDate( currentDate ); + }; + + /** + * Get the primitive value of a Date object. + * + * @param {string|Date} dateString The post status for the snapshot. + * @returns {object|string} The primitive value or date object. + */ + component.dateValueOf = function( dateString ) { + var date; + + if ( 'string' === typeof dateString ) { + date = new Date( dateString ); + } else if ( dateString instanceof Date ) { + date = dateString; + } else { + date = new Date(); + } + + return date.valueOf(); + }; + component.init(); } )( wp.customize, jQuery ); diff --git a/package.json b/package.json index 3ad081a1..086a2aa9 100644 --- a/package.json +++ b/package.json @@ -1,22 +1,23 @@ { - "name": "customize-snapshots", - "title": "Customize Snapshots", - "homepage": "https://github.com/xwp/wp-customize-snapshots", - "repository": { - "type": "git", - "url": "https://github.com/xwp/wp-customize-snapshots.git" - }, - "author": "XWP", - "license": "GPL-2.0+", - "devDependencies": { - "grunt": "~0.4.5", - "grunt-checktextdomain": "~1.0.0", - "grunt-contrib-clean": "~1.0.0", - "grunt-contrib-copy": "~1.0.0", - "grunt-contrib-cssmin": "~1.0.1", - "grunt-contrib-jshint": "~1.0.0", - "grunt-contrib-uglify": "~1.0.1", - "grunt-shell": "~1.3.0", - "grunt-wp-deploy": "^1.1.0" - } + "name": "customize-snapshots", + "title": "Customize Snapshots", + "homepage": "https://github.com/xwp/wp-customize-snapshots", + "repository": { + "type": "git", + "url": "https://github.com/xwp/wp-customize-snapshots.git" + }, + "author": "XWP", + "license": "GPL-2.0+", + "devDependencies": { + "eslint": "^3.2.2", + "grunt": "~0.4.5", + "grunt-checktextdomain": "~1.0.0", + "grunt-contrib-clean": "~1.0.0", + "grunt-contrib-copy": "~1.0.0", + "grunt-contrib-cssmin": "~1.0.1", + "grunt-contrib-jshint": "~1.0.0", + "grunt-contrib-uglify": "~1.0.1", + "grunt-shell": "~1.3.0", + "grunt-wp-deploy": "^1.1.0" + } } diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 62d83872..d02b4369 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -525,6 +525,17 @@ public function preview_early_nav_menus_in_customizer() { ); if ( $is_nav_menu_setting ) { $setting->preview(); + + /* + * The following is redundant because it will be done later in + * Customize_Snapshot_Manager::preview_snapshot_settings(). + * Also note that the $setting instance here will likely be + * blown away inside of WP_Customize_Nav_Menus::customize_register(), + * when add_setting is called there. What matters here is that + * preview() is called on the setting _before_ the logic inside + * WP_Customize_Nav_Menus::customize_register() runs, so that + * the nav menu sections will be created. + */ $setting->dirty = true; } } @@ -634,16 +645,25 @@ public function enqueue_controls_scripts() { wp_enqueue_style( 'customize-snapshots' ); wp_enqueue_script( 'customize-snapshots' ); + if ( $this->snapshot ) { + $post = $this->snapshot->post(); + $this->override_post_date_default_data( $post ); + } // Script data array. $exports = apply_filters( 'customize_snapshots_export_data', array( 'action' => self::AJAX_ACTION, 'uuid' => $this->snapshot ? $this->snapshot->uuid() : self::generate_uuid(), - 'editLink' => $this->snapshot ? get_edit_post_link( $this->snapshot->post(), 'raw' ) : '', + 'editLink' => isset( $post ) ? get_edit_post_link( $post, 'raw' ) : '', + 'publishDate' => isset( $post->post_date ) ? $post->post_date : '', + 'postStatus' => isset( $post->post_status ) ? $post->post_status : '', 'currentUserCanPublish' => current_user_can( 'customize_publish' ), + 'initialServerDate' => current_time( 'mysql', false ), + 'initialServerTimestamp' => floor( microtime( true ) * 1000 ), 'i18n' => array( 'saveButton' => __( 'Save', 'customize-snapshots' ), 'updateButton' => __( 'Update', 'customize-snapshots' ), + 'scheduleButton' => __( 'Schedule', 'customize-snapshots' ), 'submit' => __( 'Submit', 'customize-snapshots' ), 'submitted' => __( 'Submitted', 'customize-snapshots' ), 'publish' => __( 'Publish', 'customize-snapshots' ), @@ -780,9 +800,18 @@ function( $value ) { } if ( ! $this->snapshot->post() || 'publish' !== $this->snapshot->post()->post_status ) { - $r = $this->snapshot->save( array( + $args = array( 'status' => 'publish', - ) ); + ); + + // Ensure a scheduled Snapshot is published. + if ( $this->snapshot->post() && 'future' === $this->snapshot->post()->post_status ) { + $args['edit_date'] = true; + $args['post_date'] = current_time( 'mysql', false ); + $args['post_date_gmt'] = current_time( 'mysql', true ); + } + + $r = $this->snapshot->save( $args ); if ( is_wp_error( $r ) ) { add_filter( 'customize_save_response', function( $response ) use ( $r, $that ) { $response['snapshot_errors'] = $that->prepare_errors_for_response( $r ); @@ -1044,10 +1073,19 @@ public function handle_update_snapshot_request() { } else { $status = 'draft'; } - if ( ! in_array( $status, array( 'draft', 'pending' ), true ) ) { + if ( ! in_array( $status, array( 'draft', 'pending', 'future' ), true ) ) { status_header( 400 ); wp_send_json_error( 'bad_status' ); } + $publish_date = isset( $_POST['publish_date'] ) ? $_POST['publish_date'] : ''; + if ( 'future' === $status ) { + $publish_date_obj = new \DateTime( $publish_date ); + $current_date = new \DateTime(); + if ( empty( $publish_date ) || ! $publish_date_obj || $publish_date > $current_date ) { + status_header( 400 ); + wp_send_json_error( 'bad_schedule_time' ); + } + } // Prevent attempting to modify a "locked" snapshot (a published one). $post = $this->snapshot->post(); @@ -1093,14 +1131,23 @@ function( $value ) { $data['errors'] = $this->prepare_errors_for_response( $r['errors'] ); wp_send_json_error( $data ); } - - $r = $this->snapshot->save( array( + $args = array( 'status' => $status, - ) ); + ); + $args['edit_date'] = current_time( 'mysql' ); + + if ( isset( $publish_date_obj ) && 'future' === $status ) { + $args['post_date'] = $publish_date_obj->format( 'Y-m-d H:i:s' ); + $args['post_date_gmt'] = '0000-00-00 00:00:00'; + } else { + $args['post_date_gmt'] = $args['post_date'] = '0000-00-00 00:00:00'; + } + $r = $this->snapshot->save( $args ); $post = $this->snapshot->post(); if ( $post ) { $data['edit_link'] = get_edit_post_link( $post, 'raw' ); + $data['snapshot_publish_date'] = $post->post_date; } if ( is_wp_error( $r ) ) { @@ -1322,6 +1369,22 @@ public function remove_all_non_snapshot_admin_bar_links( $wp_admin_bar ) { * Underscore (JS) templates for dialog windows. */ public function render_templates() { + $data = $this->get_month_choices(); + + $tz_string = get_option( 'timezone_string' ); + if ( $tz_string ) { + $tz = new \DateTimezone( $tz_string ); + $formatted_gmt_offset = $this->format_gmt_offset( $tz->getOffset( new \DateTime() ) / 3600 ); + $tz_name = str_replace( '_', ' ', $tz->getName() ); + + /* translators: 1: timezone name, 2: gmt offset */ + $date_control_description = sprintf( __( 'This site\'s dates are in the %1$s timezone (currently UTC%2$s).', 'customize-snapshots' ), $tz_name, $formatted_gmt_offset ); + } else { + $formatted_gmt_offset = $this->format_gmt_offset( get_option( 'gmt_offset' ) ); + + /* translators: %s: gmt offset */ + $date_control_description = sprintf( __( 'Dates are in UTC%s.', 'customize-snapshots' ), $formatted_gmt_offset ); + } ?> - + + + + get_month_abbrev( $wp_locale->get_month( $i ) ); + + /* translators: 1: month number (01, 02, etc.), 2: month abbreviation */ + $months[ $i ]['text'] = sprintf( __( '%1$s-%2$s', 'customize-snapshots' ), $month_number, $month_text ); + $months[ $i ]['value'] = $month_number; + } + return array( 'month_choices' => $months ); + } + + /** + * Override default date values to a post. + * + * @param \WP_Post $post Post. + * @return \WP_Post Object if the post data did not apply. + */ + public function override_post_date_default_data( \WP_Post &$post ) { + if ( ! is_array( $post ) ) { + // Make sure that empty dates are not used in case of setting invalidity. + $empty_date = '0000-00-00 00:00:00'; + if ( $empty_date === $post->post_date ) { + $post->post_date = current_time( 'mysql', false ); + } + if ( $empty_date === $post->post_date_gmt ) { + $post->post_date_gmt = current_time( 'mysql', true ); + } + if ( $empty_date === $post->post_modified ) { + $post->post_modified = current_time( 'mysql', false ); + } + if ( $empty_date === $post->post_modified_gmt ) { + $post->post_modified_gmt = current_time( 'mysql', true ); + } + } + return $post; + } } diff --git a/php/class-post-type.php b/php/class-post-type.php index ca9af763..fb0782cb 100644 --- a/php/class-post-type.php +++ b/php/class-post-type.php @@ -508,6 +508,11 @@ public function save( array $args ) { ), ); if ( ! empty( $args['status'] ) ) { + if ( isset( $args['post_date'], $args['edit_date'], $args['post_date_gmt'] ) ) { + $post_arr['post_date'] = $args['post_date']; + $post_arr['edit_date'] = $args['edit_date']; + $post_arr['post_date_gmt'] = $args['post_date_gmt']; + } if ( ! get_post_status_object( $args['status'] ) ) { return new \WP_Error( 'bad_status' ); } diff --git a/tests/php/test-class-ajax-customize-snapshot-manager.php b/tests/php/test-class-ajax-customize-snapshot-manager.php index 360be871..4b6ac33f 100644 --- a/tests/php/test-class-ajax-customize-snapshot-manager.php +++ b/tests/php/test-class-ajax-customize-snapshot-manager.php @@ -276,7 +276,9 @@ function test_ajax_update_snapshot_cap_check( $role, $expected_results ) { if ( $response['success'] ) { $this->assertNotEmpty( $response['data']['edit_link'] ); + $this->assertNotEmpty( $response['data']['snapshot_publish_date'] ); unset( $response['data']['edit_link'] ); + unset( $response['data']['snapshot_publish_date'] ); } $this->assertSame( $expected_results, $response ); } @@ -417,4 +419,48 @@ function make_save_snapshot_ajax_call() { unset( $e ); } } + + /** + * Testing schedule Snapshot + */ + function test_ajax_update_snapshot_schedule() { + unset( $GLOBALS['wp_customize'] ); + remove_all_actions( 'wp_ajax_' . Customize_Snapshot_Manager::AJAX_ACTION ); + + $setting_key = 'anyonecanedit'; + $tomorrow = date( 'Y-m-d H:i:s', time() + 86400 ); + $this->set_current_user( 'administrator' ); + $this->set_input_vars( array( + 'action' => Customize_Snapshot_Manager::AJAX_ACTION, + 'nonce' => wp_create_nonce( Customize_Snapshot_Manager::AJAX_ACTION ), + 'customize_snapshot_uuid' => self::UUID, + 'customized' => wp_json_encode( array( $setting_key => 'Hello' ) ), + 'status' => 'future', + 'publish_date' => $tomorrow, // Tomorrow. + ) ); + + $this->plugin = new Plugin(); + $this->plugin->init(); + $this->add_setting(); + + $this->make_ajax_call( Customize_Snapshot_Manager::AJAX_ACTION ); + $post_id = get_plugin_instance()->customize_snapshot_manager->post_type->find_post( self::UUID ); + $expected_results = array( + 'success' => true, + 'data' => array( + 'errors' => null, + 'setting_validities' => array( $setting_key => true ), + 'edit_link' => get_edit_post_link( $post_id, 'raw' ), + 'snapshot_publish_date' => $tomorrow, + ), + ); + require_once ABSPATH . WPINC . '/class-wp-customize-manager.php'; + if ( ! method_exists( 'WP_Customize_Manager', 'prepare_setting_validity_for_js' ) ) { + unset( $expected_results['data']['setting_validities'] ); + } + // Get the results. + $response = json_decode( $this->_last_response, true ); + $this->assertSame( $expected_results, $response ); + $this->assertEquals( 'future', get_post_status( $post_id ) ); + } } diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php index 24854795..62d60b93 100644 --- a/tests/php/test-class-customize-snapshot-manager.php +++ b/tests/php/test-class-customize-snapshot-manager.php @@ -190,7 +190,7 @@ function test_construct_with_customize_bootstrapped() { /** * Tests init hooks. * - * @covers Customize_Snapshot_Manager::init() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::init() */ public function test_init_hooks() { $manager = new Customize_Snapshot_Manager( $this->plugin ); @@ -219,8 +219,8 @@ public function test_init_hooks() { /** * Tests init hooks. * - * @covers Customize_Snapshot_Manager::init() - * @covers Customize_Snapshot_Manager::read_current_snapshot_uuid() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::init() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::read_current_snapshot_uuid() */ public function test_read_current_snapshot_uuid() { $manager = new Customize_Snapshot_Manager( $this->plugin ); @@ -244,8 +244,8 @@ public function test_read_current_snapshot_uuid() { /** * Tests load_snapshot. * - * @covers Customize_Snapshot_Manager::init() - * @covers Customize_Snapshot_Manager::load_snapshot() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::init() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::load_snapshot() */ public function test_load_snapshot() { global $wp_actions; @@ -272,8 +272,8 @@ public function test_load_snapshot() { /** * Tests setup_preview_ajax_requests. * - * @covers Customize_Snapshot_Manager::init() - * @covers Customize_Snapshot_Manager::setup_preview_ajax_requests() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::init() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::setup_preview_ajax_requests() */ public function test_setup_preview_ajax_requests() { wp_set_current_user( $this->user_id ); @@ -290,10 +290,40 @@ public function test_setup_preview_ajax_requests() { $this->assertEquals( 5, has_action( 'parse_request', array( $manager, 'override_request_method' ) ) ); } + + /** + * Tests setup_preview_ajax_requests for admin_ajax. + * + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::init() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::setup_preview_ajax_requests() + */ + public function test_setup_preview_ajax_requests_for_admin_ajax() { + global $pagenow; + wp_set_current_user( $this->user_id ); + + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'GET'; + $pagenow = 'admin-ajax.php'; // WPCS: Global override ok. + set_current_screen( 'admin-ajax' ); + $this->assertTrue( is_admin() ); + + $_REQUEST['wp_customize_preview_ajax'] = 'true'; + $_POST['customized'] = wp_slash( wp_json_encode( array( 'blogname' => 'Foo' ) ) ); + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $manager->init(); + do_action( 'admin_init' ); + $this->do_customize_boot_actions( true ); + $this->assertTrue( is_customize_preview() ); + $this->assertFalse( has_action( 'shutdown', array( $this->wp_customize, 'customize_preview_signature' ) ) ); + $this->assertFalse( has_action( 'parse_request', array( $manager, 'override_request_method' ) ) ); + $this->assertEquals( 'GET', $_SERVER['REQUEST_METHOD'] ); + $this->assertEquals( 'Foo', get_option( 'blogname' ) ); + } + /** * Tests override_request_method. * - * @covers Customize_Snapshot_Manager::override_request_method() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::override_request_method() */ public function test_override_request_method() { global $wp; @@ -323,12 +353,16 @@ public function test_override_request_method() { $this->assertEquals( 'foo=1&bar=2', $_SERVER['QUERY_STRING'] ); $this->assertArrayHasKey( 'foo', $_GET ); $this->assertArrayHasKey( 'bar', $_GET ); + + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'PUT'; + $this->assertFalse( $manager->override_request_method() ); } /** * Tests doing_customize_save_ajax. * - * @covers Customize_Snapshot_Manager::doing_customize_save_ajax() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::doing_customize_save_ajax() */ public function test_doing_customize_save_ajax() { $manager = new Customize_Snapshot_Manager( $this->plugin ); @@ -344,7 +378,7 @@ public function test_doing_customize_save_ajax() { /** * Tests ensure_customize_manager. * - * @covers Customize_Snapshot_Manager::ensure_customize_manager() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::ensure_customize_manager() */ public function test_ensure_customize_manager() { global $wp_customize; @@ -359,7 +393,7 @@ public function test_ensure_customize_manager() { /** * Tests is_theme_active. * - * @covers Customize_Snapshot_Manager::is_theme_active() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::is_theme_active() */ public function test_is_theme_active() { global $wp_customize; @@ -374,7 +408,7 @@ public function test_is_theme_active() { /** * Tests should_import_and_preview_snapshot. * - * @covers Customize_Snapshot_Manager::should_import_and_preview_snapshot() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::should_import_and_preview_snapshot() */ public function test_should_import_and_preview_snapshot() { global $pagenow, $wp_customize; @@ -431,7 +465,7 @@ public function test_should_import_and_preview_snapshot() { /** * Tests is_previewing_settings. * - * @covers Customize_Snapshot_Manager::is_previewing_settings() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::is_previewing_settings() */ public function test_is_previewing_settings() { $_REQUEST['customize_snapshot_uuid'] = self::UUID; @@ -448,7 +482,7 @@ public function test_is_previewing_settings() { /** * Tests is_previewing_settings. * - * @covers Customize_Snapshot_Manager::is_previewing_settings() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::is_previewing_settings() */ public function test_is_previewing_settings_via_preview_init() { $manager = new Customize_Snapshot_Manager( $this->plugin ); @@ -460,25 +494,74 @@ public function test_is_previewing_settings_via_preview_init() { /** * Tests preview_snapshot_settings. * - * @covers Customize_Snapshot_Manager::preview_snapshot_settings() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::preview_snapshot_settings() */ public function test_preview_snapshot_settings() { - $this->markTestIncomplete(); + global $wp_actions; + $_REQUEST['customize_snapshot_uuid'] = self::UUID; + $this->manager->post_type->save( array( + 'uuid' => self::UUID, + 'data' => array( + 'blogname' => array( 'value' => 'Hello' ), + ), + 'status' => 'draft', + ) ); + + // Prevent init from calling preview_snapshot_settings straight away. + unset( $wp_actions['wp_loaded'] ); + + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $manager->init(); + $manager->ensure_customize_manager(); + do_action( 'customize_register', $manager->customize_manager ); + $this->assertFalse( $manager->is_previewing_settings() ); + $this->assertFalse( $manager->customize_manager->get_setting( 'blogname' )->dirty ); + $this->assertNotEquals( 'Hello', get_option( 'blogname' ) ); + $manager->preview_snapshot_settings(); + $this->assertEquals( 'Hello', get_option( 'blogname' ) ); + $this->assertTrue( $manager->customize_manager->get_setting( 'blogname' )->dirty ); } /** * Tests import_snapshot_data. * - * @covers Customize_Snapshot_Manager::import_snapshot_data() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::import_snapshot_data() */ public function test_import_snapshot_data() { - $this->markTestIncomplete(); + global $wp_actions; + $_REQUEST['customize_snapshot_uuid'] = self::UUID; + $this->manager->post_type->save( array( + 'uuid' => self::UUID, + 'data' => array( + 'blogname' => array( 'value' => 'Hello' ), + 'blogdescription' => array( 'value' => null ), + ), + 'status' => 'draft', + ) ); + + // Prevent init from calling import_snapshot_data straight away. + unset( $wp_actions['setup_theme'] ); + + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $manager->init(); + $manager->ensure_customize_manager(); + do_action( 'customize_register', $manager->customize_manager ); + + $this->assertArrayNotHasKey( 'customized', $_POST ); + $this->assertArrayNotHasKey( 'customized', $_REQUEST ); + $this->assertArrayNotHasKey( 'blogname', $manager->customize_manager->unsanitized_post_values() ); + $this->assertArrayNotHasKey( 'blogdescription', $manager->customize_manager->unsanitized_post_values() ); + $manager->import_snapshot_data(); + $this->assertArrayHasKey( 'customized', $_POST ); + $this->assertArrayHasKey( 'customized', $_REQUEST ); + $this->assertArrayHasKey( 'blogname', $manager->customize_manager->unsanitized_post_values() ); + $this->assertArrayNotHasKey( 'blogdescription', $manager->customize_manager->unsanitized_post_values() ); } /** * Tests add_widget_setting_preview_filters. * - * @covers Customize_Snapshot_Manager::add_widget_setting_preview_filters() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::add_widget_setting_preview_filters() */ public function test_add_widget_setting_preview_filters() { $this->markTestIncomplete(); @@ -487,7 +570,7 @@ public function test_add_widget_setting_preview_filters() { /** * Tests add_nav_menu_setting_preview_filters. * - * @covers Customize_Snapshot_Manager::add_nav_menu_setting_preview_filters() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::add_nav_menu_setting_preview_filters() */ public function test_add_nav_menu_setting_preview_filters() { $this->markTestIncomplete(); @@ -496,10 +579,39 @@ public function test_add_nav_menu_setting_preview_filters() { /** * Tests preview_early_nav_menus_in_customizer. * - * @covers Customize_Snapshot_Manager::preview_early_nav_menus_in_customizer() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::preview_early_nav_menus_in_customizer() */ public function test_preview_early_nav_menus_in_customizer() { - $this->markTestIncomplete(); + global $pagenow; + $pagenow = 'customize.php'; // WPCS: Global override ok. + set_current_screen( 'customize' ); + + $menu_id = -123; + $setting_id = sprintf( 'nav_menu[%d]', $menu_id ); + + $_REQUEST['customize_snapshot_uuid'] = self::UUID; + $this->manager->post_type->save( array( + 'uuid' => self::UUID, + 'data' => array( + $setting_id => array( + 'value' => array( + 'name' => 'Bar', + ), + ), + ), + 'status' => 'draft', + ) ); + + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $manager->init(); + do_action( 'customize_register', $manager->customize_manager ); + + $setting = $manager->customize_manager->get_setting( $setting_id ); + $this->assertInstanceOf( 'WP_Customize_Nav_Menu_Setting', $setting ); + $nav_menu = wp_get_nav_menu_object( $menu_id ); + $this->assertEquals( 'Bar', $nav_menu->name ); + + $this->assertInstanceOf( 'WP_Customize_Nav_Menu_Section', $manager->customize_manager->get_section( $setting_id ) ); } /** @@ -523,7 +635,7 @@ public function test_add_snapshot_uuid_to_return_url() { /** * Tests show_theme_switch_error. * - * @covers Customize_Snapshot_Manager::show_theme_switch_error() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::show_theme_switch_error() */ function test_show_theme_switch_error() { $this->markTestIncomplete(); @@ -532,7 +644,7 @@ function test_show_theme_switch_error() { /** * Tests get_theme_switch_error. * - * @covers Customize_Snapshot_Manager::get_theme_switch_error() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::get_theme_switch_error() */ function test_get_theme_switch_error() { $this->markTestIncomplete(); @@ -541,7 +653,7 @@ function test_get_theme_switch_error() { /** * Tests check_customize_publish_authorization. * - * @covers Customize_Snapshot_Manager::check_customize_publish_authorization() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::check_customize_publish_authorization() */ function test_check_customize_publish_authorization() { $this->markTestIncomplete(); @@ -575,6 +687,39 @@ function test_enqueue_controls_scripts() { $this->assertTrue( wp_style_is( 'customize-snapshots', 'enqueued' ) ); } + /** + * Test customize preview init. + * + * @see Customize_Snapshot_Manager::customize_preview_init() + */ + function test_customize_preview_init() { + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $this->assertFalse( has_action( 'wp_enqueue_scripts', array( $manager, 'enqueue_preview_scripts' ) ) ); + $manager->customize_preview_init(); + $this->assertEquals( 10, has_action( 'wp_enqueue_scripts', array( $manager, 'enqueue_preview_scripts' ) ) ); + } + + /** + * Test enqueue preview scripts. + * + * @see Customize_Snapshot_Manager::enqueue_preview_scripts() + */ + function test_enqueue_preview_scripts() { + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $manager->ensure_customize_manager(); + $manager->init(); + $handle = 'customize-snapshots-preview'; + $this->assertFalse( wp_scripts()->query( $handle, 'enqueued' ) ); + $this->assertFalse( wp_styles()->query( $handle, 'enqueued' ) ); + $manager->enqueue_preview_scripts(); + $this->assertTrue( wp_scripts()->query( $handle, 'enqueued' ) ); + $this->assertTrue( wp_styles()->query( $handle, 'enqueued' ) ); + + $after = wp_scripts()->get_data( $handle, 'after' ); + $this->assertNotEmpty( $after ); + $this->assertContains( 'CustomizeSnapshotsPreview', join( '', $after ) ); + } + /** * Test enqueue frontend scripts. * @@ -600,10 +745,11 @@ function test_enqueue_frontend_scripts() { /** * Test filter_customize_refresh_nonces. * - * @covers Customize_Snapshot_Manager::filter_customize_refresh_nonces() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::filter_customize_refresh_nonces() */ function test_filter_customize_refresh_nonces() { - $this->markTestIncomplete(); + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $this->assertArrayHasKey( 'snapshot', $manager->filter_customize_refresh_nonces( array() ) ); } /** @@ -621,7 +767,7 @@ function test_snapshot() { /** * Test publish snapshot with customize_save_after. * - * @covers Customize_Snapshot_Manager::publish_snapshot_with_customize_save_after() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::publish_snapshot_with_customize_save_after() */ function test_publish_snapshot_with_customize_save_after() { wp_set_current_user( $this->user_id ); @@ -645,7 +791,7 @@ function test_publish_snapshot_with_customize_save_after() { /** * Test prepare_snapshot_post_content_for_publish. * - * @covers Customize_Snapshot_Manager::prepare_snapshot_post_content_for_publish() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::prepare_snapshot_post_content_for_publish() */ public function test_prepare_snapshot_post_content_for_publish() { $snapshot_manager = get_plugin_instance()->customize_snapshot_manager; @@ -676,7 +822,7 @@ public function test_prepare_snapshot_post_content_for_publish() { /** * Test save_settings_with_publish_snapshot. * - * @covers Customize_Snapshot_Manager::save_settings_with_publish_snapshot() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::save_settings_with_publish_snapshot() */ public function test_save_settings_with_publish_snapshot() { $post_type = $this->manager->post_type; @@ -740,7 +886,7 @@ public function test_save_settings_with_publish_snapshot() { /** * Test prepare_errors_for_response. * - * @covers Customize_Snapshot_Manager::prepare_errors_for_response() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::prepare_errors_for_response() */ public function test_prepare_errors_for_response() { $this->markTestIncomplete(); @@ -749,7 +895,7 @@ public function test_prepare_errors_for_response() { /** * Tests generate_uuid. * - * @covers Customize_Snapshot_Manager::generate_uuid() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::generate_uuid() */ public function test_generate_uuid() { $this->markTestIncomplete(); @@ -758,7 +904,7 @@ public function test_generate_uuid() { /** * Tests is_valid_uuid. * - * @covers Customize_Snapshot_Manager::is_valid_uuid() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::is_valid_uuid() */ public function test_is_valid_uuid() { $this->markTestIncomplete(); @@ -814,7 +960,7 @@ public function test_customize_menu_return() { /** * Tests print_admin_bar_styles. * - * @covers Customize_Snapshot_Manager::print_admin_bar_styles() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::print_admin_bar_styles() */ public function test_print_admin_bar_styles() { $manager = new Customize_Snapshot_Manager( $this->plugin ); @@ -828,7 +974,7 @@ public function test_print_admin_bar_styles() { /** * Test replace_customize_link. * - * @covers Customize_Snapshot_Manager::replace_customize_link() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::replace_customize_link() */ public function test_replace_customize_link() { global $wp_admin_bar; @@ -871,10 +1017,10 @@ public function test_replace_customize_link() { /** * Test misc admin bar extensions. * - * @covers Customize_Snapshot_Manager::add_post_edit_screen_link() - * @covers Customize_Snapshot_Manager::add_snapshot_exit_link() - * @covers Customize_Snapshot_Manager::add_resume_snapshot_link() - * @covers Customize_Snapshot_Manager::remove_all_non_snapshot_admin_bar_links() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::add_post_edit_screen_link() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::add_snapshot_exit_link() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::add_resume_snapshot_link() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::remove_all_non_snapshot_admin_bar_links() */ public function test_add_post_edit_and_exit_links() { global $wp_admin_bar; @@ -921,7 +1067,7 @@ public function test_add_post_edit_and_exit_links() { /** * Test render templates. * - * @see Customize_Snapshot_Manager::render_templates() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::render_templates() */ public function test_render_templates() { ob_start(); @@ -930,5 +1076,47 @@ public function test_render_templates() { ob_end_clean(); $this->assertContains( 'tmpl-snapshot-save', $templates ); $this->assertContains( 'tmpl-snapshot-dialog-error', $templates ); + $this->assertContains( 'tmpl-snapshot-preview-link', $templates ); + $this->assertContains( 'tmpl-snapshot-schedule-button', $templates ); + $this->assertContains( 'tmpl-snapshot-schedule', $templates ); + $this->assertContains( 'tmpl-snapshot-scheduled-countdown', $templates ); + $this->assertContains( 'tmpl-snapshot-submit', $templates ); + } + + /** + * Test format_gmt_offset + * + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::format_gmt_offset() + */ + public function test_format_gmt_offset() { + $offset = $this->manager->format_gmt_offset( 7.0 ); + $this->assertEquals( '+7', $offset ); + } + + /** + * Test month choices + * + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::get_month_choices() + */ + public function test_get_month_choices() { + $data = $this->manager->get_month_choices(); + $this->assertArrayHasKey( 'month_choices', $data ); + $this->assertCount( 12, $data['month_choices'] ); + } + + /** + * Test override post date if empty. + * + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::override_post_date_default_data() + */ + public function test_override_post_date_default_data() { + $post_id = $this->factory()->post->create(); + $post = get_post( $post_id ); + $post->post_date = $post->post_date_gmt = $post->post_modified = $post->post_modified_gmt = '0000-00-00 00:00:00'; + $this->manager->override_post_date_default_data( $post ); + $this->assertNotEquals( $post->post_date, '0000-00-00 00:00:00' ); + $this->assertNotEquals( $post->post_date_gmt, '0000-00-00 00:00:00' ); + $this->assertNotEquals( $post->post_modified, '0000-00-00 00:00:00' ); + $this->assertNotEquals( $post->post_modified_gmt, '0000-00-00 00:00:00' ); } } diff --git a/tests/php/test-class-post-type.php b/tests/php/test-class-post-type.php index b2027887..773c6209 100644 --- a/tests/php/test-class-post-type.php +++ b/tests/php/test-class-post-type.php @@ -63,7 +63,7 @@ public function test_register() { /** * Test filter_post_type_link. * - * @covers Post_Type::filter_post_type_link() + * @covers CustomizeSnapshots\Post_Type::filter_post_type_link() */ function test_filter_post_type_link() { $post_type = new Post_Type( $this->plugin->customize_snapshot_manager ); @@ -382,7 +382,7 @@ public function test_find_post() { /** * Test getting the snapshot array out of the post_content. * - * @covers Post_Type::get_post_content() + * @covers CustomizeSnapshots\Post_Type::get_post_content() * @expectedException \PHPUnit_Framework_Error_Warning */ public function test_get_post_content() { @@ -626,7 +626,7 @@ function test_filter_user_has_cap() { /** * Tests display_post_states. * - * @covers Post_Type::display_post_states() + * @covers CustomizeSnapshots\Post_Type::display_post_states() */ public function test_display_post_states() { $post_type = new Post_Type( $this->plugin->customize_snapshot_manager ); @@ -646,7 +646,7 @@ public function test_display_post_states() { /** * Tests show_publish_error_admin_notice. * - * @covers Post_Type::show_publish_error_admin_notice() + * @covers CustomizeSnapshots\Post_Type::show_publish_error_admin_notice() */ public function test_show_publish_error_admin_notice() { global $current_screen, $post; @@ -687,7 +687,7 @@ public function test_show_publish_error_admin_notice() { /** * Tests disable_revision_ui_for_published_posts. * - * @covers Post_Type::disable_revision_ui_for_published_posts() + * @covers CustomizeSnapshots\Post_Type::disable_revision_ui_for_published_posts() */ public function test_disable_revision_ui_for_published_posts() { $post_type = new Post_Type( $this->plugin->customize_snapshot_manager ); @@ -716,7 +716,7 @@ public function test_disable_revision_ui_for_published_posts() { /** * Tests hide_disabled_publishing_actions. * - * @covers Post_Type::hide_disabled_publishing_actions() + * @covers CustomizeSnapshots\Post_Type::hide_disabled_publishing_actions() */ public function test_hide_disabled_publishing_actions() { $post_type = new Post_Type( $this->plugin->customize_snapshot_manager ); diff --git a/tests/test-customize-snapshots.php b/tests/test-customize-snapshots.php index bf391a53..0b326566 100644 --- a/tests/test-customize-snapshots.php +++ b/tests/test-customize-snapshots.php @@ -47,7 +47,7 @@ function test_customize_snapshots_php_version_text() { /** * Tests is_previewing_settings(). * - * @covers is_previewing_settings() + * @see is_previewing_settings() */ public function test_is_previewing_settings() { $this->assertFalse( is_previewing_settings() ); @@ -58,7 +58,7 @@ public function test_is_previewing_settings() { /** * Tests current_snapshot_uuid(). * - * @covers current_snapshot_uuid() + * @see current_snapshot_uuid() */ public function test_current_snapshot_uuid() { global $customize_snapshots_plugin;