exist with that id.' ), array( 'status' => 404 ) ); $id = (int) $id; if ( $id <= 0 ) { return $error; } $post = get_post( $id ); if ( empty( $post ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) { return $error; } return $post; } /** * Checks if a given request has access to read a single global style. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $post = $this->get_post( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } if ( 'edit' === $request['context'] && $post && ! $this->check_update_permission( $post ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit this global style.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ! $this->check_read_permission( $post ) ) { return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to view this global style.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Checks if a global style can be read. * * @since 5.9.0 * * @param WP_Post $post Post object. * @return bool Whether the post can be read. */ public function check_read_permission( $post ) { return current_user_can( 'read_post', $post->ID ); } /** * Checks if a given request has access to write a single global styles config. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { $post = $this->get_post( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } if ( $post && ! $this->check_update_permission( $post ) ) { return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to edit this global style.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Prepares a single global styles config for update. * * @since 5.9.0 * @since 6.2.0 Added validation of styles.css property. * @since 6.6.0 Added registration of block style variations from theme.json sources (theme.json, user theme.json, partials). * * @param WP_REST_Request $request Request object. * @return stdClass|WP_Error Prepared item on success. WP_Error on when the custom CSS is not valid. */ protected function prepare_item_for_database( $request ) { $changes = new stdClass(); $changes->ID = $request['id']; $post = get_post( $request['id'] ); $existing_config = array(); if ( $post ) { $existing_config = json_decode( $post->post_content, true ); $json_decoding_error = json_last_error(); if ( JSON_ERROR_NONE !== $json_decoding_error || ! isset( $existing_config['isGlobalStylesUserThemeJSON'] ) || ! $existing_config['isGlobalStylesUserThemeJSON'] ) { $existing_config = array(); } } if ( isset( $request['styles'] ) || isset( $request['settings'] ) ) { $config = array(); if ( isset( $request['styles'] ) ) { if ( isset( $request['styles']['css'] ) ) { $css_validation_result = $this->validate_custom_css( $request['styles']['css'] ); if ( is_wp_error( $css_validation_result ) ) { return $css_validation_result; } } $config['styles'] = $request['styles']; } elseif ( isset( $existing_config['styles'] ) ) { $config['styles'] = $existing_config['styles']; } // Register theme-defined variations e.g. from block style variation partials under `/styles`. $variations = WP_Theme_JSON_Resolver::get_style_variations( 'block' ); wp_register_block_style_variations_from_theme_json_partials( $variations ); if ( isset( $request['settings'] ) ) { $config['settings'] = $request['settings']; } elseif ( isset( $existing_config['settings'] ) ) { $config['settings'] = $existing_config['settings']; } $config['isGlobalStylesUserThemeJSON'] = true; $config['version'] = WP_Theme_JSON::LATEST_SCHEMA; $changes->post_content = wp_json_encode( $config ); } // Post title. if ( isset( $request['title'] ) ) { if ( is_string( $request['title'] ) ) { $changes->post_title = $request['title']; } elseif ( ! empty( $request['title']['raw'] ) ) { $changes->post_title = $request['title']['raw']; } } return $changes; } /** * Prepare a global styles config output for response. * * @since 5.9.0 * @since 6.6.0 Added custom relative theme file URIs to `_links`. * * @param WP_Post $post Global Styles post object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $post, $request ) { $raw_config = json_decode( $post->post_content, true ); $is_global_styles_user_theme_json = isset( $raw_config['isGlobalStylesUserThemeJSON'] ) && true === $raw_config['isGlobalStylesUserThemeJSON']; $config = array(); $theme_json = null; if ( $is_global_styles_user_theme_json ) { $theme_json = new WP_Theme_JSON( $raw_config, 'custom' ); $config = $theme_json->get_raw_data(); } // Base fields for every post. $fields = $this->get_fields_for_response( $request ); $data = array(); if ( rest_is_field_included( 'id', $fields ) ) { $data['id'] = $post->ID; } if ( rest_is_field_included( 'title', $fields ) ) { $data['title'] = array(); } if ( rest_is_field_included( 'title.raw', $fields ) ) { $data['title']['raw'] = $post->post_title; } if ( rest_is_field_included( 'title.rendered', $fields ) ) { add_filter( 'protected_title_format', array( $this, 'protected_title_format' ) ); add_filter( 'private_title_format', array( $this, 'protected_title_format' ) ); $data['title']['rendered'] = get_the_title( $post->ID ); remove_filter( 'protected_title_format', array( $this, 'protected_title_format' ) ); remove_filter( 'private_title_format', array( $this, 'protected_title_format' ) ); } if ( rest_is_field_included( 'settings', $fields ) ) { $data['settings'] = ! empty( $config['settings'] ) && $is_global_styles_user_theme_json ? $config['settings'] : new stdClass(); } if ( rest_is_field_included( 'styles', $fields ) ) { $data['styles'] = ! empty( $config['styles'] ) && $is_global_styles_user_theme_json ? $config['styles'] : new stdClass(); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); // Wrap the data in a response object. $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = $this->prepare_links( $post->ID ); // Only return resolved URIs for get requests to user theme JSON. if ( $theme_json ) { $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $theme_json ); if ( ! empty( $resolved_theme_uris ) ) { $links['https://api.w.org/theme-file'] = $resolved_theme_uris; } } $response->add_links( $links ); if ( ! empty( $links['self']['href'] ) ) { $actions = $this->get_available_actions( $post, $request ); $self = $links['self']['href']; foreach ( $actions as $rel ) { $response->add_link( $rel, $self ); } } } return $response; } /** * Prepares links for the request. * * @since 5.9.0 * @since 6.3.0 Adds revisions count and rest URL href to version-history. * * @param integer $id ID. * @return array Links for the given post. */ protected function prepare_links( $id ) { $base = sprintf( '%s/%s', $this->namespace, $this->rest_base ); $links = array( 'self' => array( 'href' => rest_url( trailingslashit( $base ) . $id ), ), 'about' => array( 'href' => rest_url( 'wp/v2/types/' . $this->post_type ), ), ); if ( post_type_supports( $this->post_type, 'revisions' ) ) { $revisions = wp_get_latest_revision_id_and_total_count( $id ); $revisions_count = ! is_wp_error( $revisions ) ? $revisions['count'] : 0; $revisions_base = sprintf( '/%s/%d/revisions', $base, $id ); $links['version-history'] = array( 'href' => rest_url( $revisions_base ), 'count' => $revisions_count, ); } return $links; } /** * Get the link relations available for the post and current user. * * @since 5.9.0 * @since 6.2.0 Added 'edit-css' action. * @since 6.6.0 Added $post and $request parameters. * * @param WP_Post $post Post object. * @param WP_REST_Request $request Request object. * @return array List of link relations. */ protected function get_available_actions( $post, $request ) { $rels = array(); $post_type = get_post_type_object( $post->post_type ); if ( current_user_can( $post_type->cap->publish_posts ) ) { $rels[] = 'https://api.w.org/action-publish'; } if ( current_user_can( 'edit_css' ) ) { $rels[] = 'https://api.w.org/action-edit-css'; } return $rels; } /** * Retrieves the query params for the global styles collection. * * @since 5.9.0 * * @return array Collection parameters. */ public function get_collection_params() { return array(); } /** * Retrieves the global styles type' schema, conforming to JSON Schema. * * @since 5.9.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => $this->post_type, 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'ID of global styles config.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'styles' => array( 'description' => __( 'Global styles.' ), 'type' => array( 'object' ), 'context' => array( 'view', 'edit' ), ), 'settings' => array( 'description' => __( 'Global settings.' ), 'type' => array( 'object' ), 'context' => array( 'view', 'edit' ), ), 'title' => array( 'description' => __( 'Title of the global styles variation.' ), 'type' => array( 'object', 'string' ), 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'properties' => array( 'raw' => array( 'description' => __( 'Title for the global styles variation, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), ), 'rendered' => array( 'description' => __( 'HTML title for the post, transformed for display.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), ), ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Checks if a given request has access to read a single theme global styles config. * * @since 5.9.0 * @since 6.7.0 Allow users with edit post capabilities to view theme global styles. * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_theme_item_permissions_check( $request ) { /* * Verify if the current user has edit_posts capability. * This capability is required to view global styles. */ if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } /* * Verify if the current user has edit_theme_options capability. */ if ( current_user_can( 'edit_theme_options' ) ) { return true; } return new WP_Error( 'rest_cannot_read_global_styles', __( 'Sorry, you are not allowed to access the global styles on this site.' ), array( 'status' => rest_authorization_required_code(), ) ); } /** * Returns the given theme global styles config. * * @since 5.9.0 * @since 6.6.0 Added custom relative theme file URIs to `_links`. * * @param WP_REST_Request $request The request instance. * @return WP_REST_Response|WP_Error */ public function get_theme_item( $request ) { if ( get_stylesheet() !== $request['stylesheet'] ) { // This endpoint only supports the active theme for now. return new WP_Error( 'rest_theme_not_found', __( 'Theme not found.' ), array( 'status' => 404 ) ); } $theme = WP_Theme_JSON_Resolver::get_merged_data( 'theme' ); $fields = $this->get_fields_for_response( $request ); $data = array(); if ( rest_is_field_included( 'settings', $fields ) ) { $data['settings'] = $theme->get_settings(); } if ( rest_is_field_included( 'styles', $fields ) ) { $raw_data = $theme->get_raw_data(); $data['styles'] = isset( $raw_data['styles'] ) ? $raw_data['styles'] : array(); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = array( 'self' => array( 'href' => rest_url( sprintf( '%s/%s/themes/%s', $this->namespace, $this->rest_base, $request['stylesheet'] ) ), ), ); $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $theme ); if ( ! empty( $resolved_theme_uris ) ) { $links['https://api.w.org/theme-file'] = $resolved_theme_uris; } $response->add_links( $links ); } return $response; } /** * Checks if a given request has access to read a single theme global styles config. * * @since 6.0.0 * @since 6.7.0 Allow users with edit post capabilities to view theme global styles. * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_theme_items_permissions_check( $request ) { return $this->get_theme_item_permissions_check( $request ); } /** * Returns the given theme global styles variations. * * @since 6.0.0 * @since 6.2.0 Returns parent theme variations, if they exist. * @since 6.6.0 Added custom relative theme file URIs to `_links` for each item. * * @param WP_REST_Request $request The request instance. * * @return WP_REST_Response|WP_Error */ public function get_theme_items( $request ) { if ( get_stylesheet() !== $request['stylesheet'] ) { // This endpoint only supports the active theme for now. return new WP_Error( 'rest_theme_not_found', __( 'Theme not found.' ), array( 'status' => 404 ) ); } $response = array(); // Register theme-defined variations e.g. from block style variation partials under `/styles`. $partials = WP_Theme_JSON_Resolver::get_style_variations( 'block' ); wp_register_block_style_variations_from_theme_json_partials( $partials ); $variations = WP_Theme_JSON_Resolver::get_style_variations(); foreach ( $variations as $variation ) { $variation_theme_json = new WP_Theme_JSON( $variation ); $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $variation_theme_json ); $data = rest_ensure_response( $variation ); if ( ! empty( $resolved_theme_uris ) ) { $data->add_links( array( 'https://api.w.org/theme-file' => $resolved_theme_uris, ) ); } $response[] = $this->prepare_response_for_collection( $data ); } return rest_ensure_response( $response ); } /** * Validate style.css as valid CSS. * * Currently just checks for invalid markup. * * @since 6.2.0 * @since 6.4.0 Changed method visibility to protected. * * @param string $css CSS to validate. * @return true|WP_Error True if the input was validated, otherwise WP_Error. */ protected function validate_custom_css( $css ) { if ( preg_match( '# 400 ) ); } return true; } } _included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $term ) ); } /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ return apply_filters( "rest_prepare_{$this->taxonomy}", $response, $term, $request ); } /** * Prepares links for the request. * * @since 5.9.0 * * @param WP_Term $term Term object. * @return array Links for the given term. */ protected function prepare_links( $term ) { $links = parent::prepare_links( $term ); $locations = $this->get_menu_locations( $term->term_id ); foreach ( $locations as $location ) { $url = rest_url( sprintf( 'wp/v2/menu-locations/%s', $location ) ); $links['https://api.w.org/menu-location'][] = array( 'href' => $url, 'embeddable' => true, ); } return $links; } /** * Prepares a single term for create or update. * * @since 5.9.0 * * @param WP_REST_Request $request Request object. * @return object Prepared term data. */ public function prepare_item_for_database( $request ) { $prepared_term = parent::prepare_item_for_database( $request ); $schema = $this->get_item_schema(); if ( isset( $request['name'] ) && ! empty( $schema['properties']['name'] ) ) { $prepared_term->{'menu-name'} = $request['name']; } return $prepared_term; } /** * Creates a single term in a taxonomy. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { if ( isset( $request['parent'] ) ) { if ( ! is_taxonomy_hierarchical( $this->taxonomy ) ) { return new WP_Error( 'rest_taxonomy_not_hierarchical', __( 'Cannot set parent term, taxonomy is not hierarchical.' ), array( 'status' => 400 ) ); } $parent = wp_get_nav_menu_object( (int) $request['parent'] ); if ( ! $parent ) { return new WP_Error( 'rest_term_invalid', __( 'Parent term does not exist.' ), array( 'status' => 400 ) ); } } $prepared_term = $this->prepare_item_for_database( $request ); $term = wp_update_nav_menu_object( 0, wp_slash( (array) $prepared_term ) ); if ( is_wp_error( $term ) ) { /* * If we're going to inform the client that the term already exists, * give them the identifier for future use. */ if ( in_array( 'menu_exists', $term->get_error_codes(), true ) ) { $existing_term = get_term_by( 'name', $prepared_term->{'menu-name'}, $this->taxonomy ); $term->add_data( $existing_term->term_id, 'menu_exists' ); $term->add_data( array( 'status' => 400, 'term_id' => $existing_term->term_id, ) ); } else { $term->add_data( array( 'status' => 400 ) ); } return $term; } $term = $this->get_term( $term ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ do_action( "rest_insert_{$this->taxonomy}", $term, $request, true ); $schema = $this->get_item_schema(); if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $term->term_id ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $locations_update = $this->handle_locations( $term->term_id, $request ); if ( is_wp_error( $locations_update ) ) { return $locations_update; } $this->handle_auto_add( $term->term_id, $request ); $fields_update = $this->update_additional_fields_for_object( $term, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'view' ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ do_action( "rest_after_insert_{$this->taxonomy}", $term, $request, true ); $response = $this->prepare_item_for_response( $term, $request ); $response = rest_ensure_response( $response ); $response->set_status( 201 ); $response->header( 'Location', rest_url( $this->namespace . '/' . $this->rest_base . '/' . $term->term_id ) ); return $response; } /** * Updates a single term from a taxonomy. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { $term = $this->get_term( $request['id'] ); if ( is_wp_error( $term ) ) { return $term; } if ( isset( $request['parent'] ) ) { if ( ! is_taxonomy_hierarchical( $this->taxonomy ) ) { return new WP_Error( 'rest_taxonomy_not_hierarchical', __( 'Cannot set parent term, taxonomy is not hierarchical.' ), array( 'status' => 400 ) ); } $parent = get_term( (int) $request['parent'], $this->taxonomy ); if ( ! $parent ) { return new WP_Error( 'rest_term_invalid', __( 'Parent term does not exist.' ), array( 'status' => 400 ) ); } } $prepared_term = $this->prepare_item_for_database( $request ); // Only update the term if we have something to update. if ( ! empty( $prepared_term ) ) { if ( ! isset( $prepared_term->{'menu-name'} ) ) { // wp_update_nav_menu_object() requires that the menu-name is always passed. $prepared_term->{'menu-name'} = $term->name; } $update = wp_update_nav_menu_object( $term->term_id, wp_slash( (array) $prepared_term ) ); if ( is_wp_error( $update ) ) { return $update; } } $term = get_term( $term->term_id, $this->taxonomy ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ do_action( "rest_insert_{$this->taxonomy}", $term, $request, false ); $schema = $this->get_item_schema(); if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $term->term_id ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $locations_update = $this->handle_locations( $term->term_id, $request ); if ( is_wp_error( $locations_update ) ) { return $locations_update; } $this->handle_auto_add( $term->term_id, $request ); $fields_update = $this->update_additional_fields_for_object( $term, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'view' ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ do_action( "rest_after_insert_{$this->taxonomy}", $term, $request, false ); $response = $this->prepare_item_for_response( $term, $request ); return rest_ensure_response( $response ); } /** * Deletes a single term from a taxonomy. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { $term = $this->get_term( $request['id'] ); if ( is_wp_error( $term ) ) { return $term; } // We don't support trashing for terms. if ( ! $request['force'] ) { /* translators: %s: force=true */ return new WP_Error( 'rest_trash_not_supported', sprintf( __( "Menus do not support trashing. Set '%s' to delete." ), 'force=true' ), array( 'status' => 501 ) ); } $request->set_param( 'context', 'view' ); $previous = $this->prepare_item_for_response( $term, $request ); $result = wp_delete_nav_menu( $term ); if ( ! $result || is_wp_error( $result ) ) { return new WP_Error( 'rest_cannot_delete', __( 'The menu cannot be deleted.' ), array( 'status' => 500 ) ); } $response = new WP_REST_Response(); $response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data(), ) ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ do_action( "rest_delete_{$this->taxonomy}", $term, $response, $request ); return $response; } /** * Returns the value of a menu's auto_add setting. * * @since 5.9.0 * * @param int $menu_id The menu id to query. * @return bool The value of auto_add. */ protected function get_menu_auto_add( $menu_id ) { $nav_menu_option = (array) get_option( 'nav_menu_options', array( 'auto_add' => array() ) ); return in_array( $menu_id, $nav_menu_option['auto_add'], true ); } /** * Updates the menu's auto add from a REST request. * * @since 5.9.0 * * @param int $menu_id The menu id to update. * @param WP_REST_Request $request Full details about the request. * @return bool True if the auto add setting was successfully updated. */ protected function handle_auto_add( $menu_id, $request ) { if ( ! isset( $request['auto_add'] ) ) { return true; } $nav_menu_option = (array) get_option( 'nav_menu_options', array( 'auto_add' => array() ) ); if ( ! isset( $nav_menu_option['auto_add'] ) ) { $nav_menu_option['auto_add'] = array(); } $auto_add = $request['auto_add']; $i = array_search( $menu_id, $nav_menu_option['auto_add'], true ); if ( $auto_add && false === $i ) { $nav_menu_option['auto_add'][] = $menu_id; } elseif ( ! $auto_add && false !== $i ) { array_splice( $nav_menu_option['auto_add'], $i, 1 ); } $update = update_option( 'nav_menu_options', $nav_menu_option ); /** This action is documented in wp-includes/nav-menu.php */ do_action( 'wp_update_nav_menu', $menu_id ); return $update; } /** * Returns the names of the locations assigned to the menu. * * @since 5.9.0 * * @param int $menu_id The menu id. * @return string[] The locations assigned to the menu. */ protected function get_menu_locations( $menu_id ) { $locations = get_nav_menu_locations(); $menu_locations = array(); foreach ( $locations as $location => $assigned_menu_id ) { if ( $menu_id === $assigned_menu_id ) { $menu_locations[] = $location; } } return $menu_locations; } /** * Updates the menu's locations from a REST request. * * @since 5.9.0 * * @param int $menu_id The menu id to update. * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True on success, a WP_Error on an error updating any of the locations. */ protected function handle_locations( $menu_id, $request ) { if ( ! isset( $request['locations'] ) ) { return true; } $menu_locations = get_registered_nav_menus(); $menu_locations = array_keys( $menu_locations ); $new_locations = array(); foreach ( $request['locations'] as $location ) { if ( ! in_array( $location, $menu_locations, true ) ) { return new WP_Error( 'rest_invalid_menu_location', __( 'Invalid menu location.' ), array( 'status' => 400, 'location' => $location, ) ); } $new_locations[ $location ] = $menu_id; } $assigned_menu = get_nav_menu_locations(); foreach ( $assigned_menu as $location => $term_id ) { if ( $term_id === $menu_id ) { unset( $assigned_menu[ $location ] ); } } $new_assignments = array_merge( $assigned_menu, $new_locations ); set_theme_mod( 'nav_menu_locations', $new_assignments ); return true; } /** * Retrieves the term's schema, conforming to JSON Schema. * * @since 5.9.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = parent::get_item_schema(); unset( $schema['properties']['count'], $schema['properties']['link'], $schema['properties']['taxonomy'] ); $schema['properties']['locations'] = array( 'description' => __( 'The locations assigned to the menu.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), 'context' => array( 'view', 'edit' ), 'arg_options' => array( 'validate_callback' => static function ( $locations, $request, $param ) { $valid = rest_validate_request_arg( $locations, $request, $param ); if ( true !== $valid ) { return $valid; } $locations = rest_sanitize_request_arg( $locations, $request, $param ); foreach ( $locations as $location ) { if ( ! array_key_exists( $location, get_registered_nav_menus() ) ) { return new WP_Error( 'rest_invalid_menu_location', __( 'Invalid menu location.' ), array( 'location' => $location, ) ); } } return true; }, ), ); $schema['properties']['auto_add'] = array( 'description' => __( 'Whether to automatically add top level pages to this menu.' ), 'context' => array( 'view', 'edit' ), 'type' => 'boolean', ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } } {"id":1731,"date":"2024-04-22T02:18:04","date_gmt":"2024-04-22T00:18:04","guid":{"rendered":"https:\/\/nasopresse.com\/?p=1731"},"modified":"2024-04-23T13:29:56","modified_gmt":"2024-04-23T11:29:56","slug":"cote-divoire-yamoussoukro-4eme-edition-dhappy-run-m-porquet-herve-exhorte-la-jeunesse-a-rester-figer-sur-ses-objectifs","status":"publish","type":"post","link":"https:\/\/nasopresse.com\/2024\/04\/22\/cote-divoire-yamoussoukro-4eme-edition-dhappy-run-m-porquet-herve-exhorte-la-jeunesse-a-rester-figer-sur-ses-objectifs\/","title":{"rendered":"C\u00d4TE-D\u2019IVOIRE \/ YAMOUSSOUKRO : 4\u00e8me EDITION D\u2019HAPPY RUN \/ M .PORQUET HERVE EXHORTE LA JEUNESSE A RESTER FIGER SUR SES OBJECTIFS."},"content":{"rendered":"

