first commit

This commit is contained in:
2026-03-05 13:07:40 +01:00
commit 64ba0721ee
25709 changed files with 4691006 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
.wpdesk-helpscout-beacon-icon-container {
position: fixed;
bottom: 37px;
right: 37px;
outline: none;
}
.rtl .wpdesk-helpscout-beacon-icon-container {
right: initial;
left: 37px;
}

View File

@@ -0,0 +1,112 @@
'use strict';
/**
* Creates a Beacon object with given params.
*
* @param {string} beaconId Id of the beacon from HelpScout.
* @param {string} confirmationMessage Message shown to user to get his confirmation for Beacon initialization.
* @param {string} searchElementsClass Css class of elements which modifies beacon search.
* @constructor
*/
function HsBeacon(beaconId, confirmationMessage, searchElementsClass) {
this.beaconId = beaconId;
this.confirmationMessage = confirmationMessage;
this.searchElementsClass = searchElementsClass;
}
/**
* HelpScout Beacon implementation. Can ask for permission before initialize&show.
*/
HsBeacon.prototype = {
initialized: false,
confirmationMessage: '',
beaconId: '',
searchElementsClass: '',
searchQuery: '',
/**
* Attach ask&show event to given class.
*
* @param {string} buttonClass
*/
attachBeaconEvents: function (buttonClass) {
const self = this;
if (this.confirmationMessage !== '') {
jQuery('.' + buttonClass).click(function () {
jQuery(this).blur();
if (self.showBeaconIfConfirmed()) {
jQuery(this).fadeOut("slow");
}
});
} else {
this.ensureBeaconInitialization();
}
if (this.searchElementsClass !== '') {
this.attachSearchListener();
}
},
/**
* Listen on focus events to modify search query on beacon.
*/
attachSearchListener: function () {
let beacon = this;
jQuery(document).on('focus','.' + this.searchElementsClass,function(){
if (jQuery(this).attr('data-beacon_search') !== undefined) {
beacon.searchQuery = jQuery(this).attr('data-beacon_search');
if (window.Beacon !== undefined) {
window.Beacon('search', beacon.searchQuery);
}
}
});
},
/**
* Show confirmation dialog and then show Beacon if user confirmed. Must be initialized first.
*
* @returns {boolean}
*/
showBeaconIfConfirmed: function () {
let wantBeaconRun = confirm(this.confirmationMessage);
if (wantBeaconRun) {
this.ensureBeaconInitialization();
this.beaconShow();
}
return wantBeaconRun;
},
/**
* Initilize Beacon libs.
*/
ensureBeaconInitialization: function () {
if (!this.initialized) {
this.initialized = true;
!function (e, t, n) {
function a() {
var e = t.getElementsByTagName("script")[0], n = t.createElement("script");
n.type = "text/javascript", n.async = !0, n.src = "https://beacon-v2.helpscout.net", e.parentNode.insertBefore(n, e)
}
if (e.Beacon = n = function (t, n, a) {
e.Beacon.readyQueue.push({method: t, options: n, data: a})
}, n.readyQueue = [], "complete" === t.readyState) return a();
e.attachEvent ? e.attachEvent("onload", a) : e.addEventListener("load", a, !1)
}(window, document, window.Beacon || function () {
});
window.Beacon('init', this.beaconId);
}
},
/**
* Show Beacon. Must be initialized first.
*/
beaconShow: function () {
window.Beacon('open');
if (this.searchQuery !== '') {
window.Beacon('search', this.searchQuery);
}
}
};

View File

