“Unlocking Hidden Potential: How WordPress Can Transform Your Data Entry into a Powerful Central API!”

"Unlocking Hidden Potential: How WordPress Can Transform Your Data Entry into a Powerful Central API!"

Hint: even if you decide that GET (read) requests should/can be publicly available, we still recommend that any POST // PUT // DELETE (create, update, delete) requests always be guarded by a current_user_can check.

Here is a REST controller that we added to Code Snippets in order to be able to list the employees on the site and fetch them by ID:

add_action(
	'rest_api_init',
	function() {
		if ( ! class_exists( 'WP_REST_Controller' ) ) { 
			return;
		}
	
		class Employees_Controller extends WP_REST_Controller {
			protected $namespace = 'custom/v1';
			protected $rest_base = 'employees';

			public function register_routes(): void {
				register_rest_route(
					$this->namespace,
					"/$this->rest_base",
					array(
						array(
							'methods'             => WP_REST_Server::READABLE,
							'permission_callback' => array( $this, 'get_items_permissions_check' ),
							'callback'            => array( $this, 'get_items' ),
							'args'                => $this->get_collection_params(),
						),
						'schema' => array( $this, 'get_public_item_schema' ),
					)
				);
				
				register_rest_route(
					$this->namespace,
					"/$this->rest_base/(?P<employee_id>[d]+)",
					array(
						'args'        => array(
							'employee_id' => array(
								'description' => __( 'Unique identifier for the employee.', 'psapi-features' ),
								'type'        => 'integer',
							),
						),
						array(
							'methods'             => WP_REST_Server::READABLE,
							'permission_callback' => array( $this, 'get_item_permissions_check' ),
							'callback'            => array( $this, 'get_item' ),
						),
						'schema'      => array( $this, 'get_public_item_schema' ),
					)
				);
			}

			public function get_items_permissions_check( $request ): WP_Error|bool {
				return true; // This information is public. You probably want to do a `current_user_can` check.
			}
			
			public function get_item_permissions_check( $request ): WP_Error|bool {
				return $this->get_items_permissions_check( $request ); // Same as for listing all. Can be different.
			}

			public function get_items( $request ): WP_Error|WP_REST_Response {
				$response = array();

				$employees = new WP_Query( $this->prepare_posts_query_args( $request ) );
				foreach ( $employees->posts as $employee ) {
					$data       = $this->prepare_item_for_response( $employee, $request );
					$response[] = $this->prepare_response_for_collection( $data );
				}

				$response = rest_ensure_response( $response );

				$response->header( 'X-WP-Total', $employees->found_posts );
				$response->header( 'X-WP-TotalPages', $employees->max_num_pages );
				foreach ( $this->prepare_link_headers( $request, $employees->max_num_pages ) as $key => $value ) {
					$response->link_header( $key, $value );
				}

				return $response;
			}
			
			public function get_item( $request ): WP_Error|WP_REST_Response {
				$employee = get_post( $request['employee_id'] );
				if ( ! $employee ) {
					return new WP_Error( 'rest_not_found', __( 'No employee found for the given identifier.', 'wpcom-demo' ), array( 'status' => 404 ) );
				}
				
				$response = $this->prepare_item_for_response( $employee, $request );
				return rest_ensure_response( $response );
			}

			public function prepare_item_for_response( $item, $request ): WP_Error|WP_REST_Response {
				$fields = $this->get_fields_for_response( $request );
				$data   = array();

				if ( rest_is_field_included( 'id', $fields ) ) {
					$data['id'] = $item->ID;
				}
				if ( rest_is_field_included( 'name', $fields ) ) {
					$data['name'] = $item->post_title;
				}
				if ( rest_is_field_included( 'picture', $fields ) ) {
					$picture = get_the_post_thumbnail_url( $item, 'full' );
					$data['picture'] = empty( $picture ) ? null : $picture;
				}

				$data     = rest_sanitize_value_from_schema( $data, $this->get_item_schema() );
				$response = rest_ensure_response( $data );
				if ( rest_is_field_included( '_links', $fields ) ) {
					$response->add_links( $this->prepare_links( $item, $request ) );
				}

				return $response;
			}

			public function get_item_schema(): array {
				if ( $this->schema ) {
					return $this->add_additional_fields_schema( $this->schema );
				}

				$this->schema = array(
					'$schema'    => 'http://json-schema.org/draft-04/schema#',
					'title'      => 'employee',
					'type'       => 'object',
					'properties' => array(
						'id'           => array(
							'description' => __( 'Unique identifier for the employee.', 'wpcom-demo' ),
							'type'        => 'integer',
							'readonly'    => true,
						),
						'name'         => array(
							'description' => __( 'The name of the employee.', 'wpcom-demo' ),
							'type'        => 'string',
							'required'    => true,
						),
						'picture'      => array(
							'description' => __( 'URL to the employee profile picture.', 'wpcom-demo' ),
							'type'        => array( 'string', 'null' ),
							'format'      => 'uri',
							'required'    => true,
						),
					)
				);

				return $this->add_additional_fields_schema( $this->schema );
			}
			
			protected function prepare_posts_query_args( WP_REST_Request $request ): array {
				return array(
					'post_type'      => 'employee',
					'post_status'    => 'publish',
					'order'          => $request['order'],
					'orderby'        => $request['orderby'],
					'posts_per_page' => $request['per_page'],
					'paged'          => $request['page'],
					's'              => $request['search'] ?? '',
					'tax_query'      => $this->prepare_posts_taxonomy_query_args( $request ), // phpcs:ignore WordPress.DB.SlowDBQuery
				);
			}
			protected function prepare_posts_taxonomy_query_args( WP_REST_Request $request ): array {
				$tax_query = array();

				if ( $request['team'] ?? false ) {
					$tax_query[] = array(
						'taxonomy' => 'team',
						'field'    => 'slug',
						'terms'    => array( $request['team'] ),
					);
				}

				return $tax_query;
			}
			
			protected function prepare_link_headers( WP_REST_Request $request, int $max_pages ): array {
				$link_headers = array();

				$base = add_query_arg(
					urlencode_deep( $request->get_query_params() ),
					rest_url( $request->get_route() )
				);

				$next_page = $request['page'] < $max_pages ? ( $request['page'] + 1 ) : null;
				if ( $next_page ) {
					$link_headers['next'] = add_query_arg( 'page', $next_page, $base );
				}

				$prev_page = $request['page'] > 1 ? ( $request['page'] - 1 ) : null;
				if ( $prev_page ) {
					$link_headers['prev'] = add_query_arg( 'page', $prev_page, $base );
				}

				return $link_headers;
			}
			
			protected function prepare_links( WP_Post $employee, WP_REST_Request $request ): array {
				$links = array();
				
				if ( ! isset( $request['employee_id'] ) ) {
					$links['self'] = array(
						array(
							'href' => rest_url( "$this->namespace/$this->rest_base/{$employee->ID}" ),
						),
					);
				} else {
					$links['collection'] = array(
						array(
							'href' => rest_url( "$this->namespace/$this->rest_base" ),
						),
					);
				}
				
				return $links;
			}
		}
		
		( new Employees_Controller() )->register_routes();
	}
);

Testing your REST routes

Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

Post Comment