WP-REST API excluding category doesn't work - wordpress

I used this semi-official plugin to enable API call.
But I can't find a way to exclude category. For example if I have mysite.com/wp-json/wp/v2/posts?filter[category__not_in]=10, it will ignores the filter and show all latest posts.
Is there a way to exclude category from the API call?

With the Rest API some filters are available only for logged in users:
In addition, the following are available when authenticated as a user
with edit_posts:
[...]
category__not_in
This is taken from the Rest API 1.0 documentation.
What that mean is you need to logged in as an editor (user with edit_posts capability). For doing this in a clean way, I suggest create a minimal role for REST user with only the capabilities you need, something like this:
add_role(
'rest_user',
__( 'REST User' ),
array(
'read' => true,
'edit_posts' => true,
'delete_posts' => false
)
);
Then do your query as authenticated user with the following:
$response = wp_remote_request('http://example.com/wp-json/wp/v2/posts?filter[category__not_in]=10', array(
'method' => 'GET',
'headers' => array(
'Authorization' => 'Basic ' . base64_encode('login:password')
)
));
Thanks to this article you shared, it seems you need to declare the filter name as query var, so in this case:
add_filter('query_vars', function($query_vars) {
$query_vars[] = 'category__not_in';
return $query_vars;
});
Which make sense because Wordpress is droping any GET parameter that isn't declare, though I don't understand why all the filters are not declared as query vars inside the WP Core...

For WP API V2 use a minus sign, for example:
http://yourwpwebsite/wp-json/wp/v2/posts/&filter[cat]=1,2,-3
will retrieve all posts in categories with id= 1 and id = 2 but excluding any posts in category with id= 3

Related

Creating page with custom url / meta tags using Wordpress REST API

