PluginProbe
Polylang / 3.4
Polylang v3.4
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 / include / switcher.php

switcher.php in Polylang 3.4, at include/switcher.php

288 lines 10.7 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 * A class to display a language switcher on frontend
8 *
9 * @since 1.2
10 */
11 class PLL_Switcher {
12 const DEFAULTS = array(
13 'dropdown' => 0, // Display as list and not as dropdown.
14 'echo' => 1, // Echoes the list.
15 'hide_if_empty' => 1, // Hides languages with no posts (or pages).
16 'show_flags' => 0, // Don't show flags.
17 'show_names' => 1, // Show language names.
18 'display_names_as' => 'name', // Display the language name.
19 'force_home' => 0, // Tries to find a translation.
20 'hide_if_no_translation' => 0, // Don't hide the link if there is no translation.
21 'hide_current' => 0, // Don't hide the current language.
22 'post_id' => null, // Link to the translations of the current page.
23 'raw' => 0, // Build the language switcher.
24 'item_spacing' => 'preserve', // Preserve whitespace between list items.
25 'admin_render' => 0, // Make the switcher in a frontend context.
26 'admin_current_lang' => null, // Use the global current language.
27 );
28
29 /**
30 * @var PLL_Links|null
31 */
32 protected $links;
33
34 /**
35 * Returns options available for the language switcher - menu or widget
36 * either strings to display the options or default values
37 *
38 * @since 0.7
39 *
40 * @param string $type optional either 'menu', 'widget' or 'block', defaults to 'widget'
41 * @param string $key optional either 'string' or 'default', defaults to 'string'
42 * @return array list of switcher options strings or default values
43 */
44 public static function get_switcher_options( $type = 'widget', $key = 'string' ) {
45 $options = array(
46 'dropdown' => array( 'string' => __( 'Displays as a dropdown', 'polylang' ), 'default' => 0 ),
47 'show_names' => array( 'string' => __( 'Displays language names', 'polylang' ), 'default' => 1 ),
48 'show_flags' => array( 'string' => __( 'Displays flags', 'polylang' ), 'default' => 0 ),
49 'force_home' => array( 'string' => __( 'Forces link to front page', 'polylang' ), 'default' => 0 ),
50 'hide_current' => array( 'string' => __( 'Hides the current language', 'polylang' ), 'default' => 0 ),
51 'hide_if_no_translation' => array( 'string' => __( 'Hides languages with no translation', 'polylang' ), 'default' => 0 ),
52 );
53 return wp_list_pluck( $options, $key );
54 }
55
56 /**
57 * Returns the current language code.
58 *
59 * @since 3.0
60 *
61 * @param array $args Arguments passed to {@see PLL_Switcher::the_languages()}.
62 * @return string
63 */
64 protected function get_current_language( $args ) {
65 if ( $args['admin_current_lang'] ) {
66 return $args['admin_current_lang'];
67 }
68
69 if ( isset( $this->links->curlang ) ) {
70 return $this->links->curlang->slug;
71 }
72
73 return $this->links->options['default_lang'];
74 }
75
76 /**
77 * Returns the link for a given language.
78 *
79 * @since 3.0
80 *
81 * @param PLL_Language $language Language.
82 * @param array $args Arguments passed to {@see PLL_Switcher::the_languages()}.
83 * @return string|null
84 */
85 protected function get_link( $language, $args ) {
86 global $post;
87
88 // Priority to the post passed in parameters.
89 if ( null !== $args['post_id'] ) {
90 $tr_id = $this->links->model->post->get( $args['post_id'], $language );
91 if ( $tr_id && $this->links->model->post->current_user_can_read( $tr_id ) ) {
92 return get_permalink( $tr_id );
93 }
94 }
95
96 // If we are on frontend.
97 if ( $this->links instanceof PLL_Frontend_Links ) {
98 return $this->links->get_translation_url( $language );
99 }
100
101 // For blocks in posts in REST requests.
102 if ( $post instanceof WP_Post ) {
103 $tr_id = $this->links->model->post->get( $post->ID, $language );
104 if ( $tr_id && $this->links->model->post->current_user_can_read( $tr_id ) ) {
105 return get_permalink( $tr_id );
106 }
107 }
108
109 return null;
110 }
111
112 /**
113 * Get the language elements for use in a walker
114 *
115 * @since 1.2
116 *
117 * @param array $args Arguments passed to {@see PLL_Switcher::the_languages()}.
118 * @return array Language switcher elements.
119 */
120 protected function get_elements( $args ) {
121 $first = true;
122 $out = array();
123
124 foreach ( $this->links->model->get_languages_list( array( 'hide_empty' => $args['hide_if_empty'] ) ) as $language ) {
125 $id = (int) $language->term_id;
126 $order = (int) $language->term_group;
127 $slug = $language->slug;
128 $locale = $language->get_locale( 'display' );
129 $item_classes = array( 'lang-item', 'lang-item-' . $id, 'lang-item-' . esc_attr( $slug ) );
130 $classes = isset( $args['classes'] ) && is_array( $args['classes'] ) ?
131 array_merge(
132 $item_classes,
133 $args['classes']
134 ) :
135 $item_classes;
136 $link_classes = isset( $args['link_classes'] ) ? $args['link_classes'] : array();
137 $current_lang = $this->get_current_language( $args ) === $slug;
138
139 if ( $current_lang ) {
140 if ( $args['hide_current'] && ! ( $args['dropdown'] && ! $args['raw'] ) ) {
141 continue; // Hide current language except for dropdown
142 } else {
143 $classes[] = 'current-lang';
144 }
145 }
146
147 $url = $this->get_link( $language, $args );
148
149 if ( $no_translation = empty( $url ) ) {
150 $classes[] = 'no-translation';
151 }
152
153 /**
154 * Filter the link in the language switcher
155 *
156 * @since 0.7
157 *
158 * @param string|null $url The link, null if no translation was found.
159 * @param string $slug The language code.
160 * @param string $locale The language locale
161 */
162 $url = apply_filters( 'pll_the_language_link', $url, $slug, $language->locale );
163
164 // Hide if no translation exists
165 if ( empty( $url ) && $args['hide_if_no_translation'] ) {
166 continue;
167 }
168
169 $url = empty( $url ) || $args['force_home'] ? $this->links->get_home_url( $language ) : $url; // If the page is not translated, link to the home page
170
171 $name = $args['show_names'] || ! $args['show_flags'] || $args['raw'] ? ( 'slug' == $args['display_names_as'] ? $slug : $language->name ) : '';
172 $flag = $args['raw'] && ! $args['show_flags'] ? $language->get_display_flag_url() : ( $args['show_flags'] ? $language->get_display_flag() : '' );
173
174 if ( $first ) {
175 $classes[] = 'lang-item-first';
176 $first = false;
177 }
178
179 $out[ $slug ] = compact( 'id', 'order', 'slug', 'locale', 'name', 'url', 'flag', 'current_lang', 'no_translation', 'classes', 'link_classes' );
180 }
181
182 return $out;
183 }
184
185 /**
186 * Displays a language switcher
187 * or returns the raw elements to build a custom language switcher.
188 *
189 * @since 0.1
190 *
191 * @param PLL_Links $links Instance of PLL_Links.
192 * @param array $args {
193 * Optional array of arguments.
194 *
195 * @type int $dropdown The list is displayed as dropdown if set, defaults to 0.
196 * @type int $echo Echoes the list if set to 1, defaults to 1.
197 * @type int $hide_if_empty Hides languages with no posts ( or pages ) if set to 1, defaults to 1.
198 * @type int $show_flags Displays flags if set to 1, defaults to 0.
199 * @type int $show_names Shows language names if set to 1, defaults to 1.
200 * @type string $display_names_as Whether to display the language name or its slug, valid options are 'slug' and 'name', defaults to name.
201 * @type int $force_home Will always link to home in translated language if set to 1, defaults to 0.
202 * @type int $hide_if_no_translation Hides the link if there is no translation if set to 1, defaults to 0.
203 * @type int $hide_current Hides the current language if set to 1, defaults to 0.
204 * @type int $post_id Returns links to the translations of the post defined by post_id if set, defaults not set.
205 * @type int $raw Return a raw array instead of html markup if set to 1, defaults to 0.
206 * @type string $item_spacing Whether to preserve or discard whitespace between list items, valid options are 'preserve' and 'discard', defaults to 'preserve'.
207 * @type int $admin_render Allows to force the current language code in an admin context if set, default to 0. Need to set the admin_current_lang argument below.
208 * @type string $admin_current_lang The current language code in an admin context. Need to set the admin_render to 1, defaults not set.
209 * @type string[] $classes A list of CSS classes to set to each elements outputted.
210 * @type string[] $link_classes A list of CSS classes to set to each link outputted.
211 * }
212 * @return string|array either the html markup of the switcher or the raw elements to build a custom language switcher
213 */
214 public function the_languages( $links, $args = array() ) {
215
216 $this->links = $links;
217 $args = wp_parse_args( $args, self::DEFAULTS );
218
219 /**
220 * Filter the arguments of the 'pll_the_languages' template tag
221 *
222 * @since 1.5
223 *
224 * @param array $args
225 */
226 $args = apply_filters( 'pll_the_languages_args', $args );
227
228 // Force not to hide the language for the widget preview even if the option is checked.
229 if ( $this->links instanceof PLL_Admin_Links ) {
230 $args['hide_if_no_translation'] = 0;
231 }
232
233 // Prevents showing empty options in dropdown
234 if ( $args['dropdown'] ) {
235 $args['show_names'] = 1;
236 }
237
238 $elements = $this->get_elements( $args );
239
240 if ( $args['raw'] ) {
241 return $elements;
242 }
243
244 if ( $args['dropdown'] ) {
245 $args['name'] = 'lang_choice_' . $args['dropdown'];
246 $args['class'] = 'pll-switcher-select';
247 $args['value'] = 'url';
248 $args['selected'] = $this->get_link( $this->links->model->get_language( $this->get_current_language( $args ) ), $args );
249 $walker = new PLL_Walker_Dropdown();
250 } else {
251 $walker = new PLL_Walker_List();
252 }
253
254 // Cast each element to stdClass because $walker::walk() expects an array of objects.
255 foreach ( $elements as $i => $element ) {
256 $elements[ $i ] = (object) $element;
257 }
258
259 /**
260 * Filter the whole html markup returned by the 'pll_the_languages' template tag
261 *
262 * @since 0.8
263 *
264 * @param string $html html returned/outputted by the template tag
265 * @param array $args arguments passed to the template tag
266 */
267 $out = apply_filters( 'pll_the_languages', $walker->walk( $elements, -1, $args ), $args );
268
269 // Javascript to switch the language when using a dropdown list
270 if ( $args['dropdown'] && 0 === $args['admin_render'] ) {
271 // Accept only few valid characters for the urls_x variable name ( as the widget id includes '-' which is invalid )
272 $out .= sprintf(
273 '<script type="text/javascript">
274 //<![CDATA[
275 document.getElementById( "%1$s" ).addEventListener( "change", function ( event ) { location.href = event.currentTarget.value; } )
276 //]]>
277 </script>',
278 esc_js( $args['name'] )
279 );
280 }
281
282 if ( $args['echo'] ) {
283 echo $out; // phpcs:ignore WordPress.Security.EscapeOutput
284 }
285 return $out;
286 }
287 }
288