PageRenderTime 49ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/polylang/frontend/frontend-nav-menu.php

https://gitlab.com/mostafame/team_website
PHP | 280 lines | 150 code | 33 blank | 97 comment | 32 complexity | c92f7c56fc459d940febee56de4e32bd MD5 | raw file
  1. <?php
  2. /**
  3. * Manages custom menus translations as well as the language switcher menu item on frontend
  4. *
  5. * @since 1.2
  6. */
  7. class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu {
  8. public $curlang;
  9. /**
  10. * Constructor
  11. *
  12. * @since 1.2
  13. */
  14. public function __construct( &$polylang ) {
  15. parent::__construct( $polylang );
  16. $this->curlang = &$polylang->curlang;
  17. // Split the language switcher menu item in several language menu items
  18. add_filter( 'wp_get_nav_menu_items', array( &$this, 'wp_get_nav_menu_items' ), 20 ); // after the customizer menus
  19. add_filter( 'wp_nav_menu_objects', array( &$this, 'wp_nav_menu_objects' ) );
  20. add_filter( 'nav_menu_link_attributes', array( &$this, 'nav_menu_link_attributes' ), 10, 3 );
  21. // Filters menus by language
  22. add_filter( 'theme_mod_nav_menu_locations', array( $this, 'nav_menu_locations' ), 20 );
  23. add_filter( 'wp_nav_menu_args', array( &$this, 'wp_nav_menu_args' ) );
  24. // The customizer
  25. if ( isset( $_POST['wp_customize'], $_POST['customized'] ) ) {
  26. add_filter( 'wp_nav_menu_args', array( &$this, 'filter_args_before_customizer' ) );
  27. add_filter( 'wp_nav_menu_args', array( &$this, 'filter_args_after_customizer' ), 2000 );
  28. }
  29. }
  30. /**
  31. * Sort menu items by menu order
  32. *
  33. * @since 1.7.9
  34. *
  35. * @param object $a The first object to compare
  36. * @param object $b The second object to compare
  37. * @return int -1 or 1 if $a is considered to be respectively less than or greater than $b.
  38. */
  39. protected function usort_menu_items( $a, $b ) {
  40. return ( $a->menu_order < $b->menu_order ) ? -1 : 1;
  41. }
  42. /**
  43. * Splits the one item of backend in several items on frontend
  44. * take care to menu_order as it is used later in wp_nav_menu
  45. *
  46. * @since 1.1.1
  47. *
  48. * @param array $items menu items
  49. * @return array modified items
  50. */
  51. public function wp_get_nav_menu_items( $items ) {
  52. if ( doing_action( 'customize_register' ) ) { // needed since WP 4.3, doing_action available since WP 3.9
  53. return $items;
  54. }
  55. // The customizer menus does not sort the items and we need them to be sorted before splitting the language switcher
  56. usort( $items, array( $this, 'usort_menu_items' ) );
  57. $new_items = array();
  58. $offset = 0;
  59. foreach ( $items as $key => $item ) {
  60. if ( $options = get_post_meta( $item->ID, '_pll_menu_item', true ) ) {
  61. $i = 0;
  62. $switcher = new PLL_Switcher;
  63. $args = array_merge( array( 'raw' => 1 ), $options );
  64. $the_languages = $switcher->the_languages( PLL()->links, $args );
  65. foreach ( $the_languages as $lang ) {
  66. $lang_item = clone $item;
  67. $lang_item->ID = $lang_item->ID . '-' . $lang['slug']; // A unique ID
  68. $lang_item->title = $options['show_flags'] && $options['show_names'] ? $lang['flag'] . '<span style="margin-left:0.3em;">' . esc_html( $lang['name'] ) . '</span>' : ( $options['show_flags'] ? $lang['flag'] : esc_html( $lang['name'] ) );
  69. $lang_item->url = $lang['url'];
  70. $lang_item->lang = $lang['locale']; // Save this for use in nav_menu_link_attributes
  71. $lang_item->classes = $lang['classes'];
  72. $lang_item->menu_order += $offset + $i++;
  73. $new_items[] = $lang_item;
  74. }
  75. $offset += $i - 1;
  76. } else {
  77. $item->menu_order += $offset;
  78. $new_items[] = $item;
  79. }
  80. }
  81. return $new_items;
  82. }
  83. /**
  84. * Returns the ancestors of a menu item
  85. *
  86. * @since 1.1.1
  87. *
  88. * @param object $item
  89. * @return array ancestors ids
  90. */
  91. public function get_ancestors( $item ) {
  92. $ids = array();
  93. $_anc_id = (int) $item->db_id;
  94. while ( ( $_anc_id = get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) ) && ! in_array( $_anc_id, $ids ) ) {
  95. $ids[] = $_anc_id;
  96. }
  97. return $ids;
  98. }
  99. /**
  100. * Removes current-menu and current-menu-ancestor classes to lang switcher when not on the home page
  101. *
  102. * @since 1.1.1
  103. *
  104. * @param array $items
  105. * @return array modified menu items
  106. */
  107. public function wp_nav_menu_objects( $items ) {
  108. $r_ids = $k_ids = array();
  109. foreach ( $items as $item ) {
  110. if ( ! empty( $item->classes ) && is_array( $item->classes ) ) {
  111. if ( in_array( 'current-lang', $item->classes ) ) {
  112. $item->classes = array_diff( $item->classes, array( 'current-menu-item' ) );
  113. $r_ids = array_merge( $r_ids, $this->get_ancestors( $item ) ); // Remove the classes for these ancestors
  114. } elseif ( in_array( 'current-menu-item', $item->classes ) ) {
  115. $k_ids = array_merge( $k_ids, $this->get_ancestors( $item ) ); // Keep the classes for these ancestors
  116. }
  117. }
  118. }
  119. $r_ids = array_diff( $r_ids, $k_ids );
  120. foreach ( $items as $item ) {
  121. if ( ! empty( $item->db_id ) && in_array( $item->db_id, $r_ids ) ) {
  122. $item->classes = array_diff( $item->classes, array( 'current-menu-ancestor', 'current-menu-parent', 'current_page_parent', 'current_page_ancestor' ) );
  123. }
  124. }
  125. return $items;
  126. }
  127. /**
  128. * Adds hreflang attribute for the language switcher menu items
  129. * available since WP3.6
  130. *
  131. * @since 1.1
  132. *
  133. * @param array $atts
  134. * @return array modified $atts
  135. */
  136. public function nav_menu_link_attributes( $atts, $item, $args ) {
  137. if ( isset( $item->lang ) ) {
  138. $atts['hreflang'] = esc_attr( $item->lang );
  139. }
  140. return $atts;
  141. }
  142. /**
  143. * Fills the theme nav menus locations with the right menu in the right language
  144. * Needs to wait for the language to be defined
  145. *
  146. * @since 1.2
  147. *
  148. * @param array|bool list of nav menus locations, false if menu locations have not been filled yet
  149. * @return array|bool modified list of nav menus locations
  150. */
  151. public function nav_menu_locations( $menus ) {
  152. if ( is_array( $menus ) && ! empty( $this->curlang ) ) {
  153. // First get multilingual menu locations from DB
  154. $theme = get_option( 'stylesheet' );
  155. foreach ( $menus as $loc => $menu ) {
  156. $menus[ $loc ] = empty( $this->options['nav_menus'][ $theme ][ $loc ][ $this->curlang->slug ] ) ? 0 : $this->options['nav_menus'][ $theme ][ $loc ][ $this->curlang->slug ];
  157. }
  158. // Support for theme customizer
  159. // Let's look for multilingual menu locations directly in $_POST as there are not in customizer object
  160. if ( isset( $_POST['wp_customize'], $_POST['customized'] ) ) {
  161. $customized = json_decode( wp_unslash( $_POST['customized'] ) );
  162. if ( is_object( $customized ) ) {
  163. foreach ( $customized as $key => $c ) {
  164. if ( false !== strpos( $key, 'nav_menu_locations[' ) ) {
  165. $loc = substr( trim( $key, ']' ), 19 );
  166. $infos = $this->explode_location( $loc );
  167. if ( $infos['lang'] == $this->curlang->slug ) {
  168. $menus[ $infos['location'] ] = $c;
  169. } elseif ( $this->curlang->slug == $this->options['default_lang'] ) {
  170. $menus[ $loc ] = $c;
  171. }
  172. }
  173. }
  174. }
  175. }
  176. }
  177. return $menus;
  178. }
  179. /**
  180. * Attempt to translate the nav menu when it is hardcoded or when no location is defined in wp_nav_menu
  181. *
  182. * @since 1.7.10
  183. *
  184. * @param array $args
  185. * @return array modified $args
  186. */
  187. public function wp_nav_menu_args( $args ) {
  188. $theme = get_option( 'stylesheet' );
  189. if ( empty( $this->curlang ) || empty( $this->options['nav_menus'][ $theme ] ) ) {
  190. return $args;
  191. }
  192. // Get the nav menu based on the requested menu
  193. $menu = wp_get_nav_menu_object( $args['menu'] );
  194. // Attempt to find a translation of this menu
  195. // This obviously does not work if the nav menu has no associated theme location
  196. if ( $menu ) {
  197. foreach ( $this->options['nav_menus'][ $theme ] as $menus ) {
  198. if ( in_array( $menu->term_id, $menus ) && ! empty( $menus[ $this->curlang->slug ] ) ) {
  199. $args['menu'] = $menus[ $this->curlang->slug ];
  200. return $args;
  201. }
  202. }
  203. }
  204. // Get the first menu that has items and and is in the current language if we still can't find a menu
  205. if ( ! $menu && ! $args['theme_location'] ) {
  206. $menus = wp_get_nav_menus();
  207. foreach ( $menus as $menu_maybe ) {
  208. if ( $menu_items = wp_get_nav_menu_items( $menu_maybe->term_id, array( 'update_post_term_cache' => false ) ) ) {
  209. foreach ( $this->options['nav_menus'][ $theme ] as $menus ) {
  210. if ( in_array( $menu_maybe->term_id, $menus ) && ! empty( $menus[ $this->curlang->slug ] ) ) {
  211. $args['menu'] = $menus[ $this->curlang->slug ];
  212. return $args;
  213. }
  214. }
  215. }
  216. }
  217. }
  218. return $args;
  219. }
  220. /**
  221. * Filters the nav menu location before the customizer so that it matches the temporary location in the customizer
  222. *
  223. * @since 1.8
  224. *
  225. * @param array $args wp_nav_menu $args
  226. * @return array modified $args
  227. */
  228. public function filter_args_before_customizer( $args ) {
  229. if ( ! empty( $this->curlang ) ) {
  230. $args['theme_location'] = $this->combine_location( $args['theme_location'], $this->curlang );
  231. }
  232. return $args;
  233. }
  234. /**
  235. * Filters the nav menu location after the customizer to get back the true nav menu location for the theme
  236. *
  237. * @since 1.8
  238. *
  239. * @param array $args wp_nav_menu $args
  240. * @return array modified $args
  241. */
  242. public function filter_args_after_customizer( $args ) {
  243. $infos = $this->explode_location( $args['theme_location'] );
  244. $args['theme_location'] = $infos['location'];
  245. return $args;
  246. }
  247. }