WordPress get template associated with category - wordpress

I have created a custom template and associated it with my categories.
Now what I am trying to do is check which template is associated with a specific category.
function custom_category_template( $template ) {
$categories = get_the_category();
$category_id = $categories[0]->cat_ID;
foreach ($categories[0] as $key => $value) {
echo $key;
echo $value;
echo "</br>";
}
if ( in_category( 245 ) && !is_archive() ) {
// the idea is to get rid of the hard coded id in the if condition above and check if a particular template is associated with the category then do the below thing
$new_template = locate_template( array( 'custom.php' ) );
if ( '' != $new_template ) {
return $new_template;
}
}
return $template;
}
Is there any way to do get the template name or id or something that is attached to a particular category.
I did found this one https://codex.wordpress.org/Function_Reference/get_category_template but it doesn't help me. I am on a post and I want to retrieve the current posts category's template.

Related

post_type_link using current page data instead of the post's

Goal:
I'm trying to accomplish 2 things.
Change the permalink structure of a custom post type
Output a list of linked posts (of that CPT) based on the post's parent-child relationship via shortcode
On the main page, list states
On the state pages, list cities of that state
On the city pages, list cities in the same state
What's working:
The correct permalink is displayed on the post's edit page.
The shortcode displays the proper items.
The issue: The list's links are wrong. The links were correct until I added the "post_type_link" modification.
The permalinks are created using the data of the current page. On the main page and state pages, the permalinks are clearly incorrect. On the city pages, all of the permalinks are for that specific page.
Example: On a page for Houston, TX, Dallas and Ft Worth are listed but their links are for Houston. Specifically, it should be "domain.com/company/texas/dallas" and "domain.com/company/texas/ft-worth", but I'm getting "domain.com/company/texas/houston" on the Houston page or an error on the Texas page.
How do I ensure the proper data is being used?
Code summary:
The filter
There are 3 patterns I want to use: "/company","/company/state", and "/company/state/city". Company is constant. State and city are stored as meta data. (States are an array with name and abbreviation.) The desired pattern should be easily identified by a taxonomy (page_groups).
The shortcode
It's pretty self-explanatory. The post structure is hierarchical. The company page's children are states. And the states' children are cities.
The list is generated via a query based on parent ID. The query returns an array of OBJs. The link is generated in a foreach loop using get_post_permalink().
I am using "global $post". The shortcode doesn't work without it. I'm guessing this is part of the issue. I could manually build the list item links, but that's a terrible long term solution.
EDIT: I updated the code to use get_the_ID and removed "global $post". No change to the shortcode output.
Code:
add_filter( 'post_type_link', 'company_tag_rewrite', 10, 2 );
function company_tag_rewrite( $permalink, $post ) {
if( $post->post_type == 'company-page' ) {
// main
if( has_term( 'company-main', 'page_groups', $post) ){
return get_home_url() ."/pest-control-service/company/";
}
// state
if( has_term( 'company-state', 'page_groups', $post) ){
$state = get_field('state');
if( $state && 'All' != $state['label'] ){
$label = strtolower($state['label']);
return get_home_url() ."/pest-control-service/company/$label";
}else{
return get_home_url() ."/pest-control-service/fix-the-state-data-city/";
}
}
// city
if( has_term( 'company-city', 'page_groups', $post) ){
$state = get_field('state');
$city = strtolower(get_field('city'));
if( !$state || 'All' == $state['label'] ){
return get_home_url() ."/pest-control-service/fix-the-state-data/";
}
if( $city ){
$label = strtolower($state['label']);
return get_home_url() ."/pest-control-service/company/$label/$city/";
}else{
return get_home_url() ."/pest-control-service/fix-the-city-data/";
}
}
return get_home_url() ."/pest-control-service/set_the_page_group/";
}else{
return $permalink;
}
}
function company_page_footer_fn($atts = array(), $content = null) {
ob_start();
// start output ----------
// determine mode and set query
global $post;
$ancestors = get_post_ancestors($post->ID);
$ancestor_count = count($ancestors);
$city = get_field('city'); //? do i need this?
$state_array = get_field('state');
$state = $state_array['label'];
// determine mode and set widget title and query
if (0 == $ancestor_count){
//main
$widget_title = "Top Locations";
$target = $post->ID;
}elseif(1 == $ancestor_count){
//state
$widget_title = "company has offices throughout $state including:";
$target = $post->ID;
}elseif(2 == $ancestor_count){
$widget_title = "company has offices throughout $state including:";
$target = wp_get_post_parent_id( );
//city
}else{
wp_reset_postdata();
return "<div style='background-color: white; color:red;font-weight: 700;padding: 1rem;'>You might want to check this post's data.</div>";
}
$post_kids = get_children(array(
// returns array of objects
"post_parent" => $target,
"post_status" => "publish",
),'OBJECT'
);
// get data
foreach($post_kids as $kid) {
$link = get_post_permalink($kid);
if (0 == $ancestor_count){
$state_array = get_field('state',$kid->ID);
$title = $state_array['label'];
}else{
$title = get_field('city',$kid->ID).", $state";
}
$data[] = array(
'title' => $title,
'link' => $link,
);
}
// sort
function cmp($a, $b)
{
return strcmp($a["title"], $b["title"]);
}
uasort($data, 'cmp');
// output
?><style>
</style><?php
echo "<div class='location-list-container'>";
echo "<H2>$widget_title</H2>";
echo "<div class='location-list'>";
foreach($data as $item){
$this_title = $item['title'];
$this_link = $item['link'];
echo "<h3><a href='$this_link'>$this_title</a></h3>";
}
echo "</div";
echo "</div";
//return output ----------
wp_reset_postdata();
$thisOutput = ob_get_clean();
return $thisOutput;
}
add_shortcode( 'company-page-footer', 'company_page_footer_fn' );

