wordpress rest api v2 how to list taxonomy terms? - wordpress

i am new to v2, i use v1 for long time, currently upgrade to v2, i try to get all the terms belong to specific custom taxonomy.
In v1 i can do this to get terms
/taxonomies/location_category/terms
but in v2 i try
/taxonomies/terms
it return json error "code":"rest_no_route","message":"No route was found matching the URL and request method","data":{"status"
:404}}
if just /taxonomies/location_category/ it didn't show anything terms belong to taxonomy.
i search the question on google for few hours didn't show any result, anyone can help please, thank you

end out to write the custom code here
add blow code to functions.php
class all_terms
{
public function __construct()
{
$version = '2';
$namespace = 'wp/v' . $version;
$base = 'all-terms';
register_rest_route($namespace, '/' . $base, array(
'methods' => 'GET',
'callback' => array($this, 'get_all_terms'),
));
}
public function get_all_terms($object)
{
$return = array();
// $return['categories'] = get_terms('category');
// $return['tags'] = get_terms('post_tag');
// Get taxonomies
$args = array(
'public' => true,
'_builtin' => false
);
$output = 'names'; // or objects
$operator = 'and'; // 'and' or 'or'
$taxonomies = get_taxonomies($args, $output, $operator);
foreach ($taxonomies as $key => $taxonomy_name) {
if($taxonomy_name = $_GET['term']){
$return = get_terms($taxonomy_name);
}
}
return new WP_REST_Response($return, 200);
}
}
add_action('rest_api_init', function () {
$all_terms = new all_terms;
});
and enter url http://youdomain.com/wp-json/wp/v2/all-terms?term=you_taxonomy
so term = you_taxonomy, will get terms belong to job_category.

Taxonomy terms are simply called this way:
https://yoursite.com/wp-json/wp/v2/the-taxonomy-slug
For instance, to answer your question:
https://yoursite.com/wp-json/wp/v2/location_category
From terminal:
curl -X GET -i http://www.example.com/wp-json/wp/v2/location_category

For custom taxonomies, be sure that you're setting the 'show_in_rest' argument to be true (default is false) in your register_taxonomy() call.
The register_taxonomy() call is also where you can set the 'rest_base' argument (default will be the taxonomy name, /location_category/ in your example).

TLDR
Use the flag show_in_rest when you register the taxonomy. That's all.
Details
List all available taxonomies
All default taxonomies are available via REST API. Use the following endpoint to get a list of all available taxonomies:
https://exmaple.org/wp-json/wp/v2/taxonomies
It will tell you the correct endpoint for each taxonomy in the wp:items tag, e.g.
..., "wp:items":[{"href":"https://example.com/wp-json/wp/v2/categories"}], ...
..., "wp:items":[{"href":"https://example.com/wp-json/wp/v2/tags"}], ...
Adding new taxonomies to the REST endpoint
In case your taxonomy is not listed in this taxonomy overview, you need to enable the REST endpoint when calling register_taxonomy. You can do this by adding the argument 'show_in_rest' => true:
<php
register_taxonomy( 'location_category', 'post', [
// ...
'show_in_rest' => true, // ← make sure you have this line in the taxonomy args!
] );
Note: If you do NOT use show_in_rest, then the taxonomy is not available in the Block Editor ("Gutenberg").
I strongly advise against creating custom REST endpoints to duplicate built-in logic.
I.e. don't do this or this

Seems some confusion for some devs even for me.
Correct URL is
https://example.com/wp-json/wp/v2/{your_taxonomy}
Not
https://example.com/wp-json/wp/v2/taxonomies/{your_taxonomy}
"/taxonomies" not required

