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

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