Remove a category or categories from Breadcrumbs Woocommerce [duplicate]

Please pardon me if there's a better way to do this as I am not very familiar with this code. I would like to display only the link to the homepage and the current product on the breadcrumb.
Desire result:
Currently:
I found the code for the breadcrumb, is there a way to only display the first and last crumb regardless of the hierarchy?
foreach ( $breadcrumb as $key => $crumb ) {
echo $before;
if ( ! empty( $crumb[1] ) && sizeof( $breadcrumb ) !== $key ) {
echo '' . esc_html( $crumb[0] ) . '';
} else if(!is_product() && !flatsome_option('wc_category_page_title')) {
echo esc_html( $crumb[0] );
}
echo $after;
// Single product or Active title
if(is_product() || flatsome_option('wc_category_page_title')){
$key = $key+1;
if ( sizeof( $breadcrumb ) > $key) {
echo ' <span class="divider">'.$delimiter.'</span> ';
}
} else{
// Category pages
if ( sizeof( $breadcrumb ) !== $key + 1 ) {
echo ' <span class="divider">'.$delimiter.'</span> ';
}
}
}
The reason why I am doing this is that some of the products have multiple categories and by default, it will only show the breadcrumb for the primary category. I would rather make a truncated version as suggested by the owner.
I was also wondering if I can simply dynamically retrieve the product title and link + static homepage link, make it into a shortcode so that I can paste it in the product page.
Hi – the first example in the answer above, also removes the shop from woocommerce breadcrumb. Here is a working example, that only removes the category:
// remove only the category from woocommerce breadcrumbs
add_filter( 'woocommerce_get_breadcrumb', 'custom_breadcrumb', 20, 2 );
function custom_breadcrumb( $crumbs, $breadcrumb ) {
//print the array and look for the key with the category
//echo '<pre>';
//print_r($crumbs);
//echo '</pre>';
//unset($crumbs[2]); in my case it is key 2
// only on the single product page
if ( ! is_product() ) {
return $crumbs;
} else {
unset($crumbs[2]); // this isn't enough, it would leave a trailing delimiter
$newBreadC = array_values($crumbs); //therefore create new array
return $newBreadC; //return the new array
}
}
If you want to remove categories and subcategories from product breadcrumbs on the product page you can use the woocommerce_get_breadcrumb hook.
// change the breadcrumb on the product page
add_filter( 'woocommerce_get_breadcrumb', 'custom_breadcrumb', 20, 2 );
function custom_breadcrumb( $crumbs, $breadcrumb ) {
// only on the single product page
if ( ! is_product() ) {
return $crumbs;
}
// gets the first element of the array "$crumbs"
$new_crumbs[] = reset( $crumbs );
// gets the last element of the array "$crumbs"
$new_crumbs[] = end( $crumbs );
return $new_crumbs;
}
The code has been tested and works. Add it to your active theme's functions.php.
A good alternative is to set the primary product category for each product. You can do this by installing the Yoast SEO plugin.
You can use the _yoast_wpseo_primary_product_cat product meta to set the id of the primary product category.
After setting the primary category id by editing the product in the
backend or importing a .csv file you will only need to change the
permalink and breadcrumbs based on the primary product category.
To update the product permalink:
// update the product permalink based on the primary product category
add_filter( 'wc_product_post_type_link_product_cat', 'change_product_permalink_by_cat', 10, 3 );
function change_product_permalink_by_cat( $term, $terms, $post ) {
// get the primary term as saved by Yoast
$primary_cat_id = get_post_meta( $post->ID, '_yoast_wpseo_primary_product_cat', true );
// if there is a primary and it's not currently chosen as primary
if ( $primary_cat_id && $term->term_id != $primary_cat_id ) {
// find the primary term in the term list
foreach ( $terms as $term_key => $term_object ) {
if ( $term_object->term_id == $primary_cat_id ) {
// return this as the primary term
$term = $terms[ $term_key ];
break;
}
}
}
return $term;
}
To update the product breadcrumbs on the product page:
// change the breadcrumb on the product page
add_filter( 'woocommerce_get_breadcrumb', 'custom_breadcrumb', 20, 2 );
function custom_breadcrumb( $crumbs, $breadcrumb ) {
// only on the single product page
if ( ! is_product() ) {
return $crumbs;
}
global $product;
$new_crumbs = array();
if ( $product->get_meta( '_yoast_wpseo_primary_product_cat', true ) ) {
// gets the first element of the array "$crumbs"
$new_crumbs[] = reset( $crumbs );
// gets the id of the primary product category
$primary_cat_id = $product->get_meta( '_yoast_wpseo_primary_product_cat', true );
// create an array with all parent categories (based on the id of the primary product category)
$parent_categories = get_ancestors( $primary_cat_id, 'product_cat' );
$parent_categories = array_reverse($parent_categories);
$parent_categories[] = $primary_cat_id;
// for each product category it gets the name and the permalink
foreach ( $parent_categories as $cat_id ) {
$term = get_term_by( 'id', $cat_id, 'product_cat' );
$new_crumbs[] = array(
0 => $term->name,
1 => esc_url( get_term_link( $term, 'product_cat' ) )
);
}
// gets the last element of the array "$crumbs"
$new_crumbs[] = end( $crumbs );
} else {
// gets the first element of the array "$crumbs"
$new_crumbs[] = reset( $crumbs );
// gets the last element of the array "$crumbs"
$new_crumbs[] = end( $crumbs );
}
return $new_crumbs;
}
The code has been tested and works. Add it to your active theme's functions.php.