\u00ab Nous voulons que la jeunesse se raconte, s\u2019amuse, mais elle ne doit pas perdre ses objectifs : Elle doit prendre ses \u00e9tudes au s\u00e9rieux \u00bb, a exhort\u00e9 d\u2019entame de ses propos, M. PORQUET Herv\u00e9, Responsable des Exposants de la 4\u00e8me \u00e9dition d\u2019 Happy Run, qui s\u2019est tenue le samedi 20 avril 2024 \u00e0 la place Jean-Paul II de Yamoussoukro. Happy Run, ajouta-t-il pour expliquer : \u00ab n\u2019est pas une course mais une marche color\u00e9e qui vise \u00e0 se colorer au maximum possible sur le parcours avant d\u2019arriver sur le site. C\u2019est une activit\u00e9 de masse de jeune d\u2019horizons diverses, dont la participation n\u00e9cessite au pr\u00e9alable l\u2019achat de kits \u00e0 hauteur de 5000 ou 10 .000 F .<\/p>\n

\"\"<\/p>\n

Happy run s\u2019accompagne d\u2019une sonorit\u00e9 musicale sur supervisions des Sapeurs-Pompiers avec un staff s\u00e9curitaire incontournable\u00bb, a argument\u00e9 M.PORQUET Herv\u00e9. A l\u2019en croire, il y a stands gastronomiques au prix abordables mis \u00e0 la disposition des Happy Runners, parmi lesquels figure le G\u00e9ant bonhomme Happy runner de 12 m\u00e8tre, symbole de d\u2019accueil et de joie. Plac\u00e9 dans le cadre culturel, Cette \u00e9dition a r\u00e9uni plus de 5000 personnes. Soutenue par le Minist\u00e8re de la jeunesse, la 5\u00e8me \u00e9dition se tiendra en 2025 \u00e0 Yamoussoukro selon le calendrier du Promoteur, M. Victor D. YAPOBI\u00a0 qui a chaleureusement exprim\u00e9 sa gratitude aux Autorit\u00e9s.<\/p>\n

