@@ -681,4 +681,132 @@ public function test_log_file_name_constant(): void {
681681
682682 $ this ->assertEquals ('memberships ' , Membership_Manager::LOG_FILE_NAME );
683683 }
684+
685+ // ========================================================================
686+ // handle_pending_site_on_cancellation()
687+ // ========================================================================
688+
689+ /**
690+ * Test init registers the handle_pending_site_on_cancellation hook.
691+ */
692+ public function test_init_registers_handle_pending_site_on_cancellation_hook (): void {
693+
694+ $ manager = $ this ->get_manager_instance ();
695+
696+ $ this ->assertIsInt (
697+ has_action ('wu_transition_membership_status ' , [$ manager , 'handle_pending_site_on_cancellation ' ])
698+ );
699+ }
700+
701+ /**
702+ * Test pending_site is deleted from membership meta on cancellation.
703+ */
704+ public function test_handle_pending_site_on_cancellation_cleans_up_pending_site (): void {
705+
706+ $ membership = $ this ->create_membership (['status ' => Membership_Status::ACTIVE ]);
707+ $ manager = $ this ->get_manager_instance ();
708+
709+ $ membership ->create_pending_site (
710+ [
711+ 'title ' => 'Test Pending Site ' ,
712+ 'path ' => '/testpending/ ' ,
713+ ]
714+ );
715+
716+ $ this ->assertNotFalse ($ membership ->get_pending_site (), 'pending_site should exist before cancellation ' );
717+
718+ $ manager ->handle_pending_site_on_cancellation (
719+ Membership_Status::ACTIVE ,
720+ Membership_Status::CANCELLED ,
721+ $ membership ->get_id ()
722+ );
723+
724+ $ refreshed = wu_get_membership ($ membership ->get_id ());
725+
726+ $ this ->assertFalse ($ refreshed ->get_pending_site (), 'pending_site should be removed after cancellation ' );
727+ }
728+
729+ /**
730+ * Test transient is set with the correct key and 24-hour TTL on cancellation.
731+ */
732+ public function test_handle_pending_site_on_cancellation_sets_transient_with_correct_key (): void {
733+
734+ $ membership = $ this ->create_membership (['status ' => Membership_Status::ACTIVE ]);
735+ $ manager = $ this ->get_manager_instance ();
736+
737+ $ membership ->create_pending_site (
738+ [
739+ 'title ' => 'Transient Test Site ' ,
740+ 'path ' => '/transientpending/ ' ,
741+ ]
742+ );
743+
744+ $ email = $ this ->customer ->get_email_address ();
745+ $ transient_key = 'wu_transferable_pending_ ' . md5 ($ email );
746+
747+ // Ensure transient does not exist before the call.
748+ delete_transient ($ transient_key );
749+ $ this ->assertFalse (get_transient ($ transient_key ), 'transient should not exist before cancellation ' );
750+
751+ $ manager ->handle_pending_site_on_cancellation (
752+ Membership_Status::ACTIVE ,
753+ Membership_Status::CANCELLED ,
754+ $ membership ->get_id ()
755+ );
756+
757+ $ stored = get_transient ($ transient_key );
758+
759+ $ this ->assertNotFalse ($ stored , 'transient should be set after cancellation ' );
760+ }
761+
762+ /**
763+ * Test no transient is set and no error occurs when there is no pending_site.
764+ */
765+ public function test_handle_pending_site_on_cancellation_skips_when_no_pending_site (): void {
766+
767+ $ membership = $ this ->create_membership (['status ' => Membership_Status::ACTIVE ]);
768+ $ manager = $ this ->get_manager_instance ();
769+
770+ // Confirm no pending site exists.
771+ $ this ->assertFalse ($ membership ->get_pending_site ());
772+
773+ $ email = $ this ->customer ->get_email_address ();
774+ $ transient_key = 'wu_transferable_pending_ ' . md5 ($ email );
775+ delete_transient ($ transient_key );
776+
777+ $ manager ->handle_pending_site_on_cancellation (
778+ Membership_Status::ACTIVE ,
779+ Membership_Status::CANCELLED ,
780+ $ membership ->get_id ()
781+ );
782+
783+ $ this ->assertFalse (get_transient ($ transient_key ), 'transient should NOT be set when there is no pending_site ' );
784+ }
785+
786+ /**
787+ * Test non-cancellation transitions do not affect pending_site.
788+ */
789+ public function test_handle_pending_site_on_cancellation_ignores_non_cancelled_status (): void {
790+
791+ $ membership = $ this ->create_membership (['status ' => Membership_Status::ACTIVE ]);
792+ $ manager = $ this ->get_manager_instance ();
793+
794+ $ membership ->create_pending_site (
795+ [
796+ 'title ' => 'Should Stay ' ,
797+ 'path ' => '/shouldstay/ ' ,
798+ ]
799+ );
800+
801+ // Trigger with a non-cancelled new status.
802+ $ manager ->handle_pending_site_on_cancellation (
803+ Membership_Status::ACTIVE ,
804+ Membership_Status::ON_HOLD ,
805+ $ membership ->get_id ()
806+ );
807+
808+ $ refreshed = wu_get_membership ($ membership ->get_id ());
809+
810+ $ this ->assertNotFalse ($ refreshed ->get_pending_site (), 'pending_site should remain intact for non-cancelled transitions ' );
811+ }
684812}
0 commit comments