I'm trying to create a custom page on my domain that has the url 'http://example.com/test/slug', however the slug does not seem to support slashes (the slug '/test/slug' turns into '/testslug'). Is it possible using the rest api to create a page on a custom url?
Also, I populate the 'meta' dictionary, however the page created does not contain a meta 'description' tag in the header. How can I correctly create custom meta tags?
import requests
url = 'http://example.com/wp-json/wp/v2/pages'
data = {'content': '<h2>test content</h2>',
'meta': {'description': 'this is a test meta field'},
'slug': 'test/slug',
'status': 'publish',
'title': 'test title'}
resp = requests.post(url, json=data, auth=('user','pass'), headers={'Content-Type':'application/json'})
the slug does not seem to support slashes (the slug '/test/slug' turns
into '/testslug').
Yes, because whether you use the REST API or the admin UI for creating Pages, the slug is limited to alphanumeric characters, plus dashes (-) and underscores (_). See https://developer.wordpress.org/rest-api/reference/pages/#schema-slug.
You can remove the limitation by adding remove_filter( 'sanitize_title', 'sanitize_title_with_dashes', 10, 3 ); to the theme's functions.php file (or a custom plugin); however, visiting the page (URL) would by default throw a 404 (not found) error. There are ways to fix that, but in short, you should not remove the filter.
Is it possible using the rest api to create a page on a custom url?
No it's not, not by default.
However, if you want http://example.com/test/slug to serve/show a Page/Post/etc. be it created via the REST API or not, then you can use custom URL rewrite rules, e.g. via add_rewrite_rule().
the page created does not contain a meta 'description' tag in the
header. How can I correctly create custom meta tags?
You need to register the meta key, which in your case is description.
See
Working with registered meta in the REST API
Read and write a post meta field in post responses
And you can register it using the register_meta() function in wp-includes/meta.php.
Example for your description meta:
<?php
// The object type. For custom post types, this is 'post';
// for custom comment types, this is 'comment'. For user meta,
// this is 'user'.
$object_type = 'post'; // 'post' even for Pages
$args1 = array( // Validate and sanitize the meta value.
// Note: currently (4.7) one of 'string', 'boolean', 'integer',
// 'number' must be used as 'type'. The default is 'string'.
'type' => 'string',
// Shown in the schema for the meta key.
'description' => 'A meta key associated with a string meta value.',
// Return a single value of the type.
'single' => true,
// Show in the WP REST API response. Default: false.
'show_in_rest' => true,
);
register_meta( $object_type, 'description', $args1 );
To quickly test if the meta description was successfully registered and that it's being available from the REST API, perform a GET request to http://example.com/wp-json/wp/v2/pages/<id> where <id> is the Page ID.
First, make sure your Permalinks settings is "Post Name".
This can be configured under http://<yoursite.com>/wp-admin/options-permalink.php
I have studied "Custom Permalinks" plugin code to understand how to answer this question, it saves a metadata called "custom_permalink" and does heavy INNER JOINS to make WordPress core work with "fake" sub-slugs.
I came up with a different solution. The trick here is to create a fake parent page to serve as a base URL for children pages. I have written it in PHP, since I don't know Python.
<?php
require_once('helpers.php');
define('API_URL', 'http://temp.localhost');
# Let's get all pages in an array
$pages = curlGet(API_URL.'/wp-json/wp/v2/pages');
# Your usual $args
$args = array(
'title' => 'API TEST',
'status' => 'draft',
'content' => 'content',
'slug' => 'some/thing'
);
# We intercept it here, before sending to WordPress
$args = maybe_add_parent($args);
$response = curlPost( API_URL.'/wp-json/wp/v2/pages/', $args );
/**
* Receives an $args array that would be sent to WordPress API and checks if we need to add a parent page
*/
function maybe_add_parent(array $args) {
if (array_key_exists('slug', $args)) {
# Has parent?
if (strpos($args['slug'], '/') !== false) {
$parent = explode('/', $args['slug']);
# For simplicity sake let's do it parent/chidren slugs only
if (count($parent) !== 2) {
die('This script can only run parent/children slugs');
}
$slug = array_pop($parent);
# Here, we will check the parent to see if it exists.
$parent_id = slug_exists($parent[0]);
if ($parent_id === false) {
# If it does not, it will create it and return it's ID
$parent_id = create_parent($parent[0]);
}
# Add parent ID to $args.
$args['parent'] = $parent_id;
# Rename the slug
$args['slug'] = $slug;
}
}
return $args;
}
/**
* Checks if a given slug exists in $pages
*/
function slug_exists(string $slug) {
global $pages;
foreach ($pages as $page) {
# Checks if a "Parent" page with this slug exists
if ($page['slug'] == $slug && $page['parent'] == 0) {
return true;
}
}
return false;
}
/**
* Creates a parent page
*/
function create_parent(string $slug) {
$args = array(
'title' => $slug,
'status' => 'draft',
'content' => '',
'slug' => $slug
);
$response = json_decode(curlPost( API_URL.'/wp-json/wp/v2/pages/', $args ));
return $response->id;
}
The script does the following:
Send a GET request for all the pages on the website.
Intercepts an $args array that would be sent to the WordPress API.
Checks if this $args contains a slug in the format parent/child
If it does, check if parent page exists
If it doesn't, it will create this page as a draft and return it's ID
It the parent already exists, it will just return it's ID
With the Parent ID, it will modify $args adding parent key and return $args
When WordPress sees that that page has a parent, it will automatically add it's slug in the url, as in parent/child
It works:
To get the URL structure you want, the most straightforward way is to create a child page that references an already existing page as it's parent.
To amend your example above:
import requests
url = 'http://example.com/wp-json/wp/v2/pages'
parent_page = 43 # assuming that page with URL '/test' has id of 42
data = {'content': '<h2>test content</h2>',
'meta': {'description': 'this is a test meta field'},
'slug': 'slug',
'status': 'publish',
'title': 'test title'
'parent': parent_page} # <--
resp = requests.post(url, json=data, auth=('user','pass'), headers={'Content-Type':'application/json'})
Would give you a new page at example.com/test/slug
Reference to arguments for "Create a Page", (POST /wp/v2/pages) on WordPress rest API Handbook: https://developer.wordpress.org/rest-api/reference/pages/#create-a-page

WooCommerce - include custom fields in the search function

So I'm looking to include the functionality of displaying content by its custom fields as well as its title and content.
I need to be able to search for orders, as well as subscriptions, on WooCommerce by custom field as well as the normal method. Is there any way I can, without adding additional search forms or booleans, simply get Wordpress to display posts that match with the search term by their custom fields, too?
I have used the following code thanks to a responder on here:
function custom_search_query( $query ) {
$custom_fields = array(
// put all the meta fields you want to search for here
"gender",
"birthdate"
);
$searchterm = $query->query_vars['s'];
// we have to remove the "s" parameter from the query, because it will prevent the posts from being found
$query->query_vars['s'] = "";
if ($searchterm != "") {
$meta_query = array('relation' => 'OR');
foreach($custom_fields as $cf) {
array_push($meta_query, array(
'key' => $cf,
'value' => $searchterm,
'compare' => '=='
));
}
$query->set("meta_query", $meta_query);
};
}
add_filter( "pre_get_posts", "custom_search_query");
This works great when searching orders, but what I need to search is subscriptions, where it doesn't work.
Help would be much appreciated!

