Apply the_title filter to post titles AND backend auto social-sharing plugin, but not nav menu - wordpress

The Challenge
I have been trying to write a filter that applies (prepends a string) to (a) post titles of a certain post type and (b) to that same post type WordPress admin backend for use by an auto social sharing plugin.
I've gotten really close. I've achieved:
1. prepending only to custom post_type post titles
2. prepending to custom_post type titles AND all nav menu items
3. prepending to ALL titles (post, page, nav menu, and backend auto-sharing plugin)
The final, 3rd attempt got me very hopeful, but yet still, no matter the function, conditional statement, or combination I use, I can't get custom_post title AND backend social sharing plugin, but not nav menu items.
My Code - what I've tried
I've tried different conditionals, like is_admin() and !is_nav_menu with all nav menu IDs. I've also tried comparing the ID of the post to the ID of the menu. Finally, I've also tried adding the filter only to loop_start and that seems promising if combined with other statements. I will clean up my code for your review but I leave it this way for now in hopes it helps to see what I've tried and maybe where I went wrong with any of those methods.
// , $id = NULL
function append_album_review_to_title( $title ) {
global $post;
global $dont_apply_title_filter;
$text = 'Album Review: ';
$prepended_title = $text . $title;
/*
$nav_menus_obj = wp_get_nav_menus();
$nav_menu_ids = '';
foreach( $nav_menus_obj as $nav_menu ) {
$nav_menu_ids .= $nav_menu->term_id . ',';
}
rtrim($nav_menu_ids, ',');
*/
// if ( get_post_type( $post->ID ) == 'album_review' && in_the_loop() ){
// if ( get_post_type( $post->ID ) == 'album_review' && $id == get_the_ID() ){
// if ( !is_nav_menu( '32057,32058,35135,32054,32056' ) ) {
// if ( get_post_type( $post->ID ) == 'album_review' && is_nav_menu( $id ) ) {
if ( get_post_type( $post->ID ) == 'album_review' && !$dont_apply_title_filter ) {
//print_r( $nav_menu_ids );
//print_r( is_nav_menu( $nav_menu_ids ) );
return $prepended_title;
/*
} elseif ( get_post_type( $post->ID ) == 'album_review' ) {
return $title;
*/
} else {
return $title;
};
}
add_filter('the_title', 'append_album_review_to_title');
//add_action('save_post', 'custom_post_type_title', 100);
/*
function set_custom_title() {
add_filter( 'the_title', 'append_album_review_to_title', 10, 2 );
}
add_action( 'loop_start', 'set_custom_title' );
*/

Solution
function append_album_review_to_title( $title, $id = NULL ) {
if ($id) {
if ( get_post_type( $id ) == 'album_review' ){
return 'Album Review: ' . $title;
} else {
return $title;
}
} else {
return 'Album Review: ' . $title;
};
}
add_filter('the_title', 'append_album_review_to_title', 10, 2);
Explanation
First trying this:
function append_album_review_to_title( $title, $id ) {
if ( get_post_type( $id ) == 'album_review' ){
return 'Album Review: ' . $title;
} else {
return $title;
}
}
add_filter('the_title', 'append_album_review_to_title', 10, 2);
I noticed that on the backend, the social sharing plugin I am using to auto-share posts would return warnings like missing parameter 2 and Notice: Trying to get property of non-object..., and so it occurred to me that unlike the front end (nav menu and the loop), in the backend, apparently an $id is not being passed to the_title and so I can use this as a conditional.
Checking for $id will, for my purposes, tell me that if it is true, we are on front end, if it is false, then we are at backend post view.
This code accomplishes what I need (ie, modify post title in the loop, do NOT modify nav menu items, and modify the_title for use by a backend social sharing plugin):

Related

How to mark wordpress posts as read?

