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,54 @@
{
"name": "wpdesk\/wp-wpdesk-tracker-user-feedback",
"authors": [
{
"name": "Krzysiek",
"email": "krzysiek@wpdesk.pl"
},
{
"name": "Grzegorz",
"email": "grzegorz@wpdesk.pl"
}
],
"prefer-stable": true,
"minimum-stability": "dev",
"require": {
"php": ">=5.6"
},
"require-dev": {
"phpunit\/phpunit": "<7",
"wp-coding-standards\/wpcs": "^0.14.1",
"squizlabs\/php_codesniffer": "^3.0.2",
"mockery\/mockery": "*",
"10up\/wp_mock": "*",
"wimg\/php-compatibility": "^8",
"wpdesk\/wp-wpdesk-tracker": "^2.0",
"wpdesk\/wp-builder": "^1.4"
},
"autoload": {
"psr-4": {
"FSVendor\\WPDesk\\Tracker\\UserFeedback\\": "src\/WPDesk\/Tracker\/UserFeedback\/"
}
},
"autoload-dev": {
"classmap": [
"tests\/"
]
},
"extra": {
"text-domain": "wp-wpdesk-tracker-user-feedback",
"translations-folder": "lang",
"po-files": {
"pl_PL": "pl_PL.po"
}
},
"scripts": {
"test": "echo composer is alive",
"phpcs": "phpcs",
"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",
"docs": "apigen generate"
}
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* Null sender.
*
* @package WPDesk\Tracker\Sender
*/
namespace FSVendor\WPDesk\Tracker\Sender;
/**
* Can send data to nowhere.
*/
class NullSender implements \WPDesk_Tracker_Sender
{
/**
* Does nothing.
*
* @param array $payload .
*
* @return array|void
*/
public function send_payload(array $payload)
{
// Do nothing
}
}

View File

@@ -0,0 +1,75 @@
<?php
namespace FSVendor\WPDesk\Tracker\UserFeedback;
use FSVendor\WPDesk\PluginBuilder\Plugin\Hookable;
/**
* Can handle ajax request with user feedback data and sends data to WP Desk.
*/
class AjaxUserFeedbackDataHandler implements \FSVendor\WPDesk\PluginBuilder\Plugin\Hookable
{
const AJAX_ACTION = 'wpdesk_tracker_user_feedback_handler_';
const REQUEST_ADDITIONAL_INFO = 'additional_info';
const REQUEST_SELECTED_OPTION = 'selected_option';
const FEEDBACK_ID = 'feedback_id';
/**
* @var UserFeedbackData
*/
protected $user_feedback_data;
/**
* @var \WPDesk_Tracker_Sender
*/
private $sender;
/**
* @param UserFeedbackData $user_feedback_data .
* @param \WPDesk_Tracker_Sender $sender
*/
public function __construct(\FSVendor\WPDesk\Tracker\UserFeedback\UserFeedbackData $user_feedback_data, $sender)
{
$this->user_feedback_data = $user_feedback_data;
$this->sender = $sender;
}
/**
* Hooks.
*/
public function hooks()
{
\add_action('wp_ajax_' . self::AJAX_ACTION . $this->user_feedback_data->get_thickbox_id(), array($this, 'handle_ajax_request'));
}
/**
* Prepare payload.
*
* @param array $request .
*
* @return array
*/
private function prepare_payload(array $request)
{
$payload = array('click_action' => 'user_feedback', self::FEEDBACK_ID => $this->user_feedback_data->get_thickbox_id(), 'selected_option' => $request[self::REQUEST_SELECTED_OPTION]);
if (!empty($request[self::REQUEST_ADDITIONAL_INFO])) {
$payload['additional_info'] = $request[self::REQUEST_ADDITIONAL_INFO];
}
return \apply_filters('wpdesk_tracker_user_feedback_data', $payload);
}
/**
* Send payload to WP Desk.
*
* @param array $payload
*/
private function send_payload_to_wpdesk(array $payload)
{
$this->sender->send_payload($payload);
}
/**
* Handle AJAX request.
*/
public function handle_ajax_request()
{
\check_ajax_referer(self::AJAX_ACTION . $this->user_feedback_data->get_thickbox_id());
if (isset($_REQUEST[self::REQUEST_SELECTED_OPTION])) {
$payload = $this->prepare_payload($_REQUEST);
$this->send_payload_to_wpdesk($this->prepare_payload($_REQUEST));
\do_action('wpdesk_tracker_user_feedback_data_handled', $payload);
}
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace FSVendor\WPDesk\Tracker\UserFeedback;
/**
* Can generate user feedback scripts.
*/
class Scripts
{
use UserFeedbackContent;
/**
* Constructor.
*
* @param UserFeedbackData $user_feedback_data .
* @param string|null $view_file If null given default scrips file is used.
*/
public function __construct(\FSVendor\WPDesk\Tracker\UserFeedback\UserFeedbackData $user_feedback_data, $view_file = null)
{
$this->user_feedback_data = $user_feedback_data;
if (!empty($view_file)) {
$this->view_file = $view_file;
} else {
$this->view_file = __DIR__ . '/views/scripts.php';
}
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace FSVendor\WPDesk\Tracker\UserFeedback;
/**
* Can generate user feedback thickbox content.
*/
class Thickbox
{
use UserFeedbackContent;
/**
* Constructor.
*
* @param UserFeedbackData $user_feedback_data .
* @param string|null $view_file If null given default thickbox file is used.
*/
public function __construct(\FSVendor\WPDesk\Tracker\UserFeedback\UserFeedbackData $user_feedback_data, $view_file = null)
{
$thickbox_id = $user_feedback_data->get_thickbox_id();
$this->user_feedback_data = $user_feedback_data;
if (!empty($view_file)) {
$this->view_file = $view_file;
} else {
$this->view_file = __DIR__ . '/views/thickbox.php';
}
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace FSVendor\WPDesk\Tracker\UserFeedback;
use FSVendor\WPDesk\PluginBuilder\Plugin\Hookable;
/**
* Can track user feedback.
*/
class Tracker implements \FSVendor\WPDesk\PluginBuilder\Plugin\Hookable
{
/**
* @var UserFeedbackData
*/
private $user_feedback_data;
/**
* @var Scripts
*/
private $scripts;
/**
* @var Thickbox
*/
private $thickbox;
/**
* @var AjaxUserFeedbackDataHandler
*/
private $ajax;
/**
* Tracker constructor.
*
* @param UserFeedbackData $user_feedback_data .
* @param Scripts $scripts .
* @param Thickbox $thickbox .
* @param AjaxUserFeedbackDataHandler $ajax
*/
public function __construct(\FSVendor\WPDesk\Tracker\UserFeedback\UserFeedbackData $user_feedback_data, \FSVendor\WPDesk\Tracker\UserFeedback\Scripts $scripts, \FSVendor\WPDesk\Tracker\UserFeedback\Thickbox $thickbox, \FSVendor\WPDesk\Tracker\UserFeedback\AjaxUserFeedbackDataHandler $ajax)
{
$this->user_feedback_data = $user_feedback_data;
$this->scripts = $scripts;
$this->thickbox = $thickbox;
$this->ajax = $ajax;
}
/**
* Hooks.
*/
public function hooks()
{
\add_action('admin_print_footer_scripts-' . $this->user_feedback_data->get_hook_suffix(), [$this, 'print_user_feedback_scripts']);
\add_action('admin_footer-' . $this->user_feedback_data->get_hook_suffix(), [$this, 'print_user_feedback_thickbox']);
\add_action('admin_enqueue_scripts', [$this, 'enqueue_thickbox']);
$this->ajax->hooks();
}
/**
* Enqueue thickbox script and styles.
*/
public function enqueue_thickbox()
{
\wp_enqueue_script('thickbox');
\wp_enqueue_style('thickbox');
}
/**
* Print user feedback scripts.
*/
public function print_user_feedback_scripts()
{
echo $this->scripts->get_content();
}
/**
* Print user feedback thickbox.
*/
public function print_user_feedback_thickbox()
{
echo $this->thickbox->get_content();
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace FSVendor\WPDesk\Tracker\UserFeedback;
use FSVendor\WPDesk\Tracker\Sender\NullSender;
/**
* Can create tracker.
*/
class TrackerFactory
{
/**
* Create custom tracker.
*
* @param PluginData $user_feedback_data .
* @param Scripts|null $scripts If null given default scrips file is used.
* @param Thickbox|null $thickbox If null given default thickbox file is used.
* @param AjaxUserFeedbackDataHandler|null $ajax
*
* @return Tracker
*/
public static function create_custom_tracker(\FSVendor\WPDesk\Tracker\UserFeedback\UserFeedbackData $user_feedback_data, $scripts = null, $thickbox = null, $ajax = null)
{
if (empty($scripts)) {
$scripts = new \FSVendor\WPDesk\Tracker\UserFeedback\Scripts($user_feedback_data);
}
if (empty($thickbox)) {
$thickbox = new \FSVendor\WPDesk\Tracker\UserFeedback\Thickbox($user_feedback_data);
}
if (empty($ajax)) {
$sender = new \FSVendor\WPDesk_Tracker_Sender_Wordpress_To_WPDesk();
$sender = new \FSVendor\WPDesk_Tracker_Sender_Logged($sender);
$ajax = new \FSVendor\WPDesk\Tracker\UserFeedback\AjaxUserFeedbackDataHandler($user_feedback_data, $sender);
}
return new \FSVendor\WPDesk\Tracker\UserFeedback\Tracker($user_feedback_data, $scripts, $thickbox, $ajax);
}
/**
* Create custom tracker without sender.
* Created tracker do not sends payload data to server.
*
* @param PluginData $user_feedback_data .
* @param Scripts|null $scripts .
* @param Thickbox|null $thickbox .
* @param AjaxUserFeedbackDataHandler|null $ajax
*
* @return Tracker
*/
public static function create_custom_tracker_with_null_sender(\FSVendor\WPDesk\Tracker\UserFeedback\UserFeedbackData $user_feedback_data, $scripts = null, $thickbox = null, $ajax = null)
{
if (empty($scripts)) {
$scripts = new \FSVendor\WPDesk\Tracker\UserFeedback\Scripts($user_feedback_data);
}
if (empty($thickbox)) {
$thickbox = new \FSVendor\WPDesk\Tracker\UserFeedback\Thickbox($user_feedback_data);
}
if (empty($ajax)) {
$ajax = new \FSVendor\WPDesk\Tracker\UserFeedback\AjaxUserFeedbackDataHandler($user_feedback_data, new \FSVendor\WPDesk\Tracker\Sender\NullSender());
}
return new \FSVendor\WPDesk\Tracker\UserFeedback\Tracker($user_feedback_data, $scripts, $thickbox, $ajax);
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace FSVendor\WPDesk\Tracker\UserFeedback;
/**
* Can generate content.
*/
trait UserFeedbackContent
{
/**
* @var UserFeedbackData
*/
private $user_feedback_data;
/**
* @var string
*/
private $view_file = __DIR__ . '/views/abstract.php';
/**
* Returns HTML content.
*
* @return string
*/
public function get_content()
{
$thickbox_id = $this->user_feedback_data->get_thickbox_id();
$thickbox_title = $this->user_feedback_data->get_thickbox_title();
$thickbox_heading = $this->user_feedback_data->get_heading();
$thickbox_question = $this->user_feedback_data->get_question();
$thickbox_feedback_options = $this->user_feedback_data->get_feedback_options();
$thickbox_all_options = \count($thickbox_feedback_options);
$button_send_text = \__('Proceed', 'flexible-shipping');
$ajax_action = \FSVendor\WPDesk\Tracker\UserFeedback\AjaxUserFeedbackDataHandler::AJAX_ACTION . $thickbox_id;
$ajax_nonce = \wp_create_nonce($ajax_action);
\ob_start();
include $this->view_file;
return \ob_get_clean();
}
}

View File

@@ -0,0 +1,100 @@
<?php
namespace FSVendor\WPDesk\Tracker\UserFeedback;
class UserFeedbackData
{
/**
* @var UserFeedbackOption[]
*/
private $feedback_options = array();
/**
* @var string
*/
private $thickbox_id;
/**
* @var string
*/
private $thickbox_title;
/**
* @var string
*/
private $heading;
/**
* @var string
*/
private $question;
/**
* @var string
*/
private $hook_suffix;
/**
* UserFeedbackData constructor.
*
* @param string $thickbox_id
* @param string $thickbox_title
* @param string $heading
* @param string $question
* @param string $hook_suffix
*/
public function __construct($thickbox_id, $thickbox_title, $heading, $question, $hook_suffix)
{
$this->thickbox_id = $thickbox_id;
$this->thickbox_title = $thickbox_title;
$this->heading = $heading;
$this->question = $question;
$this->hook_suffix = $hook_suffix;
}
/**
* @param UserFeedbackOption $feedback_option
*
* @return UserFeedbackData
*/
public function add_feedback_option(\FSVendor\WPDesk\Tracker\UserFeedback\UserFeedbackOption $feedback_option)
{
$this->feedback_options[] = $feedback_option;
return $this;
}
/**
* @return UserFeedbackOption[]
*/
public function get_feedback_options()
{
return $this->feedback_options;
}
/**
* @return string
*/
public function get_thickbox_id()
{
return $this->thickbox_id;
}
/**
* @return string
*/
public function get_thickbox_title()
{
return $this->thickbox_title;
}
/**
* @return string
*/
public function get_heading()
{
return $this->heading;
}
/**
* @return string
*/
public function get_question()
{
return $this->question;
}
/**
* @return string
*/
public function get_hook_suffix()
{
return $this->hook_suffix;
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace FSVendor\WPDesk\Tracker\UserFeedback;
class UserFeedbackOption
{
/**
* @var string
*/
private $option_name;
/**
* @var string
*/
private $option_text;
/**
* @var bool
*/
private $has_additional_info;
/**
* @var string
*/
private $additional_info_placeholder;
/**
* UserFeedbackOption constructor.
*
* @param string $option_name
* @param string $option_text
* @param bool $has_additional_info
* @param string $additional_info_placeholder
*/
public function __construct($option_name, $option_text, $has_additional_info = \false, $additional_info_placeholder = '')
{
$this->option_name = $option_name;
$this->option_text = $option_text;
$this->has_additional_info = $has_additional_info;
$this->additional_info_placeholder = $additional_info_placeholder;
}
/**
* @return string
*/
public function get_option_name()
{
return $this->option_name;
}
/**
* @return string
*/
public function get_option_text()
{
return $this->option_text;
}
/**
* @return bool
*/
public function has_additional_info()
{
return $this->has_additional_info;
}
/**
* @return string
*/
public function get_additional_info_placeholder()
{
return $this->additional_info_placeholder;
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace FSVendor;
/**
* @var $plugin_title string
* @var $plugin_file string
* @var $plugin_slug string
* @var $thickbox_id string
* @var $ajax_action string
* @var $ajax_nonce string
*/
if (!\defined('ABSPATH')) {
exit;
}
?><!-- AbstractContent --><?php

View File

@@ -0,0 +1,161 @@
<?php
namespace FSVendor;
/**
* @var $thickbox_id string
* @var $thickbox_title string
* @var $ajax_action string
* @var $ajax_nonce string
* @var $button_send_text string
* @var $thickbox_all_options int
*/
if (!\defined('ABSPATH')) {
exit;
}
?><script type="text/javascript">
jQuery(document).ready(function(){
function resize_user_feedback_tb_window() {
let margin_horizontal = 30;
let $TB_ajaxContent = jQuery('#TB_ajaxContent');
let $TB_window = jQuery(document).find('#TB_window');
let width = $TB_ajaxContent.width();
let height = jQuery('#TB_title').outerHeight(true) + 20;
$TB_ajaxContent.children().each(function(){
height += jQuery(this).outerHeight(true);
});
$TB_ajaxContent.height( height );
$TB_window.width( width + margin_horizontal ).height( $TB_ajaxContent.outerHeight(true) ).css( 'margin-left', - ( width + margin_horizontal ) / 2 );
}
jQuery(document).bind('<?php
echo \esc_attr($thickbox_id);
?>', function(e){
let tb_id = '#TB_inline?inlineId=<?php
echo $thickbox_id;
?>';
tb_show('<?php
echo \esc_html($thickbox_title);
?>', tb_id);
resize_user_feedback_tb_window();
});
jQuery(document).on( 'click', '.<?php
echo $thickbox_id;
?> .tracker-button-close', function(e) {
e.preventDefault();
tb_remove();
});
jQuery(document).on( 'click', '.<?php
echo $thickbox_id;
?> .skip-proceed', function(e) {
e.preventDefault();
tb_remove();
jQuery(document).trigger('<?php
echo $thickbox_id;
?>_proceed');
});
jQuery(document).on( 'click', '.<?php
echo $thickbox_id;
?> .allow-proceed', function(e) {
e.preventDefault();
let selected_option = jQuery('.<?php
echo $thickbox_id;
?> input[name=selected_option]:checked').val();
let additional_info = jQuery('.<?php
echo $thickbox_id;
?> input[name=selected_option]:checked').closest('li').find('.additional-info').val();
if ( typeof selected_option !== 'undefined' ) {
jQuery('.button').attr('disabled',true);
jQuery.ajax( '<?php
echo \admin_url('admin-ajax.php');
?>',
{
type: 'POST',
data: {
'action': '<?php
echo $ajax_action;
?>',
'_ajax_nonce': '<?php
echo $ajax_nonce;
?>',
'selected_option': selected_option,
'additional_info': additional_info,
}
}
).always(function() {
jQuery(document).trigger('<?php
echo $thickbox_id;
?>_proceed');
});
}
else {
jQuery(document).trigger('<?php
echo $thickbox_id;
?>_proceed');
}
});
jQuery(document).on( 'click', '.<?php
echo $thickbox_id;
?> input[type=radio]', function(){
var tracker_user_feedback = jQuery(this).closest('.<?php
echo $thickbox_id;
?>');
tracker_user_feedback.find('input[type=radio]').each(function(){
if ( jQuery(this).data("show") ) {
var show_element = tracker_user_feedback.find( '.' + jQuery(this).data('show') );
if ( jQuery(this).is(':checked') ) {
show_element.show();
} else {
show_element.hide();
}
}
});
resize_user_feedback_tb_window();
jQuery('.<?php
echo $thickbox_id;
?> .skip-proceed').addClass('allow-proceed').removeClass('skip-proceed').html( '<?php
echo \esc_html($button_send_text);
?>' );
});
jQuery(window).on('load', function() {
jQuery(window).resize(function(){
resize_user_feedback_tb_window();
});
});
});
</script>
<style>
#TB_ajaxContent {
overflow: hidden;
}
.<?php
echo $thickbox_id;
?> input[type=text] {
margin-left: 25px;
width: 90%;
}
.<?php
echo $thickbox_id;
?> textarea {
margin-left: 25px;
width: 90%;
height: 86px;
resize: none;
}
.<?php
echo $thickbox_id;
?> textarea.no_question {
margin-left: 0px;
width: 90%;
}
</style>
<?php

View File

@@ -0,0 +1,107 @@
<?php
namespace FSVendor;
/**
* @var $thickbox_id string
* @var $thickbox_title string
* @var $thickbox_heading string
* @var $thickbox_question string
* @var $thickbox_feedback_options \WPDesk\Tracker\UserFeedback\UserFeedbackOption[]
* @var $ajax_action string
* @var $ajax_nonce string
* @var $thickbox_all_options int
*/
if (!\defined('ABSPATH')) {
exit;
}
?><div id="<?php
echo $thickbox_id;
?>" style="display:none;">
<?php
if ($thickbox_heading) {
?>
<h4><?php
echo \esc_html($thickbox_heading);
?></h4>
<?php
}
?>
<div class="wpdesk_tracker_user_feedback <?php
echo $thickbox_id;
?>">
<div class="body">
<div class="panel active" data-panel-id="options">
<h2><strong><?php
echo \esc_html($thickbox_question);
?></strong></h2>
<ul class="reasons-list">
<?php
foreach ($thickbox_feedback_options as $feedback_option) {
?>
<li class="reason <?php
echo \esc_attr($feedback_option->has_additional_info() ? 'has-input' : '');
?>">
<label style="<?php
echo \esc_attr($feedback_option->get_option_text() === '' ? 'display: none' : '');
?>">
<span>
<input
type="radio"
name="selected_option"
value="<?php
echo \esc_attr($feedback_option->get_option_name());
?>"
data-show="<?php
echo \esc_attr($feedback_option->get_option_name());
?>"
<?php
echo \esc_attr(1 === $thickbox_all_options ? 'checked' : '');
?>
/>
</span>
<span><?php
echo \esc_html($feedback_option->get_option_text());
?></span>
</label>
<?php
if ($feedback_option->has_additional_info()) {
?>
<div class="<?php
echo \esc_attr($feedback_option->get_option_name());
?>" class="option-input" style="<?php
echo \esc_attr(1 !== $thickbox_all_options ? 'display: none' : '');
?>">
<textarea
class="additional-info <?php
echo \esc_attr($feedback_option->get_option_text() === '' ? 'no_question' : '');
?>"
name="<?php
echo \esc_attr($feedback_option->get_option_name());
?>_input"
placeholder="<?php
echo \esc_attr($feedback_option->get_additional_info_placeholder());
?>"></textarea>
</div>
<?php
}
?>
</li>
<?php
}
?>
</ul>
</div>
</div>
<div class="footer">
<a href="#" class="button button-secondary button-close tracker-button-close"><?php
\_e('Cancel', 'flexible-shipping');
?></a>
<a href="#" class="button button-primary <?php
echo \esc_attr(1 === $thickbox_all_options ? 'allow-proceed' : 'skip-proceed');
?>"><?php
echo \esc_html(1 === $thickbox_all_options ? $button_send_text : \__('Skip', 'flexible-shipping'));
?></a>
</div>
</div>
</div><?php