Skip to content

Instantly share code, notes, and snippets.

@gaambo
Last active March 22, 2024 07:32
Show Gist options
  • Save gaambo/d4723975b7de3d282c5da76c3b8521d2 to your computer and use it in GitHub Desktop.
Save gaambo/d4723975b7de3d282c5da76c3b8521d2 to your computer and use it in GitHub Desktop.
wordpress events post type with future post_dates
<?php
// Making future/scheduled posts publicly available is done like this:
// 1. Store event date in post_date field (may be in future)
// 2. Save. WordPress automatically sets status to 'future'
// if the "wished" status is 'published' and the date is in future
// 3. WordPress triggers a post_transition hook for the future post status
// 4. WordPress normally would schedule a cron event to publish the post - this is removed
// 5. Instead on transitioning to future we publish the post (= force status to publish)
// This works, by using wp_publish_post because this only changes the status in the database
// but keeps the post_date
remove_action('future_' . POST_TYPE, '_future_post_hook');
add_action('future_' . POST_TYPE, __NAMESPACE__ . '\publishScheduledPost', 10, 3);
add_action('pre_get_posts', __NAMESPACE__ . '\showFuturePosts');
add_filter('query_vars', __NAMESPACE__ . '\registerCustomQueryVars');
function showFuturePosts(WP_Query $query)
{
if (is_admin()) {
return;
}
$postType = (array)$query->get('post_type');
if (!in_array(POST_TYPE, $postType)) {
return;
}
//
// 1. Handle future/publish post status
//
$queriedStatus = $query->get('post_status');
// If want to display published posts only -> show future posts as well.
if (empty($queriedStatus) || $queriedStatus === 'publish') {
$query->set('post_status', ['publish', 'future']);
} elseif (is_array($queriedStatus) && in_array('publish', $queriedStatus)) {
// If filters on post_status are enabled, check if publish is in them
// then add future as well.
$query->set('post_status', [...$queriedStatus, 'future']);
}
//
// 2. Handle custom "scope" query arg which allows showing only future ore past events in custom queries and filters.
//
$scope = $query->get('event_scope');
if (!empty($scope)) {
$oldDateQuery = $query->get('date_query');
$oldDateQuery = !is_array($oldDateQuery) || empty($oldDateQuery) ? [] : $oldDateQuery;
$newDateQuery = [];
if ($scope === 'past') {
$newDateQuery['before'] = current_time('Y-m-d');
} elseif ($scope === 'future') {
$newDateQuery['after'] = date('Y-m-d', strtotime('-1 day', current_time('U'))); // after yesterday
}
if (!empty($newDateQuery)) {
$newDateQuery = array_merge($oldDateQuery, $newDateQuery);
$query->set('date_query', $newDateQuery);
}
}
}
/**
* Force publishes a scheduled post
* See comment at top of the file
*
* No need to check for post type, because this is hooked to a post status + post type specific action
*
* @param int $postId
* @param WP_Post $post
* @param string $oldStatus
* @return void
*/
function publishScheduledPost(int $postId, WP_Post $post, string $oldStatus): void
{
if ($oldStatus === 'publish' || $oldStatus === 'future') {
wp_publish_post($postId);
}
}
function registerCustomQueryVars(array $queryVars): array
{
$queryVars[] = 'event_scope';
return $queryVars;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment