I have added the below code to the functions.php file to load different post templates per category. The code is doing what it is supposed to do. The issue I am facing is that when I open posts these load correctly but whilst loading an error is displayed for a instant saying "trying to get property of non-object in .......functions.php" How may I get rid of that error? Appreciate your help.
/* ----------------------------------------------------------------------------
custom single posts per category
*/
add_filter('single_template', 'check_for_category_single_template');
function check_for_category_single_template( $t )
{
foreach( (array) get_the_category() as $cat )
{
if ( file_exists(get_stylesheet_directory() . "/single-category-{$cat->slug}.php") ) return get_stylesheet_directory() . "/single-category-{$cat->slug}.php";
if($cat->parent)
{
$cat = get_the_category_by_ID( $cat->parent );
if ( file_exists(get_stylesheet_directory() . "/single-category-{$cat->slug}.php") ) return get_stylesheet_directory() . "/single-category-{$cat->slug}.php";
}
}
return $t;
}
The error trying to get property of non-object means, you try to get a property of something that is not an object. So looking at your code you are getting two properties with ->: "slug" and "parent".
This gives us the hint, that the value saved in the $cat variable might not be an object.
You are using get_the_category_by_ID which gives you a name, not a category object. https://developer.wordpress.org/reference/functions/get_the_category_by_id/ So you cannot access any property. The problem is this: get_the_category_by_ID( $cat->parent ); There is no parent property in $cat, because it only contains the name. You need to get the object to make use of the parent property. Moreover the property is called category_parent, and not parent.
$parent_id = $cat->category_parent;
$cat = get_category($parent_id);
This should solve your problem.
If it does not solve your problem, I wrote the code in another way. It shows single steps and maybe it is useful for you or some other users.
The function to get all your category objects is: get_categories() https://developer.wordpress.org/reference/functions/get_categories/
You can save all the IDs of the categoires into a array. After that, you loop through each position of the array and check if the single post you are viewing has the same category ID. We can check if the post is in given categories using in_category() https://developer.wordpress.org/reference/functions/in_category/
I did no testing, but the code can look something like:
add_filter('single_template', 'check_for_category_single_template');
function check_for_category_single_template() {
// Get all category objects
$categories = get_categories();
// Array for IDs
$categories_ids = [];
foreach($categories as $category) {
// add id to array
array_push($categories_ids, $category->cat_ID);
}
// Loop through array of IDs
foreach($categories_ids as $category_id) {
// Check if ID equals current post category ID
if ( in_category($category_id) ) {
// get current category object
$cat = get_category($category_id);
// check if category has parent
if( $cat->category_parent > 0 ) {
$parent_id = $cat->category_parent;
// get parent object
$cat = get_category( $parent_id );
}
// get slug of category
$cat_slug = $cat->slug;
if ( file_exists(get_stylesheet_directory() . "/single-category-" .$cat_slug. ".php") ) {
return get_stylesheet_directory() . "/single-category-" .$cat_slug. ".php";
}
}
}
}
Related
I'm working on an index page that lists all posts for a custom post type. I've been listing the categories for each post using <?php echo strip_tags(get_the_term_list( $post->ID, 'genre', ' ',' • ')); ?>.
We need to add sub-categories but I don't want these to display on the index page - just the parent category. Have tried using get_term_parents_list and a few other examples from here but can't get anything working.
Can anyone help?
You can use get_the_terms filter to change the terms to return.
add_filter('get_the_terms', 'only_parent_genre', 10, 3);
function only_parent_genre($terms, $post_id, $taxonomy) {
// TODO for you : Add condition to heck if you are not on your custom index too.
if(is_admin() || $taxonomy !== 'genre') {
return $terms;
}
// Loop over terms and if parent is something different than 0, it means that's its a child term
foreach($terms as $key => $term) {
if($term->parent !== 0) {
unset($terms[$key]);
}
}
return $terms;
}
I have problem with my catogories in my custom post type. I am trying to do a basic apartments booking system. I created custom post called Apartments and then I added a categories. The category tree looks like this:
Countries
- Spain
-- Barcelona
-- Madrid
- Greece
-- Athenes
and so on.
I want to achive effect when the user enter to the apartment in Barcelona, the higher category will be displayed in header (in this example Spain). When the user eneter to the apartment in Athenes the Greece category should be in header. I tried solution that I have found on stack but it does not work for me.
$category = get_the_category();
foreach ($category as $cat) {
echo $cat->name;
}
$ancestors = get_ancestors( $category[0]->term_id, 'category' );
$direct_parent_id = $ancestors[0];
echo $direct_parent_id;
Only the second category is displayed and as you can see the categories are displayed in alphabetical order instead of hierarchical.
I hope you understand what I mean.
Thank you in advance for directions
Function get_the_category returns the object WP_Term. So, it's possible to get the parent from that object.
Used this answer, in your case it will be:
First, add this function to your functions.php file of active theme/child theme to have access to it from other files of theme/child theme:
function get_deep_child_category( $categories )
{
$maxId = 0;
$maxKey = 0;
foreach ( $categories as $key => $value )
{
if ( $value->parent > $maxId )
{
$maxId = $value->term_id;
$maxKey = $key;
}
}
return $categories[$maxKey];
}
Note: in some cases this will not work as expected. For example, if your post has category Some_category, which is child of Some_category_parent, and the Some_category_parent was created after your Spain category, then, this will return the category Some_category.
Next step will be to use it. For example, in your post template:
$categories = get_the_category();
if ( $categories ){
$deep_child = get_deep_child_category( $categories );
echo get_cat_name($deep_child->parent);
}
After getting the deepest category object with function get_deep_child_category, we got the ID of it's parent category. get_cat_name() returned the name of parent category using it's ID. In your case, it's Spain.
I'm trying to convert my standard PHP WordPress theme to Timber/Twig and am having trouble getting any output from custom functions. This one in particular looks to see if the post has a Yoast Primary Term set, which allows you to specify a primary category for a post that has multiple categories.
I need to do this in within The Loop and most of the documentation talks about how to do it in a single page. I have a function like this in my functions.php:
function my_theme_get_post_category() {
// regular list of categories set in WP
list( $wp_category ) = get_the_category();
// primary category set with Yoast plugin
$primary_category = new WPSEO_Primary_Term( 'category', get_the_ID() );
$primary_category = $primary_category->get_primary_term();
$primary_category = get_category( $primary_category );
// use only one or the other
if ( is_wp_error( $primary_category ) || $primary_category == null ) {
$category = $wp_category;
} else {
$category = $primary_category;
}
return $category;
}
Based on what I've read in the "Functions" section here (https://github.com/timber/timber/wiki/WP-Integration#functions), I should be able to call this in my template with {{ function('my_theme_get_post_category', post.ID) }}, but that does not work.
I tried making $postID a required parameter of the function, but that also didn't help anything.
I also tried using the TimberHelper::function_wrapper and then calling it in the template with {{ my_theme_get_post_category }} but, again, that didn't accomplish anything.
If you use {{ function('my_theme_get_post_category', post.ID) }}, then the function that you call needs to accept the argument that you pass. When you use…
function my_theme_get_post_category() {
// Your function code
}
… then your post ID won’t be passed to the function. As you mentioned, you probably already tried to add the post id as a parameter:
function my_theme_get_post_category( $post_id ) {
// Your function code
}
And nothing happened. That’s because your function uses functions that depend on The Loop, like get_the_category() or get_the_ID(). These functions get the current post id from global variables, which are not always set when you loop through posts in Timber.
When using Timber, you need to tell these functions to use a certain post id. If you look at the documentation for get_the_category(), you see that there’s one optional argument that you can pass: the post id.
For the other function, get_the_ID(), you can simply replace it with the parameter $post_id that you pass to your function.
function my_theme_get_post_category( $post_id ) {
// regular list of categories set in WP
list( $wp_category ) = get_the_category( $post_id );
// primary category set with Yoast plugin
$primary_category = new WPSEO_Primary_Term( 'category', $post_id );
$primary_category = $primary_category->get_primary_term();
$primary_category = get_category( $primary_category );
// use only one or the other
if ( is_wp_error( $primary_category ) || $primary_category == null ) {
$category = $wp_category;
} else {
$category = $primary_category;
}
return $category;
}
I am using the FeedWordPress plugin http://wordpress.org/extend/plugins/feedwordpress/ to pull posts from one site to another.
I have written a filter that after some help from Stack users successfully scans the $content and extracts the image URL into $new_content
define('FWPASTOPC_AUTHOR_NAME', 'radgeek');
add_filter(
/*hook=*/ 'syndicated_item_content',
/*function=*/ 'fwp_add_source_to_content',
/*order=*/ 10,
/*arguments=*/ 2
);
function fwp_add_source_to_content ($content, $post) {
// Use SyndicatedPost::author() to get author
// data in a convenient array
$content = $post->content();
// Authored by someone else
if( preg_match( '/<img[^>]+src\s*=\s*["\']?([^"\' ]+)[^>]*>/', $content, $matches ) ) {
$new_content .= 'URL IS '.$matches[0].'';
return $new_content;
}
else
{
}
}
What I wanted to do now was save this URL into a custom field instead of just returning it. Has anyone achieved anything similar?
So as I understand it, the plugin grabs content from external RSS feeds and creates them as posts in your website.
If this is the case, using your filter you should be able to grab the post ID within the $post variable.
So all you need is the add_post_meta() function to add a custom field to the specific post.
So including your code above it should look something like:
define('FWPASTOPC_AUTHOR_NAME', 'radgeek');
add_filter(
/*hook=*/ 'syndicated_item_content',
/*function=*/ 'fwp_add_source_to_content',
/*order=*/ 10,
/*arguments=*/ 2
);
function fwp_add_source_to_content ($content, $post) {
// Use SyndicatedPost::author() to get author
// data in a convenient array
$content = $post->content();
// Authored by someone else
if( preg_match( '/<img[^>]+src\s*=\s*["\']?([^"\' ]+)[^>]*>/', $content, $matches ) ) {
$new_content .= 'URL IS '.$matches[0].'';
//Add custom field with author info to post
add_post_meta($post->ID, 'post_author', $new_content);
return $new_content;
}
}
I I am looking for a function that merely returns true or false. The function would check if the category archive being queried is a child of a particular parent category. The function would look something like this (similar to the is_category() function):
if(is_child_of_category('3')){ //do something }
if(is_child_of_category('4')){ //do something else }
if(is_child_of_category('5')){ //do something entirely different }
I have looked through the documentation and the forums but have not found any solutions, any ideas if this has been done or how one would go about it?
/////////////
addendum
////////////
Here is the working code that I wrote with help from Gavin:
Thanks Gavin
first a function for the functions.php file to get the category id:
function getCurrentCatID(){
global $wp_query;
if(is_category() || is_single()){
$cat_ID = get_query_var('cat');
}
return $cat_ID;
}
Next use cat_is_ancestor_of
$post = $wp_query->post;
$id = getCurrentCatID();
if ( cat_is_ancestor_of(3, $id) { include(TEMPLATEPATH . '/unique.php'); }
cat_is_ancestor_of
This will return true still, however, if the category is a grandchild of the specified category.
I need something similar yesterday, so I wrote this function which hands me back an array with all the child categories + the parent-category (which might be useful if you want to, let's say, hide the comment form on all FAQ-cat posts and childs thereof, but show it on others).
Pass $catname as a var and get an array back, which you can use as an argument in e.g. in_category() function.
// Get List of Child Categories
function get_child_cats( $catname ) {
$parentcat = get_cat_ID( '$catname' );
$subcat = get_categories( array('child_of' => $parentcat ) );
$cat_array = array();
array_push($cat_array, $parentcat); // add the parent cat to the array
foreach ($subcat as $sc) {
array_push($cat_array, $sc->cat_ID);
}
return $cat_array;
}