Yoast Title in custom post archive-posttype.php is blank when add more query string
- [x ] I've read and understood the contribution guidelines.
- [x ] I've searched for any related issues and avoided creating a duplicate issue.
Please give us a description of what happened.
I have
- archive page: archive-movies.php (post type
movies) - custom taxonomy: country
When i query in archive-movies.php with url like:
website.com/movies
or
website.com/movies?a=b (with a is not a query_var)
The title replacement work fine like: Movies Archive - Site title
But when i add more query such as:
website.com/movies?country=us (country is my custom taxonomy )
The title just return Movies - Site title (not match SEO title replacement)
I tried to update SEO title replacement but it was not effected ( follow this post ).
I tried add filter:
add_filter( 'wpseo_title', 'add_to_page_titles');
add_filter( 'wpseo_opengraph_title', 'add_to_page_titles' );
function add_to_page_titles( $title ) {
var_dump($title); die();
}
But just show empty string.
Please describe what you expected to happen and why.
My target the title should be Movies Archive US - Site title.
How can we reproduce this behavior?
- Install empty latest Wordpress with theme Twenty Twenty - Version 1.5, setup site permalinks as
Post name|https://my-web.com/sample-post/ - Add custom post type and custom taxonomy
function wporg_custom_post_type() {
register_post_type('book',
array(
'labels' => array(
'name' => __('Books', 'textdomain'),
'singular_name' => __('Book', 'textdomain'),
),
'public' => true,
'has_archive' => true,
)
);
}
add_action('init', 'wporg_custom_post_type');
/**
* Create two taxonomies, genres and writers for the post type "book".
*
* @see register_post_type() for registering custom post types.
*/
function wpdocs_create_book_taxonomies() {
// Add new taxonomy, make it hierarchical (like categories)
$labels = array(
'name' => _x( 'Genres', 'taxonomy general name', 'textdomain' ),
'singular_name' => _x( 'Genre', 'taxonomy singular name', 'textdomain' ),
'search_items' => __( 'Search Genres', 'textdomain' ),
'all_items' => __( 'All Genres', 'textdomain' ),
'parent_item' => __( 'Parent Genre', 'textdomain' ),
'parent_item_colon' => __( 'Parent Genre:', 'textdomain' ),
'edit_item' => __( 'Edit Genre', 'textdomain' ),
'update_item' => __( 'Update Genre', 'textdomain' ),
'add_new_item' => __( 'Add New Genre', 'textdomain' ),
'new_item_name' => __( 'New Genre Name', 'textdomain' ),
'menu_name' => __( 'Genre', 'textdomain' ),
);
$args = array(
'hierarchical' => true,
'labels' => $labels,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'genre' ),
);
register_taxonomy( 'genre', array( 'book' ), $args );
unset( $args );
unset( $labels );
// Add new taxonomy, NOT hierarchical (like tags)
$labels = array(
'name' => _x( 'Writers', 'taxonomy general name', 'textdomain' ),
'singular_name' => _x( 'Writer', 'taxonomy singular name', 'textdomain' ),
'search_items' => __( 'Search Writers', 'textdomain' ),
'popular_items' => __( 'Popular Writers', 'textdomain' ),
'all_items' => __( 'All Writers', 'textdomain' ),
'parent_item' => null,
'parent_item_colon' => null,
'edit_item' => __( 'Edit Writer', 'textdomain' ),
'update_item' => __( 'Update Writer', 'textdomain' ),
'add_new_item' => __( 'Add New Writer', 'textdomain' ),
'new_item_name' => __( 'New Writer Name', 'textdomain' ),
'separate_items_with_commas' => __( 'Separate writers with commas', 'textdomain' ),
'add_or_remove_items' => __( 'Add or remove writers', 'textdomain' ),
'choose_from_most_used' => __( 'Choose from the most used writers', 'textdomain' ),
'not_found' => __( 'No writers found.', 'textdomain' ),
'menu_name' => __( 'Writers', 'textdomain' ),
);
$args = array(
'hierarchical' => false,
'labels' => $labels,
'show_ui' => true,
'show_admin_column' => true,
'update_count_callback' => '_update_post_term_count',
'query_var' => true,
'rewrite' => array( 'slug' => 'writer' ),
);
register_taxonomy( 'writer', 'book', $args );
}
// hook into the init action and call create_book_taxonomies when it fires
add_action( 'init', 'wpdocs_create_book_taxonomies', 0 );
- Add new archive-book.php file
<?php
/**
* The template for displaying archive pages
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
*
* @package WordPress
* @subpackage Twenty_Seventeen
* @since Twenty Seventeen 1.0
* @version 1.0
*/
get_header(); ?>
<div class="wrap">
<?php if ( have_posts() ) : ?>
<header class="page-header">
<?php
the_archive_title( '<h1 class="page-title">', '</h1>' );
the_archive_description( '<div class="taxonomy-description">', '</div>' );
?>
</header><!-- .page-header -->
<?php endif; ?>
<div id="primary" class="content-area">
<main id="main" class="site-main" role="main">
<?php
if ( have_posts() ) :
?>
<?php
// Start the Loop.
while ( have_posts() ) :
the_post();
/*
* Include the Post-Format-specific template for the content.
* If you want to override this in a child theme, then include a file
* called content-___.php (where ___ is the Post Format name) and that
* will be used instead.
*/
get_template_part( 'template-parts/post/content', get_post_format() );
endwhile;
the_posts_pagination(
array(
'prev_text' => __( 'Previous page', 'twentyseventeen' ),
'next_text' => __( 'Next page', 'twentyseventeen' ),
'before_page_number' => '<span class="meta-nav screen-reader-text">' . __( 'Page', 'twentyseventeen' ) . ' </span>',
)
);
else :
get_template_part( 'template-parts/post/content', 'none' );
endif;
?>
</main><!-- #main -->
</div><!-- #primary -->
<?php get_sidebar(); ?>
</div><!-- .wrap -->
<?php
get_footer();
- Install Yoast plugin
- Run first time wizard
- Add new post with post type is
book, add genreaction - Check Yoast Search apprearance for Book archive:
%%pt_plural%% Archive %%page%% %%sep%% %%sitename%% - Navigate to url
https://my-web.com/book/--> Site title show correct.Books Archive - Site Name - Navigate to url
https://my-web.com/book/?genre=action--> Site title show incorrect.Books - Site Nameinstead ofBooks Archive - Site Name
Technical info
Yoast SEO with up to date wordpress 5.5.3
- If relevant, which editor is affected (or editors):
- [ ] Classic Editor
- [ ] Gutenberg
- [ ] Classic Editor plugin
- Which browser is affected (or browsers):
- [x] Chrome
- [ ] Firefox
- [ ] Safari
- [ ] Other
Used versions
- WordPress version: 5.5.3
- Yoast SEO version: 15.3
- Gutenberg plugin version:
- Classic Editor plugin version:
- Relevant plugins in case of a bug:
- Tested with theme: Twenty Twenty - Version 1.5
@nguyentuandat can you share the necessary code / reproduction steps to reproduce your issue from an empty WordPress installation? The current information is not sufficient enough to work with.
@nguyentuandat can you share the necessary code / reproduction steps to reproduce your issue from an empty WordPress installation? The current information is not sufficient enough to work with.
Thank @Djennez I just update reproduction steps and code.
Hmmm, I can reproduce the issue, with our Test helper plugin as well.
It looks like adding this argument is making our plugin use the indexable data of the taxonomy that is requested in the argument. So book/?genre=action will make the code think it should return indexable data of the page of the action genre (url/book-genre/action). However, it does then not seem to use the title of that indexable...
Thank you! Are you have any temporary solution for this issue @Djennez ?
A bit of extra investigation;
This goes wrong on
$title = $this->options->get_title_default( 'title-ptarchive-' . $post_type );
because the indexables think we're on both a posttype archive as well as a taxonomy archive. So it tries to get the default title of title-ptarchive-<taxonomy_name> which does not exist.
The reason the indexables get confused here is because when building the indexable for the current page, we rely on WPQuery, and it looks like WPQuery is doing a query for both the posttype as well as the taxonomy. We have 2 functions where this goes wrong:
public function for_current_page() {
$indexable = false;
switch ( true ) {
case $this->current_page->is_simple_page():
$indexable = $this->find_by_id_and_type( $this->current_page->get_simple_page_id(), 'post' );
break;
case $this->current_page->is_home_static_page():
$indexable = $this->find_by_id_and_type( $this->current_page->get_front_page_id(), 'post' );
break;
case $this->current_page->is_home_posts_page():
$indexable = $this->find_for_home_page();
break;
case $this->current_page->is_term_archive():
$indexable = $this->find_by_id_and_type( $this->current_page->get_term_id(), 'term' );
break;
case $this->current_page->is_date_archive():
$indexable = $this->find_for_date_archive();
break;
case $this->current_page->is_search_result():
$indexable = $this->find_for_system_page( 'search-result' );
break;
case $this->current_page->is_post_type_archive():
$indexable = $this->find_for_post_type_archive( $this->current_page->get_queried_post_type() );
break;
case $this->current_page->is_author_archive():
$indexable = $this->find_by_id_and_type( $this->current_page->get_author_id(), 'user' );
break;
case $this->current_page->is_404():
$indexable = $this->find_for_system_page( '404' );
break;
}
hits is_term_archive() first, which matches and so it returns term archive data. However:
public function get_page_type() {
switch ( true ) {
case $this->is_search_result():
return 'Search_Result_Page';
case $this->is_static_posts_page():
return 'Static_Posts_Page';
case $this->is_home_static_page():
return 'Static_Home_Page';
case $this->is_home_posts_page():
return 'Home_Page';
case $this->is_simple_page():
return 'Post_Type';
case $this->is_post_type_archive():
return 'Post_Type_Archive';
case $this->is_term_archive():
return 'Term_Archive';
case $this->is_author_archive():
return 'Author_Archive';
case $this->is_date_archive():
return 'Date_Archive';
case $this->is_404():
return 'Error_Page';
}
hits is_post_type_archive() first, which matches, so it returns data for a posttype archive. In both cases, when switching the order of the cases, it will hit the one which matches first.
Code that combines these results, like the line at the top of my post, will try to combine these results.
I don't feel like matching the order is the solution here. The code should likely account for WPQueries that return 2 types of results, and determine which one to use.
I don't feel like matching the order is the solution here.
I agree it wouldn't be the cleanest solution, but would fix the immediate problem in this case by picking one of the options. Also the behaviour would be somewhat defined and explainable, as opposed to 'random'. Or make it filterable which one to prefer.
The code should likely account for WPQueries that return 2 types of results, and determine which one to use.
I expect it would be hard to create a good UX for this. Either it would have to be determined by Yoast which to pick (which would be the same as above). Or the user would be able to pick for each combination of post-types and terms which SEO title to use. This second solution would get complicated really fast.
Along the lines of Niels' first suggestion: it would help if Yoast picks one of the two options (say "post type archive") as a default and makes the behavior (checking order) customizable via a filter.
Hi, I have same proble when I am improving a WordPress site now.
I tried adding taxonomy template for taxonomy that only use with certain custom type, but YoastSEO evaluate is_post_type_archive() in taxonomy template.
So, title tag is empty at display taxonomy archive and input title tag for each term at term edit page.
According to WordPress template hierarchy and rewrite rule, http://examlpe.com/some-post-type/some-term/ call archive-some_post_type.php.
But often I want to let WordPress display taxonomy archive at http://examlpe.com/some-post-type/some-term/.
For now, change query string (instead of taxonomy name) is a simple solution for me. :D
I've noticed this behaviour, while having a custom permalink structure for a cpt which is
/insights -> CPT archive
/insights/tag/EU -> CPT archive for term EU
And I wanted each tag to have it's own meta data.
I've come up with the following workaround:
<?php
use Yoast\WP\SEO\Helpers\Current_Page_Helper;
/**
* Fixes Current_Page_Helper
* because Current_Page_helper::get_page_type checks for post type archive BEFORE checking for term_archive
* But Indexable_Repository checks in reverse. And we want the way Indexable_Repository does it
* Because term_archive is more specific and should be handled first.
*
* See https://github.com/Yoast/wordpress-seo/issues/16436
*/
class Custom_Current_Page_Helper extends Current_Page_Helper {
public function get_page_type() {
switch ( true ) {
case $this->is_term_archive():
return 'Term_Archive';
case $this->is_post_type_archive():
return 'Post_Type_Archive';
}
return parent::get_page_type();
}
}
add_filter('wpseo_frontend_presentation',function(Indexable_Presentation $presentation, Meta_Tags_Context $context) {
if(is_tax(TAG_TAXONOMY) && !$presentation instanceof Indexable_Term_Archive_Presentation) {
$tag = getQueriedTag(); // custom helper method.
if($tag) {
$indexableRepository = YoastSEO()->classes->get( Indexable_Repository::class );
$indexable = $indexableRepository->find_by_id_and_type( $tag->term_id, 'term' );
$metaTagsContextMemoizer = YoastSEO()->classes->get( Meta_Tags_Context_Memoizer::class );
$tagMetaContext = $metaTagsContextMemoizer->get($indexable, 'Term_Archive');
$presentation = $tagMetaContext->presentation;
}
}
return $presentation;
}, 10, 2);
add_action('plugins_loaded', function() {
if(!function_exists('YoastSEO')) {
return;
}
$yoast = YoastSEO();
require_once __DIR__ . '/classes/Custom_Current_Page_Helper.php';
$yoast->classes->container->set(Current_Page_Helper::class, new Custom_Current_Page_Helper(new WP_Query_Wrapper()));
}, 15); // wp_seo_init runs on 14
This is a little bit hacky, I might have to further test and refine it, but maybe it helps someone :)