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
20:31
created

hm-post-repeat.php ➔ admin_table_row_actions_view_repeat_posts()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 56
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 36
nc 3
nop 2
dl 0
loc 56
rs 9.7251
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
57
/**
58
 * Enqueue the scripts and styles that are needed by this plugin.
59
 */
60
function enqueue_scripts( $hook ) {
61
62
	// Ensure we only load them on the edit post and add new post admin screens
63
	if ( ! in_array( $hook, array( 'post.php', 'post-new.php' ) ) ) {
64
		return;
65
	}
66
67
	$plugin_data = get_plugin_data( __FILE__ );
68
	$plugin_dir_url = plugin_dir_url( __FILE__ );
69
70
	wp_enqueue_script( 'hm-post-repeat', $plugin_dir_url . 'hm-post-repeat.js', 'jquery', $plugin_data['Version'], true );
71
	wp_enqueue_style( 'hm-post-repeat', $plugin_dir_url . 'hm-post-repeat.css', array(), $plugin_data['Version'] );
72
73
}
74
75
/**
76
 * Output the Post Repeat UI that is shown in the Publish post meta box.
77
 *
78
 * The UI varies depending on whether the post is the original repeating post
79
 * or itself a repeat.
80
 */
81
function publish_box_ui() {
82
83
	if ( ! in_array( get_post_type(), repeating_post_types() ) ) {
84
		return;
85
	} ?>
86
87
	<div class="misc-pub-section misc-pub-hm-post-repeat">
88
89
		<span class="dashicons dashicons-controls-repeat"></span>
90
91
		<?php esc_html_e( 'Repeat:', 'hm-post-repeat' ); ?>
92
93
		<?php if ( is_repeat_post( get_the_id() ) ) : ?>
94
95
			<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>
96
97
		<?php else : ?>
98
99
			<?php $repeating_schedule = get_repeating_schedule( get_the_id() ); ?>
100
			<?php $is_repeating_post = is_repeating_post( get_the_id() ) && isset( $repeating_schedule ); ?>
101
102
			<strong><?php echo ! $is_repeating_post ? esc_html__( 'No', 'hm-post-repeat' ) : esc_html( $repeating_schedule['display'] ); ?></strong>
103
104
			<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>
105
106
			<span class="hide-if-js" id="hm-post-repeat">
107
108
				<select name="hm-post-repeat">
109
					<option<?php selected( ! $is_repeating_post ); ?> value="no"><?php esc_html_e( 'No', 'hm-post-repeat' ); ?></option>
110
					<?php foreach ( get_repeating_schedules() as $schedule_slug => $schedule ) : ?>
111
						<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>
112
					<?php endforeach; ?>
113
				</select>
114
115
				<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>
116
117
			</span>
118
119
		<?php endif; ?>
120
121
	</div>
122
123
<?php }
124
125
/**
126
 * Add some custom post states to cover repeat and repeating posts.
127
 *
128
 * By default post states are displayed on the Edit Post screen in bold after the post title.
129
 *
130
 * @param array   $post_states The original array of post states.
131
 * @param WP_Post $post        The post object to get / return the states.
132
 * @return array The array of post states with ours added.
133
 */
134
function admin_table_row_post_states( $post_states, $post ) {
135
136
	if ( is_repeating_post( $post->ID ) ) {
137
138
		// If the schedule has been removed since publishing, let the user know.
139
		if ( get_repeating_schedule( $post->ID ) ) {
140
			$post_states['hm-post-repeat'] = __( 'Repeating', 'hm-post-repeat' );
141
		} else {
142
			$post_states['hm-post-repeat'] = __( 'Invalid Repeating Schedule', 'hm-post-repeat' );
143
		}
144
145
	}
146
147
	if ( is_repeat_post( $post->ID ) ) {
148
		$post_states['hm-post-repeat'] = __( 'Repeat', 'hm-post-repeat' );
149
	}
150
151
	return $post_states;
152
}
153
154
/**
155
 * Save the repeating status to post meta.
156
 *
157
 * Hooked into `save_post`. When saving a post that has been set to repeat we save a post meta entry.
158
 *
159
 * @param int    $post_id             The ID of the post.
160
 * @param string $post_repeat_setting Used to manually set the repeating schedule from tests.
161
 */
