{"id":15150790,"url":"https://github.com/emranahmed/storepress-admin-utils","last_synced_at":"2026-02-01T16:01:28.370Z","repository":{"id":209488573,"uuid":"723715677","full_name":"EmranAhmed/storepress-admin-utils","owner":"EmranAhmed","description":"StorePress Admin Utils is a comprehensive PHP library for WordPress that simplifies the creation of admin interfaces for plugins. It provides a structured, object-oriented approach to building settings pages, managing plugin updates, handling rollbacks, and displaying administrative notices.","archived":false,"fork":false,"pushed_at":"2026-01-29T12:31:03.000Z","size":433,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-30T02:39:35.098Z","etag":null,"topics":["gutenberg-plugin","wordpress-development","wordpress-plugin"],"latest_commit_sha":null,"homepage":"https://packagist.org/packages/storepress/admin-utils","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EmranAhmed.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-11-26T14:53:15.000Z","updated_at":"2026-01-29T12:30:48.000Z","dependencies_parsed_at":"2025-12-31T00:06:06.905Z","dependency_job_id":null,"html_url":"https://github.com/EmranAhmed/storepress-admin-utils","commit_stats":{"total_commits":18,"total_committers":1,"mean_commits":18.0,"dds":0.0,"last_synced_commit":"69b5cb4b5a2b4625dbdb2a6bd3344c5e35fa5837"},"previous_names":["emranahmed/storepress-admin-utils"],"tags_count":38,"template":false,"template_full_name":null,"purl":"pkg:github/EmranAhmed/storepress-admin-utils","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmranAhmed%2Fstorepress-admin-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmranAhmed%2Fstorepress-admin-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmranAhmed%2Fstorepress-admin-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmranAhmed%2Fstorepress-admin-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EmranAhmed","download_url":"https://codeload.github.com/EmranAhmed/storepress-admin-utils/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmranAhmed%2Fstorepress-admin-utils/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28981893,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-01T15:35:50.179Z","status":"ssl_error","status_checked_at":"2026-02-01T15:35:38.075Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gutenberg-plugin","wordpress-development","wordpress-plugin"],"created_at":"2024-09-26T14:42:29.275Z","updated_at":"2026-02-01T16:01:28.362Z","avatar_url":"https://github.com/EmranAhmed.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# StorePress Admin Utils\n\nStorePress Admin Utils is a comprehensive PHP library for WordPress that simplifies the creation of admin interfaces for plugins. It provides a structured, object-oriented approach to building settings pages, managing plugin updates, handling rollbacks, and displaying administrative notices.\n\n## Core Features\n\n## Settings Framework\n\nThe library's cornerstone is its powerful settings framework, which allows developers to create complex settings pages with multiple tabs and a wide variety of field types.\n\n### Field Types\n\nIt supports a rich set of field types including `text`, `unit`, `textarea`, `checkbox`, `toggle`,`radio`, `select`, `color`, `number`, and more advanced fields like `toggle` switches and `group` fields.\n\n### Structure\n\nSettings are organized into sections and tabs, providing a clean and intuitive user experience. The framework handles the rendering of the entire settings page, including the navigation tabs, fields, and save/reset buttons.\n\n### Data Management \n\nIt streamlines the process of saving, retrieving, and deleting plugin options from the database. It also includes mechanisms for data sanitization and validation.\n\n## Plugin Updater\n\nStorePress Admin Utils includes a robust module for managing plugin updates from a custom, non-WordPress.org server.\n\n### Custom Update Server\n\nDevelopers can specify a URL to their own update server in the plugin's header. The library then communicates with this server to check for new versions.\n\n### Update Process\n\nIt handles the entire update process, from checking for new versions and displaying update notifications in the WordPress admin to downloading and installing the new plugin package. The `README.md` file provides a clear example of how to set up the server-side endpoint to respond to update requests.\n\n## Plugin Rollback\n\nA key feature is the ability to roll back a plugin to a previous version.\n\n## Simple DI Container\n\nSimple DI Container with singleton and factory support.\n\n### Rollback UI\n\nIt adds a \"Rollback\" link to the plugin's action links on the plugins page. This leads to a dedicated page where the user can select a previous version to install.\n\n### Version Management\n\nThe rollback functionality is tied into the update server, which must provide a list of available versions and their corresponding package URLs.\n\n## REST API Integration\n\nThe settings framework can automatically expose plugin settings via the WordPress REST API.\n\n### Endpoints\n\nIt creates REST API endpoints for fetching settings, allowing for headless WordPress implementations or integration with other applications.\n\n### Configuration\n\nDevelopers can easily enable or disable this feature and customize the API namespace and version.\n\n## Upgrade \u0026 Compatibility Notices\n\nThe library provides a class for managing admin notices, which is particularly useful for handling compatibility issues between a primary plugin and its extensions. \nIt can display notices in the admin area and on the plugins page if an incompatible version of an extension is detected.\n\n## Usage and Implementation\n\nTo use StorePress Admin Utils, developers typically extend the core classes provided by the library, such as `Settings`, `Updater`, and `Upgrade_Notice`. By implementing the abstract methods in these classes, developers can configure the library to suit their plugin's specific needs.\n\n## Installation\n\n```shell\ncomposer require storepress/admin-utils\n```\n\n## Plugin Directory Structure\n\n```\nexample/\n│\n├── example.php                            # Main plugin entry point, registers hooks, initializes Init class\n├── composer.json                          # Composer dependencies \u0026 PSR-4 autoloading configuration\n├── CLAUDE.md                              # AI assistant guidance for codebase conventions\n├── README.md                              # Plugin Readme file\n├── CHANGELOG.md                           # Plugin Changelog file\n│\n└── includes/                              # PHP source files (PSR-4: StorePress\\Example\\)\n    │\n    ├── Init.php                           # Plugin bootstrap: loads autoloader, registers/boots services\n    ├── functions.php                      # Utility functions.\n    │\n    ├── Features/                          # Feature modules\n    │   ├── Blocks.php                     # Gutenberg blocks.    \n    │\n    ├── Integrations/                      # Classes that integrate with WordPress/external systems\n    │   ├── AdminPage.php                  # Base settings page with sidebar and localized strings\n    │   ├── DeactivationFeedback.php       # Collects user feedback on plugin deactivation via dialog\n    │   ├── ProPluginInCompatibility.php   # Checks pro plugin version compatibility (v3.0.0+)\n    │   └── Updater.php                    # Handles plugin updates from custom server with rollback\n    │\n    ├── ServiceContainers/                 # Dependency injection\n    │   └── ServiceContainer.php           # DI container singleton for registering/resolving services\n    │\n    ├── ServiceProviders/                  # Service registration \u0026 bootstrapping\n    │   └── ServiceProvider.php            # Registers all services and boots them in correct order\n    │\n    └── Services/                          # Business logic services\n        └── Settings.php                   # Defines admin settings tabs and fields (General, Basic, Advanced, Rest)\n```\n\n## Usage\n\n### Plugin entry file.\n\n```php\n\u003c?php\n  /**\n  Plugin Name: Plugin Example\n  Plugin URI: https://storepress.com/plugins/plugin-example/\n  Description: Example Plugin.\n  Author: Emran Ahmed\n  Version: 1.0.0\n  Tested up to: 6.3\n  Author URI: https://storepress.com/emran/\n  Update URI: http://sites.local/\n  */\n  \n  defined( 'ABSPATH' ) || die( 'Keep Silent' );\n  \n  use StorePress\\Example\\Init;\n  \n  // Include the main class.\n  if ( ! class_exists( Init::class, false ) ) {\n    require_once __DIR__ . '/includes/Init.php';\n  }\n  \n  /**\n   * Plugin class init\n   *\n   * @return Init\n   */\n  function plugin_example(): Init {\n    return Init::instance(__FILE__);\n  }\n  \n  add_action( 'plugins_loaded', 'plugin_example' );\n```\n\n### Sample `Init.php` file\n\n```php\n\u003c?php\n\t/**\n\t * Plugin Initialization Class File.\n\t *\n\t * Handles plugin bootstrap, dependency loading, and service provider initialization.\n\t *\n\t * @package    StorePress/B\n\t * @since      1.0.0\n\t * @version    1.0.0\n\t */\n\n\tdeclare( strict_types=1 );\n\n\tnamespace StorePress\\Example;\n\n\tdefined( 'ABSPATH' ) || die( 'Keep Silent' );\n\t\n\tuse StorePress\\Example\\ServiceContainers\\ServiceContainer;\n\tuse StorePress\\Example\\ServiceProviders\\ServiceProvider;\n\t\n\t/**\n\t * Plugin Initialization Class.\n\t *\n\t * Bootstraps the plugin by loading vendor autoloaders, registering the service provider,\n\t * and initializing hooks. Uses the singleton pattern to ensure only one instance exists.\n\t *\n\t * @name Init\n\t *\n\t * @example\n\t * // Initialize the plugin from main plugin file.\n\t * Init::instance( __FILE__ );\n\t *\n\t * @example\n\t * // Access the service container.\n\t * $container = Init::instance( __FILE__ )-\u003eget_container();\n\t *\n\t * @example\n\t * // Get the plugin file path.\n\t * $plugin_file = plugin_b()-\u003eget_plugin_file();\n\t */\n\tclass Init {\n\n\t\t// =====================================================================\n\t\t// Properties\n\t\t// =====================================================================\n\n\t\t/**\n\t\t * Plugin file path.\n\t\t *\n\t\t * Stores the absolute path to the main plugin file.\n\t\t *\n\t\t * @var string\n\t\t */\n\t\tprotected string $plugin_file;\n\n\t\t// =====================================================================\n\t\t// Singleton Instance\n\t\t// =====================================================================\n\n\t\t/**\n\t\t * Return singleton instance of the Init class.\n\t\t *\n\t\t * The instance will be created if it does not exist yet.\n\t\t *\n\t\t * @param string $plugin_file The absolute path to the main plugin file.\n\t\t *\n\t\t * @return self The singleton instance.\n\t\t *\n\t\t * @since 1.0.0\n\t\t *\n\t\t * @example\n\t\t * // Get or create the singleton instance.\n\t\t * $init = Init::instance( __FILE__ );\n\t\t *\n\t\t * @example\n\t\t * // Access from global function.\n\t\t * function plugin_b(): Init {\n\t\t *     return Init::instance( __FILE__ );\n\t\t * }\n\t\t */\n\t\tpublic static function instance( string $plugin_file ): self {\n\t\t\tstatic $instance = null;\n\t\t\treturn $instance ??= new self( $plugin_file );\n\t\t}\n\n\t\t// =====================================================================\n\t\t// Constructor\n\t\t// =====================================================================\n\n\t\t/**\n\t\t * Initialize the plugin.\n\t\t *\n\t\t * Loads vendor autoloaders and functions, registers the service provider,\n\t\t * boots the service provider, and runs initialization hooks.\n\t\t *\n\t\t * @param string $plugin_file The absolute path to the main plugin file.\n\t\t *\n\t\t * @since 1.0.0\n\t\t *\n\t\t * @see Init::includes()          Loads required files.\n\t\t * @see Init::service_provider()  Gets the service provider instance.\n\t\t * @see Init::hooks()             Registers WordPress hooks.\n\t\t */\n\t\tpublic function __construct( string $plugin_file ) {\n\n\t\t\t$this-\u003eplugin_file = $plugin_file;\n\n\t\t\t$this-\u003eincludes();\n\n\t\t\t$this-\u003eservice_provider()-\u003eregister();\n\n\t\t\t$this-\u003eservice_provider()-\u003eboot();\n\n\t\t\t$this-\u003ehooks();\n\t\t}\n\n\t\t// =====================================================================\n\t\t// File Loading Methods\n\t\t// =====================================================================\n\n\t\t/**\n\t\t * Load required files.\n\t\t *\n\t\t * Includes the vendor autoload_packages.php file if it exists and the\n\t\t * plugin functions.php file for utility functions.\n\t\t *\n\t\t * @return void\n\t\t *\n\t\t * @since 1.0.0\n\t\t *\n\t\t * @see Init::get_plugin_file() Gets the plugin file path.\n\t\t *\n\t\t * @example\n\t\t * // Files loaded:\n\t\t * // - vendor/autoload_packages.php (if exists)\n\t\t * // - includes/functions.php\n\t\t */\n\t\tpublic function includes(): void {\n\t\t\t$vendor_path = untrailingslashit( plugin_dir_path( $this-\u003eget_plugin_file() ) ) . '/vendor';\n\n\t\t\tif ( file_exists( $vendor_path . '/autoload_packages.php' ) ) {\n\t\t\t\trequire_once $vendor_path . '/autoload_packages.php';\n\t\t\t}\n\n\t\t\trequire_once __DIR__ . '/functions.php';\n\t\t}\n\n\t\t// =====================================================================\n\t\t// Getter Methods\n\t\t// =====================================================================\n\n\t\t/**\n\t\t * Get the plugin file path.\n\t\t *\n\t\t * Returns the absolute path to the main plugin file, useful for\n\t\t * deriving plugin directory, URL, basename, and version.\n\t\t *\n\t\t * @return string The absolute path to the main plugin file.\n\t\t *\n\t\t * @since 1.0.0\n\t\t *\n\t\t * @example\n\t\t * // Get the plugin file path.\n\t\t * $file = $init-\u003eget_plugin_file();\n\t\t * // Returns: /path/to/wp-content/plugins/plugin-b/plugin-b.php\n\t\t *\n\t\t * @example\n\t\t * // Derive plugin directory.\n\t\t * $dir = plugin_dir_path( $init-\u003eget_plugin_file() );\n\t\t *\n\t\t * @example\n\t\t * // Derive plugin URL.\n\t\t * $url = plugin_dir_url( $init-\u003eget_plugin_file() );\n\t\t *\n\t\t * @example\n\t\t * // Get plugin basename.\n\t\t * $basename = plugin_basename( $init-\u003eget_plugin_file() );\n\t\t * // Returns: plugin-b/plugin-b.php\n\t\t */\n\t\tpublic function get_plugin_file(): string {\n\t\t\treturn $this-\u003eplugin_file;\n\t\t}\n\n\t\t// =====================================================================\n\t\t// Hook Methods\n\t\t// =====================================================================\n\n\t\t/**\n\t\t * Register WordPress hooks.\n\t\t *\n\t\t * Hook into WordPress actions and filters for plugin functionality.\n\t\t * This method is intended to be extended with additional hook registrations\n\t\t * as the plugin grows.\n\t\t *\n\t\t * @return void\n\t\t *\n\t\t * @since 1.0.0\n\t\t *\n\t\t * @example\n\t\t * // Override in subclass or extend with hooks:\n\t\t * public function hooks(): void {\n\t\t *     add_action( 'init', array( $this, 'register_post_types' ) );\n\t\t *     add_filter( 'plugin_action_links', array( $this, 'add_settings_link' ) );\n\t\t * }\n\t\t */\n\t\tpublic function hooks(): void {}\n\n\t\t// =====================================================================\n\t\t// Service Container Methods\n\t\t// =====================================================================\n\n\t\t/**\n\t\t * Get the service provider instance.\n\t\t *\n\t\t * Returns the singleton instance of ServiceProvider which manages\n\t\t * dependency injection and service registration for the plugin.\n\t\t *\n\t\t * @return ServiceProvider The service provider instance.\n\t\t *\n\t\t * @since 1.0.0\n\t\t *\n\t\t * @see ServiceProvider::instance() Creates or returns the provider instance.\n\t\t *\n\t\t * @example\n\t\t * // Access the service provider.\n\t\t * $provider = $init-\u003eservice_provider();\n\t\t *\n\t\t * @example\n\t\t * // Register a new service.\n\t\t * $init-\u003eservice_provider()-\u003eregister();\n\t\t *\n\t\t * @example\n\t\t * // Boot all registered services.\n\t\t * $init-\u003eservice_provider()-\u003eboot();\n\t\t */\n\t\tpublic function service_provider(): ServiceProvider {\n\t\t\treturn ServiceProvider::instance( $this );\n\t\t}\n\n\t\t/**\n\t\t * Get the dependency injection container.\n\t\t *\n\t\t * Provides access to the service container for resolving dependencies\n\t\t * registered with the service provider.\n\t\t *\n\t\t * @return ServiceContainer The dependency injection container.\n\t\t *\n\t\t * @since 1.0.0\n\t\t *\n\t\t * @see Init::service_provider()       Gets the service provider.\n\t\t * @see ServiceProvider::get_container() Gets the container from provider.\n\t\t *\n\t\t * @example\n\t\t * // Get a registered service.\n\t\t * $settings = $init-\u003eget_container()-\u003eget( Settings::class );\n\t\t *\n\t\t * @example\n\t\t * // Check if a service is registered.\n\t\t * if ( $init-\u003eget_container()-\u003ehas( Updater::class ) ) {\n\t\t *     $updater = $init-\u003eget_container()-\u003eget( Updater::class );\n\t\t * }\n\t\t *\n\t\t * @example\n\t\t * // Access from global function.\n\t\t * $container = plugin_b()-\u003eget_container();\n\t\t * $settings = $container-\u003eget( Settings::class );\n\t\t */\n\t\tpublic function get_container(): ServiceContainer {\n\t\t\t return $this-\u003eservice_provider()-\u003eget_container();\n\t\t}\n\t}\n```\n\n### `AbstractSettings` class usages example\n\n```php\n\u003c?php\n\t\n\tnamespace StorePress\\Example\\Integrations;\n\t\n\tdefined( 'ABSPATH' ) || die( 'Keep Silent' );\n\t\n\tuse StorePress\\AdminUtils\\Abstracts\\AbstractSettings;\n\t\n\tclass AdminPage extends AbstractSettings {\n\t\t\n\t\tpublic function settings_id(): string {\n\t\t\treturn 'example-plugin-settings';\n\t\t}\n\t\t\n\t\tpublic function get_default_sidebar(): void {\n\t\t\techo 'Hello from default sidebar';\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic function localize_strings(): array {\n\t\t\treturn array(\n\t\t\t\t'unsaved_warning_text'            =\u003e 'The changes you made will be lost if you navigate away from this page.',\n\t\t\t\t'reset_warning_text'              =\u003e 'Are you sure to reset?',\n\t\t\t\t'reset_button_text'               =\u003e 'Reset All',\n\t\t\t\t'settings_link_text'              =\u003e 'Settings',\n\t\t\t\t'settings_error_message_text'     =\u003e 'Settings not saved',\n\t\t\t\t'settings_updated_message_text'   =\u003e 'Settings Saved',\n\t\t\t\t'settings_deleted_message_text'   =\u003e 'Settings Reset',\n\t\t\t\t'settings_tab_not_available_text' =\u003e 'Settings Tab is not available.',\n\t\t\t);\n\t\t}\n\t\t\n\t\t\n\t\t\n\t\t   // Adding custom scripts.\n    public function enqueue_scripts(): void {\n        parent::enqueue_scripts();\n        if ( $this-\u003ehas_field_type( 'wc-enhanced-select' ) ) {\n            wp_enqueue_style( 'woocommerce_admin_styles' );\n            wp_enqueue_script( 'wc-enhanced-select' );\n        }\n    }\n    \n    // Adding Custom TASK: \n    public function get_custom_action_uri(): string {\n       return wp_nonce_url( $this-\u003eget_settings_uri( array( 'action' =\u003e 'custom-action' ) ), $this-\u003eget_nonce_action() );\n    }\n    \n    // Task: 02\n    public function process_actions($current_action): void{\n    \n        parent::process_actions($current_action);\n      \n        if ( 'custom-action' === $current_action ) {\n          $this-\u003eprocess_action_custom();\n        }\n    }\n    \n    // Task: 03\n    public function process_action_custom(): void{\n        check_admin_referer( $this-\u003eget_nonce_action() );\n        \n        \n        \n        // Process your task.\n        \n        \n        \n        wp_safe_redirect( $this-\u003eget_action_uri( array( 'message' =\u003e 'custom-action-done' ) ) ); \n        exit;\n    }\n    \n    // Task: 04\n    public function settings_messages(): void{\n      \n      parent::settings_messages();\n      \n      $message = $this-\u003eget_message_query_arg_value();\n      \n      if ( 'custom-action-done' === $message ) {\n          $this-\u003eadd_settings_message( 'Custom action done successfully.' );\n      }\n      \n      if ( 'custom-action-fail' === $message ) {\n          $this-\u003eadd_settings_message( 'Custom action failed.', 'error' );\n      }\n    }\n\t}\n```\n\n```php\n\u003c?php\n\t\n\tnamespace StorePress\\Example\\Services;\n\t\n\tdefined( 'ABSPATH' ) || die( 'Keep Silent' );\n\t\n\tuse StorePress\\AdminUtils\\Traits\\CallerTrait;\n\tuse StorePress\\AdminUtils\\Traits\\SingletonTrait;\n\tuse StorePress\\Example\\Init;\n\tuse StorePress\\Example\\Integrations\\AdminPage;\n\t\n\t/**\n\t * Admin Menu Class.\n\t *\n\t * @name Settings\n\t * @phpstan-use CallerTrait\u003cInit\u003e\n\t * @method Init get_caller()\n\t */\n\t\n\tclass Settings extends AdminPage {\n\t\t\n\t\tuse SingletonTrait;\n\t\t\n\t\tpublic function add_settings(): array {\n\t\t\treturn array(\n\t\t\t\t'general' =\u003e 'General',\n\t\t\t\t\n\t\t\t\t//'pure' =\u003e 'Pure',\n\t\t\t\t'basic'   =\u003e array(\n\t\t\t\t\t'name'     =\u003e 'Basic',\n\t\t\t\t\t'sidebar'  =\u003e 25,\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t'advance' =\u003e array(\n\t\t\t\t\t'name'     =\u003e 'Advanced',\n\t\t\t\t\t'icon'     =\u003e 'dashicons dashicons-analytics',\n\t\t\t\t\t'sidebar'  =\u003e false,\n\t\t\t\t\t'hidden'   =\u003e false,\n\t\t\t\t\t'external' =\u003e false,\n\t\t\t\t),\n\t\t\t\t'rest' =\u003e 'Rest',\n\t\t\t);\n\t\t}\n\t\t\n\t\t// Naming Convention: add_\u003cTAB ID\u003e_settings_page()\n    public function add_basic_settings_page() {\n        echo 'custom page ui';\n    }\n\t\t\n\t\tpublic function add_general_settings_fields() {\n\t\t\treturn array(\n\t\t\t\tarray(\n\t\t\t\t\t'type'        =\u003e 'section',\n\t\t\t\t\t'title'       =\u003e 'Section title',\n\t\t\t\t\t'description' =\u003e 'Section description',\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'field-text-mn',\n\t\t\t\t\t'type'        =\u003e 'text',\n\t\t\t\t\t'title'       =\u003e 'Input Type text',\n\t\t\t\t\t'description' =\u003e 'Input Description',\n\t\t\t\t\t'placeholder' =\u003e 'Placeholder',\n\t\t\t\t\t'default'     =\u003e 'text field default',\n\t\t\t\t\t'suffix'      =\u003e 'px',\n\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t'add_tag'     =\u003e array('PRO'),\n\t\t\t\t\t// 'condition' =\u003e array('selector'=\u003e$this-\u003eget_field_selector('grps')),\n\t\t\t\t\t// 'html_datalist' =\u003e array('yes','no'),\n\t\t\t\t\t// 'show_in_rest'    =\u003e array( 'name' =\u003e 'custom_rest_id' ),\n\t\t\t\t\t// 'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'grps',\n\t\t\t\t\t'type'        =\u003e 'toggle',\n\t\t\t\t\t'title'       =\u003e 'Show Grpups',\n\t\t\t\t\t'default'     =\u003e 'no',\n\t\t\t\t\t'tooltip'      =\u003e 'Textarea Help tooltip',\n\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t'add_tag'    =\u003e array('NEW', '#d63639'),\n\t\t\t\t\t// 'options'=\u003earray('key'=\u003e 'value','key2'=\u003e 'value2')\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'condition'=\u003earray('selector'=\u003e$this-\u003eget_field_selector('grps')),\n\t\t\t\t\t'id'          =\u003e 'input_group',\n\t\t\t\t\t'type'        =\u003e 'group',\n\t\t\t\t\t// 'show_in_rest'        =\u003e false,\n\t\t\t\t\t'title'       =\u003e 'Input text 01 general',\n\t\t\t\t\t'description' =\u003e 'Input desc of 01',\n\t\t\t\t\t'tooltip'      =\u003e 'Input Group Help Tooltip',\n\t\t\t\t\t'fields'      =\u003e array(\n\t\t\t\t\t\t\n\t\t\t\t\t\tarray(\n\t\t\t\t\t\t\t'id'          =\u003e 'inputaxxx',\n\t\t\t\t\t\t\t'type'        =\u003e 'text',\n\t\t\t\t\t\t\t'title'       =\u003e 'Single Toggle',\n\t\t\t\t\t\t\t'placeholder' =\u003e 'Abcd',\n\t\t\t\t\t\t\t'default'     =\u003e 'yes',\n\t\t\t\t\t\t\t'html_datalist'=\u003earray('yes','no'),\n\t\t\t\t\t\t\t'class'=\u003earray('large-text'),\n\t\t\t\t\t\t\t'tooltip'      =\u003e 'Textarea Help tooltip',\n\t\t\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t\t),\n\t\t\t\t\t\t\n\t\t\t\t\t\tarray(\n\t\t\t\t\t\t\t'id'          =\u003e 'field-color',\n\t\t\t\t\t\t\t'type'        =\u003e 'color',\n\t\t\t\t\t\t\t'title'       =\u003e 'Input Type Color',\n\t\t\t\t\t\t\t'description' =\u003e 'Input Type Color',\n\t\t\t\t\t\t\t'placeholder' =\u003e 'Placeholder',\n\t\t\t\t\t\t\t'default'     =\u003e '#ffccff',\n\t\t\t\t\t\t\t'html_datalist'=\u003earray('#dddddd','#eeeeee'),\n\t\t\t\t\t\t\t'tooltip'      =\u003e 'Textarea Help tooltip',\n\t\t\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t\t\t// 'required'    =\u003e true,\n\t\t\t\t\t\t\t//'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t\t\t),\n\t\t\t\t\t\t\n\t\t\t\t\t\tarray(\n\t\t\t\t\t\t\t'id'          =\u003e 'inputakk',\n\t\t\t\t\t\t\t'type'        =\u003e 'unit',\n\t\t\t\t\t\t\t'title'       =\u003e 'Single Unit',\n\t\t\t\t\t\t\t'placeholder' =\u003e '',\n\t\t\t\t\t\t\t'default'     =\u003e '20px',\n\t\t\t\t\t\t\t'units'=\u003e     array('%','px'),\n\t\t\t\t\t\t\t'tooltip'      =\u003e 'Textarea Help tooltip',\n\t\t\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t\t),\n\t\t\t\t\t\t\n\t\t\t\t\t\tarray(\n\t\t\t\t\t\t\t'id'          =\u003e 'inputas',\n\t\t\t\t\t\t\t'type'        =\u003e 'toggle',\n\t\t\t\t\t\t\t'title'       =\u003e 'Single Toggle',\n\t\t\t\t\t\t\t'placeholder' =\u003e 'Abcd',\n\t\t\t\t\t\t\t'default'     =\u003e 'no',\n\t\t\t\t\t\t\t'tooltip'      =\u003e 'Textarea Help tooltip',\n\t\t\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t\t\t//'options'=\u003earray('X', 'Y', 'Z'),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tarray(\n\t\t\t\t\t\t\t'id'          =\u003e 'input2',\n\t\t\t\t\t\t\t'type'        =\u003e 'checkbox',\n\t\t\t\t\t\t\t'title'       =\u003e 'Single Checkbox',\n\t\t\t\t\t\t\t'placeholder' =\u003e 'Abcd',\n\t\t\t\t\t\t\t'default'     =\u003e 'yes',\n\t\t\t\t\t\t\t'tooltip'      =\u003e 'Textarea Help tooltip',\n\t\t\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tarray(\n\t\t\t\t\t\t\t//'show_in_rest'    =\u003e false,\n\t\t\t\t\t\t\t'condition'=\u003earray('selector'=\u003e$this-\u003eget_group_field_selector('input_group','inputas')),\n\t\t\t\t\t\t\t'id'                =\u003e 'input5',\n\t\t\t\t\t\t\t'type'              =\u003e 'number',\n\t\t\t\t\t\t\t'title'             =\u003e 'Width WW',\n\t\t\t\t\t\t\t'description'       =\u003e 'Input desc of 01',\n\t\t\t\t\t\t\t'placeholder'       =\u003e 'Abcd',\n\t\t\t\t\t\t\t'default'           =\u003e '100',\n\t\t\t\t\t\t\t'suffix'            =\u003e 'x',\n\t\t\t\t\t\t\t'sanitize_callback' =\u003e 'absint',\n\t\t\t\t\t\t\t'html_attributes'   =\u003e array( 'min' =\u003e 10 ),\n\t\t\t\t\t\t\t'tooltip'      =\u003e 'Textarea Help tooltip',\n\t\t\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tarray(\n\t\t\t\t\t\t\t//'show_in_rest'    =\u003e false,\n\t\t\t\t\t\t\t'id'              =\u003e 'input45',\n\t\t\t\t\t\t\t'type'            =\u003e 'textarea',\n\t\t\t\t\t\t\t'title'           =\u003e 'Width',\n\t\t\t\t\t\t\t'description'     =\u003e 'Input desc of 01',\n\t\t\t\t\t\t\t'placeholder'     =\u003e 'Abcd',\n\t\t\t\t\t\t\t'default'         =\u003e '100',\n\t\t\t\t\t\t\t'suffix'          =\u003e 'x',\n\t\t\t\t\t\t\t'html_attributes' =\u003e array( 'min' =\u003e 10 ),\n\t\t\t\t\t\t\t'tooltip'      =\u003e 'Textarea Help tooltip',\n\t\t\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t\t),\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tarray(\n\t\t\t\t\t\t\t'id'              =\u003e 'inputse2xx',\n\t\t\t\t\t\t\t'type'            =\u003e 'select',\n\t\t\t\t\t\t\t'title'           =\u003e 'Int value',\n\t\t\t\t\t\t\t'description'     =\u003e 'Input desc of 01\u003ccode\u003erxxx\u003c/code\u003e',\n\t\t\t\t\t\t\t// 'default'     =\u003e array( 'home3', 'home1' ),\n\t\t\t\t\t\t\t// 'multiple'    =\u003e true,\n\t\t\t\t\t\t\t'default'         =\u003e '2',\n\t\t\t\t\t\t\t'class'=\u003earray('x', 'y'),\n\t\t\t\t\t\t\t'tooltip'      =\u003e 'Textarea Help tooltip',\n\t\t\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t\t\t'html_attributes' =\u003e array( 'data-demo' =\u003e true ),\n\t\t\t\t\t\t\t'options'         =\u003e array(\n\t\t\t\t\t\t\t\t'1' =\u003e 'Home One',\n\t\t\t\t\t\t\t\t'2' =\u003e 'Home Two',\n\t\t\t\t\t\t\t\t'3' =\u003e 'Home three',\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t),\n\t\t\t\t\t\t\n\t\t\t\t\t\tarray(\n\t\t\t\t\t\t\t'id'          =\u003e 'input_wi',\n\t\t\t\t\t\t\t'type'        =\u003e 'radio',\n\t\t\t\t\t\t\t'title'       =\u003e 'Width X',\n\t\t\t\t\t\t\t'placeholder' =\u003e 'Abcd',\n\t\t\t\t\t\t\t'default'     =\u003e 'y',\n\t\t\t\t\t\t\t'options'     =\u003e array(\n\t\t\t\t\t\t\t\t'x' =\u003e 'Home X',\n\t\t\t\t\t\t\t\t'y' =\u003e 'Home Y',\n\t\t\t\t\t\t\t\t'z' =\u003e 'Home Z',\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t'tooltip'      =\u003e 'Textarea Help tooltip',\n\t\t\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tarray(\n\t\t\t\t\t\t\t'id'      =\u003e 'input_wx',\n\t\t\t\t\t\t\t'type'    =\u003e 'checkbox',\n\t\t\t\t\t\t\t'title'   =\u003e 'Multi Checkbox',\n\t\t\t\t\t\t\t'default' =\u003e array( 'y', 'z' ),\n\t\t\t\t\t\t\t'options' =\u003e array(\n\t\t\t\t\t\t\t\t'x' =\u003e 'Home X',\n\t\t\t\t\t\t\t\t'y' =\u003e 'Home Y',\n\t\t\t\t\t\t\t\t'z' =\u003e 'Home Z',\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t'tooltip'      =\u003e 'Textarea Help tooltip',\n\t\t\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t\t),\n\t\t\t\t\t\t\n\t\t\t\t\t\tarray(\n\t\t\t\t\t\t\t'id'      =\u003e 'input_wewdsf',\n\t\t\t\t\t\t\t'type'    =\u003e 'toggle',\n\t\t\t\t\t\t\t'title'   =\u003e 'Multi Toggle Checkbox',\n\t\t\t\t\t\t\t'default' =\u003e array( 'y', 'z' ),\n\t\t\t\t\t\t\t'options' =\u003e array(\n\t\t\t\t\t\t\t\t'x' =\u003e 'Home X',\n\t\t\t\t\t\t\t\t'y' =\u003e 'Home Y',\n\t\t\t\t\t\t\t\t'z' =\u003e 'Home Z',\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t'tooltip'      =\u003e 'Textarea Help tooltip',\n\t\t\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t////////////\n\t\t\t\tarray(\n\t\t\t\t\t'id'           =\u003e 'field-password',\n\t\t\t\t\t'type'         =\u003e 'password',\n\t\t\t\t\t'title'        =\u003e 'Input Type Password',\n\t\t\t\t\t'description'  =\u003e 'Input Description',\n\t\t\t\t\t'placeholder'  =\u003e 'Placeholder',\n\t\t\t\t\t'default'      =\u003e 'text field default',\n\t\t\t\t\t//'suffix'       =\u003e 'px',\n\t\t\t\t\t'required'     =\u003e true,\n\t\t\t\t\t'tooltip'      =\u003e 'Password Help tooltip',\n\t\t\t\t\t'condition'=\u003earray('selector'=\u003e$this-\u003eget_field_selector('field-textarea')),\n\t\t\t\t\t\n\t\t\t\t\t//'show_in_rest' =\u003e array( 'name' =\u003e 'custom_rest_id' ),\n\t\t\t\t\t//'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'           =\u003e 'field-textarea',\n\t\t\t\t\t'type'         =\u003e 'textarea',\n\t\t\t\t\t'title'        =\u003e 'Input Type text',\n\t\t\t\t\t'description'  =\u003e 'Input Description',\n\t\t\t\t\t'placeholder'  =\u003e 'Placeholder',\n\t\t\t\t\t'default'      =\u003e '',\n\t\t\t\t\t'suffix'       =\u003e 'px',\n\t\t\t\t\t'required'     =\u003e true,\n\t\t\t\t\t'tooltip'      =\u003e 'Textarea Help tooltip',\n\t\t\t\t\t//'show_in_rest' =\u003e array( 'name' =\u003e 'custom_rest_id' ),\n\t\t\t\t\t//'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'field-text',\n\t\t\t\t\t'type'        =\u003e 'text',\n\t\t\t\t\t'title'       =\u003e 'Input Type text',\n\t\t\t\t\t'description' =\u003e 'Input Description',\n\t\t\t\t\t'placeholder' =\u003e 'Placeholder',\n\t\t\t\t\t'default'     =\u003e 'text field default',\n\t\t\t\t\t'suffix'      =\u003e 'px',\n\t\t\t\t\t'required'    =\u003e true,\n\t\t\t\t\t// 'html_datalist'=\u003earray('yes','no'),\n\t\t\t\t\t// 'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'field-number',\n\t\t\t\t\t'type'        =\u003e 'number',\n\t\t\t\t\t'title'       =\u003e 'Input Type Number',\n\t\t\t\t\t'description' =\u003e 'Input Type Number',\n\t\t\t\t\t'placeholder' =\u003e '',\n\t\t\t\t\t'default'     =\u003e '1',\n\t\t\t\t\t'suffix'      =\u003e 'px',\n\t\t\t\t\t// 'required'    =\u003e true,\n\t\t\t\t\t// 'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t///////\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'field-color',\n\t\t\t\t\t'type'        =\u003e 'color',\n\t\t\t\t\t'title'       =\u003e 'Input Type Color',\n\t\t\t\t\t'description' =\u003e 'Input Type Color',\n\t\t\t\t\t'placeholder' =\u003e 'Placeholder',\n\t\t\t\t\t'default'     =\u003e '#ffccff',\n\t\t\t\t\t'html_datalist'=\u003earray('#dddddd','#eeeeee'),\n\t\t\t\t\t// 'required'    =\u003e true,\n\t\t\t\t\t// 'show_in_rest'    =\u003e 'fieldColor',\n\t\t\t\t\t// 'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'field-radio',\n\t\t\t\t\t'type'        =\u003e 'radio',\n\t\t\t\t\t'title'       =\u003e 'Input Type Radio',\n\t\t\t\t\t'description' =\u003e 'Input Type Radio',\n\t\t\t\t\t'placeholder' =\u003e 'Placeholder',\n\t\t\t\t\t'default'     =\u003e 'y',\n\t\t\t\t\t'options'     =\u003e array(\n\t\t\t\t\t\t'x' =\u003e 'Home X',\n\t\t\t\t\t\t'y' =\u003e 'Home Y',\n\t\t\t\t\t\t'z' =\u003e 'Home Z',\n\t\t\t\t\t)\n\t\t\t\t\t// 'required'    =\u003e true,\n\t\t\t\t\t// 'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t// license\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'license',\n\t\t\t\t\t'type'        =\u003e 'code',\n\t\t\t\t\t'title'       =\u003e 'License',\n\t\t\t\t\t'private'     =\u003e true,\n\t\t\t\t\t'show_in_rest' =\u003e false,\n\t\t\t\t\t'description' =\u003e 'Input for license',\n\t\t\t\t\t'placeholder' =\u003e 'xxxx-xxxx-xxxx',\n\t\t\t\t\t//'class'       =\u003e 'code'\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'input-single-check',\n\t\t\t\t\t'type'        =\u003e 'checkbox',\n\t\t\t\t\t'title'       =\u003e 'Single Checkbox Full',\n\t\t\t\t\t'description' =\u003e 'Single Checkbox Full desc',\n\t\t\t\t\t'default'     =\u003e 'yes',\n\t\t\t\t\t'full_width'=\u003etrue,\n\t\t\t\t\t'add_tag'    =\u003e array('NEW', '#d63639'),\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'input-single-toggle',\n\t\t\t\t\t'type'        =\u003e 'toggle',\n\t\t\t\t\t'title'       =\u003e 'Single Toggle Full',\n\t\t\t\t\t'description' =\u003e 'Single Checkbox Full desc',\n\t\t\t\t\t'default'     =\u003e 'yes',\n\t\t\t\t\t// 'full_width'=\u003etrue\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'      =\u003e 'input-multi-check',\n\t\t\t\t\t'type'    =\u003e 'checkbox',\n\t\t\t\t\t'title'   =\u003e 'Multiple Checkbox Full',\n\t\t\t\t\t'description' =\u003e 'Multiple Checkbox  Full desc',\n\t\t\t\t\t'default' =\u003e 'yes',\n\t\t\t\t\t'options' =\u003e array(\n\t\t\t\t\t\t'x'     =\u003e 'Home X',\n\t\t\t\t\t\t'y'     =\u003e 'Home Y',\n\t\t\t\t\t\t'new'   =\u003e array(\n\t\t\t\t\t\t\t'label'       =\u003e 'New',\n\t\t\t\t\t\t\t'description' =\u003e 'New Item',\n\t\t\t\t\t\t),\n\t\t\t\t\t\t'z'     =\u003e 'Home Z',\n\t\t\t\t\t\t'alpha' =\u003e 'Alpha',\n\t\t\t\t\t\t'yes' =\u003e 'YES',\n\t\t\t\t\t\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'      =\u003e 'input-multi-check-toggle',\n\t\t\t\t\t'type'    =\u003e 'toggle',\n\t\t\t\t\t'title'   =\u003e 'Multiple Toggle Full',\n\t\t\t\t\t'default' =\u003e 'yes',\n\t\t\t\t\t'options' =\u003e array(\n\t\t\t\t\t\t'x'     =\u003e 'Home X',\n\t\t\t\t\t\t'new'   =\u003e array(\n\t\t\t\t\t\t\t'label'       =\u003e 'New',\n\t\t\t\t\t\t\t'description' =\u003e 'New Item',\n\t\t\t\t\t\t),\n\t\t\t\t\t\t'y'     =\u003e 'Home Y',\n\t\t\t\t\t\t'z'     =\u003e 'Home Z',\n\t\t\t\t\t\t'alpha' =\u003e 'Alpha',\n\t\t\t\t\t)\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'inputr',\n\t\t\t\t\t'type'        =\u003e 'radio',\n\t\t\t\t\t'title'       =\u003e 'Input text 01 general',\n\t\t\t\t\t'description' =\u003e 'Input desc of 01',\n\t\t\t\t\t'default'     =\u003e 'home2',\n\t\t\t\t\t'options'     =\u003e array(\n\t\t\t\t\t\t'home'  =\u003e 'Home One',\n\t\t\t\t\t\t'home2' =\u003e 'Home Twos',\n\t\t\t\t\t)\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'inputc',\n\t\t\t\t\t'type'        =\u003e 'checkbox',\n\t\t\t\t\t'title'       =\u003e 'Input text 01 general single checkbox',\n\t\t\t\t\t'description' =\u003e 'Input desc of 01',\n\t\t\t\t\t'default'     =\u003e 'home3',\n\t\t\t\t\t'options'     =\u003e array(\n\t\t\t\t\t\t'home1' =\u003e 'Home One',\n\t\t\t\t\t\t'home3' =\u003e 'Home 3',\n\t\t\t\t\t\t'home2' =\u003e 'Home 2',\n\t\t\t\t\t)\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'              =\u003e 'inputse',\n\t\t\t\t\t'type'            =\u003e 'wc-enhanced-select',\n\t\t\t\t\t'title'           =\u003e '2 Input text 01 general single selectbox',\n\t\t\t\t\t'description'     =\u003e 'Input desc of 01\u003ccode\u003exxx\u003c/code\u003e',\n\t\t\t\t\t// 'default'     =\u003e array( 'home3', 'home1' ),\n\t\t\t\t\t// 'multiple'    =\u003e true,\n\t\t\t\t\t'default'         =\u003e 'home3',\n\t\t\t\t\t'class'=\u003earray('x', 'y'),\n\t\t\t\t\t'html_attributes' =\u003e array( 'data-demo' =\u003e true ),\n\t\t\t\t\t'options'         =\u003e array(\n\t\t\t\t\t\t'home1' =\u003e 'Home One',\n\t\t\t\t\t\t'home3' =\u003e 'Home 3',\n\t\t\t\t\t\t'home2' =\u003e 'Home 2',\n\t\t\t\t\t)\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'              =\u003e 'inputse2xx',\n\t\t\t\t\t'type'            =\u003e 'wc-enhanced-select',\n\t\t\t\t\t'title'           =\u003e 'Int value',\n\t\t\t\t\t'description'     =\u003e 'Input desc of 01\u003ccode\u003erxxx\u003c/code\u003e',\n\t\t\t\t\t// 'default'     =\u003e array( 'home3', 'home1' ),\n\t\t\t\t\t// 'multiple'    =\u003e true,\n\t\t\t\t\t'default'         =\u003e '2',\n\t\t\t\t\t'class'=\u003earray('x', 'y'),\n\t\t\t\t\t'html_attributes' =\u003e array( 'data-demo' =\u003e true ),\n\t\t\t\t\t'options'         =\u003e array(\n\t\t\t\t\t\t'1' =\u003e 'Home One',\n\t\t\t\t\t\t'2' =\u003e 'Home Two',\n\t\t\t\t\t\t'3' =\u003e 'Home three',\n\t\t\t\t\t)\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'input2',\n\t\t\t\t\t'type'        =\u003e 'text',\n\t\t\t\t\t'title'       =\u003e 'Input text 02',\n\t\t\t\t\t'description' =\u003e 'Input desc of 02',\n\t\t\t\t\t'default'     =\u003e '',\n\t\t\t\t\t'placeholder' =\u003e 'Abcd 02'\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'inputunit',\n\t\t\t\t\t'type'        =\u003e 'unit',\n\t\t\t\t\t'title'       =\u003e 'Input text unit',\n\t\t\t\t\t'description' =\u003e 'Input desc of unit',\n\t\t\t\t\t'default'     =\u003e '10px',\n\t\t\t\t\t'html_attributes' =\u003e array( 'min' =\u003e 0, 'max'=\u003e100, 'step'=\u003e5 ),\n\t\t\t\t\t'units'=\u003earray('px', '%', 'em', 'rem'),\n\t\t\t\t\t'condition'=\u003earray('selector'=\u003e$this-\u003eget_field_selector('input2')),\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'type'        =\u003e 'section',\n\t\t\t\t\t'title'       =\u003e 'Section 02',\n\t\t\t\t\t'description' =\u003e 'Section of 02',\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\t\n\t\tpublic function add_rest_settings_fields() {\n\t\t\treturn array(\n\t\t\t\tarray(\n\t\t\t\t\t'type'        =\u003e 'section',\n\t\t\t\t\t'title'       =\u003e 'Section rest',\n\t\t\t\t\t'description' =\u003e 'Section description',\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'           =\u003e 'field-textarea-x',\n\t\t\t\t\t'type'         =\u003e 'textarea',\n\t\t\t\t\t'title'        =\u003e 'Input Type text',\n\t\t\t\t\t'description'  =\u003e 'Input Description',\n\t\t\t\t\t'placeholder'  =\u003e 'Placeholder',\n\t\t\t\t\t'default'      =\u003e 'text field default',\n\t\t\t\t\t'suffix'       =\u003e 'px',\n\t\t\t\t\t'required'     =\u003e true,\n\t\t\t\t\t'add_tag'    =\u003e array('NEW'),\n\t\t\t\t\t// 'show_in_rest' =\u003e array( 'name' =\u003e 'custom_rest_id' ),\n\t\t\t\t\t// 'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'field-text-x',\n\t\t\t\t\t'type'        =\u003e 'text',\n\t\t\t\t\t'title'       =\u003e 'Input Type text',\n\t\t\t\t\t'description' =\u003e 'Input Description',\n\t\t\t\t\t'placeholder' =\u003e 'Placeholder',\n\t\t\t\t\t// 'default'     =\u003e 'text field default',\n\t\t\t\t\t'suffix'      =\u003e 'px',\n\t\t\t\t\t// 'required'    =\u003e true,\n\t\t\t\t\t'add_tag'    =\u003e array('PRO', '#d63639'),\n\t\t\t\t\t// 'show_in_rest'    =\u003e array('name'=\u003e'fieldTextX'),\n\t\t\t\t\t// 'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'field-text-x-dep',\n\t\t\t\t\t'type'        =\u003e 'unit',\n\t\t\t\t\t'title'       =\u003e 'Input Type Unit extra comp',\n\t\t\t\t\t'description' =\u003e 'Input Type Number',\n\t\t\t\t\t'placeholder' =\u003e '',\n\t\t\t\t\t'default'     =\u003e '10px',\n\t\t\t\t\t'html_attributes' =\u003e array( 'min' =\u003e 0, 'max'=\u003e100, 'step'=\u003e5 ),\n\t\t\t\t\t'units'=\u003earray('px', '%', 'em', 'rem'),\n\t\t\t\t\t'condition'=\u003earray('selector'=\u003e $this-\u003eget_field_selector('field-text-x')),\n\t\t\t\t\t// 'required'    =\u003e true,\n\t\t\t\t\t// 'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'field-text-x-dep-text',\n\t\t\t\t\t'type'        =\u003e 'text',\n\t\t\t\t\t'title'       =\u003e 'Input Type Unit extra comp 2',\n\t\t\t\t\t'description' =\u003e 'Input Type Number',\n\t\t\t\t\t'placeholder' =\u003e '',\n\t\t\t\t\t// 'default'     =\u003e '',\n\t\t\t\t\t'condition'=\u003earray('selector'=\u003e$this-\u003eget_field_selector('field-text-x')),\n\t\t\t\t\t// 'required'    =\u003e true,\n\t\t\t\t\t// 'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'field-number-x',\n\t\t\t\t\t'type'        =\u003e 'number',\n\t\t\t\t\t'title'       =\u003e 'Input Type Number',\n\t\t\t\t\t'description' =\u003e 'Input Type Number',\n\t\t\t\t\t'placeholder' =\u003e '',\n\t\t\t\t\t'default'     =\u003e '1',\n\t\t\t\t\t'suffix'      =\u003e 'px',\n\t\t\t\t\t'add_tag'    =\u003e array('BETA', '#000'),\n\t\t\t\t\t// 'required'    =\u003e true,\n\t\t\t\t\t'show_in_rest'    =\u003e array('name'=\u003e'fieldNumberX'),\n\t\t\t\t\t// 'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'field-extra2-x',\n\t\t\t\t\t'type'        =\u003e 'number',\n\t\t\t\t\t'title'       =\u003e 'Input Type Number extra',\n\t\t\t\t\t'description' =\u003e 'Input Type Number',\n\t\t\t\t\t'placeholder' =\u003e '',\n\t\t\t\t\t'default'     =\u003e '1',\n\t\t\t\t\t'suffix'      =\u003e 'px',\n\t\t\t\t\t'show_in_rest'    =\u003e 'fieldExtraX',\n\t\t\t\t\t// 'required'    =\u003e true,\n\t\t\t\t\t// 'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tarray(\n\t\t\t\t\t'id'          =\u003e 'field-extra2-unit',\n\t\t\t\t\t'type'        =\u003e 'unit',\n\t\t\t\t\t'title'       =\u003e 'Input Type Unit extra',\n\t\t\t\t\t'description' =\u003e 'Input Type Number',\n\t\t\t\t\t'placeholder' =\u003e '',\n\t\t\t\t\t'default'     =\u003e '10px',\n\t\t\t\t\t'show_in_rest'    =\u003e 'fieldExtra2Unit',\n\t\t\t\t\t'html_attributes' =\u003e array( 'min' =\u003e 0, 'max'=\u003e100, 'step'=\u003e5 ),\n\t\t\t\t\t'units'=\u003earray('px', '%', 'em', 'rem'),\n\t\t\t\t\t// 'required'    =\u003e true,\n\t\t\t\t\t// 'class'       =\u003e array( 'large-text', 'code', 'custom-class' )\n\t\t\t\t),\n\t\t\t\t\n\t\t\t);\n\t\t}\n\t}\n```\n\n### REST API\n\n- URL will be: `/wp-json/\u003cpage_slug\u003e/\u003crest_api_version\u003e/settings`\n- Default IS: `/wp-json/\u003cpage_slug\u003e/v1/settings`\n- Example: `/wp-json/plugin-a/v1/settings`\n\n### WordPress Data Store Usages example\n\n```js\nimport { select } from '@wordpress/data';\n\n// For a single record (no ID needed if your endpoint returns one object)\nconst settings = select( 'core' ).getEntityRecord( '\u003cparent_slug\u003e', '\u003cpage_slug\u003e' );\nconst settings = wp.data.select( 'core' ).getEntityRecord( '\u003cparent_slug\u003e', '\u003cpage_slug\u003e' );\n\n// Or use the resolver hook in a component\nimport { useEntityRecord } from '@wordpress/core-data';\n\nfunction MyComponent() {\n  const { record, isResolving } = useEntityRecord( 'storepress', '\u003cpage_slug\u003e' );\n\n  if ( isResolving ) return \u003cp\u003eLoading...\u003c/p\u003e;\n\n  return \u003cdiv\u003e{ record?.['field-text'] }\u003c/div\u003e;\n}\n```\n\nNOTE: If parent menu is a page like:\n\n```php\npublic function parent_menu(): string {\n\t\treturn 'edit.php?post_type=wporg_product';\n}\n```\n\nIt will create like:\n\n```js\nselect( 'core' ).getEntityRecord( '\u003cshow_in_rest\u003e', '\u003crest_api_base\u003e' );\nselect( 'core' ).getEntityRecord( 'plugin-name/v1', 'settings' );\n```\n\n- See: [@wordpress/core-data](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-core-data/)\n\n\n### Section data structure\n\n```php\n\u003c?php\narray(\n    'type'        =\u003e 'section',\n    'title'       =\u003e 'Section Title',\n    'description' =\u003e 'Section Description',\n)\n```\n\n### Field data options\n\n```php\n\u003c?php\n\narray(\n    'id'          =\u003e 'input3', // Field ID.\n    'type'        =\u003e 'text', // text, unit, password, toggle, code, small-text, tiny-text, large-text, textarea, email, url, number, color, select, wc-enhanced-select, radio, checkbox\n    'title'       =\u003e 'Input Label',\n    \n    // Optional.\n    'full_width' =\u003e true, // To make field full width. Just remove this key if do not want to use.\n    \n    'add_tag' =\u003e \"PRO\", // Add TAG\n    'add_tag' =\u003e array(\"PRO\", 'BACKGROUND COLOR HEX CODE'), // Add PRO Label\n    'add_tag' =\u003e array(\"BETA\", 'BACKGROUND COLOR HEX CODE', 'TEXT COLOR HEX CODE'), // Add PRO Label\n    \n    'description' =\u003e 'Input field description',\n    \n    'default'       =\u003e 'Hello World', //  default value can be string or array\n    'default'       =\u003e array('x','y'), //  default value can be string or array\n    \n    'placeholder' =\u003e '' // Placeholder\n    'suffix'      =\u003e '' // Field suffix.\n    'html_attributes' =\u003e array('min' =\u003e 10) // Custom html attributes.\n    'html_datalist'   =\u003e array('value 1', 'value 2') // HTML Datalist for suggestion.\n    'required'    =\u003e true, // If field is required and cannot be empty.\n    'private'     =\u003e true, // Private field does not delete from db during reset all action trigger.\n    'multiple'    =\u003e true, // for select box \n    'class'       =\u003e array( 'large-text', 'code', 'custom-class' ),\n    'tooltip'     =\u003e 'Textarea Help tooltip',\n    'condition'   =\u003e array( 'selector'=\u003e$this-\u003eget_field_selector('input2') ), // Conditional field, show or hide based on other input value.\n    'condition'   =\u003e array( 'selector'=\u003e$this-\u003eget_field_selector('input2'), 'value'=\u003e'hello' ),\n    'units'       =\u003e array('px', '%', 'em', 'rem'), // For unit type\n\n    'sanitize_callback'=\u003e'absint', // Use custom sanitize function. Default is: sanitize_text_field.\n    'show_in_rest'    =\u003e true, // Hide from rest api field. Default is: true\n    'show_in_rest'    =\u003e 'custom_rest_id', // Change field id on rest api.\n    'show_in_rest'    =\u003e array( 'name'=\u003e'custom_rest_id' ), // Change field id on rest api.\n    'show_in_rest'    =\u003e array( 'name'=\u003e'custom_rest_id', 'schema'=\u003earray() ), // Add input schema for REST Api. See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/\n    // Options array for select, radio and checkbox [key=\u003evalue]\n    // If checkbox have no options or value, default will be yes|no\n    'options' =\u003e array(\n        'x' =\u003e 'Home X',\n        'y' =\u003e 'Home Y',\n        'z' =\u003e 'Home Z',\n        'new'   =\u003e array(\n            'label' =\u003e 'New',\n            'description' =\u003e 'New Item',\n        ),\n    )\n),\n```\n\n### `AbstractProPluginInCompatibility`  class usages example\n\n- Show notice for incompatible pro or extended plugin.\n\n```php\n\u003c?php\n\t\n\tnamespace StorePress\\Example\\Integrations;\n\t\n\tdefined( 'ABSPATH' ) || die( 'Keep Silent' );\n\t\n\tuse StorePress\\AdminUtils\\Abstracts\\AbstractProPluginInCompatibility;\n\tuse StorePress\\AdminUtils\\Traits\\CallerTrait;\n\tuse StorePress\\AdminUtils\\Traits\\SingletonTrait;\n\tuse StorePress\\Example\\Init;\n\t\n\t/**\n\t * Updater Class.\n\t *\n\t * @name ProPluginInCompatibility\n\t * @phpstan-use CallerTrait\u003cInit\u003e\n\t * @method Init get_caller()\n\t */\n\t\n\tclass ProPluginInCompatibility extends AbstractProPluginInCompatibility {\n\t\t\n\t\tuse SingletonTrait;\n\t\t\n\t\tpublic function compatible_version(): string {\n\t\t\treturn '3.0.0';\n\t\t}\n\t\t\n\t\tpublic function pro_plugin_file(): string {\n\t\t\treturn 'plugin-pro/plugin-pro.php'; // OR FILE CONSTANCE OF PRO PLUGIN FILE.\n\t\t}\n\t\t\n\t\tpublic function localize_notice_format(): string {\n\t\t\t// translators: 1: Extended Plugin Name. 2: Extended Plugin Version. 3: Extended Plugin Compatible Version.\n\t\t\treturn 'You are using an incompatible version of \u003cstrong\u003e%1$s - (%2$s)\u003c/strong\u003e. Please upgrade to version \u003cstrong\u003e%3$s\u003c/strong\u003e or upper.';\n\t\t}\n\t}\n\t\n```\n\n### `AbstractUpdater`  class usages example\n\n- NOTE: Update server and client server should not be in same WordPress setup.\n\n- You must add `Update URI:` on plugin file header to perform update.\n\n```php\n\u003c?php\n/**\n * Plugin Name: Plugin A\n * Tested up to: 6.4.1\n * Update URI: https://update.example.com/\n*/\n```\n\n### `Updater.php` file\n\n```php\n\u003c?php\n\u003c?php\n\t\n\tnamespace StorePress\\Example\\Integrations;\n\t\n\tdefined( 'ABSPATH' ) || die( 'Keep Silent' );\n\t\n\tuse StorePress\\AdminUtils\\Abstracts\\AbstractUpdater;\n\tuse StorePress\\AdminUtils\\Traits\\CallerTrait;\n\tuse StorePress\\AdminUtils\\Traits\\SingletonTrait;\n\tuse StorePress\\Example\\Init;\n\t\n\t/**\n\t * Updater Class.\n\t *\n\t * @name Updater\n\t * @phpstan-use CallerTrait\u003cInit\u003e\n\t * @method Init get_caller()\n\t */\n\t\n\tclass Updater extends AbstractUpdater {\n\t\t\n\t\tuse SingletonTrait;\n\t\t\n\t\tpublic function license_key(): string {\n\t\t\t// $this-\u003eget_caller()-\u003eget_container()-\u003eget( Settings::class)-\u003eget_option( 'license' )\n\t\t\treturn 'hello';\n\t\t}\n\t\t\n\t\tpublic function product_id(): int {\n\t\t\treturn 123450;\n\t\t}\n\t\t\n\t\tpublic function update_server_path(): string {\n\t\t\treturn '/storepress-admin-utils/wp-json/plugin-updater/v1/check-update';\n\t\t}\n\t\t\n\t\tpublic function localize_strings(): array {\n\t\t\t\n\t\t\t$name = $this-\u003eget_plugin_name();\n\t\t\t\n\t\t\treturn array(\n\t\t\t\t'license_key_empty_message'     =\u003e 'License key is not available.',\n\t\t\t\t'check_update_link_text'        =\u003e sprintf('Check Update %s', $name),\n\t\t\t\t'rollback_changelog_title'      =\u003e 'Changelog',\n\t\t\t\t'rollback_action_running'       =\u003e 'Rolling back',\n\t\t\t\t'rollback_action_button'        =\u003e sprintf('Rollback %s', $name),\n\t\t\t\t'rollback_cancel_button'        =\u003e 'Cancel',\n\t\t\t\t'rollback_current_version'      =\u003e 'Current version',\n\t\t\t\t'rollback_last_updated'         =\u003e 'Last updated %s ago.',\n\t\t\t\t'rollback_view_changelog'       =\u003e sprintf('View Changelog for %s', $name),\n\t\t\t\t'rollback_page_title'           =\u003e sprintf( 'Rollback Plugin %s', $name),\n\t\t\t\t'rollback_link_text'            =\u003e sprintf('Rollback %s', $name),\n\t\t\t\t'rollback_failed'               =\u003e 'Rollback failed.',\n\t\t\t\t'rollback_success'              =\u003e 'Rollback success: %s rolled back to version %s.',\n\t\t\t\t'rollback_plugin_not_available' =\u003e 'Plugin is not available.',\n\t\t\t\t'rollback_no_access'            =\u003e 'Sorry, you are not allowed to rollback plugins for this site.',\n\t\t\t\t'rollback_not_available'        =\u003e 'Rollback is not available for plugin: %s',\n\t\t\t\t'rollback_no_target_version'    =\u003e 'Plugin version not selected.',\n\t\t\t);\n\t\t}\n\t\t\n\t\t// If you need to send additional arguments to update server.\n\t\t// Check get_request_args() method.\n\t\tpublic function additional_request_args(): array {\n\t\t\treturn array( 'domain'=\u003e $this-\u003eget_client_hostname() );\n\t\t}\n\t}\n```\n\n## `AbstractDeactivationFeedback`  class usages example\n\n```php\n\u003c?php\n\t\n\tnamespace StorePress\\Example\\Integrations;\n\t\n\tdefined( 'ABSPATH' ) || die( 'Keep Silent' );\n\t\n\tuse StorePress\\AdminUtils\\Abstracts\\AbstractDeactivationFeedback;\n\tuse StorePress\\AdminUtils\\Traits\\SingletonTrait;\n\tuse StorePress\\AdminUtils\\Traits\\CallerTrait;\n\tuse StorePress\\Example\\Init;\n\t\n\t/**\n\t * Changelog Dialog Class.\n\t *\n\t * @name DeactivationFeedback\n\t * @phpstan-use CallerTrait\u003cInit\u003e\n\t * @method Init get_caller()\n\t */\n\t\n\tclass DeactivationFeedback extends AbstractDeactivationFeedback {\n\t\t\n\t\tuse SingletonTrait;\n\t\t\n\t\t/**\n\t\t * Get deactivation title.\n\t\t *\n\t\t * @return string\n\t\t */\n\t\tpublic function title(): string {\n\t\t\treturn 'QUICK FEEDBACK from plugin B';\n\t\t}\n\t\t\n\t\tpublic function sub_title(): string {\n\t\t\treturn 'May we have a little info about why you are deactivating?';\n\t\t}\n\t\t\n\t\t/**\n\t\t * Set API URL to send feedback.\n\t\t *\n\t\t * @return string\n\t\t * @example https://example.com/wp-json/__NAMESPACE__/v1/deactivate\n\t\t */\n\t\tpublic function api_url(): string {\n\t\t\treturn 'http://sites.local/storepress-admin-utils/wp-json/feedback/v1/deactivate';\n\t\t}\n\t\t\n\t\t/**\n\t\t * Get saved settings data.\n\t\t *\n\t\t * @return array\u003cstring, mixed\u003e\n\t\t */\n\t\tpublic function options(): array {\n\t\t\t// $this-\u003eget_caller()-\u003eget_container()-\u003eget( Settings::class)-\u003eget_options();\n\t\t\treturn array();\n\t\t}\n\t\t\n\t\tpublic function get_buttons(): array {\n\t\t\t\n\t\t\treturn array(\n\t\t\t\tarray(\n\t\t\t\t\t'type'       =\u003e 'button',\n\t\t\t\t\t'label'      =\u003e __( 'Send feedback \u0026 Deactivate' ),\n\t\t\t\t\t'attributes' =\u003e array(\n\t\t\t\t\t\t'disabled'        =\u003e true,\n\t\t\t\t\t\t'type'            =\u003e 'submit',\n\t\t\t\t\t\t'data-action'     =\u003e 'submit',\n\t\t\t\t\t\t'data-label'      =\u003e __( 'Send feedback \u0026 Deactivate' ),\n\t\t\t\t\t\t'data-processing' =\u003e __( 'Deactivate...' ),\n\t\t\t\t\t\t'class'           =\u003e array( 'button', 'button-primary' ),\n\t\t\t\t\t),\n\t\t\t\t\t'spinner'    =\u003e true,\n\t\t\t\t),\n\t\t\t\tarray(\n\t\t\t\t\t'type'       =\u003e 'link',\n\t\t\t\t\t'label'      =\u003e __( 'Skip \u0026 Deactivate' ),\n\t\t\t\t\t'attributes' =\u003e array(\n\t\t\t\t\t\t'href'  =\u003e '#',\n\t\t\t\t\t\t'class' =\u003e array( 'skip-deactivate' ),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\t\n\t\tpublic function get_reasons(): array {\n\t\t\t$current_user = wp_get_current_user();\n\t\t\t$name = $this-\u003eget_plugin_name();\n\t\t\t\n\t\t\treturn array(\n\t\t\t\t'temporary_deactivation' =\u003e array(\n\t\t\t\t\t'title'             =\u003e esc_html__( 'It\\'s a temporary deactivation.', 'woo-variation-swatches' ),\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t'dont_know_about' =\u003e array(\n\t\t\t\t\t'title'             =\u003e esc_html__( 'I couldn\\'t understand how to make it work.', 'woo-variation-swatches' ),\n\t\t\t\t\t'message'             =\u003e sprintf( 'Its Plugin %s.', $name),\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t'no_longer_needed' =\u003e array(\n\t\t\t\t\t'title'             =\u003e esc_html__( 'I no longer need the plugin.', 'woo-variation-swatches' ),\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t'found_a_better_plugin' =\u003e array(\n\t\t\t\t\t'title'             =\u003e esc_html__( 'I found a better plugin.', 'woo-variation-swatches' ),\n\t\t\t\t\t'input' =\u003e array(\n\t\t\t\t\t\t'placeholder'=\u003eesc_html__( 'Please let us know which one', 'woo-variation-swatches' ),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t'broke_site_layout' =\u003e array(\n\t\t\t\t\t'title'             =\u003e __( 'The plugin \u003cstrong\u003ebroke my layout\u003c/strong\u003e or some functionality.', 'woo-variation-swatches' ),\n\t\t\t\t\t'message'           =\u003e __( '\u003ca target=\"_blank\" href=\"https://getwooplugins.com/tickets/\"\u003ePlease open a support ticket\u003c/a\u003e, we will fix it immediately.', 'woo-variation-swatches' ),\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t'plugin_setup_help' =\u003e array(\n\t\t\t\t\t'title'             =\u003e __( 'I need someone to \u003cstrong\u003esetup this plugin.\u003c/strong\u003e', 'woo-variation-swatches' ),\n\t\t\t\t\t'input' =\u003e array(\n\t\t\t\t\t\t'placeholder'=\u003eesc_html__( 'Your email address.', 'woo-variation-swatches' ),\n\t\t\t\t\t\t'value'=\u003esanitize_email( $current_user-\u003euser_email )\n\t\t\t\t\t),\n\t\t\t\t\t'message'             =\u003e __( 'Please provide your email address to contact with you \u003cbr\u003eand help you to set up and configure this plugin.', 'woo-variation-swatches' ),\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t'plugin_config_too_complicated' =\u003e array(\n\t\t\t\t\t'title'             =\u003e __( 'The plugin is \u003cstrong\u003etoo complicated to configure.\u003c/strong\u003e', 'woo-variation-swatches' ),\n\t\t\t\t\t'message'             =\u003e __( '\u003ca target=\"_blank\" href=\"https://getwooplugins.com/documentation/woocommerce-variation-swatches/\"\u003eHave you checked our documentation?\u003c/a\u003e.', 'woo-variation-swatches' ),\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t'need_specific_feature' =\u003e array(\n\t\t\t\t\t'title'             =\u003e esc_html__( 'I need specific feature that you don\\'t support.', 'woo-variation-swatches' ),\n\t\t\t\t\t\n\t\t\t\t\t'input' =\u003e array(\n\t\t\t\t\t\t'placeholder'=\u003eesc_html__( 'Please share with us.', 'woo-variation-swatches' ),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\t'other' =\u003e array(\n\t\t\t\t\t'title'             =\u003e esc_html__( 'Other', 'woo-variation-swatches' ),\n\t\t\t\t\t'input' =\u003e array(\n\t\t\t\t\t\t'placeholder'=\u003eesc_html__( 'Please share the reason', 'woo-variation-swatches' ),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\t\n\t\t/**\n\t\t * Dialog width.  - Optional.\n\t\t *\n\t\t * @return string\n\t\t */\n\t\t/*public function get_dialog_width(): string {\n\t\t\treturn ''; // 600px\n\t\t}*/\n\t}\n```\n\n\n## `BaseServiceContainer` class usages example\n\n```php\n\u003c?php\n\n\tdeclare( strict_types=1 );\n\n\tnamespace StorePress\\Example\\ServiceContainers;\n\n\tdefined( 'ABSPATH' ) || die( 'Keep Silent' );\n\n\tuse StorePress\\AdminUtils\\ServiceContainers\\BaseServiceContainer;\n\tuse StorePress\\AdminUtils\\Traits\\SingletonTrait;\n\n\t/**\n\t * Dependency Injection Container Class.\n\t *\n\t * Extends the base service container to provide plugin-specific dependency\n\t * injection capabilities. Uses the singleton pattern to ensure a single\n\t * container instance throughout the plugin's lifecycle. Inherits service\n\t * registration, resolution, and management functionality from BaseServiceContainer.\n\t *\n\t * @name ServiceContainer\n\t */\n\tclass ServiceContainer extends BaseServiceContainer {\n\t\tuse SingletonTrait;\n\t}\n```\n\n\n## `AbstractServiceProvider` class usages example\n\n```php\n\u003c?php\n\n\tdeclare( strict_types=1 );\n\n\tnamespace StorePress\\Example\\ServiceProviders;\n\n\tdefined( 'ABSPATH' ) || die( 'Keep Silent' );\n\t\n\tuse StorePress\\AdminUtils\\Abstracts\\AbstractServiceProvider;\n\tuse StorePress\\AdminUtils\\Traits\\SingletonTrait;\n\tuse StorePress\\Example\\Integrations\\DeactivationFeedback;\n\tuse StorePress\\Example\\Integrations\\ProPluginInCompatibility;\n\tuse StorePress\\Example\\Services\\Settings;\n\tuse StorePress\\Example\\Integrations\\Updater;\n\tuse StorePress\\Example\\ServiceContainers\\ServiceContainer;\n\t\n\t/**\n\t * Plugin Service Provider Class.\n\t *\n\t * Extends AbstractServiceProvider to manage plugin-specific service registration\n\t * and bootstrapping. Uses the singleton pattern to ensure a single provider\n\t * instance manages all service lifecycle operations. Registers the Updater\n\t * service and handles its initialization during the boot phase.\n\t *\n\t * @name ServiceProvider\n\t */\n\tclass ServiceProvider extends AbstractServiceProvider {\n\t\t\n\t\tuse SingletonTrait;\n\t\t\n\t\tpublic function get_container(): ServiceContainer {\n\t\t\treturn ServiceContainer::instance();\n\t\t}\n\n\t\t/**\n\t\t * Register services with the container.\n\t\t *\n\t\t * Registers the Updater service as a factory closure that instantiates\n\t\t * the Updater with the caller (Init) instance. Called during the service\n\t\t * provider initialization phase before boot().\n\t\t *\n\t\t * @return void\n\t\t * @since 2.0.0\n\t\t */\n\t\tpublic function register(): void {\n\t\t\t\n\t\t\t$this-\u003eget_container()-\u003eregister(\n\t\t\t\tUpdater::class,\n\t\t\t\tfunction () {\n\t\t\t\t\treturn Updater::instance( $this-\u003eget_caller() );\n\t\t\t\t}\n\t\t\t);\n\t\t\t\n\t\t\t$this-\u003eget_container()-\u003eregister(\n\t\t\t\tDeactivationFeedback::class,\n\t\t\t\tfunction () {\n\t\t\t\t\treturn DeactivationFeedback::instance( $this-\u003eget_caller() );\n\t\t\t\t}\n\t\t\t);\n\t\t\t\n\t\t\t$this-\u003eget_container()-\u003eregister(\n\t\t\t\tProPluginInCompatibility::class,\n\t\t\t\tfunction () {\n\t\t\t\t\treturn ProPluginInCompatibility::instance( $this-\u003eget_caller() );\n\t\t\t\t}\n\t\t\t);\n\t\t\t\n\t\t\t/*$this-\u003eget_container()-\u003eregister(\n\t\t\t\tAdminMenu::class,\n\t\t\t\tfunction () {\n\t\t\t\t\treturn AdminMenu::instance( $this-\u003eget_caller() );\n\t\t\t\t}\n\t\t\t);*/\n\t\t\t$this-\u003eget_container()-\u003eregister(\n\t\t\t\tSettings::class,\n\t\t\t\tfunction () {\n\t\t\t\t\treturn Settings::instance( $this-\u003eget_caller() );\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\t/**\n\t\t * Bootstrap services after all providers are registered.\n\t\t *\n\t\t * Initializes registered services by resolving the Updater service\n\t\t * from the container. Called after all services are registered to\n\t\t * perform any necessary setup or initialization logic.\n\t\t *\n\t\t * @return void\n\t\t * @since 2.0.0\n\t\t */\n\t\tpublic function boot(): void {\n\t\t\t$this-\u003eget_container()-\u003eget( Updater::class );\n\t\t\t$this-\u003eget_container()-\u003eget( DeactivationFeedback::class );\n\t\t\t$this-\u003eget_container()-\u003eget( ProPluginInCompatibility::class );\n\t\t\t//$this-\u003eget_container()-\u003eget( AdminMenu::class );\n\t\t\t$this-\u003eget_container()-\u003eget( Settings::class );\n\t\t}\n\t}\n```\n\n## Preparing Update Server\n\n```php\n\u003c?php\n\n// Based on Update URI:  \n// https://update.example.com/wp-json/plugin-updater/v1/check-update\nadd_action( 'rest_api_init', function () {\n    register_rest_route( 'plugin-updater/v1', '/check-update', [\n        'methods'             =\u003e WP_REST_Server::READABLE,\n        'callback'            =\u003e 'updater_get_plugin',\n        'permission_callback' =\u003e '__return_true',\n    ] );\n} );\n\n/**\n * @param WP_REST_Request $request REST request instance.\n *\n * @return WP_REST_Response|WP_Error WP_REST_Response instance if the plugin was found,\n *                                    WP_Error if the plugin isn't found.\n *                                   \n * @see Updater::prepare_remote_data()\n */\nfunction updater_get_plugin( WP_REST_Request $request ) {\n    \n    $params = $request-\u003eget_params();\n            \n    $type        = $request-\u003eget_param( 'type' ); // plugins\n    $plugin_name = $request-\u003eget_param( 'name' ); // plugin-dir/plugin-name.php\n    $license_key = $request-\u003eget_param( 'license_key' ); // plugin\n    $product_id  = $request-\u003eget_param( 'product_id' ); // plugin\n    $args        = (array) $request-\u003eget_param( 'args' ); // plugin additional arguments.\n    \n    \n    /**\n     * $data [\n     *\n     *     'description'=\u003e'',\n     * \n     *     'active_installs'=\u003e'1000',\n     *\n     *     'faq'=\u003e'',\n     * \n     *     'changelog'=\u003e'',\n     *\n     *     'new_version'=\u003e'x.x.x', // * REQUIRED\n     * \n\t\t *     'banners'=\u003e['low'=\u003e'https://ps.w.org/woocommerce/assets/banner-772x250.png', 'high'=\u003e'https://ps.w.org/woocommerce/assets/banner-1544x500.png'],\n\t\t *\n\t\t *     'banners_rtl'=\u003e[],\n\t\t *\n\t\t *     Using SVG Icon Recommended.\n\t\t *\n\t\t *     'icons'=\u003e[ 'svg' =\u003e 'https://ps.w.org/woocommerce/assets/icon.svg', '2x'  =\u003e 'https://ps.w.org/woocommerce/assets/icon-256x256.png', '1x'  =\u003e 'https://ps.w.org/woocommerce/assets/icon-128x128.png' ], // icons.\n\t\t *  \n\t\t *     'screenshots'=\u003e[['src'=\u003e'', 'caption'=\u003e'' ], ['src'=\u003e'', 'caption'=\u003e''], ['src'=\u003e'', 'caption'=\u003e'']],\n     *\n     *     'last_updated'=\u003e'2023-11-11 3:24pm GMT+6',\n     *\n     *     'upgrade_notice'=\u003e'',\n     * \n     *     'upgrade_notice'=\u003e['1.1.0'=\u003e'Notice for this version', '1.2.0'=\u003e'Notice for 1.2.0 version'],\n     *\n     *     'package'=\u003e'https://plugin-server.com/plugin-2.0.0.zip', // * REQUIRED ABSOLUTE URL\n     *\n     *     'tested'=\u003e'x.x.x', // WP testes Version\n     *\n     *     'requires'=\u003e'x.x.x', // Minimum Required WP\n     *\n     *     'requires_php'=\u003e'x.x.x', // Minimum Required PHP\n     *\n     *     'requires_plugins'=\u003e ['woocommerce'], // Requires Plugins\n     *\n     *     'versions'=\u003e [  '1.0.0' =\u003e 'https://plugin-server.com/plugin-1.0.0.zip', '2.0.0' =\u003e 'https://plugin-server.com/plugin-2.0.0.zip' ], // Available versions\n     *\n     *     'preview_link'=\u003e'', // Plugin Preview Link\n     * \n     *     'allow_rollback'=\u003e'yes', // yes | no // * REQUIRED for ROLLBACK\n     *\n     * ]\n     */\n    \n    $data = array(\n        'new_version'    =\u003e '1.3.4',\n        'last_updated'   =\u003e '2023-12-12 09:58pm GMT+6',\n        'package'        =\u003e'https://updater.example.com/plugin.zip', // After license verified.\n        'upgrade_notice' =\u003e 'Its Fine',\n        'changelog'      =\u003e'Change log text',\n        'versions'       =\u003e [  \n                '1.0.0' =\u003e 'https://plugin-server.com/plugin-1.0.0.zip', \n                '2.0.0' =\u003e 'https://plugin-server.com/plugin-2.0.0.zip' \n        ], // Available versions\n       'allow_rollback'=\u003e'yes', // yes | no // * REQUIRED for ROLLBACK\n    );\n    \n    return rest_ensure_response( $data );\n}\n```\n\n## Preparing Feedback Server\n\n```php\n\u003c?php\n\n// Sample API:  \n// https://state.example.com/wp-json/feedback/v1/deactivate\nadd_action( 'rest_api_init', function () {\n    register_rest_route( 'feedback/v1', '/deactivate', [\n        'methods'             =\u003e WP_REST_Server::CREATABLE,\n        'callback'            =\u003e 'store_deactivate_data',\n        'permission_callback' =\u003e '__return_true',\n    ] );\n} );\n\n/**\n * @param WP_REST_Request $request REST request instance.\n *\n * @return WP_REST_Response|WP_Error WP_REST_Response instance if the plugin was found,\n *                                    WP_Error if the plugin isn't found.\n *                                   \n * @see Deactivation_Feedback::send_feedback()\n */\n \nfunction store_deactivate_data( WP_REST_Request $request ) {\n    \n    $params = $request-\u003eget_params();\n            \n    $feedback  = (array) $request-\u003eget_param( 'feedback' );\n    $wordpress = (array) $request-\u003eget_param( 'wordpress' );\n    $theme     = (array) $request-\u003eget_param( 'theme' );\n    $plugins   = (array) $request-\u003eget_param( 'plugins' );\n    $server    = (array) $request-\u003eget_param( 'server' );\n    \n    // Save data\n    \n    return rest_ensure_response( true );\n}\n```\n\n## Best Practices to write plugin based on this package.\n\n1. **Use Singleton Pattern** - All services should use `SingletonTrait`\n2. **Use CallerTrait** - Access the `Init` instance and container\n3. **Register Before Boot** - Always register services before booting\n4. **Lazy Loading** - Services are only instantiated when resolved\n5. **Single Responsibility** - Each service handles one concern\n6. **Extend Base Classes** - Use abstract classes from AdminUtils\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femranahmed%2Fstorepress-admin-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femranahmed%2Fstorepress-admin-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femranahmed%2Fstorepress-admin-utils/lists"}