diff --git a/README.md b/README.md index a22f150..e1bffba 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ **Donate link:** https://www.paypal.me/BrainstormForce **Requires at least:** 4.2 **Tested up to:** 5.4 -**Stable tag:** 1.0.3 +**Stable tag:** 1.1.0 **License:** GPLv2 or later **License URI:** http://www.gnu.org/licenses/gpl-2.0.html @@ -85,6 +85,8 @@ Check Screenshots for more details. 5. Blank - No Header / Footer Template ## Changelog ## +### 1.1.0 ### +- New: Users can now share non-personal usage data to help us test and develop better products. ( Know More ) ### 1.0.3 ### - Make the plugin translation compatible. diff --git a/admin/bsf-analytics/assets/css/minified/style.min-rtl.css b/admin/bsf-analytics/assets/css/minified/style.min-rtl.css new file mode 100644 index 0000000..036f45f --- /dev/null +++ b/admin/bsf-analytics/assets/css/minified/style.min-rtl.css @@ -0,0 +1 @@ +#bsf-optin-notice{padding:1px 12px;border-right-color:#007cba}#bsf-optin-notice .notice-container{padding-top:10px;padding-bottom:12px}#bsf-optin-notice .notice-content{margin:0}#bsf-optin-notice .notice-heading{padding:0 0 12px 20px}#bsf-optin-notice .button-primary{margin-left:5px} \ No newline at end of file diff --git a/admin/bsf-analytics/assets/css/minified/style.min.css b/admin/bsf-analytics/assets/css/minified/style.min.css new file mode 100644 index 0000000..9dc616e --- /dev/null +++ b/admin/bsf-analytics/assets/css/minified/style.min.css @@ -0,0 +1 @@ +#bsf-optin-notice{padding:1px 12px;border-left-color:#007cba}#bsf-optin-notice .notice-container{padding-top:10px;padding-bottom:12px}#bsf-optin-notice .notice-content{margin:0}#bsf-optin-notice .notice-heading{padding:0 20px 12px 0}#bsf-optin-notice .button-primary{margin-right:5px} \ No newline at end of file diff --git a/admin/bsf-analytics/assets/css/unminified/style-rtl.css b/admin/bsf-analytics/assets/css/unminified/style-rtl.css new file mode 100644 index 0000000..de4a4b5 --- /dev/null +++ b/admin/bsf-analytics/assets/css/unminified/style-rtl.css @@ -0,0 +1,21 @@ +#bsf-optin-notice { + padding: 1px 12px; + border-right-color: #007cba; +} + +#bsf-optin-notice .notice-container { + padding-top: 10px; + padding-bottom: 12px; +} + +#bsf-optin-notice .notice-content { + margin: 0; +} + +#bsf-optin-notice .notice-heading { + padding: 0 0 12px 20px; +} + +#bsf-optin-notice .button-primary { + margin-left: 5px; +} \ No newline at end of file diff --git a/admin/bsf-analytics/assets/css/unminified/style.css b/admin/bsf-analytics/assets/css/unminified/style.css new file mode 100644 index 0000000..09a6e55 --- /dev/null +++ b/admin/bsf-analytics/assets/css/unminified/style.css @@ -0,0 +1,21 @@ +#bsf-optin-notice { + padding: 1px 12px; + border-left-color: #007cba; +} + +#bsf-optin-notice .notice-container { + padding-top: 10px; + padding-bottom: 12px; +} + +#bsf-optin-notice .notice-content { + margin: 0; +} + +#bsf-optin-notice .notice-heading { + padding: 0 20px 12px 0; +} + +#bsf-optin-notice .button-primary { + margin-right: 5px; +} \ No newline at end of file diff --git a/admin/bsf-analytics/class-bsf-analytics-stats.php b/admin/bsf-analytics/class-bsf-analytics-stats.php new file mode 100644 index 0000000..2fe30fe --- /dev/null +++ b/admin/bsf-analytics/class-bsf-analytics-stats.php @@ -0,0 +1,257 @@ +get_default_stats() ); + } + + /** + * Retrieve stats for site. + * + * @return array stats data. + * @since 1.0.0 + */ + private function get_default_stats() { + return array( + 'graupi_version' => defined( 'BSF_UPDATER_VERSION' ) ? BSF_UPDATER_VERSION : false, + 'domain_name' => get_site_url(), + 'php_os' => PHP_OS, + 'server_software' => isset( $_SERVER['SERVER_SOFTWARE'] ) ? filter_var( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ), FILTER_SANITIZE_STRING ) : '', + 'mysql_version' => $this->get_mysql_version(), + 'php_version' => $this->get_php_version(), + 'php_max_input_vars' => ini_get( 'max_input_vars' ), // phpcs:ignore:PHPCompatibility.IniDirectives.NewIniDirectives.max_input_varsFound + 'php_post_max_size' => ini_get( 'post_max_size' ), + 'php_max_execution_time' => ini_get( 'max_execution_time' ), + 'php_memory_limit' => ini_get( 'memory_limit' ), + 'zip_installed' => extension_loaded( 'zip' ), + 'imagick_availabile' => extension_loaded( 'imagick' ), + 'xmlreader_exists' => class_exists( 'XMLReader' ), + 'gd_available' => extension_loaded( 'gd' ), + 'curl_version' => $this->get_curl_version(), + 'curl_ssl_version' => $this->get_curl_ssl_version(), + 'is_writable' => $this->is_content_writable(), + + 'wp_version' => get_bloginfo( 'version' ), + 'user_count' => $this->get_user_count(), + 'site_language' => get_locale(), + 'timezone' => wp_timezone_string(), + 'is_ssl' => is_ssl(), + 'is_multisite' => is_multisite(), + 'network_url' => network_site_url(), + 'external_object_cache' => (bool) wp_using_ext_object_cache(), + 'wp_debug' => WP_DEBUG, + 'wp_debug_display' => WP_DEBUG_DISPLAY, + 'script_debug' => SCRIPT_DEBUG, + + 'active_plugins' => $this->get_active_plugins(), + + 'active_theme' => get_template(), + 'active_stylesheet' => get_stylesheet(), + ); + } + + /** + * Get installed PHP version. + * + * @return float PHP version. + * @since 1.0.0 + */ + private function get_php_version() { + if ( defined( 'PHP_MAJOR_VERSION' ) && defined( 'PHP_MINOR_VERSION' ) && defined( 'PHP_RELEASE_VERSION' ) ) { // phpcs:ignore + return PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION; + } + + return phpversion(); + } + + /** + * User count on site. + * + * @return int User count. + * @since 1.0.0 + */ + private function get_user_count() { + if ( is_multisite() ) { + $user_count = get_user_count(); + } else { + $count = count_users(); + $user_count = $count['total_users']; + } + + return $user_count; + } + + /** + * Get active plugin's data. + * + * @return array active plugin's list. + * @since 1.0.0 + */ + private function get_active_plugins() { + if ( ! $this->plugins ) { + // Ensure get_plugin_data function is loaded. + if ( ! function_exists( 'get_plugin_data' ) ) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + + $plugins = wp_get_active_and_valid_plugins(); + $plugins = array_map( 'get_plugin_data', $plugins ); + $this->plugins = array_map( array( $this, 'format_plugin' ), $plugins ); + } + + return $this->plugins; + } + + /** + * Format plugin data. + * + * @param string $plugin plugin. + * @return array formatted plugin data. + * @since 1.0.0 + */ + public function format_plugin( $plugin ) { + return array( + 'name' => html_entity_decode( $plugin['Name'], ENT_COMPAT, 'UTF-8' ), + 'url' => $plugin['PluginURI'], + 'version' => $plugin['Version'], + 'slug' => $plugin['TextDomain'], + 'author_name' => html_entity_decode( wp_strip_all_tags( $plugin['Author'] ), ENT_COMPAT, 'UTF-8' ), + 'author_url' => $plugin['AuthorURI'], + ); + } + + /** + * Curl SSL version. + * + * @return float SSL version. + * @since 1.0.0 + */ + private function get_curl_ssl_version() { + $curl = array(); + if ( function_exists( 'curl_version' ) ) { + $curl = curl_version(); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_version + } + + return isset( $curl['ssl_version'] ) ? $curl['ssl_version'] : false; + } + + /** + * Get cURL version. + * + * @return float cURL version. + * @since 1.0.0 + */ + private function get_curl_version() { + $curl = array(); + if ( function_exists( 'curl_version' ) ) { + $curl = curl_version(); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_version + } + + return isset( $curl['version'] ) ? $curl['version'] : false; + } + + /** + * Get MySQL version. + * + * @return float MySQL version. + * @since 1.0.0 + */ + private function get_mysql_version() { + global $wpdb; + return $wpdb->db_version(); + } + + /** + * Check if content directory is writable. + * + * @return bool + * @since 1.0.0 + */ + private function is_content_writable() { + $upload_dir = wp_upload_dir(); + return wp_is_writable( $upload_dir['basedir'] ); + } + } +} + +/** + * Polyfill for sites using WP version less than 5.3 + */ +if ( ! function_exists( 'wp_timezone_string' ) ) { + /** + * Get timezone string. + * + * @return string timezone string. + * @since 1.0.0 + */ + function wp_timezone_string() { + $timezone_string = get_option( 'timezone_string' ); + + if ( $timezone_string ) { + return $timezone_string; + } + + $offset = (float) get_option( 'gmt_offset' ); + $hours = (int) $offset; + $minutes = ( $offset - $hours ); + + $sign = ( $offset < 0 ) ? '-' : '+'; + $abs_hour = abs( $hours ); + $abs_mins = abs( $minutes * 60 ); + $tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins ); + + return $tz_offset; + } +} diff --git a/admin/bsf-analytics/class-bsf-analytics.php b/admin/bsf-analytics/class-bsf-analytics.php new file mode 100644 index 0000000..a032a78 --- /dev/null +++ b/admin/bsf-analytics/class-bsf-analytics.php @@ -0,0 +1,525 @@ +bsf_analytics_url() ); + + add_action( 'admin_init', array( $this, 'handle_optin_optout' ) ); + add_action( 'cron_schedules', array( $this, 'every_two_days_schedule' ) ); + add_action( 'admin_notices', array( $this, 'option_notice' ) ); + add_action( 'astra_notice_before_markup_bsf-optin-notice', array( $this, 'enqueue_assets' ) ); + + add_action( 'init', array( $this, 'schedule_unschedule_event' ) ); + + if ( ! has_action( 'bsf_analytics_send', array( $this, 'send' ) ) ) { + add_action( 'bsf_analytics_send', array( $this, 'send' ) ); + } + + add_action( 'admin_init', array( $this, 'register_usage_tracking_setting' ) ); + + add_action( 'update_option_bsf_analytics_optin', array( $this, 'update_analytics_option_callback' ), 10, 3 ); + add_action( 'add_option_bsf_analytics_optin', array( $this, 'add_analytics_option_callback' ), 10, 2 ); + + $this->includes(); + } + + /** + * BSF Analytics URL + * + * @return String URL of bsf-analytics directory. + * @since 1.0.0 + */ + public function bsf_analytics_url() { + + $path = wp_normalize_path( BSF_ANALYTICS_PATH ); + $theme_dir = wp_normalize_path( get_template_directory() ); + + if ( strpos( $path, $theme_dir ) !== false ) { + return rtrim( get_template_directory_uri() . '/admin/bsf-analytics/', '/' ); + } else { + return rtrim( plugin_dir_url( BSF_ANALYTICS_FILE ), '/' ); + } + } + + /** + * Get API URL for sending analytics. + * + * @return string API URL. + * @since 1.0.0 + */ + private function get_api_url() { + return defined( 'BSF_API_URL' ) ? BSF_API_URL : 'https://support.brainstormforce.com/'; + } + + /** + * Enqueue Scripts. + * + * @since 1.0.0 + * @return void + */ + public function enqueue_assets() { + + /** + * Load unminified if SCRIPT_DEBUG is true. + * + * Directory and Extensions. + */ + $dir_name = ( SCRIPT_DEBUG ) ? 'unminified' : 'minified'; + $file_rtl = ( is_rtl() ) ? '-rtl' : ''; + $css_ext = ( SCRIPT_DEBUG ) ? '.css' : '.min.css'; + + $css_uri = BSF_ANALYTICS_URI . '/assets/css/' . $dir_name . '/style' . $file_rtl . $css_ext; + + wp_enqueue_style( 'bsf-analytics-admin-style', $css_uri, false, BSF_ANALYTICS_VERSION, 'all' ); + } + + /** + * Send analytics API call. + * + * @since 1.0.0 + */ + public function send() { + wp_remote_post( + $this->get_api_url() . 'wp-json/bsf-core/v1/analytics/', + array( + 'body' => BSF_Analytics_Stats::instance()->get_stats(), + 'timeout' => 5, + 'blocking' => false, + ) + ); + } + + /** + * Check if usage tracking is enabled. + * + * @return bool + * @since 1.0.0 + */ + public function is_tracking_enabled() { + $is_enabled = get_site_option( 'bsf_analytics_optin' ) === 'yes' ? true : false; + $is_enabled = $this->is_white_label_enabled() ? false : $is_enabled; + + return apply_filters( 'bsf_tracking_enabled', $is_enabled ); + } + + /** + * Check if WHITE label is enabled for BSF products. + * + * @return bool + * @since 1.0.0 + */ + public function is_white_label_enabled() { + + $options = apply_filters( 'bsf_white_label_options', array() ); + $is_enabled = false; + + if ( is_array( $options ) ) { + foreach ( $options as $option ) { + if ( true === $option ) { + $is_enabled = true; + break; + } + } + } + + return $is_enabled; + } + + /** + * Display admin notice for usage tracking. + * + * @since 1.0.0 + */ + public function option_notice() { + + if ( ! current_user_can( 'manage_options' ) ) { + return; + } + + // Don't display the notice if tracking is disabled or White Label is enabled for any of our plugins. + if ( false !== get_site_option( 'bsf_analytics_optin', false ) || $this->is_white_label_enabled() ) { + return; + } + + // Show tracker consent notice after 24 hours from installed time. + if ( strtotime( '+24 hours', $this->get_analytics_install_time() ) > time() ) { + return; + } + + /* translators: %s product name */ + $notice_string = __( 'Want to help make %1s even more awesome? Allow us to collect non-sensitive diagnostic data and usage information. ', 'fullwidth-templates' ); + + if ( is_multisite() ) { + $notice_string .= __( 'This will be applicable for all sites from the network.', 'fullwidth-templates' ); + } + + $language_dir = is_rtl() ? 'rtl' : 'ltr'; + + Astra_Notices::add_notice( + array( + 'id' => 'bsf-optin-notice', + 'type' => '', + 'message' => sprintf( + '
', + /* translators: %s usage doc link */ + sprintf( $notice_string . '%4s', esc_html( $this->get_product_name() ), $language_dir, esc_url( $this->usage_doc_link ), __( ' Know More.', 'fullwidth-templates' ) ), + add_query_arg( + array( + 'bsf_analytics_optin' => 'yes', + 'bsf_analytics_nonce' => wp_create_nonce( 'bsf_analytics_optin' ), + ) + ), + __( 'Yes! Allow it', 'fullwidth-templates' ), + add_query_arg( + array( + 'bsf_analytics_optin' => 'no', + 'bsf_analytics_nonce' => wp_create_nonce( 'bsf_analytics_optin' ), + ) + ), + MONTH_IN_SECONDS, + __( 'No Thanks', 'fullwidth-templates' ) + ), + 'show_if' => true, + 'repeat-notice-after' => false, + 'priority' => 18, + 'display-with-other-notices' => true, + ) + ); + } + + /** + * Process usage tracking opt out. + * + * @since 1.0.0 + */ + public function handle_optin_optout() { + if ( ! isset( $_GET['bsf_analytics_nonce'] ) ) { + return; + } + + if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['bsf_analytics_nonce'] ) ), 'bsf_analytics_optin' ) ) { + return; + } + + $optin_status = isset( $_GET['bsf_analytics_optin'] ) ? sanitize_text_field( wp_unslash( $_GET['bsf_analytics_optin'] ) ) : ''; + + if ( 'yes' === $optin_status ) { + $this->optin(); + } elseif ( 'no' === $optin_status ) { + $this->optout(); + } + + wp_safe_redirect( + remove_query_arg( + array( + 'bsf_analytics_optin', + 'bsf_analytics_nonce', + ) + ) + ); + } + + /** + * Opt in to usage tracking. + * + * @since 1.0.0 + */ + private function optin() { + update_site_option( 'bsf_analytics_optin', 'yes' ); + } + + /** + * Opt out to usage tracking. + * + * @since 1.0.0 + */ + private function optout() { + update_site_option( 'bsf_analytics_optin', 'no' ); + } + + /** + * Add two days event schedule variables. + * + * @param array $schedules scheduled array data. + * @since 1.0.0 + */ + public function every_two_days_schedule( $schedules ) { + $schedules['every_two_days'] = array( + 'interval' => 2 * DAY_IN_SECONDS, + 'display' => __( 'Every two days', 'fullwidth-templates' ), + ); + + return $schedules; + } + + /** + * Schedule usage tracking event. + * + * @since 1.0.0 + */ + private function schedule_event() { + if ( ! wp_next_scheduled( 'bsf_analytics_send' ) && $this->is_tracking_enabled() ) { + wp_schedule_event( time(), 'every_two_days', 'bsf_analytics_send' ); + } + } + + /** + * Unschedule usage tracking event. + * + * @since 1.0.0 + */ + private function unschedule_event() { + wp_clear_scheduled_hook( 'bsf_analytics_send' ); + } + + /** + * Load analytics stat class. + * + * @since 1.0.0 + */ + private function includes() { + require_once __DIR__ . '/class-bsf-analytics-stats.php'; + } + + /** + * Register usage tracking option in General settings page. + * + * @since 1.0.0 + */ + public function register_usage_tracking_setting() { + + if ( ! apply_filters( 'bsf_tracking_enabled', true ) || $this->is_white_label_enabled() ) { + return; + } + + register_setting( + 'general', // Options group. + 'bsf_analytics_optin', // Option name/database. + array( 'sanitize_callback' => array( $this, 'sanitize_option' ) ) // sanitize callback function. + ); + + add_settings_field( + 'bsf-analytics-optin', // Field ID. + __( 'Usage Tracking', 'fullwidth-templates' ), // Field title. + array( $this, 'render_settings_field_html' ), // Field callback function. + 'general' // Settings page slug. + ); + } + + /** + * Sanitize Callback Function + * + * @param bool $input Option value. + * @since 1.0.0 + */ + public function sanitize_option( $input ) { + + if ( ! $input || 'no' === $input ) { + return 'no'; + } + + return 'yes'; + } + + /** + * Print settings field HTML. + * + * @since 1.0.0 + */ + public function render_settings_field_html() { + ?> + + get( 'Name' ); + } + + $base = plugin_basename( __FILE__ ); + + $exploded_path = explode( '/', $base, 2 ); + $plugin_slug = $exploded_path[0]; + + return $this->get_plugin_name( $plugin_slug ); + } + + /** + * Get plugin name by plugin slug. + * + * @param string $plugin_slug Plugin slug. + * @return string $plugin_info['Name'] Plugin name. + */ + private function get_plugin_name( $plugin_slug ) { + + $plugins = get_option( 'active_plugins' ); + + if ( ! function_exists( 'get_plugin_data' ) ) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + + foreach ( $plugins as $plugin_file ) { + if ( 0 === strpos( $plugin_file, $plugin_slug ) ) { + $plugin_path = WP_PLUGIN_DIR . '/' . $plugin_file; + $plugin_data = get_plugin_data( $plugin_path ); + return $plugin_data['Name']; + } + } + } + + /** + * Set analytics installed time in option. + * + * @return string $time analytics installed time. + * @since 1.0.0 + */ + private function get_analytics_install_time() { + + $time = get_site_option( 'bsf_analytics_installed_time' ); + + if ( ! $time ) { + $time = time(); + update_site_option( 'bsf_analytics_installed_time', time() ); + } + + return $time; + } + + /** + * Schedule/unschedule cron event on updation of option. + * + * @param string $old_value old value of option. + * @param string $value value of option. + * @param string $option Option name. + * @since 1.0.0 + */ + public function update_analytics_option_callback( $old_value, $value, $option ) { + $this->add_option_to_network( $value ); + } + + /** + * Analytics option add callback. + * + * @param string $option Option name. + * @param string $value value of option. + * @since 1.0.0 + */ + public function add_analytics_option_callback( $option, $value ) { + $this->add_option_to_network( $value ); + } + + /** + * Schedule or unschedule event based on analytics option value. + * + * @since 1.0.0 + */ + public function schedule_unschedule_event() { + + if ( true === $this->is_white_label_enabled() ) { + $this->unschedule_event(); + return; + } + + $analytics_option = get_site_option( 'bsf_analytics_optin' ); + + if ( 'no' === $analytics_option ) { + $this->unschedule_event(); + } elseif ( 'yes' === $analytics_option ) { + $this->schedule_event(); + } + } + + /** + * Save analytics option to network. + * + * @param string $value value of option. + * @since 1.0.0 + */ + public function add_option_to_network( $value ) { + + // If action coming from general settings page. + if ( isset( $_POST['option_page'] ) && 'general' === $_POST['option_page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + + if ( get_site_option( 'bsf_analytics_optin' ) ) { + update_site_option( 'bsf_analytics_optin', $value ); + } else { + add_site_option( 'bsf_analytics_optin', $value ); + } + } + } + } + + new BSF_Analytics(); + +} diff --git a/admin/notices/class-astra-notices.php b/admin/notices/class-astra-notices.php new file mode 100644 index 0000000..6456b66 --- /dev/null +++ b/admin/notices/class-astra-notices.php @@ -0,0 +1,350 @@ + Create custom close notice link in the notice markup. E.g. + * `` + * It close the notice for 30 days. + * + * @package Astra Sites + * @since 1.4.0 + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +if ( ! class_exists( 'Astra_Notices' ) ) : + + /** + * Astra_Notices + * + * @since 1.4.0 + */ + class Astra_Notices { + + /** + * Notices + * + * @access private + * @var array Notices. + * @since 1.4.0 + */ + private static $version = '1.1.5'; + + /** + * Notices + * + * @access private + * @var array Notices. + * @since 1.4.0 + */ + private static $notices = array(); + + /** + * Instance + * + * @access private + * @var object Class object. + * @since 1.4.0 + */ + private static $instance; + + /** + * Initiator + * + * @since 1.4.0 + * @return object initialized object of class. + */ + public static function get_instance() { + if ( ! isset( self::$instance ) ) { + self::$instance = new self(); + } + return self::$instance; + } + + /** + * Constructor + * + * @since 1.4.0 + */ + public function __construct() { + add_action( 'admin_notices', array( $this, 'show_notices' ), 30 ); + add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); + add_action( 'wp_ajax_astra-notice-dismiss', array( $this, 'dismiss_notice' ) ); + add_filter( 'wp_kses_allowed_html', array( $this, 'add_data_attributes' ), 10, 2 ); + } + + /** + * Filters and Returns a list of allowed tags and attributes for a given context. + * + * @param Array $allowedposttags Array of allowed tags. + * @param String $context Context type (explicit). + * @since 1.4.0 + * @return Array + */ + public function add_data_attributes( $allowedposttags, $context ) { + $allowedposttags['a']['data-repeat-notice-after'] = true; + + return $allowedposttags; + } + + /** + * Add Notice. + * + * @since 1.4.0 + * @param array $args Notice arguments. + * @return void + */ + public static function add_notice( $args = array() ) { + self::$notices[] = $args; + } + + /** + * Dismiss Notice. + * + * @since 1.4.0 + * @return void + */ + public function dismiss_notice() { + $notice_id = ( isset( $_POST['notice_id'] ) ) ? sanitize_key( $_POST['notice_id'] ) : ''; + $repeat_notice_after = ( isset( $_POST['repeat_notice_after'] ) ) ? absint( $_POST['repeat_notice_after'] ) : ''; + $nonce = ( isset( $_POST['nonce'] ) ) ? sanitize_key( $_POST['nonce'] ) : ''; + + if ( false === wp_verify_nonce( $nonce, 'astra-notices' ) ) { + wp_send_json_error( _e( 'WordPress Nonce not validated.', 'fullwidth-templates' ) ); + } + + // Valid inputs? + if ( ! empty( $notice_id ) ) { + if ( ! empty( $repeat_notice_after ) ) { + set_transient( $notice_id, true, $repeat_notice_after ); + } else { + update_user_meta( get_current_user_id(), $notice_id, 'notice-dismissed' ); + } + + wp_send_json_success(); + } + + wp_send_json_error(); + } + + /** + * Enqueue Scripts. + * + * @since 1.4.0 + * @return void + */ + public function enqueue_scripts() { + wp_register_script( 'astra-notices', self::_get_uri() . 'notices.js', array( 'jquery' ), self::$version, true ); + wp_localize_script( + 'astra-notices', + 'astraNotices', + array( + '_notice_nonce' => wp_create_nonce( 'astra-notices' ), + ) + ); + } + + /** + * Rating priority sort + * + * @since 1.5.2 + * @param array $array1 array one. + * @param array $array2 array two. + * @return array + */ + public function sort_notices( $array1, $array2 ) { + if ( ! isset( $array1['priority'] ) ) { + $array1['priority'] = 10; + } + if ( ! isset( $array2['priority'] ) ) { + $array2['priority'] = 10; + } + + return $array1['priority'] - $array2['priority']; + } + + /** + * Notice Types + * + * @since 1.4.0 + * @return void + */ + public function show_notices() { + $defaults = array( + 'id' => '', // Optional, Notice ID. If empty it set `astra-notices-id-<$array-index>`. + 'type' => 'info', // Optional, Notice type. Default `info`. Expected [info, warning, notice, error]. + 'message' => '', // Optional, Message. + 'show_if' => true, // Optional, Show notice on custom condition. E.g. 'show_if' => if( is_admin() ) ? true, false, . + 'repeat-notice-after' => '', // Optional, Dismiss-able notice time. It'll auto show after given time. + 'display-notice-after' => false, // Optional, Dismiss-able notice time. It'll auto show after given time. + 'class' => '', // Optional, Additional notice wrapper class. + 'priority' => 10, // Priority of the notice. + 'display-with-other-notices' => true, // Should the notice be displayed if other notices are being displayed from Astra_Notices. + 'is_dismissible' => true, + ); + + // Count for the notices that are rendered. + $notices_displayed = 0; + + // sort the array with priority. + usort( self::$notices, array( $this, 'sort_notices' ) ); + + foreach ( self::$notices as $key => $notice ) { + $notice = wp_parse_args( $notice, $defaults ); + + $notice['id'] = self::get_notice_id( $notice, $key ); + + $notice['classes'] = self::get_wrap_classes( $notice ); + + // Notices visible after transient expire. + if ( isset( $notice['show_if'] ) && true === $notice['show_if'] ) { + + // don't display the notice if it is not supposed to be displayed with other notices. + if ( 0 !== $notices_displayed && false === $notice['display-with-other-notices'] ) { + continue; + } + + if ( self::is_expired( $notice ) ) { + self::markup( $notice ); + ++$notices_displayed; + } + } + } + } + + /** + * Markup Notice. + * + * @since 1.4.0 + * @param array $notice Notice markup. + * @return void + */ + public static function markup( $notice = array() ) { + wp_enqueue_script( 'astra-notices' ); + + do_action( 'astra_notice_before_markup' ); + + do_action( "astra_notice_before_markup_{$notice['id']}" ); + + ?> +