Changeset 3081706
- Timestamp:
- 05/06/2024 07:01:26 AM (23 months ago)
- Location:
- woo-2checkout
- Files:
-
- 56 added
- 15 edited
-
tags/3.0.2 (added)
-
tags/3.0.2/README.txt (added)
-
tags/3.0.2/build (added)
-
tags/3.0.2/build/convert-plus-block.asset.php (added)
-
tags/3.0.2/build/convert-plus-block.js (added)
-
tags/3.0.2/changelog.txt (added)
-
tags/3.0.2/images (added)
-
tags/3.0.2/images/2checkout-dark.svg (added)
-
tags/3.0.2/images/2checkout-light.svg (added)
-
tags/3.0.2/includes (added)
-
tags/3.0.2/includes/API.php (added)
-
tags/3.0.2/includes/Common.php (added)
-
tags/3.0.2/includes/ConvertPlus (added)
-
tags/3.0.2/includes/ConvertPlus/ConvertPlus_Block.php (added)
-
tags/3.0.2/includes/ConvertPlus/ConvertPlus_Gateway.php (added)
-
tags/3.0.2/includes/Extended_Plugin_Upgrade_Notice.php (added)
-
tags/3.0.2/includes/Payment_Gateway.php (added)
-
tags/3.0.2/includes/Plugin.php (added)
-
tags/3.0.2/includes/functions.php (added)
-
tags/3.0.2/languages (added)
-
tags/3.0.2/languages/woo-2checkout.pot (added)
-
tags/3.0.2/uninstall.php (added)
-
tags/3.0.2/vendor (added)
-
tags/3.0.2/vendor/autoload.php (added)
-
tags/3.0.2/vendor/composer (added)
-
tags/3.0.2/vendor/composer/ClassLoader.php (added)
-
tags/3.0.2/vendor/composer/InstalledVersions.php (added)
-
tags/3.0.2/vendor/composer/LICENSE (added)
-
tags/3.0.2/vendor/composer/autoload_classmap.php (added)
-
tags/3.0.2/vendor/composer/autoload_namespaces.php (added)
-
tags/3.0.2/vendor/composer/autoload_psr4.php (added)
-
tags/3.0.2/vendor/composer/autoload_real.php (added)
-
tags/3.0.2/vendor/composer/autoload_static.php (added)
-
tags/3.0.2/vendor/composer/installed.json (added)
-
tags/3.0.2/vendor/composer/installed.php (added)
-
tags/3.0.2/vendor/composer/platform_check.php (added)
-
tags/3.0.2/vendor/storepress (added)
-
tags/3.0.2/vendor/storepress/admin-utils (added)
-
tags/3.0.2/vendor/storepress/admin-utils/README.md (added)
-
tags/3.0.2/vendor/storepress/admin-utils/assets (added)
-
tags/3.0.2/vendor/storepress/admin-utils/assets/admin-settings.asset.php (added)
-
tags/3.0.2/vendor/storepress/admin-utils/assets/admin-settings.css (added)
-
tags/3.0.2/vendor/storepress/admin-utils/assets/admin-settings.js (added)
-
tags/3.0.2/vendor/storepress/admin-utils/composer.json (added)
-
tags/3.0.2/vendor/storepress/admin-utils/includes (added)
-
tags/3.0.2/vendor/storepress/admin-utils/includes/Field.php (added)
-
tags/3.0.2/vendor/storepress/admin-utils/includes/Fields.php (added)
-
tags/3.0.2/vendor/storepress/admin-utils/includes/Menu.php (added)
-
tags/3.0.2/vendor/storepress/admin-utils/includes/REST_API.php (added)
-
tags/3.0.2/vendor/storepress/admin-utils/includes/Section.php (added)
-
tags/3.0.2/vendor/storepress/admin-utils/includes/Settings.php (added)
-
tags/3.0.2/vendor/storepress/admin-utils/includes/Updater.php (added)
-
tags/3.0.2/vendor/storepress/admin-utils/includes/Upgrade_Notice.php (added)
-
tags/3.0.2/vendor/storepress/admin-utils/includes/templates (added)
-
tags/3.0.2/vendor/storepress/admin-utils/includes/templates/classic-template.php (added)
-
tags/3.0.2/woo-2checkout.php (added)
-
trunk/README.txt (modified) (2 diffs)
-
trunk/changelog.txt (modified) (1 diff)
-
trunk/includes/API.php (modified) (2 diffs)
-
trunk/includes/ConvertPlus/ConvertPlus_Gateway.php (modified) (1 diff)
-
trunk/includes/Payment_Gateway.php (modified) (1 diff)
-
trunk/languages/woo-2checkout.pot (modified) (2 diffs)
-
trunk/vendor/autoload.php (modified) (1 diff)
-
trunk/vendor/composer/autoload_real.php (modified) (2 diffs)
-
trunk/vendor/composer/autoload_static.php (modified) (2 diffs)
-
trunk/vendor/composer/installed.json (modified) (3 diffs)
-
trunk/vendor/composer/installed.php (modified) (3 diffs)
-
trunk/vendor/storepress/admin-utils/composer.json (modified) (1 diff)
-
trunk/vendor/storepress/admin-utils/includes/REST_API.php (modified) (3 diffs)
-
trunk/vendor/storepress/admin-utils/includes/Settings.php (modified) (2 diffs)
-
trunk/woo-2checkout.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
woo-2checkout/trunk/README.txt
r3072401 r3081706 2 2 Contributors: EmranAhmed, getwooplugins 3 3 Tags: 2checkout, 2checkout for woocommerce, 2checkout payment gateway, payment gateway, woocommerce payment gateway 4 Stable tag: 3.0. 14 Stable tag: 3.0.2 5 5 Requires PHP: 7.4 6 6 Requires at least: 6.1 … … 86 86 == Changelog == 87 87 88 = 3.0.2 = 89 90 * Update: WC 8.8+ compatibility 91 88 92 = 3.0.1 = 89 93 -
woo-2checkout/trunk/changelog.txt
r3044506 r3081706 1 1 == 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. 2 10 3 11 = 3.0.0 - 2024-02-29 = -
woo-2checkout/trunk/includes/API.php
r3044506 r3081706 61 61 } 62 62 63 // https://verifone.cloud/docs/2checkout/Documentation/07Commerce/2Checkout-ConvertPlus/How-to-generate-a-JSON-Web-Token-JWT 63 64 public function generate_jwt_token( $merchant_id, $iat, $exp, $buy_link_secret_word ) { 64 65 … … 93 94 94 95 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 ); 96 102 } 97 103 -
woo-2checkout/trunk/includes/ConvertPlus/ConvertPlus_Gateway.php
r3044506 r3081706 365 365 if ( wc_tax_enabled() && 0 < $order->get_total_tax() ) { 366 366 367 if ( get_option( 'woocommerce_tax_total_display' ) == 'itemized') {367 if ( 'itemized' === get_option( 'woocommerce_tax_total_display' ) ) { 368 368 foreach ( $order->get_tax_totals() as $tax ) { 369 369 $product_info['type'][] = 'tax'; -
woo-2checkout/trunk/includes/Payment_Gateway.php
r3044506 r3081706 211 211 $icon_url = $this->get_icon_url(); 212 212 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 ) ); 214 214 } 215 215 -
woo-2checkout/trunk/languages/woo-2checkout.pot
r3072401 r3081706 3 3 msgid "" 4 4 msgstr "" 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" 6 6 "Report-Msgid-Bugs-To: https://getwooplugins.com/new-ticket/\n" 7 7 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" … … 10 10 "Content-Type: text/plain; charset=UTF-8\n" 11 11 "Content-Transfer-Encoding: 8bit\n" 12 "POT-Creation-Date: 2024-0 4-17T12:50:23+00:00\n"12 "POT-Creation-Date: 2024-05-06T06:54:50+00:00\n" 13 13 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 14 "X-Generator: WP-CLI 2.10.0\n" -
woo-2checkout/trunk/vendor/autoload.php
r3072401 r3081706 23 23 require_once __DIR__ . '/composer/autoload_real.php'; 24 24 25 return ComposerAutoloaderInit 5e905c2118fdd7340ebd2d72a1e80d2d::getLoader();25 return ComposerAutoloaderInitce260624bbcd03fad5e82c3fe1f7a15c::getLoader(); -
woo-2checkout/trunk/vendor/composer/autoload_real.php
r3072401 r3081706 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit 5e905c2118fdd7340ebd2d72a1e80d2d5 class ComposerAutoloaderInitce260624bbcd03fad5e82c3fe1f7a15c 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit 5e905c2118fdd7340ebd2d72a1e80d2d', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInitce260624bbcd03fad5e82c3fe1f7a15c', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit 5e905c2118fdd7340ebd2d72a1e80d2d', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInitce260624bbcd03fad5e82c3fe1f7a15c', 'loadClassLoader')); 30 30 31 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\Composer\Autoload\ComposerStaticInit 5e905c2118fdd7340ebd2d72a1e80d2d::getInitializer($loader));32 call_user_func(\Composer\Autoload\ComposerStaticInitce260624bbcd03fad5e82c3fe1f7a15c::getInitializer($loader)); 33 33 34 34 $loader->register(true); -
woo-2checkout/trunk/vendor/composer/autoload_static.php
r3072401 r3081706 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit 5e905c2118fdd7340ebd2d72a1e80d2d7 class ComposerStaticInitce260624bbcd03fad5e82c3fe1f7a15c 8 8 { 9 9 public static $prefixLengthsPsr4 = array ( … … 48 48 { 49 49 return \Closure::bind(function () use ($loader) { 50 $loader->prefixLengthsPsr4 = ComposerStaticInit 5e905c2118fdd7340ebd2d72a1e80d2d::$prefixLengthsPsr4;51 $loader->prefixDirsPsr4 = ComposerStaticInit 5e905c2118fdd7340ebd2d72a1e80d2d::$prefixDirsPsr4;52 $loader->classMap = ComposerStaticInit 5e905c2118fdd7340ebd2d72a1e80d2d::$classMap;50 $loader->prefixLengthsPsr4 = ComposerStaticInitce260624bbcd03fad5e82c3fe1f7a15c::$prefixLengthsPsr4; 51 $loader->prefixDirsPsr4 = ComposerStaticInitce260624bbcd03fad5e82c3fe1f7a15c::$prefixDirsPsr4; 52 $loader->classMap = ComposerStaticInitce260624bbcd03fad5e82c3fe1f7a15c::$classMap; 53 53 54 54 }, null, ClassLoader::class); -
woo-2checkout/trunk/vendor/composer/installed.json
r3072401 r3081706 3 3 { 4 4 "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", 7 7 "source": { 8 8 "type": "git", 9 9 "url": "https://github.com/EmranAhmed/storepress-admin-utils.git", 10 "reference": " aef787a2db43acb2f6a320de93f788b25bbe9f66"10 "reference": "36b4d595519ae25f3be2625f70e16b9ef8769cfa" 11 11 }, 12 12 "dist": { 13 13 "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", 16 16 "shasum": "" 17 17 }, … … 23 23 "wp-coding-standards/wpcs": "^3.0.1" 24 24 }, 25 "time": "2024-0 3-31T10:40:04+00:00",25 "time": "2024-04-24T07:44:14+00:00", 26 26 "type": "library", 27 27 "installation-source": "dist", … … 53 53 "support": { 54 54 "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" 56 56 }, 57 57 "install-path": "../storepress/admin-utils" -
woo-2checkout/trunk/vendor/composer/installed.php
r3072401 r3081706 4 4 'pretty_version' => 'dev-master', 5 5 'version' => 'dev-master', 6 'reference' => 'b efcfee293356215e968354e4505ca935d2dafbd',6 'reference' => 'bb7bfb37f35a118844290275253ed6720fa7a5ab', 7 7 'type' => 'wordpress-plugin', 8 8 'install_path' => __DIR__ . '/../../', … … 12 12 'versions' => array( 13 13 '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', 17 17 'type' => 'library', 18 18 'install_path' => __DIR__ . '/../storepress/admin-utils', … … 23 23 'pretty_version' => 'dev-master', 24 24 'version' => 'dev-master', 25 'reference' => 'b efcfee293356215e968354e4505ca935d2dafbd',25 'reference' => 'bb7bfb37f35a118844290275253ed6720fa7a5ab', 26 26 'type' => 'wordpress-plugin', 27 27 'install_path' => __DIR__ . '/../../', -
woo-2checkout/trunk/vendor/storepress/admin-utils/composer.json
r3072401 r3081706 2 2 "name" : "storepress/admin-utils", 3 3 "description" : "Utility Classes for WordPress Plugin Projects.", 4 "version" : "1.8. 4",4 "version" : "1.8.5", 5 5 "license" : "GPL-3.0-or-later", 6 6 "type" : "library", -
woo-2checkout/trunk/vendor/storepress/admin-utils/includes/REST_API.php
r3044506 r3081706 1 1 <?php 2 2 3 3 namespace StorePress\AdminUtils; 4 4 5 5 defined( 'ABSPATH' ) || die( 'Keep Silent' ); 6 6 7 7 /** 8 8 * Settings REST API … … 14 14 * @version 1.0 15 15 */ 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 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 // 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( 54 58 array( 55 59 'methods' => \WP_REST_Server::READABLE, … … 58 62 'permission_callback' => array( $this, 'get_item_permissions_check' ), 59 63 ), 60 64 61 65 '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'] ); 63 118 } 64 119 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. 71 137 */ 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 } 86 193 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 } 105 237 } 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 126 259 /* 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. 130 262 */ 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' ), 285 298 ); 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 ); 319 325 } 320 326 } 327 } -
woo-2checkout/trunk/vendor/storepress/admin-utils/includes/Settings.php
r3044506 r3081706 1 1 <?php 2 2 3 3 namespace StorePress\AdminUtils; 4 4 5 5 defined( 'ABSPATH' ) || die( 'Keep Silent' ); 6 6 7 7 /** 8 8 * Admin Settings … … 12 12 * @version 1.0 13 13 */ 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 ); 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 * @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(); 82 243 } 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, 96 328 ); 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; 120 334 } 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 229 362 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; 369 367 } 368 $_field = ( new Field( $field ) )->add_settings( $this ); 369 370 $all_fields[ $field['id'] ] = $_field; 371 // $all_fields[ $field[ 'id' ] ] = $field; 370 372 } 371 373 } 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 ); 671 393 /** 672 394 * @var array $field 673 395 */ 674 396 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']; 678 410 } 679 411 } 680 412 } 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(); 687 436 /** 688 * @param string $field_id 689 * 690 * @return Field|null 437 * @var array $tab 691 438 */ 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 ''; 740 464 } 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 : ''; 762 468 } 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; 768 686 } 769 687 } 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; 893 740 } 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'] ); 904 916 } 905 917 } 918 } -
woo-2checkout/trunk/woo-2checkout.php
r3072401 r3081706 10 10 * Description: 2Checkout Payment Gateway for WooCommerce. 11 11 * Author: Emran Ahmed 12 * Version: 3.0. 112 * Version: 3.0.2 13 13 * Requires PHP: 7.4 14 14 * Requires at least: 6.1 15 15 * Tested up to: 6.5 16 16 * WC requires at least: 8.1 17 * WC tested up to: 8. 717 * WC tested up to: 8.8 18 18 * Text Domain: woo-2checkout 19 19 * Author URI: https://getwooplugins.com/
Note: See TracChangeset
for help on using the changeset viewer.