PluginProbe
Polylang / 2.2
Polylang v2.2
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.2, at admin/admin-nav-menu.php

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