Update User Meta with spaces using REST API - WordPress

I'm trying to update the user meta with spaces registered on my website. I am using register_meta hook to register user meta. And for updating users using WordPress REST API I use wp_remote_post but the problem is when I tried to update a user meta with spaces it will add as array in response then it will add as new user meta.
For example the value of user meta is - community test
Sample Response:
[meta] => Array
(
[agent_community] => Array
(
[0] => community
[1] => test
)
)
Sample Code for registering user meta.
register_meta('user', 'agent_community', array(
"type" => "string",
"show_in_rest" => true
));
Update using wp_remote_post
$update_data = array('email'=> 'test#mail.com', 'meta[agent_community]' => 'community test');
$args = array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( 'username:password' ),
),
'body' => array_filter($update_data));
$update_url = 'https://test-url.com/wp-json/wp/v2/users/17';
$response = wp_remote_post( $update_url, $args);
Database:
Is there a way that can merge the array on user meta?
implode() might help you. And you can change spaces with HTML entities. Or use function like urledncode() / urlendecode() or something like this.

How to get all user details in rest api wordpress

I am trying to get all the user details from wordpress 4.7 through the rest api - wp-json/wp/v2/users.
Currently I am seeing a lot of fields for the user object (close to 100 fields, amr user plugin installed) in the wordpress site, but the api is returning very few fields.
How can I get all the fields of user object in the rest api, should I install any other plugin for the same?
You are only receiving the user fields which are stored in the wp_users table, but not the fields which are stored in the wp_usermeta table.
In order to get all information about a user, you have to get the user meta fields of this user from the REST API.
How to get user meta fields from the REST API:
Look into register_rest_field() to register meta with the rest api.
add_action( 'rest_api_init', 'adding_user_meta_rest' );
function adding_user_meta_rest() {
register_rest_field( 'user',
'collapsed_widgets',
array(
'get_callback' => 'user_meta_callback',
'update_callback' => null,
'schema' => null,
)
);
}
And then put your get_user_meta bit in the callback.
function user_meta_callback( $user, $field_name, $request) {
return get_user_meta( $user[ 'id' ], $field_name, true );
}
The WP_REST_Meta_Fields class may provide more useful insight as well.
The later part of this answer I have found in this answer on WordPress Stackexchange: https://wordpress.stackexchange.com/questions/270154/getting-user-meta-data-from-wp-rest-api

WordPress get user by meta data

How can I retrieve all users registered in my WordPress blog having a particular meta data?
For example I have made an option to add a custom meta data for every registering users having meta key as parent_id. If I want to list all users having parent_id as 2 , then how can I do this?
Since WP v3.1 it's ridiculously easy to search for a user by his/her meta key.
Use the function
get_users($args)
(WP Documentation)
The function takes an array of parameters, in your case you need
get_users(array(
'meta_key' => 'parent_id',
'meta_value' => '42'
))
Simple way how to get one user by his metadata is:
$user = reset(
get_users(
array(
'meta_key' => $meta_key,
'meta_value' => $meta_value,
'number' => 1
)
)
);
Here is how you can get users based on a custom role and multiple metadata keys,
$available_drivers = get_users(
array(
'role' => 'driver',
'meta_query' => array(
array(
'key' => 'approved',
'value' => true,
'compare' => '=='
),
array(
'key' => 'available',
'value' => true,
'compare' => '=='
)
)
)
);
Explaining the above query, I want only those users who I assigned the role of driver, and they are approved and available. The approved and available are custom fields created using ACF as True/False fields.
If you have additional metadata to test, add another array element to the meta_query array.
Meanwhile checkout my open source at github.com/patrickingle
Here is the codex page from Wordpress detailing how to use the get_users($arg); function.
It contains examples how how to build custom functions to fetch various parts of user data. You'll have to naturally build and make some of your own changes to get it how you want.
Additionally here is a link to a function somebody built that will fetch user data based on roles within wordpress. You can configure it in many different ways with some tweeking, but this will allow you to filter your results in a more powerful manner.

Resources