PluginProbe
Elementor Website Builder – more than just a page builder / 3.35.0-dev4
Elementor Website Builder – more than just a page builder v3.35.0-dev4
4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.3.0-beta3 4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 All 457 releases
← All changes | core/experiments/manager.php +22 -124 4.3.4 → 3.35.0-dev4 View file →
@@ -89,10 +89,8 @@
89 89 }
90 90
91 91 $this->features[ $options['name'] ] = $experimental_data;
92 92
93 - $this->resolve_registered_dependants( $options['name'], $experimental_data );
94 -
95 93 if ( $experimental_data['mutable'] && is_admin() ) {
96 94 $feature_option_key = $this->get_feature_option_key( $options['name'] );
97 95
98 96 $on_state_change_callback = function( $old_state, $new_state ) use ( $experimental_data, $feature_option_key ) {
@@ -122,11 +120,9 @@
122 120 private function install_compare( $version ) {
123 121 $installs_history = Upgrade_Manager::get_installs_history();
124 122
125 123 if ( empty( $installs_history ) ) {
126 - // Fresh installation: upgrade manager hasn't written history yet on this first request.
127 - // Use the current plugin version as the effective first-install version.
128 - return version_compare( ELEMENTOR_VERSION, $version, '>=' );
124 + return false;
129 125 }
130 126
131 127 $cleaned_version = preg_replace( '/-(beta|cloud|dev)\d*$/', '', key( $installs_history ) );
132 128
@@ -251,11 +247,9 @@
251 247 *
252 248 * @since 3.1.0
253 249 * @access public
254 250 *
255 - * @param string $feature_name Experiment feature name.
256 - * @param bool $check_dependencies When true, also require dependency experiments to be active.
257 - * Missing dependencies always fail closed. Hidden dependencies are treated as satisfied.
251 + * @param string $feature_name
258 252 *
259 253 * @return bool
260 254 */
261 255 public function is_feature_active( $feature_name, $check_dependencies = false ) {
@@ -264,36 +258,11 @@
264 258 if ( ! $feature || self::STATE_ACTIVE !== $this->get_feature_actual_state( $feature ) ) {
265 259 return false;
266 260 }
267 261
268 - if ( isset( $feature['dependencies'] ) && is_array( $feature['dependencies'] ) ) {
262 + if ( $check_dependencies && isset( $feature['dependencies'] ) && is_array( $feature['dependencies'] ) ) {
269 263 foreach ( $feature['dependencies'] as $dependency ) {
270 264 $dependent_feature = $this->get_features( $dependency->get_name() );
271 -
272 - // A dependency that Core still does not ship can never be verified as active.
273 - // Non existing dependencies are re-resolved first to cover later registrations.
274 - if ( $dependency instanceof Non_Existing_Dependency && ! $dependent_feature ) {
275 - return false;
276 - }
277 -
278 - if ( ! $dependent_feature ) {
279 - // A Core experiment dependency that no longer resolves fails closed.
280 - // Class dependencies are not experiment names and stay exempt.
281 - if ( $dependency instanceof Wrap_Core_Dependency ) {
282 - return false;
283 - }
284 -
285 - continue;
286 - }
287 -
288 - if ( ! $check_dependencies ) {
289 - continue;
290 - }
291 -
292 - if ( ! empty( $dependent_feature[ static::TYPE_HIDDEN ] ) ) {
293 - continue;
294 - }
295 -
296 265 $feature_state = self::STATE_ACTIVE === $this->get_feature_actual_state( $dependent_feature );
297 266
298 267 if ( ! $feature_state ) {
299 268 return false;
@@ -371,13 +340,15 @@
371 340 $this->add_feature( [
372 341 'name' => 'container',
373 342 'title' => esc_html__( 'Container', 'elementor' ),
374 343 'description' => sprintf(
375 - /* translators: 1: Link opening tag, 2: Link closing tag, 3: Link opening tag, 4: Link closing tag */
376 - esc_html__( 'Create advanced layouts and responsive designs with %1$sFlexbox%2$s and %3$sGrid%4$s container elements.', 'elementor' ),
344 + /* translators: 1: Link opening tag, 2: Link closing tag, 3: Link opening tag, 4: Link closing tag, 5: Link opening tag, 6: Link closing tag */
345 + esc_html__( 'Create advanced layouts and responsive designs with %1$sFlexbox%2$s and %3$sGrid%4$s container elements. Give it a try using the %5$sContainer playground%6$s.', 'elementor' ),
377 346 '<a target="_blank" href="https://go.elementor.com/wp-dash-flex-container/">',
378 347 '</a>',
379 348 '<a target="_blank" href="https://go.elementor.com/wp-dash-grid-container/">',
349 + '</a>',
350 + '<a target="_blank" href="https://go.elementor.com/wp-dash-flex-container-playground/">',
380 351 '</a>'
381 352 ),
382 353 'release_status' => self::RELEASE_STATUS_STABLE,
383 354 'default' => self::STATE_INACTIVE,
@@ -405,18 +376,8 @@
405 376 'default_active' => true,
406 377 'minimum_installation_version' => '3.30.0',
407 378 ],
408 379 ] );
409 -
410 - $this->add_feature( [
411 - 'name' => 'e_optimized_css_files',
412 - 'title' => esc_html__( 'Optimized CSS Files', 'elementor' ),
413 - 'tag' => esc_html__( 'Performance', 'elementor' ),
414 - 'description' => esc_html__( 'Keeps external CSS files available and consistent for sites behind page caching or a CDN.', 'elementor' ),
415 - 'release_status' => self::RELEASE_STATUS_ALPHA,
416 - 'default' => self::STATE_INACTIVE,
417 - 'generator_tag' => true,
418 - ] );
419 380 }
420 381
421 382 /**
422 383 * Init States
@@ -677,8 +638,9 @@
677 638 private function get_feature_settings_label_html( array $feature ) {
678 639 ob_start();
679 640
680 641 $is_feature_active = $this->is_feature_active( $feature['name'] );
642 + $is_editor_one_enabled = $this->is_feature_active( 'e_editor_one' );
681 643
682 644 $indicator_classes = 'e-experiment__title__indicator';
683 645
684 646 if ( $is_feature_active ) {
@@ -692,9 +654,12 @@
692 654 <div class="<?php echo $indicator_classes; ?>" data-tooltip="<?php echo $indicator_tooltip; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>"></div>
693 655 <label class="e-experiment__title__label" for="e-experiment-<?php echo $feature['name']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>"><?php echo $feature['title']; ?></label>
694 656 <?php foreach ( $feature['tags'] as $tag ) { ?>
695 657 <?php
696 - $tag_classes = 'e-experiment__title__tag e-experiment__title__tag__' . $tag['type'] . ' e-editor-one';
658 + $tag_classes = 'e-experiment__title__tag e-experiment__title__tag__' . $tag['type'];
659 + if ( $is_editor_one_enabled ) {
660 + $tag_classes .= ' e-editor-one';
661 + }
697 662 ?>
698 663 <span class="<?php echo esc_attr( $tag_classes ); ?>"><?php echo $tag['label']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
699 664 <?php } ?>
700 665 <?php if ( $feature['deprecated'] ) { ?>
@@ -808,43 +773,22 @@
808 773 }
809 774
810 775 // Validate if the current feature dependency is available.
811 776 foreach ( $feature['dependencies'] as $dependency ) {
812 - if ( $dependency instanceof Non_Existing_Dependency ) {
813 - $this->warn_removed_or_hidden_dependency(
814 - sprintf(
815 - 'The feature `%s` has a dependency `%s` that is not available in Core.',
816 - esc_html( $feature['name'] ),
817 - esc_html( $dependency->get_name() )
818 - )
819 - );
820 - continue;
821 - }
822 -
823 777 $dependency_feature = $this->get_features( $dependency->get_name() );
824 778
825 779 if ( ! $dependency_feature ) {
826 - $this->warn_removed_or_hidden_dependency(
780 + $rollback( $feature_option_key, self::STATE_INACTIVE );
781 +
782 + throw new Exceptions\Dependency_Exception(
827 783 sprintf(
828 - 'The feature `%s` has a dependency `%s` that is not available in Core.',
784 + 'The feature `%s` has a dependency `%s` that is not available.',
829 785 esc_html( $feature['name'] ),
830 786 esc_html( $dependency->get_name() )
831 787 )
832 788 );
833 - continue;
834 789 }
835 790
836 - if ( $this->is_removed_or_hidden_dependency( $dependency_feature ) ) {
837 - $this->warn_removed_or_hidden_dependency(
838 - sprintf(
839 - 'The feature `%1$s` depends on hidden experiment `%2$s`.',
840 - esc_html( $feature['name'] ),
841 - esc_html( $dependency_feature['name'] )
842 - )
843 - );
844 - continue;
845 - }
846 -
847 791 $dependency_state = $this->get_feature_actual_state( $dependency_feature );
848 792
849 793 // If dependency is not active.
850 794 if ( self::STATE_INACTIVE === $dependency_state ) {
@@ -995,8 +939,10 @@
995 939
996 940 /**
997 941 * @param array $experimental_data
998 942 * @return array
943 + *
944 + * @throws Exceptions\Dependency_Exception If the feature dependency is not initialized or depends on a hidden experiment.
999 945 */
1000 946 private function initialize_feature_dependencies( array $experimental_data ): array {
1001 947 foreach ( $experimental_data['dependencies'] as $key => $dependency ) {
1002 948 $feature = $this->get_features( $dependency );
@@ -1001,28 +947,20 @@
1001 947 foreach ( $experimental_data['dependencies'] as $key => $dependency ) {
1002 948 $feature = $this->get_features( $dependency );
1003 949
1004 950 if ( ! isset( $feature ) ) {
1005 - $this->warn_removed_or_hidden_dependency(
951 + // since we must validate the state of each dependency, we have to make sure that dependencies are initialized in the correct order, otherwise, error.
952 + throw new Exceptions\Dependency_Exception(
1006 953 sprintf(
1007 - 'Feature %1$s depends on experiment %2$s that is not registered in Core.',
954 + 'Feature %s cannot be initialized before dependency feature: %s.',
1008 955 esc_html( $experimental_data['name'] ),
1009 956 esc_html( $dependency )
1010 957 )
1011 958 );
1012 -
1013 - $experimental_data['dependencies'][ $key ] = $this->create_dependency_class( $dependency, null );
1014 - continue;
1015 959 }
1016 960
1017 961 if ( ! empty( $feature[ static::TYPE_HIDDEN ] ) ) {
1018 - $this->warn_removed_or_hidden_dependency(
1019 - sprintf(
1020 - 'Feature %1$s depends on hidden experiment %2$s.',
1021 - esc_html( $experimental_data['name'] ),
1022 - esc_html( $dependency )
1023 - )
1024 - );
962 + throw new Exceptions\Dependency_Exception( 'Depending on a hidden experiment is not allowed.' );
1025 963 }
1026 964
1027 965 $experimental_data['dependencies'][ $key ] = $this->create_dependency_class( $dependency, $feature );
1028 966 $experimental_data = $this->set_feature_default_state_to_match_dependencies( $feature, $experimental_data );
@@ -1028,48 +966,8 @@
1028 966 $experimental_data = $this->set_feature_default_state_to_match_dependencies( $feature, $experimental_data );
1029 967 }
1030 968
1031 969 return $experimental_data;
1032 - }
1033 -
1034 - private function is_removed_or_hidden_dependency( $dependency_feature ): bool {
1035 - if ( ! $dependency_feature ) {
1036 - return true;
1037 - }
1038 -
1039 - return ! empty( $dependency_feature[ static::TYPE_HIDDEN ] );
1040 - }
1041 -
1042 - /**
1043 - * Re-resolve non existing dependency placeholders of dependants that were
1044 - * registered before this feature existed.
1045 - *
1046 - * @param string $feature_name Newly registered feature name.
1047 - * @param array $feature_data Newly registered feature data.
1048 - */
1049 - private function resolve_registered_dependants( string $feature_name, array $feature_data ): void {
1050 - foreach ( $this->features as $name => $registered_feature ) {
1051 - if ( $name === $feature_name || empty( $registered_feature['dependencies'] ) || ! is_array( $registered_feature['dependencies'] ) ) {
1052 - continue;
1053 - }
1054 -
1055 - foreach ( $registered_feature['dependencies'] as $key => $dependency ) {
1056 - if ( ! ( $dependency instanceof Non_Existing_Dependency ) || $dependency->get_name() !== $feature_name ) {
1057 - continue;
1058 - }
1059 -
1060 - $this->features[ $name ]['dependencies'][ $key ] = $this->create_dependency_class( $feature_name, $feature_data );
1061 - }
1062 - }
1063 - }
1064 -
1065 - private function warn_removed_or_hidden_dependency( string $message ): void {
1066 - if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
1067 - return;
1068 - }
1069 -
1070 - // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Developer notice; message is escaped.
1071 - _doing_it_wrong( __METHOD__, esc_html( $message ), ELEMENTOR_VERSION );
1072 970 }
1073 971
1074 972 /**
1075 973 * @param array $feature