162
function save_post_repeating_status( $post_id = null, $post_repeat_setting = null ) {
163
164
	if ( is_null( $post_repeat_setting ) ) {
165
		$post_repeat_setting = isset( $_POST['hm-post-repeat'] ) ? sanitize_text_field( $_POST['hm-post-repeat'] ) : '';
166
	}
167
168
	if ( ! in_array( get_post_type( $post_id ), repeating_post_types() ) || empty( $post_repeat_setting ) ) {
169
		return;
170
	}
171
172
	if ( 'no' === $post_repeat_setting ) {
173
		delete_post_meta( $post_id, 'hm-post-repeat' );
174
	}
175
176
	// Make sure we have a valid schedule.
177
	elseif ( in_array( $post_repeat_setting, array_keys( get_repeating_schedules() ) ) ) {
178
		update_post_meta( $post_id, 'hm-post-repeat', $post_repeat_setting );
179
	}
180
181
}
182
183
184
/**
185
 * Create the next repeat post when the last one is published.
186
 *
187
 * When a repeat post (or the original) is published we copy and schedule a new post
188
 * to publish on the correct interval. That way the next repeat post is always ready to go.
189
 * This is hooked into publish_post so that the repeat post is only created when the original
190
 * is published.
191
 *
192
 * @param int $post_id The ID of the post.
193
 */
194
function create_next_repeat_post( $post_id ) {
195
196
	if ( ! in_array( get_post_type( $post_id ), repeating_post_types() ) ) {
197
		return false;
198
	}
199
200
	if ( 'publish' !== get_post_status( $post_id ) ) {
201
		return false;
202
	}
203
204
	$original_post_id = get_repeating_post( $post_id );
205
206
	// Bail if we're not publishing a repeat(ing) post
207
	if ( ! $original_post_id ) {
208
		return false;
209
	}
210
211
	$original_post = get_post( $original_post_id, ARRAY_A );
212
213
	// If there is already a repeat post scheduled don't create another one
214
	if ( get_next_scheduled_repeat_post( $original_post['ID'] ) ) {
215
		return false;
216
	}
217
218
	// Bail if the saved schedule doesn't exist
219
	$repeating_schedule = get_repeating_schedule( $original_post['ID'] );
220
221
	if ( ! $repeating_schedule ) {
222
		return false;
223
	}
224
225
	// Bail if the original post isn't already published
226
	if ( 'publish' !== $original_post['post_status'] ) {
227
		return false;
228
	}
229
230
	$next_post = $original_post;
231
232
	// Create the repeat post as a copy of the original, but ignore some fields
233
	unset( $next_post['ID'] );
234
	unset( $next_post['guid'] );
235
	unset( $next_post['post_date_gmt'] );
236
	unset( $next_post['post_modified'] );
237
	unset( $next_post['post_modified_gmt'] );
238
239
	// We set the post_parent to the original post_id, so they're related
240
	$next_post['post_parent'] = $original_post['ID'];
241
242
	// Set the next post to publish in the future
243
	$next_post['post_status'] = 'future';
244
245
	// Use the date of the current post being saved as the base
246
	$next_post['post_date'] = date( 'Y-m-d H:i:s', strtotime( get_post_field( 'post_date', $post_id ) . ' + ' . $repeating_schedule['interval'] ) );
247
248
	// Make sure the next post will be in the future
249
	if ( strtotime( $next_post['post_date'] ) <= time() ) {
250
		return false;
251
	}
252
253
	/**
254
	 * Use this filter to modify the scheduled post before it gets stored.
255
	 *
256
	 * @param array $next_post          The post data about to be saved.
257
	 * @param array $repeating_schedule Repeating schedule info.
258
	 * @param array $original_post      The original repeating post.
259
	 */
260
	$next_post = apply_filters( 'hm_post_repeat_edit_repeat_post', $next_post, $repeating_schedule, $original_post );
261
262
	// All checks done, get that post scheduled!
263
	$next_post_id = wp_insert_post( wp_slash( $next_post ), true );
264
265
	if ( is_wp_error( $next_post_id ) ) {
266
		return false;
267
	}
268
269
	// Mirror any post_meta
270
	$post_meta = get_post_meta( $original_post['ID'] );
271
272
	if ( $post_meta  ) {
273
274
		// Ignore some internal meta fields
275
		unset( $post_meta['_edit_lock'] );
276
		unset( $post_meta['_edit_last'] );
277
278
		// Don't copy the post repeat meta as only the original post should have that
279
		unset( $post_meta['hm-post-repeat'] );
280
281
		foreach ( $post_meta as $key => $values ) {
282
			foreach ( $values as $value ) {
283
				add_post_meta( $next_post_id, $key, maybe_unserialize( $value ) );
284
			}
285
		}
286
	}
287
288
	// Mirror any term relationships
289
	$taxonomies = get_object_taxonomies( $original_post['post_type'] );
290
291
	foreach ( $taxonomies as $taxonomy ) {
292
		wp_set_object_terms( $next_post_id, wp_list_pluck( wp_get_object_terms( $original_post['ID'], $taxonomy ), 'slug' ), $taxonomy );
293
	}
294
295
	return $next_post_id;
296
297
}
298
299
/**
300
 * The post types the feature is enabled on
301
 *
302
 * By default only posts have the feature enabled but others can be added with the `hm_post_repeat_post_types` filter.
303
 *
304
 * @return array An array of post types
305
 */
