| Server IP : 103.88.176.108 / Your IP : 216.73.216.211 Web Server : Apache/2.4.41 (Ubuntu) System : Linux webserver 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64 User : www-data ( 33) PHP Version : 7.4.3-4ubuntu2.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /var/www/html/wp-content/themes/neve/header-footer-grid/Core/Builder/ |
Upload File : |
<?php
/**
* Abstract Builder class for Header Footer Grid.
*
* Name: Header Footer Grid
* Author: Bogdan Preda <bogdan.preda@themeisle.com>
*
* @version 1.0.0
* @package HFG
*/
namespace HFG\Core\Builder;
use HFG\Core\Components\Abstract_Component;
use HFG\Core\Components\Nav;
use HFG\Core\Css_Generator;
use HFG\Core\Interfaces\Builder;
use HFG\Core\Interfaces\Component;
use HFG\Core\Settings;
use HFG\Core\Settings\Manager as SettingsManager;
use HFG\Traits\Core;
use Neve\Core\Settings\Config;
use Neve\Core\Styles\Css_Prop;
use Neve\Core\Styles\Dynamic_Selector;
use Neve\Core\Theme_Info;
use Neve\Customizer\Controls\React\Instructions_Section;
use WP_Customize_Manager;
/**
* Class Abstract_Builder
*
* @package HFG\Core\Builder
*/
abstract class Abstract_Builder implements Builder {
use Core;
use Theme_Info;
const LAYOUT_SETTING = 'layout';
const COLUMNS_NUMBER = 'columns_number';
const COLUMNS_LAYOUT = 'columns_layout';
const HEIGHT_SETTING = 'height';
const BOTTOM_BORDER = 'bottom_border';
const BORDER_COLOR = 'border_color';
const SKIN_SETTING = 'skin';
const TEXT_COLOR = 'new_text_color';
const BACKGROUND_SETTING = 'background';
const WIDTH = 'width';
const CONTENT_ALIGNMENT = 'content_alignment';
const VERTICAL_ALIGN = 'vertical_align';
/**
* Layout config data.
*
* @var array Layout data.
*/
private $layout_data = [];
/**
* Active components ids.
*
* @var array Layout data.
*/
private $active_components = [];
/**
* Internal pointer for current device id.
*
* @var null|string Device id.
*/
public static $current_device = null;
/**
* Internal pointer for current row id.
*
* @var null|string Row id.
*/
public static $current_row = null;
/**
* Internal pointer for current slot id.
*
* @var null|string Slot id.
*/
public static $current_slot = null;
/**
* Internal pointer for current component id.
*
* @var null|string Component id.
*/
public static $current_component = null;
/**
* Internal pointer for current builder id.
*
* @var null|string Builder id.
*/
public static $current_builder = null;
/**
* Holds the control id.
*
* @since 1.0.0
* @access protected
* @var string $control_id
*/
protected $control_id;
/**
* Holds the layout control id.
*
* @since 3.0.0
* @access protected
* @var string $layout_control_id
*/
protected $layout_control_id;
/**
* Holds the panel id.
*
* @since 1.0.0
* @access protected
* @var string $panel
*/
protected $panel;
/**
* Holds the section id.
*
* @since 1.0.0
* @access protected
* @var string $section
*/
protected $section;
/**
* Holds the title.
*
* @since 1.0.0
* @access public
* @var string|null $title
*/
public $title;
/**
* Holds the description.
*
* @since 1.0.1
* @access public
* @var string|null $description
*/
public $description;
/**
* A list of panel keys to be removed.
*
* @since 1.0.0
* @access protected
* @var array $remove_panels
*/
protected $remove_panels = [];
/**
* A list of sections keys to be removed.
*
* @since 1.0.0
* @access protected
* @var array $remove_sections
*/
protected $remove_sections = [];
/**
* A list of supported devices and labels.
*
* @since 1.0.0
* @access protected
* @var array $devices
*/
protected $devices = [];
/**
* Default colors for rows.
*
* Holds the default values for row colors.
*
* @since 1.0.0
* @access protected
* @var array
*/
protected $default_colors = array(
'header' => array(
'top' => '#f0f0f0',
'main' => '#ffffff',
'bottom' => '#ffffff',
'sidebar' => '#ffffff',
),
'footer' => array(
'top' => '#ffffff',
'bottom' => '#24292e',
),
'page_header' => array(
'top' => '#ffffff',
'bottom' => '#ffffff',
),
);
/**
* A list of builder components.
*
* @since 1.0.0
* @access protected
* @var array $builder_components
*/
protected $builder_components = array();
/**
* The quick links setup array.
*
* @var array
*/
protected $instructions_array = array();
/**
* Does this layout have columns?
*
* @var boolean
*/
protected $columns_layout = false;
/**
* Abstract_Builder constructor.
*
* @since 1.0.0
* @access public
*/
public function __construct() {
$this->set_property( 'control_id', 'hfg_' . $this->get_id() . '_layout' );
$this->set_property( 'layout_control_id', $this->control_id . ( neve_is_new_builder() ? '_v2' : '' ) );
$this->set_property( 'panel', 'hfg_' . $this->get_id() );
$this->set_property( 'section', $this->control_id . '_section' );
$this->init();
add_action( 'hfg_' . $this->get_id() . '_render', [ $this, 'load_template' ] );
$this->define_builder_settings();
foreach ( $this->get_rows() as $row_id => $row_name ) {
$this->define_row_settings( $row_id );
}
add_filter( 'hfg_header_row_classes', [ $this, 'add_header_row_utility_classes' ], 10, 2 );
add_filter( 'hfg_page_header_row_classes', [ $this, 'add_header_row_utility_classes' ], 10, 2 );
$this->devices = [
'desktop' => __( 'Desktop', 'neve' ),
'mobile' => __( 'Mobile', 'neve' ),
];
}
/**
* Method to set protected properties for class.
*
* @param string $key The property key name.
* @param mixed $value The property value.
*
* @return bool
* @since 1.0.0
* @access protected
*/
protected function set_property( $key = '', $value = '' ) {
if ( ! property_exists( $this, $key ) ) {
return false;
}
$this->$key = $value;
return true;
}
/**
* Define builder settings.
*/
public function define_builder_settings() {
$is_new_builder = neve_is_new_builder();
SettingsManager::get_instance()->add(
[
'id' => $this->layout_control_id,
'group' => $this->control_id,
'tab' => false,
'noformat' => true,
'transport' => 'post' . $this->get_id(),
'sanitize_callback' => [ $this, 'sanitize_json' ],
'default' => '',
'label' => '',
'type' => $is_new_builder ? '\Neve\Customizer\Controls\React\Builder' : 'text',
'options' => [
'builder_type' => $this->get_id(),
'columns_layout' => $this->columns_layout,
],
'conditional_header' => $this->get_id() === 'header',
'section' => $this->section,
]
);
do_action( 'hfg_row_settings', $this->get_id(), $this->control_id );
}
/**
* Used to define the rows in the builder sections.
*
* @return array Rows array.
*/
abstract protected function get_rows();
/**
* Define Row settings.
*
* @param string $row_id Row id.
*/
public function define_row_settings( $row_id ) {
$row_setting_id = $this->control_id . '_' . $row_id;
$row_class = '.' . join(
'-',
array(
$this->get_id(),
$row_id,
'inner',
)
);
if ( $row_id === 'sidebar' ) {
$row_class = '.header-menu-sidebar';
}
SettingsManager::get_instance()->add(
[
'id' => $row_setting_id,
'transport' => 'postMessage',
'sanitize_callback' => array( $this, 'sanitize_json' ),
'default' => '',
]
);
if ( $row_id === 'sidebar' ) {
$this->add_sidebar_controls( $row_setting_id );
}
if ( $row_id !== 'sidebar' ) {
SettingsManager::get_instance()->add(
[
'id' => self::LAYOUT_SETTING,
'group' => $row_setting_id,
'tab' => SettingsManager::TAB_LAYOUT,
'label' => __( 'Layout', 'neve' ),
'type' => 'select',
'section' => $row_setting_id,
'options' => [
'choices' => [
'layout-full-contained' => __( 'Full Width', 'neve' ) . ' - ' . __( 'Contained', 'neve' ),
'layout-fullwidth' => __( 'Full Width', 'neve' ),
'layout-contained' => __( 'Contained', 'neve' ),
],
],
'conditional_header' => $this->get_id() === 'header',
'transport' => 'post' . $row_setting_id,
'sanitize_callback' => 'wp_filter_nohtml_kses',
'default' => 'layout-full-contained',
]
);
SettingsManager::get_instance()->add(
[
'id' => self::HEIGHT_SETTING,
'group' => $row_setting_id,
'tab' => SettingsManager::TAB_STYLE,
'section' => $row_setting_id,
'label' => __( 'Row height', 'neve' ),
'type' => '\Neve\Customizer\Controls\React\Responsive_Range',
'live_refresh_selector' => $row_class,
'live_refresh_css_prop' => [
'cssVar' => [
'responsive' => true,
'vars' => '--height',
'suffix' => 'px',
'fallback' => 'auto',
'selector' => $row_class,
'dispatchWindowResize' => true,
],
'prop' => 'height',
'unit' => 'px',
],
'options' => [
'input_attrs' => [
'min' => 0,
'max' => 700,
'defaultVal' => [
'mobile' => 0,
'tablet' => 0,
'desktop' => 0,
'suffix' => [
'mobile' => 'px',
'tablet' => 'px',
'desktop' => 'px',
],
],
'units' => [ 'px', 'em', 'rem' ],
],
],
'transport' => 'postMessage',
'sanitize_callback' => array( $this, 'sanitize_responsive_int_json' ),
'default' => '{ "mobile": "0", "tablet": "0", "desktop": "0" }',
'conditional_header' => $this->get_id() === 'header',
]
);
SettingsManager::get_instance()->add(
[
'id' => self::BOTTOM_BORDER,
'group' => $row_setting_id,
'tab' => SettingsManager::TAB_STYLE,
'section' => $row_setting_id,
'label' => __( 'Border Width', 'neve' ),
'type' => '\Neve\Customizer\Controls\React\Responsive_Range',
'live_refresh_selector' => true,
'live_refresh_css_prop' => [
'cssVar' => [
'responsive' => true,
'vars' => '--rowbwidth',
'suffix' => 'px',
'fallback' => '0',
'selector' => '.' . $this->get_id() . '-' . $row_id,
'dispatchWindowResize' => true,
],
],
'options' => [
'input_attrs' => [
'min' => 0,
'max' => 50,
'defaultVal' => [
'mobile' => 0,
'tablet' => 0,
'desktop' => 0,
'suffix' => [
'mobile' => 'px',
'tablet' => 'px',
'desktop' => 'px',
],
],
'units' => [ 'px' ],
],
],
'transport' => 'postMessage',
'sanitize_callback' => array( $this, 'sanitize_responsive_int_json' ),
'default' => '{ "mobile": "0", "tablet": "0", "desktop": "0" }',
'conditional_header' => $this->get_id() === 'header',
]
);
SettingsManager::get_instance()->add(
[
'id' => self::BORDER_COLOR,
'group' => $row_setting_id,
'tab' => SettingsManager::TAB_STYLE,
'label' => __( 'Border Color', 'neve' ),
'section' => $row_setting_id,
'conditional_header' => $this->get_id() === 'header',
'type' => 'neve_color_control',
'transport' => 'postMessage',
'live_refresh_selector' => true,
'live_refresh_css_prop' => [
'cssVar' => [
'vars' => '--rowbcolor',
'selector' => '.' . $this->get_id() . '-' . $row_id,
],
],
'sanitize_callback' => 'neve_sanitize_colors',
'default' => 'var(--nv-light-bg)',
]
);
}
if ( $this->columns_layout && neve_is_new_builder() ) {
$this->add_columns_layout_controls( $row_setting_id, $row_id );
}
$default_colors = $this->get_default_row_colors( $row_id );
SettingsManager::get_instance()->add(
[
'id' => self::BACKGROUND_SETTING,
'group' => $row_setting_id,
'tab' => SettingsManager::TAB_STYLE,
'section' => $row_setting_id,
'label' => __( 'Row Background', 'neve' ),
'type' => '\Neve\Customizer\Controls\React\Background',
'live_refresh_selector' => $row_id === 'sidebar' ? $row_class . ' .header-menu-sidebar-bg' : $row_class,
'live_refresh_css_prop' => [
'cssVar' => [
'vars' => 'backgroundControl',
'selector' => $row_id === 'sidebar' ? '.header-menu-sidebar-bg' : '.' . $this->get_id() . '-' . $row_id,
],
'partial' => $row_id === 'sidebar' ? 'hfg_header_layout_partial' : $row_setting_id . '_partial',
],
'options' => [
'priority' => 100,
'active_callback' => function () use ( $row_id ) {
return $this->has_background_setting( $row_id );
},
],
'default' => [
'type' => 'color',
'colorValue' => $default_colors['background'],
],
'transport' => 'postMessage',
'sanitize_callback' => 'neve_sanitize_background',
'conditional_header' => $this->get_id() === 'header',
]
);
do_action( 'hfg_add_settings_to_rows', SettingsManager::get_instance(), $row_setting_id, $row_id, $this->get_id() );
SettingsManager::get_instance()->add(
[
'id' => self::TEXT_COLOR,
'group' => $row_setting_id,
'tab' => SettingsManager::TAB_STYLE,
'label' => __( 'Text Color', 'neve' ),
'section' => $row_setting_id,
'conditional_header' => $this->get_id() === 'header',
'type' => 'neve_color_control',
'transport' => 'postMessage',
'live_refresh_selector' => $row_class,
'live_refresh_css_prop' => [
'cssVar' => [
'vars' => '--color',
'selector' => $row_id === 'sidebar' ? '.header-menu-sidebar-bg' : '.' . $this->get_id() . '-' . $row_id,
],
'partial' => $row_id === 'sidebar' ? 'hfg_header_layout_partial' : $row_setting_id . '_partial',
],
'sanitize_callback' => 'wp_filter_nohtml_kses',
'default' => $default_colors['text'],
]
);
if ( $this->get_id() === 'header' && $row_id !== 'sidebar' ) {
SettingsManager::get_instance()->add(
[
'id' => 'global_header_background_shortcut',
'group' => $row_setting_id,
'section' => $row_setting_id,
'tab' => 'style',
'transport' => 'postMessage',
'sanitize_callback' => 'esc_attr',
'type' => '\Neve\Customizer\Controls\Button',
'options' => [
'button_text' => esc_html__( 'Background', 'neve' ),
'active_callback' => function() {
return ! get_theme_mod( 'neve_pro_global_header_settings_advanced_style', true );
},
'button_class' => 'button_background',
'icon_class' => 'edit',
'shortcut' => true,
'is_button' => false,
'control_to_focus' => 'neve_pro_global_header_settings_background',
],
]
);
}
do_action( 'hfg_row_settings', $this->get_id(), $row_id, $row_setting_id );
}
/**
* Decides if the background setting should be visible for current row.
*
* @param string $row_id The row id.
* @return bool True if setting should be displayed, false if not.
*/
public function has_background_setting( $row_id ) {
if ( $this->get_id() !== 'header' ) {
return true;
}
if ( $row_id === 'sidebar' ) {
return true;
}
if ( get_theme_mod( 'neve_pro_global_header_settings_advanced_style', true ) === true ) {
return true;
}
return false;
}
/**
* Returns current builder id.
*
* @return string|null Builder id.
*/
public static function get_current_builder() {
return self::$current_builder;
}
/**
* Define templates used to loading the builder.
*/
abstract public function load_template();
/**
* Method to get protected properties for class.
*
* @param string $key The property key name.
*
* @return mixed
* @since 1.0.0
* @access protected
*/
public function get_property( $key = '' ) {
if ( ! property_exists( $this, $key ) ) {
return false;
}
return $this->$key;
}
/**
* Register builder scripts
*
* @since 1.0.0
* @access public
*/
public function scripts() {
wp_add_inline_style( 'hfg-customizer-control', $this->inline_builder_styles() );
}
/**
* Returns a string of css rules.
*
* @return string
* @since 1.0.0
* @access protected
*/
protected function inline_builder_styles() {
$style = '';
$style_array = [];
$rows = $this->get_rows();
if ( ! empty( $rows ) ) {
foreach ( $rows as $row_id => $row_label ) {
$style_array[ '#accordion-section-' . $this->control_id . '_' . $row_id ] = array(
'display' => 'none !important',
);
}
}
return $style . $this->css_array_to_css( $style_array );
}
/**
* Called to register component controls.
*
* @param WP_Customize_Manager $wp_customize The Customize Manager.
*
* @return WP_Customize_Manager
* @since 1.0.0
* @access public
*/
public function customize_register( WP_Customize_Manager $wp_customize ) {
/**
* An instance of Component.
*
* @var Component $component
*/
foreach ( $this->builder_components as $component ) {
$component->customize_register( $wp_customize );
}
/** @var \WP_Customize_Panel|null $panel */
$panel = $wp_customize->get_panel( $this->panel );
if ( null !== $panel ) {
return $wp_customize;
}
$title = ( isset( $this->title ) && ! empty( $this->title ) )
? $this->title
: __( 'Header', 'neve' );
$description = ( isset( $this->description ) && ! empty( $this->description ) )
? $this->description
: '';
$wp_customize->add_panel(
$this->panel,
/* @phpstan-ignore-next-line The wordpress-stub os incorect, proper type should be string|array for `theme_supports` */
array(
'priority' => 25,
'capability' => 'edit_theme_options',
'theme_supports' => Settings\Config::get_support(),
'title' => $title,
'description' => $description,
)
);
$wp_customize->add_section(
$this->section,
array(
'title' => $title,
'priority' => 299,
'panel' => $this->panel,
)
);
if ( ! empty( $this->instructions_array ) ) {
$wp_customize->add_section(
new Instructions_Section(
$wp_customize,
$this->section . '_quick_links',
array(
'priority' => - 100,
'panel' => $this->panel,
'type' => 'hfg_instructions',
'options' => $this->instructions_array,
)
)
);
}
Settings\Manager::get_instance()->load( $this->control_id, $wp_customize );
$this->add_rows_controls( $wp_customize );
$wp_customize->selective_refresh->add_partial(
$this->control_id . '_partial',
array(
'selector' => '.' . $this->panel,
'settings' => Settings\Manager::get_instance()->get_transport_group( $this->get_id() ),
'render_callback' => array( $this, 'render' ),
)
);
$wp_customize = apply_filters( 'hfg_after_builder_' . $this->get_id() . '_registered', $wp_customize, $this );
return $wp_customize;
}
/**
* Adds row controls.
*
* @param WP_Customize_Manager $wp_customize The Customize Manager.
*
* @return WP_Customize_Manager|null
* @since 1.0.0
* @access protected
*/
protected function add_rows_controls( $wp_customize ) {
$rows = $this->get_rows();
if ( empty( $rows ) ) {
return null;
}
foreach ( $rows as $row_id => $row ) {
$row_setting_id = $this->control_id . '_' . $row_id;
$title = $row;
$description = '';
if ( is_array( $row ) ) {
$title = ( isset( $row['title'] ) && ! empty( $row['title'] ) )
? $row['title']
: __( 'Section Content', 'neve' );
$description = ( isset( $row['description'] ) && ! empty( $row['description'] ) )
? $row['description']
: $description;
}
$wp_customize->add_section(
$row_setting_id,
array(
'title' => $title,
'description' => $description,
'description_hidden' => ( $description !== '' ),
'priority' => 100,
'panel' => $this->panel,
)
);
Settings\Manager::get_instance()->load( $row_setting_id, $wp_customize );
$wp_customize->selective_refresh->add_partial(
$row_setting_id . '_partial',
array(
'selector' => '.' . $this->panel,
'settings' => Settings\Manager::get_instance()->get_transport_group( $row_setting_id ),
'render_callback' => array( $this, 'render' ),
)
);
}
return $wp_customize;
}
/**
* Return current device in the loop.
*
* @return null|string Current device.
*/
public function get_current_device() {
return self::$current_device;
}
/**
* Return current row in the loop.
*
* @return null|string Current row.
*/
public function get_current_row_index() {
return self::$current_row;
}
/**
* Return current slot in the loop.
*
* @return null|string Current slot.
*/
public function get_current_slot_index() {
return self::$current_slot;
}
/**
* Render markup for builder.
*/
public function render() {
$layout = $this->get_layout_data();
self::$current_builder = $this->get_id();
if ( is_customize_preview() ) {
$style = $this->add_style( [] );
$generator = new Css_Generator();
$generator->set( $style );
$style = $generator->generate();
echo '<style type="text/css" id="' . esc_attr( $this->get_id() ) . '-style">' . $style . '</style>';// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
foreach ( $layout as $device_name => $device ) {
if ( empty( $device ) ) {
continue;
}
self::$current_device = $device_name;
$this->render_device( $device_name, $device );
}
}
/**
* Return builder data.
*
* @return array Builder data.
*/
public function get_layout_data() {
if ( ! empty( $this->layout_data ) ) {
return $this->layout_data;
}
$mod_value = json_decode( SettingsManager::get_instance()->get( $this->layout_control_id ), true );
$this->layout_data = wp_parse_args( $mod_value, array_fill_keys( array_keys( $this->devices ), array_fill_keys( array_keys( $this->get_rows() ), [] ) ) );
return $this->layout_data;
}
/**
* See if row is populated.
*
* @param string $row_id Row id.
*
* @return bool Is row used?
*/
public function is_row_used( $row_id ) {
foreach ( $this->get_layout_data() as $devices ) {
if ( isset( $devices[ $row_id ] ) && ! empty( $devices[ $row_id ] ) ) {
return true;
}
}
return false;
}
/**
* Check if component is used in builder.
*
* @param string $component_id Component id.
*
* @return bool Is used?
*/
public function is_component_active( $component_id ) {
if ( empty( $this->active_components ) ) {
$components = [];
foreach ( $this->get_layout_data() as $devices ) {
foreach ( $devices as $row_index => $row ) {
if ( neve_is_new_builder() && $row_index !== 'sidebar' ) {
foreach ( $row as $slot ) {
if ( empty( $slot ) || ! is_array( $slot ) ) {
continue;
}
$components = array_merge( $components, array_combine( wp_list_pluck( $slot, 'id' ), array_fill( 0, count( $slot ), true ) ) );
}
continue;
}
// Legacy
$row_components = [];
foreach ( $row as $component ) {
if ( isset( $component['id'] ) ) {
$row_components[ $component['id'] ] = true;
}
}
$components = array_merge( $components, $row_components );
}
}
$this->active_components = $components;
}
return isset( $this->active_components[ $component_id ] );
}
/**
* Method to add Builder css styles.
*
* @param array $css_array An array containing css rules.
*
* @return array
* @since 1.0.0
* @access public
*/
public function add_style( array $css_array = array() ) {
foreach ( $this->get_rows() as $row_index => $row_label ) {
if ( ! $this->is_row_used( $row_index ) ) {
continue;
}
$css_array = $this->add_row_style( $row_index, $css_array );
}
/**
* An instance of Component.
*
* @var Abstract_Component $component
*/
foreach ( $this->builder_components as $component ) {
if ( ! $this->is_component_active( $component->get_id() ) ) {
continue;
}
$css_array = $component->add_style( $css_array );
}
return $css_array;
}
/**
* Returns the featured image for the header row.
*
* @param string $image_url The image URL.
* @param boolean $use_featured Flag if featured image should be used.
* @param array $meta Additional meta for the image.
*
* @return string
*/
protected function get_row_featured_image( $image_url, $use_featured, $meta ) {
$image = 'none';
if ( ! empty( $use_featured ) && $use_featured === true && is_singular() ) {
$featured_image = get_the_post_thumbnail_url();
if ( ! empty( $featured_image ) ) {
$image = sprintf( 'url("%s")', esc_url( $featured_image ) );
} else {
$image = sprintf( 'url("%s")', esc_url( $image_url ) );
}
} elseif ( ! empty( $image_url ) ) {
$image = sprintf( 'url("%s")', esc_url( $image_url ) );
}
/**
* Filters the background featured image output url.
*
* @param string $image The background image value: `none` or `url(<url>)`.
* @param boolean $use_featured Flag to specify if featured image should be used or fallback.
* @param array $meta Additional meta for the image.
*
* @since 3.0.5
*/
return apply_filters( 'nv_builder_row_image_url', $image, $use_featured, $meta );
}
/**
* Method to generate css array for each row.
*
* @param string $row_index The row index.
* @param array $css_array The css array.
*
* @return array
* @since 1.0.0
* @access private
*/
private function add_row_style( $row_index, $css_array = array() ) {
$css_array = $this->add_new_builder_styles( $css_array, $row_index );
$rules = [];
$selector = $row_index === 'sidebar' ? '.header-menu-sidebar-bg' : '.' . $this->get_id() . '-' . $row_index;
$default_colors = $this->get_default_row_colors( $row_index );
if ( $row_index !== 'sidebar' ) {
$rules['--height'] = [
Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_height',
Dynamic_Selector::META_IS_RESPONSIVE => true,
Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) {
$value = (int) $value;
$unit_suffix = Css_Prop::get_suffix_responsive( $meta, $device );
if ( $value > 0 ) {
return sprintf( '%s:%s;', $css_prop, $value . $unit_suffix );
}
return '';
},
Dynamic_Selector::META_SUFFIX => 'responsive_suffix',
Dynamic_Selector::META_DEFAULT => '{ desktop: 0, tablet: 0, mobile: 0 }',
];
$rules['--rowbwidth'] = [
Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_' . self::BOTTOM_BORDER,
Dynamic_Selector::META_IS_RESPONSIVE => true,
Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) {
$value = (int) $value;
if ( $value >= 0 ) {
return sprintf( '%s:%s;', $css_prop, $value . 'px' );
}
return '';
},
];
$rules['--rowbcolor'] = [
Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_' . self::BORDER_COLOR,
Dynamic_Selector::META_DEFAULT => 'var(--nv-light-bg)',
];
}
$rules['--color'] = [
Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_' . self::TEXT_COLOR,
Dynamic_Selector::META_DEFAULT => $default_colors['text'],
];
// Exclude the following rules for the header when the global header background is active.
if ( get_theme_mod( 'neve_pro_global_header_settings_advanced_style', true ) === true || $this->get_id() !== 'header' || $row_index === 'sidebar' ) {
// If there is no default, use site background.
$default_color = isset( $default_colors['background'] ) ? $default_colors['background'] : 'var(--nv-site-bg)';
$background = get_theme_mod(
$this->control_id . '_' . $row_index . '_background',
[
'type' => 'color',
'colorValue' => $default_color,
]
);
if ( $background['type'] === 'color' && ! empty( $background['colorValue'] ) ) {
$rules = array_merge(
$rules,
[
'--bgcolor' => [
Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_background.colorValue',
Dynamic_Selector::META_DEFAULT => $default_color,
],
]
);
}
if ( $background['type'] === 'image' ) {
$rules = array_merge(
$rules,
[
'--overlaycolor' => [
Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_background.overlayColorValue',
],
'--bgimage' => [
Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_background',
Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) {
$image_url = array_key_exists( 'imageUrl', $value ) ? $value['imageUrl'] : '';
$use_featured = array_key_exists( 'useFeatured', $value ) ? $value['useFeatured'] : false;
$image = $this->get_row_featured_image( $image_url, $use_featured, $meta );
return sprintf( '%s:%s;', $css_prop, $image );
},
],
'--bgposition' => [
Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_background',
Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) {
$focus_point = array_key_exists( 'focusPoint', $value ) ? $value['focusPoint'] : false;
if ( ! $this->is_valid_focus_point( $focus_point ) ) {
return '';
}
$parsed_position = round( $value['focusPoint']['x'] * 100 ) . '% ' . round( $value['focusPoint']['y'] * 100 ) . '%;';
return sprintf( '%s:%s;', $css_prop, $parsed_position );
},
],
'--bgattachment' => [
Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_background',
Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) {
if ( ! isset( $value['fixed'] ) || $value['fixed'] !== true ) {
return '';
}
return sprintf( '%s:fixed;', $css_prop );
},
],
'--bgoverlayopacity' => [
Dynamic_Selector::META_KEY => $this->control_id . '_' . $row_index . '_background',
Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) {
if ( ! isset( $value['overlayOpacity'] ) ) {
return '';
}
return sprintf( '%s:%s;', $css_prop, $value['overlayOpacity'] / 100 );
},
],
]
);
}
}
$css_array[] = [
Dynamic_Selector::KEY_SELECTOR => $selector,
Dynamic_Selector::KEY_RULES => $rules,
];
if ( $row_index === 'sidebar' ) {
$css_array = $this->add_sidebar_styles( $css_array );
}
return $css_array;
}
/**
* Render device markup.
*
* @param string $device_name Device id.
* @param array $device_details Device meta.
*/
public function render_device( $device_name, $device_details ) {
// Make sure we hold the defined order.
$default_order = array_keys( $this->get_rows() );
foreach ( $default_order as $row_index ) {
if ( ! isset( $device_details[ $row_index ] ) ) {
continue;
}
$row = $device_details[ $row_index ];
if ( neve_is_new_builder() ) {
$used = [];
foreach ( $row as $components ) {
$used = array_merge( $used, $components );
}
if ( empty( $used ) ) {
if ( $this->get_id() !== 'footer' ) {
continue;
}
if ( $row_index !== 'bottom' ) {
continue;
}
if ( $this->has_valid_addons() ) {
continue;
}
}
} elseif ( empty( $row ) ) {
continue;
}
self::$current_row = $row_index;
$this->render_row( $device_name, $row_index, $row );
}
}
/**
* Get the component alignment.
*
* @param string $id component id.
* @param bool $vertical should get vertical alignment.
*
* @return array|string|false
*/
private function get_component_alignment( $id, $vertical = false ) {
if ( $vertical ) {
return SettingsManager::get_instance()->get( $id . '_' . Abstract_Component::VERTICAL_ALIGN_ID, null );
}
$alignment = SettingsManager::get_instance()->get( $id . '_' . Abstract_Component::ALIGNMENT_ID, null );
// Make sure we migrate old alignment values.
if ( is_array( $alignment ) ) {
return $alignment;
}
$is_menu_component = strpos( $id, 'primary-menu' ) > - 1 || strpos( $id, 'secondary-menu' );
$tmp_align = ( is_string( $alignment ) && in_array(
$alignment,
[
'left',
'right',
'center',
'justify',
]
) ) ? $alignment : 'left';
return [
'desktop' => $tmp_align,
'tablet' => $is_menu_component ? 'left' : $tmp_align,
'mobile' => $is_menu_component ? 'left' : $tmp_align,
];
}
/**
* Checks if a row has items inside a slot.
*
* @param string $slot slot to check in row.
*
* @return bool
*/
private function row_has_slot( $slot ) {
$current_row = $this->get_current_row_index();
$layout_data = $this->get_layout_data();
$device = $this->get_current_device();
if ( ! isset( $layout_data[ $device ] ) ) {
return false;
}
if ( ! isset( $layout_data[ $device ][ $current_row ] ) ) {
return false;
}
$row_data = $layout_data[ $device ][ $current_row ];
if ( ! isset( $row_data[ $slot ] ) || empty( $row_data[ $slot ] ) ) {
return false;
}
return true;
}
/**
* Add row utility classes.
*
* @param array $classes footer classes.
* @param string $row_index row index.
*
* @return mixed
*/
public function add_header_row_utility_classes( $classes, $row_index ) {
if ( $this->get_id() !== self::$current_builder ) {
return $classes;
}
if ( $this->row_has_slot( 'center' ) ) {
$classes[] = 'has-center';
}
return $classes;
}
/**
* Render the builder components.
*
* @param string|null $device the device [desktop|mobile].
*/
public function new_render_components( $device ) {
$row_index = 0;
if ( $device === null ) {
$device = self::$current_device;
$row_index = self::$current_row;
}
$builder_id = $this->get_id();
$data = $this->get_layout_data()[ $device ][ $row_index ];
// Remap sidebar data so we can use it as a slot.
if ( $row_index === 'sidebar' ) {
$data = [ 'sidebar' => $data ];
}
$render_buffer = [
'left' => [],
'c-left' => [],
'center' => [],
'c-right' => [],
'right' => [],
];
$slot = null;
$component_index = null;
$slot_data = null;
foreach ( $data as $slot => $slot_data ) {
$is_side_slot = in_array( $slot, [ 'right', 'left' ], true );
if ( ! ( $this->row_has_slot( 'center' ) && $is_side_slot ) && empty( $slot_data ) && $builder_id !== 'footer' ) {
continue;
}
$render_index = 0;
$was_previous_mergeable = false;
$has_divider = false;
foreach ( $slot_data as $component_index => $component ) {
if ( ! isset( $component['id'] ) ) {
continue;
}
if ( ! isset( $this->builder_components[ $component['id'] ] ) ) {
continue;
}
$has_divider = false;
if ( preg_match( '/^divider/', $component['id'] ) ) {
$has_divider = true;
}
/**
* An instance of Abstract_Component
*
* @var Abstract_Component $component_instance
*/
$component_instance = $this->builder_components[ $component['id'] ];
$is_mergeable = $component_instance->get_property( 'is_auto_width' );
if ( ! $is_mergeable && ! $was_previous_mergeable ) {
$render_index ++;
}
if ( $row_index === 'sidebar' ) {
$render_index ++;
}
$align = $this->get_component_alignment( $component['id'] );
$vertical_align = $this->get_component_alignment( $component['id'], true );
$classes = [ 'builder-item' ];
if ( strpos( $component['id'], 'primary-menu' ) > - 1 ) {
$classes[] = 'has-nav';
}
// We don't add align classes to primary menus as there's no align control in new skin.
if ( strpos( $component['id'], Nav::COMPONENT_ID ) === false ) {
foreach ( $align as $device_slug => $align_slug ) {
$alignment_is_mobile = in_array( $device_slug, [ 'tablet', 'mobile' ], true );
$is_header_sidebar = $builder_id === 'header' && $row_index === 'sidebar';
// Make sure we don't apply device-specific classes if the rows aren't visible on respective device.
// Footer has same rows on all devices.
if ( $builder_id === 'footer' || $is_header_sidebar || ( $device === $device_slug || ( $alignment_is_mobile && $device === 'mobile' ) ) ) {
$classes[] = $device_slug . '-' . $align_slug;
}
}
}
// If we don't have anything at render index, make sure we do.
if ( ! isset( $render_buffer[ $slot ][ $render_index ] ) ) {
$render_buffer[ $slot ][ $render_index ] = [
'classes' => $classes,
'components' => [],
];
}
// If the component is a divider, add a supplementary class
if ( $has_divider && ! in_array( 'has-divider', $render_buffer[ $slot ][ $render_index ]['classes'], true ) && $row_index !== 'sidebar' ) {
$render_buffer[ $slot ][ $render_index ]['classes'][] = 'has-divider';
}
$render_buffer[ $slot ][ $render_index ]['components'][] = $component['id'];
if ( $is_mergeable ) {
$was_previous_mergeable = true;
continue;
}
$was_previous_mergeable = false;
}
if ( isset( $render_buffer[ $slot ] ) && is_array( $render_buffer[ $slot ] ) ) {
$render_buffer[ $slot ] = array_values( $render_buffer[ $slot ] );
}
}
if ( ! $this->columns_layout ) {
if ( $slot === 'c-left' && $component_index === 0 ) {
$classes[] = 'hfg-end';
}
if ( $slot === 'c-right' && $component_index === count( $slot_data ) - 1 ) {
$classes[] = 'hfg-start';
}
}
if ( ! $this->columns_layout ) {
// Move center-side-slot components inside the side slots.
if ( isset( $render_buffer['c-right'] ) ) {
$length = count( $render_buffer['c-right'] ) - 1;
if ( $length >= 0 ) {
$render_buffer['c-right'][ $length ]['classes'][] = 'hfg-start';
}
$render_buffer['right'] = array_merge( $render_buffer['c-right'], $render_buffer['right'] );
}
if ( isset( $render_buffer['c-left'] ) ) {
$render_buffer['c-left'][0]['classes'][] = 'hfg-end';
$render_buffer['left'] = array_merge( $render_buffer['left'], $render_buffer['c-left'] );
}
unset( $render_buffer['c-left'] );
unset( $render_buffer['c-right'] );
} else {
// Drop the unused columns for columned layout.
$columns = SettingsManager::get_instance()->get( 'hfg_footer_layout_' . $row_index . '_' . self::COLUMNS_NUMBER, 3 );
array_splice( $render_buffer, absint( $columns ) );
}
foreach ( $render_buffer as $slot => $slot_data ) {
if ( $slot === 'center' && empty( $slot_data ) && ! $this->columns_layout ) {
continue;
}
$slot_classes = [ 'hfg-slot', $slot ];
foreach ( $slot_data as $item ) {
if ( array_key_exists( 'components', $item ) && preg_grep( '/^divider/', $item['components'] ) ) {
$slot_classes[] = 'has-divider';
}
}
if ( $row_index !== 'sidebar' ) {
echo sprintf( '<div class="%s">', esc_attr( join( ' ', $slot_classes ) ) );
}
self::$current_slot = $slot;
foreach ( $slot_data as $group_index => $component_group ) {
if ( empty( $component_group['components'] ) ) {
continue;
}
if ( count( $component_group['components'] ) > 1 ) {
$component_group['classes'][] = 'hfg-is-group';
// If there is a primary or secondary menu component inside the group, add a class to it.
foreach ( $component_group['components'] as $component_slug ) {
if ( strpos( $component_slug, 'primary-menu' ) === false && strpos( $component_slug, 'secondary-menu' ) === false ) {
continue;
}
if ( strpos( $component_slug, 'primary-menu' ) !== false && ! in_array( 'has-nav', $component_group['classes'], true ) ) {
$component_group['classes'][] = 'has-nav';
}
$component_group['classes'][] = 'has-' . $component_slug;
}
}
echo sprintf( '<div class="%s">', esc_attr( join( ' ', $component_group['classes'] ) ) );
foreach ( $component_group['components'] as $component ) {
self::$current_component = $component;
$instance = $this->builder_components[ $component ];
$instance->render( $device );
}
echo '</div>';
}
do_action( 'neve_after_slot_component', $this->get_id(), $row_index, $slot );
if ( $row_index !== 'sidebar' ) {
echo '</div>';
}
}
}
/**
* Render components in the row.
*
* @param null|string $device Device id.
*/
public function render_components( $device = null ) {
if ( neve_is_new_builder() ) {
$this->new_render_components( $device );
return;
}
$row_index = 0;
if ( $device === null ) {
$device = self::$current_device;
$row_index = self::$current_row;
}
$data = $this->get_layout_data()[ $device ][ $row_index ];
$max_columns = 12;
$last_item = null;
usort(
$data,
function ( $item1, $item2 ) {
if ( $item1['x'] === $item2['x'] ) {
return 0;
}
return $item1['x'] < $item2['x'] ? - 1 : 1;
}
);
$collection = new \CachingIterator(
new \ArrayIterator(
$data
),
\CachingIterator::TOSTRING_USE_CURRENT
);
$render_buffer = [];
$render_index = 1;
foreach ( $collection as $component_location ) {
if ( ! isset( $this->builder_components[ $component_location['id'] ] ) ) {
continue;
}
/**
* An instance of Abstract_Component
*
* @var Abstract_Component $component
*/
$component = $this->builder_components[ $component_location['id'] ];
$x = intval( $component_location['x'] );
$width = intval( $component_location['width'] );
$align = $this->get_component_alignment( $component_location['id'] );
$vertical_align = $this->get_component_alignment( $component_location['id'], true );
if ( ! $collection->hasNext() && ( $x + $width < $max_columns ) ) {
$width += $max_columns - ( $x + $width );
}
$is_auto_width = $component->get_property( 'is_auto_width' );
if ( $row_index === 'sidebar' ) {
$width = 12;
$is_auto_width = false;
}
// Let's check if the component is nearby another.
$is_near_next = $collection->hasNext();
$is_near_prev = $last_item !== null;
// Check if component is nearby the next component.
if ( $collection->hasNext() ) {
$next_component_object = $collection->getInnerIterator()->current();
if ( $next_component_object['x'] - ( $x + $width ) !== 0 ) {
$is_near_next = false;
}
}
// Check if component is nearby the prev component.
if ( $last_item !== null ) {
if ( ( (int) $last_item['x'] + (int) $last_item['width'] ) - $x !== 0 ) {
$is_near_prev = false;
}
}
// If there is a gap between components, build new group.
if ( $last_item !== null && ! $is_near_prev ) {
$render_index ++;
}
// If there are two neighbours and none of them have auto_width, build new group.
if ( $is_near_prev && ! $last_item['is_auto_width'] && ! $is_auto_width ) {
$render_index ++;
}
// If there are neighbours prev and next, always group with the next on.
if ( $is_near_prev && $is_near_next && ! $last_item['is_auto_width'] && $is_auto_width && ! isset( $render_buffer[ $render_index ] ) ) {
$render_index ++;
}
// Use alignment only of non-auto width element.
if ( ! $is_auto_width && isset( $render_buffer[ $render_index ] ) ) {
$render_buffer[ $render_index ]['align'] = $align;
$render_buffer[ $render_index ]['vertical-align'] = $vertical_align;
}
$is_first = false;
$is_last = false;
if ( $last_item === null ) {
$is_first = true;
$render_index = 0;
}
if ( ! $collection->hasNext() ) {
$is_last = true;
}
if ( $row_index !== 'sidebar' ) {
if ( $x > 0 && $last_item !== null ) {
$origin = intval( $last_item['width'] ) + intval( $last_item['x'] );
if ( ( $x - $origin ) > 0 ) {
$x = $x - $origin;
} else {
$x = 0;
}
}
}
if ( ! isset( $render_buffer[ $render_index ] ) ) {
$render_buffer[ $render_index ] = [
'components' => [],
'align' => $align,
'vertical-align' => $vertical_align,
'is_first' => $is_first,
'is_last' => false,
];
}
if ( strpos( $component_location['id'], 'primary-menu' ) > - 1 ) {
$render_buffer[ $render_index ]['has_primary_nav'] = true;
}
$render_buffer[ $render_index ]['is_last'] = $is_last;
$render_buffer[ $render_index ]['components'][] = [
'component' => $component,
'offset' => $x,
'width' => $width,
];
$component_location['is_auto_width'] = $is_auto_width;
$component_location['align'] = $align;
$component_location['vertical-align'] = $vertical_align;
$last_item = $component_location;
}
foreach ( $render_buffer as $render_groups ) {
$width = array_sum( array_column( $render_groups['components'], 'width' ) );
$x = max( array_column( $render_groups['components'], 'offset' ) );
$align = $render_groups['align'];
$vertical_align = $render_groups['vertical-align'];
$classes = [ 'builder-item' ];
if ( isset( $render_groups['has_primary_nav'] ) ) {
$classes[] = 'has-nav';
}
if ( $render_groups['is_last'] ) {
$classes[] = 'hfg-item-last';
}
if ( $render_groups['is_first'] ) {
$classes[] = 'hfg-item-first';
}
$classes[] = 'col-' . $width;
foreach ( $align as $device_slug => $align_slug ) {
$builder_id = $this->get_id();
$alignment_is_mobile = in_array( $device_slug, [ 'tablet', 'mobile' ], true );
$is_header_sidebar = $builder_id === 'header' && $row_index === 'sidebar';
// Make sure we don't apply device-specific classes if the rows aren't visible on respective device.
// Footer has same rows on all devices.
if ( $builder_id === 'footer' || $is_header_sidebar || ( $device === $device_slug || ( $alignment_is_mobile && $device === 'mobile' ) ) ) {
$classes[] = $device_slug . '-' . $align_slug;
}
}
if ( $vertical_align ) {
$classes[] = 'hfg-item-v-' . $vertical_align;
}
if ( $row_index !== 'sidebar' && $x > 0 ) {
$classes[] = 'offset-' . $x;
}
if ( count( $render_groups['components'] ) > 1 ) {
$classes[] = 'hfg-is-group';
}
echo sprintf( '<div class="%s">', esc_attr( join( ' ', $classes ) ) );
foreach ( $render_groups['components'] as $component_data ) {
$component_data['component']->current_x = $x;
$component_data['component']->current_width = $width;
self::$current_component = $component_data['component']->get_id();
$component_data['component']->render();
}
echo '</div>';
}
}
/**
* Register a new component for builder.
*
* @param mixed $component_to_add A component.
*
* @return bool
* @since 1.0.0
* @access public
*/
public function register_component( $component_to_add ) {
if ( ! class_exists( $component_to_add ) || ! in_array( 'HFG\Core\Interfaces\Component', class_implements( $component_to_add ), true ) ) {
return false;
}
/**
* An instance of Component.
*
* @var Abstract_Component $component
*/
$component = new $component_to_add( $this->panel );
if ( $component->is_active() ) {
$this->builder_components[ $component->get_id() ] = $component;
$component->assign_builder( $this->get_id() );
}
return true;
}
/**
* Get a component from builder.
*
* @param string|null $id The id of the component.
*
* @return Abstract_Component|null
* @since 1.0.0
* @access public
*/
public function get_component( $id = null ) {
if ( $id === null ) {
$id = ( self::$current_component === null ) ? Abstract_Component::$current_component : self::$current_component;
}
return $this->builder_components[ $id ];
}
/**
* Returns the builder components.
*
* @return array
* @since 1.0.0
* @access public
*/
public function get_components() {
return $this->builder_components;
}
/**
* A representation of the builder as array.
*
* @return array
* @since 1.0.0
* @access public
*/
final public function get_builder() {
return array(
'id' => $this->control_id,
'control_id' => $this->control_id,
'panel' => $this->panel,
'section' => $this->section,
'title' => $this->title,
'devices' => $this->devices,
'items' => $this->get_components_settings(),
'rows' => $this->get_rows(),
'upsells' => $this->get_upsell_components(),
);
}
/**
* Returns the components settings.
*
* @return array
* @since 1.0.0
* @access public
*/
public function get_components_settings() {
$components_settings = array();
/**
* An instance of Component.
*
* @var Component $component
*/
foreach ( $this->builder_components as $component ) {
$components_settings[ $component->get_id() ] = $component->get_settings();
}
uasort(
$components_settings,
function ( $a, $b ) {
if ( $a['name'] === $b['name'] ) {
return 0;
}
return $a['name'] > $b['name'] ? 1 : - 1;
}
);
return $components_settings;
}
/**
* Get the default row colors based on the old settings.
*
* @param string $row_id the row id.
*
* @return array
*/
protected function get_default_row_colors( $row_id ) {
$bg_color_map = [
'background' => [
'dark-mode' => 'var(--nv-dark-bg)',
'light-mode' => 'var(--nv-site-bg)',
],
'text' => [
'dark-mode' => 'var(--nv-text-dark-bg)',
'light-mode' => 'var(--nv-text-color)',
],
];
$is_footer_bottom = $this->get_id() === 'footer' && $row_id === 'bottom';
// On the new skin, the bottom footer row should be dark by default.
if ( $is_footer_bottom ) {
$bg_color_map = [
'background' => [
'dark-mode' => 'var(--nv-site-bg)',
'light-mode' => 'var(--nv-dark-bg)',
],
'text' => [
'dark-mode' => 'var(--nv-text-color)',
'light-mode' => 'var(--nv-text-dark-bg)',
],
];
}
$row_setting_id = $this->control_id . '_' . $row_id;
$background = $bg_color_map['background']['light-mode'];
$text = $bg_color_map['text']['light-mode'];
$old_skin = get_theme_mod( $row_setting_id . '_' . self::SKIN_SETTING );
if ( ! empty( $old_skin ) ) {
$background = $bg_color_map['background'][ $old_skin ];
$text = $bg_color_map['text'][ $old_skin ];
}
return [
'background' => $background,
'text' => $text,
];
}
/**
* Adds Sidebar Controls.
*
* @param string $row_setting_id row id.
*/
private function add_sidebar_controls( $row_setting_id ) {
$align_choices = [
'left' => [
'tooltip' => __( 'Left', 'neve' ),
'icon' => 'editor-alignleft',
],
'center' => [
'tooltip' => __( 'Center', 'neve' ),
'icon' => 'editor-aligncenter',
],
'right' => [
'tooltip' => __( 'Right', 'neve' ),
'icon' => 'editor-alignright',
],
];
SettingsManager::get_instance()->add(
[
'id' => self::CONTENT_ALIGNMENT,
'group' => $row_setting_id,
'tab' => SettingsManager::TAB_LAYOUT,
'transport' => 'postMessage',
'label' => __( 'Alignment', 'neve' ),
'type' => '\Neve\Customizer\Controls\React\Responsive_Radio_Buttons',
'section' => $row_setting_id,
'options' => [
'choices' => $align_choices,
],
'conditional_header' => true,
'sanitize_callback' => 'neve_sanitize_alignment',
'default' => [
'desktop' => 'left',
'tablet' => 'left',
'mobile' => 'left',
],
'live_refresh_selector' => true,
'live_refresh_css_prop' => [
'cssVar' => [
'vars' => [
'--justify',
'--textalign',
'--flexg',
'--wrapdropdownwidth',
],
'valueRemap' => [
'--justify' => [
'left' => 'flex-start',
'center' => 'center',
'right' => 'flex-end',
],
'--flexg' => [
'left' => '1',
'center' => '0',
'right' => '0',
],
'--wrapdropdownwidth' => [
'left' => 'auto',
'center' => 'calc( 100% + 44px )',
'right' => 'auto',
],
],
'responsive' => true,
'selector' => '.header-menu-sidebar-bg',
],
'is_for' => 'horizontal',
],
]
);
SettingsManager::get_instance()->add(
[
'id' => self::LAYOUT_SETTING,
'group' => $row_setting_id,
'tab' => SettingsManager::TAB_LAYOUT,
'label' => __( 'Open Behaviour', 'neve' ),
'type' => 'select',
'section' => $row_setting_id,
'options' => [
'choices' => [
'slide_left' => __( 'Slide from Left', 'neve' ),
'slide_right' => __( 'Slide from Right', 'neve' ),
'pull_left' => __( 'Pull from Left', 'neve' ),
'pull_right' => __( 'Pull from Right', 'neve' ),
'full_canvas' => __( 'Full Canvas', 'neve' ),
'dropdown' => __( 'Slide Down', 'neve' ),
],
],
'conditional_header' => true,
'transport' => 'refresh',
'sanitize_callback' => 'wp_filter_nohtml_kses',
'default' => 'slide_left',
]
);
SettingsManager::get_instance()->add(
[
'id' => self::WIDTH,
'group' => $row_setting_id,
'tab' => SettingsManager::TAB_LAYOUT,
'label' => __( 'Sidebar Width', 'neve' ),
'transport' => 'postMessage',
'section' => $row_setting_id,
'conditional_header' => true,
'type' => '\Neve\Customizer\Controls\React\Responsive_Range',
'default' => '{ "mobile": "350", "tablet": "350", "desktop": "350" }',
'options' => [
'active_callback' => function () {
return in_array(
get_theme_mod( $this->control_id . '_sidebar_' . self::LAYOUT_SETTING, 'slide_left' ),
[
'slide_left',
'slide_right',
'pull_left',
'pull_right',
],
true
);
},
'input_attrs' => [
'min' => 1,
'max' => 1000,
'units' => [ 'px', 'em', 'rem' ],
'defaultVal' => [
'mobile' => 360,
'tablet' => 360,
'desktop' => 360,
'suffix' => [
'mobile' => 'px',
'tablet' => 'px',
'desktop' => 'px',
],
],
],
],
'live_refresh_selector' => true,
'live_refresh_css_prop' => [
'responsive' => true,
'template' =>
'.hfg_header .header-menu-sidebar {
width: {{value}}px;
}',
],
'sanitize_callback' => 'neve_sanitize_range_value',
]
);
}
/**
* Adds Column Layout Controls.
*
* @param string $row_setting_id row setting id [e.g. hfg_footer_layout_bottom].
* @param string $row_id row id.
*/
private function add_columns_layout_controls( $row_setting_id, $row_id ) {
$choices = [];
for ( $i = 1; $i <= 5; $i ++ ) {
$choices[ $i ] = [
'tooltip' => $i,
'icon' => 'text',
];
}
SettingsManager::get_instance()->add(
[
'id' => self::COLUMNS_NUMBER,
'group' => $row_setting_id,
'tab' => SettingsManager::TAB_LAYOUT,
'label' => __( 'Number of Columns', 'neve' ),
'type' => '\Neve\Customizer\Controls\React\Radio_Buttons',
'section' => $row_setting_id,
'options' => [
'choices' => $choices,
],
'transport' => 'post' . $row_setting_id,
'sanitize_callback' => 'absint',
'default' => '3',
]
);
SettingsManager::get_instance()->add(
[
'id' => self::COLUMNS_LAYOUT,
'group' => $row_setting_id,
'tab' => SettingsManager::TAB_LAYOUT,
'label' => __( 'Columns Layout', 'neve' ),
'type' => '\Neve\Customizer\Controls\React\Builder_Columns',
'section' => $row_setting_id,
'options' => [
'columns_control' => $row_setting_id . '_' . self::COLUMNS_NUMBER,
],
'transport' => 'post' . $row_setting_id,
'sanitize_callback' => [ $this, 'sanitize_columns' ],
'default' => 'equal',
]
);
$align_choices = [
'flex-start' => [
'tooltip' => __( 'Top', 'neve' ),
'icon' => 'arrow-up',
],
'center' => [
'tooltip' => __( 'Middle', 'neve' ),
'icon' => 'sort',
],
'flex-end' => [
'tooltip' => __( 'Bottom', 'neve' ),
'icon' => 'arrow-down',
],
];
SettingsManager::get_instance()->add(
[
'id' => self::VERTICAL_ALIGN,
'group' => $row_setting_id,
'tab' => SettingsManager::TAB_LAYOUT,
'transport' => 'postMessage',
'sanitize_callback' => 'wp_filter_nohtml_kses',
'default' => 'flex-start',
'section' => $row_setting_id,
'label' => __( 'Vertical Alignment', 'neve' ),
'type' => '\Neve\Customizer\Controls\React\Radio_Buttons',
'live_refresh_selector' => true,
'live_refresh_css_prop' => [
'cssVar' => [
'vars' => '--valign',
'selector' => '.' . $this->get_id() . '-' . $row_id . ' .row',
],
'is_for' => 'vertical',
],
'options' => [
'choices' => $align_choices,
],
]
);
}
/**
* Sanitize builder columns
*
* @param string $value control value.
*
* @return string
*/
public function sanitize_columns( $value ) {
$allowed = [
'equal',
'right-third',
'left-third',
'left-half',
'right-half',
'center-half',
'center-two-thirds',
];
if ( ! in_array( $value, $allowed ) ) {
return 'equal';
}
return $value;
}
/**
* Adds sidebar styles.
*
* @param array $css_array array of styles.
*
* @return array
*/
private function add_sidebar_styles( $css_array ) {
$type = get_theme_mod( $this->control_id . '_sidebar_' . self::LAYOUT_SETTING, 'slide_left' );
$default_sidebar_width = '{ "mobile": "360", "tablet": "360", "desktop": "360" }';
if ( ! in_array( $type, [ 'full_canvas', 'dropdown' ], true ) ) {
$css_array[] = [
Dynamic_Selector::KEY_SELECTOR => '.header-menu-sidebar',
Dynamic_Selector::KEY_RULES => [
Config::CSS_PROP_WIDTH => [
Dynamic_Selector::META_KEY => $this->control_id . '_sidebar_' . self::WIDTH,
Dynamic_Selector::META_DEFAULT => $default_sidebar_width,
Dynamic_Selector::META_SUFFIX => 'responsive_suffix',
Dynamic_Selector::META_IS_RESPONSIVE => true,
],
],
];
}
if ( $type === 'pull_left' ) {
$css_array[] = [
Dynamic_Selector::KEY_SELECTOR => '.is-menu-sidebar > .wrapper',
Dynamic_Selector::KEY_RULES => [
Config::CSS_PROP_LEFT => [
Dynamic_Selector::META_KEY => $this->control_id . '_sidebar_' . self::WIDTH,
Dynamic_Selector::META_DEFAULT => $default_sidebar_width,
Dynamic_Selector::META_SUFFIX => 'responsive_suffix',
Dynamic_Selector::META_IS_RESPONSIVE => true,
],
],
];
}
if ( $type === 'pull_right' ) {
$css_array[] = [
Dynamic_Selector::KEY_SELECTOR => '.menu_sidebar_pull_right.is-menu-sidebar > .wrapper',
Dynamic_Selector::KEY_RULES => [
Config::CSS_PROP_RIGHT => [
Dynamic_Selector::META_KEY => $this->control_id . '_sidebar_' . self::WIDTH,
Dynamic_Selector::META_DEFAULT => $default_sidebar_width,
Dynamic_Selector::META_SUFFIX => 'responsive_suffix',
Dynamic_Selector::META_IS_RESPONSIVE => true,
],
],
];
}
return $css_array;
}
/**
* Adds the new builder row styles.
*
* @param array $css_array array of styles.
*
* @return array
*/
private function add_new_builder_styles( $css_array, $row ) {
$justify_map = [
'left' => 'flex-start',
'center' => 'center',
'right' => 'flex-end',
];
$align_default = [
'desktop' => 'left',
'tablet' => 'left',
'mobile' => 'left',
];
$align_id = $this->control_id . '_' . $row . '_' . self::CONTENT_ALIGNMENT;
if ( $row === 'sidebar' ) {
$css_array[] = [
Dynamic_Selector::KEY_SELECTOR => '.header-menu-sidebar-bg',
Dynamic_Selector::KEY_RULES => [
'--justify' => [
Dynamic_Selector::META_KEY => $align_id,
Dynamic_Selector::META_IS_RESPONSIVE => true,
Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) use ( $justify_map ) {
return sprintf( '%s: %s;', $css_prop, $justify_map[ $value ] );
},
Dynamic_Selector::META_DEFAULT => $align_default,
],
'--textalign' => [
Dynamic_Selector::META_KEY => $align_id,
Dynamic_Selector::META_IS_RESPONSIVE => true,
Dynamic_Selector::META_DEFAULT => $align_default,
],
'--flexg' => [
Dynamic_Selector::META_KEY => $align_id,
Dynamic_Selector::META_IS_RESPONSIVE => true,
Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) {
if ( $value === 'left' ) {
return sprintf( '%s: 1;', $css_prop );
}
return sprintf( '%s: 0;', $css_prop );
},
Dynamic_Selector::META_DEFAULT => $align_default,
],
'--wrapdropdownwidth' => [
Dynamic_Selector::META_KEY => $align_id,
Dynamic_Selector::META_IS_RESPONSIVE => true,
Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) {
if ( $value === 'center' ) {
return sprintf( '%s: %s;', $css_prop, 'calc( 100% + 44px )' );
}
return sprintf( '%s: auto;', $css_prop );
},
Dynamic_Selector::META_DEFAULT => $align_default,
],
],
];
}
if ( ! $this->columns_layout ) {
return $css_array;
}
$builder = $this->get_id();
$mods_prefix = 'hfg_' . $builder . '_layout_' . $row . '_';
$columns = SettingsManager::get_instance()->get( $mods_prefix . self::COLUMNS_NUMBER, 3 );
$layout = SettingsManager::get_instance()->get( $mods_prefix . self::COLUMNS_LAYOUT, 'equal' );
$styles_map = [
1 => [
'equal' => '1fr',
],
2 => [
'equal' => '1fr 1fr',
'right-third' => '2fr 1fr',
'left-third' => '1fr 2fr',
],
3 => [
'equal' => '1fr 1fr 1fr',
'left-half' => '2fr 1fr 1fr',
'right-half' => '1fr 1fr 2fr',
'center-half' => '1fr 2fr 1fr',
'center-two-thirds' => '1fr 3fr 1fr',
],
4 => [
'equal' => 'repeat(4, 1fr)',
'left-half' => '3fr 1fr 1fr 1fr',
'right-half' => '1fr 1fr 1fr 3fr',
],
5 => [
'equal' => 'repeat(5, 1fr)',
],
];
$proportions = 'equal';
if ( isset( $styles_map[ $columns ] ) && isset( $styles_map[ $columns ][ $layout ] ) ) {
$proportions = $styles_map[ $columns ][ $layout ];
}
$css_array[] = [
Dynamic_Selector::KEY_SELECTOR => '.' . $builder . '-' . $row . '-inner .row',
Dynamic_Selector::KEY_RULES => [
Config::CSS_PROP_GRID_TEMPLATE_COLS => [
Dynamic_Selector::META_KEY => $mods_prefix . self::COLUMNS_LAYOUT,
Dynamic_Selector::META_DEFAULT => 'auto',
Dynamic_Selector::META_FILTER => function ( $css_prop, $value, $meta, $device ) use ( $proportions ) {
return sprintf( '%s:%s;', $css_prop, $proportions );
},
],
'--valign' => [
Dynamic_Selector::META_KEY => $mods_prefix . self::VERTICAL_ALIGN,
Dynamic_Selector::META_DEFAULT => 'flex-start',
],
],
];
return $css_array;
}
/**
* Get upsell components.
*
* @return array
*/
protected function get_upsell_components() {
return [];
}
}