PluginProbe
Polylang / 3.8.10
Polylang v3.8.10
3.8.10 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 All 234 releases
polylang / src / modules / site-health / admin-site-health.php

admin-site-health.php in Polylang 3.8.10, at src/modules/site-health/admin-site-health.php

388 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 * Class PLL_Admin_Site_Health to add debug info in WP Site Health.
8 *
9 * @see https://make.wordpress.org/core/2019/04/25/site-health-check-in-5-2/ since WordPress 5.2
10 *
11 * @since 2.8
12 */
13 class PLL_Admin_Site_Health {
14 /**
15 * A reference to the PLL_Model instance.
16 *
17 * @since 2.8
18 *
19 * @var PLL_Model
20 */
21 protected $model;
22
23 /**
24 * A reference to the PLL_Admin_Static_Pages instance.
25 *
26 * @since 2.8
27 *
28 * @var PLL_Admin_Static_Pages|null
29 */
30 protected $static_pages;
31
32 /**
33 * PLL_Admin_Site_Health constructor.
34 *
35 * @since 2.8
36 *
37 * @param object $polylang The Polylang object.
38 */
39 public function __construct( &$polylang ) {
40 $this->model = &$polylang->model;
41 $this->static_pages = &$polylang->static_pages;
42
43 // Information tab.
44 add_filter( 'debug_information', array( $this, 'info_options' ), 15 );
45 add_filter( 'debug_information', array( $this, 'info_languages' ), 15 );
46 add_filter( 'debug_information', array( $this, 'info' ), 15 );
47
48 // Tests Tab.
49 add_filter( 'site_status_tests', array( $this, 'status_tests' ) );
50 add_filter( 'site_status_test_php_modules', array( $this, 'site_status_test_php_modules' ) ); // Require simplexml in Site health.
51 }
52
53 /**
54 * Returns a list of keys to exclude from the site health information.
55 *
56 * @since 2.8
57 *
58 * @return string[] List of option keys to ignore.
59 */
60 protected function exclude_options_keys() {
61 return array(
62 'uninstall',
63 'first_activation',
64 );
65 }
66
67 /**
68 * Returns a list of keys to exclude from the site health information.
69 *
70 * @since 2.8
71 *
72 * @return string[] List of language keys to ignore.
73 */
74 protected function exclude_language_keys() {
75 return array(
76 'flag',
77 'host',
78 'taxonomy',
79 'description',
80 'parent',
81 'filter',
82 'custom_flag',
83 );
84 }
85
86 /**
87 * Add Polylang Options to Site Health Information tab.
88 *
89 * @since 2.8
90 * @param array $debug_info The debug information to be added to the core information page.
91 *
92 * @return array
93 */
94 public function info_options( $debug_info ) {
95 $fields = $this->model->options->get_site_health_info();
96
97 // Get effective translated post types and taxonomies. The options doesn't show all translated ones.
98 if ( ! empty( $this->model->get_translated_post_types() ) ) {
99 $fields['cpt']['label'] = __( 'Translated post types', 'polylang' );
100 $fields['cpt']['value'] = implode( ', ', $this->model->get_translated_post_types() );
101 }
102 if ( ! empty( $this->model->get_translated_taxonomies() ) ) {
103 $fields['taxonomies']['label'] = __( 'Translated taxonomies', 'polylang' );
104 $fields['taxonomies']['value'] = implode( ', ', $this->model->get_translated_taxonomies() );
105 }
106
107 $debug_info['pll_options'] = array(
108 /* translators: placeholder is the plugin name */
109 'label' => sprintf( __( '%s options', 'polylang' ), POLYLANG ),
110 'fields' => $fields,
111 );
112
113 return $debug_info;
114 }
115
116 /**
117 * Adds Polylang Languages settings to Site Health Information tab.
118 *
119 * @since 2.8
120 *
121 * @param array $debug_info The debug information to be added to the core information page.
122 * @return array
123 */
124 public function info_languages( $debug_info ) {
125 foreach ( $this->model->get_languages_list() as $language ) {
126 $fields = array();
127
128 foreach ( $language->to_array() as $key => $value ) {
129 if ( in_array( $key, $this->exclude_language_keys(), true ) ) {
130 continue;
131 }
132
133 if ( empty( $value ) ) {
134 $value = '0';
135 }
136
137 $fields[ $key ]['label'] = $key;
138
139 if ( 'term_props' === $key && is_array( $value ) ) {
140 $fields[ $key ]['value'] = $this->get_info_term_props( $value );
141 } else {
142 $fields[ $key ]['value'] = $value;
143 }
144
145 if ( 'term_group' === $key ) {
146 $fields[ $key ]['label'] = 'order'; // Changed for readability but not translated as other keys are not.
147 }
148 }
149
150 $debug_info[ 'pll_language_' . $language->slug ] = array(
151 /* translators: %1$s placeholder is the language name, %2$s is the language code */
152 'label' => sprintf( __( 'Language: %1$s - %2$s', 'polylang' ), $language->name, $language->slug ),
153 /* translators: placeholder is the flag image */
154 'description' => sprintf( esc_html__( 'Flag used in the language switcher: %s', 'polylang' ), $this->get_flag( $language ) ),
155 'fields' => $fields,
156 );
157 }
158
159 return $debug_info;
160 }
161
162 /**
163 * Adds term props data to the info languages array.
164 *
165 * @since 3.4
166 *
167 * @param array $value The term props data.
168 * @return array The term props data formatted for the info languages tab.
169 */
170 protected function get_info_term_props( $value ) {
171 $return_value = array();
172
173 foreach ( $value as $language_taxonomy => $item ) {
174 $language_taxonomy_array = array_fill( 0, count( $item ), $language_taxonomy );
175
176 $keys_with_language_taxonomy = array_map(
177 function ( $key, $language_taxonomy ) {
178 return "{$language_taxonomy}/{$key}";
179 },
180 array_keys( $item ),
181 $language_taxonomy_array
182 );
183
184 $value = array_combine( $keys_with_language_taxonomy, $item );
185 if ( is_array( $value ) ) {
186 $return_value = array_merge( $return_value, $value );
187 }
188 }
189 return $return_value;
190 }
191
192 /**
193 * Returns the flag used in the language switcher.
194 *
195 * @since 2.8
196 *
197 * @param PLL_Language $language Language object.
198 * @return string
199 */
200 protected function get_flag( $language ) {
201 $flag = $language->get_display_flag();
202 return empty( $flag ) ? '<span>' . esc_html__( 'Undefined', 'polylang' ) . '</span>' : $flag;
203 }
204
205 /**
206 * Add a Site Health test on homepage translation.
207 *
208 * @since 2.8
209 *
210 * @param array $tests Array with tests declaration data.
211 * @return array
212 */
213 public function status_tests( $tests ) {
214 // Add the test only if the homepage displays static page.
215 if ( 'page' === get_option( 'show_on_front' ) && get_option( 'page_on_front' ) ) {
216 $tests['direct']['pll_homepage'] = array(
217 'label' => esc_html__( 'Homepage translated', 'polylang' ),
218 'test' => array( $this, 'homepage_test' ),
219 );
220 }
221 return $tests;
222 }
223
224 /**
225 * Test if the home page is translated or not.
226 *
227 * @since 2.8
228 *
229 * @return array $result Array with test results.
230 */
231 public function homepage_test() {
232 $result = array(
233 'label' => __( 'All languages have a translated homepage', 'polylang' ),
234 'status' => 'good',
235 'badge' => array(
236 'label' => POLYLANG,
237 'color' => 'blue',
238 ),
239 'description' => sprintf(
240 '<p>%s</p>',
241 esc_html__( 'It is mandatory to translate the static front page in all languages.', 'polylang' )
242 ),
243 'actions' => '',
244 'test' => 'pll_homepage',
245 );
246
247 $message = $this->static_pages->get_must_translate_message();
248
249 if ( ! empty( $message ) ) {
250 $result['status'] = 'critical';
251 $result['label'] = __( 'The homepage is not translated in all languages', 'polylang' );
252 $result['description'] = sprintf( '<p>%s</p>', $message );
253 }
254 return $result;
255 }
256
257 /**
258 * Add Polylang Warnings to Site Health Information tab.
259 *
260 * @since 3.1
261 *
262 * @param array $debug_info The debug information to be added to the core information page.
263 * @return array
264 */
265 public function info( $debug_info ) {
266 $fields = array();
267
268 // Add Post Types without languages.
269 $posts_no_lang = $this->get_post_ids_without_lang();
270
271 if ( ! empty( $posts_no_lang ) ) {
272 $fields['post-no-lang']['label'] = __( 'Posts without language', 'polylang' );
273 $fields['post-no-lang']['value'] = $posts_no_lang;
274 }
275
276 $terms_no_lang = $this->get_term_ids_without_lang();
277
278 if ( ! empty( $terms_no_lang ) ) {
279 $fields['term-no-lang']['label'] = __( 'Terms without language', 'polylang' );
280 $fields['term-no-lang']['value'] = $terms_no_lang;
281 }
282
283 // Add WPML files.
284 $wpml_files = PLL_WPML_Config::instance()->get_files();
285 if ( ! empty( $wpml_files ) ) {
286 $fields['wpml']['label'] = 'wpml-config.xml files';
287 $fields['wpml']['value'] = $wpml_files;
288
289 if ( ! extension_loaded( 'simplexml' ) ) {
290 $fields['simplexml']['label'] = __( 'PHP SimpleXML extension', 'polylang' );
291 $fields['simplexml']['value'] = __( 'Not loaded. Contact your host provider.', 'polylang' );
292 }
293 }
294
295 // Multisite
296 if ( is_multisite() ) {
297 if ( is_plugin_active_for_network( POLYLANG_BASENAME ) ) {
298 $network_activated = __( 'Yes', 'polylang' );
299 } else {
300 $network_activated = __( 'No', 'polylang' );
301 }
302 $fields['network_activated'] = array(
303 'label' => __( 'Network activated', 'polylang' ),
304 'value' => $network_activated,
305 );
306 }
307
308 // Create the section.
309 if ( ! empty( $fields ) ) {
310 $debug_info['pll_warnings'] = array(
311 /* translators: placeholder is the plugin name */
312 'label' => sprintf( __( '%s information', 'polylang' ), POLYLANG ),
313 'fields' => $fields,
314 );
315 }
316
317 return $debug_info;
318 }
319
320 /**
321 * Get an array with post_type as key and post ids as value.
322 *
323 * @since 3.1
324 *
325 * @param int $limit Max number of posts to show per post type. `-1` to return all of them. Default is 5.
326 *
327 * @return string[] An associative array where the keys are post types and the values
328 * are comma-separated strings of post IDs without a language.
329 *
330 * @phpstan-param -1|positive-int $limit *
331 */
332 public function get_post_ids_without_lang( $limit = 5 ) {
333 $posts = array();
334
335 foreach ( $this->model->get_translated_post_types() as $post_type ) {
336 $post_ids_with_no_language = $this->model->get_posts_with_no_lang( $post_type, $limit );
337
338 if ( ! empty( $post_ids_with_no_language ) ) {
339 $posts[ $post_type ] = implode( ',', $post_ids_with_no_language );
340 }
341 }
342 return $posts;
343 }
344
345 /**
346 * Get an array with taxonomy as key and term ids as value.
347 *
348 * @since 3.1
349 * @param int $limit Max number of terms to show per post type. `-1` to return all of them. Default is 5.
350 *
351 * @return string[] An associative array where the keys are post types and the values
352 * are comma-separated strings of post IDs without a language.
353 * @phpstan-param -1|positive-int $limit
354 */
355 public function get_term_ids_without_lang( $limit = 5 ) {
356 $terms = array();
357
358 foreach ( $this->model->get_translated_taxonomies() as $taxonomy ) {
359 $term_ids_with_no_language = $this->model->get_terms_with_no_lang( $taxonomy, $limit );
360
361 if ( ! empty( $term_ids_with_no_language ) ) {
362 $terms[ $taxonomy ] = implode( ',', $term_ids_with_no_language );
363 }
364 }
365 return $terms;
366 }
367
368 /**
369 * Requires the simplexml PHP module when a wpml-config.xml has been found.
370 *
371 * @since 3.1
372 * @since 3.2 Moved from PLL_WPML_Config
373 *
374 * @param array $modules An associative array of modules to test for.
375 * @return array
376 */
377 public function site_status_test_php_modules( $modules ) {
378 $files = PLL_WPML_Config::instance()->get_files();
379 if ( ! empty( $files ) ) {
380 $modules['simplexml'] = array(
381 'extension' => 'simplexml',
382 'required' => true,
383 );
384 }
385 return $modules;
386 }
387 }
388