Get WooCommerce products on sale with WC_Query - wordpress

I know there are plenty of solutions on the internet about how to get WooCommerce products on sale, by doing a WP_Query. However, WooCommerce doesn't seem to work fully if it's WC_Query object is not populated. For example: filter or sorting
Both these templates call:
woocommerce_products_will_display()
Which check's to see if the page is a taxonomy page (obvious false if you're using your own custom template):
if ( ! is_product_taxonomy() ) return false;
This is an example of a simple solution if you just want the products: WooCommerce: Display ONLY on-sale products in Shop
So, I there seems to be a couple of issues I need to solve here:
1) How to tell WC that my "Sale" page is a taxonomy page? Is there some sort of trick I need to do to force it into a taxonomy?
2) How do I get get WC_Query filled with the sales query (rather than just the WP_Query)
I have plugins that depend on:
$woocommerce->query->layered_nav_product_ids
being populated.
Any help is appreciated!
Thanks!!!

Well woocommerce_products_will_display() is pluggable, meaning you can define it in your own functions.php (or site-specific plugin) and alter it, having it return true for your specific template/page.
I think it could stand for some tweaking and a filter.
EDIT
I played around with this a bit more. Typically changing the posts that you want to retrieve is done in the pre_get_posts hook. I took a look at what WooCommerce is doing. They are adding something to the pre_get_posts hook and calling their special query stuff from there.
But their special query stuff dies if you aren't on a WooCommerce page. So, it made me thing that maybe we could just call it ourselves from our own function. I put this together and coupled with a special page template for a page called "on-sale" (basically just a copy of the shop template), seems to show just the for sale items with proper sorting and pagination.
Your mileage may vary, but I hope it helps.
function kia_pre_get_posts( $q ){
// We only want to affect the main query
if ( ! $q->is_main_query() ) {
return;
}
// Fix for verbose page rules
if ( is_page('on-sale') ) {
$q->set( 'post_type', 'product' );
$q->set( 'page_id', '' );
$q->set( 'page', '' );
$q->set( 'pagename', '' );
$meta_query = array( array(
'key' => '_sale_price',
'value' => 0,
'compare' => '>'
) );
$q->set( 'meta_query', $meta_query );
if ( isset( $q->query['paged'] ) ) {
$q->set( 'paged', $q->query['paged'] );
}
// Fix conditional Functions
$q->is_archive = true;
$q->is_post_type_archive = true;
$q->is_singular = false;
$q->is_page = false;
}
$wc_query = WC()->query;
$wc_query->product_query( $q );
if ( is_search() ) {
add_filter( 'posts_where', array( $wc_query, 'search_post_excerpt' ) );
add_filter( 'wp', array( $wc_query, 'remove_posts_where' ) );
}
add_filter( 'posts_where', array( $wc_query, 'exclude_protected_products' ) );
// We're on a shop page so queue the woocommerce_get_products_in_view function
add_action( 'wp', array( $wc_query, 'get_products_in_view' ), 2);
// And remove the pre_get_posts hook
$wc_query->remove_product_query();
}
add_action( 'pre_get_posts', 'kia_pre_get_posts' );

Related

Wordpress media library missing entries with NULL value when sorted after custom column

