shortcode_atts not parsing custom values instead defaults loaded - wordpress

I' making my own shortcode function and while the call of the shortcode works, and my page query within returns results - it never uses any settings but the defaults as if $att is null.
function test_shortcode( $atts ) {
$filter = shortcode_atts(
array(
'type' => 'major',
'sort' => 'name',
'size' => 'large',
'links' => 'yes',
),
$atts,
'customshortcode'
);
echo 'ATTS:';
print_r($atts);
echo'FILTER';
print_r($filter);
//code to query posts removed
}
add_shortcode( 'customshortcode', 'test_shortcode' );
In the post I can then add..
[customshortcode type:"other" size:"small" sort:"rand" links:"no"]
To see the result
ATTS
Array
(
[0] => type:"other"
[1] => size:"small"
[2] => sort:"rand"
[3] => links:"no"
)
FILTER
Array
(
[type] => major
[sort] => name
[size] => large
[links] => yes
)
and I can see the $atts values are received in the function but the $filter is not updated. I'm expecting both arrays to be the same at the point they are being printed out. As far as I can tell I'm following the coxed formatting here https://codex.wordpress.org/Function_Reference/shortcode_atts

You are passing attributes in the wrong way.
It should use = instead of :.
Please go through https://developer.wordpress.org/plugins/shortcodes/shortcodes-with-parameters/ to know more about shortcode with parameters.
Try with [customshortcode type="other" size="small" sort="rand" links="no"]

Related

Visual composer custom loop shortcode

I need to use custom loop from visual composer:
if( function_exists('vc_map') ) {
vc_map( array(
'base' => 'minimag_popular_post_custom',
'name' => esc_html__( 'Popular Post Custom', "minimag-toolkit" ),
'class' => '',
"category" => esc_html__("Minimag Theme", "minimag-toolkit"),
'params' => array(
array(
// this param
"type" => "loop",
"heading" => esc_html__("Display Custom Loop", "minimag-toolkit"),
"param_name" => "custom_loop",
)
),
) );
}
In past I've used vc_link which had the proper function to retrieve the value in the correct form: vc_build_link($href).
There is some function to extract the data from loop parameter? I've looked in the reference but I've not find nothing.
Here an example of the output that I need to parse:
size:8|order_by:date|order:DESC|post_type:post|categories:32,5|by_id:1537,1673
I need to have something like:
$myVar['size'] = 8;
$myVar['order_by'] = 'date';
$myVar['order'] = 'DESC';
$myVar['post_type'] = 'post';
$myVar['categories'] = array(32,5);
$myVar['by_id'] = array(1537,1673);
tested and working :)
list($args, $wp_query) = vc_build_loop_query($atts["custom_loop"]);
while ( $wp_query->have_posts() ) {
$wp_query->the_post();
}
wp_reset_postdata();
If you know your query I like to create a shotcode in the functions.php of my child-theme to create that. You can pass parameters to create different output and you can use such a shortcode everywhere in your site.

How to filter custom fields for custom post type in wordpress rest api?

