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

273 lines 9.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Polylang
4 */
5
6 /**
7 * Manages custom menus translations as well as the language switcher menu item on admin side
8 *
9 * @since 1.2
10 */
11 class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
12
13 /**
14 * Constructor: setups filters and actions
15 *
16 * @since 1.2
17 *
18 * @param object $polylang
19 */
20 public function __construct( &$polylang ) {
21 parent::__construct( $polylang );
22
23 // Populates nav menus locations
24 // Since WP 4.4, must be done before customize_register is fired
25 add_filter( 'theme_mod_nav_menu_locations', array( $this, 'theme_mod_nav_menu_locations' ), 20 );
26
27 // Integration in the WP menu interface
28 add_action( 'admin_init', array( $this, 'admin_init' ) ); // after Polylang upgrade
29 }
30
31 /**
32 * Setups filters and terms
33 * adds the language switcher metabox and create new nav menu locations
34 *
35 * @since 1.1
36 */
37 public function admin_init() {
38 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
39 add_action( 'wp_update_nav_menu_item', array( $this, 'wp_update_nav_menu_item' ), 10, 2 );
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 // FIXME is it possible to choose the order ( after theme locations in WP3.5 and older ) ?
46 // FIXME not displayed if Polylang is activated before the first time the user goes to nav menus http://core.trac.wordpress.org/ticket/16828
47 add_meta_box( 'pll_lang_switch_box', __( 'Language switcher', 'polylang' ), array( $this, 'lang_switch' ), 'nav-menus', 'side', 'high' );
48
49 $this->create_nav_menu_locations();
50 }
51
52 /**
53 * Language switcher metabox
54 * The checkbox and all hidden fields are important
55 * 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/
56 *
57 * @since 1.1
58 */
59 public function lang_switch() {
60 global $_nav_menu_placeholder, $nav_menu_selected_id;
61 $_nav_menu_placeholder = 0 > $_nav_menu_placeholder ? $_nav_menu_placeholder - 1 : -1;
62 ?>
63 <div id="posttype-lang-switch" class="posttypediv">
64 <div id="tabs-panel-lang-switch" class="tabs-panel tabs-panel-active">
65 <ul id="lang-switch-checklist" class="categorychecklist form-no-clear">
66 <li>
67 <label class="menu-item-title">
68 <input type="checkbox" class="menu-item-checkbox" name="menu-item[<?php echo (int) $_nav_menu_placeholder; ?>][menu-item-object-id]" value="-1"> <?php esc_html_e( 'Languages', 'polylang' ); ?>
69 </label>
70 <input type="hidden" class="menu-item-type" name="menu-item[<?php echo (int) $_nav_menu_placeholder; ?>][menu-item-type]" value="custom">
71 <input type="hidden" class="menu-item-title" name="menu-item[<?php echo (int) $_nav_menu_placeholder; ?>][menu-item-title]" value="<?php esc_html_e( 'Languages', 'polylang' ); ?>">
72 <input type="hidden" class="menu-item-url" name="menu-item[<?php echo (int) $_nav_menu_placeholder; ?>][menu-item-url]" value="#pll_switcher">
73 </li>
74 </ul>
75 </div>
76 <p class="button-controls">
77 <span class="add-to-menu">
78 <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', 'polylang' ); ?>" name="add-post-type-menu-item" id="submit-posttype-lang-switch">
79 <span class="spinner"></span>
80 </span>
81 </p>
82 </div>
83 <?php
84 }
85
86 /**
87 * Prepares javascript to modify the language switcher menu item
88 *
89 * @since 1.1
90 */
91 public function admin_enqueue_scripts() {
92 $screen = get_current_screen();
93 if ( 'nav-menus' != $screen->base ) {
94 return;
95 }
96
97 $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
98 wp_enqueue_script( 'pll_nav_menu', plugins_url( '/js/nav-menu' . $suffix . '.js', POLYLANG_FILE ), array( 'jquery' ), POLYLANG_VERSION );
99
100 $data = array(
101 'strings' => PLL_Switcher::get_switcher_options( 'menu', 'string' ), // The strings for the options
102 'title' => __( 'Languages', 'polylang' ), // The title
103 'val' => array(),
104 );
105
106 // Get all language switcher menu items
107 $items = get_posts(
108 array(
109 'numberposts' => -1,
110 'nopaging' => true,
111 'post_type' => 'nav_menu_item',
112 'fields' => 'ids',
113 'meta_key' => '_pll_menu_item',
114 )
115 );
116
117 // The options values for the language switcher
118 foreach ( $items as $item ) {
119 $data['val'][ $item ] = get_post_meta( $item, '_pll_menu_item', true );
120 }
121
122 // Send all these data to javascript
123 wp_localize_script( 'pll_nav_menu', 'pll_data', $data );
124 }
125
126 /**
127 * Save our menu item options
128 *
129 * @since 1.1
130 *
131 * @param int $menu_id not used
132 * @param int $menu_item_db_id
133 */
134 public function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0 ) {
135 if ( empty( $_POST['menu-item-url'][ $menu_item_db_id ] ) || '#pll_switcher' !== $_POST['menu-item-url'][ $menu_item_db_id ] ) { // phpcs:ignore WordPress.Security.NonceVerification
136 return;
137 }
138
139 // Security check as 'wp_update_nav_menu_item' can be called from outside WP admin
140 if ( current_user_can( 'edit_theme_options' ) ) {
141 check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );
142
143 $options = array( 'hide_if_no_translation' => 0, 'hide_current' => 0, 'force_home' => 0, 'show_flags' => 0, 'show_names' => 1, 'dropdown' => 0 ); // Default values
144 // Our jQuery form has not been displayed
145 if ( empty( $_POST['menu-item-pll-detect'][ $menu_item_db_id ] ) ) {
146 if ( ! get_post_meta( $menu_item_db_id, '_pll_menu_item', true ) ) { // Our options were never saved
147 update_post_meta( $menu_item_db_id, '_pll_menu_item', $options );
148 }
149 }
150 else {
151 foreach ( array_keys( $options ) as $opt ) {
152 $options[ $opt ] = empty( $_POST[ 'menu-item-' . $opt ][ $menu_item_db_id ] ) ? 0 : 1;
153 }
154 update_post_meta( $menu_item_db_id, '_pll_menu_item', $options ); // Allow us to easily identify our nav menu item
155 }
156 }
157 }
158
159 /**
160 * Assign menu languages and translations based on ( temporary ) locations
161 *
162 * @since 1.8
163 *
164 * @param array $locations nav menu locations
165 * @return array
166 */
167 public function update_nav_menu_locations( $locations ) {
168 // Extract language and menu from locations
169 foreach ( $locations as $loc => $menu ) {
170 $infos = $this->explode_location( $loc );
171 $this->options['nav_menus'][ $this->theme ][ $infos['location'] ][ $infos['lang'] ] = $menu;
172 if ( $this->options['default_lang'] != $infos['lang'] ) {
173 unset( $locations[ $loc ] ); // Remove temporary locations before database update
174 }
175 }
176
177 update_option( 'polylang', $this->options );
178 return $locations;
179 }
180
181 /**
182 * Assign menu languages and translations based on ( temporary ) locations
183 *
184 * @since 1.1
185 *
186 * @param array $mods theme mods
187 * @return unmodified $mods
188 */
189 public function pre_update_option_theme_mods( $mods ) {
190 if ( current_user_can( 'edit_theme_options' ) && isset( $mods['nav_menu_locations'] ) ) {
191
192 // Manage Locations tab in Appearance -> Menus
193 if ( isset( $_GET['action'] ) && 'locations' === $_GET['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification
194 check_admin_referer( 'save-menu-locations' );
195 $this->options['nav_menus'][ $this->theme ] = array();
196 }
197
198 // Edit Menus tab in Appearance -> Menus
199 // Add the test of $_POST['update-nav-menu-nonce'] to avoid conflict with Vantage theme
200 elseif ( isset( $_POST['action'], $_POST['update-nav-menu-nonce'] ) && 'update' === $_POST['action'] ) {
201 check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );
202 $this->options['nav_menus'][ $this->theme ] = array();
203 }
204
205 // Customizer
206 // Don't reset locations in this case.
207 // see http://wordpress.org/support/topic/menus-doesnt-show-and-not-saved-in-theme-settings-multilingual-site
208 elseif ( isset( $_POST['action'] ) && 'customize_save' == $_POST['action'] ) {
209 check_ajax_referer( 'save-customize_' . $GLOBALS['wp_customize']->get_stylesheet(), 'nonce' );
210 }
211
212 else {
213 return $mods; // No modification for nav menu locations
214 }
215
216 $mods['nav_menu_locations'] = $this->update_nav_menu_locations( $mods['nav_menu_locations'] );
217 }
218 return $mods;
219 }
220
221 /**
222 * Fills temporary menu locations based on menus translations
223 *
224 * @since 1.2
225 *
226 * @param bool|array $menus
227 * @return bool|array modified list of menu locations
228 */
229 public function theme_mod_nav_menu_locations( $menus ) {
230 // Prefill locations with 0 value in case a location does not exist in $menus
231 $locations = get_registered_nav_menus();
232 if ( is_array( $locations ) ) {
233 $locations = array_fill_keys( array_keys( $locations ), 0 );
234 $menus = is_array( $menus ) ? array_merge( $locations, $menus ) : $locations;
235 }
236
237 if ( is_array( $menus ) ) {
238 foreach ( array_keys( $menus ) as $loc ) {
239 foreach ( $this->model->get_languages_list() as $lang ) {
240 if ( ! empty( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ] ) && term_exists( $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ], 'nav_menu' ) ) {
241 $menus[ $this->combine_location( $loc, $lang ) ] = $this->options['nav_menus'][ $this->theme ][ $loc ][ $lang->slug ];
242 }
243 }
244 }
245 }
246
247 return $menus;
248 }
249
250 /**
251 * Removes the nav menu term_id from the locations stored in Polylang options when a nav menu is deleted
252 *
253 * @since 1.7.3
254 *
255 * @param int $term_id nav menu id
256 */
257 public function delete_nav_menu( $term_id ) {
258 if ( isset( $this->options['nav_menus'] ) ) {
259 foreach ( $this->options['nav_menus'] as $theme => $locations ) {
260 foreach ( $locations as $loc => $languages ) {
261 foreach ( $languages as $lang => $menu_id ) {
262 if ( $menu_id === $term_id ) {
263 unset( $this->options['nav_menus'][ $theme ][ $loc ][ $lang ] );
264 }
265 }
266 }
267 }
268
269 update_option( 'polylang', $this->options );
270 }
271 }
272 }
273