Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add post date control and preview #202

Merged
merged 85 commits into from Aug 2, 2016

Conversation

Projects
None yet
4 participants
@johnregan3
Copy link
Contributor

commented Jul 25, 2016

Fixes #56

Todos

  • Eliminate post_date_gmt
  • Ensure post_status is linked properly.
  • Re-use publish status for scheduled?
  • Use timer to change future status back to publish when time passes?
  • Just update label for “Published” to “Scheduled” when date is in future?
  • Drafts shouldn't be assigned a date unless explicitly done so by the user? Leave empty or use placeholders when value is 0000-00-00 00:00:00?
  • Fix infinite reload if modifying a partial that is not in the current view.
  • Sorting by previewed date?
  • Add unit tests.
  • Allow time to be reset to empty, allowing it to be set to current time upon publishing.
  • Handle unexpected November 30, -0001 when post setting is invalid or empty?.
  • Ensure that when a setting transitions from invalid to valid, that all related post field partials are refreshed.
  • Add countdown timer for when post will be published?
  • Refine UI for post date control.
  • Saving a published post with current time can momentarily result in a future status being returned from the server before getting converted back to publish if the server/client times are out of sync at all.
  • Date query? (This will require re-architecture of WP_Query)
  • Sync post date to parent frame if opened from post preview. (Do this later when status is synced.)

Update - 28 Jul 2:30 PM ET

This control has been improved and refactored significantly over the last few days, especially in light of Weston's comments.

I opted to deal with the post_date specifically (as opposed to post_date_gmt) because post_date timezones are easily converted in WP using get_gmt_from_date(), instead of wrangling a lot of JS. Using this method, the user's local browser time zone is never a factor; it's has the same UX as the Post Editor.

In light of this, the JS has been greatly pared down because there isn't so much use of JS Date objects.

Directly updating the post_date_gmt and post_status is no longer done in this control's JS. Now, WP_Customize_Post_Setting::sanitize() handles their updates when the Preview is saved. This functionality was almost completely in place from previous contributors.

Notes:

  • A Scheduled post does not disappear from the Preview when viewing the single post, and it only disappears on an archive after the Preview is saved.
  • Date inputs are now validated.
  • The post modified date is handled in sanitize() as well.

A couple of points for improvement:

  • Refactoring the JS in js/customize-post-date.js to eliminate using an HTML input element altogether.
  • User notification:
    • Including the "Schedule for: 01 Jan 2000 @ 00:01" text above the inputs.
    • Updating the save button to "Save & Schedule" or "Save & Update" to notify the user that their post will be Scheduled, as opposed to Published. This is similar to how the Post Edit UI currently functions.

Update - 26 Jul 11 PM ET

I've got the basic functionality working as an extension of the Dynamic control. This is found in js/customize-posts.js.

I am using JS's Date for handling the input as it will make comparison between the existing and new dates pretty simple by using operators like "<" and ">" and "=". This also allows us to utilize the gmt_offset WP option to ensure the post_date_gmt is truly GMT.

There are two new JS Date functions to handle formatting Date objects correctly based on a PHP-style format string. I went this route as they could possibly be reused elsewhere, especially when pulling in the WP options for date and time formatting. I may pull these out tomorrow, just to simplify things. What thoughts do you have?

The custom template for the inputs is found in php/class-wp-customize-post-date-control.php.

The current implementation saves both post_date and post_date_gmt.

Up next:

  • Proper Text above the inputs (e.g., "Published on Oct 16, 2015 @ 20:31").
  • Handling Post Status changes when the date is updated.
  • Ensure dates are validated before updating the preview.
  • Ensure posts scheduled for the future don't disappear from the preview.
  • Reordering posts when date is updated.
  • Need to investigate the modified dates issue.

Original Text

I'm looking to see if I'm on the right track with my work on the Post Date UI. This is my first time working heavily with the customizer in JS, and my first issue with Customize Posts, so this may be a bit clunky.

My goal is to take the post_date and split it up into separate inputs just as it is in the Post Edit screen.

in the Customizer, when any input is changed, it updates a hidden field, then that value is passed over to the preview pane. This way, we don't have to save each piece of the date (like the month, day, year, etc).

</select>
<# } else { #>
<input
type="text"

This comment has been minimized.

Copy link
@PatelUtkarsh

PatelUtkarsh Jul 26, 2016

Collaborator

@johnregan3 Can we use number as input type with max and min attributes?

This comment has been minimized.

Copy link
@johnregan3

johnregan3 Jul 26, 2016

Author Contributor

@PatelUtkarsh I would love to do that. I think it would help greatly with validation. @westonruter How closely do we want to match the existing interface? It uses simple text inputs.

This comment has been minimized.

Copy link
@PatelUtkarsh

PatelUtkarsh Jul 26, 2016

Collaborator

In number input that arrows(up and down) make it smaller(input needs more space) so maybe that's why the core is not using it?

This comment has been minimized.

Copy link
@johnregan3

johnregan3 Jul 27, 2016

Author Contributor

@PatelUtkarsh You know, I'm not really sure. I think they would just rather leave it alone since it's been used for so long. However, I think it's time for an update of that whole metabox. in addition to the UI changes, the JS for the date function could be greatly improved.

This comment has been minimized.

Copy link
@westonruter

westonruter Jul 27, 2016

Contributor

How closely do we want to match the existing interface? It uses simple text inputs.

I really don't like the existing interface 😄

function getDateInputData() {
var date, result = {}, singleCharLimit = 9;

date = new Date( postData.post_date );

This comment has been minimized.

Copy link
@westonruter

westonruter Jul 28, 2016

Contributor

Beware of timezones.

result.min = date.getMinutes().toString();
return result;
}
control.params.date_data = getDateInputData();

This comment has been minimized.

