GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#32)
by
unknown
02:05
created

hm-post-repeat.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
Plugin Name: Repeatable Posts
5
Description: Designate a post as repeatable and it'll be copied and re-published on your chosen interval.
6
Author: Human Made Limited
7
Author URI: http://hmn.md/
8
Version: 0.4
9
License: GPL-2.0+
10
License URI: http://www.gnu.org/licenses/gpl-2.0.txt
11
Text Domain: hm-post-repeat
12
Domain Path: /languages
13
*/
14
15
/*
16
Copyright Human Made Limited  (email : [email protected])
17
18
This program is free software; you can redistribute it and/or modify
19
it under the terms of the GNU General Public License as published by
20
the Free Software Foundation; either version 2 of the License, or
21
(at your option) any later version.
22
23
This program is distributed in the hope that it will be useful,
24
but WITHOUT ANY WARRANTY; without even the implied warranty of
25
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
GNU General Public License for more details.
27
28
You should have received a copy of the GNU General Public License
29
along with this program; if not, write to the Free Software
30
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31
*/
32
33
namespace HM\Post_Repeat;
34
35
/**
36
 * Setup the actions and filters required by this class.
37
 */
38
add_action( 'post_submitbox_misc_actions', __NAMESPACE__ . '\publish_box_ui' );
39
add_action( 'save_post',                   __NAMESPACE__ . '\save_post_repeating_status', 10 );
40
add_action( 'save_post',                   __NAMESPACE__ . '\create_next_repeat_post', 11 );
41
add_action( 'admin_enqueue_scripts',       __NAMESPACE__ . '\enqueue_scripts' );
42
add_filter( 'display_post_states',         __NAMESPACE__ . '\admin_table_row_post_states', 10, 2 );
43
44
// Add repeat type table view links to admin screen for each CPT that supports Repeatable Posts.
45
add_action( 'init', function() {
46
	foreach ( repeating_post_types() as $post_type ) {
47
		add_filter( "views_edit-{$post_type}", __NAMESPACE__ . '\admin_table_views_links' );
48
	}
49
} );
50
51
// Display only Repeatable Posts in admin table view for registered view links.
52
add_filter( 'pre_get_posts',    __NAMESPACE__ . '\admin_table_repeat_type_posts_query' );
53
54
// Add a row link to view all Repeat posts for the current Repeating post.
55
add_filter( 'post_row_actions', __NAMESPACE__ . '\admin_table_row_actions_view_repeat_posts', 10, 2 );
56
add_action( 'wp',               __NAMESPACE__ . '\admin_table_count_repeat_posts_for_row_links' );
57
58
/**
59
 * Enqueue the scripts and styles that are needed by this plugin.
60
 */
61
function enqueue_scripts( $hook ) {
62
63
	// Ensure we only load them on the edit post and add new post admin screens
64
	if ( ! in_array( $hook, array( 'post.php', 'post-new.php' ) ) ) {
65
		return;
66
	}
67
68
	$plugin_data = get_plugin_data( __FILE__ );
69
	$plugin_dir_url = plugin_dir_url( __FILE__ );
70
71
	wp_enqueue_script( 'hm-post-repeat', $plugin_dir_url . 'hm-post-repeat.js', 'jquery', $plugin_data['Version'], true );
72
	wp_enqueue_style( 'hm-post-repeat', $plugin_dir_url . 'hm-post-repeat.css', array(), $plugin_data['Version'] );
73
74
}
75
76
/**
77
 * Output the Post Repeat UI that is shown in the Publish post meta box.
78
 *
79
 * The UI varies depending on whether the post is the original repeating post
80
 * or itself a repeat.
81
 */
