PluginProbe
Polylang / 1.8
Polylang v1.8
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 1.8, at admin/admin-nav-menu.php

337 lines 11.8 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 _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 _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 // the strings for the options
109 foreach ( array_reverse( PLL_Switcher::get_switcher_options( 'menu', 'string' ) ) as $str ) {
110 $data['strings'][] = $str;
111 }
112
113 $data['title'] = __( 'Language switcher', 'polylang' ); // the title
114
115 // get all language switcher menu items
116 $items = get_posts( array(
117 'numberposts' => -1,
118 'nopaging' => true,
119 'post_type' => 'nav_menu_item',
120 'fields' => 'ids',
121 'meta_key' => '_pll_menu_item',
122 ) );
123
124 // the options values for the language switcher
125 $data['val'] = array();
126 foreach ( $items as $item ) {
127 $data['val'][ $item ] = get_post_meta( $item, '_pll_menu_item', true );
128 }
129
130 // send all these data to javascript
131 wp_localize_script( 'pll_nav_menu', 'pll_data', $data );
132 }
133
134 /*
135 * save our menu item options
136 *
137 * @since 1.1
138 *
139 * @param int $menu_id not used
140 * @param int $menu_item_db_id
141 */
142 public function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0 ) {
143 if ( empty( $_POST['menu-item-url'][ $menu_item_db_id ] ) || '#pll_switcher' != $_POST['menu-item-url'][ $menu_item_db_id ] ) {
144 return;
145 }
146
147 // security check
148 // as 'wp_update_nav_menu_item' can be called from outside WP admin
149 if ( current_user_can( 'edit_theme_options' ) ) {
150 check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );
151
152 $options = array( 'hide_if_no_translation' => 0, 'hide_current' => 0,'force_home' => 0 ,'show_flags' => 0 ,'show_names' => 1 ); // default values
153 // our jQuery form has not been displayed
154 if ( empty( $_POST['menu-item-pll-detect'][ $menu_item_db_id ] ) ) {
155 if ( ! get_post_meta( $menu_item_db_id, '_pll_menu_item', true ) ) { // our options were never saved
156 update_post_meta( $menu_item_db_id, '_pll_menu_item', $options );
157 }
158 }
159 else {
160 foreach ( $options as $opt => $v ) {
161 $options[ $opt ] = empty( $_POST[ 'menu-item-' . $opt ][ $menu_item_db_id ] ) ? 0 : 1;
162 }
163 update_post_meta( $menu_item_db_id, '_pll_menu_item', $options ); // allow us to easily identify our nav menu item
164 }
165 }
166 }
167
168 /*
169 * translates the language switcher menu items title in case the user switches the admin language
170 *
171 * @since 1.1.1
172 *
173 * @param array $items
174 * @return array modified $items
175 */
176 public function translate_switcher_title( $items ) {
177 foreach ( $items as $item ) {
178 if ( '#pll_switcher' == $item->url ) {
179 $item->post_title = __( 'Language switcher', 'polylang' );
180 }
181 }
182 return $items;
183 }
184
185 /*
186 * assign menu languages and translations based on ( temporary ) locations
187 *
188 * @since 1.8
189 *
190 * @param array $locations nav menu locations
191 * @return array
192 */
193 public function update_nav_menu_locations( $locations ) {
194 $default = $this->options['default_lang'];
195
196 // extract language and menu from locations
197 foreach ( $locations as $loc => $menu ) {
198 $infos = $this->explode_location( $loc );
199 $this->options['nav_menus'][ $this->theme ][ $infos['location'] ][ $infos['lang'] ] = $menu;
200 if ( $this->options['default_lang'] != $infos['lang'] ) {
201 unset( $locations[ $loc ] ); // remove temporary locations before database update
202 }
203 }
204
205 update_option( 'polylang', $this->options );
206 return $locations;
207 }
208
209 /*
210 * assign menu languages and translations based on ( temporary ) locations
211 *
212 * @since 1.1
213 *
214 * @param array $mods theme mods
215 * @return unmodified $mods
216 */
217 public function pre_update_option_theme_mods( $mods ) {
218 if ( current_user_can( 'edit_theme_options' ) && isset( $mods['nav_menu_locations'] ) ) {
219
220 // Manage Locations tab in Appearance -> Menus
221 if ( isset( $_GET['action'] ) && 'locations' == $_GET['action'] ) {
222 check_admin_referer( 'save-menu-locations' );
223 $this->options['nav_menus'][ $this->theme ] = array();
224 }
225
226 // Edit Menus tab in Appearance -> Menus
227 // add the test of $_POST['update-nav-menu-nonce'] to avoid conflict with Vantage theme
228 elseif ( isset( $_POST['action'], $_POST['update-nav-menu-nonce'] ) && 'update' == $_POST['action'] ) {
229 check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );
230 $this->options['nav_menus'][ $this->theme ] = array();
231 }
232
233 // customizer
234 // don't reset locations in this case.
235 // see http://wordpress.org/support/topic/menus-doesnt-show-and-not-saved-in-theme-settings-multilingual-site
236 elseif ( isset( $_POST['action'] ) && 'customize_save' == $_POST['action'] ) {
237 check_ajax_referer( 'save-customize_' . $GLOBALS['wp_customize']->get_stylesheet(), 'nonce' );
238 }
239
240 else {
241 return $mods; // no modification for nav menu locations
242 }
243
244 $mods['nav_menu_locations'] = $this->update_nav_menu_locations( $mods['nav_menu_locations'] );
245 }
246 return $mods;
247 }
248
249 /*
250 * fills temporary menu locations based on menus translations
251 *
252 * @since 1.2
253 *
254 * @param bool|array $menus
255 * @return bool|array modified list of menu locations
256 */
257 public function theme_mod_nav_menu_locations( $menus ) {
258 if ( is_array( $menus ) ) {
259 foreach ( $menus as $loc => $menu ) {
260 foreach ( $this->model->get_languages_list() as $lang ) {
261 if ( ! empty( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ] ) && term_exists( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ], 'nav_menu' ) ) {
262 $menus[ $this->combine_location( $loc, $lang ) ] = $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ];
263 }
264 }
265 }
266 }
267
268 return $menus;
269 }
270
271 /*
272 * removes the nav menu term_id from the locations stored in Polylang options when a nav menu is deleted
273 *
274 * @since 1.7.3
275 *
276 * @param int nav menu id
277 */
278 function delete_nav_menu( $term_id ) {
279 foreach ( $this->options['nav_menus'] as $theme => $locations ) {
280 foreach ( $locations as $loc => $languages ) {
281 foreach ( $languages as $lang => $menu_id ) {
282 if ( $menu_id === $term_id ) {
283 unset( $this->options['nav_menus'][ $theme ][ $loc ][ $lang ] );
284 }
285 }
286 }
287 }
288
289 update_option( 'polylang', $this->options );
290 }
291
292 /*
293 * filters _wp_auto_add_pages_to_menu by language
294 *
295 * @since 0.9.4
296 *
297 * @param string $new_status Transition to this post status.
298 * @param string $old_status Previous post status.
299 * @param object $post Post data.
300 */
301 public function auto_add_pages_to_menu( $new_status, $old_status, $post ) {
302 if ( 'publish' != $new_status || 'publish' == $old_status || 'page' != $post->post_type || ! empty( $post->post_parent ) || ! ( $lang = $this->model->post->get_language( $post->ID ) ) ) {
303 return;
304 }
305
306 if ( ! empty( $this->options['nav_menus'][ $this->theme ] ) ) {
307 // get all the menus in the page language
308 foreach ( $this->options['nav_menus'][ $this->theme ] as $loc ) {
309 if ( ! empty( $loc[ $lang->slug ] ) ) {
310 $menus[] = $loc[ $lang->slug ];
311 }
312 }
313
314 if ( ! empty( $menus ) ) {
315 $menus = implode( ',', $menus );
316 add_filter( 'option_nav_menu_options', create_function( '$a', "\$a['auto_add'] = array_intersect( \$a['auto_add'], array( $menus ) ); return \$a;" ) );
317 }
318 }
319 }
320
321 /*
322 * prevents sharing a menu term with a language term by renaming the nav menu before its creation
323 * to avoid http://core.trac.wordpress.org/ticket/24802
324 * and http://wordpress.org/support/topic/all-connection-between-elements-lost
325 * backward compatibility with WP < 4.1
326 *
327 * @since 1.1.3
328 *
329 * @param string $name term name
330 * @param string $taxonomy
331 * @return string modified ( nav menu ) term name if necessary
332 */
333 function pre_insert_term( $name, $taxonomy ) {
334 return ( 'nav_menu' == $taxonomy && in_array( $name, $this->model->get_languages_list( array( 'fields' => 'name' ) ) ) ) ? $name .= '-menu' : $name;
335 }
336 }
337