PluginProbe
Polylang / 3.1
Polylang v3.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 / modules / wpml / wpml-config.php

wpml-config.php in Polylang 3.1, at modules/wpml/wpml-config.php

307 lines 8.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 * Reads and interprets the file wpml-config.xml
8 * See http://wpml.org/documentation/support/language-configuration-files/
9 * The language switcher configuration is not interpreted
10 *
11 * @since 1.0
12 */
13 class PLL_WPML_Config {
14 /**
15 * Singleton instance
16 *
17 * @var PLL_WPML_Config
18 */
19 protected static $instance;
20
21 /**
22 * The content of all read xml files.
23 *
24 * @var SimpleXMLElement[]
25 */
26 protected $xmls;
27
28 /**
29 * Constructor
30 *
31 * @since 1.0
32 */
33 public function __construct() {
34 if ( extension_loaded( 'simplexml' ) ) {
35 $this->init();
36 }
37 }
38
39 /**
40 * Access to the single instance of the class
41 *
42 * @since 1.7
43 *
44 * @return object
45 */
46 public static function instance() {
47 if ( empty( self::$instance ) ) {
48 self::$instance = new self();
49 }
50 return self::$instance;
51 }
52
53 /**
54 * Finds the wpml-config.xml files to parse and setup filters
55 *
56 * @since 1.0
57 *
58 * @return void
59 */
60 public function init() {
61 $this->xmls = array();
62 $files = $this->get_files();
63
64 if ( ! empty( $files ) ) {
65 add_filter( 'site_status_test_php_modules', array( $this, 'site_status_test_php_modules' ) ); // Require simplexml in Site health.
66
67 // Read all files.
68 if ( extension_loaded( 'simplexml' ) ) {
69 foreach ( $files as $context => $file ) {
70 $xml = simplexml_load_file( $file );
71 if ( false !== $xml ) {
72 $this->xmls[ $context ] = $xml;
73 }
74 }
75 }
76 }
77
78 if ( ! empty( $this->xmls ) ) {
79 add_filter( 'pll_copy_post_metas', array( $this, 'copy_post_metas' ), 20, 2 );
80 add_filter( 'pll_copy_term_metas', array( $this, 'copy_term_metas' ), 20, 2 );
81 add_filter( 'pll_get_post_types', array( $this, 'translate_types' ), 10, 2 );
82 add_filter( 'pll_get_taxonomies', array( $this, 'translate_taxonomies' ), 10, 2 );
83
84 foreach ( $this->xmls as $context => $xml ) {
85 $keys = $xml->xpath( 'admin-texts/key' );
86 if ( is_array( $keys ) ) {
87 foreach ( $keys as $key ) {
88 $attributes = $key->attributes();
89 $name = (string) $attributes['name'];
90
91 if ( false !== strpos( $name, '*' ) ) {
92 $pattern = '#^' . str_replace( '*', '(?:.+)', $name ) . '$#';
93 $names = preg_grep( $pattern, array_keys( wp_load_alloptions() ) );
94
95 if ( is_array( $names ) ) {
96 foreach ( $names as $_name ) {
97 $this->register_or_translate_option( $context, $_name, $key );
98 }
99 }
100 } else {
101 $this->register_or_translate_option( $context, $name, $key );
102 }
103 }
104 }
105 }
106 }
107 }
108
109 /**
110 * Get all wpml-config.xml files in plugins, theme, child theme and Polylang custom directory.
111 *
112 * @since 3.1
113 *
114 * @return array
115 */
116 protected function get_files() {
117 $files = array();
118
119 // Plugins
120 // Don't forget sitewide active plugins thanks to Reactorshop http://wordpress.org/support/topic/polylang-and-yoast-seo-plugin/page/2?replies=38#post-4801829
121 $plugins = ( is_multisite() && $sitewide_plugins = get_site_option( 'active_sitewide_plugins' ) ) && is_array( $sitewide_plugins ) ? array_keys( $sitewide_plugins ) : array();
122 $plugins = array_merge( $plugins, get_option( 'active_plugins', array() ) );
123
124 foreach ( $plugins as $plugin ) {
125 if ( file_exists( $file = WP_PLUGIN_DIR . '/' . dirname( $plugin ) . '/wpml-config.xml' ) ) {
126 $files[ dirname( $plugin ) ] = $file;
127 }
128 }
129
130 // Theme
131 if ( file_exists( $file = ( $template = get_template_directory() ) . '/wpml-config.xml' ) ) {
132 $files[ get_template() ] = $file;
133 }
134
135 // Child theme
136 if ( ( $stylesheet = get_stylesheet_directory() ) !== $template && file_exists( $file = $stylesheet . '/wpml-config.xml' ) ) {
137 $files[ get_stylesheet() ] = $file;
138 }
139
140 // Custom
141 if ( file_exists( $file = PLL_LOCAL_DIR . '/wpml-config.xml' ) ) {
142 $files['Polylang'] = $file;
143 }
144
145 return $files;
146 }
147
148 /**
149 * Requires the simplexml PHP module when a wpml-config.xml has been found.
150 *
151 * @since 3.1
152 *
153 * @param array $modules An associative array of modules to test for.
154 * @return array
155 */
156 public function site_status_test_php_modules( $modules ) {
157 $modules['simplexml'] = array(
158 'extension' => 'simplexml',
159 'required' => true,
160 );
161 return $modules;
162 }
163
164 /**
165 * Adds custom fields to the list of metas to copy when creating a new translation.
166 *
167 * @since 1.0
168 *
169 * @param string[] $metas The list of custom fields to copy or synchronize.
170 * @param bool $sync True for sync, false for copy.
171 * @return string[] The list of custom fields to copy or synchronize.
172 */
173 public function copy_post_metas( $metas, $sync ) {
174 foreach ( $this->xmls as $xml ) {
175 $cfs = $xml->xpath( 'custom-fields/custom-field' );
176 if ( is_array( $cfs ) ) {
177 foreach ( $cfs as $cf ) {
178 $attributes = $cf->attributes();
179 if ( 'copy' == $attributes['action'] || ( ! $sync && in_array( $attributes['action'], array( 'translate', 'copy-once' ) ) ) ) {
180 $metas[] = (string) $cf;
181 } else {
182 $metas = array_diff( $metas, array( (string) $cf ) );
183 }
184 }
185 }
186 }
187 return $metas;
188 }
189
190 /**
191 * Adds term metas to the list of metas to copy when creating a new translation.
192 *
193 * @since 2.6
194 *
195 * @param string[] $metas The list of term metas to copy or synchronize.
196 * @param bool $sync True for sync, false for copy.
197 * @return string[] The list of term metas to copy or synchronize.
198 */
199 public function copy_term_metas( $metas, $sync ) {
200 foreach ( $this->xmls as $xml ) {
201 $cfs = $xml->xpath( 'custom-term-fields/custom-term-field' );
202 if ( is_array( $cfs ) ) {
203 foreach ( $cfs as $cf ) {
204 $attributes = $cf->attributes();
205 if ( 'copy' == $attributes['action'] || ( ! $sync && in_array( $attributes['action'], array( 'translate', 'copy-once' ) ) ) ) {
206 $metas[] = (string) $cf;
207 } else {
208 $metas = array_diff( $metas, array( (string) $cf ) );
209 }
210 }
211 }
212 }
213 return $metas;
214 }
215
216 /**
217 * Language and translation management for custom post types.
218 *
219 * @since 1.0
220 *
221 * @param string[] $types The list of post type names for which Polylang manages language and translations.
222 * @param bool $hide True when displaying the list in Polylang settings.
223 * @return string[] The list of post type names for which Polylang manages language and translations.
224 */
225 public function translate_types( $types, $hide ) {
226 foreach ( $this->xmls as $xml ) {
227 $pts = $xml->xpath( 'custom-types/custom-type' );
228 if ( is_array( $pts ) ) {
229 foreach ( $pts as $pt ) {
230 $attributes = $pt->attributes();
231 if ( 1 == $attributes['translate'] && ! $hide ) {
232 $types[ (string) $pt ] = (string) $pt;
233 } else {
234 unset( $types[ (string) $pt ] ); // The theme/plugin author decided what to do with the post type so don't allow the user to change this
235 }
236 }
237 }
238 }
239 return $types;
240 }
241
242 /**
243 * Language and translation management for custom taxonomies.
244 *
245 * @since 1.0
246 *
247 * @param string[] $taxonomies The list of taxonomy names for which Polylang manages language and translations.
248 * @param bool $hide True when displaying the list in Polylang settings.
249 * @return string[] The list of taxonomy names for which Polylang manages language and translations.
250 */
251 public function translate_taxonomies( $taxonomies, $hide ) {
252 foreach ( $this->xmls as $xml ) {
253 $taxos = $xml->xpath( 'taxonomies/taxonomy' );
254 if ( is_array( $taxos ) ) {
255 foreach ( $taxos as $tax ) {
256 $attributes = $tax->attributes();
257 if ( 1 == $attributes['translate'] && ! $hide ) {
258 $taxonomies[ (string) $tax ] = (string) $tax;
259 } else {
260 unset( $taxonomies[ (string) $tax ] ); // the theme/plugin author decided what to do with the taxonomy so don't allow the user to change this
261 }
262 }
263 }
264 }
265 return $taxonomies;
266 }
267
268 /**
269 * Registers or translates the strings for an option
270 *
271 * @since 2.8
272 *
273 * @param string $context The group in which the strings will be registered.
274 * @param string $name Option name.
275 * @param object $key XML node.
276 * @return void
277 */
278 protected function register_or_translate_option( $context, $name, $key ) {
279 $option_keys = $this->xml_to_array( $key );
280 new PLL_Translate_Option( $name, reset( $option_keys ), array( 'context' => $context ) );
281 }
282
283 /**
284 * Recursively transforms xml nodes to an array, ready for PLL_Translate_Option.
285 *
286 * @since 2.9
287 *
288 * @param object $key XML node.
289 * @param array $arr Array of option keys to translate.
290 * @return array
291 */
292 protected function xml_to_array( $key, &$arr = array() ) {
293 $attributes = $key->attributes();
294 $name = (string) $attributes['name'];
295 $children = $key->children();
296
297 if ( count( $children ) ) {
298 foreach ( $children as $child ) {
299 $arr[ $name ] = $this->xml_to_array( $child, $arr[ $name ] );
300 }
301 } else {
302 $arr[ $name ] = true; // Multiline as in WPML.
303 }
304 return $arr;
305 }
306 }
307