i have included 2 custom columns in the metadata of media entries called 'photographer' and 'copyright'. I have included both columns in the admin view of the media library and made them sortable. But when i sort by one of them the results exclude entries with a NULL value in that column
adding custom fields to admin panel media view
//Custom columns in Media Admin view
add_filter('manage_media_columns', 'media_additional_columns', 1);
function media_additional_columns($defaults){
$defaults['photographer'] = __('Photographer');
$defaults['copyright'] = __('Copyright');
return $defaults;
}
//Fill Custom Media Admin Columns with content
add_action('manage_media_custom_column', 'media_custom_columns_attachment_id', 1, 2);
function media_custom_columns_attachment_id($column_name, $post_id){
switch ( $column_name ) {
case 'photographer':
echo get_post_meta( $post_id, 'photographer', true );
break;
case 'copyright':
echo get_post_meta( $post_id, 'copyright', true );
break;
}
}
make custom columns in admin panel media view sortable
//make custom columns sortable
//add custom columns to array sortable columns
add_filter('manage_upload_sortable_columns', 'as_add_custom_column_sortable');
function as_add_custom_column_sortable($columns) {
$columns['photographer'] = 'photographer';
$columns['copyright'] = 'copyright';
return $columns;
}
//alter the post query in case stuff gets sorted by custom columns
add_action( 'pre_get_posts', 'as_custom_column_orderby' );
function as_custom_column_orderby( $query ) {
if( ! is_admin() || ! $query->is_main_query() ) {
return;
}
switch ($query->get( 'orderby')) {
case 'photographer':
$query->set( 'orderby', 'meta_value' );
$query->set( 'meta_key', 'photographer' );
break;
case 'copyright':
$query->set( 'orderby', 'meta_value' );
$query->set( 'meta_key', 'copyright' );
break;
}
}
I want to include the entries with NULL value in the sorted table, after the entries with non-NULL values.
I have found this post that answers the same question for the Posts and for Users. I thought the answer applicable for Posts would work also for media since media are basically posts of the type attachment but it doesnt, my media library turns up completely empty.
I am just starting with php, help would be much appreciated!
alrighty i circumvented the problem by putting the code into a plugin file instead of functions.php directly and adding code that updates the values of the custom columns for all images that already exist in the media library once the plugin is activated
////update all images with default values for custom fields "Photographer" and "Copyright"
// Run the loop when the plugin is activated
register_activation_hook(__FILE__, 'as_update_my_metadata');
function as_update_my_metadata(){
$args = array(
'post_type' => 'attachment', // Only get the posts
'post_status' => 'publish' OR 'private', // Only the posts that are published
'posts_per_page' => -1 // Get every post
);
$posts = get_posts($args);
foreach ( $posts as $post ) {
// Run a loop and update every meta data
update_post_meta( $post->ID, 'photographer', 'unknown' );
update_post_meta( $post->ID, 'copyright', 'not defined' );
}
}

Wordpress - Hide Category from Posts

So our Wordpress site's backend is horribly slow due to the HUGE amount of posts we have. There are three categories in particular that we shouldn't need to edit, so I am hoping to not even load them in the back end. I have seen plugins that restrict who can edit what categories of posts, but it doesn't seem to speed it up much. I'm not sure if this is because it is still pulling those posts and just filtering them out when displaying?
I am wondering if _get_list_table( 'WP_Posts_List_Table' ) has a hook of some sort where I can make it so those three categories are not even pulled from the database.
Is this possible? Would it help speed up the backend?
Thanks!
Edit:
Kinda want something like this, but set() does not allow modifiers on = or !=
function exclude_category_posts( $query ) {
if ( $query->is_main_query() && is_admin()) {
//$query->set( 'cat', '-187460' );
$query = new WP_Query( array( 'category__not_in' => array( 187460, 187460, 182149 ) ) );
}
return $query;
}
add_filter( 'pre_get_posts', 'exclude_category_posts' );
The commented out method only works with one category. The new query doesn't filter anything ):
PHP code to exclude WordPress category from blog
function exclude_category($query) {
if ( $query->is_home() ) {
$query->set('cat', '-xx');
}
return $query;
}
add_filter('pre_get_posts', 'exclude_category');
The trick is to add the minus sign in front of your category ID (the xx in the example above). Try that, it should work.
Use this notation $query->set( 'cat', '-60, -61' ); to exclude multiple categories.
Alternative
You can also use the category__not_in parameter
$query = new WP_Query( array( 'category__not_in' => array( 2, 6 ) ) );
source

woocommerce conditional products/categories on user role