The accepted answer mostly worked for me. This is what I got
<?php
// your_theme/functions.php
/**
* how to list all taxonomy terms
*/
class all_terms
{
public function __construct()
{
$version = '2';
$namespace = 'wp/v' . $version;
$base = 'all-terms';
register_rest_route($namespace, '/' . $base, array(
'methods' => 'GET',
'callback' => array($this, 'get_all_terms'),
));
}
public function get_all_terms($object)
{
$args = array(
'public' => true,
'_builtin' => false
);
$output = 'names'; // or objects
$operator = 'and'; // 'and' or 'or'
$taxonomies = get_taxonomies($args, $output, $operator);
foreach ($taxonomies as $key => $taxonomy_name) {
if ($taxonomy_name = $_GET['term']) {
$return[] = get_terms(array(
'taxonomy' => $taxonomy_name,
'hide_empty' => false,
));
}
}
return new WP_REST_Response($return, 200);
}
}
add_action( 'rest_api_init', get_all_terms);
?>
matches the docs more closely https://developer.wordpress.org/reference/functions/get_terms/

If anyone is reading this in the future, I ran into an issue where the default WP category was outputting a parent key of 0, 1, 2 etc for each term object, which is a problem in itself, but a bigger problem when custom taxonomies do not have this parent value on objects
To solve this amend the ticked example with this:
foreach ($taxonomies as $key => $taxonomy_name) {
if($taxonomy_name = $_GET['term']){
$return = get_terms( array(
'taxonomy' => $taxonomy_name,
'hide_empty' => false,
));
}
}

Related

WooCommerce - adding object terms not working properly

I'm using the following code to add attributes with terms:
$taxonomy = 'pa_' . $attr['name']; // The attribute taxonomy
if (!taxonomy_exists($taxonomy)) {
global $wpdb;
$insert = $wpdb->insert(
$wpdb->prefix . 'woocommerce_attribute_taxonomies',
array(
'attribute_name' => $attr['name'],
'attribute_label' => $attr['name'],
'attribute_public' => 0
),
array('%s', '%s', '%d')
);
if (is_wp_error($insert)) {
throw new WC_API_Exception('woocommerce_api_cannot_create_product_attribute', $insert->get_error_message(), 400);
}
// Clear transients
delete_transient('wc_attribute_taxonomies');
}
if (!term_exists($attr['value'], $attr['name'])) {
wp_insert_term($attr['value'], $attr['name']);
}
$term_slug = get_term_by('name', $attr['value'], $attr['name'])->slug; // Get the term slug
wp_set_post_terms($product_id, $attr['value'], $attr['name'], true);
// Set/save the attribute data in the product variation
update_post_meta($variation_id, 'attribute_' . $taxonomy, $term_slug);
// Assign to the product
wp_set_object_terms($product_id, $attr['value'], $taxonomy, true);
$att = array($taxonomy => array(
'name' => $taxonomy,
'value' => $attr['value'],
'is_visible' => '1',
'is_variation' => '1',
'is_taxonomy' => '1',
));
update_post_meta($product_id, '_product_attributes', $att);
However, the first time the code runs it adds the attributes without terms. If I run it a second time, only then does it add the terms to the previously added attributes.
Why is that?
Edit: The problem seems to start at the following line:
$term_slug = get_term_by('name', $attr['value'], $attr['name'])->slug
It simply doesn't yet recognize the newly created taxonomy. Only at the next run.
But why? Is there a function that can be used to "refresh" the attributes, or the $wp_attributes variable, which seems to be closely related?
Thanks!
It is hard to debug without looking at the live site. However, I think it could be something to do with this code:
if (!term_exists($attr['value'], $attr['name'])) {
wp_insert_term($attr['value'], $attr['name']);
}
On first request the term is inserted yet it will not be part of WordPress main query until further requests.
Again, this is mostly guessing as I need to see the actual implementation.
I use such a method to create a taxonomy.
public function setAttribute($attributeArgs)
{
$attributeId = wc_attribute_taxonomy_id_by_name($attributeArgs['slug']);
if ($attributeId === 0) {
$attributeId = wc_create_attribute($attributeArgs);
register_taxonomy('pa_' . $attributeArgs['slug'], ['product'], []);
} else {
$attributeId = wc_update_attribute($attributeId, $attributeArgs);
}
return [
'id' => $attributeId,
'args' => $attributeArgs,
];
}
An important line in this code is register_taxonomy('pa_' . $attributeArgs['slug'], ['product'], []);
Without this line, I had the same problem.

Wordpress REST response shows taxonomy categories only with ID's

