| @@ -2,17 +2,19 @@ | ||
| 2 | 2 | |
| 3 | 3 | namespace Elementor\Modules\Checklist; |
| 4 | 4 | |
| 5 | 5 | use Elementor\Core\Base\Module as BaseModule; |
| 6 | -use Elementor\Modules\ElementorCounter\Module as Elementor_Counter; | |
| 6 | +use Elementor\Core\Experiments\Manager; | |
| 7 | +use Elementor\Core\Upgrade\Manager as Upgrade_Manager; | |
| 8 | +use Elementor\Core\Settings\Manager as SettingsManager; | |
| 7 | 9 | use Elementor\Core\Isolation\Wordpress_Adapter; |
| 8 | 10 | use Elementor\Core\Isolation\Wordpress_Adapter_Interface; |
| 9 | -use Elementor\Core\Isolation\Elementor_Adapter; | |
| 10 | -use Elementor\Core\Isolation\Elementor_Adapter_Interface; | |
| 11 | -use Elementor\Core\Isolation\Elementor_Counter_Adapter_Interface; | |
| 11 | +use Elementor\Core\Isolation\Kit_Adapter; | |
| 12 | +use Elementor\Core\Isolation\Kit_Adapter_Interface; | |
| 12 | 13 | use Elementor\Plugin; |
| 13 | 14 | use Elementor\Utils; |
| 14 | 15 | use Elementor\Modules\Checklist\Data\Controller; |
| 16 | +use Elementor\Modules\EditorAppBar\Module as AppBarModule; | |
| 15 | 17 | |
| 16 | 18 | if ( ! defined( 'ABSPATH' ) ) { |
| 17 | 19 | exit; // Exit if accessed directly. |
| 18 | 20 | } |
| @@ -17,40 +19,43 @@ | ||
| 17 | 19 | exit; // Exit if accessed directly. |
| 18 | 20 | } |
| 19 | 21 | |
| 20 | 22 | class Module extends BaseModule implements Checklist_Module_Interface { |
| 23 | + const EXPERIMENT_ID = 'launchpad-checklist'; | |
| 21 | 24 | const DB_OPTION_KEY = 'elementor_checklist'; |
| 22 | 25 | const VISIBILITY_SWITCH_ID = 'show_launchpad_checklist'; |
| 23 | 26 | const FIRST_CLOSED_CHECKLIST_IN_EDITOR = 'first_closed_checklist_in_editor'; |
| 24 | 27 | const LAST_OPENED_TIMESTAMP = 'last_opened_timestamp'; |
| 25 | - const SHOULD_OPEN_IN_EDITOR = 'should_open_in_editor'; | |
| 26 | 28 | const IS_POPUP_MINIMIZED_KEY = 'is_popup_minimized'; |
| 29 | + const EDITOR_VISIT_COUNT = 'editor_visit_count'; | |
| 27 | 30 | |
| 28 | 31 | private Steps_Manager $steps_manager; |
| 29 | 32 | private Wordpress_Adapter_Interface $wordpress_adapter; |
| 30 | - private Elementor_Adapter_Interface $elementor_adapter; | |
| 31 | - private Elementor_Counter_Adapter_Interface $counter_adapter; | |
| 33 | + private Kit_Adapter_Interface $kit_adapter; | |
| 32 | 34 | private $user_progress = null; |
| 33 | 35 | |
| 34 | 36 | /** |
| 35 | 37 | * @param ?Wordpress_Adapter_Interface $wordpress_adapter |
| 36 | - * @param ?Elementor_Adapter_Interface $elementor_adapter | |
| 38 | + * @param ?Kit_Adapter_Interface $kit_adapter | |
| 37 | 39 | * |
| 38 | 40 | * @return void |
| 39 | 41 | */ |
| 40 | - public function __construct( | |
| 41 | - ?Wordpress_Adapter_Interface $wordpress_adapter = null, | |
| 42 | - ?Elementor_Adapter_Interface $elementor_adapter = null | |
| 43 | - ) { | |
| 42 | + public function __construct( ?Wordpress_Adapter_Interface $wordpress_adapter = null, ?Kit_Adapter_Interface $kit_adapter = null ) { | |
| 44 | 43 | $this->wordpress_adapter = $wordpress_adapter ?? new Wordpress_Adapter(); |
| 45 | - $this->elementor_adapter = $elementor_adapter ?? new Elementor_Adapter(); | |
| 44 | + $this->kit_adapter = $kit_adapter ?? new Kit_Adapter(); | |
| 45 | + parent::__construct(); | |
| 46 | 46 | |
| 47 | - parent::__construct(); | |
| 47 | + $this->register_experiment(); | |
| 48 | 48 | $this->init_user_progress(); |
| 49 | 49 | |
| 50 | + if ( ! $this->is_experiment_active() ) { | |
| 51 | + return; | |
| 52 | + } | |
| 53 | + | |
| 54 | + add_action( 'elementor/editor/init', [ $this, 'monitor_editor_visits' ] ); | |
| 55 | + | |
| 50 | 56 | Plugin::$instance->data_manager_v2->register_controller( new Controller() ); |
| 51 | 57 | $this->user_progress = $this->user_progress ?? $this->get_user_progress_from_db(); |
| 52 | - $this->handle_checklist_visibility_with_kit(); | |
| 53 | 58 | $this->steps_manager = new Steps_Manager( $this ); |
| 54 | 59 | |
| 55 | 60 | if ( ! current_user_can( 'manage_options' ) ) { |
| 56 | 61 | return; |
| @@ -63,13 +68,22 @@ | ||
| 63 | 68 | * Get the module name. |
| 64 | 69 | * |
| 65 | 70 | * @return string |
| 66 | 71 | */ |
| 67 | - public function get_name(): string { | |
| 72 | + public function get_name() : string { | |
| 68 | 73 | return 'e-checklist'; |
| 69 | 74 | } |
| 70 | 75 | |
| 71 | 76 | /** |
| 77 | + * Checks if the experiment is active | |
| 78 | + * | |
| 79 | + * @return bool | |
| 80 | + */ | |
| 81 | + public function is_experiment_active() : bool { | |
| 82 | + return Plugin::$instance->experiments->is_feature_active( self::EXPERIMENT_ID ); | |
| 83 | + } | |
| 84 | + | |
| 85 | + /** | |
| 72 | 86 | * Gets user's progress from db |
| 73 | 87 | * |
| 74 | 88 | * @return array { |
| 75 | 89 | * @type bool $is_hidden |
| @@ -82,18 +96,13 @@ | ||
| 82 | 96 | * } |
| 83 | 97 | * } |
| 84 | 98 | * } |
| 85 | 99 | */ |
| 86 | - public function get_user_progress_from_db(): array { | |
| 87 | - $db_progress = json_decode( $this->wordpress_adapter->get_option( self::DB_OPTION_KEY ), true ); | |
| 88 | - $db_progress = is_array( $db_progress ) ? $db_progress : []; | |
| 89 | - | |
| 90 | - $progress = array_merge( $this->get_default_user_progress(), $db_progress ); | |
| 91 | - | |
| 92 | - $editor_visit_count = $this->elementor_adapter->get_count( Elementor_Counter::EDITOR_COUNTER_KEY ); | |
| 93 | - $progress[ self::SHOULD_OPEN_IN_EDITOR ] = 2 === $editor_visit_count && ! $progress[ self::LAST_OPENED_TIMESTAMP ]; | |
| 94 | - | |
| 95 | - return $progress; | |
| 100 | + public function get_user_progress_from_db() : array { | |
| 101 | + return array_merge( | |
| 102 | + $this->get_default_user_progress(), | |
| 103 | + json_decode( $this->wordpress_adapter->get_option( self::DB_OPTION_KEY ), true ) | |
| 104 | + ); | |
| 96 | 105 | } |
| 97 | 106 | |
| 98 | 107 | /** |
| 99 | 108 | * Using the step's ID, get the progress of the step should it exist |
| @@ -104,9 +113,9 @@ | ||
| 104 | 113 | * @type bool $is_marked_completed |
| 105 | 114 | * @type bool $is_completed |
| 106 | 115 | * } |
| 107 | 116 | */ |
| 108 | - public function get_step_progress( $step_id ): ?array { | |
| 117 | + public function get_step_progress( $step_id ) : ?array { | |
| 109 | 118 | return $this->user_progress['steps'][ $step_id ] ?? null; |
| 110 | 119 | } |
| 111 | 120 | |
| 112 | 121 | /** |
| @@ -116,37 +125,34 @@ | ||
| 116 | 125 | * @param $step_progress |
| 117 | 126 | * |
| 118 | 127 | * @return void |
| 119 | 128 | */ |
| 120 | - public function set_step_progress( $step_id, $step_progress ): void { | |
| 129 | + public function set_step_progress( $step_id, $step_progress ) : void { | |
| 121 | 130 | $this->user_progress['steps'][ $step_id ] = $step_progress; |
| 122 | 131 | $this->update_user_progress_in_db(); |
| 123 | 132 | } |
| 124 | 133 | |
| 125 | - public function update_user_progress( $new_data ): void { | |
| 134 | + public function update_user_progress( $new_data ) : void { | |
| 126 | 135 | $allowed_properties = [ |
| 127 | 136 | self::FIRST_CLOSED_CHECKLIST_IN_EDITOR => $new_data[ self::FIRST_CLOSED_CHECKLIST_IN_EDITOR ] ?? null, |
| 128 | 137 | self::LAST_OPENED_TIMESTAMP => $new_data[ self::LAST_OPENED_TIMESTAMP ] ?? null, |
| 129 | 138 | self::IS_POPUP_MINIMIZED_KEY => $new_data[ self::IS_POPUP_MINIMIZED_KEY ] ?? null, |
| 139 | + self::EDITOR_VISIT_COUNT => $new_data[ self::EDITOR_VISIT_COUNT ] ?? null, | |
| 130 | 140 | ]; |
| 131 | 141 | |
| 132 | 142 | foreach ( $allowed_properties as $key => $value ) { |
| 133 | 143 | if ( null !== $value ) { |
| 134 | - $this->user_progress[ $key ] = $this->get_formatted_value( $key, $value ); | |
| 144 | + $this->user_progress[ $key ] = $value; | |
| 135 | 145 | } |
| 136 | 146 | } |
| 137 | 147 | |
| 138 | 148 | $this->update_user_progress_in_db(); |
| 139 | - | |
| 140 | - if ( isset( $new_data[ Elementor_Counter::EDITOR_COUNTER_KEY ] ) ) { | |
| 141 | - $this->elementor_adapter->set_count( Elementor_Counter::EDITOR_COUNTER_KEY, $new_data[ Elementor_Counter::EDITOR_COUNTER_KEY ] ); | |
| 142 | - } | |
| 143 | 149 | } |
| 144 | 150 | |
| 145 | 151 | /** |
| 146 | 152 | * @return Steps_Manager |
| 147 | 153 | */ |
| 148 | - public function get_steps_manager(): Steps_Manager { | |
| 154 | + public function get_steps_manager() : Steps_Manager { | |
| 149 | 155 | return $this->steps_manager; |
| 150 | 156 | } |
| 151 | 157 | |
| 152 | 158 | /** |
| @@ -151,20 +157,20 @@ | ||
| 151 | 157 | |
| 152 | 158 | /** |
| 153 | 159 | * @return Wordpress_Adapter |
| 154 | 160 | */ |
| 155 | - public function get_wordpress_adapter(): Wordpress_Adapter { | |
| 161 | + public function get_wordpress_adapter() : Wordpress_Adapter { | |
| 156 | 162 | return $this->wordpress_adapter; |
| 157 | 163 | } |
| 158 | 164 | |
| 159 | 165 | /** |
| 160 | - * @return Elementor_Adapter | |
| 166 | + * @return Kit_Adapter | |
| 161 | 167 | */ |
| 162 | - public function get_elementor_adapter(): Elementor_Adapter { | |
| 163 | - return $this->elementor_adapter; | |
| 168 | + public function get_kit_adapter() : Kit_Adapter { | |
| 169 | + return $this->kit_adapter; | |
| 164 | 170 | } |
| 165 | 171 | |
| 166 | - public function enqueue_editor_scripts(): void { | |
| 172 | + public function enqueue_editor_scripts() : void { | |
| 167 | 173 | add_action( 'elementor/editor/before_enqueue_scripts', function () { |
| 168 | 174 | $min_suffix = Utils::is_script_debug() ? '' : '.min'; |
| 169 | 175 | |
| 170 | 176 | wp_enqueue_script( |
| @@ -186,59 +192,74 @@ | ||
| 186 | 192 | wp_set_script_translations( $this->get_name(), 'elementor' ); |
| 187 | 193 | } ); |
| 188 | 194 | } |
| 189 | 195 | |
| 190 | - public function is_preference_switch_on(): bool { | |
| 191 | - if ( $this->should_switch_preferences_off() ) { | |
| 192 | - return false; | |
| 196 | + public static function is_preference_switch_on() : bool { | |
| 197 | + $user_preferences = SettingsManager::get_settings_managers( 'editorPreferences' ) | |
| 198 | + ->get_model() | |
| 199 | + ->get_settings( self::VISIBILITY_SWITCH_ID ); | |
| 200 | + $is_new_installation = Upgrade_Manager::is_new_installation() ? 'yes' : ''; | |
| 201 | + $is_preference_switch_on = $user_preferences ?? $is_new_installation; | |
| 202 | + | |
| 203 | + return 'yes' === $is_preference_switch_on; | |
| 204 | + } | |
| 205 | + | |
| 206 | + public function monitor_editor_visits() { | |
| 207 | + if ( ! $this->is_experiment_active() || ! self::is_preference_switch_on() ) { | |
| 208 | + return; | |
| 193 | 209 | } |
| 194 | 210 | |
| 195 | - $user_preferences = $this->wordpress_adapter->get_user_preferences( self::VISIBILITY_SWITCH_ID ); | |
| 211 | + $progress = $this->get_user_progress_from_db(); | |
| 212 | + $progress[ self::EDITOR_VISIT_COUNT ] = $progress[ self::EDITOR_VISIT_COUNT ] ?? 0; | |
| 196 | 213 | |
| 197 | - return 'yes' === $user_preferences || $this->wordpress_adapter->is_new_installation(); | |
| 214 | + if ( -1 === $progress[ self::EDITOR_VISIT_COUNT ] ) { | |
| 215 | + return; | |
| 216 | + } | |
| 217 | + | |
| 218 | + if ( 2 < ++$progress[ self::EDITOR_VISIT_COUNT ] ) { | |
| 219 | + $progress[ self::EDITOR_VISIT_COUNT ] = -1; | |
| 220 | + } | |
| 221 | + | |
| 222 | + $this->user_progress = $progress; | |
| 223 | + $this->update_user_progress_in_db(); | |
| 198 | 224 | } |
| 199 | 225 | |
| 200 | - public function should_switch_preferences_off(): bool { | |
| 201 | - return ! $this->elementor_adapter->is_active_kit_default() && ! $this->user_progress[ self::LAST_OPENED_TIMESTAMP ] && ! $this->elementor_adapter->get_count( Elementor_Counter::EDITOR_COUNTER_KEY ); | |
| 226 | + private function register_experiment() : void { | |
| 227 | + Plugin::$instance->experiments->add_feature( [ | |
| 228 | + 'name' => self::EXPERIMENT_ID, | |
| 229 | + 'title' => esc_html__( 'Launchpad Checklist', 'elementor' ), | |
| 230 | + 'description' => esc_html__( 'Launchpad Checklist feature to boost productivity and deliver your site faster', 'elementor' ), | |
| 231 | + 'release_status' => Manager::RELEASE_STATUS_ALPHA, | |
| 232 | + 'hidden' => true, | |
| 233 | + 'new_site' => [ | |
| 234 | + 'default_active' => true, | |
| 235 | + 'minimum_installation_version' => '3.25.0', | |
| 236 | + ], | |
| 237 | + ] ); | |
| 202 | 238 | } |
| 203 | 239 | |
| 204 | - private function init_user_progress(): void { | |
| 240 | + private function init_user_progress() : void { | |
| 205 | 241 | $default_settings = $this->get_default_user_progress(); |
| 206 | 242 | |
| 207 | 243 | $this->wordpress_adapter->add_option( self::DB_OPTION_KEY, wp_json_encode( $default_settings ) ); |
| 208 | 244 | } |
| 209 | 245 | |
| 210 | - private function get_default_user_progress(): array { | |
| 246 | + private function get_default_user_progress() : array { | |
| 211 | 247 | return [ |
| 212 | - self::LAST_OPENED_TIMESTAMP => null, | |
| 248 | + self::LAST_OPENED_TIMESTAMP => -1, | |
| 213 | 249 | self::FIRST_CLOSED_CHECKLIST_IN_EDITOR => false, |
| 214 | 250 | self::IS_POPUP_MINIMIZED_KEY => false, |
| 251 | + self::EDITOR_VISIT_COUNT => 0, | |
| 215 | 252 | 'steps' => [], |
| 216 | 253 | ]; |
| 217 | 254 | } |
| 218 | 255 | |
| 219 | - private function update_user_progress_in_db(): void { | |
| 256 | + private function update_user_progress_in_db() : void { | |
| 220 | 257 | $this->wordpress_adapter->update_option( self::DB_OPTION_KEY, wp_json_encode( $this->user_progress ) ); |
| 221 | 258 | } |
| 222 | 259 | |
| 223 | - private function get_formatted_value( $key, $value ) { | |
| 224 | - if ( self::LAST_OPENED_TIMESTAMP === $key ) { | |
| 225 | - return $value ? time() : null; | |
| 226 | - } | |
| 227 | - | |
| 228 | - return $value; | |
| 229 | - } | |
| 230 | - | |
| 231 | - private function handle_checklist_visibility_with_kit() { | |
| 232 | - if ( ! $this->should_switch_preferences_off() ) { | |
| 233 | - return; | |
| 234 | - } | |
| 235 | - | |
| 236 | - add_action( 'elementor/editor/init', function () { | |
| 237 | - $this->wordpress_adapter->set_user_preferences( self::VISIBILITY_SWITCH_ID, '' ); | |
| 238 | - }, 11 ); | |
| 239 | - } | |
| 240 | - | |
| 241 | - public static function should_display_checklist_toggle_control(): bool { | |
| 242 | - return current_user_can( 'manage_options' ); | |
| 260 | + public static function should_display_checklist_toggle_control() : bool { | |
| 261 | + return Plugin::$instance->experiments->is_feature_active( self::EXPERIMENT_ID ) && | |
| 262 | + Plugin::$instance->experiments->is_feature_active( AppBarModule::EXPERIMENT_NAME ) && | |
| 263 | + current_user_can( 'manage_options' ); | |
| 243 | 264 | } |
| 244 | 265 | } |