PluginProbe
Polylang / 3.0.2
Polylang v3.0.2
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.0.2, at include/switcher.php

271 lines 9.9 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
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 $classes = array( 'lang-item', 'lang-item-' . $id, 'lang-item-' . esc_attr( $slug ) );
130 $current_lang = $this->get_current_language( $args ) === $slug;
131
132 if ( $current_lang ) {
133 if ( $args['hide_current'] && ! ( $args['dropdown'] && ! $args['raw'] ) ) {
134 continue; // Hide current language except for dropdown
135 } else {
136 $classes[] = 'current-lang';
137 }
138 }
139
140 $url = $this->get_link( $language, $args );
141
142 if ( $no_translation = empty( $url ) ) {
143 $classes[] = 'no-translation';
144 }
145
146 /**
147 * Filter the link in the language switcher
148 *
149 * @since 0.7
150 *
151 * @param string|null $url The link, null if no translation was found.
152 * @param string $slug The language code.
153 * @param string $locale The language locale
154 */
155 $url = apply_filters( 'pll_the_language_link', $url, $slug, $language->locale );
156
157 // Hide if no translation exists
158 if ( empty( $url ) && $args['hide_if_no_translation'] ) {
159 continue;
160 }
161
162 $url = empty( $url ) || $args['force_home'] ? $this->links->get_home_url( $language ) : $url; // If the page is not translated, link to the home page
163
164 $name = $args['show_names'] || ! $args['show_flags'] || $args['raw'] ? ( 'slug' == $args['display_names_as'] ? $slug : $language->name ) : '';
165 $flag = $args['raw'] && ! $args['show_flags'] ? $language->get_display_flag_url() : ( $args['show_flags'] ? $language->get_display_flag() : '' );
166
167 if ( $first ) {
168 $classes[] = 'lang-item-first';
169 $first = false;
170 }
171
172 $out[ $slug ] = compact( 'id', 'order', 'slug', 'locale', 'name', 'url', 'flag', 'current_lang', 'no_translation', 'classes' );
173 }
174
175 return $out;
176 }
177
178 /**
179 * Displays a language switcher
180 * or returns the raw elements to build a custom language switcher.
181 *
182 * @since 0.1
183 *
184 * @param PLL_Links $links Instance of PLL_Links.
185 * @param array $args {
186 * Optional array of arguments.
187 *
188 * @type int $dropdown The list is displayed as dropdown if set, defaults to 0.
189 * @type int $echo Echoes the list if set to 1, defaults to 1.
190 * @type int $hide_if_empty Hides languages with no posts ( or pages ) if set to 1, defaults to 1.
191 * @type int $show_flags Displays flags if set to 1, defaults to 0.
192 * @type int $show_names Shows language names if set to 1, defaults to 1.
193 * @type string $display_names_as Whether to display the language name or its slug, valid options are 'slug' and 'name', defaults to name.
194 * @type int $force_home Will always link to home in translated language if set to 1, defaults to 0.
195 * @type int $hide_if_no_translation Hides the link if there is no translation if set to 1, defaults to 0.
196 * @type int $hide_current Hides the current language if set to 1, defaults to 0.
197 * @type int $post_id Returns links to the translations of the post defined by post_id if set, defaults not set.
198 * @type int $raw Return a raw array instead of html markup if set to 1, defaults to 0.
199 * @type string $item_spacing Whether to preserve or discard whitespace between list items, valid options are 'preserve' and 'discard', defaults to 'preserve'.
200 * @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.
201 * @type string $admin_current_lang The current language code in an admin context. Need to set the admin_render to 1, defaults not set.
202 * }
203 * @return string|array either the html markup of the switcher or the raw elements to build a custom language switcher
204 */
205 public function the_languages( $links, $args = array() ) {
206 $this->links = $links;
207 $args = wp_parse_args( $args, self::DEFAULTS );
208
209 /**
210 * Filter the arguments of the 'pll_the_languages' template tag
211 *
212 * @since 1.5
213 *
214 * @param array $args
215 */
216 $args = apply_filters( 'pll_the_languages_args', $args );
217
218 // Prevents showing empty options in dropdown
219 if ( $args['dropdown'] ) {
220 $args['show_names'] = 1;
221 }
222
223 $elements = $this->get_elements( $args );
224
225 if ( $args['raw'] ) {
226 return $elements;
227 }
228
229 if ( $args['dropdown'] ) {
230 $args['name'] = 'lang_choice_' . $args['dropdown'];
231 $walker = new PLL_Walker_Dropdown();
232 $args['selected'] = $this->get_current_language( $args );
233 } else {
234 $walker = new PLL_Walker_List();
235 }
236
237 /**
238 * Filter the whole html markup returned by the 'pll_the_languages' template tag
239 *
240 * @since 0.8
241 *
242 * @param string $html html returned/outputted by the template tag
243 * @param array $args arguments passed to the template tag
244 */
245 $out = apply_filters( 'pll_the_languages', $walker->walk( $elements, -1, $args ), $args );
246
247 // Javascript to switch the language when using a dropdown list
248 if ( $args['dropdown'] && 0 === $args['admin_render'] ) {
249 // Accept only few valid characters for the urls_x variable name ( as the widget id includes '-' which is invalid )
250 $out .= sprintf(
251 '<script type="text/javascript">
252 //<![CDATA[
253 var %1$s = %2$s;
254 document.getElementById( "%3$s" ).onchange = function() {
255 location.href = %1$s[this.value];
256 }
257 //]]>
258 </script>',
259 'urls_' . preg_replace( '#[^a-zA-Z0-9]#', '', $args['dropdown'] ),
260 wp_json_encode( wp_list_pluck( $elements, 'url' ) ),
261 esc_js( $args['name'] )
262 );
263 }
264
265 if ( $args['echo'] ) {
266 echo $out; // phpcs:ignore WordPress.Security.EscapeOutput
267 }
268 return $out;
269 }
270 }
271