if is_grandchild for single and category - wordpress

I've been searching around and can't seem to find (or piece together) code that checks to see if the current category OR post is a grandchild of a certain category. Basically, is there any way to properly code for:
<?php if ( is_grandchild(147) || in_grandchild(147) ) { do something } ?>

function get_topmost_parent($post_id){
$parent_id = get_post($post_id)->post_parent;
if($parent_id == 0){
return $post_id;
}else{
return get_topmost_parent($parent_id);
}
}
try this will return top mostparent !

Related

Show shortcode for a given word only once

I'm trying to implement a custom functionality to a wordpress shortcode plugin that shows a tooltip for specified words by automatically calling for information from Wikipedia.
Currently my code snippet works fine, but it shows the tooltips for each occurrence of the word in an article. For example if I specified the word : "dessert" in an array it will show the tooltip for all 5 words "dessert" found in the post. I'm looking for a way to limit the tooltip shortcode to be applied only once per word ( in this case "dessert" which has been specified in the array).
Me code snippet is this:
function add_wikitips($content) {
if( is_single() && is_main_query() ) {
$arr = array('dessert');
for ($i = 0; $i < count($arr); $i++) {
$content = str_replace($arr[$i], '[wiki]'.$arr[$i].'[/wiki]', $content);
}
}
return $content;
}
add_filter('the_content', 'add_wikitips');
I tried adding ob_end_clean(); then
static $content = null;
if ($content === null) {
return $content;
}
, but these methods didn't work. Probably because I didn't implement them properly.
Thanks a lot in advance for any advice and suggestions.
Probably, you can try this: Using str_replace so that it only acts on the first match?
You want the first work to have Wiki link. So replace the first occurrence only when you are doing str_replace()
May be like:
function str_replace_first($from, $to, $content)
{
$from = '/'.preg_quote($from, '/').'/';
return preg_replace($from, $to, $content, 1);
}
echo str_replace_first('abc', '123', 'abcdef abcdef abcdef');
// outputs '123def abcdef abcdef'
Mentioned in Karim's amswer

Wordpress. How to use shortcode with if else statement?

I have following code but it's displaying shortcode in text rather than showing results of shortcode.
$curr_user_id = get_current_user_id();
// the value is 0 if the user isn't logged-in
if ( $curr_user_id != 0 ) {
// we know now the user is logged-in, so we can use his/her ID to get the user meta
$um_value = get_user_meta( $curr_user_id, 'user_phone', true );
// now we check if the value is correct
if ( ! empty( $um_value ) && $um_value == 'French' ) {
// if so we can output something
echo '[ld_course_list course_category_name="french" col=4 progress_bar=true]';
} else {
// else the code, eg.
echo '[ld_course_list course_category_name="english" col=4 progress_bar=true]';
}
}
Above code will result in text below rather than showing results of the shortcode
[ld_course_list course_category_name="english" col=4
progress_bar=true]
How do I change my code so it actually runs shortcode?
Thank you.
Following code worked. Only problem is do_shortcode is breaking stylesheet. Anyone know why or how to fix it?
<?
$curr_user_id = get_current_user_id();
// the value is 0 if the user isn't logged-in
if ( $curr_user_id != 0 ) {
// we know now the user is logged-in, so we can use his/her ID to get the user meta
$um_value = get_user_meta( $curr_user_id, 'user_phone', true );
// now we check if the value is correct
if ( ! empty( $um_value ) && $um_value == 'French' ) {
// if so we can output something
echo do_shortcode('[ld_course_list course_category_name="french" col=4 progress_bar=true]');
} else {
// else the code, eg.
echo do_shortcode('[ld_course_list course_category_name="english" col="4" progress_bar="true"]');
}
}
?>
You are using it in wrong way, the method you are trying is used inside wordpress pages, posts etc.
To use inside plugin, theme or any other .php file, use WordPress function called do_shortcode() that lets you add shortcodes directly in your themes and plugins.
Add it like this:
echo do_shortcode("[ld_course_list course_category_name="english" col=4 progress_bar=true]");

add custom class to wordpress nav menu item based on specific condition

