WC_REST_Terms_Controller

Abstract Rest Terms Controller Class.

Defined (1)

The class is defined in the following location(s).

/includes/abstracts/abstract-wc-rest-terms-controller.php  
  1. abstract class WC_REST_Terms_Controller extends WC_REST_Controller { 
  2.  
  3. /** 
  4. * Route base. 
  5. * @var string 
  6. */ 
  7. protected $rest_base = ''; 
  8.  
  9. /** 
  10. * Taxonomy. 
  11. * @var string 
  12. */ 
  13. protected $taxonomy = ''; 
  14.  
  15. /** 
  16. * Register the routes for terms. 
  17. */ 
  18. public function register_routes() { 
  19. register_rest_route( $this->namespace, '/' . $this->rest_base, array( 
  20. array( 
  21. 'methods' => WP_REST_Server::READABLE,  
  22. 'callback' => array( $this, 'get_items' ),  
  23. 'permission_callback' => array( $this, 'get_items_permissions_check' ),  
  24. 'args' => $this->get_collection_params(),  
  25. ),  
  26. array( 
  27. 'methods' => WP_REST_Server::CREATABLE,  
  28. 'callback' => array( $this, 'create_item' ),  
  29. 'permission_callback' => array( $this, 'create_item_permissions_check' ),  
  30. 'args' => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( 
  31. 'name' => array( 
  32. 'type' => 'string',  
  33. 'description' => __( 'Name for the resource.', 'woocommerce' ),  
  34. 'required' => true,  
  35. ),  
  36. ) ),  
  37. ),  
  38. 'schema' => array( $this, 'get_public_item_schema' ),  
  39. )); 
  40.  
  41. register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array( 
  42. 'args' => array( 
  43. 'id' => array( 
  44. 'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),  
  45. 'type' => 'integer',  
  46. ),  
  47. ),  
  48. array( 
  49. 'methods' => WP_REST_Server::READABLE,  
  50. 'callback' => array( $this, 'get_item' ),  
  51. 'permission_callback' => array( $this, 'get_item_permissions_check' ),  
  52. 'args' => array( 
  53. 'context' => $this->get_context_param( array( 'default' => 'view' ) ),  
  54. ),  
  55. ),  
  56. array( 
  57. 'methods' => WP_REST_Server::EDITABLE,  
  58. 'callback' => array( $this, 'update_item' ),  
  59. 'permission_callback' => array( $this, 'update_item_permissions_check' ),  
  60. 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),  
  61. ),  
  62. array( 
  63. 'methods' => WP_REST_Server::DELETABLE,  
  64. 'callback' => array( $this, 'delete_item' ),  
  65. 'permission_callback' => array( $this, 'delete_item_permissions_check' ),  
  66. 'args' => array( 
  67. 'force' => array( 
  68. 'default' => false,  
  69. 'type' => 'boolean',  
  70. 'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce' ),  
  71. ),  
  72. ),  
  73. ),  
  74. 'schema' => array( $this, 'get_public_item_schema' ),  
  75. ) ); 
  76.  
  77. register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array( 
  78. array( 
  79. 'methods' => WP_REST_Server::EDITABLE,  
  80. 'callback' => array( $this, 'batch_items' ),  
  81. 'permission_callback' => array( $this, 'batch_items_permissions_check' ),  
  82. 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),  
  83. ),  
  84. 'schema' => array( $this, 'get_public_batch_schema' ),  
  85. ) ); 
  86.  
  87. /** 
  88. * Check if a given request has access to read the terms. 
  89. * @param WP_REST_Request $request Full details about the request. 
  90. * @return WP_Error|boolean 
  91. */ 
  92. public function get_items_permissions_check( $request ) { 
  93. $permissions = $this->check_permissions( $request, 'read' ); 
  94. if ( is_wp_error( $permissions ) ) { 
  95. return $permissions; 
  96.  
  97. if ( ! $permissions ) { 
  98. return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  99.  
  100. return true; 
  101.  
  102. /** 
  103. * Check if a given request has access to create a term. 
  104. * @param WP_REST_Request $request Full details about the request. 
  105. * @return WP_Error|boolean 
  106. */ 
  107. public function create_item_permissions_check( $request ) { 
  108. $permissions = $this->check_permissions( $request, 'create' ); 
  109. if ( is_wp_error( $permissions ) ) { 
  110. return $permissions; 
  111.  
  112. if ( ! $permissions ) { 
  113. return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  114.  
  115. return true; 
  116.  
  117. /** 
  118. * Check if a given request has access to read a term. 
  119. * @param WP_REST_Request $request Full details about the request. 
  120. * @return WP_Error|boolean 
  121. */ 
  122. public function get_item_permissions_check( $request ) { 
  123. $permissions = $this->check_permissions( $request, 'read' ); 
  124. if ( is_wp_error( $permissions ) ) { 
  125. return $permissions; 
  126.  
  127. if ( ! $permissions ) { 
  128. return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  129.  
  130. return true; 
  131.  
  132. /** 
  133. * Check if a given request has access to update a term. 
  134. * @param WP_REST_Request $request Full details about the request. 
  135. * @return WP_Error|boolean 
  136. */ 
  137. public function update_item_permissions_check( $request ) { 
  138. $permissions = $this->check_permissions( $request, 'edit' ); 
  139. if ( is_wp_error( $permissions ) ) { 
  140. return $permissions; 
  141.  
  142. if ( ! $permissions ) { 
  143. return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  144.  
  145. return true; 
  146.  
  147. /** 
  148. * Check if a given request has access to delete a term. 
  149. * @param WP_REST_Request $request Full details about the request. 
  150. * @return WP_Error|boolean 
  151. */ 
  152. public function delete_item_permissions_check( $request ) { 
  153. $permissions = $this->check_permissions( $request, 'delete' ); 
  154. if ( is_wp_error( $permissions ) ) { 
  155. return $permissions; 
  156.  
  157. if ( ! $permissions ) { 
  158. return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  159.  
  160. return true; 
  161.  
  162. /** 
  163. * Check if a given request has access batch create, update and delete items. 
  164. * @param WP_REST_Request $request Full details about the request. 
  165. * @return boolean 
  166. */ 
  167. public function batch_items_permissions_check( $request ) { 
  168. $permissions = $this->check_permissions( $request, 'batch' ); 
  169. if ( is_wp_error( $permissions ) ) { 
  170. return $permissions; 
  171.  
  172. if ( ! $permissions ) { 
  173. return new WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  174.  
  175. return true; 
  176.  
  177. /** 
  178. * Check permissions. 
  179. * @param WP_REST_Request $request Full details about the request. 
  180. * @param string $context Request context. 
  181. * @return bool|WP_Error 
  182. */ 
  183. protected function check_permissions( $request, $context = 'read' ) { 
  184. // Get taxonomy. 
  185. $taxonomy = $this->get_taxonomy( $request ); 
  186. if ( ! $taxonomy ) { 
  187. return new WP_Error( 'woocommerce_rest_taxonomy_invalid', __( 'Taxonomy does not exist.', 'woocommerce' ), array( 'status' => 404 ) ); 
  188.  
  189. // Check permissions for a single term. 
  190. if ( $id = intval( $request['id'] ) ) { 
  191. $term = get_term( $id, $taxonomy ); 
  192.  
  193. if ( ! $term || $term->taxonomy !== $taxonomy ) { 
  194. return new WP_Error( 'woocommerce_rest_term_invalid', __( 'Resource does not exist.', 'woocommerce' ), array( 'status' => 404 ) ); 
  195.  
  196. return wc_rest_check_product_term_permissions( $taxonomy, $context, $term->term_id ); 
  197.  
  198. return wc_rest_check_product_term_permissions( $taxonomy, $context ); 
  199.  
  200. /** 
  201. * Get terms associated with a taxonomy. 
  202. * @param WP_REST_Request $request Full details about the request. 
  203. * @return WP_REST_Response|WP_Error 
  204. */ 
  205. public function get_items( $request ) { 
  206. $taxonomy = $this->get_taxonomy( $request ); 
  207. $prepared_args = array( 
  208. 'exclude' => $request['exclude'],  
  209. 'include' => $request['include'],  
  210. 'order' => $request['order'],  
  211. 'orderby' => $request['orderby'],  
  212. 'product' => $request['product'],  
  213. 'hide_empty' => $request['hide_empty'],  
  214. 'number' => $request['per_page'],  
  215. 'search' => $request['search'],  
  216. 'slug' => $request['slug'],  
  217. ); 
  218.  
  219. if ( ! empty( $request['offset'] ) ) { 
  220. $prepared_args['offset'] = $request['offset']; 
  221. } else { 
  222. $prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number']; 
  223.  
  224. $taxonomy_obj = get_taxonomy( $taxonomy ); 
  225.  
  226. if ( $taxonomy_obj->hierarchical && isset( $request['parent'] ) ) { 
  227. if ( 0 === $request['parent'] ) { 
  228. // Only query top-level terms. 
  229. $prepared_args['parent'] = 0; 
  230. } else { 
  231. if ( $request['parent'] ) { 
  232. $prepared_args['parent'] = $request['parent']; 
  233.  
  234. /** 
  235. * Filter the query arguments, before passing them to `get_terms()`. 
  236. * Enables adding extra arguments or setting defaults for a terms 
  237. * collection request. 
  238. * @see https://developer.wordpress.org/reference/functions/get_terms/ 
  239. * @param array $prepared_args Array of arguments to be 
  240. * passed to get_terms. 
  241. * @param WP_REST_Request $request The current request. 
  242. */ 
  243. $prepared_args = apply_filters( "woocommerce_rest_{$taxonomy}_query", $prepared_args, $request ); 
  244.  
  245. if ( ! empty( $prepared_args['product'] ) ) { 
  246. $query_result = $this->get_terms_for_product( $prepared_args ); 
  247. $total_terms = $this->total_terms; 
  248. } else { 
  249. $query_result = get_terms( $taxonomy, $prepared_args ); 
  250.  
  251. $count_args = $prepared_args; 
  252. unset( $count_args['number'] ); 
  253. unset( $count_args['offset'] ); 
  254. $total_terms = wp_count_terms( $taxonomy, $count_args ); 
  255.  
  256. // Ensure we don't return results when offset is out of bounds. 
  257. // See https://core.trac.wordpress.org/ticket/35935 
  258. if ( $prepared_args['offset'] >= $total_terms ) { 
  259. $query_result = array(); 
  260.  
  261. // wp_count_terms can return a falsy value when the term has no children. 
  262. if ( ! $total_terms ) { 
  263. $total_terms = 0; 
  264. $response = array(); 
  265. foreach ( $query_result as $term ) { 
  266. $data = $this->prepare_item_for_response( $term, $request ); 
  267. $response[] = $this->prepare_response_for_collection( $data ); 
  268.  
  269. $response = rest_ensure_response( $response ); 
  270.  
  271. // Store pagation values for headers then unset for count query. 
  272. $per_page = (int) $prepared_args['number']; 
  273. $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); 
  274.  
  275. $response->header( 'X-WP-Total', (int) $total_terms ); 
  276. $max_pages = ceil( $total_terms / $per_page ); 
  277. $response->header( 'X-WP-TotalPages', (int) $max_pages ); 
  278.  
  279. $base = add_query_arg( $request->get_query_params(), rest_url( '/' . $this->namespace . '/' . $this->rest_base ) ); 
  280. if ( $page > 1 ) { 
  281. $prev_page = $page - 1; 
  282. if ( $prev_page > $max_pages ) { 
  283. $prev_page = $max_pages; 
  284. $prev_link = add_query_arg( 'page', $prev_page, $base ); 
  285. $response->link_header( 'prev', $prev_link ); 
  286. if ( $max_pages > $page ) { 
  287. $next_page = $page + 1; 
  288. $next_link = add_query_arg( 'page', $next_page, $base ); 
  289. $response->link_header( 'next', $next_link ); 
  290.  
  291. return $response; 
  292.  
  293. /** 
  294. * Create a single term for a taxonomy. 
  295. * @param WP_REST_Request $request Full details about the request. 
  296. * @return WP_REST_Request|WP_Error 
  297. */ 
  298. public function create_item( $request ) { 
  299. $taxonomy = $this->get_taxonomy( $request ); 
  300. $name = $request['name']; 
  301. $args = array(); 
  302. $schema = $this->get_item_schema(); 
  303.  
  304. if ( ! empty( $schema['properties']['description'] ) && isset( $request['description'] ) ) { 
  305. $args['description'] = $request['description']; 
  306. if ( isset( $request['slug'] ) ) { 
  307. $args['slug'] = $request['slug']; 
  308.  
  309. if ( isset( $request['parent'] ) ) { 
  310. if ( ! is_taxonomy_hierarchical( $taxonomy ) ) { 
  311. return new WP_Error( 'woocommerce_rest_taxonomy_not_hierarchical', __( 'Can not set resource parent, taxonomy is not hierarchical.', 'woocommerce' ), array( 'status' => 400 ) ); 
  312.  
  313. $parent = get_term( (int) $request['parent'], $taxonomy ); 
  314.  
  315. if ( ! $parent ) { 
  316. return new WP_Error( 'woocommerce_rest_term_invalid', __( 'Parent resource does not exist.', 'woocommerce' ), array( 'status' => 404 ) ); 
  317.  
  318. $args['parent'] = $parent->term_id; 
  319.  
  320. $term = wp_insert_term( $name, $taxonomy, $args ); 
  321. if ( is_wp_error( $term ) ) { 
  322. $error_data = array( 'status' => 400 ); 
  323.  
  324. // If we're going to inform the client that the term exists,  
  325. // give them the identifier they can actually use. 
  326. if ( $term_id = $term->get_error_data( 'term_exists' ) ) { 
  327. $error_data['resource_id'] = $term_id; 
  328.  
  329. return new WP_Error( $term->get_error_code(), $term->get_error_message(), $error_data ); 
  330.  
  331. $term = get_term( $term['term_id'], $taxonomy ); 
  332.  
  333. $this->update_additional_fields_for_object( $term, $request ); 
  334.  
  335. // Add term data. 
  336. $meta_fields = $this->update_term_meta_fields( $term, $request ); 
  337. if ( is_wp_error( $meta_fields ) ) { 
  338. wp_delete_term( $term->term_id, $taxonomy ); 
  339.  
  340. return $meta_fields; 
  341.  
  342. /** 
  343. * Fires after a single term is created or updated via the REST API. 
  344. * @param WP_Term $term Inserted Term object. 
  345. * @param WP_REST_Request $request Request object. 
  346. * @param boolean $creating True when creating term, false when updating. 
  347. */ 
  348. do_action( "woocommerce_rest_insert_{$taxonomy}", $term, $request, true ); 
  349.  
  350. $request->set_param( 'context', 'edit' ); 
  351. $response = $this->prepare_item_for_response( $term, $request ); 
  352. $response = rest_ensure_response( $response ); 
  353. $response->set_status( 201 ); 
  354.  
  355. $base = '/' . $this->namespace . '/' . $this->rest_base; 
  356. if ( ! empty( $request['attribute_id'] ) ) { 
  357. $base = str_replace( '(?P<attribute_id>[\d]+)', (int) $request['attribute_id'], $base ); 
  358.  
  359. $response->header( 'Location', rest_url( $base . '/' . $term->term_id ) ); 
  360.  
  361. return $response; 
  362.  
  363. /** 
  364. * Get a single term from a taxonomy. 
  365. * @param WP_REST_Request $request Full details about the request. 
  366. * @return WP_REST_Request|WP_Error 
  367. */ 
  368. public function get_item( $request ) { 
  369. $taxonomy = $this->get_taxonomy( $request ); 
  370. $term = get_term( (int) $request['id'], $taxonomy ); 
  371.  
  372. if ( is_wp_error( $term ) ) { 
  373. return $term; 
  374.  
  375. $response = $this->prepare_item_for_response( $term, $request ); 
  376.  
  377. return rest_ensure_response( $response ); 
  378.  
  379. /** 
  380. * Update a single term from a taxonomy. 
  381. * @param WP_REST_Request $request Full details about the request. 
  382. * @return WP_REST_Request|WP_Error 
  383. */ 
  384. public function update_item( $request ) { 
  385. $taxonomy = $this->get_taxonomy( $request ); 
  386. $term = get_term( (int) $request['id'], $taxonomy ); 
  387. $schema = $this->get_item_schema(); 
  388. $prepared_args = array(); 
  389.  
  390. if ( isset( $request['name'] ) ) { 
  391. $prepared_args['name'] = $request['name']; 
  392. if ( ! empty( $schema['properties']['description'] ) && isset( $request['description'] ) ) { 
  393. $prepared_args['description'] = $request['description']; 
  394. if ( isset( $request['slug'] ) ) { 
  395. $prepared_args['slug'] = $request['slug']; 
  396.  
  397. if ( isset( $request['parent'] ) ) { 
  398. if ( ! is_taxonomy_hierarchical( $taxonomy ) ) { 
  399. return new WP_Error( 'woocommerce_rest_taxonomy_not_hierarchical', __( 'Can not set resource parent, taxonomy is not hierarchical.', 'woocommerce' ), array( 'status' => 400 ) ); 
  400.  
  401. $parent_id = (int) $request['parent']; 
  402.  
  403. if ( 0 === $parent_id ) { 
  404. $prepared_args['parent'] = $parent_id; 
  405. } else { 
  406. $parent = get_term( $parent_id, $taxonomy ); 
  407.  
  408. if ( ! $parent ) { 
  409. return new WP_Error( 'woocommerce_rest_term_invalid', __( 'Parent resource does not exist.', 'woocommerce' ), array( 'status' => 400 ) ); 
  410.  
  411. $prepared_args['parent'] = $parent->term_id; 
  412.  
  413. // Only update the term if we haz something to update. 
  414. if ( ! empty( $prepared_args ) ) { 
  415. $update = wp_update_term( $term->term_id, $term->taxonomy, $prepared_args ); 
  416. if ( is_wp_error( $update ) ) { 
  417. return $update; 
  418.  
  419. $term = get_term( (int) $request['id'], $taxonomy ); 
  420.  
  421. $this->update_additional_fields_for_object( $term, $request ); 
  422.  
  423. // Update term data. 
  424. $meta_fields = $this->update_term_meta_fields( $term, $request ); 
  425. if ( is_wp_error( $meta_fields ) ) { 
  426. return $meta_fields; 
  427.  
  428. /** 
  429. * Fires after a single term is created or updated via the REST API. 
  430. * @param WP_Term $term Inserted Term object. 
  431. * @param WP_REST_Request $request Request object. 
  432. * @param boolean $creating True when creating term, false when updating. 
  433. */ 
  434. do_action( "woocommerce_rest_insert_{$taxonomy}", $term, $request, false ); 
  435.  
  436. $request->set_param( 'context', 'edit' ); 
  437. $response = $this->prepare_item_for_response( $term, $request ); 
  438. return rest_ensure_response( $response ); 
  439.  
  440. /** 
  441. * Delete a single term from a taxonomy. 
  442. * @param WP_REST_Request $request Full details about the request. 
  443. * @return WP_REST_Response|WP_Error 
  444. */ 
  445. public function delete_item( $request ) { 
  446. $taxonomy = $this->get_taxonomy( $request ); 
  447. $force = isset( $request['force'] ) ? (bool) $request['force'] : false; 
  448.  
  449. // We don't support trashing for this type, error out. 
  450. if ( ! $force ) { 
  451. return new WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Resource does not support trashing.', 'woocommerce' ), array( 'status' => 501 ) ); 
  452.  
  453. $term = get_term( (int) $request['id'], $taxonomy ); 
  454. $request->set_param( 'context', 'edit' ); 
  455. $response = $this->prepare_item_for_response( $term, $request ); 
  456.  
  457. $retval = wp_delete_term( $term->term_id, $term->taxonomy ); 
  458. if ( ! $retval ) { 
  459. return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'The resource cannot be deleted.', 'woocommerce' ), array( 'status' => 500 ) ); 
  460.  
  461. /** 
  462. * Fires after a single term is deleted via the REST API. 
  463. * @param WP_Term $term The deleted term. 
  464. * @param WP_REST_Response $response The response data. 
  465. * @param WP_REST_Request $request The request sent to the API. 
  466. */ 
  467. do_action( "woocommerce_rest_delete_{$taxonomy}", $term, $response, $request ); 
  468.  
  469. return $response; 
  470.  
  471. /** 
  472. * Prepare links for the request. 
  473. * @param object $term Term object. 
  474. * @param WP_REST_Request $request Full details about the request. 
  475. * @return array Links for the given term. 
  476. */ 
  477. protected function prepare_links( $term, $request ) { 
  478. $base = '/' . $this->namespace . '/' . $this->rest_base; 
  479.  
  480. if ( ! empty( $request['attribute_id'] ) ) { 
  481. $base = str_replace( '(?P<attribute_id>[\d]+)', (int) $request['attribute_id'], $base ); 
  482.  
  483. $links = array( 
  484. 'self' => array( 
  485. 'href' => rest_url( trailingslashit( $base ) . $term->term_id ),  
  486. ),  
  487. 'collection' => array( 
  488. 'href' => rest_url( $base ),  
  489. ),  
  490. ); 
  491.  
  492. if ( $term->parent ) { 
  493. $parent_term = get_term( (int) $term->parent, $term->taxonomy ); 
  494. if ( $parent_term ) { 
  495. $links['up'] = array( 
  496. 'href' => rest_url( trailingslashit( $base ) . $parent_term->term_id ),  
  497. ); 
  498.  
  499. return $links; 
  500.  
  501. /** 
  502. * Update term meta fields. 
  503. * @param WP_Term $term 
  504. * @param WP_REST_Request $request 
  505. * @return bool|WP_Error 
  506. */ 
  507. protected function update_term_meta_fields( $term, $request ) { 
  508. return true; 
  509.  
  510. /** 
  511. * Get the terms attached to a product. 
  512. * This is an alternative to `get_terms()` that uses `get_the_terms()` 
  513. * instead, which hits the object cache. There are a few things not 
  514. * supported, notably `include`, `exclude`. In `self::get_items()` these 
  515. * are instead treated as a full query. 
  516. * @param array $prepared_args Arguments for `get_terms()`. 
  517. * @return array List of term objects. (Total count in `$this->total_terms`). 
  518. */ 
  519. protected function get_terms_for_product( $prepared_args ) { 
  520. $taxonomy = $this->get_taxonomy( $request ); 
  521.  
  522. $query_result = get_the_terms( $prepared_args['product'], $taxonomy ); 
  523. if ( empty( $query_result ) ) { 
  524. $this->total_terms = 0; 
  525. return array(); 
  526.  
  527. // get_items() verifies that we don't have `include` set, and default. 
  528. // ordering is by `name`. 
  529. if ( ! in_array( $prepared_args['orderby'], array( 'name', 'none', 'include' ) ) ) { 
  530. switch ( $prepared_args['orderby'] ) { 
  531. case 'id' : 
  532. $this->sort_column = 'term_id'; 
  533. break; 
  534.  
  535. case 'slug' : 
  536. case 'term_group' : 
  537. case 'description' : 
  538. case 'count' : 
  539. $this->sort_column = $prepared_args['orderby']; 
  540. break; 
  541. usort( $query_result, array( $this, 'compare_terms' ) ); 
  542. if ( strtolower( $prepared_args['order'] ) !== 'asc' ) { 
  543. $query_result = array_reverse( $query_result ); 
  544.  
  545. // Pagination. 
  546. $this->total_terms = count( $query_result ); 
  547. $query_result = array_slice( $query_result, $prepared_args['offset'], $prepared_args['number'] ); 
  548.  
  549. return $query_result; 
  550.  
  551. /** 
  552. * Comparison function for sorting terms by a column. 
  553. * Uses `$this->sort_column` to determine field to sort by. 
  554. * @param stdClass $left Term object. 
  555. * @param stdClass $right Term object. 
  556. * @return int <0 if left is higher "priority" than right, 0 if equal, >0 if right is higher "priority" than left. 
  557. */ 
  558. protected function compare_terms( $left, $right ) { 
  559. $col = $this->sort_column; 
  560. $left_val = $left->$col; 
  561. $right_val = $right->$col; 
  562.  
  563. if ( is_int( $left_val ) && is_int( $right_val ) ) { 
  564. return $left_val - $right_val; 
  565.  
  566. return strcmp( $left_val, $right_val ); 
  567.  
  568. /** 
  569. * Get the query params for collections 
  570. * @return array 
  571. */ 
  572. public function get_collection_params() { 
  573. $params = parent::get_collection_params(); 
  574.  
  575. if ( '' !== $this->taxonomy ) { 
  576. $taxonomy = get_taxonomy( $this->taxonomy ); 
  577. } else { 
  578. $taxonomy = new stdClass(); 
  579. $taxonomy->hierarchical = true; 
  580.  
  581. $params['context']['default'] = 'view'; 
  582.  
  583. $params['exclude'] = array( 
  584. 'description' => __( 'Ensure result set excludes specific ids.', 'woocommerce' ),  
  585. 'type' => 'array',  
  586. 'items' => array( 
  587. 'type' => 'integer',  
  588. ),  
  589. 'default' => array(),  
  590. 'sanitize_callback' => 'wp_parse_id_list',  
  591. ); 
  592. $params['include'] = array( 
  593. 'description' => __( 'Limit result set to specific ids.', 'woocommerce' ),  
  594. 'type' => 'array',  
  595. 'items' => array( 
  596. 'type' => 'integer',  
  597. ),  
  598. 'default' => array(),  
  599. 'sanitize_callback' => 'wp_parse_id_list',  
  600. ); 
  601. if ( ! $taxonomy->hierarchical ) { 
  602. $params['offset'] = array( 
  603. 'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce' ),  
  604. 'type' => 'integer',  
  605. 'sanitize_callback' => 'absint',  
  606. 'validate_callback' => 'rest_validate_request_arg',  
  607. ); 
  608. $params['order'] = array( 
  609. 'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce' ),  
  610. 'type' => 'string',  
  611. 'sanitize_callback' => 'sanitize_key',  
  612. 'default' => 'asc',  
  613. 'enum' => array( 
  614. 'asc',  
  615. 'desc',  
  616. ),  
  617. 'validate_callback' => 'rest_validate_request_arg',  
  618. ); 
  619. $params['orderby'] = array( 
  620. 'description' => __( 'Sort collection by resource attribute.', 'woocommerce' ),  
  621. 'type' => 'string',  
  622. 'sanitize_callback' => 'sanitize_key',  
  623. 'default' => 'name',  
  624. 'enum' => array( 
  625. 'id',  
  626. 'include',  
  627. 'name',  
  628. 'slug',  
  629. 'term_group',  
  630. 'description',  
  631. 'count',  
  632. ),  
  633. 'validate_callback' => 'rest_validate_request_arg',  
  634. ); 
  635. $params['hide_empty'] = array( 
  636. 'description' => __( 'Whether to hide resources not assigned to any products.', 'woocommerce' ),  
  637. 'type' => 'boolean',  
  638. 'default' => false,  
  639. 'validate_callback' => 'rest_validate_request_arg',  
  640. ); 
  641. if ( $taxonomy->hierarchical ) { 
  642. $params['parent'] = array( 
  643. 'description' => __( 'Limit result set to resources assigned to a specific parent.', 'woocommerce' ),  
  644. 'type' => 'integer',  
  645. 'sanitize_callback' => 'absint',  
  646. 'validate_callback' => 'rest_validate_request_arg',  
  647. ); 
  648. $params['product'] = array( 
  649. 'description' => __( 'Limit result set to resources assigned to a specific product.', 'woocommerce' ),  
  650. 'type' => 'integer',  
  651. 'default' => null,  
  652. 'validate_callback' => 'rest_validate_request_arg',  
  653. ); 
  654. $params['slug'] = array( 
  655. 'description' => __( 'Limit result set to resources with a specific slug.', 'woocommerce' ),  
  656. 'type' => 'string',  
  657. 'validate_callback' => 'rest_validate_request_arg',  
  658. ); 
  659.  
  660. return $params; 
  661.  
  662. /** 
  663. * Get taxonomy. 
  664. * @param WP_REST_Request $request Full details about the request. 
  665. * @return int|WP_Error 
  666. */ 
  667. protected function get_taxonomy( $request ) { 
  668. // Check if taxonomy is defined. 
  669. // Prevents check for attribute taxonomy more than one time for each query. 
  670. if ( '' !== $this->taxonomy ) { 
  671. return $this->taxonomy; 
  672.  
  673. if ( ! empty( $request['attribute_id'] ) ) { 
  674. $taxonomy = wc_attribute_taxonomy_name_by_id( (int) $request['attribute_id'] ); 
  675.  
  676. $this->taxonomy = $taxonomy; 
  677.  
  678. return $this->taxonomy;