I am trying to filter products by product range in backend. Somehow I am unable to do so. Any help will be highly appreciated. Also let me know if there is any plugin available for this one? My recent code.
add_action( 'restrict_manage_posts', 'my_custom_product_filters' );
function apply_my_custom_product_filters( $query ) {
global $pagenow;
// Ensure it is an edit.php admin page, the filter exists and has a value, and that it's the products page
if ( $query->is_admin && $pagenow == 'edit.php' && isset( $_GET['price'] ) && $_GET['price'] != '' && $_GET['post_type'] == 'product' ) {
// Create meta query array and add to WP_Query
$meta_key_query = array(
array(
'key' => '_my_meta_value',
'value' => esc_attr( $_GET['price'] ),
)
);
//$query->set( 'meta_query', $meta_key_query );
$query->query_vars['price'] = $meta_key_query;
}
}
add_action( 'pre_get_posts', 'apply_my_custom_product_filters' );
Thanks in advance guys.
Related
I am trying to find a way to hide a product from the Woocommerce shop page. If the logged in user has already purchased said product.
I have already been able to block the user from purchasing again using woocommerce_is_purchasable, and woocommerce_variation_is_purchasable. But I would like to hide it all together not even shown to them in the shop page. I have been coming up empty on this one. So any help would be appreciated.
You can change the product query using the pre_get_posts action hook and then you can get current user products that they already purchased. pass all products id to post__not_in. check the below code. code will go active theme function.php file.
add_action( 'pre_get_posts', 'hide_product_from_shop_page_if_user_already_purchased', 20 );
function hide_product_from_shop_page_if_user_already_purchased( $query ) {
if ( ! $query->is_main_query() ) return;
if ( ! is_admin() && is_shop() ) {
$current_user = wp_get_current_user();
if ( 0 == $current_user->ID ) return;
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => $current_user->ID,
'post_type' => 'shop_order',
'post_status' => array( 'wc-processing', 'wc-completed' ),
) );
if ( ! $customer_orders ) return;
$product_ids = array();
foreach ( $customer_orders as $customer_order ) {
$order = wc_get_order( $customer_order->ID );
if( $order ){
$items = $order->get_items();
foreach ( $items as $item ) {
$product_id = $item->get_product_id();
$product_ids[] = $product_id;
}
}
}
$product_ids = array_unique( $product_ids );
$query->set( 'post__not_in', $product_ids );
}
}
Bhautik's answer is technically correct based on the question asked. Hide product if user bought before.
However as mentioned in my question I'm already disabling purchase of said products using woocommerce_is_purchasable .
Meaning the logic of what should be hidden is already in the software. Using his idea as a template I have made the answer more generic to operate off of woocommerce_is_purchasable . Meaning I only have to implement any conditional logic in that function and the shop will reflect by hiding said products (that are not purchasable).
I am posting this as a second answer in case it helps others searching this problem. But will keep his as the selected answer to the question.
add_action( 'woocommerce_product_query', 'hide_product_from_shop_page_if_user_already_purchased', 20 );
function hide_product_from_shop_page_if_user_already_purchased( $query ) {
//Get all the products in the store.
$products = wc_get_products(['limit' => -1]);
//Blank exclusion array.
$product_ids = array();
//Check each product to see if it is purchasable or not.
foreach($products as $product){
if(!$product->is_purchasable()){
//If product is not purchasable then add to exclusion array.
$product_ids[] = $product->get_id();
}
}
//Use array of id's to exclude products in the shop page.
$query->set( 'post__not_in', $product_ids );
}
I am using the hook "pre_get_posts" to query only posts that have featured image in the front page:
add_action( 'pre_get_posts', 'my_pre_get_posts' );
function my_pre_get_posts( $q ){
if ( $q->is_home() // only target homepage
&& $q->is_main_query() // only target the main query
&& !is_admin() // target front end only
) {
$q->set( 'meta_key', array( '_thumbnail_id' ) );
}
}
It looks like this portion is being ignored.
$q->set( 'meta_key', array( '_thumbnail_id' ) );
Your help is appreciated.
You need to check whether '_thumbnail_id' meta_key exists or not. So let's modify your code like this.
add_action( 'pre_get_posts', 'my_pre_get_posts' );
function my_pre_get_posts( $q ){
if ( $q->is_home() // only target homepage
&& $q->is_main_query() // only target the main query
&& !is_admin() // target front end only
) {
$meta_query = array(
array(
'key'=>'_thumbnail_id',
'compare'=>'EXISTS',
),
);
$query->set('meta_query',$meta_query);
}
}
I have a custom post type called Contact, with custom fields like first name, surname, telephone number etc.
In the admin section they're sorted chronologically I think, but I need them to be sorted by surname by default.
I've read all the other solutions on here and none of them work, including:
function set_post_order_in_admin( $wp_query ) {
global $pagenow;
if ( is_admin() && 'edit.php' == $pagenow && !isset($_GET['orderby'])) {
$wp_query->set( 'orderby', 'surname' );
$wp_query->set( 'order', 'ASC' );
}
}
add_filter('pre_get_posts', 'set_post_order_in_admin' );
But whatever field I try to sort by, nothing changes, except toggling ASC/DESC seems to change to reverse chronological ordering.
What am I doing wrong?
Refer below solutions,
function wpa84258_admin_posts_sort_last_name( $query ){
global $pagenow;
if( is_admin()
&& 'edit.php' == $pagenow
&& !isset( $_GET['orderby'] )
&& !isset( $_GET['post_type'] ) ){
$query->set( 'meta_key', 'last_name' );
$query->set( 'orderby', 'meta_value' );
$query->set( 'order', 'ASC' );
}
}
add_action( 'pre_get_posts', 'wpa84258_admin_posts_sort_last_name' );
OR refer this solution
Replace
$wp_query->set( 'orderby', 'surname' );
$wp_query->set( 'order', 'ASC' );
With
$query->set( 'meta_key', 'surname' ); // name of your post meta key
$query->set( 'orderby', 'meta_value'); // meta_value since it is a string
It may help
I am a drupal developer and haven't got a chance to play with WordPress.
We had the same problem and this is how we fixed it.
Get your custom content type data (either WP default api or custom query), it would be an array of objects. Sort them using below function. return sorted array of posts. Not sure, in which hook you need to implement this in wordpress.
/**
* Function to sort array by key
* sortArrayByKey($yourArray,"name",true); //String sort (ascending order)
* sortArrayByKey($yourArray,"name",true,false); //String sort (descending order)
* sortArrayByKey($yourArray,"id"); //number sort (ascending order)
* sortArrayByKey($yourArray,"count",false,false); //number sort (descending order)
*/
function sortArrayByKey(&$array, $key, $string = false, $asc = true)
{
if ($string) {
usort($array, function ($a, $b) use (&$key, &$asc) {
if ($asc) return strcmp(strtolower($a{$key}), strtolower($b{$key}));
else return strcmp(strtolower($b{$key}), strtolower($a{$key}));
});
} else {
usort($array, function ($a, $b) use (&$key, &$asc) {
if ($a[$key] == $b{$key}) {
return 0;
}
if ($asc) return ($a{$key} < $b{$key}) ? -1 : 1;
else return ($a{$key} > $b{$key}) ? -1 : 1;
});
}
}
and then in your hook, you can call this function by
return $this->sortArrayByKey($posts, "surname");
Function copied from this answer: https://stackoverflow.com/a/39872303/3086531
This snippet sets the 'Name' column as the default sorting order (ascending) for Woocommerce Products
function sort_woocommerce_products_by_name( $query ){
global $pagenow;
if( is_admin()
&& 'edit.php' == $pagenow
&& isset($_GET['post_type']) && $_GET['post_type']=='product'
&& !isset( $_GET['orderby'] ) ){
$query->set( 'orderby', 'title' );
$query->set( 'order', 'asc' );
}
}
add_action( 'pre_get_posts', 'sort_woocommerce_products_by_name' );
I am developing a ecommerce store using WordPress and WooCommerce.
I have a products.
I will only allow a specific customer to purchase the product.
So I would like to only show this product if the specific customer is logged in.
Thanks
This is useful to restrict user,
// Woocommerce - Redirect unauthorised users from accessing a specified product category when clicked or visited via direct url
function woocommerce_hide_non_registered() {
if( ( is_product_category('specials') ) && ! ( current_user_can( 'customer' ) || current_user_can( 'administrator' ) ) ) {
wp_redirect( site_url( '/' ) );
exit();
}
}
add_action( 'template_redirect','woocommerce_hide_non_registered' );
// End - Woocommerce - redirect unauthorised users from accessing a specified product category
// Woocommerce - Removes category link from woocommerce product category widgets so they are not seen
add_filter( 'get_terms', 'get_subcategory_terms', 10, 3 );
function get_subcategory_terms( $terms, $taxonomies, $args ) {
$new_terms = array();
// if a product category and on the shop page
if ( in_array( 'product_cat', $taxonomies ) && ! ( current_user_can( 'customer' ) || current_user_can( 'administrator' ) ) && is_shop() ) {
foreach ( $terms as $key => $term ) {
if ( ! in_array( $term->slug, array( 'specials' ) ) ) {
$new_terms[] = $term;
}
}
$terms = $new_terms;
}
return $terms;
}
// End - Woocommerce - Removes category link from woocommerce product category widgets so they are not seen
// Woocommerce - Remove products from being displayed that belong to a category user is not authorised to visit. Products seem to still be accessible via direct url unfortunately.
add_action( 'pre_get_posts', 'custom_pre_get_posts' );
function custom_pre_get_posts( $q ) {
if ( ! $q->is_main_query() ) return;
if ( ! $q->is_post_type_archive() ) return;
if ( ! ( current_user_can( 'customer' ) || current_user_can( 'administrator' ) ) && is_shop() ) {
$q->set( 'tax_query', array(array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => array( 'specials'), // Don't display products in the private-clients category on the shop page
'operator' => 'NOT IN'
)));
}
remove_action( 'pre_get_posts', 'custom_pre_get_posts_query' );
}
// End - Woocommerce - Remove products from being displayed that belong to a category user is not authorised to visit. Products seem to still be accessible via direct url unfortunately.
This will do the trick for you.
add_action( 'pre_get_posts', 'dm_restrict_user_to_show_own_posts_only' );
function dm_restrict_user_to_show_own_posts_only( $dm_wp_query_obj )
{
// Front end, do nothing
if( !is_admin() )
return;
global $current_user, $pagenow;
wp_get_current_user();
// http://php.net/manual/en/function.is-a.php
if( !is_a( $current_user, 'WP_User') )
return;
// Not the correct screen, bail out
if( 'edit.php' != $pagenow )
return;
// Not the correct post type, bail out
if( 'product' != $dm_wp_query_obj->query['post_type'] )
return;
// If the user is not administrator, filter the post listing
if( !current_user_can( 'delete_plugins' ) )
$dm_wp_query_obj->set('author', $current_user->ID );
}
For example I have two variations, 'from_year' and 'until_year', how can I filtering products by range in product archive page.
If to call this url, will get only products that equals to the variables, but need from_year >= 2005 and until_year <= 20015
mysite.com/?from_year=2005&until_year=2015&post_type=product
you need date queries. Here's a good tutorial on date queries and here's the Codex on date parameters for WP_Query.
You will also need to filter query_vars to add your new query variables and pre_get_posts to modify the posts retrieved based on your new query vars.
With all that reference material, here's my attempt at how this should be done.
// Add query vars for filtering by years
function so_33714675_add_vars($query_vars) {
$query_vars[] = 'from_year';
$query_vars[] = 'until_year';
return $query_vars;
}
add_filter( 'query_vars', 'so_33714675_add_vars' );
// Filter product arvhice if query vars are present
function so_33714675_pre_get_posts($query) {
if ( !is_admin() && is_shop() && $query->is_main_query() ) {
$from_year = get_query_var('from_year');
$until_year = get_query_var('until_year');
$date_query = array();
if( ! empty( $from_year ) ){
$date_query['after'] = array(
'year' => $from_year,
);
}
if( ! empty( $until_year ) ){
$date_query['before'] = array(
'year' => $until_year,
);
}
// order by date
if( ! empty( $date_query ) ){
set_query_var( 'orderby', 'date' );
set_query_var( 'order', 'ASC' );
$date_query['inclusive'] = true;
set_query_var( 'date_query', array( $date_query ) );
}
}
}
add_action( 'pre_get_posts', 'so_33714675_pre_get_posts' );
Keep in mind that this is not fully tested. I'm 99% positive this is the correct approach, but it may need some tweaking.