get_categories order by last post - wordpress

What is the best and shortest way in Wordpress to get_categories ordered by last posted article?
Means that categories with recent posts should appear first, is it available somehow?

Try it:
function get_sorted_categories( $order_by = 'id', $args = array() ){
global $wpdb;
$category = get_categories( $args );
$order = [
'id' => 'post.ID',
'date' => 'post.post_date',
'modified' => 'post.post_modified',
];
$order_by = $order[ $order_by ];
$q = $wpdb->get_results("SELECT tax.term_id FROM `{$wpdb->prefix}term_taxonomy` tax
INNER JOIN `{$wpdb->prefix}term_relationships` rel ON rel.term_taxonomy_id = tax.term_id
INNER JOIN `{$wpdb->prefix}posts` post ON rel.object_id = post.ID WHERE tax.taxonomy = 'category' AND post.post_type = 'post' AND post.post_status = 'publish' ORDER BY {$order_by} DESC");
$sort = array_flip( array_unique( wp_list_pluck( $q, 'term_id' ) ) );
usort( $category, function( $a, $b ) use ( $sort, $category ) {
if( isset( $sort[ $a->term_id ], $sort[ $b->term_id ] ) && $sort[ $a->term_id ] != $sort[ $b->term_id ] )
$res = ($sort[ $a->term_id ] > $sort[ $b->term_id ]) ? 1 : -1;
else if( !isset( $sort[ $a->term_id ] ) && isset( $sort[ $b->term_id ] ) )
$res = 1;
else if( isset( $sort[ $a->term_id ] ) && !isset( $sort[ $b->term_id ] ) )
$res = -1;
else
$res = 0;
return $res;
} );
return $category;
}
print_r( get_sorted_categories() );
print_r( get_sorted_categories('date') );
print_r( get_sorted_categories('modified') );
Get categories order by (post ID | post date | post modified date). Without any loop and fast!

I think the easiest way would be to loop through all of your posts ordered by post_date and then save the categories to an array. You can then loop through the categories and display them. They will be in order.
Something like this:
<?php
// Initiate array
$cats = array();
// Query arguments
$args = array(
'post_type' => 'post',
'posts_per_page' => -1,
'orderby' = 'post_date'.
'order' => 'DESC'
);
// The query
$query = new WP_Query($args);
// The loop
if($query->have_posts()) {
while($query->have_posts()) {
$query->the_post();
// Get the term object
$term = get_the_category();
// Make sure the term doesn't already exist in the array
if(!array_key_exists($term[0]->ID, $cats)) {
// Add the terms to the array
$cats[$term[0]->ID] = $term;
}
}
}
foreach($cats as $cid => $cat) {
// Loop through the categories here
}
?>
Of course, as mentioned in the comment above you could also do it the other way around and loop through the categories first then sort the array. Something like this could do:
<?php
// Initiate array
$cats = get_categories();
$recent_cats = array();
foreach($cats as $k => $cat) {
// Query arguments
$args = array(
'post_type' => 'post',
'posts_per_page' => 1,
'orderby' = 'post_date'.
'order' => 'DESC',
'cat' => $cat->term_id
);
// The query
$query = new WP_Query($args);
// The loop
if($query->have_posts()) {
while($query->have_posts()) {
$query->the_post();
$date_str = strtotime(the_date());
if(!array_key_exists($date_str, $recent_cats)) {
$recent_cats[$date_str] = $cat->name;
}
}
}
}
krsort($recent_cats);
// Loop through $recent_cats here
?>

Related

How to save or update order item meta in woocommerce admin order details page? [duplicate]

This question already has an answer here:
Save Order item custom field in Woocommerce Admin order pages
(1 answer)
Closed 2 years ago.
I want to set item meta key and value for each order item from the dashboard order details page only.
** I am trying to form submit and get the $_post data to save in hook but it's not working. How can I catch my custom form data in order update hook? or some other kind of solution also appreciated. Thanks for your kind help.**
Please review my code below:
function get_users_by_role($role, $orderby, $order) {
$args = array(
'role' => $role,
'orderby' => $orderby,
'order' => $order
);
$users = get_users( $args );
return $users;
}
add_action( 'woocommerce_before_order_itemmeta', 'so_32457241_before_order_itemmeta', 10, 3 );
function so_32457241_before_order_itemmeta( $item_id, $item, $_product ){
// wc_update_order_item_meta($item_id, $key, $value);
$users = get_users_by_role('field_worker', 'user_nicename', 'ASC');
echo '<form method="post" action=""><select name="assigned_engineer">';
echo '<option value="">Select a engineer to assign this job</option>';
foreach ( $users as $user )
{
echo $user->user_email;
echo '<option value="'.$user->ID.'">'.$user->user_email.'</option>';
}
echo '</select><input type="submit" name="set_engineer"></form>';
}
Here is my solution similar solution like this post Save Order item custom field in Woocommerce Admin order pages
function get_users_by_role($role, $orderby, $order) {
$args = array(
'role' => $role,
'orderby' => $orderby,
'order' => $order
);
$users = get_users( $args );
return $users;
}
//Add a custom field
add_action( 'woocommerce_before_order_itemmeta', 'add_order_item_sohag_assigned', 10, 2 );
function add_order_item_sohag_assigned( $item_id, $item ) {
// Targeting line items type only
if( $item->get_type() !== 'line_item' ) return;
$users = get_users_by_role('field_worker', 'user_nicename', 'ASC');
$opts = array();
foreach ( $users as $user )
{
$opts[$user->ID] = $user->user_email;
}
woocommerce_wp_select( array(
'id' => 'sohag_assigned_'.$item_id,
'label' => __( 'Assigned Engineer', 'cfwc' ),
'description' => __( 'Select an engineer', 'ctwc' ),
'desc_tip' => true,
'class' => 'woocommerce',
'options' => $opts,
'value' => wc_get_order_item_meta( $item_id, '_sohag_assigned' ),
) );}
// Save the custom field value
add_action('save_post_shop_order', 'save_order_item_sohag_assigned_value');
function save_order_item_sohag_assigned_value( $post_id ){
if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
return $post_id;
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return $post_id;
if ( ! current_user_can( 'edit_shop_order', $post_id ) )
return $post_id;
$order = wc_get_order( $post_id );
// Loop through order items
foreach ( $order->get_items() as $item_id => $item ) {
if( isset( $_POST['sohag_assigned_'.$item_id] ) ) {
wc_update_order_item_meta( $item_id, '_sohag_assigned',
sanitize_text_field( $_POST['sohag_assigned_'.$item_id] ) );
}
}
}
// Optionally Keep the new meta key/value as hidden in backend
add_filter( 'woocommerce_hidden_order_itemmeta','additional_hidden_order_itemmeta', 10, 1 );
function additional_hidden_order_itemmeta( $args ) {
$args[] = '_sohag_assigned';
return $args;
}

Query to get Attributes based on Product Category selected in WooCommerce?

I need to implement custom functionality like "Product filter by Attributes" widget works in woocommerce.
For example in Product category page:
In Parent Category like Clothing, it loads all the attributes filter (pa_color , pa_size).
Now, when you check sub-category of that parent category i.e., Hoodies. It gets filtered and loads only related attributes (pa_color).
Please suggest the query to achieve this requirement.
This is how I am getting the data as per my requirement :
$filter_raw = array();
$attrs_raw = wc_get_attribute_taxonomy_names(); // Getting data of attributes assign in backend.
$cat_name = get_term($request['category'], 'product_cat', ARRAY_A ); //Category data by category ID.
$args = array(
'category' => array($cat_name['slug'] )
);
foreach( wc_get_products($args) as $product ){
foreach( $product->get_attributes() as $attr_name => $attr ){
$filter_raw[] = $attr_name;
if(is_array($attr->get_terms())){
foreach( $attr->get_terms() as $term ){
$terms_raw[] = $term->name;
}
}
}
}
$filters = array_unique(array_intersect((array)$filter_raw,(array)$attrs_raw)); //Filtering the attributes used by products in particular category
if(is_array($filters)){
foreach ( $filters as $filter ){
$terms = get_terms( $filter );
if ( ! empty( $terms ) ) {
$return['items'][ $filter ] = array(
'id' => $filter,
'type' => 'checkbox',
'label' => $this->decode_html( wc_attribute_label( $filter ) ),
);
foreach ( $terms as $term ) {
if(in_array($term->name,$terms_raw)){ //Filtering the terms from attribute used by the products in a category and showing required result.
$return['items'][ $filter ]['values'][] = array(
'label' => $this->decode_html( $term->name ),
'value' => $term->slug,
);
}
}
}
}
}
print_r($return);

WooCommerce REST API : query products by multiple attributes

According to the API : http://woocommerce.github.io/woocommerce-rest-api-docs/#list-all-products we can filter products by a single attribute. But Is it impossible to search by multiple attributes through API ?
Example : "I want red shirts". Here attribute is color and attribute term is red. To accomplish the search, the query string goes like this : products?category=17&attribute=pa_color&attribute_term=22&
And we get the red shirts only.
But for "I want red medium shirts" , here an additional size attribute with value medium is encountered. And according to the API there is no way to associate both the color and the size attributes in the query string. So the query -
products?category=17&attribute=pa_color&attribute_term=22&attribute=pa_size&attribute_term=24&
returns all products from the store
Is there any workaround ?
I have written custom query that does it all :D
This is a callback function. All you need to do is create new endpoint with this callback:
Here is a documentation:
category - string (category slug) - filter by products category.
per_page - int (default - from admin) - show items on one page.
offset - int (default - 1) - show page number.
order - string (ASC/DESC, default: desc) - order products ascending or descending.
orderby - string (name, price, default: name) - order products by key.
filter - array
[pa_attribute_name (string) ] = array of ID's.
[min_price (string) ] = int.
[max_price (string) ] = int.
Example:
/wp-json/go/v1/products/?category=smartphones&filter[pa_brand]=87,88&filter[pa_colour]=17&filter[min_price]=1&filter[max_price]=50&per_page=10&offset=1&order=DESC&orderby=price
Here is a function:
public function get_products_list_callback( \WP_REST_Request $request ) {
$params = $request->get_params();
$category = General_Helper::get_array_value( 'category', $params );
$filters = General_Helper::get_array_value( 'filter', $params );
$per_page = General_Helper::get_array_value( 'per_page', $params );
$offset = General_Helper::get_array_value( 'offset', $params );
$order = General_Helper::get_array_value( 'order', $params );
$orderby = General_Helper::get_array_value( 'orderby', $params );
$output = [];
// Use default arguments.
$args = [
'post_type' => Config::POST_TYPE_SLUG_PRODUCT,
'posts_per_page' => get_option( 'posts_per_page' ),
'post_status' => 'publish',
'paged' => 1,
];
// Posts per page.
if ( ! empty( $per_page ) ) {
$args['posts_per_page'] = $per_page;
}
// Pagination, starts from 1.
if ( ! empty( $offset ) ) {
$args['paged'] = $offset;
}
// Order condition. ASC/DESC.
if ( ! empty( $order ) ) {
$args['order'] = $order;
}
// Orderby condition. Name/Price.
if ( ! empty( $orderby ) ) {
if ( $orderby === 'price' ) {
$args['orderby'] = 'meta_value_num';
} else {
$args['orderby'] = $orderby;
}
}
// If filter buy category or attributes.
if ( ! empty( $category ) || ! empty( $filters ) ) {
$args['tax_query']['relation'] = 'AND';
// Category filter.
if ( ! empty( $category ) ) {
$args['tax_query'][] = [
'taxonomy' => Config::TAXONOMY_SLUG_PRODUCT,
'field' => 'slug',
'terms' => [ $category ],
];
}
// Attributes filter.
if ( ! empty( $filters ) ) {
foreach ( $filters as $filter_key => $filter_value ) {
if ( $filter_key === 'min_price' || $filter_key === 'max_price' ) {
continue;
}
$args['tax_query'][] = [
'taxonomy' => $filter_key,
'field' => 'term_id',
'terms' => \explode( ',', $filter_value ),
];
}
}
// Min / Max price filter.
if ( isset( $filters['min_price'] ) || isset( $filters['max_price'] ) ) {
$price_request = [];
if ( isset( $filters['min_price'] ) ) {
$price_request['min_price'] = $filters['min_price'];
}
if ( isset( $filters['max_price'] ) ) {
$price_request['max_price'] = $filters['max_price'];
}
$args['meta_query'][] = \wc_get_min_max_price_meta_query( $price_request );
}
}
$the_query = new \WP_Query( $args );
if ( ! $the_query->have_posts() ) {
return $output;
}
while ( $the_query->have_posts() ) {
$the_query->the_post();
$output[] = get_the_title();
}
wp_reset_postdata();
return $output;
}
Hope it helps
Try to request like this:
products?attribute=pa_color&attribute_term=51,50&per_page=100
Its worked for me.
Latest woocommerce-api wc/v2!
after test on WooRest API v3, you can pass multiple term taxonomy IDs.
You have to pass a string with ids separated by comma, this will be parsed as an array by WooRest API v3.
Like this :
/wp-json/wc/v3/products/?category=1,2,3,4
Don't forget to encode query parameter or use Automattic\WooCommerce package
Enjoy,
I just looked into the woocommerce rest api implementation at
plugins/woocommerce/includes/api/class-wc-rest-products-controller.php
file but unfortunately their codes doesn't support multiple attributes.
But you can write your own query to achieve your goal.
$args = array(
'post_type' => 'product',
'tax_query' => array(
array(
'relation' => 'AND',
array(
'taxonomy' => 'pa_color',
'field' => 'term_id',
'terms' => array( 'red' ),
),
array(
'taxonomy' => 'pa_size',
'field' => 'term_id',
'terms' => array( 'Long' ),
),
),
),
);
$products = new WP_Query( $args );
print_r($products);

Hide specific category in listings

I'm working on a Wordpress theme. The theme is Classifieds theme from premiumpress. The theme has a shortcode to list all the listings. The corresponding shortcode is [LISTINGS].
The function for the shortcode is as follows
/* =============================================================================
[LISTINGS] - SHORTCODE
========================================================================== */
function wlt_page_listings( $atts, $content = null ) {
global $userdata, $wpdb, $CORE; $STRING = ""; $extra=""; $i=1; $stopcount = 4;
extract( shortcode_atts( array( 'query' => '', 'show' => '', 'type' => '', 'cat' => '', 'orderby' => '', 'order' => '', 'grid' => "no", 'featuredonly' => "no"), $atts ) );
// SETUP DEFAULTS
if(!isset($atts['show']) || (isset($atts['show']) && $atts['show'] == "") ){ $atts['show'] = 5; }
if($atts['type'] == ""){ $atts['type'] = THEME_TAXONOMY.'_type'; }
if($atts['orderby'] == ""){ $atts['orderby'] = "post_title"; }
if($atts['order'] == ""){ $atts['order'] = "desc"; }
// DEFAULT FOR LIST STYLE
if($grid == "yes"){
$sstyle = "grid_style";
$STRING .= '<script language="javascript">jQuery(window).load(function() { equalheight(\'.grid_style .item .thumbnail\');});</script>';
}else{
$sstyle = "list_style";
}
$query= str_replace("#038;","&",$query);
if(strlen($query) > 1){
// ADD ON POST TYPE FOR THOSE WHO FORGET
if(strpos($query,'post_type') == false){
$args = $query ."&post_type=".THEME_TAXONOMY."_type";
}else{
$args = $query;
}
}elseif($featuredonly == "yes"){
$args = array('posts_per_page' => $atts['show'],
'post_type' => $atts['type'], 'orderby' => $atts['orderby'], 'order' => $atts['order'],
'meta_query' => array (
array (
'key' => 'featured',
'value' => 'yes',
)
)
);
}else{
/*** default string ***/
$args = array('posts_per_page' => $atts['show'], 'post_type' => $atts['type'], 'orderby' => $atts['orderby'], 'order' => $atts['order'] );
}
/*** custom category ***/
if(strlen($atts['cat']) > 1){
$args = array('tax_query' => array( array( 'taxonomy' => str_replace("_type","",$atts['type']) ,'field' => 'term_id','terms' => array( $atts['cat'] ))), 'posts_per_page' => $atts['show'] );
}
// BUILD QUERY
$the_query = new WP_Query( hook_custom_queries($args) );
if ( $the_query->have_posts() ) {
$STRING .= '<div class="_searchresultsdata"><div class="wlt_search_results row '.$sstyle.'">';
while ( $the_query->have_posts() ) { $the_query->the_post(); $post = get_post();
$STRING .= '<div class="item '.hook_gallerypage_item_class('col-md-4').$CORE->FEATURED($post->ID).'">'.hook_item_cleanup(hook_gallerypage_item($CORE->ITEM_CONTENT($post))).'</div>';
}
$STRING .= '</div></div><div class="clearfix"></div>';
}
// END QUERY
wp_reset_postdata();
return $STRING;
}
add_shortcode( 'LISTINGS', array($this,'wlt_page_listings') );
The shortcode does not have an attribute to hide certain categories. I need to display all listings, except the ones in wedding category, which is a custom taxonomy. Is there any way to do that with the above code?
Will something like this work?
if ( is_tax( 'listing', 'wedding' ) ) {
do not display the wedding listings and display the rest}
Any suggestions?
EDITS:
This my online site url : http://webzer.comxa.com/
The main page shows the all the products.I like to have all but not one that is from wedding category coz i have separate page to list wedding category.
i have tried this where 51 is the page id of my home store page
if ( is_page( 51 ) && is_tax( 'listing', 'wedding' ) ) {
?><style>.caption {display:none!important;}</style>
<?php } ?>
this also didn't work
Consider this :
change
function wlt_page_listings( $atts, $content = null ) {
to
function wlt_page_listings( $atts, $content = null, $exclude=array(99) ) { // 99 is wedding cat id
where $exclude is an optional array of excluded cat names (99 in there for ease of testing/use)
Then in the
while ( $the_query->have_posts() ) {
add something like this:
$post = get_post(); // get post obj, will use the ID attr
$cats = wp_get_post_categories( $post->ID )); // returns array of IDs for all cats
foreach($exclude as $x){ // loop on the excluded cat ids
if(in_array($x, $cats))continue; // if excluded skip
}
http://codex.wordpress.org/Function_Reference/wp_get_post_categories
I think this will work or at least got you close.
display:none is bad mojo as the content will still be in your source code for others to see.
I hope I addressed the problem correctly for you, cheers.

List authors that have written certain number of posts in category/tags in Wordpress

I'm struggling to get the list of authors on the category page. I need to list the authors who have written at least 5 articles in that category.
I need something like this in tags also.
Any idea how to do this in wordpress?
Its only possible with a custom SQL query so here is a simple function which should return an array with user id's of users with at least $n posts in the current term archive, which means it should work in categories, tags and custom taxonomies
function get_authors_with($num = 5){
global $wpdb;
$term_slug = get_query_var( 'term' );
$taxonomyName = get_query_var( 'taxonomy' );
$current_term = get_term_by( 'slug', $term_slug, $taxonomyName );
$sub_q = $wpdb->prepare("SELECT * FROM $wpdb->posts
INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)
INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
WHERE ($wpdb->term_taxonomy.term_id = %s
AND $wpdb->term_taxonomy.taxonomy = '%s'
AND $wpdb->posts.post_type = 'post'
AND $wpdb->posts.post_status = 'publish')",
$current_term->term_id,
$taxonomyName
);
$sql = $wpdb->prepare("SELECT $wpdb->posts.post_author, FROM (%s)
GROUP BY $wpdb->posts.post_author
HAVING count(*) > %s",
$sub_q,
$num
);
return $wpdb->get_results($sql);
}
Try this.
function list_author_in_this_cat ($with) {
if (is_category()) {
$current_category = get_query_var('cat');
$args = array(
'numberposts' => -1,
'category' => $current_category,
'orderby' => 'author',
'order' => 'ASC'
);
} else {
$tag_id = get_query_var('tag_id');
$args = array(
'numberposts' => -1,
'tag__in' => $tag_id,
'orderby' => 'author',
'order' => 'ASC'
);
}
$cat_posts = get_posts($args);
$author_id_array = array();
$user_posts = array();
foreach( $cat_posts as $cat_post ):
$user_posts[$cat_post->post_author][] = $cat_post->ID;
endforeach;
foreach( $user_posts as $key => $user_post ):
$user_post = array_unique($user_post);
$count_user_posts[$key] = count($user_post);
if ($count_user_posts[$key] >= $with) {
$author_id_array[] = $key;
}
endforeach;
return $author_id_array; }
In your theme files, place this code wherever you want the list of authors to be displayed:
if (is_category() || is_tag()) {
$at_least = 5; // at least 5 articles in current category or tags
$author_array = list_author_in_this_cat ($at_least);
foreach (array_slice($author_array, 0, 4) as $author) : // limit 4 results
$name = get_userdata($author)->display_name;
$link = get_userdata($author)->user_login;
echo "<a href='/author/".$link."'>".$name."</a>\n";
endforeach;
}
Add the following code to your theme's function.php
function get_authors_in_category ( $category_id, $min_posts ) {
$posts = get_posts( array( 'numberposts' => 1000, 'category' => $category_id ) );
$author_count = array();
foreach ($posts as $post) {
if( array_key_exists( get_the_author_meta( 'display_name', $post->post_author ), $author_count ) ) {
$author_count[get_the_author_meta( 'display_name', $post->post_author )]++;
} else { $author_count[get_the_author_meta( 'display_name', $post->post_author )] = 1; }
}
$authors = array();
foreach ( $author_count as $author_name => $count ) {
if ( $min_posts <= $count ) {
$authors[] = $author_name;
}
return $authors;
}
This function as you can see returns an array of authors who have a minimum number of posts in a category. Category ID has to be passed, this can be obtained using the wordpress function get_cat_ID.
You can call this function from any where in the theme and display the authors as you wish.
Note: This is a more resource intensive than the custom SQL functions. Also this function might have some errors, I typed it here and didn't test it.
I did some simple coding with query post method.,
<?php
$cur_cat_id = get_cat_id(single_cat_title("",false));
$posts=query_posts("cat=$cur_cat_id&order=ASC");
foreach($posts as $post){
$number_of_posts = number_format_i18n(get_the_author_posts($post->post_author));
if($number_of_posts>5)
{
echo the_author_meta('user_nicename',$post->post_author)."(".number_format_i18n(get_the_author_posts($post->post_author)).")<br>";
}
}
?>
I think this may help you to resolve your problem.

Resources