82
function publish_box_ui() {
83
84
	if ( ! in_array( get_post_type(), repeating_post_types() ) ) {
85
		return;
86
	} ?>
87
88
	<div class="misc-pub-section misc-pub-hm-post-repeat">
89
90
		<span class="dashicons dashicons-controls-repeat"></span>
91
92
		<?php esc_html_e( 'Repeat:', 'hm-post-repeat' ); ?>
93
94
		<?php if ( is_repeat_post( get_the_id() ) ) : ?>
95
96
			<strong><?php printf( esc_html__( 'Repeat of %s', 'hm-post-repeat' ), '<a href="' . esc_url( get_edit_post_link( get_post()->post_parent ) ) . '">' . esc_html( get_the_title( get_post_field( 'post_parent', get_the_id() ) ) ) . '</a>' ); ?></strong>
97
98
		<?php else : ?>
99
100
			<?php $repeating_schedule = get_repeating_schedule( get_the_id() ); ?>
101
			<?php $is_repeating_post = is_repeating_post( get_the_id() ) && isset( $repeating_schedule ); ?>
102
103
			<strong><?php echo ! $is_repeating_post ? esc_html__( 'No', 'hm-post-repeat' ) : esc_html( $repeating_schedule['display'] ); ?></strong>
104
105
			<a href="#hm-post-repeat" class="edit-hm-post-repeat hide-if-no-js"><span aria-hidden="true"><?php esc_html_e( 'Edit', 'hm-post-repeat' ); ?></span> <span class="screen-reader-text"><?php esc_html_e( 'Edit Repeat Settings', 'hm-post-repeat' ); ?></span></a>
106
107
			<span class="hide-if-js" id="hm-post-repeat">
108
109
				<select name="hm-post-repeat">
110
					<option<?php selected( ! $is_repeating_post ); ?> value="no"><?php esc_html_e( 'No', 'hm-post-repeat' ); ?></option>
111
					<?php foreach ( get_repeating_schedules() as $schedule_slug => $schedule ) : ?>
112
						<option<?php selected( $is_repeating_post && $schedule_slug === $repeating_schedule['slug'] ); ?> value="<?php echo esc_attr( $schedule_slug ); ?>"><?php echo esc_html( $schedule['display'] ); ?></option>
113
					<?php endforeach; ?>
114
				</select>
115
116
				<a href="#hm-post-repeat" class="save-post-hm-post-repeat hide-if-no-js button"><?php esc_html_e( 'OK', 'hm-post-repeat' ); ?></a>
117
118
			</span>
119
120
		<?php endif; ?>
121
122
	</div>
123
124
<?php }
125
126
/**
127
 * Add some custom post states to cover repeat and repeating posts.
128
 *
129
 * By default post states are displayed on the Edit Post screen in bold after the post title.
130
 *
131
 * @param array   $post_states The original array of post states.
132
 * @param WP_Post $post        The post object to get / return the states.
133
 * @return array The array of post states with ours added.
134
 */
135
function admin_table_row_post_states( $post_states, $post ) {
136
137
	if ( is_repeating_post( $post->ID ) ) {
138
139
		// If the schedule has been removed since publishing, let the user know.
140
		if ( get_repeating_schedule( $post->ID ) ) {
141
			$post_states['hm-post-repeat'] = __( 'Repeating', 'hm-post-repeat' );
142
		} else {
143
			$post_states['hm-post-repeat'] = __( 'Invalid Repeating Schedule', 'hm-post-repeat' );
144
		}
145
146
	}
147
148
	if ( is_repeat_post( $post->ID ) ) {
149
		$post_states['hm-post-repeat'] = __( 'Repeat', 'hm-post-repeat' );
150
	}
151
152
	return $post_states;
153
}
154
155
/**
156
 * Save the repeating status to post meta.
157
 *
158
 * Hooked into `save_post`. When saving a post that has been set to repeat we save a post meta entry.
159
 *
160
 * @param int    $post_id             The ID of the post.
161
 * @param string $post_repeat_setting Used to manually set the repeating schedule from tests.
162
 */
