=' ) ) { return; } if ( version_compare( $installed, '2.4.0', '<' ) ) { // Removed in 2.4.0: target board/group IDs (never sent to server; routing is server-side). delete_option( 'a1tools_form_board_id' ); delete_option( 'a1tools_form_group_id' ); } if ( version_compare( $installed, '2.4.2', '<' ) ) { // 2.4.2 fixes a TTL bug where get_option('a1tools_cache_expiry') was // multiplied by MINUTE_IN_SECONDS even though the admin form already // stored seconds. The "No caching (0)" option in particular passed 0 // to set_transient(), which WordPress treats as "no expiration" — so // every cached payload (site variables, city pages, franchises, etc.) // could persist indefinitely. Wipe all a1tools transients here so // the corrected logic rebuilds them with the right TTL. if ( function_exists( 'a1tools_clear_cache' ) ) { a1tools_clear_cache(); } } update_option( 'a1tools_db_version', A1TOOLS_VERSION, false ); } add_action( 'admin_init', 'a1tools_maybe_upgrade' ); // Split-file includes (data, shortcodes, REST, Yoast, Elementor, admin, forms). require_once A1TOOLS_PLUGIN_DIR . 'includes/a1-tools-data.php'; require_once A1TOOLS_PLUGIN_DIR . 'includes/a1-tools-shortcodes.php'; require_once A1TOOLS_PLUGIN_DIR . 'includes/a1-tools-rest-api.php'; require_once A1TOOLS_PLUGIN_DIR . 'includes/a1-tools-yoast.php'; require_once A1TOOLS_PLUGIN_DIR . 'includes/a1-tools-elementor-init.php'; require_once A1TOOLS_PLUGIN_DIR . 'includes/a1-tools-admin.php'; require_once A1TOOLS_PLUGIN_DIR . 'includes/a1-tools-forms.php'; // ============================================================================ // SOCIAL ICONS WIDGET // ============================================================================ /** * A1 Tools Social Icons Widget. * * @since 1.2.0 */ class A1Tools_Social_Icons_Widget extends WP_Widget { /** * Constructor. */ public function __construct() { parent::__construct( 'a1tools_social_icons', __( 'A1 Tools Social Icons', 'a1-tools' ), array( 'description' => __( 'Display social media icons from A1 Tools with customizable styling.', 'a1-tools' ), 'classname' => 'a1tools-social-widget', ) ); } /** * Frontend display. * * @param array $args Widget arguments. * @param array $instance Widget instance. */ public function widget( $args, $instance ) { $vars = a1tools_get_site_variables(); if ( ! $vars ) { return; } // Widget settings with defaults. $title = ! empty( $instance['title'] ) ? $instance['title'] : ''; $shape = ! empty( $instance['shape'] ) ? $instance['shape'] : 'rounded'; $style = ! empty( $instance['style'] ) ? $instance['style'] : 'default'; $size = ! empty( $instance['size'] ) ? (int) $instance['size'] : 40; $icon_size = ! empty( $instance['icon_size'] ) ? (int) $instance['icon_size'] : 18; $spacing = ! empty( $instance['spacing'] ) ? (int) $instance['spacing'] : 8; $alignment = ! empty( $instance['alignment'] ) ? $instance['alignment'] : 'left'; $custom_color = ! empty( $instance['custom_color'] ) ? $instance['custom_color'] : ''; $hover_effect = ! empty( $instance['hover_effect'] ) ? $instance['hover_effect'] : 'scale'; // Platform configurations with official colors. $platforms = array( 'facebook_url' => array( 'label' => 'Facebook', 'icon' => 'fab fa-facebook-f', 'color' => '#1877F2' ), 'instagram_url' => array( 'label' => 'Instagram', 'icon' => 'fab fa-instagram', 'color' => '#E4405F' ), 'youtube_url' => array( 'label' => 'YouTube', 'icon' => 'fab fa-youtube', 'color' => '#FF0000' ), 'twitter_url' => array( 'label' => 'X (Twitter)', 'icon' => 'svg-x', 'color' => '#000000' ), 'linkedin_url' => array( 'label' => 'LinkedIn', 'icon' => 'fab fa-linkedin-in', 'color' => '#0A66C2' ), 'tiktok_url' => array( 'label' => 'TikTok', 'icon' => 'fab fa-tiktok', 'color' => '#000000' ), 'yelp_url' => array( 'label' => 'Yelp', 'icon' => 'fab fa-yelp', 'color' => '#D32323' ), 'google_business_url' => array( 'label' => 'Google', 'icon' => 'fab fa-google', 'color' => '#4285F4' ), 'pinterest_url' => array( 'label' => 'Pinterest', 'icon' => 'fab fa-pinterest-p', 'color' => '#E60023' ), 'bbb_url' => array( 'label' => 'BBB', 'icon' => 'fas fa-shield-alt', 'color' => '#006CB7' ), 'nextdoor_url' => array( 'label' => 'Nextdoor', 'icon' => 'fas fa-home', 'color' => '#8ED500' ), 'houzz_url' => array( 'label' => 'Houzz', 'icon' => 'fab fa-houzz', 'color' => '#4DBC15' ), 'angi_url' => array( 'label' => 'Angi', 'icon' => 'fas fa-tools', 'color' => '#FF6153' ), 'thumbtack_url' => array( 'label' => 'Thumbtack', 'icon' => 'fas fa-thumbtack', 'color' => '#009FD9' ), 'homeadvisor_url' => array( 'label' => 'HomeAdvisor', 'icon' => 'fas fa-home', 'color' => '#EF6C00' ), ); // Check if any platforms have URLs. $has_platforms = false; foreach ( $platforms as $key => $data ) { if ( ! empty( $vars[ $key ] ) ) { $has_platforms = true; break; } } if ( ! $has_platforms ) { return; } // Generate unique ID for this widget instance. $widget_id = 'a1tools-social-' . $this->number; // Build inline styles. $container_styles = array( 'text-align' => $alignment, ); $link_styles = array( 'width' => $size . 'px', 'height' => $size . 'px', 'margin' => '0 ' . ( $spacing / 2 ) . 'px ' . $spacing . 'px', 'font-size' => $icon_size . 'px', 'display' => 'inline-flex', 'align-items' => 'center', 'justify-content' => 'center', 'text-decoration' => 'none', 'transition' => 'all 0.3s ease', ); // Shape styles. switch ( $shape ) { case 'circle': $link_styles['border-radius'] = '50%'; break; case 'square': $link_styles['border-radius'] = '0'; break; case 'rounded': default: $link_styles['border-radius'] = '8px'; break; } // Output widget. // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Widget args are pre-escaped by WordPress. echo $args['before_widget']; if ( $title ) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Widget args are pre-escaped by WordPress. echo $args['before_title'] . esc_html( apply_filters( 'widget_title', $title ) ) . $args['after_title']; } // Build CSS for this widget instance. $css = '#' . esc_attr( $widget_id ) . ' { '; foreach ( $container_styles as $prop => $val ) { $css .= esc_attr( $prop ) . ':' . esc_attr( $val ) . ';'; } $css .= '}'; $css .= '#' . esc_attr( $widget_id ) . ' .a1tools-social-icon { '; foreach ( $link_styles as $prop => $val ) { $css .= esc_attr( $prop ) . ':' . esc_attr( $val ) . ';'; } $css .= '}'; // Style-specific CSS. if ( 'default' === $style || 'official' === $style ) { // Official colors or custom color background. $css .= '#' . esc_attr( $widget_id ) . ' .a1tools-social-icon { color: #fff; }'; } elseif ( 'outline' === $style ) { $css .= '#' . esc_attr( $widget_id ) . ' .a1tools-social-icon { background: transparent; border: 2px solid; }'; } elseif ( 'minimal' === $style ) { $css .= '#' . esc_attr( $widget_id ) . ' .a1tools-social-icon { background: transparent; }'; } elseif ( 'light' === $style ) { $css .= '#' . esc_attr( $widget_id ) . ' .a1tools-social-icon { background: #f5f5f5; }'; } elseif ( 'dark' === $style ) { $css .= '#' . esc_attr( $widget_id ) . ' .a1tools-social-icon { background: #333; color: #fff; }'; } // Hover effects. if ( 'scale' === $hover_effect ) { $css .= '#' . esc_attr( $widget_id ) . ' .a1tools-social-icon:hover { transform: scale(1.1); }'; } elseif ( 'lift' === $hover_effect ) { $css .= '#' . esc_attr( $widget_id ) . ' .a1tools-social-icon:hover { transform: translateY(-3px); box-shadow: 0 4px 12px rgba(0,0,0,0.2); }'; } elseif ( 'rotate' === $hover_effect ) { $css .= '#' . esc_attr( $widget_id ) . ' .a1tools-social-icon:hover { transform: rotate(15deg); }'; } elseif ( 'pulse' === $hover_effect ) { $css .= '#' . esc_attr( $widget_id ) . ' .a1tools-social-icon:hover { animation: a1tools-pulse 0.5s ease; }'; $css .= '@keyframes a1tools-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.15); } }'; } // Add CSS using WordPress enqueue system. wp_register_style( 'a1tools-social-widget-' . $this->number, false, array(), A1TOOLS_VERSION ); wp_enqueue_style( 'a1tools-social-widget-' . $this->number ); wp_add_inline_style( 'a1tools-social-widget-' . $this->number, $css ); // Output icons container. echo '
'; foreach ( $platforms as $key => $data ) { if ( ! empty( $vars[ $key ] ) ) { // Determine background/border color. $item_color = $custom_color ? $custom_color : ( 'official' === $style || 'default' === $style ? $data['color'] : '' ); $inline_style = ''; if ( 'default' === $style || 'official' === $style ) { $inline_style = 'background-color:' . esc_attr( $item_color ) . ';'; } elseif ( 'outline' === $style ) { $icon_color = $custom_color ? $custom_color : $data['color']; $inline_style = 'border-color:' . esc_attr( $icon_color ) . ';color:' . esc_attr( $icon_color ) . ';'; } elseif ( 'minimal' === $style ) { $icon_color = $custom_color ? $custom_color : $data['color']; $inline_style = 'color:' . esc_attr( $icon_color ) . ';'; } elseif ( 'light' === $style ) { $icon_color = $custom_color ? $custom_color : $data['color']; $inline_style = 'color:' . esc_attr( $icon_color ) . ';'; } echo ''; echo wp_kses( a1tools_get_icon_html( $data['icon'] ), a1tools_icon_allowed_tags() ); echo '' . esc_html( $data['label'] ) . ''; echo ''; } } echo '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Widget args are pre-escaped by WordPress. echo $args['after_widget']; } /** * Backend form. * * @param array $instance Widget instance. */ public function form( $instance ) { $title = ! empty( $instance['title'] ) ? $instance['title'] : ''; $shape = ! empty( $instance['shape'] ) ? $instance['shape'] : 'rounded'; $style = ! empty( $instance['style'] ) ? $instance['style'] : 'default'; $size = ! empty( $instance['size'] ) ? (int) $instance['size'] : 40; $icon_size = ! empty( $instance['icon_size'] ) ? (int) $instance['icon_size'] : 18; $spacing = ! empty( $instance['spacing'] ) ? (int) $instance['spacing'] : 8; $alignment = ! empty( $instance['alignment'] ) ? $instance['alignment'] : 'left'; $custom_color = ! empty( $instance['custom_color'] ) ? $instance['custom_color'] : ''; $hover_effect = ! empty( $instance['hover_effect'] ) ? $instance['hover_effect'] : 'scale'; ?>