@@ -0,0 +1,50 @@
{
"name": "wpdesk\/wp-helpscout-beacon",
"authors": [
{
"name": "Krzysiek",
"email": "krzysiek@wpdesk.pl"
}
],
"license": "MIT",
"require": {
"php": ">=5.6",
"psr\/container": "^1.0"
},
"require-dev": {
"phpunit\/phpunit": "^5",
"wp-coding-standards\/wpcs": "^0.14.1",
"squizlabs\/php_codesniffer": "^3.0.2",
"wimg\/php-compatibility": "^8",
"wpdesk\/wp-wpdesk-composer": "^2.6",
"mockery\/mockery": "*",
"10up\/wp_mock": "*"
},
"autoload": {
"psr-4": {
"FSVendor\\WPDesk\\Beacon\\": "src\/"
}
},
"autoload-dev": {
"psr-4": {
"FSVendor\\WPDesk\\Beacon\\Tests\\Integration\\": "tests\/integration\/"
}
},
"scripts": {
"phpunit-unit": "phpunit --configuration phpunit-unit.xml --coverage-text --colors=never",
"phpunit-unit-fast": "phpunit --configuration phpunit-unit.xml --no-coverage",
"phpunit-integration": "phpunit --configuration phpunit-integration.xml --coverage-text --colors=never",
"phpunit-integration-fast": "phpunit --configuration phpunit-integration.xml --no-coverage"
},
"extra": {
"text-domain": "wp-helpscout-beacon",
"translations-folder": "lang",
"po-files": {
"pl_PL": "pl_PL.po",
"en_AU": "en_AU.po",
"en_CA": "en_CA.po",
"en_GB": "en_GB.po",
"de_DE": "de_DE.po"
}
}
}

View File

