'GET', 'callback' => array( $this, 'list_presets' ), 'permission_callback' => array( $this, 'can_manage' ) ), array( 'methods' => 'POST', 'callback' => array( $this, 'create_preset' ), 'permission_callback' => array( $this, 'can_manage' ) ), ) ); register_rest_route( self::NAMESPACE_NAME, '/presets/(?P[a-zA-Z0-9-]+)', array( array( 'methods' => 'GET', 'callback' => array( $this, 'get_preset' ), 'permission_callback' => array( $this, 'can_manage' ) ), array( 'methods' => 'PUT', 'callback' => array( $this, 'update_preset' ), 'permission_callback' => array( $this, 'can_manage' ) ), array( 'methods' => 'DELETE', 'callback' => array( $this, 'delete_preset' ), 'permission_callback' => array( $this, 'can_manage' ) ), ) ); } public function can_manage() { return current_user_can( 'edit_posts' ); } private function all() { $value = get_option( self::OPTION, array() ); return is_array( $value ) ? array_values( $value ) : array(); } private function save( $presets ) { // The option is intentionally absent until the first successful save. if ( false === get_option( self::OPTION, false ) ) { add_option( self::OPTION, array_values( $presets ), '', false ); } else { update_option( self::OPTION, array_values( $presets ), false ); } } private function editor( $request ) { $editor = $request->get_param( 'editor' ); return in_array( $editor, array( 'gutenberg', 'elementor' ), true ) ? $editor : null; } private function invalid( $message, $status = 400 ) { return new \WP_Error( 'animation_preset_error', $message, array( 'status' => $status ) ); } private function find_index( $presets, $id ) { foreach ( $presets as $index => $preset ) { if ( isset( $preset['id'] ) && $preset['id'] === $id ) return $index; } return -1; } private function duplicate_name( $presets, $editor, $name, $except_id = '' ) { foreach ( $presets as $preset ) { if ( $preset['editor'] === $editor && $preset['id'] !== $except_id && 0 === strcasecmp( $preset['name'], $name ) ) return true; } return false; } private function input( $request ) { $editor = $this->editor( $request ); $name = $request->get_param( 'name' ); $config = $request->get_param( 'config' ); if ( ! $editor ) return $this->invalid( __( 'Choose a valid editor.', 'advanced-animation' ) ); if ( ! is_string( $name ) || '' === trim( $name ) ) return $this->invalid( __( 'Enter a preset name.', 'advanced-animation' ) ); $name = sanitize_text_field( trim( $name ) ); if ( '' === $name ) return $this->invalid( __( 'Enter a preset name.', 'advanced-animation' ) ); if ( strlen( $name ) > 100 ) return $this->invalid( __( 'Preset names must be 100 characters or fewer.', 'advanced-animation' ) ); if ( ! is_array( $config ) || empty( $config ) || array_keys( $config ) === range( 0, count( $config ) - 1 ) || strlen( wp_json_encode( $config ) ) > 100000 ) { return $this->invalid( __( 'Enter a valid animation configuration.', 'advanced-animation' ) ); } return array( 'editor' => $editor, 'name' => $name, 'config' => $config ); } public function list_presets( $request ) { $editor = $this->editor( $request ); if ( ! $editor ) return $this->invalid( __( 'Choose a valid editor.', 'advanced-animation' ) ); return rest_ensure_response( array( 'presets' => array_values( array_filter( $this->all(), function ( $preset ) use ( $editor ) { return isset( $preset['editor'] ) && $preset['editor'] === $editor; } ) ) ) ); } public function get_preset( $request ) { $presets = $this->all(); $index = $this->find_index( $presets, $request->get_param( 'id' ) ); if ( $index < 0 ) return $this->invalid( __( 'Preset not found.', 'advanced-animation' ), 404 ); return rest_ensure_response( array( 'preset' => $presets[ $index ] ) ); } public function create_preset( $request ) { $input = $this->input( $request ); if ( is_wp_error( $input ) ) return $input; $presets = $this->all(); if ( $this->duplicate_name( $presets, $input['editor'], $input['name'] ) ) return $this->invalid( __( 'A preset with this name already exists.', 'advanced-animation' ), 409 ); $preset = array_merge( array( 'id' => wp_generate_uuid4() ), $input ); $presets[] = $preset; $this->save( $presets ); return rest_ensure_response( array( 'preset' => $preset ) ); } public function update_preset( $request ) { $presets = $this->all(); $index = $this->find_index( $presets, $request->get_param( 'id' ) ); if ( $index < 0 ) return $this->invalid( __( 'Preset not found.', 'advanced-animation' ), 404 ); $input = $this->input( $request ); if ( is_wp_error( $input ) ) return $input; if ( $input['editor'] !== $presets[ $index ]['editor'] ) return $this->invalid( __( 'Preset editor cannot change.', 'advanced-animation' ) ); if ( $this->duplicate_name( $presets, $input['editor'], $input['name'], $presets[ $index ]['id'] ) ) return $this->invalid( __( 'A preset with this name already exists.', 'advanced-animation' ), 409 ); $presets[ $index ] = array_merge( array( 'id' => $presets[ $index ]['id'] ), $input ); $this->save( $presets ); return rest_ensure_response( array( 'preset' => $presets[ $index ] ) ); } public function delete_preset( $request ) { $presets = $this->all(); $index = $this->find_index( $presets, $request->get_param( 'id' ) ); if ( $index < 0 ) return $this->invalid( __( 'Preset not found.', 'advanced-animation' ), 404 ); array_splice( $presets, $index, 1 ); $this->save( $presets ); return rest_ensure_response( array( 'deleted' => true ) ); } }