Note that a filter callback must always return something which is commonly the first parameter passed to the callback. So for example your overwriteQueryVars()
function, it must always return the $query
because request
is a filter hook.
Secondly, instead of overwriting the entire query arguments (e.g. by doing $query = array( ... )
or $query->query_vars = $new_query;
), you should only change the ones need to be changed in the existing query arguments, e.g. $query['post_type'] = $postType;
.
But anyway, try this which worked well for me:
add_filter( 'request', 'overwriteQueryVars' );
function overwriteQueryVars( $query_vars ) { // I renamed $query to $query_vars.
global $wp;
/*
* 1. Check if the current page URL path begins with library/authors/ as in example.com/library/authors/
* 2. Then check if the post_type is exactly "authors".
* 3. Finally, check if the "authors" is in the form of <slug>/<slug>.
*/
if ( preg_match( '#^library/authors/#', $wp->request ) &&
isset( $query_vars['post_type'], $query_vars['authors'] ) &&
'authors' === $query_vars['post_type'] &&
preg_match( '#^([^/]+)/([^/]+)$#', $query_vars['authors'] )
) {
$works_slug = explode( "https://wordpress.stackexchange.com/", $query_vars['authors'] )[1];
// Find "works" post with the above slug.
$ids = get_posts( array(
'post_type' => 'works',
'name' => $works_slug,
'fields' => 'ids',
) );
// If the post exists, then load it.
if ( ! empty( $ids ) ) {
$query_vars['post_type'] = 'works';
$query_vars['name'] = $query_vars['works'] = get_page_uri( $ids[0] );
unset( $query_vars['authors'] );
}
}
return $query_vars; // ALWAYS RETURN IT
}
Additionally, in the post_type_link
filter callback, I would:
-
Change the
'library/authors/' . $author . "https://wordpress.stackexchange.com/" . $post->post_name
to'library/authors/' . $author . "https://wordpress.stackexchange.com/" . ( $leavename ? '%postname%' : $post->post_name )
to ensure the post permalink (the slug part) is editable via the post editing screen (inwp-admin
). -
Change the
$author = basename(get_permalink($author_id));
to$author = $author_id ? get_post_field( 'post_name', $author_id ) : '';
.
Update
Sorry, I forgot about preview URLs (e.g. for posts with the status draft
or pending
) where the URL is not “pretty” and looks like https://example.com/?post_type=works&p=123&preview=true
.
So to ensure the URL returned is correct, in your my_website_filter_post_type_link()
function, add this at the very top:
if ( $sample || wp_force_plain_post_permalink( $post ) ) {
return $post_link;
}
I.e. Add it above the line having the switch( $post->post_type )
.
Also (to other readers), if your works
post type is not hierarchical, replace the get_page_uri( $ids[0] )
with $works_slug
.