dvadf
File manager - Edit - /home/centroca/public_html/admin.tar
Back
bsf-analytics/version.json 0000644 00000000044 15252514036 0011664 0 ustar 00 { "bsf-analytics-ver": "1.1.29" } bsf-analytics/class-bsf-analytics-loader.php 0000644 00000004601 15252514036 0015126 0 ustar 00 <?php /** * BSF analytics loader file. * * @version 1.0.0 * * @package bsf-analytics */ if ( ! defined( 'ABSPATH' ) ) { exit(); } /** * Class BSF_Analytics_Loader. */ class BSF_Analytics_Loader { /** * Analytics Entities. * * @access private * @var array Entities array. */ private $entities = array(); /** * Analytics Version. * * @access private * @var float analytics version. */ private $analytics_version = ''; /** * Analytics path. * * @access private * @var string path array. */ private $analytics_path = ''; /** * Instance * * @access private * @var object Class object. */ private static $instance = null; /** * Get instace of class. * * @return object */ public static function get_instance() { if ( null === self::$instance ) { self::$instance = new self(); } return self::$instance; } /** * Constructor */ public function __construct() { add_action( 'init', array( $this, 'load_analytics' ) ); } /** * Set entity for analytics. * * @param string $data Entity attributes data. * @return void */ public function set_entity( $data ) { array_push( $this->entities, $data ); } /** * Load Analytics library. * * @return void */ public function load_analytics() { $unique_entities = array(); if ( ! empty( $this->entities ) ) { foreach ( $this->entities as $entity ) { foreach ( $entity as $key => $data ) { if ( isset( $data['path'] ) ) { if ( file_exists( $data['path'] . '/version.json' ) ) { $file_contents = file_get_contents( $data['path'] . '/version.json' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents $analytics_version = json_decode( $file_contents, 1 ); $analytics_version = $analytics_version['bsf-analytics-ver']; if ( version_compare( $analytics_version, $this->analytics_version, '>' ) ) { $this->analytics_version = $analytics_version; $this->analytics_path = $data['path']; } } } if ( ! isset( $unique_entities[ $key ] ) ) { $unique_entities[ $key ] = $data; } } } if ( file_exists( $this->analytics_path ) && ! class_exists( 'BSF_Analytics' ) ) { require_once $this->analytics_path . '/class-bsf-analytics.php'; new BSF_Analytics( $unique_entities, $this->analytics_path, $this->analytics_version ); } } } } bsf-analytics/classes/class-bsf-analytics-helper.php 0000644 00000005462 15252514036 0016602 0 ustar 00 <?php /** * BSF analytics Helper Class File. * * @package bsf-analytics */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } if ( ! class_exists( 'BSF_Analytics_Helper' ) ) { /** * BSF analytics stat class. */ class BSF_Analytics_Helper { /** * Check is error in the received response. * * @param object $response Received API Response. * @return array $result Error result. */ public static function is_api_error( $response ) { $result = array( 'error' => false, 'error_message' => __( 'Oops! Something went wrong. Please refresh the page and try again.', 'astra-sites' ), 'error_code' => 0, ); if ( is_wp_error( $response ) ) { $result['error'] = true; $result['error_message'] = $response->get_error_message(); $result['error_code'] = $response->get_error_code(); } elseif ( ! empty( wp_remote_retrieve_response_code( $response ) ) && ! in_array( wp_remote_retrieve_response_code( $response ), array( 200, 201, 204 ), true ) ) { $result['error'] = true; $result['error_message'] = wp_remote_retrieve_response_message( $response ); $result['error_code'] = wp_remote_retrieve_response_code( $response ); } return $result; } /** * Get API headers * * @since 1.1.6 * @return array<string, string> */ public static function get_api_headers() { return array( 'Content-Type' => 'application/json', 'Accept' => 'application/json', ); } /** * Get API URL for sending analytics. * * @return string API URL. * @since 1.0.0 */ public static function get_api_url() { return defined( 'BSF_ANALYTICS_API_BASE_URL' ) ? BSF_ANALYTICS_API_BASE_URL : 'https://analytics.brainstormforce.com/'; } /** * Check if the current screen is allowed for the survey. * * This function checks if the current screen is one of the allowed screens for displaying the survey. * It uses the `get_current_screen` function to get the current screen information and compares it with the list of allowed screens. * * @since 1.1.6 * @return bool True if the current screen is allowed, false otherwise. */ public static function is_allowed_screen() { // This filter allows to dynamically modify the list of allowed screens for the survey. $allowed_screens = apply_filters( 'uds_survey_allowed_screens', array( 'plugins' ) ); $current_screen = get_current_screen(); // Check if $current_screen is a valid object before accessing its properties. if ( ! is_object( $current_screen ) ) { return false; // Return false if current screen is not valid. } $screen_id = $current_screen->id; if ( ! empty( $screen_id ) && in_array( $screen_id, $allowed_screens, true ) ) { return true; } return false; } } } bsf-analytics/changelog.txt 0000644 00000006125 15252514036 0012002 0 ustar 00 v1.1.29 - 30-June-2026 - Improvement: Added `spectra-blocks` slug to UTM analytics. v1.1.28 - 22-June-2026 - Fix: Deactivation survey loaded a non-existent RTL stylesheet (`feedback.min-rtl.css`) producing a 404 in RTL locales. Registered the file suffix so the correct `feedback-rtl.min.css` is requested. v1.1.27 - 16-June-2026 - Improvement: Added `SureDonation` slug to UTM analytics. v1.1.26 - 20-April-2026 - Improvement: Switched from `Astra_Notices` to `BSF_Admin_Notices`. v1.1.25 - 13-April-2026 - New: Added optional `$force` parameter (4th arg) to `track()` — when true, bypasses the post-send dedup and overwrites any pending entry with the latest value. Default behavior (skip on duplicate) is unchanged. Useful for recurring events like `plugin_updated`. v1.1.24 - 8-April-2026 - Improvement: Updated admin notice copy — concise heading, description, and button labels. v1.1.23 - 7-April-2026 - Improvement: Improved consent notice copy — leads with benefit, clearer CTAs. - Improvement: Standardized usage doc link with dynamic product-specific UTM parameters. - Fix: Clear tracking transient immediately on opt-out for instant effect. - New: Added `bsf_usage_tracking_enabled` global filter as a kill switch for hosting providers and compliance plugins. - New: Include admin email in tracking payload. v1.1.22 - 1-April-2026 - Improvement: Added `surecontact`, `surecookie`, `suredash`, `power-coupons` and `sigmize` slugs to UTM analytics. v1.1.21 - 27-March-2026 - New: Introduced BSF_Analytics_Events class for reusable one-time milestone event tracking with dedup. - New: Support for custom option resolver callbacks (get/update) or default plugin-slug-prefixed WordPress options. v1.1.20 - 4-March-2026 - New: Added PHPUnit test suite with 73 tests covering all 6 classes using WP_Mock. - New: Added GitHub Actions CI workflow for PHPUnit tests across PHP 7.4, 8.0, 8.1, and 8.2. v1.1.19 - 1-March-2026 - Fix: Resolved dead-code form ID fallback and reduced AJAX timeout from 90s to 15s in deactivation survey. - Fix: Moved nonce verification before $_GET access in handle_optin_optout() to comply with WordPress.org coding standards. v1.1.18 - 19-February-2026 - Improvement: Added `modern-cart` slug to UTM analytics. v1.1.17 - 29-January-2026 - Improvement: Renamed options from `*_analytics_*` to `*_usage_*`. v1.1.16 - 15-July-2025 - Improvement: Added `SureRank` slug to UTM analytics. v1.1.15 - 1-July-2025 - Improvement: Added `Ultimate_VC_Addons` slug to UTM analytics. v1.1.14 - 6-May-2025 - New: Introduced a key 'hide_optin_checkbox' to hide checkbox from Settings > General. - Improvement: Single optin notice for all bsf products. - Improvement: Introduced delay of 7 days for next optin message if user has reqested request from product. v1.1.13 - 17-April-2025 - Improvement: Ensured unique id for label's `for` attribute in deactivation survey fields by prefixing them with product slugs. - Improvement: Prevented deactivation survey from triggering when switching from a child theme to its parent. v1.1.12 - 24-March-2025 - Improvement: Added `suremails` and `latepoint` slugs to UTM analytics. bsf-analytics/assets/css/minified/style.min.css 0000644 00000000460 15252514036 0015620 0 ustar 00 [ID*="-optin-notice"]{padding:1px 12px;border-left-color:#007cba}[ID*="-optin-notice"] .notice-container{padding-top:10px;padding-bottom:12px}[ID*="-optin-notice"] .notice-content{margin:0}[ID*="-optin-notice"] .notice-heading{padding:0 20px 12px 0}[ID*="-optin-notice"] .button-primary{margin-right:5px} bsf-analytics/assets/css/minified/style-rtl.min.css 0000644 00000000460 15252514036 0016417 0 ustar 00 [ID*="-optin-notice"]{padding:1px 12px;border-right-color:#007cba}[ID*="-optin-notice"] .notice-container{padding-top:10px;padding-bottom:12px}[ID*="-optin-notice"] .notice-content{margin:0}[ID*="-optin-notice"] .notice-heading{padding:0 0 12px 20px}[ID*="-optin-notice"] .button-primary{margin-left:5px} bsf-analytics/assets/css/unminified/style-rtl.css 0000644 00000000561 15252514036 0016202 0 ustar 00 [ID*="-optin-notice"] { padding: 1px 12px; border-right-color: #007cba; } [ID*="-optin-notice"] .notice-container { padding-top: 10px; padding-bottom: 12px; } [ID*="-optin-notice"] .notice-content { margin: 0; } [ID*="-optin-notice"] .notice-heading { padding: 0 0 12px 20px; } [ID*="-optin-notice"] .button-primary { margin-left: 5px; } bsf-analytics/assets/css/unminified/style.css 0000644 00000000561 15252514036 0015403 0 ustar 00 [ID*="-optin-notice"] { padding: 1px 12px; border-left-color: #007cba; } [ID*="-optin-notice"] .notice-container { padding-top: 10px; padding-bottom: 12px; } [ID*="-optin-notice"] .notice-content { margin: 0; } [ID*="-optin-notice"] .notice-heading { padding: 0 20px 12px 0; } [ID*="-optin-notice"] .button-primary { margin-right: 5px; } bsf-analytics/class-bsf-analytics.php 0000644 00000047472 15252514036 0013677 0 ustar 00 <?php /** * BSF analytics class file. * * @version 1.0.0 * * @package bsf-analytics */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } if ( ! class_exists( 'BSF_Analytics' ) ) { /** * BSF analytics */ class BSF_Analytics { /** * Member Variable * * @var array Entities data. */ private $entities; /** * Member Variable * * @var string Usage tracking document URL */ public $usage_doc_link = 'https://store.brainstormforce.com/usage-tracking/'; /** * Setup actions, load files. * * @param array $args entity data for analytics. * @param string $analytics_path directory path to analytics library. * @param float $analytics_version analytics library version. * @since 1.0.0 */ public function __construct( $args, $analytics_path, $analytics_version ) { // Bail when no analytics entities are registered. if ( empty( $args ) ) { return; } $this->entities = $args; // Run migration from old "analytics" option names to new "usage" names. $this->maybe_migrate_options(); define( 'BSF_ANALYTICS_VERSION', $analytics_version ); define( 'BSF_ANALYTICS_URI', $this->get_analytics_url( $analytics_path ) ); add_action( 'admin_init', array( $this, 'handle_optin_optout' ) ); add_action( 'admin_init', array( $this, 'option_notice' ) ); add_action( 'init', array( $this, 'maybe_track_analytics' ), 99 ); $this->set_actions(); add_action( 'admin_init', array( $this, 'register_usage_tracking_setting' ) ); $this->includes(); $this->load_deactivation_survey_actions(); } /** * Function to load the deactivation survey form actions. * * @since 1.1.6 * @return void */ public function load_deactivation_survey_actions() { // If not in a admin area then return it. if ( ! is_admin() ) { return; } add_filter( 'uds_survey_vars', array( $this, 'add_slugs_to_uds_vars' ) ); add_action( 'admin_footer', array( $this, 'load_deactivation_survey_form' ) ); } /** * Setup actions for admin notice style and analytics cron event. * * @since 1.0.4 */ public function set_actions() { foreach ( $this->entities as $key => $data ) { add_action( 'bsf_admin_notice_before_markup_' . $key . '-optin-notice', array( $this, 'enqueue_assets' ) ); add_action( 'update_option_' . $key . '_usage_optin', array( $this, 'update_analytics_option_callback' ), 10, 3 ); add_action( 'add_option_' . $key . '_usage_optin', array( $this, 'add_analytics_option_callback' ), 10, 2 ); } } /** * BSF Analytics URL * * @param string $analytics_path directory path to analytics library. * @return String URL of bsf-analytics directory. * @since 1.0.0 */ public function get_analytics_url( $analytics_path ) { $content_dir_path = wp_normalize_path( WP_CONTENT_DIR ); $analytics_path = wp_normalize_path( $analytics_path ); return str_replace( $content_dir_path, content_url(), $analytics_path ); } /** * 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() { $api_url = BSF_Analytics_Helper::get_api_url(); wp_remote_post( $api_url . 'api/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() { // Global kill switch — allows hosting providers, compliance plugins, // or agency developers to disable all BSF tracking with one filter. if ( ! apply_filters( 'bsf_usage_tracking_enabled', true ) ) { return false; } foreach ( $this->entities as $key => $data ) { $is_enabled = get_site_option( $key . '_usage_optin', false ) === 'yes' ? true : false; $is_enabled = $this->is_white_label_enabled( $key ) ? false : $is_enabled; if ( apply_filters( $key . '_tracking_enabled', $is_enabled ) ) { return true; } } return false; } /** * Check if WHITE label is enabled for BSF products. * * @param string $source source of analytics. * @return bool * @since 1.0.0 */ public function is_white_label_enabled( $source ) { $options = apply_filters( $source . '_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; } /** * Get usage doc link with UTM parameters. * * Appends product-specific UTM params to the default usage tracking URL * so we can attribute which plugin's link was clicked. * * @param string $product_key Product key (e.g., 'spectra', 'surerank'). * @param string $context Where the link appears ('notice' or 'settings'). * @return string Full URL with UTM parameters. * @since 1.1.23 */ public function get_usage_doc_link( $product_key, $context = 'notice' ) { return add_query_arg( array( 'utm_source' => $product_key, 'utm_medium' => $context, 'utm_campaign' => 'usage_tracking', ), $this->usage_doc_link ); } /** * Display admin notice for usage tracking. * * @since 1.0.0 */ public function option_notice() { if ( ! class_exists( 'BSF_Admin_Notices' ) ) { return; } if ( ! current_user_can( 'manage_options' ) ) { return; } if( $this->is_tracking_enabled() ) { return; // Don't need to display notice if any of our plugin already have the permission. } // If the user has opted out of tracking, don't show the notice till 7 days. $last_displayed_time = get_site_option( 'bsf_usage_last_displayed_time', false ); if ( $last_displayed_time && $last_displayed_time > time() - ( 7 * DAY_IN_SECONDS ) ) { return; // Don't display the notice if it was displayed recently. } foreach ( $this->entities as $key => $data ) { $time_to_display = isset( $data['time_to_display'] ) ? $data['time_to_display'] : '+24 hours'; $usage_doc_link = isset( $data['usage_doc_link'] ) ? $data['usage_doc_link'] : $this->get_usage_doc_link( $key, 'notice' ); // Don't display the notice if tracking is disabled or White Label is enabled for any of our plugins. if ( false !== get_site_option( $key . '_usage_optin', false ) || $this->is_white_label_enabled( $key ) ) { continue; } // Show tracker consent notice after 24 hours from installed time. if ( strtotime( $time_to_display, $this->get_analytics_install_time( $key ) ) > time() ) { continue; } /* translators: %s product name */ $notice_string = sprintf( __( '<strong>Help shape the future of %1$s.</strong><br><br>Share how you use the plugin so we can build features that matter, fix issues faster, and make smarter decisions.', 'astra-sites' ), esc_html( $data['product_name'] ) ); if ( is_multisite() ) { $notice_string .= __( 'This will be applicable for all sites from the network.', 'astra-sites' ); } $language_dir = is_rtl() ? 'rtl' : 'ltr'; BSF_Admin_Notices::add_notice( array( 'id' => $key . '-optin-notice', 'type' => '', 'message' => sprintf( '<div class="notice-content"> <div class="notice-heading"> %1$s </div> <div class="astra-notices-container"> <a href="%2$s" class="astra-notices button-primary"> %3$s </a> <a href="%4$s" data-repeat-notice-after="%5$s" class="astra-notices button-secondary"> %6$s </a> </div> </div>', /* translators: %s usage doc link */ sprintf( $notice_string . '<span dir="%1s"> <a href="%2s" target="_blank" rel="noreferrer noopener">%3s</a><span><br><br>', $language_dir, esc_url( $usage_doc_link ), __( 'Learn more.', 'astra-sites' ) ), esc_url( add_query_arg( array( $key . '_analytics_optin' => 'yes', $key . '_analytics_nonce' => wp_create_nonce( $key . '_analytics_optin' ), 'bsf_analytics_source' => $key, ) ) ), __( 'Happy to help!', 'astra-sites' ), esc_url( add_query_arg( array( $key . '_analytics_optin' => 'no', $key . '_analytics_nonce' => wp_create_nonce( $key . '_analytics_optin' ), 'bsf_analytics_source' => $key, ) ) ), MONTH_IN_SECONDS, __( 'Skip', 'astra-sites' ) ), 'show_if' => true, 'repeat-notice-after' => false, 'priority' => 18, 'display-with-other-notices' => true, ) ); return; } } /** * Process usage tracking opt out. * * @since 1.0.0 */ public function handle_optin_optout() { if ( ! current_user_can( 'manage_options' ) ) { return; } // Verify nonce before accessing any $_GET data. // The nonce key is dynamic per entity, so iterate to find a valid one. $source = ''; foreach ( $this->entities as $key => $data ) { $nonce_key = $key . '_analytics_nonce'; if ( isset( $_GET[ $nonce_key ] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET[ $nonce_key ] ) ), $key . '_analytics_optin' ) ) { $source = $key; break; } } if ( empty( $source ) ) { return; } $optin_status = isset( $_GET[ $source . '_analytics_optin' ] ) ? sanitize_text_field( wp_unslash( $_GET[ $source . '_analytics_optin' ] ) ) : ''; if ( 'yes' === $optin_status ) { $this->optin( $source ); } elseif ( 'no' === $optin_status ) { $this->optout( $source ); } wp_safe_redirect( esc_url_raw( remove_query_arg( array( $source . '_analytics_optin', $source . '_analytics_nonce', 'bsf_analytics_source', ) ) ) ); exit; } /** * Opt in to usage tracking. * * @param string $source source of analytics. * @since 1.0.0 */ private function optin( $source ) { update_site_option( $source . '_usage_optin', 'yes' ); } /** * Opt out of usage tracking. * * @param string $source source of analytics. * @since 1.0.0 */ private function optout( $source ) { update_site_option( $source . '_usage_optin', 'no' ); update_site_option( 'bsf_usage_last_displayed_time', time() ); // Clear tracking transient immediately so opt-out takes effect right away. delete_site_transient( 'bsf_usage_track' ); } /** * Load analytics stat class. * * @since 1.0.0 */ private function includes() { require_once __DIR__ . '/classes/class-bsf-analytics-helper.php'; require_once __DIR__ . '/class-bsf-analytics-stats.php'; require_once __DIR__ . '/class-bsf-analytics-events.php'; // Loads all the modules. require_once __DIR__ . '/modules/deactivation-survey/classes/class-deactivation-survey-feedback.php'; require_once __DIR__ . '/modules/utm-analytics.php'; } /** * Migrate old "analytics" options to new "usage" naming. * Copies values to new options and deletes old options. * * @since 1.1.17 */ private function maybe_migrate_options() { if ( get_site_option( 'bsf_usage_migrated' ) ) { return; } // Migrate global options. $old_last_displayed = get_site_option( 'bsf_analytics_last_displayed_time' ); if ( false !== $old_last_displayed ) { update_site_option( 'bsf_usage_last_displayed_time', $old_last_displayed ); delete_site_option( 'bsf_analytics_last_displayed_time' ); } // Migrate per-product options. foreach ( $this->entities as $key => $data ) { $old_optin = get_site_option( $key . '_analytics_optin' ); if ( false !== $old_optin ) { update_site_option( $key . '_usage_optin', $old_optin ); delete_site_option( $key . '_analytics_optin' ); } $old_install_time = get_site_option( $key . '_analytics_installed_time' ); if ( false !== $old_install_time ) { update_site_option( $key . '_usage_installed_time', $old_install_time ); delete_site_option( $key . '_analytics_installed_time' ); } } // Migrate transient. $old_track = get_site_transient( 'bsf_analytics_track' ); if ( false !== $old_track ) { set_site_transient( 'bsf_usage_track', $old_track, 2 * DAY_IN_SECONDS ); delete_site_transient( 'bsf_analytics_track' ); } update_site_option( 'bsf_usage_migrated', true ); } /** * Register usage tracking option in General settings page. * * @since 1.0.0 */ public function register_usage_tracking_setting() { foreach ( $this->entities as $key => $data ) { if ( ! apply_filters( $key . '_tracking_enabled', true ) || $this->is_white_label_enabled( $key ) ) { return; } /** * Introducing a new key 'hide_optin_checkbox, which allows individual plugin to hide optin checkbox * If they are providing providing in-plugin option to manage this option. * from General > Settings page. * * @since 1.1.14 */ if( ! empty( $data['hide_optin_checkbox'] ) && true === $data['hide_optin_checkbox'] ) { continue; } $usage_doc_link = isset( $data['usage_doc_link'] ) ? $data['usage_doc_link'] : $this->get_usage_doc_link( $key, 'settings' ); $author = isset( $data['author'] ) ? $data['author'] : 'Brainstorm Force'; register_setting( 'general', // Options group. $key . '_usage_optin', // Option name/database. array( 'sanitize_callback' => array( $this, 'sanitize_option' ) ) // sanitize callback function. ); add_settings_field( $key . '-usage-optin', // Field ID. __( 'Usage Tracking', 'astra-sites' ), // Field title. array( $this, 'render_settings_field_html' ), // Field callback function. 'general', 'default', // Settings page slug. array( 'type' => 'checkbox', 'title' => $author, 'name' => $key . '_usage_optin', 'label_for' => $key . '-usage-optin', 'id' => $key . '-usage-optin', 'usage_doc_link' => $usage_doc_link, ) ); } } /** * 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. * * @param array $args arguments to field. * @since 1.0.0 */ public function render_settings_field_html( $args ) { $is_checked = ( 'yes' === get_site_option( $args['name'], false ) ); ?> <fieldset> <label for="<?php echo esc_attr( $args['label_for'] ); ?>"> <input id="<?php echo esc_attr( $args['id'] ); ?>" type="checkbox" value="1" name="<?php echo esc_attr( $args['name'] ); ?>" <?php checked( $is_checked ); ?>> <?php /* translators: %s Product title */ echo esc_html( sprintf( __( 'Help improve %s by sharing non-sensitive usage data — like PHP version and features used.', 'astra-sites' ), $args['title'] ) );// phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText if ( is_multisite() ) { esc_html_e( ' This will be applicable for all sites from the network.', 'astra-sites' ); } ?> </label> <?php echo wp_kses_post( sprintf( '<a href="%1s" target="_blank" rel="noreferrer noopener">%2s</a>', esc_url( $args['usage_doc_link'] ), __( 'Learn More.', 'astra-sites' ) ) ); ?> </fieldset> <?php } /** * Get analytics installed time from option. * * @param string $source source of analytics. * @return string $time analytics installed time. * @since 1.0.0 */ private function get_analytics_install_time( $source ) { $time = get_site_option( $source . '_usage_installed_time' ); if ( ! $time ) { $time = time(); update_site_option( $source . '_usage_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 ) { if ( is_multisite() ) { $this->add_option_to_network( $option, $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 ) { if ( is_multisite() ) { $this->add_option_to_network( $option, $value ); } } /** * Send analytics track event if tracking is enabled. * * @since 1.0.0 */ public function maybe_track_analytics() { if ( ! $this->is_tracking_enabled() ) { return; } $analytics_track = get_site_transient( 'bsf_usage_track' ); // If the last data sent is 2 days old i.e. transient is expired. if ( ! $analytics_track ) { $this->send(); set_site_transient( 'bsf_usage_track', true, 2 * DAY_IN_SECONDS ); } } /** * Save analytics option to network. * * @param string $option name of option. * @param string $value value of option. * @since 1.0.0 */ public function add_option_to_network( $option, $value ) { // If action coming from general settings page. if ( isset( $_POST['option_page'] ) && 'general' === sanitize_text_field( wp_unslash( $_POST['option_page'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing if ( get_site_option( $option ) ) { update_site_option( $option, $value ); } else { add_site_option( $option, $value ); } } } /** * Function to load the deactivation survey form on the admin footer. * * This function checks if the Deactivation_Survey_Feedback class exists and if so, it loads the deactivation survey form. * The form is configured with specific settings for plugin. Example: For CartFlows, including the source, logo, plugin slug, title, support URL, description, and the screen on which to show the form. * * @since 1.1.6 * @return void */ public function load_deactivation_survey_form() { if ( class_exists( 'Deactivation_Survey_Feedback' ) ) { foreach ( $this->entities as $key => $data ) { // If the deactivation_survey info in available then only add the form. if ( ! empty( $data['deactivation_survey'] ) && is_array( $data['deactivation_survey'] ) ) { foreach ( $data['deactivation_survey'] as $key => $survey_args ) { Deactivation_Survey_Feedback::show_feedback_form( $survey_args ); } } } } } /** * Function to add plugin slugs to Deactivation Survey vars for JS operations. * * @param array $vars UDS vars array. * @return array Modified UDS vars array with plugin slugs. * @since 1.1.6 */ public function add_slugs_to_uds_vars( $vars ) { foreach ( $this->entities as $key => $data ) { if ( ! empty( $data['deactivation_survey'] ) && is_array( $data['deactivation_survey'] ) ) { foreach ( $data['deactivation_survey'] as $key => $survey_args ) { $vars['_plugin_slug'] = isset( $vars['_plugin_slug'] ) ? array_merge( $vars['_plugin_slug'], array( $survey_args['plugin_slug'] ) ) : array( $survey_args['plugin_slug'] ); } } } return $vars; } } } bsf-analytics/modules/utm-analytics.php 0000644 00000011423 15252514036 0014262 0 ustar 00 <?php /** * UTM Analytics class * * @package bsf-analytics */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } if ( ! class_exists( 'BSF_UTM_Analytics' ) ) { if ( ! defined( 'BSF_UTM_ANALYTICS_REFERER' ) ) { define( 'BSF_UTM_ANALYTICS_REFERER', 'bsf_product_referers' ); } /** * UTM Analytics class * * @since 1.1.10 */ class BSF_UTM_Analytics { /** * List of slugs of all the bsf products that will be referer, referring another product. * * @var array<string> * @since 1.1.10 */ private static $bsf_product_slugs = [ 'all-in-one-schemaorg-rich-snippets', 'astra', 'astra-portfolio', 'astra-sites', 'bb-ultimate-addon', 'cartflows', 'checkout-paypal-woo', 'checkout-plugins-stripe-woo', 'convertpro', 'header-footer-elementor', 'latepoint', 'modern-cart', 'power-coupons', 'presto-player', 'sigmize', 'spectra-blocks', 'surecart', 'surecontact', 'surecookie', 'suredash', 'suredonation', 'sureforms', 'suremails', 'surerank', 'suretriggers', 'ultimate-addons-for-beaver-builder-lite', 'ultimate-addons-for-gutenberg', 'ultimate-elementor', 'Ultimate_VC_Addons', 'variation-swatches-woo', 'woo-cart-abandonment-recovery', 'wp-schema-pro', 'zipwp' ]; /** * This function will help to determine if provided slug is a valid bsf product or not, * This way we will maintain consistency through out all our products. * * @param string $slug unique slug of the product which can be used for referer, product. * @since 1.1.10 * @return boolean */ public static function is_valid_bsf_product_slug( $slug ) { if ( empty( $slug ) || ! is_string( $slug ) ) { return false; } return in_array( $slug, self::$bsf_product_slugs, true ); } /** * This function updates value of referer and product in option * bsf_product_referer in form of key value pair as 'product' => 'referer' * * @param string $referer slug of the product which is refering another product. * @param string $product slug of the product which is refered. * @since 1.1.10 * @return void */ public static function update_referer( $referer, $product ) { $slugs = [ 'referer' => $referer, 'product' => $product, ]; $error_count = 0; foreach ( $slugs as $type => $slug ) { if ( ! self::is_valid_bsf_product_slug( $slug ) ) { error_log( sprintf( 'Invalid %1$s slug provided "%2$s", does not match bsf_product_slugs', $type, $slug ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- adding logs in case of failure will help in debugging. $error_count++; } } if ( $error_count > 0 ) { return; } $slugs = array_map( 'sanitize_text_field', $slugs ); $bsf_product_referers = get_option( BSF_UTM_ANALYTICS_REFERER, [] ); if ( ! is_array( $bsf_product_referers ) ) { $bsf_product_referers = []; } $bsf_product_referers[ $slugs['product'] ] = $slugs['referer']; update_option( BSF_UTM_ANALYTICS_REFERER, $bsf_product_referers ); } /** * This function will add utm_args to pro link or purchase link * added utm_source by default additional utm_args such as utm_medium etc can be provided to generate location specific links * * @param string $link Ideally this should be product site link where utm_params can be tracked. * @param string $product Product slug whose utm_link need to be created. * @param mixed $utm_args additional args to be passed ex: [ 'utm_medium' => 'dashboard']. * @since 1.1.10 * @return string */ public static function get_utm_ready_link( $link, $product, $utm_args = [] ) { if ( false === wp_http_validate_url( $link ) ) { error_log( 'Invalid url passed to get_utm_ready_link function' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- adding logs in case of failure will help in debugging. return $link; } if ( empty( $product ) || ! is_string( $product ) || ! self::is_valid_bsf_product_slug( $product ) ) { error_log( sprintf( 'Invalid product slug provided "%1$s", does not match bsf_product_slugs', $product ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- adding logs in case of failure will help in debugging. return $link; } $bsf_product_referers = get_option( BSF_UTM_ANALYTICS_REFERER, [] ); if ( ! is_array( $bsf_product_referers ) || empty( $bsf_product_referers[ $product ] ) ) { return $link; } if ( ! self::is_valid_bsf_product_slug( $bsf_product_referers[ $product ] ) ) { return $link; } if ( ! is_array( $utm_args ) ) { $utm_args = []; } $utm_args['utm_source'] = $bsf_product_referers[ $product ]; $link = add_query_arg( $utm_args, $link ); return $link; } } } bsf-analytics/modules/deactivation-survey/classes/class-deactivation-survey-feedback.php 0000644 00000026134 15252514036 0025771 0 ustar 00 <?php /** * Deactivation Survey Feedback. * * @package bsf-analytics */ // Exit if accessed directly. if ( ! defined( 'ABSPATH' ) ) { exit; } if ( ! class_exists( 'Deactivation_Survey_Feedback' ) ) { /** * Class Deactivation_Survey_Feedback. */ class Deactivation_Survey_Feedback { /** * Feedback URL. * * @var string */ private static $feedback_api_endpoint = 'api/plugin-deactivate'; /** * Instance * * @access private * @var object Class object. * @since 1.1.6 */ private static $instance; /** * Initiator * * @since 1.1.6 * @return object initialized object of class. */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Constructor */ public function __construct() { add_action( 'admin_enqueue_scripts', array( $this, 'load_form_styles' ) ); add_action( 'wp_ajax_uds_plugin_deactivate_feedback', array( $this, 'send_plugin_deactivate_feedback' ) ); } /** * Render feedback HTML on plugins.php admin page only. * * This function renders the feedback form HTML on the plugins.php admin page. * It takes an optional string parameter $id for the form wrapper ID and an optional array parameter $args for customizing the form. * * @since 1.1.6 * @param array $args Optional. Custom arguments for the form. Defaults to an empty array. * @return void */ public static function show_feedback_form( array $args = array() ) { // Return if not in admin. if ( ! is_admin() ) { return; } // Set default arguments for the feedback form. $defaults = array( 'source' => 'User Deactivation Survey', 'popup_logo' => '', 'plugin_slug' => 'user-deactivation-survey', 'plugin_version' => '', 'popup_title' => __( 'Quick Feedback', 'astra-sites' ), 'support_url' => 'https://brainstormforce.com/contact/', 'popup_reasons' => self::get_default_reasons(), 'popup_description' => __( 'If you have a moment, please share why you are deactivating the plugin.', 'astra-sites' ), 'show_on_screens' => array( 'plugins' ), ); // Parse the arguments with defaults. $args = wp_parse_args( $args, $defaults ); $id = ! empty( $args['id'] ) ? sanitize_text_field( $args['id'] ) : 'uds-feedback-form--wrapper'; // Return if not on the allowed screen. if ( ! BSF_Analytics_Helper::is_allowed_screen() ) { return; } // Product slug used for input fields and labels in each plugin's deactivation survey. $product_slug = isset( $args['plugin_slug'] ) ? sanitize_text_field( $args['plugin_slug'] ) : 'bsf'; ?> <div id="<?php echo esc_attr( $id ); ?>" class="uds-feedback-form--wrapper" style="display: none"> <div class="uds-feedback-form--container"> <div class="uds-form-header--wrapper"> <div class="uds-form-title--icon-wrapper"> <?php if ( ! empty( $args['popup_logo'] ) ) { ?> <img class="uds-icon" src="<?php echo esc_url( $args['popup_logo'] ); ?>" title="<?php echo esc_attr( $args['plugin_slug'] ); ?> <?php echo esc_attr( __( 'Icon', 'astra-sites' ) ); ?>" /> <?php } ?> <h2 class="uds-title"><?php echo esc_html( $args['popup_title'] ); ?></h2> </div> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="uds-close"> <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" /> </svg> </div> <div class="uds-form-body--content"> <?php if ( ! empty( $args['popup_description'] ) ) { ?> <p class="uds-form-description"><?php echo esc_html( $args['popup_description'] ); ?></p> <?php } ?> <form class="uds-feedback-form" id="uds-feedback-form" method="post"> <?php foreach ( $args['popup_reasons'] as $key => $value ) { $input_id = $product_slug . '_uds_reason_input_' . $key; ?> <fieldset> <div class="reason"> <input type="radio" class="uds-reason-input" name="uds_reason_input" id="<?php echo esc_attr( $input_id ); ?>" value="<?php echo esc_attr( $key ); ?>" data-placeholder="<?php echo esc_attr( $value['placeholder'] ); ?>" data-show_cta="<?php echo esc_attr( $value['show_cta'] ); ?>" data-accept_feedback="<?php echo esc_attr( $value['accept_feedback'] ); ?>"> <label class="uds-reason-label" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_html( $value['label'] ); ?></label> </div> </fieldset> <?php } ?> <fieldset> <textarea class="uds-options-feedback hide" id="uds-options-feedback" rows="3" name="uds_options_feedback" placeholder="<?php echo esc_attr( __( 'Please tell us more details.', 'astra-sites' ) ); ?>"></textarea> <?php if ( ! empty( $args['support_url'] ) ) { ?> <p class="uds-option-feedback-cta hide"> <?php echo wp_kses_post( sprintf( /* translators: %1$s: link html start, %2$s: link html end*/ __( 'Need help from our experts? %1$sClick here to contact us.%2$s', 'astra-sites' ), '<a href="' . esc_url( $args['support_url'] ) . '" target="_blank">', '</a>' ) ); ?> </p> <?php } ?> </fieldset> <div class="uds-feedback-form-sumbit--actions"> <button class="button button-primary uds-feedback-submit" data-action="submit"><?php esc_html_e( 'Submit & Deactivate', 'astra-sites' ); ?></button> <button class="button button-secondary uds-feedback-skip" data-action="skip"><?php esc_html_e( 'Skip & Deactivate', 'astra-sites' ); ?></button> <input type="hidden" name="referer" value="<?php echo esc_url( get_site_url() ); ?>"> <input type="hidden" name="version" value="<?php echo esc_attr( $args['plugin_version'] ); ?>"> <input type="hidden" name="source" value="<?php echo esc_attr( $args['plugin_slug'] ); ?>"> </div> </form> </div> </div> </div> <?php } /** * Load form styles. * * This function loads the necessary styles for the feedback form. * * @since 1.1.6 * @return void */ public static function load_form_styles() { if ( ! BSF_Analytics_Helper::is_allowed_screen() ) { return; } $dir_path = BSF_ANALYTICS_URI . '/modules/deactivation-survey/'; $file_ext = ! SCRIPT_DEBUG ? '.min' : ''; wp_enqueue_script( 'uds-feedback-script', $dir_path . 'assets/js/feedback' . $file_ext . '.js', array( 'jquery' ), BSF_ANALYTICS_VERSION, true ); $data = apply_filters( 'uds_survey_vars', array( 'ajaxurl' => esc_url( admin_url( 'admin-ajax.php' ) ), '_ajax_nonce' => wp_create_nonce( 'uds_plugin_deactivate_feedback' ), '_current_theme' => function_exists( 'wp_get_theme' ) ? wp_get_theme()->get_template() : '', '_plugin_slug' => array(), ) ); // Add localize JS. wp_localize_script( 'uds-feedback-script', 'udsVars', $data ); wp_enqueue_style( 'uds-feedback-style', $dir_path . 'assets/css/feedback' . $file_ext . '.css', array(), BSF_ANALYTICS_VERSION ); wp_style_add_data( 'uds-feedback-style', 'rtl', 'replace' ); wp_style_add_data( 'uds-feedback-style', 'suffix', $file_ext ); } /** * Sends plugin deactivation feedback to the server. * * This function checks the user's permission and verifies the nonce for the request. * If the checks pass, it sends the feedback data to the server for processing. * * @return void */ public function send_plugin_deactivate_feedback() { $response_data = array( 'message' => __( 'Sorry, you are not allowed to do this operation.', 'astra-sites' ) ); /** * Check permission */ if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( $response_data ); } /** * Nonce verification */ if ( ! check_ajax_referer( 'uds_plugin_deactivate_feedback', 'security', false ) ) { $response_data = array( 'message' => __( 'Nonce validation failed', 'astra-sites' ) ); wp_send_json_error( $response_data ); } $feedback_data = array( 'reason' => isset( $_POST['reason'] ) ? sanitize_text_field( wp_unslash( $_POST['reason'] ) ) : '', 'feedback' => isset( $_POST['feedback'] ) ? sanitize_text_field( wp_unslash( $_POST['feedback'] ) ) : '', 'domain_name' => isset( $_POST['referer'] ) ? sanitize_text_field( wp_unslash( $_POST['referer'] ) ) : '', 'version' => isset( $_POST['version'] ) ? sanitize_text_field( wp_unslash( $_POST['version'] ) ) : '', 'plugin' => isset( $_POST['source'] ) ? sanitize_text_field( wp_unslash( $_POST['source'] ) ) : '', ); $api_args = array( 'body' => wp_json_encode( $feedback_data ), 'headers' => BSF_Analytics_Helper::get_api_headers(), 'timeout' => 15, //phpcs:ignore WordPressVIPMinimum.Performance.RemoteRequestTimeout.timeout_timeout ); $target_url = BSF_Analytics_Helper::get_api_url() . self::$feedback_api_endpoint; $response = wp_safe_remote_post( $target_url, $api_args ); $has_errors = BSF_Analytics_Helper::is_api_error( $response ); if ( $has_errors['error'] ) { wp_send_json_error( array( 'success' => false, 'message' => $has_errors['error_message'], ) ); } wp_send_json_success(); } /** * Get the array of default reasons. * * @return array Default reasons. */ public static function get_default_reasons() { return apply_filters( 'uds_default_deactivation_reasons', array( 'temporary_deactivation' => array( 'label' => esc_html__( 'This is a temporary deactivation for testing.', 'astra-sites' ), 'placeholder' => esc_html__( 'How can we assist you?', 'astra-sites' ), 'show_cta' => 'false', 'accept_feedback' => 'false', ), 'plugin_not_working' => array( 'label' => esc_html__( 'The plugin isn\'t working properly.', 'astra-sites' ), 'placeholder' => esc_html__( 'Please tell us more about what went wrong?', 'astra-sites' ), 'show_cta' => 'true', 'accept_feedback' => 'true', ), 'found_better_plugin' => array( 'label' => esc_html__( 'I found a better alternative plugin.', 'astra-sites' ), 'placeholder' => esc_html__( 'Could you please specify which plugin?', 'astra-sites' ), 'show_cta' => 'false', 'accept_feedback' => 'true', ), 'missing_a_feature' => array( 'label' => esc_html__( 'It\'s missing a specific feature.', 'astra-sites' ), 'placeholder' => esc_html__( 'Please tell us more about the feature.', 'astra-sites' ), 'show_cta' => 'false', 'accept_feedback' => 'true', ), 'other' => array( 'label' => esc_html__( 'Other', 'astra-sites' ), 'placeholder' => esc_html__( 'Please tell us more details.', 'astra-sites' ), 'show_cta' => 'false', 'accept_feedback' => 'true', ), ) ); } } Deactivation_Survey_Feedback::get_instance(); } bsf-analytics/modules/deactivation-survey/assets/js/feedback.js 0000644 00000015472 15252514036 0020774 0 ustar 00 ( function ( $ ) { const UserDeactivationPopup = { slug: '', skipButton: '', formWrapper: '', radioButton: '', closeButton: '', buttonAction: '', feedbackForm: '', feedbackInput: '', deactivateUrl: '', buttonTrigger: '', deactivateButton: '', submitDeactivate: '', /** * Caches elements for later use. */ _cacheElements() { this.slug = udsVars?._plugin_slug || ''; this.skipButton = $( '.uds-feedback-skip' ); this.submitDeactivate = $( '.uds-feedback-submit' ); this.deactivateButton = $( '#the-list' ).find( `.row-actions span.deactivate a` ); this.feedbackForm = $( '.uds-feedback-form' ); // Feedback Form. this.feedbackInput = $( '.uds-options-feedback' ); // Feedback Textarea. this.formWrapper = $( '.uds-feedback-form--wrapper' ); this.closeButton = $( '.uds-feedback-form--wrapper .uds-close' ); this.radioButton = $( '.uds-reason-input' ); }, /** * Shows the feedback popup by adding the 'show' class to the form wrapper. * * @param {string} slug - The slug of the plugin. */ _showPopup( slug ) { $( `#deactivation-survey-${ slug }` ).addClass( 'show_popup' ); }, /** * Hides the feedback popup by removing the 'show' class from the form wrapper. */ _hidePopup() { this.formWrapper.removeClass( 'show_popup' ); }, /** * Redirects to the deactivate URL if it exists, otherwise reloads the current page. */ _redirectOrReload() { if ( this.deactivateUrl ) { window.location.href = this.deactivateUrl; } else { location.reload(); } }, /** * Toggles the visibility of the feedback form and CTA based on the event target's attributes. * * @param {Event} event - The event that triggered this function. */ _hideShowFeedbackAndCTA( event ) { const acceptFeedback = $( event.target ).attr( 'data-accept_feedback' ) === 'true'; const showCta = $( event.target ).attr( 'data-show_cta' ) === 'true'; $( event.target ) .closest( this.formWrapper ) .find( '.uds-options-feedback' ) .removeClass( 'hide' ) .addClass( acceptFeedback ? 'show' : 'hide' ); $( event.target ) .closest( this.formWrapper ) .find( '.uds-option-feedback-cta' ) .removeClass( 'hide' ) .addClass( showCta ? 'show' : 'hide' ); }, /** * Changes the placeholder text of the feedback input based on the event target's attribute. * * @param {Event} event - The event that triggered this function. */ _changePlaceholderText( event ) { const radioButtonPlaceholder = event.target.getAttribute( 'data-placeholder' ); $( event.target ) .closest( this.formWrapper ) .find( this.feedbackInput ) .attr( 'placeholder', radioButtonPlaceholder || '' ); this._hideShowFeedbackAndCTA( event ); }, /** * Submits the feedback form and handles the response. * * @param {Event} event - The event that triggered this function. * @param {Object} self - A reference to the current object. */ _submitFeedback( event, self ) { event.preventDefault(); const currentForm = $( event.target ); const closestForm = currentForm.closest( this.feedbackForm ); // Cache the closest form // Gather form data. const formData = { action: 'uds_plugin_deactivate_feedback', security: udsVars?._ajax_nonce || '', reason: closestForm .find( this.radioButton.filter( ':checked' ) ) .val() || '', // Get the selected radio button value from the current form. source: closestForm.find( 'input[name="source"]' ).val() || '', referer: closestForm.find( 'input[name="referer"]' ).val() || '', version: closestForm.find( 'input[name="version"]' ).val() || '', feedback: closestForm.find( this.feedbackInput ).val() || '', // Get the feedback input value from the current form. }; currentForm .find( '.uds-feedback-' + this.buttonAction ) .text( 'Deactivating.' ) .addClass( 'processing' ); // Prepare AJAX call. $.ajax( { url: udsVars?.ajaxurl, // URL to send the request to. type: 'POST', // HTTP method. data: formData, // Data to be sent. success( response ) { if ( response.success ) { self._redirectOrReload(); } self._hidePopup(); }, /* eslint-disable */ error( xhr, status, error ) { /* eslint-disable */ self._redirectOrReload(); }, } ); }, _handleClick( e ) { // Close feedback form or show/hide popup if clicked outside and add a click on a Activate button of Theme. if ( e.target.classList.contains( 'show_popup' ) && e.target.closest( '.uds-feedback-form--wrapper' ) ) { this._hidePopup(); } else if ( e.target.classList.contains( 'activate' ) ) { this.deactivateUrl = e.target.href; // Don't show for Child Themes if parent theme is active & Parent Theme if child theme is active. if ( -1 !== this.deactivateUrl.indexOf( `stylesheet=${ udsVars?._current_theme }-child` ) || -1 !== this.deactivateUrl.indexOf(`stylesheet=${udsVars?._current_theme}&`) ) { return; } e.preventDefault(); this._showPopup( udsVars?._current_theme ); } }, /** * Initializes the feedback popup by caching elements and binding events. */ _init() { this._cacheElements(); this._bind(); }, /** * Binds event listeners to various elements to handle user interactions. */ _bind() { const self = this; // Store reference to the current object. // Open the popup when clicked on the deactivate button. this.deactivateButton.on( 'click', function ( event ) { let closestTr = $( event.target ).closest( 'tr' ); let slug = closestTr.data( 'slug' ); if ( self.slug.includes( slug ) ) { event.preventDefault(); // Set the deactivation URL. self.deactivateUrl = $( event.target ).attr( 'href' ); self._showPopup( slug ); } } ); // Close the popup on a click of Close button. this.closeButton.on( 'click', function ( event ) { event.preventDefault(); self._hidePopup(); // Use self to refer to the UserDeactivationPopup instance. } ); // Click event on radio button to change the placeholder of textarea. this.radioButton.on( 'click', function ( event ) { self._changePlaceholderText( event ); } ); // Combined submit and skip button actions. this.submitDeactivate .add( this.skipButton ) .on( 'click', function ( event ) { event.preventDefault(); // Prevent default button action. self.buttonAction = $( event.target ).attr( 'data-action' ); $( event.target ).closest( self.feedbackForm ).submit(); } ); this.feedbackForm.on( 'submit', function ( event ) { self._submitFeedback( event, self ); } ); document.addEventListener( 'click', function ( e ) { self._handleClick( e ); } ); }, }; $( function () { UserDeactivationPopup._init(); } ); } )( jQuery ); bsf-analytics/modules/deactivation-survey/assets/js/feedback.min.js 0000644 00000006275 15252514036 0021557 0 ustar 00 (i=>{let t={slug:"",skipButton:"",formWrapper:"",radioButton:"",closeButton:"",buttonAction:"",feedbackForm:"",feedbackInput:"",deactivateUrl:"",buttonTrigger:"",deactivateButton:"",submitDeactivate:"",_cacheElements(){this.slug=udsVars?._plugin_slug||"",this.skipButton=i(".uds-feedback-skip"),this.submitDeactivate=i(".uds-feedback-submit"),this.deactivateButton=i("#the-list").find(".row-actions span.deactivate a"),this.feedbackForm=i(".uds-feedback-form"),this.feedbackInput=i(".uds-options-feedback"),this.formWrapper=i(".uds-feedback-form--wrapper"),this.closeButton=i(".uds-feedback-form--wrapper .uds-close"),this.radioButton=i(".uds-reason-input")},_showPopup(t){i("#deactivation-survey-"+t).addClass("show_popup")},_hidePopup(){this.formWrapper.removeClass("show_popup")},_redirectOrReload(){this.deactivateUrl?window.location.href=this.deactivateUrl:location.reload()},_hideShowFeedbackAndCTA(t){var e="true"===i(t.target).attr("data-accept_feedback"),a="true"===i(t.target).attr("data-show_cta");i(t.target).closest(this.formWrapper).find(".uds-options-feedback").removeClass("hide").addClass(e?"show":"hide"),i(t.target).closest(this.formWrapper).find(".uds-option-feedback-cta").removeClass("hide").addClass(a?"show":"hide")},_changePlaceholderText(t){var e=t.target.getAttribute("data-placeholder");i(t.target).closest(this.formWrapper).find(this.feedbackInput).attr("placeholder",e||""),this._hideShowFeedbackAndCTA(t)},_submitFeedback(t,s){t.preventDefault();var t=i(t.target),e=t.closest(this.feedbackForm),e={action:"uds_plugin_deactivate_feedback",security:udsVars?._ajax_nonce||"",reason:e.find(this.radioButton.filter(":checked")).val()||"",source:e.find('input[name="source"]').val()||"",referer:e.find('input[name="referer"]').val()||"",version:e.find('input[name="version"]').val()||"",feedback:e.find(this.feedbackInput).val()||""};t.find(".uds-feedback-"+this.buttonAction).text("Deactivating.").addClass("processing"),i.ajax({url:udsVars?.ajaxurl,type:"POST",data:e,success(t){t.success&&s._redirectOrReload(),s._hidePopup()},error(t,e,a){s._redirectOrReload()}})},_handleClick(t){t.target.classList.contains("show_popup")&&t.target.closest(".uds-feedback-form--wrapper")?this._hidePopup():t.target.classList.contains("activate")&&(this.deactivateUrl=t.target.href,-1===this.deactivateUrl.indexOf(`stylesheet=${udsVars?._current_theme}-child`))&&-1===this.deactivateUrl.indexOf(`stylesheet=${udsVars?._current_theme}&`)&&(t.preventDefault(),this._showPopup(udsVars?._current_theme))},_init(){this._cacheElements(),this._bind()},_bind(){let a=this;this.deactivateButton.on("click",function(t){var e=i(t.target).closest("tr").data("slug");a.slug.includes(e)&&(t.preventDefault(),a.deactivateUrl=i(t.target).attr("href"),a._showPopup(e))}),this.closeButton.on("click",function(t){t.preventDefault(),a._hidePopup()}),this.radioButton.on("click",function(t){a._changePlaceholderText(t)}),this.submitDeactivate.add(this.skipButton).on("click",function(t){t.preventDefault(),a.buttonAction=i(t.target).attr("data-action"),i(t.target).closest(a.feedbackForm).submit()}),this.feedbackForm.on("submit",function(t){a._submitFeedback(t,a)}),document.addEventListener("click",function(t){a._handleClick(t)})}};i(function(){t._init()})})(jQuery); bsf-analytics/modules/deactivation-survey/assets/css/feedback-rtl.min.css 0000644 00000023571 15252514036 0022704 0 ustar 00 .uds-feedback-form--wrapper h2,.uds-feedback-form--wrapper input[type=radio],.uds-feedback-form--wrapper p{margin:0;padding:0}.uds-feedback-form--wrapper .show{display:block}.uds-feedback-form--wrapper .hide{display:none}.uds-feedback-form--wrapper{align-items:center;background-color:rgba(0,0,0,.75);bottom:0;display:none;justify-content:center;right:0;position:fixed;left:0;top:0;user-select:none;z-index:-9999}.uds-feedback-form--wrapper.show_popup{display:flex!important;z-index:99999}.uds-feedback-form--wrapper .uds-feedback-form--container{background-color:#fff;border-radius:8px;box-shadow:-4px 4px 24px rgba(0,0,0,.25);max-width:90%;width:540px}.uds-feedback-form--container .uds-form-header--wrapper{align-items:center;display:flex;justify-content:space-between;padding:16px 20px 0}.uds-feedback-form--container .uds-form-title--icon-wrapper{display:flex;align-items:center;gap:12px}.uds-feedback-form--container .uds-form-header--wrapper .uds-close,.uds-feedback-form--container .uds-form-title--icon-wrapper .uds-icon{width:20px;height:20px}.uds-feedback-form--container .uds-form-title--icon-wrapper .uds-title{color:#1f2937;font-size:16px;font-weight:600;line-height:24px;text-align:right}.uds-feedback-form--container .uds-form-header--wrapper .uds-close{color:#9ca3af;cursor:pointer}.uds-feedback-form--container .uds-form-header--wrapper .uds-close:hover{color:#4b5563}.uds-feedback-form--container .uds-form-body--content{padding:20px 20px 0 20px;display:flex;flex-direction:column;gap:20px}.uds-feedback-form--container .uds-form-body--content .uds-form-description{color:#1f2937;font-size:16px;font-weight:500;line-height:24px;text-align:right}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .reason{display:flex;align-items:center;gap:12px;margin-bottom:12px}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback{color:#6b7280;font-size:14px;font-weight:400;line-height:20px;text-align:right;width:100%;padding:9px 13px;border-radius:6px;border-width:1px;border-style:solid;border-color:#e5e7eb;box-shadow:0 1px 2px 0 #0000000d;background:#fff}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:active,.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:focus,.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:hover{border-color:#d1d5db}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-option-feedback-cta{color:#4b5563;margin-top:10px;font-size:13px;font-weight:400;line-height:20px;text-align:right}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-option-feedback-cta a{text-decoration:none;color:#006ba1}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback::placeholder{font-size:14px;font-weight:400;line-height:20px;text-align:right;color:#6b7280;opacity:1}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;background-color:#f6f7f7;border-top:1px solid #e1e1e1;margin:40px -20px 0;border-bottom-right-radius:8px;border-bottom-left-radius:8px}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button{padding:7px 13px;border-radius:3px;border-width:1px;font-size:14px;font-weight:400;line-height:20px;text-align:right;border-style:solid;display:flex;gap:8px;align-items:center}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button:focus{outline:0;box-shadow:none}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button.processing{pointer-events:none;opacity:.8}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button.processing::before{content:"\f463";animation:spin 2s linear infinite;font-family:dashicons,sans-serif;font-weight:400;font-size:18px;cursor:pointer}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-reason-label{font-size:14px;font-weight:400;line-height:20px;text-align:right}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type=radio]{display:flex;justify-content:center;height:18px;width:18px;cursor:pointer;margin:0;border:1px solid #d1d5db;border-radius:50%;line-height:0;box-shadow:inset 0 1px 2px rgb(0 0 0 / 10%);transition:50ms border-color ease-in-out;-webkit-appearance:none;padding:0}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type=radio]:checked{vertical-align:middle;background-color:#006ba1}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type=radio]:checked::before{background-color:#fff!important;border-radius:50px;content:"\2022";font-size:24px;height:6px;line-height:13px;margin:5px;text-indent:-9999px;width:6px}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(-360deg)}},.uds-feedback-form--wrapper h2,.uds-feedback-form--wrapper input[type=radio],.uds-feedback-form--wrapper p{margin:0;padding:0}.uds-feedback-form--wrapper .show{display:block}.uds-feedback-form--wrapper .hide{display:none}.uds-feedback-form--wrapper{align-items:center;background-color:rgba(0,0,0,.75);bottom:0;display:none;justify-content:center;right:0;position:fixed;left:0;top:0;user-select:none;z-index:-9999}.uds-feedback-form--wrapper.show_popup{display:flex!important;z-index:99999}.uds-feedback-form--wrapper .uds-feedback-form--container{background-color:#fff;border-radius:8px;box-shadow:-4px 4px 24px rgba(0,0,0,.25);max-width:90%;width:540px}.uds-feedback-form--container .uds-form-header--wrapper{align-items:center;display:flex;justify-content:space-between;padding:16px 20px 0}.uds-feedback-form--container .uds-form-title--icon-wrapper{display:flex;align-items:center;gap:12px}.uds-feedback-form--container .uds-form-header--wrapper .uds-close,.uds-feedback-form--container .uds-form-title--icon-wrapper .uds-icon{width:20px;height:20px}.uds-feedback-form--container .uds-form-title--icon-wrapper .uds-title{color:#1f2937;font-size:16px;font-weight:600;line-height:24px;text-align:right}.uds-feedback-form--container .uds-form-header--wrapper .uds-close{color:#9ca3af;cursor:pointer}.uds-feedback-form--container .uds-form-header--wrapper .uds-close:hover{color:#4b5563}.uds-feedback-form--container .uds-form-body--content{padding:20px 20px 0 20px;display:flex;flex-direction:column;gap:20px}.uds-feedback-form--container .uds-form-body--content .uds-form-description{color:#1f2937;font-size:16px;font-weight:500;line-height:24px;text-align:right}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .reason{display:flex;align-items:center;gap:12px;margin-bottom:12px}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback{color:#6b7280;font-size:14px;font-weight:400;line-height:20px;text-align:right;width:100%;padding:9px 13px;border-radius:6px;border-width:1px;border-style:solid;border-color:#e5e7eb;box-shadow:0 1px 2px 0 #0000000d;background:#fff}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:active,.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:focus,.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:hover{border-color:#d1d5db}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-option-feedback-cta{color:#4b5563;margin-top:10px;font-size:13px;font-weight:400;line-height:20px;text-align:right}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-option-feedback-cta a{text-decoration:none;color:#006ba1}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback::placeholder{font-size:14px;font-weight:400;line-height:20px;text-align:right;color:#6b7280;opacity:1}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;background-color:#f6f7f7;border-top:1px solid #e1e1e1;margin:40px -20px 0;border-bottom-right-radius:8px;border-bottom-left-radius:8px}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button{padding:7px 13px;border-radius:3px;border-width:1px;font-size:14px;font-weight:400;line-height:20px;text-align:right;border-style:solid;display:flex;gap:8px;align-items:center}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button:focus{outline:0;box-shadow:none}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button.processing{pointer-events:none;opacity:.8}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button.processing::before{content:"\f463";animation:spin 2s linear infinite;font-family:dashicons,sans-serif;font-weight:400;font-size:18px;cursor:pointer}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-reason-label{font-size:14px;font-weight:400;line-height:20px;text-align:right}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type=radio]{display:flex;justify-content:center;height:18px;width:18px;cursor:pointer;margin:0;border:1px solid #d1d5db;border-radius:50%;line-height:0;box-shadow:inset 0 1px 2px rgb(0 0 0 / 10%);transition:50ms border-color ease-in-out;-webkit-appearance:none;padding:0}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type=radio]:checked{vertical-align:middle;background-color:#006ba1}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type=radio]:checked::before{background-color:#fff!important;border-radius:50px;content:"\2022";font-size:24px;height:6px;line-height:13px;margin:5px;text-indent:-9999px;width:6px}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(-360deg)}} bsf-analytics/modules/deactivation-survey/assets/css/feedback.css 0000644 00000013111 15252514036 0021310 0 ustar 00 /* Base CSS to normalize the default. */ .uds-feedback-form--wrapper h2, .uds-feedback-form--wrapper p, .uds-feedback-form--wrapper input[type="radio"] { margin: 0; padding: 0; } .uds-feedback-form--wrapper .show { display: block; } .uds-feedback-form--wrapper .hide { display: none; } .uds-feedback-form--wrapper { align-items: center; background-color: rgba( 0, 0, 0, 0.75 ); bottom: 0; display: none; justify-content: center; left: 0; position: fixed; right: 0; top: 0; user-select: none; z-index: -9999; } .uds-feedback-form--wrapper.show_popup { display: flex !important; z-index: 99999; } .uds-feedback-form--wrapper .uds-feedback-form--container { background-color: #fff; border-radius: 8px; box-shadow: 4px 4px 24px rgba( 0, 0, 0, 0.25 ); max-width: 90%; width: 540px; } .uds-feedback-form--container .uds-form-header--wrapper { align-items: center; display: flex; justify-content: space-between; padding: 16px 20px 0; } .uds-feedback-form--container .uds-form-title--icon-wrapper { display: flex; align-items: center; gap: 12px; } .uds-feedback-form--container .uds-form-title--icon-wrapper .uds-icon, .uds-feedback-form--container .uds-form-header--wrapper .uds-close { width: 20px; height: 20px; } .uds-feedback-form--container .uds-form-title--icon-wrapper .uds-title { color: #1f2937; font-size: 16px; font-weight: 600; line-height: 24px; text-align: left; } .uds-feedback-form--container .uds-form-header--wrapper .uds-close { color: #9ca3af; cursor: pointer; } .uds-feedback-form--container .uds-form-header--wrapper .uds-close:hover { color: #4b5563; } .uds-feedback-form--container .uds-form-body--content { padding: 20px 20px 0 20px; display: flex; flex-direction: column; gap: 20px; } .uds-feedback-form--container .uds-form-body--content .uds-form-description { color: #1f2937; font-size: 16px; font-weight: 500; line-height: 24px; text-align: left; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .reason { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback { color: #6b7280; font-size: 14px; font-weight: 400; line-height: 20px; text-align: left; width: 100%; padding: 9px 13px; border-radius: 6px; border-width: 1px; border-style: solid; border-color: #e5e7eb; box-shadow: 0 1px 2px 0 #0000000d; background: #fff; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:hover, .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:focus, .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:active { border-color: #d1d5db; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-option-feedback-cta { color: #4b5563; margin-top: 10px; font-size: 13px; font-weight: 400; line-height: 20px; text-align: left; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-option-feedback-cta a { text-decoration: none; color: #006ba1; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback::placeholder { font-size: 14px; font-weight: 400; line-height: 20px; text-align: left; color: #6b7280; opacity: 1; } .uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px; background-color: #f6f7f7; border-top: 1px solid #e1e1e1; margin: 40px -20px 0; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px; } .uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button { padding: 7px 13px; border-radius: 3px; border-width: 1px; font-size: 14px; font-weight: 400; line-height: 20px; text-align: left; border-style: solid; display: flex; gap: 8px; align-items: center; } .uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button:focus { outline: none; box-shadow: none; } .uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button.processing { pointer-events: none; opacity: 0.8; } .uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button.processing::before { content: "\f463"; animation: spin 2s linear infinite; font-family: dashicons, sans-serif; font-weight: 400; font-size: 18px; cursor: pointer; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-reason-label { font-size: 14px; font-weight: 400; line-height: 20px; text-align: left; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type="radio"] { display: flex; justify-content: center; height: 18px; width: 18px; cursor: pointer; margin: 0; border: 1px solid #d1d5db; border-radius: 50%; line-height: 0; box-shadow: inset 0 1px 2px rgb( 0 0 0 / 10% ); transition: 0.05s border-color ease-in-out; -webkit-appearance: none; padding: 0; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type="radio"]:checked { vertical-align: middle; background-color: #006ba1; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type="radio"]:checked::before { background-color: #fff !important; border-radius: 50px; content: "\2022"; font-size: 24px; height: 6px; line-height: 13px; margin: 5px; text-indent: -9999px; width: 6px; } @keyframes spin { 0% { transform: rotate( 0deg ); } 100% { transform: rotate( 360deg ); } } bsf-analytics/modules/deactivation-survey/assets/css/feedback-rtl.css 0000644 00000025017 15252514036 0022117 0 ustar 00 /* Base CSS to normalize the default. */ .uds-feedback-form--wrapper h2, .uds-feedback-form--wrapper p, .uds-feedback-form--wrapper input[type="radio"] { margin: 0; padding: 0; } .uds-feedback-form--wrapper .show { display: block; } .uds-feedback-form--wrapper .hide { display: none; } .uds-feedback-form--wrapper { align-items: center; background-color: rgba( 0, 0, 0, 0.75 ); bottom: 0; display: none; justify-content: center; right: 0; position: fixed; left: 0; top: 0; user-select: none; z-index: -9999; } .uds-feedback-form--wrapper.show_popup { display: flex !important; z-index: 99999; } .uds-feedback-form--wrapper .uds-feedback-form--container { background-color: #fff; border-radius: 8px; box-shadow: -4px 4px 24px rgba( 0, 0, 0, 0.25 ); max-width: 90%; width: 540px; } .uds-feedback-form--container .uds-form-header--wrapper { align-items: center; display: flex; justify-content: space-between; padding: 16px 20px 0; } .uds-feedback-form--container .uds-form-title--icon-wrapper { display: flex; align-items: center; gap: 12px; } .uds-feedback-form--container .uds-form-title--icon-wrapper .uds-icon, .uds-feedback-form--container .uds-form-header--wrapper .uds-close { width: 20px; height: 20px; } .uds-feedback-form--container .uds-form-title--icon-wrapper .uds-title { color: #1f2937; font-size: 16px; font-weight: 600; line-height: 24px; text-align: right; } .uds-feedback-form--container .uds-form-header--wrapper .uds-close { color: #9ca3af; cursor: pointer; } .uds-feedback-form--container .uds-form-header--wrapper .uds-close:hover { color: #4b5563; } .uds-feedback-form--container .uds-form-body--content { padding: 20px 20px 0 20px; display: flex; flex-direction: column; gap: 20px; } .uds-feedback-form--container .uds-form-body--content .uds-form-description { color: #1f2937; font-size: 16px; font-weight: 500; line-height: 24px; text-align: right; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .reason { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback { color: #6b7280; font-size: 14px; font-weight: 400; line-height: 20px; text-align: right; width: 100%; padding: 9px 13px; border-radius: 6px; border-width: 1px; border-style: solid; border-color: #e5e7eb; box-shadow: 0 1px 2px 0 #0000000d; background: #fff; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:hover, .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:focus, .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:active { border-color: #d1d5db; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-option-feedback-cta { color: #4b5563; margin-top: 10px; font-size: 13px; font-weight: 400; line-height: 20px; text-align: right; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-option-feedback-cta a { text-decoration: none; color: #006ba1; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback::placeholder { font-size: 14px; font-weight: 400; line-height: 20px; text-align: right; color: #6b7280; opacity: 1; } .uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px; background-color: #f6f7f7; border-top: 1px solid #e1e1e1; margin: 40px -20px 0; border-bottom-right-radius: 8px; border-bottom-left-radius: 8px; } .uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button { padding: 7px 13px; border-radius: 3px; border-width: 1px; font-size: 14px; font-weight: 400; line-height: 20px; text-align: right; border-style: solid; display: flex; gap: 8px; align-items: center; } .uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button:focus { outline: none; box-shadow: none; } .uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button.processing { pointer-events: none; opacity: 0.8; } .uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button.processing::before { content: "\f463"; animation: spin 2s linear infinite; font-family: dashicons, sans-serif; font-weight: 400; font-size: 18px; cursor: pointer; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-reason-label { font-size: 14px; font-weight: 400; line-height: 20px; text-align: right; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type="radio"] { display: flex; justify-content: center; height: 18px; width: 18px; cursor: pointer; margin: 0; border: 1px solid #d1d5db; border-radius: 50%; line-height: 0; box-shadow: inset 0 1px 2px rgb( 0 0 0 / 10% ); transition: 0.05s border-color ease-in-out; -webkit-appearance: none; padding: 0; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type="radio"]:checked { vertical-align: middle; background-color: #006ba1; } .uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type="radio"]:checked::before { background-color: #fff !important; border-radius: 50px; content: "\2022"; font-size: 24px; height: 6px; line-height: 13px; margin: 5px; text-indent: -9999px; width: 6px; } @keyframes spin { 0% { transform: rotate( 0deg ); } 100% { transform: rotate( -360deg ); } } ,.uds-feedback-form--wrapper h2,.uds-feedback-form--wrapper input[type=radio],.uds-feedback-form--wrapper p{margin:0;padding:0}.uds-feedback-form--wrapper .show{display:block}.uds-feedback-form--wrapper .hide{display:none}.uds-feedback-form--wrapper{align-items:center;background-color:rgba(0,0,0,.75);bottom:0;display:none;justify-content:center;right:0;position:fixed;left:0;top:0;user-select:none;z-index:-9999}.uds-feedback-form--wrapper.show_popup{display:flex!important;z-index:99999}.uds-feedback-form--wrapper .uds-feedback-form--container{background-color:#fff;border-radius:8px;box-shadow:-4px 4px 24px rgba(0,0,0,.25);max-width:90%;width:540px}.uds-feedback-form--container .uds-form-header--wrapper{align-items:center;display:flex;justify-content:space-between;padding:16px 20px 0}.uds-feedback-form--container .uds-form-title--icon-wrapper{display:flex;align-items:center;gap:12px}.uds-feedback-form--container .uds-form-header--wrapper .uds-close,.uds-feedback-form--container .uds-form-title--icon-wrapper .uds-icon{width:20px;height:20px}.uds-feedback-form--container .uds-form-title--icon-wrapper .uds-title{color:#1f2937;font-size:16px;font-weight:600;line-height:24px;text-align:right}.uds-feedback-form--container .uds-form-header--wrapper .uds-close{color:#9ca3af;cursor:pointer}.uds-feedback-form--container .uds-form-header--wrapper .uds-close:hover{color:#4b5563}.uds-feedback-form--container .uds-form-body--content{padding:20px 20px 0 20px;display:flex;flex-direction:column;gap:20px}.uds-feedback-form--container .uds-form-body--content .uds-form-description{color:#1f2937;font-size:16px;font-weight:500;line-height:24px;text-align:right}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .reason{display:flex;align-items:center;gap:12px;margin-bottom:12px}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback{color:#6b7280;font-size:14px;font-weight:400;line-height:20px;text-align:right;width:100%;padding:9px 13px;border-radius:6px;border-width:1px;border-style:solid;border-color:#e5e7eb;box-shadow:0 1px 2px 0 #0000000d;background:#fff}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:active,.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:focus,.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:hover{border-color:#d1d5db}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-option-feedback-cta{color:#4b5563;margin-top:10px;font-size:13px;font-weight:400;line-height:20px;text-align:right}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-option-feedback-cta a{text-decoration:none;color:#006ba1}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback::placeholder{font-size:14px;font-weight:400;line-height:20px;text-align:right;color:#6b7280;opacity:1}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;background-color:#f6f7f7;border-top:1px solid #e1e1e1;margin:40px -20px 0;border-bottom-right-radius:8px;border-bottom-left-radius:8px}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button{padding:7px 13px;border-radius:3px;border-width:1px;font-size:14px;font-weight:400;line-height:20px;text-align:right;border-style:solid;display:flex;gap:8px;align-items:center}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button:focus{outline:0;box-shadow:none}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button.processing{pointer-events:none;opacity:.8}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button.processing::before{content:"\f463";animation:spin 2s linear infinite;font-family:dashicons,sans-serif;font-weight:400;font-size:18px;cursor:pointer}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-reason-label{font-size:14px;font-weight:400;line-height:20px;text-align:right}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type=radio]{display:flex;justify-content:center;height:18px;width:18px;cursor:pointer;margin:0;border:1px solid #d1d5db;border-radius:50%;line-height:0;box-shadow:inset 0 1px 2px rgb(0 0 0 / 10%);transition:50ms border-color ease-in-out;-webkit-appearance:none;padding:0}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type=radio]:checked{vertical-align:middle;background-color:#006ba1}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type=radio]:checked::before{background-color:#fff!important;border-radius:50px;content:"\2022";font-size:24px;height:6px;line-height:13px;margin:5px;text-indent:-9999px;width:6px}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(-360deg)}} bsf-analytics/modules/deactivation-survey/assets/css/feedback.min.css 0000644 00000011663 15252514036 0022104 0 ustar 00 .uds-feedback-form--wrapper h2,.uds-feedback-form--wrapper input[type=radio],.uds-feedback-form--wrapper p{margin:0;padding:0}.uds-feedback-form--wrapper .show{display:block}.uds-feedback-form--wrapper .hide{display:none}.uds-feedback-form--wrapper{align-items:center;background-color:rgba(0,0,0,.75);bottom:0;display:none;justify-content:center;left:0;position:fixed;right:0;top:0;user-select:none;z-index:-9999}.uds-feedback-form--wrapper.show_popup{display:flex!important;z-index:99999}.uds-feedback-form--wrapper .uds-feedback-form--container{background-color:#fff;border-radius:8px;box-shadow:4px 4px 24px rgba(0,0,0,.25);max-width:90%;width:540px}.uds-feedback-form--container .uds-form-header--wrapper{align-items:center;display:flex;justify-content:space-between;padding:16px 20px 0}.uds-feedback-form--container .uds-form-title--icon-wrapper{display:flex;align-items:center;gap:12px}.uds-feedback-form--container .uds-form-header--wrapper .uds-close,.uds-feedback-form--container .uds-form-title--icon-wrapper .uds-icon{width:20px;height:20px}.uds-feedback-form--container .uds-form-title--icon-wrapper .uds-title{color:#1f2937;font-size:16px;font-weight:600;line-height:24px;text-align:left}.uds-feedback-form--container .uds-form-header--wrapper .uds-close{color:#9ca3af;cursor:pointer}.uds-feedback-form--container .uds-form-header--wrapper .uds-close:hover{color:#4b5563}.uds-feedback-form--container .uds-form-body--content{padding:20px 20px 0 20px;display:flex;flex-direction:column;gap:20px}.uds-feedback-form--container .uds-form-body--content .uds-form-description{color:#1f2937;font-size:16px;font-weight:500;line-height:24px;text-align:left}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .reason{display:flex;align-items:center;gap:12px;margin-bottom:12px}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback{color:#6b7280;font-size:14px;font-weight:400;line-height:20px;text-align:left;width:100%;padding:9px 13px;border-radius:6px;border-width:1px;border-style:solid;border-color:#e5e7eb;box-shadow:0 1px 2px 0 #0000000d;background:#fff}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:active,.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:focus,.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback:hover{border-color:#d1d5db}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-option-feedback-cta{color:#4b5563;margin-top:10px;font-size:13px;font-weight:400;line-height:20px;text-align:left}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-option-feedback-cta a{text-decoration:none;color:#006ba1}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-options-feedback::placeholder{font-size:14px;font-weight:400;line-height:20px;text-align:left;color:#6b7280;opacity:1}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;background-color:#f6f7f7;border-top:1px solid #e1e1e1;margin:40px -20px 0;border-bottom-left-radius:8px;border-bottom-right-radius:8px}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button{padding:7px 13px;border-radius:3px;border-width:1px;font-size:14px;font-weight:400;line-height:20px;text-align:left;border-style:solid;display:flex;gap:8px;align-items:center}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button:focus{outline:0;box-shadow:none}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button.processing{pointer-events:none;opacity:.8}.uds-feedback-form--container .uds-form-body--content .uds-feedback-form-sumbit--actions .button.processing::before{content:"\f463";animation:spin 2s linear infinite;font-family:dashicons,sans-serif;font-weight:400;font-size:18px;cursor:pointer}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form .uds-reason-label{font-size:14px;font-weight:400;line-height:20px;text-align:left}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type=radio]{display:flex;justify-content:center;height:18px;width:18px;cursor:pointer;margin:0;border:1px solid #d1d5db;border-radius:50%;line-height:0;box-shadow:inset 0 1px 2px rgb(0 0 0 / 10%);transition:50ms border-color ease-in-out;-webkit-appearance:none;padding:0}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type=radio]:checked{vertical-align:middle;background-color:#006ba1}.uds-feedback-form--container .uds-form-body--content #uds-feedback-form input[type=radio]:checked::before{background-color:#fff!important;border-radius:50px;content:"\2022";font-size:24px;height:6px;line-height:13px;margin:5px;text-indent:-9999px;width:6px}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}} bsf-analytics/class-bsf-analytics-events.php 0000644 00000017615 15252514036 0015175 0 ustar 00 <?php /** * BSF Analytics Events — reusable one-time milestone tracking. * * Tracks events temporarily, sends them once via BSF Analytics, * then cleans up. Only a minimal dedup flag remains. * * @package bsf-analytics * @since 1.1.21 */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } if ( ! class_exists( 'BSF_Analytics_Events' ) ) { /** * BSF Analytics Events Class. * * @since 1.1.21 */ class BSF_Analytics_Events { /** * Plugin slug used as option key prefix in default storage. * * @var string */ private $slug; /** * Option resolver callbacks. * * @var array{get: callable|null, update: callable|null} */ private $option_resolver; /** * Constructor. * * @param string $slug Plugin slug (e.g. 'sureforms', 'astra'). * @param array $option_resolver Optional. Custom callbacks for option storage. * 'get' => callable( $key, $default ) — retrieve an option. * 'update' => callable( $key, $value ) — persist an option. * When omitted, uses get_option( '{slug}_{key}' ) / update_option( '{slug}_{key}' ). * @since 1.1.21 */ public function __construct( $slug, $option_resolver = array() ) { $this->slug = sanitize_key( $slug ); $this->option_resolver = wp_parse_args( $option_resolver, array( 'get' => null, 'update' => null, ) ); } /** * Track an event. By default, skips if already tracked or pending (one-time semantics). * When $force is true, the event is treated as retrackable — bypasses the post-send * dedup check and overwrites any pending entry with the same name. Useful for * recurring events like `plugin_updated` where the latest value should always win. * Only stores temporary data — cleaned up after analytics send. * * @param string $event_name Event identifier. * @param string $event_value Primary value (version, form ID, mode, etc.). * @param array<string, mixed> $properties Additional context as key-value pairs. Values are stored as-is — sanitization is the caller's responsibility. * @param bool $force When true, bypass pushed dedup and overwrite pending entry. Default false. * @since 1.1.21 * @since 1.1.25 Added the $force parameter. * @return void */ public function track( $event_name, $event_value = '', $properties = array(), $force = false ) { // Sanitize inputs once upfront — ensures dedup comparisons match stored values. $event_name = sanitize_text_field( $event_name ); $event_value = sanitize_text_field( (string) $event_value ); $properties = is_array( $properties ) ? $properties : array(); $force = (bool) $force; // Check dedup flag — already sent in a previous cycle. // Force bypasses this check; pushed list will be refreshed on next flush_pending(). if ( ! $force ) { $pushed = $this->get_option( 'usage_events_pushed', array() ); $pushed = is_array( $pushed ) ? $pushed : array(); if ( in_array( $event_name, $pushed, true ) ) { return; } } // Check if already queued in current cycle. $pending = $this->get_option( 'usage_events_pending', array() ); $pending = is_array( $pending ) ? $pending : array(); $new_event = array( 'event_name' => $event_name, 'event_value' => $event_value, 'properties' => $properties, 'date' => current_time( 'mysql' ), ); if ( ! $force ) { // Default path: cheap membership check — no need to locate the key. if ( in_array( $event_name, array_column( $pending, 'event_name' ), true ) ) { return; } $pending[] = $new_event; } else { // Force path: locate any existing entry by actual key to overwrite safely. $existing_key = null; foreach ( $pending as $key => $entry ) { if ( isset( $entry['event_name'] ) && $entry['event_name'] === $event_name ) { $existing_key = $key; break; } } if ( null !== $existing_key ) { // Skip the write when nothing material changed (only `date` would differ). $existing = $pending[ $existing_key ]; if ( array_key_exists( 'event_value', $existing ) && array_key_exists( 'properties', $existing ) && $existing['event_value'] === $new_event['event_value'] && $existing['properties'] === $new_event['properties'] ) { return; } $pending[ $existing_key ] = $new_event; } else { $pending[] = $new_event; } } $this->update_option( 'usage_events_pending', $pending ); } /** * Flush pending events: returns them for the payload, then cleans up. * * After this call: * - usage_events_pending is EMPTY (full event data deleted). * - usage_events_pushed has event_name strings added (minimal dedup). * * @since 1.1.21 * @return array Pending events to include in payload. Empty if none. */ public function flush_pending() { $pending = $this->get_option( 'usage_events_pending', array() ); if ( empty( $pending ) || ! is_array( $pending ) ) { return array(); } // Add event names to dedup flag (minimal — just strings). $pushed = $this->get_option( 'usage_events_pushed', array() ); $pushed = is_array( $pushed ) ? $pushed : array(); $pushed = array_unique( array_merge( $pushed, array_column( $pending, 'event_name' ) ) ); $this->update_option( 'usage_events_pushed', $pushed ); // DELETE all temporary event data. $this->update_option( 'usage_events_pending', array() ); return $pending; } /** * Remove specific event names from the pushed dedup flag, allowing them to be re-tracked. * * Pass an array of event names to remove only those entries. * Pass an empty array (or omit) to clear all pushed events. * * @param array<string> $event_names Event names to remove. Empty = clear all. * @since 1.1.21 * @return void */ public function flush_pushed( $event_names = array() ) { $pushed = $this->get_option( 'usage_events_pushed', array() ); $pushed = is_array( $pushed ) ? $pushed : array(); if ( empty( $event_names ) ) { $this->update_option( 'usage_events_pushed', array() ); return; } $pushed = array_values( array_diff( $pushed, $event_names ) ); $this->update_option( 'usage_events_pushed', $pushed ); } /** * Check if an event has already been tracked (sent or pending). * * @param string $event_name Event identifier. * @since 1.1.21 * @return bool */ public function is_tracked( $event_name ) { $pushed = $this->get_option( 'usage_events_pushed', array() ); $pushed = is_array( $pushed ) ? $pushed : array(); if ( in_array( $event_name, $pushed, true ) ) { return true; } $pending = $this->get_option( 'usage_events_pending', array() ); $pending = is_array( $pending ) ? $pending : array(); return in_array( $event_name, array_column( $pending, 'event_name' ), true ); } /** * Get an option value using custom resolver or default WordPress option. * * @param string $key Option key (e.g. 'usage_events_pending'). * @param mixed $default Default value. * @return mixed */ private function get_option( $key, $default = null ) { if ( is_callable( $this->option_resolver['get'] ) ) { return call_user_func( $this->option_resolver['get'], $key, $default ); } return get_option( $this->slug . '_' . $key, $default ); } /** * Update an option value using custom resolver or default WordPress option. * * @param string $key Option key (e.g. 'usage_events_pending'). * @param mixed $value Value to store. * @return void */ private function update_option( $key, $value ) { if ( is_callable( $this->option_resolver['update'] ) ) { call_user_func( $this->option_resolver['update'], $key, $value ); return; } update_option( $this->slug . '_' . $key, $value ); } } } bsf-analytics/class-bsf-analytics-stats.php 0000644 00000015410 15252514036 0015016 0 ustar 00 <?php /** * BSF analytics stat class file. * * @package bsf-analytics */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } if ( ! class_exists( 'BSF_Analytics_Stats' ) ) { /** * BSF analytics stat class. */ class BSF_Analytics_Stats { /** * Active plugins. * * Holds the sites active plugins list. * * @var array */ private $plugins; /** * Instance of BSF_Analytics_Stats. * * Holds only the first object of class. * * @var object */ private static $instance = null; /** * Create only once instance of a class. * * @return object * @since 1.0.0 */ public static function instance() { if ( null === self::$instance ) { self::$instance = new self(); } return self::$instance; } /** * Get stats. * * @return array stats data. * @since 1.0.0 */ public function get_stats() { return apply_filters( 'bsf_core_stats', $this->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'] ) ? wp_kses( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ), [] ) : '', '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(), 'posts_count' => wp_count_posts()->publish, 'page_count' => wp_count_posts( 'page' )->publish, '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(), 'admin_email' => get_option( 'admin_email' ), ); } /** * 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() { 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; } } admin-notices.php 0000644 00000110457 15252521333 0010020 0 ustar 00 <?php namespace Elementor\Core\Admin; use Elementor\Api; use Elementor\Core\Admin\UI\Components\Button; use Elementor\Core\Base\Module; use Elementor\Core\Upgrade\Manager; use Elementor\Core\Utils\Hints; use Elementor\Core\Utils\Promotions\Filtered_Promotions_Manager; use Elementor\Plugin; use Elementor\Settings; use Elementor\Tracker; use Elementor\User; use Elementor\Utils; use Elementor\Core\Admin\Notices\Base_Notice; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Admin_Notices extends Module { const DEFAULT_EXCLUDED_PAGES = [ 'plugins.php', 'plugin-install.php', 'plugin-editor.php' ]; const LOCAL_GOOGLE_FONTS_DISABLED_NOTICE_ID = 'local_google_fonts_disabled'; const LOCAL_GOOGLE_FONTS_NOTICE_MIN_VERSION = '3.33.3'; const EXIT_EARLY_FOR_BACKWARD_COMPATIBILITY = false; private $plain_notices = [ 'api_notice', 'api_upgrade_plugin', 'tracker', 'tracker_last_update', 'rate_us_feedback', 'role_manager_promote', 'experiment_promotion', 'site_mailer_promotion', 'plugin_image_optimization', 'ally_pages_promotion', self::LOCAL_GOOGLE_FONTS_DISABLED_NOTICE_ID, ]; private $elementor_pages_count = null; private $install_time = null; private $current_screen_id = null; private function get_notices() { /** * Admin notices. * * Filters Elementor admin notices. * * This hook can be used by external developers to manage existing * admin notice or to add new notices for Elementor add-ons. * * @param array $notices A list of notice classes. */ $notices = apply_filters( 'elementor/core/admin/notices', [] ); return $notices; } private function get_install_time() { if ( null === $this->install_time ) { $this->install_time = Plugin::$instance->get_install_time(); } return $this->install_time; } private function get_elementor_pages_count() { if ( null === $this->elementor_pages_count ) { $elementor_pages = new \WP_Query( [ 'no_found_rows' => true, 'post_type' => 'any', 'post_status' => 'publish', 'fields' => 'ids', 'update_post_meta_cache' => false, 'update_post_term_cache' => false, 'meta_key' => '_elementor_edit_mode', 'meta_value' => 'builder', ] ); $this->elementor_pages_count = $elementor_pages->post_count; } return $this->elementor_pages_count; } private function notice_api_upgrade_plugin() { $upgrade_notice = Api::get_upgrade_notice(); if ( empty( $upgrade_notice ) ) { return false; } if ( ! current_user_can( 'update_plugins' ) ) { return false; } if ( ! $this->is_elementor_admin_screen_with_system_info() ) { return false; } // Check for upgrades. $update_plugins = get_site_transient( 'update_plugins' ); $has_remote_update_package = ! ( empty( $update_plugins ) || empty( $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ] ) || empty( $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ]->package ) ); if ( ! $has_remote_update_package && empty( $upgrade_notice['update_link'] ) ) { return false; } if ( $has_remote_update_package ) { $product = $update_plugins->response[ ELEMENTOR_PLUGIN_BASE ]; $details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $product->slug . '§ion=changelog&TB_iframe=true&width=600&height=800' ); $upgrade_url = wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' . ELEMENTOR_PLUGIN_BASE ), 'upgrade-plugin_' . ELEMENTOR_PLUGIN_BASE ); $new_version = $product->new_version; } else { $upgrade_url = $upgrade_notice['update_link']; $details_url = $upgrade_url; $new_version = $upgrade_notice['version']; } // Check if upgrade messages should be shown. if ( version_compare( ELEMENTOR_VERSION, $upgrade_notice['version'], '>=' ) ) { return false; } $notice_id = 'upgrade_notice_' . $upgrade_notice['version']; if ( User::is_user_notice_viewed( $notice_id ) ) { return false; } $message = sprintf( /* translators: 1: Details URL, 2: Accessibility text, 3: Version number, 4: Update URL, 5: Accessibility text. */ __( 'There is a new version of Elementor Page Builder available. <a href="%1$s" class="thickbox open-plugin-details-modal" aria-label="%2$s">View version %3$s details</a> or <a href="%4$s" class="update-link" aria-label="%5$s">update now</a>.', 'elementor' ), esc_url( $details_url ), sprintf( /* translators: %s: Elementor version. */ esc_attr__( 'View Elementor version %s details', 'elementor' ), $new_version ), $new_version, esc_url( $upgrade_url ), esc_attr__( 'Update Now', 'elementor' ) ); $options = [ 'title' => esc_html__( 'Update Notification', 'elementor' ), 'description' => $message, 'button' => [ 'icon_classes' => 'dashicons dashicons-update', 'text' => esc_html__( 'Update Now', 'elementor' ), 'url' => $upgrade_url, ], 'id' => $notice_id, ]; $this->print_admin_notice( $options ); return true; } private function notice_api_notice() { $admin_notice = Api::get_admin_notice(); if ( empty( $admin_notice ) ) { return false; } if ( ! current_user_can( 'manage_options' ) ) { return false; } if ( ! $this->is_elementor_admin_screen_with_system_info() ) { return false; } $notice_id = 'admin_notice_api_' . $admin_notice['notice_id']; if ( User::is_user_notice_viewed( $notice_id ) ) { return false; } $options = [ 'title' => esc_html__( 'Update Notification', 'elementor' ), 'description' => $admin_notice['notice_text'], 'id' => $notice_id, ]; $this->print_admin_notice( $options ); return true; } private function notice_tracker() { if ( ! current_user_can( 'manage_options' ) ) { return false; } // Show tracker notice after 24 hours from installed time. if ( strtotime( '+24 hours', $this->get_install_time() ) > time() ) { return false; } if ( '1' === get_option( 'elementor_tracker_notice' ) ) { return false; } if ( Tracker::is_allow_track() ) { return false; } if ( 2 > $this->get_elementor_pages_count() ) { return false; } // TODO: Skip for development env. $optin_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_into' ), 'opt_into' ); $optout_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_out' ), 'opt_out' ); $tracker_description_text = esc_html__( 'Become a super contributor by helping us understand how you use our service to enhance your experience and improve our product.', 'elementor' ); /** * Tracker admin description text. * * Filters the admin notice text for non-sensitive data collection. * * @since 1.0.0 * * @param string $tracker_description_text Description text displayed in admin notice. */ $tracker_description_text = apply_filters( 'elementor/tracker/admin_description_text', $tracker_description_text ); $message = esc_html( $tracker_description_text ) . ' <a href="https://go.elementor.com/usage-data-tracking/" target="_blank">' . esc_html__( 'Learn more.', 'elementor' ) . '</a>'; $options = [ 'title' => esc_html__( 'Want to shape the future of web creation?', 'elementor' ), 'description' => $message, 'dismissible' => false, 'button' => [ 'text' => esc_html__( 'Sure! I\'d love to help', 'elementor' ), 'url' => $optin_url, 'type' => 'cta', ], 'button_secondary' => [ 'text' => esc_html__( 'No thanks', 'elementor' ), 'url' => $optout_url, 'variant' => 'outline', 'type' => 'cta', ], ]; $this->print_admin_notice( $options ); return true; } private function notice_tracker_last_update() { if ( ! current_user_can( 'manage_options' ) ) { return false; } if ( ! Tracker::has_terms_changed() ) { return false; } $notice_id = 'tracker_last_update_' . Tracker::LAST_TERMS_UPDATED; if ( User::is_user_notice_viewed( $notice_id ) ) { return false; } $optin_url = wp_nonce_url( add_query_arg( 'elementor_tracker', 'opt_into' ), 'opt_into' ); $message = esc_html__( 'We\'re updating our Terms and Conditions to include the collection of usage and behavioral data. This information helps us understand how you use Elementor so we can make informed improvements to the product.', 'elementor' ); $options = [ 'id' => $notice_id, 'title' => esc_html__( 'Update regarding usage data collection', 'elementor' ), 'description' => $message, 'button' => [ 'text' => esc_html__( 'Opt in', 'elementor' ), 'url' => $optin_url, 'type' => 'cta', ], 'button_secondary' => [ 'text' => esc_html__( 'Learn more', 'elementor' ), 'url' => 'https://go.elementor.com/wp-dash-update-usage-notice/', 'new_tab' => true, 'type' => 'cta', ], ]; $this->print_admin_notice( $options ); return true; } private function notice_rate_us_feedback() { $notice_id = 'rate_us_feedback'; if ( ! current_user_can( 'manage_options' ) ) { return false; } if ( 'dashboard' !== $this->current_screen_id || User::is_user_notice_viewed( $notice_id ) ) { return false; } if ( 10 >= $this->get_elementor_pages_count() ) { return false; } $dismiss_url = add_query_arg( [ 'action' => 'elementor_set_admin_notice_viewed', 'notice_id' => esc_attr( $notice_id ), '_wpnonce' => wp_create_nonce( 'elementor_set_admin_notice_viewed' ), ], admin_url( 'admin-post.php' ) ); $options = [ 'title' => esc_html__( 'Congrats!', 'elementor' ), 'description' => esc_html__( 'You created over 10 pages with Elementor. Great job! If you can spare a minute, please help us by leaving a five star review on WordPress.org.', 'elementor' ), 'id' => $notice_id, 'button' => [ 'text' => esc_html__( 'Happy To Help', 'elementor' ), 'url' => 'https://go.elementor.com/admin-review/', 'new_tab' => true, 'type' => 'cta', ], 'button_secondary' => [ 'text' => esc_html__( 'Hide Notification', 'elementor' ), 'classes' => [ 'e-notice-dismiss' ], 'url' => esc_url_raw( $dismiss_url ), 'new_tab' => true, 'type' => 'cta', ], ]; $this->print_admin_notice( $options ); return true; } private function notice_role_manager_promote() { $notice_id = 'role_manager_promote'; if ( Utils::has_pro() ) { return false; } if ( ! current_user_can( 'manage_options' ) ) { return false; } if ( 'elementor_page_elementor-role-manager' !== $this->current_screen_id || User::is_user_notice_viewed( $notice_id ) ) { return false; } $users = new \WP_User_Query( [ 'fields' => 'ID', 'number' => 10, ] ); if ( 5 > $users->get_total() ) { return false; } $options = [ 'title' => esc_html__( 'Managing a multi-user site?', 'elementor' ), 'description' => esc_html__( 'With Elementor Pro, you can control user access and make sure no one messes up your design.', 'elementor' ), 'id' => $notice_id, 'button' => [ 'text' => esc_html__( 'Learn More', 'elementor' ), 'url' => 'https://go.elementor.com/plugin-promotion-role-manager/', 'new_tab' => true, 'type' => 'cta', ], ]; $options = Filtered_Promotions_Manager::get_filtered_promotion_data( $options, 'core/admin/notice_role_manager_promote', 'button', 'url' ); $this->print_admin_notice( $options ); return true; } private function notice_experiment_promotion() { $notice_id = 'experiment_promotion'; if ( ! current_user_can( 'manage_options' ) || User::is_user_notice_viewed( $notice_id ) ) { return false; } $experiments = Plugin::$instance->experiments; $is_all_performance_features_active = ( $experiments->is_feature_active( 'e_font_icon_svg' ) && $experiments->is_feature_active( 'e_optimized_markup' ) ); if ( $is_all_performance_features_active ) { return false; } $options = [ 'title' => esc_html__( 'Improve your site’s performance score.', 'elementor' ), 'description' => esc_html__( 'With our experimental speed boosting features you can go faster than ever before. Look for the Performance label on our Experiments page and activate those experiments to improve your site loading speed.', 'elementor' ), 'id' => $notice_id, 'button' => [ 'text' => esc_html__( 'Try it out', 'elementor' ), 'url' => Settings::get_settings_tab_url( 'experiments' ), 'type' => 'cta', ], 'button_secondary' => [ 'text' => esc_html__( 'Learn more', 'elementor' ), 'url' => 'https://go.elementor.com/wp-dash-experiment-promotion/', 'new_tab' => true, 'type' => 'cta', ], ]; $this->print_admin_notice( $options ); return true; } private function site_has_forms_plugins() { return defined( 'WPFORMS_VERSION' ) || defined( 'WPCF7_VERSION' ) || defined( 'FLUENTFORM_VERSION' ) || class_exists( '\GFCommon' ) || class_exists( '\Ninja_Forms' ) || function_exists( 'load_formidable_forms' ) || did_action( 'metform/after_load' ) || defined( 'FORMINATOR_PLUGIN_BASENAME' ); } private function site_has_woocommerce() { return class_exists( 'WooCommerce' ); } private function get_installed_form_plugin_name() { static $detected_form_plugin = null; if ( null !== $detected_form_plugin ) { return $detected_form_plugin; } $form_plugins_constants_to_name_mapper = [ 'WPFORMS_VERSION' => 'WPForms', 'WPCF7_VERSION' => 'Contact Form 7', ]; foreach ( $form_plugins_constants_to_name_mapper as $constant => $name ) { if ( defined( $constant ) ) { $detected_form_plugin = $name; return $detected_form_plugin; } } $form_plugins_classes_to_name_mapper = [ '\GFCommon' => 'Gravity Forms', '\Ninja_Forms' => 'Ninja Forms', ]; foreach ( $form_plugins_classes_to_name_mapper as $class => $name ) { if ( class_exists( $class ) ) { $detected_form_plugin = $name; return $detected_form_plugin; } } $detected_form_plugin = false; return $detected_form_plugin; } private function notice_local_google_fonts_disabled() { if ( ! $this->is_elementor_page() && ! $this->is_elementor_admin_screen() ) { return false; } if ( ! Manager::had_install_prior_to( self::LOCAL_GOOGLE_FONTS_NOTICE_MIN_VERSION ) ) { return false; } if ( User::is_user_notice_viewed( self::LOCAL_GOOGLE_FONTS_DISABLED_NOTICE_ID ) ) { return false; } $is_local_gf_enabled = (bool) get_option( 'elementor_local_google_fonts', '0' ); if ( $is_local_gf_enabled ) { return false; } $options = [ 'title' => esc_html__( 'Important: Local Google Fonts Settings in Elementor', 'elementor' ), 'description' => esc_html__( 'Please note: The "Load Google Fonts Locally" feature has been disabled by default on all websites. To turn it back on, go to Elementor → Settings → Performance → Enable Load Google Fonts Locally.', 'elementor' ), 'id' => self::LOCAL_GOOGLE_FONTS_DISABLED_NOTICE_ID, 'type' => '', 'button' => [ 'text' => esc_html__( 'Take me there', 'elementor' ), 'url' => '../wp-admin/admin.php?page=elementor-settings#tab-performance', 'new_tab' => false, 'type' => 'cta', ], 'button_secondary' => [ 'text' => esc_html__( 'Learn more', 'elementor' ), 'url' => 'https://go.elementor.com/wp-dash-google-fonts-locally-notice/', 'new_tab' => true, 'type' => 'cta', ], ]; $this->print_admin_notice( $options ); return true; } private function notice_ally_pages_promotion() { global $pagenow; $notice_id = 'ally_pages_promotion'; if ( 'edit.php' !== $pagenow || empty( $_GET['post_type'] ) || 'page' !== $_GET['post_type'] ) { return false; } if ( ! current_user_can( 'manage_options' ) ) { return false; } if ( User::is_user_notice_viewed( $notice_id ) ) { return false; } $plugin_slug = 'pojo-accessibility'; $plugin_file_path = 'pojo-accessibility/pojo-accessibility.php'; $one_subscription = Hints::is_plugin_connected_to_one_subscription(); $is_installed = Hints::is_plugin_installed( $plugin_slug ); $is_active = Hints::is_plugin_active( $plugin_slug ); if ( $is_active ) { return false; } if ( $one_subscription ) { $learn_more_url = 'https://go.elementor.com/acc-plg-learn-more-one'; if ( ! $is_installed ) { $description = esc_html__( 'Make sure your site has an accessibility statement page. Install Web Accessibility, included in ONE, to create it in a few clicks.', 'elementor' ); $button_text = esc_html__( 'Install now', 'elementor' ); $button_url = $this->get_plugin_button_install_url( $plugin_slug ); $campaign_data = [ 'name' => 'elementor_ea11y_campaign', 'campaign' => 'acc-statement-plg-pages-one-install', 'source' => 'wp-pages-one-install', 'medium' => 'wp-dash-one', ]; } elseif ( ! $is_active ) { $description = esc_html__( 'Your ONE subscription includes Web Accessibility. Activate it to create your accessibility statement page quickly.', 'elementor' ); $button_text = esc_html__( 'Activate now', 'elementor' ); $button_url = $this->get_plugin_button_activate_url( $plugin_file_path ); $campaign_data = [ 'name' => 'elementor_ea11y_campaign', 'campaign' => 'acc-statement-plg-pages-one-activate', 'source' => 'wp-pages-one-activate', 'medium' => 'wp-dash-one', ]; } } else { $description = esc_html__( "Create a more inclusive site experience for all your visitors. With Web Accessibility, it's easy to add your statement page in just a few clicks.", 'elementor' ); $learn_more_url = 'https://go.elementor.com/acc-plg-learn-more'; if ( ! $is_installed ) { $button_text = esc_html__( 'Install now', 'elementor' ); $button_url = $this->get_plugin_button_install_url( $plugin_slug ); $campaign_data = [ 'name' => 'elementor_ea11y_campaign', 'campaign' => 'acc-statement-plg-pages-install', 'source' => 'wp-pages-install', 'medium' => 'wp-dash', ]; } elseif ( ! $is_active ) { $button_text = esc_html__( 'Activate now', 'elementor' ); $button_url = $this->get_plugin_button_activate_url( $plugin_file_path ); $campaign_data = [ 'name' => 'elementor_ea11y_campaign', 'campaign' => 'acc-statement-plg-pages-activate', 'source' => 'wp-pages-activate', 'medium' => 'wp-dash', ]; } } $options = [ 'title' => esc_html__( 'Make sure your site has an accessibility statement page', 'elementor' ), 'description' => $description, 'id' => $notice_id, 'type' => 'cta', 'button' => [ 'text' => $button_text, 'url' => self::add_plg_campaign_data( $button_url, $campaign_data ), 'type' => 'cta', ], 'button_secondary' => [ 'text' => esc_html__( 'Learn more', 'elementor' ), 'url' => $learn_more_url, 'new_tab' => true, 'type' => 'cta', ], ]; $this->print_admin_notice( $options ); return true; } private function notice_site_mailer_promotion() { $notice_id = 'site_mailer_promotion'; $has_forms = $this->site_has_forms_plugins(); $has_woocommerce = $this->site_has_woocommerce(); if ( ! $has_forms && ! $has_woocommerce ) { return false; } if ( ! $this->is_elementor_page() && ! $this->is_elementor_admin_screen() ) { return false; } if ( ( Utils::has_pro() && ! $has_woocommerce ) || ! current_user_can( 'install_plugins' ) || User::is_user_notice_viewed( $notice_id ) ) { return false; } $plugin_slug = 'site-mailer'; $plugin_file_path = 'site-mailer/site-mailer.php'; $one_subscription = Hints::is_plugin_connected_to_one_subscription(); $is_woocommerce = $this->should_render_woocommerce_hint( $has_forms, $has_woocommerce ); $is_installed = Hints::is_plugin_installed( $plugin_slug ); $is_active = Hints::is_plugin_active( $plugin_slug ); if ( $is_active ) { return false; } if ( $one_subscription ) { if ( $is_woocommerce ) { $title = esc_html__( 'Improve transactional email deliverability', 'elementor' ); if ( ! $is_installed ) { $description = esc_html__( 'Use Email Deliverability to ensure store emails like purchase confirmations and shipping updates reach the inbox every time. Included in your ONE subscription.', 'elementor' ); $button_text = esc_html__( 'Install now', 'elementor' ); $button_url = $this->get_plugin_button_install_url( $plugin_slug ); $campaign_data = [ 'name' => 'elementor_site_mailer_campaign', 'campaign' => 'sm-plg-one', 'source' => 'sm-core-woo-one-install', 'medium' => 'wp-dash', ]; } elseif ( ! $is_active ) { $description = esc_html__( 'Email Deliverability is installed and included in your ONE subscription. Activate it to ensure store emails like purchase confirmations and shipping updates reach the inbox every time.', 'elementor' ); $button_text = esc_html__( 'Activate now', 'elementor' ); $button_url = $this->get_plugin_button_activate_url( $plugin_file_path ); $campaign_data = [ 'name' => 'elementor_site_mailer_campaign', 'campaign' => 'sm-plg-one', 'source' => 'sm-core-woo-one-activate', 'medium' => 'wp-dash', ]; } } else { $title = esc_html__( 'Keep your form emails out of the spam folder', 'elementor' ); if ( ! $is_installed ) { $description = esc_html__( 'Use Email Deliverability to ensure emails reach the inbox and track delivery with built-in logs. Included in your ONE subscription.', 'elementor' ); $button_text = esc_html__( 'Install now', 'elementor' ); $button_url = $this->get_plugin_button_install_url( $plugin_slug ); $campaign_data = [ 'name' => 'elementor_site_mailer_campaign', 'campaign' => 'sm-plg-one', 'source' => 'sm-core-form-one-install', 'medium' => 'wp-dash', ]; } elseif ( ! $is_active ) { $description = esc_html__( 'Use Email Deliverability to ensure emails reach the inbox and track delivery with built-in logs. Email Deliverability is included in your ONE subscription. Activate it to continue.', 'elementor' ); $button_text = esc_html__( 'Activate now', 'elementor' ); $button_url = $this->get_plugin_button_activate_url( $plugin_file_path ); $campaign_data = [ 'name' => 'elementor_site_mailer_campaign', 'campaign' => 'sm-plg-one', 'source' => 'sm-core-form-one-activate', 'medium' => 'wp-dash', ]; } } // phpcs:ignore Universal.ControlStructures.DisallowLonelyIf.Found } else { if ( $is_woocommerce ) { $title = esc_html__( 'Improve Transactional Email Deliverability', 'elementor' ); $description = esc_html__( "Use Elementor's Email Deliverability to ensure your store emails like purchase confirmations, shipping updates and more are reliably delivered.", 'elementor' ); if ( ! $is_installed ) { $button_text = esc_html__( 'Install now', 'elementor' ); $button_url = $this->get_plugin_button_install_url( $plugin_slug ); $campaign_data = [ 'name' => 'elementor_site_mailer_campaign', 'campaign' => 'sm-plg', 'source' => 'sm-core-woo-install', 'medium' => 'wp-dash', ]; } elseif ( ! $is_active ) { $button_text = esc_html__( 'Activate now', 'elementor' ); $button_url = $this->get_plugin_button_activate_url( $plugin_file_path ); $campaign_data = [ 'name' => 'elementor_site_mailer_campaign', 'campaign' => 'sm-plg', 'source' => 'sm-core-woo-activate', 'medium' => 'wp-dash', ]; } } else { $title = esc_html__( 'Ensure your form emails avoid the spam folder!', 'elementor' ); $description = esc_html__( 'Use Email Deliverability for improved email deliverability, detailed email logs, and an easy setup.', 'elementor' ); if ( ! $is_installed ) { $button_text = esc_html__( 'Install now', 'elementor' ); $button_url = $this->get_plugin_button_install_url( $plugin_slug ); $campaign_data = [ 'name' => 'elementor_site_mailer_campaign', 'campaign' => 'sm-plg', 'source' => 'sm-core-form-install', 'medium' => 'wp-dash', ]; } elseif ( ! $is_active ) { $button_text = esc_html__( 'Activate now', 'elementor' ); $button_url = $this->get_plugin_button_activate_url( $plugin_file_path ); $campaign_data = [ 'name' => 'elementor_site_mailer_campaign', 'campaign' => 'sm-plg', 'source' => 'sm-core-form-activate', 'medium' => 'wp-dash', ]; } } } $learn_more_url = $one_subscription && $is_woocommerce ? 'https://go.elementor.com/sm-woo-learn-more-one' : 'https://go.elementor.com/sm-core-form/'; $options = [ 'title' => $title, 'description' => $description, 'id' => $notice_id, 'type' => 'cta', 'button' => [ 'text' => $button_text, 'url' => self::add_plg_campaign_data( $button_url, $campaign_data ), 'type' => 'cta', 'data' => [ 'campaign' => $campaign_data['campaign'], 'source' => $campaign_data['source'], 'medium' => $campaign_data['medium'], ], ], 'button_secondary' => [ 'text' => esc_html__( 'Learn more', 'elementor' ), 'url' => $learn_more_url, 'new_tab' => true, 'type' => 'cta', ], ]; if ( $is_woocommerce ) { // We include WP's default notice class so it will be properly handled by WP's js handler // And add a new one to distinguish between the two types of notices $options['classes'] = [ 'notice', 'e-notice', 'sm-notice-wc' ]; } $this->print_admin_notice( $options ); return true; } private function should_render_woocommerce_hint( $has_forms, $has_woocommerce ): bool { if ( ! $has_forms && ! $has_woocommerce ) { return false; } if ( ! $has_forms && $has_woocommerce ) { return true; } if ( $has_forms && $has_woocommerce && Utils::has_pro() ) { return true; } if ( ! $has_woocommerce ) { return false; } return (bool) wp_rand( 0, 1 ); } private function is_elementor_page(): bool { return 0 === strpos( $this->current_screen_id, 'elementor_page' ); } private function is_elementor_admin_screen(): bool { return in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library' ], true ); } private function is_elementor_admin_screen_with_system_info(): bool { return in_array( $this->current_screen_id, [ 'toplevel_page_elementor', 'edit-elementor_library', 'elementor_page_elementor-system-info', 'dashboard' ], true ); } private function get_plugin_button_install_url( $plugin_slug ) { return wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $plugin_slug ), 'install-plugin_' . $plugin_slug ); } private function get_plugin_button_activate_url( $plugin_file_path ) { return wp_nonce_url( 'plugins.php?action=activate&plugin=' . $plugin_file_path . '&plugin_status=all&paged=1&s', 'activate-plugin_' . $plugin_file_path ); } private function get_plugin_button_connect_url( $plugin_settings_page ) { return self_admin_url( $plugin_settings_page ); } private function get_plugin_cta_data( $plugin_slug, $plugin_file_path ) { if ( Hints::is_plugin_active( $plugin_slug ) ) { return false; } if ( Hints::is_plugin_installed( $plugin_slug ) ) { $url = $this->get_plugin_button_activate_url( $plugin_file_path ); $cta_text = esc_html__( 'Activate now', 'elementor' ); } else { $url = $this->get_plugin_button_install_url( $plugin_slug ); $cta_text = esc_html__( 'Install now', 'elementor' ); } return [ 'url' => $url, 'text' => $cta_text, ]; } /** * For testing purposes */ public function get_elementor_version() { return ELEMENTOR_VERSION; } private function notice_plugin_image_optimization() { $notice_id = 'plugin_image_optimization'; if ( 'upload' !== $this->current_screen_id ) { return false; } if ( ! current_user_can( 'manage_options' ) ) { return false; } if ( User::is_user_notice_viewed( $notice_id ) ) { return false; } $attachments = new \WP_Query( [ 'post_type' => 'attachment', 'post_status' => 'any', 'fields' => 'ids', ] ); if ( 1 > $attachments->found_posts ) { return false; } $plugin_slug = 'image-optimization'; $plugin_file_path = 'image-optimization/image-optimization.php'; $one_subscription = Hints::is_plugin_connected_to_one_subscription(); $is_installed = Hints::is_plugin_installed( $plugin_slug ); $is_active = Hints::is_plugin_active( $plugin_slug ); if ( $is_active ) { return false; } if ( $one_subscription ) { if ( ! $is_installed ) { $description = esc_html__( 'Automatically optimize images to improve site speed and performance. Included with your ONE subscription.', 'elementor' ); $button_text = esc_html__( 'Install now', 'elementor' ); $button_url = $this->get_plugin_button_install_url( $plugin_slug ); $campaign_data = [ 'name' => 'elementor_image_optimization_campaign', 'campaign' => 'io-plg-one', 'source' => 'io-wp-media-library-one-install', 'medium' => 'wp-dash-one', ]; } elseif ( ! $is_active ) { $description = esc_html__( 'Your ONE subscription includes Image Optimization. Activate it to optimize images and improve site performance.', 'elementor' ); $button_text = esc_html__( 'Activate now', 'elementor' ); $button_url = $this->get_plugin_button_activate_url( $plugin_file_path ); $campaign_data = [ 'name' => 'elementor_image_optimization_campaign', 'campaign' => 'io-plg-one', 'source' => 'io-wp-media-library-one-activate', 'medium' => 'wp-dash-one', ]; } } else { $description = esc_html__( 'Automatically compress and optimize images, resize larger files, or convert to WebP. Optimize images individually, in bulk, or on upload.', 'elementor' ); if ( ! $is_installed ) { $button_text = esc_html__( 'Install now', 'elementor' ); $button_url = $this->get_plugin_button_install_url( $plugin_slug ); $campaign_data = [ 'name' => 'elementor_image_optimization_campaign', 'campaign' => 'io-plg', 'source' => 'io-wp-media-library-install', 'medium' => 'wp-dash', ]; } elseif ( ! $is_active ) { $button_text = esc_html__( 'Activate now', 'elementor' ); $button_url = $this->get_plugin_button_activate_url( $plugin_file_path ); $campaign_data = [ 'name' => 'elementor_image_optimization_campaign', 'campaign' => 'io-plg', 'source' => 'io-wp-media-library-activate', 'medium' => 'wp-dash', ]; } } $options = [ 'title' => esc_html__( 'Speed up your website with Image Optimization', 'elementor' ), 'description' => $description, 'id' => $notice_id, 'type' => 'cta', 'button' => [ 'text' => $button_text, 'url' => self::add_plg_campaign_data( $button_url, $campaign_data ), 'type' => 'cta', 'data' => [ 'campaign' => $campaign_data['campaign'], 'source' => $campaign_data['source'], 'medium' => $campaign_data['medium'], ], ], ]; $this->print_admin_notice( $options ); return true; } public function print_admin_notice( array $options, $exclude_pages = self::DEFAULT_EXCLUDED_PAGES ) { global $pagenow; if ( in_array( $pagenow, $exclude_pages, true ) ) { return; } $default_options = [ 'id' => null, 'title' => '', 'description' => '', 'classes' => [ 'notice', 'e-notice' ], // We include WP's default notice class so it will be properly handled by WP's js handler 'type' => '', 'dismissible' => true, 'icon' => 'eicon-elementor-circle', 'button' => [], 'button_secondary' => [], ]; $options = array_replace_recursive( $default_options, $options ); $notice_classes = $options['classes']; $dismiss_button = ''; $icon = ''; if ( $options['type'] ) { $notice_classes[] = 'e-notice--' . $options['type']; } $wrapper_attributes = [ 'role' => 'region', 'aria-label' => esc_html__( 'Elementor notice', 'elementor' ), ]; if ( $options['dismissible'] ) { $label = esc_html__( 'Dismiss this notice.', 'elementor' ); $notice_classes[] = 'e-notice--dismissible'; $dismiss_button = '<i class="e-notice__dismiss" role="button" aria-label="' . $label . '" tabindex="0"></i>'; $wrapper_attributes['data-nonce'] = wp_create_nonce( 'elementor_set_admin_notice_viewed' ); } if ( $options['icon'] ) { $notice_classes[] = 'e-notice--extended'; $icon = '<div class="e-notice__icon-wrapper"><i class="' . esc_attr( $options['icon'] ) . '" aria-hidden="true"></i></div>'; } $wrapper_attributes['class'] = $notice_classes; if ( $options['id'] ) { $wrapper_attributes['data-notice_id'] = $options['id']; } if ( ! empty( $options['source'] ) ) { $wrapper_attributes['data-source'] = $options['source']; } ?> <div <?php Utils::print_html_attributes( $wrapper_attributes ); ?>> <?php echo $dismiss_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> <div class="e-notice__aside"> <?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> </div> <div class="e-notice__content"> <?php if ( $options['title'] ) { ?> <h3><?php echo wp_kses_post( $options['title'] ); ?></h3> <?php } ?> <?php if ( $options['description'] ) { ?> <p><?php echo wp_kses_post( $options['description'] ); ?></p> <?php } ?> <?php if ( ! empty( $options['button']['text'] ) || ! empty( $options['button_secondary']['text'] ) ) { ?> <div class="e-notice__actions"> <?php $one_subscription = Hints::is_plugin_connected_to_one_subscription(); foreach ( [ $options['button'], $options['button_secondary'] ] as $index => $button_settings ) { if ( empty( $button_settings['variant'] ) && $index ) { $button_settings['variant'] = 'outline'; } if ( empty( $button_settings['text'] ) ) { continue; } if ( $one_subscription ) { if ( ! isset( $button_settings['classes'] ) ) { $button_settings['classes'] = []; } if ( ! is_array( $button_settings['classes'] ) ) { $button_settings['classes'] = [ $button_settings['classes'] ]; } // index 0 = button, index 1 = button_secondary $button_class = ( 0 === $index ) ? 'button-primary' : 'button-secondary'; $button_settings['classes'][] = $button_class; } $button = new Button( $button_settings ); $button->print_button(); } ?> </div> <?php } ?> </div> </div> <?php } public function admin_notices() { $this->install_time = Plugin::$instance->get_install_time(); $this->current_screen_id = get_current_screen()->id; foreach ( $this->plain_notices as $notice ) { $method_callback = "notice_{$notice}"; if ( $this->$method_callback() ) { return; } } /** @var Base_Notice $notice_instance */ foreach ( $this->get_notices() as $notice_instance ) { if ( ! $notice_instance->should_print() ) { continue; } $this->print_admin_notice( $notice_instance->get_config() ); // It exits the method to make sure it prints only one notice. return; } } public function maybe_log_campaign() { if ( empty( $_GET['plg_campaign'] ) || empty( $_GET['plg_campaign_name'] ) ) { return; } $allowed_plgs = [ 'elementor_image_optimization_campaign', 'elementor_ea11y_campaign', 'elementor_site_mailer_campaign', ]; if ( ! in_array( $_GET['plg_campaign_name'], $allowed_plgs, true ) ) { return; } if ( ! isset( $_GET['plg_campaign_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['plg_campaign_nonce'] ), sanitize_key( $_GET['plg_campaign_name'] ) ) ) { return; } if ( ! current_user_can( 'manage_options' ) ) { return; } if ( empty( $_GET['plg_source'] ) || empty( $_GET['plg_medium'] ) ) { return; } $campaign_data = [ 'source' => sanitize_key( $_GET['plg_source'] ), 'campaign' => sanitize_key( $_GET['plg_campaign'] ), 'medium' => sanitize_key( $_GET['plg_medium'] ), ]; set_transient( sanitize_key( $_GET['plg_campaign_name'] ), $campaign_data, 30 * DAY_IN_SECONDS ); } public static function add_plg_campaign_data( $url, $campaign_data ) { foreach ( [ 'name', 'campaign' ] as $key ) { if ( empty( $campaign_data[ $key ] ) ) { return $url; } } return add_query_arg( [ 'plg_campaign_name' => $campaign_data['name'], 'plg_campaign' => $campaign_data['campaign'], 'plg_source' => empty( $campaign_data['source'] ) ? '' : $campaign_data['source'], 'plg_medium' => empty( $campaign_data['medium'] ) ? '' : $campaign_data['medium'], 'plg_campaign_nonce' => wp_create_nonce( $campaign_data['name'] ), ], $url ); } /** * @since 2.9.0 * @access public */ public function __construct() { add_action( 'admin_notices', [ $this, 'admin_notices' ], 20 ); add_action( 'admin_action_install-plugin', [ $this, 'maybe_log_campaign' ] ); add_action( 'admin_action_activate', [ $this, 'maybe_log_campaign' ] ); } /** * Get module name. * * Retrieve the module name. * * @since 2.9.0 * @access public * * @return string Module name. */ public function get_name() { return 'admin-notices'; } } canary-deployment.php 0000644 00000011774 15252521333 0010723 0 ustar 00 <?php namespace Elementor\Core\Admin; use Elementor\Api; use Elementor\Core\Base\Module; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * TODO: Move this class to pro version for better architecture. */ class Canary_Deployment extends Module { const CURRENT_VERSION = ELEMENTOR_VERSION; const PLUGIN_BASE = ELEMENTOR_PLUGIN_BASE; private $canary_deployment_info = null; /** * Get module name. * * Retrieve the module name. * * @since 2.6.0 * @access public * * @return string Module name. */ public function get_name() { return 'canary-deployment'; } /** * Check version. * * @since 2.6.0 * @access public * * @param object $transient Plugin updates data. * * @return object Plugin updates data. */ public function check_version( $transient ) { // First transient before the real check. if ( ! isset( $transient->response ) ) { return $transient; } // Placeholder $stable_version = '0.0.0'; if ( ! empty( $transient->response[ static::PLUGIN_BASE ]->new_version ) ) { $stable_version = $transient->response[ static::PLUGIN_BASE ]->new_version; } if ( null === $this->canary_deployment_info ) { $this->canary_deployment_info = $this->get_canary_deployment_info(); } // Can be false - if canary version is not available. if ( empty( $this->canary_deployment_info ) ) { return $transient; } if ( ! version_compare( $this->canary_deployment_info['new_version'], $stable_version, '>' ) ) { return $transient; } $canary_deployment_info = $this->canary_deployment_info; // Most of plugin info comes from the $transient but on first check - the response is empty. if ( ! empty( $transient->response[ static::PLUGIN_BASE ] ) ) { $canary_deployment_info = array_merge( (array) $transient->response[ static::PLUGIN_BASE ], $canary_deployment_info ); } $transient->response[ static::PLUGIN_BASE ] = (object) $canary_deployment_info; return $transient; } protected function get_canary_deployment_remote_info( $force ) { return Api::get_canary_deployment_info( $force ); } private function get_canary_deployment_info() { global $pagenow; $force = 'update-core.php' === $pagenow && isset( $_GET['force-check'] ); $canary_deployment = $this->get_canary_deployment_remote_info( $force ); if ( empty( $canary_deployment['plugin_info']['new_version'] ) ) { return false; } $canary_version = $canary_deployment['plugin_info']['new_version']; if ( version_compare( $canary_version, static::CURRENT_VERSION, '<=' ) ) { return false; } if ( ! empty( $canary_deployment['conditions'] ) && ! $this->check_conditions( $canary_deployment['conditions'] ) ) { return false; } return $canary_deployment['plugin_info']; } private function check_conditions( $groups ) { foreach ( $groups as $group ) { if ( $this->check_group( $group ) ) { return true; } } return false; } private function check_group( $group ) { $is_or_relation = ! empty( $group['relation'] ) && 'OR' === $group['relation']; unset( $group['relation'] ); $result = false; foreach ( $group as $condition ) { // Reset results for each condition. $result = false; switch ( $condition['type'] ) { case 'wordpress': // phpcs:ignore WordPress.WP.CapitalPDangit.MisspelledInText // include an unmodified $wp_version include ABSPATH . WPINC . '/version.php'; $result = version_compare( $wp_version, $condition['version'], $condition['operator'] ); break; case 'multisite': $result = is_multisite() === $condition['multisite']; break; case 'language': $in_array = in_array( get_locale(), $condition['languages'], true ); $result = 'in' === $condition['operator'] ? $in_array : ! $in_array; break; case 'plugin': if ( ! empty( $condition['plugin_file'] ) ) { $plugin_file = $condition['plugin_file']; // For PHP Unit tests. } else { $plugin_file = WP_PLUGIN_DIR . '/' . $condition['plugin']; // Default. } $version = ''; if ( is_plugin_active( $condition['plugin'] ) && file_exists( $plugin_file ) ) { $plugin_data = get_plugin_data( $plugin_file ); if ( isset( $plugin_data['Version'] ) ) { $version = $plugin_data['Version']; } } $result = version_compare( $version, $condition['version'], $condition['operator'] ); break; case 'theme': $theme = wp_get_theme(); if ( wp_get_theme()->parent() ) { $theme = wp_get_theme()->parent(); } if ( $theme->get_template() === $condition['theme'] ) { $version = $theme->version; } else { $version = ''; } $result = version_compare( $version, $condition['version'], $condition['operator'] ); break; } if ( ( $is_or_relation && $result ) || ( ! $is_or_relation && ! $result ) ) { return $result; } } return $result; } /** * @since 2.6.0 * @access public */ public function __construct() { add_filter( 'pre_set_site_transient_update_plugins', [ $this, 'check_version' ] ); } } feedback.php 0000644 00000013304 15252521333 0007003 0 ustar 00 <?php namespace Elementor\Core\Admin; use Elementor\Api; use Elementor\Core\Base\Module; use Elementor\Plugin; use Elementor\Tracker; use Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Feedback extends Module { /** * @since 2.2.0 * @access public */ public function __construct() { add_action( 'current_screen', function () { if ( ! $this->is_plugins_screen() ) { return; } add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_feedback_dialog_scripts' ] ); } ); // Ajax. add_action( 'wp_ajax_elementor_deactivate_feedback', [ $this, 'ajax_elementor_deactivate_feedback' ] ); } /** * Get module name. * * Retrieve the module name. * * @since 1.7.0 * @access public * * @return string Module name. */ public function get_name() { return 'feedback'; } /** * Enqueue feedback dialog scripts. * * Registers the feedback dialog scripts and enqueues them. * * @since 1.0.0 * @access public */ public function enqueue_feedback_dialog_scripts() { add_action( 'admin_footer', [ $this, 'print_deactivate_feedback_dialog' ] ); $suffix = Utils::is_script_debug() ? '' : '.min'; wp_register_script( 'elementor-admin-feedback', ELEMENTOR_ASSETS_URL . 'js/admin-feedback' . $suffix . '.js', [ 'elementor-common', 'wp-i18n', ], ELEMENTOR_VERSION, true ); wp_enqueue_script( 'elementor-admin-feedback' ); wp_set_script_translations( 'elementor-admin-feedback', 'elementor' ); } /** * Print deactivate feedback dialog. * * Display a dialog box to ask the user why he deactivated Elementor. * * Fired by `admin_footer` filter. * * @since 1.0.0 * @access public */ public function print_deactivate_feedback_dialog() { $deactivate_reasons = [ 'no_longer_needed' => [ 'title' => esc_html__( 'I no longer need the plugin', 'elementor' ), 'input_placeholder' => '', ], 'found_a_better_plugin' => [ 'title' => esc_html__( 'I found a better plugin', 'elementor' ), 'input_placeholder' => esc_html__( 'Please share which plugin', 'elementor' ), ], 'couldnt_get_the_plugin_to_work' => [ 'title' => esc_html__( 'I couldn\'t get the plugin to work', 'elementor' ), 'input_placeholder' => '', ], 'temporary_deactivation' => [ 'title' => esc_html__( 'It\'s a temporary deactivation', 'elementor' ), 'input_placeholder' => '', ], 'elementor_pro' => [ 'title' => esc_html__( 'I have Elementor Pro', 'elementor' ), 'input_placeholder' => '', 'alert' => esc_html__( 'Wait! Don\'t deactivate Elementor. You have to activate both Elementor and Elementor Pro in order for the plugin to work.', 'elementor' ), ], 'other' => [ 'title' => esc_html__( 'Other', 'elementor' ), 'input_placeholder' => esc_html__( 'Please share the reason', 'elementor' ), ], ]; ?> <div id="elementor-deactivate-feedback-dialog-wrapper"> <div id="elementor-deactivate-feedback-dialog-header"> <i class="eicon-elementor-square" aria-hidden="true"></i> <span id="elementor-deactivate-feedback-dialog-header-title"><?php echo esc_html__( 'Quick Feedback', 'elementor' ); ?></span> </div> <form id="elementor-deactivate-feedback-dialog-form" method="post"> <?php wp_nonce_field( '_elementor_deactivate_feedback_nonce' ); ?> <input type="hidden" name="action" value="elementor_deactivate_feedback" /> <div id="elementor-deactivate-feedback-dialog-form-caption"><?php echo esc_html__( 'If you have a moment, please share why you are deactivating Elementor:', 'elementor' ); ?></div> <div id="elementor-deactivate-feedback-dialog-form-body"> <?php foreach ( $deactivate_reasons as $reason_key => $reason ) : ?> <div class="elementor-deactivate-feedback-dialog-input-wrapper"> <input id="elementor-deactivate-feedback-<?php echo esc_attr( $reason_key ); ?>" class="elementor-deactivate-feedback-dialog-input" type="radio" name="reason_key" value="<?php echo esc_attr( $reason_key ); ?>" /> <label for="elementor-deactivate-feedback-<?php echo esc_attr( $reason_key ); ?>" class="elementor-deactivate-feedback-dialog-label"><?php echo esc_html( $reason['title'] ); ?></label> <?php if ( ! empty( $reason['input_placeholder'] ) ) : ?> <input class="elementor-feedback-text" type="text" name="reason_<?php echo esc_attr( $reason_key ); ?>" placeholder="<?php echo esc_attr( $reason['input_placeholder'] ); ?>" /> <?php endif; ?> <?php if ( ! empty( $reason['alert'] ) ) : ?> <div class="elementor-feedback-text"><?php echo esc_html( $reason['alert'] ); ?></div> <?php endif; ?> </div> <?php endforeach; ?> </div> </form> </div> <?php } /** * Ajax elementor deactivate feedback. * * Send the user feedback when Elementor is deactivated. * * Fired by `wp_ajax_elementor_deactivate_feedback` action. * * @since 1.0.0 * @access public */ public function ajax_elementor_deactivate_feedback() { $wpnonce = Utils::get_super_global_value( $_POST, '_wpnonce' ); // phpcs:ignore -- Nonce verification is made in `wp_verify_nonce()`. if ( ! wp_verify_nonce( $wpnonce, '_elementor_deactivate_feedback_nonce' ) ) { wp_send_json_error(); } if ( ! current_user_can( 'activate_plugins' ) ) { wp_send_json_error( 'Permission denied' ); } $reason_key = Utils::get_super_global_value( $_POST, 'reason_key' ) ?? ''; $reason_text = Utils::get_super_global_value( $_POST, "reason_{$reason_key}" ) ?? ''; Api::send_feedback( $reason_key, $reason_text ); wp_send_json_success(); } /** * @since 2.3.0 * @access private */ private function is_plugins_screen() { return in_array( get_current_screen()->id, [ 'plugins', 'plugins-network' ] ); } } menu/interfaces/admin-menu-item.php 0000644 00000000445 15252521333 0013336 0 ustar 00 <?php namespace Elementor\Core\Admin\Menu\Interfaces; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } interface Admin_Menu_Item { public function get_capability(); public function get_label(); public function get_parent_slug(); public function is_visible(); } menu/interfaces/admin-menu-item-with-page.php 0000644 00000000377 15252521333 0015225 0 ustar 00 <?php namespace Elementor\Core\Admin\Menu\Interfaces; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } interface Admin_Menu_Item_With_Page extends Admin_Menu_Item { public function get_page_title(); public function render(); } menu/interfaces/admin-menu-item-has-position.php 0000644 00000000314 15252521333 0015744 0 ustar 00 <?php namespace Elementor\Core\Admin\Menu\Interfaces; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } interface Admin_Menu_Item_Has_Position { public function get_position(); } menu/base.php 0000644 00000004034 15252521333 0007135 0 ustar 00 <?php namespace Elementor\Core\Admin\Menu; use Elementor\Core\Base\Base_Object; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } abstract class Base extends Base_Object { private $args; private $submenus = []; abstract protected function get_init_args(); public function __construct() { $this->init_args(); add_action( 'admin_menu', function() { $this->register(); } ); } public function get_args( $arg = null ) { return self::get_items( $this->args, $arg ); } public function add_submenu( $submenu_args ) { $default_submenu_args = [ 'page_title' => '', 'capability' => $this->args['capability'], 'function' => null, 'index' => null, ]; $this->submenus[] = array_merge( $default_submenu_args, $submenu_args ); } protected function register_default_submenus() {} protected function register() { $args = $this->args; add_menu_page( $args['page_title'], $args['menu_title'], $args['capability'], $args['menu_slug'], $args['function'], $args['icon_url'], $args['position'] ); $this->register_default_submenus(); do_action( 'elementor/admin/menu_registered/' . $args['menu_slug'], $this ); usort( $this->submenus, function( $a, $b ) { return $a['index'] - $b['index']; } ); foreach ( $this->submenus as $index => $submenu_item ) { $submenu_args = [ $args['menu_slug'], $submenu_item['page_title'], $submenu_item['menu_title'], $submenu_item['capability'], $submenu_item['menu_slug'], $submenu_item['function'], ]; if ( 0 === $submenu_item['index'] ) { $submenu_args[] = 0; } add_submenu_page( ...$submenu_args ); if ( ! empty( $submenu_item['class'] ) ) { global $submenu; $submenu[ $args['menu_slug'] ][ $index + 1 ][4] = $submenu_item['class']; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited } } } private function init_args() { $default_args = [ 'function' => null, 'icon_url' => null, 'position' => null, ]; $this->args = array_merge( $default_args, $this->get_init_args() ); } } menu/admin-menu-manager.php 0000644 00000005370 15252521333 0011671 0 ustar 00 <?php namespace Elementor\Core\Admin\Menu; use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item; use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item_Has_Position; use Elementor\Core\Admin\Menu\Interfaces\Admin_Menu_Item_With_Page; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Admin_Menu_Manager { /** * @var Admin_Menu_Item[] */ private $items = []; public function register( $item_slug, Admin_Menu_Item $item ) { $this->items[ $item_slug ] = $item; } public function unregister( $item_slug ) { unset( $this->items[ $item_slug ] ); } public function get( $item_slug ) { if ( empty( $this->items[ $item_slug ] ) ) { return null; } return $this->items[ $item_slug ]; } public function get_all() { return $this->items; } public function register_actions() { add_action( 'admin_menu', function () { $this->register_wp_menus(); }, 20 ); add_action( 'admin_head', function () { $this->hide_invisible_menus(); } ); } private function register_wp_menus() { do_action( 'elementor/admin/menu/register', $this ); $hooks = []; foreach ( $this->get_all() as $item_slug => $item ) { $is_top_level = empty( $item->get_parent_slug() ); if ( $is_top_level ) { $hooks[ $item_slug ] = $this->register_top_level_menu( $item_slug, $item ); } else { $hooks[ $item_slug ] = $this->register_sub_menu( $item_slug, $item ); } } do_action( 'elementor/admin/menu/after_register', $this, $hooks ); } private function register_top_level_menu( $item_slug, Admin_Menu_Item $item ) { $has_page = ( $item instanceof Admin_Menu_Item_With_Page ); $has_position = ( $item instanceof Admin_Menu_Item_Has_Position ); $page_title = $has_page ? $item->get_page_title() : ''; $callback = $has_page ? [ $item, 'render' ] : ''; $position = $has_position ? $item->get_position() : null; return add_menu_page( $page_title, $item->get_label(), $item->get_capability(), $item_slug, $callback, '', $position ); } private function register_sub_menu( $item_slug, Admin_Menu_Item $item ) { $has_page = ( $item instanceof Admin_Menu_Item_With_Page ); $page_title = $has_page ? $item->get_page_title() : ''; $callback = $has_page ? [ $item, 'render' ] : ''; return add_submenu_page( $item->get_parent_slug(), $page_title, $item->get_label(), $item->get_capability(), $item_slug, $callback ); } private function hide_invisible_menus() { foreach ( $this->get_all() as $item_slug => $item ) { if ( $item->is_visible() ) { continue; } $is_top_level = empty( $item->get_parent_slug() ); if ( $is_top_level ) { remove_menu_page( $item_slug ); } else { remove_submenu_page( $item->get_parent_slug(), $item_slug ); } } } } menu/main.php 0000644 00000000625 15252521333 0007151 0 ustar 00 <?php namespace Elementor\Core\Admin\Menu; if ( ! defined( 'ABSPATH' ) ) { exit; } class Main extends Base { protected function get_init_args() { return [ 'page_title' => esc_html__( 'Elementor', 'elementor' ), 'menu_title' => esc_html__( 'Elementor', 'elementor' ), 'capability' => 'manage_options', 'menu_slug' => 'elementor', 'function' => null, 'position' => 58.5, ]; } } notices/base-notice.php 0000644 00000001003 15252521333 0011105 0 ustar 00 <?php namespace Elementor\Core\Admin\Notices; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } abstract class Base_Notice { /** * Determine if the notice should be printed or not. * * @return boolean */ abstract public function should_print(); /** * Returns the config of the notice itself. * based on that config the notice will be printed. * * @see \Elementor\Core\Admin\Admin_Notices::admin_notices * * @return array */ abstract public function get_config(); } ui/components/button.php 0000644 00000004575 15252521333 0011406 0 ustar 00 <?php namespace Elementor\Core\Admin\UI\Components; use Elementor\Core\Base\Base_Object; use Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Button extends Base_Object { private $options; /** * @inheritDoc */ public function get_name() { return 'admin-button'; } public function print_button() { $options = $this->get_options(); if ( empty( $options['text'] ) ) { return; } $html_tag = ! empty( $options['url'] ) ? 'a' : 'button'; $before = ''; $icon = ''; $attributes = []; if ( ! empty( $options['icon'] ) ) { $icon = '<i class="' . esc_attr( $options['icon'] ) . '"></i>'; } $classes = $options['classes']; $default_classes = $this->get_default_options( 'classes' ); $classes = array_merge( $classes, $default_classes ); if ( ! empty( $options['type'] ) ) { $classes[] = 'e-button--' . $options['type']; } if ( ! empty( $options['variant'] ) ) { $classes[] = 'e-button--' . $options['variant']; } if ( ! empty( $options['before'] ) ) { $before = '<span>' . wp_kses_post( $options['before'] ) . '</span>'; } if ( ! empty( $options['url'] ) ) { $attributes['href'] = $options['url']; if ( $options['new_tab'] ) { $attributes['target'] = '_blank'; } } $attributes['class'] = $classes; $html = $before . '<' . $html_tag . ' ' . Utils::render_html_attributes( $attributes ) . '>'; $html .= $icon; $html .= '<span>' . sanitize_text_field( $options['text'] ) . '</span>'; $html .= '</' . $html_tag . '>'; echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } /** * @param string $option Optional default is null. * @return array|mixed */ private function get_options( $option = null ) { return $this->get_items( $this->options, $option ); } /** * @param null $option * @return array */ private function get_default_options( $option = null ) { $default_options = [ 'classes' => [ 'e-button' ], 'icon' => '', 'new_tab' => false, 'text' => '', 'type' => '', 'url' => '', 'variant' => '', 'before' => '', ]; if ( null !== $option && -1 !== in_array( $option, $default_options, true ) ) { return $default_options[ $option ]; } return $default_options; } public function __construct( array $options ) { $this->options = $this->merge_properties( $this->get_default_options(), $options ); } } editor-one-menu/menu/legacy-submenu-item.php 0000644 00000003053 15252521333 0015106 0 ustar 00 <?php namespace Elementor\Core\Admin\EditorOneMenu\Menu; use Elementor\Core\Admin\EditorOneMenu\Interfaces\Menu_Item_Third_Level_Interface; use Elementor\Modules\EditorOne\Classes\Menu_Config; if ( ! defined( 'ABSPATH' ) ) { exit; } class Legacy_Submenu_Item implements Menu_Item_Third_Level_Interface { private $submenu_data; private $parent_slug; private $position; public function __construct( array $submenu_data, ?string $parent_slug = null, ?int $position = 100 ) { $this->submenu_data = $submenu_data; $this->parent_slug = $parent_slug ?? Menu_Config::ELEMENTOR_MENU_SLUG; $this->position = $position; } public function get_label(): string { return $this->submenu_data[0] ?? ''; } public function get_capability(): string { return $this->submenu_data[1] ?? Menu_Config::CAPABILITY_MANAGE_OPTIONS; } public function get_slug(): string { return $this->submenu_data[2] ?? ''; } public function get_parent_slug(): string { return $this->parent_slug; } public function is_visible(): bool { return true; } public function get_page_title(): string { return $this->submenu_data[3] ?? $this->get_label(); } public function get_position(): int { return $this->position; } public function get_group_id(): string { return $this->submenu_data[4] ?? Menu_Config::EDITOR_GROUP_ID; } public function get_icon(): string { $item_slug = $this->get_slug(); $icon = Menu_Config::get_attribute_mapping()[ $item_slug ]['icon'] ?? 'admin-generic'; return $icon; } public function has_children(): bool { return false; } } editor-one-menu/menu/abstract-menu-item.php 0000644 00000001604 15252521333 0014733 0 ustar 00 <?php namespace Elementor\Core\Admin\EditorOneMenu\Menu; use Elementor\Core\Admin\EditorOneMenu\Interfaces\Menu_Item_Third_Level_Interface; use Elementor\Modules\EditorOne\Classes\Menu_Config; if ( ! defined( 'ABSPATH' ) ) { exit; } abstract class Abstract_Menu_Item implements Menu_Item_Third_Level_Interface { public function get_capability(): string { return Menu_Config::CAPABILITY_MANAGE_OPTIONS; } public function get_parent_slug(): string { return Menu_Config::ELEMENTOR_MENU_SLUG; } public function is_visible(): bool { return true; } public function get_group_id(): string { return Menu_Config::EDITOR_GROUP_ID; } public function has_children(): bool { return false; } abstract public function get_label(): string; abstract public function get_position(): int; abstract public function get_slug(): string; abstract public function get_icon(): string; } editor-one-menu/menu/legacy-submenu-item-not-mapped.php 0000644 00000002427 15252521333 0017154 0 ustar 00 <?php namespace Elementor\Core\Admin\EditorOneMenu\Menu; use Elementor\Core\Admin\EditorOneMenu\Interfaces\Menu_Item_Interface; use Elementor\Modules\EditorOne\Classes\Menu_Config; if ( ! defined( 'ABSPATH' ) ) { exit; } class Legacy_Submenu_Item_Not_Mapped implements Menu_Item_Interface { private $submenu_data; private $parent_slug; private $position; public function __construct( array $submenu_data, ?string $parent_slug = null, ?int $position = 100 ) { $this->submenu_data = $submenu_data; $this->parent_slug = $parent_slug ?? Menu_Config::ELEMENTOR_MENU_SLUG; $this->position = $position; } public function get_label(): string { return $this->submenu_data[0] ?? ''; } public function get_capability(): string { return $this->submenu_data[1] ?? Menu_Config::CAPABILITY_MANAGE_OPTIONS; } public function get_slug(): string { return $this->submenu_data[2] ?? ''; } public function get_parent_slug(): string { return $this->parent_slug; } public function is_visible(): bool { return true; } public function get_page_title(): string { return $this->submenu_data[3] ?? $this->get_label(); } public function get_position(): int { return $this->position; } public function get_group_id(): string { return Menu_Config::THIRD_PARTY_GROUP_ID; } } editor-one-menu/menu/third-party-pages-menu.php 0000644 00000001752 15252521333 0015544 0 ustar 00 <?php namespace Elementor\Core\Admin\EditorOneMenu\Menu; use Elementor\Core\Admin\EditorOneMenu\Interfaces\Menu_Item_Third_Level_Interface; use Elementor\Modules\EditorOne\Classes\Menu_Config; if ( ! defined( 'ABSPATH' ) ) { exit; } class Third_Party_Pages_Menu implements Menu_Item_Third_Level_Interface { public function get_capability(): string { return Menu_Config::CAPABILITY_EDIT_POSTS; } public function get_parent_slug(): string { return Menu_Config::ELEMENTOR_HOME_MENU_SLUG; } public function is_visible(): bool { return true; } public function get_label(): string { return esc_html__( 'Addons', 'elementor' ); } public function get_position(): int { return 200; } public function get_slug(): string { return 'elementor-third-party-pages'; } public function get_icon(): string { return 'extension'; } public function get_group_id(): string { return Menu_Config::THIRD_PARTY_GROUP_ID; } public function has_children(): bool { return true; } } editor-one-menu/menu/abstract-level4-menu-item.php 0000644 00000001346 15252521333 0016127 0 ustar 00 <?php namespace Elementor\Core\Admin\EditorOneMenu\Menu; use Elementor\Core\Admin\EditorOneMenu\Interfaces\Menu_Item_Interface; use Elementor\Modules\EditorOne\Classes\Menu_Config; if ( ! defined( 'ABSPATH' ) ) { exit; } abstract class Abstract_Level4_Menu_Item implements Menu_Item_Interface { public function get_capability(): string { return Menu_Config::CAPABILITY_MANAGE_OPTIONS; } public function get_parent_slug(): string { return Menu_Config::ELEMENTOR_MENU_SLUG; } public function is_visible(): bool { return true; } abstract public function get_label(): string; abstract public function get_position(): int; abstract public function get_slug(): string; abstract public function get_group_id(): string; } editor-one-menu/menu/editor-one-custom-elements-menu.php 0000644 00000001776 15252521333 0017375 0 ustar 00 <?php namespace Elementor\Core\Admin\EditorOneMenu\Menu; use Elementor\Core\Admin\EditorOneMenu\Interfaces\Menu_Item_Third_Level_Interface; use Elementor\Modules\EditorOne\Classes\Menu_Config; if ( ! defined( 'ABSPATH' ) ) { exit; } class Editor_One_Custom_Elements_Menu implements Menu_Item_Third_Level_Interface { public function get_capability(): string { return Menu_Config::CAPABILITY_MANAGE_OPTIONS; } public function get_parent_slug(): string { return Menu_Config::ELEMENTOR_MENU_SLUG; } public function is_visible(): bool { return true; } public function get_label(): string { return esc_html__( 'Custom Elements', 'elementor' ); } public function get_position(): int { return 80; } public function get_slug(): string { return 'elementor-custom-elements'; } public function get_icon(): string { return 'adjustments'; } public function get_group_id(): string { return Menu_Config::CUSTOM_ELEMENTS_GROUP_ID; } public function has_children(): bool { return true; } } editor-one-menu/interfaces/menu-item-third-level-interface.php 0000644 00000000403 15252521333 0020460 0 ustar 00 <?php namespace Elementor\Core\Admin\EditorOneMenu\Interfaces; if ( ! defined( 'ABSPATH' ) ) { exit; } interface Menu_Item_Third_Level_Interface extends Menu_Item_Interface { public function get_icon(): string; public function has_children(): bool; } editor-one-menu/interfaces/menu-item-interface.php 0000644 00000000652 15252521333 0016251 0 ustar 00 <?php namespace Elementor\Core\Admin\EditorOneMenu\Interfaces; if ( ! defined( 'ABSPATH' ) ) { exit; } interface Menu_Item_Interface { public function get_capability(): string; public function get_label(): string; public function get_parent_slug(): string; public function is_visible(): bool; public function get_position(): int; public function get_slug(): string; public function get_group_id(): string; } editor-one-menu/interfaces/menu-item-with-custom-url-interface.php 0000644 00000000307 15252521333 0021327 0 ustar 00 <?php namespace Elementor\Core\Admin\EditorOneMenu\Interfaces; if ( ! defined( 'ABSPATH' ) ) { exit; } interface Menu_Item_With_Custom_Url_Interface { public function get_menu_url(): string; } editor-one-menu/elementor-one-menu-manager.php 0000644 00000023651 15252521333 0015417 0 ustar 00 <?php namespace Elementor\Core\Admin\EditorOneMenu; use Elementor\Core\Admin\EditorOneMenu\Menu\Editor_One_Custom_Elements_Menu; use Elementor\Core\Admin\EditorOneMenu\Interfaces\Menu_Item_Interface; use Elementor\Modules\EditorOne\Classes\Legacy_Submenu_Interceptor; use Elementor\Modules\EditorOne\Classes\Menu_Config; use Elementor\Modules\EditorOne\Classes\Menu_Data_Provider; use Elementor\Modules\EditorOne\Classes\Slug_Normalizer; use Elementor\Plugin; use Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; } class Elementor_One_Menu_Manager { private Menu_Data_Provider $menu_data_provider; private bool $is_pro_module_enabled = false; private Legacy_Submenu_Interceptor $legacy_submenu_interceptor; public function __construct() { $this->menu_data_provider = Menu_Data_Provider::instance(); $this->legacy_submenu_interceptor = new Legacy_Submenu_Interceptor( $this->menu_data_provider, new Slug_Normalizer() ); $this->register_actions(); } private function register_actions(): void { add_action( 'init', [ $this, 'check_if_pro_module_is_enabled' ] ); add_action( 'admin_menu', [ $this, 'register_elementor_home_submenus' ], 9 ); add_action( 'admin_menu', function () { do_action( 'elementor/editor-one/menu/register', $this->menu_data_provider ); } ); add_action( 'admin_menu', [ $this, 'register_pro_submenus' ], 100 ); add_action( 'admin_menu', [ $this, 'intercept_legacy_submenus' ], 10003 ); add_action( 'admin_menu', [ $this, 'register_flyout_items_as_hidden_submenus' ], 10004 ); add_action( 'admin_menu', [ $this, 'remove_all_submenus_for_edit_posts_users' ], 10005 ); add_action( 'admin_menu', [ $this, 'override_elementor_page_for_edit_posts_users' ], 1006 ); add_filter( 'add_menu_classes', [ $this, 'fix_theme_builder_submenu_url' ] ); add_action( 'admin_head', [ $this, 'hide_flyout_items_from_wp_menu' ] ); add_action( 'admin_head', [ $this, 'hide_legacy_templates_menu' ] ); add_action( 'admin_head', [ $this, 'hide_old_elementor_menu' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_menu_assets' ] ); add_action( 'admin_print_scripts-toplevel_page_elementor', [ $this, 'enqueue_home_screen_on_editor_page' ] ); } public function check_if_pro_module_is_enabled(): void { $this->is_pro_module_enabled = apply_filters( 'elementor/modules/editor-one/is_pro_module_enabled', false ); if ( ! $this->is_pro_module_enabled && Utils::has_pro() ) { $this->menu_data_provider->register_menu( new Editor_One_Custom_Elements_Menu() ); } } public function register_elementor_home_submenus(): void { add_submenu_page( Menu_Config::ELEMENTOR_HOME_MENU_SLUG, esc_html__( 'Editor', 'elementor' ), esc_html__( 'Editor', 'elementor' ), Menu_Config::CAPABILITY_EDIT_POSTS, Menu_Config::ELEMENTOR_MENU_SLUG, [ $this, 'render_editor_page' ], 20 ); do_action( 'elementor/editor-one/menu/register_submenus' ); } /** * TODO: This can be removed in v4.1.0 [ED-22806] */ public function register_pro_submenus(): void { if ( ! $this->is_pro_module_enabled && Utils::has_pro() && class_exists( '\ElementorPro\License\API' ) && \ElementorPro\License\API::is_license_active() ) { add_submenu_page( Menu_Config::ELEMENTOR_HOME_MENU_SLUG, esc_html__( 'Theme Builder', 'elementor' ), esc_html__( 'Theme Builder', 'elementor' ), Menu_Config::CAPABILITY_EDIT_POSTS, 'elementor-theme-builder', '', 70 ); add_submenu_page( Menu_Config::ELEMENTOR_HOME_MENU_SLUG, esc_html__( 'Submissions', 'elementor' ), esc_html__( 'Submissions', 'elementor' ), 'edit_posts', 'e-form-submissions', '', 80 ); } } public function remove_all_submenus_for_edit_posts_users(): void { $user_capabilities = Menu_Data_Provider::get_current_user_capabilities(); if ( ! $user_capabilities['is_edit_posts_user'] ) { return; } global $submenu; if ( empty( $submenu[ Menu_Config::ELEMENTOR_MENU_SLUG ] ) ) { return; } $submenu_items = $submenu[ Menu_Config::ELEMENTOR_MENU_SLUG ]; foreach ( $submenu_items as $index => $submenu_item ) { if ( 0 === $index ) { continue; } $submenu_slug = $submenu_item[2] ?? ''; if ( ! empty( $submenu_slug ) ) { remove_submenu_page( Menu_Config::ELEMENTOR_MENU_SLUG, $submenu_slug ); } } } public function render_editor_page(): void { Plugin::instance()->settings->display_home_screen(); } public function override_elementor_page_for_edit_posts_users(): void { $user_capabilities = Menu_Data_Provider::get_current_user_capabilities(); if ( ! $user_capabilities['is_edit_posts_user'] ) { return; } $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) ?? ''; if ( Menu_Config::ELEMENTOR_MENU_SLUG !== $page ) { return; } $templates_url = admin_url( 'edit.php?post_type=elementor_library&tabs_group=library' ); wp_safe_redirect( $templates_url ); exit; } public function enqueue_home_screen_on_editor_page(): void { $home_module = Plugin::instance()->modules_manager->get_modules( 'home' ); if ( $home_module && method_exists( $home_module, 'enqueue_home_screen_scripts' ) ) { $home_module->enqueue_home_screen_scripts(); } } public function fix_theme_builder_submenu_url( $menu ) { global $submenu; $menu_slugs = [ Menu_Config::ELEMENTOR_HOME_MENU_SLUG ]; foreach ( $menu_slugs as $menu_slug ) { if ( empty( $submenu[ $menu_slug ] ) ) { continue; } foreach ( $submenu[ $menu_slug ] as &$item ) { if ( 'elementor-theme-builder' === $item[2] ) { $item[2] = $this->get_theme_builder_url(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited break; } } } return $menu; } private function get_theme_builder_url(): string { return $this->menu_data_provider->get_theme_builder_url(); } public function hide_legacy_templates_menu(): void { ?> <style type="text/css"> #menu-posts-elementor_library { display: none !important; } </style> <?php } public function hide_old_elementor_menu(): void { $this->remove_elementor_separator(); ?> <style type="text/css"> #toplevel_page_elementor { display: none !important; } </style> <?php } private function remove_elementor_separator(): void { global $menu; foreach ( $menu as $key => $item ) { if ( isset( $item[2] ) && 'separator-elementor' === $item[2] ) { unset( $menu[ $key ] ); break; } } } public function register_flyout_items_as_hidden_submenus(): void { $hooks = []; $this->iterate_all_flyout_items( function( string $item_slug, Menu_Item_Interface $item ) use ( &$hooks ) { $hook = $this->register_hidden_submenu( $item_slug, $item ); if ( $hook ) { $hooks[ $item_slug ] = $hook; } } ); do_action( 'elementor/editor-one/menu/after_register_hidden_submenus', $hooks ); } private function register_hidden_submenu( string $item_slug, Menu_Item_Interface $item ) { $original_parent = $this->get_original_parent_slug( $item ); $parent_slug = $this->resolve_hidden_submenu_parent( $original_parent ); $has_page = method_exists( $item, 'render' ); $page_title = $has_page ? $item->get_page_title() : ''; $callback = $has_page ? [ $item, 'render' ] : ''; $capability = $item->get_capability(); $position = $item->get_position(); return add_submenu_page( $parent_slug, $page_title, $item->get_label(), $capability, $item_slug, $callback, $position ); } private function resolve_hidden_submenu_parent( ?string $parent_slug ): string { $default_parent_slug = Menu_Config::ELEMENTOR_HOME_MENU_SLUG; if ( empty( $parent_slug ) ) { return $default_parent_slug; } $elementor_parent_slugs = [ Menu_Config::EDITOR_GROUP_ID => true, Menu_Config::EDITOR_MENU_SLUG => true, Menu_Config::TEMPLATES_GROUP_ID => true, Menu_Config::LEGACY_TEMPLATES_SLUG => true, Menu_Config::SETTINGS_GROUP_ID => true, Menu_Config::CUSTOM_ELEMENTS_GROUP_ID => true, Menu_Config::SYSTEM_GROUP_ID => true, ]; if ( isset( $elementor_parent_slugs[ $parent_slug ] ) ) { return $default_parent_slug; } return $parent_slug; } private function iterate_all_flyout_items( callable $callback ): void { $level3_items = $this->menu_data_provider->get_level3_items(); $level4_items = $this->menu_data_provider->get_level4_items(); $all_items = array_merge_recursive( $level3_items, $level4_items ); foreach ( $all_items as $group_items ) { foreach ( $group_items as $item_slug => $item ) { $callback( $item_slug, $item ); } } } private function get_original_parent_slug( $item ): ?string { return $item->get_parent_slug(); } public function hide_flyout_items_from_wp_menu(): void { $protected_wp_menu_slugs = [ Menu_Config::EDITOR_MENU_SLUG, 'elementor-theme-builder', 'e-form-submissions', ]; $this->iterate_all_flyout_items( function( string $item_slug, Menu_Item_Interface $item ) use ( $protected_wp_menu_slugs ) { if ( in_array( $item_slug, $protected_wp_menu_slugs, true ) ) { return; } $original_parent = $this->get_original_parent_slug( $item ); $parent_slug = $this->resolve_hidden_submenu_parent( $original_parent ); remove_submenu_page( $parent_slug, $item_slug ); } ); } public function intercept_legacy_submenus(): void { $this->legacy_submenu_interceptor->intercept_all( $this->is_pro_module_enabled ); } public function enqueue_admin_menu_assets(): void { $min_suffix = Utils::is_script_debug() ? '' : '.min'; wp_enqueue_style( 'elementor-admin-menu', ELEMENTOR_ASSETS_URL . 'css/modules/editor-one/admin-menu' . $min_suffix . '.css', [], ELEMENTOR_VERSION ); $config = [ 'editorFlyout' => $this->menu_data_provider->get_third_level_data( Menu_Data_Provider::THIRD_LEVEL_FLYOUT_MENU ), ]; wp_enqueue_script( 'editor-one-menu', ELEMENTOR_ASSETS_URL . 'js/editor-one-menu' . $min_suffix . '.js', [], ELEMENTOR_VERSION, true ); wp_localize_script( 'editor-one-menu', 'editorOneMenuConfig', $config ); } } admin.php 0000644 00000111235 15252521333 0006351 0 ustar 00 <?php namespace Elementor\Core\Admin; use Elementor\Api; use Elementor\Beta_Testers; use Elementor\App\Modules\Onboarding\Module as Onboarding_Module; use Elementor\Core\Base\App; use Elementor\Core\Upgrade\Manager as Upgrade_Manager; use Elementor\Core\Utils\Assets_Config_Provider; use Elementor\Core\Utils\Collection; use Elementor\Modules\FloatingButtons\Module as Floating_Buttons_Module; use Elementor\Plugin; use Elementor\Settings; use Elementor\User; use Elementor\Utils; use Elementor\Core\Utils\Hints; use Elementor\Core\DocumentTypes\Page; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Admin extends App { private $menus = []; /** * Get module name. * * Retrieve the module name. * * @since 2.3.0 * @access public * * @return string Module name. */ public function get_name() { return 'admin'; } /** * Check if current page is an Elementor admin page. * * @param \WP_Screen|null $current_screen Optional. Screen object to check. Defaults to current screen. * * @return bool Whether current page is an Elementor admin page. */ public static function is_elementor_admin_page( $current_screen = null ) { if ( ! $current_screen ) { $current_screen = get_current_screen(); } if ( ! $current_screen ) { return false; } $screen_id = $current_screen->id ?? ''; $post_type = $current_screen->post_type ?? ''; $is_elementor_screen = strpos( $screen_id, 'elementor' ) !== false || strpos( $screen_id, Floating_Buttons_Module::CPT_FLOATING_BUTTONS ) !== false; $is_elementor_post_type = strpos( $post_type, 'elementor' ) !== false || strpos( $post_type, Floating_Buttons_Module::CPT_FLOATING_BUTTONS ) !== false; return $is_elementor_screen || $is_elementor_post_type; } /** * @since 2.2.0 * @access public */ public function maybe_redirect_to_getting_started() { if ( ! get_transient( 'elementor_activation_redirect' ) ) { return; } if ( wp_doing_ajax() ) { return; } delete_transient( 'elementor_activation_redirect' ); if ( is_network_admin() || isset( $_GET['activate-multi'] ) ) { return; } $already_had_onboarding = get_option( Onboarding_Module::ONBOARDING_OPTION ); // Get the latest installation from Elementor's Install log in the DB. $latest_install = key( Upgrade_Manager::get_installs_history() ); if ( ! empty( $latest_install ) ) { $is_new_install = version_compare( $latest_install, '3.6.0-beta', '>=' ); } else { // If `$latest_install` is not set, Elementor was never installed on this site. $is_new_install = true; } if ( $already_had_onboarding || ! $is_new_install ) { return; } wp_safe_redirect( admin_url( 'admin.php?page=elementor-app#onboarding' ) ); exit; } private function register_packages() { $assets_config_provider = ( new Assets_Config_Provider() ) ->set_path_resolver( function ( $name ) { return ELEMENTOR_ASSETS_PATH . "js/packages/{$name}/{$name}.asset.php"; } ); Collection::make( [ 'ui', 'icons', 'query' ] ) ->each( function( $package ) use ( $assets_config_provider ) { $suffix = Utils::is_script_debug() ? '' : '.min'; $config = $assets_config_provider->load( $package )->get( $package ); if ( ! $config ) { return; } wp_register_script( $config['handle'], ELEMENTOR_ASSETS_URL . "js/packages/{$package}/{$package}{$suffix}.js", $config['deps'], ELEMENTOR_VERSION, true ); } ); } /** * Enqueue admin scripts. * * Registers all the admin scripts and enqueues them. * * Fired by `admin_enqueue_scripts` action. * * @since 1.0.0 * @access public */ public function enqueue_scripts() { wp_register_script( 'elementor-admin-modules', $this->get_js_assets_url( 'admin-modules' ), [], ELEMENTOR_VERSION, true ); $this->register_packages(); // Temporary solution for the admin. wp_register_script( 'elementor-ai-admin', $this->get_js_assets_url( 'ai-admin' ), [ 'elementor-common', 'elementor-v2-ui', 'elementor-v2-icons', ], ELEMENTOR_VERSION, true ); wp_register_script( 'elementor-admin', $this->get_js_assets_url( 'admin' ), [ 'elementor-common', 'elementor-admin-modules', ], ELEMENTOR_VERSION, true ); wp_enqueue_script( 'elementor-admin' ); wp_set_script_translations( 'elementor-admin', 'elementor' ); $this->maybe_enqueue_hints(); $this->print_config(); } /** * Enqueue admin styles. * * Registers all the admin styles and enqueues them. * * Fired by `admin_enqueue_scripts` action. * * @since 1.0.0 * @access public */ public function enqueue_styles() { wp_register_style( 'elementor-admin', $this->get_css_assets_url( 'admin' ), [ 'elementor-common', ], ELEMENTOR_VERSION ); wp_enqueue_style( 'elementor-admin' ); // It's for upgrade notice. // TODO: enqueue this just if needed. add_thickbox(); } /** * Print switch mode button. * * Adds a switch button in post edit screen (which has cpt support). To allow * the user to switch from the native WordPress editor to Elementor builder. * * Fired by `edit_form_after_title` action. * * @since 1.0.0 * @access public * * @param \WP_Post $post The current post object. */ public function print_switch_mode_button( $post ) { // Exit if Gutenberg are active. if ( did_action( 'enqueue_block_editor_assets' ) ) { return; } $document = Plugin::$instance->documents->get( $post->ID ); if ( ! $document || ! $document->is_editable_by_current_user() ) { return; } wp_nonce_field( basename( __FILE__ ), '_elementor_edit_mode_nonce' ); ?> <div id="elementor-switch-mode"> <input id="elementor-switch-mode-input" type="hidden" name="_elementor_post_mode" value="<?php echo esc_attr( $document->is_built_with_elementor() ); ?>" /> <button id="elementor-switch-mode-button" type="button" class="button button-primary button-hero"> <span class="elementor-switch-mode-on"> <i class="eicon-arrow-<?php echo ( is_rtl() ) ? 'right' : 'left'; ?>" aria-hidden="true"></i> <?php echo esc_html__( 'Back to WordPress Editor', 'elementor' ); ?> </span> <span class="elementor-switch-mode-off"> <i class="eicon-elementor-square" aria-hidden="true"></i> <?php echo esc_html__( 'Edit with Elementor', 'elementor' ); ?> </span> </button> </div> <div id="elementor-editor"> <a id="elementor-go-to-edit-page-link" href="<?php echo esc_url( $document->get_edit_url() ); ?>"> <div id="elementor-editor-button" class="button button-primary button-hero"> <i class="eicon-elementor-square" aria-hidden="true"></i> <?php echo esc_html__( 'Edit with Elementor', 'elementor' ); ?> </div> <div class="elementor-loader-wrapper"> <div class="elementor-loader"> <div class="elementor-loader-boxes"> <div class="elementor-loader-box"></div> <div class="elementor-loader-box"></div> <div class="elementor-loader-box"></div> <div class="elementor-loader-box"></div> </div> </div> <div class="elementor-loading-title"><?php echo esc_html__( 'Loading', 'elementor' ); ?></div> </div> </a> </div> <?php } /** * Save post. * * Flag the post mode when the post is saved. * * Fired by `save_post` action. * * @since 1.0.0 * @access public * * @param int $post_id Post ID. */ public function save_post( $post_id ) { if ( ! wp_verify_nonce( Utils::get_super_global_value( $_POST, '_elementor_edit_mode_nonce' ), basename( __FILE__ ) ) ) { return; } if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; } Plugin::$instance->documents->get( $post_id )->set_is_built_with_elementor( ! empty( $_POST['_elementor_post_mode'] ) ); } /** * Add Elementor post state. * * Adds a new "Elementor" post state to the post table. * * Fired by `display_post_states` filter. * * @since 1.8.0 * @access public * * @param array $post_states An array of post display states. * @param \WP_Post $post The current post object. * * @return array A filtered array of post display states. */ public function add_elementor_post_state( $post_states, $post ) { $document = Plugin::$instance->documents->get( $post->ID ); if ( $document && $document->is_built_with_elementor() && $document->is_editable_by_current_user() ) { $post_states['elementor'] = esc_html__( 'Elementor', 'elementor' ); } return $post_states; } /** * Body status classes. * * Adds CSS classes to the admin body tag. * * Fired by `admin_body_class` filter. * * @since 1.0.0 * @access public * * @param string $classes Space-separated list of CSS classes. * * @return string Space-separated list of CSS classes. */ public function body_status_classes( $classes ) { global $pagenow; if ( in_array( $pagenow, [ 'post.php', 'post-new.php' ], true ) && Utils::is_post_support() ) { $post = get_post(); $document = Plugin::$instance->documents->get( $post->ID ); $mode_class = $document && $document->is_built_with_elementor() ? 'elementor-editor-active' : 'elementor-editor-inactive'; $classes .= ' ' . $mode_class; } return $classes; } /** * Plugin action links. * * Adds action links to the plugin list table * * Fired by `plugin_action_links` filter. * * @since 1.0.0 * @access public * * @param array $links An array of plugin action links. * * @return array An array of plugin action links. */ public function plugin_action_links( $links ) { $settings_link = sprintf( '<a href="%1$s">%2$s</a>', admin_url( 'admin.php?page=' . Settings::PAGE_ID ), esc_html__( 'Settings', 'elementor' ) ); array_unshift( $links, $settings_link ); $go_pro_text = esc_html__( 'Get Elementor Pro', 'elementor' ); if ( Utils::is_sale_time() ) { $go_pro_text = esc_html__( 'Sale! Upgrade Now', 'elementor' ); } $links['go_pro'] = sprintf( '<a href="%1$s" target="_blank" class="elementor-plugins-gopro">%2$s</a>', 'https://go.elementor.com/go-pro-wp-plugins/', $go_pro_text ); return $links; } /** * Plugin row meta. * * Adds row meta links to the plugin list table * * Fired by `plugin_row_meta` filter. * * @since 1.1.4 * @access public * * @param array $plugin_meta An array of the plugin's metadata, including * the version, author, author URI, and plugin URI. * @param string $plugin_file Path to the plugin file, relative to the plugins * directory. * * @return array An array of plugin row meta links. */ public function plugin_row_meta( $plugin_meta, $plugin_file ) { if ( ELEMENTOR_PLUGIN_BASE === $plugin_file ) { $row_meta = [ 'docs' => '<a href="https://go.elementor.com/docs-admin-plugins/" aria-label="' . esc_attr__( 'View Elementor Documentation', 'elementor' ) . '" target="_blank">' . esc_html__( 'Docs & FAQs', 'elementor' ) . '</a>', 'ideo' => '<a href="https://go.elementor.com/yt-admin-plugins/" aria-label="' . esc_attr__( 'View Elementor Video Tutorials', 'elementor' ) . '" target="_blank">' . esc_html__( 'Video Tutorials', 'elementor' ) . '</a>', ]; $plugin_meta = array_merge( $plugin_meta, $row_meta ); } return $plugin_meta; } /** * Admin footer text. * * Modifies the "Thank you" text displayed in the admin footer. * * Fired by `admin_footer_text` filter. * * @since 1.0.0 * @access public * * @param string $footer_text The content that will be printed. * * @return string The content that will be printed. */ public function admin_footer_text( $footer_text ) { $current_screen = get_current_screen(); $is_elementor_screen = ( $current_screen && false !== strpos( $current_screen->id, 'elementor' ) ); if ( $is_elementor_screen ) { $footer_text = sprintf( /* translators: 1: Elementor, 2: Link to plugin review */ __( 'Enjoyed %1$s? Please leave us a %2$s rating. We really appreciate your support!', 'elementor' ), '<strong>' . esc_html__( 'Elementor', 'elementor' ) . '</strong>', '<a href="https://go.elementor.com/admin-review/" target="_blank">★★★★★</a>' ); } return $footer_text; } /** * Register dashboard widgets. * * Adds a new Elementor widgets to WordPress dashboard. * * Fired by `wp_dashboard_setup` action. * * @since 1.9.0 * @access public */ public function register_dashboard_widgets() { wp_add_dashboard_widget( 'e-dashboard-overview', esc_html__( 'Elementor Overview', 'elementor' ), [ $this, 'elementor_dashboard_overview_widget' ] ); // Move our widget to top. global $wp_meta_boxes; $dashboard = $wp_meta_boxes['dashboard']['normal']['core']; $ours = [ 'e-dashboard-overview' => $dashboard['e-dashboard-overview'], ]; $wp_meta_boxes['dashboard']['normal']['core'] = array_merge( $ours, $dashboard ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited } /** * Displays the Elementor dashboard widget. * * Fired by `wp_add_dashboard_widget` function. * * @since 1.9.0 * @access public */ public function elementor_dashboard_overview_widget() { ?> <div class="e-dashboard-overview e-dashboard-widget"> <?php self::elementor_dashboard_overview_header(); self::elementor_dashboard_overview_recently_edited(); self::elementor_dashboard_overview_news_updates(); self::elementor_dashboard_overview_footer(); ?> </div> <?php } /** * Displays the Elementor dashboard widget - header section. * Fired by `elementor_dashboard_overview_widget` function. * * @param bool $show_versions * @param bool $is_create_post_enabled * * @return void * @since 3.12.0 */ public static function elementor_dashboard_overview_header( bool $show_versions = true, bool $is_create_post_enabled = true ) { if ( User::is_current_user_can_edit_post_type( 'page' ) ) { $create_new_label = esc_html__( 'Create New Page', 'elementor' ); $create_new_post_type = 'page'; } elseif ( User::is_current_user_can_edit_post_type( 'post' ) ) { $create_new_label = esc_html__( 'Create New Post', 'elementor' ); $create_new_post_type = 'post'; } ?> <div class="e-overview__header"> <?php if ( $show_versions ) { ?> <div class="e-overview__logo"> <div class="e-logo-wrapper"><i class="eicon-elementor-circle"></i></div> </div> <div class="e-overview__versions"> <span class="e-overview__version"><?php echo esc_html__( 'Elementor', 'elementor' ); ?> v<?php echo ELEMENTOR_VERSION; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span> <?php /** * Elementor dashboard widget after the version. * Fires after Elementor version display in the dashboard widget. * * @since 1.9.0 */ do_action( 'elementor/admin/dashboard_overview_widget/after_version' ); ?> </div> <?php } ?> <?php if ( ! empty( $create_new_post_type ) && $is_create_post_enabled ) { ?> <div class="e-overview__create"> <a href="<?php echo esc_url( Plugin::$instance->documents->get_create_new_post_url( $create_new_post_type ) ); ?>" class="button"><span aria-hidden="true" class="dashicons dashicons-plus"></span> <?php echo esc_html( $create_new_label ); ?></a> </div> <?php } ?> </div> <?php } /** * Displays the Elementor dashboard widget - recently edited section. * Fired by `elementor_dashboard_overview_widget` function. * * @param array $args * @param bool $show_heading * * @return void * @since 3.12.0 */ public static function elementor_dashboard_overview_recently_edited( array $args = [], bool $show_heading = true ) { $recently_edited_query = Utils::get_recently_edited_posts_query( $args ); if ( $recently_edited_query->have_posts() ) { ?> <div class="e-overview__recently-edited"> <?php if ( $show_heading ) { ?> <h3 class="e-heading e-divider_bottom"><?php echo esc_html__( 'Recently Edited', 'elementor' ); ?></h3> <?php } ?> <ul class="e-overview__posts"> <?php while ( $recently_edited_query->have_posts() ) { $recently_edited_query->the_post(); $document = Plugin::$instance->documents->get( get_the_ID() ); $date = date_i18n( _x( 'M jS', 'Dashboard Overview Widget Recently Date', 'elementor' ), get_the_modified_time( 'U' ) ); ?> <li class="e-overview__post"> <a href="<?php echo esc_url( $document->get_edit_url() ); ?>" class="e-overview__post-link"><?php echo esc_html( get_the_title() ); ?> <span class="dashicons dashicons-edit"></span></a> <span><?php echo $date; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>, <?php the_modified_time(); ?></span> </li> <?php } ?> </ul> </div> <?php } } /** * Displays the Elementor dashboard widget - news and updates section. * Fired by `elementor_dashboard_overview_widget` function. * * @param int $limit_feed * @param bool $show_heading * * @return void * @since 3.12.0 * @access public */ public static function elementor_dashboard_overview_news_updates( int $limit_feed = 0, bool $show_heading = true ) { $elementor_feed = Api::get_feed_data(); if ( $limit_feed > 0 ) { $elementor_feed = array_slice( $elementor_feed, 0, $limit_feed ); } if ( ! empty( $elementor_feed ) ) { ?> <div class="e-overview__feed"> <?php if ( $show_heading ) { ?> <h3 class="e-heading e-divider_bottom"><?php echo esc_html__( 'News & Updates', 'elementor' ); ?></h3> <?php } ?> <ul class="e-overview__posts"> <?php foreach ( $elementor_feed as $feed_item ) { ?> <li class="e-overview__post"> <a href="<?php echo esc_url( $feed_item['url'] ); ?>" class="e-overview__post-link" target="_blank"> <?php if ( ! empty( $feed_item['badge'] ) ) { ?> <span class="e-overview__badge"><?php echo esc_html( $feed_item['badge'] ); ?></span> <?php } ?> <?php echo esc_html( $feed_item['title'] ); ?> </a> <p class="e-overview__post-description"><?php echo esc_html( $feed_item['excerpt'] ); ?></p> </li> <?php } ?> </ul> </div> <?php } } /** * Displays the Elementor dashboard widget - footer section. * Fired by `elementor_dashboard_overview_widget` function. * * @since 3.12.0 */ public static function elementor_dashboard_overview_footer() { ?> <div class="e-overview__footer e-divider_top"> <ul> <?php foreach ( self::static_get_dashboard_overview_widget_footer_actions() as $action_id => $action ) { ?> <li class="e-overview__<?php echo esc_attr( $action_id ); ?>"> <a href="<?php echo esc_url( $action['link'] ); ?>" target="_blank"><?php echo esc_html( $action['title'] ); ?> <span class="screen-reader-text"><?php echo esc_html__( '(opens in a new window)', 'elementor' ); ?></span> <span aria-hidden="true" class="dashicons dashicons-external"></span></a> </li> <?php } ?> </ul> </div> <?php } /** * Get elementor dashboard overview widget footer actions. * * Retrieves the footer action links displayed in elementor dashboard widget. * * @since 3.12.0 * @access public */ public static function static_get_dashboard_overview_widget_footer_actions() { $base_actions = [ 'blog' => [ 'title' => esc_html__( 'Blog', 'elementor' ), 'link' => 'https://go.elementor.com/overview-widget-blog/', ], 'help' => [ 'title' => esc_html__( 'Help', 'elementor' ), 'link' => 'https://go.elementor.com/overview-widget-docs/', ], ]; $additions_actions = []; $additions_actions['ai'] = [ 'title' => esc_html__( 'Build Smart with AI', 'elementor' ), 'link' => 'https://go.elementor.com/overview-widget-ai/', ]; $additions_actions['go-pro'] = [ 'title' => esc_html__( 'Upgrade', 'elementor' ), 'link' => 'https://go.elementor.com/go-pro-wp-overview-widget/', ]; /** * Dashboard widget footer actions. * * Filters the additions actions displayed in Elementor dashboard widget. * * Developers can add new action links to Elementor dashboard widget * footer using this filter. * * @since 1.9.0 * * @param array $additions_actions Elementor dashboard widget footer actions. */ $additions_actions = apply_filters( 'elementor/admin/dashboard_overview_widget/footer_actions', $additions_actions ); $actions = $base_actions + $additions_actions; return $actions; } /** * Get elementor dashboard overview widget footer actions. * * Retrieves the footer action links displayed in elementor dashboard widget. * * @since 1.9.0 * @access private */ private function get_dashboard_overview_widget_footer_actions() { return self::static_get_dashboard_overview_widget_footer_actions(); } /** * Admin action new post. * * When a new post action is fired the title is set to 'Elementor' and the post ID. * * Fired by `admin_action_elementor_new_post` action. * * @since 1.9.0 * @access public */ public function admin_action_new_post() { check_admin_referer( 'elementor_action_new_post' ); $post_type = Utils::get_super_global_value( $_GET, 'post_type' ) ?? 'post'; if ( ! User::is_current_user_can_edit_post_type( $post_type ) ) { return; } if ( empty( $_GET['template_type'] ) ) { $type = 'post'; } else { $type = sanitize_text_field( wp_unslash( $_GET['template_type'] ) ); } $post_data = Utils::get_super_global_value( $_GET, 'post_data' ) ?? []; $post_data = $this->filter_post_data( $post_data ); /** * Create new post meta data. * * Filters the meta data of any new post created. * * @since 2.0.0 * * @param array $meta Post meta data. */ $meta = []; if ( isset( $_GET['meta'] ) && is_array( $_GET['meta'] ) ) { $meta = array_map( 'sanitize_text_field', wp_unslash( $_GET['meta'] ) ); } $meta = apply_filters( 'elementor/admin/create_new_post/meta', $meta ); $post_data['post_type'] = $post_type; $document = Plugin::$instance->documents->create( $type, $post_data, $meta ); if ( is_wp_error( $document ) ) { wp_die( $document ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } wp_safe_redirect( $document->get_edit_url() ); die; } public function admin_action_site_settings_redirect() { check_admin_referer( 'elementor_action_site_settings_redirect' ); if ( ! current_user_can( 'edit_theme_options' ) ) { wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'elementor' ) ); } $active_tab = filter_input( INPUT_GET, 'active-tab', FILTER_SANITIZE_ENCODED ); $site_settings_url_config = Page::get_site_settings_url_config( $active_tab ); if ( empty( $site_settings_url_config['url'] ) ) { wp_die( esc_html__( 'Unable to create or access Site Settings page.', 'elementor' ) ); } wp_safe_redirect( $site_settings_url_config['url'] ); die; } /** * Admin action edit website. * * Redirects to the homepage edit URL if it exists and is built with Elementor, * otherwise redirects to create a new page. * * Fired by `admin_action_elementor_edit_website` action. * * @since 3.x.x * @access public */ public function admin_action_edit_website_redirect() { check_admin_referer( 'elementor_action_edit_website' ); if ( ! User::is_current_user_can_edit_post_type( 'page' ) ) { wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'elementor' ) ); } $homepage_id = $this->get_homepage_id(); $edit_url = $this->get_edit_website_url( $homepage_id ); wp_safe_redirect( $edit_url ); die; } private function get_homepage_id(): ?int { if ( get_option( 'show_on_front' ) !== 'page' ) { return null; } $homepage_id = get_option( 'page_on_front' ); return $homepage_id ? (int) $homepage_id : null; } private function get_edit_website_url( ?int $homepage_id ): string { if ( ! $homepage_id ) { return Plugin::$instance->documents->get_create_new_post_url( 'page' ); } $document = Plugin::$instance->documents->get( $homepage_id ); if ( ! $document || ! $document->is_built_with_elementor() ) { return Plugin::$instance->documents->get_create_new_post_url( 'page' ); } return $document->get_edit_url(); } private function get_allowed_fields_for_role() { $allowed_fields = [ 'post_title', 'post_content', 'post_excerpt', 'post_category', 'post_type', 'tags_input', ]; if ( current_user_can( 'publish_posts' ) ) { $allowed_fields[] = 'post_status'; } if ( current_user_can( 'edit_others_posts' ) ) { $allowed_fields[] = 'post_author'; } return $allowed_fields; } private function filter_post_data( $post_data ) { $allowed_fields = $this->get_allowed_fields_for_role(); return array_filter( $post_data, function( $key ) use ( $allowed_fields ) { return in_array( $key, $allowed_fields, true ); }, ARRAY_FILTER_USE_KEY ); } /** * @since 2.3.0 * @access public */ public function add_new_template_template() { Plugin::$instance->common->add_template( ELEMENTOR_PATH . 'includes/admin-templates/new-template.php' ); } public function add_new_floating_elements_template() { Plugin::$instance->common->add_template( ELEMENTOR_PATH . 'includes/admin-templates/new-floating-elements.php' ); } public function enqueue_new_floating_elements_scripts() { $suffix = Utils::is_script_debug() ? '' : '.min'; wp_enqueue_script( 'elementor-floating-elements-modal', ELEMENTOR_ASSETS_URL . 'js/floating-elements-modal' . $suffix . '.js', [], ELEMENTOR_VERSION, true ); wp_set_script_translations( 'elementor-floating-elements-modal', 'elementor' ); } /** * @access public */ public function enqueue_new_template_scripts() { $suffix = Utils::is_script_debug() ? '' : '.min'; wp_enqueue_script( 'elementor-new-template', ELEMENTOR_ASSETS_URL . 'js/new-template' . $suffix . '.js', [], ELEMENTOR_VERSION, true ); wp_set_script_translations( 'elementor-new-template', 'elementor' ); } /** * @since 2.6.0 * @access public */ public function add_beta_tester_template() { Plugin::$instance->common->add_template( ELEMENTOR_PATH . 'includes/admin-templates/beta-tester.php' ); } /** * @access public */ public function enqueue_beta_tester_scripts() { $suffix = Utils::is_script_debug() ? '' : '.min'; wp_enqueue_script( 'elementor-beta-tester', ELEMENTOR_ASSETS_URL . 'js/beta-tester' . $suffix . '.js', [], ELEMENTOR_VERSION, true ); wp_set_script_translations( 'elementor-beta-tester', 'elementor' ); } public function init_floating_elements() { $screens = [ 'elementor_library_page_e-floating-buttons' => true, 'edit-e-floating-buttons' => true, ]; if ( ! isset( $screens[ get_current_screen()->id ] ) ) { return; } add_action( 'admin_head', [ $this, 'add_new_floating_elements_template' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_new_floating_elements_scripts' ] ); } /** * @access public */ public function init_new_template() { if ( 'edit-elementor_library' !== get_current_screen()->id ) { return; } // Allow plugins to add their templates on admin_head. add_action( 'admin_head', [ $this, 'add_new_template_template' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_new_template_scripts' ] ); } public function version_update_warning( $current_version, $new_version ) { $current_version_minor_part = explode( '.', $current_version )[1]; $new_version_minor_part = explode( '.', $new_version )[1]; if ( $current_version_minor_part === $new_version_minor_part ) { return; } ?> <hr class="e-major-update-warning__separator" /> <div class="e-major-update-warning"> <div class="e-major-update-warning__icon"> <i class="eicon-info-circle"></i> </div> <div> <div class="e-major-update-warning__title"> <?php echo esc_html__( 'Heads up, Please backup before upgrade!', 'elementor' ); ?> </div> <div class="e-major-update-warning__message"> <?php printf( /* translators: %1$s Link open tag, %2$s: Link close tag. */ esc_html__( 'The latest update includes some substantial changes across different areas of the plugin. We highly recommend you %1$sbackup your site before upgrading%2$s, and make sure you first update in a staging environment', 'elementor' ), '<a href="https://go.elementor.com/wp-dash-update-backup/">', '</a>' ); ?> </div> </div> </div> <?php } /** * @access public */ public function init_beta_tester( $current_screen ) { if ( ( 'toplevel_page_elementor' === $current_screen->base ) || 'elementor_page_elementor-tools' === $current_screen->id ) { add_action( 'admin_head', [ $this, 'add_beta_tester_template' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_beta_tester_scripts' ] ); } } /** * Admin constructor. * * Initializing Elementor in WordPress admin. * * @since 1.0.0 * @access public */ public function __construct() { Plugin::$instance->init_common(); $this->add_component( 'feedback', new Feedback() ); $this->add_component( 'admin-notices', new Admin_Notices() ); add_action( 'admin_init', [ $this, 'maybe_redirect_to_getting_started' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_styles' ] ); add_action( 'edit_form_after_title', [ $this, 'print_switch_mode_button' ] ); add_action( 'save_post', [ $this, 'save_post' ] ); add_filter( 'display_post_states', [ $this, 'add_elementor_post_state' ], 10, 2 ); add_filter( 'plugin_action_links_' . ELEMENTOR_PLUGIN_BASE, [ $this, 'plugin_action_links' ] ); add_filter( 'plugin_row_meta', [ $this, 'plugin_row_meta' ], 10, 2 ); add_filter( 'admin_body_class', [ $this, 'body_status_classes' ] ); add_filter( 'admin_footer_text', [ $this, 'admin_footer_text' ] ); // Register Dashboard Widgets. add_action( 'wp_dashboard_setup', [ $this, 'register_dashboard_widgets' ] ); // Admin Actions add_action( 'admin_action_elementor_new_post', [ $this, 'admin_action_new_post' ] ); add_action( 'admin_action_elementor_site_settings_redirect', [ $this, 'admin_action_site_settings_redirect' ] ); add_action( 'admin_action_elementor_edit_website_redirect', [ $this, 'admin_action_edit_website_redirect' ] ); add_action( 'current_screen', [ $this, 'init_new_template' ] ); add_action( 'current_screen', [ $this, 'init_floating_elements' ] ); add_action( 'current_screen', [ $this, 'init_beta_tester' ] ); add_action( 'in_plugin_update_message-' . ELEMENTOR_PLUGIN_BASE, function( $plugin_data ) { $this->version_update_warning( ELEMENTOR_VERSION, $plugin_data['new_version'] ); } ); add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_hints' ] ); } /** * @since 2.3.0 * @access protected */ protected function get_init_settings() { $beta_tester_email = get_user_meta( get_current_user_id(), User::BETA_TESTER_META_KEY, true ); $elementor_beta = get_option( 'elementor_beta', 'no' ); $all_introductions = User::get_introduction_meta(); $beta_tester_signup_dismissed = array_key_exists( Beta_Testers::BETA_TESTER_SIGNUP, $all_introductions ); $settings = [ 'home_url' => home_url(), 'settings_url' => Settings::get_url(), 'user' => [ 'introduction' => User::get_introduction_meta(), 'restrictions' => Plugin::$instance->role_manager->get_user_restrictions_array(), 'is_administrator' => current_user_can( 'manage_options' ), ], 'beta_tester' => [ 'beta_tester_signup' => Beta_Testers::BETA_TESTER_SIGNUP, 'has_email' => $beta_tester_email, 'option_enabled' => 'no' !== $elementor_beta, 'signup_dismissed' => $beta_tester_signup_dismissed, ], 'experiments' => $this->get_experiments(), ]; /** * Localize settings. * * Filters the initial localize settings in the admin. * * WordPress has it's own way to pass localized data from PHP (backend) to * JS (frontend). Elementor uses this method to pass localize data in the * admin. This hook can be used to add more localized settings in addition * to the initial Elementor settings. * * @since 2.3.0 * * @param array $settings Initial localize settings. */ $settings = apply_filters( 'elementor/admin/localize_settings', $settings ); return $settings; } private function get_experiments() { return ( new Collection( Plugin::$instance->experiments->get_features() ) ) ->map( function ( $experiment_data ) { $dependencies = $experiment_data['dependencies'] ?? []; $dependencies = ( new Collection( $dependencies ) ) ->map( function ( $dependency ) { return $dependency->get_name(); } )->all(); return [ 'name' => $experiment_data['name'], 'title' => $experiment_data['title'] ?? $experiment_data['name'], 'state' => $experiment_data['state'], 'default' => $experiment_data['default'], 'dependencies' => $dependencies, 'messages' => $experiment_data['messages'] ?? [], ]; } )->all(); } private function maybe_enqueue_hints() { $plugin_slug = 'image-optimization'; if ( ! Hints::should_display_hint( $plugin_slug ) ) { return; } wp_register_script( 'media-hints', $this->get_js_assets_url( 'media-hints' ), [], ELEMENTOR_VERSION, true ); $one_subscription = Hints::is_plugin_connected_to_one_subscription(); $is_installed = Hints::is_plugin_installed( $plugin_slug ); $is_active = Hints::is_plugin_active( $plugin_slug ); if ( $is_active ) { return; } if ( $one_subscription ) { if ( ! $is_installed ) { $description = esc_html__( 'Automatically optimize images to improve site speed and performance. Included with your ONE subscription.', 'elementor' ); $button_text = esc_html__( 'Install now', 'elementor' ); $button_url = Hints::get_plugin_install_url( $plugin_slug ); } elseif ( ! $is_active ) { $description = esc_html__( 'Image Optimization is installed and included in your ONE subscription. Activate it to optimize images and improve site performance.', 'elementor' ); $button_text = esc_html__( 'Activate now', 'elementor' ); $button_url = Hints::get_plugin_activate_url( $plugin_slug ); } } else { $description = esc_html__( 'Optimize your images to enhance site performance by using Image Optimization.', 'elementor' ); if ( ! $is_installed ) { $button_text = esc_html__( 'Install now', 'elementor' ); $button_url = Hints::get_plugin_install_url( $plugin_slug ); } elseif ( ! $is_active ) { $button_text = esc_html__( 'Activate now', 'elementor' ); $button_url = Hints::get_plugin_activate_url( $plugin_slug ); } } $dismissible = 'image_optimizer_hint'; $title = esc_html__( 'Speed up your website with Image Optimization', 'elementor' ); $content = sprintf( "<strong>%1\$s</strong><br>%2\$s <a class='e-btn-1' href='%3\$s' target='_blank'>%4\$s</a>!", $title, $description, $button_url, $button_text ); wp_localize_script( 'media-hints', 'elementorAdminHints', [ 'mediaHint' => [ 'display' => true, 'type' => 'info', 'content' => $content, 'icon' => true, 'dismissible' => $dismissible, 'dismiss' => esc_attr__( 'Dismiss this notice.', 'elementor' ), 'button_event' => $dismissible, 'button_data' => base64_encode( wp_json_encode( [ 'action_url' => $button_url, ] ), ), ], ] ); wp_enqueue_script( 'media-hints' ); } public function register_ajax_hints( $ajax_manager ) { $ajax_manager->register_ajax_action( 'elementor_image_optimization_campaign', [ $this, 'ajax_set_image_optimization_campaign' ] ); $ajax_manager->register_ajax_action( 'elementor_core_site_mailer_campaign', [ $this, 'ajax_site_mailer_campaign' ] ); $ajax_manager->register_ajax_action( 'elementor_core_ally_campaign', [ $this, 'ajax_ally_campaign' ] ); } public function ajax_ally_campaign( $request ) { if ( ! current_user_can( 'install_plugins' ) ) { return; } $campaign_data = [ 'campaign' => sanitize_key( $request['campaign'] ?? '' ), 'source' => sanitize_key( $request['source'] ?? '' ), 'medium' => sanitize_key( $request['medium'] ?? '' ), ]; set_transient( 'elementor_ea11y_campaign', $campaign_data, 30 * DAY_IN_SECONDS ); } public function ajax_set_image_optimization_campaign( $request ) { if ( ! current_user_can( 'install_plugins' ) ) { return; } $campaign_data = [ 'campaign' => sanitize_key( $request['campaign'] ?? '' ), 'source' => sanitize_key( $request['source'] ?? '' ), 'medium' => sanitize_key( $request['medium'] ?? '' ), ]; set_transient( 'elementor_image_optimization_campaign', $campaign_data, 30 * DAY_IN_SECONDS ); } public function ajax_site_mailer_campaign( $request ) { if ( ! current_user_can( 'install_plugins' ) ) { return; } $campaign_data = [ 'campaign' => sanitize_key( $request['campaign'] ?? '' ), 'source' => sanitize_key( $request['source'] ?? '' ), 'medium' => sanitize_key( $request['medium'] ?? '' ), ]; set_transient( 'elementor_site_mailer_campaign', $campaign_data, 30 * DAY_IN_SECONDS ); } }
dvadf
dvadf
| ver. 1.4 |
Github
|
.
| PHP 8.2.33 | Generation time: 0.01 |
proxy
|
phpinfo
|
Settings