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 / helpers.php

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

339 lines 9.5 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 /**
5 * Return an array of post types
6 *
7 * @param string $original_post_type Optional. Original post type to always include in dropdown
8 * @return array Array of post types
9 */
10 function duplicator_post_types( $original_post_type = null ) {
11
12 $post_types = array('same' => __('Same as original', 'post-duplicator'));
13 $pts = get_post_types(array(), 'objects');
14
15 // Remove framework post types
16 unset( $pts['attachment'] );
17 unset( $pts['revision'] );
18 unset( $pts['nav_menu_item'] );
19 unset( $pts['wooframework'] );
20
21 // Get enabled post types for dropdown
22 $enabled_for_dropdown = get_enabled_post_types_for_dropdown();
23
24 // Always include original post type if provided, even if not enabled in dropdown
25 if ( $original_post_type && isset( $pts[ $original_post_type ] ) ) {
26 $post_types[ $original_post_type ] = sanitize_text_field( $pts[ $original_post_type ]->labels->singular_name );
27 }
28
29 if( is_array($pts) && count($pts) > 0 ) {
30 foreach( $pts as $i=>$pt ) {
31 // Only include if enabled in dropdown (and not already added as original post type)
32 if ( in_array( $i, $enabled_for_dropdown ) && $i !== $original_post_type ) {
33 $post_types[$i] = sanitize_text_field( $pt->labels->singular_name );
34 }
35 }
36 }
37
38 // Sort alphabetically by label (keep 'same' at the top)
39 $same_option = array( 'same' => $post_types['same'] );
40 unset( $post_types['same'] );
41 uasort( $post_types, function( $a, $b ) {
42 return strcasecmp( $a, $b );
43 } );
44
45 // Put 'same' back at the beginning
46 return array_merge( $same_option, $post_types );
47 }
48
49 /**
50 * Check if a user can duplicate
51 */
52 function user_can_duplicate( $post ) {
53
54 if ( ! current_user_can( 'duplicate_posts' ) ) {
55 return false;
56 }
57
58 if ( get_current_user_id() != $post->post_author ) {
59 if ( ! current_user_can( 'duplicate_others_posts' ) ) {
60 return false;
61 }
62
63 if ( 'draft' == $post->post_status && 'disabled' === get_option_value( 'duplicate_other_draft' ) ) {
64 return false;
65 }
66
67 if ( 'pending' == $post->post_status && 'disabled' === get_option_value( 'duplicate_other_pending' ) ) {
68 return false;
69 }
70
71 if ( 'private' == $post->post_status && 'disabled' === get_option_value( 'duplicate_other_private' ) ) {
72 return false;
73 }
74
75 if ( '' != $post->post_password && 'disabled' === get_option_value( 'duplicate_other_password' ) ) {
76 return false;
77 }
78
79 if ( 'future' == $post->post_status && 'disabled' === get_option_value( 'duplicate_other_future' ) ) {
80 return false;
81 }
82 }
83
84 return true;
85 }
86
87 /**
88 * Check if a post type supports authors
89 */
90 function post_type_supports_author( $post_type ) {
91 $post_type_obj = get_post_type_object( $post_type );
92 if ( ! $post_type_obj ) {
93 return false;
94 }
95 return post_type_supports( $post_type, 'author' );
96 }
97
98 /**
99 * Get author support information for all post types
100 */
101 function get_post_types_author_support() {
102 $post_types = get_post_types( array(), 'objects' );
103 $author_support = array();
104
105 foreach ( $post_types as $post_type => $post_type_obj ) {
106 // Skip system post types
107 if ( in_array( $post_type, array( 'attachment', 'revision', 'nav_menu_item', 'wooframework' ) ) ) {
108 continue;
109 }
110 $author_support[ $post_type ] = post_type_supports( $post_type, 'author' );
111 }
112
113 return $author_support;
114 }
115
116 /**
117 * Get hierarchical support information for all post types
118 */
119 function get_post_types_hierarchical_support() {
120 $post_types = get_post_types( array(), 'objects' );
121 $hierarchical_support = array();
122
123 foreach ( $post_types as $post_type => $post_type_obj ) {
124 // Skip system post types
125 if ( in_array( $post_type, array( 'attachment', 'revision', 'nav_menu_item', 'wooframework' ) ) ) {
126 continue;
127 }
128 $hierarchical_support[ $post_type ] = $post_type_obj->hierarchical;
129 }
130
131 return $hierarchical_support;
132 }
133
134 /**
135 * Get public status information for all post types
136 */
137 function get_post_types_public_support() {
138 $post_types = get_post_types( array(), 'objects' );
139 $public_support = array();
140
141 foreach ( $post_types as $post_type => $post_type_obj ) {
142 // Skip system post types
143 if ( in_array( $post_type, array( 'attachment', 'revision', 'nav_menu_item', 'wooframework' ) ) ) {
144 continue;
145 }
146 // A post type is considered public if 'public' is true OR 'publicly_queryable' is true
147 $public_support[ $post_type ] = ! empty( $post_type_obj->public ) || ! empty( $post_type_obj->publicly_queryable );
148 }
149
150 return $public_support;
151 }
152
153 /**
154 * Get meta keys that should never be cloned to duplicated posts
155 *
156 * These meta keys will be excluded from:
157 * - The duplicate post modal display
158 * - The duplication process
159 *
160 * @return array Array of meta keys to exclude
161 */
162 function get_excluded_meta_keys() {
163 /**
164 * Filter the list of meta keys that should never be cloned
165 *
166 * @param array $excluded_keys Array of meta keys to exclude from duplication
167 */
168 $excluded_keys = apply_filters( 'mtphr_post_duplicator_excluded_meta_keys', array(
169 '_elementor_css',
170 '_elementor_element_cache',
171 '_edit_lock',
172 ) );
173
174 $setting = get_option_value( 'excluded_meta_keys' );
175 if ( ! empty( $setting ) ) {
176 $user_keys = array_filter( array_map( 'trim', explode( "\n", $setting ) ) );
177 $excluded_keys = array_unique( array_merge( $excluded_keys, $user_keys ) );
178 }
179
180 return $excluded_keys;
181 }
182
183 /**
184 * Get all post types for configuration
185 * Returns array of post type objects with id and label
186 *
187 * @return array Array of post type objects [{id: 'post', label: 'Post'}, ...]
188 */
189 function get_all_post_types( $label_type = 'label' ) {
190 $post_types = get_post_types( array(), 'objects' );
191 $result = array();
192
193 // System post types to exclude
194 $excluded = apply_filters(
195 'mtphr_post_duplicator_excluded_post_types',
196 array( 'attachment', 'revision', 'nav_menu_item', 'wooframework' )
197 );
198
199 foreach ( $post_types as $post_type => $post_type_obj ) {
200 if ( ! in_array( $post_type, $excluded ) ) {
201 $label = $post_type_obj->labels->singular_name;
202 if ( $label_type === 'label_slug' ) {
203 $label = "{$label} ({$post_type})";
204 } elseif ( $label_type === 'slug' ) {
205 $label = $post_type;
206 }
207 $result[] = array(
208 'id' => $post_type,
209 'label' => $label,
210 );
211 }
212 }
213
214 // Sort alphabetically by label
215 usort( $result, function( $a, $b ) {
216 return strcasecmp( $a['label'], $b['label'] );
217 } );
218
219 return $result;
220 }
221
222 /**
223 * Get enabled post types for duplication
224 * Returns array of post type slugs where allow_duplication is true
225 *
226 * @return array Array of post type slugs
227 */
228 function get_enabled_post_types_for_duplication() {
229 $config = get_post_types_config_with_defaults();
230
231 $enabled = array();
232 foreach ( $config as $post_type => $settings ) {
233 if ( isset( $settings['allow_duplication'] ) && $settings['allow_duplication'] ) {
234 $enabled[] = $post_type;
235 }
236 }
237
238 return $enabled;
239 }
240
241 /**
242 * Get enabled post types for dropdown
243 * Returns array of post type slugs where allow_in_dropdown is true
244 *
245 * @return array Array of post type slugs
246 */
247 function get_enabled_post_types_for_dropdown() {
248 $config = get_post_types_config_with_defaults();
249
250 $enabled = array();
251 foreach ( $config as $post_type => $settings ) {
252 if ( isset( $settings['allow_in_dropdown'] ) && $settings['allow_in_dropdown'] ) {
253 $enabled[] = $post_type;
254 }
255 }
256
257 return $enabled;
258 }
259
260 /**
261 * Check if a post type is enabled for duplication
262 *
263 * @param string $post_type Post type slug
264 * @return bool True if enabled
265 */
266 function is_post_type_duplication_enabled( $post_type ) {
267 $enabled = get_enabled_post_types_for_duplication();
268 return in_array( $post_type, $enabled );
269 }
270
271 /**
272 * Get post type configuration merged with current defaults.
273 *
274 * This keeps backward compatibility when a saved config is missing newly
275 * registered post types (for example when another plugin/theme only registers
276 * post types on specific admin screens). Missing current post types fall back
277 * to default behavior; legacy saved-only post types are still respected.
278 *
279 * @return array
280 */
281 function get_post_types_config_with_defaults() {
282 $saved_config = get_option_value( 'post_types_config' );
283 $default_config = get_default_post_types_config();
284
285 if ( empty( $saved_config ) || ! is_array( $saved_config ) ) {
286 return $default_config;
287 }
288
289 foreach ( $saved_config as $post_type => $settings ) {
290 if ( ! is_array( $settings ) ) {
291 continue;
292 }
293
294 if ( ! isset( $default_config[ $post_type ] ) ) {
295 $default_config[ $post_type ] = array(
296 'allow_duplication' => ! empty( $settings['allow_duplication'] ),
297 'allow_in_dropdown' => ! empty( $settings['allow_in_dropdown'] ),
298 );
299 continue;
300 }
301
302 if ( isset( $settings['allow_duplication'] ) ) {
303 $default_config[ $post_type ]['allow_duplication'] = (bool) $settings['allow_duplication'];
304 }
305 if ( isset( $settings['allow_in_dropdown'] ) ) {
306 $default_config[ $post_type ]['allow_in_dropdown'] = (bool) $settings['allow_in_dropdown'];
307 }
308 }
309
310 return $default_config;
311 }
312
313 /**
314 * Check if a string is valid JSON
315 *
316 * @param string $string String to check
317 * @return bool True if valid JSON
318 */
319 function is_json_string( $string ) {
320 if ( ! is_string( $string ) ) {
321 return false;
322 }
323
324 json_decode( $string );
325 return json_last_error() === JSON_ERROR_NONE;
326 }
327
328 // add_action( 'admin_notices', function() {
329 // if ( ! current_user_can( 'manage_options' ) ) {
330 // return;
331 // }
332 // $settings = Settings::get_value( 'mtphr_post_duplicator_settings' );
333 // unset( $settings['post_types_config'] );
334 // //update_option( 'mtphr_post_duplicator_settings', $settings );
335
336 // echo '<div class="notice notice-info"><pre style="background: #fff; padding: 15px; overflow: auto;">';
337 // print_r( $settings );
338 // echo '</pre></div>';
339 // } );