Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 104 additions & 39 deletions includes/Vendor/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@
*/
class Manager {

/**
* The statuses the vendor listing knows how to filter on.
*
* @since DOKAN_SINCE
*
* @var string[]
*/
const STATUSES = [ 'all', 'approved', 'pending' ];

/**
* Total vendors found
*
Expand All @@ -37,6 +46,10 @@
/**
* Get vendors
*
* `status` accepts 'all', 'approved' or 'pending' (string or array); asking for both halves
* means everyone and anything unrecognised falls back to 'approved'. Pending is applied
* through the `dokan_pending_only` query var, which `exclude_approved_vendors()` acts on.
*
* @param array $args
*
* @return array
Expand All @@ -52,37 +65,25 @@
'order' => 'ASC',
'status' => [ 'approved' ],
'featured' => '', // yes or no
'meta_query' => [],

Check warning on line 68 in includes/Vendor/Manager.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Detected usage of meta_query, possible slow query.
'fields' => 'all',
];

$args = wp_parse_args( $args, $defaults );

$status = (array) $args['status'];
$status = $this->resolve_status( $args['status'] );

$meta_query = [ 'relation' => 'OR' ];

foreach ( $status as $stat ) {
if ( $stat === 'all' ) {
continue;
}

$meta_query[] = [
if ( 'approved' === $status ) {
$args['meta_query']['relation'] = 'AND';
$args['meta_query'][] = [
'key' => 'dokan_enable_selling',
'value' => ( $stat == 'approved' ) ? 'yes' : 'no',
'value' => 'yes',
'compare' => '=',
];
}

if ( ! empty( $args['meta_query'] ) ) {
$args['meta_query']['relation'] = 'AND';
$args['meta_query'][] = $meta_query;
} else {
$args['meta_query'] = $meta_query;
}

// if featured
if ( 'yes' == $args['featured'] ) {
if ( 'yes' === $args['featured'] ) {
$args['meta_query']['relation'] = 'AND';
$args['meta_query'][] = [
'key' => 'dokan_feature_seller',
Expand All @@ -94,6 +95,17 @@
unset( $args['status'] );
unset( $args['featured'] );

// Pending is everyone not approved, a missing flag included, exactly as the status counters and dokan_is_seller_enabled() read it.
if ( 'pending' === $status ) {
// Carried into the query so the callback can tell our query from any other one running inside the same hook.
$args['dokan_pending_only'] = true;
Comment thread
MdAsifHossainNadim marked this conversation as resolved.

// Hooked once and left in place: it is a no-op without the query var, and unhooking it around the query let a nested listing disarm the outer one.
if ( ! has_action( 'pre_user_query', [ $this, 'exclude_approved_vendors' ] ) ) {
add_action( 'pre_user_query', [ $this, 'exclude_approved_vendors' ] );
}
}

$user_query = new WP_User_Query( $args );
$results = $user_query->get_results();

Expand All @@ -110,6 +122,57 @@
return $vendors;
}

/**
* Collapse the requested statuses into the single filter the query applies.
*
* Only 'all', 'approved' and 'pending' are understood. Asking for both halves — or for 'all'
* outright — means everyone. Anything else names no status this listing can filter on, so it
* falls back to the default rather than widening the result, the same way
* `Abilities\Definitions\VendorsQuery::resolve_status()` coerces an unknown status.
*
* @since DOKAN_SINCE
*
* @param string|string[] $status
*
* @return string One of 'all', 'approved' or 'pending'.
*/
protected function resolve_status( $status ): string {
$known = array_values( array_unique( array_intersect( (array) $status, self::STATUSES ) ) );

// Never let a typo read as a wider set than the caller asked for.
if ( empty( $known ) ) {
return 'approved';
}

return 1 === count( $known ) ? $known[0] : 'all';
}

/**
* Drop every approved vendor from a user query that asked for pending ones only.
*
* A correlated NOT EXISTS rides the usermeta index and stops at the first match per row.
*
* @since DOKAN_SINCE
*
* @param \WP_User_Query $query
*
* @return void
*/
public function exclude_approved_vendors( $query ) {
global $wpdb;

// Every user query on the site passes through here once hooked, so only the one that asked for pending gets the clause.
if ( ! $query->get( 'dokan_pending_only' ) ) {
return;
}

$query->query_where .= $wpdb->prepare(
" AND NOT EXISTS ( SELECT 1 FROM {$wpdb->usermeta} WHERE user_id = {$wpdb->users}.ID AND meta_key = %s AND meta_value = %s )",
'dokan_enable_selling',
'yes'
);
}

/**
* Get total user according to query
*
Expand Down Expand Up @@ -168,26 +231,28 @@
/**
* @since 3.2.7 added $data parameter
*/
$store_data = apply_filters( 'dokan_vendor_create_data', [
'store_name' => ! empty( $data['store_name'] ) ? $data['store_name'] : '',
'social' => ! empty( $data['social'] ) ? $data['social'] : [],
'payment' => ! empty( $data['payment'] ) ? $data['payment'] : [
'paypal' => [ 'email' ],
'bank' => [],
],
'phone' => ! empty( $data['phone'] ) ? $data['phone'] : '',
'show_email' => ! empty( $data['show_email'] ) ? $data['show_email'] : 'no',
'address' => ! empty( $data['address'] ) ? $data['address'] : [],
'location' => ! empty( $data['location'] ) ? $data['location'] : '',
'banner' => ! empty( $data['banner_id'] ) ? $data['banner_id'] : 0,
'icon' => ! empty( $data['icon'] ) ? $data['icon'] : '',
'gravatar' => ! empty( $data['gravatar_id'] ) ? $data['gravatar_id'] : 0,
'enable_tnc' => ! empty( $data['enable_tnc'] ) ? $data['enable_tnc'] : 'off',
'store_tnc' => ! empty( $data['store_tnc'] ) ? $data['store_tnc'] : '',
'show_min_order_discount' => ! empty( $data['show_min_order_discount'] ) ? $data['show_min_order_discount'] : 'no',
'store_seo' => ! empty( $data['store_seo'] ) ? $data['store_seo'] : [],
'dokan_store_time' => ! empty( $data['store_open_close'] ) ? $data['store_open_close'] : [],
], $data );
$store_data = apply_filters(
'dokan_vendor_create_data', [
'store_name' => ! empty( $data['store_name'] ) ? $data['store_name'] : '',
'social' => ! empty( $data['social'] ) ? $data['social'] : [],
'payment' => ! empty( $data['payment'] ) ? $data['payment'] : [
'paypal' => [ 'email' ],
'bank' => [],
],
'phone' => ! empty( $data['phone'] ) ? $data['phone'] : '',
'show_email' => ! empty( $data['show_email'] ) ? $data['show_email'] : 'no',
'address' => ! empty( $data['address'] ) ? $data['address'] : [],
'location' => ! empty( $data['location'] ) ? $data['location'] : '',
'banner' => ! empty( $data['banner_id'] ) ? $data['banner_id'] : 0,
'icon' => ! empty( $data['icon'] ) ? $data['icon'] : '',
'gravatar' => ! empty( $data['gravatar_id'] ) ? $data['gravatar_id'] : 0,
'enable_tnc' => ! empty( $data['enable_tnc'] ) ? $data['enable_tnc'] : 'off',
'store_tnc' => ! empty( $data['store_tnc'] ) ? $data['store_tnc'] : '',
'show_min_order_discount' => ! empty( $data['show_min_order_discount'] ) ? $data['show_min_order_discount'] : 'no',
'store_seo' => ! empty( $data['store_seo'] ) ? $data['store_seo'] : [],
'dokan_store_time' => ! empty( $data['store_open_close'] ) ? $data['store_open_close'] : [],
], $data
);

$vendor = dokan()->vendor->get( $vendor_id );

Expand Down Expand Up @@ -383,7 +448,7 @@

// for backward compatibility we'll allow both `enable_tnc` and `toc_enabled` to set store trams and condition settings
if ( ( isset( $data['enable_tnc'] ) && dokan_validate_boolean( $data['enable_tnc'] ) )
|| ( isset( $data['toc_enabled'] ) && dokan_validate_boolean( $data['toc_enabled'] ) ) ) {
|| ( isset( $data['toc_enabled'] ) && dokan_validate_boolean( $data['toc_enabled'] ) ) ) {
$vendor->set_enable_tnc( 'on' );
} else {
$vendor->set_enable_tnc( 'off' );
Expand Down
16 changes: 7 additions & 9 deletions includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,7 @@
*
* @return string
*/
function dokan_posted_input( $key, $array = false ) {

Check warning on line 823 in includes/functions.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

It is recommended not to use reserved keyword "array" as function parameter name. Found: $array

Check warning on line 823 in includes/functions.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

The method parameter $array is never used

Check warning on line 823 in includes/functions.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

The method parameter $key is never used
wc_deprecated_function( 'dokan_posted_input', '3.6.6' );

return '';
Expand All @@ -833,7 +833,7 @@
*
* @return string
*/
function dokan_posted_textarea( $key ) {

Check warning on line 836 in includes/functions.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

The method parameter $key is never used
wc_deprecated_function( 'dokan_posted_textarea', '3.6.6' );

return '';
Expand Down Expand Up @@ -930,7 +930,7 @@
*
* @return string
*/
function dokan_locate_template( $template_name, $template_path = '', $default_path = '', $pro = false ) {

Check warning on line 933 in includes/functions.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

The method parameter $pro is never used
if ( ! $template_path ) {
$template_path = dokan()->template_path();
}
Expand Down Expand Up @@ -1500,7 +1500,7 @@
$now = dokan_current_datetime();
$inactive_sellers = dokan_get_sellers(
[
'number' => - 1,
'number' => 1, // Only the total is read; one row keeps this from building a Vendor object per pending seller.
Comment thread
MdAsifHossainNadim marked this conversation as resolved.
'status' => 'pending',
]
);
Expand Down Expand Up @@ -1993,7 +1993,7 @@
*
* @return string maybe modified url
*/
function dokan_get_avatar_url( $url, $id_or_email, $args ) {

Check warning on line 1996 in includes/functions.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

The method parameter $args is never used
if ( is_numeric( $id_or_email ) ) {
$user = get_user_by( 'id', $id_or_email );
} elseif ( is_object( $id_or_email ) ) {
Expand Down Expand Up @@ -2666,7 +2666,7 @@
*
* @return int $commission_rate
*/
function dokan_get_category_wise_seller_commission( $product_id, $category_id = 0 ) {

Check warning on line 2669 in includes/functions.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

The method parameter $category_id is never used

Check warning on line 2669 in includes/functions.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

The method parameter $product_id is never used
wc_deprecated_function( __FUNCTION__, '3.14.0' );

return 0;
Expand All @@ -2683,7 +2683,7 @@
*
* @return int $commission_rate
*/
function dokan_get_category_wise_seller_commission_type( $product_id, $category_id = 0 ) {

Check warning on line 2686 in includes/functions.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

The method parameter $product_id is never used
wc_deprecated_function( __FUNCTION__, '3.14.0' );

return '';
Expand Down Expand Up @@ -3484,14 +3484,12 @@
/**
* Count the vendors that are waiting for admin approval.
*
* Delegates to the very query the Vendors list is built from instead of reusing
* `dokan_get_seller_status_count()['inactive']`. That figure is derived as
* "everything that is not approved", so it also counts users carrying no
* `dokan_enable_selling` meta at all — every administrator, for one, since
* `dokan_admin_user_register()` only writes that meta for the `seller` role. The
* listing matches on `dokan_enable_selling = 'no'` and therefore leaves those users
* out, so a count taken from `inactive` is one an admin can never clear: the page it
* points at has nothing pending to show.
* Delegates to the very query the Vendors list is built from, so the badge can never
* claim a count the Pending tab is unable to show. Both read a missing
* `dokan_enable_selling` flag as pending, as `dokan_is_seller_enabled()`,
* `dokan_get_seller_status_count()` and the Users-screen "Pending Vendors" filter all
* do. That includes an administrator who never touched the seller fields, since
* `dokan_admin_user_register()` only writes the flag for the `seller` role.
*
* Cached in the shared `vendors` group, which VendorCache already invalidates on
* vendor create/update/delete and on enable/disable.
Expand Down
Loading
Loading