306
function repeating_post_types() {
307
308
	/**
309
	 * Enable support for additional post types.
310
	 *
311
	 * @param string[] $post_types Post type slugs.
312
	 */
313
	return apply_filters( 'hm_post_repeat_post_types', array( 'post' ) );
314
315
}
316
317
/**
318
 * All available repeat schedules.
319
 *
320
 * @return array An array of all available repeat schedules
321
 */
322
function get_repeating_schedules() {
323
324
	/**
325
	 * Enable support for additional schedules.
326
	 *
327
	 * @param array[] $schedules Schedule array items.
328
	 */
329
	$schedules = apply_filters( 'hm_post_repeat_schedules', array(
330
		'daily'   => array( 'interval' => '1 day',   'display' => __( 'Daily',   'hm-post-repeat' ) ),
331
		'weekly'  => array( 'interval' => '1 week',  'display' => __( 'Weekly',  'hm-post-repeat' ) ),
332
		'monthly' => array( 'interval' => '1 month', 'display' => __( 'Monthly', 'hm-post-repeat' ) ),
333
	) );
334
335
	foreach ( $schedules as $slug => &$schedule ) {
336
		$schedule['slug'] = $slug;
337
	}
338
339
	return $schedules;
340
341
}
342
343
/**
344
 * Get the repeating schedule of the given post_id.
345
 *
346
 * @param int $post_id The id of the post you want to check.
347
 * @return array|null The schedule to repeat by, or null if invalid.
348
 */
349
function get_repeating_schedule( $post_id ) {
350
351
	if ( ! is_repeating_post( $post_id ) ) {
352
		return;
353
	}
354
355
	$repeating_schedule = get_post_meta( $post_id, 'hm-post-repeat', true );
356
	$schedules = get_repeating_schedules();
357
358
	// Backwards compatibility with 0.3 when we only supported weekly
359
	if ( '1' === $repeating_schedule ) {
360
		$repeating_schedule = 'weekly';
361
	}
362
363
	if ( array_key_exists( $repeating_schedule, $schedules ) ) {
364
		return $schedules[ $repeating_schedule ];
365
	}
366
367
}
368
369
/**
370
 * Check whether a given post_id is a repeating post.
371
 *
372
 * A repeating post is defined as the original post that was set to repeat.
373
 *
374
 * @param int $post_id The ID of the post you want to check.
375
 *
376
 * @return bool Whether the passed post_id is a repeating post or not.
377
 */