I'm using WP as a headless CMS with ACF en ACF-2-REST plugins. I've added categories to a post-type and when I make a GET call, it shows me all the information of a particular post including the categories, but only the ID's. If I want to match it, I have to do another call to Categories to get the information of that categories (name, parent etc).
How can I show that information instead of just the ID in a post call?
How the JSON looks now at the /activities call:
{
"id":111,
"date":"2020-01-18T15:39:27",
"date_gmt":"2020-01-18T15:39:27",
"guid":{"rendered":"https:\/\/url.be\/?post_type=activities&p=111"},
"modified":"2020-01-18T15:39:27",
"modified_gmt":"2020-01-18T15:39:27",
"slug":"walking-on-wood",
"status":"publish",
"type":"activities",
"link":"https:\/\/url.be\/activities\/walking-on-wood\/",
"title":{"rendered":"Walking on wood"},
"template":"",
"categories":[14,25,13,2,18,21,6,24],
"acf":{...}
}
What I want to show in the "categories" instead of just the numbers (from the categories call)
{
"id":3,
"count":1,
"description":"",
"link":"https:\/\/url.be\/category\/duration\/lower-than-30-min\/",
"name":"< 30 min.",
"slug":"lower-than-30-min",
"taxonomy":"category",
"parent":2,"meta":[],
"acf":[],
"_links":{"self":[{"href":"https:\/\/url.be\/wp-json\/wp\/v2\/categories\/3"}],
"collection":[{"href":"https:\/\/url.be\/wp-json\/wp\/v2\/categories"}],
"about":[{"href":"https:\/\/url.be\/wp-json\/wp\/v2\/taxonomies\/category"}],
"up":[{"embeddable":true,"href":"https:\/\/url.be\/wp-json\/wp\/v2\/categories\/2"}],
"wp:post_type":[{"href":"https:\/\/url.be\/wp-json\/wp\/v2\/posts?categories=3"},{"href":"https:\/\/url.be\/wp-json\/wp\/v2\/activities?categories=3"}],
"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}
}
Can't find any solution on the internet how I could manipulate the structure of that JSON with a custom function, would appreciate it a lot if someone point me to the right direction. Thanks!
As discussed in the comments section, a solution to this question is to use a custom endpoint method for the WP REST API and perform extra queries in there to get the data you need. This way, you can do all the data manipulation to get the perfect response, resulting in one REST call.
As taken from the official developer docs
Define an endpoint method and add some extra data
<?php
add_action( 'rest_api_init', function () {
register_rest_route( 'myplugin/v1', '/author/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => 'my_awesome_func', //note that this is the method it will fire
'args' => array(
'id' => array(
'validate_callback' => function($param, $request, $key) {
return is_numeric( $param );
}
),
),
) );
/**
* Grab latest post by an author along with its category!
*
* #param array $data Options for the function.
* #return array Post,
*/
function my_awesome_func( $data ) {
$posts = get_posts( array(
'author' => $data['id'],
) );
if(!empty($posts)) {
//Example of appending extra data
foreach($posts as $post) {
$category = wp_get_post_terms($post->ID, 'category');
$post['category'] = $category;
}
return $posts;
} else {
return new WP_Error( 'no_author', 'Invalid author', array( 'status' => 404 ) );
}
}

Drupal 7: custom module: display custom contentTypy in custom block

I'm new at Drupal 7, so I have a question.
I have my own content type Writers that includes such fields as Title, Years of life, Photo, Description.
I have a task to display 3 random Writers at page. Actual I've done it with help of Views module, but I want to do it myself.
So I created my own module random_content like that:
<?php
function random_content_help($path, $arg) {
switch ($path) {
case "admin/help#random_content":
return '<p>'. t("Displays random content") .'</p>';
break;
}
}
function random_content_block_info() {
$blocks['random_content'] = array(
'info' => t('Random content'),
'cache' => DRUPAL_CACHE_PER_ROLE,
);
return $blocks;
}
function random_content_contents() {
$query = db_select('node', 'n')
->fields('n', array('nid', 'title'))
->condition('type', 'writers')
->orderBy('rand()')
->range(0,3)
->execute();
return $query;
}
function random_content_block_view($delta = '') {
switch($delta){
case 'random_content':
$block['subject'] = t('Random content');
if(user_access('access content')) {
$result = random_content_contents();
$items = array();
foreach ($result as $node){
$items[] = array(
'data' => l($node->title, 'node/' . $node->nid) . '</br>',
);
}
if (empty($items)) {
$block['content'] = t('No data availible.');
} else {
$block['content'] = theme('item_list', array(
'items' => $items));
}
}
}
return $block;
}
As you can see, I've learned only to add links to particular content. But how can I display full information including Title, Years of life, Photo and Description?
To display the full node, or parts of it you need to load the node. E.g.
$my_node = node_load($nid);
$render_array = array();
$render_array['title'] = array(
'#type' => 'markup',
'#markup' => $my_node->title
);
$author = field_get_items('node', $my_node, 'field_author','und');
$render_array['author'] = array(
'#type' => 'markup',
'#markup' => $author[0]['safe_value']
);
// or as some like to do it
$render_array['author'] = array(
'#type' => 'markup',
'#markup' => $my_node->field_author['und'][0]['value']
);
echo drupal_render($render_array);
Note the 'und' constant means the language is undefined. If you have translation/language enabled and different content for different languages you would have to use 'en', 'de' etc. for the appropriate language.
You can also let drupal render the node and then manipulate or retrieve individual items. Like this
$my_node = node_load($nid);
$build = node_view($my_node,'full');
$build['body'][0]['#markup'] = $build['body'][0]['#markup'].' some addition';
$build['field_author'][0]['#markup'] = $build['field_author'][0]['#markup'].' my favorite';
echo drupal_render($build);
The advantage of using this latter method is that then the whole themeing engine kicks in, and all hooks that are set to act on the content etc. Of course, if you only want to retrieve values you don't need that.
Note also, I assume your author field is named field_author. You should check that in the field edit window for the content type.

Wordpress Add Taxonomy tag to permalink custom post type

I am searching days now for the answer how to add taxonomy to my custom post type permalink. I've found this article which almost exactly gives the answer but it doesn't work for my custom post type.
http://shibashake.com/wordpress-theme/add-custom-taxonomy-tags-to-your-wordpress-permalinks
The article describes that you first make a simple Taxonomy:
add_action('init', 'my_rating_init');
function my_rating_init() {
if (!is_taxonomy('rating')) {
register_taxonomy( 'rating', 'post',
array( 'hierarchical' => FALSE, 'label' => __('Rating'),
'public' => TRUE, 'show_ui' => TRUE,
'query_var' => 'rating',
'rewrite' => true ) );
}
}
And then you can rewrite the url in your Wordpress system like: /%rating%/%postname%
And then you need to translate %rating% to the taxonomy tags by doing:
add_filter('post_link', 'rating_permalink', 10, 3);
add_filter('post_type_link', 'rating_permalink', 10, 3);
function rating_permalink($permalink, $post_id, $leavename) {
if (strpos($permalink, '%rating%') === FALSE) return $permalink;
// Get post
$post = get_post($post_id);
if (!$post) return $permalink;
// Get taxonomy terms
$terms = wp_get_object_terms($post->ID, 'rating');
if (!is_wp_error($terms) && !empty($terms) && is_object($terms[0])) $taxonomy_slug = $terms[0]->slug;
else $taxonomy_slug = 'not-rated';
return str_replace('%rating%', $taxonomy_slug, $permalink);
}
This works fine for "post" but when I change:
register_taxonomy( 'rating', 'post',
to:
register_taxonomy( 'rating', 'mycustomposttype',
The URL rewrite doesn't work anymore. And only gives the following url:
http://www.website.com/custom-post-type/post
Where I want this:
http://www.website.com/custom-post-type/taxonomy-tag/post
So my 2 questions are:
How can I make this work for my custom post type?
How can I make this work only for my custom post type? Because I need to add %rating% to my wordpress system (settings -> permalinks) so it changes all my URLS.
Try like this
add_filter('post_link', 'modify_permalink', 10, 2);
add_filter('post_type_link', 'modify_permalink', 10, 2);
function modify_permalink($url, $post) {
// limit to certain post type. remove if not needed
if ($post->post_type != 'article') {
return $url;
}
// fetches post type to get slug for post type
$type = get_post_type_object($post->post_type);
// fetches term
$term = get_the_terms($post->ID, 'rating');
if ($term && count($term)) {
// takes only 1st one
$term = array_pop($term);
// creates the url prepending post type slug and term slug to post name
$url = site_url('/').($type->rewrite ? $type->rewrite['slug'].'/' : '' ).$term->slug.'/'.$post->post_name;
}
return $url;
}
And then you must add custom url rewrites. As explained here on wordpress site

wordpress custom post types - broken publish button

I created a gallery post type (as part of a plugin) that contains besides a title and some meta information also a wp_list_table that queries those attachments which have the current post as post_parent. I ran into a problem when suddenly my publish button stopped working. No matter if I'm creating a new gallery or if I'm editing an old one, once I click on update/publish my changes get lost and I end up on edit.php.
Anybody knows what that's all about?
I where able to figure out where the problem seems to be. It's in my list_table class which inherits from wp_list_table. after commenting out some unimportant functions i ended up with a different error but still no new or updated gallery. Now I get the are you sure you want to do this page.
Even the most basic class won't work...
if( ! class_exists( 'WP_List_Table' ) ) {
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
class Yard_Attachment_Table extends WP_List_Table {
function __construct() {
global $status, $page;
parent::__construct( array(
'singular' => 'yard Attachment',
'plural' => 'yard Attachments',
'ajax' => false
) );
}
function column_default($item, $column_name) {
return 'default';
}
function get_columns(){
$columns = array(
'checkbox' => '<input type="checkbox" />', //for simplicity its not 'cb'
'thumb' => 'Thumbnail',
'title' => 'Titel',
'pos' => 'Position'
);
return $columns;
}
function prepare_items() {
global $wpdb;
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array($columns, $hidden, $sortable);
if (isset($_REQUEST['post'])) {
$query = " SELECT *
FROM $wpdb->posts
WHERE post_type = 'attachment'
AND post_parent = {$_REQUEST['post']}";
$data = $wpdb->get_results($query, ARRAY_A);
} else {
$data = array();
}
$this->items = $data;
}
}
In the plugin class' constructor I use
add_action('add_meta_boxes_yard_gallery', array($this, 'yard_metaboxes'));.
In yard_metaboxes I use add_meta_box and in the function I have as a callback i'm creating a new instance of my table class and I call prepare_items() and display()
Turning error_reporting on my page dies with these messages:
Strict Standards: Only variables should be passed by reference in /Applications/MAMP/htdocs/Web/ChristophRokitta/wp v.1.0/wp-includes/pomo/mo.php on line 210
Warning: Cannot modify header information - headers already sent by (output started at /Applications/MAMP/htdocs/Web/ChristophRokitta/wp v.1.0/wp-includes/pomo/mo.php:210) in /Applications/MAMP/htdocs/Web/ChristophRokitta/wp v.1.0/wp-includes/pluggable.php on line 876
BTW I'm not localizing.
Please help! If i had more reputation I'd offer it.
Adding the meta box code
in my plugin file:
require_once( plugin_dir_path( __FILE__ ) . 'class-yard.php' );
Yard::get_instance();
in my class-yard file the meta box methods are at the bottom:
class Yard {
protected static $instance = null;
private function __construct() {
include_once('class-yard-attachments.php');
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_styles' ) );
add_action('after_setup_theme', array($this, 'yard_thumbnails'));
add_action('init', array($this, 'yard_post_type'));
add_action('init', array($this, 'yard_taxonomies'));
add_filter('manage_yard_gallery_posts_columns', array($this, 'yard_add_columns'));
add_action('manage_posts_custom_column', array($this, 'yard_fill_columns'));
add_action('add_meta_boxes_yard_gallery', array($this, 'yard_metaboxes'));
}
public static function get_instance() {// If the single instance hasn't been set, set it now.
if (null == self::$instance ) {
self::$instance = new self;
}
return self::$instance;
}
public function enqueue_admin_styles() {
$screen = get_current_screen();
if ($screen->post_type == 'yard_gallery') {
wp_register_style( 'yard-gallery-style', plugins_url('css/yard-gallery-style.css', __FILE__) );
wp_enqueue_style( 'yard-gallery-style' );
}
}
public function yard_thumbnails() {
//add_image_size('yard-thumbnail', 100, 100, true);
}
public function yard_post_type() {
$gallery_labels = array(
'name' => 'Galerien',
'singular_name' => 'Galerie',
'all_items' => 'Alle Galerien',
'add_new' => 'Erstellen',
'add_new_item' => 'Neue Galerie erstellen',
'edit_item' => 'Galerie bearbeiten',
'new_item' => 'Neue Galerie',
'view' => 'Galerie anzeigen',
'view_item' => 'Gallerie anzeigen',
'search_items' => 'Galerie durchsuchen',
'not_found' => 'Keine Galerien gefunden',
'not_found_in_trash' => 'Es befinden sich keine Galerien im Papierkorb',
'parent_item_colon' => ''
);
$gallery_args = array(
'labels' => $gallery_labels,
'public' => true,
// 'publicly_queryable' => true,
// 'show_ui' => true,
// 'show_in_menu' => true,
// 'query_var' => true,
'rewrite' => true,
// 'capability_type' => 'post',
// 'hierarchical' => false,
'menu_position' => 12,
'supports' => array(
'title'
)
// 'menu_icon' => plugin_dir_url(__FILE__) . '/assets/icon_16_grey.png'//16x16 png if you want an icon
);
register_post_type('yard_gallery', $gallery_args);
}
public function yard_taxonomies() {
register_taxonomy(
'yard_work_type',
'yard_gallery',
array(
'hierarchical' => true,
'label' => 'Art der Arbeit'
)
);
register_taxonomy(
'yard_subject',
'yard_gallery',
array(
'hierarchical' => true,
'label' => 'Motiv'
)
);
}
public function yard_add_columns( $columns ){
$columns = array(
'cb' => '<input type="checkbox">',
'yard_post_thumb' => 'Thumbnail',
'title' => 'Bezeichnung',
'yard_pos' => 'Position',
'date' => 'Datum'
);
return $columns;
}
public function yard_fill_columns( $column ) {
global $post;
switch ($column) {
case 'yard_post_thumb' :
echo the_post_thumbnail('admin-list-thumb');
break;
}
}
public function yard_metaboxes( $post ) {
global $wp_meta_boxes;
add_meta_box(
'yard-attachments',
'Bilder',
array($this, 'get_yard_attachment_table'),
'yard_gallery'
);
}
public function get_yard_attachment_table() {
$yard_list_table = new Yard_Attachment_Table();
$yard_list_table->prepare_items();
$yard_list_table->display();
}
}
Strict Standards: Only variables should be passed by reference in /Applications/MAMP/htdocs/Web/ChristophRokitta/wp v.1.0/wp-includes/pomo/mo.php on line 210
The error message tells it all. The ".../popo/mo.php" file has to do with (is related to) the Wordpress translation. (I bet you're using Wordpress with German language files).
I can't see what could be wrong in the code you've posted here, but something is interfering with translation. Looking at what the error message tells us, some variable that Wordpress tries to translate fails to be translated since it's not the correct type.
Warning: Cannot modify header information - headers already sent by (output started at /Applications/MAMP/htdocs/Web/ChristophRokitta/wp v.1.0/wp-includes/pomo/mo.php:210) in /Applications/MAMP/htdocs/Web/ChristophRokitta/wp v.1.0/wp-includes/pluggable.php on line 876
This is a logic result of the previous error message and the headers Wordpress tries to send to the browser.
What's happening: the first error message is being pushed to the client and flushed to the browser screen. Next, Wordpress tries to send it's usual headers and produces an error while doing so because headers have to be send before ANY content is being send to the client.
In other words: the "Cannot modify header information" error always comes up when you echo something to screen and then try to send "header(...)" information. In this case, the translation problem produces the first error message and then Wordpress tries to send headers, which fails and produces the second error message.
TIPS
Check everything you're doing which is related to translation (read: wherever you are passing "German" and/or "English" language strings)
and even more important
Make sure that you're actually passing the correct type(s)... looking at the error and your code, it could well be you're passing a class, a class reference, or another object somewhere instead of the expected variable.

Resources