I use wordpress standard with the plugins "Advanced custom fields" and "custom_post_type ui". I created a post_type called deals and added some custom fields with it.
What I need to do now, is filter the results when accessing the rest api like this:
http://localhost:8000/wp-json/wp/v2/deals
Actually I only need the acf part of it. I dont care about the rest.
[{"id":29,"date":"2019-04-12T12:34:14","date_gmt":"2019-04-
12T12:34:14","guid":{"rendered":"http:\/\/localhost:8000\/?
post_type=deals&p=29"},"modified":"2019-04-
12T12:34:14","modified_gmt":"2019-04-12T12:34:14",
"slug":"test-title","status":"publish","type":"deals",
"link":"http:\/\/localhost:8000\/deal s\/test- title\/","template":"",
"meta":[],"tax-deals":[],"acf":{"title":"Title for Deals
Post","description":"","image":false,"date_start":"01.01.1970",
"date_end":"01.01.1970","category":"Kleidung"},"_links":{"self":
[{"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/deals\/29"}],
"collection":[{"href":"http:\/\/localhost:8000\/wp-
json\/wp\/v2\/deals"}],"about":[{"href":"http:\/\/localhost:8000\/wp-
json\/wp\/v2\/types\/deals"}],"wp:attachment":
[{"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/media?
parent=29"}],"wp:term":[{"taxonomy":"tax_deals","embeddable":true,
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/tax-deals?
post=29"}],"curies":
[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}},
I have already tried using
http://localhost:8000/wp-json/wp/v2/deals?search=id
to get the id or something, but response is empty.
Also this didnt work:
http://localhost:8000/wp-json/wp/v2/deals?id=28
Again empty response.
To summarize: I need to filter my custom post type on my custom fields by the "acf" attribute shown in my response json. How does it work?
EDIT: I already installed "WP REST Filter" but still dont know how to do it.
I suggest you to create a new API where you can customize the output. Take advantage of wordpress function register_rest_route() using this you can create an API from CPT and ACF in one ajax url. And you do not need to install anything.
Check how I get my instructor CPT and mycheckbox ACF.
// your ajaxurl will be: http://localhost/yoursite/wp-json/custom/v2/instructor/
add_action( 'rest_api_init', function () {
register_rest_route( 'custom/v2', '/instructor', array(
'methods' => 'GET',
'callback' => 'instructor_json_query',
));
});
// the callback function
function instructor_json_query(){
// args to get the instructor
$args = array(
'post_type' => 'instructor',
'posts_per_page' => -1,
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => 'mycheckbox', // your acf key
'compare' => '=',
'value' => '1' // your acf value
)
)
);
$posts = get_posts($args);
// check if $post is empty
if ( empty( $posts ) ) {
return null;
}
// Store data inside $ins_data
$ins_data = array();
$i = 0;
foreach ( $posts as $post ) {
$ins_data[] = array( // you can ad anything here and as many as you want
'id' => $posts[$i]->ID,
'slug' => $posts[$i]->post_name,
'name' => $posts[$i]->post_title,
'imgurl' => get_the_post_thumbnail_url( $posts[$i]->ID, 'medium' ),
);
$i++;
}
// Returned Data
return $ins_data;
}
Then, you can use the link: http://localhost/yoursite/wp-json/custom/v2/instructor/ in your ajax url.

Wordpress REST API, how to get /post schema?

I have created a custom endpoint, that basically just grabs a few different posts from each category and returns it. This endpoint works fine, but the schema of each post being returned is not the same as when you just hit the default, built-in /posts endpoint. What do I have to do to keep the schemas consistent?
I have a feeling get_posts is the problem, but I have been doc crawling, and I cant seem to find anything that uses the same schema as /posts does.
// How the endpoint is built.
function anon_content_api_posts($category) {
$posts = get_posts(
array(
'posts_per_page' => 3,
'tax_query' => array(
array(
'taxonomy' => 'content_category',
'field' => 'term_id',
'terms' => $category->term_id,
)
)
)
);
$posts = array_map('get_extra_post_data', $posts); // just me appending more data to each post.
return $posts;
}
function anon_content_api_resources() {
$data = array();
$categories = get_categories(
array(
'taxonomy' => 'content_category',
)
);
foreach($categories as $category) {
$category->posts = anon_content_api_posts($category);
array_push($data, $category);
}
return $data;
}
Custom endpoint schema
ID:
author:
comment_count:
comment_status:
featured_image_url:
filter:
guid:
menu_order:
ping_status:
pinged:
post_author:
post_content:
post_content_filtered:
post_date:
post_date_gmt:
post_excerpt:
post_mime_type:
post_modified:
post_modified_gmt:
post_name:
post_parent:
post_password:
post_status:
post_title:
post_type:
to_ping:
Default /posts schema
_links:
author:
categories:
comment_status:
content:
date:
date_gmt:
excerpt:
featured_image_url:
featured_media:
format:
guid:
id:
link:
meta:
modified:
modified_gmt:
ping_status:
slug:
status:
sticky:
task_category:
template:
title:
type:
Any help would be appreciated!
Although this question is older, I had a difficult time finding the answer to getting the schema myself, so I wanted to share what I found.
Short Answer (to getting the schema information back): Use OPTIONS method on the route request
You are dealing with an endpoint that already exists /wp/v2/posts, so you probably want to modify the response of the existing route which you can do with register_rest_field() (this should keep the appropriate schema for all exposed post columns / fields, but allows you to modify the schema for the fields you are now exposing as well):
Something like this:
function demo_plugin_extend_route_rest_api()
{
register_rest_field(
'post',
'unexposed_column_in_wp_posts_table',
array(
'get_callback' => function( $post_arr ) {
$post_obj = get_post( $post_arr['id'] );
return $post_obj->unexposed_column_in_wp_posts_table;
},
'update_callback' => function( $unexposed_column_in_wp_posts_table, $post_obj ) {
$ret = wp_update_post(
array(
// ID is the name of the column in the posts table
// unexposed_column_in_wp_posts_table should be replaced throughout with the unexposed column in the posts table
'ID' => $post_obj->ID,
'unexposed_column_in_wp_posts_table' => $unexposed_column_in_wp_posts_table
)
);
if ( false === $ret )
{
return new WP_Error(
'rest_post_unexposed_column_in_wp_posts_table_failed',
__( 'Failed to update unexposed_column_in_wp_posts_table.' ),
array( 'status' => 500 )
);
}
return true;
},
'schema' => array(
'description' => __( 'Post unexposed_column_in_wp_posts_table' ),
'type' => 'integer'
),
)
);
}
// Not-in-class call (use only this add_action or the one below, but not both)
add_action( 'rest_api_init', 'demo_plugin_extend_route_rest_api' );
// In-class call
add_action( 'rest_api_init', array($this, 'demo_plugin_extend_route_rest_api') );
If what you are really wanting is to create a new route and endpoint with custom tables (or another endpoint to the posts table), something like this should work:
function demo_plugin_custom_rest_api()
{
// Adding Custom Endpoints (add tables and fields not currently exposed)
// register_rest_route()
// $namespace (string) (Required) The first URL segment after core prefix.
// Should be unique to your package/plugin.
// $route (string) (Required) The base URL for route you are adding.
// $args (array) (Optional) Either an array of options for the endpoint, or an
// array of arrays for multiple methods. Default value: array()
// array: If using schema element to define the schema, or multiple methods,
// then wrap the 'methods', 'args', and 'permission_callback' in an array,
// otherwise they do not need to be wrapped in an array. Best practice
// would be to wrap them in an array though
// 'methods' (array | string): GET, POST, DELETE, PUT, PATCH, etc.
// 'args' (array)
// '<schema property name>' (array) (ie. parameter name - if not including a schema
// then can include field names as valid parameters as a way to
// describe them):
// 'default': Used as the default value for the argument, if none is supplied
// Note: (if defined, then it will validate and sanitize regardless of if
// the parameter is passed in query).
// 'required': If defined as true, and no value is passed for that argument, an
// error will be returned. No effect if a default value is set, as the argument
// will always have a value.
// 'description': Field Description
// 'type': Data Type
// 'validate_callback' (function): Used to pass a function that will be passed the
// value of the argument. That function should return true if the value is valid,
// and false if not.
// 'sanitize_callback' (function): Used to pass a function that is used to sanitize
// the value of the argument before passing it to the main callback.
// 'permission_callback' (function): Checks if the user can perform the
// action (reading, updating, etc) before the real callback is called
// 'schema' (callback function) (optional): Defines the schema.
// NOTE: Can view this schema information by making OPTIONS method request.
// $override (bool) (Optional) If the route already exists, should we override it? True overrides,
// false merges (with newer overriding if duplicate keys exist). Default value: false
//
// View your describe page at: /wp-json/demo-plugin/v1
// View your JSON data at: /wp-json/demo-plugin/v1/demo-plugin_options
// View your schema at (with OPTIONS method) at: /wp-json/demo-plugin/v1/demo-plugin_options
// Note: For a browser method to see OPTIONS Request in Firefox:
// Inspect the JSON data endpoint (goto endpoint and click F12)
// > goto Network
// > find a GET request
// > click it
// > goto headers section
// > click Edit and Resend
// > change Method to OPTIONS
// > click Send
// > double click on last OPTIONS request
// > goto Response (the JSON data returned shows your schema)
register_rest_route(
'demo-plugin/v1',
'/demo-plugin_options/',
array(
// GET array options
array(
'methods' => array('GET'),
'callback' => function ( WP_REST_Request $request ){
// Get Data (here we are getting from options, but could be any data retrieval)
$options_data = get_option('demo_option_name');
// Set $param
$param = $request->get_params();
// Do Other things based upon Params
return $options_data;
},
'args' => array(
// Valid Parameters
'element_1' => array(
'description'=> 'Element text field',
'type'=> 'string',
),
'element_color' => array(
'description'=> 'Element color select box',
'type'=> 'string',
)
)
),
// POST array options
array(
'methods' => array('POST'),
'callback' => function ( WP_REST_Request $request ){
// Get Data (here we are getting from options, but could be any data retrieval)
$options_data = get_option('demo_option_name');
// Set $param
$param = $request->get_params();
// Do Other things based upon Params
if (is_array($param) && isset($param))
{
foreach ($param as $k=>$v)
{
// $param is in an array($key => array($key => $value), ...)
if (is_array($v) && array_key_exists($k, $options_data) && array_key_exists($k, $v))
{
$options_data[$k] = $v;
}
}
}
update_option('demo_option_name', $options_data);
return $options_data;
},
'args' => array(
'element_1' => array(
'default' => '',
'required' => false,
'description'=> 'Element text field',
'type'=> 'string',
'validate_callback' => function($param, $request, $key) { //validation function },
'sanitize_callback' => function($param, $request, $key) { //sanitization function }
),
'element_color' => array(
'default' => 'red',
'required' => true,
'description'=> 'Element color select box',
'type'=> 'integer',
'validate_callback' => function($param, $request, $key) {
$colors = array('red', 'blue');
return in_array($param, $colors);
},
'sanitize_callback' => function($param, $request, $key) {
// If it includes a default, and sanitize callback for other properties above are set, it seems to need it here as well
return true;
})
),
'permission_callback' => function () {
// See Capabilities here: https://wordpress.org/support/article/roles-and-capabilities/
$approved = current_user_can( 'activate_plugins' );
return $approved;
}
),
'schema' => function() {
$schema = array(
// This tells the spec of JSON Schema we are using which is draft 4.
'$schema' => 'http://json-schema.org/draft-04/schema#',
// The title property marks the identity of the resource.
'title' => 'demo-plugin_options',
'type' => 'object',
// In JSON Schema you can specify object properties in the properties attribute.
'properties' => array(
'element_1' => array(
'description' => esc_html__( 'Element text field', 'demo-plugin' ),
'type' => 'string',
'context' => array( 'view', 'edit', 'embed' ),
'readonly' => false,
),
'element_color' => array(
'description' => esc_html__( 'Element color select box', 'demo-plugin' ),
'type' => 'string',
'readonly' => false,
),
),
);
return $schema;
})
);
}
// Not-in-class call (use only this add_action or the one below, but not both)
add_action( 'rest_api_init', 'demo_plugin_custom_rest_api' );
// In-class call
add_action( 'rest_api_init', array($this, 'demo_plugin_custom_rest_api') );
Of course, this is just a basic outline. Here is a caveat:
According to the documentation listed below, it is best to use a Controller Pattern class extension method (rather than the method I outlined above): https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/#the-controller-pattern
These were very helpful links in finally putting this all together for myself:
REST API Handbook: https://developer.wordpress.org/rest-api/
See Sub-Pages:
REST API Modifying Responses,
REST API Adding Custom Endpoints,
REST API Schema
Register REST Field Function: https://developer.wordpress.org/reference/functions/register_rest_field/
Register REST Route Function: https://developer.wordpress.org/reference/functions/register_rest_route/

perform meta_query to a custom post meta with array values in pre_get_posts callback

I have a custom post meta that contains array values
code:
update_post_meta($post_id,'custom_meta_key',array('val1','val2','val3','val4'));
Now I want to hook a call back to pre_get_posts to modify the query
code:
add_action('pre_get_posts','foo');
function foo ($q){
if ( ! $q->is_main_query() ) return;
if ( ! $q->is_post_type_archive() ) return;
if ( ! is_admin() ) {
$q->set('meta_query',array(
array(
'key' => 'custom_meta_key',
'value' => array('val1','val3'),
'compare' => 'IN'
)
));
}
remove_action( 'pre_get_posts','foo');
}
I want to only get the posts with the 'custom_meta_key' post meta having values of 'val1' or 'val3'
but the result is blank, the page doesn't return any items at all.
this must be because update_post_meta serializes the array upon save?
Is what I am trying to achieve possible?
In order to achieve my goal, I need to change the way I persist post meta.
Instead of using update_post_meta, I have to use add_post_meta
so for this to work
$q->set('meta_query',array(
array(
'key' => 'custom_meta_key',
'value' => array('val1','val3'),
'compare' => 'IN'
)
));
I need to do this
delete_post_meta($post->id,'custom_meta_key');
add_post_meta($post->id,'custom_meta_key','val1');
add_post_meta($post->id,'custom_meta_key','val2');
I executed delete_post_meta first to prevent the values of the post meta from duplicating (I have attached a callback to save_post hook)
then I do add_post_meta for each of the values
now custom_meta_key will have a value of array('val1','val2') and the above code will work.
also, update_post_meta does serializes array, but when used as an argument to WP_Query's meta query, it does not unserialize the array string, that's why my code above on my question didn't worked
I confirmed this by doing this
update_post_meta($post->id,'custom_meta_key',array('val1'))
array(
'key' => 'custom_meta_key',
'value' => serialize(array('val1')),
'compare' => 'IN'
)
and it worked
referrences:
update_post_meta
add_post_meta
delete_post_meta

Custom filter in admin post list makes search form unvisible

I want to filter the posts list in admin area by custom field key/value :
So, I do :
add_filter( 'pre_get_posts', 'my_admin_posts_filter' );
function my_admin_posts_filter( $query )
{
global $pagenow;
$metaquery = array(
'relation' => 'AND',
array(
'key' => 'categorie_de_produit',
'value' => array(23559),
'compare' => 'IN'
));
set_query_var( 'meta_query', $metaquery );
//idem : $query->set( 'meta_query', $metaquery );
}
when the value exist, the results are ok. I have 3 results and the search form is visible:
But if the value (ex : 'value' => array(54644848486486486) ) doesn’t exist, the results are also correct (no result but it’s normal) but the search form is not visible…
Why the search form disappears?
It's default of Wordpress, if there have no post, it's will hide search form.
LOGIC = If doesn't have any post, what want search? :)

Resources