378
function is_repeating_post( $post_id ) {
379
380
	// We check $_POST data so that this function works inside a `save_post` hook when the post_meta hasn't yet been saved.
381
	if ( isset( $_POST['hm-post-repeat'] ) && isset( $_POST['ID'] ) && $_POST['ID'] === $post_id ) {
382
		return true;
383
	}
384
385
	// For saved posts - Repeating post has meta key and does NOT have a parent.
386
	$post_parent = get_post_field( 'post_parent', $post_id );
387
388
	if ( ! $post_parent && get_post_meta( $post_id, 'hm-post-repeat', true ) ) {
389
		return true;
390
	}
391
392
	return false;
393
394
}
395
396
/**
397
 * Check whether a given post_id is a repeat post.
398
 *
399
 * A repeat post is defined as any post which is a repeat of the original repeating post.
400
 *
401
 * @param int $post_id The ID of the post you want to check.
402
 *
403
 * @return bool Whether the passed post_id is a repeat post or not.
404
 */
405
function is_repeat_post( $post_id ) {
406
407
	// Repeat post has meta key and has a parent.
408
	$post_parent = get_post_field( 'post_parent', $post_id );
409
410
	if ( $post_parent && get_post_meta( $post_parent, 'hm-post-repeat', true ) ) {
411
		return true;
412
	}
413
414
	return false;
415
416
}
417
418
/**
419
 * Get the next scheduled repeat post
420
 *
421
 * @param int $post_id The id of a repeat or repeating post
422
 * @return Int|Bool Return the ID of the next repeat post_id or false if it can't find one
423
 */
424
function get_next_scheduled_repeat_post( $post_id ) {
425
426
	$post = get_post( get_repeating_post( $post_id ) );
427
428
	$repeat_posts = get_posts( array( 'post_status' => 'future', 'post_parent' => $post->ID ) );
429
430
	if ( isset( $repeat_posts[0] ) ) {
431
	 	return $repeat_posts[0];
432
	}
433
434
	return false;
435
436
}
437
438
/**
439
 * Get the next scheduled repeat post
440
 *
441
 * @param int $post_id The id of a repeat or repeating post
442
 * @return Int|Bool Return the original repeating post_id or false if it can't find it
443
 */
444
function get_repeating_post( $post_id ) {
445
446
	$original_post_id = false;
447
448
	// Are we publishing a repeat post
449
	if ( is_repeat_post( $post_id ) ) {
450
		$original_post_id = get_post( $post_id )->post_parent;
451
	}
452
453
	// Or the original
454
	elseif ( is_repeating_post( $post_id ) ) {
455
		$original_post_id = $post_id;
456
	}
457
458
	return $original_post_id;
459
460
}
461
462
/**
463
 * Adds admin table view link per available repeat type.
464
 * So that only all posts of specific repeat type are displayed.
465
 *
466
 * Added at the end of link list for All | Mine | Published | Scheduled | Drafts
467
 *
468
 * @param array $views An array of available list table views.
469
 *
470
 * @return array Available list of table views with custom added views per repeat type.
471
 */
