filters.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. <?php
  2. /**
  3. * Test apply_filters() and related functions
  4. *
  5. * @group hooks
  6. */
  7. class Tests_Filters extends WP_UnitTestCase {
  8. function test_simple_filter() {
  9. $a = new MockAction();
  10. $tag = __FUNCTION__;
  11. $val = __FUNCTION__ . '_val';
  12. add_filter( $tag, array( $a, 'filter' ) );
  13. $this->assertSame( $val, apply_filters( $tag, $val ) );
  14. // Only one event occurred for the hook, with empty args.
  15. $this->assertSame( 1, $a->get_call_count() );
  16. // Only our hook was called.
  17. $this->assertSame( array( $tag ), $a->get_tags() );
  18. $argsvar = $a->get_args();
  19. $args = array_pop( $argsvar );
  20. $this->assertSame( array( $val ), $args );
  21. }
  22. function test_remove_filter() {
  23. $a = new MockAction();
  24. $tag = __FUNCTION__;
  25. $val = __FUNCTION__ . '_val';
  26. add_filter( $tag, array( $a, 'filter' ) );
  27. $this->assertSame( $val, apply_filters( $tag, $val ) );
  28. // Make sure our hook was called correctly.
  29. $this->assertSame( 1, $a->get_call_count() );
  30. $this->assertSame( array( $tag ), $a->get_tags() );
  31. // Now remove the filter, do it again, and make sure it's not called this time.
  32. remove_filter( $tag, array( $a, 'filter' ) );
  33. $this->assertSame( $val, apply_filters( $tag, $val ) );
  34. $this->assertSame( 1, $a->get_call_count() );
  35. $this->assertSame( array( $tag ), $a->get_tags() );
  36. }
  37. function test_has_filter() {
  38. $tag = __FUNCTION__;
  39. $func = __FUNCTION__ . '_func';
  40. $this->assertFalse( has_filter( $tag, $func ) );
  41. $this->assertFalse( has_filter( $tag ) );
  42. add_filter( $tag, $func );
  43. $this->assertSame( 10, has_filter( $tag, $func ) );
  44. $this->assertTrue( has_filter( $tag ) );
  45. remove_filter( $tag, $func );
  46. $this->assertFalse( has_filter( $tag, $func ) );
  47. $this->assertFalse( has_filter( $tag ) );
  48. }
  49. // One tag with multiple filters.
  50. function test_multiple_filters() {
  51. $a1 = new MockAction();
  52. $a2 = new MockAction();
  53. $tag = __FUNCTION__;
  54. $val = __FUNCTION__ . '_val';
  55. // Add both filters to the hook.
  56. add_filter( $tag, array( $a1, 'filter' ) );
  57. add_filter( $tag, array( $a2, 'filter' ) );
  58. $this->assertSame( $val, apply_filters( $tag, $val ) );
  59. // Both filters called once each.
  60. $this->assertSame( 1, $a1->get_call_count() );
  61. $this->assertSame( 1, $a2->get_call_count() );
  62. }
  63. function test_filter_args_1() {
  64. $a = new MockAction();
  65. $tag = __FUNCTION__;
  66. $val = __FUNCTION__ . '_val';
  67. $arg1 = __FUNCTION__ . '_arg1';
  68. add_filter( $tag, array( $a, 'filter' ), 10, 2 );
  69. // Call the filter with a single argument.
  70. $this->assertSame( $val, apply_filters( $tag, $val, $arg1 ) );
  71. $this->assertSame( 1, $a->get_call_count() );
  72. $argsvar = $a->get_args();
  73. $this->assertSame( array( $val, $arg1 ), array_pop( $argsvar ) );
  74. }
  75. function test_filter_args_2() {
  76. $a1 = new MockAction();
  77. $a2 = new MockAction();
  78. $tag = __FUNCTION__;
  79. $val = __FUNCTION__ . '_val';
  80. $arg1 = __FUNCTION__ . '_arg1';
  81. $arg2 = __FUNCTION__ . '_arg2';
  82. // $a1 accepts two arguments, $a2 doesn't.
  83. add_filter( $tag, array( $a1, 'filter' ), 10, 3 );
  84. add_filter( $tag, array( $a2, 'filter' ) );
  85. // Call the filter with two arguments.
  86. $this->assertSame( $val, apply_filters( $tag, $val, $arg1, $arg2 ) );
  87. // $a1 should be called with both args.
  88. $this->assertSame( 1, $a1->get_call_count() );
  89. $argsvar1 = $a1->get_args();
  90. $this->assertSame( array( $val, $arg1, $arg2 ), array_pop( $argsvar1 ) );
  91. // $a2 should be called with one only.
  92. $this->assertSame( 1, $a2->get_call_count() );
  93. $argsvar2 = $a2->get_args();
  94. $this->assertSame( array( $val ), array_pop( $argsvar2 ) );
  95. }
  96. function test_filter_priority() {
  97. $a = new MockAction();
  98. $tag = __FUNCTION__;
  99. $val = __FUNCTION__ . '_val';
  100. // Make two filters with different priorities.
  101. add_filter( $tag, array( $a, 'filter' ), 10 );
  102. add_filter( $tag, array( $a, 'filter2' ), 9 );
  103. $this->assertSame( $val, apply_filters( $tag, $val ) );
  104. // There should be two events, one per filter.
  105. $this->assertSame( 2, $a->get_call_count() );
  106. $expected = array(
  107. // 'filter2' is called first because it has priority 9.
  108. array(
  109. 'filter' => 'filter2',
  110. 'tag' => $tag,
  111. 'args' => array( $val ),
  112. ),
  113. // 'filter' is called second.
  114. array(
  115. 'filter' => 'filter',
  116. 'tag' => $tag,
  117. 'args' => array( $val ),
  118. ),
  119. );
  120. $this->assertSame( $expected, $a->get_events() );
  121. }
  122. function test_all_filter() {
  123. $a = new MockAction();
  124. $tag1 = __FUNCTION__ . '_1';
  125. $tag2 = __FUNCTION__ . '_2';
  126. $val = __FUNCTION__ . '_val';
  127. // Add an 'all' filter.
  128. add_filter( 'all', array( $a, 'filterall' ) );
  129. // Apply some filters.
  130. $this->assertSame( $val, apply_filters( $tag1, $val ) );
  131. $this->assertSame( $val, apply_filters( $tag2, $val ) );
  132. $this->assertSame( $val, apply_filters( $tag1, $val ) );
  133. $this->assertSame( $val, apply_filters( $tag1, $val ) );
  134. // Our filter should have been called once for each apply_filters call.
  135. $this->assertSame( 4, $a->get_call_count() );
  136. // The right hooks should have been called in order.
  137. $this->assertSame( array( $tag1, $tag2, $tag1, $tag1 ), $a->get_tags() );
  138. remove_filter( 'all', array( $a, 'filterall' ) );
  139. $this->assertFalse( has_filter( 'all', array( $a, 'filterall' ) ) );
  140. }
  141. function test_remove_all_filter() {
  142. $a = new MockAction();
  143. $tag = __FUNCTION__;
  144. $val = __FUNCTION__ . '_val';
  145. add_filter( 'all', array( $a, 'filterall' ) );
  146. $this->assertTrue( has_filter( 'all' ) );
  147. $this->assertSame( 10, has_filter( 'all', array( $a, 'filterall' ) ) );
  148. $this->assertSame( $val, apply_filters( $tag, $val ) );
  149. // Make sure our hook was called correctly.
  150. $this->assertSame( 1, $a->get_call_count() );
  151. $this->assertSame( array( $tag ), $a->get_tags() );
  152. // Now remove the filter, do it again, and make sure it's not called this time.
  153. remove_filter( 'all', array( $a, 'filterall' ) );
  154. $this->assertFalse( has_filter( 'all', array( $a, 'filterall' ) ) );
  155. $this->assertFalse( has_filter( 'all' ) );
  156. $this->assertSame( $val, apply_filters( $tag, $val ) );
  157. // Call cound should remain at 1.
  158. $this->assertSame( 1, $a->get_call_count() );
  159. $this->assertSame( array( $tag ), $a->get_tags() );
  160. }
  161. /**
  162. * @ticket 20920
  163. */
  164. function test_remove_all_filters_should_respect_the_priority_argument() {
  165. $a = new MockAction();
  166. $tag = __FUNCTION__;
  167. $val = __FUNCTION__ . '_val';
  168. add_filter( $tag, array( $a, 'filter' ), 12 );
  169. $this->assertTrue( has_filter( $tag ) );
  170. // Should not be removed.
  171. remove_all_filters( $tag, 11 );
  172. $this->assertTrue( has_filter( $tag ) );
  173. remove_all_filters( $tag, 12 );
  174. $this->assertFalse( has_filter( $tag ) );
  175. }
  176. /**
  177. * @ticket 9886
  178. */
  179. function test_filter_ref_array() {
  180. $obj = new stdClass();
  181. $a = new MockAction();
  182. $tag = __FUNCTION__;
  183. add_action( $tag, array( $a, 'filter' ) );
  184. apply_filters_ref_array( $tag, array( &$obj ) );
  185. $args = $a->get_args();
  186. $this->assertSame( $args[0][0], $obj );
  187. // Just in case we don't trust assertSame().
  188. $obj->foo = true;
  189. $this->assertFalse( empty( $args[0][0]->foo ) );
  190. }
  191. /**
  192. * @ticket 12723
  193. */
  194. function test_filter_ref_array_result() {
  195. $obj = new stdClass();
  196. $a = new MockAction();
  197. $b = new MockAction();
  198. $tag = __FUNCTION__;
  199. add_action( $tag, array( $a, 'filter_append' ), 10, 2 );
  200. add_action( $tag, array( $b, 'filter_append' ), 10, 2 );
  201. $result = apply_filters_ref_array( $tag, array( 'string', &$obj ) );
  202. $this->assertSame( $result, 'string_append_append' );
  203. $args = $a->get_args();
  204. $this->assertSame( $args[0][1], $obj );
  205. // Just in case we don't trust assertSame().
  206. $obj->foo = true;
  207. $this->assertFalse( empty( $args[0][1]->foo ) );
  208. $args = $b->get_args();
  209. $this->assertSame( $args[0][1], $obj );
  210. // Just in case we don't trust assertSame().
  211. $obj->foo = true;
  212. $this->assertFalse( empty( $args[0][1]->foo ) );
  213. }
  214. function _self_removal( $tag ) {
  215. remove_action( $tag, array( $this, '_self_removal' ), 10, 1 );
  216. return $tag;
  217. }
  218. /**
  219. * @ticket 29070
  220. */
  221. function test_has_filter_after_remove_all_filters() {
  222. $a = new MockAction();
  223. $tag = __FUNCTION__;
  224. $val = __FUNCTION__ . '_val';
  225. // No priority.
  226. add_filter( $tag, array( $a, 'filter' ), 11 );
  227. add_filter( $tag, array( $a, 'filter' ), 12 );
  228. $this->assertTrue( has_filter( $tag ) );
  229. remove_all_filters( $tag );
  230. $this->assertFalse( has_filter( $tag ) );
  231. // Remove priorities one at a time.
  232. add_filter( $tag, array( $a, 'filter' ), 11 );
  233. add_filter( $tag, array( $a, 'filter' ), 12 );
  234. $this->assertTrue( has_filter( $tag ) );
  235. remove_all_filters( $tag, 11 );
  236. remove_all_filters( $tag, 12 );
  237. $this->assertFalse( has_filter( $tag ) );
  238. }
  239. /**
  240. * @ticket 10441
  241. * @expectedDeprecated tests_apply_filters_deprecated
  242. */
  243. public function test_apply_filters_deprecated() {
  244. $p = 'Foo';
  245. add_filter( 'tests_apply_filters_deprecated', array( __CLASS__, 'deprecated_filter_callback' ) );
  246. $p = apply_filters_deprecated( 'tests_apply_filters_deprecated', array( $p ), '4.6.0' );
  247. remove_filter( 'tests_apply_filters_deprecated', array( __CLASS__, 'deprecated_filter_callback' ) );
  248. $this->assertSame( 'Bar', $p );
  249. }
  250. public static function deprecated_filter_callback( $p ) {
  251. $p = 'Bar';
  252. return $p;
  253. }
  254. /**
  255. * @ticket 10441
  256. * @expectedDeprecated tests_apply_filters_deprecated
  257. */
  258. public function test_apply_filters_deprecated_with_multiple_params() {
  259. $p1 = 'Foo1';
  260. $p2 = 'Foo2';
  261. add_filter( 'tests_apply_filters_deprecated', array( __CLASS__, 'deprecated_filter_callback_multiple_params' ), 10, 2 );
  262. $p1 = apply_filters_deprecated( 'tests_apply_filters_deprecated', array( $p1, $p2 ), '4.6.0' );
  263. remove_filter( 'tests_apply_filters_deprecated', array( __CLASS__, 'deprecated_filter_callback_multiple_params' ), 10, 2 );
  264. $this->assertSame( 'Bar1', $p1 );
  265. // Not passed by reference, so not modified.
  266. $this->assertSame( 'Foo2', $p2 );
  267. }
  268. public static function deprecated_filter_callback_multiple_params( $p1, $p2 ) {
  269. $p1 = 'Bar1';
  270. $p2 = 'Bar2';
  271. return $p1;
  272. }
  273. /**
  274. * @ticket 10441
  275. */
  276. public function test_apply_filters_deprecated_without_filter() {
  277. $val = 'Foobar';
  278. $this->assertSame( $val, apply_filters_deprecated( 'tests_apply_filters_deprecated', array( $val ), '4.6.0' ) );
  279. }
  280. private $current_priority;
  281. /**
  282. * @ticket 39007
  283. */
  284. public function test_current_priority() {
  285. add_action( 'test_current_priority', array( $this, '_current_priority_action' ), 99 );
  286. do_action( 'test_current_priority' );
  287. remove_action( 'test_current_priority', array( $this, '_current_priority_action' ), 99 );
  288. $this->assertSame( 99, $this->current_priority );
  289. }
  290. public function _current_priority_action() {
  291. global $wp_filter;
  292. $this->current_priority = $wp_filter[ current_filter() ]->current_priority();
  293. }
  294. /**
  295. * @ticket 39007
  296. */
  297. public function test_other_priority() {
  298. add_action( 'test_current_priority', array( $this, '_other_priority_action' ), 99 );
  299. do_action( 'test_current_priority' );
  300. remove_action( 'test_current_priority', array( $this, '_other_priority_action' ), 99 );
  301. $this->assertFalse( $this->current_priority );
  302. }
  303. public function _other_priority_action() {
  304. global $wp_filter;
  305. $this->current_priority = $wp_filter['the_content']->current_priority();
  306. }
  307. }