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

325 lines 11.3 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><?php
86 }
87
88 /**
89 * prepares javascript to modify the language switcher menu item
90 *
91 * @since 1.1
92 */
93 public function admin_enqueue_scripts() {
94 $screen = get_current_screen();
95 if ( 'nav-menus' != $screen->base ) {
96 return;
97 }
98
99 $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
100 wp_enqueue_script( 'pll_nav_menu', plugins_url( '/js/nav-menu' . $suffix . '.js', POLYLANG_FILE ), array( 'jquery' ), POLYLANG_VERSION );
101
102 $data['strings'] = PLL_Switcher::get_switcher_options( 'menu', 'string' ); // the strings for the options
103 $data['title'] = __( 'Language switcher', 'polylang' ); // the title
104
105 // get all language switcher menu items
106 $items = get_posts( array(
107 'numberposts' => -1,
108 'nopaging' => true,
109 'post_type' => 'nav_menu_item',
110 'fields' => 'ids',
111 'meta_key' => '_pll_menu_item',
112 ) );
113
114 // the options values for the language switcher
115 $data['val'] = array();
116 foreach ( $items as $item ) {
117 $data['val'][ $item ] = get_post_meta( $item, '_pll_menu_item', true );
118 }
119
120 // send all these data to javascript
121 wp_localize_script( 'pll_nav_menu', 'pll_data', $data );
122 }
123
124 /**
125 * save our menu item options
126 *
127 * @since 1.1
128 *
129 * @param int $menu_id not used
130 * @param int $menu_item_db_id
131 */
132 public function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0 ) {
133 if ( empty( $_POST['menu-item-url'][ $menu_item_db_id ] ) || '#pll_switcher' != $_POST['menu-item-url'][ $menu_item_db_id ] ) {
134 return;
135 }
136
137 // security check
138 // 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 if ( is_array( $menus ) ) {
249 foreach ( $menus as $loc => $menu ) {
250 foreach ( $this->model->get_languages_list() as $lang ) {
251 if ( ! empty( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ] ) && term_exists( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ], 'nav_menu' ) ) {
252 $menus[ $this->combine_location( $loc, $lang ) ] = $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ];
253 }
254 }
255 }
256 }
257
258 return $menus;
259 }
260
261 /**
262 * removes the nav menu term_id from the locations stored in Polylang options when a nav menu is deleted
263 *
264 * @since 1.7.3
265 *
266 * @param int nav menu id
267 */
268 function delete_nav_menu( $term_id ) {
269 if ( isset( $this->options['nav_menus'] ) ) {
270 foreach ( $this->options['nav_menus'] as $theme => $locations ) {
271 foreach ( $locations as $loc => $languages ) {
272 foreach ( $languages as $lang => $menu_id ) {
273 if ( $menu_id === $term_id ) {
274 unset( $this->options['nav_menus'][ $theme ][ $loc ][ $lang ] );
275 }
276 }
277 }
278 }
279
280 update_option( 'polylang', $this->options );
281 }
282 }
283
284 /**
285 * filters the option nav_menu_options for auto added pages to menu
286 *
287 * @since 0.9.4
288 *
289 * @param array $options
290 * @return array Modified options
291 */
292 public function nav_menu_options( $options ) {
293 $options['auto_add'] = array_intersect( $options['auto_add'], $this->auto_add_menus );
294 return $options;
295 }
296
297 /**
298 * filters _wp_auto_add_pages_to_menu by language
299 *
300 * @since 0.9.4
301 *
302 * @param string $new_status Transition to this post status.
303 * @param string $old_status Previous post status.
304 * @param object $post Post data.
305 */
306 public function auto_add_pages_to_menu( $new_status, $old_status, $post ) {
307 if ( 'publish' != $new_status || 'publish' == $old_status || 'page' != $post->post_type || ! empty( $post->post_parent ) || ! ( $lang = $this->model->post->get_language( $post->ID ) ) ) {
308 return;
309 }
310
311 if ( ! empty( $this->options['nav_menus'][ $this->theme ] ) ) {
312 $this->auto_add_menus = array();
313
314 // get all the menus in the page language
315 foreach ( $this->options['nav_menus'][ $this->theme ] as $loc ) {
316 if ( ! empty( $loc[ $lang->slug ] ) ) {
317 $this->auto_add_menus[] = $loc[ $lang->slug ];
318 }
319 }
320
321 add_filter( 'option_nav_menu_options', array( $this, 'nav_menu_options' ) );
322 }
323 }
324 }
325