472
function admin_table_views_links( $views ) {
473
474
	// Add status link for each repeat type.
475
	foreach ( get_available_repeat_types() as $repeat_type => $repeat_desc ) {
476
477
		$url_args = array(
478
			'post_type'      => get_current_screen()->post_type,
479
			'hm-post-repeat' => $repeat_type,
480
		);
481
482
		// Custom WP_Query to get posts count of repeat type.
483
		$repeat_type_query = new \WP_Query( get_repeat_type_query_params( $repeat_type ) );
484
485
		$link_label = sprintf(
486
				'%s <span class="count">(%s)</span>',
487
			esc_html( $repeat_desc ),
488
			esc_html( number_format_i18n( $repeat_type_query->post_count ) )
489
		);
490
491
		/**
492
		 * Add current class to the view link to highlight it when it's selected.
493
		 * NB: do not highlight the view link when displaying subsection of results
494
		 * (i.e. Repeat posts for a specific Repeating post).
495
		 */
496
		$class_html = '';
497
		if (
498
			get_repeat_type_url_param() === $repeat_type &&
499
			! isset( $_GET['post_parent'] )
500
		) {
501
			$class_html = ' class="current"';
502
		}
503
504
		$link_html = sprintf(
505
			'<a href="%s"%s>%s</a>',
506
			esc_url( add_query_arg( $url_args, 'edit.php' ) ),
507
			$class_html, // html - hardcoded, no need to escape.
508
			$link_label  // html - escaped earlier in the code.
509
		);
510
511
		$views[ $repeat_type ] = $link_html;
512
	}
513
514
	return $views;
515
}
516
517
/**
518
 * Customise main admin query to get posts of specified repeat type
519
 * to be displayed in the admin table.
520
 *
521
 * The main admin query only displays requested posts in the main table view!
522
 * It does NOT do the post count for table view links see `admin_table_views_links()` -
523
 * it has got a separate query for the total post count for view links.
524
 *
525
 * @param \WP_Query $wp_query Main admin query.
526
 *
527
 * @return mixed Main admin query with edited params to get posts of specified repeat type.
528
 */
529
function admin_table_repeat_type_posts_query( $wp_query ) {
530
531
	// Stop - if not admin or not main query (there are secondary WP_Query for counting posts for view links, etc).
532
	if ( ! is_admin() || ! $wp_query->is_main_query() ) {
533
		return $wp_query;
534
	}
535
536
	// Get URL query param for repeat type and check it's valid.
537
	$repeat_type = get_repeat_type_url_param();
538
539
	if ( ! $repeat_type || ! is_allowed_repeat_type( $repeat_type ) ) {
540
		return $wp_query;
541
	}
542
543
	// Repeat post display - only displaying Repeat posts for a specific Repeating post.
544
	$post_parent_id = isset( $_GET['post_parent'] ) ? intval( $_GET['post_parent'] ) : 0;
545
546
	// Add WP_Query param depending on displayed repeat type.
547
	foreach ( get_repeat_type_query_params( $repeat_type, $post_parent_id ) as $key => $value ) {
548
		$wp_query->set( $key, $value );
549
	}
550
551
	return $wp_query;
552
}
553
554
/**
555
 * Returns array of custom WP_Query params to get posts of specified repeat type.
556
 * Works for all CPT that support Repeatable Posts.
557
 *
558
 * @param string $repeat_type    Repeat type of posts to get.
559
 * @param int    $post_parent_id Post parent ID - to find Repeat posts for.
560
 *
561
 * @return array Array of custom WP_Query params.
562
 */
563
function get_repeat_type_query_params( $repeat_type, $post_parent_id = 0 ) {
564
565
	$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...
566
567
	// Construct custom query to get posts of specified repeat type.
568
	$query['meta_query'] = array(
569
			array(
570
					'key'     => 'hm-post-repeat',
571
					'compare' => 'EXISTS',
572
			),
573
	);
574
575
	if ( $repeat_type === 'repeat' ) {
576
		$query['post_parent__not_in'] = array( 0 );
577
578
	} elseif ( $repeat_type === 'repeating' ) {
579
		$query['post_parent__in'] = array( 0 );
580
	}
581
582
	// Repeat post display - only displaying Repeat posts for specific Repeating post.
583
	if ( $post_parent_id ) {
584
		$query['post_parent']         = $post_parent_id;
585
		$query['post_parent__not_in'] = '';
586
		$query['post_parent__in']     = '';
587
	}
588
589
	return $query;
590
}
591
592
/**
593
 * Get URL query param for the repeat type of posts being displayed
594
 * in the admin post table.
595
 *
596
 * @return string Sanitized string of repeat type being displayed.
597
 */
