_register_route('/post_types', [ 'methods' => WP_REST_Server::READABLE, 'callback' => [ $this, 'get_post_types' ], 'args' => [ 'return_all' => [ 'description' => 'Include all post types or only public', 'type' => 'boolean', 'default' => null ] ] ], self::PERMISSIONS); // Get list of all registered taxonomies $this->_register_route('/taxonomies', array( 'methods' => WP_REST_Server::READABLE, 'callback' => array($this, 'get_taxonomies') ), self::PERMISSIONS); // Get list of terms for given taxonomy $this->_register_route('/terms', array( 'methods' => WP_REST_Server::READABLE, 'callback' => array($this, 'get_terms'), 'args' => array( 'taxonomy' => array( 'description' => 'Scope for specific taxonomy', 'type' => 'string', 'required' => true ), 'post_type' => array( 'description' => 'Scope for specific post type', 'type' => 'string' ), 'search' => array( 'description' => 'Search string', 'type' => 'string' ), 'offset' => array( 'description' => 'Pagination offset', 'type' => 'number', 'default' => 0 ), 'per_page' => array( 'description' => 'Pagination limit per page', 'type' => 'number', 'default' => 10 ) ) ), self::PERMISSIONS); // Get list of posts for given post type $this->_register_route('/posts', array( 'methods' => WP_REST_Server::READABLE, 'callback' => array($this, 'get_posts'), 'args' => array( 'post_type' => array( 'description' => 'Unique post type identifier', 'type' => 'string', 'required' => true ), 'search' => array( 'description' => 'Search string', 'type' => 'string' ), 'offset' => array( 'description' => 'Pagination offset', 'type' => 'number', 'default' => 0 ), 'per_page' => array( 'description' => 'Pagination limit per page', 'type' => 'number', 'default' => 10 ) ) ), self::PERMISSIONS); // Get post permissions $this->_register_route('/post/(?P[\d]+)', array( 'methods' => WP_REST_Server::READABLE, 'callback' => array($this, 'get_post'), 'args' => array( 'id' => array( 'description' => 'Unique post identifier', 'type' => 'number', 'required' => true ) ) ), self::PERMISSIONS); // Update post permissions $this->_register_route('/post/(?P[\d]+)', array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array($this, 'update_post_permissions'), 'args' => array( 'id' => array( 'description' => 'Unique post identifier', 'type' => 'number', 'required' => true ), 'permissions' => array( 'description' => 'Collection of permissions', 'type' => 'array', 'required' => true, 'items' => array( 'type' => 'object', 'properties' => array( 'permission' => array( 'type' => 'string', 'required' => true ), 'effect' => array( 'type' => 'string', 'required' => true, 'default' => 'deny', 'enum' => [ 'allow', 'deny' ] ) ) ) ) ) ), self::PERMISSIONS); // Update post permission $this->_register_route('/post/(?P[\d]+)/(?P[\w]+)', [ 'methods' => WP_REST_Server::EDITABLE, 'callback' => [ $this, 'set_post_permission' ], 'args' => [ 'id' => [ 'description' => 'Unique post identifier', 'type' => 'number', 'required' => true ], 'permission' => [ 'description' => 'Permission', 'type' => 'string', 'required' => true ], 'effect' => [ 'type' => 'string', 'required' => true, 'default' => 'deny', 'enum' => [ 'allow', 'deny' ] ] ] ], self::PERMISSIONS); // Reset post permissions $this->_register_route('/post/(?P[\d]+)', array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array($this, 'reset_post_permissions'), 'args' => array( 'id' => array( 'description' => 'Unique post identifier', 'type' => 'number', 'required' => true ) ) ), self::PERMISSIONS); // The legacy content form also manages post types, taxonomies and terms. $resource_route = '/content/(?Ppost_type|taxonomy|term)/(?P[\w-]+)'; $this->_register_route($resource_route, [ 'methods' => WP_REST_Server::READABLE, 'callback' => [ $this, 'get_content_resource' ] ], self::PERMISSIONS); $this->_register_route($resource_route, [ 'methods' => WP_REST_Server::EDITABLE, 'callback' => [ $this, 'update_content_permissions' ], 'args' => [ 'permissions' => [ 'type' => 'array', 'required' => true, 'items' => [ 'type' => 'object' ] ] ] ], self::PERMISSIONS); $this->_register_route($resource_route, [ 'methods' => WP_REST_Server::DELETABLE, 'callback' => [ $this, 'reset_content_resource' ] ], self::PERMISSIONS); }); } /** Resolve the same resource identifier and optional term scope as the legacy form. */ private function _resolve_content_resource(WP_REST_Request $request) { $type = $request->get_param('resource_type'); $id = $request->get_param('id'); if ($type === AAM_Framework_Type_Resource::POST_TYPE) { $identifier = get_post_type_object($id); } elseif ($type === AAM_Framework_Type_Resource::TAXONOMY) { $identifier = get_taxonomy($id); } else { $taxonomy = $request->get_param('taxonomy'); if (empty($taxonomy) || !taxonomy_exists($taxonomy) || !ctype_digit((string) $id)) { throw new InvalidArgumentException('A valid term ID and taxonomy are required'); } $identifier = get_term((int) $id, $taxonomy); $post_type = $request->get_param('post_type'); if ($identifier instanceof WP_Term && $post_type) { if (!post_type_exists($post_type) || !in_array($post_type, get_taxonomy($taxonomy)->object_type, true)) { throw new InvalidArgumentException('Post type is not registered for this taxonomy'); } $identifier->post_type = $post_type; } } if (!$identifier || is_wp_error($identifier)) { throw new OutOfRangeException('Content resource not found'); } $resource = $this->_determine_access_level($request)->get_resource($type); return [ $resource, $identifier ]; } private function _content_controls($resource, $identifier) { $controls = apply_filters( 'aam_content_access_controls_filter', [], $resource, $identifier ); return is_array($controls) ? $controls : []; } private function _prepare_content_resource($resource, $identifier) { $controls = []; foreach ($this->_content_controls($resource, $identifier) as $key => $settings) { if (is_array($settings)) { $controls[$key] = [ 'title' => $settings['title'] ?? $key, 'description' => $settings['description'] ?? '' ]; } } return [ 'permissions' => $resource->get_permissions($identifier), 'explicit_permissions' => $resource->get_explicit_permissions($identifier), 'is_customized' => $resource->is_customized($identifier), 'controls' => $controls ]; } public function get_content_resource(WP_REST_Request $request) { try { [ $resource, $identifier ] = $this->_resolve_content_resource($request); $result = $this->_prepare_content_resource($resource, $identifier); } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } public function update_content_permissions(WP_REST_Request $request) { try { [ $resource, $identifier ] = $this->_resolve_content_resource($request); $allowed = $this->_content_controls($resource, $identifier); $changes = $request->get_json_params()['permissions'] ?? []; foreach ($changes as $change) { if (!is_array($change) || empty($change['permission']) || !array_key_exists($change['permission'], $allowed) || !in_array($change['effect'] ?? null, [ 'allow', 'deny' ], true)) { throw new InvalidArgumentException('Unsupported content permission'); } } foreach ($changes as $change) { $permission = $change['permission']; unset($change['permission']); if (!$resource->set_permission($identifier, $permission, $change)) { throw new RuntimeException('Could not save content permission'); } } $result = $this->_prepare_content_resource($resource, $identifier); } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } public function reset_content_resource(WP_REST_Request $request) { try { [ $resource, $identifier ] = $this->_resolve_content_resource($request); $result = [ 'success' => $resource->reset($identifier) ]; } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Get the list of all registered post type * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.0 */ public function get_post_types(WP_REST_Request $request) { try { $access_level = $this->_determine_access_level($request); $raw_list = AAM::api()->content->get_post_types( $request->get_param('return_all') ); $result = [ 'list' => [], 'summary' => [ 'total_count' => count(get_post_types()), 'filtered_count' => 0 ] ]; foreach($raw_list as $post_type) { array_push( $result['list'], $this->_prepare_post_type_output( $access_level, $post_type ) ); $result['summary']['filtered_count']++; } } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Get list of taxonomies * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.0 */ public function get_taxonomies(WP_REST_Request $request) { try { $access_level = $this->_determine_access_level($request); $raw_list = AAM::api()->content->get_taxonomies( $request->get_param('return_all') ); $result = [ 'list' => [], 'summary' => [ 'total_count' => count(get_taxonomies()), 'filtered_count' => 0 ] ]; foreach($raw_list as $taxonomy) { array_push( $result['list'], $this->_prepare_taxonomy_output( $access_level, $taxonomy ) ); $result['summary']['filtered_count']++; } } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Get list of posts * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.0 */ public function get_posts(WP_REST_Request $request) { try { $args = [ 'numberposts' => $request->get_param('per_page'), 'post_type' => $request->get_param('post_type'), 's' => $request->get_param('search'), 'offset' => $request->get_param('offset') ]; // Getting the list of posts // The minimum required attribute is post_type. If it is not defined, // throw an error if (empty($args['post_type']) || !is_string($args['post_type'])) { throw new InvalidArgumentException( 'The post_type has to be a valid string' ); } if (empty($args['numberposts'])) { $args['numberposts'] = 10; } $result = [ 'list' => [], 'summary' => [ 'total_count' => AAM::api()->content->get_post_count( $args['post_type'] ), 'filtered_count' => AAM::api()->content->get_post_count( $args['post_type'], $args['s'] ) ] ]; $access_level = $this->_determine_access_level($request); foreach(AAM::api()->content->get_posts($args) as $item) { array_push($result['list'], $this->_prepare_post_output( $item, $access_level )); } } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Get post permissions * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.0 */ public function get_post(WP_REST_Request $request) { try { $result = $this->_prepare_post_output( get_post($request->get_param('id')), $this->_determine_access_level($request) ); } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Get list of terms * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.0 */ public function get_terms(WP_REST_Request $request) { try { $access_level = $this->_determine_access_level($request); $args = [ 'number' => $request->get_param('per_page'), 'taxonomy' => $request->get_param('taxonomy'), 'hide_empty' => false, 'search' => $request->get_param('search'), 'offset' => $request->get_param('offset') ]; // Getting the list of terms // The minimum required attribute is taxonomy. If it is not defined, // throw an error if (empty($args['taxonomy']) || !is_string($args['taxonomy'])) { throw new InvalidArgumentException( 'The taxonomy has to be a valid string' ); } if (empty($args['number'])) { $args['number'] = 10; } $result = [ 'list' => [], 'summary' => [ 'total_count' => AAM::api()->content->get_term_count( $args['taxonomy'] ), 'filtered_count' => AAM::api()->content->get_term_count( $args['taxonomy'], $args ) ] ]; $raw_list = AAM::api()->content->get_terms( $args, $request->get_param('post_type') ); foreach($raw_list as $item) { array_push($result['list'], $this->_prepare_term_output( $access_level, $item )); } } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Update post permissions * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.0 */ public function update_post_permissions(WP_REST_Request $request) { try { $post = get_post($request->get_param('id')); $access_level = $this->_determine_access_level($request); $resource = $access_level->get_resource( AAM_Framework_Type_Resource::POST ); foreach($request->get_param('permissions') as $item) { $permission = $item['permission']; $settings = array_filter($item, function($k) { return $k !== 'permission'; }, ARRAY_FILTER_USE_KEY); $resource->set_permission($post, $permission, $settings); } $result = $this->_prepare_post_output($post, $access_level); } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Update single post permission * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.0 */ public function set_post_permission(WP_REST_Request $request) { try { $post = get_post($request->get_param('id')); $access_level = $this->_determine_access_level($request); $resource = $access_level->get_resource( AAM_Framework_Type_Resource::POST ); $resource->set_permission( $post, $request->get_param('permission'), $request->get_json_params() ); $result = $this->_prepare_post_output($post, $access_level); } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Delete post permissions * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.0 */ public function reset_post_permissions(WP_REST_Request $request) { try { $post = get_post($request->get_param('id')); $resource = $this->_determine_access_level($request)->get_resource( AAM_Framework_Type_Resource::POST ); $result = [ 'success' => $resource->reset($post) ]; } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Prepare post output model * * @param WP_Post $post * @param AAM_Framework_AccessLevel_Interface $access_level * * @return array * @access private * * @version 7.0.0 */ private function _prepare_post_output($post, $access_level) { // Get post type to add additional information about post $post_type = get_post_type_object($post->post_type); $resource = $access_level->get_resource( AAM_Framework_Type_Resource::POST ); $status = get_post_status_object($post->post_status); $result = [ 'id' => $post->ID, 'icon' => $post_type->menu_icon, 'is_hierarchical' => $post_type->hierarchical, 'post_status' => $post->post_status, 'post_status_label' => $status ? $status->label : $post->post_status ]; if ($post->post_type === 'nav_menu_item') { $result['title'] = wp_setup_nav_menu_item($post)->title; } else { $result['title'] = $post->post_title; } $result['permissions'] = $resource->get_permissions($post); $result['explicit_permissions'] = $resource->get_explicit_permissions($post); $result['is_customized'] = $resource->is_customized($post); return $result; } /** * Prepare post type item for output * * @param AAM_Framework_AccessLevel_Interface $access_level * @param WP_Post_Type $post_type * * @return array * @access private * * @version 7.0.0 */ private function _prepare_post_type_output($access_level, $post_type) { $resource = $access_level->get_resource( AAM_Framework_Type_Resource::POST_TYPE ); return [ 'slug' => $post_type->name, 'title' => $post_type->label, 'icon' => $post_type->menu_icon, 'is_hierarchical' => $post_type->hierarchical, 'permissions' => $resource->get_permissions($post_type), 'explicit_permissions' => $resource->get_explicit_permissions($post_type), 'is_customized' => $resource->is_customized($post_type) ]; } /** * Prepare taxonomy item for output * * @param AAM_Framework_AccessLevel_Interface $access_level * @param \WP_Taxonomy $taxonomy * * @return array * @access private * * @version 7.0.0 */ private function _prepare_taxonomy_output($access_level, $taxonomy) { $resource = $access_level->get_resource( AAM_Framework_Type_Resource::TAXONOMY ); return [ 'slug' => $taxonomy->name, 'title' => $taxonomy->label, 'is_hierarchical' => $taxonomy->hierarchical, 'permissions' => $resource->get_permissions($taxonomy), 'explicit_permissions' => $resource->get_explicit_permissions($taxonomy), 'is_customized' => $resource->is_customized($taxonomy), 'post_types' => array_values($taxonomy->object_type) ]; } /** * Prepare term item for output * * @param AAM_Framework_AccessLevel_Interface $access_level * @param WP_Term $term * * @return array * @access private * * @version 7.0.5 */ private function _prepare_term_output($access_level, $term) { $resource = $access_level->get_resource(AAM_Framework_Type_Resource::TERM); $result = [ 'id' => $term->term_id, 'title' => $term->name, 'slug' => $term->slug, 'taxonomy' => $term->taxonomy, 'is_hierarchical' => get_taxonomy($term->taxonomy)->hierarchical, 'permissions' => $resource->get_permissions($term), 'explicit_permissions' => $resource->get_explicit_permissions($term), 'is_customized' => $resource->is_customized($term) ]; if (!empty($term->post_type)) { $is_default = $term->taxonomy === 'category' && intval(get_option('default_category')) === $term->term_id; $result['is_default'] = apply_filters( 'aam_is_default_term_filter', $is_default, $term, $access_level ); // Also adding post type scope to the output $result['post_type'] = $term->post_type; } return $result; } }