163
function save_post_repeating_status( $post_id = null, $post_repeat_setting = null ) {
164
165
	if ( is_null( $post_repeat_setting ) ) {
166
		$post_repeat_setting = isset( $_POST['hm-post-repeat'] ) ? sanitize_text_field( $_POST['hm-post-repeat'] ) : '';
167
	}
168
169
	if ( ! in_array( get_post_type( $post_id ), repeating_post_types() ) || empty( $post_repeat_setting ) ) {
170
		return;
171
	}
172
173
	if ( 'no' === $post_repeat_setting ) {
174
		delete_post_meta( $post_id, 'hm-post-repeat' );
175
	}
176
177
	// Make sure we have a valid schedule.
178
	elseif ( in_array( $post_repeat_setting, array_keys( get_repeating_schedules() ) ) ) {
179
		update_post_meta( $post_id, 'hm-post-repeat', $post_repeat_setting );
180
	}
181
182
}
183
184
185
/**
186
 * Create the next repeat post when the last one is published.
187
 *
188
 * When a repeat post (or the original) is published we copy and schedule a new post
189
 * to publish on the correct interval. That way the next repeat post is always ready to go.
190
 * This is hooked into publish_post so that the repeat post is only created when the original
191
 * is published.
192
 *
193
 * @param int $post_id The ID of the post.
194
 */
195
function create_next_repeat_post( $post_id ) {
196
197
	if ( ! in_array( get_post_type( $post_id ), repeating_post_types() ) ) {
198
		return false;
199
	}
200
201
	if ( 'publish' !== get_post_status( $post_id ) ) {
202
		return false;
203
	}
204
205
	$original_post_id = get_repeating_post( $post_id );
206
207
	// Bail if we're not publishing a repeat(ing) post
208
	if ( ! $original_post_id ) {
209
		return false;
210
	}
211
212
	$original_post = get_post( $original_post_id, ARRAY_A );
213
214
	// If there is already a repeat post scheduled don't create another one
215
	if ( get_next_scheduled_repeat_post( $original_post['ID'] ) ) {
216
		return false;
217
	}
218
219
	// Bail if the saved schedule doesn't exist
220
	$repeating_schedule = get_repeating_schedule( $original_post['ID'] );
221
222
	if ( ! $repeating_schedule ) {
223
		return false;
224
	}
225
226
	// Bail if the original post isn't already published
227
	if ( 'publish' !== $original_post['post_status'] ) {
228
		return false;
229
	}
230
231
	$next_post = $original_post;
232
233
	// Create the repeat post as a copy of the original, but ignore some fields
234
	unset( $next_post['ID'] );
235
	unset( $next_post['guid'] );
236
	unset( $next_post['post_date_gmt'] );
237
	unset( $next_post['post_modified'] );
238
	unset( $next_post['post_modified_gmt'] );
239
240
	// We set the post_parent to the original post_id, so they're related
241
	$next_post['post_parent'] = $original_post['ID'];
242
243
	// Set the next post to publish in the future
244
	$next_post['post_status'] = 'future';
245
246
	// Use the date of the current post being saved as the base
247
	$next_post['post_date'] = date( 'Y-m-d H:i:s', strtotime( get_post_field( 'post_date', $post_id ) . ' + ' . $repeating_schedule['interval'] ) );
248
249
	// Make sure the next post will be in the future
250
	if ( strtotime( $next_post['post_date'] ) <= time() ) {
251
		return false;
252
	}
253
254
	/**
255
	 * Use this filter to modify the scheduled post before it gets stored.
256
	 *
257
	 * @param array $next_post          The post data about to be saved.
258
	 * @param array $repeating_schedule Repeating schedule info.
259
	 * @param array $original_post      The original repeating post.
260
	 */
261
	$next_post = apply_filters( 'hm_post_repeat_edit_repeat_post', $next_post, $repeating_schedule, $original_post );
262
263
	// All checks done, get that post scheduled!
264
	$next_post_id = wp_insert_post( wp_slash( $next_post ), true );
265
266
	if ( is_wp_error( $next_post_id ) ) {
267
		return false;
268
	}
269
270
	// Mirror any post_meta
271
	$post_meta = get_post_meta( $original_post['ID'] );
272
273
	if ( $post_meta  ) {
274
275
		// Ignore some internal meta fields
276
		unset( $post_meta['_edit_lock'] );
277
		unset( $post_meta['_edit_last'] );
278
279
		// Don't copy the post repeat meta as only the original post should have that
280
		unset( $post_meta['hm-post-repeat'] );
281
282
		foreach ( $post_meta as $key => $values ) {
283
			foreach ( $values as $value ) {
284
				add_post_meta( $next_post_id, $key, maybe_unserialize( $value ) );
285
			}
286
		}
287
	}
288
289
	// Mirror any term relationships
290
	$taxonomies = get_object_taxonomies( $original_post['post_type'] );
291
292
	foreach ( $taxonomies as $taxonomy ) {
293
		wp_set_object_terms( $next_post_id, wp_list_pluck( wp_get_object_terms( $original_post['ID'], $taxonomy ), 'slug' ), $taxonomy );
294
	}
295
296
	return $next_post_id;
297
298
}
299
300
/**
301
 * The post types the feature is enabled on
302
 *
303
 * By default only posts have the feature enabled but others can be added with the `hm_post_repeat_post_types` filter.
304
 *
305
 * @return array An array of post types
306
 */
