<?php abstract class SiteOrigin_Widget_Base_Carousel extends SiteOrigin_Widget { public $global_settings; /** * Register all the frontend scripts and styles for the base carousel. */ public function initialize() { $this->register_frontend_scripts( array( array( 'slick', plugin_dir_url( SOW_BUNDLE_BASE_FILE ) . 'js/lib/slick' . SOW_BUNDLE_JS_SUFFIX . '.js', array( 'jquery' ), '1.8.1', ), array( 'sow-carousel', plugin_dir_url( SOW_BUNDLE_BASE_FILE ) . 'js/carousel' . SOW_BUNDLE_JS_SUFFIX . '.js', array( 'jquery', 'slick' ), SOW_BUNDLE_VERSION, true, ), ) ); $this->register_frontend_styles( array( array( 'slick', plugin_dir_url( SOW_BUNDLE_BASE_FILE ) . 'css/lib/slick.css', array(), '1.8.1', ), ) ); add_action( 'wp_enqueue_scripts', array( $this, 'register_assets' ) ); } /** * Allow widgets and other plugins to register assets for this slider. */ public function register_assets() { do_action( 'siteorigin_widgets_carousel_register_assets', $this ); } /** * Allow widgets to override settings. * * @return array If overridden, an array is expected. */ public function override_carousel_settings() { // Intentionally left blank. return array(); } /** * Handle carousel specific settings and defaults. * * @return array */ private function get_carousel_settings() { if ( ! empty( $this->global_settings ) ) { return $this->global_settings; } $defaults = array( 'breakpoints' => array( 'tablet_landscape' => 1366, 'tablet_portrait' => 1025, 'mobile' => 480, ), 'slides_to_scroll' => array( 'desktop' => 3, 'tablet_landscape' => 3, 'tablet_portrait' => 2, 'mobile' => 1, ), 'slides_to_show' => array( 'desktop' => 3, 'tablet_landscape' => 3, 'tablet_portrait' => 2, 'mobile' => 1, ), 'navigation' => array( 'desktop' => true, 'tablet_landscape' => true, 'tablet_portrait' => true, 'mobile' => true, ), 'navigation_label' => __( 'Navigation Arrows', 'so-widgets-bundle' ), 'navigation_dots' => array( 'desktop' => true, 'tablet_landscape' => true, 'tablet_portrait' => true, 'mobile' => true, ), 'navigation_dots_label' => __( 'Navigation Dots', 'so-widgets-bundle' ), ); $this->global_settings = wp_parse_args( $this->override_carousel_settings(), $defaults ); // If the global settings are somehow empty, return the defaults. if ( empty( $this->global_settings ) ) { $this->global_settings = $defaults; } return $this->global_settings; } /** * Utility method for adding section groups. * * @param array $field Field data * @param string $value_type Whether the field is a placeholder or standard field. This controls whether the field data is stored by default. * * @return array The structured section group. */ private function add_section_group( $field, $value_type ) { $carousel_settings = $this->get_carousel_settings(); $section = array( 'type' => 'section', 'label' => $field['label'], 'hide' => true, 'fields' => array(), ); if ( isset( $field['fields'] ) ) { foreach ( $field['fields'] as $sub_field_key => $sub_field ) { $section['fields'][ $sub_field_key ] = $this->add_section_group( $sub_field, $value_type ); } } else { if ( isset( $field['breakpoint'] ) ) { $section['fields']['breakpoint'] = array( 'type' => 'number', 'label' => __( 'Breakpoint', 'so-widgets-bundle' ), $value_type => $field['breakpoint'], ); } $section['fields']['slides_to_scroll'] = array( 'type' => 'number', 'label' => __( 'Slides to Scroll', 'so-widgets-bundle' ), 'abs' => true, 'description' => sprintf( __( 'Set the number of slides to scroll per navigation click or swipe on %s', 'so-widgets-bundle' ), strtolower( $field['label'] ) ), $value_type => $field['slides_to_scroll'], ); if ( ! empty( $carousel_settings['slides_to_show'] ) ) { $section['fields']['slides_to_show'] = array( 'type' => 'number', 'abs' => true, 'label' => __( 'Slides to Show ', 'so-widgets-bundle' ), 'description' => sprintf( __( 'The number of slides to show on %s.', 'so-widgets-bundle' ), strtolower( $field['label'] ) ), $value_type => $field['slides_to_show'], ); } if ( isset( $field['navigation'] ) && ! empty( $carousel_settings['navigation_label'] ) ) { $section['fields']['navigation'] = array( 'type' => 'checkbox', 'label' => $carousel_settings['navigation_label'], 'default' => $field['navigation'], 'state_handler' => array( 'nav_arrows[show]' => array( 'show' ), 'nav_arrows[hide]' => array( 'hide' ), ), ); } if ( isset( $field['navigation_dots'] ) && ! empty( $carousel_settings['navigation_dots_label'] ) ) { $section['fields']['navigation_dots'] = array( 'type' => 'checkbox', 'label' => $carousel_settings['navigation_dots_label'], 'default' => $field['navigation'], 'state_handler' => array( 'nav_dots[show]' => array( 'show' ), 'nav_dots[hide]' => array( 'hide' ), ), ); } } return $section; } public function responsive_form_fields( $context = 'widget' ) { $carousel_settings = $this->get_carousel_settings(); // If the context is a widget, the global values are displayed using a // placeholder to prevent the values from being stored. $value_type = $context == 'widget' ? 'placeholder' : 'default'; $fields = array( 'desktop' => array( 'label' => __( 'Desktop', 'so-widgets-bundle' ), 'slides_to_scroll' => $carousel_settings['slides_to_scroll']['desktop'], 'navigation' => $carousel_settings['navigation']['desktop'], ), 'tablet' => array( 'label' => __( 'Tablet', 'so-widgets-bundle' ), 'fields' => array( 'landscape' => array( 'label' => __( 'Landscape', 'so-widgets-bundle' ), 'breakpoint' => $carousel_settings['breakpoints']['tablet_landscape'], 'slides_to_scroll' => $carousel_settings['slides_to_scroll']['tablet_landscape'], 'navigation' => $carousel_settings['navigation']['tablet_landscape'], ), 'portrait' => array( 'label' => __( 'Portrait', 'so-widgets-bundle' ), 'breakpoint' => $carousel_settings['breakpoints']['tablet_portrait'], 'slides_to_scroll' => $carousel_settings['slides_to_scroll']['tablet_portrait'], 'navigation' => $carousel_settings['navigation']['tablet_portrait'], ), ), ), 'mobile' => array( 'label' => __( 'Mobile', 'so-widgets-bundle' ), 'breakpoint' => $carousel_settings['breakpoints']['mobile'], 'slides_to_scroll' => $carousel_settings['slides_to_scroll']['mobile'], 'navigation' => $carousel_settings['navigation']['mobile'], 'navigation_dots' => $carousel_settings['navigation_dots']['mobile'], ), ); if ( ! empty( $carousel_settings['navigation_dots'] ) ) { $fields['desktop']['navigation_dots'] = $carousel_settings['navigation_dots']['desktop']; $fields['tablet']['fields']['landscape']['navigation_dots'] = $carousel_settings['navigation_dots']['tablet_landscape']; $fields['tablet']['fields']['portrait']['navigation_dots'] = $carousel_settings['navigation_dots']['tablet_portrait']; $fields['mobile']['navigation_dots'] = $carousel_settings['navigation_dots']['mobile']; } // Add slides to show settings if this widget uses them. if ( ! empty( $carousel_settings['slides_to_show'] ) ) { $fields['desktop']['slides_to_show'] = $carousel_settings['slides_to_show']['desktop']; $fields['tablet']['fields']['landscape']['slides_to_show'] = $carousel_settings['slides_to_show']['tablet_landscape']; $fields['tablet']['fields']['portrait']['slides_to_show'] = $carousel_settings['slides_to_show']['tablet_portrait']; $fields['mobile']['slides_to_show'] = $carousel_settings['slides_to_show']['mobile']; } $generated_fields = array(); foreach ( $fields as $field_key => $field ) { $generated_fields[ $field_key ] = $this->add_section_group( $field, $value_type ); } return array( 'type' => 'section', 'label' => __( 'Responsive', 'so-widgets-bundle' ), 'hide' => $context == 'widget', 'fields' => $generated_fields, ); } public function carousel_settings_form_fields() { $carousel_settings = $this->get_carousel_settings(); $fields = array( 'type' => 'section', 'label' => __( 'Settings', 'so-widgets-bundle' ), 'hide' => true, 'fields' => array( 'loop' => array( 'type' => 'checkbox', 'label' => __( 'Loop Items', 'so-widgets-bundle' ), 'description' => __( 'Automatically return to the first item after the last item.', 'so-widgets-bundle' ), 'default' => true, 'state_emitter' => array( 'callback' => 'conditional', 'args' => array( 'loop_posts[show]: val', 'loop_posts[hide]: ! val', ), ), ), 'dots' => array( 'type' => 'checkbox', 'label' => __( 'Navigation Dots', 'so-widgets-bundle' ), 'default' => true, 'state_emitter' => array( 'callback' => 'conditional', 'args' => array( 'nav_dots[show]: val', 'nav_dots[hide]: ! val', ), ), ), 'arrows' => array( 'type' => 'checkbox', 'label' => __( 'Navigation Arrows', 'so-widgets-bundle' ), 'default' => true, 'state_emitter' => array( 'callback' => 'conditional', 'args' => array( 'nav_arrows[show]: val', 'nav_arrows[hide]: ! val', ), ), ), 'animation' => array( 'type' => 'select', 'label' => __( 'Animation', 'so-widgets-bundle' ), 'default' => 'Ease', 'options' => array( 'ease' => __( 'Ease', 'so-widgets-bundle' ), 'linear' => __( 'Linear', 'so-widgets-bundle' ), ), ), 'animation_speed' => array( 'type' => 'number', 'label' => __( 'Animation Speed', 'so-widgets-bundle' ), 'default' => 400, ), 'autoplay' => array( 'type' => 'checkbox', 'label' => __( 'Autoplay', 'so-widgets-bundle' ), 'state_emitter' => array( 'callback' => 'conditional', 'args' => array( 'autoplay[show]: val', 'autoplay[hide]: ! val', ), ), ), 'autoplay_pause_hover' => array( 'type' => 'checkbox', 'label' => __( 'Autoplay Pause on Hover', 'so-widgets-bundle' ), 'state_handler' => array( 'autoplay[show]' => array( 'show' ), 'autoplay[hide]' => array( 'hide' ), ), ), 'timeout' => array( 'type' => 'number', 'label' => __( 'Timeout', 'so-widgets-bundle' ), 'default' => 8000, 'state_handler' => array( 'autoplay[show]' => array( 'show' ), 'autoplay[hide]' => array( 'hide' ), ), ), ), ); if ( ! isset( $carousel_settings['navigation'] ) || empty( $carousel_settings['navigation_label'] ) ) { unset( $fields['fields']['arrows'] ); } if ( ! isset( $carousel_settings['navigation_dots'] ) || empty( $carousel_settings['navigation_dots_label'] ) ) { unset( $fields['fields']['dots'] ); } return $fields; } public function design_settings_form_fields( $settings = array() ) { $fields = array( 'type' => 'section', 'label' => __( 'Design', 'so-widgets-bundle' ), 'hide' => true, 'fields' => array( 'item_title' => array( 'type' => 'section', 'label' => __( 'Item title', 'so-widgets-bundle' ), 'hide' => true, 'fields' => array( 'tag' => array( 'type' => 'select', 'label' => __( 'HTML Tag', 'so-widgets-bundle' ), 'default' => 'h4', 'options' => array( 'h1' => __( 'H1', 'so-widgets-bundle' ), 'h2' => __( 'H2', 'so-widgets-bundle' ), 'h3' => __( 'H3', 'so-widgets-bundle' ), 'h4' => __( 'H4', 'so-widgets-bundle' ), 'h5' => __( 'H5', 'so-widgets-bundle' ), 'h6' => __( 'H6', 'so-widgets-bundle' ), 'p' => __( 'Paragraph', 'so-widgets-bundle' ), ), ), 'font' => array( 'type' => 'font', 'label' => __( 'Font', 'so-widgets-bundle' ), ), 'size' => array( 'type' => 'measurement', 'label' => __( 'Font size', 'so-widgets-bundle' ), ), 'color' => array( 'type' => 'color', 'label' => __( 'Color', 'so-widgets-bundle' ), ), ), ), ), ); if ( ! empty( $settings ) ) { $fields = array_merge_recursive( $fields, array( 'fields' => $settings ) ); } return $fields; } public function get_settings_form() { return array( 'responsive' => $this->responsive_form_fields( 'global' ), ); } public function responsive_template_variables( $responsive, $encode = true ) { $carousel_settings = $this->get_carousel_settings(); $variables = array( 'desktop_slides_to_scroll' => ! empty( $responsive['desktop']['slides_to_scroll'] ) ? $responsive['desktop']['slides_to_scroll'] : $carousel_settings['slides_to_scroll']['desktop'], 'tablet_landscape_breakpoint' => ! empty( $responsive['tablet']['landscape']['breakpoint'] ) ? $responsive['tablet']['landscape']['breakpoint'] : $carousel_settings['breakpoints']['tablet_landscape'], 'tablet_landscape_slides_to_scroll' => ! empty( $responsive['tablet']['landscape']['slides_to_scroll'] ) ? $responsive['tablet']['landscape']['slides_to_scroll'] : $carousel_settings['slides_to_scroll']['tablet_landscape'], 'tablet_portrait_breakpoint' => ! empty( $responsive['tablet']['portrait']['breakpoint'] ) ? $responsive['tablet']['portrait']['breakpoint'] : $carousel_settings['breakpoints']['tablet_portrait'], 'tablet_portrait_slides_to_scroll' => ! empty( $responsive['tablet']['portrait']['slides_to_scroll'] ) ? $responsive['tablet']['portrait']['slides_to_scroll'] : $carousel_settings['slides_to_scroll']['tablet_portrait'], 'mobile_breakpoint' => ! empty( $responsive['mobile']['breakpoint'] ) ? $responsive['mobile']['breakpoint'] : $carousel_settings['breakpoints']['mobile'], 'mobile_slides_to_scroll' => ! empty( $responsive['mobile']['slides_to_scroll'] ) ? $responsive['mobile']['slides_to_scroll'] : $carousel_settings['slides_to_scroll']['mobile'], ); if ( ! empty( $carousel_settings['slides_to_show'] ) ) { $variables['desktop_slides_to_show'] = ! empty( $responsive['desktop']['slides_to_show'] ) ? $responsive['desktop']['slides_to_show'] : $carousel_settings['slides_to_show']['desktop']; $variables['tablet_landscape_slides_to_show'] = ! empty( $responsive['tablet']['landscape']['slides_to_show'] ) ? $responsive['tablet']['landscape']['slides_to_show'] : $carousel_settings['slides_to_show']['tablet_landscape']; $variables['tablet_portrait_slides_to_show'] = ! empty( $responsive['tablet']['portrait']['slides_to_show'] ) ? $responsive['tablet']['portrait']['slides_to_show'] : $carousel_settings['slides_to_show']['tablet_portrait']; $variables['mobile_slides_to_show'] = ! empty( $responsive['mobile']['slides_to_show'] ) ? $responsive['mobile']['slides_to_show'] : $carousel_settings['slides_to_show']['mobile']; } // Negative values can be problematic so let's avoid them by ensuring everything is positive. $variables = array_map( function( $value ) { return is_null( $value ) ? 0 : abs( $value ); }, $variables ); return $encode ? json_encode( $variables ) : $variables; } public function responsive_less_variables( $less_vars, $instance ) { $carousel_settings = $this->get_carousel_settings(); // Breakpoint. $less_vars['breakpoint_tablet_landscape'] = ( ! empty( $instance['responsive']['tablet_landscape']['breakpoint'] ) ? $instance['responsive']['tablet_landscape']['breakpoint'] : $carousel_settings['breakpoints']['tablet_landscape'] ) . 'px'; $less_vars['breakpoint_tablet_portrait'] = ( ! empty( $instance['responsive']['tablet_portrait']['breakpoint'] ) ? $instance['responsive']['tablet_portrait']['breakpoint'] : $carousel_settings['breakpoints']['tablet_portrait'] ) . 'px'; $less_vars['breakpoint_mobile'] = ( ! empty( $instance['responsive']['mobile']['breakpoint'] ) ? $instance['responsive']['mobile']['breakpoint'] : $carousel_settings['breakpoints']['mobile'] ) . 'px'; // Navigation. $less_vars['navigation_arrows'] = isset( $instance['carousel_settings']['arrows'] ) ? ! empty( $instance['carousel_settings']['arrows'] ) : false; $less_vars['navigation_desktop'] = isset( $instance['responsive']['desktop']['navigation'] ) ? ! empty( $instance['responsive']['desktop']['navigation'] ) : $carousel_settings['navigation']['desktop']; $less_vars['navigation_tablet_landscape'] = isset( $instance['responsive']['tablet']['landscape']['navigation'] ) ? ! empty( $instance['responsive']['tablet']['landscape']['navigation'] ) : $carousel_settings['navigation']['tablet_landscape']; $less_vars['navigation_tablet_portrait'] = isset( $instance['responsive']['tablet']['portrait']['navigation'] ) ? ! empty( $instance['responsive']['tablet']['portrait']['navigation'] ) : $carousel_settings['navigation']['tablet_portrait']; $less_vars['navigation_mobile'] = isset( $instance['responsive']['mobile']['navigation'] ) ? ! empty( $instance['responsive']['mobile']['navigation'] ) : $carousel_settings['navigation']['mobile']; // Navigation dots. $less_vars['navigation_dots_desktop'] = isset( $instance['responsive']['desktop']['navigation_dots'] ) ? ! empty( $instance['responsive']['desktop']['navigation_dots'] ) : $carousel_settings['navigation_dots']['desktop']; $less_vars['navigation_dots_tablet_landscape'] = isset( $instance['responsive']['tablet']['landscape']['navigation_dots'] ) ? ! empty( $instance['responsive']['tablet']['landscape']['navigation_dots'] ) : $carousel_settings['navigation_dots']['tablet_landscape']; $less_vars['navigation_dots_tablet_portrait'] = isset( $instance['responsive']['tablet']['portrait']['navigation_dots'] ) ? ! empty( $instance['responsive']['tablet']['portrait']['navigation_dots'] ) : $carousel_settings['navigation_dots']['tablet_portrait']; $less_vars['navigation_dots_mobile'] = isset( $instance['responsive']['mobile']['navigation_dots'] ) ? ! empty( $instance['responsive']['mobile']['navigation_dots'] ) : $carousel_settings['navigation_dots']['mobile']; return $less_vars; } public function carousel_settings_template_variables( $settings, $encode = true ) { $variables = array( 'loop' => isset( $settings['loop'] ) ? $settings['loop'] : true, 'dots' => isset( $settings['dots'] ) ? $settings['dots'] : true, 'animation' => isset( $settings['animation'] ) ? $settings['animation'] : 'ease', 'animation_speed' => ! empty( $settings['animation_speed'] ) ? $settings['animation_speed'] : 400, 'autoplay' => isset( $settings['autoplay'] ) ? $settings['autoplay'] : false, 'pauseOnHover' => isset( $settings['autoplay_pause_hover'] ) ? $settings['autoplay_pause_hover'] : false, 'autoplaySpeed' => ! empty( $settings['timeout'] ) ? $settings['timeout'] : 8000, 'item_overflow' => isset( $settings['item_overflow'] ) ? $settings['item_overflow'] : false, ); return $encode ? json_encode( $variables ) : $variables; } public function render_template( $settings, $args, $instance ) { if ( ! empty( $settings['container_classes'] ) && is_array( $settings['container_classes'] ) ) { $container_classes = implode( array_map( 'sanitize_html_class', $settings['container_classes'] ) ); } include plugin_dir_path( __FILE__ ) . 'tpl/carousel.php'; } public function render_navigation( $nav ) { if ( $nav == 'next' || $nav == 'both' ) { ?> <a href="#" class="sow-carousel-next" title="<?php esc_attr_e( 'Next', 'so-widgets-bundle' ); ?>" aria-label="<?php esc_attr_e( 'Next Posts', 'so-widgets-bundle' ); ?>" role="button"></a> <?php } if ( $nav == 'prev' || $nav == 'both' ) { ?> <a href="#" class="sow-carousel-previous" title="<?php esc_attr_e( 'Previous', 'so-widgets-bundle' ); ?>" aria-label="<?php esc_attr_e( 'Previous Posts', 'so-widgets-bundle' ); ?>" role="button"></a> <?php } } }