After looking at documentation and searching around, I haven’t been able to find anything, so here goes:
Are there any way of custom-post-type-inheritance, and an url structure like this:
domain.com/%parenttype%/%parentname%/%posttype/%postname%/
Lets say artists have songs, would look like:
domain.com/artist/john-lennon/songs/imagine/
I haven’t seen this done in development before. Does anyone know anything about this?
1 Answer
Here we go:
- Register your two CPT (= custom post types) e.g. artist, song
- Edit the rewrite slug from your child CPT to
parent-type/%parent-slug%/child-slug
(Attention: Don’t use the same word forparent-type
andparent-slug
;parent-slug
should match your parent CPT slug) - Add a meta box to your child CPT, where you can define a parent CPT
- Modify the child CPT permalink to your needs
I wrapped it all up, ready to use:
class myArtistSongs{
function init_post_types() {
$args = array(
'menu_position' => 8,
'labels' => array(
'name' => __('Songs', 'myArtistSongs'),
'all_items' => __('All Songs', 'myArtistSongs'),
'singular_name' => __('Song', 'myArtistSongs')
),
'menu_icon' => 'dashicons-format-audio',
'public' => true,
'publicly_queryable' => true,
'query_var' => false,
'capability_type' => 'post',
'has_archive' => false,
'rewrite' => array(
'slug' => 'artist/%artist%/songs',
'feeds' => true,
'pages' => true,
'with_front' => true,
),
'taxonomies' => array(
'artist'
),
'supports' => array(
'title',
'editor',
'thumbnail',
'excerpt'
)
);
register_post_type( 'song', $args);
$args = array(
'menu_position' => 8,
'labels' => array(
'name' => __('Artists', 'myArtistSongs'),
'all_items' => __('All Artists', 'myArtistSongs'),
'singular_name' => __('Artist', 'myArtistSongs')
),
'menu_icon' => 'dashicons-groups',
'public' => true,
'publicly_queryable' => true,
'query_var' => false,
'capability_type' => 'post',
'has_archive' => false,
'rewrite' => array(
'slug' => 'artists',
'feeds' => true,
'pages' => true,
'with_front' => true,
),
'taxonomies' => array(
'artist'
),
'supports' => array(
'title',
'editor',
'thumbnail',
'excerpt'
)
);
register_post_type( 'artist', $args);
}
static function song_permalink($permalink, $post_id, $leavename) {
if (strpos($permalink, '%artist%') === FALSE) return $permalink;
$post = get_post($post_id);
if (!$post) return $permalink;
$artist = get_post_meta($post->ID, '_artist', true);
if ($artist > 0) {
$artist = get_post($artist);
if (!$artist) $artist = false;
else $artist = $artist->post_name;
}
if (!$artist) $artist="no-artist";
return str_replace('%artist%', $artist, $permalink);
}
function add_meta_box() {
add_meta_box(
'article-parent',
__('Artist',''),
array('myArtistSongs', 'meta_box'),
'song',
'side',
'low'
);
}
function meta_box($post) {
$artist = get_post_meta($post->ID, '_artist', true);
global $wp_query, $post;
$old_wp_query = $wp_query;
$old_post = $post;
$loop = new WP_Query(array('post_type' => 'artist', 'posts_per_page=-1'));
echo "<select name="artist" id='artist'>";
$no_value = __('(no artist)','myArtistSongs');
echo "<option value=""".(empty($artist)?" selected='selected'":'').">".$no_value."</option>";
if($loop->have_posts()) while ($loop->have_posts()) {
$loop->the_post();
$o_id = get_the_ID();
$o = get_the_title();
echo "<option value="{$o_id}"".(!empty($artist) && $artist == $o_id?" selected='selected'":'').">{$o}</option>";
}
echo "</select>";
$post = $old_post;
$wp_query = $old_wp_query;
}
function save($post_id) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;
if ( !current_user_can( 'edit_post', $post_id ) )
return;
if ($_POST['artist']) {
update_post_meta($post_id, '_artist', $_POST['artist']);
} else {
delete_post_meta($post_id, '_artist');
}
}
}
add_action('init', array('myArtistSongs', 'init_post_types'));
add_filter('post_link', array('myArtistSongs', 'song_permalink'), 10, 3);
add_filter('post_type_link', array('myArtistSongs', 'song_permalink'), 10, 3);
add_action('add_meta_boxes', array('myArtistSongs', 'add_meta_box'));
add_action( 'save_post', array('myArtistSongs','save') );