Add featured image to wp_nav_menu items

This is a self Q&A.
How do you modify the text/html that appears in the output of a wp_nav_menu? For example, I wanted to add the featured image for pages and categories.
You see examples of doing this with a custom walker, but the code is very complex to do for small changes. Surely there is a way to do it with a filter?
This is the code I came up with thanks to some help from a Wordpress StackOverflow answer that I can't find anymore (please comment with a link if you find it).
First you need to add the filter to the specific menu (you could add it to all menus if you want - just use the add_filter line by itself).
// Add filter to specific menus
add_filter('wp_nav_menu_args', 'add_filter_to_menus');
function add_filter_to_menus($args) {
// You can test agasint things like $args['menu'], $args['menu_id'] or $args['theme_location']
if( $args['theme_location'] == 'header_menu') {
add_filter( 'wp_setup_nav_menu_item', 'filter_menu_items' );
}
return $args;
}
Then you need to build out the code to get the post or category ID from the $item object passed to the filter. It's not as easy as you'd expect, as $item doesn't contain the underlying post/category ID, just the menu item ID. So I use the URL's to do a reverse lookup of the IDs.
This won't work for tags used in a menu, or custom taxonomys. I only needed it for categories, so this is all I built.
// Filter menu
function filter_menu_items($item) {
if( $item->type == 'taxonomy') {
// For category menu items
$cat_base = get_option('category_base');
if( empty($cat_base) ) {
$cat_base = 'category';
}
// Get the path to the category (excluding the home and category base parts of the URL)
$cat_path = str_replace(home_url().'/'.$cat_base, '', $item->url);
// Get category and image ID
$cat = get_category_by_path($cat_path, true);
$thumb_id = get_term_meta($cat->term_id, '_term_image_id', true); // I'm using the 'Simple Term Meta' plugin to store an attachment ID as the featured image
} else {
// Get post and image ID
$post_id = url_to_postid( $item->url );
$thumb_id = get_post_thumbnail_id( $post_id );
}
if( !empty($thumb_id) ) {
// Make the title just be the featured image.
$item->title = wp_get_attachment_image( $thumb_id, 'poster');
}
return $item;
}
And then you want to remove the filter that you applied at the beginning, so that the next menu processed doesn't use the same HTML as defined above in filter_menu_items().
// Remove filters
add_filter('wp_nav_menu_items','remove_filter_from_menus', 10, 2);
function remove_filter_from_menus( $nav, $args ) {
remove_filter( 'wp_setup_nav_menu_item', 'filter_menu_items' );
return $nav;
}
Modified Drew Baker answer. It works without plugins, also if there is no category with current slug it checks for woocommerce product category ('product_cat').
functions.php
// Add filter to specific menus
add_filter('wp_nav_menu_args', 'add_filter_to_menus');
function add_filter_to_menus($args) {
// You can test agasint things like $args['menu'], $args['menu_id'] or $args['theme_location']
if( $args['theme_location'] == 'menu-header') {
add_filter( 'wp_setup_nav_menu_item', 'filter_menu_items' );
}
return $args;
}
// Filter menu
function filter_menu_items($item) {
if( $item->type == 'taxonomy') {
// Get category and image ID
$slug = pathinfo( $item->url, PATHINFO_BASENAME );
$cat = get_term_by( 'slug', $slug, 'category' );
// If there is no standard category try getting product category
if( !$cat ) {
$cat = get_term_by( 'slug', $slug, 'product_cat' );
}
$thumb_id = get_term_meta($cat->term_id, 'thumbnail_id', true);
} else {
// Get post and image ID
$post_id = url_to_postid( $item->url );
$thumb_id = get_post_thumbnail_id( $post_id );
}
if( !empty($thumb_id) ) {
// Make the title just be the featured image.
$item->title = wp_get_attachment_image( $thumb_id, 'poster');
// Display image + title example
// $item->title = wp_get_attachment_image( $thumb_id, 'poster').$item->title;
}
return $item;
}
// Remove filters
add_filter('wp_nav_menu_items','remove_filter_from_menus', 10, 2);
function remove_filter_from_menus( $nav, $args ) {
remove_filter( 'wp_setup_nav_menu_item', 'filter_menu_items' );
return $nav;
}

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

