PluginProbe
Polylang / 3.6.7
Polylang v3.6.7
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.6.7, at settings/settings-module.php

380 lines 9.0 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 update_option( 'polylang', $this->options );
199 }
200 }
201
202 /**
203 * Deactivates the module.
204 *
205 * @since 1.8
206 *
207 * @return void
208 */
209 public function deactivate() {
210 if ( 'none' !== $this->active_option && 'preview' !== $this->active_option ) {
211 $this->options[ $this->active_option ] = false;
212 update_option( 'polylang', $this->options );
213 }
214 }
215
216 /**
217 * Protected method to display a configuration form.
218 *
219 * @since 1.8
220 *
221 * @return void
222 */
223 protected function form() {
224 // Child classes can provide a form.
225 }
226
227 /**
228 * Public method returning the form if any.
229 *
230 * @since 1.8
231 *
232 * @return string
233 */
234 public function get_form() {
235 if ( ! $this->is_active() ) {
236 return '';
237 }
238
239 // Read the form only once
240 if ( false === $this->form ) {
241 ob_start();
242 $this->form();
243 $this->form = ob_get_clean();
244 }
245
246 return $this->form;
247 }
248
249 /**
250 * Allows child classes to validate their options before saving.
251 *
252 * @since 1.8
253 *
254 * @param array $options Unsanitized options to save.
255 * @return array Options
256 */
257 protected function update( $options ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
258 return array(); // It's responsibility of the child class to decide what is saved.
259 }
260
261 /**
262 * Ajax method to save the options.
263 *
264 * @since 1.8
265 *
266 * @return void
267 */
268 public function save_options() {
269 check_ajax_referer( 'pll_options', '_pll_nonce' );
270 if ( ! current_user_can( 'manage_options' ) ) {
271 wp_die( -1 );
272 }
273
274 if ( isset( $_POST['module'] ) && $this->module === $_POST['module'] ) {
275 // It's up to the child class to decide which options are saved, whether there are errors or not
276 $post = array_diff_key( $_POST, array_flip( array( 'action', 'module', 'pll_ajax_backend', '_pll_nonce' ) ) );
277 $options = $this->update( $post );
278 $this->options = array_merge( $this->options, $options );
279 update_option( 'polylang', $this->options );
280
281 // Refresh language cache in case home urls have been modified
282 $this->model->clean_languages_cache();
283
284 // Refresh rewrite rules in case rewrite, hide_default, post types or taxonomies options have been modified
285 // Don't use flush_rewrite_rules as we don't have the right links model and permastruct
286 delete_option( 'rewrite_rules' );
287
288
289 ob_start();
290
291 if ( empty( get_settings_errors( 'polylang' ) ) ) {
292 // Send update message
293 pll_add_notice( new WP_Error( 'settings_updated', __( 'Settings saved.', 'polylang' ), 'success' ) );
294 settings_errors( 'polylang' );
295 $x = new WP_Ajax_Response( array( 'what' => 'success', 'data' => ob_get_clean() ) );
296 $x->send();
297 } else {
298 // Send error messages
299 settings_errors( 'polylang' );
300 $x = new WP_Ajax_Response( array( 'what' => 'error', 'data' => ob_get_clean() ) );
301 $x->send();
302 }
303 }
304 }
305
306 /**
307 * Get the row actions.
308 *
309 * @since 1.8
310 *
311 * @return string[]
312 */
313 protected function get_actions() {
314 $actions = array();
315
316 if ( $this->is_active() && $this->get_form() ) {
317 $actions[] = 'configure';
318 }
319
320 if ( 'none' !== $this->active_option && 'preview' !== $this->active_option ) {
321 $actions[] = $this->is_active() ? 'deactivate' : 'activate';
322 }
323
324 if ( empty( $actions ) ) {
325 $actions[] = $this->is_active() ? 'activated' : 'deactivated';
326 }
327
328 return $actions;
329 }
330
331 /**
332 * Get the actions links.
333 *
334 * @since 1.8
335 *
336 * @return string[] Action links.
337 */
338 public function get_action_links() {
339 return array_intersect_key( $this->action_links, array_flip( $this->get_actions() ) );
340 }
341
342 /**
343 * Default upgrade message (to Pro version).
344 *
345 * @since 1.9
346 *
347 * @return string
348 */
349 protected function default_upgrade_message() {
350 return sprintf(
351 '%s <a href="%s">%s</a>',
352 __( 'To enable this feature, you need Polylang Pro.', 'polylang' ),
353 'https://polylang.pro',
354 __( 'Upgrade now.', 'polylang' )
355 );
356 }
357
358 /**
359 * Allows child classes to display an upgrade message.
360 *
361 * @since 1.9
362 *
363 * @return string
364 */
365 public function get_upgrade_message() {
366 return 'preview' === $this->active_option ? $this->default_upgrade_message() : '';
367 }
368
369 /**
370 * Get the buttons.
371 *
372 * @since 1.9
373 *
374 * @return string[] An array of html fragment for the buttons.
375 */
376 public function get_buttons() {
377 return $this->buttons;
378 }
379 }
380