PluginProbe
TablePress – Tables in WordPress made easy / 3.4
TablePress – Tables in WordPress made easy v3.4
3.4 3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 All 45 releases
tablepress / models / model-options.php

model-options.php in TablePress – Tables in WordPress made easy 3.4, at models/model-options.php

409 lines 12.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Options Model
4 *
5 * @package TablePress
6 * @subpackage Models
7 * @author Tobias Bäthge
8 * @since 1.0.0
9 */
10
11 declare(strict_types=1);
12
13 // Prohibit direct script loading.
14 defined( 'ABSPATH' ) || die( 'No direct script access allowed!' );
15
16 /**
17 * Options Model class
18 *
19 * @package TablePress
20 * @subpackage Models
21 * @author Tobias Bäthge
22 * @since 1.0.0
23 */
24 class TablePress_Options_Model extends TablePress_Model {
25
26 /**
27 * Default Plugin Options.
28 *
29 * @since 1.0.0
30 * @since 2.0.0 Added the "modules" option.
31 * @var array<string, mixed>
32 */
33 protected array $default_plugin_options = array(
34 'plugin_options_db_version' => 0,
35 'table_scheme_db_version' => 0,
36 'prev_tablepress_version' => '0',
37 'tablepress_version' => TablePress::version,
38 'first_activation' => 0,
39 'message_plugin_update' => false,
40 'message_donation_nag' => true,
41 'use_custom_css' => true,
42 'use_custom_css_file' => true,
43 'custom_css' => '',
44 'custom_css_minified' => '',
45 'custom_css_version' => 0,
46 'modules' => false,
47 );
48
49 /**
50 * Default User Options.
51 *
52 * @since 1.0.0
53 * @var array<string, mixed>
54 */
55 protected array $default_user_options = array(
56 'user_options_db_version' => TablePress::db_version, // To prevent saving on first load.
57 'admin_menu_parent_page' => 'middle',
58 'message_first_visit' => true,
59 'message_superseded_extensions' => true,
60 'table_editor_column_width' => '170', // Default column width of 170px of the table editor on the "Edit" screen.
61 'table_editor_line_clamp' => '5', // Maximum number of lines per cell in the table editor on the "Edit" screen.
62 );
63
64 /**
65 * Instance of WP_Option class for Plugin Options.
66 *
67 * @since 1.0.0
68 */
69 protected \TablePress_WP_Option $plugin_options;
70
71 /**
72 * Instance of WP_User_Option class for User Options.
73 *
74 * @since 1.0.0
75 */
76 protected \TablePress_WP_User_Option $user_options;
77
78 /**
79 * Init Options Model by creating the object instances for the Plugin and User Options.
80 *
81 * @since 1.0.0
82 */
83 public function __construct() {
84 parent::__construct();
85
86 $params = array(
87 'option_name' => 'tablepress_plugin_options',
88 'default_value' => $this->default_plugin_options,
89 );
90 if ( strtotime( '2026-10-10' ) >= strtotime( 'today' ) ) {
91 $params['default_value']['message_plugin_update'] = true;
92 }
93 $this->plugin_options = TablePress::load_class( 'TablePress_WP_Option', 'class-wp_option.php', 'classes', $params );
94
95 $params = array(
96 'option_name' => 'tablepress_user_options',
97 'default_value' => $this->default_user_options,
98 );
99 $this->user_options = TablePress::load_class( 'TablePress_WP_User_Option', 'class-wp_user_option.php', 'classes', $params );
100
101 // Filter to map Meta capabilities to Primitive Capabilities.
102 add_filter( 'map_meta_cap', array( $this, 'map_tablepress_meta_caps' ), 10, 4 );
103 }
104
105 /**
106 * Update a single option or an array of options with new values.
107 *
108 * @since 1.0.0
109 *
110 * @param array<string, mixed>|string $new_options Array of new options (name => value) or name of a single option.
111 * @param mixed $single_value Optional. New value for a single option (only if $new_options is not an array).
112 */
113 public function update( /* array|string */ $new_options, /* string|bool|int|float|null */ $single_value = null ): void {
114 // Allow saving of single options that are not in an array.
115 if ( ! is_array( $new_options ) ) {
116 $new_options = array( $new_options => $single_value );
117 }
118
119 $plugin_options = $this->plugin_options->get();
120 $user_options = $this->user_options->get();
121
122 $old_options = array_merge( $plugin_options, $user_options );
123
124 foreach ( $new_options as $name => $value ) {
125 if ( isset( $this->default_plugin_options[ $name ] ) ) {
126 $plugin_options[ $name ] = $value;
127 } elseif ( isset( $this->default_user_options[ $name ] ) ) {
128 $user_options[ $name ] = $value;
129 } else { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedElse
130 // No valid Plugin or User Option -> discard the name/value pair.
131 }
132 }
133
134 $this->plugin_options->update( $plugin_options );
135 $this->user_options->update( $user_options );
136
137 /**
138 * Fires after the options have been saved.
139 *
140 * @since 3.1.0
141 *
142 * @param array<string, mixed> $old_options Array of all options before the update.
143 */
144 do_action( 'tablepress_event_updated_options', $old_options );
145 }
146
147 /**
148 * Get the value of a single option, or an array with all options.
149 *
150 * @since 1.0.0
151 *
152 * @param string|false $name Optional. Name of a single option to get, or false for all options.
153 * @param mixed $default_value Optional. Default value, if the option $name does not exist.
154 * @return mixed Value of the retrieved option $name, or $default_value if it does not exist, or array of all options.
155 */
156 public function get( /* string|false */ $name = false, /* string|bool|int|float|null */ $default_value = null ) /* : string|bool|int|float|array|null */ {
157 if ( false === $name ) {
158 return array_merge( $this->plugin_options->get(), $this->user_options->get() );
159 }
160
161 // Single Option wanted.
162 if ( $this->plugin_options->is_set( $name ) ) {
163 return $this->plugin_options->get( $name );
164 } elseif ( $this->user_options->is_set( $name ) ) {
165 return $this->user_options->get( $name );
166 } else {
167 // No valid Plugin or User Option.
168 return $default_value;
169 }
170 }
171
172 /**
173 * Get all Plugin Options (only used in Debug).
174 *
175 * @since 1.0.0
176 *
177 * @return array<string, mixed> Array of all Plugin Options.
178 */
179 public function _debug_get_plugin_options(): array {
180 return $this->plugin_options->get();
181 }
182
183 /**
184 * Get all User Options (only used in Debug).
185 *
186 * @since 1.0.0
187 *
188 * @return array<string, mixed> Array of all User Options.
189 */
190 public function _debug_get_user_options(): array {
191 return $this->user_options->get();
192 }
193
194 /**
195 * Merge existing Plugin Options with default Plugin Options,
196 * remove (no longer) existing options, e.g. after a plugin update.
197 *
198 * @since 1.0.0
199 */
200 public function merge_plugin_options_defaults(): void {
201 $plugin_options = $this->plugin_options->get();
202 // Remove old (i.e. no longer existing) Plugin Options.
203 $plugin_options = array_intersect_key( $plugin_options, $this->default_plugin_options );
204 // Merge current into new Plugin Options.
205 $plugin_options = array_merge( $this->default_plugin_options, $plugin_options );
206
207 $this->plugin_options->update( $plugin_options );
208 }
209
210 /**
211 * Merge existing User Options with default User Options,
212 * remove (no longer) existing options, e.g. after a plugin update.
213 *
214 * @since 1.0.0
215 */
216 public function merge_user_options_defaults(): void {
217 $user_options = $this->user_options->get();
218 // Remove old (i.e. no longer existing) User Options.
219 $user_options = array_intersect_key( $user_options, $this->default_user_options );
220 // Merge current into new User Options.
221 $user_options = array_merge( $this->default_user_options, $user_options );
222
223 $this->user_options->update( $user_options );
224 }
225
226 /**
227 * Adds the TablePress default capabilities to the "Administrator", "Editor", and "Author" user roles.
228 *
229 * @since 1.0.0
230 */
231 public function add_access_capabilities(): void {
232 // Capabilities for all roles.
233 $roles = array( 'administrator', 'editor', 'author' );
234 foreach ( $roles as $role ) {
235 $role = get_role( $role );
236 if ( empty( $role ) ) {
237 continue;
238 }
239
240 // From get_post_type_capabilities().
241 $role->add_cap( 'tablepress_edit_tables' );
242 // $role->add_cap( 'tablepress_edit_others_tables' );
243 $role->add_cap( 'tablepress_delete_tables' );
244 // $role->add_cap( 'tablepress_delete_others_tables' );
245
246 // Custom capabilities.
247 $role->add_cap( 'tablepress_list_tables' );
248 $role->add_cap( 'tablepress_add_tables' );
249 $role->add_cap( 'tablepress_copy_tables' );
250 $role->add_cap( 'tablepress_import_tables' );
251 $role->add_cap( 'tablepress_export_tables' );
252 $role->add_cap( 'tablepress_access_options_screen' );
253 $role->add_cap( 'tablepress_access_about_screen' );
254 }
255
256 // Capabilities for single roles.
257 $role = get_role( 'administrator' );
258 if ( ! empty( $role ) ) {
259 $role->add_cap( 'tablepress_edit_options' );
260 $role->add_cap( 'tablepress_import_tables_url' );
261 }
262 $role = get_role( 'editor' );
263 if ( ! empty( $role ) ) {
264 $role->add_cap( 'tablepress_import_tables_url' );
265 }
266
267 // Refresh current set of capabilities of the user, to be able to directly use the new caps.
268 $user = wp_get_current_user();
269 $user->get_role_caps();
270 }
271
272 /**
273 * Adds a custom "Import from URL" access capability to the "Editor" and "Administrator" user roles.
274 *
275 * @since 2.3.2
276 */
277 public function add_access_capabilities_tp232(): void {
278 $roles = array( 'administrator', 'editor' );
279 foreach ( $roles as $role ) {
280 $role = get_role( $role );
281 if ( ! empty( $role ) ) {
282 $role->add_cap( 'tablepress_import_tables_url' );
283 }
284 }
285
286 // Refresh current set of capabilities of the user, to be able to directly use the new caps.
287 $user = wp_get_current_user();
288 $user->get_role_caps();
289 }
290
291 /**
292 * Remove all TablePress capabilities from all roles.
293 *
294 * @since 1.1.0
295 *
296 * @global WP_Roles $wp_roles WordPress User Roles abstraction object.
297 * @see add_access_capabilities()
298 */
299 public function remove_access_capabilities(): void {
300 global $wp_roles;
301
302 if ( ! isset( $wp_roles ) ) {
303 $wp_roles = new WP_Roles(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
304 }
305
306 foreach ( $wp_roles->roles as $role => $details ) {
307 $role = $wp_roles->get_role( $role );
308 if ( empty( $role ) ) {
309 continue;
310 }
311
312 $role->remove_cap( 'tablepress_edit_tables' );
313 $role->remove_cap( 'tablepress_delete_tables' );
314 $role->remove_cap( 'tablepress_list_tables' );
315 $role->remove_cap( 'tablepress_add_tables' );
316 $role->remove_cap( 'tablepress_copy_tables' );
317 $role->remove_cap( 'tablepress_import_tables' );
318 $role->remove_cap( 'tablepress_export_tables' );
319 $role->remove_cap( 'tablepress_access_options_screen' );
320 $role->remove_cap( 'tablepress_access_about_screen' );
321 $role->remove_cap( 'tablepress_import_tables_wptr' ); // No longer used since 1.10, but might still be in the database.
322 $role->remove_cap( 'tablepress_edit_options' );
323 }
324
325 // Refresh current set of capabilities of the user, to be able to directly use the new caps.
326 $user = wp_get_current_user();
327 $user->get_role_caps();
328 }
329
330 /**
331 * Map TablePress meta capabilities to primitive capabilities.
332 *
333 * @since 1.0.0
334 *
335 * @param string[] $caps Current set of primitive caps.
336 * @param string $cap Meta cap that is to be checked/mapped.
337 * @param int $user_id User ID for which meta cap is to be checked.
338 * @param mixed[] $args Arguments for the check, here e.g. the table ID.
339 * @return string[] Modified set of primitive caps.
340 */
341 public function map_tablepress_meta_caps( array $caps, /* string */ $cap, int $user_id, array $args ): array {
342 // Don't use a type hint for the `$cap` argument as many WordPress plugins seem to be passing `null` to capability check or admin menu functions.
343
344 // Protect against other plugins not supplying a string for the `$cap` argument.
345 if ( ! is_string( $cap ) ) { // @phpstan-ignore function.alreadyNarrowedType (The `is_string()` check is needed as the input is coming from a filter hook.)
346 return $caps;
347 }
348
349 if ( ! in_array( $cap, array( 'tablepress_edit_table', 'tablepress_edit_table_id', 'tablepress_copy_table', 'tablepress_delete_table', 'tablepress_export_table', 'tablepress_preview_table' ), true ) ) {
350 return $caps;
351 }
352
353 // $table_id = ( ! empty( $args ) ) ? $args[0] : false;
354
355 // Reset current set of primitive caps.
356 $caps = array();
357
358 switch ( $cap ) {
359 case 'tablepress_edit_table':
360 $caps[] = 'tablepress_edit_tables';
361 break;
362 case 'tablepress_edit_table_id':
363 $caps[] = 'tablepress_edit_tables';
364 break;
365 case 'tablepress_copy_table':
366 $caps[] = 'tablepress_copy_tables';
367 break;
368 case 'tablepress_delete_table':
369 $caps[] = 'tablepress_delete_tables';
370 break;
371 case 'tablepress_export_table':
372 $caps[] = 'tablepress_export_tables';
373 break;
374 case 'tablepress_preview_table':
375 $caps[] = 'tablepress_edit_tables';
376 break;
377 default:
378 // Something went wrong, deny access to be on the safe side.
379 $caps[] = 'do_not_allow';
380 break;
381 }
382
383 /**
384 * Filters a user's TablePress capabilities.
385 *
386 * @since 1.0.0
387 *
388 * @see map_meta_cap()
389 *
390 * @param string[] $caps The user's current TablePress capabilities.
391 * @param string $cap Capability name.
392 * @param int $user_id The user ID.
393 * @param mixed[] $args Adds the context to the cap, typically the table ID.
394 */
395 return apply_filters( 'tablepress_map_meta_caps', $caps, $cap, $user_id, $args );
396 }
397
398 /**
399 * Delete the WP_Option and the user option of the model.
400 *
401 * @since 1.0.0
402 */
403 public function destroy(): void {
404 $this->plugin_options->delete();
405 $this->user_options->delete_for_all_users();
406 }
407
408 } // class TablePress_Options_Model
409