2
0

Introduce bot v2 in builder (#328)

Also, the new engine is the default for updated typebots for viewer

Closes #211
This commit is contained in:
Baptiste Arnaud
2023-02-21 15:25:14 +01:00
committed by GitHub
parent 527dc8a5b1
commit debdac12ff
208 changed files with 4462 additions and 5236 deletions

View File

@ -5,7 +5,7 @@ Requires at least: 5.0
Tested up to: 6.0
License: GPL 2.0
License URI: http://www.gnu.org/licenses/gpl-2.0.txt
Stable Tag: 2.1.11
Stable Tag: 3.0.0
Build beautiful conversational forms
@ -26,6 +26,9 @@ This plugin relies on Typebot which is a tool that allows you to create conversa
3. Activate your Typebot with the "Typebot" admin button located in the sidebar
== Changelog ==
= 3.0.0 =
* Complete rework of the plugin. You are now required to generate a code snippet on https://app.typebot.io
= 2.1.9 =
* Fix standard embed when window is already loaded

View File

@ -5,26 +5,6 @@ if (!defined('ABSPATH')) {
class Typebot_Admin
{
private $version;
public function __construct($version)
{
$this->version = $version;
}
public function enqueue_styles($hook)
{
if ($hook === 'toplevel_page_typebot/settings') {
wp_enqueue_style(
'bulma',
plugin_dir_url(__FILE__) . 'css/bulma.min.css',
[],
$this->version,
'all'
);
}
}
public function my_admin_menu()
{
add_menu_page(
@ -45,47 +25,6 @@ class Typebot_Admin
public function register_typebot_settings()
{
register_setting('typebot', 'url', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'embed_type', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'popup_delay', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'bubble_delay', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'chat_delay', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'avatar', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'text_content', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'button_color', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'chat_included_pages', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'popup_included_pages', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'chat_icon', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'custom_code', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'config_type', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'dont_show_callout_twice', [
'sanitize_callback' => 'sanitize_text_field',
]);
register_setting('typebot', 'init_snippet');
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,255 +1,25 @@
<script>
let isContainer, isPopup, isBubble, popupParamsElement, bubbleParamsElement, showAdvanced;
window.addEventListener("load", function(event) {
isContainer = document.getElementById("radio-container").checked
isPopup = document.getElementById("radio-popup").checked
isBubble = document.getElementById("radio-bubble").checked
popupParamsElement = document.getElementById("popup-params")
bubbleParamsElement = document.getElementById("bubble-params")
if (isPopup) popupParamsElement.style.display = "block"
if (isBubble) bubbleParamsElement.style.display = "block"
});
const updateParams = (type) => {
popupParamsElement.style.display = "none"
bubbleParamsElement.style.display = "none"
if (type === "popup") popupParamsElement.style.display = "block"
if (type === "bubble") bubbleParamsElement.style.display = "block"
}
const onRadioClick = (e) => updateParams(e.target.value)
var currentValue;
function handleClick(myRadio) {
const easyBlock = document.getElementById("easy-block")
const codeBlock = document.getElementById("code-block")
currentValue = myRadio.value;
if(currentValue === "easy"){
easyBlock.style.display = "block"
codeBlock.style.display = "none"
} else if(currentValue === "advanced"){
easyBlock.style.display = "none"
codeBlock.style.display = "block"
}
}
</script>
<div class="box" style="padding: 3rem; margin-top: 1rem; margin-right: 1rem; max-width: 800px">
<h1 class="title">Typebot Settings</h1>
<a style="text-decoration: underline" href="https://app.typebot.io/typebots" target="_blank">First, you need to create a Typebot with our builder. It's free.</a>
<form method="post" action="options.php" style="margin-top: 1rem">
<?php
settings_fields('typebot');
do_settings_sections('typebot');
?>
<div style="display: flex; flex-direction: column;">
<label>
<input type="radio" name="config_type" onclick="handleClick(this);" value="easy" <?php if (
esc_attr(get_option('config_type')) == 'easy'
) {
echo esc_attr('checked');
} ?>>
Easy setup
</label>
<div id="easy-block" style="display: <?php if (
esc_attr(get_option('config_type')) == 'easy'
) {
echo esc_attr('block');
} else {
echo esc_attr('none');
} ?>; margin-top:0.5rem">
<div class="field">
<label class="label">Your typebot URL</label>
<div class="control">
<input class="input" type="url" placeholder="Found in 'Share' page of your typebot" name="url" value="<?php echo esc_attr(
get_option('url')
); ?>">
</div>
</div>
<label class="label">Select an embed type</label>
<div class="field is-grouped">
<label class="box is-flex-direction-column" style="margin-bottom: 0; margin-right: 1rem; padding: 3rem">
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="100" rx="5" fill="#0042DA" />
<rect x="10" y="28" width="80" height="42" rx="6" fill="#FF8E20" />
<circle cx="18" cy="37" r="5" fill="white" />
<rect x="24" y="33" width="45" height="8" rx="4" fill="white" />
<circle cx="18" cy="61" r="5" fill="white" />
<rect x="24" y="57" width="45" height="8" rx="4" fill="white" />
<rect x="31" y="45" width="45" height="8" rx="4" fill="white" />
<circle cx="82" cy="49" r="5" fill="white" />
<rect x="10" y="9" width="80" height="1" rx="0.5" fill="white" />
<rect x="10" y="14" width="80" height="1" rx="0.5" fill="white" />
<rect x="10" y="19" width="80" height="1" rx="0.5" fill="white" />
<rect x="10" y="80" width="80" height="1" rx="0.5" fill="white" />
<rect x="10" y="85" width="80" height="1" rx="0.5" fill="white" />
<rect x="10" y="90" width="80" height="1" rx="0.5" fill="white" />
</svg>
<p style="text-align: center; font-size: 20px; margin-bottom: .5rem">Container</p>
<input type="radio" onclick="onRadioClick(event)" name="embed_type" id="radio-container" style="display:flex; margin:auto" <?php if (
esc_attr(get_option('embed_type')) === 'container'
) {
echo esc_attr('checked');
} ?> value="container">
</label>
<label class="box is-flex-direction-column" style="margin-bottom: 0; margin-right: 1rem; padding: 3rem">
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="100" rx="5" fill="#0042DA" />
<rect x="19" y="20" width="63" height="63" rx="6" fill="#FF8E20" />
<circle cx="25.7719" cy="33.7719" r="3.77193" fill="white" />
<rect x="31" y="30" width="27" height="8" rx="4" fill="white" />
<circle r="3.77193" transform="matrix(-1 0 0 1 75.2281 43.7719)" fill="white" />
<rect width="22" height="8" rx="4" transform="matrix(-1 0 0 1 70 40)" fill="white" />
<rect x="31.0527" y="52" width="26.9473" height="7.54386" rx="3.77193" fill="white" />
<circle cx="25.7719" cy="67.7719" r="3.77193" fill="white" />
<rect x="31" y="64" width="27" height="8" rx="4" fill="white" />
</svg>
<p style="text-align: center; font-size: 20px; margin-bottom: .5rem">Popup</p>
<input type="radio" onclick="onRadioClick(event)" name="embed_type" id="radio-popup" style="display:flex; margin:auto" <?php if (
esc_attr(get_option('embed_type')) === 'popup'
) {
echo esc_attr('checked');
} ?> value="popup">
</label>
<label class="box is-flex-direction-column" style="margin-bottom: 0; padding: 3rem">
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="100" rx="5" fill="#0042DA" />
<circle cx="85.5" cy="85.5" r="7.5" fill="#FF8E20" />
</svg>
<p style="text-align: center; font-size: 20px; margin-bottom: .5rem">Bubble</p>
<input type="radio" onclick="onRadioClick(event)" name="embed_type" id="radio-bubble" style="display:flex; margin:auto" <?php if (
esc_attr(get_option('embed_type')) === 'bubble'
) {
echo esc_attr('checked');
} ?> value="bubble">
</label>
</div>
<div style="margin-top: 2rem; display:none" id="popup-params">
<div class="field">
<label class="label">Delay before apparition in seconds</label>
<div class="control" style="margin-bottom: 1rem;">
<input class="input" type="number" placeholder="0" name="popup_delay" value="<?php echo esc_attr(
get_option('popup_delay')
); ?>">
</div>
</div>
<div class="field">
<label class="label">Pages to include separated by a comma (optionnal)</label>
<div class="control" style="margin-bottom: 1rem;">
<input class="input" type="text" placeholder="/my-page/*,/my-other-page" name="popup_included_pages" value="<?php echo esc_attr(
get_option('popup_included_pages')
); ?>">
</div>
</div>
</div>
<div style="margin-top: 2rem; display:none" id="bubble-params">
<div class="field">
<label class="label">Bubble button color</label>
<div class="control">
<input class="input" type="text" placeholder="#0042DA" name="button_color" value="<?php echo esc_attr(
get_option('button_color')
); ?>">
</div>
</div>
<div class="field">
<label class="label">Auto open delay (optional)</label>
<div class="control">
<input class="input" type="number" placeholder="Delay before the chat opens up (5)" name="chat_delay" value="<?php echo esc_attr(
get_option('chat_delay')
); ?>">
</div>
</div>
<div class="field">
<label class="label">Bubble button icon (optional)</label>
<div class="control">
<input class="input" type="text" placeholder="Type an image URL..." name="chat_icon" value="<?php echo esc_attr(
get_option('chat_icon')
); ?>">
</div>
</div>
<div class="field">
<label class="label">Proactive message (optional)</label>
<div class="control">
<input class="input" type="text" placeholder="Message (Hey, I have some questions for you 👋)" name="text_content" value="<?php echo esc_attr(
get_option('text_content')
); ?>">
</div>
<div class="control" style="margin-top: .5rem">
<input class="input" type="text" placeholder="Avatar photo URL (https://...)" name="avatar" value="<?php echo esc_attr(
get_option('avatar')
); ?>">
</div>
<div class="control" style="margin-top: .5rem; margin-bottom: 1rem">
<input class="input" type="number" placeholder="Delay before message apparition (5)" name="bubble_delay" value="<?php echo esc_attr(
get_option('bubble_delay')
); ?>">
</div>
<label>
<input type="checkbox" <?php if (
esc_attr(get_option('dont_show_callout_twice'))
) {
echo esc_attr('checked');
} ?> name="dont_show_callout_twice">
Don't show callout message when opened or closed once
</label>
</div>
<div class="field">
<label class="label">Pages to include separated by a comma (optionnal)</label>
<div class="control" style="margin-bottom: 1rem;">
<input class="input" type="text" placeholder="/my-page/*,/my-other-page" name="chat_included_pages" value="<?php echo esc_attr(
get_option('chat_included_pages')
); ?>">
</div>
</div>
</div>
<?php if (esc_attr(get_option('embed_type')) === 'container'): ?>
<div class="notification is-link" style="margin-bottom: 1rem;">
You can now place your typebot container anywhere in your site using [typebot] shortcode.
<br><br>
Your page templating system probably has a "Shortcode" element (if not, use a text element) where you can paste:
<pre>[typebot]</pre>
<br>
Optionnaly, you can adjust `width`, `height`, `background-color` and/or `url` if you want to embed multiple typebots:
<pre>[typebot width="100%" height="500px" background-color="#F7F8FF" url="https://my.typebot.io"]</pre>
</div>
<?php endif; ?>
</div>
<label>
<input type="radio" name="config_type" onclick="handleClick(this);" value="advanced" <?php if (
esc_attr(get_option('config_type')) == 'advanced'
) {
echo esc_attr('checked');
} ?>>
Advanced setup (with code)
</label>
<div id="code-block" style="display: <?php if (
esc_attr(get_option('config_type')) == 'advanced'
) {
echo esc_attr('block');
} else {
echo esc_attr('none');
} ?>">
<label>Paste the code from "HTML & Js" in Typebot in the Share tab:</label>
<textarea class="textarea" style="margin-top:0.5rem" name="custom_code"><?php echo esc_attr(
get_option('custom_code')
); ?></textarea>
<div style="padding: 1rem; max-width: 700px">
<h1 style="margin-bottom: 2rem;">Typebot Settings</h1>
<ol style="margin-top: 1rem; margin-left: 1rem; font-size: 16px; display: flex; flex-direction: column;gap: 1rem">
<li>Generate your initialization snippet in the Share tab of your typebot.</li>
<li>If embedding as <strong>Standard</strong> container, paste the generated shortcode anywhere on your site.</li>
<li>
<form method="post" action="options.php">
<?php
settings_fields('typebot');
do_settings_sections('typebot');
?>
<div style="display: flex; flex-direction: column">
<label>If embedding as <strong>Popup</strong> or <strong>Bubble</strong>, paste the initialization snippet here:</label>
<textarea name="init_snippet" placeholder='Typebot.initPopup({ typebot: "https://typebot.io/my-typebot" });' style="min-height: 150px; padding: 0.5rem; margin-top: 1rem"><?php echo esc_attr(get_option('init_snippet')); ?></textarea>
</div>
</div>
<div class="field" style="margin-top: 2rem">
<div class="control">
<button class="button is-link is-medium">Save</button>
</div>
</div>
</form>
<div style="margin-top: 1rem">
<div>
<button class="button">Save</button>
</div>
</div>
</form>
</li>
</ol>
</div>

