Plugin Directory

Changeset 3081706


Ignore:
Timestamp:
05/06/2024 07:01:26 AM (23 months ago)
Author:
EmranAhmed
Message:

Update to 3.0.2

Location:
woo-2checkout
Files:
56 added
15 edited

Legend:

Unmodified
Added
Removed
  • woo-2checkout/trunk/README.txt

    r3072401 r3081706  
    22Contributors: EmranAhmed, getwooplugins
    33Tags: 2checkout, 2checkout for woocommerce, 2checkout payment gateway, payment gateway, woocommerce payment gateway
    4 Stable tag: 3.0.1
     4Stable tag: 3.0.2
    55Requires PHP: 7.4
    66Requires at least: 6.1
     
    8686== Changelog ==
    8787
     88= 3.0.2 =
     89
     90* Update: WC 8.8+ compatibility
     91
    8892= 3.0.1 =
    8993
  • woo-2checkout/trunk/changelog.txt

    r3044506 r3081706  
    11== Payment Gateway - 2Checkout for WooCommerce ==
     2
     3= 3.0.2 - 2024-05-05 =
     4
     5* Add - WC 8.8+ compatibility.
     6
     7= 3.0.1 - 2024-04-17 =
     8
     9* Add - WC 8.7+ compatibility.
    210
    311= 3.0.0 - 2024-02-29 =
  • woo-2checkout/trunk/includes/API.php

    r3044506 r3081706  
    6161    }
    6262
     63    // https://verifone.cloud/docs/2checkout/Documentation/07Commerce/2Checkout-ConvertPlus/How-to-generate-a-JSON-Web-Token-JWT
    6364    public function generate_jwt_token( $merchant_id, $iat, $exp, $buy_link_secret_word ) {
    6465
     
    9394
    9495    private function encode( $data ) {
    95         return str_replace( '=', '', strtr( base64_encode( $data ), '+/', '-_' ) );
     96
     97        return str_replace(
     98            array( '+', '/', '=' ),
     99            array( '-', '_', '' ),
     100            base64_encode( $data ) // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
     101        );
    96102    }
    97103
  • woo-2checkout/trunk/includes/ConvertPlus/ConvertPlus_Gateway.php

    r3044506 r3081706  
    365365        if ( wc_tax_enabled() && 0 < $order->get_total_tax() ) {
    366366
    367             if ( get_option( 'woocommerce_tax_total_display' ) == 'itemized' ) {
     367            if ( 'itemized' === get_option( 'woocommerce_tax_total_display' ) ) {
    368368                foreach ( $order->get_tax_totals() as $tax ) {
    369369                    $product_info['type'][]         = 'tax';
  • woo-2checkout/trunk/includes/Payment_Gateway.php

    r3044506 r3081706  
    211211        $icon_url = $this->get_icon_url();
    212212
    213         return sprintf( '<img  class="woo-2checkout-gateway-pay-image" alt="%s" src="%s" style="width: %d%%" />', esc_attr( $this->order_button_text ), esc_url( $icon_url ), absint( $this->icon_width ) );
     213        return sprintf( '<img class="woo-2checkout-gateway-pay-image" alt="%s" src="%s" style="width: %d%%" />', esc_attr( $this->order_button_text ), esc_url( $icon_url ), absint( $this->icon_width ) );
    214214    }
    215215
  • woo-2checkout/trunk/languages/woo-2checkout.pot

    r3072401 r3081706  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Payment Gateway - 2Checkout for WooCommerce 3.0.1\n"
     5"Project-Id-Version: Payment Gateway - 2Checkout for WooCommerce 3.0.2\n"
    66"Report-Msgid-Bugs-To: https://getwooplugins.com/new-ticket/\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2024-04-17T12:50:23+00:00\n"
     12"POT-Creation-Date: 2024-05-06T06:54:50+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.10.0\n"
  • woo-2checkout/trunk/vendor/autoload.php

    r3072401 r3081706  
    2323require_once __DIR__ . '/composer/autoload_real.php';
    2424
    25 return ComposerAutoloaderInit5e905c2118fdd7340ebd2d72a1e80d2d::getLoader();
     25return ComposerAutoloaderInitce260624bbcd03fad5e82c3fe1f7a15c::getLoader();
  • woo-2checkout/trunk/vendor/composer/autoload_real.php

    r3072401 r3081706  
    33// autoload_real.php @generated by Composer
    44
    5 class ComposerAutoloaderInit5e905c2118fdd7340ebd2d72a1e80d2d
     5class ComposerAutoloaderInitce260624bbcd03fad5e82c3fe1f7a15c
    66{
    77    private static $loader;
     
    2525        require __DIR__ . '/platform_check.php';
    2626
    27         spl_autoload_register(array('ComposerAutoloaderInit5e905c2118fdd7340ebd2d72a1e80d2d', 'loadClassLoader'), true, true);
     27        spl_autoload_register(array('ComposerAutoloaderInitce260624bbcd03fad5e82c3fe1f7a15c', 'loadClassLoader'), true, true);
    2828        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
    29         spl_autoload_unregister(array('ComposerAutoloaderInit5e905c2118fdd7340ebd2d72a1e80d2d', 'loadClassLoader'));
     29        spl_autoload_unregister(array('ComposerAutoloaderInitce260624bbcd03fad5e82c3fe1f7a15c', 'loadClassLoader'));
    3030
    3131        require __DIR__ . '/autoload_static.php';
    32         call_user_func(\Composer\Autoload\ComposerStaticInit5e905c2118fdd7340ebd2d72a1e80d2d::getInitializer($loader));
     32        call_user_func(\Composer\Autoload\ComposerStaticInitce260624bbcd03fad5e82c3fe1f7a15c::getInitializer($loader));
    3333
    3434        $loader->register(true);
  • woo-2checkout/trunk/vendor/composer/autoload_static.php

    r3072401 r3081706  
    55namespace Composer\Autoload;
    66
    7 class ComposerStaticInit5e905c2118fdd7340ebd2d72a1e80d2d
     7class ComposerStaticInitce260624bbcd03fad5e82c3fe1f7a15c
    88{
    99    public static $prefixLengthsPsr4 = array (
     
    4848    {
    4949        return \Closure::bind(function () use ($loader) {
    50             $loader->prefixLengthsPsr4 = ComposerStaticInit5e905c2118fdd7340ebd2d72a1e80d2d::$prefixLengthsPsr4;
    51             $loader->prefixDirsPsr4 = ComposerStaticInit5e905c2118fdd7340ebd2d72a1e80d2d::$prefixDirsPsr4;
    52             $loader->classMap = ComposerStaticInit5e905c2118fdd7340ebd2d72a1e80d2d::$classMap;
     50            $loader->prefixLengthsPsr4 = ComposerStaticInitce260624bbcd03fad5e82c3fe1f7a15c::$prefixLengthsPsr4;
     51            $loader->prefixDirsPsr4 = ComposerStaticInitce260624bbcd03fad5e82c3fe1f7a15c::$prefixDirsPsr4;
     52            $loader->classMap = ComposerStaticInitce260624bbcd03fad5e82c3fe1f7a15c::$classMap;
    5353
    5454        }, null, ClassLoader::class);
  • woo-2checkout/trunk/vendor/composer/installed.json

    r3072401 r3081706  
    33        {
    44            "name": "storepress/admin-utils",
    5             "version": "1.8.4",
    6             "version_normalized": "1.8.4.0",
     5            "version": "1.8.5",
     6            "version_normalized": "1.8.5.0",
    77            "source": {
    88                "type": "git",
    99                "url": "https://github.com/EmranAhmed/storepress-admin-utils.git",
    10                 "reference": "aef787a2db43acb2f6a320de93f788b25bbe9f66"
     10                "reference": "36b4d595519ae25f3be2625f70e16b9ef8769cfa"
    1111            },
    1212            "dist": {
    1313                "type": "zip",
    14                 "url": "https://api.github.com/repos/EmranAhmed/storepress-admin-utils/zipball/aef787a2db43acb2f6a320de93f788b25bbe9f66",
    15                 "reference": "aef787a2db43acb2f6a320de93f788b25bbe9f66",
     14                "url": "https://api.github.com/repos/EmranAhmed/storepress-admin-utils/zipball/36b4d595519ae25f3be2625f70e16b9ef8769cfa",
     15                "reference": "36b4d595519ae25f3be2625f70e16b9ef8769cfa",
    1616                "shasum": ""
    1717            },
     
    2323                "wp-coding-standards/wpcs": "^3.0.1"
    2424            },
    25             "time": "2024-03-31T10:40:04+00:00",
     25            "time": "2024-04-24T07:44:14+00:00",
    2626            "type": "library",
    2727            "installation-source": "dist",
     
    5353            "support": {
    5454                "issues": "https://github.com/EmranAhmed/storepress-admin-utils/issues",
    55                 "source": "https://github.com/EmranAhmed/storepress-admin-utils/tree/1.8.4"
     55                "source": "https://github.com/EmranAhmed/storepress-admin-utils/tree/1.8.5"
    5656            },
    5757            "install-path": "../storepress/admin-utils"
  • woo-2checkout/trunk/vendor/composer/installed.php

    r3072401 r3081706  
    44        'pretty_version' => 'dev-master',
    55        'version' => 'dev-master',
    6         'reference' => 'befcfee293356215e968354e4505ca935d2dafbd',
     6        'reference' => 'bb7bfb37f35a118844290275253ed6720fa7a5ab',
    77        'type' => 'wordpress-plugin',
    88        'install_path' => __DIR__ . '/../../',
     
    1212    'versions' => array(
    1313        'storepress/admin-utils' => array(
    14             'pretty_version' => '1.8.4',
    15             'version' => '1.8.4.0',
    16             'reference' => 'aef787a2db43acb2f6a320de93f788b25bbe9f66',
     14            'pretty_version' => '1.8.5',
     15            'version' => '1.8.5.0',
     16            'reference' => '36b4d595519ae25f3be2625f70e16b9ef8769cfa',
    1717            'type' => 'library',
    1818            'install_path' => __DIR__ . '/../storepress/admin-utils',
     
    2323            'pretty_version' => 'dev-master',
    2424            'version' => 'dev-master',
    25             'reference' => 'befcfee293356215e968354e4505ca935d2dafbd',
     25            'reference' => 'bb7bfb37f35a118844290275253ed6720fa7a5ab',
    2626            'type' => 'wordpress-plugin',
    2727            'install_path' => __DIR__ . '/../../',
  • woo-2checkout/trunk/vendor/storepress/admin-utils/composer.json

    r3072401 r3081706  
    22  "name" : "storepress/admin-utils",
    33  "description" : "Utility Classes for WordPress Plugin Projects.",
    4   "version" : "1.8.4",
     4  "version" : "1.8.5",
    55  "license" : "GPL-3.0-or-later",
    66  "type" : "library",
  • woo-2checkout/trunk/vendor/storepress/admin-utils/includes/REST_API.php

    r3044506 r3081706  
    11<?php
    2    
     2
    33    namespace StorePress\AdminUtils;
    4    
     4
    55    defined( 'ABSPATH' ) || die( 'Keep Silent' );
    6    
     6
    77    /**
    88     * Settings REST API
     
    1414     * @version    1.0
    1515     */
    16    
    17     if ( ! class_exists( '\StorePress\AdminUtils\REST_API' ) ) {
    18         class REST_API extends \WP_REST_Controller {
    19            
    20             /**
    21              * Constructor.
    22              */
    23             protected Settings $settings;
    24             protected string   $permission;
    25            
    26             protected $namespace;
    27             protected $rest_base = 'settings';
    28            
    29             public function __construct( Settings $settings ) {
    30                 $this->settings   = $settings;
    31                 $this->permission = $this->get_settings()->get_capability();
    32                 $this->namespace  = $this->get_settings()->show_in_rest();
    33             }
    34            
    35             /**
    36              * @return Settings
    37              */
    38             public function get_settings(): Settings {
    39                 return $this->settings;
    40             }
    41            
    42             /**
    43              * Registers the routes for the StorePress's settings.
    44              *
    45              * @see   register_rest_route()
    46              */
    47             public function register_routes() {
    48                
    49                 if ( empty( $this->namespace ) ) {
    50                     return;
    51                 }
    52                
    53                 register_rest_route( $this->namespace, '/' . $this->rest_base, array(
     16
     17if ( ! class_exists( '\StorePress\AdminUtils\REST_API' ) ) {
     18    class REST_API extends \WP_REST_Controller {
     19
     20        /**
     21         * Constructor.
     22         */
     23        protected Settings $settings;
     24        protected string $permission;
     25
     26        protected $namespace;
     27        protected $rest_base = 'settings';
     28
     29        public function __construct( Settings $settings ) {
     30            $this->settings   = $settings;
     31            $this->permission = $this->get_settings()->get_capability();
     32            $this->namespace  = $this->get_settings()->show_in_rest();
     33        }
     34
     35        /**
     36         * @return Settings
     37         */
     38        public function get_settings(): Settings {
     39            return $this->settings;
     40        }
     41
     42        /**
     43         * Registers the routes for the StorePress's settings.
     44         *
     45         * @see register_rest_route()
     46         */
     47        public function register_routes() {
     48
     49            if ( empty( $this->namespace ) ) {
     50                return;
     51            }
     52
     53            // See: https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/
     54            register_rest_route(
     55                $this->namespace,
     56                '/' . $this->rest_base,
     57                array(
    5458                    array(
    5559                        'methods'             => \WP_REST_Server::READABLE,
     
    5862                        'permission_callback' => array( $this, 'get_item_permissions_check' ),
    5963                    ),
    60                    
     64
    6165                    'schema' => array( $this, 'get_public_item_schema' ),
    62                 ) );
     66                )
     67            );
     68        }
     69
     70        /**
     71         * Checks if a given request has access to read and manage settings.
     72         *
     73         * @param \WP_REST_Request $request Full details about the request.
     74         *
     75         * @return bool True if the request has read access for the item, otherwise false.
     76         */
     77        public function get_item_permissions_check( $request ): bool {
     78            return current_user_can( $this->permission );
     79        }
     80
     81        /**
     82         * Retrieves the settings.
     83         *
     84         * @param \WP_REST_Request $request Full details about the request.
     85         *
     86         * @return \WP_REST_Response|\WP_Error Array on success, or WP_Error object on failure.
     87         */
     88        public function get_item( $request ) {
     89            $options = $this->get_registered_options();
     90            $page_id = $this->get_settings()->get_page_id();
     91            $response = array();
     92
     93            foreach ( $options as $name => $args ) {
     94                /**
     95                 * Filters the value of a setting recognized by the REST API.
     96                 *
     97                 * Allow hijacking the setting value and overriding the built-in behavior by returning a
     98                 * non-null value.  The returned value will be presented as the setting value instead.
     99                 *
     100                 * @param mixed  $result Value to use for the requested setting. Can be a scalar
     101                 *                       matching the registered schema for the setting, or null to
     102                 *                       follow the default get_option() behavior.
     103                 * @param string $name   Setting name (as shown in REST API responses).
     104                 * @param array  $args   Custom field array with value.
     105                 */
     106                $response[ $name ] = apply_filters( "rest_pre_get_{$page_id}_setting", null, $name, $args );
     107
     108                if ( is_null( $response[ $name ] ) ) {
     109                    // Set value
     110                    $response[ $name ] = $args['value'];
     111                }
     112
     113                /*
     114                 * Because get_option() is lossy, we have to
     115                 * cast values to the type they are registered with.
     116                 */
     117                $response[ $name ] = $this->prepare_value( $response[ $name ], $args['schema'] );
    63118            }
    64119           
    65             /**
    66              * Checks if a given request has access to read and manage settings.
    67              *
    68              * @param \WP_REST_Request $request Full details about the request.
    69              *
    70              * @return bool True if the request has read access for the item, otherwise false.
     120            return new \WP_REST_Response( $response, 200 );
     121            // return $response;
     122        }
     123
     124        /**
     125         * Prepares a value for output based off a schema array.
     126         *
     127         * @param mixed $value  Value to prepare.
     128         * @param array $schema Schema to match.
     129         *
     130         * @return mixed The prepared value.
     131         */
     132        protected function prepare_value( $value, $schema ) {
     133            /*
     134             * If the value is not valid by the schema, set the value to null.
     135             * Null values are specifically non-destructive, so this will not cause
     136             * overwriting the current invalid value to null.
    71137             */
    72             public function get_item_permissions_check( $request ): bool {
    73                 return current_user_can( $this->permission );
    74             }
    75            
    76             /**
    77              * Retrieves the settings.
    78              *
    79              * @param \WP_REST_Request $request Full details about the request.
    80              *
    81              * @return array|\WP_Error Array on success, or WP_Error object on failure.
    82              */
    83             public function get_item( $request ) {
    84                 $options = $this->get_registered_options();
    85                 $page_id = $this->get_settings()->get_page_id();
     138            if ( is_wp_error( rest_validate_value_from_schema( $value, $schema ) ) ) {
     139                return null;
     140            }
     141
     142            return rest_sanitize_value_from_schema( $value, $schema );
     143        }
     144
     145        /**
     146         * Retrieves all the registered options for the Settings API.
     147         *
     148         * @return array Array of registered options.
     149         */
     150        protected function get_registered_options(): array {
     151            $rest_options = array();
     152
     153            // See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/ .
     154
     155            foreach ( $this->get_settings()->get_all_fields() as $name => $field ) {
     156
     157                if ( empty( $field->get_attribute( 'show_in_rest' ) ) ) {
     158                    continue;
     159                }
     160
     161                $rest_args = array();
     162
     163                if ( is_array( $field->get_attribute( 'show_in_rest' ) ) ) {
     164                    $rest_args = $field->get_attribute( 'show_in_rest' );
     165                }
     166
     167                $defaults = array(
     168                    'name'   => ! empty( $rest_args['name'] ) ? $rest_args['name'] : $field->get_id(),
     169                    'schema' => array(),
     170                );
     171
     172                $rest_args = array_merge( $defaults, $rest_args );
     173
     174                $default_schema = array(
     175                    'type'        => $field->get_rest_type(),
     176                    'description' => $field->get_title(),
     177                    // 'readonly'    => true,
     178                    // 'context'     => array( 'view' ),
     179                    // 'default'     => $field->get_default_value(),
     180                );
     181
     182                if ( $field->has_attribute( 'required' ) ) {
     183                    $default_schema['required'] = true;
     184                }
     185
     186                if ( 'color' === $field->get_type() ) {
     187                    $default_schema['format'] = 'hex-color';
     188                }
     189
     190                if ( 'url' === $field->get_type() ) {
     191                    $default_schema['format'] = 'uri';
     192                }
    86193               
    87                 foreach ( $options as $name => $args ) {
    88                     /**
    89                      * Filters the value of a setting recognized by the REST API.
    90                      *
    91                      * Allow hijacking the setting value and overriding the built-in behavior by returning a
    92                      * non-null value.  The returned value will be presented as the setting value instead.
    93                      *
    94                      * @param mixed  $result Value to use for the requested setting. Can be a scalar
    95                      *                       matching the registered schema for the setting, or null to
    96                      *                       follow the default get_option() behavior.
    97                      * @param string $name   Setting name (as shown in REST API responses).
    98                      * @param array  $args   Custom field array with value.
    99                      */
    100                     $response[ $name ] = apply_filters( "rest_pre_get_{$page_id}_setting", null, $name, $args );
    101                    
    102                     if ( is_null( $response[ $name ] ) ) {
    103                         // Set value
    104                         $response[ $name ] = $args[ 'value' ];
     194                if ( 'email' === $field->get_type() ) {
     195                    $default_schema['format'] = 'email';
     196                }
     197
     198                if ( $field->is_type_group() ) {
     199                    $group_fields          = $field->get_group_fields();
     200                    $default_properties    = array();
     201                    $group_rest_properties = array();
     202
     203                    foreach ( $group_fields as $group_field ) {
     204                        // @TODO: Check is multiple, has options, hex color, number
     205
     206                        $id = $group_field->get_id();
     207
     208                        if ( empty( $group_field->get_attribute( 'show_in_rest' ) ) ) {
     209                            continue;
     210                        }
     211
     212                        if ( is_array( $group_field->get_attribute( 'show_in_rest' ) ) ) {
     213                            $group_rest_properties[ $id ] = $group_field->get_attribute( 'show_in_rest' );
     214                        }
     215
     216                        $default_properties[ $id ] = array();
     217
     218                        $default_properties[ $id ]['type']        = $group_field->get_rest_type();
     219                        $default_properties[ $id ]['description'] = $group_field->get_title();
     220                        $default_properties[ $id ]['readonly']    = true;
     221
     222                        if ( $group_field->has_attribute( 'required' ) ) {
     223                            $default_properties[ $id ]['required'] = true;
     224                        }
     225
     226                        if ( 'color' === $group_field->get_type() ) {
     227                            $default_properties[ $id ]['type']['format'] = 'hex-color';
     228                        }
     229
     230                        if ( 'url' === $group_field->get_type() ) {
     231                            $default_properties[ $id ]['type']['format'] = 'uri';
     232                        }
     233
     234                        if ( 'email' === $group_field->get_type() ) {
     235                            $default_properties[ $id ]['type']['format'] = 'email';
     236                        }
    105237                    }
    106                    
    107                     /*
    108                      * Because get_option() is lossy, we have to
    109                      * cast values to the type they are registered with.
    110                      */
    111                     $response[ $name ] = $this->prepare_value( $response[ $name ], $args[ 'schema' ] );
    112                 }
    113                
    114                 return $response;
    115             }
    116            
    117             /**
    118              * Prepares a value for output based off a schema array.
    119              *
    120              * @param mixed $value  Value to prepare.
    121              * @param array $schema Schema to match.
    122              *
    123              * @return mixed The prepared value.
    124              */
    125             protected function prepare_value( $value, $schema ) {
     238
     239                    $properties = array_merge( $default_properties, $group_rest_properties );
     240
     241                    if ( count( $properties ) > 0 ) {
     242                        $default_schema['properties'] = $properties;
     243                    }
     244                }
     245
     246                $rest_args['schema']      = array_merge( $default_schema, $rest_args['schema'] );
     247                $rest_args['option_name'] = $field->get_id();
     248                if ( $field->is_type_group() ) {
     249                    $rest_args['value'] = $field->get_rest_group_values();
     250                } else {
     251                    $rest_args['value'] = $field->get_rest_value();
     252                }
     253
     254                // Skip over settings that don't have a defined type in the schema.
     255                if ( empty( $rest_args['schema']['type'] ) ) {
     256                    continue;
     257                }
     258
    126259                /*
    127                  * If the value is not valid by the schema, set the value to null.
    128                  * Null values are specifically non-destructive, so this will not cause
    129                  * overwriting the current invalid value to null.
     260                 * Allow the supported types for settings, as we don't want invalid types
     261                 * to be updated with arbitrary values that we can't do decent sanitizing for.
    130262                 */
    131                 if ( is_wp_error( rest_validate_value_from_schema( $value, $schema ) ) ) {
    132                     return null;
    133                 }
    134                
    135                 return rest_sanitize_value_from_schema( $value, $schema );
    136             }
    137            
    138            
    139             /**
    140              * Retrieves all the registered options for the Settings API.
    141              *
    142              * @return array Array of registered options.
    143              */
    144             protected function get_registered_options(): array {
    145                 $rest_options = array();
    146                
    147                 // https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/
    148                
    149                 foreach ( $this->get_settings()->get_all_fields() as $name => $field ) {
    150                    
    151                     if ( empty( $field->get_attribute( 'show_in_rest' ) ) ) {
    152                         continue;
    153                     }
    154                    
    155                     $rest_args = array();
    156                    
    157                     if ( is_array( $field->get_attribute( 'show_in_rest' ) ) ) {
    158                         $rest_args = $field->get_attribute( 'show_in_rest' );
    159                     }
    160                    
    161                     $defaults = array(
    162                         'name'   => ! empty( $rest_args[ 'name' ] ) ? $rest_args[ 'name' ] : $field->get_id(),
    163                         'schema' => array(),
    164                     );
    165                    
    166                     $rest_args = array_merge( $defaults, $rest_args );
    167                    
    168                     $default_schema = array(
    169                         'type'        => $field->get_rest_type(),
    170                         'description' => $field->get_title(),
    171                         // 'readonly'    => true,
    172                         // 'context'     => array( 'view' ),
    173                         // 'default'     => $field->get_default_value(),
    174                     );
    175                    
    176                     if ( $field->has_attribute( 'required' ) ) {
    177                         $default_schema[ 'required' ] = true;
    178                     }
    179                    
    180                     if ( 'color' === $field->get_type() ) {
    181                         $default_schema[ 'format' ] = 'hex-color';
    182                     }
    183                    
    184                     if ( 'url' === $field->get_type() ) {
    185                         $default_schema[ 'format' ] = 'uri';
    186                     }
    187                     if ( 'email' === $field->get_type() ) {
    188                         $default_schema[ 'format' ] = 'email';
    189                     }
    190                    
    191                     if ( $field->is_type_group() ) {
    192                         $group_fields          = $field->get_group_fields();
    193                         $default_properties    = array();
    194                         $group_rest_properties = array();
    195                        
    196                         foreach ( $group_fields as $group_field ) {
    197                             // @TODO: Check is multiple, has options, hex color, number
    198                            
    199                             $id = $group_field->get_id();
    200                            
    201                             if ( empty( $group_field->get_attribute( 'show_in_rest' ) ) ) {
    202                                 continue;
    203                             }
    204                            
    205                             if ( is_array( $group_field->get_attribute( 'show_in_rest' ) ) ) {
    206                                 $group_rest_properties[ $id ] = $group_field->get_attribute( 'show_in_rest' );
    207                             }
    208                            
    209                             $default_properties[ $id ] = array();
    210                            
    211                             $default_properties[ $id ][ 'type' ]        = $group_field->get_rest_type();
    212                             $default_properties[ $id ][ 'description' ] = $group_field->get_title();
    213                             $default_properties[ $id ][ 'readonly' ]    = true;
    214                            
    215                             if ( $group_field->has_attribute( 'required' ) ) {
    216                                 $default_properties[ $id ][ 'required' ] = true;
    217                             }
    218                            
    219                             if ( 'color' === $group_field->get_type() ) {
    220                                 $default_properties[ $id ][ 'type' ][ 'format' ] = 'hex-color';
    221                             }
    222                            
    223                             if ( 'url' === $group_field->get_type() ) {
    224                                 $default_properties[ $id ][ 'type' ][ 'format' ] = 'uri';
    225                             }
    226                            
    227                             if ( 'email' === $group_field->get_type() ) {
    228                                 $default_properties[ $id ][ 'type' ][ 'format' ] = 'email';
    229                             }
    230                         }
    231                        
    232                         $properties = array_merge( $default_properties, $group_rest_properties );
    233                        
    234                         if ( count( $properties ) > 0 ) {
    235                             $default_schema[ 'properties' ] = $properties;
    236                         }
    237                     }
    238                    
    239                     $rest_args[ 'schema' ]      = array_merge( $default_schema, $rest_args[ 'schema' ] );
    240                     $rest_args[ 'option_name' ] = $field->get_id();
    241                     if ( $field->is_type_group() ) {
    242                         $rest_args[ 'value' ] = $field->get_rest_group_values();
    243                     } else {
    244                         $rest_args[ 'value' ] = $field->get_rest_value();
    245                     }
    246                    
    247                     // Skip over settings that don't have a defined type in the schema.
    248                     if ( empty( $rest_args[ 'schema' ][ 'type' ] ) ) {
    249                         continue;
    250                     }
    251                    
    252                     /*
    253                      * Allow the supported types for settings, as we don't want invalid types
    254                      * to be updated with arbitrary values that we can't do decent sanitizing for.
    255                      */
    256                     if ( ! in_array( $rest_args[ 'schema' ][ 'type' ], array( 'number', 'integer', 'string', 'boolean', 'array', 'object' ), true ) ) {
    257                         continue;
    258                     }
    259                    
    260                     $rest_args[ 'schema' ] = rest_default_additional_properties_to_false( $rest_args[ 'schema' ] );
    261                    
    262                     $rest_options[ $rest_args[ 'name' ] ] = $rest_args;
    263                 }
    264                
    265                 return $rest_options;
    266             }
    267            
    268             /**
    269              * Retrieves the site setting schema, conforming to JSON Schema.
    270              *
    271              * @return array Item schema data.
    272              */
    273             public function get_item_schema(): array {
    274                 if ( $this->schema ) {
    275                     return $this->add_additional_fields_schema( $this->schema );
    276                 }
    277                
    278                 $options = $this->get_registered_options();
    279                
    280                 $schema = array(
    281                     '$schema'    => 'http://json-schema.org/draft-04/schema#',
    282                     'title'      => 'settings',
    283                     'type'       => 'object',
    284                     'properties' => array(),
     263                if ( ! in_array( $rest_args['schema']['type'], array( 'number', 'integer', 'string', 'boolean', 'array', 'object' ), true ) ) {
     264                    continue;
     265                }
     266
     267                $rest_args['schema'] = rest_default_additional_properties_to_false( $rest_args['schema'] );
     268
     269                $rest_options[ $rest_args['name'] ] = $rest_args;
     270            }
     271
     272            return $rest_options;
     273        }
     274
     275        /**
     276         * Retrieves the site setting schema, conforming to JSON Schema.
     277         *
     278         * @return array Item schema data.
     279         */
     280        public function get_item_schema(): array {
     281            if ( $this->schema ) {
     282                return $this->add_additional_fields_schema( $this->schema );
     283            }
     284
     285            $options = $this->get_registered_options();
     286
     287            $schema = array(
     288                '$schema'    => 'http://json-schema.org/draft-04/schema#',
     289                'title'      => 'settings',
     290                'type'       => 'object',
     291                'properties' => array(),
     292            );
     293
     294            foreach ( $options as $option_name => $option ) {
     295                $schema['properties'][ $option_name ]                = $option['schema'];
     296                $schema['properties'][ $option_name ]['arg_options'] = array(
     297                    'sanitize_callback' => array( $this, 'sanitize_callback' ),
    285298                );
    286                
    287                 foreach ( $options as $option_name => $option ) {
    288                     $schema[ 'properties' ][ $option_name ]                  = $option[ 'schema' ];
    289                     $schema[ 'properties' ][ $option_name ][ 'arg_options' ] = array(
    290                         'sanitize_callback' => array( $this, 'sanitize_callback' ),
    291                     );
    292                 }
    293                
    294                 $this->schema = $schema;
    295                
    296                 return $this->add_additional_fields_schema( $this->schema );
    297             }
    298            
    299             /**
    300              * Custom sanitize callback used for all options to allow the use of 'null'.
    301              *
    302              * By default, the schema of settings will throw an error if a value is set to
    303              * `null` as it's not a valid value for something like "type => string". We
    304              * provide a wrapper sanitizer to allow the use of `null`.
    305              *
    306              * @param mixed            $value   The value for the setting.
    307              * @param \WP_REST_Request $request The request object.
    308              * @param string           $param   The parameter name.
    309              *
    310              * @return mixed|\WP_Error
    311              */
    312             public function sanitize_callback( $value, $request, $param ) {
    313                 if ( is_null( $value ) ) {
    314                     return $value;
    315                 }
    316                
    317                 return rest_parse_request_arg( $value, $request, $param );
    318             }
     299            }
     300
     301            $this->schema = $schema;
     302
     303            return $this->add_additional_fields_schema( $this->schema );
     304        }
     305
     306        /**
     307         * Custom sanitize callback used for all options to allow the use of 'null'.
     308         *
     309         * By default, the schema of settings will throw an error if a value is set to
     310         * `null` as it's not a valid value for something like "type => string". We
     311         * provide a wrapper sanitizer to allow the use of `null`.
     312         *
     313         * @param mixed            $value   The value for the setting.
     314         * @param \WP_REST_Request $request The request object.
     315         * @param string           $param   The parameter name.
     316         *
     317         * @return mixed|\WP_Error
     318         */
     319        public function sanitize_callback( $value, $request, $param ) {
     320            if ( is_null( $value ) ) {
     321                return $value;
     322            }
     323
     324            return rest_parse_request_arg( $value, $request, $param );
    319325        }
    320326    }
     327}
  • woo-2checkout/trunk/vendor/storepress/admin-utils/includes/Settings.php

    r3044506 r3081706  
    11<?php
    2    
     2
    33    namespace StorePress\AdminUtils;
    4    
     4
    55    defined( 'ABSPATH' ) || die( 'Keep Silent' );
    6    
     6
    77    /**
    88     * Admin Settings
     
    1212     * @version    1.0
    1313     */
    14     if ( ! class_exists( '\StorePress\AdminUtils\Settings' ) ) {
    15         abstract class Settings extends Menu {
    16            
    17             /**
    18              * @var string $fields_callback_fn_name_convention
    19              */
    20             private string $fields_callback_fn_name_convention = 'add_%s_settings_fields';
    21             /**
    22              * @var string $sidebar_callback_fn_name_convention
    23              */
    24             private string $sidebar_callback_fn_name_convention = 'add_%s_settings_sidebar';
    25             /**
    26              * @var string $page_callback_fn_name_convention
    27              */
    28             private string $page_callback_fn_name_convention = 'add_%s_settings_page';
    29             /**
    30              * @var array $options Store All Saved Options
    31              */
    32             private array $options = array();
    33            
    34             /**
    35              * @return string
    36              */
    37             abstract public function settings_id(): string;
    38            
    39             /**
    40              * @return string
    41              */
    42             abstract public function plugin_file(): string;
    43            
    44             /**
    45              * Show Settings in REST. If empty rest api will disable.
    46              *
    47              * @return string|bool
    48              */
    49             public function show_in_rest(): ?string {
    50                 return sprintf( '%s/%s', $this->get_page_id(), $this->rest_api_version() );
    51             }
    52            
    53             /**
    54              * Rest API version
    55              * @return string
    56              */
    57             public function rest_api_version(): string {
    58                 return 'v1';
    59             }
    60            
    61             /**
    62              * Control displaying reset button.
    63              *
    64              * @return bool
    65              */
    66             public function show_reset_button(): bool {
    67                 return true;
    68             }
    69            
    70             final public function settings_init() {
    71                 add_action( 'admin_enqueue_scripts', array( $this, 'register_admin_scripts' ), 20 );
    72                 add_action( 'plugin_action_links_' . plugin_basename( $this->get_plugin_file() ), array( $this, 'plugin_action_links' ) );
    73             }
    74            
    75             final public function settings_actions() {
    76                
    77                 $plugin_page    = sanitize_text_field( wp_unslash( $_GET[ 'page' ] ?? false ) );
    78                 $current_action = sanitize_text_field( wp_unslash( $_REQUEST[ 'action' ] ?? false ) );
    79                
    80                 if ( $plugin_page && $current_action && $plugin_page === $this->get_current_page_slug() ) {
    81                     $this->process_actions( $current_action );
     14if ( ! class_exists( '\StorePress\AdminUtils\Settings' ) ) {
     15    abstract class Settings extends Menu {
     16
     17        /**
     18         * @var string $fields_callback_fn_name_convention
     19         */
     20        private string $fields_callback_fn_name_convention = 'add_%s_settings_fields';
     21        /**
     22         * @var string $sidebar_callback_fn_name_convention
     23         */
     24        private string $sidebar_callback_fn_name_convention = 'add_%s_settings_sidebar';
     25        /**
     26         * @var string $page_callback_fn_name_convention
     27         */
     28        private string $page_callback_fn_name_convention = 'add_%s_settings_page';
     29        /**
     30         * @var array $options Store All Saved Options
     31         */
     32        private array $options = array();
     33
     34        /**
     35         * @return string
     36         */
     37        abstract public function settings_id(): string;
     38
     39        /**
     40         * @return string
     41         */
     42        abstract public function plugin_file(): string;
     43
     44        /**
     45         * Show Settings in REST. If empty rest api will disable.
     46         *
     47         * @example GET: /wp-json/<page-id>/<rest-api-version>/settings
     48         * @return string|bool
     49         */
     50        public function show_in_rest(): ?string {
     51            return sprintf( '%s/%s', $this->get_page_id(), $this->rest_api_version() );
     52        }
     53
     54        /**
     55         * Rest API version
     56         *
     57         * @return string
     58         */
     59        public function rest_api_version(): string {
     60            return 'v1';
     61        }
     62
     63        /**
     64         * Control displaying reset button.
     65         *
     66         * @return bool
     67         */
     68        public function show_reset_button(): bool {
     69            return true;
     70        }
     71
     72        final public function settings_init() {
     73            add_action( 'admin_enqueue_scripts', array( $this, 'register_admin_scripts' ), 20 );
     74            add_action( 'plugin_action_links_' . plugin_basename( $this->get_plugin_file() ), array( $this, 'plugin_action_links' ) );
     75        }
     76
     77        final public function settings_actions() {
     78
     79            $plugin_page    = sanitize_text_field( wp_unslash( $_GET['page'] ?? false ) );
     80            $current_action = sanitize_text_field( wp_unslash( $_REQUEST['action'] ?? false ) );
     81
     82            if ( $plugin_page && $current_action && $plugin_page === $this->get_current_page_slug() ) {
     83                $this->process_actions( $current_action );
     84            }
     85        }
     86
     87        // GET: /wp-json/<page-id>/<rest-api-version>/settings
     88        public function rest_api_init() {
     89            ( new REST_API( $this ) )->register_routes();
     90        }
     91
     92        public function plugin_action_links( $links ): array {
     93
     94            $strings = $this->localize_strings();
     95
     96            $action_links = array(
     97                'settings' => sprintf( '<a href="%1$s" aria-label="%2$s">%2$s</a>', esc_url( $this->get_settings_uri() ), esc_html( $strings['settings_link_text'] ) ),
     98            );
     99
     100            return array_merge( $action_links, $links );
     101        }
     102
     103        /**
     104         * Admin Scripts
     105         *
     106         * @return void
     107         */
     108        public function register_admin_scripts() {
     109
     110            if ( $this->is_admin_page() ) {
     111                $plugin_dir_url  = untrailingslashit( plugin_dir_url( $this->get_plugin_file() ) );
     112                $plugin_dir_path = untrailingslashit( plugin_dir_path( $this->get_plugin_file() ) );
     113
     114                $script_src_url    = $plugin_dir_url . '/vendor/storepress/admin-utils/assets/admin-settings.js';
     115                $style_src_url     = $plugin_dir_url . '/vendor/storepress/admin-utils/assets/admin-settings.css';
     116                $script_asset_file = $plugin_dir_path . '/vendor/storepress/admin-utils/assets/admin-settings.asset.php';
     117                $script_assets     = include $script_asset_file;
     118
     119                wp_register_script( 'storepress-admin-settings', $script_src_url, $script_assets['dependencies'], $script_assets['version'], true );
     120                wp_register_style( 'storepress-admin-settings', $style_src_url, array(), $script_assets['version'] );
     121                wp_localize_script( 'storepress-admin-settings', 'StorePressAdminUtilsSettingsParams', $this->localize_strings() );
     122            }
     123        }
     124
     125        /**
     126         * @return void
     127         */
     128        public function enqueue_scripts() {
     129            wp_enqueue_script( 'storepress-admin-settings' );
     130            wp_enqueue_style( 'storepress-admin-settings' );
     131        }
     132
     133        /**
     134         * Translated Strings
     135         *
     136         * @abstract
     137         * @return array{
     138         *     unsaved_warning_text: string,
     139         *     reset_warning_text: string,
     140         *     reset_button_text: string,
     141         *     settings_link_text: string,
     142         *     settings_updated_message_text: string,
     143         *     settings_deleted_message_text:string
     144         *     }
     145         */
     146        public function localize_strings(): array {
     147
     148            $message = esc_html__( 'not implemented. Must be overridden in subclass.' );
     149            $this->trigger_error( __METHOD__, $message );
     150
     151            return array(
     152                'unsaved_warning_text'          => 'The changes you made will be lost if you navigate away from this page.',
     153                'reset_warning_text'            => 'Are you sure to reset?',
     154                'reset_button_text'             => 'Reset All',
     155                'settings_link_text'            => 'Settings',
     156                'settings_updated_message_text' => 'Settings Saved',
     157                'settings_deleted_message_text' => 'Settings Reset',
     158            );
     159        }
     160
     161        /**
     162         * @abstract
     163         * @return array
     164         */
     165        public function add_settings(): array {
     166
     167            $message = esc_html__( 'not implemented. Must be overridden in subclass.' );
     168            $this->trigger_error( __METHOD__, $message );
     169
     170            return array();
     171        }
     172
     173        /**
     174         * @return array
     175         */
     176        final public function get_settings(): array {
     177            return $this->add_settings();
     178        }
     179
     180        // used on ui template.
     181
     182        /**
     183         * @return void
     184         */
     185        final public function display_sidebar() {
     186            $tab_sidebar = $this->get_tab_sidebar();
     187
     188            if ( is_callable( $tab_sidebar ) ) {
     189                call_user_func( $tab_sidebar );
     190            } else {
     191                // load default sidebar
     192                $this->get_default_sidebar();
     193            }
     194        }
     195
     196        /**
     197         * @return callable|null
     198         */
     199        private function get_tab_sidebar(): ?callable {
     200            $data = $this->get_tab();
     201
     202            return $data['sidebar_callback'];
     203        }
     204
     205        /**
     206         * @abstract
     207         * @return void
     208         */
     209        public function get_default_sidebar() {
     210            $current_tab       = $this->get_current_tab();
     211            $callback_function = sprintf( $this->sidebar_callback_fn_name_convention, $current_tab );
     212            $message           = sprintf( __( 'not implemented. Must be overridden in subclass. Create "%1$s" method for "%2$s" tab sidebar.' ), $callback_function, $current_tab );
     213            $this->trigger_error( __METHOD__, $message );
     214        }
     215
     216        // used on ui template.
     217
     218        /**
     219         * @return void
     220         */
     221        final public function display_fields() {
     222            $fields_callback = $this->get_tab_fields_callback();
     223            $page_callback   = $this->get_tab_page_callback();
     224            $current_tab     = $this->get_current_tab();
     225
     226            if ( is_callable( $page_callback ) ) {
     227                return;
     228            }
     229
     230            $this->check_unique_field_ids();
     231
     232            if ( is_callable( $fields_callback ) ) {
     233                $get_fields = call_user_func( $fields_callback );
     234
     235                if ( is_array( $get_fields ) ) {
     236
     237                    settings_fields( $this->get_option_group_name() );
     238
     239                    $fields = new Fields( $get_fields, $this );
     240                    $fields->display();
     241
     242                    $this->display_buttons();
    82243                }
    83             }
    84            
    85             // GET: /wp-json/<page-id>/<rest-api-version>/settings
    86             public function rest_api_init() {
    87                 ( new REST_API( $this ) )->register_routes();
    88             }
    89            
    90             public function plugin_action_links( $links ): array {
    91                
    92                 $strings = $this->localize_strings();
    93                
    94                 $action_links = array(
    95                     'settings' => sprintf( '<a href="%1$s" aria-label="%2$s">%2$s</a>', esc_url( $this->get_settings_uri() ), esc_html( $strings[ 'settings_link_text' ] ) ),
     244            } else {
     245                $fields_fn_name = sprintf( $this->fields_callback_fn_name_convention, $current_tab );
     246                $page_fn_name   = sprintf( $this->page_callback_fn_name_convention, $current_tab );
     247                $message        = sprintf( 'Should return fields array from "<strong>%s()</strong>". Or For custom page create "<strong>%s()</strong>"', $fields_fn_name, $page_fn_name );
     248                $this->trigger_error( '', $message );
     249            }
     250        }
     251
     252        /**
     253         * @return void
     254         */
     255        public function display_buttons() {
     256            $submit_button = get_submit_button( null, 'primary large', 'submit', false, null );
     257            $reset_button  = $this->get_reset_button();
     258            printf( '<p class="submit">%s %s</p>', $submit_button, $reset_button );
     259        }
     260
     261        /**
     262         * @return string
     263         */
     264        public function get_reset_button(): string {
     265            if ( ! $this->show_reset_button() ) {
     266                return '';
     267            }
     268
     269            $strings = $this->localize_strings();
     270
     271            return sprintf( '<a href="%s" class="storepress-settings-reset-action-link button-link-delete">%s</a>', esc_url( $this->get_reset_uri() ), esc_html( $strings['reset_button_text'] ) );
     272        }
     273
     274        /**
     275         * @return callable|null
     276         */
     277        private function get_tab_fields_callback(): ?callable {
     278            $data = $this->get_tab();
     279
     280            return $data['fields_callback'];
     281        }
     282
     283        /**
     284         * @return callable|null
     285         */
     286        private function get_tab_page_callback(): ?callable {
     287            $data = $this->get_tab();
     288
     289            return $data['page_callback'];
     290        }
     291
     292        // used on ui template.
     293
     294        /**
     295         * @return void
     296         */
     297        final public function display_page() {
     298            $callback = $this->get_tab_page_callback();
     299
     300            if ( is_callable( $callback ) ) {
     301                call_user_func( $callback );
     302            }
     303        }
     304
     305        /**
     306         * @return array
     307         */
     308        final public function get_tabs(): array {
     309            $tabs = $this->get_settings();
     310            $navs = array();
     311
     312            foreach ( $tabs as $key => $tab ) {
     313                if ( empty( $key ) ) {
     314                    $key = $this->default_tab_name();
     315                }
     316
     317                $item = array(
     318                    'id'          => $key,
     319                    'name'        => $tab,
     320                    'hidden'      => false,
     321                    'external'    => false,
     322                    'icon'        => null,
     323                    'css-classes' => array(),
     324                    'sidebar'     => true,
     325                    // 'page_callback'    => null,
     326                    // 'fields_callback'  => null,
     327                    // 'sidebar_callback' => null,
    96328                );
    97                
    98                 return array_merge( $action_links, $links );
    99             }
    100            
    101             /**
    102              * Admin Scripts
    103              *
    104              * @return void
    105              */
    106             public function register_admin_scripts() {
    107                
    108                 if ( $this->is_admin_page() ) {
    109                     $plugin_dir_url  = untrailingslashit( plugin_dir_url( $this->get_plugin_file() ) );
    110                     $plugin_dir_path = untrailingslashit( plugin_dir_path( $this->get_plugin_file() ) );
    111                    
    112                     $script_src_url    = $plugin_dir_url . '/vendor/storepress/admin-utils/assets/admin-settings.js';
    113                     $style_src_url     = $plugin_dir_url . '/vendor/storepress/admin-utils/assets/admin-settings.css';
    114                     $script_asset_file = $plugin_dir_path . '/vendor/storepress/admin-utils/assets/admin-settings.asset.php';
    115                     $script_assets     = include $script_asset_file;
    116                    
    117                     wp_register_script( 'storepress-admin-settings', $script_src_url, $script_assets[ 'dependencies' ], $script_assets[ 'version' ], true );
    118                     wp_register_style( 'storepress-admin-settings', $style_src_url, array(), $script_assets[ 'version' ] );
    119                     wp_localize_script( 'storepress-admin-settings', 'StorePressAdminUtilsSettingsParams', $this->localize_strings() );
     329
     330                if ( is_array( $tab ) ) {
     331                    $navs[ $key ] = wp_parse_args( $tab, $item );
     332                } else {
     333                    $navs[ $key ] = $item;
    120334                }
    121             }
    122            
    123             /**
    124              * @return void
    125              */
    126             public function enqueue_scripts() {
    127                 wp_enqueue_script( 'storepress-admin-settings' );
    128                 wp_enqueue_style( 'storepress-admin-settings' );
    129             }
    130            
    131             /**
    132              * Translated Strings
    133              * @abstract
    134              * @return array{
    135              *     unsaved_warning_text: string,
    136              *     reset_warning_text: string,
    137              *     reset_button_text: string,
    138              *     settings_link_text: string,
    139              *     settings_updated_message_text: string,
    140              *     settings_deleted_message_text:string
    141              *     }
    142              */
    143             public function localize_strings(): array {
    144                
    145                 $message = esc_html__( 'not implemented. Must be overridden in subclass.' );
    146                 $this->trigger_error( __METHOD__, $message );
    147                
    148                 return array(
    149                     'unsaved_warning_text'          => 'The changes you made will be lost if you navigate away from this page.',
    150                     'reset_warning_text'            => 'Are you sure to reset?',
    151                     'reset_button_text'             => 'Reset All',
    152                     'settings_link_text'            => 'Settings',
    153                     'settings_updated_message_text' => 'Settings Saved',
    154                     'settings_deleted_message_text' => 'Settings Reset',
    155                 );
    156             }
    157            
    158             /**
    159              * @abstract
    160              * @return array
    161              */
    162             public function add_settings(): array {
    163                
    164                 $message = esc_html__( 'not implemented. Must be overridden in subclass.' );
    165                 $this->trigger_error( __METHOD__, $message );
    166                
    167                 return array();
    168             }
    169            
    170             /**
    171              * @return array
    172              */
    173             final public function get_settings(): array {
    174                 return $this->add_settings();
    175             }
    176            
    177             // used on ui template.
    178            
    179             /**
    180              * @return void
    181              */
    182             final public function display_sidebar() {
    183                 $tab_sidebar = $this->get_tab_sidebar();
    184                
    185                 if ( is_callable( $tab_sidebar ) ) {
    186                     call_user_func( $tab_sidebar );
    187                 } else {
    188                     // load default sidebar
    189                     $this->get_default_sidebar();
    190                 }
    191             }
    192            
    193             /**
    194              * @return callable|null
    195              */
    196             private function get_tab_sidebar(): ?callable {
    197                 $data = $this->get_tab();
    198                
    199                 return $data[ 'sidebar_callback' ];
    200             }
    201            
    202             /**
    203              * @abstract
    204              * @return void
    205              */
    206             public function get_default_sidebar() {
    207                 $current_tab       = $this->get_current_tab();
    208                 $callback_function = sprintf( $this->sidebar_callback_fn_name_convention, $current_tab );
    209                 $message           = sprintf( __( 'not implemented. Must be overridden in subclass. Create "%1$s" method for "%2$s" tab sidebar.' ), $callback_function, $current_tab );
    210                 $this->trigger_error( __METHOD__, $message );
    211             }
    212            
    213             // used on ui template.
    214            
    215             /**
    216              * @return void
    217              */
    218             final public function display_fields() {
    219                 $fields_callback = $this->get_tab_fields_callback();
    220                 $page_callback   = $this->get_tab_page_callback();
    221                 $current_tab     = $this->get_current_tab();
    222                
    223                 if ( is_callable( $page_callback ) ) {
    224                     return;
    225                 }
    226                
    227                 $this->check_unique_field_ids();
    228                
     335
     336                $page_callback    = array( $this, sprintf( $this->page_callback_fn_name_convention, $key ) );
     337                $fields_callback  = array( $this, sprintf( $this->fields_callback_fn_name_convention, $key ) );
     338                $sidebar_callback = array( $this, sprintf( $this->sidebar_callback_fn_name_convention, $key ) );
     339
     340                $navs[ $key ]['buttons'] = ! is_callable( $page_callback );
     341
     342                $navs[ $key ]['page_callback']    = is_callable( $page_callback ) ? $page_callback : null;
     343                $navs[ $key ]['fields_callback']  = is_callable( $fields_callback ) ? $fields_callback : null;
     344                $navs[ $key ]['sidebar_callback'] = is_callable( $sidebar_callback ) ? $sidebar_callback : null;
     345
     346            }
     347
     348            return $navs;
     349        }
     350
     351        /***
     352         * @return Field[]
     353         */
     354        public function get_all_fields(): array {
     355            $tabs       = $this->get_tabs();
     356            $all_fields = array();
     357
     358            foreach ( $tabs as $tab ) {
     359
     360                $fields_callback = $tab['fields_callback'];
     361
    229362                if ( is_callable( $fields_callback ) ) {
    230                     $get_fields = call_user_func( $fields_callback );
    231                    
    232                     if ( is_array( $get_fields ) ) {
    233                        
    234                         settings_fields( $this->get_option_group_name() );
    235                        
    236                         $fields = new Fields( $get_fields, $this );
    237                         $fields->display();
    238                        
    239                         $this->display_buttons();
    240                     }
    241                 } else {
    242                     $fields_fn_name = sprintf( $this->fields_callback_fn_name_convention, $current_tab );
    243                     $page_fn_name   = sprintf( $this->page_callback_fn_name_convention, $current_tab );
    244                     $message        = sprintf( 'Should return fields array from "<strong>%s()</strong>". Or For custom page create "<strong>%s()</strong>"', $fields_fn_name, $page_fn_name );
    245                     $this->trigger_error( '', $message );
    246                 }
    247             }
    248            
    249             /**
    250              * @return void
    251              */
    252             public function display_buttons() {
    253                 $submit_button = get_submit_button( null, 'primary large', 'submit', false, null );
    254                 $reset_button  = $this->get_reset_button();
    255                 printf( '<p class="submit">%s %s</p>', $submit_button, $reset_button );
    256             }
    257            
    258             /**
    259              * @return string
    260              */
    261             public function get_reset_button(): string {
    262                 if ( ! $this->show_reset_button() ) {
    263                     return '';
    264                 }
    265                
    266                 $strings = $this->localize_strings();
    267                
    268                 return sprintf( '<a href="%s" class="storepress-settings-reset-action-link button-link-delete">%s</a>', esc_url( $this->get_reset_uri() ), esc_html( $strings[ 'reset_button_text' ] ) );
    269             }
    270            
    271             /**
    272              * @return callable|null
    273              */
    274             private function get_tab_fields_callback(): ?callable {
    275                 $data = $this->get_tab();
    276                
    277                 return $data[ 'fields_callback' ];
    278             }
    279            
    280             /**
    281              * @return callable|null
    282              */
    283             private function get_tab_page_callback(): ?callable {
    284                 $data = $this->get_tab();
    285                
    286                 return $data[ 'page_callback' ];
    287             }
    288            
    289             // used on ui template.
    290            
    291             /**
    292              * @return void
    293              */
    294             final public function display_page() {
    295                 $callback = $this->get_tab_page_callback();
    296                
    297                 if ( is_callable( $callback ) ) {
    298                     call_user_func( $callback );
    299                 }
    300             }
    301            
    302             /**
    303              * @return array
    304              */
    305             final public function get_tabs(): array {
    306                 $tabs = $this->get_settings();
    307                 $navs = array();
    308                
    309                 foreach ( $tabs as $key => $tab ) {
    310                     if ( empty( $key ) ) {
    311                         $key = $this->default_tab_name();
    312                     }
    313                    
    314                     $item = array(
    315                         'id'          => $key,
    316                         'name'        => $tab,
    317                         'hidden'      => false,
    318                         'external'    => false,
    319                         'icon'        => null,
    320                         'css-classes' => array(),
    321                         'sidebar'     => true,
    322                         // 'page_callback'    => null,
    323                         // 'fields_callback'  => null,
    324                         // 'sidebar_callback' => null,
    325                     );
    326                    
    327                     if ( is_array( $tab ) ) {
    328                         $navs[ $key ] = wp_parse_args( $tab, $item );
    329                     } else {
    330                         $navs[ $key ] = $item;
    331                     }
    332                    
    333                     $page_callback    = array( $this, sprintf( $this->page_callback_fn_name_convention, $key ) );
    334                     $fields_callback  = array( $this, sprintf( $this->fields_callback_fn_name_convention, $key ) );
    335                     $sidebar_callback = array( $this, sprintf( $this->sidebar_callback_fn_name_convention, $key ) );
    336                    
    337                     $navs[ $key ][ 'buttons' ] = ! is_callable( $page_callback );
    338                    
    339                     $navs[ $key ][ 'page_callback' ]    = is_callable( $page_callback ) ? $page_callback : null;
    340                     $navs[ $key ][ 'fields_callback' ]  = is_callable( $fields_callback ) ? $fields_callback : null;
    341                     $navs[ $key ][ 'sidebar_callback' ] = is_callable( $sidebar_callback ) ? $sidebar_callback : null;
    342                    
    343                 }
    344                
    345                 return $navs;
    346             }
    347            
    348             /***
    349              * @return Field[]
    350              */
    351             public function get_all_fields(): array {
    352                 $tabs       = $this->get_tabs();
    353                 $all_fields = array();
    354                
    355                 foreach ( $tabs as $tab ) {
    356                    
    357                     $fields_callback = $tab[ 'fields_callback' ];
    358                    
    359                     if ( is_callable( $fields_callback ) ) {
    360                         $fields = call_user_func( $fields_callback );
    361                         foreach ( $fields as $field ) {
    362                             if ( 'section' === $field[ 'type' ] ) {
    363                                 continue;
    364                             }
    365                             $_field = ( new Field( $field ) )->add_settings( $this );
    366                            
    367                             $all_fields[ $field[ 'id' ] ] = $_field;
    368                             // $all_fields[ $field[ 'id' ] ] = $field;
     363                    $fields = call_user_func( $fields_callback );
     364                    foreach ( $fields as $field ) {
     365                        if ( 'section' === $field['type'] ) {
     366                            continue;
    369367                        }
     368                        $_field = ( new Field( $field ) )->add_settings( $this );
     369
     370                        $all_fields[ $field['id'] ] = $_field;
     371                        // $all_fields[ $field[ 'id' ] ] = $field;
    370372                    }
    371373                }
    372                
    373                 return $all_fields;
    374             }
    375            
    376             /**
    377              * @return void
    378              */
    379             private function check_unique_field_ids() {
    380                 $tabs = $this->get_tabs();
    381                
    382                 $_field_keys = array();
    383                
    384                 foreach ( $tabs as $tab ) {
    385                     $tab_id          = $tab[ 'id' ];
    386                     $fields_callback = $tab[ 'fields_callback' ];
    387                    
    388                     if ( is_callable( $fields_callback ) ) {
    389                         $fields = call_user_func( $fields_callback );
    390                         /**
    391                          * @var array $field
    392                          */
    393                         foreach ( $fields as $field ) {
    394                             if ( 'section' === $field[ 'type' ] ) {
    395                                 continue;
    396                             }
    397                            
    398                             if ( in_array( $field[ 'id' ], $_field_keys ) ) {
    399                                
    400                                 $fields_fn_name = sprintf( $this->fields_callback_fn_name_convention, $tab_id );
    401                                 $message        = sprintf( 'Duplicate field id "<strong>%s</strong>" found. Please use unique field id.', $field[ 'id' ] );
    402                                
    403                                 $this->trigger_error( $fields_fn_name, $message );
    404                                
    405                             } else {
    406                                 $_field_keys[] = $field[ 'id' ];
    407                             }
    408                         }
    409                     }
    410                 }
    411             }
    412            
    413            
    414             // used on ui template.
    415            
    416             /**
    417              * @return void
    418              */
    419             final public function display_tabs() {
    420                 echo implode( '', $this->get_navs() );
    421             }
    422            
    423             /**
    424              * @return array
    425              */
    426             private function get_navs(): array {
    427                
    428                 $tabs = $this->get_tabs();
    429                
    430                 $current_tab = $this->get_current_tab();
    431                
    432                 $navs = array();
    433                 /**
    434                  * @var array $tab
    435                  */
    436                 foreach ( $tabs as $tab_id => $tab ) {
    437                    
    438                     if ( ! empty( $tab[ 'hidden' ] ) ) {
    439                         continue;
    440                     }
    441                    
    442                     $tab[ 'css-classes' ][] = 'nav-tab';
    443                     $tab[ 'attributes' ]    = array();
    444                     if ( $current_tab === $tab_id ) {
    445                         $tab[ 'css-classes' ][]                = 'nav-tab-active';
    446                         $tab[ 'attributes' ][ 'aria-current' ] = 'page';
    447                     }
    448                    
    449                     $tab_url    = empty( $tab[ 'external' ] ) ? $this->get_tab_uri( $tab_id ) : $tab[ 'external' ];
    450                     $tab_target = empty( $tab[ 'external' ] ) ? '_self' : '_blank';
    451                     $icon       = empty( $tab[ 'icon' ] ) ? '' : sprintf( '<span class="%s"></span>', $tab[ 'icon' ] );
    452                     $attributes = $tab[ 'attributes' ];
    453                    
    454                     $attrs = implode( ' ', array_map( function ( $key ) use ( $attributes ) {
    455                        
    456                         if ( in_array( $key, array( 'target', 'href', 'class' ) ) ) {
    457                             return '';
    458                         }
    459                        
    460                         if ( is_bool( $attributes[ $key ] ) ) {
    461                             return $attributes[ $key ] ? $key : '';
    462                         }
    463                        
    464                         return sprintf( '%s="%s"', $key, esc_attr( $attributes[ $key ] ) );
    465                     }, array_keys( $attributes ) ) );
    466                    
    467                     $navs[] = sprintf( '<a %s target="%s" href="%s" class="%s">%s</span><span>%s</span></a>', $attrs, esc_attr( $tab_target ), esc_url( $tab_url ), esc_attr( implode( ' ', $tab[ 'css-classes' ] ) ), wp_kses_post( $icon ), esc_html( $tab[ 'name' ] ) );
    468                 }
    469                
    470                 return $navs;
    471             }
    472            
    473             // used on ui template.
    474            
    475             /**
    476              * @return string
    477              */
    478             final public function get_action_uri(): string {
    479                 return $this->get_settings_uri();
    480             }
    481            
    482             // used on ui template.
    483            
    484             /**
    485              * @return string
    486              */
    487             final public function get_reset_uri(): string {
    488                 // return wp_nonce_url( $this->get_settings_uri( array( $this->action_query_args() => 'reset' ) ), $this->get_nonce() );
    489                 return wp_nonce_url( $this->get_settings_uri( array( 'action' => 'reset' ) ), $this->get_nonce() );
    490             }
    491            
    492             /**
    493              * @return string
    494              */
    495             final public function get_nonce(): string {
    496                 $group = $this->get_option_group_name();
    497                
    498                 return sprintf( '%s-options', $group );
    499             }
    500            
    501             /**
    502              * @return string
    503              */
    504             final public function get_option_group_name(): string {
    505                 $page = $this->get_current_page_slug();
    506                 $tab  = $this->get_current_tab();
    507                
    508                 return sprintf( '%s-%s', $page, $tab );
    509             }
    510            
    511             /**
    512              * @return string
    513              */
    514             public function get_plugin_file(): string {
    515                 return $this->plugin_file();
    516             }
    517            
    518             /**
    519              * @return string
    520              */
    521             public function get_settings_id(): string {
    522                 return $this->settings_id();
    523             }
    524            
    525             // override for custom ui page
    526            
    527             /**
    528              * @return void
    529              */
    530             public function display_settings_page() {
    531                 // Follow: https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/#naming-conventions
    532                 include __DIR__ . '/templates/classic-template.php';
    533             }
    534            
    535            
    536             public function process_actions( $current_action ) {
    537                
    538                 if ( 'update' === $current_action ) {
    539                     $this->process_action_update();
    540                 }
    541                
    542                 if ( 'reset' === $current_action ) {
    543                     $this->process_action_reset();
    544                 }
    545             }
    546            
    547             /**
    548              * @return void
    549              */
    550             public function process_action_update() {
    551                
    552                 check_admin_referer( $this->get_nonce() );
    553                
    554                 $_post = wp_unslash( $_POST[ $this->get_settings_id() ] );
    555                
    556                 $data = $this->sanitize_fields( $_post );
    557                
    558                 $this->update_options( $data );
    559                
    560                 wp_safe_redirect( add_query_arg( 'message', 'updated', $this->get_action_uri() ) );
    561                 exit;
    562             }
    563            
    564             /**
    565              * @return void
    566              */
    567             public function process_action_reset() {
    568                
    569                 check_admin_referer( $this->get_nonce() );
    570                
    571                 $this->delete_options();
    572                
    573                 wp_safe_redirect( add_query_arg( 'message', 'deleted', $this->get_action_uri() ) );
    574                 exit;
    575             }
    576            
    577             /**
    578              * @return void
    579              */
    580             public function settings_messages() {
    581                 $strings = $this->localize_strings();
    582                 $message = sanitize_text_field( wp_slash( $_GET[ 'message' ] ?? '' ) );
    583                 if ( 'updated' === $message ) {
    584                     $this->add_settings_message( esc_html( $strings[ 'settings_updated_message_text' ] ) );
    585                 }
    586                 if ( 'deleted' === $message ) {
    587                     $this->add_settings_message( esc_html( $strings[ 'settings_deleted_message_text' ] ) );
    588                 }
    589             }
    590            
    591            
    592             /**
    593              * @param array $default . Default: empty array
    594              *
    595              * @return array|false|mixed|null
    596              */
    597             public function get_options( array $default = array() ) {
    598                
    599                 if ( ! empty( $this->options ) ) {
    600                     return $this->options;
    601                 }
    602                 $this->options = get_option( $this->get_settings_id(), $default );
    603                
    604                 return $this->options;
    605             }
    606            
    607             /**
    608              * @return bool
    609              */
    610             final public function delete_options(): bool {
    611                 return delete_option( $this->get_settings_id() );
    612             }
    613            
    614             /**
    615              * @param array $data
    616              *
    617              * @return void
    618              */
    619             final private function update_options( array $data ) {
    620                
    621                 $old_data = $this->get_options();
    622                
    623                 if ( ! empty( $old_data ) ) {
    624                     $current_data = array_merge( $old_data, $data[ 'public' ] );
    625                 } else {
    626                     $current_data = $data[ 'public' ];
    627                 }
    628                
    629                 foreach ( $data[ 'private' ] as $key => $value ) {
    630                     update_option( esc_attr( $key ), $value );
    631                 }
    632                
    633                 update_option( $this->get_settings_id(), $current_data );
    634             }
    635            
    636             /**
    637              * @param string $field_id
    638              * @param mixed  $default . Default null
    639              *
    640              * @return mixed|null
    641              */
    642             public function get_option( string $field_id, $default = null ) {
    643                 $field = $this->get_field( $field_id );
    644                
    645                 return $field->get_value( $default );
    646             }
    647            
    648             /**
    649              * @param string $group_id
    650              * @param string $field_id
    651              * @param mixed  $default . Default: null
    652              *
    653              * @return mixed|null
    654              */
    655             public function get_group_option( string $group_id, string $field_id, $default = null ) {
    656                 $field = $this->get_field( $group_id );
    657                
    658                 return $field->get_group_value( $field_id, $default );
    659             }
    660            
    661             // Current tab fields
    662            
    663             /***
    664              * @return Field[]
    665              */
    666             private function get_available_fields(): array {
    667                 $field_cb         = $this->get_tab_fields_callback();
    668                 $available_fields = array();
    669                 if ( is_callable( $field_cb ) ) {
    670                     $fields = call_user_func( $field_cb );
     374            }
     375
     376            return $all_fields;
     377        }
     378
     379        /**
     380         * @return void
     381         */
     382        private function check_unique_field_ids() {
     383            $tabs = $this->get_tabs();
     384
     385            $_field_keys = array();
     386
     387            foreach ( $tabs as $tab ) {
     388                $tab_id          = $tab['id'];
     389                $fields_callback = $tab['fields_callback'];
     390
     391                if ( is_callable( $fields_callback ) ) {
     392                    $fields = call_user_func( $fields_callback );
    671393                    /**
    672394                     * @var array $field
    673395                     */
    674396                    foreach ( $fields as $field ) {
    675                         if ( 'section' !== $field[ 'type' ] ) {
    676                             $_field                             = ( new Field( $field ) )->add_settings( $this );
    677                             $available_fields[ $field[ 'id' ] ] = $_field;
     397                        if ( 'section' === $field['type'] ) {
     398                            continue;
     399                        }
     400
     401                        if ( in_array( $field['id'], $_field_keys, true ) ) {
     402
     403                            $fields_fn_name = sprintf( $this->fields_callback_fn_name_convention, $tab_id );
     404                            $message        = sprintf( 'Duplicate field id "<strong>%s</strong>" found. Please use unique field id.', $field['id'] );
     405
     406                            $this->trigger_error( $fields_fn_name, $message );
     407
     408                        } else {
     409                            $_field_keys[] = $field['id'];
    678410                        }
    679411                    }
    680412                }
    681                
    682                 return $available_fields;
    683             }
    684            
    685             // Current tab
    686            
     413            }
     414        }
     415
     416
     417        // used on ui template.
     418
     419        /**
     420         * @return void
     421         */
     422        final public function display_tabs() {
     423            echo implode( '', $this->get_navs() );
     424        }
     425
     426        /**
     427         * @return array
     428         */
     429        private function get_navs(): array {
     430
     431            $tabs = $this->get_tabs();
     432
     433            $current_tab = $this->get_current_tab();
     434
     435            $navs = array();
    687436            /**
    688              * @param string $field_id
    689              *
    690              * @return Field|null
     437             * @var array $tab
    691438             */
    692             private function get_available_field( string $field_id ): ?Field {
    693                 $fields = $this->get_available_fields();
    694                
    695                 return $fields[ $field_id ] ?? null;
    696             }
    697            
    698             /**
    699              * @param string $field_id
    700              *
    701              * @return Field|null
    702              */
    703             private function get_field( string $field_id ): ?Field {
    704                 $fields = $this->get_all_fields();
    705                
    706                 return $fields[ $field_id ] ?? null;
    707             }
    708            
    709             /**
    710              *
    711              * @param array $_post
    712              *
    713              * @return array{ public: array, private: array }
    714              */
    715             private function sanitize_fields( array $_post ): array {
    716                
    717                 $fields = $this->get_available_fields();
    718                
    719                 $public_data  = array();
    720                 $private_data = array();
    721                
    722                 foreach ( $fields as $key => $field ) {
    723                    
    724                     $sanitize_callback = $field->get_sanitize_callback();
    725                     $type              = $field->get_type();
    726                     $options           = $field->get_options();
    727                    
    728                     if ( $field->is_private() ) {
    729                         $id                  = $field->get_private_name();
    730                         $private_data[ $id ] = map_deep( $_post[ $key ], $sanitize_callback );
    731                         continue;
    732                     }
    733                    
    734                     switch ( $type ) {
    735                         case 'checkbox':
    736                            
    737                             // Add default checkbox value
    738                             if ( ! isset( $_post[ $key ] ) ) {
    739                                 $_post[ $key ] = ( count( $options ) > 0 ) ? array() : 'no';
     439            foreach ( $tabs as $tab_id => $tab ) {
     440
     441                if ( ! empty( $tab['hidden'] ) ) {
     442                    continue;
     443                }
     444
     445                $tab['css-classes'][] = 'nav-tab';
     446                $tab['attributes']    = array();
     447                if ( $current_tab === $tab_id ) {
     448                    $tab['css-classes'][]              = 'nav-tab-active';
     449                    $tab['attributes']['aria-current'] = 'page';
     450                }
     451
     452                $tab_url    = empty( $tab['external'] ) ? $this->get_tab_uri( $tab_id ) : $tab['external'];
     453                $tab_target = empty( $tab['external'] ) ? '_self' : '_blank';
     454                $icon       = empty( $tab['icon'] ) ? '' : sprintf( '<span class="%s"></span>', $tab['icon'] );
     455                $attributes = $tab['attributes'];
     456
     457                $attrs = implode(
     458                    ' ',
     459                    array_map(
     460                        function ( $key ) use ( $attributes ) {
     461
     462                            if ( in_array( $key, array( 'target', 'href', 'class' ), true ) ) {
     463                                        return '';
    740464                            }
    741                            
    742                             $public_data[ $key ] = map_deep( $_post[ $key ], $sanitize_callback );
    743                            
    744                             break;
    745                         case 'group':
    746                             $group_fields = $field->get_group_fields();
    747                            
    748                             foreach ( $group_fields as $group_field ) {
    749                                 $group_field_id          = $group_field->get_id();
    750                                 $group_field_type        = $group_field->get_type();
    751                                 $group_field_options     = $group_field->get_options();
    752                                 $group_sanitize_callback = $field->get_sanitize_callback();
    753                                
    754                                 // Add default checkbox value
    755                                 if ( 'checkbox' === $group_field_type ) {
    756                                     if ( ! isset( $_post[ $key ][ $group_field_id ] ) ) {
    757                                         $_post[ $key ][ $group_field_id ] = ( count( $group_field_options ) > 0 ) ? array() : 'no';
    758                                     }
    759                                 }
    760                                
    761                                 $public_data[ $key ][ $group_field_id ] = map_deep( $_post[ $key ][ $group_field_id ], $group_sanitize_callback );
     465
     466                            if ( is_bool( $attributes[ $key ] ) ) {
     467                                    return $attributes[ $key ] ? $key : '';
    762468                            }
    763                             break;
    764                        
    765                         default:
    766                             $public_data[ $key ] = map_deep( $_post[ $key ], $sanitize_callback );
    767                             break;
     469
     470                            return sprintf( '%s="%s"', $key, esc_attr( $attributes[ $key ] ) );
     471                        },
     472                        array_keys( $attributes )
     473                    )
     474                );
     475
     476                $navs[] = sprintf( '<a %s target="%s" href="%s" class="%s">%s</span><span>%s</span></a>', $attrs, esc_attr( $tab_target ), esc_url( $tab_url ), esc_attr( implode( ' ', $tab['css-classes'] ) ), wp_kses_post( $icon ), esc_html( $tab['name'] ) );
     477            }
     478
     479            return $navs;
     480        }
     481
     482        // used on ui template.
     483
     484        /**
     485         * @return string
     486         */
     487        final public function get_action_uri(): string {
     488            return $this->get_settings_uri();
     489        }
     490
     491        // used on ui template.
     492
     493        /**
     494         * @return string
     495         */
     496        final public function get_reset_uri(): string {
     497            // return wp_nonce_url( $this->get_settings_uri( array( $this->action_query_args() => 'reset' ) ), $this->get_nonce() );
     498            return wp_nonce_url( $this->get_settings_uri( array( 'action' => 'reset' ) ), $this->get_nonce() );
     499        }
     500
     501        /**
     502         * @return string
     503         */
     504        final public function get_nonce(): string {
     505            $group = $this->get_option_group_name();
     506
     507            return sprintf( '%s-options', $group );
     508        }
     509
     510        /**
     511         * @return string
     512         */
     513        final public function get_option_group_name(): string {
     514            $page = $this->get_current_page_slug();
     515            $tab  = $this->get_current_tab();
     516
     517            return sprintf( '%s-%s', $page, $tab );
     518        }
     519
     520        /**
     521         * @return string
     522         */
     523        public function get_plugin_file(): string {
     524            return $this->plugin_file();
     525        }
     526
     527        /**
     528         * @return string
     529         */
     530        public function get_settings_id(): string {
     531            return $this->settings_id();
     532        }
     533
     534        // override for custom ui page
     535
     536        /**
     537         * @return void
     538         */
     539        public function display_settings_page() {
     540            // Follow: https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/#naming-conventions
     541            include __DIR__ . '/templates/classic-template.php';
     542        }
     543
     544
     545        public function process_actions( $current_action ) {
     546
     547            if ( 'update' === $current_action ) {
     548                $this->process_action_update();
     549            }
     550
     551            if ( 'reset' === $current_action ) {
     552                $this->process_action_reset();
     553            }
     554        }
     555
     556        /**
     557         * @return void
     558         */
     559        public function process_action_update() {
     560
     561            check_admin_referer( $this->get_nonce() );
     562
     563            $_post = wp_unslash( $_POST[ $this->get_settings_id() ] );
     564
     565            $data = $this->sanitize_fields( $_post );
     566
     567            $this->update_options( $data );
     568
     569            wp_safe_redirect( add_query_arg( 'message', 'updated', $this->get_action_uri() ) );
     570            exit;
     571        }
     572
     573        /**
     574         * @return void
     575         */
     576        public function process_action_reset() {
     577
     578            check_admin_referer( $this->get_nonce() );
     579
     580            $this->delete_options();
     581
     582            wp_safe_redirect( add_query_arg( 'message', 'deleted', $this->get_action_uri() ) );
     583            exit;
     584        }
     585
     586        /**
     587         * @return void
     588         */
     589        public function settings_messages() {
     590            $strings = $this->localize_strings();
     591            $message = sanitize_text_field( wp_slash( $_GET['message'] ?? '' ) );
     592            if ( 'updated' === $message ) {
     593                $this->add_settings_message( esc_html( $strings['settings_updated_message_text'] ) );
     594            }
     595            if ( 'deleted' === $message ) {
     596                $this->add_settings_message( esc_html( $strings['settings_deleted_message_text'] ) );
     597            }
     598        }
     599       
     600        /**
     601         * @param array $default . Default: empty array
     602         *
     603         * @return array|false|mixed|null
     604         */
     605        public function get_options( array $default = array() ) {
     606
     607            if ( ! empty( $this->options ) ) {
     608                return $this->options;
     609            }
     610            $this->options = get_option( $this->get_settings_id(), $default );
     611
     612            return $this->options;
     613        }
     614
     615        /**
     616         * @return bool
     617         */
     618        final public function delete_options(): bool {
     619            return delete_option( $this->get_settings_id() );
     620        }
     621
     622        /**
     623         * @param array $data
     624         *
     625         * @return void
     626         */
     627        final private function update_options( array $data ) {
     628
     629            $old_data = $this->get_options();
     630
     631            if ( ! empty( $old_data ) ) {
     632                $current_data = array_merge( $old_data, $data['public'] );
     633            } else {
     634                $current_data = $data['public'];
     635            }
     636
     637            foreach ( $data['private'] as $key => $value ) {
     638                update_option( esc_attr( $key ), $value );
     639            }
     640
     641            update_option( $this->get_settings_id(), $current_data );
     642        }
     643
     644        /**
     645         * @param string $field_id
     646         * @param mixed  $default . Default null
     647         *
     648         * @return mixed|null
     649         */
     650        public function get_option( string $field_id, $default = null ) {
     651            $field = $this->get_field( $field_id );
     652
     653            return $field->get_value( $default );
     654        }
     655
     656        /**
     657         * @param string $group_id
     658         * @param string $field_id
     659         * @param mixed  $default . Default: null
     660         *
     661         * @return mixed|null
     662         */
     663        public function get_group_option( string $group_id, string $field_id, $default = null ) {
     664            $field = $this->get_field( $group_id );
     665
     666            return $field->get_group_value( $field_id, $default );
     667        }
     668
     669        // Current tab fields
     670
     671        /***
     672         * @return Field[]
     673         */
     674        private function get_available_fields(): array {
     675            $field_cb         = $this->get_tab_fields_callback();
     676            $available_fields = array();
     677            if ( is_callable( $field_cb ) ) {
     678                $fields = call_user_func( $field_cb );
     679                /**
     680                 * @var array $field
     681                 */
     682                foreach ( $fields as $field ) {
     683                    if ( 'section' !== $field['type'] ) {
     684                        $_field                           = ( new Field( $field ) )->add_settings( $this );
     685                        $available_fields[ $field['id'] ] = $_field;
    768686                    }
    769687                }
    770                
    771                 return array(
    772                     'public'  => $public_data,
    773                     'private' => $private_data,
    774                 );
    775             }
    776            
    777             /**
    778              * @return void
    779              */
    780             public function settings_page_init() {
    781                 $this->enqueue_scripts();
    782                 $this->settings_messages();
    783             }
    784            
    785             /**
    786              * used on ui template.
    787              *
    788              * @return void
    789              */
    790             final public function display_settings_messages() {
    791                 settings_errors( $this->get_current_page_slug() );
    792             }
    793            
    794             /**
    795              * @param string $message  Message
    796              * @param string $type     Message type. Optional. Message type, controls HTML class. Possible values include 'error',
    797              *                         'success', 'warning', 'info', 'updated'. Default: 'updated'.
    798              *
    799              * @return Settings
    800              */
    801             final public function add_settings_message( string $message, string $type = 'updated' ): Settings {
    802                 add_settings_error( $this->get_current_page_slug(), sprintf( '%s_message', $this->get_settings_id() ), $message, $type );
    803                
    804                 return $this;
    805             }
    806            
    807             /**
    808              * @return string Parent Menu Slug
    809              */
    810             public function parent_menu(): string {
    811                 return 'storepress';
    812             }
    813            
    814             public function capability(): string {
    815                 return 'manage_options';
    816             }
    817            
    818             public function menu_position(): string {
    819                 return '45';
    820             }
    821            
    822             public function menu_icon(): string {
    823                 return 'dashicons-admin-settings';
    824             }
    825            
    826             public function default_tab_name(): string {
    827                 return 'general';
    828             }
    829            
    830             public function get_current_tab(): string {
    831                 $default_tab_query_key = $this->default_tab_name();
    832                
    833                 return empty( $_GET[ 'tab' ] ) ? $default_tab_query_key : sanitize_title( wp_unslash( $_GET[ 'tab' ] ) ); // WPCS: input var okay, CSRF ok.
    834             }
    835            
    836             final public function get_tab( $tab_id = '' ) {
    837                 $tabs = $this->get_tabs();
    838                
    839                 $_tab_id = empty( $tab_id ) ? $this->get_current_tab() : $tab_id;
    840                
    841                 return $tabs[ $_tab_id ];
    842             }
    843            
    844             final public function has_save_button(): bool {
    845                 $data = $this->get_tab();
    846                
    847                 return ! empty( $data[ 'buttons' ] );
    848             }
    849            
    850             final public function has_sidebar(): bool {
    851                 $data = $this->get_tab();
    852                
    853                 return ! empty( $data[ 'sidebar' ] );
    854             }
    855            
    856             /**
    857              * @param $tab_id
    858              *
    859              * @return string
    860              */
    861             public function get_tab_uri( $tab_id ): string {
    862                 return $this->get_settings_uri( array( 'tab' => $tab_id ) );
    863             }
    864            
    865             /**
    866              * @param array $extra
    867              *
    868              * @return string
    869              */
    870             public function get_settings_uri( array $extra = array() ): string {
    871                
    872                 $admin_url = $this->is_submenu() ? $this->get_parent_slug() : 'admin.php';
    873                 $args      = $this->get_uri_args( $extra );
    874                
    875                 return admin_url( add_query_arg( $args, $admin_url ) );
    876             }
    877            
    878             /**
    879              * @param array $extra
    880              *
    881              * @return array
    882              */
    883             public function get_uri_args( array $extra = array() ): array {
    884                
    885                 $current_tab = $this->get_current_tab();
    886                
    887                 $args = array(
    888                     'page' => $this->get_current_page_slug(),
    889                 );
    890                
    891                 if ( ! empty( $current_tab ) ) {
    892                     $args[ 'tab' ] = $current_tab;
     688            }
     689
     690            return $available_fields;
     691        }
     692
     693        // Current tab
     694
     695        /**
     696         * @param string $field_id
     697         *
     698         * @return Field|null
     699         */
     700        private function get_available_field( string $field_id ): ?Field {
     701            $fields = $this->get_available_fields();
     702
     703            return $fields[ $field_id ] ?? null;
     704        }
     705
     706        /**
     707         * @param string $field_id
     708         *
     709         * @return Field|null
     710         */
     711        private function get_field( string $field_id ): ?Field {
     712            $fields = $this->get_all_fields();
     713
     714            return $fields[ $field_id ] ?? null;
     715        }
     716
     717        /**
     718         *
     719         * @param array $_post
     720         *
     721         * @return array{ public: array, private: array }
     722         */
     723        private function sanitize_fields( array $_post ): array {
     724
     725            $fields = $this->get_available_fields();
     726
     727            $public_data  = array();
     728            $private_data = array();
     729
     730            foreach ( $fields as $key => $field ) {
     731
     732                $sanitize_callback = $field->get_sanitize_callback();
     733                $type              = $field->get_type();
     734                $options           = $field->get_options();
     735
     736                if ( $field->is_private() ) {
     737                    $id                  = $field->get_private_name();
     738                    $private_data[ $id ] = map_deep( $_post[ $key ], $sanitize_callback );
     739                    continue;
    893740                }
    894                
    895                 return wp_parse_args( $extra, $args );
    896             }
    897            
    898             /**
    899              * @return bool
    900              */
    901             public function is_admin_page(): bool {
    902                 return ( is_admin() && isset( $_GET[ 'page' ] ) && $this->get_current_page_slug() === $_GET[ 'page' ] );
    903             }
     741
     742                switch ( $type ) {
     743                    case 'checkbox':
     744                        // Add default checkbox value
     745                        if ( ! isset( $_post[ $key ] ) ) {
     746                            $_post[ $key ] = ( count( $options ) > 0 ) ? array() : 'no';
     747                        }
     748
     749                        $public_data[ $key ] = map_deep( $_post[ $key ], $sanitize_callback );
     750
     751                        break;
     752                    case 'group':
     753                        $group_fields = $field->get_group_fields();
     754
     755                        foreach ( $group_fields as $group_field ) {
     756                            $group_field_id          = $group_field->get_id();
     757                            $group_field_type        = $group_field->get_type();
     758                            $group_field_options     = $group_field->get_options();
     759                            $group_sanitize_callback = $field->get_sanitize_callback();
     760
     761                            // Add default checkbox value
     762                            if ( 'checkbox' === $group_field_type ) {
     763                                if ( ! isset( $_post[ $key ][ $group_field_id ] ) ) {
     764                                    $_post[ $key ][ $group_field_id ] = ( count( $group_field_options ) > 0 ) ? array() : 'no';
     765                                }
     766                            }
     767
     768                            $public_data[ $key ][ $group_field_id ] = map_deep( $_post[ $key ][ $group_field_id ], $group_sanitize_callback );
     769                        }
     770                        break;
     771
     772                    default:
     773                        $public_data[ $key ] = map_deep( $_post[ $key ], $sanitize_callback );
     774                        break;
     775                }
     776            }
     777
     778            return array(
     779                'public'  => $public_data,
     780                'private' => $private_data,
     781            );
     782        }
     783
     784        /**
     785         * @return void
     786         */
     787        public function settings_page_init() {
     788            $this->enqueue_scripts();
     789            $this->settings_messages();
     790        }
     791
     792        /**
     793         * used on ui template.
     794         *
     795         * @return void
     796         */
     797        final public function display_settings_messages() {
     798            settings_errors( $this->get_current_page_slug() );
     799        }
     800
     801        /**
     802         * @param string $message  Message
     803         * @param string $type     Message type. Optional. Message type, controls HTML class. Possible values include 'error',
     804         *                         'success', 'warning', 'info', 'updated'. Default: 'updated'.
     805         *
     806         * @return Settings
     807         */
     808        final public function add_settings_message( string $message, string $type = 'updated' ): Settings {
     809            add_settings_error( $this->get_current_page_slug(), sprintf( '%s_message', $this->get_settings_id() ), $message, $type );
     810
     811            return $this;
     812        }
     813
     814        /**
     815         * @return string Parent Menu Slug
     816         */
     817        public function parent_menu(): string {
     818            return 'storepress';
     819        }
     820
     821        public function capability(): string {
     822            return 'manage_options';
     823        }
     824
     825        public function menu_position(): string {
     826            return '45';
     827        }
     828
     829        public function menu_icon(): string {
     830            return 'dashicons-admin-settings';
     831        }
     832
     833        public function default_tab_name(): string {
     834            return 'general';
     835        }
     836
     837        final public function get_current_tab(): string {
     838            $default_tab_query_key = $this->default_tab_name();
     839
     840            $available_tab_keys = array_keys( $this->get_tabs() );
     841
     842            $tab_query_key = in_array( $default_tab_query_key, $available_tab_keys, true ) ? $default_tab_query_key : $available_tab_keys[0];
     843
     844            return empty( $_GET['tab'] ) ? $tab_query_key : sanitize_title( wp_unslash( $_GET['tab'] ) ); // WPCS: input var okay, CSRF ok.
     845        }
     846
     847        final public function get_tab( $tab_id = '' ) {
     848            $tabs = $this->get_tabs();
     849
     850            $_tab_id = empty( $tab_id ) ? $this->get_current_tab() : $tab_id;
     851
     852            return $tabs[ $_tab_id ] ?? array('page_callback'=>function(){
     853                 echo '<div class="notice error"><p>Settings Tab is not available.</p></div>';
     854            });
     855        }
     856
     857        final public function has_save_button(): bool {
     858            $data = $this->get_tab();
     859
     860            return ! empty( $data['buttons'] );
     861        }
     862
     863        final public function has_sidebar(): bool {
     864            $data = $this->get_tab();
     865
     866            return ! empty( $data['sidebar'] );
     867        }
     868
     869        /**
     870         * @param $tab_id
     871         *
     872         * @return string
     873         */
     874        public function get_tab_uri( $tab_id ): string {
     875            return $this->get_settings_uri( array( 'tab' => $tab_id ) );
     876        }
     877
     878        /**
     879         * @param array $extra
     880         *
     881         * @return string
     882         */
     883        public function get_settings_uri( array $extra = array() ): string {
     884
     885            $admin_url = $this->is_submenu() ? $this->get_parent_slug() : 'admin.php';
     886            $args      = $this->get_uri_args( $extra );
     887
     888            return admin_url( add_query_arg( $args, $admin_url ) );
     889        }
     890
     891        /**
     892         * @param array $extra
     893         *
     894         * @return array
     895         */
     896        public function get_uri_args( array $extra = array() ): array {
     897
     898            $current_tab = $this->get_current_tab();
     899
     900            $args = array(
     901                'page' => $this->get_current_page_slug(),
     902            );
     903
     904            if ( ! empty( $current_tab ) ) {
     905                $args['tab'] = $current_tab;
     906            }
     907
     908            return wp_parse_args( $extra, $args );
     909        }
     910
     911        /**
     912         * @return bool
     913         */
     914        public function is_admin_page(): bool {
     915            return ( is_admin() && isset( $_GET['page'] ) && $this->get_current_page_slug() === $_GET['page'] );
    904916        }
    905917    }
     918}
  • woo-2checkout/trunk/woo-2checkout.php

    r3072401 r3081706  
    1010 * Description:          2Checkout Payment Gateway for WooCommerce.
    1111 * Author:               Emran Ahmed
    12  * Version:              3.0.1
     12 * Version:              3.0.2
    1313 * Requires PHP:         7.4
    1414 * Requires at least:    6.1
    1515 * Tested up to:         6.5
    1616 * WC requires at least: 8.1
    17  * WC tested up to:      8.7
     17 * WC tested up to:      8.8
    1818 * Text Domain:          woo-2checkout
    1919 * Author URI:           https://getwooplugins.com/
Note: See TracChangeset for help on using the changeset viewer.