nav-menus.php 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231
  1. <?php
  2. /**
  3. * Tests WP_Customize_Nav_Menus.
  4. *
  5. * @group customize
  6. */
  7. class Test_WP_Customize_Nav_Menus extends WP_UnitTestCase {
  8. /**
  9. * Instance of WP_Customize_Manager which is reset for each test.
  10. *
  11. * @var WP_Customize_Manager
  12. */
  13. public $wp_customize;
  14. /**
  15. * Set up a test case.
  16. *
  17. * @see WP_UnitTestCase::setup()
  18. */
  19. function setUp() {
  20. parent::setUp();
  21. require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
  22. wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
  23. global $wp_customize;
  24. $this->wp_customize = new WP_Customize_Manager();
  25. $wp_customize = $this->wp_customize;
  26. }
  27. /**
  28. * Delete the $wp_customize global when cleaning up scope.
  29. */
  30. function clean_up_global_scope() {
  31. global $wp_customize;
  32. $wp_customize = null;
  33. parent::clean_up_global_scope();
  34. }
  35. /**
  36. * Filter to add custom menu item types.
  37. *
  38. * @param array $items Menu item types.
  39. * @return array Menu item types.
  40. */
  41. function filter_item_types( $items ) {
  42. $items[] = array(
  43. 'title' => 'Custom',
  44. 'type_label' => 'Custom Type',
  45. 'type' => 'custom_type',
  46. 'object' => 'custom_object',
  47. );
  48. return $items;
  49. }
  50. /**
  51. * Filter to add custom menu items.
  52. *
  53. * @param array $items The menu items.
  54. * @param string $type The object type (e.g. taxonomy).
  55. * @param string $object The object name (e.g. category).
  56. * @return array Menu items.
  57. */
  58. function filter_items( $items, $type, $object ) {
  59. $items[] = array(
  60. 'id' => 'custom-1',
  61. 'title' => 'Cool beans',
  62. 'type' => $type,
  63. 'type_label' => 'Custom Label',
  64. 'object' => $object,
  65. 'url' => home_url( '/cool-beans/' ),
  66. 'classes' => 'custom-menu-item cool-beans',
  67. );
  68. return $items;
  69. }
  70. /**
  71. * Test constructor.
  72. *
  73. * @see WP_Customize_Nav_Menus::__construct()
  74. */
  75. function test_construct() {
  76. do_action( 'customize_register', $this->wp_customize );
  77. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  78. $this->assertInstanceOf( 'WP_Customize_Manager', $menus->manager );
  79. $this->assertTrue( add_filter( 'customize_refresh_nonces', array( $menus, 'filter_nonces' ) ) );
  80. $this->assertTrue( add_action( 'wp_ajax_load-available-menu-items-customizer', array( $menus, 'ajax_load_available_items' ) ) );
  81. $this->assertTrue( add_action( 'wp_ajax_search-available-menu-items-customizer', array( $menus, 'ajax_search_available_items' ) ) );
  82. $this->assertTrue( add_action( 'wp_ajax_customize-nav-menus-insert-auto-draft', array( $menus, 'ajax_insert_auto_draft_post' ) ) );
  83. $this->assertTrue( add_action( 'customize_controls_enqueue_scripts', array( $menus, 'enqueue_scripts' ) ) );
  84. $this->assertTrue( add_action( 'customize_register', array( $menus, 'customize_register' ) ) );
  85. $this->assertTrue( add_filter( 'customize_dynamic_setting_args', array( $menus, 'filter_dynamic_setting_args' ) ) );
  86. $this->assertTrue( add_filter( 'customize_dynamic_setting_class', array( $menus, 'filter_dynamic_setting_class' ) ) );
  87. $this->assertTrue( add_action( 'customize_controls_print_footer_scripts', array( $menus, 'print_templates' ) ) );
  88. $this->assertTrue( add_action( 'customize_controls_print_footer_scripts', array( $menus, 'available_items_template' ) ) );
  89. $this->assertTrue( add_action( 'customize_preview_init', array( $menus, 'customize_preview_init' ) ) );
  90. $this->assertTrue( add_action( 'customize_preview_init', array( $menus, 'make_auto_draft_status_previewable' ) ) );
  91. $this->assertTrue( add_action( 'customize_save_nav_menus_created_posts', array( $menus, 'save_nav_menus_created_posts' ) ) );
  92. $this->assertTrue( add_filter( 'customize_dynamic_partial_args', array( $menus, 'customize_dynamic_partial_args' ) ) );
  93. }
  94. /**
  95. * Test that the load_available_items_query method returns a WP_Error object.
  96. *
  97. * @see WP_Customize_Nav_Menus::load_available_items_query()
  98. */
  99. function test_load_available_items_query_returns_wp_error() {
  100. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  101. // Invalid post type $obj_name.
  102. $items = $menus->load_available_items_query( 'post_type', 'invalid' );
  103. $this->assertInstanceOf( 'WP_Error', $items );
  104. $this->assertSame( 'nav_menus_invalid_post_type', $items->get_error_code() );
  105. // Invalid taxonomy $obj_name.
  106. $items = $menus->load_available_items_query( 'taxonomy', 'invalid' );
  107. $this->assertInstanceOf( 'WP_Error', $items );
  108. $this->assertSame( 'invalid_taxonomy', $items->get_error_code() );
  109. }
  110. /**
  111. * Test the load_available_items_query method maybe returns the home page item.
  112. *
  113. * @see WP_Customize_Nav_Menus::load_available_items_query()
  114. */
  115. function test_load_available_items_query_maybe_returns_home() {
  116. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  117. // Expected menu item array.
  118. $expected = array(
  119. 'id' => 'home',
  120. 'title' => _x( 'Home', 'nav menu home label' ),
  121. 'type' => 'custom',
  122. 'type_label' => __( 'Custom Link' ),
  123. 'object' => '',
  124. 'url' => home_url(),
  125. );
  126. // Create pages.
  127. self::factory()->post->create_many( 12, array( 'post_type' => 'page' ) );
  128. // Home is included in menu items when page is zero.
  129. $items = $menus->load_available_items_query( 'post_type', 'page', 0 );
  130. $this->assertContains( $expected, $items );
  131. // Home is not included in menu items when page is larger than zero.
  132. $items = $menus->load_available_items_query( 'post_type', 'page', 1 );
  133. $this->assertNotEmpty( $items );
  134. $this->assertNotContains( $expected, $items );
  135. }
  136. /**
  137. * Test the load_available_items_query method returns post item.
  138. *
  139. * @see WP_Customize_Nav_Menus::load_available_items_query()
  140. */
  141. function test_load_available_items_query_returns_post_item_with_page_number() {
  142. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  143. // Create page.
  144. $post_id = self::factory()->post->create( array( 'post_title' => 'Post Title' ) );
  145. // Create pages.
  146. self::factory()->post->create_many( 10 );
  147. // Expected menu item array.
  148. $expected = array(
  149. 'id' => "post-{$post_id}",
  150. 'title' => 'Post Title',
  151. 'type' => 'post_type',
  152. 'type_label' => 'Post',
  153. 'object' => 'post',
  154. 'object_id' => (int) $post_id,
  155. 'url' => get_permalink( (int) $post_id ),
  156. );
  157. // Offset the query and get the second page of menu items.
  158. $items = $menus->load_available_items_query( 'post_type', 'post', 1 );
  159. $this->assertContains( $expected, $items );
  160. }
  161. /**
  162. * Test the load_available_items_query method returns page item.
  163. *
  164. * @see WP_Customize_Nav_Menus::load_available_items_query()
  165. */
  166. function test_load_available_items_query_returns_page_item() {
  167. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  168. // Create page.
  169. $page_id = self::factory()->post->create(
  170. array(
  171. 'post_title' => 'Page Title',
  172. 'post_type' => 'page',
  173. )
  174. );
  175. // Expected menu item array.
  176. $expected = array(
  177. 'id' => "post-{$page_id}",
  178. 'title' => 'Page Title',
  179. 'type' => 'post_type',
  180. 'type_label' => 'Page',
  181. 'object' => 'page',
  182. 'object_id' => (int) $page_id,
  183. 'url' => get_permalink( (int) $page_id ),
  184. );
  185. $items = $menus->load_available_items_query( 'post_type', 'page', 0 );
  186. $this->assertContains( $expected, $items );
  187. }
  188. /**
  189. * Test the load_available_items_query method returns post item.
  190. *
  191. * @see WP_Customize_Nav_Menus::load_available_items_query()
  192. */
  193. function test_load_available_items_query_returns_post_item() {
  194. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  195. // Create post.
  196. $post_id = self::factory()->post->create( array( 'post_title' => 'Post Title' ) );
  197. // Expected menu item array.
  198. $expected = array(
  199. 'id' => "post-{$post_id}",
  200. 'title' => 'Post Title',
  201. 'type' => 'post_type',
  202. 'type_label' => 'Post',
  203. 'object' => 'post',
  204. 'object_id' => (int) $post_id,
  205. 'url' => get_permalink( (int) $post_id ),
  206. );
  207. $items = $menus->load_available_items_query( 'post_type', 'post', 0 );
  208. $this->assertContains( $expected, $items );
  209. }
  210. /**
  211. * Test the load_available_items_query method returns term item.
  212. *
  213. * @see WP_Customize_Nav_Menus::load_available_items_query()
  214. */
  215. function test_load_available_items_query_returns_term_item() {
  216. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  217. // Create term.
  218. $term_id = self::factory()->category->create( array( 'name' => 'Term Title' ) );
  219. // Expected menu item array.
  220. $expected = array(
  221. 'id' => "term-{$term_id}",
  222. 'title' => 'Term Title',
  223. 'type' => 'taxonomy',
  224. 'type_label' => 'Category',
  225. 'object' => 'category',
  226. 'object_id' => (int) $term_id,
  227. 'url' => get_term_link( (int) $term_id, 'category' ),
  228. );
  229. $items = $menus->load_available_items_query( 'taxonomy', 'category', 0 );
  230. $this->assertContains( $expected, $items );
  231. }
  232. /**
  233. * Test the load_available_items_query method returns custom item.
  234. *
  235. * @see WP_Customize_Nav_Menus::load_available_items_query()
  236. */
  237. function test_load_available_items_query_returns_custom_item() {
  238. add_filter( 'customize_nav_menu_available_item_types', array( $this, 'filter_item_types' ) );
  239. add_filter( 'customize_nav_menu_available_items', array( $this, 'filter_items' ), 10, 4 );
  240. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  241. // Expected menu item array.
  242. $expected = array(
  243. 'id' => 'custom-1',
  244. 'title' => 'Cool beans',
  245. 'type' => 'custom_type',
  246. 'type_label' => 'Custom Label',
  247. 'object' => 'custom_object',
  248. 'url' => home_url( '/cool-beans/' ),
  249. 'classes' => 'custom-menu-item cool-beans',
  250. );
  251. $items = $menus->load_available_items_query( 'custom_type', 'custom_object', 0 );
  252. $this->assertContains( $expected, $items );
  253. }
  254. /**
  255. * Test the search_available_items_query method.
  256. *
  257. * @see WP_Customize_Nav_Menus::search_available_items_query()
  258. */
  259. function test_search_available_items_query() {
  260. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  261. do_action( 'customize_register', $this->wp_customize );
  262. // Create posts.
  263. $post_ids = array();
  264. $post_ids[] = self::factory()->post->create( array( 'post_title' => 'Search & Test' ) );
  265. $post_ids[] = self::factory()->post->create( array( 'post_title' => 'Some Other Title' ) );
  266. // Create terms.
  267. $term_ids = array();
  268. $term_ids[] = self::factory()->category->create( array( 'name' => 'Dogs Are Cool' ) );
  269. $term_ids[] = self::factory()->category->create( array( 'name' => 'Cats Drool' ) );
  270. // Test empty results.
  271. $expected = array();
  272. $results = $menus->search_available_items_query(
  273. array(
  274. 'pagenum' => 1,
  275. 's' => 'This Does NOT Exist',
  276. )
  277. );
  278. $this->assertSame( $expected, $results );
  279. // Test posts.
  280. foreach ( $post_ids as $post_id ) {
  281. $expected = array(
  282. 'id' => 'post-' . $post_id,
  283. 'title' => html_entity_decode( get_the_title( $post_id ) ),
  284. 'type' => 'post_type',
  285. 'type_label' => get_post_type_object( 'post' )->labels->singular_name,
  286. 'object' => 'post',
  287. 'object_id' => (int) $post_id,
  288. 'url' => get_permalink( (int) $post_id ),
  289. );
  290. wp_set_object_terms( $post_id, $term_ids, 'category' );
  291. $search = $post_id === $post_ids[0] ? 'test & search' : 'other title';
  292. $s = sanitize_text_field( wp_unslash( $search ) );
  293. $results = $menus->search_available_items_query(
  294. array(
  295. 'pagenum' => 1,
  296. 's' => $s,
  297. )
  298. );
  299. $this->assertSame( $expected, $results[0] );
  300. }
  301. // Test terms.
  302. foreach ( $term_ids as $term_id ) {
  303. $term = get_term_by( 'id', $term_id, 'category' );
  304. $expected = array(
  305. 'id' => 'term-' . $term_id,
  306. 'title' => $term->name,
  307. 'type' => 'taxonomy',
  308. 'type_label' => get_taxonomy( 'category' )->labels->singular_name,
  309. 'object' => 'category',
  310. 'object_id' => (int) $term_id,
  311. 'url' => get_term_link( (int) $term_id, 'category' ),
  312. );
  313. $s = sanitize_text_field( wp_unslash( $term->name ) );
  314. $results = $menus->search_available_items_query(
  315. array(
  316. 'pagenum' => 1,
  317. 's' => $s,
  318. )
  319. );
  320. $this->assertSame( $expected, $results[0] );
  321. }
  322. // Test filtered results.
  323. $results = $menus->search_available_items_query(
  324. array(
  325. 'pagenum' => 1,
  326. 's' => 'cat',
  327. )
  328. );
  329. $this->assertCount( 2, $results ); // Category terms Cats Drool and Uncategorized.
  330. $count = $this->filter_count_customize_nav_menu_searched_items;
  331. add_filter( 'customize_nav_menu_searched_items', array( $this, 'filter_search' ), 10, 2 );
  332. $results = $menus->search_available_items_query(
  333. array(
  334. 'pagenum' => 1,
  335. 's' => 'cat',
  336. )
  337. );
  338. $this->assertSame( $count + 1, $this->filter_count_customize_nav_menu_searched_items );
  339. $this->assertInternalType( 'array', $results );
  340. $this->assertCount( 3, $results );
  341. remove_filter( 'customize_nav_menu_searched_items', array( $this, 'filter_search' ), 10 );
  342. // Test home.
  343. $title = _x( 'Home', 'nav menu home label' );
  344. $results = $menus->search_available_items_query(
  345. array(
  346. 'pagenum' => 1,
  347. 's' => $title,
  348. )
  349. );
  350. $this->assertCount( 1, $results );
  351. $this->assertSame( 'home', $results[0]['id'] );
  352. $this->assertSame( 'custom', $results[0]['type'] );
  353. }
  354. /*
  355. * Tests that the search_available_items_query method should return term items
  356. * not assigned to any posts.
  357. *
  358. * @ticket 45298
  359. */
  360. public function test_search_available_items_query_should_return_unassigned_term_items() {
  361. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  362. register_taxonomy(
  363. 'wptests_tax',
  364. 'post',
  365. array(
  366. 'labels' => array(
  367. 'name' => 'Tests Taxonomy',
  368. ),
  369. )
  370. );
  371. $term_id = $this->factory->term->create(
  372. array(
  373. 'taxonomy' => 'wptests_tax',
  374. 'name' => 'foobar',
  375. )
  376. );
  377. // Expected menu item array.
  378. $expected = array(
  379. 'title' => 'foobar',
  380. 'id' => "term-{$term_id}",
  381. 'type' => 'taxonomy',
  382. 'type_label' => 'Tests Taxonomy',
  383. 'object' => 'wptests_tax',
  384. 'object_id' => (int) $term_id,
  385. 'url' => get_term_link( (int) $term_id, '' ),
  386. );
  387. $results = $menus->search_available_items_query(
  388. array(
  389. 'pagenum' => 1,
  390. 's' => 'foo',
  391. )
  392. );
  393. $this->assertSameSets( $expected, $results[0] );
  394. }
  395. /**
  396. * Count for number of times customize_nav_menu_searched_items filtered.
  397. *
  398. * @var int
  399. */
  400. protected $filter_count_customize_nav_menu_searched_items = 0;
  401. /**
  402. * Filter to search menu items.
  403. *
  404. * @param array $items Items.
  405. * @param array $args {
  406. * Search args.
  407. *
  408. * @type int $pagenum Page number.
  409. * @type string $s Search string.
  410. * }
  411. * @return array Items.
  412. */
  413. function filter_search( $items, $args ) {
  414. $this->assertInternalType( 'array', $items );
  415. $this->assertInternalType( 'array', $args );
  416. $this->assertArrayHasKey( 's', $args );
  417. $this->assertArrayHasKey( 'pagenum', $args );
  418. $this->filter_count_customize_nav_menu_searched_items += 1;
  419. if ( 'cat' === $args['s'] ) {
  420. array_unshift(
  421. $items,
  422. array(
  423. 'id' => 'home',
  424. 'title' => 'COOL CAT!',
  425. 'type' => 'custom',
  426. 'type_label' => __( 'Custom Link' ),
  427. 'object' => '',
  428. 'url' => home_url( '/cool-cat' ),
  429. )
  430. );
  431. }
  432. return $items;
  433. }
  434. /**
  435. * Test the enqueue method.
  436. *
  437. * @see WP_Customize_Nav_Menus::enqueue_scripts()
  438. */
  439. function test_enqueue_scripts() {
  440. do_action( 'customize_register', $this->wp_customize );
  441. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  442. $menus->enqueue_scripts();
  443. $this->assertTrue( wp_script_is( 'customize-nav-menus' ) );
  444. wp_dequeue_style( 'customize-nav-menus' );
  445. wp_dequeue_script( 'customize-nav-menus' );
  446. }
  447. /**
  448. * Test the filter_dynamic_setting_args method.
  449. *
  450. * @see WP_Customize_Nav_Menus::filter_dynamic_setting_args()
  451. */
  452. function test_filter_dynamic_setting_args() {
  453. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  454. $expected = array( 'type' => 'nav_menu_item' );
  455. $results = $menus->filter_dynamic_setting_args( $this->wp_customize, 'nav_menu_item[123]' );
  456. $this->assertSame( $expected['type'], $results['type'] );
  457. $expected = array( 'type' => 'nav_menu' );
  458. $results = $menus->filter_dynamic_setting_args( $this->wp_customize, 'nav_menu[123]' );
  459. $this->assertSame( $expected['type'], $results['type'] );
  460. }
  461. /**
  462. * Test the filter_dynamic_setting_class method.
  463. *
  464. * @see WP_Customize_Nav_Menus::filter_dynamic_setting_class()
  465. */
  466. function test_filter_dynamic_setting_class() {
  467. do_action( 'customize_register', $this->wp_customize );
  468. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  469. $expected = 'WP_Customize_Nav_Menu_Item_Setting';
  470. $results = $menus->filter_dynamic_setting_class( 'WP_Customize_Setting', 'nav_menu_item[123]', array( 'type' => 'nav_menu_item' ) );
  471. $this->assertSame( $expected, $results );
  472. $expected = 'WP_Customize_Nav_Menu_Setting';
  473. $results = $menus->filter_dynamic_setting_class( 'WP_Customize_Setting', 'nav_menu[123]', array( 'type' => 'nav_menu' ) );
  474. $this->assertSame( $expected, $results );
  475. }
  476. /**
  477. * Test the customize_register method.
  478. *
  479. * @see WP_Customize_Nav_Menus::customize_register()
  480. */
  481. function test_customize_register() {
  482. do_action( 'customize_register', $this->wp_customize );
  483. $menu_id = wp_create_nav_menu( 'Primary' );
  484. $post_id = self::factory()->post->create( array( 'post_title' => 'Hello World' ) );
  485. $item_id = wp_update_nav_menu_item(
  486. $menu_id,
  487. 0,
  488. array(
  489. 'menu-item-type' => 'post_type',
  490. 'menu-item-object' => 'post',
  491. 'menu-item-object-id' => $post_id,
  492. 'menu-item-title' => 'Hello World',
  493. 'menu-item-status' => 'publish',
  494. )
  495. );
  496. do_action( 'customize_register', $this->wp_customize );
  497. $this->assertInstanceOf( 'WP_Customize_Nav_Menu_Item_Setting', $this->wp_customize->get_setting( "nav_menu_item[$item_id]" ) );
  498. $this->assertSame( 'Primary', $this->wp_customize->get_section( "nav_menu[$menu_id]" )->title );
  499. $this->assertSame( 'Hello World', $this->wp_customize->get_control( "nav_menu_item[$item_id]" )->label );
  500. $nav_menus_created_posts_setting = $this->wp_customize->get_setting( 'nav_menus_created_posts' );
  501. $this->assertInstanceOf( 'WP_Customize_Filter_Setting', $nav_menus_created_posts_setting );
  502. $this->assertSame( 'postMessage', $nav_menus_created_posts_setting->transport );
  503. $this->assertSame( array(), $nav_menus_created_posts_setting->default );
  504. $this->assertSame( array( $this->wp_customize->nav_menus, 'sanitize_nav_menus_created_posts' ), $nav_menus_created_posts_setting->sanitize_callback );
  505. }
  506. /**
  507. * Test the intval_base10 method.
  508. *
  509. * @see WP_Customize_Nav_Menus::intval_base10()
  510. */
  511. function test_intval_base10() {
  512. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  513. $this->assertSame( 2, $menus->intval_base10( 2 ) );
  514. $this->assertSame( 4, $menus->intval_base10( 4.1 ) );
  515. $this->assertSame( 4, $menus->intval_base10( '4' ) );
  516. $this->assertSame( 4, $menus->intval_base10( '04' ) );
  517. $this->assertSame( 42, $menus->intval_base10( +42 ) );
  518. $this->assertSame( -42, $menus->intval_base10( -42 ) );
  519. $this->assertSame( 26, $menus->intval_base10( 0x1A ) );
  520. $this->assertSame( 0, $menus->intval_base10( array() ) );
  521. }
  522. /**
  523. * Test the available_item_types method.
  524. *
  525. * @see WP_Customize_Nav_Menus::available_item_types()
  526. */
  527. function test_available_item_types() {
  528. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  529. $expected = array(
  530. array(
  531. 'title' => 'Posts',
  532. 'type_label' => __( 'Post' ),
  533. 'type' => 'post_type',
  534. 'object' => 'post',
  535. ),
  536. array(
  537. 'title' => 'Pages',
  538. 'type_label' => __( 'Page' ),
  539. 'type' => 'post_type',
  540. 'object' => 'page',
  541. ),
  542. array(
  543. 'title' => 'Categories',
  544. 'type_label' => __( 'Category' ),
  545. 'type' => 'taxonomy',
  546. 'object' => 'category',
  547. ),
  548. array(
  549. 'title' => 'Tags',
  550. 'type_label' => __( 'Tag' ),
  551. 'type' => 'taxonomy',
  552. 'object' => 'post_tag',
  553. ),
  554. );
  555. if ( current_theme_supports( 'post-formats' ) ) {
  556. $expected[] = array(
  557. 'title' => 'Format',
  558. 'type_label' => __( 'Format' ),
  559. 'type' => 'taxonomy',
  560. 'object' => 'post_format',
  561. );
  562. }
  563. $this->assertSame( $expected, $menus->available_item_types() );
  564. register_taxonomy( 'wptests_tax', array( 'post' ), array( 'labels' => array( 'name' => 'Foo' ) ) );
  565. $expected[] = array(
  566. 'title' => 'Foo',
  567. 'type_label' => 'Foo',
  568. 'type' => 'taxonomy',
  569. 'object' => 'wptests_tax',
  570. );
  571. $this->assertSame( $expected, $menus->available_item_types() );
  572. $expected[] = array(
  573. 'title' => 'Custom',
  574. 'type_label' => 'Custom Type',
  575. 'type' => 'custom_type',
  576. 'object' => 'custom_object',
  577. );
  578. add_filter( 'customize_nav_menu_available_item_types', array( $this, 'filter_item_types' ) );
  579. $this->assertSame( $expected, $menus->available_item_types() );
  580. remove_filter( 'customize_nav_menu_available_item_types', array( $this, 'filter_item_types' ) );
  581. }
  582. /**
  583. * Test insert_auto_draft_post method.
  584. *
  585. * @covers WP_Customize_Nav_Menus::insert_auto_draft_post
  586. */
  587. public function test_insert_auto_draft_post() {
  588. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  589. $r = $menus->insert_auto_draft_post( array() );
  590. $this->assertInstanceOf( 'WP_Error', $r );
  591. $this->assertSame( 'unknown_post_type', $r->get_error_code() );
  592. // Non-existent post types allowed as of #39610.
  593. $r = $menus->insert_auto_draft_post(
  594. array(
  595. 'post_title' => 'Non-existent',
  596. 'post_type' => 'nonexistent',
  597. )
  598. );
  599. $this->assertInstanceOf( 'WP_Post', $r );
  600. $this->assertSame( $this->wp_customize->changeset_uuid(), get_post_meta( $r->ID, '_customize_changeset_uuid', true ) );
  601. $r = $menus->insert_auto_draft_post( array( 'post_type' => 'post' ) );
  602. $this->assertInstanceOf( 'WP_Error', $r );
  603. $this->assertSame( 'empty_title', $r->get_error_code() );
  604. $r = $menus->insert_auto_draft_post(
  605. array(
  606. 'post_status' => 'publish',
  607. 'post_title' => 'Bad',
  608. 'post_type' => 'post',
  609. )
  610. );
  611. $this->assertInstanceOf( 'WP_Error', $r );
  612. $this->assertSame( 'status_forbidden', $r->get_error_code() );
  613. $r = $menus->insert_auto_draft_post(
  614. array(
  615. 'post_title' => 'Hello World',
  616. 'post_type' => 'post',
  617. )
  618. );
  619. $this->assertInstanceOf( 'WP_Post', $r );
  620. $this->assertSame( 'Hello World', $r->post_title );
  621. $this->assertSame( '', $r->post_name );
  622. $this->assertSame( 'hello-world', get_post_meta( $r->ID, '_customize_draft_post_name', true ) );
  623. $this->assertSame( $this->wp_customize->changeset_uuid(), get_post_meta( $r->ID, '_customize_changeset_uuid', true ) );
  624. $this->assertSame( 'post', $r->post_type );
  625. $r = $menus->insert_auto_draft_post(
  626. array(
  627. 'post_title' => 'Hello World',
  628. 'post_type' => 'post',
  629. 'post_name' => 'greetings-world',
  630. 'post_content' => 'Hi World',
  631. )
  632. );
  633. $this->assertInstanceOf( 'WP_Post', $r );
  634. $this->assertSame( 'Hello World', $r->post_title );
  635. $this->assertSame( 'post', $r->post_type );
  636. $this->assertSame( '', $r->post_name );
  637. $this->assertSame( 'greetings-world', get_post_meta( $r->ID, '_customize_draft_post_name', true ) );
  638. $this->assertSame( $this->wp_customize->changeset_uuid(), get_post_meta( $r->ID, '_customize_changeset_uuid', true ) );
  639. $this->assertSame( 'Hi World', $r->post_content );
  640. }
  641. /**
  642. * Test the print_templates method.
  643. *
  644. * @see WP_Customize_Nav_Menus::print_templates()
  645. */
  646. function test_print_templates() {
  647. do_action( 'customize_register', $this->wp_customize );
  648. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  649. ob_start();
  650. $menus->print_templates();
  651. $template = ob_get_clean();
  652. $expected = sprintf(
  653. '<button type="button" class="menus-move-up">%1$s</button><button type="button" class="menus-move-down">%2$s</button><button type="button" class="menus-move-left">%3$s</button><button type="button" class="menus-move-right">%4$s</button>',
  654. esc_html( 'Move up' ),
  655. esc_html( 'Move down' ),
  656. esc_html( 'Move one level up' ),
  657. esc_html( 'Move one level down' )
  658. );
  659. $this->assertContains( $expected, $template );
  660. }
  661. /**
  662. * Test the available_items_template method.
  663. *
  664. * @see WP_Customize_Nav_Menus::available_items_template()
  665. */
  666. function test_available_items_template() {
  667. add_filter( 'customize_nav_menu_available_item_types', array( $this, 'filter_item_types' ) );
  668. do_action( 'customize_register', $this->wp_customize );
  669. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  670. ob_start();
  671. $menus->available_items_template();
  672. $template = ob_get_clean();
  673. $expected = sprintf( 'Customizing &#9656; %s', esc_html( $this->wp_customize->get_panel( 'nav_menus' )->title ) );
  674. $this->assertContains( $expected, $template );
  675. $post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'object' );
  676. if ( $post_types ) {
  677. foreach ( $post_types as $type ) {
  678. $this->assertContains( 'available-menu-items-post_type-' . esc_attr( $type->name ), $template );
  679. $this->assertRegExp( '#<h4 class="accordion-section-title".*>\s*' . esc_html( $type->labels->name ) . '#', $template );
  680. $this->assertContains( 'data-type="post_type"', $template );
  681. $this->assertContains( 'data-object="' . esc_attr( $type->name ) . '"', $template );
  682. $this->assertContains( 'data-type_label="' . esc_attr( $type->labels->singular_name ) . '"', $template );
  683. }
  684. }
  685. $taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'object' );
  686. if ( $taxonomies ) {
  687. foreach ( $taxonomies as $tax ) {
  688. $this->assertContains( 'available-menu-items-taxonomy-' . esc_attr( $tax->name ), $template );
  689. $this->assertRegExp( '#<h4 class="accordion-section-title".*>\s*' . esc_html( $tax->labels->name ) . '#', $template );
  690. $this->assertContains( 'data-type="taxonomy"', $template );
  691. $this->assertContains( 'data-object="' . esc_attr( $tax->name ) . '"', $template );
  692. $this->assertContains( 'data-type_label="' . esc_attr( $tax->labels->singular_name ) . '"', $template );
  693. }
  694. }
  695. $this->assertContains( 'available-menu-items-custom_type', $template );
  696. $this->assertRegExp( '#<h4 class="accordion-section-title".*>\s*Custom#', $template );
  697. $this->assertContains( 'data-type="custom_type"', $template );
  698. $this->assertContains( 'data-object="custom_object"', $template );
  699. $this->assertContains( 'data-type_label="Custom Type"', $template );
  700. }
  701. /**
  702. * Test WP_Customize_Nav_Menus::customize_dynamic_partial_args().
  703. *
  704. * @see WP_Customize_Nav_Menus::customize_dynamic_partial_args()
  705. */
  706. function test_customize_dynamic_partial_args() {
  707. do_action( 'customize_register', $this->wp_customize );
  708. $args = apply_filters( 'customize_dynamic_partial_args', false, 'nav_menu_instance[68b329da9893e34099c7d8ad5cb9c940]' );
  709. $this->assertInternalType( 'array', $args );
  710. $this->assertSame( 'nav_menu_instance', $args['type'] );
  711. $this->assertSame( array( $this->wp_customize->nav_menus, 'render_nav_menu_partial' ), $args['render_callback'] );
  712. $this->assertTrue( $args['container_inclusive'] );
  713. $args = apply_filters( 'customize_dynamic_partial_args', array( 'fallback_refresh' => false ), 'nav_menu_instance[4099c7d8ad5cb9c94068b329da9893e3]' );
  714. $this->assertInternalType( 'array', $args );
  715. $this->assertSame( 'nav_menu_instance', $args['type'] );
  716. $this->assertSame( array( $this->wp_customize->nav_menus, 'render_nav_menu_partial' ), $args['render_callback'] );
  717. $this->assertTrue( $args['container_inclusive'] );
  718. $this->assertFalse( $args['fallback_refresh'] );
  719. }
  720. /**
  721. * Test the customize_preview_init method.
  722. *
  723. * @see WP_Customize_Nav_Menus::customize_preview_init()
  724. */
  725. function test_customize_preview_init() {
  726. do_action( 'customize_register', $this->wp_customize );
  727. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  728. $menus->customize_preview_init();
  729. $this->assertSame( 10, has_action( 'wp_enqueue_scripts', array( $menus, 'customize_preview_enqueue_deps' ) ) );
  730. $this->assertSame( 1000, has_filter( 'wp_nav_menu_args', array( $menus, 'filter_wp_nav_menu_args' ) ) );
  731. $this->assertSame( 10, has_filter( 'wp_nav_menu', array( $menus, 'filter_wp_nav_menu' ) ) );
  732. }
  733. /**
  734. * Test make_auto_draft_status_previewable.
  735. *
  736. * @covers WP_Customize_Nav_Menus::make_auto_draft_status_previewable
  737. */
  738. function test_make_auto_draft_status_previewable() {
  739. global $wp_post_statuses;
  740. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  741. $menus->make_auto_draft_status_previewable();
  742. $this->assertTrue( $wp_post_statuses['auto-draft']->protected );
  743. }
  744. /**
  745. * Test sanitize_nav_menus_created_posts.
  746. *
  747. * @covers WP_Customize_Nav_Menus::sanitize_nav_menus_created_posts
  748. */
  749. function test_sanitize_nav_menus_created_posts() {
  750. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  751. $contributor_user_id = $this->factory()->user->create( array( 'role' => 'contributor' ) );
  752. $author_user_id = $this->factory()->user->create( array( 'role' => 'author' ) );
  753. $administrator_user_id = $this->factory()->user->create( array( 'role' => 'administrator' ) );
  754. $contributor_post_id = $this->factory()->post->create(
  755. array(
  756. 'post_status' => 'auto-draft',
  757. 'post_title' => 'Contributor Post',
  758. 'post_type' => 'post',
  759. 'post_author' => $contributor_user_id,
  760. )
  761. );
  762. $author_post_id = $this->factory()->post->create(
  763. array(
  764. 'post_status' => 'auto-draft',
  765. 'post_title' => 'Author Post',
  766. 'post_type' => 'post',
  767. 'post_author' => $author_user_id,
  768. )
  769. );
  770. $administrator_post_id = $this->factory()->post->create(
  771. array(
  772. 'post_status' => 'auto-draft',
  773. 'post_title' => 'Admin Post',
  774. 'post_type' => 'post',
  775. 'post_author' => $administrator_user_id,
  776. )
  777. );
  778. $draft_post_id = $this->factory()->post->create(
  779. array(
  780. 'post_status' => 'draft',
  781. 'post_title' => 'Draft',
  782. 'post_author' => $administrator_user_id,
  783. )
  784. );
  785. $private_post_id = $this->factory()->post->create(
  786. array(
  787. 'post_status' => 'private',
  788. 'post_title' => 'Private',
  789. 'post_author' => $administrator_user_id,
  790. )
  791. );
  792. $value = array(
  793. 'bad',
  794. $contributor_post_id,
  795. $author_post_id,
  796. $administrator_post_id,
  797. $draft_post_id,
  798. $private_post_id,
  799. );
  800. wp_set_current_user( $contributor_user_id );
  801. $sanitized = $menus->sanitize_nav_menus_created_posts( $value );
  802. $this->assertSame( array(), $sanitized );
  803. wp_set_current_user( $author_user_id );
  804. $sanitized = $menus->sanitize_nav_menus_created_posts( $value );
  805. $this->assertSame( array( $author_post_id ), $sanitized );
  806. wp_set_current_user( $administrator_user_id );
  807. $sanitized = $menus->sanitize_nav_menus_created_posts( $value );
  808. $this->assertSame( array( $contributor_post_id, $author_post_id, $administrator_post_id, $draft_post_id ), $sanitized );
  809. }
  810. /**
  811. * Test save_nav_menus_created_posts.
  812. *
  813. * @covers WP_Customize_Nav_Menus::save_nav_menus_created_posts
  814. */
  815. function test_save_nav_menus_created_posts() {
  816. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  817. do_action( 'customize_register', $this->wp_customize );
  818. $post_ids = array();
  819. // Auto-draft.
  820. $r = $menus->insert_auto_draft_post(
  821. array(
  822. 'post_title' => 'Auto Draft',
  823. 'post_type' => 'post',
  824. 'post_name' => 'auto-draft-1',
  825. )
  826. );
  827. $this->assertInstanceOf( 'WP_Post', $r );
  828. $post_ids[] = $r->ID;
  829. // Draft.
  830. $r = $menus->insert_auto_draft_post(
  831. array(
  832. 'post_title' => 'Draft',
  833. 'post_type' => 'post',
  834. 'post_name' => 'auto-draft-2',
  835. )
  836. );
  837. $this->assertInstanceOf( 'WP_Post', $r );
  838. wp_update_post(
  839. array(
  840. 'ID' => $r->ID,
  841. 'post_status' => 'draft',
  842. )
  843. );
  844. $post_ids[] = $r->ID;
  845. $drafted_post_ids = $post_ids;
  846. // Private (this will exclude it from being considered a stub).
  847. $r = $menus->insert_auto_draft_post(
  848. array(
  849. 'post_title' => 'Private',
  850. 'post_type' => 'post',
  851. 'post_name' => 'auto-draft-3',
  852. )
  853. );
  854. $this->assertInstanceOf( 'WP_Post', $r );
  855. wp_update_post(
  856. array(
  857. 'ID' => $r->ID,
  858. 'post_status' => 'private',
  859. )
  860. );
  861. $post_ids[] = $r->ID;
  862. $private_post_id = $r->ID;
  863. // Trashed (this will exclude it from being considered a stub).
  864. $r = $menus->insert_auto_draft_post(
  865. array(
  866. 'post_title' => 'Trash',
  867. 'post_type' => 'post',
  868. 'post_name' => 'auto-draft-4',
  869. )
  870. );
  871. $this->assertInstanceOf( 'WP_Post', $r );
  872. wp_trash_post( $r->ID );
  873. $post_ids[] = $r->ID;
  874. $trashed_post_id = $r->ID;
  875. $pre_published_post_id = $this->factory()->post->create( array( 'post_status' => 'publish' ) );
  876. $setting_id = 'nav_menus_created_posts';
  877. $this->wp_customize->set_post_value( $setting_id, array_merge( $post_ids, array( $pre_published_post_id ) ) );
  878. $setting = $this->wp_customize->get_setting( $setting_id );
  879. $this->assertInstanceOf( 'WP_Customize_Filter_Setting', $setting );
  880. $this->assertSame( array( $menus, 'sanitize_nav_menus_created_posts' ), $setting->sanitize_callback );
  881. $this->assertSame( $drafted_post_ids, $setting->post_value() );
  882. $this->assertArrayNotHasKey( $private_post_id, $post_ids );
  883. $this->assertArrayNotHasKey( $trashed_post_id, $post_ids );
  884. $this->assertSame( 'auto-draft', get_post_status( $drafted_post_ids[0] ) );
  885. $this->assertSame( 'draft', get_post_status( $drafted_post_ids[1] ) );
  886. foreach ( $drafted_post_ids as $post_id ) {
  887. $this->assertEmpty( get_post( $post_id )->post_name );
  888. $this->assertNotEmpty( get_post_meta( $post_id, '_customize_draft_post_name', true ) );
  889. }
  890. $save_action_count = did_action( 'customize_save_nav_menus_created_posts' );
  891. $setting->save();
  892. $this->assertSame( $save_action_count + 1, did_action( 'customize_save_nav_menus_created_posts' ) );
  893. foreach ( $drafted_post_ids as $post_id ) {
  894. $this->assertSame( 'publish', get_post_status( $post_id ) );
  895. $this->assertRegExp( '/^auto-draft-\d+$/', get_post( $post_id )->post_name );
  896. $this->assertEmpty( get_post_meta( $post_id, '_customize_draft_post_name', true ) );
  897. }
  898. $this->assertSame( 'private', get_post_status( $private_post_id ) );
  899. $this->assertSame( 'trash', get_post_status( $trashed_post_id ) );
  900. // Ensure that unique slugs were assigned.
  901. $posts = array_map( 'get_post', $drafted_post_ids );
  902. $post_names = wp_list_pluck( $posts, 'post_name' );
  903. $this->assertSameSets( $post_names, array_unique( $post_names ) );
  904. }
  905. /**
  906. * Test the filter_wp_nav_menu_args method.
  907. *
  908. * @see WP_Customize_Nav_Menus::filter_wp_nav_menu_args()
  909. */
  910. function test_filter_wp_nav_menu_args() {
  911. do_action( 'customize_register', $this->wp_customize );
  912. $menus = $this->wp_customize->nav_menus;
  913. $menu_id = wp_create_nav_menu( 'Foo' );
  914. $results = $menus->filter_wp_nav_menu_args(
  915. array(
  916. 'echo' => true,
  917. 'fallback_cb' => 'wp_page_menu',
  918. 'walker' => '',
  919. 'menu' => $menu_id,
  920. 'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
  921. )
  922. );
  923. $this->assertArrayHasKey( 'customize_preview_nav_menus_args', $results );
  924. $this->assertTrue( $results['can_partial_refresh'] );
  925. $results = $menus->filter_wp_nav_menu_args(
  926. array(
  927. 'echo' => false,
  928. 'fallback_cb' => 'wp_page_menu',
  929. 'walker' => new Walker_Nav_Menu(),
  930. 'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
  931. )
  932. );
  933. $this->assertFalse( $results['can_partial_refresh'] );
  934. $this->assertArrayHasKey( 'customize_preview_nav_menus_args', $results );
  935. $this->assertSame( 'wp_page_menu', $results['fallback_cb'] );
  936. $nav_menu_term = get_term( wp_create_nav_menu( 'Bar' ) );
  937. $results = $menus->filter_wp_nav_menu_args(
  938. array(
  939. 'echo' => true,
  940. 'fallback_cb' => 'wp_page_menu',
  941. 'walker' => '',
  942. 'menu' => $nav_menu_term,
  943. 'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
  944. )
  945. );
  946. $this->assertTrue( $results['can_partial_refresh'] );
  947. $this->assertArrayHasKey( 'customize_preview_nav_menus_args', $results );
  948. $this->assertSame( $nav_menu_term->term_id, $results['customize_preview_nav_menus_args']['menu'] );
  949. $results = $menus->filter_wp_nav_menu_args(
  950. array(
  951. 'echo' => true,
  952. 'fallback_cb' => 'wp_page_menu',
  953. 'walker' => '',
  954. 'menu' => $menu_id,
  955. 'container' => 'div',
  956. 'items_wrap' => '%3$s',
  957. )
  958. );
  959. $this->assertTrue( $results['can_partial_refresh'] );
  960. $results = $menus->filter_wp_nav_menu_args(
  961. array(
  962. 'echo' => true,
  963. 'fallback_cb' => 'wp_page_menu',
  964. 'walker' => '',
  965. 'menu' => $menu_id,
  966. 'container' => false,
  967. 'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
  968. )
  969. );
  970. $this->assertTrue( $results['can_partial_refresh'] );
  971. $results = $menus->filter_wp_nav_menu_args(
  972. array(
  973. 'echo' => true,
  974. 'fallback_cb' => 'wp_page_menu',
  975. 'walker' => '',
  976. 'menu' => $menu_id,
  977. 'container' => false,
  978. 'items_wrap' => '%3$s',
  979. )
  980. );
  981. $this->assertFalse( $results['can_partial_refresh'] );
  982. }
  983. /**
  984. * Test the filter_wp_nav_menu method.
  985. *
  986. * @covers WP_Customize_Nav_Menus::filter_wp_nav_menu
  987. * @covers WP_Customize_Nav_Menus::filter_wp_nav_menu_args
  988. */
  989. function test_filter_wp_nav_menu() {
  990. do_action( 'customize_register', $this->wp_customize );
  991. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  992. $original_args = array(
  993. 'echo' => true,
  994. 'menu' => wp_create_nav_menu( 'Foo' ),
  995. 'fallback_cb' => 'wp_page_menu',
  996. 'walker' => '',
  997. 'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
  998. );
  999. // Add global namespace prefix to check #41488.
  1000. $original_args['fallback_cb'] = '\\' . $original_args['fallback_cb'];
  1001. $args = $menus->filter_wp_nav_menu_args( $original_args );
  1002. ob_start();
  1003. wp_nav_menu( $args );
  1004. $nav_menu_content = ob_get_clean();
  1005. $result = $menus->filter_wp_nav_menu( $nav_menu_content, (object) $args );
  1006. $this->assertContains( sprintf( ' data-customize-partial-id="nav_menu_instance[%s]"', $args['customize_preview_nav_menus_args']['args_hmac'] ), $result );
  1007. $this->assertContains( ' data-customize-partial-type="nav_menu_instance"', $result );
  1008. $this->assertTrue( (bool) preg_match( '/data-customize-partial-placement-context="(.+?)"/', $result, $matches ) );
  1009. $context = json_decode( html_entity_decode( $matches[1] ), true );
  1010. $this->assertSame( $original_args, wp_array_slice_assoc( $context, array_keys( $original_args ) ) ); // Because assertArraySubset is not available in PHP 5.2.
  1011. $this->assertTrue( $context['can_partial_refresh'] );
  1012. }
  1013. /**
  1014. * Test the customize_preview_enqueue_deps method.
  1015. *
  1016. * @see WP_Customize_Nav_Menus::customize_preview_enqueue_deps()
  1017. */
  1018. function test_customize_preview_enqueue_deps() {
  1019. do_action( 'customize_register', $this->wp_customize );
  1020. $menus = new WP_Customize_Nav_Menus( $this->wp_customize );
  1021. $menus->customize_preview_enqueue_deps();
  1022. $this->assertTrue( wp_script_is( 'customize-preview-nav-menus' ) );
  1023. }
  1024. /**
  1025. * Test WP_Customize_Nav_Menus::export_preview_data() method.
  1026. *
  1027. * @see WP_Customize_Nav_Menus::export_preview_data()
  1028. */
  1029. function test_export_preview_data() {
  1030. ob_start();
  1031. $this->wp_customize->nav_menus->export_preview_data();
  1032. $html = ob_get_clean();
  1033. $this->assertTrue( (bool) preg_match( '/_wpCustomizePreviewNavMenusExports = ({.+})/s', $html, $matches ) );
  1034. $exported_data = json_decode( $matches[1], true );
  1035. $this->assertArrayHasKey( 'navMenuInstanceArgs', $exported_data );
  1036. }
  1037. /**
  1038. * Test WP_Customize_Nav_Menus::render_nav_menu_partial() method.
  1039. *
  1040. * @see WP_Customize_Nav_Menus::render_nav_menu_partial()
  1041. */
  1042. function test_render_nav_menu_partial() {
  1043. $this->wp_customize->nav_menus->customize_preview_init();
  1044. $menu = wp_create_nav_menu( 'Foo' );
  1045. wp_update_nav_menu_item(
  1046. $menu,
  1047. 0,
  1048. array(
  1049. 'menu-item-type' => 'custom',
  1050. 'menu-item-title' => 'WordPress.org',
  1051. 'menu-item-url' => 'https://wordpress.org',
  1052. 'menu-item-status' => 'publish',
  1053. )
  1054. );
  1055. $nav_menu_args = $this->wp_customize->nav_menus->filter_wp_nav_menu_args(
  1056. array(
  1057. 'echo' => true,
  1058. 'menu' => $menu,
  1059. 'fallback_cb' => 'wp_page_menu',
  1060. 'walker' => '',
  1061. 'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
  1062. )
  1063. );
  1064. $partial_id = sprintf( 'nav_menu_instance[%s]', $nav_menu_args['customize_preview_nav_menus_args']['args_hmac'] );
  1065. $partials = $this->wp_customize->selective_refresh->add_dynamic_partials( array( $partial_id ) );
  1066. $this->assertNotEmpty( $partials );
  1067. $partial = array_shift( $partials );
  1068. $this->assertSame( $partial_id, $partial->id );
  1069. $missing_args_hmac_args = array_merge(
  1070. $nav_menu_args['customize_preview_nav_menus_args'],
  1071. array( 'args_hmac' => null )
  1072. );
  1073. $this->assertFalse( $partial->render( $missing_args_hmac_args ) );
  1074. $args_hmac_mismatch_args = array_merge(
  1075. $nav_menu_args['customize_preview_nav_menus_args'],
  1076. array( 'args_hmac' => strrev( $nav_menu_args['customize_preview_nav_menus_args']['args_hmac'] ) )
  1077. );
  1078. $this->assertFalse( $partial->render( $args_hmac_mismatch_args ) );
  1079. $rendered = $partial->render( $nav_menu_args['customize_preview_nav_menus_args'] );
  1080. $this->assertContains( 'data-customize-partial-type="nav_menu_instance"', $rendered );
  1081. $this->assertContains( 'WordPress.org', $rendered );
  1082. }
  1083. }