PluginProbe
Polylang / 3.7.6
Polylang v3.7.6
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 / settings / settings-module.php

settings-module.php in Polylang 3.7.6, at settings/settings-module.php

376 lines 8.8 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 * Base class for all settings
8 *
9 * @since 1.8
10 */
11 class PLL_Settings_Module {
12 /**
13 * Stores the plugin options.
14 *
15 * @var array
16 */
17 public $options;
18
19 /**
20 * @var PLL_Model
21 */
22 public $model;
23
24 /**
25 * Instance of a child class of PLL_Links_Model.
26 *
27 * @var PLL_Links_Model
28 */
29 public $links_model;
30
31 /**
32 * Key to use to manage the module activation state.
33 * Possible values:
34 * - An option key for a module that can be activated/deactivated.
35 * - 'none' for a module that doesn't have a activation/deactivation setting.
36 * - 'preview' for a preview module whose functionalities are available in the Pro version.
37 *
38 * @var string
39 *
40 * @phpstan-var non-falsy-string
41 */
42 public $active_option;
43
44 /**
45 * Stores the display order priority.
46 *
47 * @var int
48 */
49 public $priority = 100;
50
51 /**
52 * Stores the module name.
53 * It must be unique.
54 *
55 * @var string
56 *
57 * @phpstan-var non-falsy-string
58 */
59 public $module;
60
61 /**
62 * Stores the module title.
63 *
64 * @var string
65 */
66 public $title;
67
68 /**
69 * Stores the module description.
70 *
71 * @var string
72 */
73 public $description;
74
75 /**
76 * Stores the settings actions.
77 *
78 * @var array
79 */
80 protected $action_links;
81
82 /**
83 * Stores html fragment for the buttons.
84 *
85 * @var array
86 */
87 protected $buttons;
88
89 /**
90 * Stores html form when provided by a child class.
91 *
92 * @var string|false
93 */
94 protected $form = false;
95
96 /**
97 * Constructor
98 *
99 * @since 1.8
100 *
101 * @param object $polylang The Polylang object.
102 * @param array $args {
103 * @type string $module Unique module name.
104 * @type string $title The title of the settings module.
105 * @type string $description The description of the settings module.
106 * @type string $active_option Optional. Key to use to manage the module activation state.
107 * Possible values:
108 * - An option key for a module that can be activated/deactivated.
109 * - 'none' for a module that doesn't have a activation/deactivation setting.
110 * - 'preview' for a preview module whose functionalities are available in the Pro version.
111 * Default is 'none'.
112 * }
113 *
114 * @phpstan-param array{
115 * module: non-falsy-string,
116 * title: string,
117 * description: string,
118 * active_option?: non-falsy-string
119 * } $args
120 */
121 public function __construct( &$polylang, $args ) {
122 $this->options = &$polylang->options;
123 $this->model = &$polylang->model;
124 $this->links_model = &$polylang->links_model;
125
126 $args = wp_parse_args(
127 $args,
128 array(
129 'title' => '',
130 'description' => '',
131 'active_option' => 'none',
132 )
133 );
134
135 if ( empty( $args['active_option'] ) ) {
136 // Backward compatibility.
137 $args['active_option'] = 'none';
138 }
139
140 foreach ( $args as $prop => $value ) {
141 $this->$prop = $value;
142 }
143
144 // All possible action links, even if not always a link ;-)
145 $this->action_links = array(
146 'configure' => sprintf(
147 '<a title="%s" href="%s">%s</a>',
148 esc_attr__( 'Configure this module', 'polylang' ),
149 '#',
150 esc_html__( 'Settings', 'polylang' )
151 ),
152 'deactivate' => sprintf(
153 '<a title="%s" href="%s">%s</a>',
154 esc_attr__( 'Deactivate this module', 'polylang' ),
155 esc_url( wp_nonce_url( '?page=mlang&tab=modules&pll_action=deactivate&noheader=true&module=' . $this->module, 'pll_deactivate' ) ),
156 esc_html__( 'Deactivate', 'polylang' )
157 ),
158 'activate' => sprintf(
159 '<a title="%s" href="%s">%s</a>',
160 esc_attr__( 'Activate this module', 'polylang' ),
161 esc_url( wp_nonce_url( '?page=mlang&tab=modules&pll_action=activate&noheader=true&module=' . $this->module, 'pll_activate' ) ),
162 esc_html__( 'Activate', 'polylang' )
163 ),
164 'activated' => esc_html__( 'Activated', 'polylang' ),
165 'deactivated' => esc_html__( 'Deactivated', 'polylang' ),
166 );
167
168 $this->buttons = array(
169 'cancel' => sprintf( '<button type="button" class="button button-secondary cancel">%s</button>', esc_html__( 'Cancel', 'polylang' ) ),
170 'save' => sprintf( '<button type="button" class="button button-primary save">%s</button>', esc_html__( 'Save Changes', 'polylang' ) ),
171 );
172
173 // Ajax action to save options.
174 add_action( 'wp_ajax_pll_save_options', array( $this, 'save_options' ) );
175 }
176
177 /**
178 * Tells if the module is active.
179 *
180 * @since 1.8
181 *
182 * @return bool
183 */
184 public function is_active() {
185 return 'none' === $this->active_option || ( 'preview' !== $this->active_option && ! empty( $this->options[ $this->active_option ] ) );
186 }
187
188 /**
189 * Activates the module.
190 *
191 * @since 1.8
192 *
193 * @return void
194 */
195 public function activate() {
196 if ( 'none' !== $this->active_option && 'preview' !== $this->active_option ) {
197 $this->options[ $this->active_option ] = true;
198 }
199 }
200
201 /**
202 * Deactivates the module.
203 *
204 * @since 1.8
205 *
206 * @return void
207 */
208 public function deactivate() {
209 if ( 'none' !== $this->active_option && 'preview' !== $this->active_option ) {
210 $this->options[ $this->active_option ] = false;
211 }
212 }
213
214 /**
215 * Protected method to display a configuration form.
216 *
217 * @since 1.8
218 *
219 * @return void
220 */
221 protected function form() {
222 // Child classes can provide a form.
223 }
224
225 /**
226 * Public method returning the form if any.
227 *
228 * @since 1.8
229 *
230 * @return string
231 */
232 public function get_form() {
233 if ( ! $this->is_active() ) {
234 return '';
235 }
236
237 // Read the form only once
238 if ( false === $this->form ) {
239 ob_start();
240 $this->form();
241 $this->form = ob_get_clean();
242 }
243
244 return $this->form;
245 }
246
247 /**
248 * Allows child classes to prepare the received data before saving.
249 *
250 * @since 3.7
251 *
252 * @param array $options Raw values to save.
253 * @return array
254 */
255 protected function prepare_raw_data( array $options ): array {
256 return $options;
257 }
258
259 /**
260 * Ajax method to save the options.
261 *
262 * @since 1.8
263 *
264 * @return void
265 */
266 public function save_options() {
267 check_ajax_referer( 'pll_options', '_pll_nonce' );
268 if ( ! current_user_can( 'manage_options' ) ) {
269 wp_die( -1 );
270 }
271
272 if ( isset( $_POST['module'] ) && $this->module === $_POST['module'] ) {
273 // It's up to the child class to decide which options are saved, whether there are errors or not
274 $posted_options = array_diff_key( $_POST, array_flip( array( 'action', 'module', 'pll_ajax_backend', 'pll_ajax_settings', '_pll_nonce' ) ) );
275 $errors = $this->options->merge( $this->prepare_raw_data( $posted_options ) );
276
277 // Refresh language cache in case home urls have been modified
278 $this->model->clean_languages_cache();
279
280 // Refresh rewrite rules in case rewrite, hide_default, post types or taxonomies options have been modified
281 // Don't use flush_rewrite_rules as we don't have the right links model and permastruct
282 delete_option( 'rewrite_rules' );
283
284 ob_start();
285
286 if ( ! $errors->has_errors() ) {
287 // Send update message
288 pll_add_notice( new WP_Error( 'settings_updated', __( 'Settings saved.', 'polylang' ), 'success' ) );
289 settings_errors( 'polylang' );
290 $x = new WP_Ajax_Response( array( 'what' => 'success', 'data' => ob_get_clean() ) );
291 $x->send();
292 } else {
293 // Send error messages
294 pll_add_notice( $errors );
295 settings_errors( 'polylang' );
296 $x = new WP_Ajax_Response( array( 'what' => 'error', 'data' => ob_get_clean() ) );
297 $x->send();
298 }
299 }
300 }
301
302 /**
303 * Get the row actions.
304 *
305 * @since 1.8
306 *
307 * @return string[]
308 */
309 protected function get_actions() {
310 $actions = array();
311
312 if ( $this->is_active() && $this->get_form() ) {
313 $actions[] = 'configure';
314 }
315
316 if ( 'none' !== $this->active_option && 'preview' !== $this->active_option ) {
317 $actions[] = $this->is_active() ? 'deactivate' : 'activate';
318 }
319
320 if ( empty( $actions ) ) {
321 $actions[] = $this->is_active() ? 'activated' : 'deactivated';
322 }
323
324 return $actions;
325 }
326
327 /**
328 * Get the actions links.
329 *
330 * @since 1.8
331 *
332 * @return string[] Action links.
333 */
334 public function get_action_links() {
335 return array_intersect_key( $this->action_links, array_flip( $this->get_actions() ) );
336 }
337
338 /**
339 * Default upgrade message (to Pro version).
340 *
341 * @since 1.9
342 *
343 * @return string
344 */
345 protected function default_upgrade_message() {
346 return sprintf(
347 '%s <a href="%s">%s</a>',
348 __( 'To enable this feature, you need Polylang Pro.', 'polylang' ),
349 'https://polylang.pro',
350 __( 'Upgrade now.', 'polylang' )
351 );
352 }
353
354 /**
355 * Allows child classes to display an upgrade message.
356 *
357 * @since 1.9
358 *
359 * @return string
360 */
361 public function get_upgrade_message() {
362 return 'preview' === $this->active_option ? $this->default_upgrade_message() : '';
363 }
364
365 /**
366 * Get the buttons.
367 *
368 * @since 1.9
369 *
370 * @return string[] An array of html fragment for the buttons.
371 */
372 public function get_buttons() {
373 return $this->buttons;
374 }
375 }
376