1

What would be the best way to go about creating something like this (https://www.fiawtcc.com/calendar/) in WordPress?

This is a calendar, with posts (containing the event date and event description), separated by year.

A thought doing something like this, but I do not know, if this is a good solution, or if it is possible:

  1. Creating a category
  2. Add a date picker with advanced custom fields to the category
  3. Separate category posts by the value of the date picker (event date).

Any advice would be appreciated.

2

Probably the most "WordPress-y" approach to such a problem is to store the date of your 'event' custom post-type in the post's metadata. Enabling users to set meta-data on a post is usually accomplished by using the 'register_meta_box_cb' argument to the register_post_type() function to add an extra "meta box" interface to the pages for creating or editing a post on the dashboard. Alternately, you can enable custom fields support for the post-type, then check the box for "Custom Fields" in the screen options when creating or editing an 'event', after which you can manually enter the key ('event_date' would be a good meta-key) and value in the "Custom Fields" section of the editor.

The actual meta-value itself should detail dates in YYYY-MM-DD format in order to best make use of WordPress's meta-query functionality.

In order to create permalinks to custom queries, you use a custom rewrite rule to populate a custom query var from the desired URL, then alter the main WP_Query with a 'pre_get_posts' hook to retrieve the content indicated with your query var. All together, it looks something like this:

// Allow WP to pass around an "event_year" variable as part of URL querystrings
function wpse_224309_add_event_year_query_var( $vars )
{
  array_push( $vars, 'event_year' );
  return $vars;
}
add_filter( 'query_vars', 'wpse_224309_add_event_date_query_var' );

// Populate the "event_year" query var when visiting "/seasons/{year}" URLs
function wpse_224309_event_archive_year_rewrite() {
  add_rewrite_rule( 'seasons/([0-9]{4})/?', 'index.php?post_type=event&event_year=$matches[1]', 'top' );
}
add_action( 'init', 'wpse_224309_event_archive_year_rewrite' );

// If the "event_year" query var exists when in an event archive query, set up
// a meta-query to retrieve events with appropriate "event_date" metadata
function wpse_224309_event_archive_query_meta_date( $query ) {
  // Don't modify queries that aren't for primary content
  if( ! $query->is_main_query() )
    return;

  // Don't modify queries for anything but the 'events' post-type archive
  if( ! is_post_type_archive( 'events' ) )
    return;

  $year = $query->get( 'event_year' ); // Get the target year from the qv

  // If the "event_year" query var wasn't set, don't alter the query
  if( ! isset( $year ) )
    return;

  $year = absint( $year ); // Make sure $year is a non-negative integer

  // Look for events with an "event_date" meta-value between the end of the
  // previous year and before the start of the next year.
  $meta_query = array(
    'key'     => 'event_date',
    'type'    => 'DATE',
    'compare' => 'BETWEEN'
    'value'   => array(
      ($year - 1) . '-12-31',
      ($year + 1) . '-01-01'
  );

  // Overwrite the meta-query to retrieve events with an "event_date" in the
  // specified year, ordered by ascending date.
  $query->set( 'meta_query', array( $meta_query ) );
  $query->set( 'orderby', 'meta_value_date' );
  $query->set( 'meta_key', 'event_date' );
  $query->set( 'order', 'ASC' );
);
add_action( 'pre_get_posts', 'wpse_224309_event_archive_query_meta_date' );

If you need to filter events for other meta-data as well, however, you'll need to compose a more detailed meta-query instead of completely overwriting it as I've done (see the Codex entries on WP_Query and WP_Meta_Query for details).

For the front-end, create an archive template for your "event" post type (likely archive-events.php, in order to permit WordPress to load it automatically via template hierarchy conventions). You'll need to create a list of links to your custom year archive manually. In order to do so, you'll need to retrieve an array of unique years in for the 'event_date' metadata. There are various ways to do this, but I believe that the most efficient is to directly query the database (WPDB->get_col() example courtesy of WPSE 9394):

function wpse_224309_get_event_years( $order ) {
  global $wpdb;

  if( ! $order )
    $order = 'DESC';

  return $wpdb->get_col( $wpdb->prepare( "
    SELECT DISTINCT YEAR( pm.meta_value ) FROM {$wpdb->postmeta} pm
    LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
    WHERE pm.meta_key = 'event_date' 
    AND p.post_status = 'publish' 
    AND p.post_type = 'events'
    ORDER BY pm.meta_value %s
  ", $order ) );
}

function wpse_224309_event_year_archive_links( $args = '' ) {
  $defaults = array(
    'format' => 'html',
    'before' => '',
    'after' => '',
    'echo' => 1,
    'order' => 'DESC'
  );

  $r = wp_parse_args( $args, $defaults );
  $years = wpse_224309_get_event_years( $r['order'] );

  if( ! is_array( $years ) || 0 === count( $years ) )
    $return;

  $output = '';

  for( $i = 0; $i < count( $years ); $i++ )
    $output .= get_archive_link( get_home_url( null, 'seasons/' . $years[ $i ] ), $years[ $i ], $r['format'], $r['before'], $r['after'] );

  if( $r['echo'] )
    echo $output;

  return $output;
}

Alternate Solutions

A simpler solution might be to simply use just a 'pre_get_posts' hook to modify queries on the front-end for year-based event archives (i.e. ! is_admin() && is_post_type_archive( 'events' ) && is_year()), unsetting all date-related query vars and redirecting the value of the year query var to the meta-query instead. This has the advantage of enabling you to simply use the wp_get_archives() function to print a list of year-based archive links. However, the approach is "hacky" in that it foils expected core behaviors, and may break other functionality as a result.

Similarly, the 'get_archives_link' filter could be used to replace the links produced by wp_get_archives() on the fly.

There are many different approaches to this problem - but it's worth noting that filtering "events" by a date stored in metadata is something that's no doubt come up time and time again - I'm confident that implemented solutions are out there if you dig deep enough.

  • But it will not work out-of-the-box for categories. Even if it would work, this will sort posts by publication date, not the date of the actual event, which could be next year. – Fee-fi-fo-fum Apr 20 '16 at 19:11
  • Then you're probably looking at creating a custom WP_Query and sorting by a meta value that you store the date of the actual event in. – Andrew Bartel Apr 20 '16 at 20:44
  • @Fee-fi-fo-fum ah, I misinterpreted your question - that's somewhat more complicated. Questions regarding 3rd-party products are considered off-topic for our site, but I'll try to give you an overview of the most "WordPress-y" way to accomplish what you ask, ignoring the Advanced Custom Fields plugin. AndrewBartel's on the money - post metadata and a custom query is the way to go – bosco Apr 20 '16 at 22:06
  • Added a thorough overview of the solution I would pursue. Could certainly be accomplished more easily with hackery. I haven't tested anything - I'm sure much could use tweaking. – bosco Apr 21 '16 at 2:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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