\d+)/alt', array( 'methods' => 'PUT', 'callback' => array( $this, 'put' ), 'permission_callback' => array( RestModule::class, 'require_manage_woocommerce' ), ) ); } /** * @return \WP_REST_Response|\WP_Error */ public function put( \WP_REST_Request $request ) { $id = (int) $request['id']; if ( ! wp_attachment_is_image( $id ) || ! ProductImages::of_any_product( $id ) ) { return new \WP_Error( 'cortexcommerce_not_found', __( 'Unknown product image.', 'cortexcommerce' ), array( 'status' => 404 ) ); } $body = $request->get_json_params(); if ( ! self::has_valid_alt( $body ) ) { return self::invalid( __( 'Send a JSON object with one string field, alt.', 'cortexcommerce' ) ); } $alt = trim( sanitize_text_field( $body['alt'] ) ); if ( mb_strlen( $alt ) > self::MAX_LENGTH ) { /* translators: %d: maximum length. */ return self::invalid( sprintf( __( 'alt must be at most %d characters.', 'cortexcommerce' ), self::MAX_LENGTH ) ); } update_post_meta( $id, '_wp_attachment_image_alt', wp_slash( $alt ) ); return new \WP_REST_Response( array( 'id' => $id, 'alt' => $alt, ) ); } /** * True when $body decodes to an object with exactly one string field, alt. * * Takes the decoded body as `mixed` (rather than checking `is_array()` on the return value of * `get_json_params()` directly) so PHPStan doesn't flag the check as dead code: the WordPress stub * declares that method `@return array`, which doesn't account for the `null` WordPress core can * actually hand back for a literal JSON `null` body. * * @param mixed $body Decoded JSON body. */ private static function has_valid_alt( $body ): bool { return is_array( $body ) && array( 'alt' ) === array_keys( $body ) && is_string( $body['alt'] ); } private static function invalid( string $message ): \WP_Error { return new \WP_Error( 'cortexcommerce_invalid_alt', $message, array( 'status' => 400 ) ); } }