Does anyone know how to incorporate a while loop into a basic order by filter? I have the following basic filter in my functions.php page that orders my products by the featured products and it works:
add_filter('woocommerce_get_catalog_ordering_args', 'am_woocommerce_catalog_orderby');
function am_woocommerce_catalog_orderby( $args ) {
if(!$_GET['orderby']) {
$args = array(
'orderby' => array( 'meta_value' => 'DESC' ),
'meta_key' => '_featured'
);
return $args;
}
}
My problem is I want to use some more advanced while loops to try and get multiple different arguments tied into the same args. I am trying to show my featured products first, then load that into an array then get my next loop and only show the products that are 6 months old or younger and add that to my array, then show everything else and sort them by menu_order and title and add it to my array as shown below:
add_filter('woocommerce_get_catalog_ordering_args', 'am_woocommerce_catalog_orderby');
function am_woocommerce_catalog_orderby( $my_post_array ) {
if(!$_GET['orderby']) {
//First loop - show featured
$args['orderby'] = array( 'meta_value' => 'DESC' );
$args['meta_key'] = '_featured';
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
$post_id = get_the_ID();
$my_post = my_post_function($post_id);
//Store the items in an array
$my_post_array [] = $my_post;
query_posts($args);
endwhile;
wp_reset_query();
//Second loop - Show newer than 6 months
$args = array(
'orderby' => 'date',
'order' => 'DESC',
'date_query' => array(
array(
'before' => '6 months ago',
),
)
);
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
$post_id = get_the_ID();
$my_post = my_post_function($post_id);
//Store the items in an array
$my_post_array [] = $my_post;
query_posts($args);
endwhile;
wp_reset_query();
//Third loop - show everything else and sort by menu_order and title
$args['orderby'] = array( 'menu_order' => 'ASC', 'title' => 'ASC' );
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
$post_id = get_the_ID();
$my_post = my_post_function($post_id);
//Store the items in an array
$my_post_array [] = $my_post;
query_posts($args);
endwhile;
wp_reset_query();
//Remove duplicate entries from the array
array_unique ( $my_post_array, SORT_STRING );
}
}
Then the last thing I do is remove my duplicates. Only problem is it does not work and I am not sure where I am going wrong, I have not done something like this before so I could be working in the wrong area or missing something obvious. Anyone have ideas on how I can trouble shoot this or does anyone see something that may be causing me issues? Thanks for the help, still learning and trying to improve!
Related
Spent 3 days trying to get the WP_Query to work with Elementor, however had no luck so far. Elementor either refuses to process the query or does not filter the posts at all. Can somebody help me and point out some mistakes that I have in my code?
Context: the query looks for current WP user's enrollment records of post_type 'tutor_enrolled' in 'wpv1_posts' and collects IDs of user's enrolled courses into $course_ids[]. The query should then filter only the posts with IDs matching the $course_ids array, therefore displaying all of current user's courses on Elementor frontend.
function custom_query_callback( $query ) {
$current_user = wp_get_current_user();
$args = array(
'post_type' => 'tutor_enrolled',
'author' => $current_user->ID,
);
$enrollments = new WP_Query( $args );
if ( $enrollments->have_posts() ) {
$course_ids = array();
while ( $enrollments->have_posts() ) {
$enrollments->the_post();
$course_ids[] = get_post_field( 'post_parent' );
}
wp_reset_postdata();
$args = array(
'post_type' => 'courses',
'post__in' => $course_ids,
'posts_per_page' => -1,
'orderby' => 'post__in'
);
$query = new WP_Query ( $args );
}
}
}
add_action( 'elementor/query/custom_query_callback', 'custom_query_callback' );
I tried calling get_course_ids() and custom_query_callback() as two separate functions and trying to pass the $course_ids array in $query->set( 'post__in', $course_ids );.
Then I also moved the variables outside of the function, ending up with:
$current_user = wp_get_current_user();
$args = array(
'post_type' => 'tutor_enrolled',
'author' => $current_user->ID,
);
$enrollments = new WP_Query( $args );
if ( $enrollments->have_posts() ) {
$course_ids = array();
while ( $enrollments->have_posts() ) {
$enrollments->the_post();
$course_ids[] = get_post_field( 'post_parent' );
}
wp_reset_postdata();
}
add_action( 'elementor/query/custom_query_callback', function( $query ) {
$query->set( 'post__in', $course_ids );
});
None of the above resolved my issue and kept causing errors in Elementor.
I'm trying to update the Item Name in the wp_woocommerce_order_items table and found the function wc_update_order_item to do the trick.
I want it to change to a randomly picked product. They main thing here is I already know the order_item_id that I want to change.
Here's my code:
$order_item_id = array(1,2,3);
$num = 3;
$ctr = 0;
$products = new WP_Query( array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => $num,
'orderby' => 'rand',
));
if ( $products->have_posts() ): while ( $products->have_posts() ): $products->the_post();
wc_update_order_item($order_item_id[$ctr], array('order_item_name' => $products->post->post_title));
$ctr++;
endwhile; wp_reset_postdata(); endif;
The wc_update_order_item() is where it is supposed to update the order item name. It does update the order_item_name but not with the current $products->post->post_title value. It updates with with a random product title.
How do I know the title being saved is different from the current post_title inside the loop? If I echo $products->post->post_title inside the loop, it displays the current product name, as it should, but the updated order_item_name has a different value.
Try the following that will get the related product IDs corresponding to the Order items, to exclude them from the WP_Query, avoiding having the same product names:
$order_item_ids = array(1,2,3);
$num = 3;
$ctr = 0;
$exluded_ids = array();
// Loop through the Order items Ids
foreach ( $order_item_ids as $item_id ) {
// Get the order ID from the order Item ID
$order_id = wc_get_order_id_by_order_item_id( $item_id );
// Get the WC_Order object instance
$order = wc_get_order( $order_id );
// Get the WC_Order_Item_Product object instance
$item = $order->get_item( $item_id );
// Products IDs to be excluded from the WP_Query (array)
$exluded_ids[] = $item->get_product_id();
}
$products = new WP_Query( array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => $num,
'orderby' => 'rand',
'post__not_in' => $exluded_ids,
));
if ( $products->have_posts() ):
while ( $products->have_posts() ): $products->the_post();
wc_update_order_item($order_item_id[$ctr], array('order_item_name' => $products->post->post_title));
$ctr++;
endwhile;
wp_reset_postdata();
endif;
It should work.
Now as we don't know how you get the $order_item_id array, it's not possible to know what really happen. It should be better to explain what you are trying to do from the start.
I am trying to set my default sort for my products in WordPress with Woocommerce to show me all the featured products first, then any new products that are no older than 120 days, then show everything else by menu order and finally by the title. Below is my initial code that does kind of do what i want but i have no idea how to set a date range of 120 days or newer.
add_filter('woocommerce_get_catalog_ordering_args', 'am_woocommerce_catalog_orderby');
function am_woocommerce_catalog_orderby( $args ) {
if(!$_GET['orderby']) {
$args['orderby'] = array(
'meta_value' => 'DESC',
'date' => 'DESC',
'menu_order' => 'ASC',
'title' => 'ASC'
);
$args['meta_key'] = '_featured';
return $args;
}
}
UPDATE
Ok so I have done some searching and i found some code that is supposed to loop through arguments and then remove duplicates, being a noob I am not sure what I am missing. My code below gets an error: Fatal error: Call to a member function have_posts() on null so i tried to add $loop = new WP_Query( $args ); but then the code does nothing. So I am lost and looking for some clues on what i need to fix. Thanks!
add_filter('woocommerce_get_catalog_ordering_args', 'am_woocommerce_catalog_orderby');
function am_woocommerce_catalog_orderby( $my_post_array ) {
if(!$_GET['orderby']) {
//First loop - show featured
$args['orderby'] = array( 'meta_value' => 'DESC' );
$args['meta_key'] = '_featured';
while ( $loop->have_posts() ) : $loop->the_post();
$post_id = get_the_ID();
$my_post = my_post_function($post_id);
//Store the items in an array
$my_post_array [] = $my_post;
query_posts($args);
endwhile;
//Second loop - Show newer than 6 months
$args = array(
'orderby' => 'date',
'order' => 'DESC',
'date_query' => array(
array(
'before' => '6 months ago',
),
)
);
while ( $loop->have_posts() ) : $loop->the_post();
$post_id = get_the_ID();
$my_post = my_post_function($post_id);
//Store the items in an array
$my_post_array [] = $my_post;
query_posts($args);
endwhile;
//Third loop - show everything else and sort by menu_order and title
$args['orderby'] = array( 'menu_order' => 'ASC', 'title' => 'ASC' );
while ( $loop->have_posts() ) : $loop->the_post();
$post_id = get_the_ID();
$my_post = my_post_function($post_id);
//Store the items in an array
$my_post_array [] = $my_post;
query_posts($args);
endwhile;
//Remove duplicate entries from the array
array_unique ( $my_post_array, SORT_STRING );
}
}
Update 2
I have yet to have any luck, any chance someone can take a look at my latest code above and give me some ideas on a direction to try? This loop does not seem to work for this filter when adding to the functions.php, maybe i need to do something different. Any help is appreciated!
So on my template for taxonomy-product_tag.php, I want to get all product id's from the Category.
Here is how I currently do it
<?php
$post_ids = array();
$args = array( 'post_type' => 'product', 'posts_per_page' => 1, 'product_cat' => 'dog-collars', 'orderby' => 'rand' );
$loop = new WP_Query( $args );
if ( $loop->have_posts() ) {
while ( $loop->have_posts() ) : $loop->the_post();
$post_ids[] = get_the_ID();
endwhile;
} else {
echo __( 'No products found' );
}
wp_reset_query();
print_r($post_ids);
?>
I can loop through the product_cat, pull id's into an array and then further down the page I use foreach and the WC product factory to manipulate data how I want it shown for users.
My problem is I need the loop to be Dynamic based on categories, and I can't understand how to do this.
I did think I can just grab the category name from the url
<?php $actual_link = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"; ?>
Grab it and the parse to just get the last , i.e category name, and then print into loop
But this seems like it would be a really poor way of doing it.
What I want is in the args
$args = array( 'post_type' => 'product', 'posts_per_page' => 1, 'product_cat' => 'DYNAMICHERE', 'orderby' => 'rand' );
I want to be able to populate product_cat dynamically based on the category I am on
Any help or advise / pointing me in the right direction would be appreciated
Use get_query_var( 'product_cat' ).
I've been searching high and low for and answer to this, but I'm not actually sure it's possible!
I have a WP_Query that pulls posts from almost everything, however, I wish to exclude a specific category and/or all it's sub categories.
Searching around people are yet to find a solution for this.
Here's my query so far:
$args = array(
'post_type' => 'sell_media_item',
'cat' => -98,
'orderby' => 'desc',
'paged' => $paged,
'posts_per_page' => 20
); ?>
<?php $loop = new WP_Query( $args ); ?>
I thought just excluding cat 98 would grab all the sub categories too, but apparently not.
I've tried using:
category__not_in, depth=0, parent=0 and even an adaptation of this, with no luck.
Any ideas?
[EDIT]
I'm using a custom taxonomy called Collections, so putting 'collection' => 'vip' into the query means it will only show this collection. I'm thinking if there's a way of reversing this so it excludes the collection instead?
As it's not possible to list all of the categories that will appear here as they will be changing all of the time.
[EDIT 2]
After the discussion in the comments below, here's the updated code.
$ex = array(
'taxonomy' => 'collection',
'child_of' => 98,
'hide_empty' => 0
);
$categories = get_categories($ex);
$categoriesToExclude = array();
foreach ($categories as $category) {
$categoriesToExclude[] = $category->cat_ID;
}
echo('<pre>'); var_dump($categories);
$args = array(
'post_type' => 'sell_media_item',
'category__not_in' => $categoriesToExclude,
'orderby' => 'desc',
'paged' => $paged,
'posts_per_page' => 20
); ?>
<?php echo('<br /><pre>'); var_dump($args); ?>
<?php $loop = new WP_Query( $args ); ?>
I would get the list of all sub categories with get_categories() and then build a 'cat' exclusion array based on the results.
$args = array('parent' => 98);
$categories = get_categories($args);
$categoriesToExclude = array();
foreach ($categories as $category) {
$categoriesToExclude[] = $category->cat_ID;
}
$args = array(
'post_type' => 'sell_media_item',
'category__not_in' => $categoriesToExclude,
'orderby' => 'desc',
'paged' => $paged,
'posts_per_page' => 20
); ?>
<?php $loop = new WP_Query( $args ); ?>
This is just an example, you may have to modify it slightly to fit your needs.
So!
It appears I was trying to do the impossible. I couldn't get this script working for the life of me. So I tried a different angle. Instead of excluding a custom taxonomy and its terms, I decided to move all of my other terms into a parent term and just called that instead.
Here's the code if anyone's interested...
<?php $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$args = array(
'post_type' => 'sell_media_item',
'taxonomy' => 'collection',
'term' => 'clubs',
'orderby' => 'desc',
'paged' => $paged,
'posts_per_page' => 20
);
$loop = new WP_Query( $args );
if ( $loop->have_posts() ) : while ($loop->have_posts()) : $loop->the_post(); ?>
I wrote my own function in order to exclude subcategory posts from the loop, using tips from the above post and elsewhere.
In my theme archive.php file, above the loop, I list the subcategories (optional):
<?php
$current_cat = get_queried_object();
$args = array( 'parent'=>$current_cat->term_id, 'child_of' => $current_cat->term_id, );
$categories = get_categories( $args );
foreach($categories as $category) { ?>
<h2><?php echo $category->name ;?></h2>
<p> etc....</p>
<?php } ?>
In my functions.php file, I've added the following custom function using pre_get_posts:
add_action( 'pre_get_posts', 'main_query_without_subcategory_posts' );
function main_query_without_subcategory_posts( $query ) {
if ( ! is_admin() && $query->is_main_query() ) {
// Not a query for an admin page.
// It's the main query for a front end page of your site.
if ( is_category() ) {
//Get the current category
$current_category = get_queried_object();
//get the id of the current category
$current_cat_id = $current_category->term_id;
//find the children of current category
$cat_args = array( 'parent'=>$current_category->term_id, 'child_of' => $current_category->term_id, );
$subcategories = get_categories( $cat_args );
//Get a list of subcategory ids, stick a minus sign in front
$subcat_id = array();
foreach($subcategories as $subcategory) {
$subcat_id[] = " -". $subcategory->term_id;
}
//join them together as a string with a comma seperator
$excludesubcatlist = join(',', $subcat_id);
//If you have multiple parameters, use $query->set multiple times
$query->set( 'posts_per_page', '10' );
$query->set( 'cat', ''.$current_cat_id.','.$excludesubcatlist.'' );
}
}
}
Then in the archive.php, below the subcategories, I've added the regular WordPress loop which is now being modified by the above function:
<?php while (have_posts() ) : the_post(); ?>
<h2><?php the_title();?></h2>
<p> etc....</p>
<?php endwhile;?>
Though the WordPress codex says that using "category__in" will exclude posts from subcategories, that didn't work for me and subcategory posts were still showing.
https://codex.wordpress.org/Class_Reference/WP_Query#Category_Parameters
https://developer.wordpress.org/reference/hooks/pre_get_posts/