Back to Blog
Lesson 10 of the Intermediate WordPress Plugins: REST API & React Admin course
WordPressJune 25, 20263 min read

Updating Existing API Resources: REST API, PUT, and PATCH

Learn to update existing WordPress resources using REST API PUT and PATCH methods. Master ID-based routing and secure data modification for your plugins.

WordPressREST APIPHPDevelopmentBackendplugin-development

Previously in this course, we explored creating POST endpoints for data submission to add new entries to our Knowledge Base. Now, we expand our API's capabilities by implementing the logic required to modify existing resources.

In a RESTful architecture, the ability to update data is just as critical as the ability to create it. We achieve this by using the PUT and PATCH HTTP methods, which allow us to target specific resources via their unique identifiers.

Understanding PUT vs. PATCH

While both methods update resources, they serve different semantic purposes:

  • PUT: Represents a complete replacement of the resource. If you send a PUT request, you are expected to provide the full set of required data. If a field is missing, the API should ideally treat it as an empty value or an error.
  • PATCH: Represents a partial update. You only send the fields that need to be changed, and the server updates only those specific attributes.

When building WordPress plugins, we often use WP_REST_Request to handle these. While WordPress doesn't strictly enforce the structural difference between PUT and PATCH in the database layer, following these conventions makes your API predictable for other developers.

Implementing ID-based Routing

To update a resource, our endpoint must accept an ID parameter. We define this in our register_rest_route call by including a capture group in the route path.

PHP
register_rest_route( 'kb/v1', '/entry/(?P<id>\d+)', [
    'methods'  => [ 'PUT', 'PATCH' ],
    'callback' => 'kb_update_entry_handler',
    'permission_callback' => 'kb_check_permissions',
    'args' => [
        'id' => [
            'validate_callback' => 'is_numeric',
        ],
    ],
] );

By using (?P<id>\d+), we ensure the id is passed directly into our callback function as part of the $request object.

Worked Example: Updating an Entry

In our handler, we need to retrieve the post, verify it exists, and then perform the update using wp_update_post. We must also perform validating and sanitizing API arguments before committing changes to the database.

PHP
function kb_update_entry_handler( WP_REST_Request $request ) {
    $id = $request->get_param( 'id' );
    $post = get_post( $id );

    if ( ! $post || $post->post_type !== 'knowledge_base' ) {
        return new WP_Error( 'not_found', 'Entry not found', [ 'status' => 404 ] );
    }

    $args = [
        'ID'           => $id,
        'post_title'   => sanitize_text_field( $request->get_param( 'title' ) ),
        'post_content' => wp_kses_post( $request->get_param( 'content' ) ),
    ];

    #6A9955">// Remove null values for partial updates(PATCH behavior)
    $args = array_filter( $args, function( $value ) {
        return ! is_null( $value );
    } );

    $result = wp_update_post( $args, true );

    if ( is_wp_error( $result ) ) {
        return $result;
    }

    return new WP_REST_Response( [ 'success' => true, 'id' => $result ], 200 );
}

Hands-on Exercise

  1. Modify your existing kb_update_entry_handler to support both PUT and PATCH.
  2. Add a check to ensure that if a user attempts to update a post, they have the edit_post capability for that specific ID.
  3. Test your endpoint using Postman or cURL by sending a PATCH request to /wp-json/kb/v1/entry/{id} with only the title field in the body. Ensure the content remains unchanged.

Common Pitfalls

  • Ignoring Permission Callbacks: Never assume that because a user is logged in, they can edit every post. Always use current_user_can( 'edit_post', $id ) inside your handler, even if you have a global permission callback defined.
  • Overwriting Data: When implementing PATCH, avoid updating fields that weren't provided in the request. Using array_filter or checking $request->has_param() is essential to avoid overwriting existing data with null or empty strings.
  • Race Conditions: If two users edit the same resource simultaneously, the last one to save wins. For high-concurrency plugins, consider implementing ETag headers or "last modified" timestamps to prevent data loss.

Recap

Updating resources requires precise ID-based routing and careful handling of the request body. By distinguishing between the intent of PUT (full replacement) and PATCH (partial update), you create a robust API. Always sanitize your inputs and verify user permissions against specific post objects to keep your Knowledge Base secure.

Up next: We will begin managing the client-side experience by handling asynchronous state in React.

Similar Posts