File: /storage/v4513/tepnot/public_html/wp-content/plugins/dokan-pro/includes/Announcement/Manager.php
<?php
namespace WeDevs\DokanPro\Announcement;
use DateTimeZone;
use stdClass;
use WeDevs\Dokan\Cache;
use WP_Error;
use WP_Post;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class Manager {
/**
* @since 3.9.4
*
* @var string $post_table
*/
private $post_table;
/**
* @since 3.9.4
*
* @var string $announcement_table
*/
private $announcement_table;
/**
* Manager constructor.
*
* @since 3.9.4
*/
public function __construct() {
global $wpdb;
$this->post_table = $wpdb->prefix . 'posts';
$this->announcement_table = $wpdb->prefix . 'dokan_announcement';
}
/**
* Get announcement
*
* @since 3.9.4
*
* @param array $args
*
* @return int|Single[]|int[]|WP_Error
*/
public function all( $args = [] ) {
$defaults = [
'id' => 0, // this is announcement id
'notice_id' => 0, // this is single vendor notice id
'vendor_id' => 0,
'page' => 1,
'per_page' => apply_filters( 'dokan_announcement_list_number', 10 ),
'search' => '',
'status' => 'all', // publish, future, draft
'read_status' => 'all', // read, unread
'from' => '',
'to' => '',
'return' => 'all', // all, count, ids
];
$args = wp_parse_args( $args, $defaults );
global $wpdb;
$fields = '';
$from = "$this->post_table AS p";
$join = '';
$where = ' AND p.post_type = %s';
$inner_where = '';
$groupby = '';
$orderby = ' p.post_date DESC';
$limits = '';
$query_args = [ 1, 1, 'dokan_announcement' ];
$status = '';
if ( 'ids' === $args['return'] ) {
$fields = 'p.ID';
} elseif ( 'count' === $args['return'] ) {
$fields = 'COUNT(p.ID)';
} else {
$fields = 'p.ID AS id, p.post_title AS title, p.post_content AS content, p.post_status as status, p.post_date_gmt AS date_gmt, p.post_date AS date';
}
if ( ! empty( $args['id'] ) ) {
$where .= ' AND p.ID = %d';
$query_args[] = absint( $args['id'] );
$args['page'] = 1;
$args['per_page'] = 1;
}
if ( ! empty( $args['vendor_id'] ) ) {
$fields .= ', a.id as notice_id, a.user_id as vendor_id, a.status AS read_status';
$join .= "INNER JOIN $this->announcement_table AS a ON p.ID = a.post_id";
$where .= ' AND a.user_id = %d AND a.status != %s';
$query_args[] = absint( $args['vendor_id'] );
$query_args[] = 'trash';
}
if ( ! empty( $args['vendor_id'] ) && ! empty( $args['notice_id'] ) ) {
$where .= ' AND a.id = %d';
$query_args[] = absint( $args['notice_id'] );
$args['page'] = 1;
$args['per_page'] = 1;
}
if ( ! empty( $args['vendor_id'] ) && in_array( $args['read_status'], [ 'read', 'unread' ], true ) ) {
$where .= ' AND a.status = %s';
$query_args[] = $args['read_status'];
}
if ( ! empty( $args['status'] ) && in_array( $args['status'], [ 'publish', 'pending', 'draft', 'future', 'trash' ], true ) ) {
$where .= ' AND p.post_status = %s';
$query_args[] = $args['status'];
} elseif ( empty( $args['status'] ) || ( ! empty( $args['status'] ) && 'trash' === $args['status'] ) ) {
$where .= ' AND p.post_status != %s';
$query_args[] = 'trash';
}
if ( ! empty( $args['search'] ) ) {
$search = trim( sanitize_text_field( $args['search'] ) );
$like = '%' . $wpdb->esc_like( $search ) . '%';
$where .= $wpdb->prepare( ' AND ( p.post_title LIKE %s OR p.post_content LIKE %s )', $like, $like );
}
$now = dokan_current_datetime();
$from_date = '';
if ( ! empty( $args['from'] ) ) {
$from_date = $now->modify( $args['from'] );
$from_date = $from_date ? $from_date->setTimezone( new DateTimeZone( 'UTC' ) )->setTime( 0, 0, 0 )->format( 'Y-m-d H:i:s' ) : '';
}
$to_date = '';
if ( ! empty( $args['to'] ) ) {
$to_date = $now->modify( $args['to'] );
$to_date = $to_date ? $to_date->setTimezone( new DateTimeZone( 'UTC' ) )->setTime( 23, 59, 59 )->format( 'Y-m-d H:i:s' ) : '';
}
if ( ! empty( $from_date ) && ! empty( $to_date ) ) {
$where .= ' AND ( p.post_date_gmt BETWEEN %s AND %s )';
$query_args[] = $from_date;
$query_args[] = $to_date;
} elseif ( ! empty( $from_date ) ) {
$where .= ' AND p.post_date_gmt >= %s';
$query_args[] = $from_date;
} elseif ( ! empty( $to_date ) ) {
$where .= ' AND p.post_date_gmt <= %s';
$query_args[] = $to_date;
}
// pagination param
if ( 'count' !== $args['return'] && ! empty( $args['per_page'] ) && - 1 !== intval( $args['per_page'] ) ) {
$limit = absint( $args['per_page'] );
$page = absint( $args['page'] );
$page = $page ? $page : 1;
$offset = ( $page - 1 ) * $limit;
$limits = 'LIMIT %d, %d';
$query_args[] = $offset;
$query_args[] = $limit;
}
$cache_group = 'announcement'; // caching for admin announcement lists
if ( ! empty( $args['vendor_id'] ) ) {
$cache_group = "seller_announcement_{$args['vendor_id']}"; // caching for seller announcement lists
}
$cache_key = 'get_announcement_' . md5( wp_json_encode( $args ) );
$results = Cache::get( $cache_key, $cache_group );
if ( false === $results && 'count' === $args['return'] ) {
// @codingStandardsIgnoreStart
$results = (int) $wpdb->get_var(
$wpdb->prepare(
"SELECT $fields FROM $from $join WHERE %d=%d $where",
$query_args
)
);
// @codingStandardsIgnoreEnd
if ( $wpdb->last_error ) {
// database query error
$db_error = $wpdb->last_error;
$error_message = sprintf(
'%1$s %2$s',
__( 'Announcement: Something went wrong while querying data.', 'dokan' ),
current_user_can( 'manage_options' ) ? ': ' . $db_error : ''
);
return new WP_Error( 'announcement_count_db_error', $error_message );
}
// store on cache
Cache::set( $cache_key, $results, $cache_group );
} elseif ( false === $results && 'ids' === $args['return'] ) {
// @codingStandardsIgnoreStart
$results = $wpdb->get_col(
$wpdb->prepare(
"SELECT $fields FROM $from $join WHERE %d=%d $where $groupby ORDER BY $orderby $limits",
$query_args
)
);
// @codingStandardsIgnoreEnd
if ( $wpdb->last_error ) { // get_col returns empty array in case of error or no result
// database query error
$db_error = $wpdb->last_error;
$error_message = sprintf(
'%1$s %2$s',
__( 'Announcement: Something went wrong while querying data.', 'dokan' ),
current_user_can( 'manage_options' ) ? ': ' . $db_error : ''
);
return new WP_Error( 'announcement_db_error', $error_message );
}
// store on cache
Cache::set( $cache_key, $results, $cache_group );
} elseif ( false === $results ) {
// @codingStandardsIgnoreStart
$data = $wpdb->get_results(
$wpdb->prepare(
"SELECT $fields FROM $from $join WHERE %d=%d $where $groupby ORDER BY $orderby $limits",
$query_args
),
ARRAY_A
);
// @codingStandardsIgnoreEnd
if ( $wpdb->last_error ) {
// database query error
$db_error = $wpdb->last_error;
$error_message = sprintf(
'%1$s %2$s',
__( 'Announcement: Something went wrong while querying data.', 'dokan' ),
current_user_can( 'manage_options' ) ? ': ' . $db_error : ''
);
return new WP_Error( 'announcement_count_db_error', $error_message );
}
$results = [];
if ( ! empty( $data ) && 1 === (int) $args['per_page'] ) {
// we need to return a single object
$data = reset( $data );
$results = new Single( $data );
} elseif ( ! empty( $data ) ) {
foreach ( $data as $single ) {
$results[] = new Single( $single );
}
}
// store on cache
Cache::set( $cache_key, $results, $cache_group );
}
return $results;
}
/**
* Get a single announcement
*
* @since 3.9.4
*
* @param int $id
*
* @return Single|WP_Error
*/
public function get_single_announcement( $id ) {
$args = [
'id' => $id,
'return' => 'all',
];
$result = $this->all( $args );
if ( is_wp_error( $result ) ) {
return $result;
}
if ( empty( $result ) ) {
return new WP_Error( 'no_announcement', __( 'No announcement found with given id.', 'dokan' ) );
}
return $result;
}
/**
* Get a single announcement
*
* @since 3.9.4
*
* @param int $id
*
* @return string[]|WP_Error
*/
public function get_pagination_data( $args = [] ) {
$args['return'] = 'count';
$total = $this->all( $args );
if ( is_wp_error( $total ) ) {
return [
'total_count' => 0,
'per_page' => $args['per_page'],
'total_pages' => 0,
];
}
$per_page = $args['per_page'];
$per_page = $per_page > 0 ? $per_page : 10;
$total_page = ceil( $total / $per_page );
return [
'total_count' => $total,
'per_page' => $per_page,
'total_pages' => $total_page,
];
}
/**
* Create announcement
*
* @since 3.9.4
*
* @param array $args
* @param bool $update
*
* @return int|WP_Error
*/
public function create_announcement( $args = [], $update = false ) {
if ( empty( trim( $args['title'] ) ) ) {
return new WP_Error( 'no_title', __( 'Announcement title is required.', 'dokan' ) );
}
$data = [
'post_title' => sanitize_text_field( $args['title'] ),
'post_content' => ! empty( $args['content'] ) ? wp_kses_post( $args['content'] ) : '',
'post_status' => ! empty( $args['status'] ) ? $args['status'] : 'draft',
'post_type' => 'dokan_announcement',
'post_author' => isset( $args['author'] ) ? absint( $args['author'] ) : get_current_user_id(),
];
if ( ! empty( $args['date'] ) ) {
$data['post_date'] = $args['date'];
}
// if an announcement is `scheduled`, but want to publish it now
// and set post_date_gmt to `0000-00-00 00:00:00`
if ( ! empty( $args['date_gmt'] ) ) {
$data['post_date_gmt'] = $args['date_gmt'];
}
if ( ! $update ) {
$post_id = wp_insert_post( $data );
} else {
$data['ID'] = $args['id'];
$post_id = wp_update_post( $data );
}
if ( is_wp_error( $post_id ) ) {
return $post_id;
}
$announcement_type = ! empty( $args['announcement_type'] ) ? $args['announcement_type'] : 'all_seller';
$sender_ids = ! empty( $args['sender_ids'] ) ? $args['sender_ids'] : [];
$assigned_sellers = ! empty( $args['sender_ids'] ) ? $args['sender_ids'] : [];
$announcement_types = apply_filters( 'dokan_announcement_seller_types', [ 'all_seller', 'enabled_seller', 'disabled_seller', 'featured_seller' ] );
if ( 'selected_seller' !== $announcement_type && in_array( $announcement_type, $announcement_types, true ) ) {
$seller_args = [
'fields' => 'ID',
'number' => -1,
];
switch ( $announcement_type ) {
case 'enabled_seller':
$seller_args['status'] = [ 'approved' ];
break;
case 'disabled_seller':
$seller_args['status'] = [ 'pending' ];
break;
case 'featured_seller':
$seller_args['featured'] = 'yes';
break;
default:
$seller_args['status'] = [ 'all' ];
}
$assigned_sellers = dokan()->vendor->all( $seller_args );
}
// Remove excluded sellers ids
if ( ! empty( $args['exclude_seller_ids'] ) && is_array( $args['exclude_seller_ids'] ) ) {
$assigned_sellers = array_diff( $assigned_sellers, $args['exclude_seller_ids'] );
}
$this->process_seller_announcement_data( $assigned_sellers, $post_id );
update_post_meta( $post_id, '_announcement_type', $announcement_type );
update_post_meta( $post_id, '_announcement_selected_user', $assigned_sellers );
do_action( 'dokan_after_announcement_saved', $post_id, $assigned_sellers );
// clear cache
dokan_pro()->announcement->delete_announcement_cache( $assigned_sellers, $post_id );
return $post_id;
}
/**
* Process seller announcement data
*
* @since 2.1
* @since 3.9.4 rewritten some logic
*
* @param array $announcement_seller
* @param integer $announcment_id
*
* @return void
*/
protected function process_seller_announcement_data( $announcement_seller, $announcment_id ) {
// delete old cache
dokan_pro()->announcement->delete_announcement_cache( $announcement_seller );
$db = $this->get_assigned_seller_from_db( $announcment_id );
$sellers = $announcement_seller;
$existing_seller = $new_seller = $del_seller = []; // phpcs:ignore
foreach ( $sellers as $seller ) {
if ( in_array( $seller, $db, true ) ) {
$existing_seller[] = $seller;
} else {
$new_seller[] = $seller;
}
}
$del_seller = array_diff( $db, $existing_seller );
if ( $del_seller ) {
$this->delete_assigned_seller( $del_seller, $announcment_id );
}
if ( $new_seller ) {
$this->insert_assigned_seller( $new_seller, $announcment_id );
}
}
/**
* Get assign seller
*
* @since 2.1
*
* @param int $announcment_id
* @param bool $exclude_trash
*
* @return int[]|stdClass[]
*/
public function get_assigned_seller_from_db( $announcment_id, $exclude_trash = false ) {
global $wpdb;
$status_where = $exclude_trash ? " AND status != 'trash'" : '';
// @codingStandardsIgnoreStart
return $wpdb->get_col(
$wpdb->prepare(
"SELECT user_id FROM {$this->announcement_table} WHERE `post_id`= %d $status_where",
$announcment_id
)
);
// @codingStandardsIgnoreEnd
}
/**
* Insert assigned seller
*
* @since 2.1
*
* @param int[] $seller_array
* @param int $announcment_id
*
* @return void
*/
protected function insert_assigned_seller( $seller_array, $announcment_id ) {
global $wpdb;
$values = '';
$i = 0;
foreach ( $seller_array as $seller_id ) {
$sep = ( $i === 0 ) ? '' : ',';
$values .= sprintf( "%s ( %d, %d, '%s')", $sep, $seller_id, $announcment_id, 'unread' );
++$i;
}
// @codingStandardsIgnoreStart
$sql = "INSERT INTO {$this->announcement_table} (`user_id`, `post_id`, `status` ) VALUES $values";
$wpdb->query( $sql );
// @codingStandardsIgnoreEnd
}
/**
* Delete assign seller
*
* @since 2.1
*
* @param int[] $seller_array
* @param int $announcment_id
*
* @return void
*/
protected function delete_assigned_seller( $seller_array, $announcment_id ) {
if ( ! is_array( $seller_array ) ) {
return;
}
global $wpdb;
$values = '';
$i = 0;
foreach ( $seller_array as $seller_id ) {
$sep = ( $i === 0 ) ? '' : ',';
$values .= sprintf( '%s( %d, %d )', $sep, $seller_id, $announcment_id );
++$i;
}
// @codingStandardsIgnoreStart
$sql = "DELETE FROM {$this->announcement_table} WHERE (`user_id`, `post_id` ) IN ($values)";
if ( $values ) {
$wpdb->query( $sql );
}
// @codingStandardsIgnoreEnd
}
/**
* Delete a single announcement
*
* @since 3.9.4
*
* @param int $id
* @param bool $force
*
* @return WP_Post|WP_Error Post data on success, WP_Error on failure.
*/
public function delete_announcement( $id, $force = false ) {
$announcement = $this->get_single_announcement( $id );
$supports_trash = apply_filters( 'dokan_announcement_trashable', ( EMPTY_TRASH_DAYS > 0 ), $announcement );
// delete individual announcement cache
dokan_pro()->announcement->delete_announcement_cache( [], $id );
// If we're forcing, then delete permanently.
if ( $force ) {
$result = wp_delete_post( $id, true );
if ( $result ) {
$this->delete_announcement_data( $id );
} else {
$result = new WP_Error( 'delete_announcement_error', __( 'Error while deleting announcement.', 'dokan' ) );
}
return $result;
}
// If we don't support trashing for this type, error out.
if ( ! $supports_trash ) {
/* translators: %s: force=true */
return new WP_Error( 'announcement_trash_not_supported', sprintf( __( "The post does not support trashing. Set '%s' to delete.", 'dokan' ), 'force=true' ), [ 'status' => 501 ] );
}
// Otherwise, only trash if we haven't already.
if ( 'trash' === $announcement->get_status() ) {
return new WP_Error( 'announcement_already_trashed', __( 'The announcement has already been trashed.', 'dokan' ), [ 'status' => 410 ] );
}
// (Note that internally this falls through to `wp_delete_post` if
// the trash is disabled.)
$result = wp_trash_post( $id );
if ( ! $result ) {
return new WP_Error( 'delete_announcement_error', __( 'Error while adding announcement to trash.', 'dokan' ) );
}
return $result;
}
/**
* Delete announcement relational table data
*
* @since 2.8.2
*
* @return void
*/
protected function delete_announcement_data( $post_id ) {
global $wpdb;
$wpdb->delete( $this->announcement_table, [ 'post_id' => $post_id ], [ '%d' ] );
}
/**
* Trash a single announcement
*
* @since 3.9.4
*
* @param int $announcement_id
*
* @return WP_Post|WP_Error Post data on success, WP_Error on failure.
*/
public function untrash_announcement( $announcement_id ) {
$result = wp_untrash_post( $announcement_id );
if ( ! $result ) {
return new WP_Error( 'untrash_announcement_error', __( 'Error in untrashing announcement.', 'dokan' ) );
}
// delete individual announcement cache
dokan_pro()->announcement->delete_announcement_cache( [], $announcement_id );
return $result;
}
/**
* Get a single notice
*
* @since 3.9.4
*
* @param int $notice_id
*
* @return Single|WP_Error
*/
public function get_notice( $notice_id, $vendor_id = null ) {
$vendor_id = $vendor_id ? $vendor_id : dokan_get_current_user_id();
$notice = $this->all(
[
'notice_id' => $notice_id,
'vendor_id' => $vendor_id,
'return' => 'all',
]
);
if ( is_wp_error( $notice ) ) {
return $notice;
}
if ( empty( $notice ) ) {
return new WP_Error( 'no_notice', __( 'No notice found with given id.', 'dokan' ) );
}
return $notice;
}
/**
* Update notice read status
*
* @since 3.9.4
*
* @param int $notice_id
* @param string $read_status read,unread,trash
* @param int $vendor_id vendor id is required to ensure that the request is coming from the same vendor
*
* @return bool|WP_Error true on success, WP_Error on failure.
*/
public function update_read_status( $notice_id, $read_status, $vendor_id = null ) {
global $wpdb;
$vendor_id = $vendor_id ? $vendor_id : dokan_get_current_user_id();
// get notice data
$notice = $this->get_notice( $notice_id, $vendor_id );
if ( is_wp_error( $notice ) ) {
return $notice;
}
$updated = $wpdb->update(
$this->announcement_table,
[
'status' => $read_status,
],
[
'id' => $notice_id,
'user_id' => $vendor_id,
],
[ '%s' ],
[ '%d', '%d' ]
);
if ( false === $updated ) {
return new WP_Error( 'update_notice_error', __( 'Error while updating notice status.', 'dokan' ) );
}
// clear cache
dokan_pro()->announcement->delete_announcement_cache( [ $vendor_id ], $notice->get_notice_id() );
return true;
}
/**
* Delete a single notice
*
* @param int $notice_id
* @param int|null $vendor_id
*
* @return bool|WP_Error true on success, WP_Error on failure.
*/
public function delete_notice( $notice_id, $vendor_id = null ) {
global $wpdb;
$vendor_id = $vendor_id ? $vendor_id : dokan_get_current_user_id();
// get notice data
$notice = $this->get_notice( $notice_id, $vendor_id );
if ( is_wp_error( $notice ) ) {
return $notice;
}
$result = $wpdb->delete(
$this->announcement_table, [
'id' => $notice_id,
'user_id' => $vendor_id,
], [ '%d', '%d' ]
);
if ( false === $result ) {
return new WP_Error( 'update_notice_error', __( 'Error while deleting notice status.', 'dokan' ) );
}
// clear cache
dokan_pro()->announcement->delete_announcement_cache( [ $vendor_id ], $notice->get_id() );
return true;
}
}