Hi!
First of all: Yes, I have flushed permalink settings.
My question:
I have two custom post types. <strong>Open List</strong> (open_list) and <strong>User Images</strong> (user_images).
The open_list post type is the parent, and the user_images post type is the child. In other words:
Every user_images custom post is a child to a open_list custom post.
This is my permalink setting:
<strong>http://site.com/%postname%/</strong>
I register the post types like this:
$image_type_labels = array(
'name' => _x('User images', 'post type general name'),
'singular_name' => _x('User Image', 'post type singular name'),
'add_new' => _x('Add New User Image', 'image'),
'add_new_item' => __('Add New User Image'),
'edit_item' => __('Edit User Image'),
'new_item' => __('Add New User Image'),
'all_items' => __('View User Images'),
'view_item' => __('View User Image'),
'search_items' => __('Search User Images'),
'not_found' => __('No User Images found'),
'not_found_in_trash' => __('No User Images found in Trash'),
'parent_item_colon' => '',
'menu_name' => 'User Images'
);
$image_type_args = array(
'labels' => $image_type_labels,
'public' => true,
'query_var' => true,
'rewrite' => true,
'capability_type' => 'post',
'has_archive' => false,
'hierarchical' => true,
'map_meta_cap' => true,
'menu_position' => null,
'supports' => array('title', 'editor', 'author', 'thumbnail', 'page-attributes', 'custom-fields'),
'taxonomies' => array('category'),
);
register_post_type('user_images', $image_type_args);
$open_list_labels = array(
'name' => _x('Open lists', 'post type general name'),
'singular_name' => _x('Open list', 'post type singular name'),
'add_new' => _x('Add New Open List', 'image'),
'add_new_item' => __('Add New Open list'),
'edit_item' => __('Edit Open List'),
'new_item' => __('Add New Open List'),
'all_items' => __('View Open Lists'),
'view_item' => __('View Open List'),
'search_items' => __('Search Open Lists'),
'not_found' => __('No Open Lists found'),
'not_found_in_trash' => __('No Open Lists found in Trash'),
'parent_item_colon' => '',
'menu_name' => 'Open Lists'
);
$open_list_args = array(
'labels' => $open_list_labels,
'public' => true,
'query_var' => true,
'rewrite' => true,
'capability_type' => 'post',
'has_archive' => false,
'hierarchical' => true,
'map_meta_cap' => true,
'menu_position' => null,
'supports' => array('title', 'editor', 'author', 'thumbnail', 'page-attributes'),
'taxonomies' => array('category'),
);
register_post_type('open_list', $open_list_args);
I also have the following code to remove the post type name from the slug of these custom post types and to match the name on old posts:
function jf_remove_cpt_slug( $post_link, $post, $leavename ) {
if ( ! in_array( $post->post_type, array( 'usp_post', 'open_list', 'user_images' ) ) || 'publish' != $post->post_status )
return $post_link;
$post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
return $post_link;
}
add_filter( 'post_type_link', 'jf_remove_cpt_slug', 10, 3 );
/**
* Have WordPress match postname to any of our public post types (page, post, race)
* All of our public post types can have /post-name/ as the slug, so they better be unique across all posts
* By default, core only accounts for posts and pages where the slug is /post-name/
*/
function jf_parse_request_trick( $query ) {
// Only noop the main query
if ( ! $query->is_main_query() )
return;
// Only noop our very specific rewrite rule match
if ( 2 != count( $query->query ) || ! isset( $query->query['page'] ) ) {
return;
}
// 'name' will be set if post permalinks are just post_name, otherwise the page rule will match
if ( ! empty( $query->query['name'] ) ) {
$query->set( 'post_type', array( 'post', 'usp_post', 'open_list', 'user_images', 'page' ) );
}
}
add_action( 'pre_get_posts', 'jf_parse_request_trick' );
When visiting the parent post, everything works as expected. Like this:
<strong>http://mysite.com/post-slug-of-open-list-post-type/</strong>
But if I visit the child post, WordPress returns a 404. Like this:
<strong>http://mysite.com/post-slug-of-open-list-post-type/post-slug-of-user-images-post-type/</strong>
Any ideas how I can solve this? It's important for me to keep this hierarchy.
I'm pretty sure that this kind of hierarchy, between two different post types, should work, because I can fetch the child posts inside the parent post without a problem. The problem is when I try to visit the child post, this is where the 404 shows up.
Thanks!
// Jens.
<strong>Edit:</strong> I just noticed that I can access the child post if I go to this page:
<em>http://mysite.com/post-slug-of-user-images-post-type/</em>
But this is wrong, I need the parent post type slug in there as well, to show that this is a hierarchical post...
Rempty answers:
Try this, dont forget to flush rewrite rules
$image_type_labels = array(
'name' => _x('User images', 'post type general name'),
'singular_name' => _x('User Image', 'post type singular name'),
'add_new' => _x('Add New User Image', 'image'),
'add_new_item' => __('Add New User Image'),
'edit_item' => __('Edit User Image'),
'new_item' => __('Add New User Image'),
'all_items' => __('View User Images'),
'view_item' => __('View User Image'),
'search_items' => __('Search User Images'),
'not_found' => __('No User Images found'),
'not_found_in_trash' => __('No User Images found in Trash'),
'parent_item_colon' => '',
'menu_name' => 'User Images'
);
$image_type_args = array(
'labels' => $image_type_labels,
'public' => true,
'query_var' => true,
"rewrite" => array( "slug" => "open-list/%open-listname%", "with_front" => true ),
'capability_type' => 'post',
'has_archive' => false,
'hierarchical' => true,
'map_meta_cap' => true,
'menu_position' => null,
'supports' => array('title', 'editor', 'author', 'thumbnail', 'page-attributes', 'custom-fields'),
'taxonomies' => array('category'),
);
register_post_type('user_images', $image_type_args);
$open_list_labels = array(
'name' => _x('Open lists', 'post type general name'),
'singular_name' => _x('Open list', 'post type singular name'),
'add_new' => _x('Add New Open List', 'image'),
'add_new_item' => __('Add New Open list'),
'edit_item' => __('Edit Open List'),
'new_item' => __('Add New Open List'),
'all_items' => __('View Open Lists'),
'view_item' => __('View Open List'),
'search_items' => __('Search Open Lists'),
'not_found' => __('No Open Lists found'),
'not_found_in_trash' => __('No Open Lists found in Trash'),
'parent_item_colon' => '',
'menu_name' => 'Open Lists'
);
$open_list_args = array(
'labels' => $open_list_labels,
'public' => true,
'query_var' => true,
"rewrite" => array( "slug" => "open-list", "with_front" => true ),
'capability_type' => 'post',
'has_archive' => false,
'hierarchical' => true,
'map_meta_cap' => true,
'menu_position' => null,
'supports' => array('title', 'editor', 'author', 'thumbnail', 'page-attributes'),
'taxonomies' => array('category'),
);
register_post_type('open_list', $open_list_args);
add_action( 'init', function() {
add_rewrite_rule( '^open-list/(.*)/?$','index.php?user_images=$matches[2]','top' );
});
add_filter( 'post_type_link', function( $link, $post ) {
if ( 'user_images' == get_post_type( $post ) ) {
if( $post->post_parent ) {
$parent = get_post( $post->post_parent );
if( !empty($parent->post_name) ) {
return str_replace( '%open-listname%', $parent->post_name, $link );
}
} else {
//This seems to not work. It is intented to build pretty permalinks
//when user_images has not parent, but it seems that it would need
//additional rewrite rules
//return str_replace( '/%open-listname%', '', $link );
}
}
return $link;
}, 10, 2 );
Jens Filipsson comments:
Looks promising! Just wondering about the else statement, should everything be uncommented?
Rempty comments:
There is 1 problem, first need a permalink structure like open-list/%open-listname%/%user_images%
Why?
Because you need to use the rewite rule and do the replacement.
add_rewrite_rule( '^'open-list/(.*)/([^/]+)/?$','index.php?user_images=$matches[2]','top' );
Rempty comments:
i made some modifications use 'hierarchical' => false to user_images and fixed some typos, but can't get it working without "slug post_type"
$image_type_labels = array(
'name' => _x('User images', 'post type general name'),
'singular_name' => _x('User Image', 'post type singular name'),
'add_new' => _x('Add New User Image', 'image'),
'add_new_item' => __('Add New User Image'),
'edit_item' => __('Edit User Image'),
'new_item' => __('Add New User Image'),
'all_items' => __('View User Images'),
'view_item' => __('View User Image'),
'search_items' => __('Search User Images'),
'not_found' => __('No User Images found'),
'not_found_in_trash' => __('No User Images found in Trash'),
'parent_item_colon' => '',
'menu_name' => 'User Images'
);
$image_type_args = array(
'labels' => $image_type_labels,
'public' => true,
'query_var' => true,
"rewrite" => array( "slug" => "open-list/%open-listname%", "with_front" => true ),
'capability_type' => 'post',
'has_archive' => false,
'hierarchical' => false,
'map_meta_cap' => true,
'menu_position' => null,
'supports' => array('title', 'editor', 'author', 'thumbnail', 'page-attributes', 'custom-fields'),
'taxonomies' => array('category'),
);
register_post_type('user_images', $image_type_args);
$open_list_labels = array(
'name' => _x('Open lists', 'post type general name'),
'singular_name' => _x('Open list', 'post type singular name'),
'add_new' => _x('Add New Open List', 'image'),
'add_new_item' => __('Add New Open list'),
'edit_item' => __('Edit Open List'),
'new_item' => __('Add New Open List'),
'all_items' => __('View Open Lists'),
'view_item' => __('View Open List'),
'search_items' => __('Search Open Lists'),
'not_found' => __('No Open Lists found'),
'not_found_in_trash' => __('No Open Lists found in Trash'),
'parent_item_colon' => '',
'menu_name' => 'Open Lists'
);
$open_list_args = array(
'labels' => $open_list_labels,
'public' => true,
'query_var' => true,
"rewrite" => array( "slug" => "open-list", "with_front" => true ),
'capability_type' => 'post',
'has_archive' => false,
'hierarchical' => true,
'map_meta_cap' => true,
'menu_position' => null,
'supports' => array('title', 'editor', 'author', 'thumbnail', 'page-attributes'),
'taxonomies' => array('category'),
);
register_post_type('open_list', $open_list_args);
add_action( 'init', function() {
add_rewrite_rule( '^open-list/(.*)/([^/]+)/?$','index.php?user_images=$matches[2]','top' );
});
add_filter( 'post_type_link', function( $link, $post ) {
if ( 'user_images' == get_post_type( $post ) ) {
if( $post->post_parent ) {
$parent = get_post( $post->post_parent );
if( !empty($parent->post_name) ) {
return str_replace( '%open-listname%', $parent->post_name, $link );
}
} else {
//This seems to not work. It is intented to build pretty permalinks
//when user_images has not parent, but it seems that it would need
//additional rewrite rules
//return str_replace( '/%open-listname%', '', $link );
}
}
return $link;
}, 10, 2 );
Jens Filipsson comments:
So I should remove the filter I currently have in place you mean?
Rempty comments:
Yes, because dont work like pages /pageparent/pagechild
Need a base slug, i am using "open-list" as base
open-list/listparent-slug
open-list/listparent-slug/userimage_slug
Userimage can't be hiererchical
open-list/listparent-slug/userimage1/useimage2 Will not work
Jens Filipsson comments:
But that's a good thing, since I don't want userimages to be hierarchial. I only want them to be hierarchial to the open_list. My filter takes care of removing the base, so could it work as we want with your code + my filter?
// Jens.
Jens Filipsson comments:
This is what I want:
listparent-slug/userimage-slug
Would it be possible to remove the open-list part of your code?
// Jens.
Jens Filipsson comments:
Remove open-list from this url I mean:
open-list/listparent-slug/userimage_slug
Rempty comments:
After a lot of work
Delete your filters and flush rewite rules
$image_type_labels = array(
'name' => _x('User images', 'post type general name'),
'singular_name' => _x('User Image', 'post type singular name'),
'add_new' => _x('Add New User Image', 'image'),
'add_new_item' => __('Add New User Image'),
'edit_item' => __('Edit User Image'),
'new_item' => __('Add New User Image'),
'all_items' => __('View User Images'),
'view_item' => __('View User Image'),
'search_items' => __('Search User Images'),
'not_found' => __('No User Images found'),
'not_found_in_trash' => __('No User Images found in Trash'),
'parent_item_colon' => '',
'menu_name' => 'User Images'
);
$image_type_args = array(
'labels' => $image_type_labels,
'public' => true,
'query_var' => true,
"rewrite" => true,
'capability_type' => 'post',
'has_archive' => false,
'hierarchical' => false,
'map_meta_cap' => true,
'menu_position' => null,
'supports' => array('title', 'editor', 'author', 'thumbnail', 'page-attributes', 'custom-fields'),
'taxonomies' => array('category'),
);
register_post_type('user_images', $image_type_args);
$open_list_labels = array(
'name' => _x('Open lists', 'post type general name'),
'singular_name' => _x('Open list', 'post type singular name'),
'add_new' => _x('Add New Open List', 'image'),
'add_new_item' => __('Add New Open list'),
'edit_item' => __('Edit Open List'),
'new_item' => __('Add New Open List'),
'all_items' => __('View Open Lists'),
'view_item' => __('View Open List'),
'search_items' => __('Search Open Lists'),
'not_found' => __('No Open Lists found'),
'not_found_in_trash' => __('No Open Lists found in Trash'),
'parent_item_colon' => '',
'menu_name' => 'Open Lists'
);
$open_list_args = array(
'labels' => $open_list_labels,
'public' => true,
'query_var' => true,
"rewrite" => true,
'capability_type' => 'post',
'has_archive' => false,
'hierarchical' => true,
'map_meta_cap' => true,
'menu_position' => null,
'supports' => array('title', 'editor', 'author', 'thumbnail', 'page-attributes'),
'taxonomies' => array('category'),
);
add_filter(
'post_type_link',
'custom_post_type_link',
10,
3
);
function custom_post_type_link($permalink, $post, $leavename) {
if (!gettype($post) == 'post') {
return $permalink;
}
$parent = get_post( $post->post_parent );
switch ($post->post_type) {
case 'user_images':
$permalink = get_home_url() . '/'.$parent->post_name.'/'.$post->post_name . '/';
break;
case 'open_list':
$permalink = get_home_url() . '/'.$post->post_name . '/';
break;
}
return $permalink;
}
add_action( 'pre_get_posts', 'custom_pre_get_posts');
function custom_pre_get_posts($query) {
global $wpdb;
if(!$query->is_main_query()) {
return;
}
if($query->get('attachment')!=''){
$post_name = $query->get('attachment');
}else{
$post_name = $query->get('name');
}
//echo '<pre>' . print_r($query, true) . '</pre>';
$post_type = $wpdb->get_var(
$wpdb->prepare(
'SELECT post_type FROM ' . $wpdb->posts . ' WHERE post_name = %s LIMIT 1',
$post_name
)
);
$result = $wpdb->get_row(
$wpdb->prepare(
'SELECT wpp1.post_type, wpp2.post_name AS parent_post_name FROM ' . $wpdb->posts . ' as wpp1 LEFT JOIN ' . $wpdb->posts . ' as wpp2 ON wpp1.post_parent = wpp2.ID WHERE wpp1.post_name = %s LIMIT 1',
$post_name
)
);
switch($post_type) {
case 'user_images':
$query->set('user_images', $post_name);
$query->set('post_type', $post_type);
$query->is_single = true;
$query->is_page = false;
break;
case 'open_list':
$query->set('open_list', $post_name);
$query->set('post_type', $post_type);
$query->is_single = true;
$query->is_page = false;
break;
}
return $query;
}
Jens Filipsson comments:
This seems to work perfectly. Thank you so much for your help! Greatly appreciated!
Jens Filipsson comments:
I might have been a bit quick to vote for the answer. Right now the pages (not posts) on the site returns 404 errors. If I remove the functions, it works.
Would it be possible to make your functions only affect the two post types and nothing else on the site?
Sébastien | French WordpressDesigner answers:
could you just refresh the page of setting of permalinks please ?
Jens Filipsson comments:
Thanks for you answer, Sébastien!
As I stated in the top of my post:
<em>First of all: Yes, I have flushed permalink settings.</em>
So I have already tried this...
Jens Filipsson comments:
But now I noticed something:
I can access the child post if I visit:
<strong>http://mysite.com/post-slug-of-user-images-post-type/</strong>
But this is wrong, I need to show that it is hierarchical. Any ideas what might be wrong?
Sébastien | French WordpressDesigner comments:
do you say that the both url works and display the same page :
http://mysite.com/post-slug-of-open-list-post-type/post-slug-of-user-images-post-type/
http://mysite.com/post-slug-of-user-images-post-type/
Jens Filipsson comments:
No. This <strong>works:</strong>
http://mysite.com/post-slug-of-open-list-post-type/
And this <strong>works:</strong>
http://mysite.com/post-slug-of-user-images-post-type/
But this <strong>doesn't work</strong> (although this is the output of the_permalink to the child post type. And this is what I want)
http://mysite.com/post-slug-of-open-list-post-type/post-slug-of-user-images-post-type/
Hai Bui answers:
How did you create the parent-child relationship between the two custom post types?