File: /storage/v4513/tepnot/public_html/wp-content/plugins/dokan-pro/modules/store-support/module.php
<?php
namespace WeDevs\DokanPro\Modules\StoreSupport;
use WC_Emails;
use WeDevs\Dokan\Cache;
use WeDevs\DokanPro\Modules\StoreSupport\SettingsApi\Store;
use WP_Query;
class Module {
private $post_type = 'dokan_store_support';
private $per_page = 15;
/**
* @var int
*/
private $total_query_result;
/**
* Constructor for the Dokan_Store_Support class
*
* Sets up all the appropriate hooks and actions
* within our plugin.
*
* @uses register_activation_hook()
* @uses register_deactivation_hook()
* @uses is_admin()
* @uses add_action()
*/
public function __construct() {
define( 'DOKAN_STORE_SUPPORT_PLUGIN_VERSION', '1.3.6' );
define( 'DOKAN_STORE_SUPPORT_DIR', __DIR__ );
define( 'DOKAN_STORE_SUPPORT_INC_DIR', DOKAN_STORE_SUPPORT_DIR . '/includes' );
define( 'DOKAN_STORE_SUPPORT_PLUGIN_ASSEST', plugins_url( 'assets', __FILE__ ) );
add_filter( 'dokan_get_all_cap', [ $this, 'add_capabilities' ], 10 );
add_filter( 'dokan_get_all_cap', [ $this, 'add_capabilities' ] );
add_filter( 'dokan_get_all_cap_labels', [ $this, 'add_caps_labels' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
add_action( 'init', [ $this, 'register_scripts' ] );
$this->init_hooks();
// Init Cache
require_once DOKAN_STORE_SUPPORT_INC_DIR . '/DokanStoreSupportCache.php';
new \DokanStoreSupportCache();
require_once DOKAN_STORE_SUPPORT_DIR . '/support-widget.php';
add_action( 'dokan_activated_module_store_support', [ $this, 'activate' ] );
$this->instances();
}
/**
* Initialize all hooks and filters
*
* @since 1.0.0
*
* @return void
*/
public function init_hooks() {
add_action( 'init', [ $this, 'register_dokan_store_support' ], 50 );
add_action( 'init', [ $this, 'register_dokan_support_topic_status' ], 50 );
add_action( 'init', [ $this, 'register_dokan_support_meta_fields' ], 50 );
add_action( 'template_redirect', [ $this, 'change_topic_status' ] );
add_filter( 'dokan_settings_sections', array( $this, 'render_store_support_section' ) );
add_filter( 'dokan_settings_fields', array( $this, 'render_store_support_settings' ) );
add_action( 'dokan_after_store_tabs', [ $this, 'generate_support_button' ] );
add_action( 'woocommerce_after_add_to_cart_button', [ $this, 'generate_support_button_product_page' ] );
add_action( 'dokan_product_seller_tab_end', [ $this, 'generate_support_button_product_page_inner_tab' ], 10, 2 );
add_action( 'wp_ajax_dokan_support_ajax_handler', [ $this, 'ajax_handler' ] );
add_action( 'wp_ajax_nopriv_dokan_support_ajax_handler', [ $this, 'ajax_handler' ] );
add_action( 'wp_ajax_dokan_search_support_customers', [ $this, 'dokan_ajax_search_support_customers' ] );
add_filter( 'dokan_query_var_filter', [ $this, 'register_support_queryvar' ], 20 );
add_filter( 'dokan_get_dashboard_nav', [ $this, 'add_store_support_page' ], 20 );
add_filter( 'dokan_set_template_path', [ $this, 'load_store_support_templates' ], 11, 3 );
add_action( 'dokan_load_custom_template', [ $this, 'load_template_from_plugin' ], 20 );
add_filter( 'comment_post_redirect', [ $this, 'redirect_after_comment' ], 15, 2 );
add_filter( 'edit_comment_link', [ $this, 'remove_comment_edit_link' ], 15, 3 );
add_action( 'wp_insert_comment', [ $this, 'change_topic_status_on_comment' ], 13, 2 );
add_action( 'woocommerce_account_menu_items', [ $this, 'place_support_menu' ] );
add_action( 'dokan_settings_form_bottom', [ $this, 'add_support_btn_title_input' ], 13, 2 );
add_action( 'dokan_store_profile_saved', [ $this, 'save_supoort_btn_title' ], 13 );
add_filter( 'dokan_widgets', [ $this, 'register_widgets' ] );
add_action( 'init', [ $this, 'register_support_tickets_endpoint' ] );
add_action( 'woocommerce_account_support-tickets_endpoint', [ $this, 'support_tickets_content' ] );
add_action( 'woocommerce_order_details_after_order_table', [ $this, 'generate_support_button_customer_order_page' ], 11 );
// flush rewrite rules
add_action( 'woocommerce_flush_rewrite_rules', [ $this, 'flush_rewrite_rules' ] );
add_filter( 'dokan_email_classes', [ $this, 'load_support_ticket_emails' ] );
add_filter( 'dokan_email_list', [ $this, 'set_email_template_directory' ] );
add_filter( 'woocommerce_email_actions', [ $this, 'register_email_actions' ] );
add_filter( 'dokan_rest_api_class_map', [ $this, 'rest_api_class_map' ] );
add_filter( 'dokan_rest_admin_dashboard_todo_data', [ $this, 'load_todo_support_tickets_count' ] );
add_filter( 'dokan_rest_admin_dashboard_monthly_overview_data', [ $this, 'load_monthly_support_tickets_count' ], 10, 2 );
}
/**
* Add store support section in Dokan Settings
*
* @param array $sections
*
* @return array
*@since 3.2.0
*/
public function render_store_support_section( $sections ): array {
$sections[] = [
'id' => 'dokan_store_support_setting',
'title' => __( 'Store Support', 'dokan' ),
'icon_url' => plugins_url( 'assets/images/support.svg', __FILE__ ),
'description' => __( 'Store Support Manage', 'dokan' ),
'document_link' => 'https://dokan.co/docs/wordpress/modules/how-to-install-and-use-store-support/',
'settings_title' => __( 'Store Support Settings', 'dokan' ),
'settings_description' => __( 'You can configure how and where store support settings are displayed in your site.', 'dokan' ),
];
return $sections;
}
/**
* Add store support options on Dokan Settings under General section
*
* @since 3.2.0
*
* @param array $settings_fields
*
* @return array
*/
public function render_store_support_settings( $settings_fields ): array {
$settings_fields['dokan_store_support_setting'] = [
'enabled_for_customer_order' => [
'name' => 'enabled_for_customer_order',
'label' => __( 'Display on Order Details', 'dokan' ),
'type' => 'switcher',
'desc' => __( 'Display store support button on the order details page for customer', 'dokan' ),
],
'store_support_product_page' => [
'name' => 'store_support_product_page',
'label' => __( 'Display on Single Product Page', 'dokan' ),
'desc' => __( 'Display store support button on single product page', 'dokan' ),
'type' => 'select',
'default' => 'above_tab',
'tooltip' => __( 'Select where to display Store Support button on Single Product page.', 'dokan' ),
'options' => [
'above_tab' => __( 'Above Product Tab', 'dokan' ),
'inside_tab' => __( 'Inside Vendor Info Product Tab', 'dokan' ),
'dont_show' => __( 'Don\'t Show', 'dokan' ),
],
],
'support_button_label' => [
'name' => 'support_button_label',
'desc' => __( 'Default store support button label', 'dokan' ),
'type' => 'text',
'label' => __( 'Support Button Label', 'dokan' ),
'default' => __( 'Get Support', 'dokan' ),
'tooltip' => __( 'Customize Store Support Button Label.', 'dokan' ),
],
];
return $settings_fields;
}
/**
* Placeholder for activation function
*
* Nothing being called here yet.
*/
public function activate() {
global $wp_roles;
if ( class_exists( 'WP_Roles' ) && ! isset( $wp_roles ) ) {
// phpcs:ignore
$wp_roles = new \WP_Roles();
}
$all_cap = [
'dokan_manage_support_tickets',
];
foreach ( $all_cap as $key => $cap ) {
$wp_roles->add_cap( 'seller', $cap );
$wp_roles->add_cap( 'administrator', $cap );
$wp_roles->add_cap( 'shop_manager', $cap );
}
$support_url = dokan_get_page_url( 'myaccount', 'woocommerce', 'support-tickets/' );
add_option( 'dokan-customer-support', $support_url );
// flush rewrite rules after plugin is activate
$this->flush_rewrite_rules();
}
/**
* Flush rewrite rules
*
* @since 3.3.1
*
* @return void
*/
public function flush_rewrite_rules() {
add_filter( 'dokan_query_var_filter', [ $this, 'register_support_queryvar' ], 20 );
dokan()->rewrite->register_rule();
flush_rewrite_rules( true );
}
/**
* Register Scripts
*
* @since 3.7.4
*/
public function register_scripts() {
list( $suffix, $version ) = dokan_get_script_suffix_and_version();
wp_register_style( 'dokan-store-support-styles', plugins_url( 'assets/css/style.css', __FILE__ ), [], $version );
wp_register_script( 'dokan-store-support-scripts', plugins_url( 'assets/js/script.js', __FILE__ ), [ 'jquery' ], $version, true );
wp_register_script( 'dokan-store-support-filter', plugins_url( 'assets/js/store-support-filter.js', __FILE__ ), [ 'jquery', 'dokan-select2-js', 'moment', 'dokan-date-range-picker', 'wp-i18n', 'dokan-util-helper' ], $version, true );
$asset_file = DOKAN_STORE_SUPPORT_DIR . '/assets/dist/js/vendor-store-support.asset.php';
if ( file_exists( $asset_file ) ) {
$asset = include $asset_file;
$dependencies = $asset['dependencies'] ?? [];
$version = $asset['version'] ?? $version;
wp_register_script(
'dokan-vendor-store-support',
DOKAN_STORE_SUPPORT_PLUGIN_ASSEST . '/dist/js/vendor-store-support.js',
array_merge( [ 'dokan-react-components', 'dokan-utilities' ], $dependencies ),
$version,
true
);
wp_register_style(
'dokan-vendor-store-support',
DOKAN_STORE_SUPPORT_PLUGIN_ASSEST . '/dist/js/vendor-store-support.css',
[],
$version
);
wp_localize_script(
'dokan-vendor-store-support',
'DokanStoreSupport',
[
'currentUserId' => dokan_get_current_user_id(),
'currentUserName' => wp_get_current_user()->display_name,
'currentUserAvatar' => get_avatar_url( dokan_get_current_user_id() ),
]
);
}
}
/**
* Enqueue admin scripts
*
* Allows plugin assets to be loaded.
*
* @uses wp_enqueue_script()
* @uses wp_localize_script()
* @uses wp_enqueue_style
*/
public function enqueue_scripts() {
global $wp;
if (
( dokan_is_seller_dashboard() && ( isset( $wp->query_vars['support'] ) || ( isset( $wp->query_vars['settings'] ) && 'store' === $wp->query_vars['settings'] ) ) ) ||
dokan_is_store_page() ||
is_product() ||
( is_account_page() && ( isset( $wp->query_vars['support-tickets'] ) || isset( $wp->query_vars['view-order'] ) ) ) ||
( is_checkout() && isset( $wp->query_vars['order-received'] ) )
) {
wp_enqueue_script( 'dokan-login-form-popup' );
wp_enqueue_style( 'dokan-store-support-styles' );
wp_enqueue_script( 'dokan-store-support-scripts' );
wp_localize_script(
'dokan-store-support-scripts',
'dokan_store_support_i18n',
[
'wait' => __( 'wait...', 'dokan' ),
'empty_comment_msg' => __( 'Comment box is empty', 'dokan' ),
]
);
}
//load store support filter js
if ( dokan_is_seller_dashboard() && isset( $wp->query_vars['support'] ) ) {
wp_enqueue_style( 'dokan-select2-css' );
wp_enqueue_style( 'dokan-date-range-picker' );
wp_enqueue_script( 'dokan-store-support-filter' );
}
if ( dokan_is_seller_dashboard() ) {
wp_enqueue_script( 'dokan-vendor-store-support' );
wp_enqueue_style( 'dokan-vendor-store-support' );
}
}
/**
* Set per page value
*
* @since 1.3.5
*
* @param type $val
*/
public function set_per_page( $val ) {
$this->per_page = $val;
}
/**
* Register Custom Post type for support
*
* @since 1.0
*
* @return void
*/
public function register_dokan_store_support() {
$labels = [
'name' => _x( 'Topics', 'Post Type General Name', 'dokan' ),
'singular_name' => _x( 'Topic', 'Post Type Singular Name', 'dokan' ),
'menu_name' => __( 'Support', 'dokan' ),
'name_admin_bar' => __( 'Support', 'dokan' ),
'parent_item_colon' => __( 'Parent Item', 'dokan' ),
'all_items' => __( 'All Topics', 'dokan' ),
'add_new_item' => __( 'Add New Topic', 'dokan' ),
'add_new' => __( 'Add New', 'dokan' ),
'new_item' => __( 'New Topic', 'dokan' ),
'edit_item' => __( 'Edit Topic', 'dokan' ),
'update_item' => __( 'Update Topic', 'dokan' ),
'view_item' => __( 'View Topic', 'dokan' ),
'search_items' => __( 'Search Topic', 'dokan' ),
'not_found' => __( 'Not found', 'dokan' ),
'not_found_in_trash' => __( 'Not found in Trash', 'dokan' ),
];
$args = [
'label' => __( 'Store Support', 'dokan' ),
'description' => __( 'Support Topics by customer', 'dokan' ),
'labels' => $labels,
'supports' => [ 'title', 'author', 'comments', 'editor', 'custom-fields' ],
'hierarchical' => false,
'public' => false,
'show_ui' => false,
'show_in_menu' => false,
'menu_position' => 5,
'show_in_admin_bar' => false,
'show_in_nav_menus' => false,
'show_in_rest' => true,
'rewrite' => [ 'slug' => '' ],
'can_export' => true,
'has_archive' => true,
];
register_post_type( $this->post_type, $args );
}
public function register_dokan_support_topic_status() {
register_post_status(
'open', [
'label' => __( 'Open', 'dokan' ),
'public' => true,
'exclude_from_search' => false,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
// translators: %s: total open count
'label_count' => _n_noop( 'Open <span class="count">(%s)</span>', 'Open <span class="count">(%s)</span>', 'dokan' ),
]
);
register_post_status(
'closed', [
'label' => __( 'Closed', 'dokan' ),
'public' => true,
'exclude_from_search' => false,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
// translators: %s: total closed count
'label_count' => _n_noop( 'Closed <span class="count">(%s)</span>', 'Closed <span class="count">(%s)</span>', 'dokan' ),
]
);
}
/**
* Register dokan support meta fields
*
* @since 3.7.23
*
* @return void
*/
public function register_dokan_support_meta_fields() {
register_meta(
'post', 'store_id', [
'object_subtype' => 'dokan_store_support',
'type' => 'integer',
'description' => 'store id',
'single' => true,
'show_in_rest' => true,
]
);
register_meta(
'post', 'order_id', [
'object_subtype' => 'dokan_store_support',
'type' => 'integer',
'description' => 'order id',
'single' => true,
'show_in_rest' => true,
]
);
}
/**
* Get store support button
*
* @since 2.9.7
*
* @param int $store_id
*
* @return array
*/
public function get_support_button( $store_id ) {
$button = [
'class' => 'user_logged_out',
'text' => '',
];
if ( is_user_logged_in() ) {
$button['class'] = 'user_logged';
}
$store_info = dokan_get_store_info( $store_id );
$get_support_default_text = dokan_get_option( 'support_button_label', 'dokan_store_support_setting', __( 'Get Support', 'dokan' ) );
$button['text'] = ! empty( $store_info['support_btn_name'] ) ? $store_info['support_btn_name'] : $get_support_default_text;
return $button;
}
/**
* Prints Get support button on store page
*
* @param int $store_id store_id
* @since 1.0
*/
public function generate_support_button( $store_id ) {
$store_info = dokan_get_store_info( $store_id );
if ( isset( $store_info['show_support_btn'] ) && 'no' === $store_info['show_support_btn'] ) {
return;
}
$button = $this->get_support_button( $store_id );
?>
<div class="dokan-store-support-modals"></div>
<li class="dokan-store-support-btn-wrap dokan-right">
<button data-store_id="<?php echo esc_attr( (string) $store_id ); ?>" class="dokan-store-support-btn dokan-btn dokan-btn-theme dokan-btn-sm <?php echo esc_attr( $button['class'] ); ?>"><?php echo esc_html( $button['text'] ); ?></button>
</li>
<?php
}
/**
* Prints Get support button on above tab
*
* @since 3.2.0
*/
public function generate_support_button_product_page() {
$store_support_show = dokan_get_option( 'store_support_product_page', 'dokan_store_support_setting', 'above_tab' );
if ( 'above_tab' !== $store_support_show ) {
return;
}
$product_id = get_the_ID();
$store_id = get_post_field( 'post_author', $product_id );
$store_info = dokan_get_store_info( $store_id );
if ( isset( $store_info['show_support_btn_product'] ) && 'no' === $store_info['show_support_btn_product'] ) {
return;
}
$button = $this->get_support_button( (int) $store_id );
?>
<button data-store_id="<?php echo esc_attr( $store_id ); ?>" class="dokan-store-support-btn-product dokan-store-support-btn button alt <?php echo esc_attr( $button['class'] ); ?>"><?php echo esc_html( $button['text'] ); ?></button>
<?php
}
/**
* Prints Get support button on product page inner tab
*
* @since 3.2.0
*
* @param obj $author
*/
public function generate_support_button_product_page_inner_tab( $author ) {
$store_support_show = dokan_get_option( 'store_support_product_page', 'dokan_store_support_setting', 'above_tab' );
if ( 'inside_tab' !== $store_support_show ) {
return;
}
$store_info = dokan_get_store_info( $author->ID );
if ( isset( $store_info['show_support_btn_product'] ) && 'no' === $store_info['show_support_btn_product'] ) {
return;
}
$button = $this->get_support_button( $author->ID );
?>
<button data-store_id="<?php echo esc_attr( $author->ID ); ?>" class="dokan-store-support-btn-product dokan-store-support-btn button alt <?php echo esc_attr( $button['class'] ); ?>"><?php echo esc_html( $button['text'] ); ?></button>
<?php
}
/**
* Prints Get support button on order details page for customers
*
* @param object $order
* @since 3.2.3
*/
public function generate_support_button_customer_order_page( $order ) {
$allow_for_order = dokan_get_option( 'enabled_for_customer_order', 'dokan_store_support_setting', 'off' );
if ( empty( get_object_vars( $order ) ) ) {
return;
}
if ( 'on' !== $allow_for_order ) {
return;
}
if ( $order->get_meta( 'has_sub_order' ) ) {
return;
}
$order_id = $order->get_id();
$store_id = dokan_get_seller_id_by_order( $order_id );
$store_info = dokan_get_store_info( $store_id );
if ( isset( $store_info['show_support_btn_product'] ) && 'no' === $store_info['show_support_btn_product'] ) {
return;
}
$button = $this->get_support_button( $store_id );
?>
<button data-order_id="<?php echo esc_attr( $order_id ); ?>" data-store_id="<?php echo esc_attr( $store_id ); ?>" class="dokan-store-support-btn-product dokan-store-support-btn button alt <?php echo esc_attr( $button['class'] ); ?>"><?php echo esc_html( $button['text'] ); ?></button>
<?php
}
/**
* Ajax handler for all frontend Ajax submits
*
* @since 1.0
*
* @return void
*/
public function ajax_handler() {
$get_data = isset( $_POST['data'] ) ? sanitize_text_field( wp_unslash( $_POST['data'] ) ) : ''; // phpcs:ignore
if ( is_user_logged_in() && 'login_form' === $get_data ) {
$get_data = 'get_support_form';
}
if ( ! is_user_logged_in() && 'get_support_form' === $get_data ) {
$get_data = 'login_form';
}
switch ( $get_data ) {
case 'login_form':
wp_send_json_success( $this->login_form() );
// No need for break since wp_send_json_success() terminates execution
case 'get_support_form':
wp_send_json_success( $this->get_support_form() );
// No need for break since wp_send_json_success() terminates execution
case 'login_data_submit':
$this->login_data_submit();
return; // Add return since login_data_submit() handles its own response
case 'support_msg_submit':
$this->support_msg_submit();
return; // Add return since support_msg_submit() handles its own response
default:
wp_send_json_success( '<div>Error!! try again!</div>' );
// No need for break since wp_send_json_success() terminates execution
}
}
/**
* Generate login form
*
* @since 1.0
*
* @return string Login form Html
*/
public function login_form(): string {
ob_start();
$login_url = apply_filters( 'dokan_redirect_login', dokan_get_page_url( 'myaccount', 'woocommerce' ) );
?>
<h2><?php esc_html_e( 'Please Login to Continue', 'dokan' ); ?></h2>
<form class="dokan-form-container" id="dokan-support-login">
<div class="dokan-form-group">
<label class="dokan-form-label" for="login-name"><?php esc_html_e( 'Username :', 'dokan' ); ?></label>
<input required class="dokan-form-control" type="text" name='login-name' id='login-name'/>
</div>
<div class="dokan-form-group">
<label class="dokan-form-label" for="login-password"><?php esc_html_e( 'Password :', 'dokan' ); ?></label>
<input required class="dokan-form-control" type="password" name='login-password' id='login-password'/>
</div>
<?php wp_nonce_field( 'dokan-support-login-action', 'dokan-support-login-nonce' ); ?>
<div class="dokan-form-group">
<input id='support-submit-btn' type="submit" value="<?php esc_html_e( 'Login', 'dokan' ); ?>" class="dokan-w5 dokan-btn dokan-btn-theme"/>
</div>
<p class="dokan-popup-create-an-account">
<?php esc_html_e( 'or', 'dokan' ); ?> <a href="<?php echo esc_url( $login_url ); ?>" class="dokan-btn dokan-btn-theme"><?php esc_html_e( 'Create an account', 'dokan' ); ?></a>
</p>
</form>
<div class="dokan-clearfix"></div>
<?php
return ob_get_clean();
}
/**
* Generate Support form
*
* @since 1.0
*
* @return string support form html
*/
public function get_support_form( $seller_id = '' ): string {
$seller_id = $seller_id !== '' ? absint( $seller_id ) : ( isset( $_POST['store_id'] ) ? absint( wp_unslash( $_POST['store_id'] ) ) : 0 ); // phpcs:ignore
$order_id = isset( $_POST['order_id'] ) ? absint( wp_unslash( $_POST['order_id'] ) ) : 0; // phpcs:ignore
$customer_orders = apply_filters( 'dokan_store_support_order_id_select_in_form', dokan()->order->get_customer_order_ids_by_seller( dokan_get_current_user_id(), $seller_id ) );
$current_user = wp_get_current_user();
ob_start();
?>
<div class="dokan-support-intro-user"><strong>
<?php
// translators: %s: User display name
printf( __( 'Hi, %s', 'dokan' ), $current_user->display_name );
?>
</strong></div>
<div class="dokan-support-intro-text"><?php esc_html_e( 'Create a new support topic', 'dokan' ); ?></div>
<form class="dokan-form-container" id="dokan-support-form">
<div class="dokan-form-group">
<label class="dokan-form-label" for="dokan-support-subject"><?php esc_html_e( 'Subject :', 'dokan' ); ?></label>
<input required class="dokan-form-control" type="text" name='dokan-support-subject' id='dokan-support-subject'/>
</div>
<div class="dokan-form-group">
<?php if ( ! empty( $customer_orders ) ) { ?>
<select class="dokan-form-control dokan-select" name="order_id">
<option><?php esc_html_e( 'Select Order ID', 'dokan' ); ?></option>
<?php
foreach ( $customer_orders as $order ) :
$selected = $order_id && ( $order === $order_id ) ? 'selected' : '';
?>
<option value='<?php echo esc_attr( $order ); ?>' <?php echo esc_attr( $selected ); ?>><?php esc_html_e( 'Order', 'dokan' ); ?> #<?php echo esc_html( $order ); ?></option>
<?php endforeach; ?>
</select>
<?php } ?>
</div>
<div class="dokan-form-group">
<label class="dokan-form-label" for="dokan-support-msg"><?php esc_html_e( 'Message :', 'dokan' ); ?></label>
<textarea required class="dokan-form-control" name='dokan-support-msg' rows="5" id='dokan-support-msg'></textarea>
</div>
<input type="hidden" name='store_id' value="<?php echo $seller_id; ?>" />
<?php wp_nonce_field( 'dokan-support-form-action', 'dokan-support-form-nonce' ); ?>
<div class="dokan-form-group">
<input id='support-submit-btn' type="submit" value="<?php esc_html_e( 'Submit', 'dokan' ); ?>" class="dokan-w5 dokan-btn dokan-btn-theme"/>
</div>
</form>
<div class="dokan-clearfix"></div>
<?php
return ob_get_clean();
}
/**
* Handles login data and signs in user
*
* @since 1.0
*
* @return void
*/
public function login_data_submit() {
$form_data = ! empty( $_POST['form_data'] ) ? wp_unslash( $_POST['form_data'] ) : ''; // phpcs:ignore
parse_str( $form_data, $postdata );
if ( ! wp_verify_nonce( $postdata['dokan-support-login-nonce'], 'dokan-support-login-action' ) ) {
wp_send_json_error( __( 'Are you cheating?', 'dokan' ) );
}
$info = [];
$info['user_login'] = $postdata['login-name'];
$info['user_password'] = $postdata['login-password'];
$user_signon = wp_signon( $info, false );
if ( is_wp_error( $user_signon ) ) {
wp_send_json(
[
'success' => false,
'msg' => __( 'Invalid Username or Password', 'dokan' ),
]
);
} else {
wp_send_json(
[
'success' => true,
'msg' => __( 'Logged in', 'dokan' ),
]
);
}
}
/**
* Create post from fronend AJAX data
*
* @since 1.0
*
* @return void
*/
public function support_msg_submit( $postdata = [] ) {
WC_Emails::instance();
if ( isset( $_POST['form_data'] ) ) {
parse_str( wp_unslash( $_POST['form_data'] ), $postdata ); // phpcs:ignore
}
if ( ! isset( $postdata['dokan-support-form-nonce'] ) || ! wp_verify_nonce( $postdata['dokan-support-form-nonce'], 'dokan-support-form-action' ) ) {
wp_send_json_error( __( 'Are you cheating?', 'dokan' ) );
}
if ( empty( $postdata['store_id'] ) || ! is_numeric( $postdata['store_id'] ) ) {
wp_send_json(
[
'success' => false,
'msg' => __( 'No store found to create support ticket. Try again', 'dokan' ),
]
);
}
$my_post = [
'post_title' => sanitize_text_field( $postdata['dokan-support-subject'] ),
'post_content' => wp_kses_post( $postdata['dokan-support-msg'] ),
'post_status' => 'open',
'post_author' => dokan_get_current_user_id(),
'post_type' => 'dokan_store_support',
'comment_status' => 'open',
];
$post_id = wp_insert_post( apply_filters( 'dss_new_ticket_insert_args', $my_post ) );
if ( $post_id ) {
$store_id = ( ! empty( $postdata['store_id'] ) ) ? absint( $postdata['store_id'] ) : null;
$order_id = ( ! empty( $postdata['order_id'] ) ) ? absint( $postdata['order_id'] ) : null;
update_post_meta( $post_id, 'store_id', $store_id );
update_post_meta( $post_id, 'order_id', $order_id );
do_action( 'dokan_new_ticket_created_notify', $postdata['store_id'], $post_id );
$success_msg = __( 'Thank you. Your ticket has been submitted!', 'dokan' );
do_action( 'dss_new_ticket_created', $post_id, $postdata['store_id'] );
wp_send_json(
[
'success' => true,
'msg' => apply_filters( 'dss_ticket_submission_msg', $success_msg ),
]
);
} else {
$error_msg = __( 'Sorry, something went wrong! Couldn\'t create the ticket.', 'dokan' );
wp_send_json(
[
'success' => false,
'msg' => apply_filters( 'dss_ticket_submission_error_msg', $error_msg ),
]
);
}
}
/**
* Load new support ticket email class
*
* @param array $emails
*
* @return array
*/
public function load_support_ticket_emails( $emails ): array {
require_once DOKAN_STORE_SUPPORT_INC_DIR . '/class-new-support-ticket-email.php';
require_once DOKAN_STORE_SUPPORT_INC_DIR . '/class-reply-to-store-support-ticket-email.php';
require_once DOKAN_STORE_SUPPORT_INC_DIR . '/class-reply-to-user-support-ticket-email.php';
require_once DOKAN_STORE_SUPPORT_INC_DIR . '/class-new-support-ticket-admin-email.php';
require_once DOKAN_STORE_SUPPORT_INC_DIR . '/class-reply-to-admin-support-ticket-email.php';
$emails['Dokan_New_Support_Ticket'] = new \Dokan_New_Support_Ticket();
$emails['Dokan_Reply_To_Store_Support_Ticket'] = new \Dokan_Reply_To_Store_Support_Ticket();
$emails['Dokan_Reply_To_User_Support_Ticket'] = new \Dokan_Reply_To_User_Support_Ticket();
$emails['DokanNewSupportTicketForAdmin'] = new \DokanNewSupportTicketForAdmin();
$emails['DokanReplyToAdminSupportTicket'] = new \DokanReplyToAdminSupportTicket();
return $emails;
}
/**
* Set Proper template directory.
*
* @param array $template_array
*
* @return array
*/
public function set_email_template_directory( array $template_array ): array {
array_push( $template_array, 'new-support-ticket.php', 'reply-to-store-support-ticket.php', 'reply-to-user-support-ticket.php' );
return $template_array;
}
/**
* Register Dokan Email actions for WC
*
* @param array $actions
*
* @return array $actions
* @since 3.3.4
*/
public function register_email_actions( $actions ): array {
$actions[] = 'dokan_new_ticket_created_notify';
$actions[] = 'dokan_reply_to_store_ticket_created_notify';
$actions[] = 'dokan_reply_to_user_ticket_created_notify';
$actions[] = 'dokan_reply_to_admin_ticket_created_notify';
return $actions;
}
/**
* Register dokan query vars
*
* @param array $vars
*
* @return array new $vars
*@since 1.0
*/
public function register_support_queryvar( $vars ): array {
$vars[] = 'support';
$vars[] = 'support-tickets';
return $vars;
}
/**
* Add menu on seller dashboard
*
* @param array $urls
*
* @return array $urls
* @since 1.0
*/
public function add_store_support_page( $urls ): array {
$menu = [
'title' => __( 'Support', 'dokan' ),
'icon' => '<i class="far fa-life-ring"></i>',
'url' => dokan_get_navigation_url( 'support' ),
'pos' => 199,
'icon_name' => 'Headphones',
'react_route' => 'support',
];
if ( ! current_user_can( 'dokan_manage_support_tickets' ) ) {
return $urls;
}
if ( dokan_is_seller_enabled( get_current_user_id() ) ) {
$counts = $this->topic_count( dokan_get_current_user_id() );
$count = 0;
if ( is_array( $counts ) ) {
$count = wp_list_pluck( $counts, 'count', 'post_status' );
}
$defaults = [
'open' => 0,
'closed' => 0,
];
$count = wp_parse_args( $count, $defaults );
$menu['counts'] = $count['open'] ?? 0;
$urls['support'] = $menu;
}
return $urls;
}
/**
* Get plugin path
*
* @return string
**@since 2.8
*/
public function plugin_path(): string {
return untrailingslashit( plugin_dir_path( __FILE__ ) );
}
/**
* Load Dokan Store support templates
*
* @return string
**@since 2.8
*/
public function load_store_support_templates( $template_path, $template, $args ): string {
if ( isset( $args['is_store_support'] ) && $args['is_store_support'] ) {
return $this->plugin_path() . '/templates';
}
return $template_path;
}
/**
* Register page templates
*
* @param array $query_vars
*
* @return void $query_vars
* @since 1.0
*/
public function load_template_from_plugin( $query_vars ): void {
if ( isset( $query_vars['support'] ) ) {
if ( ! current_user_can( 'dokan_manage_support_tickets' ) ) {
dokan_get_template_part(
'global/dokan-error', '', [
'deleted' => false,
'message' => __( 'You have no permission to view this page', 'dokan' ),
]
);
return;
}
// This format of nonce checking used intentionally. Because the function might be used without form submission.
if ( isset( $_GET['dokan-support-listing-search-nonce'] ) && ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['dokan-support-listing-search-nonce'] ) ), 'dokan-support-listing-search' ) ) {
return;
}
$args['customer_id'] = ! empty( $_GET['customer_id'] ) ? absint( wp_unslash( $_GET['customer_id'] ) ) : 0;
$args['ticket_start_date'] = ! empty( $_GET['ticket_start_date'] ) ? sanitize_text_field( wp_unslash( $_GET['ticket_start_date'] ) ) : '';
$args['ticket_end_date'] = ! empty( $_GET['ticket_end_date'] ) ? sanitize_text_field( wp_unslash( $_GET['ticket_end_date'] ) ) : '';
$args['ticket_keyword'] = ! empty( $_GET['ticket_keyword'] ) ? sanitize_text_field( wp_unslash( $_GET['ticket_keyword'] ) ) : '';
$args['ticket_status'] = ! empty( $_GET['ticket_status'] ) ? sanitize_text_field( wp_unslash( $_GET['ticket_status'] ) ) : 'open';
$args['pagenum'] = ! empty( $_GET['pagenum'] ) ? absint( wp_unslash( $_GET['pagenum'] ) ) : 1;
$args['is_store_support'] = true;
if ( ! empty( $_GET['customer_id'] ) ) {
$user = get_user_by( 'id', absint( wp_unslash( $_GET['customer_id'] ) ) );
$args['customer_name'] = $user ? $user->display_name : '';
}
dokan_get_template_part( 'store-support/support', '', $args );
}
if ( isset( $query_vars['support-tickets'] ) ) {
dokan_get_template_part( 'store-support/support-tickets', '', [ 'is_store_support' => true ] );
}
}
/**
* Query for support topics using given arguments
*
* @param array $args
*
* @return WP_Query $query
* @since 1.0
*/
public function get_support_topics( $args = array() ): WP_Query {
global $wpdb;
if ( empty( $args['ticket_end_date'] ) ) {
unset( $args['ticket_end_date'] );
}
$defaults = [
'vendor_id' => absint( dokan_get_current_user_id() ),
'customer_id' => 0,
'ticket_keyword' => '',
'ticket_start_date' => 0,
'ticket_end_date' => dokan_current_datetime()->format( 'Y-m-d' ),
'ticket_status' => 'open',
'pagenum' => 1,
'posts_per_page' => $this->per_page,
'paged' => 1,
];
$args = wp_parse_args( $args, $defaults );
$offset = ( $args['pagenum'] - 1 ) * $args['posts_per_page'];
// WP_Query arguments
$qry_args = [
'post_type' => 'dokan_store_support',
'author' => $args['customer_id'],
'post_status' => $args['ticket_status'],
'posts_per_page' => $args['posts_per_page'],
'offset' => $offset,
'paged' => $args['paged'],
'meta_query' => [
[
'key' => 'store_id',
'value' => $args['vendor_id'],
'compare' => '=',
'type' => 'NUMERIC',
],
],
];
if ( is_numeric( $args['ticket_keyword'] ) ) {
$qry_args['p'] = $wpdb->esc_like( $args['ticket_keyword'] );
} elseif ( ! empty( $args['ticket_keyword'] ) ) {
$qry_args['s'] = $wpdb->esc_like( $args['ticket_keyword'] );
}
if ( ! empty( $args['ticket_start_date'] ) && ! empty( $args['ticket_end_date'] ) ) {
$qry_args['date_query'] = [
'after' => $args['ticket_start_date'],
'before' => $args['ticket_end_date'],
'inclusive' => true,
];
}
$qry_args = apply_filters( 'dokan_get_topic_by_seller_qry_args', $qry_args );
$cache_group = "store_support_{$args['vendor_id']}";
$cache_key = 'get_support_topics_' . md5( wp_json_encode( $qry_args ) );
$query = Cache::get( $cache_key, $cache_group );
if ( false === $query ) {
$query = new WP_Query( $qry_args );
Cache::set( $cache_key, $query, $cache_group );
}
$this->total_query_result = $query->found_posts;
return $query;
}
/**
* Print html of all topics for given arguments
*
* @param array $args
*
* @return void
* @since 1.0
*/
public function print_support_topics( $args = array() ) {
$query = $this->get_support_topics( $args );
?>
<div class="dokan-support-topics-list">
<?php
if ( $query->have_posts() ) {
?>
<table class="dokan-table dokan-support-table">
<thead>
<tr>
<th><?php esc_html_e( 'Topic', 'dokan' ); ?></th>
<th><?php esc_html_e( 'Order Ref.', 'dokan' ); ?></th>
<th><?php esc_html_e( 'Title', 'dokan' ); ?></th>
<th><?php esc_html_e( 'Customer', 'dokan' ); ?></th>
<th><?php esc_html_e( 'Status', 'dokan' ); ?></th>
<th><?php esc_html_e( 'Date', 'dokan' ); ?></th>
<th><?php esc_html_e( 'Action', 'dokan' ); ?></th>
</tr>
</thead>
<tbody>
<?php
while ( $query->have_posts() ) {
$query->the_post();
global $post;
$topic_url = dokan_get_navigation_url( "support/{$post->ID}/" );
$order_id = get_post_meta( $post->ID, 'order_id', true );
if ( ! empty( $order_id ) ) {
$order_url = esc_url( wp_nonce_url( add_query_arg( [ 'order_id' => $order_id ], dokan_get_navigation_url( 'orders' ) ), 'dokan_view_order' ) );
} else {
$order_url = '#';
}
?>
<tr>
<td>
<a href="<?php echo esc_url( $topic_url ); ?>">
<strong>
<?php
// translators: %s: topic id
printf( __( '#%s', 'dokan' ), get_the_ID() );
?>
</strong>
</a>
</td>
<td>
<a href="<?php echo $order_url; ?>" target="_blank">
<strong>
<?php
// translators: %s: Order Id
$order_id ? printf( __( '#%s', 'dokan' ), $order_id ) : esc_html_e( '-', 'dokan' );
?>
</strong>
</a>
</td>
<td class="column-primary">
<a href="<?php echo esc_url( $topic_url ); ?>">
<?php the_title(); ?>
</a>
<button type="button" class="toggle-row"></button>
</td>
<td data-title="<?php esc_attr_e( 'Customer', 'dokan' ); ?>">
<div class="dokan-support-customer-name">
<?php echo get_avatar( get_the_author_meta( 'ID' ), 50 ); ?>
<strong><?php the_author(); ?></strong>
</div>
</td>
<?php
switch ( get_post_status() ) {
case 'closed':
$c_status = 'open';
$btn_icon = 'fa-file';
$topic_status = 'dokan-label-danger';
$status_label = __( 'Closed', 'dokan' );
$btn_title = __( 'Re-open Topic', 'dokan' );
break;
default:
$c_status = 'closed';
$btn_icon = 'fa-times';
$topic_status = 'dokan-label-success';
$status_label = __( 'Open', 'dokan' );
$btn_title = __( 'Close Topic', 'dokan' );
break;
}
$query_args = [
'action' => 'dokan-support-topic-status',
'topic_id' => get_the_ID(),
'ticket_status' => $c_status,
];
$action_url = wp_nonce_url( add_query_arg( $query_args, dokan_get_navigation_url( 'support' ) ), 'dokan-change-topic-status' );
?>
<td data-title="<?php esc_attr_e( 'Status', 'dokan' ); ?>"><span class="dokan-label <?php echo esc_attr( $topic_status ); ?>"><?php echo esc_html( $status_label ); ?></span></td>
<td class="dokan-order-date" data-title="<?php esc_attr_e( 'Date', 'dokan' ); ?>"><span><?php echo esc_html( dokan_format_datetime( dokan_get_timestamp( $post->post_date_gmt, true ) ) ); ?></span></td>
<td data-title="<?php esc_attr_e( 'Action', 'dokan' ); ?>">
<?php $selected_icon = 'fa-file' === $btn_icon ? esc_attr( 'far' ) : esc_attr( 'fas' ); ?>
<a class="dokan-btn dokan-btn-default dokan-btn-sm tips dokan-support-status-change" onclick="dokan_show_delete_prompt( event, dokan.delete_confirm );" href="<?php echo esc_url( $action_url ); ?>" title="" data-changing_post_id="<?php echo get_the_ID(); ?>" data-original-title="<?php echo esc_attr( $btn_title ); ?>"><i data-url="<?php echo esc_url( $action_url ); ?>" class="<?php echo esc_attr( $selected_icon . ' ' . $btn_icon ); ?>"> </i></a>
</td>
</tr>
<?php
}
wp_reset_postdata();
} else {
?>
<div class="dokan-error">
<?php esc_html_e( 'No tickets found!', 'dokan' ); ?>
</div>
<?php
}
?>
</tbody>
</table>
</div>
<?php
$this->topics_pagination( 'support' );
}
/**
* Query single topic for given seller id
*
* @since 1.0
*
* @param int $topic_id
* @param int $seller_id
*
* @return WP_Query $query_dss
*/
public function get_single_topic( $topic_id, $seller_id ): WP_Query {
$args_t = [
'p' => $topic_id,
'post_type' => $this->post_type,
'meta_query' => [
[
'key' => 'store_id',
'value' => $seller_id,
'compare' => '=',
'type' => 'NUMERIC',
],
],
];
$args_t = apply_filters( 'dokan_support_get_single_topic_args', $args_t );
$query_dss = new WP_Query( $args_t );
return $query_dss;
}
/**
* Query single topic for given customer id
*
* @since 1.0
*
* @param int $topic_id
* @param int $customer_id
*
* @return WP_Query $query_dss
*/
public function get_single_topic_by_customer( $topic_id, $customer_id ) {
$args_t = [
'p' => $topic_id,
'post_type' => $this->post_type,
'author' => $customer_id,
];
$query_dss = new WP_Query( $args_t );
return $query_dss;
}
/**
* Print Html for single topic with given topic object
*
* @since 1.0
*
* @param object $topic Custom post type 'dokan_store_support' object
*
* @return void
*/
public function print_single_topic( $topic ) {
global $wp;
$is_customer = 0;
$back_url = dokan_get_navigation_url( 'support' );
$is_seller_dashboard = dokan_is_seller_dashboard() ? 1 : 0;
if ( isset( $wp->query_vars['support-tickets'] ) ) {
$is_customer = 1;
$back_url = dokan_get_page_url( 'myaccount', 'woocommerce', 'support-tickets/' );
}
if ( $topic->have_posts() ) {
while ( $topic->have_posts() ) {
$topic->the_post();
global $post;
?>
<a href="<?php echo $back_url; ?>">← <?php esc_html_e( 'Back to Tickets', 'dokan' ); ?></a>
<div class="dokan-support-single-title">
<div class="dokan-dss-chat-header">
<div class="dokan-chat-title-box">
<span class="dokan-chat-title"><?php the_title(); ?></span>
<span class="dokan-chat-title dokan-chat-status">
<?php
// translators: %s: topic id
printf( __( '#%s', 'dokan' ), get_the_ID() );
?>
</span>
</div>
<div class="dokan-chat-status-box">
<span class="dokan-chat-status <?php echo get_post_status( get_the_ID() ) === 'open' ? 'chat-open' : 'chat-closed'; ?>"><?php echo get_post_status( get_the_ID() ) === 'open' ? __( 'Open', 'dokan' ) : __( 'Closed', 'dokan' ); ?></span>
</div>
</div>
<?php
$order_id = get_post_meta( get_the_ID(), 'order_id', true );
$order = wc_get_order( $order_id );
if ( $order_id && $order ) {
$ticket_ref_url = $order->get_view_order_url();
if ( $is_seller_dashboard ) {
$ticket_ref_url = wp_nonce_url( add_query_arg( array( 'order_id' => $order_id ), dokan_get_navigation_url( 'orders' ) ), 'dokan_view_order' );
}
?>
<span class="order-reference" >
<h3>
<?php /* translators: %s: Referenced Order */ ?>
<?php echo '<a href="' . esc_url( $ticket_ref_url ) . '"><strong>' . sprintf( __( 'Referenced Order #%s', 'dokan' ), esc_attr( number_format_i18n( $order_id ) ) ) . '</strong></a>'; ?>
</h3>
</span>
<?php
}
?>
</div>
<div class="dokan-dss-chat-box main-topic">
<div class="dokan-chat-image-box">
<div class="dokan-chat-image-container dokan-chat-image-container-topic">
<?php echo get_avatar( get_the_author_meta( 'ID' ), 90 ); ?>
</div>
</div>
<div class="dokan-chat-info-box">
<div class="dokan-chat-sender-info">
<div class="dokan-chat-user-box">
<span class="chat-user"><?php the_author(); ?></span>
</div>
</div>
<div class="dokan-chat-text dokan-customer-chat-text">
<?php the_content(); ?>
</div>
<div class="dokan-chat-time-box">
<span class="dokan-chat-time">
<?php echo esc_html( dokan_format_datetime( dokan_get_timestamp( $post->post_date_gmt, true ) ) ); ?>
</span>
</div>
</div>
</div>
<ul class="dokan-support-commentlist">
<?php
$ticket_status = get_post_status( get_the_ID() );
// Gather comments for a specific page/post
$comments = get_comments(
[
'post_id' => get_the_ID(),
'status' => 'approve', //Change this to the type of comments to be displayed
]
);
// Display the list of comments
wp_list_comments(
[
'max_depth' => 0,
'page' => 1,
'per_page' => 100, //Allow comment pagination
'reverse_top_level' => true, //Show the latest comments at the top of the list
'format' => 'html5',
'callback' => [ $this, 'support_comment_format' ],
],
$comments
);
?>
</ul>
<?php
}
?>
<div class="dokan-panel dokan-panel-default dokan-dss-panel-default">
<div class="dokan-dss-panel-heading">
<?php
$ticket_status = get_post_status( get_the_ID() );
$heading = $ticket_status === 'open' ? __( 'Add Reply', 'dokan' ) : __( 'Ticket Closed', 'dokan' );
?>
<strong><?php echo $heading; ?></strong>
<?php
if ( ! $is_customer && $ticket_status === 'closed' ) {
echo '<em>' . __( '(Adding reply will re-open the ticket)', 'dokan' ) . '</em>';
}
?>
</div>
<div class="dokan-dss-panel-body dokan-support-reply-form">
<?php
if ( $ticket_status === 'open' || ! $is_customer ) {
$comment_textarea = '<p class="comment-form-comment">
<label for="Reply"></label>
<textarea class="dokan-dss-comment-textarea" required="required" id="comment" name="comment" rows="3" aria-required="true"></textarea>
</p>';
$select_topic_status = $ticket_status === 'open' ?
'<select class="dokan-support-topic-select dokan-form-control dokan-w3" name="dokan-topic-status-change">
<option value="0">' . __( '-- Change Status --', 'dokan' ) . '</option>
<option value="1">' . __( 'Close Ticket', 'dokan' ) . '</option>
</select>'
: '<input type="hidden" value="1" name="dokan-topic-status-change">';
$comment_field = $comment_textarea;
if ( ! $is_customer ) {
$comment_field = $comment_textarea . $select_topic_status . '<div class="clearfix"></div>';
}
$comment_args = [
'id_form' => 'dokan-support-commentform',
'id_submit' => 'submit',
'class_submit' => 'submit dokan-btn dokan-btn-theme',
'name_submit' => 'submit',
'title_reply' => __( 'Leave a Reply', 'dokan' ),
'title_reply_to' => '',
'cancel_reply_link' => __( 'Cancel Reply', 'dokan' ),
'label_submit' => __( 'Submit Reply', 'dokan' ),
'format' => 'html5',
'comment_field' => $comment_field,
'must_log_in' => '<p class="must-log-in">' .
/* translators: %s: Login url link */
sprintf( __( 'You must be <a href="%s">logged in</a> to post a comment.', 'dokan' ), wp_login_url( apply_filters( 'the_permalink', get_permalink() ) ) ) . '</p>',
'logged_in_as' => '',
'comment_notes_before' => '',
'comment_notes_after' => '',
];
comment_form( $comment_args, get_the_ID() );
} else {
?>
<div class="dokan-alert dokan-alert-warning">
<?php esc_html_e( 'This ticket has been closed. Open a new support ticket if you have any further query.', 'dokan' ); ?>
</div>
<?php
}
wp_reset_postdata();
?>
</div>
</div>
<?php
} else {
?>
<div class="dokan-error">
<?php esc_html_e( 'Topic not found', 'dokan' ); ?>
</div>
<?php
}
}
/**
* Redirect users to same topic after a comment is submitted if it is dokan_store_support post type
*
* @param string $location
* @param object $comment
*
* @return string location
*@since 1.0
*/
public function redirect_after_comment( $location, $comment ): string {
if ( get_post_type( $comment->comment_post_ID ) === $this->post_type ) {
return isset( $_SERVER['HTTP_REFERER'] ) ? wp_unslash( sanitize_text_field( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) ) : home_url();
}
return $location;
}
/**
* Print support topics on customer my account page
*
* @since 1.0
*
* @return void
*/
public function my_account_support_topics() {
?>
<h2><?php esc_html_e( 'Support Tickets', 'dokan' ); ?></h2>
<div class="dokan-support-topics">
<a href="<?php echo dokan_get_page_url( 'myaccount', 'woocommerce', 'support-tickets/' ); ?>"><button class="dokan-btn dokan-btn-theme"><?php esc_html_e( 'View Support Tickets', 'dokan' ); ?></button></a>
</div>
<?php
}
/**
* Prints html of all topics for given customer
*
* @since 1.0
*
* @param int $customer_id
*
* @return void
*/
public function print_support_topics_by_customer( $customer_id ) {
$query = $this->get_topics_by_customer( $customer_id );
?>
<div class="dokan-support-topics-list">
<?php if ( $query->posts ) { ?>
<table class="dokan-table dokan-support-table">
<thead>
<tr>
<th><?php esc_html_e( 'Topic', 'dokan' ); ?></th>
<th><?php esc_html_e( 'Store Name', 'dokan' ); ?></th>
<th><?php esc_html_e( 'Title', 'dokan' ); ?></th>
<th><?php esc_html_e( 'Status', 'dokan' ); ?></th>
<th><?php esc_html_e( 'Date', 'dokan' ); ?></th>
</tr>
</thead>
<tbody>
<?php
foreach ( $query->posts as $topic ) {
$topic_url = dokan_get_page_url( 'myaccount', 'woocommerce', "support-tickets/{$topic->ID}/" );
?>
<tr>
<td>
<a href="<?php echo $topic_url; ?>"
<strong>
<?php
// translators: %s: Topic ID
printf( __( '#%s', 'dokan' ), $topic->ID );
?>
</strong>
</a>
</td>
<td>
<div class="dokan-support-customer-name">
<?php
$store_id = is_object( $topic ) ? $topic->store_id : 0;
$store_info = dokan_get_store_info( $store_id );
$store_name = $store_info['store_name'] ?? get_user_meta( $store_id, 'nickname', true );
$store_url = dokan_get_store_url( $store_id );
?>
<strong><a href="<?php echo esc_url( $store_url ); ?>" target="_blank"><?php echo esc_html( empty( $store_name ) ? __( '( No name )', 'dokan' ) : $store_name ); ?></a></strong>
</div>
</td>
<td>
<a href="<?php echo $topic_url; ?>">
<?php echo $topic->post_title; ?>
</a>
</td>
<?php
switch ( $topic->post_status ) {
case 'closed':
$c_status = __( 'open', 'dokan' );
$btn_icon = 'fa-file-o';
$topic_status = 'dokan-label-danger';
$btn_title = __( 're-open topic', 'dokan' );
$status_label = __( 'Closed', 'dokan' );
break;
default:
$c_status = __( 'closed', 'dokan' );
$btn_icon = 'fa-close';
$topic_status = 'dokan-label-success';
$btn_title = __( 'close topic', 'dokan' );
$status_label = __( 'Open', 'dokan' );
break;
}
?>
<td><span class="dokan-label <?php echo $topic_status; ?>"><?php echo esc_html( $status_label ); ?></span></td>
<td class="dokan-order-date"> <span><?php echo esc_html( dokan_format_datetime( dokan_get_timestamp( $topic->post_date_gmt, true ) ) ); ?></span></td>
</tr>
<?php
}
?>
<?php } else { ?>
<div class="dokan-error">
<?php esc_html_e( 'No tickets found!', 'dokan' ); ?>
</div>
<?php } ?>
</tbody>
</table>
</div>
<?php
$this->topics_pagination( 'support-tickets' );
wp_reset_postdata();
}
/**
* Query all topics by given customer
*
* @param int $customer_id
* @param array $args
*
* @phpcs:disabled WordPress.Security.NonceVerification.Recommended
*
* @return WP_Query $topic_query
*@since 1.0
*/
public function get_topics_by_customer( $customer_id, $args = [] ): WP_Query {
global $wpdb;
$pagenum = isset( $_GET['pagenum'] ) ? absint( wp_unslash( $_GET['pagenum'] ) ) : 1;
$this->per_page = $args['posts_per_page'] ?? $this->per_page;
$pagenum = $args['pagenum'] ?? $pagenum;
$offset = ( $pagenum - 1 ) * $this->per_page;
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$args_c = [
'author' => $customer_id,
'post_type' => 'dokan_store_support',
'posts_per_page' => $this->per_page,
'offset' => $offset,
'paged' => $paged,
'orderby' => 'post_date',
'order' => 'DESC',
'meta_query' => [ // phpcs:ignore
[
'key' => 'store_id',
'value' => '',
'compare' => '!=', // Not equal to empty
],
],
];
$args_c['post_status'] = 'open';
if ( isset( $_GET['ticket_status'] ) ) {
$args_c['post_status'] = sanitize_text_field( wp_unslash( $_GET['ticket_status'] ) );
}
if ( isset( $_GET['ticket_keyword'] ) ) {
if ( is_numeric( $args['ticket_keyword'] ) ) {
$args_c['p'] = $wpdb->esc_like( $args['ticket_keyword'] );
} else {
$args_c['s'] = $wpdb->esc_like( $args['ticket_keyword'] );
}
}
if ( isset( $args['ticket_start_date'] ) && isset( $args['ticket_end_date'] ) ) {
$args_c['date_query'] = [
'after' => $args['ticket_start_date'],
'before' => $args['ticket_end_date'],
'inclusive' => true,
];
}
$cache_group = "store_support_customer_{$customer_id}";
$cache_key = 'get_topics_' . md5( wp_json_encode( $args_c ) );
$topic_query = Cache::get( $cache_key, $cache_group );
if ( false === $topic_query ) {
$topic_query = new WP_Query( $args_c );
Cache::set( $cache_key, $topic_query, $cache_group );
}
$this->total_query_result = $topic_query->found_posts;
return $topic_query;
}
/**
* Disable edit of comments on comment listing
*
* @since 1.0
*
* @return string
*/
public function remove_comment_edit_link( $link, $comment_id ) {
$comment = get_comment( $comment_id );
if ( get_post_type( (int) $comment->comment_post_ID ) === $this->post_type ) {
$link = '';
return $link;
}
return $link;
}
/**
* Show pagination on support listing
*
* @param string $query_var
*
* @return void
*@since 1.0
*/
public function topics_pagination( $query_var ) {
$request_data = $_GET; // phpcs:ignore
$pagenum = isset( $request_data['pagenum'] ) ? absint( wp_unslash( $request_data['pagenum'] ) ) : 1;
$num_of_pages = ceil( $this->total_query_result / $this->per_page );
if ( is_account_page() ) {
$base_url = dokan_get_page_url( 'myaccount', 'woocommerce', 'support-tickets/' );
} else {
$base_url = dokan_get_navigation_url( $query_var );
}
$page_links = paginate_links(
[
'base' => $base_url . '%_%',
'format' => '?pagenum=%#%',
'prev_text' => __( '«', 'dokan' ),
'next_text' => __( '»', 'dokan' ),
'total' => (int) $num_of_pages,
'current' => $pagenum,
'type' => 'array',
]
);
if ( $page_links ) {
echo "<div class='pagination-wrap'>\n\t<ul class='pagination'>\n\t<li>";
echo join( "</li>\n\t<li>", $page_links );
echo "</li>\n</ul>\n</div>\n";
}
}
/**
* Print comments into formatted html, callback for wp_comment_list function
*
* @since 1.0
*/
public function support_comment_format( $comment ) {
$GLOBALS['comment'] = $comment;
$user_type = 'dokan-customer-chat-text';
$user_image = get_avatar_url( $comment->user_id );
$site_name = '';
if ( user_can( $comment->user_id, 'manage_options' ) && dokan_is_user_seller( $comment->user_id ) ) {
$user_type = 'dokan-admin-chat-text';
$custom_logo_id = get_theme_mod( 'custom_logo' );
$logo = wp_get_attachment_image_src( $custom_logo_id, 'full' );
$user_image = has_custom_logo() ? $logo[0] : get_avatar_url( 0 );
$site_name = get_bloginfo( 'name', 'display' );
} elseif ( dokan_is_user_seller( $comment->user_id ) ) {
$user_type = 'dokan-vendor-chat-text';
}
?>
<li <?php comment_class(); ?> id="li-comment-<?php comment_ID(); ?>">
<div class="dokan-dss-chat-box">
<div class="dokan-chat-image-box">
<div class="dokan-chat-image-container">
<img src="<?php echo esc_attr( $user_image ); ?>" alt="<?php echo esc_attr( $user_image ); ?>" class="dokan-chat-image">
</div>
</div>
<div class="dokan-chat-info-box">
<div class="dokan-chat-sender-info">
<div class="dokan-chat-user-box">
<?php if ( '' === $site_name ) : ?>
<span class="chat-user"><?php comment_author(); ?></span>
<?php else : ?>
<span class="chat-user"><?php echo esc_html( $site_name ); ?></span>
<?php endif; ?>
</div>
</div>
<div class="dokan-chat-text <?php echo esc_attr( $user_type ); ?>">
<?php comment_text(); ?>
</div>
<div class="dokan-chat-time-box">
<span class="dokan-chat-time">
<time>
<?php echo get_comment_time() . '<span class="human-diff"> ( ' . human_time_diff( time(), (int) get_comment_time( 'U' ) ) . ' )</span>'; ?> </time>
</span>
</div>
</div>
<!-- <div class="chat-action-box"></div> -->
</div>
<?php
}
/**
* Change status of topic from support list action
*
* @since 1.0
*
* @return void
*/
public function change_topic_status() {
if ( ! is_user_logged_in() ) {
return;
}
if ( ! dokan_is_user_seller( dokan_get_current_user_id() ) ) {
return;
}
$defaults = [
'topic_id' => 0,
'ticket_status' => '',
];
$defaults = wp_parse_args( $_GET, $defaults ); // phpcs:ignore
if ( $defaults['topic_id'] !== 0 && $defaults['ticket_status'] !== '' ) {
$post_id = $defaults['topic_id'];
$status = $defaults['ticket_status'];
$my_post = [
'ID' => $post_id,
'post_status' => $status,
];
wp_update_post( $my_post );
$status = $status === 'open' ? 'closed' : 'open';
/**
* Fires an action when a support ticket status is changed.
*
* @since 3.4.2
*
* @param int $post_id
* @param string $status
*/
do_action( 'dokan_support_topic_status_changed', $post_id, $status );
wp_safe_redirect( add_query_arg( [ 'ticket_status' => $status ], dokan_get_navigation_url( 'support' ) ) );
}
}
/**
* Change topic status from comment section
*
* @param int $comment_id
* @param obj $comment
*
* @return void
*/
public function change_topic_status_on_comment( $comment_id, $comment ) {
$post_id = (int) $comment->comment_post_ID;
$parent_post = get_post( $post_id );
$request_data = $_POST; // phpcs:ignore
if ( empty( $parent_post ) || $parent_post->post_type !== $this->post_type ) {
return;
}
$store_id = get_post_meta( $post_id, 'store_id', true );
do_action( 'dss_new_comment_inserted', $post_id, $store_id );
if ( ! isset( $request_data['dokan-topic-status-change'] ) ) {
$this->notify_ticket_author( $comment, $parent_post, true );
return;
}
// override default comment notification
add_filter( 'comment_notification_recipients', '__return_empty_array', PHP_INT_MAX );
$this->notify_ticket_author( $comment, $parent_post );
// if a new comment is on a closed topic by seller, it should re-open
if ( $parent_post->post_status === 'closed' ) {
wp_update_post(
[
'ID' => $post_id,
'post_status' => 'open',
]
);
return;
}
if ( (int) $request_data['dokan-topic-status-change'] === 1 || (int) $request_data['dokan-topic-status-change'] === 2 ) {
$status = (int) $request_data['dokan-topic-status-change'] === 1 ? 'closed' : 'open';
$my_post = [
'ID' => $post_id,
'post_status' => $status,
];
wp_update_post( $my_post );
}
}
/**
* Send email notification on a new reply
*
* @param object $comment
* @param \WP_Post $ticket
* @param bool $to_store
*
* @return void
*/
public function notify_ticket_author( $comment, $ticket, $to_store = false ) {
WC_Emails::instance();
$store_id = get_post_meta( $ticket->ID, 'store_id', true );
$store = dokan_get_store_info( $store_id );
$store_name = $store['store_name'];
$store_email = get_userdata( $store_id )->user_email;
$url = dokan_get_navigation_url( "support/{$ticket->ID}/" );
$account_ticket_url = dokan_get_page_url( 'myaccount', 'woocommerce', "support-tickets/{$ticket->ID}/" );
$email_data = array(
'ticket_title' => $ticket->post_title,
'account_ticket_url' => $account_ticket_url,
'store_name' => $store_name,
'store_url' => dokan_get_store_url( $store_id ),
'ticket_url' => $url,
'ticket_id' => $ticket->ID,
'comment' => $comment,
'store_id' => $store_id,
'to_email' => $to_store ? $store_email : get_userdata( (int) $ticket->post_author )->user_email,
);
/**
* Scenario:
*
* When admin comments send email to customer and store.
* When customer comments send email to store and admin.
* When store comments send email to customer and admin.
*/
/**
* When customer or admin comments $to_store is true and send email to store.
* And when vendor comments $to_store is false and send email to customer.
*/
if ( $to_store ) {
do_action( 'dokan_reply_to_store_ticket_created_notify', $store_id, $email_data );
} else {
do_action( 'dokan_reply_to_user_ticket_created_notify', $store_id, $email_data );
}
/**
* Whoever comments if he/she is admin send email to customer or send email to admin.
*/
if ( user_can( $comment->user_id, 'manage_options' ) ) {
$author_id = get_post_field( 'post_author', $comment->comment_post_ID );
$customer_email = get_the_author_meta( 'user_email', (int) $author_id );
$email_data['to_email'] = $customer_email;
do_action( 'dokan_reply_to_user_ticket_created_notify', $store_id, $email_data );
} else {
$email_data['to_email'] = get_option( 'admin_email', true );
do_action( 'dokan_reply_to_admin_ticket_created_notify', $store_id, $email_data );
}
}
/**
* Support button text input field generator
*
* @param int $current_user
* @param array $profile_info
*
* @return void
*/
public function add_support_btn_title_input( $current_user, $profile_info ) {
$support_text = isset( $profile_info['support_btn_name'] ) ? $profile_info['support_btn_name'] : '';
$enable_support = isset( $profile_info['show_support_btn'] ) ? $profile_info['show_support_btn'] : 'yes';
$enable_support_product = isset( $profile_info['show_support_btn_product'] ) ? $profile_info['show_support_btn_product'] : 'yes';
$store_support_product_page = dokan_get_option( 'store_support_product_page', 'dokan_store_support_setting', 'above_tab' );
?>
<div class="dokan-form-group">
<label class="dokan-w3 dokan-control-label"><?php esc_html_e( 'Enable Support', 'dokan' ); ?></label>
<div class="dokan-w5 dokan-text-left">
<div class="checkbox">
<label>
<input type="hidden" name="support_checkbox" value="no">
<input type="checkbox" id="support_checkbox" name="support_checkbox" value="yes" <?php checked( $enable_support, 'yes' ); ?>> <?php esc_html_e( 'Show support button in store', 'dokan' ); ?>
</label>
<?php if ( 'dont_show' !== $store_support_product_page ) : ?>
<label>
<input type="hidden" name="support_checkbox_product" value="no">
<input type="checkbox" id="support_checkbox_product" name="support_checkbox_product" value="yes" <?php checked( $enable_support_product, 'yes' ); ?>> <?php esc_html_e( 'Show support button in single product', 'dokan' ); ?>
</label>
<?php endif; ?>
</div>
</div>
</div>
<div class="dokan-form-group support-enable-check">
<label class="dokan-w3 dokan-control-label" for="dokan_support_btn_name"><?php esc_html_e( 'Support Button text', 'dokan' ); ?></label>
<div class="dokan-w5 dokan-text-left">
<input id="dokan_support_btn_name" value="<?php echo $support_text; ?>" name="dokan_support_btn_name" placeholder="<?php esc_html_e( 'Get Support', 'dokan' ); ?>" class="dokan-form-control" type="text">
</div>
</div>
<?php
}
/**
* Save support button text on store settings
*
* @param int $user_id
*/
public function save_supoort_btn_title( $user_id ) {
if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['_wpnonce'] ), 'dokan_store_settings_nonce' ) ) {
return;
}
$profile_info = dokan_get_store_info( $user_id );
if ( isset( $_POST['dokan_support_btn_name'] ) && isset( $_POST['support_checkbox_product'] ) ) {
$profile_info['show_support_btn_product'] = sanitize_text_field( wp_unslash( $_POST['support_checkbox_product'] ) );
update_user_meta( $user_id, 'dokan_profile_settings', $profile_info );
}
if ( isset( $_POST['dokan_support_btn_name'] ) && isset( $_POST['support_checkbox'] ) ) {
$profile_info['support_btn_name'] = sanitize_text_field( wp_unslash( $_POST['dokan_support_btn_name'] ) );
$profile_info['show_support_btn'] = sanitize_text_field( wp_unslash( $_POST['support_checkbox'] ) );
update_user_meta( $user_id, 'dokan_profile_settings', $profile_info );
}
}
/**
* Return counts for all topic status count
*
* @since 1.0
*
* @global $wpdb
*
* @param int $store_id
*
* @return array|null|object|bool $result
*/
public function topic_count( $store_id ) {
global $wpdb;
$cache_group = "store_support_{$store_id}";
$cache_key = 'topic_count';
$results = Cache::get( $cache_key, $cache_group );
if ( false === $results ) {
$where = apply_filters(
'dss_topic_count_where_clause',
"WHERE tpm.meta_key ='store_id' AND tpm.meta_value = $store_id"
);
$sql = "SELECT `post_status`, count(`ID`) as count
FROM {$wpdb->posts} as tp
LEFT JOIN {$wpdb->postmeta} as tpm
ON tp.ID = tpm.post_id
$where
GROUP BY tp.post_status";
$results = $wpdb->get_results( $sql );
Cache::set( $cache_key, $results, $cache_group );
}
if ( $results ) {
return $results;
}
return false;
}
/**
* Return counts for all ticket status count for customer
*
* @param int $customer_id
*
* @return array|null|object|bool $result
*@since 1.0
*
* @global $wpdb
*/
public function topic_count_by_customer( $customer_id ) {
global $wpdb;
$cache_group = "store_support_customer_{$customer_id}";
$cache_key = 'topic_count';
$results = Cache::get( $cache_key, $cache_group );
if ( false === $results ) {
$sql = "SELECT tp.post_status, COUNT(tp.ID) AS count
FROM {$wpdb->posts} AS tp
INNER JOIN {$wpdb->postmeta} AS pm
ON tp.ID = pm.post_id
WHERE tp.post_author = '$customer_id'
AND tp.post_type = '$this->post_type'
AND pm.meta_key = 'store_id'
AND pm.meta_value != ''
GROUP BY tp.post_status";
$results = $wpdb->get_results( $sql );
Cache::set( $cache_key, $results, $cache_group );
}
if ( $results ) {
return $results;
}
return false;
}
/**
* Generate support topic status list with count
*
* @since 1.0
*
* @return void
*/
public function support_topic_status_list( $seller = true ) {
if ( $seller ) {
$counts = $this->topic_count( dokan_get_current_user_id() );
$redir_url = dokan_get_navigation_url( 'support' );
} else {
$counts = $this->topic_count_by_customer( dokan_get_current_user_id() );
$redir_url = dokan_get_page_url( 'myaccount', 'woocommerce', 'support-tickets' );
}
$count = 0;
if ( $counts ) {
$count = wp_list_pluck( $counts, 'count', 'post_status' );
}
$defaults = [
'open' => 0,
'closed' => 0,
];
$count = wp_parse_args( $count, $defaults );
$open = number_format_i18n( (int) $count['open'] );
$closed = number_format_i18n( (int) $count['closed'] );
$all = number_format_i18n( (int) $count['open'] + (int) $count['closed'] );
$current_status = isset( $_GET['ticket_status'] ) ? sanitize_text_field( wp_unslash( $_GET['ticket_status'] ) ) : 'open'; // phpcs:ignore
?>
<ul class="dokan-support-topic-counts subsubsub">
<li <?php echo $current_status === 'all' ? 'class = "active"' : ''; ?>>
<a href="<?php echo add_query_arg( [ 'ticket_status' => 'all' ], $redir_url ); ?>"><?php echo __( 'All Tickets', 'dokan' ) . ' (' . $all . ')'; ?></a>
</li>
<li <?php echo $current_status === 'open' ? 'class = "active"' : ''; ?>>
<a href="<?php echo add_query_arg( [ 'ticket_status' => 'open' ], $redir_url ); ?>"><?php echo __( 'Open Tickets', 'dokan' ) . ' (' . $open . ')'; ?></a>
</li>
<li <?php echo $current_status === 'closed' ? 'class = "active"' : ''; ?>>
<a href="<?php echo add_query_arg( [ 'ticket_status' => 'closed' ], $redir_url ); ?>"><?php echo __( 'Closed Tickets', 'dokan' ) . ' (' . $closed . ')'; ?></a>
</li>
</ul>
<?php
}
/**
* Add Support ticket in My Account Menu
*
* @param array $items
*
* @return array $items
* @since 1.3.3
*/
public function place_support_menu( $items ) {
$counts = $this->topic_count_by_customer( dokan_get_current_user_id() );
$count = [];
if ( $counts ) {
$count = wp_list_pluck( $counts, 'count', 'post_status' );
}
$default = [
'open' => 0,
'closed' => 0,
];
$count = wp_parse_args( $count, $default );
$count_text = $count['open'] ? " ({$count['open']})" : '';
unset( $items['customer-logout'] );
$items['support-tickets'] = sprintf( '%s%s', __( 'Seller Support Tickets', 'dokan' ), $count_text );
$items['customer-logout'] = __( 'Logout', 'dokan' );
return $items;
}
/**
* Add capabilities
*
* @return array capabilities
*/
public function add_capabilities( $capabilities ) {
$capabilities['store_support'] = [
'dokan_manage_support_tickets' => __( 'Manage support ticket', 'dokan' ),
];
return $capabilities;
}
/**
* Add caps labels
*
* @since 3.0.0
*
* @param array $caps
*
* @return array
*/
public function add_caps_labels( $caps ) {
$caps['store_support'] = __( 'Store Support', 'dokan' );
return $caps;
}
/**
* Register widgets
*
* @since 2.8
*
* @return array $widgets
*/
public function register_widgets( $widgets ) {
$widgets['store_support'] = 'Dokan_Store_Support_Widget';
return $widgets;
}
/**
* Register store support endpoint on my-account page
*
* @since 2.9.17
*
* @return void
*/
public function register_support_tickets_endpoint() {
add_rewrite_endpoint( 'support-tickets', EP_PAGES );
}
/**
* Load support tickets content
*
* @since 2.9.17
*
* @return void
*/
public function support_tickets_content() {
dokan_get_template_part( 'store-support/support-tickets', '', [ 'is_store_support' => true ] );
}
/**
* Create module related class instances
*
* @since 3.5.0
*
* @return void
*/
private function instances() {
require_once DOKAN_STORE_SUPPORT_INC_DIR . '/Admin/class-admin-support.php';
require_once DOKAN_STORE_SUPPORT_INC_DIR . '/Admin/Dashboard.php';
require_once DOKAN_STORE_SUPPORT_INC_DIR . '/SettingsApi/Store.php';
new \Dokan_Admin_Support();
// Register Admin Dashboard page for Store Support
( new \WeDevs\DokanPro\Modules\StoreSupport\Admin\Dashboard() )->register_hooks();
new Store();
}
/**
* Load store support rest api class.
*
* @since 3.5.0
*
* @param array $class_map
*
* @return array $class_map
*/
public function rest_api_class_map( $class_map ) {
$store_support_controller_class = DOKAN_STORE_SUPPORT_INC_DIR . '/Rest/class-dokan-admin-store-support-rest-controller.php';
require_once $store_support_controller_class;
$class_map[ $store_support_controller_class ] = \AdminStoreSupportTicketController::class;
// Register vendor store support REST controller
$vendor_store_support_controller_class = DOKAN_STORE_SUPPORT_INC_DIR . '/Rest/class-dokan-vendor-store-support-rest-controller.php';
$customer_store_support_controller_class = DOKAN_STORE_SUPPORT_INC_DIR . '/Rest/CustomerStoreSupportTicketController.php';
$class_map[ $vendor_store_support_controller_class ] = \WeDevs\DokanPro\Modules\StoreSupport\Rest\VendorStoreSupportTicketController::class;
$class_map[ $customer_store_support_controller_class ] = \WeDevs\DokanPro\Modules\StoreSupport\Rest\CustomerStoreSupportTicketController::class;
return $class_map;
}
/**
* Load open support tickets count in the admin dashboard to-do data.
*
* @since 4.1.0
*
* @param array $data The existing to-do data.
*
* @return array The modified to-do data with open support tickets count.
*/
public function load_todo_support_tickets_count( array $data ): array {
$counts = \StoreSupportHelper::dokan_get_support_topics_status_count();
$data['open_support_tickets'] = [
'icon' => 'Headset',
'count' => $counts['open_topics'] ?? 0,
'title' => esc_html__( 'Open Support Tickets', 'dokan' ),
'redirect_url' => admin_url( 'admin.php?page=dokan#/admin-store-support' ),
'position' => 50,
];
return $data;
}
/**
* Load monthly support tickets count for the dashboard.
*
* @since 4.1.0
*
* @param array $data
* @param array $date_rage
*
* @return mixed
*/
public function load_monthly_support_tickets_count( $data, $date_range ) {
global $wpdb;
$results = $wpdb->get_row(
$wpdb->prepare(
"SELECT
SUM(CASE WHEN post_date BETWEEN %s AND %s THEN 1 ELSE 0 END) as current_count,
SUM(CASE WHEN post_date BETWEEN %s AND %s THEN 1 ELSE 0 END) as previous_count
FROM $wpdb->posts
WHERE post_type = 'dokan_store_support'
AND post_date BETWEEN %s AND %s",
$date_range['current_month_start'],
$date_range['current_month_end'],
$date_range['previous_month_start'],
$date_range['previous_month_end'],
$date_range['previous_month_start'],
$date_range['current_month_end']
)
);
$support_tickets_current = $results->current_count ?? 0;
$support_tickets_previous = $results->previous_count ?? 0;
// Apply filters to modify the support tickets data.
$data['support_tickets'] = apply_filters(
'dokan_dashboard_monthly_support_tickets_count',
[
'icon' => 'Tag',
'current' => (int) $support_tickets_current,
'previous' => (int) $support_tickets_previous,
'title' => esc_html__( 'Support Tickets', 'dokan' ),
'tooltip' => esc_html__( 'Support tickets raised in the time period', 'dokan' ),
'position' => 90,
]
);
return $data;
}
/**
* Search for support topics customer id and names
*
* @since 3.4.2
*
* @return AJAX Success/fail
*/
public function dokan_ajax_search_support_customers() {
$request_data = $_GET; // phpcs:ignore
if ( ! isset( $request_data['support_listing_nonce'] ) || ! wp_verify_nonce( sanitize_key( $request_data['support_listing_nonce'] ), 'dokan-support-listing-search' ) ) {
wp_send_json_error( __( 'Invalid nonce', 'dokan' ) );
}
global $wpdb;
$args = [
absint( dokan_get_current_user_id() ),
];
$like_clause = '';
if ( ! empty( $request_data['search'] ) ) {
$like_clause = 'AND u.display_name LIKE %s';
$args[] = '%' . $wpdb->esc_like( $request_data['search'] ) . '%';
}
$args[] = 10;
$sql_query = $wpdb->prepare(
"SELECT DISTINCT u.ID, u.display_name
FROM ( ( {$wpdb->prefix}posts AS p
INNER JOIN {$wpdb->prefix}users AS u
ON p.post_author=u.ID )
INNER JOIN {$wpdb->prefix}postmeta AS pm
ON p.ID=pm.post_id )
WHERE p.post_type='dokan_store_support'
AND pm.meta_key='store_id'
AND pm.meta_value=%d {$like_clause}
LIMIT %d",
$args
);
$results = $wpdb->get_results( $sql_query );
wp_send_json_success( $results );
}
}