I want to add current-menu-item class to the li if it is a single page.
I am trying to do this by using wp_nav_menu_objects hook with a custom function but don't know how to get the particular menu item and set a condition to assign the class to it.
Here is the code.
add_filter('wp_nav_menu_objects' , 'my_menu_class');
function my_menu_class($menu) {
//if it is a single post page of a particular post type (in this case 'property')
if( is_single() && is_post_type_archive( 'property' ) ) {
//get all the menu items
foreach($menu as $key => $item) {
// check if the menu item is "Commercial Property"
if($item == "Commercial Property") {
//assign the class to that menu item
$menu[$key]->classes[] = 'current-menu-item';
}
}
}
return $menu;
}
This code is just to represent the logic. Please suggest if what I need can be achieved with this method or there is a better approach to it.
Thanks.
In my WP theme, I wanted to remove all wordpess menu classes, add my own and on specific condition ( for example if the menu has an active class ) to add another class. Here s my code
function add_custom_classes($classes){
$newClasses[] = "navigation__item";
if( in_array('current_page_item', $classes) ){
array_push($newClasses, "navigation__item-active");
}
return $newClasses;
}
add_filter('nav_menu_css_class', 'add_custom_classes', 100, 1);
add_filter('nav_menu_item_id', 'add_custom_classes', 100, 1);
add_filter('page_css_class', 'add_custom_classes', 100, 1);
You can add your own conditions
is_single is actually looking for a single post. You need is_page
Wordpress already provides the class if it is a single page
current-post-ancestor
on any post detail page you can inspect the menu you will find that class so in other way you can utilize current-post-ancestor class for what you need to do
Hope it makes sense
I have solved it using the HTTP_REFERER to set conditions in the same function.
Don't feel it is the best way to achieve this but it sorts me out.
Here is the code if anyone else needs a reference.
function nav_menu_class($menu) {
//To dynamically get the directory path from the URL irrespective of the local or web server.
$ref = $_SERVER['HTTP_REFERER']; // prev page url.
$split_ref = pathinfo($ref); // splitting the url to seperate the directory (http://dev.calyxagency.com/horizoncapital/site-new/) from the file path.
$dir_path .= $split_ref[ "dirname" ]; // extracting the host + directory from the full path
$class = 'current-menu-item'; // class to be assigned.
foreach($menu as $key => $item) {
if( $menu[$key]-> ID == 101 ) { // check if the menu item matches this ID
if( $ref == $dir_path.'/properties-to-let/' || $ref == $dir_path.'/properties-for-sale/' || $ref == $dir_path.'/commercial-property/' ) {
$menu[$key]->classes[] = $class;
}
} elseif( $menu[$key]-> ID == 15 ) { // check if the menu item matches this ID
if( $ref == $dir_path.'/business-for-sale/' ) { // check if the single page has come from this page for assigning current class to only this menu item
$menu[$key]->classes[] = $class;
}
} elseif( $menu[$key]-> ID == 18 ) { // check if the menu item matches this ID
if( $ref == $dir_path.'/news/' ) { // check if the single page has come from this page for assigning current class to only this menu item
$menu[$key]->classes[] = $class;
}
}
}
return $menu;
}
add_filter('wp_nav_menu_objects' , 'nav_menu_class');

How do you assign a specific order for a category in Wordpress?