Looking for a plugin that helps me to restrict woocommerce products or product categories based on role.
Let's say that I only want to sell bulk products to whole sale buyers.
Any help is awesome, thanks!
Here is how I managed to hide products based on role:
First, I have added a checkbox in the product options inventory section to enable admins to hide the products based on their selection:
add_action( 'woocommerce_product_options_stock_status', 'hide_if_available_to_user_role' );
function hide_if_available_to_user_role(){
woocommerce_wp_checkbox( array( 'id' => '_hide_from_users', 'wrapper_class' => 'show_if_simple show_if_variable', 'label' => __( 'Hide this product from specific roles?', 'customhideplugin' ) ) );
}
I then saved this selection in the actual post when a post is updated.
add_action( 'woocommerce_process_product_meta', 'hide_save_product_meta' );
function hide_save_product_meta( $post_id ){
if( isset( $_POST['_hide_from_users'] ) ) {
update_post_meta( $post_id, '_hide_from_users', 'yes' );
} else {
delete_post_meta( $post_id, '_hide_from_users' );
}
}
This is how I got current user's role.
function getCurrentUserRole( $user = null ) {
$user = $user ? new WP_User( $user ) : wp_get_current_user();
return $user->roles ? $user->roles[0] : false;
}
Now query products. If the current user role matches the roles below, show the products as usual.
Otherwise, set the query based on the code above...
add_action( 'woocommerce_product_query', 'hide_product_query' );
function hide_product_query( $q ){
if((getCurrentUserRole() == 'editor' ) || (getCurrentUserRole() == 'administrator' )){
return false;
} else {
$meta_query = $q->get( 'meta_query' );
if ( get_option( 'woocommerce_hide_out_of_stock_items' ) == 'no' ) {
$meta_query[] = array(
'key' => '_hide_from_users',
'compare' => 'NOT EXISTS'
);
}
$q->set( 'meta_query', $meta_query );
}
}
To achieve this you can use the Free Groups plugin. But for that you must add all the wholesalers to one group say wholesale group 1. Then while editing any product you get an option to access to, add the wholesaler group 1 there. The product will now be only seen by the user who is in wholesalers group 1.
I tried a few different plugins to try to achieve that. I finally chose this one because it's easy to understand and can show/hide depending on procucts, tags, categories and custom taxonomies. WooCommerce Products Visibility

Exclude current post from "recent posts widget"

In a plugin for displaying recent posts in your sidebar widget, how can we apply a filter to the plugin's functions.php so that it won't include the current page/post in the display?
The plugin author replied, before he entered a long silence: "You can add custom parameter to the rpwe_default_query_arguments filter. Just add exclude => get_the_ID() to the filter."
Is it here, that we add it?
// Allow plugins/themes developer to filter the default query.
$query = apply_filters( 'rpwe_default_query_arguments', $query );
How?
This is the plugin: https://wordpress.org/plugins/recent-posts-widget-extended/
I found some guidance that appears to be quite simple
but then it results in errors in my site (localhost) while trying to correct the syntax. => seems to be not correctly used.
This is what I have so far:
add_filter( 'rpwe_default_query_arguments', 'rpwe_exclude_current' );
function rpwe_exclude_current ( $query ) {
'exclude' => get_the_ID()
$posts = new WP_Query( $query );
return $posts;
}
Here is the answer that worked in my situation:
add_filter( 'rpwe_default_query_arguments', 'my_function_name' );
function my_function_name( $args ) {
if( is_singular() && !isset( $args['post__in'] ) )
$args['post__not_in'] = array( get_the_ID() );
return $args;
}
Here is the site where I found it.

Unlimited posts_per_page for a custom post type only

I need to show all existing posts in the archive loop for a custom post type of 'vehicle'.
This is what I have so far:
function get_all_vehicle_posts( $query ) {
$query->set( 'posts_per_page', '-1' );
}
add_action( 'pre_get_posts', 'get_all_vehicle_posts' );
And I see the unlimited posts I wanted. However I need to limit this change to my custom post type.
I tried:
if ( 'vehicle' == $query->post_type ) {
$query->set( 'posts_per_page', '-1' );
}
but that doesn't seem to work. I guess we don't know the post type before the query is run unless it's a specific argument for the query?
How can I limit this function to a particular post type?
Do a check in your pre get posts with the is_post_type_archive function for the post type.
You will want to check if the query is not admin to avoid affecting the admin area, as well as checking if the query is the main query.
function get_all_vehicle_posts( $query ) {
if( !is_admin() && $query->is_main_query() && is_post_type_archive( 'vehicle' ) ) {
$query->set( 'posts_per_page', '-1' );
}
}
add_action( 'pre_get_posts', 'get_all_vehicle_posts' );
http://codex.wordpress.org/Function_Reference/is_admin
http://codex.wordpress.org/Function_Reference/is_main_query
http://codex.wordpress.org/Function_Reference/is_post_type_archive
The post type has to be set as a query parameter
$args = array(
'post_type' => 'vehicle'
);
So in your function add the post type, otherwise you are only querying the standard post objects.

Resources