307
function repeating_post_types() {
308
309
	/**
310
	 * Enable support for additional post types.
311
	 *
312
	 * @param string[] $post_types Post type slugs.
313
	 */
314
	return apply_filters( 'hm_post_repeat_post_types', array( 'post' ) );
315
316
}
317
318
/**
319
 * All available repeat schedules.
320
 *
321
 * @return array An array of all available repeat schedules
322
 */
323
function get_repeating_schedules() {
324
325
	/**
326
	 * Enable support for additional schedules.
327
	 *
328
	 * @param array[] $schedules Schedule array items.
329
	 */
330
	$schedules = apply_filters( 'hm_post_repeat_schedules', array(
331
		'daily'   => array( 'interval' => '1 day',   'display' => __( 'Daily',   'hm-post-repeat' ) ),
332
		'weekly'  => array( 'interval' => '1 week',  'display' => __( 'Weekly',  'hm-post-repeat' ) ),
333
		'monthly' => array( 'interval' => '1 month', 'display' => __( 'Monthly', 'hm-post-repeat' ) ),
334
	) );
335
336
	foreach ( $schedules as $slug => &$schedule ) {
337
		$schedule['slug'] = $slug;
338
	}
339
340
	return $schedules;
341
342
}
343
344
/**
345
 * Get the repeating schedule of the given post_id.
346
 *
347
 * @param int $post_id The id of the post you want to check.
348
 * @return array|null The schedule to repeat by, or null if invalid.
349
 */
350
function get_repeating_schedule( $post_id ) {
351
352
	if ( ! is_repeating_post( $post_id ) ) {
353
		return;
354
	}
355
356
	$repeating_schedule = get_post_meta( $post_id, 'hm-post-repeat', true );
357
	$schedules = get_repeating_schedules();
358
359
	// Backwards compatibility with 0.3 when we only supported weekly
360
	if ( '1' === $repeating_schedule ) {
361
		$repeating_schedule = 'weekly';
362
	}
363
364
	if ( array_key_exists( $repeating_schedule, $schedules ) ) {
365
		return $schedules[ $repeating_schedule ];
366
	}
367
368
}
369
370
/**
371
 * Check whether a given post_id is a repeating post.
372
 *
373
 * A repeating post is defined as the original post that was set to repeat.
374
 *
375
 * @param int $post_id The ID of the post you want to check.
376
 *
377
 * @return bool Whether the passed post_id is a repeating post or not.
378
 */
379
function is_repeating_post( $post_id ) {
380
381
	// We check $_POST data so that this function works inside a `save_post` hook when the post_meta hasn't yet been saved.
382
	if ( isset( $_POST['hm-post-repeat'] ) && isset( $_POST['ID'] ) && $_POST['ID'] === $post_id ) {
383
		return true;
384
	}
385
386
	// For saved posts - Repeating post has meta key and does NOT have a parent.
387
	$post_parent = get_post_field( 'post_parent', $post_id );
388
389
	if ( ! $post_parent && get_post_meta( $post_id, 'hm-post-repeat', true ) ) {
390
		return true;
391
	}
392
393
	return false;
394
395
}
396
397
/**
398
 * Check whether a given post_id is a repeat post.
399
 *
400
 * A repeat post is defined as any post which is a repeat of the original repeating post.
401
 *
402
 * @param int $post_id The ID of the post you want to check.
403
 *
404
 * @return bool Whether the passed post_id is a repeat post or not.
405
 */
