I would like to query my posts by filtering for a custom meta added with Advanced Custom Fields. It's a boolean meta, so every post will have something like:
GET http://localhost/wp-json/wp/v2/posts
{
...
"acf" : {
"highlight" : true
}
...
}
I'm not able to filter by this meta value, even if I exposed meta_key and meta_value to the REST API in function.php:
function my_add_meta_vars ($current_vars) {
$current_vars = array_merge ($current_vars, array ('meta_key', 'meta_value'));
return $current_vars;
}
add_filter ('rest_query_vars', 'my_add_meta_vars');
But if I try:
GET
http://localhost/wp-json/wp/v2/posts?filter[meta_key]=highlight&filter[meta_value]=true
I see all the posts as if the filter is ignored.
I was able to get this solved with this customization:
add_filter( 'rest_query_vars', function ( $valid_vars ) {
return array_merge( $valid_vars, array( 'highlight', 'meta_query' ) );
} );
add_filter( 'rest_post_query', function( $args, $request ) {
$highlight = $request->get_param( 'highlight' );
if ( ! empty( $highlight ) ) {
$args['meta_query'] = array(
array(
'key' => 'highlight',
'value' => $highlight,
'compare' => '=',
)
);
}
return $args;
}, 10, 2 );
And do a query in this way (highlight is acf boolean)
GET /wp-json/wp/v2/posts?highlight=1
Related
I need a custom fields on the inventory tab that will be filled in with the zipcode as the location of the agent.
Armed with the references I got here, now I have that field.
what I want to ask is how to concatenate this meta data with woocommerce shortcode?
I think like :
['products limit="12" columns="4" zipcode="12345"]
where "12345" will be changing dynamically as needed (zipcode filled based on agent location).
I have tried to do something but it is not working properly.
Here's the full code.
function action_woocommerce_product_options_inventory_product_data_zipcode() {
woocommerce_wp_text_input( array(
'id' => '_zipcode',
'label' => __( 'Zipcode', 'woocommerce' ),
'description' => __( 'Please fill your zipcode.', 'woocommerce' ),
'desc_tip' => 'true',
'placeholder' => __( '12345', 'woocommerce' )
) );
}
add_action( 'woocommerce_product_options_inventory_product_data', 'action_woocommerce_product_options_inventory_product_data_zipcode' );
// Save zipcode
function action_woocommerce_admin_process_product_object_zipcode( $product ) {
// Isset
if ( isset( $_POST['_zipcode'] ) ) {
// Update
$product->update_meta_data( '_zipcode', sanitize_text_field( $_POST['_zipcode'] ));
}
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object_zipcode', 10, 1 );
Try put to shortcode products :
function filter_shortcode_atts_products_zipcode ( $out, $pairs, $atts, $shortcode) {
if ( isset ( $atts['zipcode'] ) && !empty($atts['zipcode']) ) {
$out['zipcode'] = true;
} else {
$out['zipcode'] = false;
}
return $out;
}
add_filter( 'shortcode_atts_products', 'filter_shortcode_atts_products_zipcode', 10, 4);
function filter_woocommerce_shortcode_products_query_zipcode( $query_args, $atts, $type) {
if ( $type == 'products' && $atts['zipcode'] ) {
// Meta query
$query_args['meta_query'] = array(
array(
'key' => '_zipcode',
'value' => $atts['zipcode'],
'compare' => 'LIKE',
)
);
}
return $query_args;
}
add_filter( 'woocommerce_shortcode_products_query', 'filter_woocommerce_shortcode_products_query_zipcode', 10, 3 );
On testing I tried :
['products limit="12" columns="4" zipcode="12345"]
shortcode has displayed the product but does not refer to the postal code in the short code ("12345") but to all products that have a postal code.
Can somebody help me?
Thank you
Something doesn't feel right about the shortcode attribute function. I think you're setting the attribute as true and therefore it's comparing anything "truthy." Maybe just try setting the true one as the zipcode, like this:
function filter_shortcode_atts_products_zipcode ( $out, $pairs, $atts, $shortcode) {
if ( isset ( $atts['zipcode'] ) && !empty($atts['zipcode']) ) {
$out['zipcode'] = $atts['zipcode'];
} else {
$out['zipcode'] = false;
}
return $out;
}
That way it'll return the zipcode if it exists, and false if it doesn't, which the query can then use for the comparison.
I'm trying to add filters to both the shop page and product category pages in WooCommerce to allow users to filter the product list by product_tag.
First I hook into woocommerce_before_shop_loop to output a list of tags before the products list
public function render_category_tag_id_filters(): void {
// Get a list of all product IDs
if ( is_shop() ) {
$product_ids = wc_get_products(
[
'limit' => PHP_INT_MAX,
'return' => 'ids',
]
);
// Get a list of product IDs in this category
} else if ( is_product_category() ) {
$product_cat = get_query_var( 'product_cat' );
$product_ids = wc_get_products(
[
'category' => $product_cat,
'limit' => PHP_INT_MAX,
'return' => 'ids',
]
);
// Don't continue
} else {
return;
}
// Render template part here etc. etc.
}
add_action( 'woocommerce_before_shop_loop', [ $this, 'render_category_tag_id_filters' ] );
Clicking on the filters builds up a comma separated list of product_tag IDs in a query var that looks like...
/product-category/candles/?tag_ids=31,32,35
Then I'm hooking into woocommerce_product_query_tax_query to filter the main product list using the values from the query var
public function apply_category_tag_id_filters( array $tax_query, \WC_Query $wc_query ): array {
// Abort if not the main query
if(
! ( $wc_query->get_main_query() instanceof \WP_Query )
|| ! $wc_query->get_main_query()->is_main_query()
) {
return $tax_query;
}
// Get the filter tag IDs
$filter_tag_ids = $this->get_category_filter_tag_ids();
if (
! is_array( $filter_tag_ids )
|| 0 === count( $filter_tag_ids )
) {
return $tax_query;
}
//
$tax_query[] = array(
'taxonomy' => 'product_tag',
'field' => 'term_id',
'terms' => $filter_tag_ids,
'operator' => 'AND',
);
//
return $tax_query;
}
This is where I'm coming unstuck. It works perfectly on the product category pages. The problem is that none of the queries on the main shop page seem to be flagged as the main query. That means that my filter function quits out early. If I remove the check for the main query it works but my list of tag filters at the top of the page is also filtered by the active tag ID
Is this a bug? Am I not targeting the main query correctly?
I want to display my woocommerce products on two different sections on the site i.e. the shop page and on an archive page i created using Custom Post UI plugin, called artists.
Using the Advanced Custom Fields plugin, i created a field that will attach each product created to an individual artist. The plan now is, on each artist page, pull products for the artist.
This is what i have so far. I hook into woocommerce_product_query, check if i'm on the single artist page and implement my meta query:
function artist_products( $query )
{
if( is_singular('artists') )
{
$meta_query = ( is_array( $query->get('meta_query') ) ) ? $query->get('meta_query') : [];
$meta_query[] = array(
'key' => '_fld_select_artist',
'value' => get_the_ID(),
);
$query->set( 'meta_query', $meta_query );
}
}
add_action( 'woocommerce_product_query', 'artist_products' );
This is not working. When i visit my single artist page, i get a 500 server error. What I'm i missing?
woocommerce_product_query was breaking my site for some reason so i switched to pre_get_posts:
function artist_products( $query )
{
if ( $query->get('post_type') == 'nav_menu_item' )
{
return $query;
}
if( ! is_admin() && is_singular('artists') )
{
$meta_query = ( is_array( $query->get('meta_query') ) ) ? $query->get('meta_query') : [];
$meta_query[] = array(
'key' => '_fld_select_artist',
'value' => get_the_ID(),
'compare' => '=',
);
$query->set( 'meta_query', $meta_query );
}
}
add_action( 'pre_get_posts', 'artist_products' );
I am trying to create a PowerApp in which I want to integrate the post meta fields. I inserted this code in the functions.php file. But I can read and write the data for default WordPress fields, but I am not able to update the post custom fields.
add_action( 'rest_api_init', 'create_api_posts_meta_field' );
function create_api_posts_meta_field() {
// register_rest_field ( 'name-of-post-type', 'name-of-field-to-return', array-of-callbacks-and-schema() )
register_rest_field( 'post', 'post-meta-fields', array(
'get_callback' => 'get_post_meta_for_api',
'update_callback' => 'get_post_meta_update_for_api',
'schema' => null,
)
);
}
function get_post_meta_for_api( $object ) {
//get the id of the post object array
$post_id = $object['id'];
//return the post meta
return get_post_meta( $post_id );
}
function get_post_meta_update_for_api( $value, $object, $field_name ) {
return update_post_meta( $object[ 'id' ], $field_name, $value );
}
I am trying to modify all queries of a post type "products" to only show if the product/post has a certain meta_key of "wholesale_price" which the meta_value needs to be greater than 0.
Here is what i have:
add_action( 'pre_get_posts', 'rc_modify_query_get_design_projects' );
function rc_modify_query_get_design_projects( $query ) {
if($query->is_main_query() && $query->query_vars['post_type'] == 'product' ) {
$query->set('meta_key', 'wholesale_price');
$query->set('meta_compare', '>');
$query->set('meta_value', '0');
}
}
For some reason this still returns everything. Is this the right way of doing things?
The problem is the method by which you are setting your meta_query. You should read up on the WP_Query functionality, because meta queries are unfortunately not that simple.
You need to do something more like so:
add_action( 'pre_get_posts', 'rc_modify_query_get_design_projects' );
function rc_modify_query_get_design_projects( $query ) {
// Do not add meta arguments in admin pages
if (is_admin()) {
return;
}
if($query->is_main_query() && $query->query_vars['post_type'] == 'product' ) {
//Get original meta query
$meta_query = (array)$query->get('meta_query');
// Add your criteria
$meta_query[] = array(
'key' => 'wholesale_price',
'value' => 0,
'compare' => '>',
);
// Set the meta query to the complete, altered query
$query->set('meta_query',$meta_query);
}
And no need to return anything in this function.