diff --git a/composer.lock b/composer.lock index 34aa66d..0945301 100644 --- a/composer.lock +++ b/composer.lock @@ -210,23 +210,23 @@ }, { "name": "barn2/barn2-lib", - "version": "2.2.0", + "version": "2.2.4", "source": { "type": "git", "url": "git@github.com:barn2plugins/barn2-lib.git", - "reference": "a3050f716819dd957f644291d4ed745ce2b4472a" + "reference": "cc582efc9e95f63b0291777808e183b958e05d6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barn2plugins/barn2-lib/zipball/a3050f716819dd957f644291d4ed745ce2b4472a", - "reference": "a3050f716819dd957f644291d4ed745ce2b4472a", + "url": "https://api.github.com/repos/barn2plugins/barn2-lib/zipball/cc582efc9e95f63b0291777808e183b958e05d6d", + "reference": "cc582efc9e95f63b0291777808e183b958e05d6d", "shasum": "" }, "require": { "wptrt/admin-notices": "^1.0" }, "require-dev": { - "barn2/php-standards": "dev-master" + "barn2/php-standards": "^1.0.0" }, "type": "library", "autoload": { @@ -245,10 +245,10 @@ ], "description": "Barn2 Libary code", "support": { - "source": "https://github.com/barn2plugins/barn2-lib/tree/2.2.0", + "source": "https://github.com/barn2plugins/barn2-lib/tree/2.2.4", "issues": "https://github.com/barn2plugins/barn2-lib/issues" }, - "time": "2024-10-22T04:58:48+00:00" + "time": "2024-11-25T09:22:34+00:00" }, { "name": "barn2/php-scoper-excludes", diff --git a/dependencies/barn2/barn2-lib/build/css/wc-settings-styles.css b/dependencies/barn2/barn2-lib/build/css/wc-settings-styles.css index 955b4dd..e65e753 100644 --- a/dependencies/barn2/barn2-lib/build/css/wc-settings-styles.css +++ b/dependencies/barn2/barn2-lib/build/css/wc-settings-styles.css @@ -1 +1,2 @@ +.woocommerce .barn2-settings .form-table .with-suffix{margin-right:6px;vertical-align:middle}.image-size-field .separator{display:inline-block;font-size:1.2em;padding-left:4px;padding-right:4px}.image-size-field .suffix{padding-left:8px}.image-size-field .separator,.image-size-field .suffix{padding-top:9px}@media screen and (min-width:783px){.image-size-field .separator,.image-size-field .suffix{padding-top:4px}}.color-picker-field .wp-picker-container,.color-size-field .wp-picker-container{vertical-align:top}.color-picker-field .wp-picker-container input[type=text].wp-color-picker,.color-size-field .wp-picker-container input[type=text].wp-color-picker{width:5rem}.color-size-field input[type=number]{width:60px}.woocommerce .form-table .color-size-field input[type=number]{vertical-align:top;width:6em}.color-size-field .wp-picker-active{margin-right:3px}.color-size-field .description{display:inline-block;margin-left:10px;margin-top:1px}.color-size-field .description img{display:inline-block;margin:3px 6px 3px 0;vertical-align:middle}.form-table .radio-image-boxes{display:grid;gap:20px;grid-template-columns:200px 200px 200px 200px;margin-top:25px}@media(max-width:1180px){.form-table .radio-image-boxes{grid-template-columns:1fr 1fr 1fr 1fr}}@media(max-width:820px){.form-table .radio-image-boxes{grid-template-columns:200px 200px 200px}.form-table .radio-image-boxes label{margin:0!important;max-width:200px}}@media(max-width:680px){.form-table .radio-image-boxes{grid-template-columns:1fr 1fr 1fr}.form-table .radio-image-boxes label{margin:0!important;max-width:200px}}@media(max-width:520px){.form-table .radio-image-boxes{grid-template-columns:1fr 1fr}.form-table .radio-image-boxes label{max-width:200px}}.form-table .radio-image-boxes .radio-image{position:relative}.form-table .radio-image-boxes .radio-image>img{border-radius:16px 16px 0 0;height:100%;max-width:200px;width:100%}.form-table .radio-image-boxes .radio-image .image-hover{align-items:center;background:rgba(34,113,177,.8);border-radius:16px 16px 0 0;display:flex;height:100%;justify-content:center;left:0;opacity:1;position:absolute;top:0;visibility:hidden;width:100%}.form-table .radio-image-boxes .radio-image .image-hover img{width:40px}.form-table .radio-image-boxes .radio-image:hover .image-hover{opacity:1;visibility:visible}.form-table .radio-image-boxes .barn2-lightbox-image{display:none}.form-table .radio-image-boxes label{background-color:#fff;border-radius:16px;display:flex!important;flex-direction:column}.form-table .radio-image-boxes label:hover{cursor:pointer}.form-table .radio-image-boxes label span{border-top:1px solid #d9d9d9;box-sizing:border-box;display:inline-block;padding:10px 20px;width:100%} .woocommerce .barn2-settings .form-table .with-suffix{margin-right:6px;vertical-align:middle}.image-size-field .separator{display:inline-block;font-size:1.2em;padding-left:4px;padding-right:4px}.image-size-field .suffix{padding-left:8px}.image-size-field .separator,.image-size-field .suffix{padding-top:9px}@media screen and (min-width:783px){.image-size-field .separator,.image-size-field .suffix{padding-top:4px}}.color-picker-field .wp-picker-container,.color-size-field .wp-picker-container{vertical-align:top}.color-picker-field .wp-picker-container input[type=text].wp-color-picker,.color-size-field .wp-picker-container input[type=text].wp-color-picker{width:5rem}.woocommerce .form-table .color-size-field input[type=number]{vertical-align:top;width:6em}.color-size-field .wp-picker-active{margin-right:3px}.color-size-field .description{display:inline-block;margin-left:10px;margin-top:1px}.color-size-field .description img{display:inline-block;margin:3px 6px 3px 0;vertical-align:middle} diff --git a/dependencies/barn2/barn2-lib/src/Admin/Notice.php b/dependencies/barn2/barn2-lib/src/Admin/Notice.php new file mode 100644 index 0000000..bfe936d --- /dev/null +++ b/dependencies/barn2/barn2-lib/src/Admin/Notice.php @@ -0,0 +1,314 @@ + + * @license GPL-3.0 + * @copyright Barn2 Media Ltd + * @version 1.0 + * @internal + */ +class Notice +{ + /** + * The notice-ID. + * + * @var string + */ + private $id; + /** + * The notice title. + * + * @var string + */ + private $title; + /** + * The notice message. + * + * @var string + */ + private $message; + /** + * The notice options. + * + * @var array + */ + private $options = ['type' => 'info', 'alt_style' => \false, 'additional_classes' => [], 'attributes' => [], 'paragraph_wrap' => \true, 'buttons' => [], 'capability' => 'edit_theme_options', 'screens' => [], 'dismissible' => \true, 'scope' => 'global', 'option_prefix' => 'barn2_notice_dismissed', 'dissmiss_callback' => null]; + /** + * Constructor. + * + * @param string $id A unique notice ID. Should contain lowercase characters and underscores. + * @param string $title The title of the notice. + * @param string $message The notice message. + * @param array $options { + * Optional. An array of additional options to change the defaults for this notice. + * + * @type string $type The type of admin notice. Default 'info'. Accepts 'info', 'success', 'warning', 'error'. + * @type bool $alt_style Whether we want to use alt styles or not. Default false. + * @type array $additional_classes A string array of class names. + * @type array $attributes Additional attributes for the notice div. + * @type bool $paragraph_wrap Whether to wrap the message in paragraph tags. Default true. + * @type array $buttons Associative array with buttons attributes and values. Default []. + * @type string $capability The user capability required to see the notice. Default 'edit_theme_options'. + * @type array $screens An array of screens where the notice will be displayed. Default is empty to always show. + * @type bool $dismissible Whether the admin notice is dismissible. Default true. + * @type string $scope Saves the dismissed status as an option or user-meta. Accepts 'global', 'user'. Default 'global'. + * @type string $option_prefix The prefix that will be used to build the option (or post-meta) name. Should contain lowercase characters and underscores. + * @type callable $dissmiss_callback Function called before dismissing a notice. The arguments are $id, $title, $message, $options, $notice_obj. + * } + */ + public function __construct($id, $title, $message, $options = []) + { + $this->id = \sanitize_key($id); + $this->title = $title; + $this->message = $message; + $this->options = \wp_parse_args($options, $this->options); + if (!$this->id || !$this->message) { + return; + } + if ($this->options['dismissible'] === \true && !$this->is_dismissed()) { + // Enqueue notices script to handle dismissables notices. + \add_action('admin_enqueue_scripts', [$this, 'load_scripts']); + // Handle AJAX requests to dismiss the notice. + \add_action('wp_ajax_barn2_dismiss_admin_notice', [$this, 'ajax_maybe_dismiss_notice']); + } + } + /** + * Enqueues barn2-notices script. + */ + public function load_scripts() + { + \wp_enqueue_script('barn2-notices'); + } + /** + * Gets the notice markup. + * + * @return string + */ + public function get_notice() + { + // Use a deprecated notice function if WP is older than 6.4.0. + if (!\function_exists('wp_get_admin_notice')) { + return $this->get_notice_deprecated(); + } + $title = $this->get_title(); + $message = $this->message; + $buttons = $this->get_buttons(); + $additional_classes = \array_merge(['barn2-notice'], $this->options['additional_classes']); + $attributes = $this->options['attributes']; + $paragraph_wrap = $this->options['paragraph_wrap']; + // Adds a nonce to the notice data attribute to be used on the AJAX cal if the notice is dismissible. + if ($this->options['dismissible'] === \true && !$this->is_dismissed()) { + $attributes = \array_merge($attributes, ['data-nonce' => \wp_create_nonce('barn2_dismiss_admin_notice_' . $this->id)]); + } + if ($title !== '' && $this->options['paragraph_wrap'] === \true) { + $message = \wpautop($message); + $paragraph_wrap = \false; + } + // Adds the title and the buttons to the message. + $message = $title . $message . $buttons; + // Gets the notice markup. + $notice = \wp_get_admin_notice($message, ['id' => $this->id, 'type' => $this->options['type'], 'dismissible' => $this->options['dismissible'], 'additional_classes' => $additional_classes, 'attributes' => $attributes, 'paragraph_wrap' => $paragraph_wrap]); + return $notice; + } + /** + * Gets the notice markup. + * + * @return string + * @deprecated 6.4.0 Use Notice->get_notice() instead that uses wp_get_admin_notice() function. + */ + public function get_notice_deprecated() + { + $classes = 'notice barn2-notice'; + $attributes = ''; + $message = $this->message; + if (\is_string($this->options['type'])) { + $type = \trim($this->options['type']); + if ($type !== '') { + $classes .= ' notice-' . $type; + } + } + if ($this->options['dismissible'] === \true) { + $classes .= ' is-dismissible'; + } + if ($this->options['alt_style'] === \true) { + $classes .= ' notice-alt'; + } + if (\is_array($this->options['additional_classes']) && !empty($this->options['additional_classes'])) { + $classes .= ' ' . \implode(' ', $this->options['additional_classes']); + } + // Adds a nonce to the notice data attribute to be used on the AJAX cal if the notice is dismissible. + if ($this->options['dismissible'] === \true && !$this->is_dismissed()) { + $attributes = ' data-nonce="' . \wp_create_nonce('barn2_dismiss_admin_notice_' . $this->id) . '"'; + } + if (\is_array($this->options['attributes']) && !empty($this->options['attributes'])) { + foreach ($this->options['attributes'] as $attr => $val) { + if (\is_bool($val)) { + $attributes .= $val ? ' ' . $attr : ''; + } elseif (\is_int($attr)) { + $attributes .= ' ' . \esc_attr(\trim($val)); + } elseif ($val) { + $attributes .= ' ' . $attr . '="' . \esc_attr(\trim($val)) . '"'; + } + } + } + if ($this->options['paragraph_wrap'] === \true) { + $message = \wpautop($message); + } + // Adds the title and the buttons to the message. + $message = $this->get_title() . $message . $this->get_buttons(); + // Gets the notice markup. + $notice = \sprintf('
%1$s has been updated! To keep things running smoothly, we have to update your database to the newest version. The database update process runs in the background and may take a little while, so please be patient.
'), $this->plugin->get_name()), 'buttons' => ['update-db' => ['value' => 'Update Database', 'href' => \wp_nonce_url(\add_query_arg($this->plugin->get_slug() . '_update_db', 'true', \admin_url('admin.php?page=wc-settings')), 'wc_db_update', 'wc_db_update_nonce'), 'id' => $this->plugin->get_slug() . '-update-db', 'class' => 'button-primary'], 'learn-more' => ['value' => 'Learn more about updates', 'href' => 'https://barn2.com/kb/learn-more-about-updates/', 'target' => '_blank', 'class' => 'button-secondary', 'style' => 'margin-left: 8px;']]], 'updating_db_notice' => ['title' => \sprintf(__('%1$s database update'), $this->plugin->get_name()), 'message' => \sprintf(__('%1$s is updating the database in the background. The database update process may take a little while, so please be patient.
'), $this->plugin->get_name())], 'update_db_complete_notice' => ['title' => \sprintf(__('%1$s database update done'), $this->plugin->get_name()), 'message' => \sprintf(__('%1$s database update complete. Thank you for updating to the latest version!
'), $this->plugin->get_name())]]; + } + /** + * Sets the final options. + */ + public function set_options($options) + { + $this->options = \array_replace_recursive($this->get_default_options(), $options); + } + /** + * Checks the plugin's version and shows the update admin notice message if an update is required. + */ + public function check_version() + { + if ($this->needs_update() && !\defined('IFRAME_REQUEST')) { + $this->show_notice(); + } + } + /** + * Show the update admin notice message. + */ + public function show_notice() + { + // Removes all old dismissed admin notice messages status. + \delete_option('barn2_notice_dismissed_' . $this->plugin->get_slug() . '_updating_db_notice'); + \delete_option('barn2_notice_dismissed_' . $this->plugin->get_slug() . '_update_db_complete_notice'); + $admin_notice = new Notices(); + // If it needs to update. + if ($this->needs_update() && !$this->is_updating()) { + $admin_notice->add($this->plugin->get_slug() . '_needs_update_db_notice', $this->options['needs_update_db_notice']['title'], $this->options['needs_update_db_notice']['message'], ['type' => 'warning', 'capability' => 'install_plugins', 'dismissible' => \false, 'buttons' => $this->options['needs_update_db_notice']['buttons'] ?? null]); + } + // If it is updating. + if ($this->needs_update() || $this->is_updating()) { + $admin_notice->add($this->plugin->get_slug() . '_updating_db_notice', $this->options['updating_db_notice']['title'], $this->options['updating_db_notice']['message'], ['type' => 'info', 'capability' => 'install_plugins', 'additional_classes' => $this->is_updating() ? [] : ['hidden'], 'buttons' => $this->options['updating_db_notice']['buttons'] ?? null]); + } + // If the update is complete. + if ($this->needs_update() || $this->update_is_complete()) { + $admin_notice->add($this->plugin->get_slug() . '_update_db_complete_notice', $this->options['update_db_complete_notice']['title'], $this->options['update_db_complete_notice']['message'], ['type' => 'success', 'capability' => 'install_plugins', 'additional_classes' => $this->needs_update() ? ['hidden'] : [], 'buttons' => $this->options['update_db_complete_notice']['buttons'] ?? null]); + } + $admin_notice->boot(); + } + /** + * Runs all the required update callback functions. + */ + private function update() + { + // Deletes previous updating status. + \delete_transient($this->plugin->get_slug() . '_updating_db'); + \delete_transient($this->plugin->get_slug() . '_update_db_complete'); + // Set updating DB status. + \set_transient($this->plugin->get_slug() . '_updating_db', \true); + $db_version = $this->get_current_database_version(); + $code_version = $this->get_current_code_version(); + // Runs the required updates. + foreach (self::get_update_callbacks() as $version => $update_callbacks) { + if (\version_compare($db_version, $version, '<')) { + self::update_version($version); + if ($this->update_db_version($version)) { + $db_version = $version; + } + } + } + if (\version_compare($code_version, $db_version, '>')) { + $this->update_db_version($code_version); + } + // Deletes updating DB status. + \delete_transient($this->plugin->get_slug() . '_updating_db'); + // Set update DB complete status. + \set_transient($this->plugin->get_slug() . '_update_db_complete', \true); + /** + * Fires after the plugin is updated. + * + * @param string $db_version The version of the plugin as stored in the database. + * @param string $code_version The version of the plugin as stored in the code. + */ + \do_action($this->plugin->get_slug() . '_updated', $db_version, $code_version, $this->plugin); + } + /** + * Updates a specific version. + */ + public static function update_version($version = '') + { + if (isset(static::$updates[$version])) { + foreach (static::$updates[$version] as $function) { + if (\method_exists(\get_called_class(), $function)) { + static::$function(); + } + } + } + } + /** + * Updates the version on the DB. + * + * @param string|null $version Version number or null to use the current plugin version. + * + * @return bool + */ + public function update_db_version($version = null) : bool + { + return \update_option($this->options['version_option_name'], \is_null($version) ? $this->get_current_code_version() : $version); + } + /** + * Prints the script for handling the update process. + */ + public function add_script() + { + // If it needs an update. + if ($this->needs_update() && !$this->is_updating()) { + $script = "( function( \$, window, document, undefined ) {\n\n\t\$( function() {\n\n\t\t\$( '#" . $this->plugin->get_slug() . "-update-db' ).on( 'click', function( e ) {\n e.preventDefault();\n\n \$( '#" . $this->plugin->get_slug() . "_needs_update_db_notice' ).hide();\n \$( '#" . $this->plugin->get_slug() . "_updating_db_notice' ).show();\n\n\t\t\tvar data = \$( this ).data();\n\t\t\tdata.action = '" . $this->plugin->get_slug() . "_update_db';\n\t\t\tdata.nonce = '" . \wp_create_nonce($this->plugin->get_slug() . '_update_db') . "';\n\n\t\t\t\$.ajax( {\n\t\t\t\turl: ajaxurl, // always defined when running in WP Admin\n\t\t\t\ttype: 'POST',\n\t\t\t\tdata: data,\n\t\t\t\txhrFields: {\n\t\t\t\t\twithCredentials: true\n\t\t\t\t}\n\t\t\t} ).done(function (out) {\n \$( '#" . $this->plugin->get_slug() . "_updating_db_notice' ).hide();\n \$( '#" . $this->plugin->get_slug() . "_update_db_complete_notice' ).show();\n\t\t\t}).fail(function (out) {\n \$( '#" . $this->plugin->get_slug() . "_updating_db_notice' ).hide();\n \$( '#" . $this->plugin->get_slug() . "_update_db_error_notice' ).show();\n\t\t\t});\n\t\t} );\n\t} );\n\n} )( jQuery, window, document );"; + } + // If it's already updating. + if ($this->needs_update() && $this->is_updating()) { + $script = "( function( \$, window, document, undefined ) {\n\n\t\$( function() {\n\n var data = {};\n data.action = '" . $this->plugin->get_slug() . "_check_update_db';\n data.nonce = '" . \wp_create_nonce($this->plugin->get_slug() . '_check_update_db') . "';\n\n \$.ajax( {\n url: ajaxurl, // always defined when running in WP Admin\n type: 'POST',\n data: data,\n xhrFields: {\n withCredentials: true\n }\n } ).done(function (out) {\n console.log('CHECKED');\n \$( '#" . $this->plugin->get_slug() . "_updating_db_notice' ).hide();\n \$( '#" . $this->plugin->get_slug() . "_update_db_complete_notice' ).show();\n }).fail(function (out) {\n \$( '#" . $this->plugin->get_slug() . "_updating_db_notice' ).hide();\n \$( '#" . $this->plugin->get_slug() . "_update_db_error_notice' ).show();\n });\n\n\t} );\n\n} )( jQuery, window, document );"; + } + if (isset($script)) { + \wp_add_inline_script('common', $script, 'after'); + } + } + /** + * Starts the update process through AJAX. + */ + public function ajax_start_update() + { + if (!isset($_POST['action']) || $_POST['action'] !== $this->plugin->get_slug() . '_update_db') { + return; + } + \check_ajax_referer($this->plugin->get_slug() . '_update_db', 'nonce', \true); + $this->update(); + exit; + } + /** + * Check if the plugin is updating through AJAX. + */ + public function ajax_check_update_db() + { + global $wpdb; + if (!isset($_POST['action']) || $_POST['action'] !== $this->plugin->get_slug() . '_check_update_db') { + return; + } + \check_ajax_referer($this->plugin->get_slug() . '_check_update_db', 'nonce', \true); + // Using a query to get the transient value otherwise WordPress will use the first cached values instead. + $query = "SELECT option_value FROM wp_options WHERE option_name ='" . '_transient_' . $this->plugin->get_slug() . '_updating_db' . "';"; + while ($wpdb->get_var($query) !== null) { + \sleep(1); + } + exit; + } + /** + * Get the list of update callbacks from the plugin Update class. + * + * @return array + */ + public static function get_update_callbacks() : array + { + return static::$updates; + } + /** + * Gets the latest update version from the plugin Update class. + * + * @return string + */ + public function get_latest_update_version() + { + return \array_key_last(self::get_update_callbacks()); + } + /** + * Gets the current plugin version as stored in the database. + * + * @return string + */ + public function get_current_database_version() + { + return \get_option($this->options['version_option_name']); + } + /** + * Gets the current plugin version as stored in the code. + * + * @return string + */ + public function get_current_code_version() : string + { + return $this->plugin->get_version(); + } + /** + * Condition to verify if it's a new plugin installation and not an update. + * + * @return bool + */ + public function is_new_install() : bool + { + return \false; + } + /** + * Verifies if it needs to update. + * + * @return bool + */ + public function needs_update() + { + $db_version = $this->get_current_database_version(); + $latest_update_version = $this->get_latest_update_version(); + return !$this->is_new_install() && $latest_update_version !== null && \version_compare($db_version, $latest_update_version, '<'); + } + /** + * Verifies if the plugin is updating. + * + * @return string|bool + */ + public function is_updating() + { + return \get_transient($this->plugin->get_slug() . '_updating_db'); + } + /** + * Verifies if the update is complete. + * + * @return string|bool + */ + public function update_is_complete() + { + return \get_transient($this->plugin->get_slug() . '_update_db_complete'); + } +} diff --git a/dependencies/barn2/barn2-lib/src/Util.php b/dependencies/barn2/barn2-lib/src/Util.php index 50de4eb..38133a7 100644 --- a/dependencies/barn2/barn2-lib/src/Util.php +++ b/dependencies/barn2/barn2-lib/src/Util.php @@ -359,7 +359,7 @@ public static function get_plugin_data(Plugin $plugin) if (!\function_exists('get_plugin_data')) { require_once \ABSPATH . 'wp-admin/includes/plugin.php'; } - return \get_plugin_data($plugin->get_file()); + return \get_plugin_data($plugin->get_file(), \false, \false); } /** * Loops through all active plugins on the user's website and returns ones that are authored by Barn2 @@ -568,7 +568,7 @@ public static function install_bonus_plugins($bonus_plugins) if ($plugin && \current_user_can('activate_plugin', $plugin)) { $cache_plugins = \wp_cache_get('plugins', 'plugins'); if (!empty($cache_plugins)) { - $new_plugin = \get_plugin_data(\WP_PLUGIN_DIR . '/' . $plugin); + $new_plugin = \get_plugin_data(\WP_PLUGIN_DIR . '/' . $plugin, \false, \false); $cache_plugins[''][$plugin] = $new_plugin; \wp_cache_set('plugins', $cache_plugins, 'plugins'); } diff --git a/package.json b/package.json index 4e59990..796c404 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "woocommerce-product-tabs", "title": "WooCommerce Product Tabs (Free)", - "version": "2.1.7", + "version": "2.1.8", "license": "GPL-2.0+", "main_file": "woocommerce-product-tabs.php", "author": "Barn2 Plugins