Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I have a multi-author baseball site. I want authors to be able to schedule posts to be published at one of four selected times each day. This is important because some authors write game recaps, and an auto-publish of a game recap once the following game has started is pretty worthless.

I am looking for a plugin to manage this. Through research I have found a few plugins that will pick a time between a set of times set by the admin, but I am looking for something where the Admin can set up a calendar of days/times (or range of times) to allow a post to be published and set a max number of post for each time

The Author writes his post, then is presented with a selection of dates/times to schedule the post to publish.

As I mentioned, there are similar plugins, but none I have found allow Admins to set specific times.

Does anyone know of a plugin or other method? The plugin doesn't need to be free.

Update with "Vision"

Admin settings: Set dates allowed for post publishing. Set times allowed for post publishing. Set number of posts allowed to be scheduled to publish at each time (if scheduling number has been met per slot it will not be shown to Author).

Author scheduling options: "Publish" button not present. Must choose day of the week to publish post >> Must select from available times to publish post.

share|improve this question
    
Does the list of times available need to be the same across all posts, or variable depending on other factors? –  Otto May 6 '12 at 4:24
    
I hadn't really thought about it. What did you have in mind? Updated question with more info. –  Travis Pflanz May 6 '12 at 4:43
1  
This seems like it would make a pretty good plugin. I've got the publishing part and the ui for the post edit screen done but I haven't worked out the admin options yet. I'm think I will post what I have and maybe someone else can add to it. –  Chris_O May 7 '12 at 4:50

2 Answers 2

up vote 4 down vote accepted
+50

My approach is to create an hourly cron event that loops through all the draft status posts and checks for the publish month - date and hour saved in post_meta and publishes if scheduled date is not in the future.

A publish date and time select meta box is added to the publishing div that updates via ajax when a time is chosen.

Update:

Added plugin and date picker css to git: https://github.com/c3mdigital/WP-Schedule

Changed cron function to use timezone configured in WordPress for publishing.

Update:

The date and time will be stored in post_meta as an array: month' => 'string', time => int The time integer will be a value that represents an hour of the day 1-24.

The options screen has 3 inputs.

  • Times: entered as comma separated numbers representing the hour of the day to publish posts.
  • Number of posts to publish at each time
  • Dates: a comma separated array of dates

enter image description here

I added a jQuery UI Date picker to the post edit screen that is restricted to the dates chosen in the admin. The date and time are updated and saved using ajax.

enter image description here enter image description here

enter image description here

Updated Plugin Code:

 <?php
