'', 'tab_slug' => 'custom_css', 'toggle_slug' => 'conditions', 'mobile_options' => false, 'default' => '', ]; $settings = array_merge( $defaults, $args ); return array_merge( $this->get_field( $settings ) ); } /** * Retrieves field for Display Conditions. * * @since 4.11.0 * * @param array $args Associative array for settings. * * @return array $options Option settings. */ public function get_field( $args ) { static $i18n; // Cache translations. if ( ! $i18n ) { $i18n = [ 'Display Conditions' => esc_html__( 'Display Conditions', 'et_builder' ), 'description' => et_get_safe_localization( sprintf( __( 'Choose when to display this element based on a set of conditions. Multiple conditions can be added. Date & Time condition is based on your timezone settings in your WordPress General Settings', 'et_builder' ), esc_url( admin_url( 'options-general.php' ) ) ) ), ]; } $settings = array( 'label' => $i18n['Display Conditions'], 'type' => 'display_conditions', 'mobile_options' => $args['mobile_options'], 'default' => $args['default'], 'tab_slug' => $args['tab_slug'], 'toggle_slug' => $args['toggle_slug'], 'description' => $i18n['description'], ); $options = array( 'display_conditions' => $settings ); return $options; } /** * Checks all $display_conditions and returns a final boolean output. * * @since 4.11.0 * * @param array $display_conditions Associative array containing conditions. * @param boolean $only_return_status Whether to return all conditions full status (useful in VB tooltips). * * @return boolean Conditions final result. */ public function is_displayable( $display_conditions, $only_return_status = false ) { // Bail out and just display the module if below WordPress 5.3. if ( version_compare( get_bloginfo( 'version' ), '5.3', '<' ) ) { return true; } // Bail out and just display the module if $display_conditions is not array. if ( ! is_array( $display_conditions ) ) { return true; } // Holds current condition evaluation. $should_display = true; $status = []; // Reverses condition list, We start from the bottom of the list. $display_conditions = array_reverse( $display_conditions ); // Holds all the conditions that have been processed, except the ones detected as conflicted. $processed_conditions = array(); foreach ( $display_conditions as $arr_key => $condition ) { $condition_id = isset( $condition['id'] ) ? $condition['id'] : ''; $condition_name = isset( $condition['condition'] ) ? $condition['condition'] : ''; $condition_settings = isset( $condition['conditionSettings'] ) ? $condition['conditionSettings'] : []; $operator = isset( $condition['operator'] ) ? $condition['operator'] : 'OR'; $is_enable_condition_set = isset( $condition_settings['enableCondition'] ) ? true : false; $is_disabled = $is_enable_condition_set && 'off' === $condition_settings['enableCondition'] ? true : false; // Skip if condition is disabled. if ( $is_disabled ) { $status[] = [ 'id' => $condition_id, 'is_conflicted' => false, ]; continue; } $is_conflict_detected = $this->_is_condition_conflicted( $condition, $processed_conditions, $operator ); $status[] = [ 'id' => $condition_id, 'is_conflicted' => $is_conflict_detected, ]; if ( $is_conflict_detected ) { continue; } else { $should_display = $this->is_condition_true( $condition_id, $condition_name, $condition_settings ); $processed_conditions[] = $condition; } // If operator is set to "OR/ANY" break as soon as one condition is true - returning a final true. // If operator is set to "AND/ALL" break as soon as one condition is false - returning a final false. if ( 'OR' === $operator && $should_display && ! $only_return_status ) { break; } elseif ( 'AND' === $operator && ! $should_display && ! $only_return_status ) { break; } } return ( $only_return_status ) ? $status : $should_display; } /** * Checks a single condition and returns a boolean result. * * @since 4.11.0 * * @param string $condition_id Condition ID. * @param string $condition_name Condition name. * @param array $condition_settings Containing all settings of the condition. * * @return boolean Condition output. */ public function is_condition_true( $condition_id, $condition_name, $condition_settings ) { switch ( $condition_name ) { case 'loggedInStatus': return $this->_process_logged_in_status_condition( $condition_settings ); case 'userRole': return $this->_process_user_role_condition( $condition_settings ); case 'dateTime': return $this->_process_date_time_condition( $condition_settings ); case 'postType': return $this->_process_post_type_condition( $condition_settings ); case 'author': return $this->_process_author_condition( $condition_settings ); case 'categories': return $this->_process_categories_condition( $condition_settings ); case 'categoryPage': return $this->_process_category_page_condition( $condition_settings ); case 'tags': return $this->_process_tags_condition( $condition_settings ); case 'tagPage': return $this->_process_tag_page_condition( $condition_settings ); case 'dateArchive': return $this->_process_date_archive_condition( $condition_settings ); case 'productPurchase': return $this->_process_product_purchase_condition( $condition_settings ); case 'cartContents': return $this->_process_cart_contents_condition( $condition_settings ); case 'searchResults': return $this->_process_search_results_condition( $condition_settings ); case 'operatingSystem': return $this->_process_operating_system_condition( $condition_settings ); case 'browser': return $this->_process_browser_condition( $condition_settings ); case 'pageVisit': return $this->_process_page_visit_condition( $condition_settings ); case 'postVisit': return $this->_process_page_visit_condition( $condition_settings ); case 'cookie': return $this->_process_cookie_condition( $condition_settings ); case 'numberOfViews': return $this->_process_number_of_views_condition( $condition_id, $condition_settings ); default: if ( isset( $condition_settings['dynamicPosts'] ) ) { return $this->_process_dynamic_posts_condition( $condition_settings ); } return true; } } /** * Checks the $condition against $processed_conditions to determine if the $condition is considered a conflict or not. * * When operator 'OR/Any' is selected and we have more than one condition of the same type the priority * is with the latest condition (located lower in the list). * * When operator 'AND/All' is selected no condition is considered a conflict. * * @since 4.11.0 * * @param array $condition Containing all settings of the condition. * @param array $processed_conditions Containing all settings of previously processed conditions. * @param array $operator Selected operator for the Display Conditions, Options: 'OR' or 'AND'. * * @return boolean Condition output. */ protected function _is_condition_conflicted( $condition, $processed_conditions, $operator ) { if ( 'AND' === $operator ) { return false; } $is_conflicted = false; // Check condition against all previously processed conditions. foreach ( $processed_conditions as $processed_condition ) { // Only check same condition types against each other, Ex. UserRole against UserRole. if ( $condition['condition'] !== $processed_condition['condition'] ) { continue; } // Exception! "Date Time" Condition can have multiple positive conditions. $is_datetime = 'dateTime' === $condition['condition']; $is_prev_cond_datetime_and_negative = $is_datetime && 'isNotOnSpecificDate' === $processed_condition['conditionSettings']['dateTimeDisplay']; $is_current_cond_datetime_and_negative = $is_datetime && 'isNotOnSpecificDate' === $condition['conditionSettings']['dateTimeDisplay']; if ( $is_prev_cond_datetime_and_negative || $is_current_cond_datetime_and_negative ) { $is_conflicted = true; break; } elseif ( $is_datetime ) { $is_conflicted = false; break; } /** * When operator is set to "OR/ANY" and we have more than one condition, all other conditions * will be set as conflicted, giving the priority to the latest condition in the list. */ if ( count( $processed_conditions ) > 0 ) { $is_conflicted = true; break; } } return $is_conflicted; } /** * Overrides current date with specified date. * Useful for testing purposes where we don't want to depend on server's timestamp. * * @since 4.11.0 * * @param DateTimeImmutable $date The datetime which will overrides current datetime. * * @return void */ public function override_current_date( $date ) { $this->_custom_current_date = $date; } } return new ET_Builder_Module_Field_DisplayConditions();