406
function is_repeat_post( $post_id ) {
407
408
	// Repeat post has meta key and has a parent.
409
	$post_parent = get_post_field( 'post_parent', $post_id );
410
411
	if ( $post_parent && get_post_meta( $post_parent, 'hm-post-repeat', true ) ) {
412
		return true;
413
	}
414
415
	return false;
416
417
}
418
419
/**
420
 * Get the next scheduled repeat post
421
 *
422
 * @param int $post_id The id of a repeat or repeating post
423
 * @return Int|Bool Return the ID of the next repeat post_id or false if it can't find one
424
 */
425
function get_next_scheduled_repeat_post( $post_id ) {
426
427
	$post = get_post( get_repeating_post( $post_id ) );
428
429
	$repeat_posts = get_posts( array( 'post_status' => 'future', 'post_parent' => $post->ID ) );
430
431
	if ( isset( $repeat_posts[0] ) ) {
432
	 	return $repeat_posts[0];
433
	}
434
435
	return false;
436
437
}
438
439
/**
440
 * Get the next scheduled repeat post
441
 *
442
 * @param int $post_id The id of a repeat or repeating post
443
 * @return Int|Bool Return the original repeating post_id or false if it can't find it
444
 */
445
function get_repeating_post( $post_id ) {
446
447
	$original_post_id = false;
448
449
	// Are we publishing a repeat post
450
	if ( is_repeat_post( $post_id ) ) {
451
		$original_post_id = get_post( $post_id )->post_parent;
452
	}
453
454
	// Or the original
455
	elseif ( is_repeating_post( $post_id ) ) {
456
		$original_post_id = $post_id;
457
	}
458
459
	return $original_post_id;
460
461
}
462
463
/**
464
 * Adds admin table view link per available repeat type.
465
 * So that only all posts of specific repeat type are displayed.
466
 *
467
 * Added at the end of link list for All | Mine | Published | Scheduled | Drafts
468
 *
469
 * @param array $views An array of available list table views.
470
 *
471
 * @return array Available list of table views with custom added views per repeat type.
472
 */
473
function admin_table_views_links( $views ) {
474
475
	// Add status link for each repeat type.
476
	foreach ( get_available_repeat_types() as $repeat_type => $repeat_desc ) {
477
478
		$url_args = array(
479
			'post_type'      => get_current_screen()->post_type,
480
			'hm-post-repeat' => $repeat_type,
481
		);
482
483
		// Custom WP_Query to get posts count of repeat type.
484
		$repeat_type_query = new \WP_Query( get_repeat_type_query_params( $repeat_type ) );
485
486
		$link_label = sprintf(
487
				'%s <span class="count">(%s)</span>',
488
			esc_html( $repeat_desc ),
489
			esc_html( number_format_i18n( $repeat_type_query->post_count ) )
490
		);
491
492
		/**
493
		 * Add current class to the view link to highlight it when it's selected.
494
		 * NB: do not highlight the view link when displaying subsection of results
495
		 * (i.e. Repeat posts for a specific Repeating post).
496
		 */
497
		$class_html = '';
498
		if (
499
			get_repeat_type_url_param() === $repeat_type &&
500
			! isset( $_GET['post_parent'] )
501
		) {
502
			$class_html = ' class="current"';
503
		}
504
505
		$link_html = sprintf(
506
			'<a href="%s"%s>%s</a>',
507
			esc_url( add_query_arg( $url_args, 'edit.php' ) ),
508
			$class_html, // html - hardcoded, no need to escape.
509
			$link_label  // html - escaped earlier in the code.
510
		);
511
512
		$views[ $repeat_type ] = $link_html;
513
	}
514
515
	return $views;
516
}
517
518
/**
519
 * Customise main admin query to get posts of specified repeat type
520
 * to be displayed in the admin table.
521
 *
522
 * The main admin query only displays requested posts in the main table view!
523
 * It does NOT do the post count for table view links see `admin_table_views_links()` -
524
 * it has got a separate query for the total post count for view links.
525
 *
526
 * @param \WP_Query $wp_query Main admin query.
527
 *
528
 * @return mixed Main admin query with edited params to get posts of specified repeat type.
529
 */