I am having a small problem which I believe to be related to a syntax issue.
I have a specific script for home which calls the bloginfo("name") for the page title then an else statement below which titles pages based on the name of the first category associated them and it works fine:
else{
$category = get_the_category();
echo $category[0]->cat_name;
}
However, I also have a default "home" category for most posts(with a few exceptions) and I do not want this category to be picked up as the page title if it happens to come first in the list of categories associated for this page.
There are two ways I can think of making this possible but I do not know how to code them. The first would be to exclude the home category in the code above but don't know how to implement it. The second would be to somehow force wordpress to always add the category "home" after the first chosen category for a particular post.
I hope that this is clear. Anyone come up with a basic solution?
Many thanks.
This plugin does most of what you want out of the box:
http://wordpress.org/extend/plugins/sem-opt-in-front/
Alternatively, do something like:
function the_main_topic_link($link = '', $id = '')
{
if (!$id || $id != get_option('default_category')) return $link;
if (get_option('show_on_front') == 'page' && get_option('page_on_front')) {
if ($blog_page_id = get_option('page_for_posts')) {
return apply_filters('the_permalink', get_permalink($blog_page_id));
} else {
return $link;
}
} else {
return home_url('/');
}
}
add_filter('category_link', 'the_main_topic_link', 10, 2);
function pre_get_posts_redirect_main_topic($q)
{
global $wp_the_query;
if ($q !== $wp_the_query) return;
if ($q->is_category(get_option('default_category'))) {
wp_redirect(home_url('/'));
die;
}
}
if (!is_admin()) add_action('pre_get_posts', 'pre_get_posts_redirect_main_topic');
It'll treat linking to your default category as linking to your front page.

Wordpress custom post type hierarchy and menu highlighting (current_page_parent)

