Context: WordPress 5.4.5, Yoast 3.7.1
I'm a plugin developer who has access to the client's site. The site has Yoast 3.7.1 installed and I'm wondering if that is significant because no matter what I do I can't change the 404 page's title.
Now on other pages on StackOverflow where similar questions have been posed (here, here and here for example), those answering have asked if the header.php is correctly embedding a call to wp_title(). Here's what's in the current theme's header.php at that point:
<title><?php wp_title( '|', true, 'right' ); ?></title>
Interestingly, in my 404.php page, wp_get_document_title() tells me that the document title is Page not found - XXXX even though the wp_title call above specifies the separator as |. Yoast's rewriting of titles has been disabled so I'm not at all sure where that dash is coming from.
My plugin does a REST call and pulls in content from off-site for inclusion in the page. Part of that content is the text to be used in the title.
On previous client sites, I've been able to do the following:
add_filter('wp_title', 'change_404_title');
function change_404_title($title) {
if (is_404())
{
global $plugin_title;
if (!empty($plugin_title))
{
$title = $plugin_title;
}
}
return $title;
}
However, on this site, that's not working.
I have tried, based on the version of WordPress being used, hooking the pre_get_document_title filter, viz
add_filter('pre_get_document_title', 'change_404_title');
but again to no avail. I am currently reading up on Yoast ...
wp_title deprecated since version 4.4. So we should use the new filter pre_get_document_title. Your code looks fine but I am confused about global $plugin_title. I would rather ask you to Try this first
add_filter('pre_get_document_title', 'change_404_title');
function change_404_title($title) {
if (is_404()) {
return 'My Custom Title';
}
return $title;
}
If it doesn't work then try changing the priority to execute your function lately.
add_filter('pre_get_document_title', 'change_404_title', 50);
How document title is generated has changed since Wordpress v4.4.0. Now wp_get_document_title dictates how title is generated:
/**
* Displays title tag with content.
*
* #ignore
* #since 4.1.0
* #since 4.4.0 Improved title output replaced `wp_title()`.
* #access private
*/
function _wp_render_title_tag() {
if ( ! current_theme_supports( 'title-tag' ) ) {
return;
}
echo '<title>' . wp_get_document_title() . '</title>' . "\n";
}
Here is the code from v5.4.2. These are the filters you can use to manipulate title tag:
function wp_get_document_title() {
/**
* Filters the document title before it is generated.
*
* Passing a non-empty value will short-circuit wp_get_document_title(),
* returning that value instead.
*
* #since 4.4.0
*
* #param string $title The document title. Default empty string.
*/
$title = apply_filters( 'pre_get_document_title', '' );
if ( ! empty( $title ) ) {
return $title;
}
// --- snipped ---
/**
* Filters the separator for the document title.
*
* #since 4.4.0
*
* #param string $sep Document title separator. Default '-'.
*/
$sep = apply_filters( 'document_title_separator', '-' );
/**
* Filters the parts of the document title.
*
* #since 4.4.0
*
* #param array $title {
* The document title parts.
*
* #type string $title Title of the viewed page.
* #type string $page Optional. Page number if paginated.
* #type string $tagline Optional. Site description when on home page.
* #type string $site Optional. Site title when not on home page.
* }
*/
$title = apply_filters( 'document_title_parts', $title );
// --- snipped ---
return $title;
}
So here are two ways you can do it.
First one uses pre_get_document_title filter which short-circuits the title generation and hence more performant if you are not going make changes on current title:
function custom_document_title( $title ) {
return 'Here is the new title';
}
add_filter( 'pre_get_document_title', 'custom_document_title', 10 );
Second way uses document_title_separator and document_title_parts hooks for the title and the title seperator that are executed later in the function, after title is generated using functions like single_term_title or post_type_archive_title depending on the page, and just before the title tags is about to be outputted:
// Custom function should return a string
function custom_seperator( $sep ) {
return '>';
}
add_filter( 'document_title_separator', 'custom_seperator', 10 );
// Custom function should return an array
function custom_html_title( $title ) {
return array(
'title' => 'Custom Title',
'site' => 'Custom Site'
);
}
add_filter( 'document_title_parts', 'custom_html_title', 10 );
Add this to your functions.php
function custom_wp_title($title) {
if ( is_404() ) {
$title = 'Custom 404 Title';
}
return $title;
}
add_filter( 'wp_title', 'custom_wp_title', 10, 2 );
10 - is priority change to overwrite other plugins like SEO
Related
I am trying to overwrite the <title> tag of a page using a Wordpress plugin.
I don't want to change the theme's code. I just wanna force the theme to change some page titles via the plugin.
The theme uses add_theme_support( 'title-tag' ). Note that the use of wp_title is now deprecated.
Your problem is that you can not use wp_title() in the theme if the theme already supports title-tag. The <head> of your theme should look like this:
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<?php wp_head(); ?>
</head>
The filter and title-tag support:
add_action( 'after_setup_theme', 'my_theme_functions' );
function my_theme_functions() {
add_theme_support( 'title-tag' );
}
add_filter( 'wp_title', 'custom_titles', 10, 2 );
function custom_titles( $title, $sep ) {
//set custom title here
$title = "Some other title" . $title;;
return $title;
}
If you do this, it will work perfectly.
I posted this answer for another question but since it is relevant and more up-to-date, I though it might be useful for some people.
How document title is generated has changed since Wordpress v4.4.0. Now wp_get_document_title dictates how title is generated:
/**
* Displays title tag with content.
*
* #ignore
* #since 4.1.0
* #since 4.4.0 Improved title output replaced `wp_title()`.
* #access private
*/
function _wp_render_title_tag() {
if ( ! current_theme_supports( 'title-tag' ) ) {
return;
}
echo '<title>' . wp_get_document_title() . '</title>' . "\n";
}
Here is the code from v5.4.2. Here are the filters you can use to manipulate title tag:
function wp_get_document_title() {
/**
* Filters the document title before it is generated.
*
* Passing a non-empty value will short-circuit wp_get_document_title(),
* returning that value instead.
*
* #since 4.4.0
*
* #param string $title The document title. Default empty string.
*/
$title = apply_filters( 'pre_get_document_title', '' );
if ( ! empty( $title ) ) {
return $title;
}
// --- snipped ---
/**
* Filters the separator for the document title.
*
* #since 4.4.0
*
* #param string $sep Document title separator. Default '-'.
*/
$sep = apply_filters( 'document_title_separator', '-' );
/**
* Filters the parts of the document title.
*
* #since 4.4.0
*
* #param array $title {
* The document title parts.
*
* #type string $title Title of the viewed page.
* #type string $page Optional. Page number if paginated.
* #type string $tagline Optional. Site description when on home page.
* #type string $site Optional. Site title when not on home page.
* }
*/
$title = apply_filters( 'document_title_parts', $title );
// --- snipped ---
return $title;
}
So here are two ways you can do it.
First one uses pre_get_document_title filter which short-circuits the title generation and hence more performant if you are not going make changes on current title:
function custom_document_title( $title ) {
return 'Here is the new title';
}
add_filter( 'pre_get_document_title', 'custom_document_title', 10 );
Second way uses document_title_separator and document_title_parts hooks for the title and the title seperator that are executed later in the function, after title is generated using functions like single_term_title or post_type_archive_title depending on the page and about to be outputted:
// Custom function should return a string
function custom_seperator( $sep ) {
return '>';
}
add_filter( 'document_title_separator', 'custom_seperator', 10 );
// Custom function should return an array
function custom_html_title( $title ) {
return array(
'title' => 'Custom Title',
'site' => 'Custom Site'
);
}
add_filter( 'document_title_parts', 'custom_html_title', 10 );
Sorry if my question was basic or stupid but please help me to solve this issue. I'm trying to change <title> and <meta name="description" > tags dynamically in wordpress. so this is what I tried in function.php file.
function changeMeta_2(){
global $wpdb;
$cur_url = $_SERVER['REQUEST_URI'];
$basename = pathinfo($cur_url);
$ebasename = $basename['filename'];
if(is_numeric($ebasename)) {
$url = explode('/', $basename['dirname']);
$basename = explode('.', $url[count($url)-2]);
$ebasename = $basename[0];
}
$pageName = $ebasename;
$arraylist_subcat = array("car","bike","boat","xxxx","yyyy","zzz","mmmm");
$arraylist_maincat = array("aus","ind","usa","uae");
$category_id = get_term_by('slug',$pageName, 'category');
$category_parentid = get_term_by('id', $category_id->parent, 'category');
$parent_slug = $category_parentid->slug;
if ( is_page()) {
if ( in_array($pageName,$arraylist_maincat) ) {
$metaTitle = 'Browse '.$pageName.' | Some txt title | mysite.com';
$metaDescription = 'some of custome blablaaaaa text description '.$pageName.' some of custome blablaaaaa text description ';
echo '<title>'.$metaTitle.'</title>';
echo '<meta name="description" content="'.$metaDescription.'"/>';
}
}
}
add_action( 'wp_head', 'changeMeta_2' );
In the above code I'm trying to change the title tag and meta description for term id which are matching with array values (in_array condition).
Everything works fine, but problem is instead of override(replace) <title> tag is appending in head. Its not changing it appending. please someone help me to solve this issue.
How document title is generated has changed since Wordpress v4.4.0. Now wp_get_document_title dictates how title is generated:
/**
* Displays title tag with content.
*
* #ignore
* #since 4.1.0
* #since 4.4.0 Improved title output replaced `wp_title()`.
* #access private
*/
function _wp_render_title_tag() {
if ( ! current_theme_supports( 'title-tag' ) ) {
return;
}
echo '<title>' . wp_get_document_title() . '</title>' . "\n";
}
Here is the code from v5.4.2. Here are the filters you can use to manipulate title tag:
function wp_get_document_title() {
/**
* Filters the document title before it is generated.
*
* Passing a non-empty value will short-circuit wp_get_document_title(),
* returning that value instead.
*
* #since 4.4.0
*
* #param string $title The document title. Default empty string.
*/
$title = apply_filters( 'pre_get_document_title', '' );
if ( ! empty( $title ) ) {
return $title;
}
// --- snipped ---
/**
* Filters the separator for the document title.
*
* #since 4.4.0
*
* #param string $sep Document title separator. Default '-'.
*/
$sep = apply_filters( 'document_title_separator', '-' );
/**
* Filters the parts of the document title.
*
* #since 4.4.0
*
* #param array $title {
* The document title parts.
*
* #type string $title Title of the viewed page.
* #type string $page Optional. Page number if paginated.
* #type string $tagline Optional. Site description when on home page.
* #type string $site Optional. Site title when not on home page.
* }
*/
$title = apply_filters( 'document_title_parts', $title );
// --- snipped ---
return $title;
}
So here are two ways you can do it.
First one uses pre_get_document_title filter which short-circuits the title generation and hence more performant if you are not going make changes on current title:
function custom_document_title( $title ) {
return 'Here is the new title';
}
add_filter( 'pre_get_document_title', 'custom_document_title', 10 );
Second way uses document_title_separator and document_title_parts hooks for the title and the title seperator that are executed later in the function, after title is generated using functions like single_term_title or post_type_archive_title depending on the page and about to be outputted:
// Custom function should return a string
function custom_seperator( $sep ) {
return '>';
}
add_filter( 'document_title_separator', 'custom_seperator', 10 );
// Custom function should return an array
function custom_html_title( $title ) {
return array(
'title' => 'Custom Title',
'site' => 'Custom Site'
);
}
add_filter( 'document_title_parts', 'custom_html_title', 10 );
For anybody coming to this question in the future: This functionality can be accomplished using the Yoast SEO plugin.
However, if you do want to still do this yourself....
In order to modify the title, rather than the wp_head hook, you need to be using the filters that actually allow you to modify the title: wp_title
And you can / should use the wp_head in order to add the meta description (see the docs here: http://codex.wordpress.org/Meta_Tags_in_WordPress)
Also note there's easier ways to get the page title, mentioned below...
For the title, your code would look something like so:
function changeTitle($title, $sep, $seplocation){
global $wpdb;
// NOTE: This is the HARD way to get the page title, and is unreliable...
$cur_url = $_SERVER['REQUEST_URI'];
$basename = pathinfo($cur_url);
$ebasename = $basename['filename'];
if(is_numeric($ebasename)) {
$url = explode('/', $basename['dirname']);
$basename = explode('.', $url[count($url)-2]);
$ebasename = $basename[0];
}
$pageName = $ebasename;
// NOTE: Why not get pagename this way?
global $post;
$pageName = $post->post_title;
// or if you need the slug...
$pageName = $post->post_slug;
$arraylist_subcat = array("car","bike","boat","xxxx","yyyy","zzz","mmmm");
$arraylist_maincat = array("aus","ind","usa","uae");
$category_id = get_term_by('slug',$pageName, 'category');
$category_parentid = get_term_by('id', $category_id->parent, 'category');
$parent_slug = $category_parentid->slug;
if ( is_page()) {
if ( in_array($pageName,$arraylist_maincat) ) {
$title = 'Browse '.$pageName.' | Some txt title | mysite.com';
}
}
return $title;
}
add_action( 'wp_title', 'changeTitle', 10, 3 );
What is the difference between filter and hooks in wordpress.
How can i use the following filter in child theme ?
<?php
foreach ( $results as $result ) {
// external plugins can modify or disable field
$result = apply_filters( 'cp_package_field', $result, 'ad' );
if ( ! $result )
continue;
?>
how can i use the following hook in child theme ?
/**
* called in cp_add_new_listing() to hook into inserting new ad process
*
* #since 3.2.1
* #param int $post_id
*
*/
function cp_action_add_new_listing( $post_id ) {
do_action( 'cp_action_add_new_listing', $post_id );
}
For the first part of your question, here is a link to an explanation I found a while back that was pretty comprehensive and it helped me to understand the difference.
https://wordpress.stackexchange.com/questions/1007/difference-between-filter-and-action-hooks
To use the hook in your child theme, you'd probably need to have the following piece of code in your child theme's functions.php file:
/**
* Our callback function to the hook
* #param int $post_id id of the post
* #return void
*/
function my_child_theme_new_listing_cb( $post_id ) {
if($post_id == 10) { //Or whatever you want
echo 'Hello World';
}
//We do not have the responsibility to return something as it is a hook
}
add_action( 'cp_action_add_new_listing', 'my_child_theme_new_listing_cb', 10, 1 );
Hope it helps.
The function:
/**
* Retrieve post title.
*
* If the post is protected and the visitor is not an admin, then "Protected"
* will be displayed before the post title. If the post is private, then
* "Private" will be located before the post title.
*
* #since 0.71
*
* #param int $id Optional. Post ID.
* #return string
*/
function get_the_title( $id = 0 ) {
$post = &get_post($id);
$title = isset($post->post_title) ? $post->post_title : '';
$id = isset($post->ID) ? $post->ID : (int) $id;
if ( !is_admin() ) {
if ( !empty($post->post_password) ) {
$protected_title_format = apply_filters('protected_title_format', __('Protected: %s'));
$title = sprintf($protected_title_format, $title);
} else if ( isset($post->post_status) && 'private' == $post->post_status ) {
$private_title_format = apply_filters('private_title_format', __('Private: %s'));
$title = sprintf($private_title_format, $title);
}
}
return apply_filters( 'the_title', $title, $id );
}
I don't understand what the parameter __('Protected: %s') means in a particular line of code below. What kind of parameter is it?
$protected_title_format = apply_filters('protected_title_format', __('Protected: %s'));
__() is a localization function which is used to get the localized string of the English word "Protected".
%s is a replacement parameter that is used by sprintf(). Basically, it replaces that with the title of a blog post.
The entire __('Protected: %s') call is passed as a parameter to the apply_filters() function to simply format the post title. By default I don't think anything happens, but plugins may hook on the protected_title_format filter to further manipulate the format before applying the post title on it.
I have some setup code in my functions.php file that sets permalinks and adds categories that are used by the theme. I only want this code to run when the theme is first activated. There is no need for the code to run again. However, by placing it in the functions.php file, it runs each and every time a page on the website is loaded.
Is there an alternative method to use so that this code only runs when the custom theme is first activated?
In wp-includes/theme.php you’ll find the function switch_theme(). It offers an action hook:
/**
* Switches current theme to new template and stylesheet names.
*
* #since unknown
* #uses do_action() Calls 'switch_theme' action on updated theme display name.
*
* #param string $template Template name
* #param string $stylesheet Stylesheet name.
*/
function switch_theme($template, $stylesheet) {
update_option('template', $template);
update_option('stylesheet', $stylesheet);
delete_option('current_theme');
$theme = get_current_theme();
do_action('switch_theme', $theme);
}
So you may use this in your functions.php:
function my_activation_settings($theme)
{
if ( 'Your Theme Name' == $theme )
{
// do something
}
return;
}
add_action('switch_theme', 'my_activation_settings');
Just an idea; I haven’t tested it.
Another one to look at would be after_switch_theme it is also in wp-includes/theme.php
It seems to be a hook run in check_theme_switched
/**
* Checks if a theme has been changed and runs 'after_switch_theme' hook on the next WP load
*
* #since 3.3.0
*/
function check_theme_switched() {
if ( $stylesheet = get_option( 'theme_switched' ) ) {
$old_theme = wp_get_theme( $stylesheet );
// Prevent retrieve_widgets() from running since Customizer already called it up front
if ( get_option( 'theme_switched_via_customizer' ) ) {
remove_action( 'after_switch_theme', '_wp_sidebars_changed' );
update_option( 'theme_switched_via_customizer', false );
}
if ( $old_theme->exists() ) {
/**
* Fires on the first WP load after a theme switch if the old theme still exists.
*
* This action fires multiple times and the parameters differs
* according to the context, if the old theme exists or not.
* If the old theme is missing, the parameter will be the slug
* of the old theme.
*
* #since 3.3.0
*
* #param string $old_name Old theme name.
* #param WP_Theme $old_theme WP_Theme instance of the old theme.
*/
do_action( 'after_switch_theme', $old_theme->get( 'Name' ), $old_theme );
} else {
/** This action is documented in wp-includes/theme.php */
do_action( 'after_switch_theme', $stylesheet );
}
flush_rewrite_rules();
update_option( 'theme_switched', false );
}
}`
add_action('after_switch_theme', 'my_activation_settings');
I think both ways work just something else to look into :)