PluginProbe
Polylang / 2.0.3
Polylang v2.0.3
3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 3.0.3 All 233 releases
polylang / admin / admin-nav-menu.php

admin-nav-menu.php in Polylang 2.0.3, at admin/admin-nav-menu.php

348 lines 12.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * manages custom menus translations as well as the language switcher menu item on admin side
5 *
6 * @since 1.2
7 */
8 class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
9
10 /**
11 * constructor: setups filters and actions
12 *
13 * @since 1.2
14 *
15 * @param object $polylang
16 */
17 public function __construct( &$polylang ) {
18 parent::__construct( $polylang );
19
20 $this->theme = get_option( 'stylesheet' );
21
22 // populates nav menus locations
23 // since WP 4.4, must be done before customize_register is fired
24 add_filter( 'theme_mod_nav_menu_locations', array( $this, 'theme_mod_nav_menu_locations' ), 20 );
25
26 // integration in the WP menu interface
27 add_action( 'admin_init', array( $this, 'admin_init' ) ); // after Polylang upgrade
28
29 // protection against #24802
30 // backward compatibility with WP < 4.1
31 if ( version_compare( $GLOBALS['wp_version'], '4.1', '<' ) ) {
32 add_filter( 'pre_insert_term', array( $this, 'pre_insert_term' ), 10, 2 );
33 }
34 }
35
36 /**
37 * setups filters and terms
38 * adds the language switcher metabox and create new nav menu locations
39 *
40 * @since 1.1
41 */
42 public function admin_init() {
43 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
44 add_action( 'wp_update_nav_menu_item', array( $this, 'wp_update_nav_menu_item' ), 10, 2 );
45 add_filter( 'wp_get_nav_menu_items', array( $this, 'translate_switcher_title' ) );
46
47 // translation of menus based on chosen locations
48 add_filter( 'pre_update_option_theme_mods_' . $this->theme, array( $this, 'pre_update_option_theme_mods' ) );
49 add_action( 'delete_nav_menu', array( $this, 'delete_nav_menu' ) );
50
51 // filter _wp_auto_add_pages_to_menu by language
52 add_action( 'transition_post_status', array( $this, 'auto_add_pages_to_menu' ), 5, 3 ); // before _wp_auto_add_pages_to_menu
53
54 // FIXME is it possible to choose the order ( after theme locations in WP3.5 and older ) ?
55 // FIXME not displayed if Polylang is activated before the first time the user goes to nav menus http://core.trac.wordpress.org/ticket/16828
56 add_meta_box( 'pll_lang_switch_box', __( 'Language switcher', 'polylang' ), array( $this, 'lang_switch' ), 'nav-menus', 'side', 'high' );
57
58 $this->create_nav_menu_locations();
59 }
60
61 /**
62 * language switcher metabox
63 * The checkbox and all hidden fields are important
64 * 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/
65 *
66 * @since 1.1
67 */
68 public function lang_switch() {
69 global $_nav_menu_placeholder, $nav_menu_selected_id;
70 $_nav_menu_placeholder = 0 > $_nav_menu_placeholder ? $_nav_menu_placeholder - 1 : -1; ?>
71
72 <div id="posttype-lang-switch" class="posttypediv">
73 <div id="tabs-panel-lang-switch" class="tabs-panel tabs-panel-active">
74 <ul id ="lang-switch-checklist" class="categorychecklist form-no-clear">
75 <li>
76 <label class="menu-item-title">
77 <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' ); ?>
78 </label>
79 <input type="hidden" class="menu-item-type" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-type]" value="custom">
80 <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' ); ?>">
81 <input type="hidden" class="menu-item-url" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-url]" value="#pll_switcher">
82 </li>
83 </ul>
84 </div>
85 <p class="button-controls">
86 <span class="add-to-menu">
87 <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">
88 <span class="spinner"></span>
89 </span>
90 </p>
91 </div><?php
92 }
93
94 /**
95 * prepares javascript to modify the language switcher menu item
96 *
97 * @since 1.1
98 */
99 public function admin_enqueue_scripts() {
100 $screen = get_current_screen();
101 if ( 'nav-menus' != $screen->base ) {
102 return;
103 }
104
105 $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
106 wp_enqueue_script( 'pll_nav_menu', POLYLANG_URL .'/js/nav-menu' . $suffix . '.js', array( 'jquery' ), POLYLANG_VERSION );
107
108 $data['strings'] = PLL_Switcher::get_switcher_options( 'menu', 'string' ); // the strings for the options
109 $data['title'] = __( 'Language switcher', 'polylang' ); // the title
110
111 // get all language switcher menu items
112 $items = get_posts( array(
113 'numberposts' => -1,
114 'nopaging' => true,
115 'post_type' => 'nav_menu_item',
116 'fields' => 'ids',
117 'meta_key' => '_pll_menu_item',
118 ) );
119
120 // the options values for the language switcher
121 $data['val'] = array();
122 foreach ( $items as $item ) {
123 $data['val'][ $item ] = get_post_meta( $item, '_pll_menu_item', true );
124 }
125
126 // send all these data to javascript
127 wp_localize_script( 'pll_nav_menu', 'pll_data', $data );
128 }
129
130 /**
131 * save our menu item options
132 *
133 * @since 1.1
134 *
135 * @param int $menu_id not used
136 * @param int $menu_item_db_id
137 */
138 public function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0 ) {
139 if ( empty( $_POST['menu-item-url'][ $menu_item_db_id ] ) || '#pll_switcher' != $_POST['menu-item-url'][ $menu_item_db_id ] ) {
140 return;
141 }
142
143 // security check
144 // as 'wp_update_nav_menu_item' can be called from outside WP admin
145 if ( current_user_can( 'edit_theme_options' ) ) {
146 check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );
147
148 $options = array( 'hide_if_no_translation' => 0, 'hide_current' => 0,'force_home' => 0 ,'show_flags' => 0 ,'show_names' => 1, 'dropdown' => 0 ); // default values
149 // our jQuery form has not been displayed
150 if ( empty( $_POST['menu-item-pll-detect'][ $menu_item_db_id ] ) ) {
151 if ( ! get_post_meta( $menu_item_db_id, '_pll_menu_item', true ) ) { // our options were never saved
152 update_post_meta( $menu_item_db_id, '_pll_menu_item', $options );
153 }
154 }
155 else {
156 foreach ( $options as $opt => $v ) {
157 $options[ $opt ] = empty( $_POST[ 'menu-item-' . $opt ][ $menu_item_db_id ] ) ? 0 : 1;
158 }
159 update_post_meta( $menu_item_db_id, '_pll_menu_item', $options ); // allow us to easily identify our nav menu item
160 }
161 }
162 }
163
164 /**
165 * translates the language switcher menu items title in case the user switches the admin language
166 *
167 * @since 1.1.1
168 *
169 * @param array $items
170 * @return array modified $items
171 */
172 public function translate_switcher_title( $items ) {
173 foreach ( $items as $item ) {
174 if ( '#pll_switcher' == $item->url ) {
175 $item->post_title = __( 'Language switcher', 'polylang' );
176 }
177 }
178 return $items;
179 }
180
181 /**
182 * assign menu languages and translations based on ( temporary ) locations
183 *
184 * @since 1.8
185 *
186 * @param array $locations nav menu locations
187 * @return array
188 */
189 public function update_nav_menu_locations( $locations ) {
190 $default = $this->options['default_lang'];
191
192 // extract language and menu from locations
193 foreach ( $locations as $loc => $menu ) {
194 $infos = $this->explode_location( $loc );
195 $this->options['nav_menus'][ $this->theme ][ $infos['location'] ][ $infos['lang'] ] = $menu;
196 if ( $this->options['default_lang'] != $infos['lang'] ) {
197 unset( $locations[ $loc ] ); // remove temporary locations before database update
198 }
199 }
200
201 update_option( 'polylang', $this->options );
202 return $locations;
203 }
204
205 /**
206 * assign menu languages and translations based on ( temporary ) locations
207 *
208 * @since 1.1
209 *
210 * @param array $mods theme mods
211 * @return unmodified $mods
212 */
213 public function pre_update_option_theme_mods( $mods ) {
214 if ( current_user_can( 'edit_theme_options' ) && isset( $mods['nav_menu_locations'] ) ) {
215
216 // Manage Locations tab in Appearance -> Menus
217 if ( isset( $_GET['action'] ) && 'locations' == $_GET['action'] ) {
218 check_admin_referer( 'save-menu-locations' );
219 $this->options['nav_menus'][ $this->theme ] = array();
220 }
221
222 // Edit Menus tab in Appearance -> Menus
223 // add the test of $_POST['update-nav-menu-nonce'] to avoid conflict with Vantage theme
224 elseif ( isset( $_POST['action'], $_POST['update-nav-menu-nonce'] ) && 'update' == $_POST['action'] ) {
225 check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );
226 $this->options['nav_menus'][ $this->theme ] = array();
227 }
228
229 // customizer
230 // don't reset locations in this case.
231 // see http://wordpress.org/support/topic/menus-doesnt-show-and-not-saved-in-theme-settings-multilingual-site
232 elseif ( isset( $_POST['action'] ) && 'customize_save' == $_POST['action'] ) {
233 check_ajax_referer( 'save-customize_' . $GLOBALS['wp_customize']->get_stylesheet(), 'nonce' );
234 }
235
236 else {
237 return $mods; // no modification for nav menu locations
238 }
239
240 $mods['nav_menu_locations'] = $this->update_nav_menu_locations( $mods['nav_menu_locations'] );
241 }
242 return $mods;
243 }
244
245 /**
246 * fills temporary menu locations based on menus translations
247 *
248 * @since 1.2
249 *
250 * @param bool|array $menus
251 * @return bool|array modified list of menu locations
252 */
253 public function theme_mod_nav_menu_locations( $menus ) {
254 if ( is_array( $menus ) ) {
255 foreach ( $menus as $loc => $menu ) {
256 foreach ( $this->model->get_languages_list() as $lang ) {
257 if ( ! empty( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ] ) && term_exists( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ], 'nav_menu' ) ) {
258 $menus[ $this->combine_location( $loc, $lang ) ] = $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ];
259 }
260 }
261 }
262 }
263
264 return $menus;
265 }
266
267 /**
268 * removes the nav menu term_id from the locations stored in Polylang options when a nav menu is deleted
269 *
270 * @since 1.7.3
271 *
272 * @param int nav menu id
273 */
274 function delete_nav_menu( $term_id ) {
275 if ( isset( $this->options['nav_menus'] ) ) {
276 foreach ( $this->options['nav_menus'] as $theme => $locations ) {
277 foreach ( $locations as $loc => $languages ) {
278 foreach ( $languages as $lang => $menu_id ) {
279 if ( $menu_id === $term_id ) {
280 unset( $this->options['nav_menus'][ $theme ][ $loc ][ $lang ] );
281 }
282 }
283 }
284 }
285
286 update_option( 'polylang', $this->options );
287 }
288 }
289
290 /**
291 * filters the option nav_menu_options for auto added pages to menu
292 *
293 * @since 0.9.4
294 *
295 * @param array $options
296 * @return array Modified options
297 */
298 public function nav_menu_options( $options ) {
299 $options['auto_add'] = array_intersect( $options['auto_add'], array( $this->auto_add_menus ) );
300 return $options;
301 }
302
303 /**
304 * filters _wp_auto_add_pages_to_menu by language
305 *
306 * @since 0.9.4
307 *
308 * @param string $new_status Transition to this post status.
309 * @param string $old_status Previous post status.
310 * @param object $post Post data.
311 */
312 public function auto_add_pages_to_menu( $new_status, $old_status, $post ) {
313 if ( 'publish' != $new_status || 'publish' == $old_status || 'page' != $post->post_type || ! empty( $post->post_parent ) || ! ( $lang = $this->model->post->get_language( $post->ID ) ) ) {
314 return;
315 }
316
317 if ( ! empty( $this->options['nav_menus'][ $this->theme ] ) ) {
318 // get all the menus in the page language
319 foreach ( $this->options['nav_menus'][ $this->theme ] as $loc ) {
320 if ( ! empty( $loc[ $lang->slug ] ) ) {
321 $menus[] = $loc[ $lang->slug ];
322 }
323 }
324
325 if ( ! empty( $menus ) ) {
326 $this->auto_add_menus = implode( ',', $menus );
327 add_filter( 'option_nav_menu_options', array( $this, 'nav_menu_options' ) );
328 }
329 }
330 }
331
332 /**
333 * prevents sharing a menu term with a language term by renaming the nav menu before its creation
334 * to avoid http://core.trac.wordpress.org/ticket/24802
335 * and http://wordpress.org/support/topic/all-connection-between-elements-lost
336 * backward compatibility with WP < 4.1
337 *
338 * @since 1.1.3
339 *
340 * @param string $name term name
341 * @param string $taxonomy
342 * @return string modified ( nav menu ) term name if necessary
343 */
344 function pre_insert_term( $name, $taxonomy ) {
345 return ( 'nav_menu' == $taxonomy && in_array( $name, $this->model->get_languages_list( array( 'fields' => 'name' ) ) ) ) ? $name .= '-menu' : $name;
346 }
347 }
348