From 8c8444559b798e17a1a7599ec2f0967a9b1d9e2b Mon Sep 17 00:00:00 2001 From: Towfiqul Islam <43319312+towfiq1997@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:03:55 +0600 Subject: [PATCH 1/2] Add global setting and campaign-level override for post-goal behavior. Enforce behavior in donation product and frontend: --- includes/Admin/Actions.php | 10 ++++---- includes/Admin/Settings.php | 12 ++++++++++ includes/Admin/views/campaigns/add.php | 17 +++++++++++++ includes/Admin/views/campaigns/edit.php | 15 ++++++++++++ includes/Donation/class-donation-product.php | 25 ++++++++++++++++++++ includes/Frontend/Orders.php | 5 ++++ includes/Frontend/Product.php | 15 ++++++++++++ includes/functions.php | 14 +++++++++++ 8 files changed, 109 insertions(+), 4 deletions(-) diff --git a/includes/Admin/Actions.php b/includes/Admin/Actions.php index 57a3042..78c140f 100644 --- a/includes/Admin/Actions.php +++ b/includes/Admin/Actions.php @@ -50,8 +50,9 @@ public static function add_campaign() { 'post_content' => $cause, 'post_status' => $status, 'meta_input' => array( - 'wcdm_goal_amount' => $goal_amount, - '_end_date' => $end_date, + 'wcdm_goal_amount' => $goal_amount, + '_end_date' => $end_date, + 'wcdm_goal_behavior' => ( ! empty( $_POST['goal_behavior'] ) ? sanitize_key( wp_unslash( $_POST['goal_behavior'] ) ) : get_option( 'wcdm_goal_behavior', 'continue' ) ), ), ); @@ -96,8 +97,9 @@ public static function edit_campaign() { 'post_content' => wp_kses_post( $cause ), 'post_status' => $status, 'meta_input' => array( - 'wcdm_goal_amount' => $goal_amount, - '_end_date' => $end_date, + 'wcdm_goal_amount' => $goal_amount, + '_end_date' => $end_date, + 'wcdm_goal_behavior' => ( ! empty( $_POST['goal_behavior'] ) ? sanitize_key( wp_unslash( $_POST['goal_behavior'] ) ) : get_option( 'wcdm_goal_behavior', 'continue' ) ), ), ); diff --git a/includes/Admin/Settings.php b/includes/Admin/Settings.php index 025e8fa..c7551e0 100644 --- a/includes/Admin/Settings.php +++ b/includes/Admin/Settings.php @@ -160,6 +160,18 @@ public function get_settings( $tab ) { 'default' => 'no', 'type' => 'checkbox', ), + array( + 'title' => __( 'Donation behaviour after goal completion', 'wc-donation-manager' ), + 'desc' => __( 'Define what should happen when a campaign reaches its goal.', 'wc-donation-manager' ), + 'id' => 'wcdm_goal_behavior', + 'type' => 'select', + 'default' => 'continue', + 'options' => array( + 'continue' => __( 'Continue accepting donations', 'wc-donation-manager' ), + 'close' => __( 'Close campaign automatically', 'wc-donation-manager' ), + 'soft_close' => __( 'Show as completed but still allow donations', 'wc-donation-manager' ), + ), + ), array( 'type' => 'sectionend', 'id' => 'advanced_options', diff --git a/includes/Admin/views/campaigns/add.php b/includes/Admin/views/campaigns/add.php index 4da3a78..b91cc01 100644 --- a/includes/Admin/views/campaigns/add.php +++ b/includes/Admin/views/campaigns/add.php @@ -72,6 +72,23 @@

+ + + + + + + +

+ +

+ + diff --git a/includes/Admin/views/campaigns/edit.php b/includes/Admin/views/campaigns/edit.php index 38d89ef..46f5d24 100644 --- a/includes/Admin/views/campaigns/edit.php +++ b/includes/Admin/views/campaigns/edit.php @@ -87,6 +87,21 @@

+ +
+ +
+ ID, 'wcdm_goal_behavior', true ); ?> + +

