How to replace meta title and meta description in wordpress? - php

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 );

Related

Use object values passed into another function with apply_filter

First of all what I'm trying to do is have an html tag inserted that I can then target with css.
Here's the current html that I have to work with:
<p>
Rebecca DeAcetis
posted an update in the group
Creating a Dynasty™ November 2020
<a href="https://account.danijohnson.com/activity/p/6965/" class="view activity-time-since">.
<span class="time-since">2 days ago</span>
</a>
</p>
What I would like is to have " posted an update in the group " wrapped with <span class="activity-action"></span>
The plugin function that is creating the html is:
/**
* Format groups 'activity_update' activity actions.
*
* #since BuddyBoss 1.1.9
*
* #param string $action Static activity action.
* #param object $activity Activity data object.
* #return string
*/
function bp_groups_format_activity_action_activity_update( $action, $activity ) {
$user_link = bp_core_get_userlink( $activity->user_id );
$group = groups_get_group( $activity->item_id );
$group_link = '' . esc_html( $group->name ) . '';
$action = sprintf( __( '%1$s posted an update in the group %2$s', 'buddyboss' ), $user_link, $group_link );
/**
* Filters the groups 'activity_update' activity actions.
*
* #since BuddyBoss 1.1.9
*
* #param string $action The groups 'activity_update' activity actions.
* #param object $activity Activity data object.
*/
return apply_filters( 'bp_groups_format_activity_action_activity_update', $action, $activity );
}
I've tried adding this to my theme functions.php:
function add_span_to_timeline_action($action) {
$action = sprintf( '%1$s<span class="activtiy-action"> posted in the group %2$s</span>', $user_link, $group_link );
return $action;
}
add_filter('bp_groups_format_activity_action_activity_update','add_span_to_timeline_action');
It does update the html and add the <span> tags but the <a> elements don't work because the $user_link and $group_link variables are not defined in my function.
I can't figure out how to make the $activity object available inside my function to that I can define the link variables.
I know accomplish the css I want with javascript/jquery but I'd like not rely on that because the activity loads on the page and updates with ajax so I'd have to have a setTimeout setInterval so that the activity has loaded which would result in the page updating after it's already loaded.
The original filter passes the $activity variable, so you have access to it too:
function add_span_to_timeline_action($action, $activity) {
$user_link = bp_core_get_userlink( $activity->user_id );
$group = groups_get_group( $activity->item_id );
$group_link = '' . esc_html( $group->name ) . '';
$action = sprintf( '%1$s<span class="activity-action"> posted in the group %2$s</span>', $user_link, $group_link );
return $action;
}
add_filter('bp_groups_format_activity_action_activity_update','add_span_to_timeline_action', 10, 2);
Just make sure you update the parameter count on the add_filter (10 - priority, 2 - argument count)

WooCommerce Blocks - Add short product description to product grid

So I'm using the new WooCommerce Blocks for the first time. On the homepage of my website I've included the "ProductBestSellers" block and the "ProductOnSale" block. Both of these blocks show a grid styled layout for either best selling products or products on sale.
For the design I needed I had to add some wrappers to the html and therefore I cloned the repository from here; WooCommerce Gutenberg Blocks
The added html does work but now I need to include the product short description within these blocks. I've eddit the AbstractProductGrid.php as follows;
AbstractProductGrid.php
/**
* Render a single products.
* Edited: 24/02/2020
*
* Added wrappers to display content with padding borders and other styling
*
* #param int $id Product ID.
* #return string Rendered product output.
*/
public function render_product( $id ) {
$product = wc_get_product( $id );
if ( ! $product ) {
return '';
}
$data = (object) array(
'permalink' => esc_url( $product->get_permalink() ),
'description' => $this->get_description_html( $product ), <--- Add product short description
'image' => $this->get_image_html( $product ),
'title' => $this->get_title_html( $product ),
'rating' => $this->get_rating_html( $product ),
'price' => $this->get_price_html( $product ),
'badge' => $this->get_sale_badge_html( $product ),
'button' => $this->get_button_html( $product ),
);
return apply_filters(
'woocommerce_blocks_product_grid_item_html',
"<li class=\"wc-block-grid__product\">
<div class=\"wc-block-grid__product__wrapper\">
<div class=\"wc-block-grid__product__items\">
<a href=\"{$data->permalink}\" class=\"wc-block-grid__product-link\">
{$data->image}
{$data->title}
</a>
{$data->badge}
{$data->rating}
{$data->description}
<div class=\"wc-block-grid__product__price-wrapper\">
{$data->price}
{$data->button}
</div>
</div>
</div>
</li>",
$data,
$product
);
}
/**
* Get the product short description.
*
* #param \WC_Product $product Product.
* #return string
*/
protected function get_description_html( $product ) {
if ( empty( $this->attributes['contentVisibility']['description'] ) ) {
return '<p class="purple">The short description is empty</p>';
}
return '<div class="wc-block-grid__description">' . $product->get_short_description() ? $product->get_short_description() : wc_trim_string( $product->get_description(), 400 ) . '</div>';
}
The code above returns an empty attribute, how can I include the short description for the new WooCommerce Blocks?
I found this post when looking for an answer to this, I guess you might have solved it already but here is a suggested solution for anyone coming here.
First, It´s not recommended to change the core files of WooCommerce or the Blocks-plugin, since if you update the plugin your changes will be overwritten.
A better way is utilizing that the plugin is exposing a filter for the rendered output called "woocommerce_blocks_product_grid_item_html".
So if you put this in your functions.php you will get the short description after the product title:
/**
* Add short description to WooCommerce product blocks
*/
add_filter('woocommerce_blocks_product_grid_item_html', 'add_short_desc_woocommerce_blocks_product_grid_item_html', 10 , 3);
function add_short_desc_woocommerce_blocks_product_grid_item_html($content, $data, $product) {
$short_description = '<div class="wc-block-grid__product-short-description">' . $product->get_short_description() . '</div>';
// This will inject the short description after the first link (assumed: the default product link).
$after_link_pos = strpos($content, "</a>");
$before = substr($content, 0, $after_link_pos + 4);
$after = substr($content, $after_link_pos + 4);
$content = $before . $short_description . $after;
return $content;
}
This is very interesting, I tried it on my site, and it works - however my first is after the image, which also is a link.
So for me, the code from #Pierre, ended up outputtin:
Image
Description
Title
Anyone have any suggestions on how to make it output
Image
Title
Description
(Even when images are linked to the product page)
?

Overwrite title tag using a Wordpress plugin

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 );

How to change the title on a WordPress page?

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

Confusions about Wordpress get_the_title function

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.

Categories