530
function admin_table_repeat_type_posts_query( $wp_query ) {
531
532
	// Stop - if not admin or not main query (there are secondary WP_Query for counting posts for view links, etc).
533
	if ( ! is_admin() || ! $wp_query->is_main_query() ) {
534
		return $wp_query;
535
	}
536
537
	// Get URL query param for repeat type and check it's valid.
538
	$repeat_type = get_repeat_type_url_param();
539
540
	if ( ! $repeat_type || ! is_allowed_repeat_type( $repeat_type ) ) {
541
		return $wp_query;
542
	}
543
544
	// Repeat post display - only displaying Repeat posts for a specific Repeating post.
545
	$post_parent_id = isset( $_GET['post_parent'] ) ? intval( $_GET['post_parent'] ) : 0;
546
547
	// Add WP_Query param depending on displayed repeat type.
548
	foreach ( get_repeat_type_query_params( $repeat_type, $post_parent_id ) as $key => $value ) {
549
		$wp_query->set( $key, $value );
550
	}
551
552
	return $wp_query;
553
}
554
555
/**
556
 * Returns array of custom WP_Query params to get posts of specified repeat type.
557
 * Works for all CPT that support Repeatable Posts.
558
 *
559
 * @param string $repeat_type    Repeat type of posts to get.
560
 * @param int    $post_parent_id Post parent ID - to find Repeat posts for.
561
 *
562
 * @return array Array of custom WP_Query params.
563
 */
564
function get_repeat_type_query_params( $repeat_type, $post_parent_id = 0 ) {
565
566
	$query['post_type'] = get_current_screen()->post_type;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$query was never initialized. Although not strictly required by PHP, it is generally a good practice to add $query = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
567
568
	// Construct custom query to get posts of specified repeat type.
569
	$query['meta_query'] = array(
570
			array(
571
					'key'     => 'hm-post-repeat',
572
					'compare' => 'EXISTS',
573
			),
574
	);
575
576
	if ( $repeat_type === 'repeat' ) {
577
		$query['post_parent__not_in'] = array( 0 );
578
579
	} elseif ( $repeat_type === 'repeating' ) {
580
		$query['post_parent__in'] = array( 0 );
581
	}
582
583
	// Repeat post display - only displaying Repeat posts for specific Repeating post.
584
	if ( $post_parent_id ) {
585
		$query['post_parent']         = $post_parent_id;
586
		$query['post_parent__not_in'] = '';
587
		$query['post_parent__in']     = '';
588
	}
589
590
	return $query;
591
}
592
593
/**
594
 * Get URL query param for the repeat type of posts being displayed
595
 * in the admin post table.
596
 *
597
 * @return string Sanitized string of repeat type being displayed.
598
 */
599
function get_repeat_type_url_param() {
600
	return isset( $_GET['hm-post-repeat'] ) ? sanitize_text_field( $_GET['hm-post-repeat'] ) : '';
601
}
602
603
/**
604
 * Return available repeat types, i.e. repeating or repeat.
605
 *
606
 * @return array Available repeat types.
607
 */
608
function get_available_repeat_types() {
609
	return array(
610
		'repeating' => __( 'Repeating', 'hm-post-repeat' ),
611
		'repeat'    => __( 'Repeat', 'hm-post-repeat' ),
612
	);
613
}
614
615
/**
616
 * Check if a repeat type is valid.
617
 *
618
 * @param string $repeat_type Repeat type to check.
619
 *
620
 * @return bool True if repeat type is valid,
621
 *              False otherwise.
622
 */
623
function is_allowed_repeat_type( $repeat_type ) {
624
	return in_array( $repeat_type, array_keys( get_available_repeat_types() ) );
625
}
626
627
/**
628
 * Add a row link to view all Repeat posts for the current Repeating post.
629
 *
630
 * The link text is `# repeat posts` where # is the number of corresponding Repeat posts.
631
 *
632
 * The filter is evaluated only for non-hierarchical post types.
633
 *
634
 * @global $repeat_posts_count Array of all Repeating post IDs currently displayed on the admin page -
635
 *                             as keys, with their corresponding Repeat posts count as values.
636
 *
637
 * @param array   $actions An array of row action links.
638
 * @param WP_Post $post    The post object to display row links for.
639
 *
640
 * @return array An array of row action links with added link to view Repeat posts and there count.
641
 */
