start_controls_section( 'mode_section', array( 'label' => __( 'Placement', 'a1-tools' ), 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, ) ); $this->add_control( 'placement', array( 'label' => __( 'Placement', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => 'floating', 'options' => array( 'floating' => __( 'Floating (fixed to corner)', 'a1-tools' ), 'inline' => __( 'Inline (place in layout)', 'a1-tools' ), ), 'description' => __( 'Both modes share the same conversation — drop multiple onto a page if you want a sticky button + an in-content CTA.', 'a1-tools' ), ) ); $this->add_control( 'floating_corner', array( 'label' => __( 'Floating Corner', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => 'br', 'options' => array( 'br' => __( 'Bottom Right', 'a1-tools' ), 'bl' => __( 'Bottom Left', 'a1-tools' ), 'tr' => __( 'Top Right', 'a1-tools' ), 'tl' => __( 'Top Left', 'a1-tools' ), ), 'condition' => array( 'placement' => 'floating' ), ) ); $this->end_controls_section(); // ── Button content ──────────────────────────────────────── $this->start_controls_section( 'content_section', array( 'label' => __( 'Button & Window', 'a1-tools' ), 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, ) ); $this->add_control( 'button_label', array( 'label' => __( 'Button Label', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => __( 'Live chat', 'a1-tools' ), ) ); $this->add_control( 'show_icon', array( 'label' => __( 'Show Icon', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::SWITCHER, 'default' => 'yes', 'return_value' => 'yes', ) ); $this->add_control( 'window_title', array( 'label' => __( 'Window Title', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => __( 'Chat with us', 'a1-tools' ), ) ); $this->add_control( 'window_subtitle', array( 'label' => __( 'Window Subtitle', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => __( "We're online and ready to help.", 'a1-tools' ), ) ); $this->add_control( 'pre_chat_intro', array( 'label' => __( 'Pre-chat Intro', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::TEXTAREA, 'default' => __( 'Quick details first so we can get back to you if we disconnect:', 'a1-tools' ), 'label_block' => true, ) ); $this->add_control( 'greeting_message', array( 'label' => __( 'Greeting (sent after pre-chat)', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::TEXTAREA, 'default' => __( "Hi! Thanks for reaching out — a team member will be with you in just a moment.", 'a1-tools' ), 'label_block' => true, ) ); $this->add_control( 'offline_message', array( 'label' => __( 'Offline Subhead', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => __( "We're offline — leave a note and we'll reply by email or call.", 'a1-tools' ), 'description' => __( 'Shown when no dispatcher is currently connected.', 'a1-tools' ), ) ); $this->end_controls_section(); // ── Pre-chat Form (content) ──────────────────────────────── // (2.5.2) Mirrors the field configurability added to the Web // Form widget. The pre-chat form has only two fields by design // (name + phone-or-email) — both required by default since // CRM dispatchers need *some* way to reconnect if the visitor // closes the tab. Each field's label and required-flag is // editable here. $this->start_controls_section( 'prechat_section', array( 'label' => __( 'Pre-chat Form', 'a1-tools' ), 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, ) ); $this->add_control( 'prechat_name_label', array( 'label' => __( 'Name field label', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => __( 'Your name', 'a1-tools' ), ) ); $this->add_control( 'prechat_name_required', array( 'label' => __( 'Name required', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::SWITCHER, 'return_value' => 'yes', 'default' => 'yes', ) ); $this->add_control( 'prechat_contact_label', array( 'label' => __( 'Phone-or-Email field label', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => __( 'Phone or email', 'a1-tools' ), 'description' => __( 'Single field accepting either a phone number or an email address.', 'a1-tools' ), ) ); $this->add_control( 'prechat_contact_required', array( 'label' => __( 'Contact required', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::SWITCHER, 'return_value' => 'yes', 'default' => 'yes', ) ); $this->add_control( 'prechat_submit_label', array( 'label' => __( 'Start-chat button label', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => __( 'Start chat', 'a1-tools' ), ) ); $this->end_controls_section(); // ── Button Style ──────────────────────────────────────── $this->start_controls_section( 'style_button_section', array( 'label' => __( 'Button Style', 'a1-tools' ), 'tab' => \Elementor\Controls_Manager::TAB_STYLE, ) ); $this->start_controls_tabs( 'button_state_tabs' ); $this->start_controls_tab( 'button_normal_tab', array( 'label' => __( 'Normal', 'a1-tools' ) ) ); $this->add_control( 'button_bg_color', array( 'label' => __( 'Background', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::COLOR, 'default' => '#f49320', 'selectors' => array( '{{WRAPPER}} .a1tools-web-chat__button' => 'background-color: {{VALUE}};', ), ) ); $this->add_control( 'button_text_color', array( 'label' => __( 'Text/Icon', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::COLOR, 'default' => '#ffffff', 'selectors' => array( '{{WRAPPER}} .a1tools-web-chat__button' => 'color: {{VALUE}};', ), ) ); $this->end_controls_tab(); $this->start_controls_tab( 'button_hover_tab', array( 'label' => __( 'Hover', 'a1-tools' ) ) ); $this->add_control( 'button_bg_hover_color', array( 'label' => __( 'Background', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::COLOR, 'default' => '#d67d10', 'selectors' => array( '{{WRAPPER}} .a1tools-web-chat__button:hover' => 'background-color: {{VALUE}};', ), ) ); $this->add_control( 'button_text_hover_color', array( 'label' => __( 'Text/Icon', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::COLOR, 'default' => '#ffffff', 'selectors' => array( '{{WRAPPER}} .a1tools-web-chat__button:hover' => 'color: {{VALUE}};', ), ) ); $this->end_controls_tab(); $this->end_controls_tabs(); $this->add_group_control( \Elementor\Group_Control_Typography::get_type(), array( 'name' => 'button_typography', 'selector' => '{{WRAPPER}} .a1tools-web-chat__button', ) ); $this->add_control( 'button_border_radius', array( 'label' => __( 'Border Radius', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::DIMENSIONS, 'size_units' => array( 'px', '%' ), 'default' => array( 'top' => 30, 'right' => 30, 'bottom' => 30, 'left' => 30, 'unit' => 'px', ), 'selectors' => array( '{{WRAPPER}} .a1tools-web-chat__button' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', ), ) ); $this->add_responsive_control( 'button_padding', array( 'label' => __( 'Padding', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::DIMENSIONS, 'size_units' => array( 'px', 'em', '%' ), 'default' => array( 'top' => 14, 'right' => 24, 'bottom' => 14, 'left' => 24, 'unit' => 'px', ), 'selectors' => array( '{{WRAPPER}} .a1tools-web-chat__button' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', ), ) ); $this->add_group_control( \Elementor\Group_Control_Box_Shadow::get_type(), array( 'name' => 'button_box_shadow', 'selector' => '{{WRAPPER}} .a1tools-web-chat__button', ) ); $this->end_controls_section(); // ── Window Style ─────────────────────────────────────── $this->start_controls_section( 'style_window_section', array( 'label' => __( 'Window Style', 'a1-tools' ), 'tab' => \Elementor\Controls_Manager::TAB_STYLE, ) ); $this->add_control( 'window_header_bg', array( 'label' => __( 'Header Background', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::COLOR, 'default' => '#f49320', 'selectors' => array( '.a1tools-web-chat-window__header' => 'background-color: {{VALUE}};', ), ) ); $this->add_control( 'window_header_text', array( 'label' => __( 'Header Text', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::COLOR, 'default' => '#ffffff', 'selectors' => array( '.a1tools-web-chat-window__header, .a1tools-web-chat-window__header *' => 'color: {{VALUE}};', ), ) ); $this->add_control( 'window_dispatcher_bubble', array( 'label' => __( 'Dispatcher Bubble', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::COLOR, 'default' => '#eef2ff', 'selectors' => array( '.a1tools-web-chat-window__msg--dispatcher .a1tools-web-chat-window__bubble' => 'background-color: {{VALUE}};', ), ) ); $this->add_control( 'window_visitor_bubble', array( 'label' => __( 'Visitor Bubble', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::COLOR, 'default' => '#f49320', 'selectors' => array( '.a1tools-web-chat-window__msg--visitor .a1tools-web-chat-window__bubble' => 'background-color: {{VALUE}}; color: #fff;', ), ) ); // (2.5.2) Window container styling — bg, border, radius, shadow. // These keep the chat window visually coherent with the host // page rather than always being the default white card. // Selectors are unscoped (no {{WRAPPER}}) because the window // renders into document.body via the global JS module, not as // a child of the Elementor widget wrapper. $this->add_control( 'window_bg', array( 'label' => __( 'Window Background', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::COLOR, 'default' => '#ffffff', 'selectors' => array( '.a1tools-web-chat-window' => 'background-color: {{VALUE}};', ), ) ); $this->add_control( 'window_border_color', array( 'label' => __( 'Window Border Color', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::COLOR, 'default' => '', 'selectors' => array( '.a1tools-web-chat-window' => 'border-color: {{VALUE}}; border-style: solid;', ), ) ); $this->add_control( 'window_border_width', array( 'label' => __( 'Window Border Width', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::SLIDER, 'size_units' => array( 'px' ), 'range' => array( 'px' => array( 'min' => 0, 'max' => 6 ) ), 'default' => array( 'size' => 0, 'unit' => 'px' ), 'selectors' => array( '.a1tools-web-chat-window' => 'border-width: {{SIZE}}{{UNIT}}; border-style: solid;', ), ) ); $this->add_control( 'window_radius', array( 'label' => __( 'Window Border Radius', 'a1-tools' ), 'type' => \Elementor\Controls_Manager::DIMENSIONS, 'size_units' => array( 'px', '%' ), 'selectors' => array( '.a1tools-web-chat-window' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}}; overflow: hidden;', ), ) ); $this->add_group_control( \Elementor\Group_Control_Box_Shadow::get_type(), array( 'name' => 'window_shadow', 'selector' => '.a1tools-web-chat-window', ) ); $this->add_group_control( \Elementor\Group_Control_Typography::get_type(), array( 'name' => 'window_typography', 'selector' => '.a1tools-web-chat-window, .a1tools-web-chat-window input, .a1tools-web-chat-window textarea, .a1tools-web-chat-window button', ) ); $this->end_controls_section(); } // ──────────────────────────────────────────────────────────────── // Render // ──────────────────────────────────────────────────────────────── protected function render() { $settings = $this->get_settings_for_display(); // Read the CRM company id from the SAME option key the existing // form pipeline + admin UI use (`a1tools_form_crm_company_id`). // An earlier draft of this widget mistakenly read // `a1tools_form_company_id` (no `_crm_`), which doesn't exist — // every site rendered the widget with `data-company-id="0"` and // the JS bailed at the `if (!config.companyId)` check, so the // button click handler was never attached. (Plugin 2.5.1.) // // (2.5.6) When the option is still 0 (the default — most sites // never get manually configured), fall through to the // auto-resolver which hits `?action=public&url=` // once and back-fills the option from the server's // `wordpress_sites → wordpress_groups.company_id` lookup. // Result is cached in the option, so subsequent renders // skip the API hop. $company_id = (int) get_option( 'a1tools_form_crm_company_id', 0 ); if ( $company_id === 0 && function_exists( 'a1tools_resolve_crm_company_id' ) ) { $company_id = a1tools_resolve_crm_company_id(); } $placement = in_array( ( $settings['placement'] ?? '' ), array( 'inline', 'floating' ), true ) ? $settings['placement'] : 'floating'; $corner = $settings['floating_corner'] ?? 'br'; $button_label = $settings['button_label'] ?? __( 'Live chat', 'a1-tools' ); $window_title = $settings['window_title'] ?? __( 'Chat with us', 'a1-tools' ); $window_subtitle = $settings['window_subtitle'] ?? ''; $pre_chat_intro = $settings['pre_chat_intro'] ?? ''; $greeting = $settings['greeting_message'] ?? ''; $offline_msg = $settings['offline_message'] ?? ''; $show_icon = ( $settings['show_icon'] ?? 'yes' ) === 'yes'; // (2.5.2) Pre-chat form labels — passed to the JS module via // data attributes so the same global window honours per-widget // label overrides on the host page. $prechat_name_label = $settings['prechat_name_label'] ?? __( 'Your name', 'a1-tools' ); $prechat_name_required = ( $settings['prechat_name_required'] ?? 'yes' ) === 'yes'; $prechat_contact_label = $settings['prechat_contact_label'] ?? __( 'Phone or email', 'a1-tools' ); $prechat_contact_required = ( $settings['prechat_contact_required'] ?? 'yes' ) === 'yes'; $prechat_submit_label = $settings['prechat_submit_label'] ?? __( 'Start chat', 'a1-tools' ); $api_base = 'https://tools.a-1chimney.com/api/web_chat.php'; $site_url = home_url(); // Per-widget DOM id so multiple placements on one page coexist. $wid_id = 'a1tools-web-chat-' . wp_unique_id(); $wrap_classes = array( 'a1tools-web-chat' ); $wrap_classes[] = 'a1tools-web-chat--' . ( 'inline' === $placement ? 'inline' : 'floating' ); if ( 'floating' === $placement ) { $wrap_classes[] = 'a1tools-web-chat--corner-' . sanitize_key( $corner ); } ?>