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();
})();
"
);
}
});