How to Check Which level category it is for wordpress?

Let me tell you the scenario first say the structure of the categories in wordpress is like this
Level 1: Top
Level 2: -Nextme_1
Level 3: --Nextme_2
--Nextme_3
Level 4: ---Nextme_4
---Nextme_5
Now I require to check what is the level of the category? Say I catch a category of level 3 so I have to use different template and if its level 4. Then I need to use another template?
Anybody can give me some hint?
Thanks
Rahul
If you don't have many categories you can try to edit their slug from admin, and then in your page you get the category slug this way:
if (is_category()) {
$cat = get_query_var('cat');
$category = get_category($cat);
echo 'your slug is '. $category->slug;
}
Now, when you're editing the categories slugs try naming them after their level: cat-lvl-1, cat-lvl-2. Then in your page you extract the number from category slug using some php string function, and then you check that number:
if ($category->slug == 1 ) {
//load the template for the category of level 1
}
if ($category->slug == 2 ) {
//load the template for the category of level 2
}
and so on.
Later edit:
Try this:
function get_level($category, $level = 0)
{
if ($category->category_parent == 0) {
return $level;
} else {
$level++;
$category = get_category($category->category_parent);
get_level($category, $level);
}
}
if (is_category()) {
$cat = get_query_var('cat');
$yourcat = get_category($cat);
echo get_level($yourcat);
}
You can call the get_ancestors() function to get an array containing the parents of the given object. Then you need to count elements in the result.
function get_the_level($id, $type = 'category') {
return count( get_ancestors($id, $type) );
}
if( is_category() ) {
$level = get_the_level( $cat );
}
elseif( is_product_category() ) {
$level = get_the_level( $wp_query->get_queried_object()->term_id, 'product_cat' );
}
Thanks a lot. This is superb with slight a change the code that you have written is fine but its not returning any value.(i,e the $level) although its calculating correct. A minor change i did and its work fine now with a slight editing of you code given below..
`
function get_level($category, $level = 0)
{
if ($category->category_parent == 0) {
return $level;
} else {
$level++;
$category = get_category($category->category_parent);
return get_level($category, $level);
}
}
if (is_category()) {
$cat = get_query_var('cat');
$yourcat = get_category($cat);
echo get_level($yourcat);
}
`
Thanks #zuzuleinen
I visited this page months back. I came back today, arrow up on the above solution then still went digging. Although it is a good solution, Wordpress often offers better or close.
get_category_parents()
This function does as Rahul has typed basically. It also calls itself which seems the most logical approach and that is why Rahul gets a point from me on this. Do not use $link, return a string of categories, explode() them then count or I suppose we could count the number of times the separator has been used and add 1.
function get_category_parents( $id, $link = false, $separator = '/', $nicename = false, $visited = array() ) {
$chain = '';
$parent = get_term( $id, 'category' );
if ( is_wp_error( $parent ) )
return $parent;
if ( $nicename )
$name = $parent->slug;
else
$name = $parent->name;
if ( $parent->parent && ( $parent->parent != $parent->term_id ) && !in_array( $parent->parent, $visited ) ) {
$visited[] = $parent->parent;
$chain .= get_category_parents( $parent->parent, $link, $separator, $nicename, $visited );
}
if ( $link )
$chain .= ''.$name.'' . $separator;
else
$chain .= $name.$separator;
return $chain;
}

Resources