I want to make something similar to what Techcrunch have on their site. For now I use wordpress plugin that mark posts as new and think to modified it to achieve similar functionality but the plugin won't work for ajax loading.
What I want to make is when user open new post, automatically after he returns to the front page, title and excerpt of the post to be color faded. How to make this with setting cookie and make it to work for title and excerpt on any page (for post list, grids etc.), instead of single post page. And also I need this to work when new posts are loaded with ajax.
I tried this function and It's work ok, but now I need text label to change to Old after user open the post, and then to inject some css to the title. Also, this is not perfect, because I want all posts to be New on first visit, an then to change to Old after user open them.
function wpb_lastvisit_set_cookie() {
if ( ! is_admin() && ! isset( $_COOKIE['lastvisit'] ) ) {
setcookie( 'lastvisit', $current, time() + 3600 * 24 * 100, COOKIEPATH, COOKIE_DOMAIN, false );
}
}
add_action( 'init', 'wpb_lastvisit_set_cookie');
function wpb_lastvisit_the_title ( $title, $id ) {
if ( !in_the_loop() || is_singular() || get_post_type( $id ) == 'page' ) return $title;
// if no cookie then just return the title
if ( !isset($_COOKIE['lastvisit']) || $_COOKIE['lastvisit'] == '' ) return $title;
$lastvisit = $_COOKIE['lastvisit'];
$publish_date = get_post_time( 'U', true, $id );
if ($publish_date > $lastvisit) $title .= ' New';
if ($publish_date < $lastvisit) $title .= ' Old';
return $title;
}
add_filter( 'the_title', 'wpb_lastvisit_the_title', 10, 2);

Remove Yoast Breadcrumb Last Item On Single Pages Only

