PluginProbe
Post Duplicator / trunk
Post Duplicator vtrunk
3.0.16 trunk 1.1 2.0 2.2 2.20 2.21 2.22 2.23 2.24 2.25 2.26 2.27 2.28 2.29 2.3 2.30 2.31 2.32 2.33 2.34 2.35 2.36 2.37 2.38 All 52 releases
post-duplicator / includes / settings.php

settings.php in Post Duplicator trunk, at includes/settings.php

658 lines 22.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Mtphr\PostDuplicator;
3
4 use Mtphr\PostDuplicator\Settings;
5
6 // Initialize the Settings instance (this registers all WordPress hooks)
7 Settings::instance();
8
9 /**
10 * Initialize things
11 * Hook names are namespace-specific: {NamespaceIdentifier}Settings/init_settings
12 * For Mtphr\PostDuplicator namespace, the hook prefix is: MtphrPostDuplicatorSettings
13 */
14 add_action( 'MtphrPostDuplicatorSettings/init_settings', __NAMESPACE__ . '\initialize_settings', 1 );
15 add_action( 'MtphrPostDuplicatorSettings/init_settings', __NAMESPACE__ . '\initialize_sidebar' );
16 add_action( 'MtphrPostDuplicatorSettings/init_fields', __NAMESPACE__ . '\initialize_fields' );
17
18 /**
19 * Initialize the settings
20 */
21 function initialize_settings() {
22
23 // Add an admin page for your settings page
24 Settings::admin_page( [
25 'page_title' => esc_html__( 'Post Duplicator Settings', 'post-duplicator' ),
26 'menu_title' => esc_html__( 'Post Duplicator', 'post-duplicator' ),
27 'capability' => 'manage_options',
28 'menu_slug' => 'mtphr_post_duplicator',
29 'parent_slug' => 'options-general.php',
30 'position' => 25,
31 //'header_icon' => 'dashicons-heart', // Optional
32 'header_description' => esc_html__( 'Configure default duplication settings, manage user permissions, and set advanced options for post duplication.', 'post-duplicator' ), // Optional
33 'header_version' => 'v' . MTPHR_POST_DUPLICATOR_VERSION, // Optional
34 ] );
35
36 // Add setting sections.
37 Settings::section( [
38 'id' => 'mtphr_post_duplicator_general',
39 'slug' => 'general',
40 'label' => __( 'General', 'post-duplicator' ),
41 'option' => 'mtphr_post_duplicator_settings',
42 'menu_slug' => 'mtphr_post_duplicator',
43 'parent_slug' => 'options-general.php',
44 ] );
45
46 Settings::section( [
47 'id' => 'mtphr_post_duplicator_defaults',
48 'slug' => 'defaults',
49 'label' => __( 'Defaults', 'post-duplicator' ),
50 'option' => 'mtphr_post_duplicator_settings',
51 'menu_slug' => 'mtphr_post_duplicator',
52 'parent_slug' => 'options-general.php',
53 ] );
54
55 Settings::section( [
56 'id' => 'mtphr_post_duplicator_post_types',
57 'slug' => 'post_types',
58 'label' => __( 'Post Types', 'post-duplicator' ),
59 'option' => 'mtphr_post_duplicator_settings',
60 'menu_slug' => 'mtphr_post_duplicator',
61 'parent_slug' => 'options-general.php',
62 ] );
63
64 Settings::section( [
65 'id' => 'mtphr_post_duplicator_permissions',
66 'slug' => 'permissions',
67 'label' => __( 'Permissions', 'post-duplicator' ),
68 'option' => 'disabled',
69 'menu_slug' => 'mtphr_post_duplicator',
70 'parent_slug' => 'options-general.php',
71 ] );
72
73 Settings::section( [
74 'id' => 'mtphr_post_duplicator_advanced',
75 'slug' => 'advanced',
76 'label' => __( 'Advanced', 'post-duplicator' ),
77 'option' => 'mtphr_post_duplicator_settings',
78 'menu_slug' => 'mtphr_post_duplicator',
79 'parent_slug' => 'options-general.php',
80 ] );
81
82 // Add default values
83 Settings::default_values( 'mtphr_post_duplicator_settings', [
84 'additional_screens' => '',
85 'excluded_meta_keys' => '',
86 'mode' => 'advanced',
87 'single_after_duplication_action' => 'notice',
88 'list_single_after_duplication_action' => 'notice',
89 'list_multiple_after_duplication_action' => 'notice',
90 'status' => 'draft',
91 'type' => 'same',
92 'post_author' => 'current_user',
93 'timestamp' => 'current',
94 'title' => esc_html__( 'Copy', 'post-duplicator' ),
95 'slug' => esc_html__( 'copy', 'post-duplicator' ),
96 'time_offset_days' => (int) 0,
97 'time_offset_hours' => (int) 0,
98 'time_offset_minutes' => (int) 0,
99 'time_offset_seconds' => (int) 0,
100 'time_offset_direction' => 'newer',
101 'duplicate_other_draft' => 'enabled',
102 'duplicate_other_pending' => 'enabled',
103 'duplicate_other_private' => 'enabled',
104 'duplicate_other_password' => 'enabled',
105 'duplicate_other_future' => 'enabled',
106 'post_types_config' => get_default_post_types_config(),
107 ] );
108 Settings::default_values( 'disabled',
109 user_roles_and_capabilities( 'defaults' )
110 );
111
112 // Add sanitize settings
113 Settings::sanitize_settings( 'mtphr_post_duplicator_settings', [
114 'excluded_meta_keys' => 'sanitize_textarea_field',
115 'time_offset' => 'boolval',
116 'time_offset_days' => 'intval',
117 'time_offset_hours' => 'intval',
118 'time_offset_minutes' => 'intval',
119 'time_offset_seconds' => 'intval',
120 ] );
121 Settings::sanitize_settings( 'disabled',
122 user_roles_and_capabilities( 'sanitizers' )
123 );
124 }
125
126 /**
127 * Initialize sidebar
128 * @return void
129 */
130 function initialize_sidebar() {
131 Settings::sidebar([
132 'items' => [
133 [
134 'type' => 'group',
135 'id' => 'sidebar_docs',
136 'direction' => 'column',
137 'fields' => [
138 [
139 'type' => 'heading',
140 'label' => __( 'Documentation', 'post-duplicator' ),
141 'container' => [
142 'style' => 'simple',
143 'margin' => '0',
144 ],
145 ],
146 [
147 'type' => 'links',
148 'id' => 'sidebar_doc_links',
149 'links' => [
150 [
151 'label' => 'Duplicating Posts',
152 'url' => 'https://www.metaphorcreations.com/article/post-duplicator/general/duplicating-posts/?ref=post-duplicator'
153 ],
154 [
155 'label' => 'Settings',
156 'url' => 'https://www.metaphorcreations.com/article/post-duplicator/general/settings/?ref=post-duplicator'
157 ]
158 ],
159 'container' => 'simple',
160 ],
161 ]
162 ],
163 [
164 'type' => 'group',
165 'id' => 'sidebar_ad',
166 'direction' => 'column',
167 'alignment' => 'center',
168 'spacing' => '0',
169 'backgroundColor' => 'transparent',
170 'container' => 'simple',
171 'fields' => [
172 [
173 'type' => 'ad',
174 'id' => 'email_customizer',
175 'image' => MTPHR_POST_DUPLICATOR_URL . 'assets/img/marketing/email-customizer.png',
176 'link' => 'https://www.metaphorcreations.com/wordpress-plugins/email-customizer/?campaign=post-duplicator-settings&ref=266',
177 'container' => 'simple',
178 ],
179 [
180 'type' => 'ad',
181 'id' => 'ditty_everything',
182 'image' => MTPHR_POST_DUPLICATOR_URL . 'assets/img/marketing/ditty-everything.png',
183 'link' => 'https://www.metaphorcreations.com/ditty/pricing/?campaign=post-duplicator-settings&ref=266',
184 'container' => 'simple',
185 ],
186 ]
187 ]
188 ],
189 'width' => '300px',
190 'main_max_width' => '1000px'
191 ] );
192 }
193
194 /**
195 * Initialize setting fields
196 */
197 function initialize_fields() {
198
199 // Allow integrations to prepend notices/fields to the general section
200 $general_notices = apply_filters( 'mtphr_post_duplicator_general_notices', array() );
201
202 // Add general fields
203 Settings::fields( [
204 'section' => 'mtphr_post_duplicator_general',
205 'fields' => array_merge( $general_notices, [
206 [
207 'type' => 'selection',
208 'id' => 'mode',
209 'label' => __( 'Mode', 'post-duplicator' ),
210 'choices' => [
211 'basic' => [
212 'heading' => esc_html__( 'Basic', 'post-duplicator' ),
213 'description' => esc_html__( 'Quickly duplicate posts based on duplication default settings.', 'post-duplicator' ),
214 ],
215 'advanced' => [
216 'heading' => esc_html__( 'Advanced', 'post-duplicator' ),
217 'description' => esc_html__( 'Open a modal to adjust duplicated settings for each post before the post is duplicated.', 'post-duplicator' ),
218 ],
219 ],
220 ],
221 [
222 'type' => 'radio_buttons',
223 'id' => 'single_after_duplication_action',
224 'label' => __( 'After Duplication - Edit Post Screen', 'post-duplicator' ),
225 'choices' => [
226 'new_tab' => esc_html__( 'Open Duplicated Post in New Tab', 'post-duplicator' ),
227 'same_tab' => esc_html__( 'Open Duplicated Post in Same Tab', 'post-duplicator' ),
228 'notice' => esc_html__( 'Display Notice', 'post-duplicator' ),
229 ],
230 'inline' => false,
231 'hide' => [
232 'id' => 'mode',
233 'value' => 'advanced',
234 'compare' => '='
235 ],
236 ],
237 [
238 'type' => 'radio_buttons',
239 'id' => 'list_single_after_duplication_action',
240 'label' => __( 'After Duplication - Post List Screen (Single Post)', 'post-duplicator' ),
241 'choices' => [
242 'new_tab' => esc_html__( 'Open Duplicated Post in New Tab', 'post-duplicator' ),
243 'same_tab' => esc_html__( 'Open Duplicated Post in Same Tab', 'post-duplicator' ),
244 'notice' => esc_html__( 'Display Notice', 'post-duplicator' ),
245 'refresh' => esc_html__( 'Refresh Page', 'post-duplicator' )
246 ],
247 'inline' => false,
248 'hide' => [
249 'id' => 'mode',
250 'value' => 'advanced',
251 'compare' => '='
252 ],
253 ],
254 [
255 'type' => 'radio_buttons',
256 'id' => 'list_multiple_after_duplication_action',
257 'label' => __( 'After Duplication - Post List Screen (Multiple Posts)', 'post-duplicator' ),
258 'choices' => [
259 'notice' => esc_html__( 'Display Notice', 'post-duplicator' ),
260 'refresh' => esc_html__( 'Refresh Page', 'post-duplicator' )
261 ],
262 'inline' => false,
263 'hide' => [
264 'id' => 'mode',
265 'value' => 'advanced',
266 'compare' => '='
267 ],
268 ],
269 ] ),
270 ] );
271
272 // Add default fields
273 Settings::fields( [
274 'section' => 'mtphr_post_duplicator_defaults',
275 'fields' => [
276 [
277 'type' => 'heading',
278 'label' => __( 'Defaults', 'post-duplicator' ),
279 ],
280 [
281 'type' => 'select',
282 'id' => 'status',
283 'label' => __( 'Post Status', 'post-duplicator' ),
284 'choices' => [
285 'same' => esc_html__( 'Same as original', 'post-duplicator' ),
286 'draft' => esc_html__( 'Draft', 'post-duplicator' ),
287 'publish' => esc_html__( 'Published', 'post-duplicator' ),
288 'pending' => esc_html__( 'Pending', 'post-duplicator' )
289 ],
290 ],
291 [
292 'type' => 'select',
293 'id' => 'type',
294 'label' => __( 'Post Type', 'post-duplicator' ),
295 'choices' => duplicator_post_types(),
296 ],
297 [
298 'type' => 'radio_buttons',
299 'id' => 'post_author',
300 'label' => __( 'Post Author', 'post-duplicator' ),
301 'choices' => [
302 'current_user' => esc_html__( 'Current User', 'post-duplicator' ),
303 'original_user' => esc_html__( 'Original Post Author', 'post-duplicator' ),
304 ],
305 'inline' => true,
306 ],
307 [
308 'type' => 'radio_buttons',
309 'id' => 'timestamp',
310 'label' => __( 'Post Date', 'post-duplicator' ),
311 'choices' => [
312 'duplicate' => esc_html__( 'Duplicate Timestamp', 'post-duplicator' ),
313 'current' => esc_html__( 'Current Time', 'post-duplicator' )
314 ],
315 'inline' => true,
316 ],
317 [
318 'type' => 'text',
319 'id' => 'title',
320 'label' => __( 'Duplicate Title', 'post-duplicator' ),
321 'help' => esc_html__( "String that should be appended to the duplicate post's title", 'post-duplicator' ),
322 ],
323 [
324 'type' => 'text',
325 'id' => 'slug',
326 'label' => __( 'Duplicate Slug', 'post-duplicator' ),
327 'help' => esc_html__( "String that should be appended to the duplicate post's slug", 'post-duplicator' ),
328 ],
329 [
330 'type' => 'checkbox',
331 'id' => 'time_offset',
332 'label' => __( 'Offset Date', 'post-duplicator' ),
333 'sanitize' => 'boolval',
334 ],
335 [
336 'type' => 'group',
337 'wrap' => true,
338 'fields' => [
339 [
340 'type' => 'number',
341 'id' => 'time_offset_days',
342 'label' => __( 'Days', 'post-duplicator' ),
343 'min' => (int) 0,
344 ],
345 [
346 'type' => 'number',
347 'id' => 'time_offset_hours',
348 'label' => __( 'Hours', 'post-duplicator' ),
349 'min' => (int) 0,
350 ],
351 [
352 'type' => 'number',
353 'id' => 'time_offset_minutes',
354 'label' => __( 'Minutes', 'post-duplicator' ),
355 'min' => (int) 0,
356 ],
357 [
358 'type' => 'number',
359 'id' => 'time_offset_seconds',
360 'label' => __( 'Seconds', 'post-duplicator' ),
361 'min' => (int) 0,
362 ],
363 ],
364 'show' => [
365 'id' => 'time_offset',
366 'value' => true,
367 'compare' => '='
368 ],
369 ],
370 [
371 'type' => 'radio_buttons',
372 'id' => 'time_offset_direction',
373 'label' => __( 'Offset direction', 'post-duplicator' ),
374 'choices' => [
375 'newer' => esc_html__( 'Newer', 'post-duplicator' ),
376 'older' => esc_html__( 'Older', 'post-duplicator' )
377 ],
378 'inline' => true,
379 'show' => [
380 'id' => 'time_offset',
381 'value' => true,
382 'compare' => '='
383 ],
384 ],
385 ],
386 ] );
387
388 Settings::fields( [
389 'section' => 'mtphr_post_duplicator_post_types',
390 'fields' => [
391 [
392 'type' => 'heading',
393 'label' => __( 'Post Types Configuration', 'post-duplicator' ),
394 'help' => __( 'Configure which post types can be duplicated and which appear in the "Post Type" dropdown menu.', 'post-duplicator' ),
395 ],
396 [
397 'type' => 'options_matrix',
398 'id' => 'post_types_config',
399 'item_label' => false,
400 'items' => get_all_post_types( 'slug' ),
401 'options' => [
402 [
403 'key' => 'allow_duplication',
404 'type' => 'checkbox',
405 'label' => __( 'Allow Duplication', 'post-duplicator' ),
406 'help' => __( 'Allow this post type to be duplicated.', 'post-duplicator' ),
407 ],
408 [
409 'key' => 'allow_in_dropdown',
410 'type' => 'checkbox',
411 'label' => __( 'Allow Switch', 'post-duplicator' ),
412 'help' => __( 'Allow duplicated posts to be switched to this post type.', 'post-duplicator' ),
413 ],
414 ],
415 ],
416 ],
417 ] );
418
419 Settings::fields( [
420 'section' => 'mtphr_post_duplicator_permissions',
421 'fields' => [
422 [
423 'label' => esc_html__( 'Permissions', 'post-duplicator' ),
424 'type' => 'group',
425 'direction' => 'column',
426 'fields' => user_roles_and_capabilities(),
427 ]
428 ],
429 ] );
430
431 Settings::fields( [
432 'section' => 'mtphr_post_duplicator_advanced',
433 'fields' => [
434 [
435 'type' => 'heading',
436 'label' => __( 'Excluded Meta Keys', 'post-duplicator' ),
437 'help' => __( 'Enter meta keys (one per line) that should never be duplicated and will not appear in the duplication modal.', 'post-duplicator' ),
438 ],
439 [
440 'type' => 'textarea',
441 'id' => 'excluded_meta_keys',
442 'label' => __( 'Meta Keys', 'post-duplicator' ),
443 'help' => __( 'One meta key per line. These are added to the built-in exclusion list.', 'post-duplicator' ),
444 'placeholder' => "_some_key\nanother_key",
445 ],
446 [
447 'type' => 'heading',
448 'label' => __( 'Additional Admin Screens', 'post-duplicator' ),
449 'help' => __( 'Enter admin page slugs (one per line) where Post Duplicator scripts should load. Use this for plugins that display post lists on non-standard admin screens so the full duplication modal is available.', 'post-duplicator' ),
450 ],
451 [
452 'type' => 'textarea',
453 'id' => 'additional_screens',
454 'label' => __( 'Page Slugs', 'post-duplicator' ),
455 'help' => __( 'One slug prefix per line. Scripts load when the current page slug starts with any entry here.', 'post-duplicator' ),
456 'placeholder' => "nestedpages\nwpca-list",
457 ],
458 [
459 'type' => 'heading',
460 'label' => __( 'Advanced Duplication Settings', 'post-duplicator' ),
461 'help' => __( "Advanced settings related to duplication of other user posts.", 'post-duplicator' ),
462 ],
463 [
464 'type' => 'radio_buttons',
465 'id' => 'duplicate_other_draft',
466 'label' => __( 'Draft Posts', 'post-duplicator' ),
467 'help' => __( "Should users be able to duplicate other's draft posts?", 'post-duplicator' ),
468 'choices' => [
469 'disabled' => esc_html__( 'Disabled', 'post-duplicator' ),
470 'enabled' => esc_html__( 'Enabled', 'post-duplicator' ),
471 ],
472 'inline' => true,
473 ],
474 [
475 'type' => 'radio_buttons',
476 'id' => 'duplicate_other_pending',
477 'label' => __( 'Pending Posts', 'post-duplicator' ),
478 'help' => __( "Should users be able to duplicate other's pending posts?", 'post-duplicator' ),
479 'choices' => [
480 'disabled' => esc_html__( 'Disabled', 'post-duplicator' ),
481 'enabled' => esc_html__( 'Enabled', 'post-duplicator' ),
482 ],
483 'inline' => true,
484 ],
485 [
486 'type' => 'radio_buttons',
487 'id' => 'duplicate_other_private',
488 'label' => __( 'Private Posts', 'post-duplicator' ),
489 'help' => __( "Should users be able to duplicate other's private posts?", 'post-duplicator' ),
490 'choices' => [
491 'disabled' => esc_html__( 'Disabled', 'post-duplicator' ),
492 'enabled' => esc_html__( 'Enabled', 'post-duplicator' ),
493 ],
494 'inline' => true,
495 ],
496 [
497 'type' => 'radio_buttons',
498 'id' => 'duplicate_other_password',
499 'label' => __( 'Password Protected Posts', 'post-duplicator' ),
500 'help' => __( "Should users be able to duplicate other's password protected posts?", 'post-duplicator' ),
501 'choices' => [
502 'disabled' => esc_html__( 'Disabled', 'post-duplicator' ),
503 'enabled' => esc_html__( 'Enabled', 'post-duplicator' ),
504 ],
505 'inline' => true,
506 ],
507 [
508 'type' => 'radio_buttons',
509 'id' => 'duplicate_other_future',
510 'label' => __( 'Future Posts', 'post-duplicator' ),
511 'help' => __( "Should users be able to duplicate other's future posts?", 'post-duplicator' ),
512 'choices' => [
513 'disabled' => esc_html__( 'Disabled', 'post-duplicator' ),
514 'enabled' => esc_html__( 'Enabled', 'post-duplicator' ),
515 ],
516 'inline' => true,
517 ],
518 ],
519 ] );
520 }
521
522 /**
523 * Return settings
524 */
525 function get_option_value( $key = false, $option = false ) {
526 $option = $option ? $option : 'mtphr_post_duplicator_settings';
527 return Settings::get_value( $option, $key );
528 }
529
530 /**
531 * Update settings
532 */
533 function set_option_value( $key, $value = false, $option = false ) {
534 $option = $option ? $option : 'mtphr_post_duplicator_settings';
535 return Settings::set_value( $option, $key, $value );
536 }
537
538 /**
539 * Return user roles and capabilities
540 */
541 function user_roles_and_capabilities( $type = '' ) {
542 $wp_roles_instance = wp_roles();
543 $all_roles = $wp_roles_instance->roles;
544 $fields = [];
545 $defaults = [];
546 $sanitize = [];
547
548 $capabilities = get_capabilities();
549 $active_capabilities = get_active_capabilities();
550
551 foreach ($all_roles as $role_key => $role) {
552 $role_capabilities = $capabilities;
553 $checkboxes = [
554 'id' => $role_key,
555 'label' => sprintf( esc_html__( '%s Permissions', 'post-duplicator' ), $role['name'] ),
556 'type' => 'checkboxes',
557 'inline' => false,
558 'choices' => $role_capabilities,
559 'noupdate' => true,
560 ];
561 $fields[] = $checkboxes;
562 $defaults[$role_key] = $active_capabilities[$role_key];
563 $sanitize[$role_key] = __NAMESPACE__ . '\update_capabilities';
564 }
565
566 if ( 'defaults' == $type ) {
567 return $defaults;
568 } elseif( 'sanitizers' == $type ) {
569 return $sanitize;
570 } else {
571 return $fields;
572 }
573 }
574
575 /**
576 * Get capabilities
577 */
578 function get_capabilities() {
579 $capabilities = [
580 'duplicate_posts',
581 'duplicate_others_posts',
582 ];
583 return array_combine( $capabilities, $capabilities );
584 }
585
586 /**
587 * Get active capabilities
588 */
589 function get_active_capabilities( $role = false) {
590 $duplicator_capabilities = get_capabilities();
591 $active_capabilities = [];
592 if ( $role ) {
593 foreach ( $role->capabilities as $capability => $enabled ) {
594 if ( $enabled && in_array( $capability, $duplicator_capabilities ) ) {
595 $active_capabilities[] = $capability;
596 }
597 }
598 } else {
599 $wp_roles_instance = wp_roles();
600 $all_roles = $wp_roles_instance->roles;
601 foreach ($all_roles as $role_key => $role) {
602 $capabilities = [];
603 foreach ( $role['capabilities'] as $capability => $enabled ) {
604 if ( $enabled && in_array( $capability, $duplicator_capabilities ) ) {
605 $capabilities[] = $capability;
606 }
607 }
608 $active_capabilities[$role_key] = $capabilities;
609 }
610 }
611 return $active_capabilities;
612 }
613
614 /**
615 * Update a role capability
616 */
617 function update_capabilities( $value, $key, $option, $type ) {
618 if ( 'update' == $type ) {
619 $role = get_role( $key );
620 $active_capabilities = get_active_capabilities( $role );
621 $capability_value = is_array( $value ) ? $value : [];
622 $added_capabilities = array_diff( $capability_value, $active_capabilities );
623 $removed_capabilities = array_diff( $active_capabilities, $capability_value );
624
625 if ( is_array( $added_capabilities ) && count( $added_capabilities ) > 0 ) {
626 foreach ( $added_capabilities as $added_capability ) {
627 $role->add_cap( esc_attr( $added_capability ) );
628 }
629 }
630 if ( is_array( $removed_capabilities ) && count( $removed_capabilities ) > 0 ) {
631 foreach ( $removed_capabilities as $removed_capability ) {
632 $role->remove_cap( esc_attr( $removed_capability ) );
633 }
634 }
635 }
636 return $value;
637 }
638
639 /**
640 * Get default post types configuration
641 * All post types enabled for duplication, only post and page for dropdown
642 *
643 * @return array Default configuration
644 */
645 function get_default_post_types_config() {
646 $all_types = get_all_post_types();
647 $config = array();
648
649 foreach ( $all_types as $type ) {
650 $config[ $type['id'] ] = array(
651 'allow_duplication' => true,
652 'allow_in_dropdown' => in_array( $type['id'], array( 'post', 'page' ) ),
653 );
654 }
655
656 return $config;
657 }
658