Copy link
@westonruter

westonruter Jul 28, 2016

Contributor

This logic should be encapsulated inside of the control itself. So whenever the setting's value is updated, you can look at control.setting().post_date to re-parse and populate the individual inputs.

This comment has been minimized.

Copy link
@johnregan3

johnregan3 Jul 28, 2016

Author Contributor

@westonruter Would this go inside of initialize() or _setUpSettingRootLinks() (or somewhere else)?

This comment has been minimized.

Copy link
@westonruter

westonruter Jul 28, 2016

Contributor

Good question. The syncing logic should probably go into the ready method, that is when control.deferred.embedded is resolved (like you have below). You could add control.deferred.embedded.done( ... ) to an extended initialize method.

This comment has been minimized.

Copy link
@westonruter

westonruter Jul 28, 2016

Contributor

Important to note that this syncing needs to be bi-directional. So if you update the field, it should update the setting, and if the setting is updated, it should update the field. You can see this logic here:

element = new api.Element( node );
control.propertyElements.push( element );
element.set( control.setting()[ propertyName ] );
element.bind( function( newPropertyValue ) {
var newSetting = control.setting();
if ( newPropertyValue === newSetting[ propertyName ] ) {
return;
}
newSetting = _.clone( newSetting );
newSetting[ propertyName ] = newPropertyValue;
control.setting.set( newSetting );
} );
control.setting.bind( function( newValue ) {
if ( newValue[ propertyName ] !== element.get() ) {
element.set( newValue[ propertyName ] );
}
} );

It's a bit more complicated in this example of a date control because you're updating parts of a setting's property (like just the month or just the date).

This comment has been minimized.

Copy link
@westonruter

westonruter Jul 28, 2016

Contributor

I could get you started with some initial code if you like.

*
* @todo update Post Status as appropriate.
*/
api.controlConstructor.post_date = api.controlConstructor.dynamic.extend({

This comment has been minimized.

Copy link
@westonruter

westonruter Jul 28, 2016

Contributor

I think we'll want to put this control into its own separate JS file.

This comment has been minimized.

Copy link
@johnregan3

johnregan3 Jul 28, 2016

Author Contributor

Yeah. It grew pretty large over time. 😄

@westonruter

This comment has been minimized.

Copy link
Contributor

commented Aug 1, 2016

I've added a new scheduled countdown to appear with the timezone information when the status is future and the time is after now. The countdown updates dynamically each minute:

screen shot 2016-07-31 at 11 46 38 pm

If the time status is publish (or anything other than future) then the countdown does not appear:

screen shot 2016-07-31 at 11 46 58 pm

And again, you can reset the time to be empty so that it will update with the current time (notice placeholders). As noted above, clicking this button will cause the post_date to be reset to 0000-00-00 00:00:00 ensuring that it will be set to the current time whenever the post is saved. Clicking this has the UI effect of removing the button and changing the date inputs to have placeholders which correspond to the current time (and these placeholders keep updating to reflect the current time):

screen shot 2016-07-31 at 11 46 47 pm

In these examples, notice that I've moved the description below the input fields. I'm still very much unhappy with how I've “designed” the info under the control. I don't like how the description and the reset button look. They should perhaps be collapsed by default in some details or only appear if clicking some question mark icon or something.
Help appreciated!!

<?php
$tz_string = get_option( 'timezone_string' );
if ( $tz_string ) {
$tz = new DateTimezone( get_option( 'timezone_string' ) );

This comment has been minimized.

Copy link
@PatelUtkarsh

PatelUtkarsh Aug 1, 2016

Collaborator

Reuse $tz_string

@ahmadawais

This comment has been minimized.

Copy link
Contributor

commented Aug 1, 2016

Maybe something like this would do?

@ahmadawais

This comment has been minimized.

Copy link
Contributor

commented Aug 1, 2016

@westonruter or maybe a reset icon (this one's a refresh icon though)

@westonruter

This comment has been minimized.

Copy link
Contributor

commented Aug 1, 2016

@ahmadawais great! Re: your tweet, I think to implement these changes, you'd add the appropriate CSS to

.customize-control-post_date select,
.customize-control-post_date input.date-input {
min-width: 10%;
width: auto;
}
.customize-control-post_date input.date-input {
-moz-appearance: textfield;
}
.customize-control-post_date input.date-input::-webkit-outer-spin-button,
.customize-control-post_date input.date-input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
and move the reset button/link to be inside the customize-control-title:
<button type="button" class="button button-secondary reset-time"><?php esc_html_e( 'Reset to current time', 'customize-posts' ) ?></button>

Open a PR to the feature/issue-56-post-date-control branch to amend this PR.

@westonruter

This comment has been minimized.

Copy link
Contributor

commented Aug 2, 2016

Here's where the UI has ended up with input from @ahmadawais. I've moved the timezone and schedule countdown info into a details element, the summary for which is now the timezone abbreviation:

screen shot 2016-08-01 at 8 26 56 pm

screen shot 2016-08-01 at 8 26 40 pm

screen shot 2016-08-01 at 8 25 57 pm

screen shot 2016-08-01 at 8 25 43 pm

screen shot 2016-08-01 at 8 25 33 pm

@westonruter

This comment has been minimized.

Copy link
Contributor

commented Aug 2, 2016

I'll merge this at some point over the next 12 hours unless someone finds an issue needing fixed first.

@westonruter westonruter added this to the 0.7 milestone Aug 2, 2016

@westonruter westonruter merged commit 2a5a796 into develop Aug 2, 2016

3 checks passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
continuous-integration/travis-ci/push The Travis CI build passed
Details
coverage/coveralls First build on develop at 38.727%
Details

@westonruter westonruter deleted the feature/issue-56-post-date-control branch Aug 2, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.