View File

@ -50,7 +50,7 @@ class Typebot
private function define_public_hooks()
{
$plugin_public = new Typebot_Public($this->get_plugin_name(), $this->get_version());
$this->loader->add_action('wp_head', $plugin_public, 'add_head_code');
$this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'add_head_code');
$this->loader->add_shortcode('typebot', $plugin_public, 'add_typebot_container');
}

View File

@ -4,219 +4,33 @@ class Typebot_Public
{
public function add_head_code()
{
wp_enqueue_script(
'typebot',
'https://unpkg.com/typebot-js@2.2/dist/index.umd.min.js'
);
function add_module_type($tag, $handle)
{
if ('typebot' !== $handle) {
return $tag;
}
$tag = str_replace(
'<script',
'<script type ="module"',
$tag
);
return $tag;
}
wp_enqueue_script('typebot', 'whatever.js');
add_filter('script_loader_tag', 'add_module_type', 10, 2);
wp_add_inline_script('typebot', $this->parse_wp_user());
if (get_option('config_type') === 'advanced') {
echo esc_html(get_option('custom_code'));
if (get_option('init_snippet') && get_option('init_snippet') !== '') {
wp_add_inline_script('typebot', get_option('init_snippet'));
wp_add_inline_script('typebot', 'Typebot.setPrefilledVariables({ typebotWpUser });');
}
if (get_option('embed_type') === 'popup') {
return $this->parse_popup_head_code();
}
if (get_option('embed_type') === 'bubble') {
return $this->parse_bubble_head_code();
}
}
private function parse_popup_head_code()
{
$url = str_starts_with(get_option('url'), 'https://typebot.io')
? 'https://viewer.typebot.io' . '/' . explode('/', get_option('url'))[3]
: get_option('url');
if (!$url) {
return;
}
if (
get_option('popup_included_pages') !== null &&
get_option('popup_included_pages') !== ''
) {
$paths = explode(',', get_option('popup_included_pages'));
$arr_js = 'const typebot_include_paths = [';
foreach ($paths as $path) {
$arr_js = $arr_js . '"' . $path . '",';
}
$arr_js = $arr_js . ']';
wp_add_inline_script('typebot', $arr_js);
} else {
wp_add_inline_script('typebot', 'const typebot_include_paths = null');
}
$params =
'{
url: "' .
$url .
'",
hiddenVariables: typebotWpUser,
}';
if (
get_option('popup_delay') !== null &&
get_option('popup_delay') !== ''
) {
$params =
'{
url: "' .
$url .
'",
delay: ' .
get_option('popup_delay') * 1000 .
'
}';
}
wp_add_inline_script(
'typebot',
'if (!typebot_include_paths) {
Typebot.initPopup(' .
$params .
');
} else if (
typebot_include_paths.some((path) => {
let includePath = path;
let windowPath = window.location.pathname;
if (includePath.endsWith("*")) {
return windowPath.startsWith(includePath.slice(0, -1));
}
if (includePath.endsWith("/")) {
includePath = path.slice(0, -1);
}
if (windowPath.endsWith("/")) {
windowPath = windowPath.slice(0, -1);
}
return windowPath === includePath;
})
) {
Typebot.initPopup(' .
$params .
');
}'
);
}
private function parse_bubble_head_code()
{
$url = str_starts_with(get_option('url'), 'https://typebot.io')
? 'https://viewer.typebot.io' . '/' . explode('/', get_option('url'))[3]
: get_option('url');
if (!$url) {
return;
}
$chat_icon = get_option('chat_icon');
if (
get_option('chat_included_pages') !== null &&
get_option('chat_included_pages') !== ''
) {
$paths = explode(',', get_option('chat_included_pages'));
$arr_js = 'const typebot_include_paths = [';
foreach ($paths as $path) {
$arr_js = $arr_js . '"' . $path . '",';
}
$arr_js = $arr_js . ']';
wp_add_inline_script('typebot', $arr_js);
} else {
wp_add_inline_script('typebot', 'const typebot_include_paths = null');
}
$button_color = '#0042DA';
if (
get_option('button_color') !== null &&
get_option('button_color') !== ''
) {
$button_color = get_option('button_color');
}
$params =
'{
url: "' .
$url .
'",
autoOpenDelay: ' .
(get_option('chat_delay') === '' || get_option('chat_delay') === null
? 'undefined'
: get_option('chat_delay') * 1000) .
',
button: {
color: "' .
$button_color .
'",
iconUrl: "' .
$chat_icon .
'",
},
hiddenVariables: typebotWpUser,
}';
if (
get_option('text_content') !== '' &&
get_option('text_content') !== null
) {
$remember =
get_option('dont_show_callout_twice') === 'on' ? 'true' : 'false';
$params =
'{
url: "' .
$url .
'",
autoOpenDelay: ' .
(get_option('chat_delay') === '' || get_option('chat_delay') === null
? 'undefined'
: get_option('chat_delay') * 1000) .
',
proactiveMessage: {
avatarUrl: "' .
get_option('avatar') .
'",
textContent: "' .
get_option('text_content') .
'",
delay: ' .
get_option('bubble_delay') * 1000 .
',
rememberClose: ' .
$remember .
'
},
hiddenVariables: typebotWpUser,
button: {
color: "' .
$button_color .
'",
iconUrl: "' .
$chat_icon .
'",
},
}';
}
wp_add_inline_script(
'typebot',
'if (!typebot_include_paths) {
Typebot.initBubble(' .
$params .
');
} else if (
typebot_include_paths.some((path) => {
let includePath = path;
let windowPath = window.location.pathname;
if (includePath.endsWith("*")) {
return windowPath.startsWith(includePath.slice(0, -1));
}
if (includePath.endsWith("/")) {
includePath = path.slice(0, -1);
}
if (windowPath.endsWith("/")) {
windowPath = windowPath.slice(0, -1);
}
return windowPath === includePath;
})
) {
Typebot.initBubble(' .
$params .
');
}'
);
}
private function parse_wp_user()
{
$wp_user = wp_get_current_user();
return 'if(typeof typebotWpUser === "undefined"){
var typebotWpUser = {
return 'if(typeof window.typebotWpUser === "undefined"){
window.typebotWpUser = {
wp_id:"' .
$wp_user->ID .
'",
@ -238,69 +52,29 @@ class Typebot_Public
public function add_typebot_container($attributes = [])
{
$lib_url = "https://cdn.jsdelivr.net/npm/@typebot.io/js@0.0.9/dist/web.js";
$width = '100%';
$height = '500px';
$bg_color = 'rgba(255, 255, 255, 0)';
$url = str_starts_with(get_option('url'), 'https://typebot.io')
? 'https://viewer.typebot.io' . '/' . explode('/', get_option('url'))[3]
: get_option('url');
if (is_array($attributes)) {
if (array_key_exists('width', $attributes)) {
$width = sanitize_text_field($attributes['width']);
}
if (array_key_exists('height', $attributes)) {
$height = sanitize_text_field($attributes['height']);
}
if (array_key_exists('background-color', $attributes)) {
$bg_color = sanitize_text_field($attributes['background-color']);
}
if (array_key_exists('url', $attributes)) {
$url = sanitize_text_field($attributes['url']);
}
if (array_key_exists('width', $attributes)) {
$width = sanitize_text_field($attributes['width']);
}
if (!$url) {
if (array_key_exists('height', $attributes)) {
$height = sanitize_text_field($attributes['height']);
}
if (array_key_exists('typebot', $attributes)) {
$typebot = sanitize_text_field($attributes['typebot']);
}
if (!$typebot) {
return;
}
$container_id = 'typebot-container-' . $this->generateRandomString(4);
$bot_initializer =
'var typebot = Typebot.initContainer("' .
$container_id .
'",{
hiddenVariables: typebotWpUser,
url: "' .
$url .
'",
})';
$id = $this->generateRandomString();
return '<script>' .
$this->parse_wp_user() .
'</script>' .
'<div
id="' .
$container_id .
'"
style="width: ' .
$width .
'; height: ' .
$height .
'; background-color: ' .
$bg_color .
'"
></div>
<script>
if(document.readyState == "complete"){
' .
$bot_initializer .
'
} else {
window.addEventListener("load",(event) => {
' .
$bot_initializer .
'
})
}
</script>';
$bot_initializer = '<script type="module">
import Typebot from "' . $lib_url . '"
Typebot.initStandard({ id: "' . $id . '", typebot: "' . $typebot . '", prefilledVariables: { typebotWpUser } });</script>';
return '<typebot-standard id="' . $id . '" style="width: ' . $width . '; height: ' . $height . ';"></typebot-standard>' . $bot_initializer;
}
private function generateRandomString($length = 10)

View File

@ -3,7 +3,7 @@
/**
* Plugin Name: Typebot
* Description: Convert more with conversational forms
* Version: 2.1.11
* Version: 3.0.0
* Author: Typebot
* Author URI: http://typebot.io/
* License: GPL-2.0+
@ -16,7 +16,7 @@ if (!defined('WPINC')) {
die();
}
define('TYPEBOT_VERSION', '2.1.11');
define('TYPEBOT_VERSION', '3.0.0');
function activate_typebot()
{