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

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