PluginProbe
Polylang / 2.8.1
Polylang v2.8.1
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-filters.php

admin-filters.php in Polylang 2.8.1, at admin/admin-filters.php

294 lines 10.2 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 * Setup miscellaneous admin filters as well as filters common to admin and frontend
8 *
9 * @since 1.2
10 */
11 class PLL_Admin_Filters extends PLL_Filters {
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 // Widgets languages filter
24 add_action( 'in_widget_form', array( $this, 'in_widget_form' ), 10, 3 );
25 add_filter( 'widget_update_callback', array( $this, 'widget_update_callback' ), 10, 4 );
26
27 // Language management for users
28 add_action( 'personal_options_update', array( $this, 'personal_options_update' ) );
29 add_action( 'edit_user_profile_update', array( $this, 'personal_options_update' ) );
30 add_action( 'personal_options', array( $this, 'personal_options' ) );
31
32 // Upgrades languages files after a core upgrade ( timing is important )
33 // Backward compatibility WP < 4.0 *AND* Polylang < 1.6
34 add_action( '_core_updated_successfully', array( $this, 'upgrade_languages' ), 1 ); // since WP 3.3
35
36 // Upgrades plugins and themes translations files
37 add_filter( 'themes_update_check_locales', array( $this, 'update_check_locales' ) );
38 add_filter( 'plugins_update_check_locales', array( $this, 'update_check_locales' ) );
39
40 // We need specific filters for German and Danish
41 $specific_locales = array( 'da_DK', 'de_DE', 'de_DE_formal', 'de_CH', 'de_CH_informal', 'ca', 'sr_RS', 'bs_BA' );
42 if ( array_intersect( $this->model->get_languages_list( array( 'fields' => 'locale' ) ), $specific_locales ) ) {
43 add_filter( 'sanitize_title', array( $this, 'sanitize_title' ), 10, 3 );
44 add_filter( 'sanitize_user', array( $this, 'sanitize_user' ), 10, 3 );
45 }
46
47 add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
48
49 // Add post state for translations of the privacy policy page
50 add_filter( 'display_post_states', array( $this, 'display_post_states' ), 10, 2 );
51 }
52
53 /**
54 * Modifies the widgets forms to add our language dropdown list
55 *
56 * @since 0.3
57 *
58 * @param object $widget Widget instance
59 * @param null $return Not used
60 * @param array $instance Widget settings
61 */
62 public function in_widget_form( $widget, $return, $instance ) {
63 $screen = get_current_screen();
64
65 // Test the Widgets screen and the Customizer to avoid displaying the option in page builders
66 // Saving the widget reloads the form. And curiously the action is in $_REQUEST but neither in $_POST, nor in $_GET.
67 if ( ( isset( $screen ) && 'widgets' === $screen->base ) || ( isset( $_REQUEST['action'] ) && 'save-widget' === $_REQUEST['action'] ) || isset( $GLOBALS['wp_customize'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
68 $dropdown = new PLL_Walker_Dropdown();
69
70 $dropdown_html = $dropdown->walk(
71 array_merge(
72 array( (object) array( 'slug' => 0, 'name' => __( 'All languages', 'polylang' ) ) ),
73 $this->model->get_languages_list()
74 ),
75 -1,
76 array(
77 'name' => $widget->id . '_lang_choice',
78 'class' => 'tags-input pll-lang-choice',
79 'selected' => empty( $instance['pll_lang'] ) ? '' : $instance['pll_lang'],
80 )
81 );
82
83 printf(
84 '<p><label for="%1$s">%2$s %3$s</label></p>',
85 esc_attr( $widget->id . '_lang_choice' ),
86 esc_html__( 'The widget is displayed for:', 'polylang' ),
87 $dropdown_html // phpcs:ignore WordPress.Security.EscapeOutput
88 );
89 }
90 }
91
92 /**
93 * Called when widget options are saved
94 * saves the language associated to the widget
95 *
96 * @since 0.3
97 *
98 * @param array $instance Widget options
99 * @param array $new_instance Not used
100 * @param array $old_instance Not used
101 * @param object $widget WP_Widget object
102 * @return array Widget options
103 */
104 public function widget_update_callback( $instance, $new_instance, $old_instance, $widget ) {
105 $key = $widget->id . '_lang_choice';
106
107 if ( ! empty( $_POST[ $key ] ) && $lang = $this->model->get_language( sanitize_key( $_POST[ $key ] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
108 $instance['pll_lang'] = $lang->slug;
109 } else {
110 unset( $instance['pll_lang'] );
111 }
112
113 return $instance;
114 }
115
116 /**
117 * Updates language user preference set in user profile
118 *
119 * @since 0.4
120 *
121 * @param int $user_id
122 */
123 public function personal_options_update( $user_id ) {
124 // Biography translations
125 foreach ( $this->model->get_languages_list() as $lang ) {
126 $meta = $lang->slug == $this->options['default_lang'] ? 'description' : 'description_' . $lang->slug;
127 $description = empty( $_POST[ 'description_' . $lang->slug ] ) ? '' : trim( $_POST[ 'description_' . $lang->slug ] ); // phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput
128
129 /** This filter is documented in wp-includes/user.php */
130 $description = apply_filters( 'pre_user_description', $description ); // Applies WP default filter wp_filter_kses
131 update_user_meta( $user_id, $meta, $description );
132 }
133 }
134
135 /**
136 * Outputs hidden information to modify the biography form with js
137 *
138 * @since 0.4
139 *
140 * @param object $profileuser
141 */
142 public function personal_options( $profileuser ) {
143 foreach ( $this->model->get_languages_list() as $lang ) {
144 $meta = $lang->slug == $this->options['default_lang'] ? 'description' : 'description_' . $lang->slug;
145
146 /** This filter is documented in wp-includes/user.php */
147 $description = apply_filters( 'user_description', get_user_meta( $profileuser->ID, $meta, true ) ); // Applies WP default filter wp_kses_data
148
149 printf(
150 '<input type="hidden" class="biography" name="%s___%s" value="%s" />',
151 esc_attr( $lang->slug ),
152 esc_attr( $lang->name ),
153 esc_attr( $description )
154 );
155 }
156 }
157
158 /**
159 * Upgrades languages files after a core upgrade
160 * only for backward compatibility WP < 4.0 *AND* Polylang < 1.6
161 *
162 * @since 0.6
163 *
164 * @param string $version new WP version
165 */
166 public function upgrade_languages( $version ) {
167 // $GLOBALS['wp_version'] is the old WP version
168 if ( version_compare( $version, '4.0', '>=' ) && version_compare( $GLOBALS['wp_version'], '4.0', '<' ) ) {
169
170 /** This filter is documented in wp-admin/includes/update-core.php */
171 apply_filters( 'update_feedback', __( 'Upgrading language files&#8230;', 'polylang' ) );
172 PLL_Upgrade::download_language_packs();
173 }
174 }
175
176 /**
177 * Allows to update translations files for plugins and themes
178 *
179 * @since 1.6
180 *
181 * @param array $locales Not used
182 * @return array list of locales to update
183 */
184 public function update_check_locales( $locales ) {
185 return $this->model->get_languages_list( array( 'fields' => 'locale' ) );
186 }
187
188 /**
189 * Filters the locale according to the current language instead of the language
190 * of the admin interface
191 *
192 * @since 2.0
193 *
194 * @param string $locale
195 * @return string
196 */
197 public function get_locale( $locale ) {
198 if ( isset( $_POST['post_lang_choice'] ) && $lang = $this->model->get_language( sanitize_key( $_POST['post_lang_choice'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
199 $locale = $lang->locale;
200 } elseif ( isset( $_POST['term_lang_choice'] ) && $lang = $this->model->get_language( sanitize_key( $_POST['term_lang_choice'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
201 $locale = $lang->locale;
202 } elseif ( isset( $_POST['inline_lang_choice'] ) && $lang = $this->model->get_language( sanitize_key( $_POST['inline_lang_choice'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
203 $locale = $lang->locale;
204 } elseif ( ! empty( $this->curlang ) ) {
205 $locale = $this->curlang->locale;
206 }
207
208 return $locale;
209 }
210
211 /**
212 * Maybe fix the result of sanitize_title() in case the languages include German or Danish
213 * Without this filter, if language of the title being sanitized is different from the language
214 * used for the admin interface and if one this language is German or Danish, some specific
215 * characters such as ä, ö, ü, ß are incorrectly sanitized.
216 *
217 * @since 2.0
218 *
219 * @param string $title Sanitized title.
220 * @param string $raw_title The title prior to sanitization.
221 * @param string $context The context for which the title is being sanitized.
222 * @return string
223 */
224 public function sanitize_title( $title, $raw_title, $context ) {
225 static $once = false;
226
227 if ( ! $once && 'save' == $context && ! empty( $title ) ) {
228 $once = true;
229 add_filter( 'locale', array( $this, 'get_locale' ), 20 ); // After the filter for the admin interface
230 $title = sanitize_title( $raw_title, '', $context );
231 remove_filter( 'locale', array( $this, 'get_locale' ), 20 );
232 $once = false;
233 }
234 return $title;
235 }
236
237 /**
238 * Maybe fix the result of sanitize_user() in case the languages include German or Danish
239 *
240 * @since 2.0
241 *
242 * @param string $username Sanitized username.
243 * @param string $raw_username The username prior to sanitization.
244 * @param bool $strict Whether to limit the sanitization to specific characters. Default false.
245 * @return string
246 */
247 public function sanitize_user( $username, $raw_username, $strict ) {
248 static $once = false;
249
250 if ( ! $once ) {
251 $once = true;
252 add_filter( 'locale', array( $this, 'get_locale' ), 20 ); // After the filter for the admin interface
253 $username = sanitize_user( $raw_username, '', $strict );
254 remove_filter( 'locale', array( $this, 'get_locale' ), 20 );
255 $once = false;
256 }
257 return $username;
258 }
259
260 /**
261 * Adds a text direction dependent class to the body
262 *
263 * @since 2.2
264 *
265 * @param string $classes Space-separated list of CSS classes.
266 * @return string
267 */
268 public function admin_body_class( $classes ) {
269 if ( ! empty( $this->curlang ) ) {
270 $classes .= ' pll-dir-' . ( $this->curlang->is_rtl ? 'rtl' : 'ltr' );
271 }
272 return $classes;
273 }
274
275 /**
276 * Add post state for translations of the privacy policy page
277 *
278 * @since 2.7
279 *
280 * @param array $post_states An array of post display states.
281 * @param object $post The current post object.
282 * @return array
283 */
284 public function display_post_states( $post_states, $post ) {
285 $page_for_privacy_policy = get_option( 'wp_page_for_privacy_policy' );
286
287 if ( $page_for_privacy_policy && in_array( $post->ID, $this->model->post->get_translations( $page_for_privacy_policy ) ) ) {
288 $post_states['page_for_privacy_policy'] = __( 'Privacy Policy Page', 'polylang' );
289 }
290
291 return $post_states;
292 }
293 }
294