PLL_Admin_Nav_Menu

Manages custom menus translations as well as the language switcher menu item on admin side.

Defined (1)

The class is defined in the following location(s).

/admin/admin-nav-menu.php  
  1. class PLL_Admin_Nav_Menu extends PLL_Nav_Menu { 
  2.  
  3. /** 
  4. * constructor: setups filters and actions 
  5. * @since 1.2 
  6. * @param object $polylang 
  7. */ 
  8. public function __construct( &$polylang ) { 
  9. parent::__construct( $polylang ); 
  10.  
  11. $this->theme = get_option( 'stylesheet' ); 
  12.  
  13. // populates nav menus locations 
  14. // since WP 4.4, must be done before customize_register is fired 
  15. add_filter( 'theme_mod_nav_menu_locations', array( $this, 'theme_mod_nav_menu_locations' ), 20 ); 
  16.  
  17. // integration in the WP menu interface 
  18. add_action( 'admin_init', array( $this, 'admin_init' ) ); // after Polylang upgrade 
  19.  
  20. /** 
  21. * setups filters and terms 
  22. * adds the language switcher metabox and create new nav menu locations 
  23. * @since 1.1 
  24. */ 
  25. public function admin_init() { 
  26. add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); 
  27. add_action( 'wp_update_nav_menu_item', array( $this, 'wp_update_nav_menu_item' ), 10, 2 ); 
  28. add_filter( 'wp_get_nav_menu_items', array( $this, 'translate_switcher_title' ) ); 
  29.  
  30. // translation of menus based on chosen locations 
  31. add_filter( 'pre_update_option_theme_mods_' . $this->theme, array( $this, 'pre_update_option_theme_mods' ) ); 
  32. add_action( 'delete_nav_menu', array( $this, 'delete_nav_menu' ) ); 
  33.  
  34. // filter _wp_auto_add_pages_to_menu by language 
  35. add_action( 'transition_post_status', array( $this, 'auto_add_pages_to_menu' ), 5, 3 ); // before _wp_auto_add_pages_to_menu 
  36.  
  37. // FIXME is it possible to choose the order ( after theme locations in WP3.5 and older ) ? 
  38. // FIXME not displayed if Polylang is activated before the first time the user goes to nav menus http://core.trac.wordpress.org/ticket/16828 
  39. add_meta_box( 'pll_lang_switch_box', __( 'Language switcher', 'polylang' ), array( $this, 'lang_switch' ), 'nav-menus', 'side', 'high' ); 
  40.  
  41. $this->create_nav_menu_locations(); 
  42.  
  43. /** 
  44. * language switcher metabox 
  45. * The checkbox and all hidden fields are important 
  46. * thanks to John Morris for his very interesting post http://www.johnmorrisonline.com/how-to-add-a-fully-functional-custom-meta-box-to-wordpress-navigation-menus/ 
  47. * @since 1.1 
  48. */ 
  49. public function lang_switch() { 
  50. global $_nav_menu_placeholder, $nav_menu_selected_id; 
  51. $_nav_menu_placeholder = 0 > $_nav_menu_placeholder ? $_nav_menu_placeholder - 1 : -1; ?> 
  52.  
  53. <div id="posttype-lang-switch" class="posttypediv"> 
  54. <div id="tabs-panel-lang-switch" class="tabs-panel tabs-panel-active"> 
  55. <ul id="lang-switch-checklist" class="categorychecklist form-no-clear"> 
  56. <li> 
  57. <label class="menu-item-title"> 
  58. <input type="checkbox" class="menu-item-checkbox" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-object-id]" value="-1"> <?php esc_html_e( 'Language switcher', 'polylang' ); ?> 
  59. </label> 
  60. <input type="hidden" class="menu-item-type" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-type]" value="custom"> 
  61. <input type="hidden" class="menu-item-title" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-title]" value="<?php esc_html_e( 'Language switcher', 'polylang' ); ?>"> 
  62. <input type="hidden" class="menu-item-url" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-url]" value="#pll_switcher"> 
  63. </li> 
  64. </ul> 
  65. </div> 
  66. <p class="button-controls"> 
  67. <span class="add-to-menu"> 
  68. <input type="submit" <?php disabled( $nav_menu_selected_id, 0 ); ?> class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-post-type-menu-item" id="submit-posttype-lang-switch"> 
  69. <span class="spinner"></span> 
  70. </span> 
  71. </p> 
  72. </div><?php 
  73.  
  74. /** 
  75. * prepares javascript to modify the language switcher menu item 
  76. * @since 1.1 
  77. */ 
  78. public function admin_enqueue_scripts() { 
  79. $screen = get_current_screen(); 
  80. if ( 'nav-menus' != $screen->base ) { 
  81. return; 
  82.  
  83. $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; 
  84. wp_enqueue_script( 'pll_nav_menu', plugins_url( '/js/nav-menu' . $suffix . '.js', POLYLANG_FILE ), array( 'jquery' ), POLYLANG_VERSION ); 
  85.  
  86. $data['strings'] = PLL_Switcher::get_switcher_options( 'menu', 'string' ); // the strings for the options 
  87. $data['title'] = __( 'Language switcher', 'polylang' ); // the title 
  88.  
  89. // get all language switcher menu items 
  90. $items = get_posts( array( 
  91. 'numberposts' => -1,  
  92. 'nopaging' => true,  
  93. 'post_type' => 'nav_menu_item',  
  94. 'fields' => 'ids',  
  95. 'meta_key' => '_pll_menu_item',  
  96. ) ); 
  97.  
  98. // the options values for the language switcher 
  99. $data['val'] = array(); 
  100. foreach ( $items as $item ) { 
  101. $data['val'][ $item ] = get_post_meta( $item, '_pll_menu_item', true ); 
  102.  
  103. // send all these data to javascript 
  104. wp_localize_script( 'pll_nav_menu', 'pll_data', $data ); 
  105.  
  106. /** 
  107. * save our menu item options 
  108. * @since 1.1 
  109. * @param int $menu_id not used 
  110. * @param int $menu_item_db_id 
  111. */ 
  112. public function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0 ) { 
  113. if ( empty( $_POST['menu-item-url'][ $menu_item_db_id ] ) || '#pll_switcher' != $_POST['menu-item-url'][ $menu_item_db_id ] ) { 
  114. return; 
  115.  
  116. // security check 
  117. // as 'wp_update_nav_menu_item' can be called from outside WP admin 
  118. if ( current_user_can( 'edit_theme_options' ) ) { 
  119. check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' ); 
  120.  
  121. $options = array( 'hide_if_no_translation' => 0, 'hide_current' => 0, 'force_home' => 0 , 'show_flags' => 0 , 'show_names' => 1, 'dropdown' => 0 ); // default values 
  122. // our jQuery form has not been displayed 
  123. if ( empty( $_POST['menu-item-pll-detect'][ $menu_item_db_id ] ) ) { 
  124. if ( ! get_post_meta( $menu_item_db_id, '_pll_menu_item', true ) ) { // our options were never saved 
  125. update_post_meta( $menu_item_db_id, '_pll_menu_item', $options ); 
  126. else { 
  127. foreach ( $options as $opt => $v ) { 
  128. $options[ $opt ] = empty( $_POST[ 'menu-item-' . $opt ][ $menu_item_db_id ] ) ? 0 : 1; 
  129. update_post_meta( $menu_item_db_id, '_pll_menu_item', $options ); // allow us to easily identify our nav menu item 
  130.  
  131. /** 
  132. * translates the language switcher menu items title in case the user switches the admin language 
  133. * @since 1.1.1 
  134. * @param array $items 
  135. * @return array modified $items 
  136. */ 
  137. public function translate_switcher_title( $items ) { 
  138. foreach ( $items as $item ) { 
  139. if ( '#pll_switcher' == $item->url ) { 
  140. $item->post_title = __( 'Language switcher', 'polylang' ); 
  141. return $items; 
  142.  
  143. /** 
  144. * assign menu languages and translations based on ( temporary ) locations 
  145. * @since 1.8 
  146. * @param array $locations nav menu locations 
  147. * @return array 
  148. */ 
  149. public function update_nav_menu_locations( $locations ) { 
  150. $default = $this->options['default_lang']; 
  151.  
  152. // extract language and menu from locations 
  153. foreach ( $locations as $loc => $menu ) { 
  154. $infos = $this->explode_location( $loc ); 
  155. $this->options['nav_menus'][ $this->theme ][ $infos['location'] ][ $infos['lang'] ] = $menu; 
  156. if ( $this->options['default_lang'] != $infos['lang'] ) { 
  157. unset( $locations[ $loc ] ); // remove temporary locations before database update 
  158.  
  159. update_option( 'polylang', $this->options ); 
  160. return $locations; 
  161.  
  162. /** 
  163. * assign menu languages and translations based on ( temporary ) locations 
  164. * @since 1.1 
  165. * @param array $mods theme mods 
  166. * @return unmodified $mods 
  167. */ 
  168. public function pre_update_option_theme_mods( $mods ) { 
  169. if ( current_user_can( 'edit_theme_options' ) && isset( $mods['nav_menu_locations'] ) ) { 
  170.  
  171. // Manage Locations tab in Appearance -> Menus 
  172. if ( isset( $_GET['action'] ) && 'locations' == $_GET['action'] ) { 
  173. check_admin_referer( 'save-menu-locations' ); 
  174. $this->options['nav_menus'][ $this->theme ] = array(); 
  175.  
  176. // Edit Menus tab in Appearance -> Menus 
  177. // add the test of $_POST['update-nav-menu-nonce'] to avoid conflict with Vantage theme 
  178. elseif ( isset( $_POST['action'], $_POST['update-nav-menu-nonce'] ) && 'update' == $_POST['action'] ) { 
  179. check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' ); 
  180. $this->options['nav_menus'][ $this->theme ] = array(); 
  181.  
  182. // customizer 
  183. // don't reset locations in this case. 
  184. // see http://wordpress.org/support/topic/menus-doesnt-show-and-not-saved-in-theme-settings-multilingual-site 
  185. elseif ( isset( $_POST['action'] ) && 'customize_save' == $_POST['action'] ) { 
  186. check_ajax_referer( 'save-customize_' . $GLOBALS['wp_customize']->get_stylesheet(), 'nonce' ); 
  187.  
  188. else { 
  189. return $mods; // no modification for nav menu locations 
  190.  
  191. $mods['nav_menu_locations'] = $this->update_nav_menu_locations( $mods['nav_menu_locations'] ); 
  192. return $mods; 
  193.  
  194. /** 
  195. * fills temporary menu locations based on menus translations 
  196. * @since 1.2 
  197. * @param bool|array $menus 
  198. * @return bool|array modified list of menu locations 
  199. */ 
  200. public function theme_mod_nav_menu_locations( $menus ) { 
  201. if ( is_array( $menus ) ) { 
  202. foreach ( $menus as $loc => $menu ) { 
  203. foreach ( $this->model->get_languages_list() as $lang ) { 
  204. if ( ! empty( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ] ) && term_exists( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ], 'nav_menu' ) ) { 
  205. $menus[ $this->combine_location( $loc, $lang ) ] = $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ]; 
  206.  
  207. return $menus; 
  208.  
  209. /** 
  210. * removes the nav menu term_id from the locations stored in Polylang options when a nav menu is deleted 
  211. * @since 1.7.3 
  212. * @param int nav menu id 
  213. */ 
  214. function delete_nav_menu( $term_id ) { 
  215. if ( isset( $this->options['nav_menus'] ) ) { 
  216. foreach ( $this->options['nav_menus'] as $theme => $locations ) { 
  217. foreach ( $locations as $loc => $languages ) { 
  218. foreach ( $languages as $lang => $menu_id ) { 
  219. if ( $menu_id === $term_id ) { 
  220. unset( $this->options['nav_menus'][ $theme ][ $loc ][ $lang ] ); 
  221.  
  222. update_option( 'polylang', $this->options ); 
  223.  
  224. /** 
  225. * filters the option nav_menu_options for auto added pages to menu 
  226. * @since 0.9.4 
  227. * @param array $options 
  228. * @return array Modified options 
  229. */ 
  230. public function nav_menu_options( $options ) { 
  231. $options['auto_add'] = array_intersect( $options['auto_add'], $this->auto_add_menus ); 
  232. return $options; 
  233.  
  234. /** 
  235. * filters _wp_auto_add_pages_to_menu by language 
  236. * @since 0.9.4 
  237. * @param string $new_status Transition to this post status. 
  238. * @param string $old_status Previous post status. 
  239. * @param object $post Post data. 
  240. */ 
  241. public function auto_add_pages_to_menu( $new_status, $old_status, $post ) { 
  242. if ( 'publish' != $new_status || 'publish' == $old_status || 'page' != $post->post_type || ! empty( $post->post_parent ) || ! ( $lang = $this->model->post->get_language( $post->ID ) ) ) { 
  243. return; 
  244.  
  245. if ( ! empty( $this->options['nav_menus'][ $this->theme ] ) ) { 
  246. $this->auto_add_menus = array(); 
  247.  
  248. // get all the menus in the page language 
  249. foreach ( $this->options['nav_menus'][ $this->theme ] as $loc ) { 
  250. if ( ! empty( $loc[ $lang->slug ] ) ) { 
  251. $this->auto_add_menus[] = $loc[ $lang->slug ]; 
  252.  
  253. add_filter( 'option_nav_menu_options', array( $this, 'nav_menu_options' ) );