WordPress: Get terms from author - php

On the author archive page I want to show every taxonomy (in my case product category) in which the author has posts (in my case WooCommerce products).
To do so, I'm using the following code:
$posts = get_posts( array('post_type' => 'product', 'posts_per_page' => -1, 'author' => $author_id) );
$author_categories = array();
//loop over the posts and collect the terms
foreach ($posts as $p) {
$author_categories = wp_get_object_terms( $p->ID, 'product_cat');
if ( ! empty( $author_categories ) && ! is_wp_error( $author_categories ) ){
echo '<div class="d-flex flex-wrap">';
foreach ($author_categories as $author_category) {
//var_dump($t);
$author_category_link = get_term_link( $author_category );
$author_category_name = $author_categories[] = $author_category->name;
echo '<a href="'.esc_url( $author_category_link ).'" class="p-2 p-lg-5 bg-light text-center">';
echo $author_category_name;
echo '</a>';
}
echo '</div>';
}
}
wp_reset_postdata();
The problem is, that the product category appears multiple times. I guess for every post in that product category.
Is there any way to collect the terms first and display them only once ordered by the count of posts in the product category?

You should first collect all categories in a container array. By using the ID or the name of the category as the array key when adding categories to the array, you eliminate duplicates. Then you just loop over the resulting array to echo the categories.
// First just collect the distinct categories.
$posts = get_posts( array('post_type' => 'product', 'posts_per_page' => -1, 'author' => $author_id) );
$all_author_categories = array();
foreach ($posts as $p) {
$author_categories_for_p = wp_get_object_terms( $p->ID, 'product_cat');
if ( ! empty( $author_categories_for_p ) && ! is_wp_error( $author_categories_for_p ) ){
foreach ($author_categories_for_p as $author_category) {
$all_author_categories[$author_category->name] = $author_category;
}
}
}
// Then just loop over the collected categories and display them.
echo '<div class="d-flex flex-wrap">';
foreach($all_author_categories as $author_category) {
$author_category_link = get_term_link( $author_category );
$author_category_name = $author_categories[] = $author_category->name;
echo '<a href="'.esc_url( $author_category_link ).'" class="p-2 p-lg-5 bg-light text-center">';
echo $author_category_name;
echo '</a>';
}
echo '</div>';
Remarks:
This code does not scale well when you have a lot of posts. You should use a custom query instead.
I am pretty sure the wp_reset_postdata(); is not needed at the end, because you are not altering the global $post object.

Related

Wordpress loop: custom number of posts and sort by date

