Plugin Directory

Changeset 3434593


Ignore:
Timestamp:
01/07/2026 06:06:33 PM (3 months ago)
Author:
whiteshadow
Message:

Refactor more modules to use new internal features (e.g. save forms)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • admin-menu-editor/trunk/modules/redirector/redirector.php

    r3432118 r3434593  
    1212use WP_Error;
    1313use WP_User;
     14use YahnisElsts\AdminMenuEditor\Customizable\Schemas\SchemaFactory;
     15use YahnisElsts\AdminMenuEditor\Options\None;
    1416use YahnisElsts\AdminMenuEditor\Options\Option;
    1517use YahnisElsts\AdminMenuEditor\Options\Some;
    16 use YahnisElsts\AdminMenuEditor\Options\None;
    1718use YahnisElsts\AdminMenuEditor\Utils\Forms\KnockoutSaveForm;
    1819use YahnisElsts\AjaxActionWrapper\v2\Action;
     20use function YahnisElsts\AdminMenuEditor\Collections\w;
    1921
    2022class Module extends amePersistentModule {
     
    394396        $submittedSettings = $submission->getSettings();
    395397
    396         $validationResult = $this->validateSubmittedSettings($submittedSettings);
    397         if ( is_wp_error($validationResult) ) {
    398             //It seems that wp_die() doesn't automatically escape special characters, so let's do that.
    399             wp_die(esc_html($validationResult->get_error_message()));
    400         }
    401 
    402         $newRedirects = new RedirectCollection();
    403         foreach ($submittedSettings['redirects'] as $redirect) {
    404             $newRedirects->add($redirect);
    405         }
    406         $this->redirects = $newRedirects;
     398        $this->redirects = w($submittedSettings['redirects'])->foldLeft(
     399            new RedirectCollection(),
     400            fn($collection, $redirectData) => $collection->add($redirectData)
     401        );
    407402        $this->saveSettings();
    408403
     
    418413
    419414    /**
    420      * @param $settings
    421      * @return bool|WP_Error
    422      */
    423     protected function validateSubmittedSettings($settings) {
    424         if ( !is_array($settings) ) {
    425             return new WP_Error(
    426                 'ame_invalid_json',
    427                 sprintf('Invalid JSON data. Expected an associative array, got %s.', gettype($settings))
    428             );
    429         }
    430 
    431         if ( !array_key_exists('redirects', $settings) ) {
    432             return new WP_Error('rui_missing_redirects_key', 'The required "redirects" field is missing.');
    433         }
    434 
    435         $allowedProperties = [
    436             //Actor IDs always follow the "prefix:value" format.
    437             'actorId'           => /** @lang RegExp */
    438                 '@^[a-z]{1,15}+:[^\s].{0,300}+$@i',
    439             //The URL can be basically anything, so we don't try to validate it.
    440             'urlTemplate'       => null,
    441             //Menu template IDs are based on menu URLs, so they're pretty unpredictable. If one is given, it must be non-empty.
    442             'menuTemplateId'    => /** @lang RegExp */
    443                 '@^.@',
    444             //A trigger is always a lowercase string. We could just list the supported values once dev. is done.
    445             'trigger'           => /** @lang RegExp */
    446                 '@^[a-z\-]{2,20}+$@i',
    447             //The shortcode flag is a boolean value. No regex for that.
    448             'shortcodesEnabled' => null,
    449         ];
    450         $requiredProperties = [
    451             'actorId'           => true,
    452             'urlTemplate'       => true,
    453             'shortcodesEnabled' => true,
    454             'trigger'           => true,
    455         ];
    456 
    457         foreach ($settings['redirects'] as $key => $redirect) {
    458             if ( !is_array($redirect) ) {
    459                 return new WP_Error(
    460                     'rui_bad_redirect_data_type',
    461                     sprintf('Redirect %s should be an array but it is actually %s', $key, gettype($redirect))
    462                 );
    463             }
    464 
    465             //Verify that it has all the required properties.
    466             $missingProperties = array_diff_key($requiredProperties, $redirect);
    467             if ( !empty($missingProperties) ) {
    468                 $firstMissingProp = reset($missingProperties);
    469                 return new WP_Error(
    470                     'rui_missing_key',
    471                     sprintf('Redirect %s is missing the required property "%s"', $key, $firstMissingProp)
    472                 );
    473             }
    474 
    475             //Verify that the redirect has only allowed properties.
    476             $badProperties = array_diff_key($redirect, $allowedProperties);
    477             if ( !empty($badProperties) ) {
    478                 $firstBadProp = reset($badProperties);
    479                 return new WP_Error(
    480                     'rui_bad_key',
    481                     sprintf('Redirect %s has an unsupported property "%s"', $key, $firstBadProp)
    482                 );
    483             }
    484 
    485             //String properties must match their validation regex (if any).
    486             foreach ($allowedProperties as $property => $regex) {
    487                 if (
    488                     is_string($regex) && isset($redirect[$property])
    489                     && (!is_string($redirect[$property]) || !preg_match($regex, $redirect[$property]))
    490                 ) {
    491                     return new WP_Error(
    492                         'rui_invalid_property_value',
    493                         sprintf('Redirect %s: Property "%s" has an invalid value.', $key, $property)
    494                     );
    495                 }
    496             }
    497 
    498             //shortcodesEnabled must be a boolean.
    499             if ( array_key_exists('shortcodesEnabled', $redirect) && !is_bool($redirect['shortcodesEnabled']) ) {
    500                 return new WP_Error(
    501                     'rui_invalid_property_value',
    502                     sprintf(
    503                         'Redirect %s: The "shortcodesEnabled" property is invalid.'
    504                         . ' Expected a boolean, but actual type is "%s".',
    505                         $key,
    506                         gettype($redirect['shortcodesEnabled'])
    507                     )
    508                 );
    509             }
    510 
    511             //URL template must be a string.
    512             if ( !is_string($redirect['urlTemplate']) ) {
    513                 return new WP_Error(
    514                     'rui_invalid_property_value',
    515                     sprintf(
    516                         'Redirect %s: The "urlTemplate" property is invalid.'
    517                         . ' Expected a string, but actual type is "%s".',
    518                         $key,
    519                         gettype($redirect['urlTemplate'])
    520                     )
    521                 );
    522             }
    523 
    524             //URL template must be non-empty.
    525             if ( trim($redirect['urlTemplate']) === '' ) {
    526                 return new WP_Error(
    527                     'rui_empty_url',
    528                     sprintf('Redirect %s: The "urlTemplate" property is empty.', $key)
    529                 );
    530             }
    531         }
    532 
    533         return true;
    534     }
    535 
    536     /**
    537415     * @var KnockoutSaveForm|null
    538416     */
    539     private $saveForm = null;
     417    private ?KnockoutSaveForm $saveForm = null;
    540418
    541419    private function getSaveSettingsForm(): KnockoutSaveForm {
    542420        if ( $this->saveForm === null ) {
     421            $s = new SchemaFactory();
     422            $submittedSettingsSchema = $s->struct([
     423                'redirects' => $s->arr(
     424                    $s->struct([
     425                        //Actor IDs always follow the "prefix:value" format.
     426                        'actorId'           => $s->actorId(),
     427                        //The URL can be basically anything, so we don't try to validate it.
     428                        'urlTemplate'       => $s->string()->max(2000),
     429                        //Menu template IDs are based on menu URLs, so they're pretty unpredictable.
     430                        //If one is given, it must be non-empty.
     431                        'menuTemplateId'    => $s->string()->min(1),
     432                        //A trigger is always a lowercase string.
     433                        'trigger'           => $s->string()->min(2)->max(20)->regex('@^[a-z\-]{2,20}+$@i'),
     434                        'shortcodesEnabled' => $s->boolean(),
     435                    ])->required([
     436                        'actorId',
     437                        'urlTemplate',
     438                        'trigger',
     439                        'shortcodesEnabled',
     440                    ])
     441                ),
     442            ])->required();
     443
    543444            $this->saveForm = KnockoutSaveForm::builderFor($this)
     445                ->settingsFieldSchema($submittedSettingsSchema)
    544446                ->passThroughParams(['selectedTrigger'])
    545447                ->build();
     
    862764     *
    863765     * @param array $redirectProperties
    864      */
    865     public function add($redirectProperties) {
     766     * @return $this
     767     */
     768    public function add(array $redirectProperties): self {
    866769        $trigger = $redirectProperties['trigger'];
    867770        if ( !isset($this->rawItems[$trigger]) ) {
     
    869772        }
    870773        $this->rawItems[$trigger][] = $redirectProperties;
     774        return $this;
    871775    }
    872776}
Note: See TracChangeset for help on using the changeset viewer.