/*
Plugin Name: c3m wp-schedule
Plugin URI: 
Description: Gives contributors a jQuery date picker to choose available date and times available to publish posts
Version: 0.1.2
Author: Chris Olbekson
Author URI: http://c3mdigital.com/
License: GPL v2
*/


    register_activation_hook( __FILE__, 'c3m_activate_cron' );
    add_action( 'post_submitbox_misc_actions', 'c3m_create_schedule_meta', 10 );
    add_action( 'admin_print_footer_scripts', 'c3m_echo_js' );
    add_action( 'admin_enqueue_scripts', 'c3m_enqueue_scripts' );

    function c3m_activate_cron() {
        wp_schedule_event( current_time( 'timestamp' ), 'hourly', 'c3m_check_posts' );

    }

    function c3m_check_posts() {
        $args = array(
            'post_status' => array( 'draft', 'pending' ),
            'posts_per_page' => -1,
            );

            $timestamp = current_time( 'timestamp' );
            $posts = get_posts( $args );
            $month = (int) date('m', $timestamp );
            $day = (int) date('d', $timestamp );
            $hour = (int) date('G', $timestamp );

                foreach ( $posts as $post ) {
                    $date = get_post_meta( $post->ID, '_schedule_date', true );

                    if ( !$date ) continue;
                    $sched_date = explode( "-", $date['date'] );

                    if ( (int) $sched_date[0] > $month  ) continue;
                    if ( (int) $sched_date[1] > $day ) continue;
                    if ( (int) $sched_date[1] >= $day && (int)$date['time'] > $hour )  continue;

                    wp_publish_post( $post->ID );

                    }

    }

    function c3m_create_schedule_meta() {
        global $post_ID;

        $date = get_post_meta( $post_ID, '_schedule_date', TRUE );
        $options = c3m_get_options ();
        $times = $options[ 'c3m_hour_string' ];
        $times_available = explode ( ",", $times );
        $time_output = "Choose Time to publish<br/>";
        $time_output .= "<select class='time-div' name='c3m_sched_time' id='" . $post_ID . "' >\n";
        $time_output .= "\t<option value='-1'>" . esc_html ( 'Select Publish Time' ) . "</option>\n";

        foreach ( $times_available as $time ) {
            $time_output .= "\t<option value='$time'>" . esc_html ( $time ) . "</option>\n";

        }
        $time_output .= "</select>";

        echo '<div id="schedule" class="misc-pub-section" style="border-top-style:solid; border-top-width:1px; border-top-color:#EEEEEE; border-bottom-width:1px;">';

        if ( !$date ) {
        $output = 'Choose Date to publish';
        $output .= "<input class='sched-div datepicker' type='text' name='c3m_sched_date' id='".$post_ID."' />\n";
        $output .= '<br /><br /><div id="sched_time_div">'.$time_output.'</div>';

        echo $output;
        echo '<p id="hidden-p"><a id="save-time" style="margin-left: 10px" class="button">Save</a></p>';

        } else {
            if ( $date['time'] > 12 ) $pm = 'pm'; else $pm = 'am';

            echo '<p style="padding-left: 10px;">Scheduled to publish on: <strong>' . $date['date'] . '</strong><br />';
            echo 'At approx: <strong>' .  $date['time'].$pm. '</strong><br /></p>';
             }

        echo '</div>';

    }

    function c3m_enqueue_scripts() {
        global $pagenow, $typenow;
        if ( ( $pagenow == 'post.php' || $pagenow == 'post-new.php' ) && $typenow == 'post' ) {
        wp_enqueue_script( 'jquery-ui-datepicker' );
        wp_enqueue_style ( 'jquery-ui-lightness', plugins_url( 'ui-lightness/jquery-ui-1.8.20.custom.css', __FILE__ )  );
        }

    }

    function c3m_echo_js() { 
        global $pagenow, $typenow;
        if ( ( $pagenow=='post.php' || $pagenow=='post-new.php')   && $typenow=='post') {
              $options = c3m_get_options ();
              $dates = $options[ 'c3m_date_string' ];
              $find = '/';
              $replace = '-';
              $dates = str_replace( $find, $replace, $dates );
              $days = explode ( ",", $dates );
              $year = date ( 'Y' );

              ?>

        <script type="text/javascript">
            jQuery(document).ready(function() {
                jQuery("#publishing-action").hide();
                jQuery(".misc-pub-section-last").hide();
                jQuery("a#save-time").click(function() {
                    var postID = jQuery("#post_ID").val();
                    var pubDate = jQuery(".sched-div").val();
                    var theTime = jQuery(".time-div option:selected").val();
                    console.log( postID, pubDate, theTime );
                    jQuery.ajax({
                        type:'POST',
                        url: ajaxurl,
                        data: {"action": "save_pub_time", post_id: postID, sched: pubDate, time: theTime },
                        success: function(response) {
                            jQuery("#schedule").replaceWith(response);

                        }
                    });

                    return false;

                });

                var enabledDays = [ <?php foreach( $days as $day ) {  ?>
                 "<?php  echo $day.'-'.$year; ?>",
            <?php  } ?>];

            function enableAllTheseDays(date) {
                var m = date.getMonth(), d = date.getDate(), y = date.getFullYear();
                for (i = 0; i < enabledDays.length; i++) {
                    if (jQuery.inArray((m + 1) + '-' + d + '-' + y, enabledDays) != -1) {
                        return [true, ''];
                    }
                }
                return [false, ''];
            }
            jQuery('.datepicker').datepicker({
                dateFormat:'mm-dd-yy',
                beforeShowDay:enableAllTheseDays
            });
            });
    </script>

    <?php   }
    }

    add_action ( 'wp_ajax_save_pub_time', 'c3m_ajax_save' );
    function c3m_ajax_save() {
        $post_id = $_POST[ 'post_id' ];
        $date = $_POST[ 'sched' ];
        $time = $_POST[ 'time' ];
        if ( $time > 12 ) $pm = 'pm'; else $pm = 'am';
        update_post_meta ( $post_id, '_schedule_date', array ( 'date' => $date, 'time' => $time ) );
        $output = '<p style="padding-left: 10px;">Scheduled to publish on: <strong>'.$date.'</strong><br />';
        $output .= 'At approx: <strong>'.$time. $pm.'</strong></p><br />';
        echo $output;

        die(1);
    }

    /**
     * @return array
     * Array
     * (
     * [c3m_hour_string] => 11,03,05,07
     * [c3m_allowed_string] => 4
     * [c3m_date_string] => 05/10,05/11,05/12
     * )
     *
     */

     function c3m_get_options() {
        $c3m_options = get_option('c3m_options');
        return $c3m_options;
    }

    add_action( 'admin_menu', 'c3m_create_menu' );
    function c3m_create_menu() {
        add_options_page( 'Manage Post Schedule', 'Manage Post Schedules', 'manage_options', 'post_schedules', 'c3m_schedule_options' );
    }

    function c3m_schedule_options() {
        echo '<div class="wrap">';
        echo '<h2>Manage Post Schedules</h2>';
        echo 'Manages the custom post scheduling options';
        echo '<form action="options.php" method="post">';
        settings_fields( 'c3m_options' );
        do_settings_sections( 'post_schedules' );
        echo '<input name="Submit" type="submit" class="button-primary" value="Save Changes" />';
        echo '</form></div>';

    }
    add_action( 'admin_init', 'c3m_plugin_init' );
    function c3m_plugin_init() {
        register_setting( 'c3m_options', 'c3m_options', 'c3m_validate' );
        add_settings_section( 'plugin_main', 'Post Schedule Dates and Times', 'settings_array', 'post_schedules' );
        add_settings_field( 'c3m_hour_string', 'Enter Post Publish Times (use 2 digit hours seperated by commas. ie 11,16,17  will publish at 11am, 4pm and 5pm):', 'c3m_hour_setting', 'post_schedules', 'plugin_main' );
        add_settings_field( 'c3m_allowed_string', 'Enter how many posts can be published at each time: ', 'c3m_allowed_setting', 'post_schedules', 'plugin_main' );
        add_settings_field( 'c3m_date_string', 'Enter Publish Dates (use month/day seperated by commas ie: 5/5,5/7 for May 5th and May 7th): ', 'c3m_date_setting', 'post_schedules', 'plugin_main' );
        add_settings_field( 'c3m_editor', 'click to load an editor', 'c3m_editor_setting', 'post_schedules', 'plugin_main' );
    }

    function settings_array() {
        echo '<p>Add post schedule date and time settings here</p>';
    }

    function c3m_hour_setting() {
        $options = get_option( 'c3m_options' );
        echo "<input id='c3m_hour_string' name='c3m_options[c3m_hour_string]' size='40' type='text' value='{$options['c3m_hour_string']}' />";
    }

    function c3m_allowed_setting() {
        $options = get_option( 'c3m_options' );
        echo "<input id='c3m_allowed_string' name='c3m_options[c3m_allowed_string]' size='40' type='text' value='{$options['c3m_allowed_string']}' />";
    }

    function c3m_date_setting() {
        $options = get_option( 'c3m_options' );
        echo "<input id='c3m_date_string' name='c3m_options[c3m_date_string]' size='40' type='text' value='{$options['c3m_date_string']}' />";
    }

    function c3m_validate( $input ) {
        $options = get_option( 'c3m_options' );
        $options['c3m_hour_string'] = trim( $input['c3m_hour_string'] );
        $options[ 'c3m_allowed_string' ] = trim ( $input[ 'c3m_allowed_string' ] );
        $options[ 'c3m_date_string' ] = trim ( $input[ 'c3m_date_string' ] );
        return $options;
        // Todo:  Create a real validate function
    }

