Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/elementor/app/modules/onboarding/module.php
Keine Baseline-Datei – Diff nur gegen leer.
1
-
1
+
<?php
2
+
namespace Elementor\App\Modules\Onboarding;
3
+
4
+
use Automatic_Upgrader_Skin;
5
+
use Elementor\Core\Base\Module as BaseModule;
6
+
use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
7
+
use Elementor\Core\Common\Modules\Connect\Apps\Library;
8
+
use Elementor\Core\Files\Uploads_Manager;
9
+
use Elementor\Includes\EditorAssetsAPI;
10
+
use Elementor\Plugin;
11
+
use Elementor\Utils;
12
+
use Plugin_Upgrader;
13
+
14
+
if ( ! defined( 'ABSPATH' ) ) {
15
+
exit; // Exit if accessed directly.
16
+
}
17
+
18
+
/**
19
+
* Onboarding Module
20
+
*
21
+
* Responsible for initializing Elementor App functionality
22
+
*
23
+
* @since 3.6.0
24
+
*/
25
+
class Module extends BaseModule {
26
+
27
+
const VERSION = '1.0.0';
28
+
const ONBOARDING_OPTION = 'elementor_onboarded';
29
+
30
+
const EXPERIMENT_EMPHASIZE_CONNECT_BENEFITS = 'emphasizeConnectBenefits101';
31
+
const EXPERIMENT_OFFER_THEME_CHOICES_HELLO_BIZ = 'offerThemeChoicesHelloBiz201';
32
+
const EXPERIMENT_EMPHASIZE_THEME_VALUE_AUDIENCE_202 = 'emphasizeThemeValueAudience202';
33
+
const EXPERIMENT_UPDATE_COPY_VISUALS = 'updateCopyVisuals401';
34
+
const EXPERIMENT_REDUCE_HIERARCHY_BLANK_OPTION = 'reduceHierarchyBlankOption402';
35
+
36
+
private ?API $editor_assets_api = null;
37
+
38
+
/**
39
+
* Get name.
40
+
*
41
+
* @since 3.6.0
42
+
* @access public
43
+
*
44
+
* @return string
45
+
*/
46
+
public function get_name() {
47
+
return 'onboarding';
48
+
}
49
+
50
+
private function is_experiment_enabled( string $experiment_key ) {
51
+
$editor_assets_api = $this->get_editor_assets_api();
52
+
53
+
if ( null === $editor_assets_api ) {
54
+
return false;
55
+
}
56
+
57
+
return $editor_assets_api->is_experiment_enabled( $experiment_key );
58
+
}
59
+
60
+
private function is_hello_theme_activated(): bool {
61
+
$current_theme = get_option( 'template' );
62
+
$hello_theme_variants = [ 'hello-elementor', 'hello-biz', 'hello-commerce', 'hello-theme' ];
63
+
64
+
return in_array( $current_theme, $hello_theme_variants, true );
65
+
}
66
+
67
+
private function get_editor_assets_api(): ?API {
68
+
if ( null !== $this->editor_assets_api ) {
69
+
return $this->editor_assets_api;
70
+
}
71
+
72
+
$editor_assets_api_instance = new EditorAssetsAPI( $this->get_editor_assets_api_config() );
73
+
$this->editor_assets_api = new API( $editor_assets_api_instance );
74
+
75
+
return $this->editor_assets_api;
76
+
}
77
+
78
+
private function get_editor_assets_api_config(): array {
79
+
return [
80
+
EditorAssetsAPI::ASSETS_DATA_URL => 'https://assets.elementor.com/ab-testing/v1/ab-testing.json',
81
+
EditorAssetsAPI::ASSETS_DATA_TRANSIENT_KEY => '_elementor_ab_testing_data',
82
+
EditorAssetsAPI::ASSETS_DATA_KEY => 'ab-testing',
83
+
];
84
+
}
85
+
86
+
/**
87
+
* Set Onboarding Settings
88
+
*
89
+
* Creates an array of module settings that is localized into the JS App config.
90
+
*
91
+
* @since 3.6.0
92
+
*/
93
+
private function set_onboarding_settings() {
94
+
if ( ! Plugin::$instance->common ) {
95
+
return;
96
+
}
97
+
98
+
// Get the published pages and posts
99
+
$pages_and_posts = new \WP_Query( [
100
+
'post_type' => [ 'page', 'post' ],
101
+
'post_status' => 'publish',
102
+
'update_post_meta_cache' => false,
103
+
'update_post_term_cache' => false,
104
+
'no_found_rows' => true,
105
+
] );
106
+
107
+
$custom_site_logo_id = get_theme_mod( 'custom_logo' );
108
+
$custom_logo_src = wp_get_attachment_image_src( $custom_site_logo_id, 'full' );
109
+
$site_name = get_option( 'blogname', '' );
110
+
111
+
$hello_theme = wp_get_theme( 'hello-elementor' );
112
+
$hello_theme_errors = is_object( $hello_theme->errors() ) ? $hello_theme->errors()->errors : [];
113
+
114
+
/** @var Library $library */
115
+
$library = Plugin::$instance->common->get_component( 'connect' )->get_app( 'library' );
116
+
117
+
Plugin::$instance->app->set_settings( 'onboarding', [
118
+
'eventPlacement' => 'Onboarding wizard',
119
+
'onboardingAlreadyRan' => get_option( self::ONBOARDING_OPTION ),
120
+
'onboardingVersion' => self::VERSION,
121
+
'isLibraryConnected' => $library->is_connected(),
122
+
// Used to check if the Hello Elementor theme is installed but not activated.
123
+
'helloInstalled' => empty( $hello_theme_errors['theme_not_found'] ),
124
+
'helloActivated' => $this->is_hello_theme_activated(),
125
+
// The "Use Hello theme on my site" checkbox should be checked by default only if this condition is met.
126
+
'helloOptOut' => count( $pages_and_posts->posts ) < 5,
127
+
'siteName' => esc_html( $site_name ),
128
+
'isUnfilteredFilesEnabled' => Uploads_Manager::are_unfiltered_uploads_enabled(),
129
+
'urls' => [
130
+
'kitLibrary' => Plugin::$instance->app->get_base_url() . '&source=onboarding#/kit-library?order[direction]=desc&order[by]=featuredIndex',
131
+
'sitePlanner' => add_query_arg( [
132
+
'type' => 'editor',
133
+
'siteUrl' => esc_url( home_url() ),
134
+
'siteName' => esc_html( $site_name ),
135
+
'siteDescription' => esc_html( get_bloginfo( 'description' ) ),
136
+
'siteLanguage' => get_locale(),
137
+
], 'https://planner.elementor.com/onboarding.html' ),
138
+
'createNewPage' => Plugin::$instance->documents->get_create_new_post_url(),
139
+
'connect' => $library->get_admin_url( 'authorize', [
140
+
'utm_source' => 'onboarding-wizard',
141
+
'utm_campaign' => 'connect-account',
142
+
'utm_medium' => 'wp-dash',
143
+
'utm_term' => self::VERSION,
144
+
'source' => 'generic',
145
+
] ),
146
+
'upgrade' => 'https://go.elementor.com/go-pro-onboarding-wizard-upgrade/',
147
+
'signUp' => $library->get_admin_url( 'authorize', [
148
+
'utm_source' => 'onboarding-wizard',
149
+
'utm_campaign' => 'connect-account',
150
+
'utm_medium' => 'wp-dash',
151
+
'utm_term' => self::VERSION,
152
+
'source' => 'generic',
153
+
'screen_hint' => 'signup',
154
+
] ),
155
+
'uploadPro' => Plugin::$instance->app->get_base_url() . '#/onboarding/uploadAndInstallPro?mode=popup',
156
+
],
157
+
'siteLogo' => [
158
+
'id' => $custom_site_logo_id,
159
+
'url' => $custom_logo_src ? $custom_logo_src[0] : '',
160
+
],
161
+
'utms' => [
162
+
'connectTopBar' => '&utm_content=top-bar',
163
+
'connectCta' => '&utm_content=cta-button',
164
+
'connectCtaLink' => '&utm_content=cta-link',
165
+
'downloadPro' => '?utm_source=onboarding-wizard&utm_campaign=my-account-subscriptions&utm_medium=wp-dash&utm_content=import-pro-plugin&utm_term=' . self::VERSION,
166
+
],
167
+
'nonce' => wp_create_nonce( 'onboarding' ),
168
+
'experiment' => true,
169
+
'isExperiment101Enabled' => $this->is_experiment_enabled( self::EXPERIMENT_EMPHASIZE_CONNECT_BENEFITS ),
170
+
'isExperiment201Enabled' => $this->is_experiment_enabled( self::EXPERIMENT_OFFER_THEME_CHOICES_HELLO_BIZ ),
171
+
'isExperiment202Enabled' => $this->is_experiment_enabled( self::EXPERIMENT_EMPHASIZE_THEME_VALUE_AUDIENCE_202 ),
172
+
'isExperiment401Enabled' => $this->is_experiment_enabled( self::EXPERIMENT_UPDATE_COPY_VISUALS ),
173
+
'isExperiment402Enabled' => $this->is_experiment_enabled( self::EXPERIMENT_REDUCE_HIERARCHY_BLANK_OPTION ),
174
+
'experimentNames' => [
175
+
'101' => self::EXPERIMENT_EMPHASIZE_CONNECT_BENEFITS,
176
+
'201' => self::EXPERIMENT_OFFER_THEME_CHOICES_HELLO_BIZ,
177
+
'202' => self::EXPERIMENT_EMPHASIZE_THEME_VALUE_AUDIENCE_202,
178
+
'401' => self::EXPERIMENT_UPDATE_COPY_VISUALS,
179
+
'402' => self::EXPERIMENT_REDUCE_HIERARCHY_BLANK_OPTION,
180
+
],
181
+
] );
182
+
}
183
+
184
+
/**
185
+
* Get Permission Error Response
186
+
*
187
+
* Returns the response that is returned when the user's capabilities are not sufficient for performing an action.
188
+
*
189
+
* @since 3.6.4
190
+
*
191
+
* @return array
192
+
*/
193
+
private function get_permission_error_response() {
194
+
return [
195
+
'status' => 'error',
196
+
'payload' => [
197
+
'error_message' => esc_html__( 'You do not have permission to perform this action.', 'elementor' ),
198
+
],
199
+
];
200
+
}
201
+
202
+
/**
203
+
* Maybe Update Site Logo
204
+
*
205
+
* If a new name is provided, it will be updated as the Site Name.
206
+
*
207
+
* @since 3.6.0
208
+
*
209
+
* @return array
210
+
*/
211
+
private function maybe_update_site_name() {
212
+
$problem_error = [
213
+
'status' => 'error',
214
+
'payload' => [
215
+
'error_message' => esc_html__( 'There was a problem setting your site name.', 'elementor' ),
216
+
],
217
+
];
218
+
219
+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
220
+
if ( empty( $_POST['data'] ) ) {
221
+
return $problem_error;
222
+
}
223
+
224
+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
225
+
$data = json_decode( Utils::get_super_global_value( $_POST, 'data' ), true );
226
+
227
+
if ( ! isset( $data['siteName'] ) ) {
228
+
return $problem_error;
229
+
}
230
+
231
+
/**
232
+
* Onboarding Site Name
233
+
*
234
+
* Filters the new site name passed by the user to update in Elementor's onboarding process.
235
+
* Elementor runs `esc_html()` on the Site Name passed by the user for security reasons. If a user wants to
236
+
* include special characters in their site name, they can use this filter to override it.
237
+
*
238
+
* @since 3.6.0
239
+
*
240
+
* @param string Escaped new site name
241
+
*/
242
+
$new_site_name = apply_filters( 'elementor/onboarding/site-name', $data['siteName'] );
243
+
244
+
// The site name is sanitized in `update_options()`
245
+
update_option( 'blogname', $new_site_name );
246
+
247
+
return [
248
+
'status' => 'success',
249
+
'payload' => [
250
+
'siteNameUpdated' => true,
251
+
],
252
+
];
253
+
}
254
+
255
+
/**
256
+
* Maybe Update Site Logo
257
+
*
258
+
* If an image attachment ID is provided, it will be updated as the Site Logo Theme Mod.
259
+
*
260
+
* @since 3.6.0
261
+
*
262
+
* @return array
263
+
*/
264
+
private function maybe_update_site_logo() {
265
+
if ( ! current_user_can( 'edit_theme_options' ) ) {
266
+
return $this->get_permission_error_response();
267
+
}
268
+
269
+
$data_error = [
270
+
'status' => 'error',
271
+
'payload' => [
272
+
'error_message' => esc_html__( 'There was a problem setting your site logo.', 'elementor' ),
273
+
],
274
+
];
275
+
276
+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
277
+
if ( empty( $_POST['data'] ) ) {
278
+
return $data_error;
279
+
}
280
+
281
+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
282
+
$data = json_decode( Utils::get_super_global_value( $_POST, 'data' ), true );
283
+
284
+
// If there is no attachment ID passed or it is not a valid ID, exit here.
285
+
if ( empty( $data['attachmentId'] ) ) {
286
+
return $data_error;
287
+
}
288
+
289
+
$absint_attachment_id = absint( $data['attachmentId'] );
290
+
291
+
if ( 0 === $absint_attachment_id ) {
292
+
return $data_error;
293
+
}
294
+
295
+
$attachment_url = wp_get_attachment_url( $data['attachmentId'] );
296
+
297
+
// Check if the attachment exists. If it does not, exit here.
298
+
if ( ! $attachment_url ) {
299
+
return $data_error;
300
+
}
301
+
302
+
set_theme_mod( 'custom_logo', $absint_attachment_id );
303
+
304
+
return [
305
+
'status' => 'success',
306
+
'payload' => [
307
+
'siteLogoUpdated' => true,
308
+
],
309
+
];
310
+
}
311
+
312
+
/**
313
+
* Maybe Upload Logo Image
314
+
*
315
+
* If an image file upload is provided, and it passes validation, it will be uploaded to the site's Media Library.
316
+
*
317
+
* @since 3.6.0
318
+
*
319
+
* @return array
320
+
*/
321
+
private function maybe_upload_logo_image() {
322
+
$error_message = esc_html__( 'There was a problem uploading your file.', 'elementor' );
323
+
324
+
$file = Utils::get_super_global_value( $_FILES, 'fileToUpload' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
325
+
326
+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
327
+
if ( ! is_array( $file ) || empty( $file['type'] ) ) {
328
+
return [
329
+
'status' => 'error',
330
+
'payload' => [
331
+
'error_message' => $error_message,
332
+
],
333
+
];
334
+
}
335
+
336
+
// If the user has allowed it, set the Request's state as an "Elementor Upload" request, in order to add
337
+
// support for non-standard file uploads.
338
+
if ( 'image/svg+xml' === $file['type'] ) {
339
+
if ( Uploads_Manager::are_unfiltered_uploads_enabled() ) {
340
+
Plugin::$instance->uploads_manager->set_elementor_upload_state( true );
341
+
} else {
342
+
wp_send_json_error( 'To upload SVG files, you must allow uploading unfiltered files.' );
343
+
}
344
+
}
345
+
346
+
// If the image is an SVG file, sanitation is performed during the import (upload) process.
347
+
$image_attachment = Plugin::$instance->templates_manager->get_import_images_instance()->import( $file );
348
+
349
+
if ( 'image/svg+xml' === $file['type'] && Uploads_Manager::are_unfiltered_uploads_enabled() ) {
350
+
// Reset Upload state.
351
+
Plugin::$instance->uploads_manager->set_elementor_upload_state( false );
352
+
}
353
+
354
+
if ( $image_attachment && ! is_wp_error( $image_attachment ) ) {
355
+
$result = [
356
+
'status' => 'success',
357
+
'payload' => [
358
+
'imageAttachment' => $image_attachment,
359
+
],
360
+
];
361
+
} else {
362
+
$result = [
363
+
'status' => 'error',
364
+
'payload' => [
365
+
'error_message' => $error_message,
366
+
],
367
+
];
368
+
}
369
+
370
+
return $result;
371
+
}
372
+
373
+
/**
374
+
* Activate Hello Theme
375
+
*
376
+
* @since 3.6.0
377
+
*
378
+
* @return array
379
+
*/
380
+
private function maybe_activate_hello_theme() {
381
+
if ( ! current_user_can( 'switch_themes' ) ) {
382
+
return $this->get_permission_error_response();
383
+
}
384
+
385
+
$theme_slug = Utils::get_super_global_value( $_POST, 'theme_slug' ) ?? 'hello-biz'; // phpcs:ignore WordPress.Security.NonceVerification.Missing
386
+
$allowed_themes = [ 'hello-elementor', 'hello-biz' ];
387
+
if ( ! in_array( $theme_slug, $allowed_themes, true ) ) {
388
+
$theme_slug = 'hello-biz';
389
+
}
390
+
391
+
switch_theme( $theme_slug );
392
+
393
+
return [
394
+
'status' => 'success',
395
+
'payload' => [
396
+
'helloThemeActivated' => true,
397
+
],
398
+
];
399
+
}
400
+
401
+
/**
402
+
* Upload and Install Elementor Pro
403
+
*
404
+
* @since 3.6.0
405
+
*
406
+
* @return array
407
+
*/
408
+
private function upload_and_install_pro() {
409
+
if ( ! current_user_can( 'install_plugins' ) || ! current_user_can( 'activate_plugins' ) ) {
410
+
return $this->get_permission_error_response();
411
+
}
412
+
413
+
$error_message = esc_html__( 'There was a problem uploading your file.', 'elementor' );
414
+
415
+
$file = Utils::get_super_global_value( $_FILES, 'fileToUpload' ) ?? []; // phpcs:ignore WordPress.Security.NonceVerification.Missing
416
+
417
+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
418
+
if ( ! is_array( $file ) || empty( $file['type'] ) ) {
419
+
return [
420
+
'status' => 'error',
421
+
'payload' => [
422
+
'error_message' => $error_message,
423
+
],
424
+
];
425
+
}
426
+
427
+
$result = [];
428
+
429
+
if ( ! class_exists( 'Automatic_Upgrader_Skin' ) ) {
430
+
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
431
+
}
432
+
433
+
$skin = new Automatic_Upgrader_Skin();
434
+
$upgrader = new Plugin_Upgrader( $skin );
435
+
$upload_result = $upgrader->install( $file['tmp_name'], [ 'overwrite_package' => false ] );
436
+
437
+
if ( ! $upload_result || is_wp_error( $upload_result ) ) {
438
+
$result = [
439
+
'status' => 'error',
440
+
'payload' => [
441
+
'error_message' => $error_message,
442
+
],
443
+
];
444
+
} else {
445
+
$activated = activate_plugin( WP_PLUGIN_DIR . '/elementor-pro/elementor-pro.php', false, false, true );
446
+
447
+
if ( ! is_wp_error( $activated ) ) {
448
+
$result = [
449
+
'status' => 'success',
450
+
'payload' => [
451
+
'elementorProInstalled' => true,
452
+
],
453
+
];
454
+
} else {
455
+
$result = [
456
+
'status' => 'error',
457
+
'payload' => [
458
+
'error_message' => $error_message,
459
+
'elementorProInstalled' => false,
460
+
],
461
+
];
462
+
}
463
+
}
464
+
465
+
return $result;
466
+
}
467
+
468
+
private function maybe_update_onboarding_db_option() {
469
+
$db_option = get_option( self::ONBOARDING_OPTION );
470
+
471
+
if ( ! $db_option ) {
472
+
update_option( self::ONBOARDING_OPTION, true );
473
+
}
474
+
475
+
return [
476
+
'status' => 'success',
477
+
'payload' => 'onboarding DB',
478
+
];
479
+
}
480
+
481
+
/**
482
+
* Maybe Handle Ajax
483
+
*
484
+
* This method checks if there are any AJAX actions being
485
+
*
486
+
* @since 3.6.0
487
+
*/
488
+
private function maybe_handle_ajax() {
489
+
$result = [];
490
+
491
+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
492
+
switch ( Utils::get_super_global_value( $_POST, 'action' ) ) {
493
+
case 'elementor_update_site_name':
494
+
// If no value is passed for any reason, no need to update the site name.
495
+
$result = $this->maybe_update_site_name();
496
+
break;
497
+
case 'elementor_update_site_logo':
498
+
$result = $this->maybe_update_site_logo();
499
+
break;
500
+
case 'elementor_upload_site_logo':
501
+
$result = $this->maybe_upload_logo_image();
502
+
break;
503
+
case 'elementor_activate_hello_theme':
504
+
$result = $this->maybe_activate_hello_theme();
505
+
break;
506
+
case 'elementor_upload_and_install_pro':
507
+
$result = $this->upload_and_install_pro();
508
+
break;
509
+
case 'elementor_update_onboarding_option':
510
+
$result = $this->maybe_update_onboarding_db_option();
511
+
break;
512
+
case 'elementor_save_onboarding_features':
513
+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
514
+
$result = $this->get_component( 'features_usage' )->save_onboarding_features( Utils::get_super_global_value( $_POST, 'data' ) ?? [] );
515
+
}
516
+
517
+
if ( ! empty( $result ) ) {
518
+
if ( 'success' === $result['status'] ) {
519
+
wp_send_json_success( $result['payload'] );
520
+
} else {
521
+
wp_send_json_error( $result['payload'] );
522
+
}
523
+
}
524
+
}
525
+
526
+
public function __construct() {
527
+
$this->add_component( 'features_usage', new Features_Usage() );
528
+
529
+
add_action( 'elementor/init', function() {
530
+
// Only load when viewing the onboarding app.
531
+
if ( Plugin::$instance->app->is_current() ) {
532
+
$this->set_onboarding_settings();
533
+
// Needed for installing the Hello Elementor theme.
534
+
wp_enqueue_script( 'updates' );
535
+
// Needed for uploading Logo from WP Media Library.
536
+
wp_enqueue_media();
537
+
}
538
+
}, 12 );
539
+
540
+
// Needed for uploading Logo from WP Media Library. The 'admin_menu' hook is used because it runs before
541
+
// 'admin_init', and the App triggers printing footer scripts on 'admin_init' at priority 0.
542
+
add_action( 'admin_menu', function () {
543
+
add_action( 'wp_print_footer_scripts', function () {
544
+
if ( function_exists( 'wp_print_media_templates' ) ) {
545
+
wp_print_media_templates();
546
+
}
547
+
} );
548
+
} );
549
+
550
+
add_action( 'admin_init', function() {
551
+
if ( wp_doing_ajax() &&
552
+
isset( $_POST['action'] ) &&
553
+
isset( $_POST['_nonce'] ) &&
554
+
wp_verify_nonce( Utils::get_super_global_value( $_POST, '_nonce' ), Ajax::NONCE_KEY ) &&
555
+
current_user_can( 'manage_options' )
556
+
) {
557
+
$this->maybe_handle_ajax();
558
+
}
559
+
} );
560
+
561
+
$this->get_component( 'features_usage' )->register();
562
+
}
563
+
}
564
+