Ferdinand Keyn<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"

C\u00d4TE-D\u2019IVOIRE \/ YAMOUSSOUKRO : 4\u00e8me EDITION D\u2019HAPPY RUN \/ M .PORQUET HERVE EXHORTE LA JEUNESSE A RESTER FIGER SUR SES OBJECTIFS. <\/p>\n","protected":false},"author":1,"featured_media":1733,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-1731","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-np-societe"],"acf":[],"_links":{"self":[{"href":"https:\/\/nasopresse.com\/wp-json\/wp\/v2\/posts\/1731","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nasopresse.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nasopresse.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nasopresse.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nasopresse.com\/wp-json\/wp\/v2\/comments?post=1731"}],"version-history":[{"count":3,"href":"https:\/\/nasopresse.com\/wp-json\/wp\/v2\/posts\/1731\/revisions"}],"predecessor-version":[{"id":1751,"href":"https:\/\/nasopresse.com\/wp-json\/wp\/v2\/posts\/1731\/revisions\/1751"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nasopresse.com\/wp-json\/wp\/v2\/media\/1733"}],"wp:attachment":[{"href":"https:\/\/nasopresse.com\/wp-json\/wp\/v2\/media?parent=1731"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nasopresse.com\/wp-json\/wp\/v2\/categories?post=1731"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nasopresse.com\/wp-json\/wp\/v2\/tags?post=1731"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}