642
function admin_table_row_actions_view_repeat_posts( $actions, $post ) {
643
	global $repeat_posts_count;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
644
645
	if ( ! is_repeating_post( $post->ID ) ) {
646
		return $actions;
647
	}
648
649
	// URL args to display associated Repeat posts for the current Repeating post.
650
	$url_args = array(
651
		'post_type'      => get_current_screen()->post_type,
652
		'hm-post-repeat' => 'repeat',
653
		'post_parent'    => $post->ID,
654
	);
655
656
	$count = $repeat_posts_count[ $post->ID ];
657
658
	// Repeating post has got some Repeat posts - display the link to view them with the count.
659
	if ( $count ) {
660
		$actions['view_repeat'] = sprintf(
661
			'<a href="%s" aria-label="%s">%s</a>',
662
			esc_url( add_query_arg( $url_args, 'edit.php' ) ),
663
			esc_attr( sprintf(
664
				_n(
665
					'View %d repeat post',
666
					'View %d repeat posts',
667
					$count,
668
					'hm-post-repeat'
669
				),
670
				number_format_i18n( $count )
671
			) ),
672
			esc_html( sprintf(
673
				_n(
674
					'%d repeat post',
675
					'%d repeat posts',
676
					$count,
677
					'hm-post-repeat'
678
				),
679
				number_format_i18n( $count )
680
			) )
681
		);
682
	}
683
	// Repeating post has no Repeat posts - display text, not a link.
684
	else {
685
		$actions['view_repeat'] = esc_html( sprintf(
686
			_n(
687
				'%d repeat post',
688
				'%d repeat posts',
689
				$count,
690
				'hm-post-repeat'
691
			),
692
			number_format_i18n( $count )
693
		) );
694
	}
695
696
	return $actions;
697
}
698
699
/**
700
 * A helper/optimisation function to count Repeat posts for all Repeating posts
701
 * currently displayed on the admin screen.
702
 *
703
 * The row action links filter fires per each post displayed on the screen.
704
 * We're hooking in earlier that row action link, straight after the main query
705
 * for Repeating posts has run.
706
 *
707
 * @global $wp_query           Main wp_query for the page.
708
 * @global $repeat_posts_count Array of all Repeating post IDs currently displayed on the admin page -
709
 *                             as keys, with their corresponding Repeat posts count as values.
710
 */
711
function admin_table_count_repeat_posts_for_row_links() {
712
	global $wp_query, $repeat_posts_count;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
713
714
	// Stop - if current page is not admin page displaying Repeating posts.
715
	if ( ! is_admin() && get_repeat_type_url_param() !== 'repeating' ) {
716
		return;
717
	}
718
719
	// Stop - if no Repeating posts found to display.
720
	if ( ! $wp_query->posts || ! count( $wp_query->posts ) ) {
721
		return;
722
	}
723
724
	// Get currently displayed Repeating posts IDs on the screen.
725
	$repeating_ids = wp_list_pluck( $wp_query->posts, 'ID' );
726
727
	// Get Repeating posts' corresponding Repeat posts so we can count them.
728
	$repeat_posts_query = new \WP_Query( array( 'post_parent__in' => $repeating_ids ) );
729
	$repeat_posts       = $repeat_posts_query->posts;
730
731
	// Create array with keys as Repeating post IDs and 0 values.
732
	$repeat_posts_count = array();
733
	foreach ( $repeating_ids as $repeating_id ) {
734
		$repeat_posts_count[ $repeating_id ] = 0;
735
	}
736
737
	// Count for each Repeating ID, how many Repeat posts there are.
738
	foreach ( $repeat_posts as $repeat_post ) {
739
		$repeat_posts_count[ $repeat_post->post_parent ] += 1;
740
	}
741
}
742