I’m building a WordPress site, with two nested custom post types, but I’m experiencing an error. I’m hoping to achieve the following basic structure:
- https://website.com/news/ –> shows me my regular wordpress posts
- https://website.com/events/ –> shows me custom events listing, my custom type of ‘events’
- https://website.com/events/an-event/ –> an example event
- https://website.com/events/an-event/ride-01/ –> shows me custom ‘rides’ post type instance
I achieve (1.) on Settings > Permalinks > Custom Structure: /news/%postname%/ – it’s working fine.
I achieve the rest with a custom plugin, code below.
(2.) is working fine.
(3.) is working fine.
My problem is with (4.) – I’m able to create rides, and in the admin panel everything looks fine, even the link to view them. However, when I go to view the post, for example at ‘https://website.com/events/an-event/ride-01/’ I get a 404 error. It looks to me like this should be handled by this line, but isn’t:
add_rewrite_rule( '^/events/([^/]+)/([^/]+)/?$','/index.php?rides=$matches[2]','top' );
When I view https://website.com/index.php?rides=ride-01 I can see my ‘ride’ ok.
How can I view rides with my desired URL as per (4.)? I’ve tried numerous configurations of the ‘rewrite’ and ‘hierarchy’ options but can’t seem to get it to work.
It’s worth noting, every time I make a change I restart my webserver and save the permalinks page to clear any caches.
Thanks!
<?php
/*
Plugin Name: Etc etc.
*/
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly.
}
function fun_be_post_type()
{
$labels = array(
'name' => _x('Events', 'post type general name'),
'singular_name' => _x('Event', 'post type singular name'),
'add_new' => _x('Add New', 'track'),
'add_new_item' => __('Add New Event'),
'edit_item' => __('Edit Event'),
'new_item' => __('New Event'),
'all_items' => __('All Events'),
'view_item' => __('View Event'),
'search_items' => __('Search Events'),
'not_found' => __('No events found'),
'not_found_in_trash' => __('No events found in the Trash'),
'menu_name' => 'Events'
);
$args = array(
'labels' => $labels,
'rewrite' => array(
'slug' => 'events', // This controls the base slug that will display before each term
'with_front' => false // Don't display the category base before "/locations/"
),
'hierarchical' => true,
'description' => 'Holds our bike events and event-specific data',
'public' => true,
'publicly_queryable' => true,
'show_in_rest' => true,
'query_var' => true,
'capability_type' => 'post',
'map_meta_cap' => true,
'rest_controller_class' => 'WP_REST_Posts_Controller',
'menu_position' => 5,
'menu_icon' => 'data:image/svg+xml;base64,PHN2ZyB3etc...+', // base64 encoded svg menu icon
'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'comments', 'revisions', 'custom-fields'),
'has_archive' => true,
'autop' => false
);
register_post_type('events', $args);
$labels = array(
"name" => "Rides",
"singular_name" => "Ride",
);
$args = array(
"labels" => $labels,
"description" => "",
"public" => true,
"show_ui" => true,
"has_archive" => true,
"show_in_menu" => true,
'menu_position' => 6,
//'with_front' => false,
"exclude_from_search" => false,
"capability_type" => "post",
"map_meta_cap" => true,
'hierarchical' => false,
"rewrite" => array("slug" => "events/%event%", "with_front" => false),
"query_var" => true,
"supports" => array("title", "revisions", "thumbnail")
);
register_post_type("rides", $args);
}
add_action('init', 'fun_be_post_type');
add_action('add_meta_boxes', function () {
add_meta_box('rides-parent', 'Events', 'rides_attributes_meta_box', 'rides', 'side', 'default');
});
function rides_attributes_meta_box($post)
{
$pages = wp_dropdown_pages(array('post_type' => 'events', 'selected' => $post->post_parent, 'name' => 'parent_id', 'show_option_none' => __('(no parent)'), 'sort_column' => 'menu_order, post_title', 'echo' => 0));
if (! empty($pages)) {
echo $pages;
} // end empty pages check
}
add_action('init', function () {
add_rewrite_rule('^/events/([^/]+)/([^/]+)/?$', '/index.php?rides=$matches[2]', 'top');
});
add_filter('post_type_link', function ($link, $post) {
if ('rides' == get_post_type($post)) {
//Lets go to get the parent cartoon-series name
if ($post->post_parent) {
$parent = get_post($post->post_parent);
if (!empty($parent->post_name)) {
return str_replace('%event%', $parent->post_name, $link);
}
} else {
//to add later
}
}
return $link;
}, 10, 2);
add_filter('manage_rides_posts_columns', 'set_custom_edit_br_columns');
function set_custom_edit_br_columns($columns)
{
$columns['br_highlight'] = __('Strava ID', 'bike-ride');
$columns = array(
'cb' => $columns['cb'],
'title' => __('Title'),
'parent_id' => __('Event'),
'date' => __('Date'),
);
return $columns;
}
add_action('manage_rides_posts_custom_column', 'custom_br_column', 10, 2);
function custom_br_column($column, $post_id)
{
switch ($column) {
case 'parent_id':
$post_parent = get_post_parent($post_id);
$parent_title = get_the_title($post_parent);
$parent_view_link = get_permalink($post_parent);
$parent_edit_link = get_edit_post_link($post_parent);
echo ("
<a class='row' href='" . $parent_edit_link . "' aria-label='" . $parent_title . " (Edit)'>" . $parent_title . "</a>
<div class='row-actions'><span class='edit'><a href='" . $parent_edit_link . "' aria-label='Edit “" . $parent_title . "”'>Edit</a> | </span><span class='view'><a href='" . $parent_view_link . "' rel='bookmark' aria-label='View “" . $parent_title . "”'>View</a></span></div>
");
break;
}
}