get_json_params(); return '' !== trim( (string) ( $body[ self::FIELD ] ?? '' ) ); } /** * Check a request against the record it means to change. * * @param WP_REST_Request $request The request. * @param array|null $record The record as it stands now. * * @return true|WP_Error True to proceed; a 409 to refuse. */ public static function check( WP_REST_Request $request, ?array $record ): true|WP_Error { // Nothing to compare against: a create, a route with no single record, or an entity whose // controller does not implement record_for(). None of those can conflict. if ( ! is_array( $record ) || ! array_key_exists( self::FIELD, $record ) ) { return true; } $body = (array) $request->get_json_params(); $expected = trim( (string) ( $body[ self::FIELD ] ?? '' ) ); if ( '' === $expected ) { return true; } $current = trim( (string) ( $record[ self::FIELD ] ?? '' ) ); /* * COMPARED AS TIMESTAMPS, NOT AS STRINGS. * * The value makes a round trip through JSON and back, and a client that reformats it — or a * site whose MySQL returns `2026-07-31T09:14:22` where PHP wrote `2026-07-31 09:14:22` — * would produce a mismatch on two spellings of the same instant. That is a conflict prompt * for a conflict that does not exist, which teaches people to ignore the prompt. */ $expected_at = strtotime( $expected ); $current_at = strtotime( $current ); if ( false === $expected_at || false === $current_at || $expected_at === $current_at ) { return true; } return new WP_Error( 'plugixa_crm_conflict', __( 'Somebody else changed this record while you were editing it. Reload to see their version before saving yours.', 'plugixa-crm' ), array( 'status' => 409, 'expected' => $expected, 'current' => $current, ) ); } }