I have created a custom post type of 'portfolio' and page with a template that retrieves all posts matching that custom post type.
The problem is when I drill down into the actual post, the post seems to sit under 'blog' in the main menu highlighting (displays current_page_parent as a class)
The permalink url is correct: www.site.com/portfolio/post-slug
But the menu thinks the parent is 'blog'.
This is obviously a hierarchical issue but I don't know what to do to fix it.
It appears this is an issue with the core Wordpress code; the code that generates the menu classes adds current_page_parent to your Blog page everywhere except when viewing static page templates.
(This has been discussed in passing at http://core.trac.wordpress.org/ticket/13543).
You can however get around this with some custom code using the page_css_class filter. For example, add something along these lines to functions.php (not 100% tested):
function my_page_css_class($css_class, $page) {
if (get_post_type()=='portfolio' || is_page(57)) {
if ($page->ID == get_option('page_for_posts')) {
foreach ($css_class as $k=>$v) {
if ($v=='current_page_parent') unset($css_class[$k]);
}
}
if ($page->ID==57) {
$css_class[]='current_page_parent';
}
}
return $css_class;
}
add_filter('page_css_class','my_page_css_class',10,2);
Replacing 57 with the ID of your portfolios page, of course. That removes current_page_parent when printing the blog page and adds current_page_parent to your portfolios page, when either viewing a single portfolio or viewing the portfolios page itself.
Here is my optimized/extended version of previously suggested solutions, which is pretty much fully automated. No more extra CSS or menu attributes needed.
This version dynamically gets a list of custom post types and if the current post type is a custom post type, then it removes the 'current_page_parent' class from all menu items.
Furthermore it checks each menu item to see if it's for a page with a page template like "page-{custom_post_type_slug}.php", and if so, it'll add the 'current_page_parent' class.
The filter priority is 1, as some themes, replace the current_page_parent/etc. classes with a class like 'active' (eg. 'roots' does this), so this filter needs to execute first.
Lastly, it makes use of 3 static variables since this function is repeatedly called and these (obviously) remain the same through all calls.
function theme_current_type_nav_class($css_class, $item) {
static $custom_post_types, $post_type, $filter_func;
if (empty($custom_post_types))
$custom_post_types = get_post_types(array('_builtin' => false));
if (empty($post_type))
$post_type = get_post_type();
if ('page' == $item->object && in_array($post_type, $custom_post_types)) {
$css_class = array_filter($css_class, function($el) {
return $el !== "current_page_parent";
});
$template = get_page_template_slug($item->object_id);
if (!empty($template) && preg_match("/^page(-[^-]+)*-$post_type/", $template) === 1)
array_push($css_class, 'current_page_parent');
}
return $css_class;
}
add_filter('nav_menu_css_class', 'theme_current_type_nav_class', 1, 2);
PS. Just to point out one shortcoming in all non-CSS solutions I've seen so far, including my own:
Something not taken into account is highlighting the menu item parent/ancestor of an item linking to a page which displays posts of the current custom post type. Consider a custom post type "product" and a menu like:
Home Company News Contact
|
\--About Us
\--Products
"Products" is a page with a template "page-product.php" and shows an overview of posts of type 'product'. It is highlighted due to posted solution. However 'Company' as its parent/ancestor should also be highlighted, but isn't. Something to keep in mind.
WP ticket: http://core.trac.wordpress.org/ticket/16382
function fix_blog_menu_css_class( $classes, $item ) {
if ( is_tax( 'my-cat-tax' ) || is_singular( 'my-post-type' ) || is_post_type_archive( 'my-post-type' ) ) {
if ( $item->object_id == get_option('page_for_posts') ) {
$key = array_search( 'current_page_parent', $classes );
if ( false !== $key )
unset( $classes[ $key ] );
}
}
return $classes;
}
add_filter( 'nav_menu_css_class', 'fix_blog_menu_css_class', 10, 2 );
I did some more looking around on this and found another way of doing this.
add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2);
function current_type_nav_class($css_class, $item)
{
if (get_post_type() === 'portfolio') {
$current_value = 'current_page_parent';
$css_class = array_filter($css_class, function ($element) use ($current_value) {
return ($element != $current_value);
});
}
$post_type = get_query_var('post_type');
if ($item->attr_title !== '' && $item->attr_title === $post_type) {
array_push($css_class, 'current_page_parent');
};
return $css_class;
}
I got some help form this post and then modified it to also remove the "current_page_parent" class from the blog page.
https://wordpress.stackexchange.com/questions/3014/highlighting-wp-nav-menu-ancestor-class-w-o-children-in-nav-structure/3034#3034
Cordially
Vayu
As explained at https://core.trac.wordpress.org/ticket/16382, .current_page_parent matches "anything that isn't a page" for the sake of backwards compatibility (bear in mind that this was considered backwards 10 years ago...) so themes nowadays really shouldn't still be using it.
So the simplest solution, and the most efficient (since unlike previous answers it doesn't require running extra code on every page load), is to modify your theme's CSS to replace use of the .current_page_parent class selector with .current-menu-parent, which does the right thing. (NB underscores vs hyphens.)
If you are using a third-party theme and don't want to modify it directly, then you can overwrite its properties in your own stylesheet. For example, if your theme has:
.current_page_parent > a {
border-bottom: 4px solid blue;
}
then in your child theme's stylesheet you would do this to cancel out its effects, and apply them to the correct class:
.current_page_parent > a {
border-bottom: transparent !important; /* Cancel out incorrect styling */
}
.current-menu-parent > a {
border-bottom: 4px solid blue; /* Add styling correctly */
}
This is just an example - the correct way will depend on how your theme is styling these links.
Here is a solution that worked for me, without having to define my custom post type or menu id or page id in the code:
http://dtbaker.net/web-development/how-to-stop-wordpress-automatically-highlighting-the-blog-page-in-the-menu/
function dtbaker_wp_nav_menu_objects($sorted_menu_items, $args){
// this is the code from nav-menu-template.php that we want to stop running
// so we try our best to "reverse" this code wp code in this filter.
/* if ( ! empty( $home_page_id ) && 'post_type' == $menu_item->type && empty( $wp_query->is_page ) && $home_page_id == $menu_item->object_id )
$classes[] = 'current_page_parent'; */
// check if the current page is really a blog post.
//print_r($wp_query);exit;
global $wp_query;
if(!empty($wp_query->queried_object_id)){
$current_page = get_post($wp_query->queried_object_id);
if($current_page && $current_page->post_type=='post'){
//yes!
}else{
$current_page = false;
}
}else{
$current_page = false;
}
$home_page_id = (int) get_option( 'page_for_posts' );
foreach($sorted_menu_items as $id => $menu_item){
if ( ! empty( $home_page_id ) && 'post_type' == $menu_item->type && empty( $wp_query->is_page ) && $home_page_id == $menu_item->object_id ){
if(!$current_page){
foreach($sorted_menu_items[$id]->classes as $classid=>$classname){
if($classname=='current_page_parent'){
unset($sorted_menu_items[$id]->classes[$classid]);
}
}
}
}
}
return $sorted_menu_items;
}
add_filter('wp_nav_menu_objects','dtbaker_wp_nav_menu_objects',10,2);

Resources