PluginProbe
Polylang / 2.6
Polylang v2.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.6, 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['strings'] = PLL_Switcher::get_switcher_options( 'menu', 'string' ); // The strings for the options
98 $data['title'] = __( 'Languages', 'polylang' ); // The title
99
100 // Get all language switcher menu items
101 $items = get_posts(
102 array(
103 'numberposts' => -1,
104 'nopaging' => true,
105 'post_type' => 'nav_menu_item',
106 'fields' => 'ids',
107 'meta_key' => '_pll_menu_item',
108 )
109 );
110
111 // The options values for the language switcher
112 $data['val'] = array();
113 foreach ( $items as $item ) {
114 $data['val'][ $item ] = get_post_meta( $item, '_pll_menu_item', true );
115 }
116
117 // Send all these data to javascript
118 wp_localize_script( 'pll_nav_menu', 'pll_data', $data );
119 }
120
121 /**
122 * Save our menu item options
123 *
124 * @since 1.1
125 *
126 * @param int $menu_id not used
127 * @param int $menu_item_db_id
128 */
129 public function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0 ) {
130 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
131 return;
132 }
133
134 // Security check as 'wp_update_nav_menu_item' can be called from outside WP admin
135 if ( current_user_can( 'edit_theme_options' ) ) {
136 check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );
137
138 $options = array( 'hide_if_no_translation' => 0, 'hide_current' => 0, 'force_home' => 0, 'show_flags' => 0, 'show_names' => 1, 'dropdown' => 0 ); // Default values
139 // Our jQuery form has not been displayed
140 if ( empty( $_POST['menu-item-pll-detect'][ $menu_item_db_id ] ) ) {
141 if ( ! get_post_meta( $menu_item_db_id, '_pll_menu_item', true ) ) { // Our options were never saved
142 update_post_meta( $menu_item_db_id, '_pll_menu_item', $options );
143 }
144 }
145 else {
146 foreach ( $options as $opt => $v ) {
147 $options[ $opt ] = empty( $_POST[ 'menu-item-' . $opt ][ $menu_item_db_id ] ) ? 0 : 1;
148 }
149 update_post_meta( $menu_item_db_id, '_pll_menu_item', $options ); // Allow us to easily identify our nav menu item
150 }
151 }
152 }
153
154 /**
155 * Assign menu languages and translations based on ( temporary ) locations
156 *
157 * @since 1.8
158 *
159 * @param array $locations nav menu locations
160 * @return array
161 */
162 public function update_nav_menu_locations( $locations ) {
163 $default = $this->options['default_lang'];
164
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 ( $menus as $loc => $menu ) {
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