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-filters.php

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

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