diff -r 7b1b88e27a20 -r 48c4eec2b7e6 wp/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php --- a/wp/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php Thu Sep 29 08:06:27 2022 +0200 +++ b/wp/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php Fri Sep 05 18:40:08 2025 +0200 @@ -145,12 +145,41 @@ } /** + * Checks if the terms for a post can be read. + * + * @since 6.0.3 + * + * @param WP_Post $post Post object. + * @param WP_REST_Request $request Full details about the request. + * @return bool Whether the terms for the post can be read. + */ + public function check_read_terms_permission_for_post( $post, $request ) { + // If the requested post isn't associated with this taxonomy, deny access. + if ( ! is_object_in_taxonomy( $post->post_type, $this->taxonomy ) ) { + return false; + } + + // Grant access if the post is publicly viewable. + if ( is_post_publicly_viewable( $post ) ) { + return true; + } + + // Otherwise grant access if the post is readable by the logged in user. + if ( current_user_can( 'read_post', $post->ID ) ) { + return true; + } + + // Otherwise, deny access. + return false; + } + + /** * Checks if a request has access to read terms in the specified taxonomy. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. - * @return true|WP_Error True if the request has read access, otherwise false or WP_Error object. + * @return bool|WP_Error True if the request has read access, otherwise false or WP_Error object. */ public function get_items_permissions_check( $request ) { $tax_obj = get_taxonomy( $this->taxonomy ); @@ -167,6 +196,30 @@ ); } + if ( ! empty( $request['post'] ) ) { + $post = get_post( $request['post'] ); + + if ( ! $post ) { + return new WP_Error( + 'rest_post_invalid_id', + __( 'Invalid post ID.' ), + array( + 'status' => 400, + ) + ); + } + + if ( ! $this->check_read_terms_permission_for_post( $post, $request ) ) { + return new WP_Error( + 'rest_forbidden_context', + __( 'Sorry, you are not allowed to view terms for this post.' ), + array( + 'status' => rest_authorization_required_code(), + ) + ); + } + } + return true; } @@ -295,15 +348,18 @@ // Store pagination values for headers. $per_page = (int) $prepared_args['number']; - $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); + $page = (int) ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); $response->header( 'X-WP-Total', (int) $total_terms ); - $max_pages = ceil( $total_terms / $per_page ); + $max_pages = (int) ceil( $total_terms / $per_page ); + + $response->header( 'X-WP-TotalPages', $max_pages ); - $response->header( 'X-WP-TotalPages', (int) $max_pages ); + $request_params = $request->get_query_params(); + $collection_url = rest_url( rest_get_route_for_taxonomy_items( $this->taxonomy ) ); + $base = add_query_arg( urlencode_deep( $request_params ), $collection_url ); - $base = add_query_arg( urlencode_deep( $request->get_query_params() ), rest_url( $this->namespace . '/' . $this->rest_base ) ); if ( $page > 1 ) { $prev_page = $page - 1; @@ -361,7 +417,7 @@ * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. - * @return true|WP_Error True if the request has read access for the item, otherwise false or WP_Error object. + * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object. */ public function get_item_permissions_check( $request ) { $term = $this->get_term( $request['id'] ); @@ -751,7 +807,7 @@ * @return object Term object. */ public function prepare_item_for_database( $request ) { - $prepared_term = new stdClass; + $prepared_term = new stdClass(); $schema = $this->get_item_schema(); if ( isset( $request['name'] ) && ! empty( $schema['properties']['name'] ) ) { @@ -859,7 +915,9 @@ $response = rest_ensure_response( $data ); - $response->add_links( $this->prepare_links( $item ) ); + if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { + $response->add_links( $this->prepare_links( $item ) ); + } /** * Filters the term data for a REST API response. @@ -891,13 +949,12 @@ * @return array Links for the given term. */ protected function prepare_links( $term ) { - $base = $this->namespace . '/' . $this->rest_base; $links = array( 'self' => array( - 'href' => rest_url( trailingslashit( $base ) . $term->term_id ), + 'href' => rest_url( rest_get_route_for_term( $term ) ), ), 'collection' => array( - 'href' => rest_url( $base ), + 'href' => rest_url( rest_get_route_for_taxonomy_items( $this->taxonomy ) ), ), 'about' => array( 'href' => rest_url( sprintf( 'wp/v2/taxonomies/%s', $this->taxonomy ) ), @@ -909,7 +966,7 @@ if ( $parent_term ) { $links['up'] = array( - 'href' => rest_url( trailingslashit( $base ) . $parent_term->term_id ), + 'href' => rest_url( rest_get_route_for_term( $parent_term ) ), 'embeddable' => true, ); }