@@ -0,0 +1,99 @@
<?php
namespace FSVendor\WPDesk\Beacon;
/**
* Can display HelpScout Beacon. For more info check https://secure.helpscout.net/settings/beacons/
*/
class Beacon
{
/**
* Beacon UUID from HelpScout.
*
* @var string
*/
private $beacon_id;
/**
* When to display beacon.
*
* @var BeaconShouldShowStrategy
*/
private $activation_strategy;
/**
* @var string
*/
private $assets_url;
/**
* @var string
*/
private $beacon_search_elements_class;
/**
* @var string
*/
protected $confirmation_message;
/**
* @var string
*/
private $beacon_image_content;
/**
* Beacon constructor.
*
* @param string $beacon_id .
* @param BeaconShouldShowStrategy $strategy When to display beacon.
* @param string $assets_url With ending /
*/
public function __construct($beacon_id, \FSVendor\WPDesk\Beacon\BeaconShouldShowStrategy $strategy, $assets_url, $beacon_search_elements_class = 'hs-beacon-search', $beacon_image_content = '')
{
$this->beacon_id = $beacon_id;
$this->activation_strategy = $strategy;
$this->assets_url = $assets_url;
$this->beacon_search_elements_class = $beacon_search_elements_class;
$this->confirmation_message = \__('When you click OK we will open our HelpScout beacon where you can find answers to your questions. This beacon will load our help articles and also potentially set cookies.', 'flexible-shipping');
$this->beacon_image_content = $beacon_image_content;
}
/**
* @return string
*/
public function get_beacon_id()
{
return $this->beacon_id;
}
/**
* Hooks.
*/
public function hooks()
{
\add_action('admin_footer', [$this, 'add_beacon_to_footer']);
\add_action('admin_enqueue_scripts', [$this, 'add_beacon_js']);
}
/**
* Should display beacon?
*
* @return bool
*/
protected function should_display_beacon()
{
return \apply_filters('helpscout-beacon/should-display-beacon', $this->activation_strategy->shouldDisplay());
}
public function add_beacon_js()
{
if ($this->should_display_beacon()) {
\wp_enqueue_style('hs-beacon', $this->assets_url . 'css/beacon.css', []);
\wp_enqueue_script('hs-beacon', $this->assets_url . 'js/hs-bc.js', []);
}
}
/**
* Display Beacon script.
*/
public function add_beacon_to_footer()
{
if ($this->should_display_beacon()) {
$beacon_id = $this->beacon_id;
$confirmation_message = \__('When you click OK we will open our HelpScout beacon where you can find answers to your questions. This beacon will load our help articles and also potentially set cookies.', 'flexible-shipping');
$beacon_search_elements_class = $this->beacon_search_elements_class;
$confirmation_message = $this->confirmation_message;
$beacon_image_content = $this->beacon_image_content;
include __DIR__ . '/templates/html-beacon-script.php';
}
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace FSVendor\WPDesk\Beacon;
/**
* When and if show Beacon.
*/
class BeaconGetShouldShowStrategy implements \FSVendor\WPDesk\Beacon\BeaconShouldShowStrategy
{
/**
* Whether to show beacon on the page or not. Array of arrays with condition for _GET.
* Inner arrays mean AND, outer arrays mean OR conditions.
*
* ie. [ [ .. and .. and ..] or [ .. and .. and ..] or .. ]
*
* @var array
*/
private $conditions;
public function __construct(array $conditions)
{
$this->conditions = $conditions;
}
/**
* Should Beacon be visible?
*
* @return bool
*/
public function shouldDisplay()
{
foreach ($this->conditions as $or_conditions) {
$display = \true;
foreach ($or_conditions as $parameter => $value) {
if (!isset($_GET[$parameter]) || $_GET[$parameter] !== $value) {
$display = \false;
}
}
if ($display) {
return $display;
}
}
return \false;
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace FSVendor\WPDesk\Beacon;
/**
* Can display HelpScout Beacon without confirmation. For more info check https://secure.helpscout.net/settings/beacons/
*/
class BeaconPro extends \FSVendor\WPDesk\Beacon\Beacon
{
/**
* Beacon constructor.
*
* @param string $beacon_id .
* @param BeaconShouldShowStrategy $strategy When to display beacon.
* @param string $assets_url With ending /
*/
public function __construct($beacon_id, \FSVendor\WPDesk\Beacon\BeaconShouldShowStrategy $strategy, $assets_url, $beacon_search_elements_class = 'hs-beacon-search')
{
parent::__construct($beacon_id, $strategy, $assets_url, $beacon_search_elements_class);
$this->confirmation_message = '';
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace FSVendor\WPDesk\Beacon;
/**
* When to show Beacon.
*/
interface BeaconShouldShowStrategy
{
/**
* Should Beacon be visible?
*
* @return bool
*/
public function shouldDisplay();
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* WooCommerce settings fields modifier.
*
* @package WPDesk\Beacon\Beacon
*/
namespace FSVendor\WPDesk\Beacon\Beacon;
/**
* Can modify WooCommerce settings fields.
* Use it on WooCommerce settings fields for Beacon search functionality.
*/
class WooCommerceSettingsFieldsModifier
{
const FIELD_CLASS = 'class';
const FIELD_CUSTOM_ATTRIBUTES = 'custom_attributes';
const FIELD_TITLE = 'title';
const CLASS_HS_BEACON_SEARCH = 'hs-beacon-search';
const DATA_BEACON_SEARCH = 'data-beacon_search';
/**
* Appends beacon search data to fields.
* It takes field title and set it as beacon search.
*
* @param array $form_fields .
*
* @return array
*/
public function append_beacon_search_data_to_fields(array $form_fields)
{
foreach ($form_fields as $field_name => $field) {
if (isset($field[self::FIELD_TITLE])) {
if (empty($field[self::FIELD_CLASS])) {
$field[self::FIELD_CLASS] = self::CLASS_HS_BEACON_SEARCH;
} else {
$field[self::FIELD_CLASS] .= ' ' . self::CLASS_HS_BEACON_SEARCH;
}
if (!isset($field[self::FIELD_CUSTOM_ATTRIBUTES])) {
$field[self::FIELD_CUSTOM_ATTRIBUTES] = array();
}
$field[self::FIELD_CUSTOM_ATTRIBUTES][self::DATA_BEACON_SEARCH] = $field[self::FIELD_TITLE];
}
$form_fields[$field_name] = $field;
}
return $form_fields;
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace FSVendor;
/**
* Displays Beacon script.
*
* @var $beacon_id string .
* @var $confirmation_message string .
* @var $beacon_search_elements_class string .
* @var $beacon_image_content string .
*/
$beacon_button_class = 'wpdesk-helpscout-beacon-button';
$beacon_image_content = !empty($beacon_image_content) ? $beacon_image_content : 'data:image/png;base64,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';
if ('' !== $confirmation_message) {
?><div id="wpdesk-helpscout-beacon">
<div class="wpdesk-helpscout-beacon-frame">
<div class="wpdesk-helpscout-beacon-icon-container">
<img class="<?php
echo \esc_attr($beacon_button_class);
?>" id="image0" src="<?php
echo \esc_attr($beacon_image_content);
?>" />
</div>
</div>
</div><?php
}
?>
<script type="text/javascript">
jQuery(document).ready(function () {
(new HsBeacon(
'<?php
echo \esc_attr($beacon_id);
?>',
'<?php
echo \esc_attr($confirmation_message);
?>',
'<?php
echo \esc_attr($beacon_search_elements_class);
?>'
)).attachBeaconEvents('<?php
echo \esc_attr($beacon_button_class);
?>');
});
</script>
<?php