From f8d4fe46a149809cfa1a77326028cb9b17f0ce92 Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Thu, 6 Aug 2026 00:30:46 +0600 Subject: [PATCH 01/21] feat(order): add prepaid status --- includes/enums/order/status.php | 4 +++- includes/payments/functions.php | 1 + includes/repositories/order-repository.php | 3 ++- .../Version1/class-orders-controller.php | 2 ++ includes/setup/activation.php | 24 ++++++++++++++++++- 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/includes/enums/order/status.php b/includes/enums/order/status.php index b67531f9d8..c4ee9bd76c 100644 --- a/includes/enums/order/status.php +++ b/includes/enums/order/status.php @@ -6,6 +6,7 @@ class Status { const PENDING = 'pending'; + const PREPAID = 'prepaid'; const PAID = 'paid'; const FAILED = 'failed'; const CANCELLED = 'cancelled'; @@ -16,6 +17,7 @@ class Status { public static function all() { return [ self::PENDING, + self::PREPAID, self::PAID, self::FAILED, self::CANCELLED, @@ -24,4 +26,4 @@ public static function all() { self::UNPAID, ]; } -} \ No newline at end of file +} diff --git a/includes/payments/functions.php b/includes/payments/functions.php index 73106870b8..5cb3386b4c 100644 --- a/includes/payments/functions.php +++ b/includes/payments/functions.php @@ -45,6 +45,7 @@ function atbdp_get_payment_statuses() { $statuses = [ 'created' => __( "Created", 'directorist' ), 'pending' => __( "Pending", 'directorist' ), + 'prepaid' => __( "Prepaid", 'directorist' ), 'completed' => __( "Completed", 'directorist' ), 'failed' => __( "Failed", 'directorist' ), 'cancelled' => __( "Cancelled", 'directorist' ), diff --git a/includes/repositories/order-repository.php b/includes/repositories/order-repository.php index 67b9ebc600..9a4265dd95 100644 --- a/includes/repositories/order-repository.php +++ b/includes/repositories/order-repository.php @@ -11,6 +11,7 @@ use Directorist\Helpers\DateTime; use Directorist\DTO\Order\DTO; use Directorist\Enums\Order\Status as OrderStatus; +use Directorist\Enums\Payment\Status as PaymentStatus; use Directorist\Enums\Order\TaxType as OrderTaxType; use Directorist\Enums\Order\DiscountType as OrderDiscountType; use Directorist\DTO\Order\Read; @@ -169,7 +170,7 @@ public function update( \Directorist\Utils\DTO $dto ) { do_action( 'directorist_after_order_update', $this->to_dto( $updated_order ), $old_order ); - if ( $dto->is_initialized( 'status' ) ) { + if ( $dto->is_initialized( 'status' ) && in_array( $dto->get_status(), PaymentStatus::all(), true ) ) { ( new PaymentRepository )->update_status_by_order_id( $dto->get_id(), $dto->get_status() ); } diff --git a/includes/rest-api/Version1/class-orders-controller.php b/includes/rest-api/Version1/class-orders-controller.php index 4058166c37..afbea5c885 100644 --- a/includes/rest-api/Version1/class-orders-controller.php +++ b/includes/rest-api/Version1/class-orders-controller.php @@ -305,6 +305,7 @@ protected function legacy_status_to_current_status( string $status ): string { $map = array( 'created' => OrderStatus::PENDING, 'pending' => OrderStatus::PENDING, + 'prepaid' => OrderStatus::PREPAID, 'completed' => OrderStatus::PAID, 'failed' => OrderStatus::FAILED, 'cancelled' => OrderStatus::CANCELLED, @@ -317,6 +318,7 @@ protected function legacy_status_to_current_status( string $status ): string { protected function current_status_to_legacy_status( string $status ): string { $map = array( OrderStatus::PENDING => 'pending', + OrderStatus::PREPAID => 'prepaid', OrderStatus::PAID => 'completed', OrderStatus::FAILED => 'failed', OrderStatus::CANCELLED => 'cancelled', diff --git a/includes/setup/activation.php b/includes/setup/activation.php index f347f1034f..9f08fde7c0 100644 --- a/includes/setup/activation.php +++ b/includes/setup/activation.php @@ -21,6 +21,7 @@ public static function register_hooks() { public static function run() { // Run the activation tasks. self::create_tables(); + self::sync_order_status_enum(); } public static function create_tables() { @@ -77,4 +78,25 @@ public static function create_tables() { } ); } -} \ No newline at end of file + + private static function sync_order_status_enum() { + global $wpdb; + + $table_name = $wpdb->prefix . 'directorist_orders'; + + if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ) ) !== $table_name ) { + return; + } + + $statuses = array_map( + function( $status ) { + return "'" . esc_sql( $status ) . "'"; + }, + OrderStatus::all() + ); + + $wpdb->query( + "ALTER TABLE {$table_name} MODIFY status ENUM(" . implode( ',', $statuses ) . ") DEFAULT '" . esc_sql( OrderStatus::PENDING ) . "'" + ); + } +} From c6146117c1ded325c9df6d3b34a9bd167a8a5a08 Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Thu, 6 Aug 2026 22:35:45 +0600 Subject: [PATCH 02/21] fix: include directory slug in author profile links --- includes/classes/class-permalink.php | 20 ++++++++++++++++---- templates/single/section-author_info.php | 15 ++++++++------- templates/widgets/author-info.php | 17 +++++++++-------- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/includes/classes/class-permalink.php b/includes/classes/class-permalink.php index f3f9776a33..52c615c3aa 100644 --- a/includes/classes/class-permalink.php +++ b/includes/classes/class-permalink.php @@ -33,12 +33,26 @@ public static function get_listing_permalink( $post_id = 0, $permalink = '' ) { $permalink = get_the_permalink( $post_id ); } + $directory_slug = self::get_listing_directory_type_slug( $post_id ); + + $permalink = str_replace( '%' . ATBDP_DIRECTORY_TYPE . '%', $directory_slug, $permalink ); + + return $permalink; + } + + /** + * Get the directory type slug for a listing. + * + * @param int $post_id Listing ID. + * @return string + */ + public static function get_listing_directory_type_slug( $post_id = 0 ) { $directory_slug = ''; $directory_id = directorist_get_listing_directory( $post_id ); if ( $directory_id ) { $directory_term = get_term( $directory_id, ATBDP_DIRECTORY_TYPE ); - $directory_slug = $directory_term ? $directory_term->slug : ''; + $directory_slug = ( $directory_term && ! is_wp_error( $directory_term ) ) ? $directory_term->slug : ''; } if ( empty( $directory_slug ) ) { @@ -49,9 +63,7 @@ public static function get_listing_permalink( $post_id = 0, $permalink = '' ) { } } - $permalink = str_replace( '%' . ATBDP_DIRECTORY_TYPE . '%', $directory_slug, $permalink ); - - return $permalink; + return $directory_slug; } public static function get_listing_slug() { diff --git a/templates/single/section-author_info.php b/templates/single/section-author_info.php index dea02ad27a..ba6a63b198 100644 --- a/templates/single/section-author_info.php +++ b/templates/single/section-author_info.php @@ -9,12 +9,13 @@ if ( ! defined( 'ABSPATH' ) ) exit; -$id = $listing->id; -$author_id = $listing->author_id; -$u_pro_pic = get_user_meta( $author_id, 'pro_pic', true ); -$u_pro_pic = ! empty( $u_pro_pic ) ? wp_get_attachment_image_src( $u_pro_pic, 'thumbnail' ) : ''; -$author_img = ! empty( $u_pro_pic ) ? $u_pro_pic[0] : ''; -$avatar_img = get_avatar( $author_id, 32 ); +$id = $listing->id; +$author_id = $listing->author_id; +$directory_type = ATBDP_Permalink::get_listing_directory_type_slug( $id ); +$u_pro_pic = get_user_meta( $author_id, 'pro_pic', true ); +$u_pro_pic = ! empty( $u_pro_pic ) ? wp_get_attachment_image_src( $u_pro_pic, 'thumbnail' ) : ''; +$author_img = ! empty( $u_pro_pic ) ? $u_pro_pic[0] : ''; +$avatar_img = get_avatar( $author_id, 32 ); ?>
section_id( $id ); ?>> @@ -112,7 +113,7 @@ - + diff --git a/templates/widgets/author-info.php b/templates/widgets/author-info.php index 876f701ec7..3cc293665d 100644 --- a/templates/widgets/author-info.php +++ b/templates/widgets/author-info.php @@ -12,13 +12,14 @@
@@ -124,8 +125,8 @@ class="directorist-single-author-contact-info-text" - -
\ No newline at end of file +
From 2cb30a0a5fe9c9a0ce6a195f58772b34475d0770 Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Mon, 17 Aug 2026 17:12:01 +0600 Subject: [PATCH 03/21] fix(order): preserve status column constraints --- includes/setup/activation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/setup/activation.php b/includes/setup/activation.php index 9f08fde7c0..ee76faa185 100644 --- a/includes/setup/activation.php +++ b/includes/setup/activation.php @@ -96,7 +96,7 @@ function( $status ) { ); $wpdb->query( - "ALTER TABLE {$table_name} MODIFY status ENUM(" . implode( ',', $statuses ) . ") DEFAULT '" . esc_sql( OrderStatus::PENDING ) . "'" + "ALTER TABLE {$table_name} MODIFY status ENUM(" . implode( ',', $statuses ) . ") NOT NULL DEFAULT '" . esc_sql( OrderStatus::PENDING ) . "'" ); } } From 9eec0b0dcc6cde03bfb225b36209aeb16aa36df7 Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Mon, 17 Aug 2026 17:18:13 +0600 Subject: [PATCH 04/21] fix: include directory slug in author avatar link --- includes/model/SingleListing.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/includes/model/SingleListing.php b/includes/model/SingleListing.php index 377c707c8e..e2f551a55f 100644 --- a/includes/model/SingleListing.php +++ b/includes/model/SingleListing.php @@ -1590,12 +1590,13 @@ public function user_avatar() { $user_pro_pic = get_user_meta( $this->author_id, 'pro_pic', true ); $u_pro_pic = ! empty( $u_pro_pic ) ? wp_get_attachment_image_src( $u_pro_pic, 'thumbnail' ) : ''; $author_data = get_userdata( $this->author_id ); + $directory_type = ATBDP_Permalink::get_listing_directory_type_slug( $this->id ); $author_first_name = ! empty( $author_data ) ? $author_data->first_name : ''; $author_last_name = ! empty( $author_data ) ? $author_data->last_name : ''; $args = [ - 'author_link' => ATBDP_Permalink::get_user_profile_page_link( $this->author_id ), + 'author_link' => ATBDP_Permalink::get_user_profile_page_link( $this->author_id, $directory_type ), 'u_pro_pic' => $u_pro_pic, 'avatar_img' => get_avatar( $this->author_id, apply_filters( 'atbdp_avatar_size', 32 ) ), 'author_full_name' => $author_first_name . ' ' . $author_last_name, From 1bc3a55b50925e3cbcacb148d01bb59f81c019a1 Mon Sep 17 00:00:00 2001 From: Armanul46 <47377178+Armanul46@users.noreply.github.com> Date: Tue, 18 Aug 2026 01:54:00 +0600 Subject: [PATCH 05/21] readme update --- config.php | 2 +- directorist-base.php | 2 +- readme.txt | 10 +++++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/config.php b/config.php index ebd94a5c14..85dec62a2b 100644 --- a/config.php +++ b/config.php @@ -1,7 +1,7 @@ Date: Wed, 19 Aug 2026 12:53:16 +0600 Subject: [PATCH 06/21] fix(featured-listing): sync expiration after order update --- .../class-featured-listing-checkout.php | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/includes/classes/class-featured-listing-checkout.php b/includes/classes/class-featured-listing-checkout.php index e7ae39ef75..a09e81bd96 100644 --- a/includes/classes/class-featured-listing-checkout.php +++ b/includes/classes/class-featured-listing-checkout.php @@ -156,7 +156,11 @@ public function handle_after_order_update( OrderDTO $dto ) { // Publish the listing if it's pending $listing = get_post( $dto->get_listing_id() ); - + + if ( $listing ) { + $this->updated_listing_expiration( $listing, $dto ); + } + if ( $listing && 'publish' !== $listing->post_status ) { directorist_set_listing_status( $dto->get_listing_id(), 'publish' ); } @@ -165,6 +169,28 @@ public function handle_after_order_update( OrderDTO $dto ) { } } + private function updated_listing_expiration( $listing, OrderDTO $order ) { + if ( ! $order->is_initialized( 'expires_at' ) || get_post_meta( $listing->ID, '_never_expire', true ) ) { + return; + } + + $order_expiration = $order->get_expires_at(); + $listing_expiration = get_post_meta( $listing->ID, '_expiry_date', true ); + $listing_expiration_date = $listing_expiration + ? date_create_from_format( 'Y-m-d H:i:s', $listing_expiration, wp_timezone() ) + : false; + + if ( + $listing_expiration_date && + $listing_expiration === $listing_expiration_date->format( 'Y-m-d H:i:s' ) && + $listing_expiration_date->getTimestamp() >= $order_expiration->getTimestamp() + ) { + return; + } + + update_post_meta( $listing->ID, '_expiry_date', $order_expiration->format( 'Y-m-d H:i:s' ) ); + } + public function handle_payment_receipt_order_items( array $order_items, OrderDTO $order ) { if ( ! $this->is_featured_order( $order ) ) { return $order_items; From 9c4b14201aec7a0a9e417ef3f848fa636b9636f4 Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Wed, 19 Aug 2026 13:07:36 +0600 Subject: [PATCH 07/21] fix(featured-listing): honor force-disabled state --- includes/classes/class-cron.php | 4 ++++ includes/classes/class-featured-listing-checkout.php | 9 +++++++-- includes/directorist-core-functions.php | 7 +++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/includes/classes/class-cron.php b/includes/classes/class-cron.php index 8858b9a323..a80326cc6a 100644 --- a/includes/classes/class-cron.php +++ b/includes/classes/class-cron.php @@ -98,6 +98,10 @@ public function atbdp_custom_schedule_cron() { */ private function featured_listing_followup() { + if ( directorist_is_force_disabled_featured_listings() ) { + return; + } + if ( directorist_is_monetization_enabled() && directorist_is_featured_listing_enabled() ) { $featured_days = get_directorist_option( 'featured_listing_time', 30 ); // Define the query diff --git a/includes/classes/class-featured-listing-checkout.php b/includes/classes/class-featured-listing-checkout.php index a09e81bd96..26c4be8dd1 100644 --- a/includes/classes/class-featured-listing-checkout.php +++ b/includes/classes/class-featured-listing-checkout.php @@ -14,10 +14,15 @@ class FeaturedListingCheckout { const CHECKOUT_TYPE = 'featured_listing'; public function __construct() { - add_filter( 'directorist_checkout_types', [$this, 'add_checkout_type'] ); add_filter( 'directorist_order_data', [ $this, 'handle_order_data' ] ); - add_action( 'directorist_after_order_update', [$this, 'handle_after_order_update'] ); add_filter( 'directorist_payment_receipt_order_items', [$this, 'handle_payment_receipt_order_items'], 10, 2 ); + + if ( directorist_is_force_disabled_featured_listings() ) { + return; + } + + add_filter( 'directorist_checkout_types', [$this, 'add_checkout_type'] ); + add_action( 'directorist_after_order_update', [$this, 'handle_after_order_update'] ); add_filter( 'directorist_checkout_validation', [$this, 'validate_checkout'], 10, 2 ); add_action( 'directorist_checkout_table', [$this, 'handle_checkout_table'], 10, 4 ); add_filter( 'directorist_checkout_subtotal', [$this, 'handle_checkout_subtotal'], 10, 3 ); diff --git a/includes/directorist-core-functions.php b/includes/directorist-core-functions.php index 240cf293dd..e2d77dbb53 100644 --- a/includes/directorist-core-functions.php +++ b/includes/directorist-core-functions.php @@ -18,6 +18,13 @@ function directorist_is_guest_submission_enabled() { return (bool) get_directorist_option( 'guest_listings', false ); } +/** + * @return bool + */ +function directorist_is_force_disabled_featured_listings() { + return (bool) apply_filters( 'directorist_is_force_disabled_featured_listings', false ); +} + function directorist_is_featured_listing_enabled( array $context = [] ) { return (bool) apply_filters( 'directorist_is_featured_listing_enabled', get_directorist_option( 'enable_featured_listing' ), $context ); } From eb5329977ec6032d3fcc22a7f7c7a826154a6f83 Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Wed, 19 Aug 2026 13:12:47 +0600 Subject: [PATCH 08/21] refactor(featured-listing): use new orders in expiration cron --- includes/classes/class-cron.php | 51 +++++++--------------- includes/repositories/order-repository.php | 10 +++++ 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/includes/classes/class-cron.php b/includes/classes/class-cron.php index a80326cc6a..e1f84d1597 100644 --- a/includes/classes/class-cron.php +++ b/includes/classes/class-cron.php @@ -103,7 +103,9 @@ private function featured_listing_followup() { } if ( directorist_is_monetization_enabled() && directorist_is_featured_listing_enabled() ) { - $featured_days = get_directorist_option( 'featured_listing_time', 30 ); + $featured_days = (int) get_directorist_option( 'featured_listing_time', 30 ); + $orders = directorist_order_repository(); + $current_time = directorist_now()->getTimestamp(); // Define the query $args = [ 'post_type' => ATBDP_POST_TYPE, @@ -124,44 +126,23 @@ private function featured_listing_followup() { // Start the Loop if ( $listings->found_posts ) { foreach ( $listings->posts as $listing ) { - $order = $this->get_order_by_listing( $listing->ID ); - if ( $order ) { - $days = round( abs( strtotime( current_time( 'mysql' ) ) - strtotime( $order[0]->post_date ) ) / 86400 ); - if ( $days > $featured_days ) { - do_action( 'atbdp_listing_featured_to_general', $listing->ID ); - update_post_meta( $listing->ID, '_featured', '' ); - } - } - } - } - } - } + $order = $orders->get_latest_paid_featured_order_by_listing_id( $listing->ID ); - private function get_order_by_listing( $listing_id ) { - $args = [ - 'post_type' => ATBDP_ORDER_POST_TYPE, - 'posts_per_page' => 1, - 'post_status' => 'publish', - 'meta_query' => [ - 'relation' => 'AND', - [ - 'key' => '_listing_id', - 'value' => $listing_id, - ], - [ - 'key' => '_payment_status', - 'value' => 'completed', - ], - ], - ]; + if ( ! $order ) { + continue; + } - $listings = new WP_Query( $args ); + $expiration = ! empty( $order->expires_at ) + ? new \Directorist\Helpers\DateTime( $order->expires_at ) + : ( new \Directorist\Helpers\DateTime( $order->created_at ) )->add_days( $featured_days ); - // Start the Loop - if ( $listings->found_posts ) { - return $listings->posts; + if ( $expiration->getTimestamp() <= $current_time ) { + do_action( 'atbdp_listing_featured_to_general', $listing->ID ); + update_post_meta( $listing->ID, '_featured', '' ); + } + } + } } - return ''; } /** diff --git a/includes/repositories/order-repository.php b/includes/repositories/order-repository.php index 9a4265dd95..08f5181b0f 100644 --- a/includes/repositories/order-repository.php +++ b/includes/repositories/order-repository.php @@ -89,6 +89,16 @@ public function listing_has_paid_featured_order( int $listing_id ): bool { return $order ? true : false; } + public function get_latest_paid_featured_order_by_listing_id( int $listing_id ) { + return $this->get_query_builder() + ->select( 'd_order.created_at', 'd_order.expires_at' ) + ->where( 'd_order.listing_id', $listing_id ) + ->where( 'd_order.is_featured_listing', 1 ) + ->where( 'd_order.status', OrderStatus::PAID ) + ->order_by_desc( 'd_order.id' ) + ->first(); + } + protected function get_orders( Builder $query, Read $dto ) { $query = apply_filters( 'directorist_order_list_query', $query, $dto ); From 5af64bfc5a948fea5cbfe105f7c5a1b970d840c2 Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Wed, 19 Aug 2026 15:51:47 +0600 Subject: [PATCH 09/21] fix(featured-listing): handle provider and order edge cases --- .../classes/class-featured-listing-checkout.php | 15 +++++++++------ includes/repositories/order-repository.php | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/includes/classes/class-featured-listing-checkout.php b/includes/classes/class-featured-listing-checkout.php index 26c4be8dd1..c7c53f29f5 100644 --- a/includes/classes/class-featured-listing-checkout.php +++ b/includes/classes/class-featured-listing-checkout.php @@ -13,10 +13,14 @@ class FeaturedListingCheckout { const CHECKOUT_TYPE = 'featured_listing'; - public function __construct() { + public function __construct() { add_filter( 'directorist_order_data', [ $this, 'handle_order_data' ] ); add_filter( 'directorist_payment_receipt_order_items', [$this, 'handle_payment_receipt_order_items'], 10, 2 ); + add_action( 'plugins_loaded', [ $this, 'register_hooks' ], 20 ); + } + + public function register_hooks() { if ( directorist_is_force_disabled_featured_listings() ) { return; } @@ -185,10 +189,9 @@ private function updated_listing_expiration( $listing, OrderDTO $order ) { ? date_create_from_format( 'Y-m-d H:i:s', $listing_expiration, wp_timezone() ) : false; - if ( - $listing_expiration_date && - $listing_expiration === $listing_expiration_date->format( 'Y-m-d H:i:s' ) && - $listing_expiration_date->getTimestamp() >= $order_expiration->getTimestamp() + if ( $listing_expiration_date + && $listing_expiration === $listing_expiration_date->format( 'Y-m-d H:i:s' ) + && $listing_expiration_date->getTimestamp() >= $order_expiration->getTimestamp() ) { return; } @@ -237,7 +240,7 @@ public function handle_checkout_product_name( string $product_name, OrderDTO $dt } public function is_featured_order( OrderDTO $order_dto ): bool { - if ( ! $order_dto->is_initialized( 'ref_type' ) || ! $order_dto->is_initialized( 'ref' ) || ! $order_dto->is_initialized( 'listing_id' ) ) { + if ( ! $order_dto->is_initialized( 'ref_type' ) || ! $order_dto->is_initialized( 'listing_id' ) ) { return false; } diff --git a/includes/repositories/order-repository.php b/includes/repositories/order-repository.php index 08f5181b0f..8b8d453c12 100644 --- a/includes/repositories/order-repository.php +++ b/includes/repositories/order-repository.php @@ -94,6 +94,7 @@ public function get_latest_paid_featured_order_by_listing_id( int $listing_id ) ->select( 'd_order.created_at', 'd_order.expires_at' ) ->where( 'd_order.listing_id', $listing_id ) ->where( 'd_order.is_featured_listing', 1 ) + ->where( 'd_order.ref_type', 'featured_listing' ) ->where( 'd_order.status', OrderStatus::PAID ) ->order_by_desc( 'd_order.id' ) ->first(); From 6c4a2a482c4067309ece39f529ff240c7bd7344b Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Wed, 19 Aug 2026 20:20:27 +0600 Subject: [PATCH 10/21] fix(featured-listing): set expiration on partial paid updates --- .../class-featured-listing-checkout.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/includes/classes/class-featured-listing-checkout.php b/includes/classes/class-featured-listing-checkout.php index c7c53f29f5..097087f308 100644 --- a/includes/classes/class-featured-listing-checkout.php +++ b/includes/classes/class-featured-listing-checkout.php @@ -31,7 +31,7 @@ public function register_hooks() { add_action( 'directorist_checkout_table', [$this, 'handle_checkout_table'], 10, 4 ); add_filter( 'directorist_checkout_subtotal', [$this, 'handle_checkout_subtotal'], 10, 3 ); add_action( 'directorist_checkout_create_order', [$this, 'handle_checkout_create_order'], 10, 3 ); - add_action( 'directorist_before_order_update', [$this, 'handle_before_order_update'] ); + add_action( 'directorist_before_order_update', [$this, 'handle_before_order_update'], 10, 2 ); add_filter( 'directorist_checkout_product_name', [$this, 'handle_checkout_product_name'], 10, 2 ); add_filter( 'directorist_ajax_listing_submission_response', [ $this, 'handle_listing_submission_response_data' ], 10, 2 ); add_filter( 'directorist_listing_update_args_after_preview', [ $this, 'handle_listing_status_after_preview' ], 10, 2 ); @@ -134,21 +134,20 @@ public function handle_checkout_create_order( OrderDTO $dto, string $checkout_ty $dto->set_listing_id( $request->get_param( 'listing_id' ) )->set_is_featured_listing( 1 )->set_ref_type( self::CHECKOUT_TYPE )->set_amount( $amount )->set_sub_total( $amount ); } - public function handle_before_order_update( OrderDTO $dto ) { - if ( ! $this->is_featured_order( $dto ) ) { + public function handle_before_order_update( OrderDTO $dto, $old_order ) { + if ( ! $dto->is_initialized( 'status' ) || $dto->get_status() !== Status::PAID ) { return; } - if ( ! $dto->is_initialized( 'status' ) || $dto->get_status() !== Status::PAID ) { + if ( empty( $old_order->is_featured_listing ) + || self::CHECKOUT_TYPE !== ( $old_order->ref_type ?? null ) + || ! empty( $old_order->expires_at ) + ) { return; } - $order = directorist_get_order_by_id( $dto->get_id() ); - - if ( $order->is_featured_listing && ! $order->expires_at ) { - $featured_days = get_directorist_option( 'featured_listing_time', 30 ); - $dto->set_expires_at( directorist_now()->add_days( $featured_days ) ); - } + $featured_days = (int) get_directorist_option( 'featured_listing_time', 30 ); + $dto->set_expires_at( directorist_now()->add_days( $featured_days ) ); } public function handle_after_order_update( OrderDTO $dto ) { From 7bf7b67a80ccc39379ed1938221077ed9c211981 Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Thu, 20 Aug 2026 10:59:26 +0600 Subject: [PATCH 11/21] fix(featured-listing): refresh expiration on paid updates --- includes/classes/class-featured-listing-checkout.php | 1 - 1 file changed, 1 deletion(-) diff --git a/includes/classes/class-featured-listing-checkout.php b/includes/classes/class-featured-listing-checkout.php index 097087f308..61c5fd9e8a 100644 --- a/includes/classes/class-featured-listing-checkout.php +++ b/includes/classes/class-featured-listing-checkout.php @@ -141,7 +141,6 @@ public function handle_before_order_update( OrderDTO $dto, $old_order ) { if ( empty( $old_order->is_featured_listing ) || self::CHECKOUT_TYPE !== ( $old_order->ref_type ?? null ) - || ! empty( $old_order->expires_at ) ) { return; } From 4dda2b3458ae41f7ba5a326a2cf45f1698818ddb Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Thu, 20 Aug 2026 14:42:44 +0600 Subject: [PATCH 12/21] fix(featured-listing): persist expiration after listing update --- .../class-featured-listing-checkout.php | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/includes/classes/class-featured-listing-checkout.php b/includes/classes/class-featured-listing-checkout.php index 61c5fd9e8a..9110b22653 100644 --- a/includes/classes/class-featured-listing-checkout.php +++ b/includes/classes/class-featured-listing-checkout.php @@ -31,7 +31,6 @@ public function register_hooks() { add_action( 'directorist_checkout_table', [$this, 'handle_checkout_table'], 10, 4 ); add_filter( 'directorist_checkout_subtotal', [$this, 'handle_checkout_subtotal'], 10, 3 ); add_action( 'directorist_checkout_create_order', [$this, 'handle_checkout_create_order'], 10, 3 ); - add_action( 'directorist_before_order_update', [$this, 'handle_before_order_update'], 10, 2 ); add_filter( 'directorist_checkout_product_name', [$this, 'handle_checkout_product_name'], 10, 2 ); add_filter( 'directorist_ajax_listing_submission_response', [ $this, 'handle_listing_submission_response_data' ], 10, 2 ); add_filter( 'directorist_listing_update_args_after_preview', [ $this, 'handle_listing_status_after_preview' ], 10, 2 ); @@ -134,21 +133,6 @@ public function handle_checkout_create_order( OrderDTO $dto, string $checkout_ty $dto->set_listing_id( $request->get_param( 'listing_id' ) )->set_is_featured_listing( 1 )->set_ref_type( self::CHECKOUT_TYPE )->set_amount( $amount )->set_sub_total( $amount ); } - public function handle_before_order_update( OrderDTO $dto, $old_order ) { - if ( ! $dto->is_initialized( 'status' ) || $dto->get_status() !== Status::PAID ) { - return; - } - - if ( empty( $old_order->is_featured_listing ) - || self::CHECKOUT_TYPE !== ( $old_order->ref_type ?? null ) - ) { - return; - } - - $featured_days = (int) get_directorist_option( 'featured_listing_time', 30 ); - $dto->set_expires_at( directorist_now()->add_days( $featured_days ) ); - } - public function handle_after_order_update( OrderDTO $dto ) { if ( ! $this->is_featured_order( $dto ) ) { return; @@ -177,11 +161,13 @@ public function handle_after_order_update( OrderDTO $dto ) { } private function updated_listing_expiration( $listing, OrderDTO $order ) { - if ( ! $order->is_initialized( 'expires_at' ) || get_post_meta( $listing->ID, '_never_expire', true ) ) { + if ( get_post_meta( $listing->ID, '_never_expire', true ) ) { return; } - $order_expiration = $order->get_expires_at(); + $featured_days = (int) get_directorist_option( 'featured_listing_time', 30 ); + $order_expiration = directorist_now()->add_days( $featured_days ); + $listing_expiration = get_post_meta( $listing->ID, '_expiry_date', true ); $listing_expiration_date = $listing_expiration ? date_create_from_format( 'Y-m-d H:i:s', $listing_expiration, wp_timezone() ) @@ -194,6 +180,9 @@ private function updated_listing_expiration( $listing, OrderDTO $order ) { return; } + $order->set_expires_at( $order_expiration ); + directorist_order_repository()->silent_update( $order ); + update_post_meta( $listing->ID, '_expiry_date', $order_expiration->format( 'Y-m-d H:i:s' ) ); } From 8255e7d9c9cefdf59a7d44a32bf77fcde280b9d5 Mon Sep 17 00:00:00 2001 From: Armanul46 <47377178+Armanul46@users.noreply.github.com> Date: Thu, 27 Aug 2026 10:42:00 +0600 Subject: [PATCH 13/21] readme update --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index d01e6a3bc3..5a19c4f12a 100644 --- a/readme.txt +++ b/readme.txt @@ -307,6 +307,7 @@ Directorist comes with an AI-powered directory builder. Use the Create with AI o **Fixed** - Author profile links missing directory type slug in multi-directory listings. (#2957) +- Featured listing expiration sync issue. (#2969) = 8.9.3 - Aug 9, 2026 = From 34f369a438eaf28d0f90cb230bda4f1b164e08f7 Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Thu, 27 Aug 2026 12:14:52 +0600 Subject: [PATCH 14/21] fix(featured-listing): persist order expiration before early return --- includes/classes/class-featured-listing-checkout.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/includes/classes/class-featured-listing-checkout.php b/includes/classes/class-featured-listing-checkout.php index 9110b22653..07cb3329e5 100644 --- a/includes/classes/class-featured-listing-checkout.php +++ b/includes/classes/class-featured-listing-checkout.php @@ -173,6 +173,10 @@ private function updated_listing_expiration( $listing, OrderDTO $order ) { ? date_create_from_format( 'Y-m-d H:i:s', $listing_expiration, wp_timezone() ) : false; + + $order->set_expires_at( $order_expiration ); + directorist_order_repository()->silent_update( $order ); + if ( $listing_expiration_date && $listing_expiration === $listing_expiration_date->format( 'Y-m-d H:i:s' ) && $listing_expiration_date->getTimestamp() >= $order_expiration->getTimestamp() @@ -180,9 +184,6 @@ private function updated_listing_expiration( $listing, OrderDTO $order ) { return; } - $order->set_expires_at( $order_expiration ); - directorist_order_repository()->silent_update( $order ); - update_post_meta( $listing->ID, '_expiry_date', $order_expiration->format( 'Y-m-d H:i:s' ) ); } From 33f08652ae0107afa54013003ad29eabdce214ac Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Thu, 27 Aug 2026 12:47:39 +0600 Subject: [PATCH 15/21] fix(payment): resolve prepaid and featured expiry handling --- .../class-featured-listing-checkout.php | 27 ++++++++++------ .../Version1/class-orders-controller.php | 32 +++++++++++++++++-- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/includes/classes/class-featured-listing-checkout.php b/includes/classes/class-featured-listing-checkout.php index 07cb3329e5..691567601d 100644 --- a/includes/classes/class-featured-listing-checkout.php +++ b/includes/classes/class-featured-listing-checkout.php @@ -143,13 +143,15 @@ public function handle_after_order_update( OrderDTO $dto ) { } if ( Status::PAID === $dto->get_status() ) { + $order_expiration = $this->refresh_order_expiration( $dto ); + directorist_set_listing_featured( $dto->get_listing_id(), true ); // Publish the listing if it's pending $listing = get_post( $dto->get_listing_id() ); if ( $listing ) { - $this->updated_listing_expiration( $listing, $dto ); + $this->update_listing_expiration( $listing, $order_expiration ); } if ( $listing && 'publish' !== $listing->post_status ) { @@ -160,23 +162,30 @@ public function handle_after_order_update( OrderDTO $dto ) { } } - private function updated_listing_expiration( $listing, OrderDTO $order ) { + private function refresh_order_expiration( OrderDTO $order ) { + $featured_days = (int) get_directorist_option( 'featured_listing_time', 30 ); + $order_expiration = directorist_now()->add_days( $featured_days ); + + $order->set_expires_at( $order_expiration ); + $expiration_update = ( new OrderDTO() ) + ->set_id( $order->get_id() ) + ->set_expires_at( $order_expiration ); + + directorist_order_repository()->silent_update( $expiration_update ); + + return $order_expiration; + } + + private function update_listing_expiration( $listing, $order_expiration ) { if ( get_post_meta( $listing->ID, '_never_expire', true ) ) { return; } - $featured_days = (int) get_directorist_option( 'featured_listing_time', 30 ); - $order_expiration = directorist_now()->add_days( $featured_days ); - $listing_expiration = get_post_meta( $listing->ID, '_expiry_date', true ); $listing_expiration_date = $listing_expiration ? date_create_from_format( 'Y-m-d H:i:s', $listing_expiration, wp_timezone() ) : false; - - $order->set_expires_at( $order_expiration ); - directorist_order_repository()->silent_update( $order ); - if ( $listing_expiration_date && $listing_expiration === $listing_expiration_date->format( 'Y-m-d H:i:s' ) && $listing_expiration_date->getTimestamp() >= $order_expiration->getTimestamp() diff --git a/includes/rest-api/Version1/class-orders-controller.php b/includes/rest-api/Version1/class-orders-controller.php index afbea5c885..2b805adc77 100644 --- a/includes/rest-api/Version1/class-orders-controller.php +++ b/includes/rest-api/Version1/class-orders-controller.php @@ -12,6 +12,7 @@ use Directorist\DTO\Order\DTO as OrderDTO; use Directorist\DTO\Payment\DTO as PaymentDTO; use Directorist\Enums\Order\Status as OrderStatus; +use Directorist\Enums\Payment\Status as PaymentStatus; use WP_Error; use WP_REST_Request; use WP_REST_Server; @@ -140,7 +141,8 @@ public function create_item( $request ) { $dto = apply_filters( 'directorist_rest_legacy_order_create_dto', $dto, $request ); - $order_id = directorist_order_repository()->create( $dto ); + $order_repository = directorist_order_repository(); + $order_id = $order_repository->create( $dto ); if ( ! $order_id ) { return new WP_Error( 'invalid_order', __( 'Unable to create order.', 'directorist' ), array( 'status' => 400 ) ); @@ -153,11 +155,21 @@ public function create_item( $request ) { ->set_order_id( $order_id ) ->set_amount( $amount ) ->set_currency( $currency ) - ->set_status( $this->legacy_status_to_current_status( $legacy_status ) ) + ->set_status( $this->legacy_payment_status_to_current_status( $legacy_status ) ) ->set_method( $gateway ) ->set_transaction_id( $transaction_id ? $transaction_id : null ); - directorist_payment_repository()->create( apply_filters( 'directorist_rest_legacy_order_create_payment_dto', $payment_dto, $request, $dto ) ); + $payment_dto = apply_filters( 'directorist_rest_legacy_order_create_payment_dto', $payment_dto, $request, $dto ); + $payment_repository = directorist_payment_repository(); + $payment_id = $payment_repository->create( $payment_dto ); + $payment = $payment_repository->get_last_payment( $order_id ); + + if ( ! $payment_id || ! $payment || $payment->status !== $payment_dto->get_status() ) { + $payment_repository->delete_by( 'order_id', $order_id ); + $order_repository->delete_by_id( $order_id ); + + return new WP_Error( 'rest_payment_create_failed', __( 'Unable to create payment.', 'directorist' ), array( 'status' => 500 ) ); + } } do_action( 'atbdp_order_created', $order_id, $listing_id ); @@ -315,6 +327,20 @@ protected function legacy_status_to_current_status( string $status ): string { return $map[ $status ] ?? OrderStatus::PENDING; } + protected function legacy_payment_status_to_current_status( string $status ): string { + $map = array( + 'created' => PaymentStatus::PENDING, + 'pending' => PaymentStatus::PENDING, + 'prepaid' => PaymentStatus::PAID, + 'completed' => PaymentStatus::PAID, + 'failed' => PaymentStatus::FAILED, + 'cancelled' => PaymentStatus::CANCELLED, + 'refunded' => PaymentStatus::REFUNDED, + ); + + return $map[ $status ] ?? PaymentStatus::PENDING; + } + protected function current_status_to_legacy_status( string $status ): string { $map = array( OrderStatus::PENDING => 'pending', From 0e9bbf13c41f5877b25ce0215705823df8d2c907 Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Thu, 27 Aug 2026 15:08:34 +0600 Subject: [PATCH 16/21] fix(payment): preserve prepaid order lifecycle --- includes/repositories/payment-repository.php | 26 ++++++++++++++++--- .../Version1/class-orders-controller.php | 13 +++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/includes/repositories/payment-repository.php b/includes/repositories/payment-repository.php index d669148943..0daaf82e46 100644 --- a/includes/repositories/payment-repository.php +++ b/includes/repositories/payment-repository.php @@ -9,6 +9,7 @@ use Directorist\Utils\Database\Query\Builder; use Directorist\DTO\Payment\DTO; use Directorist\Enums\Order\Status as OrderStatus; +use Directorist\Enums\Payment\Status as PaymentStatus; use Directorist\DBModels\Payment; class PaymentRepository extends Repository { @@ -33,15 +34,34 @@ public function get( $order_id ) { * @return int */ public function create( \Directorist\Utils\DTO $dto ) { - $payment_id = parent::create( $dto ); + $payment_id = $this->create_without_order_update( $dto ); + $payment = $payment_id ? $this->get_last_payment( $dto->get_order_id() ) : null; + + if ( ! $payment || (int) $payment->id !== $payment_id || $payment->status !== $dto->get_status() ) { + return 0; + } - if ( $dto->is_initialized( 'status' ) && $dto->get_status() === OrderStatus::PAID ) { + if ( $dto->is_initialized( 'status' ) && $dto->get_status() === PaymentStatus::PAID ) { $this->order_repository->update_status( $dto->get_order_id(), OrderStatus::PAID ); } return $payment_id; } + /** + * Create a payment without synchronizing the related order status. + * + * @param \Directorist\Utils\DTO $dto Payment data. + * @return int Payment ID, or zero when the insert fails. + */ + public function create_without_order_update( \Directorist\Utils\DTO $dto ) { + global $wpdb; + + $payment_id = parent::create( $dto ); + + return $wpdb->last_error ? 0 : $payment_id; + } + public function update_status_by_order_id( int $order_id, string $status ): int { return $this->get_query_builder() ->where( 'order_id', $order_id ) @@ -69,4 +89,4 @@ public function to_dto( $payment ) { return $dto; } -} \ No newline at end of file +} diff --git a/includes/rest-api/Version1/class-orders-controller.php b/includes/rest-api/Version1/class-orders-controller.php index 2b805adc77..054940c981 100644 --- a/includes/rest-api/Version1/class-orders-controller.php +++ b/includes/rest-api/Version1/class-orders-controller.php @@ -161,15 +161,19 @@ public function create_item( $request ) { $payment_dto = apply_filters( 'directorist_rest_legacy_order_create_payment_dto', $payment_dto, $request, $dto ); $payment_repository = directorist_payment_repository(); - $payment_id = $payment_repository->create( $payment_dto ); + $payment_id = $payment_repository->create_without_order_update( $payment_dto ); $payment = $payment_repository->get_last_payment( $order_id ); - if ( ! $payment_id || ! $payment || $payment->status !== $payment_dto->get_status() ) { + if ( ! $payment_id || ! $payment || (int) $payment->id !== $payment_id || $payment->status !== $payment_dto->get_status() ) { $payment_repository->delete_by( 'order_id', $order_id ); $order_repository->delete_by_id( $order_id ); return new WP_Error( 'rest_payment_create_failed', __( 'Unable to create payment.', 'directorist' ), array( 'status' => 500 ) ); } + + if ( OrderStatus::PAID === $dto->get_status() ) { + $order_repository->update_status( $order_id, OrderStatus::PAID ); + } } do_action( 'atbdp_order_created', $order_id, $listing_id ); @@ -270,6 +274,9 @@ protected function get_order( int $order_id ) { protected function prepare_legacy_order_data( $order, WP_REST_Request $request ): array { $payment = ! empty( $order->payment ) ? $order->payment : null; $plan_id = $this->get_plan_id( $order ); + $status = OrderStatus::PREPAID === ( $order->status ?? '' ) + ? $order->status + : ( $payment->status ?? $order->status ?? '' ); $data = array( 'id' => (int) $order->id, @@ -285,7 +292,7 @@ protected function prepare_legacy_order_data( $order, WP_REST_Request $request ) 'remaining_featured_listings' => 0, 'amount' => round( (float) ( $order->amount ?? 0 ), 2 ), 'currency' => (string) ( $order->currency ?? '' ), - 'payment_status' => $this->current_status_to_legacy_status( $payment->status ?? $order->status ?? '' ), + 'payment_status' => $this->current_status_to_legacy_status( $status ), 'payment_gateway' => (string) ( $payment->method ?? '' ), 'transaction_id' => (string) ( $payment->transaction_id ?? '' ), 'created_by' => 'web', From 3bc8e8a6e09c569aec42d8809adf7f5f6cd10b4b Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Thu, 27 Aug 2026 15:26:24 +0600 Subject: [PATCH 17/21] fix(payment): preserve entitlements and inserted payments --- .../class-featured-listing-checkout.php | 2 +- includes/repositories/order-repository.php | 29 +++++++++++++++++++ includes/repositories/payment-repository.php | 2 +- .../Version1/class-orders-controller.php | 2 +- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/includes/classes/class-featured-listing-checkout.php b/includes/classes/class-featured-listing-checkout.php index 691567601d..cd52ce17f0 100644 --- a/includes/classes/class-featured-listing-checkout.php +++ b/includes/classes/class-featured-listing-checkout.php @@ -157,7 +157,7 @@ public function handle_after_order_update( OrderDTO $dto ) { if ( $listing && 'publish' !== $listing->post_status ) { directorist_set_listing_status( $dto->get_listing_id(), 'publish' ); } - } else { + } elseif ( ! directorist_order_repository()->listing_has_active_featured_entitlement( $dto->get_listing_id() ) ) { directorist_set_listing_featured( $dto->get_listing_id(), false ); } } diff --git a/includes/repositories/order-repository.php b/includes/repositories/order-repository.php index 8b8d453c12..c46779507b 100644 --- a/includes/repositories/order-repository.php +++ b/includes/repositories/order-repository.php @@ -89,6 +89,35 @@ public function listing_has_paid_featured_order( int $listing_id ): bool { return $order ? true : false; } + public function listing_has_active_featured_entitlement( int $listing_id ): bool { + $orders = $this->get_query_builder() + ->select( 'd_order.ref_type', 'd_order.created_at', 'd_order.expires_at' ) + ->where( 'd_order.listing_id', $listing_id ) + ->where( 'd_order.is_featured_listing', 1 ) + ->where( 'd_order.status', OrderStatus::PAID ) + ->get(); + + $current_time = directorist_now()->getTimestamp(); + $featured_days = (int) get_directorist_option( 'featured_listing_time', 30 ); + $is_active = false; + + foreach ( $orders as $order ) { + if ( ! empty( $order->expires_at ) ) { + $is_active = ( new DateTime( $order->expires_at ) )->getTimestamp() > $current_time; + } elseif ( 'featured_listing' === $order->ref_type ) { + $is_active = ( new DateTime( $order->created_at ) )->add_days( $featured_days )->getTimestamp() > $current_time; + } else { + $is_active = true; + } + + if ( $is_active ) { + break; + } + } + + return (bool) apply_filters( 'directorist_listing_has_active_featured_entitlement', $is_active, $listing_id, $orders ); + } + public function get_latest_paid_featured_order_by_listing_id( int $listing_id ) { return $this->get_query_builder() ->select( 'd_order.created_at', 'd_order.expires_at' ) diff --git a/includes/repositories/payment-repository.php b/includes/repositories/payment-repository.php index 0daaf82e46..bb87f503ad 100644 --- a/includes/repositories/payment-repository.php +++ b/includes/repositories/payment-repository.php @@ -35,7 +35,7 @@ public function get( $order_id ) { */ public function create( \Directorist\Utils\DTO $dto ) { $payment_id = $this->create_without_order_update( $dto ); - $payment = $payment_id ? $this->get_last_payment( $dto->get_order_id() ) : null; + $payment = $payment_id ? $this->get_by_id( $payment_id ) : null; if ( ! $payment || (int) $payment->id !== $payment_id || $payment->status !== $dto->get_status() ) { return 0; diff --git a/includes/rest-api/Version1/class-orders-controller.php b/includes/rest-api/Version1/class-orders-controller.php index 054940c981..f2f55bf2c4 100644 --- a/includes/rest-api/Version1/class-orders-controller.php +++ b/includes/rest-api/Version1/class-orders-controller.php @@ -162,7 +162,7 @@ public function create_item( $request ) { $payment_dto = apply_filters( 'directorist_rest_legacy_order_create_payment_dto', $payment_dto, $request, $dto ); $payment_repository = directorist_payment_repository(); $payment_id = $payment_repository->create_without_order_update( $payment_dto ); - $payment = $payment_repository->get_last_payment( $order_id ); + $payment = $payment_id ? $payment_repository->get_by_id( $payment_id ) : null; if ( ! $payment_id || ! $payment || (int) $payment->id !== $payment_id || $payment->status !== $payment_dto->get_status() ) { $payment_repository->delete_by( 'order_id', $order_id ); From 496d25e396f7b9f9f5d8d4672ae91e078fd6a988 Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Thu, 27 Aug 2026 15:43:16 +0600 Subject: [PATCH 18/21] fix(featured-listing): preserve entitlement expiration --- includes/classes/class-cron.php | 19 ++++++------------- .../class-featured-listing-checkout.php | 14 ++++++++++---- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/includes/classes/class-cron.php b/includes/classes/class-cron.php index e1f84d1597..282db94048 100644 --- a/includes/classes/class-cron.php +++ b/includes/classes/class-cron.php @@ -103,9 +103,7 @@ private function featured_listing_followup() { } if ( directorist_is_monetization_enabled() && directorist_is_featured_listing_enabled() ) { - $featured_days = (int) get_directorist_option( 'featured_listing_time', 30 ); - $orders = directorist_order_repository(); - $current_time = directorist_now()->getTimestamp(); + $orders = directorist_order_repository(); // Define the query $args = [ 'post_type' => ATBDP_POST_TYPE, @@ -126,20 +124,15 @@ private function featured_listing_followup() { // Start the Loop if ( $listings->found_posts ) { foreach ( $listings->posts as $listing ) { - $order = $orders->get_latest_paid_featured_order_by_listing_id( $listing->ID ); + $has_paid_order = $orders->listing_has_paid_featured_order( $listing->ID ); + $has_active_entitlement = $orders->listing_has_active_featured_entitlement( $listing->ID ); - if ( ! $order ) { + if ( ! $has_paid_order || $has_active_entitlement ) { continue; } - $expiration = ! empty( $order->expires_at ) - ? new \Directorist\Helpers\DateTime( $order->expires_at ) - : ( new \Directorist\Helpers\DateTime( $order->created_at ) )->add_days( $featured_days ); - - if ( $expiration->getTimestamp() <= $current_time ) { - do_action( 'atbdp_listing_featured_to_general', $listing->ID ); - update_post_meta( $listing->ID, '_featured', '' ); - } + do_action( 'atbdp_listing_featured_to_general', $listing->ID ); + update_post_meta( $listing->ID, '_featured', '' ); } } } diff --git a/includes/classes/class-featured-listing-checkout.php b/includes/classes/class-featured-listing-checkout.php index cd52ce17f0..6e7b77048c 100644 --- a/includes/classes/class-featured-listing-checkout.php +++ b/includes/classes/class-featured-listing-checkout.php @@ -26,7 +26,7 @@ public function register_hooks() { } add_filter( 'directorist_checkout_types', [$this, 'add_checkout_type'] ); - add_action( 'directorist_after_order_update', [$this, 'handle_after_order_update'] ); + add_action( 'directorist_after_order_update', [$this, 'handle_after_order_update'], 10, 2 ); add_filter( 'directorist_checkout_validation', [$this, 'validate_checkout'], 10, 2 ); add_action( 'directorist_checkout_table', [$this, 'handle_checkout_table'], 10, 4 ); add_filter( 'directorist_checkout_subtotal', [$this, 'handle_checkout_subtotal'], 10, 3 ); @@ -133,7 +133,7 @@ public function handle_checkout_create_order( OrderDTO $dto, string $checkout_ty $dto->set_listing_id( $request->get_param( 'listing_id' ) )->set_is_featured_listing( 1 )->set_ref_type( self::CHECKOUT_TYPE )->set_amount( $amount )->set_sub_total( $amount ); } - public function handle_after_order_update( OrderDTO $dto ) { + public function handle_after_order_update( OrderDTO $dto, $old_order = null ) { if ( ! $this->is_featured_order( $dto ) ) { return; } @@ -143,14 +143,16 @@ public function handle_after_order_update( OrderDTO $dto ) { } if ( Status::PAID === $dto->get_status() ) { - $order_expiration = $this->refresh_order_expiration( $dto ); + $order_expiration = $this->is_paid_transition( $old_order ) + ? $this->refresh_order_expiration( $dto ) + : null; directorist_set_listing_featured( $dto->get_listing_id(), true ); // Publish the listing if it's pending $listing = get_post( $dto->get_listing_id() ); - if ( $listing ) { + if ( $listing && $order_expiration ) { $this->update_listing_expiration( $listing, $order_expiration ); } @@ -162,6 +164,10 @@ public function handle_after_order_update( OrderDTO $dto ) { } } + private function is_paid_transition( $old_order ): bool { + return ! $old_order || ! isset( $old_order->status ) || Status::PAID !== $old_order->status; + } + private function refresh_order_expiration( OrderDTO $order ) { $featured_days = (int) get_directorist_option( 'featured_listing_time', 30 ); $order_expiration = directorist_now()->add_days( $featured_days ); From 46e6422c0ee2bb3550747fbf11df185d15631947 Mon Sep 17 00:00:00 2001 From: Syed Galib Ahmed Date: Thu, 27 Aug 2026 15:56:41 +0600 Subject: [PATCH 19/21] fix(featured-listing): initialize missing paid expiry --- includes/classes/class-featured-listing-checkout.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/includes/classes/class-featured-listing-checkout.php b/includes/classes/class-featured-listing-checkout.php index 6e7b77048c..c1ea7b3007 100644 --- a/includes/classes/class-featured-listing-checkout.php +++ b/includes/classes/class-featured-listing-checkout.php @@ -143,7 +143,7 @@ public function handle_after_order_update( OrderDTO $dto, $old_order = null ) { } if ( Status::PAID === $dto->get_status() ) { - $order_expiration = $this->is_paid_transition( $old_order ) + $order_expiration = $this->should_refresh_order_expiration( $dto, $old_order ) ? $this->refresh_order_expiration( $dto ) : null; @@ -168,6 +168,10 @@ private function is_paid_transition( $old_order ): bool { return ! $old_order || ! isset( $old_order->status ) || Status::PAID !== $old_order->status; } + private function should_refresh_order_expiration( OrderDTO $order, $old_order ): bool { + return $this->is_paid_transition( $old_order ) || ! $order->is_initialized( 'expires_at' ); + } + private function refresh_order_expiration( OrderDTO $order ) { $featured_days = (int) get_directorist_option( 'featured_listing_time', 30 ); $order_expiration = directorist_now()->add_days( $featured_days ); From 8c6e90f5ea86a066f893a9445b31ce786b3b3420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rabbi=20Islam=20Rony=20=E2=9A=A1=EF=B8=8F?= <35329385+RabbiIslamRony@users.noreply.github.com> Date: Sun, 30 Aug 2026 16:36:43 +0600 Subject: [PATCH 20/21] fix: preserve archive filter directory context --- assets/build/js/public/search-form.js | 2 +- assets/src/js/public/search-form.js | 51 ++++++++++++++++++++------- includes/model/Listings.php | 4 +++ 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/assets/build/js/public/search-form.js b/assets/build/js/public/search-form.js index 9bfa653644..9b25673a9b 100644 --- a/assets/build/js/public/search-form.js +++ b/assets/build/js/public/search-form.js @@ -1 +1 @@ -!function(){var t={8324:function(){function t(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,r=Array(e);i'.concat(r,"");t.append(n)}var a=t.find(".directorist-select2-dropdown-toggle");e(".select2-hidden-accessible").on("select2:open",function(t){e(this).next().find(".directorist-select2-dropdown-toggle").addClass("--is-open")}),e(".select2-hidden-accessible").on("select2:close",function(t){e(this).next().find(".directorist-select2-dropdown-toggle").removeClass("--is-open");var i=e(this).closest(".directorist-search-field");e(this).next().find(".select2-selection__rendered").attr("title")?i.addClass("input-has-value"):i.removeClass("input-is-focused")}),a.on("click",function(t){var i=e(this).hasClass("--is-open"),r=e(this).closest(".select2-container").siblings("select:enabled");i?r.select2("close"):r.select2("open")}),s()}}(),function(){var i=e(".select2-hidden-accessible");if(i||i.length){var r,o=function(e,i){var r="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!r){if(Array.isArray(e)||(r=function(e,i){if(e){if("string"==typeof e)return t(e,i);var r={}.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?t(e,i):void 0}}(e))||i&&e&&"number"==typeof e.length){r&&(e=r);var n=0,o=function(){};return{s:o,n:function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}},e:function(t){throw t},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,c=!1;return{s:function(){r=r.call(e)},n:function(){var t=r.next();return a=t.done,t},e:function(t){c=!0,s=t},f:function(){try{a||null==r.return||r.return()}finally{if(c)throw s}}}}(i);try{for(o.s();!(r=o.n()).done;){var s=r.value;e(s).children("option:selected").val()&&n(s)}}catch(t){o.e(t)}finally{o.f()}}}(),e(".select2-hidden-accessible").on("change",function(t){if(e(this).children("option:selected").val()){n(e(this)),this.parentElement.querySelectorAll(".select2-selection__choice").forEach(function(t){t.childNodes&&t.childNodes.forEach(function(e){if(e.nodeType&&e.nodeType===Node.TEXT_NODE){var i=e.textContent.replace(/^[\s\xa0]+/,"");e.textContent=i,t.title=i}})});var i=this.parentElement.querySelector(".select2-selection__rendered");i.childNodes&&i.childNodes.forEach(function(t){if(t.nodeType&&t.nodeType===Node.TEXT_NODE){var e=t.textContent.replace(/^[\s\xa0]+/,"");t.textContent=e}})}})}function n(t){e(".select2-selection__clear").css({display:"none"});var i=o(t);if(i&&i.length){i.find(".directorist-select2-dropdown-close").remove();var r=directorist.assets_url+"icons/font-awesome/svgs/solid/times.svg",n=directorist.icon_markup.replace("##URL##",r).replace("##CLASS##","");i.prepend(''.concat(n,"")),i.find(".directorist-select2-dropdown-close").on("click",function(t){e(this).closest(".select2-container").siblings("select:enabled").val(null).trigger("change"),i.find(".directorist-select2-dropdown-close").remove(),s()}),s()}}function o(t){var i=t?e(t).next(".select2-container"):e(".select2-container");if((i=e(i).find(".directorist-select2-addons-area")).length||(e(".select2-container").append(''),i=e(".select2-container").find(".directorist-select2-addons-area")),!(i=t?e(t).next(".select2-container"):null))return null;var r=e(i).find(".directorist-select2-addons-area");return r.length?r:(i.append(''),i.find(".directorist-select2-addons-area"))}function s(){var t=e(".select2-container").find(".directorist-select2-addons-area");if(t.length){var i=t.outerWidth();e(".select2-container").find(".select2-selection__rendered").css({"padding-right":i+"px"})}}window.addEventListener("load",i),window.addEventListener("directorist-search-form-nav-tab-reloaded",i),window.addEventListener("directorist-type-change",i),window.addEventListener("directorist-instant-search-reloaded",i)},3563:function(){var t;t=jQuery,void 0===window.directorist_colorPicker_executed&&(window.directorist_colorPicker_executed=!0,window.addEventListener("load",function(){function e(){document.querySelectorAll(".directorist-color-picker-wrap").forEach(function(e){var i=t(e).find(".directorist-color-picker");i&&(t.fn.wpColorPicker?i.wpColorPicker({change:function(t,e){var i=e.color.toString(),r=new CustomEvent("directorist-color-changed",{detail:{color:i,input:t.target,form:t.target.closest("form")}});window.dispatchEvent(r)}}):console.warn("wpColorPicker is NOT available!"))})}e(),window.addEventListener("directorist-instant-search-reloaded",e)}))},8883:function(){var t;t=jQuery,void 0===window.directorist_dropdown_executed&&(window.directorist_dropdown_executed=!0,window.addEventListener("load",function(){var e=document.querySelectorAll(".directorist-dropdown-select"),i=0;null!==e&&e.forEach(function(t){t.querySelector(".directorist-dropdown-select-toggle").addEventListener("click",function(e){e.preventDefault(),++i%2==1?(document.querySelectorAll(".directorist-dropdown-select-items").forEach(function(t){t.classList.remove("directorist-dropdown-select-show")}),t.querySelector(".directorist-dropdown-select-items").classList.add("directorist-dropdown-select-show")):document.querySelectorAll(".directorist-dropdown-select-items").forEach(function(t){t.classList.remove("directorist-dropdown-select-show")})})}),document.body.addEventListener("click",function(t){"directorist-dropdown-select-toggle"!==t.target.getAttribute("data-drop-toggle")&&(i=0,document.querySelectorAll(".directorist-dropdown-select-items").forEach(function(t){t.classList.remove("directorist-dropdown-select-show")}))});var r=document.querySelectorAll(".atbd-drop-select");null!==r&&r.forEach(function(t){t.querySelectorAll(".directorist-dropdown-select-items").forEach(function(e){e.addEventListener("click",function(i){i.preventDefault(),t.querySelector(".directorist-dropdown-select-toggle").textContent=i.target.textContent,t.querySelectorAll(".directorist-dropdown-select-items").forEach(function(t){t.classList.remove("atbd-active")}),e.classList.add("atbd-active")})})}),t("body").on("click",".directorist-dropdown .directorist-dropdown-toggle",function(e){e.preventDefault(),t(this).siblings(".directorist-dropdown-option").toggle()}),t("body").on("click",".directorist-dropdown .directorist-dropdown-option ul li a",function(e){e.preventDefault();var i=t(this).html();t(this).children(".directorist-dropdown-toggle__text").html(i),t(this).closest(".directorist-dropdown-option").siblings(".directorist-dropdown-toggle").children(".directorist-dropdown-toggle__text").html(i),t(".directorist-dropdown-option").hide()}),t(document).bind("click",function(e){t(e.target).parents().hasClass("directorist-dropdown")||t(".directorist-dropdown-option").hide()}),t(document).on("click",".atbd_dropdown",function(e){"atbd_dropdown"===t(this).attr("class")&&(e.preventDefault(),t(this).siblings(".atbd_dropdown").removeClass("atbd_drop--active"),t(this).toggleClass("atbd_drop--active"),e.stopPropagation())}),t(document).on("click",function(e){!1===t(e.target).is(".atbd_dropdown, .atbd_drop--active")&&t(".atbd_dropdown").removeClass("atbd_drop--active")}),t("body").on("click",".atbd_dropdown-toggle",function(t){t.preventDefault()}),t("body").on("click",".directorist-dropdown-js .directorist-dropdown__toggle-js",function(e){e.preventDefault(),t(this).siblings(".directorist-dropdown__links-js").is(":visible")||t(".directorist-dropdown__links").hide(),t(this).siblings(".directorist-dropdown__links-js").toggle()}),t("body").on("click",function(e){e.target.closest(".directorist-dropdown-js")||t(".directorist-dropdown__links-js").hide()})}))},5386:function(){window.addEventListener("load",function(){if(void 0===window.directorist_select_executed){window.directorist_select_executed=!0;var t=document.querySelectorAll(".atbd-drop-select");null!==t&&t.forEach(function(t){t.querySelectorAll(".atbd-dropdown-item").forEach(function(e){e.addEventListener("click",function(i){i.preventDefault(),t.querySelector(".atbd-dropdown-toggle").textContent=e.textContent,t.querySelectorAll(".atbd-dropdown-item").forEach(function(t){t.classList.remove("atbd-active")}),e.classList.add("atbd-active")})})}),document.querySelectorAll(".atbd-drop-select.with-sort").forEach(function(t){t.querySelectorAll(".atbd-dropdown-item").forEach(function(e){var i=t.querySelector(".atbd-dropdown-toggle"),r=e.getAttribute("data-status");e.addEventListener("click",function(t){i.setAttribute("data-status","".concat(r))})})})}})}},e={};function i(r){var n=e[r];if(void 0!==n)return n.exports;var o=e[r]={exports:{}};return t[r](o,o.exports,i),o.exports}!function(){"use strict";function t(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,r=Array(e);i?@[\]^`{|}~\\])/g,"\\$1")}function m(t){if(!t||"string"!=typeof t)return"";var e=t;return t.includes("[")&&(e=t.split("[")[0]),e.endsWith("[]")&&(e=e.slice(0,-2)),e}function g(t){if(!t||"string"!=typeof t)return t;var e=String(t).trim();if(e.startsWith("custom-"))return e;var i=e.match(/^(select|radio|checkbox)(?:_(\d+))?$/i);if(i){var r=i[2]?"-"+i[2]:"";return"custom-"+i[1].toLowerCase()+r}return e}function v(t,e){if(!t||!t.length||!e)return[];var i=[];return t.find(".select2-selection__choice").each(function(){var t=e(this),r=t.find(".select2-selection__choice__display").text().trim()||t.text().trim().replace("×","").trim();r&&i.push(r)}),i}function _(t,e){if(t&&t.length&&e){var i=[],r=[],n=t.is(d.CATEGORY_CHECKLIST)||t.closest(d.CATEGORY_CHECKLIST).length>0||t.is(d.LOCATION_CHECKLIST)||t.closest(d.LOCATION_CHECKLIST).length>0;if(!n&&t.hasClass("select2-hidden-accessible")&&"function"==typeof t.select2)try{var o=t.select2("data");o&&o.length>0&&o.forEach(function(t){t.text&&i.push(t.text),t.id&&r.push(String(t.id))})}catch(t){}if(n&&0===i.length&&0===r.length&&t.find("input:checked").each(function(){var t=e(this);r.push(String(t.val()));var n=t.closest("label").text().trim();n&&i.push(n)}),0===i.length){var s=t.next(".select2-container");s.length&&v(s,e).forEach(function(t){return i.push(t)})}var a=t.val();a&&0===r.length&&(Array.isArray(a)?a:[a]).forEach(function(t){t&&r.push(String(t))}),t.attr("data-selected-label",i.join(",")),t.attr("data-selected-id",r.join(","))}}function y(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"OR";return null==t||""===t?e:String(t).trim().toUpperCase()||e}function b(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,r=Array(e);i=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:n}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,s=!0,a=!1;return{s:function(){i=i.call(t)},n:function(){var t=i.next();return s=t.done,t},e:function(t){a=!0,o=t},f:function(){try{s||null==i.return||i.return()}finally{if(a)throw o}}}}function C(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,r=Array(e);i0;default:return!1}}(e,r,i);var o=e,s=r;switch("string"==typeof o&&(o=o.trim().toLowerCase()),"string"==typeof s&&(s=s.trim().toLowerCase()),i){case"is":case"==":case"=":return String(o)===String(s);case"is not":case"!=":case"not":return String(o)!==String(s);case"contains":return"string"==typeof o&&"string"==typeof s&&o.toLowerCase().includes(s.toLowerCase());case"does not contain":return"string"!=typeof o||"string"!=typeof s||!o.toLowerCase().includes(s.toLowerCase());case"greater than":case">":return Number(o)>Number(s);case"less than":case"<":return Number(o)=":return Number(o)>=Number(s);case"less than or equal":case"<=":return Number(o)<=Number(s);case"starts with":return"string"==typeof o&&"string"==typeof s&&o.startsWith(s);case"ends with":return"string"==typeof o&&"string"==typeof s&&o.endsWith(s);default:return!1}}function A(t,e){var i="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!i){if(Array.isArray(t)||(i=function(t,e){if(t){if("string"==typeof t)return L(t,e);var i={}.toString.call(t).slice(8,-1);return"Object"===i&&t.constructor&&(i=t.constructor.name),"Map"===i||"Set"===i?Array.from(t):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?L(t,e):void 0}}(t))||e&&t&&"number"==typeof t.length){i&&(t=i);var r=0,n=function(){};return{s:n,n:function(){return r>=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:n}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,s=!0,a=!1;return{s:function(){i=i.call(t)},n:function(){var t=i.next();return s=t.done,t},e:function(t){a=!0,o=t},f:function(){try{s||null==i.return||i.return()}finally{if(a)throw o}}}}function L(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,r=Array(e);i0,a=l.includes(e)||l.includes(i)||s&&(r.is(d.CATEGORY)||r.is(d.TAGS)||r.is(d.LOCATION)||r.is(d.IN_LOC)||r.is(d.IN_CAT)||r.is(d.IN_TAG)||r.closest(d.CATEGORY_CHECKLIST).length||r.closest(d.LOCATION_CHECKLIST).length||r.closest(d.TAGS_CHECKLIST).length),u=A(t.groups);try{for(u.s();!(o=u.n()).done;){var f=o.value;if(f.conditions&&Array.isArray(f.conditions)){var p,h=A(f.conditions);try{for(h.s();!(p=h.n()).done;){var m=(p.value.field||"").trim(),g=c[m]||m,v=n(m),_=null;if(e&&e.startsWith("custom-")&&(_=e.replace(/^custom-/,"").replace(/-/g,"_")),i&&i.startsWith("custom-")){var y=i.replace(/^custom-/,"");_||(_=y)}var b=s?r.attr("id"):null,w=s?r.attr("name"):null;if("review"===m&&("search_by_rating"===e||"search_by_rating[]"===i)||"search_by_rating"===m&&"review"===e||m===e||m===i||m===b||m===w||g===e||g===i||g===b||g===w||v&&(v===e||v===i||v===b||v===w||"custom_field[".concat(v,"]")===i||"custom_field[".concat(v,"][]")===i)||_&&(m===_||g===_))return!0}}catch(t){h.e(t)}finally{h.f()}}}}catch(t){u.e(t)}finally{u.f()}if(a){var C,S=A(t.groups);try{for(S.s();!(C=S.n()).done;){var E=C.value;if(E.conditions&&Array.isArray(E.conditions)){var L,k=A(E.conditions);try{for(k.s();!(L=k.n()).done;){var x=L.value;if(l.includes(x.field))return!0}}catch(t){k.e(t)}finally{k.f()}}}}catch(t){S.e(t)}finally{S.f()}}return!1}(JSON.parse(a),e,t,n,g);f&&i(o)}catch(t){console.error("Error in conditional logic evaluation:",t)}})}!function(t,e){var i="".concat(d.CATEGORY,", ").concat(d.TAGS,", ").concat(d.LOCATION,", ").concat(d.IN_LOC,", ").concat(d.IN_CAT);function r(){var i=t("".concat(d.TAG_METABOX," .tagchecklist"));i.length&&"undefined"!=typeof MutationObserver&&new MutationObserver(function(){e("tax_input[at_biz_dir-tags][]","tax_input[at_biz_dir-tags][]",i)}).observe(i[0],{childList:!0,subtree:!0})}t(document).on("change select2:select select2:unselect select2:clear",i,function(){setTimeout(function(){var i=t(this);if(i.length){var r="category",n="admin_category_select[]";i.is(d.TAGS)?(r="tag",n=i.attr("name")||"tag"):i.is(d.LOCATION)||i.is(d.IN_LOC)?(r="location",n=i.attr("name")||"tax_input[at_biz_dir-location][]"):i.is(d.IN_CAT)&&(r="category",n=i.attr("name")||"in_cat"),_(i,t),e(n,r,i)}}.bind(this),50)}),t(document).on("click","".concat(d.TAG_METABOX," .ntdelbutton, ").concat(d.TAG_METABOX," input.tagadd, ").concat(d.TAG_METABOX," .button"),function(){setTimeout(function(){e("tax_input[at_biz_dir-tags][]","tax_input[at_biz_dir-tags][]",t("".concat(d.TAG_METABOX," .tagchecklist")))},100)}),t(document).on("keypress","".concat(d.TAG_METABOX," input.newtag, ").concat(d.TAGS," input.newtag"),function(i){13===i.which&&setTimeout(function(){e("tax_input[at_biz_dir-tags][]","tax_input[at_biz_dir-tags][]",t("".concat(d.TAG_METABOX," .tagchecklist, ").concat(d.TAGS," .tagchecklist")))},50)}),r(),setTimeout(r,1e3)}(r,n),function(t,e,i){var r=t().split(",").map(function(t){return t.trim()}).flatMap(function(t){return[t+" input",t+" select",t+" textarea",t+" .select2-hidden-accessible"]}).join(", ");function n(t){var r=e(t),n=r.attr("name")||r.attr("id");if(n){var o=m(n);setTimeout(function(){i(n,o,r)},50)}}e(document).on("change input select2:select select2:unselect",r,function(){var t=e(this),r=t.attr("name")||t.attr("id");if(r){var n=function(t,e){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:d,r=m(t);return"post_title"===t||"title"===e.attr("id")?{fieldKey:"listing_title",fieldName:t,taxonomyFieldSelector:null}:"q"===t||"q"===e.attr("name")&&e.closest(".directorist-search-query, .directorist-search-form-wrap, .directorist-search-form").length?{fieldKey:"title",fieldName:t,taxonomyFieldSelector:null}:"content"===t||"content"===e.attr("id")?{fieldKey:"listing_content",fieldName:t,taxonomyFieldSelector:null}:"admin_category_select[]"===t||e.is(i.CATEGORY)?{fieldKey:"category",fieldName:t,taxonomyFieldSelector:i.CATEGORY}:"tax_input[at_biz_dir-category][]"===t||e.closest(i.CATEGORY_CHECKLIST).length?{fieldKey:"admin_category_select[]",fieldName:t,taxonomyFieldSelector:i.CATEGORY_CHECKLIST_ID}:"tax_input[at_biz_dir-location][]"===t||e.closest(i.LOCATION_CHECKLIST).length?{fieldKey:"tax_input[at_biz_dir-location][]",fieldName:t,taxonomyFieldSelector:i.LOCATION_CHECKLIST_ID}:"tax_input[at_biz_dir-tags][]"===t||e.closest(i.TAGS_CHECKLIST).length?{fieldKey:"tax_input[at_biz_dir-tags][]",fieldName:t,taxonomyFieldSelector:i.TAGS_CHECKLIST_ID}:e.is(i.TAGS)?{fieldKey:"tag",fieldName:t,taxonomyFieldSelector:i.TAGS}:e.is(i.LOCATION)?{fieldKey:"location",fieldName:t,taxonomyFieldSelector:i.LOCATION}:"in_loc"===t||e.is(i.IN_LOC)?{fieldKey:"location",fieldName:t,taxonomyFieldSelector:u}:("address"===t||e.is("input[name='address']"))&&e.closest(".directorist-search-location").length?{fieldKey:"location",fieldName:t,taxonomyFieldSelector:f}:"in_cat"===t||e.is(i.IN_CAT)?{fieldKey:"category",fieldName:t,taxonomyFieldSelector:u}:"in_tag[]"===t||e.is(i.IN_TAG)?{fieldKey:"tag",fieldName:t,taxonomyFieldSelector:u}:{fieldKey:r,fieldName:t,taxonomyFieldSelector:null}}(r,t),o=n.fieldKey,s=n.taxonomyFieldSelector;if(s){if(s===f)return void setTimeout(function(){i(r,o,t)},50);var a=s===u?t:e(s);setTimeout(function(){a.length&&_(a,e),i(r,o,t)},50)}else i(r,o,t)}else console.warn("Field change detected but no name/id found:",t)}),e(document).on("click",".directorist-search-field__btn--clear",function(){var t=function(t){if(!t||!t.length)return{fieldKey:null,fieldName:null,$changedField:null};for(var e=0,i=[{sel:'input[name="in_tag[]"]',fieldKey:"tag",fieldName:"in_tag[]"},{sel:"select[name='in_cat']",fieldKey:"category",fieldName:"in_cat"},{sel:"select[name='in_loc']",fieldKey:"location",fieldName:"in_loc"},{sel:'input[name="search_by_rating[]"]',fieldKey:"search_by_rating",fieldName:"search_by_rating[]"},{sel:'input[name="email"]',fieldKey:"email",fieldName:"email"},{sel:'input[name="phone"]',fieldKey:"phone",fieldName:"phone"},{sel:'input[name="phone2"]',fieldKey:"phone2",fieldName:"phone2"},{sel:'input[name="fax"]',fieldKey:"fax",fieldName:"fax"},{sel:'input[name="website"]',fieldKey:"website",fieldName:"website"},{sel:'input[name="zip"]',fieldKey:"zip",fieldName:"zip"}];e0&&i.addedNodes.forEach(function(i){if(1===i.nodeType){var r=t(i);if(r.hasClass("thumb")||r.closest(".plupload-thumbs").length||r.find(".thumb").length){var n=r.closest(".directorist-form-group, .directorist-custom-field-file-upload");if(n.length){var o=k(n);o&&setTimeout(function(){e(o,o,n.find('input[type="hidden"]').first())},100)}}if(r.hasClass("ezmu__preview-section")||r.hasClass("ezmu--show")||r.closest(".ezmu__preview-section.ezmu--show").length){var s=r.closest(".directorist-form-image-upload-field");s.length&&setTimeout(function(){e("listing_img","listing_img",s.find(".ez-media-uploader").first())},200)}}}),i.removedNodes.length>0&&i.removedNodes.forEach(function(r){if(1===r.nodeType){var n=t(r);if(n.hasClass("thumb")||n.closest(".plupload-thumbs").length||n.find(".thumb").length){var o=t(i.target);if(o.hasClass("plupload-thumbs")||o.find(".plupload-thumbs").length){var s=o.closest(".directorist-form-group, .directorist-custom-field-file-upload");if(s.length){var a=k(s);a&&setTimeout(function(){e(a,a,s.find('input[type="hidden"]').first())},300)}}}if(n.hasClass("ezmu__file-item")||n.hasClass("ezmu__new-file")||n.closest(".ez-media-uploader").length||n.hasClass("ezmu__old-files-meta")||n.find(".ezmu__file-item, .ezmu__new-file").length){var c=t(i.target);if(c.hasClass("ez-media-uploader")||c.closest(".ez-media-uploader").length){var l=c.closest(".directorist-form-image-upload-field");l.length&&setTimeout(function(){e("listing_img","listing_img",l.find(".ez-media-uploader").first())},300)}}}})})}).observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["class"]}),document.addEventListener("click",function(i){var r=t(i.target),n=r.closest(".thumbremovelink").length?r.closest(".thumbremovelink"):r.hasClass("thumbremovelink")?r:null;if(n&&n.length){var o=n.closest(".thumb");if(o.length){var s=o.closest(".directorist-form-group, .directorist-custom-field-file-upload");if(s.length){var a=k(s);a&&setTimeout(function(){var t=s.find('input[type="hidden"][name="'.concat(a,'"], input[type="hidden"][name="').concat(a,'[]"]')).first();e(a,a,t.length?t:s.find('input[type="hidden"]').first()||s)},400)}}}},!0)}(r,n),function(t,e){function i(i){if(i&&i.id){var r=i.id,n=t("#"+r);if(n.length){var o=n.closest(".directorist-form-group"),s="content"===r&&n.closest("#postdivrich, #wp-content-wrap").length;if(o.length||s){var a=n.attr("name")||r,l=c[a]||a;i.directoristConditionalLogicBound||(i.on("input keyup change NodeChange",function(){e(a,l,n)}),i.directoristConditionalLogicBound=!0)}}}}"undefined"!=typeof tinymce&&(t(document).ready(function(){try{"function"==typeof tinymce.on&&tinymce.on("AddEditor",function(t){t&&t.editor&&i(t.editor)})}catch(t){}function t(){try{"undefined"!=typeof tinymce&&tinymce.editors&&"function"==typeof tinymce.editors.forEach&&tinymce.editors.forEach(function(t){t&&i(t)})}catch(t){}}t(),setTimeout(t,500),setTimeout(t,1e3),setTimeout(t,2e3)}),t(document).on("tinymce-editor-init",function(t,e){e&&i(e)}))}(r,n)}function O(t,e,i){var r;return function(){var n=this,o=arguments,s=i&&!r;clearTimeout(r),r=setTimeout(function(){r=null,i||t.apply(n,o)},e),s&&t.apply(n,o)}}i(8324);var N=jQuery;function q(t,e){var i=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),i.push.apply(i,r)}return i}function z(t){for(var e=1;e