I have tried to find a solution to something I need on the website (example here: https://www.baiweb.nl/). I have been looking for a way to show a custom number of posts per category AND sort them by date. I have managed to get a single post per category, but I can't seem to fix the rest. It sorts the posts itself by date now, but not all of them.
So, my questions are:
Is it possible to sort this loop, with all different categories, by date?
Is it possible to control the number of posts shown per category? This one is extra for me, not essential, but it would be nice.
Hope someone can help! Thanks a lot in advance for your time!
Here is my code used in the loop now:
<?php
$categories = get_categories();
$cats = array();
foreach($categories as $category) {
$cats[] = $category->name . ", ";
}
$exclude_posts = array();
foreach( $cats as $cat ) {
// build query argument
$query_args = array(
'category_name' => $cat,
'showposts' => 1,
'post_type' => 'post',
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'DESC'
);
// exclude post that already have been fetched
// this would be useful if multiple category is assigned for same post
if( !empty($exclude_posts) )
$query_args['post__not_in'] = $exclude_posts;
// do query
$query = new WP_Query( $query_args );
// check if query have any post
if ( $query->have_posts() ) {
// start loop
while ( $query->have_posts() ) {
// set post global
$query->the_post();
// add current post id to exclusion array
$exclude_posts[] = get_the_ID();
?>
<article id="post-<?php the_ID(); ?>" <?php post_class('loop');?>>
<div class="corner"><span><?php foreach((get_the_category()) as $category){ echo $category->name.'<br> '; } ?></span></div>
<!-- thumbnail -->
<a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>" class="image">
<?php
$thumb_id = get_post_thumbnail_id();
$thumb_url = wp_get_attachment_image_src($thumb_id,'medium', true);
if ( in_category('2') || in_category('32') ) {
echo '<div class="newstitle">' . the_title() . '</div>';
}
else {
if ( has_post_thumbnail()) {
echo "<div class='ctr-image test2' style='background-image: url(" . $thumb_url[0] . ")'></div>";
}
else {
echo '<div class="newstitle">' . the_title() . '</div>';
}
}
?>
</a>
<div class="content">
<span class="date"><?php the_time('j/m/Y'); ?></span>
<h3>
<a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>">
<?php if ( in_category('2') || in_category('32') ) {}
else { echo the_title();} ?>
</a>
</h3>
<div class="text">
<?php html5wp_excerpt('html5wp_index'); // Build your custom callback length in functions.php ?>
</div>
</div>
</article>
<?php
// do something
}
} else {
// no posts found
}
// Restore original Post Data
wp_reset_postdata();
} ?>
You were close. Your categories foreach loop has to englobe everything. Then we do a simple loop but we specify what arguments to use depending on each categories.
Here is our final result.
<?php
$categories = get_categories(); // ... get all our categories
foreach( $categories as $category ) { // ... start foreach categories
if ( $category->name == 'Mercury' ) { // ... if our category name is 'Mercury'
$posts_per_page = 1; // ... 1 post per page if our category is named 'Mercury'
} else { // ... else, for all other categories
$posts_per_page = 3; // ... 3 posts per page
};
$args = array( // ... all our arguments
'posts_per_page' => $posts_per_page, // ... 1 or 3 posts per page depending on our categories
'post_type' => 'post',
'category_name' => $category->name,
'post_status' => 'publish',
'orderby' => 'date', // ... order by date
'order' => 'ASC', // ... most recent first
);
$query = new WP_Query( $args ); // .. start a new loop
if( $query->have_posts() ):
echo '<section>';
echo '<h1>' . $category->name . '</h1>'; // ... only display our section IF a post exist in the category
while( $query->have_posts() ): $query->the_post();
echo '<article>'; // ... our post template
the_title( '<h4>', '</h4>' );
echo '</article>';
endwhile;
echo '</section>';
endif;
wp_reset_postdata(); // ... After looping through a separate query, this function restores the $post global to the current post in the main query.
}; // ... end foreach categories
?>
Thank you so much for your quick and comprehensive answer! The part of the number of categories is working very well, however, the outcome is slightly different than I want. It may be that my question was not clear, apologies for that.
What you have already made beautiful is all the categories with posts that belong to it. What I want to achieve is that all messages are mixed up, sorted by date and, what was already done here, I can indicate how many posts are in per category. Is that even possible?
Some screenshotsof the outcome of your code:
This is what I am trying, except now I need to sort this by date:
This is the code slightly adjusted:
<?php
$categories = get_categories(); // ... get all our categories
foreach( $categories as $category ) { // ... start foreach categories
if ( $category->name == 'Mercury' ) { // ... if our category name is 'Mercury'
$posts_per_page = 1; // ... 1 post per page if our category is named 'Mercury'
} else { // ... else, for all other categories
$posts_per_page = 2; // ... 3 posts per page
};
$args = array( // ... all our arguments
'posts_per_page' => $posts_per_page, // ... 1 or 3 posts per page depending on our categories
'post_type' => 'post',
'category_name' => $category->name,
'post_status' => 'publish',
'orderby' => 'date', // ... order by date
'order' => 'ASC', // ... most recent first
);
$query = new WP_Query( $args ); // .. start a new loop
if( $query->have_posts() ):
// echo '<section>';
// echo '<h1>' . $category->name . '</h1>'; // ... only display our section IF a post exist in the category
while( $query->have_posts() ): $query->the_post();
echo '<article>'; // ... our post template
echo '<h1>' . $category->name . '</h1>';
the_time('j/m/Y');
the_title( '<h4>', '</h4>' );
echo '</article>';
endwhile;
// echo '</section>';
endif;
wp_reset_postdata(); // ... After looping through a separate query, this function restores the $post global to the current post in the main query.
}; // ... end foreach categories ?>
Hope this is clear, thanks again!

Display current category first then child categories in WooCommerce

I'm trying to display in the sidebar the current page's category and it's subcategories. The title should be the current category's name and linked to the current category as well. An example of what I'm trying to achieve can be seen here in the sidebar: https://food52.com/shop/pantry
This is my current site as an example:https://farmtofrank.wpengine.com/product-category/prepared-foods/
This is the code I've created so far:
<?php
$terms = get_terms([
'taxonomy' => get_queried_object()->taxonomy,
'parent' => get_queried_object_id(),
]);
global $post;
$terms = get_the_terms( $post->ID, 'product_cat' );
echo '<div>';
foreach ( $terms as $term) {
echo '<p class="filters">' . $term->name . '</p>';
}
echo '</div>';
?>
It works but it puts the parent link at the bottom of the list. How can I keep the parent link at the top above the subcategories?
I suppose that this is related to product category archive pages. In this case, you are very near, try:
$queried_object = get_queried_object();
if ( is_product_category() && is_a($queried_object, 'WP_Term') ) {
$taxonomy = $queried_object->taxonomy;
echo '<h2 class="shop__sidebar-heading">
' . $queried_object->name . '
</h2>';
$children_terms = get_terms(['taxonomy' => $taxonomy, 'parent' => $queried_object->term_id]);
if ( ! empty($children_terms) ) {
echo '<ul class="'.$queried_object->slug.' child-terms">';
// Loop through children terms
foreach ( $children_terms as $term) {
echo '<li class="filters">' . $term->name . '</li>';
}
echo '</ul>';
}
}
Tested and works. It will require some styling (CSS).

How to Fetch Woo Commerce Product Categories icons with names with get_term(product_cat) or something else .. can i fetch only name?

<?php
$orderby = 'id';
$order = 'asc';
$hide_empty = false ;
$cat_args = array(
'orderby' => $orderby,
'order' => $order,
'hide_empty'=> 0,
);
$product_categories = get_terms( 'product_cat', $cat_args );
if( !empty($product_categories) ){
echo '
<ul class="display-categories list-group nav navbar-nav">';
foreach ($product_categories as $key => $category) {
echo '
<li class="list-group-item">';
echo '<a href="'.get_term_link($category).'" >';
echo '<img src="'.get_term_link($category).'" />' ;
echo $category->name;
echo '</a>';
echo '</li>';
}
echo '</ul>';
}
?>
I can't fetch the product category icons.. i want it to fetch category icons with the list of names ... please somebody help me out with this thanks
Category Icons / Images has been stored in terms meta and can be retrieved by using
$term_meta = get_woocommerce_term_meta( $category_id, 'thumbnail_id', true );
$category_icon = wp_get_attachment_url( $term_meta );

Adding Woocommerce category meta value to a sidebar

I have added a custom post type dropdown to my product categories (see below):
$args = array(
'posts_per_page' => -1,
'post_type' => 'banner',
);
$stickers = get_posts( $args );
echo '<label for="product-banner">Productbanner</label>';
echo '<select name="product-banner" class="product-banner">';
echo '<option value="">Geen banner</option>';
foreach($stickers as $sticker){
echo '<option value="'.$sticker->ID.'">'.get_the_title($sticker->ID).'</option>';
}
echo '</select>';
And to save it:
if ( isset( $_POST['product-banner'] ) ) {
$new_meta_value = $_POST['product-banner'];
$meta_key = 'product-banner';
update_term_meta( $term_id, $meta_key, $new_meta_value );
}
I am showing the sidebar on category pages, and i would like to show the featured image of my selected custom post type dropdown item in there as well.
Is there an easy solution to do this?
Thanks in advance.
EDIT :
$tax_id = get_queried_object()->term_id;
if (get_term_meta($tax_id, 'product-banner', true)) {
$banner_id = get_term_meta($tax_id, 'product-banner', true);
//echo $banner_id;
$banner_post = get_post($banner_id);
$banner_img = get_post_thumbnail_id($banner_post);
echo '<img src="'.wp_get_attachment_image_url( $banner_img, 'full' ).'"style="margin-bottom:-17px;border:1px solid #e8e8e8;" />';
//echo get_queried_object()->term_id;
}

wordpress, get category names for a custom post type

Is there a better way to get the category names for a custom post type in wordpress?
<?php // get the portfolio categories
$terms = get_the_terms( $post->ID, 'filters' );
if ( $terms && ! is_wp_error( $terms ) ) :
$names = array();
$slugs = array();
foreach ( $terms as $term ) {
$names[] = $term->name;
$slugs[] = $term->slug;
}
$name_list = join( " / ", $names );
$slug_list = join( " category-", $slugs );
endif;
?>
<!-- BEGIN portfolio-item-->
<li class="portfolio-item third column category-<?php echo $slug_list; ?>" data-filter="category-<?php echo $slug_list; ?>">
<?php
$taxonomy = 'filters';
$terms = get_terms($taxonomy);
if ( $terms && !is_wp_error( $terms ) ) :
?>
<ul>
<?php foreach ( $terms as $term ) { ?>
<li><?php echo $term->name; ?></li>
<?php } ?>
</ul>
<?php endif;?>
Or in fuctions.php place this:
function get_the_category_custompost( $id = false, $tcat = 'category' ) {
$categories = get_the_terms( $id, $tcat );
if ( ! $categories )
$categories = array();
$categories = array_values( $categories );
foreach ( array_keys( $categories ) as $key ) {
_make_cat_compat( $categories[$key] );
}
return apply_filters( 'get_the_categories', $categories );
}
and call the function as:
<?php $cat = get_the_category_custompost($post->ID, 'Your Custom Taxonomy'); ?>
My answer seems too simple, but I used this to list the categories from a wordpress plugin called DW Question Answer that has separate categories from the standard wp categories.
I am assuming that Design Wall used custom post types to create the q&a part and taxonomies to create the categories.
<ul>
<?php wp_list_categories('taxonomy=dwqa-question_category&hide_empty=0&orderby=id&title_li=');?>
</ul>
Assuming your custom taxonomy is recipegroups, i have implemented and tested this code in functions.php and i am sure that it will work in plugins too.
$recipeTerms = get_terms(array(
'taxonomy' => 'recipegroups',
));
foreach($recipeTerms as $recipeTerm){
if($recipeTerm->parent==0){
echo "<div class='termsBox'>"; // remove these div's to suit your needs..
$termLink =get_term_link( $recipeTerm );
echo "<a href='$termLink'><div class='termParent'>".$recipeTerm->name."</div></a> ";
$termChilds = get_term_children($recipeTerm->term_id, 'recipegroups' );
foreach($termChilds as $child){
$chTerm = get_term_by( 'id', $child, 'recipegroups');
$termLink =get_term_link( $chTerm );
echo "<a href='$termLink'><div class='top-cat-items'>".$chTerm->name."</div></a>";
}
echo "</div>"; // end of termsBox div
}
}

Categories