i got this code from researching and trying to modify it but no luck. I want the last item in yoast breamcrumbs not to appear on single pages only
if ( is_single() ) {
/*Remove Last item in Yoast SEO Breadcrumb */
function adjust_single_breadcrumb( $link_output) {
if(strpos( $link_output, 'breadcrumb_last' ) !== false ) {
$link_output = '';
}
return $link_output;
}
add_filter('wpseo_breadcrumb_single_link', 'adjust_single_breadcrumb' );
};
I tried adding if is single in between the function and also this
if(strpos( $link_output, 'breadcrumb_last' ) !== false && is_single) {
unfortunately, the whole breadcrumb disappears.
with this code, you can remove post title in single page.
add_filter('wpseo_breadcrumb_single_link_info', 'remove_post_title_wpseo_breadcrumb', 10, 3);
function remove_post_title_wpseo_breadcrumb($link_info, $index, $crumbs)
{
if (is_singular() && isset($link_info['id']))
return [];
return $link_info;
}
Updated: In the latest version above code does not work perfectly.
for this reason, I removed the last item with regex:
function getBreadcrumb() {
if ( function_exists( 'yoast_breadcrumb' ) ) {
ob_start();
yoast_breadcrumb( '<p id="breadcrumb" class="meta-info">', '</p>' );
$breadcrumb = trim( ob_get_clean() );
if ( is_singular() )
$breadcrumb = trim( preg_replace( '/ ' . WPSEO_Options::get( 'breadcrumbs-sep' ) . ' <span class="breadcrumb_last" aria-current="page">(.*)<\/span>/i', '',
$breadcrumb ) );
echo $breadcrumb;
}
}
And call the function anywhere you want:
<?php getBreadcrumb() ?>

How-to get a menu label via $post-> or $page->ID

Entirely Revised Please Reread
Hello,
The theme I am using displays the page's title as opposed to it's menu label in the breadcrumbs. I am trying to get the breadcrumbs to instead display the associated menu label if it is available and if not then default to the page_title.
I have come up with some code that I think is close. Line 4/// $menu_items = wp_get_nav_menu_items( $slug ); returns null and it should return the nav item that contains $slug of the current post. Obviously, there is something I do not understand.
What I am attempting to do is get the slug of the current post, then using the slug get the nav item post. Then extract the title of the nav item and use that in place of the page title in the breadcrumbs. If the page was not in the nav system then it should default to the page title, as might be the case for a ppc campaign landing page.
if ( is_page() && !$post->post_parent ) {
$title = null;
$slug = mpactMEDIA_get_the_slug( get_the_ID() );
$menu_items = wp_get_nav_menu_items( $slug );
//var_dump((array)$menu_items);
foreach ( (array)$menu_items as $key => $menu_item ) {
$title = $menu_item->post_title;
}
if ( $title ) { echo $delimiter . ' ' . $before . $title . $after; }
else { echo $delimiter . ' ' . $before . get_the_title() . $after; }
}
I'm my functions.php file I have the following function
function mpactMEDIA_get_the_slug( $id=null ){
if( empty($id) ) global $post;
if( empty($post) ) return '';
$id = $post->ID;
endif;
$slug = basename( get_permalink($id) );
return $slug;
}
Thank you in advance,
Tim
I read the question a few times, I got here searching for an answer, ended up making my own.
function get_menu_label_by_post_id($post_id, $menu) {
$menu_title = '';
$nav = wp_get_nav_menu_items($menu);
foreach ( $nav as $item ) {
if ( $post_id == $item->object_id ) {
$menu_title = $item->post_title;
break;
}
}
return ($menu_title !== '') ? $menu_title : get_the_title($post_id);
}
Example usage:
echo get_menu_label_by_post_id($post->ID, 'Primary Nav');
This will return what the menu label is if it finds it, otherwise just the title of the post ID.
Check the documentation for wp_get_nav_menu_items. It doesn't take a page slug as a parameter at all.
If you want to list child pages of a given page, use wp_list_pages and pass a child_of parameter to it.
Also, as a side note, if you know the $post and want the slug, it's just $post->post_name

Wordpress filter title

recently I made a question about content filtering which went ok.
Now I'm trying to achieve the same filtering about title, but when it comes to title it doesnt filter only the_title(); but all titles within wp_nav are being filtered.
The aim is to achieve filtering single post title not the ones within the loop (I know about in_the_loop() )
<?php
class Filter_Title {
public function __construct() {
if( !is_front_page() && !is_home() && !is_single() ) return;
if( !is_singular( array('post','page') ) ) return;
add_filter( 'the_title', array(&$this, 'manage_page_title') );
}
public function manage_page_title($title) {
$title = '';
return $title;
}
}
$filtertitle = new Filter_Title();
?>
This is my mini plugin class.
I just tested this and you can match the post_ID with a param to check if its a post.
Since post ids don't match menu ids this should work. Give it a try.
function remove_post_title($title, $id) {
if (is_single() && in_the_loop() && $id == get_the_ID()) {
$title = '';
}
return $title;
}
add_filter('the_title', 'remove_post_title', 10, 2);
Note: in a plugin you may need to hook the add_filter in another function and run it in wp_head like before.

How do you add_filter to only one instance of the_title()

I created a filter that modifies the_title() of a post, but the problem I'm having is that it's modifying every instance of the_title(). I got most of the problem sorted out with the in_the_loop() function, however any theme that has "next post" "previous post" navigation links within the loop are still having the filter applied (understandably so). How can I apply the filter to only the the_title() of the current post?
function xyz_the_title( $the_title ) {
if( !in_the_loop() )
return $the_title;
$location = get_post_meta( get_the_ID(), 'location', true );
$the_title .= ' - ' . $location;
return $the_title;
}
add_filter( 'the_title', 'xyz_the_title' );
do it with jQuery
Something like this should do the trick:
$(document).ready(function() {
$('#entry-header').text(function(i, oldText) {
return oldText === 'Popular Science' ? 'New word' : oldText;
});
});
This only replaces the content when it is Popular Science. See text in the jQuery API.
Rather than filtering the_title you could edit your template file instead and append the location to your returned the_title().
echo "<h1>" . get_the_title() . " - " . $location . "</h1>";
Ran into a similar situation and was hoping this thread could save me...
Anyways this is what I managed to do thus far in
add_filter( 'the_title', function( $title, $id ){
/**
* don't run in the backend
*/
if( is_admin() ) {
return $title;
}
/**
* invalid values received
*/
if( empty( $title ) || $id < 1 ){
return $title;
}
global $post;
if ( ! $post instanceof WP_Post ){
return $title;
}
/**
* PREVENTATIVE MEASURE...
* only apply the filter to the current page's title,
* and not to the other title's on the current page
*/
global $wp_query;
if( $id !== $wp_query->queried_object_id ){
return $title;
}
/**
* Don't run this filter if wp_head calls it
*/
if( doing_action( 'wp_head' ) ){
return $title;
}
return 'MODIFIED - '.$title;
});
Here are the shortfalls:
If you have the same post being displayed on the current page, somewhere else, it's gonna modify THAT post title as well
Currently thinking about having a look at the call stack to detect if the call is coming from the theme...
but I would suggest you find another solution bud...
Ah, didn't know it was for a plugin. In which case, I think you should be ok to use if_filter then. This checks whether the filter has been run x times on the page in question. So, we check if it has run once on the page and if so it won't run again. Also, I have assumed you only want this to run on single post pages. This is untested.
function xyz_the_title( $the_title ) {
if( is_single() AND did_filter('the_title') === 1 ) {
if( !in_the_loop() )
return $the_title;
$location = get_post_meta( get_the_ID(), 'location', true );
$the_title .= ' - ' . $location;
return $the_title;
}
}
add_filter( 'the_title', 'xyz_the_title' );

Resources