# "Add to Queue" Scheduling for Drafts

> Adds an "Add to queue" link under drafts in the Posts list that schedules the post into the next free publishing slot, such as weekdays at 9:00, without picking dates by hand.

- Type: PHP
- Runs: Admin only
- Category: [Content](https://wpide.com/library/category/content/)
- Tags: scheduling, editorial, publishing
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/content-publishing-queue/

## Code

```php
// Publishing days (1 = Monday ... 7 = Sunday) and times (24h, site time zone).
$wpide_queue_days  = array( 1, 2, 3, 4, 5 );
$wpide_queue_times = array( '09:00', '15:00' );

add_filter( 'post_row_actions', function ( $actions, $post ) {
    if ( 'draft' === $post->post_status && 'post' === $post->post_type && current_user_can( 'publish_post', $post->ID ) ) {
        $actions['wpide_queue'] = sprintf(
            '<a href="%s">Add to queue</a>',
            esc_url( wp_nonce_url( admin_url( 'admin-post.php?action=wpide_queue_post&post=' . $post->ID ), 'wpide_queue_' . $post->ID ) )
        );
    }
    return $actions;
}, 10, 2 );

add_action( 'admin_post_wpide_queue_post', function () use ( $wpide_queue_days, $wpide_queue_times ) {
    $post_id = isset( $_GET['post'] ) ? absint( $_GET['post'] ) : 0;
    check_admin_referer( 'wpide_queue_' . $post_id );
    if ( ! current_user_can( 'publish_post', $post_id ) || 'draft' !== get_post_status( $post_id ) ) {
        wp_die( 'Not allowed.', 403 );
    }

    // Slots already taken by scheduled posts.
    $taken = array();
    foreach ( get_posts( array( 'post_status' => 'future', 'posts_per_page' => -1, 'fields' => 'ids', 'no_found_rows' => true ) ) as $id ) {
        $taken[ get_post_field( 'post_date', $id ) ] = true;
    }

    $tz   = wp_timezone();
    $day  = new DateTimeImmutable( 'now', $tz );
    $slot = null;
    for ( $i = 0; $i < 90 && ! $slot; $i++ ) {
        $date = $day->modify( "+$i days" );
        if ( ! in_array( (int) $date->format( 'N' ), $wpide_queue_days, true ) ) {
            continue;
        }
        foreach ( $wpide_queue_times as $time ) {
            list( $h, $m ) = array_map( 'intval', explode( ':', $time ) );
            $candidate     = $date->setTime( $h, $m );
            if ( $candidate->getTimestamp() > time() + 5 * MINUTE_IN_SECONDS && empty( $taken[ $candidate->format( 'Y-m-d H:i:s' ) ] ) ) {
                $slot = $candidate;
                break;
            }
        }
    }

    if ( $slot ) {
        wp_update_post( array(
            'ID'            => $post_id,
            'post_status'   => 'future',
            'post_date'     => $slot->format( 'Y-m-d H:i:s' ),
            'post_date_gmt' => get_gmt_from_date( $slot->format( 'Y-m-d H:i:s' ) ),
            'edit_date'     => true,
        ) );
    }

    wp_safe_redirect( add_query_arg( 'wpide_queued', $slot ? rawurlencode( $slot->format( 'Y-m-d H:i' ) ) : 'none', admin_url( 'edit.php' ) ) );
    exit;
} );

add_action( 'admin_notices', function () {
    if ( empty( $_GET['wpide_queued'] ) ) {
        return;
    }
    $slot = sanitize_text_field( wp_unslash( $_GET['wpide_queued'] ) );
    echo 'none' === $slot
        ? '<div class="notice notice-warning is-dismissible"><p>No free slot found in the next 90 days.</p></div>'
        : '<div class="notice notice-success is-dismissible"><p>Scheduled for ' . esc_html( $slot ) . '.</p></div>';
} );
```

## Notes

Define your slots in $wpide_queue_days and $wpide_queue_times (site time zone); only one post is scheduled per slot.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find ""Add to Queue" Scheduling for Drafts" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