+
+
diff --git a/includes/Donation/class-donation-product.php b/includes/Donation/class-donation-product.php index 177e1c4..97d3080 100644 --- a/includes/Donation/class-donation-product.php +++ b/includes/Donation/class-donation-product.php @@ -38,6 +38,31 @@ public function is_sold_individually() { return true; } + /** + * Override purchasable behavior to respect campaign goal behavior. + * + * @since 1.0.0 + * @return bool + */ + public function is_purchasable() { + $base = parent::is_purchasable(); + if ( ! $base ) { + return false; + } + + $campaign_id = get_post_meta( $this->get_id(), 'wcdm_campaign_id', true ); + if ( $campaign_id ) { + $behavior = wcdm_get_goal_behavior( $campaign_id ); + $raised = (float) get_post_meta( $campaign_id, '_raised_amount', true ); + $goal = (float) get_post_meta( $campaign_id, 'wcdm_goal_amount', true ); + if ( 'close' === $behavior && $goal > 0 && $raised >= $goal ) { + return false; + } + } + + return true; + } + /** * Get the add to cart button text. * diff --git a/includes/Frontend/Orders.php b/includes/Frontend/Orders.php index 6f36867..f3cfe78 100644 --- a/includes/Frontend/Orders.php +++ b/includes/Frontend/Orders.php @@ -86,6 +86,11 @@ public static function order_status_completed( $order_id, $order ) { $raised_amount += (float) $item['subtotal']; update_post_meta( $item['product_id'], 'wcdm_orders_id', $orders_id ); update_post_meta( $campaign_id, '_raised_amount', $raised_amount ); + $behavior = wcdm_get_goal_behavior( $campaign_id ); + $goal = (float) get_post_meta( $campaign_id, 'wcdm_goal_amount', true ); + if ( 'close' === $behavior && $goal > 0 && $raised_amount >= $goal ) { + update_post_meta( $campaign_id, 'wcdm_goal_completed', 'yes' ); + } } } } diff --git a/includes/Frontend/Product.php b/includes/Frontend/Product.php index 924e43e..f82138b 100644 --- a/includes/Frontend/Product.php +++ b/includes/Frontend/Product.php @@ -170,6 +170,21 @@ public static function add_to_cart_template(): void { return; } + // Respect campaign goal behavior. + $raised = (float) get_post_meta( $campaign_id, '_raised_amount', true ); + $goal = (float) get_post_meta( $campaign_id, 'wcdm_goal_amount', true ); + $behavior = wcdm_get_goal_behavior( $campaign_id ); + if ( $goal > 0 && $raised >= $goal ) { + if ( 'close' === $behavior ) { + printf( '%1$s%2$s%3$s', '

', esc_html__( 'This campaign has reached its goal and is now closed.', 'wc-donation-manager' ), '

' ); + return; + } + if ( 'soft_close' === $behavior ) { + printf( '%1$s%2$s%3$s', '

', esc_html__( 'This campaign has reached its goal but is still accepting donations.', 'wc-donation-manager' ), '

' ); + // continue to allow donations + } + } + do_action( 'woocommerce_simple_add_to_cart' ); } diff --git a/includes/functions.php b/includes/functions.php index eaf7b95..07b3087 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -94,6 +94,20 @@ function wcdm_get_campaign_products( $campaign_id ) { return $query->posts; } +/** + * Get goal behavior for a campaign. + * + * @param int $campaign_id Campaign ID. + * @return string + */ +function wcdm_get_goal_behavior( $campaign_id ) { + $behavior = get_post_meta( $campaign_id, 'wcdm_goal_behavior', true ); + if ( ! $behavior ) { + $behavior = get_option( 'wcdm_goal_behavior', 'continue' ); + } + return $behavior; +} + /** * Get the post title. * From cac34260e937aa4374c6f1892ece199b451e93d9 Mon Sep 17 00:00:00 2001 From: Towfiqul Islam <43319312+towfiq1997@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:09:43 +0600 Subject: [PATCH 2/2] Linting issue fixed --- includes/Frontend/Product.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/includes/Frontend/Product.php b/includes/Frontend/Product.php index f82138b..56b53d6 100644 --- a/includes/Frontend/Product.php +++ b/includes/Frontend/Product.php @@ -170,9 +170,8 @@ public static function add_to_cart_template(): void { return; } - // Respect campaign goal behavior. - $raised = (float) get_post_meta( $campaign_id, '_raised_amount', true ); - $goal = (float) get_post_meta( $campaign_id, 'wcdm_goal_amount', true ); + $raised = (float) get_post_meta( $campaign_id, '_raised_amount', true ); + $goal = (float) get_post_meta( $campaign_id, 'wcdm_goal_amount', true ); $behavior = wcdm_get_goal_behavior( $campaign_id ); if ( $goal > 0 && $raised >= $goal ) { if ( 'close' === $behavior ) { @@ -181,7 +180,6 @@ public static function add_to_cart_template(): void { } if ( 'soft_close' === $behavior ) { printf( '%1$s%2$s%3$s', '

', esc_html__( 'This campaign has reached its goal but is still accepting donations.', 'wc-donation-manager' ), '

' ); - // continue to allow donations } }