PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / trunk
MxChat – AI Chatbot & Content Generation for WordPress vtrunk
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
mxchat-basic / includes / class-mxchat-elementor-widget.php

class-mxchat-elementor-widget.php in MxChat – AI Chatbot & Content Generation for WordPress trunk, at includes/class-mxchat-elementor-widget.php

165 lines 8.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) {
3 exit; // Exit if accessed directly
4 }
5
6 /**
7 * Elementor chatbot widget (plan 95dd1e, part 2). A thin wrapper over the
8 * [mxchat_chatbot] shortcode via MxChat_Block::render() — one rendering path,
9 * so per-page bot settings, consent gating and the floating/Auto-Display
10 * collision rule are all inherited here, never re-decided.
11 *
12 * The editor canvas and the preview iframe get a STATIC placeholder only: a
13 * live chatbot inside the builder would fire the front-end script, could start
14 * a chat session for the person editing, and would re-render on every property
15 * change. There is deliberately no content_template() — Elementor then asks
16 * the server for the widget markup, which lands in render() below where the
17 * edit-mode branch holds.
18 *
19 * This file is required only from MxChat_Elementor::register_widget(), inside
20 * the elementor/widgets/register hook — never load it unconditionally, the
21 * extends clause fatals without Elementor.
22 */
23 class MxChat_Elementor_Widget extends \Elementor\Widget_Base {
24
25 public function get_name() {
26 return 'mxchat_chatbot';
27 }
28
29 public function get_title() {
30 return __('MxChat Chatbot', 'mxchat');
31 }
32
33 public function get_icon() {
34 return 'eicon-comments';
35 }
36
37 public function get_categories() {
38 return array('general');
39 }
40
41 public function get_keywords() {
42 return array('chat', 'chatbot', 'ai', 'mxchat');
43 }
44
45 protected function register_controls() {
46 $this->start_controls_section('mxchat_placement', array(
47 'label' => __('Placement', 'mxchat'),
48 'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
49 ));
50
51 $this->add_control('display_mode', array(
52 'label' => __('Display mode', 'mxchat'),
53 'type' => \Elementor\Controls_Manager::SELECT,
54 'default' => 'inline',
55 'options' => array(
56 'inline' => __('Inline (in the page)', 'mxchat'),
57 'floating' => __('Floating bubble', 'mxchat'),
58 ),
59 'description' => __('Inline renders the chat box where the widget sits. Floating renders the familiar corner launcher; if the chatbot also displays automatically on this page, the usual single-widget rules apply.', 'mxchat'),
60 ));
61
62 // Bot picker only while Multi-Bot is active — same rule as the block:
63 // no free-text bot id anywhere (a typo would mean a silently wrong
64 // bot). Elementor SELECT keys can't be the empty string, so 'default'
65 // is the sentinel and maps to an omitted bot_id at render, making an
66 // untouched widget follow the page-level bot setting like a bare
67 // shortcode.
68 $bots = MxChat_Block::get_bot_choices();
69 if (!empty($bots)) {
70 $options = array();
71 foreach ($bots as $bot) {
72 $key = ($bot['value'] === '') ? 'default' : $bot['value'];
73 $options[$key] = $bot['label'];
74 }
75 $this->add_control('bot_id', array(
76 'label' => __('Bot', 'mxchat'),
77 'type' => \Elementor\Controls_Manager::SELECT,
78 'default' => 'default',
79 'options' => $options,
80 'description' => __('Default Bot follows this page&#8217;s chatbot settings.', 'mxchat'),
81 ));
82 }
83
84 $this->end_controls_section();
85 }
86
87 protected function render() {
88 $settings = $this->get_settings_for_display();
89 $display_mode = (isset($settings['display_mode']) && $settings['display_mode'] === 'floating') ? 'floating' : 'inline';
90 $bot_id = isset($settings['bot_id']) ? sanitize_key($settings['bot_id']) : '';
91 if ($bot_id === 'default') {
92 $bot_id = '';
93 }
94
95 // Editor canvas / preview iframe: static placeholder, never the live
96 // widget — the edit-mode trap this plan is built around.
97 $elementor = \Elementor\Plugin::$instance;
98 $in_editor = ($elementor->editor && $elementor->editor->is_edit_mode())
99 || ($elementor->preview && $elementor->preview->is_preview_mode());
100 if ($in_editor) {
101 $this->render_placeholder($display_mode, $bot_id);
102 return;
103 }
104
105 echo MxChat_Block::render(array(
106 'displayMode' => $display_mode,
107 'botId' => $bot_id,
108 ));
109 }
110
111 /**
112 * Static canvas placeholder — same look as the Gutenberg block's
113 * (assets/block/chatbot-block-editor.css), self-contained here because
114 * that stylesheet never loads in the Elementor canvas. The style block is
115 * emitted once per request; repeats are harmless dedupe misses across the
116 * editor's separate AJAX renders.
117 */
118 private function render_placeholder($display_mode, $bot_id) {
119 static $css_emitted = false;
120
121 $mode_text = ($display_mode === 'floating')
122 ? __('Floating bubble', 'mxchat')
123 : __('Inline (in the page)', 'mxchat');
124
125 $bots = MxChat_Block::get_bot_choices();
126 $meta_text = $mode_text;
127 if (!empty($bots)) {
128 $bot_label = __('Default Bot', 'mxchat');
129 foreach ($bots as $bot) {
130 if ($bot['value'] === $bot_id && $bot_id !== '') {
131 $bot_label = $bot['label'];
132 break;
133 }
134 }
135 $meta_text = $mode_text . ' · ' . $bot_label;
136 }
137
138 if (!$css_emitted) {
139 $css_emitted = true;
140 echo '<style>'
141 . '.mxchat-elementor-placeholder{display:flex;align-items:center;gap:12px;padding:20px 24px;border:1px dashed #949494;border-radius:4px;background:#f0f0f0;color:#1e1e1e;}'
142 . '.mxchat-elementor-placeholder-icon{display:flex;flex-shrink:0;width:48px;height:48px;color:#212121;}'
143 . '.mxchat-elementor-placeholder-icon svg{width:100%;height:100%;}'
144 . '.mxchat-elementor-placeholder-text{display:flex;flex-direction:column;gap:2px;min-width:0;}'
145 . '.mxchat-elementor-placeholder-text strong{font-size:14px;line-height:1.4;}'
146 . '.mxchat-elementor-placeholder-meta{font-size:12px;line-height:1.4;color:#555d66;}'
147 . '</style>';
148 }
149
150 // Same brand icon as the Gutenberg block (chatbot-block.js).
151 echo '<div class="mxchat-elementor-placeholder">'
152 . '<span class="mxchat-elementor-placeholder-icon">'
153 . '<svg viewBox="0 0 1120 1120" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">'
154 . '<path fill-rule="evenodd" clip-rule="evenodd" fill="currentColor" d="M252 434C252 372.144 302.144 322 364 322H770C831.856 322 882 372.144 882 434V614.459L804.595 585.816C802.551 585.06 800.94 583.449 800.184 581.405L763.003 480.924C760.597 474.424 751.403 474.424 748.997 480.924L711.816 581.405C711.06 583.449 709.449 585.06 707.405 585.816L606.924 622.997C600.424 625.403 600.424 634.597 606.924 637.003L707.405 674.184C709.449 674.94 711.06 676.551 711.816 678.595L740.459 756H629.927C629.648 756.476 629.337 756.945 628.993 757.404L578.197 825.082C572.597 832.543 561.403 832.543 555.803 825.082L505.007 757.404C504.663 756.945 504.352 756.476 504.073 756H364C302.144 756 252 705.856 252 644V434ZM633.501 471.462C632.299 468.212 627.701 468.212 626.499 471.462L619.252 491.046C618.874 492.068 618.068 492.874 617.046 493.252L597.462 500.499C594.212 501.701 594.212 506.299 597.462 507.501L617.046 514.748C618.068 515.126 618.874 515.932 619.252 516.954L626.499 536.538C627.701 539.788 632.299 539.788 633.501 536.538L640.748 516.954C641.126 515.932 641.932 515.126 642.954 514.748L662.538 507.501C665.788 506.299 665.788 501.701 662.538 500.499L642.954 493.252C641.932 492.874 641.126 492.068 640.748 491.046L633.501 471.462Z"/>'
155 . '<path fill="currentColor" d="M771.545 755.99C832.175 755.17 881.17 706.175 881.99 645.545L804.595 674.184C802.551 674.94 800.94 676.551 800.184 678.595L771.545 755.99Z"/>'
156 . '</svg>'
157 . '</span>'
158 . '<span class="mxchat-elementor-placeholder-text">'
159 . '<strong>' . esc_html__('MxChat Chatbot', 'mxchat') . '</strong>'
160 . '<span class="mxchat-elementor-placeholder-meta">' . esc_html($meta_text) . '</span>'
161 . '</span>'
162 . '</div>';
163 }
164 }
165