diff --git a/README.md b/README.md
index b91cfa2..bb2688e 100644
--- a/README.md
+++ b/README.md
@@ -16,32 +16,32 @@ __License:__ [GPL-2.0+](http://www.gnu.org/licenses/gpl-2.0.html)
__Plugin page:__ [Knowledge Base](https://webberzone.com/plugins/knowledgebase/) | [WordPress.org Plugin page](https://wordpress.org/plugins/knowledgebase/)
-Fastest way to create a highly-flexible multi-product knowledge base on you WordPress site.
+Effortlessly build a comprehensive knowledge base for unlimited products on your WordPress site and elevate your customer support experience.
## Description
-[Knowledge Base](https://webberzone.com/plugins/knowledgebase/) is an easy to use WordPress plugin that allows you to create a knowledge base / FAQ section on your WordPress blog.
+[Knowledge Base](https://webberzone.com/plugins/knowledgebase/) is an easy-to-use WordPress plugin that allows you to create a knowledge base / FAQ section on your site.
-This is perfect if you have single or multiple products and want a single knowledge base with little effort.
+You can use it to create a single or multi-product knowledge base with little effort.
-The plugin was born after I tried several free plugins and themes out there and that couldn't fit my purpose. It's designed to be very easy to install and use out of the box.
+The plugin was born after I tried several free plugins and themes that didn't fit my purpose. It's designed to be very easy to install and use out of the box.
-You can view a [live demo of my own knowledge base](https://webberzone.com/support/knowledgebase/).
+You can view a [live demo of my knowledge base](https://webberzone.com/support/knowledgebase/).
### Terminology
* __Articles__: A custom post type `wz_knowledgebase` is used to store all the knowledge base articles
-* __Sections__: A custom taxonomy ( `kbcategory` ) used to create the knowledge base. You will need *at least one category* in order to display the knowledge base. These categories can be added under *Knowledge Base > Sections*
+* __Sections__: A custom taxonomy ( `kbcategory` ) used to create the knowledge base. You will need *at least one category* to display the knowledge base. Add these categories under *Knowledge Base > Sections*
* __Tags__: Additionally you can use tags ( `kbtags` ) can also be used for each knowledge base article.
### Main features
* Supports unlimited knowledge bases using different sections with unlimited nested levels
-* Inbuilt styles that display the knowledge beautifully and are fully responsive - Uses the [Responsive Grid System](http://www.responsivegridsystem.com/)
-* Customizable permalinks: Archives are enabled so your knowledge base can be viewed at `/knowledgebase/` automatically on activation. You can change this in the Settings page
-* Shortcode: `[knowledgebase]` will allow you to display the knowledge base on any page of your choosing. For other shortcodes, check the FAQ
+* Inbuilt styles that display the Knowledge Base beautifully and are fully responsive - Uses the [Responsive Grid System](http://www.responsivegridsystem.com/)
+* Customizable permalinks: Archives are enabled so your knowledge base can be viewed automatically at `/knowledgebase/` upon activation. You can change this on the Settings page
+* Shortcode: `[knowledgebase]` will allow you to display the knowledge base on any page you choose. For other shortcodes, check the FAQ
* Gutenberg block: You can display the knowledge base using a block. Find it by typing `kb` or `knowledge base` when adding a new block
-* Breadcrumbs: Default templates include breadcrumbs. Alternatively, use functions or shortcode to display this where you want
+* Breadcrumbs: Default templates include breadcrumbs. Alternatively, use the function or shortcode to display this where you want
* Widgets: WZKB Articles, WZKB Sections and WZKB Breadcrumbs
* Inbuilt cache to speed up the display of your knowledge base articles
@@ -54,15 +54,15 @@ If you have an idea, I'd love to hear it. WebberZone Knowledge Base is also avai
![Knowledge Base Menu in the WordPress Admin](https://raw.githubusercontent.com/WebberZone/knowledgebase/master/wporg-assets/screenshot-1.png)
*Knowledge Base Menu in the WordPress Admin*
-For more screenshots visit the [WordPress plugin page](http://wordpress.org/plugins/knowledgebase/screenshots/)
+For more screenshots, visit the [WordPress plugin page](http://wordpress.org/plugins/knowledgebase/screenshots/)
## Installation
### WordPress install (The easy way)
-1. Navigate to “Plugins” within your WordPress Admin Area
-2. Click “Add new” and in the search box enter “Knowledgebase” or "Knowledge Base"
-3. Find the plugin in the list (usually the first result) and click “Install Now”
+1. Navigate to "Plugins" within your WordPress Admin Area
+2. Click "Add new" and in the search box enter "Knowledgebase" or "Knowledge Base"
+3. Find the plugin in the list (usually the first result) and click "Install Now"
4. Activate or Network activate the Plugin in WP-Admin under the Plugins screen
### Manual install
@@ -77,10 +77,10 @@ For more screenshots visit the [WordPress plugin page](http://wordpress.org/plug
2. Visit `Knowledge Base » Add New` to add new Articles to the knowledge base. You can select a section from there while adding
3. Optionally, create a new page or edit an existing one and add the shortcode `[knowledgebase]` or use the block to set up this page to display the knowledgebase
-The plugin supports unlimited levels of category hierarchy. To build a multiple product knowledge base:
+The plugin supports unlimited levels of category hierarchy. To build a multi-product knowledge base:
1. Set the *First section level* under the Output tab to 2
-2. Create a set of top level sections for each product
+2. Create a set of top-level sections for each product
3. Create sub-sections for each of the products
[This live demo](https://webberzone.com/support/knowledgebase/) is a working example of a multi-product knowledge base.
@@ -89,19 +89,19 @@ The plugin supports unlimited levels of category hierarchy. To build a multiple
Check out the [FAQ on the plugin page](http://wordpress.org/plugins/knowledgebase/faq/) and the [Knowledge Base](https://webberzone.com/support/section/knowledgebase/).
-If your question isn't listed there, please create a new post at the [WordPress.org support forum](http://wordpress.org/support/plugin/knowledgebase). It is the fastest way to get support as I monitor the forums regularly. I also provide [premium *paid* support via email](https://webberzone.com/support/).
+If your question is not listed below, please create a new post at the [WordPress.org support forum](http://wordpress.org/support/plugin/knowledgebase). It is the fastest way to get support, as I monitor the forums regularly. I also provide [premium *paid* support via email](https://webberzone.com/support/).
### 404 errors on the knowledge base
-This is usually because of outdated permalinks. To flush the existing permalinks rules simply visit Settings » Permalinks in your WordPress admin area.
+This is usually due to outdated permalinks. To flush the existing permalink rules, visit Settings > Permalinks in your WordPress admin area.
### Shortcodes
-Refer to [this Knowledge Base article](https://webberzone.com/support/knowledgebase/knowledge-base-shortcodes/) to details of all the shortcodes included in the plugin.
+For details on all the shortcodes included in the plugin, refer to [this Knowledge Base article](https://webberzone.com/support/knowledgebase/knowledge-base-shortcodes/).
-### Using your own templates for archives and search
+### Using your templates for archives and search
-WebberZone Knowledge Base comes inbuilt with a set of custom templates to display archives of the articles, category archives as well as search results. You can easily override any of these templates by creating your own template in your theme's folder or in `wp-content/knowledgebase/templates`
+WebberZone Knowledge Base comes built with custom templates to display archives of the articles, category archives, and search results. You can easily override any of these templates by creating your template in your theme's folder or in `wp-content/knowledgebase/templates`
1. Article view: single-wz_knowledgebase.php or single-wz_knowledgebase.html
2. Articles archive: archive-wz_knowledgebase.php or archive-wz_knowledgebase.html
@@ -118,4 +118,4 @@ You can report security bugs through the Patchstack Vulnerability Disclosure Pro
## About this repository
-This GitHub repository always holds the latest development version of the plugin. If you're looking for an official WordPress release, you can find this on the [WordPress.org repository](http://wordpress.org/plugins/knowledgebase). In addition to stable releases, latest beta versions are made available under [releases](https://github.com/WebberZone/knowledgebase/releases).
+This GitHub repository always holds the latest development version of the plugin. If you're looking for an official WordPress release, you can find this on the [WordPress.org repository](http://wordpress.org/plugins/knowledgebase). In addition to stable releases, the latest beta versions are made available under [releases](https://github.com/WebberZone/knowledgebase/releases).
diff --git a/composer.json b/composer.json
index f6f8457..19396ab 100644
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,7 @@
{
"name": "webberzone/knowledgebase",
"description": "Fastest way to create a highly-flexible multi-product knowledge base.",
+ "version": "2.3.0",
"type": "wordpress-plugin",
"keywords": [
"knowledge base",
@@ -21,14 +22,14 @@
"php": ">=7.4"
},
"require-dev": {
- "szepeviktor/phpstan-wordpress": "^1.3",
- "phpstan/extension-installer": "^1.3",
- "phpstan/phpstan": "^1.10",
- "php-stubs/wordpress-stubs": "^6.5",
- "wp-coding-standards/wpcs": "^3.0",
- "dealerdirect/phpcodesniffer-composer-installer": "^0.7",
- "phpcompatibility/phpcompatibility-wp": "^2.1",
- "yoast/phpunit-polyfills": "^1.0",
+ "szepeviktor/phpstan-wordpress": "^1",
+ "phpstan/extension-installer": "^1",
+ "phpstan/phpstan": "^1",
+ "php-stubs/wordpress-stubs": "^6",
+ "wp-coding-standards/wpcs": "^3",
+ "dealerdirect/phpcodesniffer-composer-installer": "^1",
+ "phpcompatibility/phpcompatibility-wp": "^2",
+ "yoast/phpunit-polyfills": "^3",
"phpunit/phpunit": "^5.7.21 || ^6.5 || ^7.5"
},
"config": {
diff --git a/includes/activate-deactivate.php b/includes/activate-deactivate.php
deleted file mode 100644
index f6c9003..0000000
--- a/includes/activate-deactivate.php
+++ /dev/null
@@ -1,132 +0,0 @@
-get_col( //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
- "
- SELECT blog_id FROM $wpdb->blogs
- WHERE archived = '0' AND spam = '0' AND deleted = '0'
- "
- );
-
- foreach ( $blog_ids as $blog_id ) {
- switch_to_blog( $blog_id );
- wzkb_single_activate();
- restore_current_blog();
- }
- } else {
- wzkb_single_activate();
- }
-}
-register_activation_hook( WZKB_PLUGIN_FILE, 'wzkb_plugin_activate' );
-
-
-/**
- * Runs on Plugin activation.
- *
- * @since 1.1.0
- */
-function wzkb_single_activate() {
-
- // Register types to register the rewrite rules.
- wzkb_register_post_type();
-
- // Then flush them.
- global $wp_rewrite;
- $wp_rewrite->init();
- flush_rewrite_rules( false );
-}
-
-
-/**
- * Fired when a new site is activated with a WPMU environment.
- *
- * @since 2.0.0
- *
- * @param int|WP_Site $blog WordPress 5.1 passes a WP_Site object.
- */
-function wzkb_activate_new_site( $blog ) {
-
- if ( ! is_plugin_active_for_network( plugin_basename( WZKB_PLUGIN_FILE ) ) ) {
- return;
- }
-
- if ( ! is_int( $blog ) ) {
- $blog = $blog->id;
- }
-
- switch_to_blog( $blog );
- wzkb_single_activate();
- restore_current_blog();
-}
-if ( version_compare( get_bloginfo( 'version' ), '5.1', '>=' ) ) {
- add_action( 'wp_initialize_site', 'wzkb_activate_new_site' );
-} else {
- add_action( 'wpmu_new_blog', 'wzkb_activate_new_site' );
-}
-
-
-/**
- * Runs on Plugin deactivation.
- *
- * @since 1.0.0
- *
- * @param bool $network_wide Network wide flag.
- */
-function wzkb_plugin_deactivate( $network_wide ) {
-
- global $wpdb;
-
- if ( is_multisite() && $network_wide ) {
-
- // Get all blogs in the network and activate plugin on each one.
- $blog_ids = $wpdb->get_col( //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
- "
- SELECT blog_id FROM $wpdb->blogs
- WHERE archived = '0' AND spam = '0' AND deleted = '0'
- "
- );
-
- foreach ( $blog_ids as $blog_id ) {
- switch_to_blog( $blog_id );
- global $wp_rewrite;
- $wp_rewrite->init();
- flush_rewrite_rules();
- }
-
- // Switch back to the current blog.
- restore_current_blog();
-
- }
-
- flush_rewrite_rules();
-}
-register_deactivation_hook( WZKB_PLUGIN_FILE, 'wzkb_plugin_deactivate' );
diff --git a/includes/admin/admin.php b/includes/admin/admin.php
deleted file mode 100644
index 26bf3cc..0000000
--- a/includes/admin/admin.php
+++ /dev/null
@@ -1,140 +0,0 @@
- 'ID',
- );
-
- return array_merge( $columns, $new_columns );
-}
-add_filter( 'manage_edit-wzkb_category_columns', 'wzkb_tax_columns' );
-add_filter( 'manage_edit-wzkb_category_sortable_columns', 'wzkb_tax_columns' );
-add_filter( 'manage_edit-wzkb_tag_columns', 'wzkb_tax_columns' );
-add_filter( 'manage_edit-wzkb_tag_sortable_columns', 'wzkb_tax_columns' );
-
-
-/**
- * Add taxonomy ID to the admin column.
- *
- * @since 1.0.0
- *
- * @param string $value Deprecated.
- * @param string $name Name of the column.
- * @param int|string $id Category ID.
- * @return int|string
- */
-function wzkb_tax_id( $value, $name, $id ) {
- return 'tax_id' === $name ? $id : $value;
-}
-add_filter( 'manage_wzkb_category_custom_column', 'wzkb_tax_id', 10, 3 );
-add_filter( 'manage_wzkb_tag_custom_column', 'wzkb_tax_id', 10, 3 );
-
-/**
- * Filters Admin Notices to add a notice when the settings are not saved.
- *
- * @since 1.2.0
- * @return void
- */
-function wzkb_admin_notices() {
-
- $kbslug = wzkb_get_option( 'kb_slug', 'not-set-random-string' );
- $catslug = wzkb_get_option( 'category_slug', 'not-set-random-string' );
- $tagslug = wzkb_get_option( 'tag_slug', 'not-set-random-string' );
-
- // Only add the notice if the user is an admin.
- if ( ! current_user_can( 'manage_options' ) ) {
- return;
- }
-
- // Only add the notice if the settings cannot be found.
- if ( 'not-set-random-string' === $kbslug || 'not-set-random-string' === $catslug || 'not-set-random-string' === $tagslug ) {
- ?>
-
-
-
- admin page to update and save the options.', 'knowledgebase' ), esc_url( admin_url( 'edit.php?post_type=wz_knowledgebase&page=wzkb-settings' ) ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- ?>
-
-
-
- publish ) ) {
- /* translators: 1. Number of articles */
- $text = _n( '%s KB article', '%s KB articles', $num_posts->publish, 'knowledgebase' );
-
- $text = sprintf( $text, number_format_i18n( $num_posts->publish ) );
-
- if ( current_user_can( 'edit_posts' ) ) {
- $text = sprintf( '%1$s ', $text );
- } else {
- $text = sprintf( '%1$s ', $text );
- }
-
- $items[] = $text;
- }
-
- return $items;
-}
-add_filter( 'dashboard_glance_items', 'wzkb_dashboard_glance_items', 1 );
-
-
-/**
- * Add CSS to Admin head
- *
- * @since 1.5.0
- *
- * return void
- */
-function wzkb_admin_head() {
- ?>
-
- 0,
+ 'spam' => 0,
+ 'deleted' => 0,
+ )
+ );
+
+ foreach ( $sites as $site ) {
+ switch_to_blog( (int) $site->blog_id );
+ self::single_activate();
+ }
+
+ // Switch back to the current blog.
+ restore_current_blog();
+
+ } else {
+ self::single_activate();
+ }
+ }
+
+ /**
+ * Activates the plugin on a new site.
+ *
+ * @since 3.3.0
+ *
+ * @param int|\WP_Site $blog The blog ID.
+ */
+ public function activate_new_site( $blog ) {
+ if ( ! is_plugin_active_for_network( plugin_basename( WZKB_PLUGIN_FILE ) ) ) {
+ return;
+ }
+
+ if ( ! is_int( $blog ) ) {
+ $blog = $blog->id;
+ }
+
+ switch_to_blog( $blog );
+ self::single_activate();
+ restore_current_blog();
+ }
+
+ /**
+ * Activation method.
+ *
+ * @since 2.3.0
+ */
+ public static function single_activate() {
+ // Register types to register the rewrite rules.
+ CPT::register_post_type();
+ CPT::register_taxonomies();
+
+ // Then flush them.
+ global $wp_rewrite;
+ $wp_rewrite->init();
+ flush_rewrite_rules( false );
+ }
+
+ /**
+ * Deactivation method.
+ *
+ * @since 2.3.0
+ *
+ * @param boolean $network_wide True if WPMU superadmin uses
+ * "Network Activate" action, false if
+ * WPMU is disabled or plugin is
+ * activated on an individual blog.
+ */
+ public static function deactivate( $network_wide ) {
+ if ( is_multisite() && $network_wide ) {
+ $sites = get_sites(
+ array(
+ 'archived' => 0,
+ 'spam' => 0,
+ 'deleted' => 0,
+ )
+ );
+
+ foreach ( $sites as $site ) {
+ switch_to_blog( (int) $site->blog_id );
+ global $wp_rewrite;
+ $wp_rewrite->init();
+ flush_rewrite_rules();
+ restore_current_blog();
+ }
+ }
+
+ // Flush the rewrite rules.
+ global $wp_rewrite;
+ $wp_rewrite->init();
+ flush_rewrite_rules();
+ }
+}
diff --git a/includes/admin/class-admin-columns.php b/includes/admin/class-admin-columns.php
new file mode 100644
index 0000000..fa85579
--- /dev/null
+++ b/includes/admin/class-admin-columns.php
@@ -0,0 +1,72 @@
+ 'ID',
+ );
+
+ return array_merge( $columns, $new_columns );
+ }
+
+ /**
+ * Add taxonomy ID to the admin column.
+ *
+ * @since 2.3.0
+ *
+ * @param string $value Deprecated.
+ * @param string $name Name of the column.
+ * @param int|string $id Category ID.
+ * @return int|string
+ */
+ public static function tax_id( $value, $name, $id ) {
+ return 'tax_id' === $name ? $id : $value;
+ }
+}
diff --git a/includes/admin/class-admin.php b/includes/admin/class-admin.php
new file mode 100644
index 0000000..5098217
--- /dev/null
+++ b/includes/admin/class-admin.php
@@ -0,0 +1,256 @@
+hooks();
+
+ // Initialise admin classes.
+ $this->settings = new Settings\Settings();
+ $this->activator = new Activator();
+ $this->cache = new Cache();
+ $this->admin_columns = new Admin_Columns();
+ }
+
+ /**
+ * Run the hooks.
+ *
+ * @since 2.3.0
+ */
+ public function hooks() {
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
+ add_action( 'admin_notices', array( $this, 'admin_notices' ) );
+ add_filter( 'dashboard_glance_items', array( $this, 'dashboard_glance_items' ), 10, 1 );
+ add_filter( 'admin_head', array( $this, 'admin_head' ) );
+ add_action( 'admin_footer', array( $this, 'maybe_add_button_to_post_list' ) );
+ }
+
+ /**
+ * Enqueue scripts in admin area.
+ *
+ * @since 2.3.0
+ */
+ public function admin_enqueue_scripts() {
+
+ $minimize = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
+
+ wp_register_script(
+ 'wzkb-admin-js',
+ plugins_url( 'js/admin-scripts' . $minimize . '.js', __FILE__ ),
+ array( 'jquery', 'jquery-ui-tabs' ),
+ WZKB_VERSION,
+ true
+ );
+ wp_localize_script(
+ 'wzkb-admin-js',
+ 'wzkb_admin',
+ array(
+ 'nonce' => wp_create_nonce( 'wzkb_admin_nonce' ),
+ )
+ );
+ wp_register_style(
+ 'wzkb-admin-ui-css',
+ plugins_url( 'css/admin' . $minimize . '.css', __FILE__ ),
+ array(),
+ WZKB_VERSION
+ );
+
+ if ( isset( $_GET['post_type'] ) && 'wz_knowledgebase' === $_GET['post_type'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended
+ wp_enqueue_style( 'wzkb-admin-ui-css' );
+ }
+ }
+
+ /**
+ * Display admin notices.
+ *
+ * @since 2.3.0
+ */
+ public function admin_notices() {
+ $kbslug = \wzkb_get_option( 'kb_slug', 'not-set-random-string' );
+ $catslug = \wzkb_get_option( 'category_slug', 'not-set-random-string' );
+ $tagslug = \wzkb_get_option( 'tag_slug', 'not-set-random-string' );
+
+ // Only add the notice if the user is an admin.
+ if ( ! current_user_can( 'manage_options' ) ) {
+ return;
+ }
+
+ // Only add the notice if the settings cannot be found.
+ if ( 'not-set-random-string' === $kbslug || 'not-set-random-string' === $catslug || 'not-set-random-string' === $tagslug ) {
+ ?>
+
+
+ admin page to update and save the options.', 'knowledgebase' ), esc_url( admin_url( 'edit.php?post_type=wz_knowledgebase&page=wzkb-settings' ) ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ ?>
+
+
+ publish ) ) {
+ /* translators: 1. Number of articles */
+ $text = _n( '%s KB article', '%s KB articles', $num_posts->publish, 'knowledgebase' );
+
+ $text = sprintf( $text, number_format_i18n( $num_posts->publish ) );
+
+ if ( current_user_can( 'edit_posts' ) ) {
+ $text = sprintf( '%1$s ', $text );
+ } else {
+ $text = sprintf( '%1$s ', $text );
+ }
+
+ $items[] = $text;
+ }
+
+ return $items;
+ }
+
+ /**
+ * Add CSS to Admin head
+ *
+ * @since 2.3.0
+ *
+ * return void
+ */
+ public function admin_head() {
+ if ( 'index.php' === $GLOBALS['pagenow'] ) {
+ ?>
+
+ post_type && 'wzkb_category' !== $screen->taxonomy ) ||
+ ( 'edit' !== $screen->base && 'wz_knowledgebase' !== $screen->post_type ) ) {
+ return;
+ }
+
+ $this->render_custom_button( 'Visit Knowledge Base' );
+ }
+
+ /**
+ * Render the custom button
+ *
+ * @since 2.3.0
+ *
+ * @param string $button_text Text to display on the button.
+ */
+ private function render_custom_button( $button_text = 'Custom Action' ) {
+ ?>
+
+ ');
+ clearCache($button);
+ }
+ });
+
+ // Function to clear the cache.
+ function clearCache($button) {
+ $.post(wzkb_admin_data.ajax_url, {
+ action: 'wzkb_clear_cache',
+ security: wzkb_admin_data.security
+ }, function (response) {
+ if (response.success) {
+ alert(response.data.message);
+ } else {
+ alert(wzkb_admin_data.fail_message);
+ }
+ }).fail(function (jqXHR, textStatus) {
+ alert(wzkb_admin_data.request_fail_message + textStatus);
+ }).always(function () {
+ $button.prop('disabled', false).find('.spinner').remove();
+ });
+ }
+
+ // Prompt the user when they leave the page without saving the form.
+ var formmodified = 0;
+
+ function confirmFormChange() {
+ formmodified = 1;
+ }
+
+ function confirmExit() {
+ if (formmodified == 1) {
+ return true;
+ }
+ }
+
+ function formNotModified() {
+ formmodified = 0;
+ }
+
+ $('form *').change(confirmFormChange);
+
+ window.onbeforeunload = confirmExit;
+
+ $("input[name='submit']").click(formNotModified);
+ $("input[id='search-submit']").click(formNotModified);
+ $("input[id='doaction']").click(formNotModified);
+ $("input[id='doaction2']").click(formNotModified);
+ $("input[name='filter_action']").click(formNotModified);
+
+ $(
+ function () {
+ $("#post-body-content").tabs(
+ {
+ create: function (event, ui) {
+ $(ui.tab.find("a")).addClass("nav-tab-active");
+ },
+ activate: function (event, ui) {
+ $(ui.oldTab.find("a")).removeClass("nav-tab-active");
+ $(ui.newTab.find("a")).addClass("nav-tab-active");
+ }
+ }
+ );
+ }
+ );
+ }
+);
diff --git a/includes/admin/js/admin-scripts.min.js b/includes/admin/js/admin-scripts.min.js
new file mode 100644
index 0000000..204169a
--- /dev/null
+++ b/includes/admin/js/admin-scripts.min.js
@@ -0,0 +1 @@
+jQuery(document).ready((function(a){a('button[name="wzkb_cache_clear"]').on("click",(function(){if(confirm(wzkb_admin_data.confirm_message)){var n=a(this);n.prop("disabled",!0).append(' '),function(n){a.post(wzkb_admin_data.ajax_url,{action:"wzkb_clear_cache",security:wzkb_admin_data.security},(function(a){a.success?alert(a.data.message):alert(wzkb_admin_data.fail_message)})).fail((function(a,n){alert(wzkb_admin_data.request_fail_message+n)})).always((function(){n.prop("disabled",!1).find(".spinner").remove()}))}(n)}}));var n=0;function i(){n=0}a("form *").change((function(){n=1})),window.onbeforeunload=function(){if(1==n)return!0},a("input[name='submit']").click(i),a("input[id='search-submit']").click(i),a("input[id='doaction']").click(i),a("input[id='doaction2']").click(i),a("input[name='filter_action']").click(i),a((function(){a("#post-body-content").tabs({create:function(n,i){a(i.tab.find("a")).addClass("nav-tab-active")},activate:function(n,i){a(i.oldTab.find("a")).removeClass("nav-tab-active"),a(i.newTab.find("a")).addClass("nav-tab-active")}})}))}));
\ No newline at end of file
diff --git a/includes/admin/modules/cache.php b/includes/admin/modules/cache.php
deleted file mode 100644
index fbec6a7..0000000
--- a/includes/admin/modules/cache.php
+++ /dev/null
@@ -1,100 +0,0 @@
-query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
- $wpdb->prepare(
- "
- DELETE FROM {$wpdb->termmeta}
- WHERE meta_key = %s
- ",
- $meta_key
- )
- );
- }
-}
-
-
-/**
- * Get the default meta keys used for the cache
- *
- * @since 1.8.0
- */
-function wzkb_cache_get_keys() {
-
- $meta_keys = wzkb_cache_get_meta_keys();
-
- /**
- * Filters the array containing the various cache keys.
- *
- * @since 1.8.0
- *
- * @param array $default_meta_keys Array of meta keys
- */
- return apply_filters( 'wzkb_cache_keys', $meta_keys );
-}
-
-
-/**
- * Get the _wzkb_cache keys.
- *
- * @since 1.8.0
- *
- * @return array Array of _wzkb_cache keys.
- */
-function wzkb_cache_get_meta_keys() {
- global $wpdb;
-
- $keys = array();
-
- $sql = "
- SELECT meta_key
- FROM {$wpdb->termmeta}
- WHERE `meta_key` LIKE '_wzkb_cache_%'
- ";
-
- $results = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
-
- $keys = wp_list_pluck( $results, 'meta_key' );
-
- /**
- * Filter the array of _wzkb_cache keys.
- *
- * @since 1.8.0
- *
- * @return array Array of _wzkb_cache keys.
- */
- return apply_filters( 'wzkb_cache_get_meta_keys', $keys );
-}
diff --git a/includes/admin/settings/class-knowledgebase-settings.php b/includes/admin/settings/class-knowledgebase-settings.php
deleted file mode 100644
index 18d26c6..0000000
--- a/includes/admin/settings/class-knowledgebase-settings.php
+++ /dev/null
@@ -1,655 +0,0 @@
-settings_key = 'wzkb_settings';
- self::$prefix = 'wzkb';
- $this->menu_slug = 'wzkb-settings';
-
- $props = array(
- 'menu_type' => 'submenu',
- 'parent_slug' => 'edit.php?post_type=wz_knowledgebase',
- 'menu_slug' => $this->menu_slug,
- 'default_tab' => 'general',
- 'help_sidebar' => $this->get_help_sidebar(),
- 'help_tabs' => $this->get_help_tabs(),
- 'admin_footer_text' => $this->get_admin_footer_text(),
- );
-
- $args = array(
- 'translation_strings' => $this->get_translation_strings(),
- 'props' => $props,
- 'settings_sections' => $this->get_settings_sections(),
- 'registered_settings' => $this->get_registered_settings(),
- 'upgraded_settings' => array(),
- );
-
- $this->settings_api = new Knowledgebase_Admin\Settings_API( $this->settings_key, self::$prefix, $args );
-
- add_action( 'admin_head', array( $this, 'admin_head' ), 11 );
- add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 2 );
- add_filter( 'plugin_action_links_' . plugin_basename( WZKB_PLUGIN_FILE ), array( $this, 'plugin_actions_links' ) );
- add_action( 'wzkb_settings_page_header', array( $this, 'settings_page_header' ), 11 );
- add_filter( 'wzkb_settings_sanitize', array( $this, 'change_settings_on_save' ), 99 );
- }
-
- /**
- * Singleton instance
- *
- * @since 2.2.0
- */
- public static function get_instance() {
- if ( ! isset( self::$instance ) ) {
- self::$instance = new self();
- }
- return self::$instance;
- }
-
- /**
- * Array containing the various strings used by the Settings_API.
- *
- * @since 2.2.0
- *
- * @return array Settings array
- */
- public function get_translation_strings() {
- $strings = array(
- 'page_title' => esc_html__( 'Knowledge Base Settings', 'knowledgebase' ),
- 'menu_title' => esc_html__( 'Settings', 'knowledgebase' ),
- 'page_header' => esc_html__( 'Knowledge Base Settings', 'knowledgebase' ),
- 'reset_message' => esc_html__( 'Settings have been reset to their default values. Reload this page to view the updated settings.', 'knowledgebase' ),
- 'success_message' => esc_html__( 'Settings updated.', 'knowledgebase' ),
- 'save_changes' => esc_html__( 'Save Changes', 'knowledgebase' ),
- 'reset_settings' => esc_html__( 'Reset all settings', 'knowledgebase' ),
- 'reset_button_confirm' => esc_html__( 'Do you really want to reset all these settings to their default values?', 'knowledgebase' ),
- 'checkbox_modified' => esc_html__( 'Modified from default setting', 'knowledgebase' ),
- );
-
- /**
- * Filter the array containing the settings' sections.
- *
- * @since 2.2.0
- *
- * @param array $strings Translation strings.
- */
- return apply_filters( self::$prefix . '_translation_strings', $strings );
- }
-
- /**
- * Array containing the settings' sections.
- *
- * @since 2.2.0
- *
- * @return array Array of settings' sections.
- */
- public function get_settings_sections() {
- $sections = array(
- 'general' => __( 'General', 'knowledgebase' ),
- 'output' => __( 'Output', 'knowledgebase' ),
- 'styles' => __( 'Styles', 'knowledgebase' ),
- );
-
- /**
- * Filter the array containing the settings' sections.
- *
- * @since 2.2.0
- *
- * @param array $sections Array of settings' sections
- */
- return apply_filters( self::$prefix . '_settings_sections', $sections );
- }
-
-
- /**
- * Retrieve the array of plugin settings
- *
- * @since 2.2.0
- *
- * @return array Settings array
- */
- public static function get_registered_settings() {
-
- $settings = array(
- 'general' => self::settings_general(),
- 'output' => self::settings_output(),
- 'styles' => self::settings_styles(),
- );
-
- /**
- * Filters the settings array
- *
- * @since 2.2.0
- *
- * @param array $Knowledgebase_setings Settings array
- */
- return apply_filters( self::$prefix . '_registered_settings', $settings );
- }
-
- /**
- * Returns the Header settings.
- *
- * @since 2.2.0
- *
- * @return array Header settings.
- */
- public static function settings_general() {
-
- $settings = array(
- 'slug_header' => array(
- 'id' => 'slug_header',
- 'name' => '' . esc_html__( 'Slug options', 'knowledgebase' ) . ' ',
- 'desc' => '',
- 'type' => 'header',
- ),
- 'kb_slug' => array(
- 'id' => 'kb_slug',
- 'name' => esc_html__( 'Knowledge Base slug', 'knowledgebase' ),
- 'desc' => esc_html__( 'This will set the opening path of the URL of the knowledge base and is set when registering the custom post type', 'knowledgebase' ),
- 'type' => 'text',
- 'options' => 'knowledgebase',
- ),
- 'category_slug' => array(
- 'id' => 'category_slug',
- 'name' => esc_html__( 'Category slug', 'knowledgebase' ),
- 'desc' => esc_html__( 'Each category is a section of the knowledge base. This setting is used when registering the custom category and forms a part of the URL when browsing category archives', 'knowledgebase' ),
- 'type' => 'text',
- 'options' => 'section',
- ),
- 'tag_slug' => array(
- 'id' => 'tag_slug',
- 'name' => esc_html__( 'Tag slug', 'knowledgebase' ),
- 'desc' => esc_html__( 'Each article can have multiple tags. This setting is used when registering the custom tag and forms a part of the URL when browsing tag archives', 'knowledgebase' ),
- 'type' => 'text',
- 'options' => 'kb-tags',
- ),
- 'cache' => array(
- 'id' => 'cache',
- 'name' => esc_html__( 'Enable cache', 'knowledgebase' ),
- 'desc' => esc_html__( 'Cache the output of the WP_Query lookups to speed up retrieval of the knowledgebase. Recommended for large knowledge bases', 'knowledgebase' ),
- 'type' => 'checkbox',
- 'options' => false,
- ),
- 'uninstall_header' => array(
- 'id' => 'uninstall_header',
- 'name' => '' . esc_html__( 'Uninstall options', 'knowledgebase' ) . ' ',
- 'desc' => '',
- 'type' => 'header',
- 'options' => '',
- ),
- 'uninstall_options' => array(
- 'id' => 'uninstall_options',
- 'name' => esc_html__( 'Delete options on uninstall', 'knowledgebase' ),
- 'desc' => esc_html__( 'Check this box to delete the settings on this page when the plugin is deleted via the Plugins page in your WordPress Admin', 'knowledgebase' ),
- 'type' => 'checkbox',
- 'options' => true,
- ),
- 'uninstall_data' => array(
- 'id' => 'uninstall_data',
- 'name' => esc_html__( 'Delete all knowledge base posts on uninstall', 'knowledgebase' ),
- 'desc' => esc_html__( 'Check this box to delete all the posts, categories and tags created by the plugin. There is no way to restore the data if you choose this option', 'knowledgebase' ),
- 'type' => 'checkbox',
- 'options' => false,
- ),
- 'feed_header' => array(
- 'id' => 'feed_header',
- 'name' => '' . esc_html__( 'Feed options', 'knowledgebase' ) . ' ',
- 'desc' => '',
- 'type' => 'header',
- 'options' => '',
- ),
- 'include_in_feed' => array(
- 'id' => 'include_in_feed',
- 'name' => esc_html__( 'Include in feed', 'knowledgebase' ),
- 'desc' => esc_html__( 'Adds the knowledge base articles to the main RSS feed for your site', 'knowledgebase' ),
- 'type' => 'checkbox',
- 'options' => true,
- ),
- 'disable_kb_feed' => array(
- 'id' => 'disable_kb_feed',
- 'name' => esc_html__( 'Disable KB feed', 'knowledgebase' ),
- /* translators: 1: Opening link tag, 2: Closing link tag. */
- 'desc' => sprintf( esc_html__( 'The knowledge base articles have a default feed. This option will disable the feed. You might need to %1$srefresh your permalinks%2$s when changing this option.', 'knowledgebase' ), '', ' ' ),
- 'type' => 'checkbox',
- 'options' => false,
- ),
- );
-
- /**
- * Filters the Header settings array
- *
- * @since 2.2.0
- *
- * @param array $settings Header Settings array
- */
- return apply_filters( self::$prefix . '_settings_general', $settings );
- }
-
- /**
- * Returns the Pingbacks/Trackbacks settings.
- *
- * @since 2.2.0
- *
- * @return array Pingbacks/Trackbacks settings.
- */
- public static function settings_output() {
-
- $settings = array(
- 'kb_title' => array(
- 'id' => 'kb_title',
- 'name' => esc_html__( 'Knowledge base title', 'knowledgebase' ),
- 'desc' => esc_html__( 'This will be displayed as the title of the archive title as well as on other relevant places.', 'knowledgebase' ),
- 'type' => 'text',
- 'options' => 'Knowledge Base',
- 'field_class' => 'large-text',
- ),
- 'category_level' => array(
- 'id' => 'category_level',
- 'name' => esc_html__( 'First section level', 'knowledgebase' ),
- 'desc' => esc_html__( 'This option allows you to create multi-level knowledge bases. This works in conjunction with the inbuilt styles. Set to 1 to lay out the top level sections in a grid. Set to 2 to lay out the second level categories in the grid. This is great if you have multiple products and want to create separate knowledge bases for each of them. The default option is 2 and was the behaviour of this plugin before v1.5.0.', 'knowledgebase' ),
- 'type' => 'number',
- 'options' => '2',
- 'size' => 'small',
- 'min' => '1',
- 'max' => '5',
- ),
- 'show_article_count' => array(
- 'id' => 'show_article_count',
- 'name' => esc_html__( 'Show article count', 'knowledgebase' ),
- 'desc' => esc_html__( 'If selected, the number of articles will be displayed in an orange circle next to the header. You can override the color by styling wzkb_section_count', 'knowledgebase' ),
- 'type' => 'checkbox',
- 'options' => false,
- ),
- 'show_excerpt' => array(
- 'id' => 'show_excerpt',
- 'name' => esc_html__( 'Show excerpt', 'knowledgebase' ),
- 'desc' => esc_html__( 'Select to include the post excerpt after the article link', 'knowledgebase' ),
- 'type' => 'checkbox',
- 'options' => false,
- ),
- 'clickable_section' => array(
- 'id' => 'clickable_section',
- 'name' => esc_html__( 'Link section title', 'knowledgebase' ),
- 'desc' => esc_html__( 'If selected, the title of each section of the knowledgebase will be linked to its own page', 'knowledgebase' ),
- 'type' => 'checkbox',
- 'options' => true,
- ),
- 'show_empty_sections' => array(
- 'id' => 'show_empty_sections',
- 'name' => esc_html__( 'Show empty sections', 'knowledgebase' ),
- 'desc' => esc_html__( 'If selected, sections with no articles will also be displayed', 'knowledgebase' ),
- 'type' => 'checkbox',
- 'options' => false,
- ),
- 'limit' => array(
- 'id' => 'limit',
- 'name' => esc_html__( 'Max articles per section', 'knowledgebase' ),
- 'desc' => esc_html__( 'Enter the number of articles that should be displayed in each section when viewing the knowledge base. After this limit is reached, the footer is displayed with the more link to view the category.', 'knowledgebase' ),
- 'type' => 'number',
- 'options' => '5',
- 'size' => 'small',
- 'min' => '1',
- 'max' => '500',
- ),
- 'show_sidebar' => array(
- 'id' => 'show_sidebar',
- 'name' => esc_html__( 'Show sidebar', 'knowledgebase' ),
- 'desc' => esc_html__( 'Add the sidebar of your theme into the inbuilt templates for archive, sections and search. Activate this option if your theme does not already include this.', 'knowledgebase' ),
- 'type' => 'checkbox',
- 'options' => false,
- ),
- 'show_related_articles' => array(
- 'id' => 'show_related_articles',
- 'name' => esc_html__( 'Show related articles', 'knowledgebase' ),
- 'desc' => esc_html__( 'Add related articles at the bottom of the knowledge base article. Only works when using the inbuilt template.', 'knowledgebase' ),
- 'type' => 'checkbox',
- 'options' => true,
- ),
- );
-
- /**
- * Filters the Pingbacks/Trackbacks settings array
- *
- * @since 2.2.0
- *
- * @param array $settings Pingbacks/Trackbacks Settings array
- */
- return apply_filters( self::$prefix . '_settings_output', $settings );
- }
-
- /**
- * Returns the Comments settings.
- *
- * @since 2.2.0
- *
- * @return array Comments settings.
- */
- public static function settings_styles() {
-
- $settings = array(
- 'include_styles' => array(
- 'id' => 'include_styles',
- 'name' => esc_html__( 'Include inbuilt styles', 'knowledgebase' ),
- 'desc' => esc_html__( 'Uncheck this to disable this plugin from adding the inbuilt styles. You will need to add your own CSS styles if you disable this option', 'knowledgebase' ),
- 'type' => 'checkbox',
- 'options' => true,
- ),
- 'columns' => array(
- 'id' => 'columns',
- 'name' => esc_html__( 'Number of columns', 'knowledgebase' ),
- 'desc' => esc_html__( 'Set number of columns to display the knowledge base archives. This is only works if the above option is selected.', 'knowledgebase' ),
- 'type' => 'number',
- 'options' => '2',
- 'size' => 'small',
- 'min' => '1',
- 'max' => '5',
- ),
- 'custom_css' => array(
- 'id' => 'custom_css',
- 'name' => esc_html__( 'Custom CSS', 'knowledgebase' ),
- 'desc' => esc_html__( 'Enter any custom valid CSS without any wrapping <style> tags', 'knowledgebase' ),
- 'type' => 'css',
- 'options' => '',
- 'field_class' => 'codemirror_css',
- ),
- );
-
- /**
- * Filters the Comments settings array
- *
- * @since 2.2.0
- *
- * @param array $settings Comments Settings array
- */
- return apply_filters( self::$prefix . '_settings_styles', $settings );
- }
-
- /**
- * Adding WordPress plugin action links.
- *
- * @since 2.2.0
- *
- * @param array $links Array of links.
- * @return array
- */
- public function plugin_actions_links( $links ) {
-
- return array_merge(
- array(
- 'settings' => '' . esc_html__( 'Settings', 'knowledgebase' ) . ' ',
- ),
- $links
- );
- }
-
- /**
- * Add meta links on Plugins page.
- *
- * @since 2.2.0
- *
- * @param array $links Array of Links.
- * @param string $file Current file.
- * @return array
- */
- public function plugin_row_meta( $links, $file ) {
-
- if ( false !== strpos( $file, 'knowledgebase.php' ) ) {
- $new_links = array(
- 'support' => '' . esc_html__( 'Support', 'knowledgebase' ) . ' ',
- );
-
- $links = array_merge( $links, $new_links );
- }
- return $links;
- }
-
- /**
- * Get the help sidebar content to display on the plugin settings page.
- *
- * @since 2.2.0
- */
- public function get_help_sidebar() {
-
- $help_sidebar =
- /* translators: 1: Plugin support site link. */
- '' . sprintf( __( 'For more information or how to get support visit the support site .', 'knowledgebase' ), esc_url( 'https://webberzone.com/support/' ) ) . '
' .
- /* translators: 1: WordPress.org support forums link. */
- '' . sprintf( __( 'Support queries should be posted in the WordPress.org support forums .', 'knowledgebase' ), esc_url( 'https://wordpress.org/support/plugin/knowledgebase' ) ) . '
' .
- '' . sprintf(
- /* translators: 1: Github issues link, 2: Github plugin page link. */
- __( 'Post an issue on GitHub (bug reports only).', 'knowledgebase' ),
- esc_url( 'https://github.com/ajaydsouza/knowledgebase/issues' ),
- esc_url( 'https://github.com/ajaydsouza/knowledgebase' )
- ) . '
';
-
- /**
- * Filter to modify the help sidebar content.
- *
- * @since 2.2.0
- *
- * @param string $help_sidebar Help sidebar content.
- */
- return apply_filters( self::$prefix . '_settings_help_sidebar', $help_sidebar );
- }
-
- /**
- * Get the help tabs to display on the plugin settings page.
- *
- * @since 2.2.0
- */
- public function get_help_tabs() {
-
- $help_tabs = array(
- array(
- 'id' => 'wzkb-settings-general',
- 'title' => __( 'General', 'knowledgebase' ),
- 'content' =>
- '' . __( 'This screen provides the basic settings for configuring your knowledge base.', 'knowledgebase' ) . '
' .
- '' . __( 'Set the knowledge base slugs which drive what the urls are for the knowledge base homepage, articles, categories and tags.', 'knowledgebase' ) . '
',
- ),
- array(
- 'id' => 'wzkb-settings-styles',
- 'title' => __( 'Styles', 'knowledgebase' ),
- 'content' =>
- '' . __( 'This screen provides options to control the look and feel of the knowledge base.', 'knowledgebase' ) . '
' .
- '' . __( 'Disable the styles included within the plugin and/or add your own CSS styles to customize this.', 'knowledgebase' ) . '
',
- ),
- );
-
- /**
- * Filter to add more help tabs.
- *
- * @since 2.2.0
- *
- * @param array $help_tabs Associative array of help tabs.
- */
- return apply_filters( self::$prefix . '_settings_help_tabs', $help_tabs );
- }
-
- /**
- * Function to add contextual help in the Tools page.
- *
- * @since 2.2.0
- */
- public function settings_help() {
- $screen = get_current_screen();
-
- if ( $screen->id === $this->tools_page ) {
-
- $screen->set_help_sidebar( $this->get_help_sidebar() );
-
- $screen->add_help_tab(
- array(
- 'id' => 'wzkb-tools-general',
- 'title' => __( 'Tools', 'knowledgebase' ),
- 'content' =>
- '' . __( 'This screen gives you a few tools namely one click buttons to run the closing algorithm or open comments, pingbacks/trackbacks.', 'knowledgebase' ) . '
' .
- '' . __( 'You can also delete the old settings from prior to v2.0.0', 'knowledgebase' ) . '
',
- )
- );
- }
- }
-
- /**
- * Add CSS to admin head.
- *
- * @since 2.2.0
- */
- public function admin_head() {
- if ( ! is_customize_preview() ) {
- $css = '
- ';
-
- echo $css; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- }
- }
-
- /**
- * Function to add a link below the page header of the Settings page.
- *
- * @since 2.2.0
- */
- public function settings_page_header() {
- ?>
-
-
-
-
-
- ',
- '',
- ''
- );
- }
-
- /**
- * Modify settings when they are being saved.
- *
- * @since 2.2.0
- *
- * @param array $settings Settings array.
- * @return array $settings Sanitized settings array.
- */
- public function change_settings_on_save( $settings ) {
-
- // Delete the cache.
- wzkb_cache_delete();
-
- return $settings;
- }
- }
-
- /** Initiate the class */
- add_action(
- 'init',
- function () {
- Knowledgebase_Settings::get_instance();
- },
- 999
- );
-
-endif;
diff --git a/includes/admin/settings/class-metabox-api.php b/includes/admin/settings/class-metabox-api.php
new file mode 100644
index 0000000..c635466
--- /dev/null
+++ b/includes/admin/settings/class-metabox-api.php
@@ -0,0 +1,352 @@
+ '',
+ 'prefix' => '',
+ 'post_type' => '',
+ 'title' => '',
+ 'registered_settings' => array(),
+ 'checkbox_modified_text' => '',
+ );
+
+ $args = wp_parse_args( $args, $defaults );
+
+ foreach ( $args as $name => $value ) {
+ $this->$name = $value;
+ }
+
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
+ add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
+ add_action( "save_post_{$this->post_type}", array( $this, 'save' ) );
+ }
+
+ /**
+ * Function to add the metabox.
+ */
+ public function add_meta_boxes() {
+ add_meta_box(
+ $this->prefix . '_metabox_id',
+ $this->title,
+ array( $this, 'html' ),
+ $this->post_type,
+ 'advanced',
+ 'high'
+ );
+ }
+
+ /**
+ * Enqueue scripts and styles.
+ *
+ * @param string $hook The current admin page.
+ */
+ public function admin_enqueue_scripts( $hook ) {
+ if ( in_array( $hook, array( 'post.php', 'post-new.php' ), true ) || get_current_screen()->post_type === $this->post_type ) {
+ self::enqueue_scripts_styles();
+ }
+ }
+
+ /**
+ * Enqueues all scripts, styles, settings, and templates necessary to use the Settings API.
+ */
+ public static function enqueue_scripts_styles() {
+
+ $minimize = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
+
+ wp_enqueue_style( 'wp-color-picker' );
+
+ wp_enqueue_media();
+ wp_enqueue_script( 'wp-color-picker' );
+ wp_enqueue_script( 'jquery' );
+ wp_enqueue_script( 'jquery-ui-autocomplete' );
+ wp_enqueue_script( 'jquery-ui-tabs' );
+
+ wp_enqueue_code_editor(
+ array(
+ 'type' => 'text/html',
+ 'codemirror' => array(
+ 'indentUnit' => 2,
+ 'tabSize' => 2,
+ ),
+ )
+ );
+
+ // Enqueue WZ Admin JS.
+ wp_enqueue_script( 'wz-admin-js' );
+ wp_enqueue_script( 'wz-codemirror-js' );
+ wp_enqueue_script( 'wz-taxonomy-suggest-js' );
+ wp_enqueue_script( 'wz-media-selector-js' );
+ }
+
+ /**
+ * Function to save the metabox.
+ *
+ * @param int|string $post_id Post ID.
+ */
+ public function save( $post_id ) {
+
+ $post_meta = array();
+
+ // Bail if we're doing an auto save.
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
+ return;
+ }
+
+ // If our nonce isn't there, or we can't verify it, bail.
+ if ( ! isset( $_POST[ $this->prefix . '_meta_box_nonce' ] ) || ! wp_verify_nonce( sanitize_key( $_POST[ $this->prefix . '_meta_box_nonce' ] ), $this->prefix . '_meta_box' ) ) {
+ return;
+ }
+
+ // If our current user can't edit this post, bail.
+ if ( ! current_user_can( 'edit_post', $post_id ) ) {
+ return;
+ }
+
+ if ( empty( $_POST[ $this->settings_key ] ) ) {
+ return;
+ }
+
+ $settings_sanitize = new Settings_Sanitize();
+
+ $posted = $_POST[ $this->settings_key ]; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash
+
+ foreach ( $this->registered_settings as $setting ) {
+ $id = $setting['id'];
+ $type = isset( $setting['type'] ) ? $setting['type'] : 'text';
+
+ /**
+ * Skip settings that are not really settings.
+ *
+ * @param array $non_setting_types Array of types which are not settings.
+ */
+ $non_setting_types = apply_filters( $this->prefix . '_metabox_non_setting_types', array( 'header', 'descriptive_text' ) );
+
+ if ( in_array( $type, $non_setting_types, true ) ) {
+ continue;
+ }
+
+ if ( isset( $posted[ $id ] ) ) {
+ $value = $posted[ $id ];
+ $sanitize_callback = is_callable( array( $settings_sanitize, "sanitize_{$type}_field" ) ) ? array( $settings_sanitize, "sanitize_{$type}_field" ) : array( $settings_sanitize, 'sanitize_missing' );
+ $post_meta[ $id ] = call_user_func( $sanitize_callback, $value );
+ }
+ }
+
+ // Run the array through a generic function that allows access to all of the settings.
+ $post_meta = call_user_func( array( $this, 'sanitize_post_meta' ), $post_meta );
+
+ /**
+ * Filter the post meta array which contains post-specific settings.
+ *
+ * @param array $post_meta Array of ATA metabox settings.
+ * @param int $post_id Post ID
+ */
+ $post_meta = apply_filters( "{$this->prefix}_meta_key", $post_meta, $post_id );
+
+ // Now loop through the settings array and either save or delete the meta key.
+ foreach ( $this->registered_settings as $setting ) {
+ if ( empty( $post_meta[ $setting['id'] ] ) ) {
+ delete_post_meta( $post_id, "_{$this->prefix}_{$setting['id']}" );
+ }
+ }
+
+ foreach ( $post_meta as $setting => $value ) {
+ if ( empty( $post_meta[ $setting ] ) ) {
+ delete_post_meta( $post_id, "_{$this->prefix}_$setting" );
+ } else {
+ update_post_meta( $post_id, "_{$this->prefix}_$setting", $value );
+ }
+ }
+ }
+
+ /**
+ * Function to display the metabox.
+ *
+ * @param \WP_Post $post Post object.
+ */
+ public function html( $post ) {
+ // Add an nonce field so we can check for it later.
+ wp_nonce_field( $this->prefix . '_meta_box', $this->prefix . '_meta_box_nonce' );
+
+ $settings_form = new Settings_Form(
+ array(
+ 'settings_key' => $this->settings_key,
+ 'prefix' => $this->prefix,
+ 'checkbox_modified_text' => $this->checkbox_modified_text,
+ )
+ );
+
+ echo '
';
+
+ /**
+ * Action triggered when displaying Better Search meta box.
+ *
+ * @param object $post Post object.
+ */
+ do_action( $this->prefix . '_meta_box', $post );
+ }
+
+ /**
+ * Sanitize Post Meta array.
+ *
+ * @param array $settings Post meta settings array.
+ * @return array Sanitized value.
+ */
+ public function sanitize_post_meta( $settings ) {
+
+ // This array holds a list of keys that will be passed through our category/tags loop to determine the ids.
+ $keys = array(
+ 'include_on_category' => array(
+ 'tax' => 'category',
+ 'ids_field' => 'include_on_category_ids',
+ ),
+ 'include_on_post_tag' => array(
+ 'tax' => 'post_tag',
+ 'ids_field' => 'include_on_post_tag_ids',
+ ),
+ );
+
+ foreach ( $keys as $key => $fields ) {
+ if ( isset( $settings[ $key ] ) ) {
+ $ids = array();
+ $names = array();
+
+ $taxes = array_unique( str_getcsv( $settings[ $key ] ) );
+
+ foreach ( $taxes as $tax ) {
+ $tax_name = get_term_by( 'name', $tax, $fields['tax'] );
+
+ if ( isset( $tax_name->term_taxonomy_id ) ) {
+ $ids[] = $tax_name->term_taxonomy_id;
+ $names[] = $tax_name->name;
+ }
+ }
+ $settings[ $fields['ids_field'] ] = join( ',', $ids );
+ $settings[ $key ] = Settings_Sanitize::str_putcsv( $names );
+ } else {
+ $settings[ $fields['ids_field'] ] = '';
+ }
+ }
+
+ return $settings;
+ }
+}
diff --git a/includes/admin/settings/class-settings-api.php b/includes/admin/settings/class-settings-api.php
index 54b3aa2..0402f7c 100644
--- a/includes/admin/settings/class-settings-api.php
+++ b/includes/admin/settings/class-settings-api.php
@@ -5,1529 +5,860 @@
* Functions to register, read, write and update settings.
* Portions of this code have been inspired by Easy Digital Downloads, WordPress Settings Sandbox, WordPress Settings API class, etc.
*
- * @link https://webberzone.com
- *
- * @package Knowledgebase
- * @subpackage Admin
+ * @package WebberZone\Knowledge_Base
*/
-namespace Knowledgebase_Admin;
+namespace WebberZone\Knowledge_Base\Admin\Settings;
// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
die;
}
-if ( ! class_exists( 'Settings_API' ) ) :
+/**
+ * Settings API wrapper class
+ *
+ * @version 2.5.2
+ */
+#[\AllowDynamicProperties]
+class Settings_API {
+
/**
- * Settings API wrapper class
+ * Current version number
*
- * @version 2.2.0
+ * @var string
*/
- class Settings_API {
-
- /**
- * Current version number
- *
- * @var string
- */
- const VERSION = '2.2.0';
-
- /**
- * Settings Key.
- *
- * @var string Settings Key.
- */
- public $settings_key;
-
- /**
- * Prefix which is used for creating the unique filters and actions.
- *
- * @var string Prefix.
- */
- public $prefix;
-
- /**
- * Translation strings.
- *
- * @var array Translation strings.
- */
- public $translation_strings;
-
- /**
- * Menu type.
- *
- * @see add_custom_menu_page()
- *
- * @var string Menu slug.
- */
- public $menu_type;
-
- /**
- * The slug name of the parent of the menu.
- *
- * @var string Menu slug of the parent.
- */
- public $parent_slug;
-
- /**
- * The slug name to refer to this menu by (should be unique for this menu).
- *
- * @var string Menu slug.
- */
- public $menu_slug;
-
- /**
- * Default navigation tab.
- *
- * @var string Default navigation tab.
- */
- protected $default_tab;
-
- /**
- * Settings page.
- *
- * @var string Settings page.
- */
- public $settings_page;
-
- /**
- * Admin Footer Text. Displayed at the bottom of the plugin settings page.
- *
- * @var string Admin Footer Text.
- */
- protected $admin_footer_text;
-
- /**
- * Array containing the settings' sections.
- *
- * @var array Settings sections array.
- */
- protected $settings_sections = array();
-
- /**
- * Array containing the settings' fields.
- *
- * @var array Settings fields array.
- */
- protected $registered_settings = array();
-
- /**
- * Array containing the settings' fields that need to be upgraded to the current Settings API.
- *
- * @var array Settings fields array.
- */
- protected $upgraded_settings = array();
-
- /**
- * Help sidebar content.
- *
- * @var string Admin Footer Text.
- */
- protected $help_sidebar;
-
- /**
- * Array of help tabs.
- *
- * @var array Settings sections array.
- */
- protected $help_tabs = array();
-
- /**
- * Main constructor class.
- *
- * @param string $settings_key Settings key.
- * @param string $prefix Prefix. Used for actions and filters.
- * @param mixed $args {
- * Array or string of arguments. Default is blank array.
- * @type array $translation_strings Translation strings.
- * @type array $settings_sections Settings sections.
- * @type array $props Properties.
- * @type array $registered_settings Registered settings.
- * @type array $upgraded_settings Upgraded settings.
- * }
- */
- public function __construct( $settings_key, $prefix, $args ) {
-
- if ( ! defined( 'WZ_SETTINGS_API_VERSION' ) ) {
- define( 'WZ_SETTINGS_API_VERSION', self::VERSION );
- }
-
- $this->settings_key = $settings_key;
- $this->prefix = $prefix;
-
- $defaults = array(
- 'translation_strings' => array(),
- 'props' => array(),
- 'settings_sections' => array(),
- 'registered_settings' => array(),
- 'upgraded_settings' => array(),
- );
- $args = wp_parse_args( $args, $defaults );
-
- $this->hooks();
- $this->set_translation_strings( $args['translation_strings'] );
- $this->set_props( $args['props'] );
- $this->set_sections( $args['settings_sections'] );
- $this->set_registered_settings( $args['registered_settings'] );
- $this->set_upgraded_settings( $args['upgraded_settings'] );
- }
-
- /**
- * Adds the functions to the appropriate WordPress hooks.
- */
- public function hooks() {
- add_action( 'admin_menu', array( $this, 'admin_menu' ), 11 );
- add_action( 'admin_init', array( $this, 'admin_init' ) );
- add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ) );
- add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
- }
-
- /**
- * Sets properties.
- *
- * @param array|string $args {
- * Array or string of arguments. Default is blank array.
- *
- * @type string $menu_type Admin menu type. See add_custom_menu_page() for options.
- * @type string $menu_parent Parent menu slug.
- * @type string $menu_slug Admin menu slug.
- * @type string $default_tab Default tab.
- * @type string $admin_footer_text Admin footer text.
- * @type string $help_sidebar Help sidebar.
- * @type array $help_tabs Help tabs.
- * }
- */
- public function set_props( $args ) {
-
- $defaults = array(
- 'menu_type' => 'options',
- 'parent_slug' => 'options-general.php',
- 'menu_slug' => '',
- 'default_tab' => 'general',
- 'admin_footer_text' => '',
- 'help_sidebar' => '',
- 'help_tabs' => array(),
- );
-
- $args = wp_parse_args( $args, $defaults );
-
- foreach ( $args as $name => $value ) {
- $this->$name = $value;
- }
- }
-
- /**
- * Sets translation strings.
- *
- * @param array $strings {
- * Array of translation strings.
- *
- * @type string $page_title Page title.
- * @type string $menu_title Menu title.
- * @type string $page_header Page header.
- * @type string $reset_message Reset message.
- * @type string $success_message Success message.
- * @type string $save_changes Save changes button label.
- * @type string $reset_settings Reset settings button label.
- * @type string $reset_button_confirm Reset button confirmation message.
- * @type string $checkbox_modified Checkbox modified label.
- * }
- *
- * @return void
- */
- public function set_translation_strings( $strings ) {
-
- // Args prefixed with an underscore are reserved for internal use.
- $defaults = array(
- 'page_title' => '',
- 'menu_title' => '',
- 'page_header' => '',
- 'reset_message' => __( 'Settings have been reset to their default values. Reload this page to view the updated settings.' ),
- 'success_message' => __( 'Settings updated.' ),
- 'save_changes' => __( 'Save Changes' ),
- 'reset_settings' => __( 'Reset all settings' ),
- 'reset_button_confirm' => __( 'Do you really want to reset all these settings to their default values?' ),
- 'checkbox_modified' => __( 'Modified from default setting' ),
- );
-
- $strings = wp_parse_args( $strings, $defaults );
-
- $this->translation_strings = $strings;
- }
-
- /**
- * Set settings sections
- *
- * @param array $sections Setting sections array.
- * @return object Class object.
- */
- public function set_sections( $sections ) {
- $this->settings_sections = (array) $sections;
-
- return $this;
- }
-
- /**
- * Add a single section
- *
- * @param array $section New Section.
- * @return object Object of the class instance.
- */
- public function add_section( $section ) {
- $this->settings_sections[] = $section;
-
- return $this;
- }
-
- /**
- * Set the settings fields for registered settings.
- *
- * @param array $registered_settings Registered settings array.
- * @return object Object of the class instance.
- */
- public function set_registered_settings( $registered_settings ) {
- $this->registered_settings = (array) $registered_settings;
-
- return $this;
- }
-
- /**
- * Set the settings fields for settings to upgrade.
- *
- * @param array $upgraded_settings Settings array.
- * @return object Object of the class instance.
- */
- public function set_upgraded_settings( $upgraded_settings = array() ) {
- $this->upgraded_settings = (array) $upgraded_settings;
-
- return $this;
- }
-
- /**
- * Add a menu page to the WordPress admin area.
- *
- * @param array $menu Array of settings for the menu page.
- */
- public function add_custom_menu_page( $menu ) {
- $defaults = array(
-
- // Modes: submenu, management, options, theme, plugins, users, dashboard, posts, media, links, pages, comments.
- 'type' => 'submenu',
-
- // Submenu default settings.
- 'parent_slug' => 'options-general.php',
- 'page_title' => '',
- 'menu_title' => '',
- 'capability' => 'manage_options',
- 'menu_slug' => '',
- 'function' => array( $this, 'plugin_settings' ),
-
- // Menu default settings.
- 'icon_url' => 'dashicons-admin-generic',
- 'position' => null,
-
- );
- $menu = wp_parse_args( $menu, $defaults );
-
- switch ( $menu['type'] ) {
- case 'submenu':
- $menu_page = add_submenu_page(
- $menu['parent_slug'],
- $menu['page_title'],
- $menu['menu_title'],
- $menu['capability'],
- $menu['menu_slug'],
- $menu['function'],
- $menu['position']
- );
- break;
- case 'management':
- case 'options':
- case 'theme':
- case 'plugins':
- case 'users':
- case 'dashboard':
- case 'posts':
- case 'media':
- case 'links':
- case 'pages':
- case 'comments':
- $f = 'add_' . $menu['type'] . '_page';
- if ( function_exists( $f ) ) {
- $menu_page = $f(
- $menu['page_title'],
- $menu['menu_title'],
- $menu['capability'],
- $menu['menu_slug'],
- $menu['function'],
- $menu['position']
- );
- }
- break;
- default:
- $menu_page = add_menu_page(
- $menu['page_title'],
- $menu['menu_title'],
- $menu['capability'],
- $menu['menu_slug'],
- $menu['function'],
- $menu['icon_url'],
- $menu['position']
- );
- break;
- }
-
- return $menu_page;
- }
-
-
- /**
- * Add admin menu.
- */
- public function admin_menu() {
- $menu = array(
- 'type' => $this->menu_type,
- 'parent_slug' => $this->parent_slug,
- 'page_title' => $this->translation_strings['page_title'],
- 'menu_title' => $this->translation_strings['menu_title'],
- 'capability' => 'manage_options',
- 'menu_slug' => $this->menu_slug,
- 'function' => array( $this, 'plugin_settings' ),
- );
-
- $this->settings_page = $this->add_custom_menu_page( $menu );
-
- // Load the settings contextual help.
- add_action( 'load-' . $this->settings_page, array( $this, 'settings_help' ) );
- }
-
- /**
- * Enqueue scripts and styles.
- *
- * @param string $hook The current admin page.
- */
- public function admin_enqueue_scripts( $hook ) {
-
- if ( $hook === $this->settings_page ) {
- $this->enqueue_scripts_styles();
- }
- }
-
- /**
- * Enqueues all scripts, styles, settings, and templates necessary to use the Settings API.
- */
- public function enqueue_scripts_styles() {
-
- $minimize = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
-
- wp_enqueue_style( 'wp-color-picker' );
-
- wp_enqueue_media();
- wp_enqueue_script( 'wp-color-picker' );
- wp_enqueue_script( 'jquery' );
- wp_enqueue_script( 'jquery-ui-autocomplete' );
- wp_enqueue_script( 'jquery-ui-tabs' );
-
- wp_enqueue_code_editor(
- array(
- 'type' => 'text/html',
- 'codemirror' => array(
- 'indentUnit' => 2,
- 'tabSize' => 2,
- ),
- )
- );
-
- wp_enqueue_script(
- 'wz-admin-js',
- plugins_url( 'js/admin-scripts' . $minimize . '.js', __FILE__ ),
- array( 'jquery' ),
- self::VERSION,
- true
- );
- wp_enqueue_script(
- 'wz-codemirror-js',
- plugins_url( 'js/apply-codemirror' . $minimize . '.js', __FILE__ ),
- array( 'jquery' ),
- self::VERSION,
- true
- );
- wp_enqueue_script(
- 'wz-taxonomy-suggest-js',
- plugins_url( 'js/taxonomy-suggest' . $minimize . '.js', __FILE__ ),
- array( 'jquery' ),
- self::VERSION,
- true
- );
- }
-
- /**
- * Initialize and registers the settings sections and fileds to WordPress
- *
- * Usually this should be called at `admin_init` hook.
- *
- * This public function gets the initiated settings sections and fields. Then
- * registers them to WordPress and ready for use.
- */
- public function admin_init() {
-
- $settings_key = $this->settings_key;
-
- if ( false === get_option( $settings_key ) ) {
- add_option( $settings_key, $this->settings_defaults() );
- }
-
- foreach ( $this->registered_settings as $section => $settings ) {
-
- add_settings_section(
- "{$settings_key}_{$section}", // ID used to identify this section and with which to register options.
- __return_null(), // No title, we will handle this via a separate function.
- '__return_false', // No callback function needed. We'll process this separately.
- "{$settings_key}_{$section}" // Page on which these options will be added.
- );
-
- foreach ( $settings as $setting ) {
-
- $args = wp_parse_args(
- $setting,
- array(
- 'section' => $section,
- 'id' => null,
- 'name' => '',
- 'desc' => '',
- 'type' => null,
- 'options' => '',
- 'max' => null,
- 'min' => null,
- 'step' => null,
- 'size' => null,
- 'field_class' => '',
- 'field_attributes' => '',
- 'placeholder' => '',
- )
- );
-
- $id = $args['id'];
- $name = $args['name'];
- $type = isset( $args['type'] ) ? $args['type'] : 'text';
- $callback = method_exists( $this, "callback_{$type}" ) ? array( $this, "callback_{$type}" ) : array( $this, 'callback_missing' );
-
- add_settings_field(
- "{$settings_key}[{$id}]", // ID of the settings field. We save it within the settings array.
- $name, // Label of the setting.
- $callback, // Function to handle the setting.
- "{$settings_key}_{$section}", // Page to display the setting. In our case it is the section as defined above.
- "{$settings_key}_{$section}", // Name of the section.
- $args
- );
- }
- }
-
- // Register the settings into the options table.
- register_setting( $settings_key, $settings_key, array( $this, 'settings_sanitize' ) );
- }
-
- /**
- * Flattens $this->registered_settings into $setting[id] => $setting[type] format.
- *
- * @return array Default settings
- */
- public function get_registered_settings_types() {
-
- $options = array();
-
- // Populate some default values.
- foreach ( $this->registered_settings as $tab => $settings ) {
- foreach ( $settings as $option ) {
- $options[ $option['id'] ] = $option['type'];
- }
- }
-
- /**
- * Filters the settings array.
- *
- * @param array $options Default settings.
- */
- return apply_filters( $this->prefix . '_get_settings_types', $options );
- }
-
-
- /**
- * Default settings.
- *
- * @return array Default settings
- */
- public function settings_defaults() {
-
- $options = array();
-
- // Populate some default values.
- foreach ( $this->registered_settings as $tab => $settings ) {
- foreach ( $settings as $option ) {
- // When checkbox is set to true, set this to 1.
- if ( 'checkbox' === $option['type'] && ! empty( $option['options'] ) ) {
- $options[ $option['id'] ] = 1;
- } else {
- $options[ $option['id'] ] = 0;
- }
- // If an option is set.
- if ( in_array( $option['type'], array( 'textarea', 'css', 'html', 'text', 'url', 'csv', 'color', 'numbercsv', 'postids', 'posttypes', 'number', 'wysiwyg', 'file', 'password' ), true ) && isset( $option['options'] ) ) {
- $options[ $option['id'] ] = $option['options'];
- }
- if ( in_array( $option['type'], array( 'multicheck', 'radio', 'select', 'radiodesc', 'thumbsizes' ), true ) && isset( $option['default'] ) ) {
- $options[ $option['id'] ] = $option['default'];
- }
- }
- }
+ const VERSION = '2.5.2';
- $upgraded_settings = $this->upgraded_settings;
-
- if ( false !== $upgraded_settings ) {
- $options = array_merge( $options, $upgraded_settings );
- }
-
- /**
- * Filters the default settings array.
- *
- * @param array $options Default settings.
- */
- return apply_filters( $this->prefix . '_settings_defaults', $options );
- }
-
-
- /**
- * Get the default option for a specific key
- *
- * @param string $key Key of the option to fetch.
- * @return mixed
- */
- public function get_default_option( $key = '' ) {
-
- $default_settings = $this->settings_defaults();
-
- if ( array_key_exists( $key, $default_settings ) ) {
- return $default_settings[ $key ];
- } else {
- return false;
- }
- }
-
-
- /**
- * Reset settings.
- *
- * @return void
- */
- public function settings_reset() {
- delete_option( $this->settings_key );
- }
-
- /**
- * Get field description for display.
- *
- * @param array $args settings Arguments array.
- */
- public function get_field_description( $args ) {
- if ( ! empty( $args['desc'] ) ) {
- $desc = '' . wp_kses_post( $args['desc'] ) . '
';
- } else {
- $desc = '';
- }
-
- /**
- * After Settings Output filter
- *
- * @param string $desc Description of the field.
- * @param array $args Arguments array.
- */
- $desc = apply_filters( $this->prefix . '_setting_field_description', $desc, $args );
- return $desc;
- }
-
- /**
- * Get the value of a settings field.
- *
- * @param string $option Settings field name.
- * @param string $default_value Default text if it's not found.
- * @return string
- */
- public function get_option( $option, $default_value = '' ) {
-
- $options = get_option( $this->settings_key );
-
- if ( isset( $options[ $option ] ) ) {
- return $options[ $option ];
- }
-
- return $default_value;
- }
-
- /**
- * Miscellaneous callback funcion
- *
- * @param array $args Arguments array.
- * @return void
- */
- public function callback_missing( $args ) {
- /* translators: 1: Code. */
- printf( esc_html__( 'The callback function used for the %1$s setting is missing.' ), '' . esc_attr( $args['id'] ) . ' ' );
- }
-
- /**
- * Header Callback
- *
- * Renders the header.
- *
- * @param array $args Arguments passed by the setting.
- * @return void
- */
- public function callback_header( $args ) {
- $html = $this->get_field_description( $args );
-
- /**
- * After Settings Output filter
- *
- * @param string $html HTML string.
- * @param array $args Arguments array.
- */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- }
-
- /**
- * Descriptive text callback.
- *
- * Renders descriptive text onto the settings field.
- *
- * @param array $args Array of arguments.
- * @return void
- */
- public function callback_descriptive_text( $args ) {
- $this->callback_header( $args );
- }
-
- /**
- * Display text fields.
- *
- * @param array $args Array of arguments.
- */
- public function callback_text( $args ) {
-
- $value = $this->get_option( $args['id'], $args['options'] );
- $size = sanitize_html_class( ( isset( $args['size'] ) && ! is_null( $args['size'] ) ) ? $args['size'] : 'regular' );
- $class = sanitize_html_class( $args['field_class'] );
- $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"';
- $disabled = ! empty( $args['disabled'] ) ? ' disabled="disabled"' : '';
- $readonly = ( isset( $args['readonly'] ) && true === $args['readonly'] ) ? ' readonly="readonly"' : '';
- $attributes = $disabled . $readonly;
-
- foreach ( (array) $args['field_attributes'] as $attribute => $val ) {
- $attributes .= sprintf( ' %1$s="%2$s"', $attribute, esc_attr( $val ) );
- }
-
- $html = sprintf(
- ' ',
- $this->settings_key,
- sanitize_key( $args['id'] ),
- $class . ' ' . $size . '-text',
- esc_attr( stripslashes( $value ) ),
- $attributes,
- $placeholder
- );
- $html .= $this->get_field_description( $args );
-
- /** This filter has been defined in class-settings-api.php */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- }
-
- /**
- * Display url fields.
- *
- * @param array $args Array of arguments.
- */
- public function callback_url( $args ) {
- $this->callback_text( $args );
- }
-
- /**
- * Display csv fields.
- *
- * @param array $args Array of arguments.
- */
- public function callback_csv( $args ) {
- $this->callback_text( $args );
- }
-
- /**
- * Display color fields.
- *
- * @param array $args Array of arguments.
- */
- public function callback_color( $args ) {
- $this->callback_text( $args );
- }
-
- /**
- * Display numbercsv fields.
- *
- * @param array $args Array of arguments.
- */
- public function callback_numbercsv( $args ) {
- $this->callback_text( $args );
- }
-
- /**
- * Display postids fields.
- *
- * @param array $args Array of arguments.
- */
- public function callback_postids( $args ) {
- $this->callback_text( $args );
- }
-
- /**
- * Display textarea.
- *
- * @param array $args Array of arguments.
- * @return void
- */
- public function callback_textarea( $args ) {
-
- $value = $this->get_option( $args['id'], $args['options'] );
- $class = sanitize_html_class( $args['field_class'] );
-
- $html = sprintf(
- '',
- $this->settings_key,
- sanitize_key( $args['id'] ),
- esc_textarea( stripslashes( $value ) ),
- 'large-text ' . $class
- );
- $html .= $this->get_field_description( $args );
-
- /** This filter has been defined in class-settings-api.php */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- }
-
- /**
- * Display CSS fields.
- *
- * @param array $args Array of arguments.
- * @return void
- */
- public function callback_css( $args ) {
- $this->callback_textarea( $args );
- }
-
- /**
- * Display HTML fields.
- *
- * @param array $args Array of arguments.
- * @return void
- */
- public function callback_html( $args ) {
- $this->callback_textarea( $args );
- }
-
- /**
- * Display checkboxes.
- *
- * @param array $args Array of arguments.
- * @return void
- */
- public function callback_checkbox( $args ) {
-
- $value = $this->get_option( $args['id'], $args['options'] );
- $checked = ! empty( $value ) ? checked( 1, $value, false ) : '';
- $default = isset( $args['options'] ) ? (int) $args['options'] : '';
+ /**
+ * Settings Key.
+ *
+ * @var string Settings Key.
+ */
+ public $settings_key;
- $html = sprintf( ' ', $this->settings_key, sanitize_key( $args['id'] ) );
- $html .= sprintf( ' ', $this->settings_key, sanitize_key( $args['id'] ), $checked );
- $html .= ( (bool) $value !== (bool) $default ) ? '' . $this->translation_strings['checkbox_modified'] . ' ' : ''; // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
- $html .= $this->get_field_description( $args );
+ /**
+ * Prefix which is used for creating the unique filters and actions.
+ *
+ * @var string Prefix.
+ */
+ public $prefix;
- /** This filter has been defined in class-settings-api.php */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- }
+ /**
+ * Translation strings.
+ *
+ * @see set_translation_strings()
+ *
+ * @var array Translation strings.
+ */
+ public $translation_strings;
- /**
- * Multicheck Callback
- *
- * Renders multiple checkboxes.
- *
- * @param array $args Array of arguments.
- * @return void
- */
- public function callback_multicheck( $args ) {
- $html = '';
-
- $value = $this->get_option( $args['id'], $args['options'] );
-
- if ( ! empty( $args['options'] ) ) {
- $html .= sprintf( ' ', $this->settings_key, $args['id'] );
-
- foreach ( $args['options'] as $key => $option ) {
- if ( isset( $value[ $key ] ) ) {
- $enabled = $key;
- } else {
- $enabled = null;
- }
-
- $html .= sprintf(
- ' ',
- $this->settings_key,
- sanitize_key( $args['id'] ),
- sanitize_key( $key ),
- esc_attr( $key ),
- checked( $key, $enabled, false )
- );
- $html .= sprintf(
- '%4$s ',
- $this->settings_key,
- sanitize_key( $args['id'] ),
- sanitize_key( $key ),
- $option
- );
- }
+ /**
+ * Menus.
+ *
+ * @var array Menus.
+ */
+ public $menus = array();
- $html .= $this->get_field_description( $args );
- }
+ /**
+ * Menu pages.
+ *
+ * @var array Menu pages.
+ */
+ public $menu_pages = array();
- /** This filter has been defined in class-settings-api.php */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- }
+ /**
+ * Default navigation tab.
+ *
+ * @var string Default navigation tab.
+ */
+ protected $default_tab;
- /**
- * Radio Callback
- *
- * Renders radio boxes.
- *
- * @param array $args Array of arguments.
- * @return void
- */
- public function callback_radio( $args ) {
- $html = '';
-
- $value = $this->get_option( $args['id'], $args['default'] );
-
- foreach ( $args['options'] as $key => $option ) {
- $html .= sprintf(
- ' ',
- $this->settings_key,
- sanitize_key( $args['id'] ),
- $key,
- checked( $value, $key, false )
- );
- $html .= sprintf(
- '%4$s ',
- $this->settings_key,
- sanitize_key( $args['id'] ),
- $key,
- $option
- );
- }
+ /**
+ * Settings page.
+ *
+ * @var string Settings page.
+ */
+ public $settings_page = '';
- $html .= $this->get_field_description( $args );
+ /**
+ * Admin Footer Text. Displayed at the bottom of the plugin settings page.
+ *
+ * @var string Admin Footer Text.
+ */
+ protected $admin_footer_text;
- /** This filter has been defined in class-settings-api.php */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- }
+ /**
+ * Array containing the settings' sections.
+ *
+ * @var array Settings sections array.
+ */
+ protected $settings_sections = array();
- /**
- * Radio callback with description.
- *
- * Renders radio boxes with each item having it separate description.
- *
- * @param array $args Array of arguments.
- * @return void
- */
- public function callback_radiodesc( $args ) {
- $html = '';
-
- $value = $this->get_option( $args['id'], $args['default'] );
-
- foreach ( $args['options'] as $option ) {
- $html .= sprintf(
- ' ',
- $this->settings_key,
- sanitize_key( $args['id'] ),
- $option['id'],
- checked( $value, $option['id'], false )
- );
- $html .= sprintf(
- '%4$s ',
- $this->settings_key,
- sanitize_key( $args['id'] ),
- $option['id'],
- $option['name']
- );
+ /**
+ * Array containing the settings' fields.
+ *
+ * @var array Settings fields array.
+ */
+ protected $registered_settings = array();
- $html .= ': ' . wp_kses_post( $option['description'] ) . ' ';
- }
+ /**
+ * Array containing the settings' fields that need to be upgraded to the current Settings API.
+ *
+ * @var array Settings fields array.
+ */
+ protected $upgraded_settings = array();
- $html .= $this->get_field_description( $args );
+ /**
+ * Help sidebar content.
+ *
+ * @var string Admin Footer Text.
+ */
+ protected $help_sidebar;
- /** This filter has been defined in class-settings-api.php */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- }
+ /**
+ * Array of help tabs.
+ *
+ * @var array Settings sections array.
+ */
+ protected $help_tabs = array();
- /**
- * Radio callback with description.
- *
- * Renders radio boxes with each item having it separate description.
- *
- * @param array $args Array of arguments.
- * @return void
- */
- public function callback_thumbsizes( $args ) {
- $html = '';
-
- $value = $this->get_option( $args['id'], $args['default'] );
-
- foreach ( $args['options'] as $name => $option ) {
- $html .= sprintf(
- ' ',
- $this->settings_key,
- sanitize_key( $args['id'] ),
- $name,
- checked( $value, $name, false )
- );
- $html .= sprintf(
- '%3$s (%4$sx%5$s%6$s) ',
- $this->settings_key,
- sanitize_key( $args['id'] ),
- $name,
- (int) $option['width'],
- (int) $option['height'],
- (bool) $option['crop'] ? ' ' . __( 'cropped' ) : ''
- );
- }
+ /**
+ * Settings form.
+ *
+ * @since 2.0.0
+ *
+ * @var object Settings form.
+ */
+ public $settings_form;
- $html .= $this->get_field_description( $args );
+ /**
+ * Main constructor class.
+ *
+ * @param string $settings_key Settings key.
+ * @param string $prefix Prefix. Used for actions and filters.
+ * @param mixed $args {
+ * Array or string of arguments. Default is blank array.
+ * @type array $translation_strings Translation strings.
+ * @type array $settings_sections Settings sections.
+ * @type array $props Properties.
+ * @type array $registered_settings Registered settings.
+ * @type array $upgraded_settings Upgraded settings.
+ * }
+ */
+ public function __construct( $settings_key, $prefix, $args ) {
- /** This filter has been defined in class-settings-api.php */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ if ( ! defined( 'WZ_SETTINGS_API_VERSION' ) ) {
+ define( 'WZ_SETTINGS_API_VERSION', self::VERSION );
}
- /**
- * Number Callback
- *
- * Renders number fields.
- *
- * @param array $args Array of arguments.
- * @return void
- */
- public function callback_number( $args ) {
- $value = $this->get_option( $args['id'], $args['options'] );
- $max = isset( $args['max'] ) ? intval( $args['max'] ) : 999999;
- $min = isset( $args['min'] ) ? intval( $args['min'] ) : 0;
- $step = isset( $args['step'] ) ? intval( $args['step'] ) : 1;
- $size = ( isset( $args['size'] ) && ! is_null( $args['size'] ) ) ? $args['size'] : 'regular';
- $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . esc_attr( $args['placeholder'] ) . '"';
-
- $html = sprintf(
- ' ',
- esc_attr( (string) $step ),
- esc_attr( (string) $max ),
- esc_attr( (string) $min ),
- sanitize_html_class( $size ) . '-text',
- sanitize_key( $args['id'] ),
- esc_attr( stripslashes( $value ) ),
- $placeholder,
- $this->settings_key
- );
- $html .= $this->get_field_description( $args );
+ $this->settings_key = $settings_key;
+ $this->prefix = $prefix;
+
+ $defaults = array(
+ 'translation_strings' => array(),
+ 'props' => array(),
+ 'settings_sections' => array(),
+ 'registered_settings' => array(),
+ 'upgraded_settings' => array(),
+ );
+ $args = wp_parse_args( $args, $defaults );
+
+ $this->hooks();
+ $this->set_translation_strings( $args['translation_strings'] );
+ $this->set_props( $args['props'] );
+ $this->set_sections( $args['settings_sections'] );
+ $this->set_registered_settings( $args['registered_settings'] );
+ $this->set_upgraded_settings( $args['upgraded_settings'] );
+ }
- /** This filter has been defined in class-settings-api.php */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- }
+ /**
+ * Adds the functions to the appropriate WordPress hooks.
+ */
+ public function hooks() {
+ add_action( 'admin_menu', array( $this, 'admin_menu' ), 11 );
+ add_action( 'admin_init', array( $this, 'admin_init' ) );
+ add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ) );
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
+ add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
+ }
- /**
- * Select Callback
- *
- * Renders select fields.
- *
- * @param array $args Array of arguments.
- * @return void
- */
- public function callback_select( $args ) {
- $value = $this->get_option( $args['id'], $args['options'] );
+ /**
+ * Filters the CSS classes for the body tag in the admin.
+ *
+ * @param string $classes Space-separated list of CSS classes.
+ * @return string Space-separated list of CSS classes.
+ */
+ public function admin_body_class( $classes ) {
+ $current_screen = get_current_screen();
- if ( isset( $args['chosen'] ) ) {
- $chosen = 'class="chosen"';
- } else {
- $chosen = '';
- }
+ if ( in_array( $current_screen->id, $this->menu_pages, true ) ) {
+ $classes .= ' ' . $this->prefix . '-dashboard-page';
+ }
+ return $classes;
+ }
- $html = sprintf( ' ', $this->settings_key, sanitize_key( $args['id'] ), $chosen );
+ /**
+ * Sets properties.
+ *
+ * @param array|string $args {
+ * Array or string of arguments. Default is blank array.
+ *
+ * @type array $menus Array of admin menus. See add_custom_menu_page() for more info.
+ * @type string $default_tab Default tab.
+ * @type string $admin_footer_text Admin footer text.
+ * @type string $help_sidebar Help sidebar.
+ * @type array $help_tabs Help tabs.
+ * }
+ */
+ public function set_props( $args ) {
- foreach ( $args['options'] as $option => $name ) {
- $html .= sprintf( '%3$s ', sanitize_key( $option ), selected( $option, $value, false ), $name );
- }
+ $defaults = array(
+ 'menus' => array(),
+ 'default_tab' => 'general',
+ 'admin_footer_text' => '',
+ 'help_sidebar' => '',
+ 'help_tabs' => array(),
+ );
- $html .= '';
- $html .= $this->get_field_description( $args );
+ $args = wp_parse_args( $args, $defaults );
- /** This filter has been defined in class-settings-api.php */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ foreach ( $args as $name => $value ) {
+ $this->$name = $value;
}
+ }
- /**
- * Display posttypes fields.
- *
- * @param array $args Array of arguments.
- * @return void
- */
- public function callback_posttypes( $args ) {
- $html = '';
+ /**
+ * Sets translation strings.
+ *
+ * @param array $strings {
+ * Array of translation strings.
+ *
+ * @type string $page_title Page title.
+ * @type string $menu_title Menu title.
+ * @type string $page_header Page header.
+ * @type string $reset_message Reset message.
+ * @type string $success_message Success message.
+ * @type string $save_changes Save changes button label.
+ * @type string $reset_settings Reset settings button label.
+ * @type string $reset_button_confirm Reset button confirmation message.
+ * @type string $checkbox_modified Checkbox modified label.
+ * }
+ *
+ * @return void
+ */
+ public function set_translation_strings( $strings ) {
+
+ // Args prefixed with an underscore are reserved for internal use.
+ $defaults = array(
+ 'page_header' => '',
+ 'reset_message' => __( 'Settings have been reset to their default values. Reload this page to view the updated settings.' ),
+ 'success_message' => __( 'Settings updated.' ),
+ 'save_changes' => __( 'Save Changes' ),
+ 'reset_settings' => __( 'Reset all settings' ),
+ 'reset_button_confirm' => __( 'Do you really want to reset all these settings to their default values?' ),
+ 'checkbox_modified' => __( 'Modified from default setting' ),
+ );
+
+ $strings = wp_parse_args( $strings, $defaults );
+
+ $this->translation_strings = $strings;
+ }
- $options = $this->get_option( $args['id'], $args['options'] );
+ /**
+ * Set settings sections
+ *
+ * @param array $sections Setting sections array in the format of: id => Title.
+ * @return object Class object.
+ */
+ public function set_sections( $sections ) {
+ $this->settings_sections = (array) $sections;
- // If post_types contains a query string then parse it with wp_parse_args.
- if ( is_string( $options ) && strpos( $options, '=' ) ) {
- $post_types = wp_parse_args( $options );
- } else {
- $post_types = wp_parse_list( $options );
- }
+ return $this;
+ }
- $wp_post_types = get_post_types(
- array(
- 'public' => true,
- )
- );
- $posts_types_inc = array_intersect( $wp_post_types, $post_types );
+ /**
+ * Add a single section
+ *
+ * @param array $section New Section.
+ * @return object Object of the class instance.
+ */
+ public function add_section( $section ) {
+ $this->settings_sections[] = $section;
- foreach ( $wp_post_types as $wp_post_type ) {
+ return $this;
+ }
- $html .= sprintf(
- ' ',
- sanitize_key( $args['id'] ),
- esc_attr( $wp_post_type ),
- checked( true, in_array( $wp_post_type, $posts_types_inc, true ), false ),
- $this->settings_key
- );
- $html .= sprintf( '%2$s ', sanitize_key( $args['id'] ), $wp_post_type, $this->settings_key );
+ /**
+ * Set the settings fields for registered settings.
+ *
+ * @param array $registered_settings {
+ * Array of settings in format id => attributes.
+ * @type string $section Section title.
+ * @type string $id Field ID.
+ * @type string $name Field name.
+ * @type string $desc Field description.
+ * @type string $type Field type.
+ * @type string $options Field default option(s).
+ * @type string $max Field max. Applicable for numbers.
+ * @type string $min Field min. Applicable for numbers.
+ * @type string $step Field step. Applicable for numbers.
+ * @type string $size Field size. Applicable for text and textarea.
+ * @type string $field_class CSS class.
+ * @type array $field_attributes HTML Attributes in the form of attribute => value.
+ * @type string $placeholder Placeholder. Applicable for text and textarea.
+ * @type string $sanitize_callback Sanitize callback.
+ * }
+ * }
+ * }
+ * @return object Object of the class instance.
+ */
+ public function set_registered_settings( $registered_settings ) {
+ $this->registered_settings = (array) $registered_settings;
- }
+ return $this;
+ }
+
+ /**
+ * Set the settings fields for settings to upgrade.
+ *
+ * @param array $upgraded_settings Settings array.
+ * @return object Object of the class instance.
+ */
+ public function set_upgraded_settings( $upgraded_settings = array() ) {
+ $this->upgraded_settings = (array) $upgraded_settings;
- $html .= $this->get_field_description( $args );
+ return $this;
+ }
- /** This filter has been defined in class-settings-api.php */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ /**
+ * Add a menu page to the WordPress admin area.
+ *
+ * @param array $menu Array of settings for the menu page.
+ */
+ public function add_custom_menu_page( $menu ) {
+ $defaults = array(
+
+ // Modes: submenu, management, options, theme, plugins, users, dashboard, posts, media, links, pages, comments.
+ 'type' => 'submenu',
+
+ // Submenu default settings.
+ 'parent_slug' => 'options-general.php',
+ 'page_title' => '',
+ 'menu_title' => '',
+ 'capability' => $this->get_capability_for_menu(),
+ 'menu_slug' => '',
+ 'function' => array( $this, 'plugin_settings' ),
+
+ // Menu default settings.
+ 'icon_url' => 'dashicons-admin-generic',
+ 'position' => null,
+
+ );
+ $menu = wp_parse_args( $menu, $defaults );
+
+ switch ( $menu['type'] ) {
+ case 'submenu':
+ $menu_page = add_submenu_page(
+ $menu['parent_slug'],
+ $menu['page_title'],
+ $menu['menu_title'],
+ $menu['capability'],
+ $menu['menu_slug'],
+ $menu['function'],
+ $menu['position']
+ );
+ break;
+ case 'management':
+ case 'options':
+ case 'theme':
+ case 'plugins':
+ case 'users':
+ case 'dashboard':
+ case 'posts':
+ case 'media':
+ case 'links':
+ case 'pages':
+ case 'comments':
+ $f = 'add_' . $menu['type'] . '_page';
+
+ $menu_page = null;
+ if ( function_exists( $f ) ) {
+ $menu_page = $f(
+ $menu['page_title'],
+ $menu['menu_title'],
+ $menu['capability'],
+ $menu['menu_slug'],
+ $menu['function'],
+ $menu['position']
+ );
+ }
+ break;
+ default:
+ $menu_page = add_menu_page(
+ $menu['page_title'],
+ $menu['menu_title'],
+ $menu['capability'],
+ $menu['menu_slug'],
+ $menu['function'],
+ $menu['icon_url'],
+ $menu['position']
+ );
+ break;
}
+ return $menu_page;
+ }
+
- /**
- * Display taxonomies fields.
- *
- * @param array $args Array of arguments.
- * @return void
- */
- public function callback_taxonomies( $args ) {
- $html = '';
+ /**
+ * Add admin menu.
+ */
+ public function admin_menu() {
+ global ${$this->prefix . '_menu_pages'};
- $options = $this->get_option( $args['id'], $args['options'] );
+ foreach ( $this->menus as $menu ) {
+ $menu_page = $this->add_custom_menu_page( $menu );
- // If taxonomies contains a query string then parse it with wp_parse_args.
- if ( is_string( $options ) && strpos( $options, '=' ) ) {
- $taxonomies = wp_parse_args( $options );
- } else {
- $taxonomies = wp_parse_list( $options );
+ $this->menu_pages[ $menu['menu_slug'] ] = $menu_page;
+ if ( isset( $menu['settings_page'] ) && $menu['settings_page'] ) {
+ $this->settings_page = $menu_page;
}
+ }
+ ${$this->prefix . '_menu_pages'} = $this->menu_pages;
- /* Fetch taxonomies */
- $argsc = array(
- 'public' => true,
- );
- $output = 'objects';
- $operator = 'and';
- $wp_taxonomies = get_taxonomies( $argsc, $output, $operator );
+ // Load the settings contextual help.
+ add_action( 'load-' . $this->settings_page, array( $this, 'settings_help' ) );
+ }
- $taxonomies_inc = array_intersect( wp_list_pluck( (array) $wp_taxonomies, 'name' ), $taxonomies );
+ /**
+ * Get the appropriate capability for the menu based on the user's roles and settings.
+ *
+ * @param array $roles Array of roles to check.
+ * @param string $base_capability The default capability.
+ * @param \WP_User $current_user The current user object.
+ * @param array $role_capabilities Array of role capabilities.
+ * @return string The capability to use for the menu.
+ */
+ public static function get_capability_for_menu( $roles = array(), $base_capability = 'manage_options', $current_user = null, $role_capabilities = array() ) {
+ if ( ! $current_user ) {
+ $current_user = wp_get_current_user();
+ }
- foreach ( $wp_taxonomies as $wp_taxonomy ) {
+ if ( empty( $roles ) || in_array( 'administrator', $current_user->roles, true ) ) {
+ return $base_capability;
+ }
- $html .= sprintf(
- ' ',
- sanitize_key( $args['id'] ),
- esc_attr( $wp_taxonomy->name ),
- checked( true, in_array( $wp_taxonomy->name, $taxonomies_inc, true ), false ),
- $this->settings_key
- );
- $html .= sprintf(
- '%3$s (%2$s) ',
- sanitize_key( $args['id'] ),
- esc_attr( $wp_taxonomy->name ),
- $wp_taxonomy->labels->name,
- $this->settings_key
- );
+ if ( empty( $role_capabilities ) ) {
+ $role_capabilities = array(
+ 'editor' => 'edit_others_posts',
+ 'author' => 'publish_posts',
+ 'contributor' => 'edit_posts',
+ 'subscriber' => 'read',
+ );
+ }
+ foreach ( $current_user->roles as $role ) {
+ if ( in_array( $role, $roles, true ) && isset( $role_capabilities[ $role ] ) ) {
+ return $role_capabilities[ $role ];
}
+ }
- $html .= $this->get_field_description( $args );
+ return $base_capability;
+ }
- /** This filter has been defined in class-settings-api.php */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ /**
+ * Enqueue scripts and styles.
+ *
+ * @param string $hook The current admin page.
+ */
+ public function admin_enqueue_scripts( $hook ) {
+
+ $minimize = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
+
+ // Settings API scripts.
+ wp_register_script(
+ 'wz-admin-js',
+ plugins_url( 'js/settings-admin-scripts' . $minimize . '.js', __FILE__ ),
+ array( 'jquery' ),
+ self::VERSION,
+ true
+ );
+ wp_register_script(
+ 'wz-codemirror-js',
+ plugins_url( 'js/apply-codemirror' . $minimize . '.js', __FILE__ ),
+ array( 'jquery' ),
+ self::VERSION,
+ true
+ );
+ wp_register_script(
+ 'wz-taxonomy-suggest-js',
+ plugins_url( 'js/taxonomy-suggest' . $minimize . '.js', __FILE__ ),
+ array( 'jquery' ),
+ self::VERSION,
+ true
+ );
+ wp_register_script(
+ 'wz-media-selector-js',
+ plugins_url( 'js/media-selector' . $minimize . '.js', __FILE__ ),
+ array( 'jquery' ),
+ self::VERSION,
+ true
+ );
+
+ if ( $hook === $this->settings_page ) {
+ self::enqueue_scripts_styles();
}
+ }
+ /**
+ * Enqueues all scripts, styles, settings, and templates necessary to use the Settings API.
+ */
+ public static function enqueue_scripts_styles() {
+
+ wp_enqueue_style( 'wp-color-picker' );
+
+ wp_enqueue_media();
+ wp_enqueue_script( 'wp-color-picker' );
+ wp_enqueue_script( 'jquery' );
+ wp_enqueue_script( 'jquery-ui-autocomplete' );
+ wp_enqueue_script( 'jquery-ui-tabs' );
+
+ wp_enqueue_code_editor(
+ array(
+ 'type' => 'text/html',
+ 'codemirror' => array(
+ 'indentUnit' => 2,
+ 'tabSize' => 2,
+ ),
+ )
+ );
- /**
- * Displays a rich text textarea for a settings field.
- *
- * @param array $args Array of arguments.
- */
- public function callback_wysiwyg( $args ) {
+ wp_enqueue_script( 'wz-admin-js' );
+ wp_enqueue_script( 'wz-codemirror-js' );
+ wp_enqueue_script( 'wz-taxonomy-suggest-js' );
+ }
+
+ /**
+ * Initialize and registers the settings sections and fields to WordPress
+ *
+ * Usually this should be called at `admin_init` hook.
+ *
+ * This public function gets the initiated settings sections and fields. Then
+ * registers them to WordPress and ready for use.
+ */
+ public function admin_init() {
- $value = $this->get_option( $args['id'], $args['options'] );
- $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : '500px';
+ $settings_key = $this->settings_key;
- echo '';
+ if ( false === get_option( $settings_key ) ) {
+ add_option( $settings_key, $this->settings_defaults() );
+ }
- $editor_settings = array(
- 'teeny' => true,
- 'textarea_name' => $args['section'] . '[' . $args['id'] . ']',
- 'textarea_rows' => 10,
+ $this->settings_form = new Settings_Form(
+ array(
+ 'settings_key' => $settings_key,
+ 'prefix' => $this->prefix,
+ 'checkbox_modified_text' => $this->translation_strings['checkbox_modified'],
+ )
+ );
+
+ foreach ( $this->registered_settings as $section => $settings ) {
+
+ add_settings_section(
+ "{$settings_key}_{$section}", // ID used to identify this section and with which to register options.
+ '', // No title, we will handle this via a separate function.
+ '__return_false', // No callback function needed. We'll process this separately.
+ "{$settings_key}_{$section}" // Page on which these options will be added.
);
- if ( isset( $args['options'] ) && is_array( $args['options'] ) ) {
- $editor_settings = array_merge( $editor_settings, $args['options'] );
+ foreach ( $settings as $setting ) {
+
+ $args = wp_parse_args(
+ $setting,
+ array(
+ 'section' => $section,
+ 'id' => null,
+ 'name' => '',
+ 'desc' => '',
+ 'type' => null,
+ 'default' => '',
+ 'options' => '',
+ 'max' => null,
+ 'min' => null,
+ 'step' => null,
+ 'size' => null,
+ 'field_class' => '',
+ 'field_attributes' => '',
+ 'placeholder' => '',
+ 'pro' => false,
+ )
+ );
+
+ $id = $args['id'];
+ $name = $args['name'];
+ $type = isset( $args['type'] ) ? $args['type'] : 'text';
+ $callback = method_exists( $this->settings_form, "callback_{$type}" ) ? array( $this->settings_form, "callback_{$type}" ) : array( $this->settings_form, 'callback_missing' );
+
+ add_settings_field(
+ "{$settings_key}[{$id}]", // ID of the settings field. We save it within the settings array.
+ $name, // Label of the setting.
+ $callback, // Function to handle the setting.
+ "{$settings_key}_{$section}", // Page to display the setting. In our case it is the section as defined above.
+ "{$settings_key}_{$section}", // Name of the section.
+ $args
+ );
}
+ }
+
+ // Register the settings into the options table.
+ register_setting(
+ $settings_key,
+ $settings_key,
+ array(
+ 'sanitize_callback' => array( $this, 'settings_sanitize' ),
+ 'show_in_rest' => true,
+ )
+ );
+ }
- wp_editor( $value, $args['section'] . '-' . $args['id'], $editor_settings );
+ /**
+ * Flattens $this->registered_settings into $setting[id] => $setting[type] format.
+ *
+ * @return array Default settings
+ */
+ public function get_registered_settings_types() {
- echo '
';
+ $options = array();
- echo $this->get_field_description( $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ // Populate some default values.
+ foreach ( $this->registered_settings as $tab => $settings ) {
+ foreach ( $settings as $option ) {
+ $options[ $option['id'] ] = $option['type'];
+ }
}
/**
- * Displays a file upload field for a settings field.
+ * Filters the settings array.
*
- * @param array $args Array of arguments.
+ * @param array $options Default settings.
*/
- public function callback_file( $args ) {
-
- $value = $this->get_option( $args['id'], $args['options'] );
- $size = sanitize_html_class( ( isset( $args['size'] ) && ! is_null( $args['size'] ) ) ? $args['size'] : 'regular' );
- $class = sanitize_html_class( $args['field_class'] );
- $label = isset( $args['options']['button_label'] ) ? $args['options']['button_label'] : __( 'Choose File' );
-
- $html = sprintf(
- ' ',
- $class . ' ' . $size . '-text file-url',
- $this->settings_key,
- sanitize_key( $args['id'] ),
- esc_attr( $value )
- );
- $html .= ' ';
- $html .= $this->get_field_description( $args );
+ return apply_filters( $this->prefix . '_get_settings_types', $options );
+ }
+
- /** This filter has been defined in class-settings-api.php */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ /**
+ * Default settings.
+ *
+ * @return array Default settings
+ */
+ public function settings_defaults() {
+
+ $options = array();
+
+ // Populate some default values.
+ foreach ( $this->registered_settings as $tab => $settings ) {
+ foreach ( $settings as $option ) {
+ // When checkbox is set to true, set this to 1.
+ if ( 'checkbox' === $option['type'] && ! empty( $option['options'] ) ) {
+ $options[ $option['id'] ] = 1;
+ } else {
+ $options[ $option['id'] ] = 0;
+ }
+ // If an option is set.
+ if ( in_array( $option['type'], array( 'textarea', 'css', 'html', 'text', 'url', 'csv', 'color', 'numbercsv', 'postids', 'posttypes', 'number', 'wysiwyg', 'file', 'password' ), true ) && isset( $option['options'] ) ) {
+ $options[ $option['id'] ] = $option['options'];
+ }
+ if ( in_array( $option['type'], array( 'multicheck', 'radio', 'select', 'radiodesc', 'thumbsizes' ), true ) && isset( $option['default'] ) ) {
+ $options[ $option['id'] ] = $option['default'];
+ }
+ }
}
- /**
- * Displays a password field for a settings field.
- *
- * @param array $args Array of arguments.
- */
- public function callback_password( $args ) {
-
- $value = $this->get_option( $args['id'], $args['options'] );
- $size = sanitize_html_class( ( isset( $args['size'] ) && ! is_null( $args['size'] ) ) ? $args['size'] : 'regular' );
- $class = sanitize_html_class( $args['field_class'] );
-
- $html = sprintf(
- ' ',
- $class . ' ' . $size . '-text',
- $this->settings_key,
- sanitize_key( $args['id'] ),
- esc_attr( $value )
- );
- $html .= $this->get_field_description( $args );
+ $upgraded_settings = $this->upgraded_settings;
- /** This filter has been defined in class-settings-api.php */
- echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ if ( false !== $upgraded_settings ) {
+ $options = array_merge( $options, $upgraded_settings );
}
/**
- * Sanitize the form data being submitted.
+ * Filters the default settings array.
*
- * @param array $input Input unclean array.
- * @return array Sanitized array
+ * @param array $options Default settings.
*/
- public function settings_sanitize( $input ) {
+ return apply_filters( $this->prefix . '_settings_defaults', $options );
+ }
- // This should be set if a form is submitted, so let's save it in the $referrer variable.
- if ( empty( $_POST['_wp_http_referer'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
- return $input;
- }
- parse_str( sanitize_text_field( wp_unslash( $_POST['_wp_http_referer'] ) ), $referrer ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ /**
+ * Get the default option for a specific key
+ *
+ * @param string $key Key of the option to fetch.
+ * @return mixed
+ */
+ public function get_default_option( $key = '' ) {
- // Check if we need to set to defaults.
- $reset = isset( $_POST['settings_reset'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ $default_settings = $this->settings_defaults();
- if ( $reset ) {
- $this->settings_reset();
- $settings = get_option( $this->settings_key );
+ if ( array_key_exists( $key, $default_settings ) ) {
+ return $default_settings[ $key ];
+ } else {
+ return false;
+ }
+ }
- add_settings_error( $this->prefix . '-notices', '', $this->translation_strings['reset_message'], 'error' );
- return $settings;
- }
+ /**
+ * Reset settings.
+ *
+ * @return void
+ */
+ public function settings_reset() {
+ delete_option( $this->settings_key );
+ }
- // Get the various settings we've registered.
- $settings = get_option( $this->settings_key );
- $settings_types = $this->get_registered_settings_types();
+ /**
+ * Sanitize the form data being submitted.
+ *
+ * @param array $input Input unclean array.
+ * @return array Sanitized array
+ */
+ public function settings_sanitize( $input ) {
- // Get the tab. This is also our settings' section.
- $tab = isset( $referrer['tab'] ) ? $referrer['tab'] : $this->default_tab;
+ // This should be set if a form is submitted, so let's save it in the $referrer variable.
+ if ( empty( $_POST['_wp_http_referer'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ return $input;
+ }
- $input = $input ? $input : array();
+ parse_str( sanitize_text_field( wp_unslash( $_POST['_wp_http_referer'] ) ), $referrer ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
- /**
- * Filter the settings for the tab. e.g. prefix_settings_general_sanitize.
- *
- * @param array $input Input unclean array
- */
- $input = apply_filters( $this->prefix . '_settings_' . $tab . '_sanitize', $input );
+ // Check if we need to set to defaults.
+ $reset = isset( $_POST['settings_reset'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
- // Create an output array by merging the existing settings with the ones submitted.
- $output = array_merge( $settings, $input );
+ if ( $reset ) {
+ $this->settings_reset();
+ $settings = get_option( $this->settings_key );
- // Loop through each setting being saved and pass it through a sanitization filter.
- foreach ( $settings_types as $key => $type ) {
+ add_settings_error( $this->prefix . '-notices', '', $this->translation_strings['reset_message'], 'error' );
- /**
- * Skip settings that are not really settings.
- *
- * @param array $non_setting_types Array of types which are not settings.
- */
- $non_setting_types = apply_filters( $this->prefix . '_non_setting_types', array( 'header', 'descriptive_text' ) );
+ return $settings;
+ }
- if ( in_array( $type, $non_setting_types, true ) ) {
- continue;
- }
+ // Get the various settings we've registered.
+ $settings = get_option( $this->settings_key );
+ $settings_types = $this->get_registered_settings_types();
- if ( array_key_exists( $key, $output ) ) {
+ // Get the tab. This is also our settings' section.
+ $tab = isset( $referrer['tab'] ) ? $referrer['tab'] : $this->default_tab;
- $sanitize_callback = $this->get_sanitize_callback( $key );
+ $input = $input ? $input : array();
- // If callback is set, call it.
- if ( $sanitize_callback ) {
- $output[ $key ] = call_user_func( $sanitize_callback, $output[ $key ] );
- continue;
- }
- }
+ /**
+ * Filter the settings for the tab. e.g. prefix_settings_general_sanitize.
+ *
+ * @param array $input Input unclean array
+ */
+ $input = apply_filters( $this->prefix . '_settings_' . $tab . '_sanitize', $input );
- // Delete any key that is not present when we submit the input array.
- if ( ! isset( $input[ $key ] ) ) {
- unset( $output[ $key ] );
- }
+ // Create an output array by merging the existing settings with the ones submitted.
+ $output = array_merge( $settings, $input );
- // Delete any settings that are no longer part of our registered settings.
- if ( array_key_exists( $key, $output ) && ! array_key_exists( $key, $settings_types ) ) {
- unset( $output[ $key ] );
- }
- }
- add_settings_error( $this->prefix . '-notices', '', $this->translation_strings['success_message'], 'updated' );
+ // Loop through each setting being saved and pass it through a sanitization filter.
+ foreach ( $settings_types as $key => $type ) {
/**
- * Filter the settings array before it is returned.
+ * Skip settings that are not really settings.
*
- * @param array $output Settings array.
- * @param array $input Input settings array.
+ * @param array $non_setting_types Array of types which are not settings.
*/
- return apply_filters( $this->prefix . '_settings_sanitize', $output, $input );
- }
+ $non_setting_types = apply_filters( $this->prefix . '_non_setting_types', array( 'header', 'descriptive_text' ) );
- /**
- * Get sanitization callback for given Settings key.
- *
- * @param string $key Settings key.
- *
- * @return string|bool Callback function or false if callback isn't found.
- */
- public function get_sanitize_callback( $key = '' ) {
- if ( empty( $key ) ) {
- return false;
+ if ( in_array( $type, $non_setting_types, true ) ) {
+ continue;
}
- // Iterate over registered fields and see if we can find proper callback.
- foreach ( $this->registered_settings as $section => $settings ) {
- foreach ( $settings as $option ) {
- if ( $option['id'] !== $key ) {
- continue;
- }
+ if ( array_key_exists( $key, $output ) ) {
- // Return the callback name.
- $sanitize_callback = false;
+ $sanitize_callback = $this->get_sanitize_callback( $key );
- if ( isset( $option['sanitize_callback'] ) && is_callable( $option['sanitize_callback'] ) ) {
- $sanitize_callback = $option['sanitize_callback'];
- return $sanitize_callback;
- }
-
- if ( is_callable( array( $this, 'sanitize_' . $option['type'] . '_field' ) ) ) {
- $sanitize_callback = array( $this, 'sanitize_' . $option['type'] . '_field' );
- return $sanitize_callback;
- }
-
- return $sanitize_callback;
+ // If callback is set, call it.
+ if ( $sanitize_callback ) {
+ $output[ $key ] = call_user_func( $sanitize_callback, $output[ $key ] );
+ continue;
}
}
- return false;
- }
+ // Delete any key that is not present when we submit the input array.
+ if ( ! isset( $input[ $key ] ) ) {
+ unset( $output[ $key ] );
+ }
- /**
- * Sanitize text fields
- *
- * @param string $value The field value.
- * @return string Sanitizied value
- */
- public function sanitize_text_field( $value ) {
- return $this->sanitize_textarea_field( $value );
+ // Delete any settings that are no longer part of our registered settings.
+ if ( array_key_exists( $key, $output ) && ! array_key_exists( $key, $settings_types ) ) {
+ unset( $output[ $key ] );
+ }
}
- /**
- * Sanitize number fields
- *
- * @param string $value The field value.
- * @return string $value Sanitized value
- */
- public function sanitize_number_field( $value ) {
- return filter_var( $value, FILTER_SANITIZE_NUMBER_INT );
- }
+ add_settings_error( $this->prefix . '-notices', '', $this->translation_strings['success_message'], 'updated' );
/**
- * Sanitize CSV fields
+ * Filter the settings array before it is returned.
*
- * @param string $value The field value.
- * @return string Sanitizied value
+ * @param array $output Settings array.
+ * @param array $input Input settings array.
*/
- public function sanitize_csv_field( $value ) {
- return implode( ',', array_map( 'trim', explode( ',', sanitize_text_field( wp_unslash( $value ) ) ) ) );
- }
+ return apply_filters( $this->prefix . '_settings_sanitize', $output, $input );
+ }
- /**
- * Sanitize CSV fields which hold numbers
- *
- * @param string $value The field value.
- * @return string Sanitized value
- */
- public function sanitize_numbercsv_field( $value ) {
- return implode( ',', array_filter( array_map( 'absint', explode( ',', sanitize_text_field( wp_unslash( $value ) ) ) ) ) );
+ /**
+ * Get sanitization callback for given Settings key.
+ *
+ * @param string $key Settings key.
+ *
+ * @return mixed Callback function or false if callback isn't found.
+ */
+ public function get_sanitize_callback( $key = '' ) {
+ if ( empty( $key ) ) {
+ return false;
}
- /**
- * Sanitize CSV fields which hold post IDs
- *
- * @param string $value The field value.
- * @return string Sanitized value
- */
- public function sanitize_postids_field( $value ) {
- $ids = array_filter( array_map( 'absint', explode( ',', sanitize_text_field( wp_unslash( $value ) ) ) ) );
+ $settings_sanitize = new Settings_Sanitize();
- foreach ( $ids as $key => $value ) {
- if ( false === get_post_status( $value ) ) {
- unset( $ids[ $key ] );
+ // Iterate over registered fields and see if we can find proper callback.
+ foreach ( $this->registered_settings as $section => $settings ) {
+ foreach ( $settings as $setting ) {
+ if ( $setting['id'] !== $key ) {
+ continue;
}
- }
-
- return implode( ',', $ids );
- }
-
- /**
- * Sanitize textarea fields
- *
- * @param string $value The field value.
- * @return string Sanitized value
- */
- public function sanitize_textarea_field( $value ) {
-
- global $allowedposttags;
-
- // We need more tags to allow for script and style.
- $moretags = array(
- 'script' => array(
- 'type' => true,
- 'src' => true,
- 'async' => true,
- 'defer' => true,
- 'charset' => true,
- ),
- 'style' => array(
- 'type' => true,
- 'media' => true,
- 'scoped' => true,
- ),
- 'link' => array(
- 'rel' => true,
- 'type' => true,
- 'href' => true,
- 'media' => true,
- 'sizes' => true,
- 'hreflang' => true,
- ),
- );
-
- $allowedtags = array_merge( $allowedposttags, $moretags );
-
- /**
- * Filter allowed tags allowed when sanitizing text and textarea fields.
- *
- * @param array $allowedtags Allowed tags array.
- */
- $allowedtags = apply_filters( $this->prefix . '_sanitize_allowed_tags', $allowedtags );
-
- return wp_kses( wp_unslash( $value ), $allowedtags );
- }
- /**
- * Sanitize checkbox fields
- *
- * @param mixed $value The field value.
- * @return int Sanitized value
- */
- public function sanitize_checkbox_field( $value ) {
- $value = ( -1 === (int) $value ) ? 0 : 1;
+ // Return the callback name.
+ $sanitize_callback = false;
- return $value;
- }
+ if ( isset( $setting['sanitize_callback'] ) && is_callable( $setting['sanitize_callback'] ) ) {
+ $sanitize_callback = $setting['sanitize_callback'];
+ return $sanitize_callback;
+ }
- /**
- * Sanitize post_types fields
- *
- * @param array $value The field value.
- * @return string $value Sanitized value
- */
- public function sanitize_posttypes_field( $value ) {
- $post_types = is_array( $value ) ? array_map( 'sanitize_text_field', wp_unslash( $value ) ) : array( 'post', 'page' );
+ if ( is_callable( array( $settings_sanitize, 'sanitize_' . $setting['type'] . '_field' ) ) ) {
+ $sanitize_callback = array( $settings_sanitize, 'sanitize_' . $setting['type'] . '_field' );
+ return $sanitize_callback;
+ }
- return implode( ',', $post_types );
+ return $sanitize_callback;
+ }
}
- /**
- * Sanitize post_types fields
- *
- * @param array $value The field value.
- * @return string $value Sanitized value
- */
- public function sanitize_taxonomies_field( $value ) {
- $taxonomies = is_array( $value ) ? array_map( 'sanitize_text_field', wp_unslash( $value ) ) : array();
-
- return implode( ',', $taxonomies );
- }
+ return false;
+ }
- /**
- * Render the settings page.
- */
- public function plugin_settings() {
- ob_start();
- ?>
+ /**
+ * Render the settings page.
+ */
+ public function plugin_settings() {
+ ob_start();
+ ?>
+ prefix . '_settings_page_header_before' ); ?>
translation_strings['page_header'] ); ?>
prefix . '_settings_page_header' ); ?>
@@ -1535,15 +866,15 @@ public function plugin_settings() {
- show_navigation(); ?>
- show_form(); ?>
+ show_navigation(); ?>
+ show_form(); ?>
@@ -1555,54 +886,54 @@ public function plugin_settings() {
settings_sections ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'general'; // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended
+ /**
+ * Show navigations as tab
+ *
+ * Shows all the settings section labels as tab
+ */
+ public function show_navigation() {
+ $active_tab = isset( $_GET['tab'] ) && array_key_exists( sanitize_key( wp_unslash( $_GET['tab'] ) ), $this->settings_sections ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'general'; // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended
- $html = '
';
+ $html = '';
- $count = count( $this->settings_sections );
+ $count = count( $this->settings_sections );
- // Don't show the navigation if only one section exists.
- if ( 1 === $count ) {
- return;
- }
+ // Don't show the navigation if only one section exists.
+ if ( 1 === $count ) {
+ return;
+ }
- foreach ( $this->settings_sections as $tab_id => $tab_name ) {
+ foreach ( $this->settings_sections as $tab_id => $tab_name ) {
- $active = $active_tab === $tab_id ? ' ' : '';
+ $active = $active_tab === $tab_id ? ' ' : '';
- $html .= '';
- $html .= esc_html( $tab_name );
- $html .= ' ';
+ $html .= '';
+ $html .= esc_html( $tab_name );
+ $html .= ' ';
- }
+ }
- $html .= ' ';
+ $html .= ' ';
- echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- }
+ echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ }
- /**
- * Show the section settings forms
- *
- * This public function displays every sections in a different form
- */
- public function show_form() {
- ob_start();
- ?>
+ /**
+ * Show the section settings forms
+ *
+ * This public function displays every sections in a different form
+ */
+ public function show_form() {
+ ob_start();
+ ?>