@Todo: Create validation function for saving the options, Create a count option that stores how many posts are scheduled for each time to restrict those times once full, and clean up & document the code.

share|improve this answer
    
Sorry for my delay in replying. I haven't been able to get to a computer much the past week or so. I am getting an error on the settings screen. Here is a screenshot - lh4.googleusercontent.com/-_mep94oKSiE/T7KkvG0t7mI/AAAAAAAAAY4/… Also, the date picker is not displaying on the post page. I use Chrome and Windows 7 –  Travis Pflanz May 15 '12 at 18:49

Here's my take: https://github.com/stephenh1988/Restrict-Publish

This will be made into a proper plug-in and some point. At the moment, it 'works' - but you manually configure the plug-in variables (i.e, no admin options yet).

All restrictions apply to users without the capability to manage_options (i.e. admins). But this could be altered as well.

The UI

The idea is to load javascript after the WP loads post.js (this includes the java-script that controls altering the time input. The plug-in over-rides this, clicking 'edit' for the publish time instead opens up a jQuery UI date-time picker.

The date-time picker only allows certain dates to be available given some rules (see below). All other dates are not selectable. On selecting the a date/time the appropriate WordPress fields are updated - and so WordPress handles the rest of the processing.

So this part of the plug-in only really prevents certain dates being inputed.

(The date-time picker is positioned a bit too low - something that can be smartened up using jQuery ui positioning).

Server-side checks

It also performs a check on save_post - just in case (js disabled? hack by user?) a 'forbidden' date is selected, the save_post callback checks the date again. If it is found to be invalid, the post is 'prevented' from being published/scheduled (as per this answer) and instead returned to draft status. A custom message appears (this message can be changed by setting $fail_message currently).

The rules

These are very basic. The set of rules kept in an $allows array:

$allow = array(
            'days_in_week'=> array(0,2),//Publish on Sunday/Tuesday
            'months_in_year'=> array(1,2,3,4,6,7,8,9,10,11,12),//Cannot publish in May
        );

'days_in_week' is an array of integers to indicate which days (0=sunday, 1=monday) the user can publish dates on. Similarly 'months_in_year' stores an array of allowed months (1=january,...). Extra rules could be added quite easily (including a shortlist of admin-specified dates).

Limiting scheduled post

There is also a $limit variable which limits the number of scheduled posts a user can have. If they reach that limit, they loose the capability to publish (instead having to submit it for review - you could remove the right to even create posts, but that would prevent editing as well).

The plug-in code

See this GitHub Repro: https://github.com/stephenh1988/Restrict-Publish

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.