@@ -553,6 +553,7 @@ public function test_check_permissions_catches_callback_exception() {
553553 public function test_before_execute_ability_action () {
554554 $ action_ability_name = null ;
555555 $ action_input = null ;
556+ $ action_ability = null ;
556557
557558 $ args = array_merge (
558559 self ::$ test_ability_properties ,
@@ -570,19 +571,21 @@ public function test_before_execute_ability_action() {
570571
571572 add_action (
572573 'wp_before_execute_ability ' ,
573- static function ( $ ability_name , $ input ) use ( &$ action_ability_name , &$ action_input ) {
574+ static function ( $ ability_name , $ input, $ ability ) use ( &$ action_ability_name , &$ action_input, & $ action_ability ) {
574575 $ action_ability_name = $ ability_name ;
575576 $ action_input = $ input ;
577+ $ action_ability = $ ability ;
576578 },
577579 10 ,
578- 2
580+ 3
579581 );
580582
581583 $ ability = new WP_Ability ( self ::$ test_ability_name , $ args );
582584 $ result = $ ability ->execute ( 5 );
583585
584586 $ this ->assertSame ( self ::$ test_ability_name , $ action_ability_name , 'Action should receive correct ability name ' );
585587 $ this ->assertSame ( 5 , $ action_input , 'Action should receive correct input ' );
588+ $ this ->assertSame ( $ ability , $ action_ability , 'Action should receive the ability instance ' );
586589 $ this ->assertSame ( 10 , $ result , 'Ability should execute correctly ' );
587590 }
588591
@@ -594,6 +597,7 @@ static function ( $ability_name, $input ) use ( &$action_ability_name, &$action_
594597 public function test_before_execute_ability_action_no_input () {
595598 $ action_ability_name = null ;
596599 $ action_input = null ;
600+ $ action_ability = null ;
597601
598602 $ args = array_merge (
599603 self ::$ test_ability_properties ,
@@ -606,19 +610,21 @@ public function test_before_execute_ability_action_no_input() {
606610
607611 add_action (
608612 'wp_before_execute_ability ' ,
609- static function ( $ ability_name , $ input ) use ( &$ action_ability_name , &$ action_input ) {
613+ static function ( $ ability_name , $ input, $ ability ) use ( &$ action_ability_name , &$ action_input, & $ action_ability ) {
610614 $ action_ability_name = $ ability_name ;
611615 $ action_input = $ input ;
616+ $ action_ability = $ ability ;
612617 },
613618 10 ,
614- 2
619+ 3
615620 );
616621
617622 $ ability = new WP_Ability ( self ::$ test_ability_name , $ args );
618623 $ result = $ ability ->execute ();
619624
620625 $ this ->assertSame ( self ::$ test_ability_name , $ action_ability_name , 'Action should receive correct ability name ' );
621626 $ this ->assertNull ( $ action_input , 'Action should receive null input when no input provided ' );
627+ $ this ->assertSame ( $ ability , $ action_ability , 'Action should receive the ability instance ' );
622628 $ this ->assertSame ( 42 , $ result , 'Ability should execute correctly ' );
623629 }
624630
@@ -631,6 +637,7 @@ public function test_after_execute_ability_action() {
631637 $ action_ability_name = null ;
632638 $ action_input = null ;
633639 $ action_result = null ;
640+ $ action_ability = null ;
634641
635642 $ args = array_merge (
636643 self ::$ test_ability_properties ,
@@ -648,13 +655,14 @@ public function test_after_execute_ability_action() {
648655
649656 add_action (
650657 'wp_after_execute_ability ' ,
651- static function ( $ ability_name , $ input , $ result ) use ( &$ action_ability_name , &$ action_input , &$ action_result ) {
658+ static function ( $ ability_name , $ input , $ result, $ ability ) use ( &$ action_ability_name , &$ action_input , &$ action_result, & $ action_ability ) {
652659 $ action_ability_name = $ ability_name ;
653660 $ action_input = $ input ;
654661 $ action_result = $ result ;
662+ $ action_ability = $ ability ;
655663 },
656664 10 ,
657- 3
665+ 4
658666 );
659667
660668 $ ability = new WP_Ability ( self ::$ test_ability_name , $ args );
@@ -663,6 +671,7 @@ static function ( $ability_name, $input, $result ) use ( &$action_ability_name,
663671 $ this ->assertSame ( self ::$ test_ability_name , $ action_ability_name , 'Action should receive correct ability name ' );
664672 $ this ->assertSame ( 7 , $ action_input , 'Action should receive correct input ' );
665673 $ this ->assertSame ( 21 , $ action_result , 'Action should receive correct result ' );
674+ $ this ->assertSame ( $ ability , $ action_ability , 'Action should receive the ability instance ' );
666675 $ this ->assertSame ( 21 , $ result , 'Ability should execute correctly ' );
667676 }
668677
@@ -675,6 +684,7 @@ public function test_after_execute_ability_action_no_input() {
675684 $ action_ability_name = null ;
676685 $ action_input = null ;
677686 $ action_result = null ;
687+ $ action_ability = null ;
678688
679689 $ args = array_merge (
680690 self ::$ test_ability_properties ,
@@ -688,13 +698,14 @@ public function test_after_execute_ability_action_no_input() {
688698
689699 add_action (
690700 'wp_after_execute_ability ' ,
691- static function ( $ ability_name , $ input , $ result ) use ( &$ action_ability_name , &$ action_input , &$ action_result ) {
701+ static function ( $ ability_name , $ input , $ result, $ ability ) use ( &$ action_ability_name , &$ action_input , &$ action_result, & $ action_ability ) {
692702 $ action_ability_name = $ ability_name ;
693703 $ action_input = $ input ;
694704 $ action_result = $ result ;
705+ $ action_ability = $ ability ;
695706 },
696707 10 ,
697- 3
708+ 4
698709 );
699710
700711 $ ability = new WP_Ability ( self ::$ test_ability_name , $ args );
@@ -703,6 +714,7 @@ static function ( $ability_name, $input, $result ) use ( &$action_ability_name,
703714 $ this ->assertSame ( self ::$ test_ability_name , $ action_ability_name , 'Action should receive correct ability name ' );
704715 $ this ->assertNull ( $ action_input , 'Action should receive null input when no input provided ' );
705716 $ this ->assertSame ( 'test-result ' , $ action_result , 'Action should receive correct result ' );
717+ $ this ->assertSame ( $ ability , $ action_ability , 'Action should receive the ability instance ' );
706718 $ this ->assertSame ( 'test-result ' , $ result , 'Ability should execute correctly ' );
707719 }
708720
@@ -1696,4 +1708,113 @@ static function () {
16961708 $ this ->assertInstanceOf ( WP_Error::class, $ result );
16971709 $ this ->assertSame ( 'custom_output_error ' , $ result ->get_error_code () );
16981710 }
1711+
1712+ /**
1713+ * Tests that wp_ability_invoked action fires with correct parameters and raw input before normalization.
1714+ *
1715+ * @ticket 65248
1716+ */
1717+ public function test_ability_invoked_action_fires_with_correct_params () {
1718+ $ args = array_merge (
1719+ self ::$ test_ability_properties ,
1720+ array (
1721+ 'input_schema ' => array (
1722+ 'type ' => 'integer ' ,
1723+ 'description ' => 'Test input parameter. ' ,
1724+ 'default ' => 42 ,
1725+ ),
1726+ 'execute_callback ' => static function ( int $ input ): int {
1727+ return $ input ;
1728+ },
1729+ )
1730+ );
1731+
1732+ $ action = new MockAction ();
1733+ add_action ( 'wp_ability_invoked ' , array ( $ action , 'action ' ), 10 , 3 );
1734+
1735+ $ ability = new WP_Ability ( self ::$ test_ability_name , $ args );
1736+ $ ability ->execute ();
1737+
1738+ $ action_args = $ action ->get_args ();
1739+ $ this ->assertSame ( self ::$ test_ability_name , $ action_args [0 ][0 ], 'Action should receive correct ability name. ' );
1740+ $ this ->assertNull ( $ action_args [0 ][1 ], 'Action should receive raw null input, not the schema default. ' );
1741+ $ this ->assertSame ( $ ability , $ action_args [0 ][2 ], 'Action should receive the ability instance. ' );
1742+ }
1743+
1744+ /**
1745+ * Tests that wp_ability_invoked action fires when execution is short-circuited.
1746+ *
1747+ * @ticket 65248
1748+ */
1749+ public function test_ability_invoked_action_fires_on_pre_execute_short_circuit () {
1750+ $ action = new MockAction ();
1751+ add_action ( 'wp_ability_invoked ' , array ( $ action , 'action ' ) );
1752+
1753+ add_filter (
1754+ 'wp_pre_execute_ability ' ,
1755+ static function () {
1756+ return 'short-circuited ' ;
1757+ }
1758+ );
1759+
1760+ $ ability = new WP_Ability ( self ::$ test_ability_name , self ::$ test_ability_properties );
1761+ $ ability ->execute ();
1762+
1763+ $ this ->assertSame ( 1 , $ action ->get_call_count (), 'wp_ability_invoked should fire before a pre-execute short-circuit. ' );
1764+ }
1765+
1766+ /**
1767+ * Tests that wp_ability_invoked action fires on permission failure.
1768+ *
1769+ * @ticket 65248
1770+ */
1771+ public function test_ability_invoked_action_fires_on_permission_failure () {
1772+ $ action = new MockAction ();
1773+ add_action ( 'wp_ability_invoked ' , array ( $ action , 'action ' ) );
1774+
1775+ $ ability = new WP_Ability (
1776+ self ::$ test_ability_name ,
1777+ array_merge (
1778+ self ::$ test_ability_properties ,
1779+ array (
1780+ 'permission_callback ' => static function (): bool {
1781+ return false ;
1782+ },
1783+ )
1784+ )
1785+ );
1786+ $ ability ->execute ();
1787+
1788+ $ this ->assertSame ( 1 , $ action ->get_call_count (), 'wp_ability_invoked should fire before permission failure. ' );
1789+ }
1790+
1791+ /**
1792+ * Tests that wp_ability_invoked action fires on input validation failure.
1793+ *
1794+ * @ticket 65248
1795+ */
1796+ public function test_ability_invoked_action_fires_on_validation_failure () {
1797+ $ action = new MockAction ();
1798+ add_action ( 'wp_ability_invoked ' , array ( $ action , 'action ' ) );
1799+
1800+ $ ability = new WP_Ability (
1801+ self ::$ test_ability_name ,
1802+ array_merge (
1803+ self ::$ test_ability_properties ,
1804+ array (
1805+ 'input_schema ' => array (
1806+ 'type ' => 'integer ' ,
1807+ 'description ' => 'Int input. ' ,
1808+ 'required ' => true ,
1809+ ),
1810+ 'execute_callback ' => static function ( int $ input ): int {
1811+ return $ input ;
1812+ },
1813+ )
1814+ )
1815+ );
1816+ $ ability ->execute ( 'not_an_integer ' );
1817+
1818+ $ this ->assertSame ( 1 , $ action ->get_call_count (), 'wp_ability_invoked should fire before input validation failure. ' );
1819+ }
16991820}
0 commit comments