widget->options['block-icon']) ? $this->widget->options['block-icon'] : ''; $this->category = !empty($this->widget->options['textdomain']) ? esc_attr( $this->widget->options['textdomain'] ) : 'Super Duper'; $this->name = $this->widget->id_base; $this->icon = (strpos($block_icon, 'fa') === 0) ? esc_attr($this->widget->options['block-icon']) : 'fas fa-globe-americas'; parent::__construct($element); } /** * Set the element name. * * @return array|string|string[]|null */ public function get_label() { $escaped_text = esc_attr( $this->widget->name ); return str_replace( ' > ', ' > ', $escaped_text ); // keep our > but have it safe } /** * Bricks function to set the controls * * @return void */ public function set_controls() { $args = $this->sd_convert_arguments($this->widget); if (!empty($args)) { $this->controls = $this->controls + $args; } } /** * Set the bricks control groups from the GD ones. * * @return void */ public function set_control_groups() { $args = $this->sd_get_arguments(); $groups = array(); if(!empty($args)) { foreach ($args as $k => $v) { $g_slug = !empty($v['group']) ? sanitize_title( $v['group'] ) : ''; if($g_slug && empty($groups[$g_slug])) { $groups[$g_slug] = array( 'title' => esc_html( $v['group'] ), 'tab' => 'content', ); } } } if(!empty($groups)) { $this->control_groups = $this->control_groups + $groups; } } /** * Get the setting input arguments. * * @return mixed */ public function sd_get_arguments() { $args = $this->widget->set_arguments(); $widget_options = ! empty( $this->widget->options ) ? $this->widget->options : array(); $widget_instance = ! empty( $this->widget->instance ) ? $this->widget->instance : array(); $args = apply_filters( 'wp_super_duper_arguments', $args, $widget_options, $widget_instance ); $arg_keys_subtract = $this->sd_remove_arguments(); if ( ! empty( $arg_keys_subtract ) ) { foreach($arg_keys_subtract as $key ){ unset($args[$key]); } } return $args; } /** * Simply use our own render function for the output. * * @return void */ public function render() { $settings = $this->sd_maybe_convert_values( $this->settings ); // Set the AyeCode UI calss on the wrapper $this->set_attribute( '_root', 'class', 'bsui' ); // We might need to add a placeholder here for previews. do_action( 'super_duper_before_render_bricks_element', $settings, $this->widget, $this ); // Add the bricks attributes to wrapper echo "
render_attributes( '_root' )}>"; echo $this->widget->output( $settings ); echo '
'; } /** * Values can never be arrays so convert if bricks setting make it an array. * * @param $settings * @return mixed */ public function sd_maybe_convert_values( $settings ) { if (!empty($settings)) { foreach( $settings as $k => $v ) { if(is_array($v)) { $value = ''; // is color if (isset($v['hex'])) { $value = $v['hex']; } elseif (isset($v['icon'])) { $value = $v['icon']; } // set the value $settings[$k] = $value; } } } return $settings; } /** * Convert SD arguments to Bricks arguments. * * @param $widget * * @return array */ public function sd_convert_arguments() { $bricks_args = array(); $args = $this->sd_get_arguments(); if ( ! empty( $args ) ) { foreach ( $args as $key => $arg ) { // convert title if ( ! empty( $arg['title'] ) ) { $arg['label'] = $arg['title']; unset( $arg['title'] ); } // set fields not to use dynamic data $arg['hasDynamicData'] = false; if ( ! empty( $arg['group'] ) ) { $arg['group'] = sanitize_title( $arg['group'] ); } $arg['rerender'] = true; // Convert checkbox to select, because Bricks settings don't save un-checked checkbox value. if ( isset( $arg['type'] ) && $arg['type'] == 'checkbox' && empty( $arg['multiple'] ) ) { $arg['type'] = 'select'; if ( ! empty( $arg['value'] ) && is_scalar( $arg['value'] ) && $arg['value'] !== '0' ) { $checked_value = $arg['value']; } else { $checked_value = '1'; } $arg['options'] = array( $checked_value => _x( 'Yes', 'Widget option: Yes', 'geodirectory' ), '0' => _x( 'No', 'Widget option: No', 'geodirectory' ) ); } // required if( ! empty( $arg['element_require'] ) ) { $arg['required'] = $this->sd_convert_required( $arg['element_require'] ); unset( $arg['element_require'] ); } // icons if ( 'icon' === $key ) { $arg['type'] = 'icon'; } // Bricks don't render dropdown when first option key is 0. if ( in_array( $key, array( 'zoom', 'mapzoom' ) ) && ! empty( $arg['options'] ) && is_array( $arg['options'] ) && ( $option_keys = array_keys( $arg['options'] ) ) ) { // Move first element to last. if ( $option_keys[0] === 0 || $option_keys[0] === '0' ) { $options = $arg['options']; unset( $arg['options'][0] ); $arg['options'][0] = $options[0]; } } $bricks_args[$key] = $arg; } } return $bricks_args; } /** * Convert the SD element_required to the Bricks required syntax. * * @param $element_require * @return array */ public function sd_convert_required($element_require) { $bricks_required = []; // Handle logical OR (||) for multiple values if (strpos($element_require, '||') !== false) { preg_match('/\[%(.+?)%\] *== *"(.*?)"/', $element_require, $matches); if ($matches) { $control_id = $matches[1]; preg_match_all('/\[%.*?%\] *== *"(.*?)"/', $element_require, $value_matches); $values = $value_matches[1]; $bricks_required[] = [$control_id, '=', $values]; } return $bricks_required; } // Match individual conditions preg_match_all('/(!)?\[%(.*?)%\](?:\s*([!=<>]=?)\s*(".*?"|\'.*?\'|\d+))?/', $element_require, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $is_negation = isset($match[1]) && $match[1] === '!'; $control_id = $match[2]; $operator = isset($match[3]) ? str_replace('==', '=', $match[3]) : ($is_negation ? '=' : '!='); $value = isset($match[4]) ? trim($match[4], '"\'') : ($is_negation ? '' : ''); // Adjust for negation without explicit operator if ($is_negation && !isset($match[3])) { $operator = '='; $value = ''; } $bricks_required[] = [$control_id, $operator, $value]; } return $bricks_required; } /** * A way to remove some settings by keys. * * @return array */ public function sd_remove_arguments() { return array(); } } /** * This implements the desktop, tablet and mobile breakpoints views with our fields that are hidden on these types and adda the icon after the label to show which it applies to. */ add_action( 'wp_enqueue_scripts', function() { // Check if we're in the Bricks Editor if ( isset( $_GET['bricks'] ) && $_GET['bricks'] && bricks_is_builder_main() ) { // Add inline script to the 'bricks-builder' script wp_add_inline_script( 'bricks-builder', " (function () { // Function to get the current breakpoint from the #bricks-preview class function getCurrentBreakpoint() { const bricksPreview = document.getElementById('bricks-preview'); if (!bricksPreview) return null; // Check which breakpoint class is active if (bricksPreview.classList.contains('desktop')) { return 'desktop'; } else if (bricksPreview.classList.contains('tablet_portrait')) { return 'tablet'; } else if (bricksPreview.classList.contains('mobile_landscape') || bricksPreview.classList.contains('mobile_portrait')) { return 'phone'; } return null; } // Function to group fields by base key function groupFields() { const controls = document.querySelectorAll('[data-controlkey]'); const grouped = {}; controls.forEach((control) => { const controlKey = control.getAttribute('data-controlkey'); const baseKey = controlKey.replace(/(_sm|_md|_lg)$/, ''); // Remove _sm, _md, or _lg suffix if (!grouped[baseKey]) { grouped[baseKey] = { base: null, md: null, lg: null }; } if (controlKey.endsWith('_lg')) { grouped[baseKey].lg = control; } else if (controlKey.endsWith('_md')) { grouped[baseKey].md = control; } else { grouped[baseKey].base = control; // No suffix is treated as base (sm) } }); return grouped; } // Function to update visibility of controls function updateControlVisibility() { const breakpoint = getCurrentBreakpoint(); const groupedFields = groupFields(); Object.keys(groupedFields).forEach((baseKey) => { const { base, md, lg } = groupedFields[baseKey]; // Skip fields that have no `_md` or `_lg` counterparts if (!md && !lg) { if (base) base.style.display = ''; // Ensure base field is always visible return; } // Apply hide/show logic based on the breakpoint if (breakpoint === 'desktop') { if (base) base.style.display = 'none'; if (md) md.style.display = 'none'; if (lg) lg.style.display = ''; // Show _lg } else if (breakpoint === 'tablet') { if (base) base.style.display = 'none'; if (md) md.style.display = ''; // Show _md if (lg) lg.style.display = 'none'; } else if (breakpoint === 'phone') { if (base) base.style.display = ''; // Show base (sm) if (md) md.style.display = 'none'; if (lg) lg.style.display = 'none'; } }); } // Observe changes in the #bricks-panel-element content const panelElementObserver = new MutationObserver(() => { updateControlVisibility(); }); const bricksPanelElement = document.getElementById('bricks-panel-element'); if (bricksPanelElement) { panelElementObserver.observe(bricksPanelElement, { childList: true, subtree: true }); } // Also observe changes to the #bricks-preview element for breakpoint changes const bricksPreviewObserver = new MutationObserver(() => { updateControlVisibility(); }); const bricksPreview = document.getElementById('bricks-preview'); if (bricksPreview) { bricksPreviewObserver.observe(bricksPreview, { attributes: true, attributeFilter: ['class'] }); } // Run on initial load updateControlVisibility(); })(); (function () { // Function to get the current breakpoint from the #bricks-preview class function getCurrentBreakpoint() { const bricksPreview = document.getElementById('bricks-preview'); if (!bricksPreview) return null; if (bricksPreview.classList.contains('desktop')) { return 'desktop'; } else if (bricksPreview.classList.contains('tablet_portrait')) { return 'tablet'; } else if (bricksPreview.classList.contains('mobile_landscape') || bricksPreview.classList.contains('mobile_portrait')) { return 'phone'; } return null; } // SVG icons const icons = { lg: ` `, md: ` `, sm: ` `, }; // Function to group fields by base key function groupFields() { const controls = document.querySelectorAll('[data-controlkey]'); const grouped = {}; controls.forEach((control) => { const controlKey = control.getAttribute('data-controlkey'); const baseKey = controlKey.replace(/(_sm|_md|_lg)$/, ''); // Remove _sm, _md, or _lg suffix if (!grouped[baseKey]) { grouped[baseKey] = { base: null, md: null, lg: null }; } if (controlKey.endsWith('_lg')) { grouped[baseKey].lg = control; } else if (controlKey.endsWith('_md')) { grouped[baseKey].md = control; } else { grouped[baseKey].base = control; // No suffix is treated as base (sm) } }); return grouped; } // Function to add icons to labels function addIconsToLabels() { const groupedFields = groupFields(); Object.keys(groupedFields).forEach((baseKey) => { const { base, md, lg } = groupedFields[baseKey]; // Skip fields that do not have `_md` or `_lg` counterparts if (!md && !lg) return; if (base) appendIcon(base, 'sm'); if (md) appendIcon(md, 'md'); if (lg) appendIcon(lg, 'lg'); }); } // Append an icon to the label of a control function appendIcon(control, type) { const label = control.querySelector('label'); if (label && !label.querySelector('.bricks-svg-wrapper')) { label.insertAdjacentHTML('beforeend', icons[type]); } } // Observe changes in the #bricks-panel-element content const panelElementObserver = new MutationObserver(() => { addIconsToLabels(); // Ensure icons are added when the panel updates }); const bricksPanelElement = document.getElementById('bricks-panel-element'); if (bricksPanelElement) { panelElementObserver.observe(bricksPanelElement, { childList: true, subtree: true }); } // Initial run to add icons addIconsToLabels(); })(); " ); } });