598
function get_repeat_type_url_param() {
599
	return isset( $_GET['hm-post-repeat'] ) ? sanitize_text_field( $_GET['hm-post-repeat'] ) : '';
600
}
601
602
/**
603
 * Return available repeat types, i.e. repeating or repeat.
604
 *
605
 * @return array Available repeat types.
606
 */
607
function get_available_repeat_types() {
608
	return array(
609
		'repeating' => __( 'Repeating', 'hm-post-repeat' ),
610
		'repeat'    => __( 'Repeat', 'hm-post-repeat' ),
611
	);
612
}
613
614
/**
615
 * Check if a repeat type is valid.
616
 *
617
 * @param string $repeat_type Repeat type to check.
618
 *
619
 * @return bool True if repeat type is valid,
620
 *              False otherwise.
621
 */
622
function is_allowed_repeat_type( $repeat_type ) {
623
	return in_array( $repeat_type, array_keys( get_available_repeat_types() ) );
624
}
625
626
/**
627
 * Add a row link to view all Repeat posts for the current Repeating post.
628
 *
629
 * The link text is `# repeat posts` where # is the number of corresponding Repeat posts.
630
 *
631
 * The filter is evaluated only for non-hierarchical post types.
632
 *
633
 * @param array   $actions An array of row action links.
634
 * @param WP_Post $post    The post object to display row links for.
635
 *
636
 * @return array An array of row action links with added link to view Repeat posts and there count.
637
 */
638
function admin_table_row_actions_view_repeat_posts( $actions, $post ) {
639
640
	if ( ! is_repeating_post( $post->ID ) ) {
641
		return $actions;
642
	}
643
644
	// Get associated Repeat posts for the current Repeating post.
645
	$url_args = array(
646
		'post_type'      => get_current_screen()->post_type,
647
		'hm-post-repeat' => 'repeat',
648
		'post_parent'    => $post->ID,
649
	);
650
651
	// TODO: I think this is an expensive thing to do per each post. Maybe we can store Repeat post count in meta data?
652
	$repeat_posts_query = new \WP_Query( get_repeat_type_query_params( 'repeat', $post->ID ) );
653
	$repeat_posts_count = $repeat_posts_query->post_count;
654
655
	if ( $repeat_posts_count ) {
656
		$actions['view_repeat'] = sprintf(
657
			'<a href="%s" aria-label="%s">%s</a>',
658
			esc_url( add_query_arg( $url_args, 'edit.php' ) ),
659
			esc_attr( sprintf(
660
				_n(
661
					'View %d repeat post',
662
					'View %d repeat posts',
663
					$repeat_posts_count,
664
					'hm-post-repeat'
665
				),
666
				number_format_i18n( $repeat_posts_count )
667
			) ),
668
			esc_html( sprintf(
669
				_n(
670
					'%d repeat post',
671
					'%d repeat posts',
672
					$repeat_posts_count,
673
					'hm-post-repeat'
674
				),
675
				number_format_i18n( $repeat_posts_count )
676
			) )
677
		);
678
	} else {
679
680
		// 0 Repeat post - display text, not a link.
681
		$actions['view_repeat'] = esc_html( sprintf(
682
			_n(
683
				'%d repeat post',
684
				'%d repeat posts',
685
				$repeat_posts_count,
686
				'hm-post-repeat'
687
			),
688
			number_format_i18n( $repeat_posts_count )
689
		) );
690
	}
691
692
	return $actions;
693
}
694