= 1 && $day <= 7 ) { $days[ $day ] = $day; } } if ( ! $days ) { return null; } ksort( $days ); return recurkit_sanitize_end( $raw, array( 'type' => 'weekly', 'days' => array_values( $days ), ) ); } /** * Adds a valid end (count or until) to $rule, or returns null. Shared with add-on rule types. * * @param array $raw Submitted fields. * @param array $rule Rule so far. * @return array|null */ function recurkit_sanitize_end( array $raw, array $rule ): ?array { $end = isset( $raw['end'] ) && is_string( $raw['end'] ) ? $raw['end'] : ''; if ( 'until' === $end ) { $until = isset( $raw['until'] ) && is_string( $raw['until'] ) ? $raw['until'] : ''; if ( ! recurkit_is_ymd( $until ) ) { return null; } $rule['end'] = 'until'; $rule['until'] = $until; return $rule; } if ( 'count' === $end ) { $count = isset( $raw['count'] ) && is_scalar( $raw['count'] ) ? absint( $raw['count'] ) : 0; if ( $count < 2 ) { return null; } $rule['end'] = 'count'; $rule['count'] = min( $count, recurkit_max_occurrences() ); return $rule; } return null; } /** * Every occurrence date of a series, the event's own date first, sorted, unique, capped. * * @param array $rule Sanitized rule. * @param string $start The event's start date, Y-m-d. * @return string[] */ function recurkit_occurrence_dates( array $rule, string $start ): array { if ( ! recurkit_is_ymd( $start ) ) { return array(); } $dates = ( isset( $rule['type'] ) && 'weekly' === $rule['type'] ) ? recurkit_weekly_dates( $rule, $start ) : array( $start ); $dates = (array) apply_filters( 'recurkit_dates', $dates, $rule, $start ); $dates = array_values( array_unique( array_filter( $dates, 'recurkit_is_ymd' ) ) ); sort( $dates ); return array_slice( $dates, 0, recurkit_max_occurrences() ); } /** * Dates of a weekly rule. Walks day by day from the start; stops at the count, the until date or the cap. * * @param array $rule Weekly rule. * @param string $start Y-m-d. * @return string[] */ function recurkit_weekly_dates( array $rule, string $start ): array { $max = recurkit_end_count( $rule ); $until = 'until' === ( $rule['end'] ?? '' ) ? (string) $rule['until'] : ''; $days = array_map( 'intval', (array) ( $rule['days'] ?? array() ) ); $day = new DateTimeImmutable( $start . ' 00:00:00', new DateTimeZone( 'UTC' ) ); $dates = array( $start ); // 7 * cap days is the furthest a series of `cap` weekly dates can reach. for ( $i = 1; $i <= 7 * recurkit_max_occurrences() && count( $dates ) < $max; $i++ ) { $day = $day->modify( '+1 day' ); $ymd = $day->format( 'Y-m-d' ); if ( '' !== $until && $ymd > $until ) { break; } if ( in_array( (int) $day->format( 'N' ), $days, true ) ) { $dates[] = $ymd; } } return $dates; } /** * How many occurrences a rule allows: its count, else the cap. * * @param array $rule Rule. */ function recurkit_end_count( array $rule ): int { $cap = recurkit_max_occurrences(); return 'count' === ( $rule['end'] ?? '' ) ? min( $cap, max( 1, (int) $rule['count'] ) ) : $cap; } /** * Short human summary of a rule for the Series screen. * * @param array $rule Rule. */ function recurkit_describe_rule( array $rule ): string { $text = ''; if ( 'weekly' === ( $rule['type'] ?? '' ) ) { $names = recurkit_weekday_names(); $days = array(); foreach ( (array) $rule['days'] as $d ) { $days[] = $names[ (int) $d ] ?? ''; } /* translators: %s: comma-separated weekday names. */ $text = sprintf( __( 'Weekly on %s', 'recurkit' ), implode( ', ', array_filter( $days ) ) ); } $text = (string) apply_filters( 'recurkit_describe_rule', $text, $rule ); if ( '' === $text ) { $text = __( 'Custom rule', 'recurkit' ); } if ( 'count' === ( $rule['end'] ?? '' ) ) { $n = (int) $rule['count']; /* translators: 1: rule summary, 2: number of occurrences. */ return sprintf( _n( '%1$s, %2$d time', '%1$s, %2$d times', $n, 'recurkit' ), $text, $n ); } if ( 'until' === ( $rule['end'] ?? '' ) ) { /* translators: 1: rule summary, 2: end date (Y-m-d). */ return sprintf( __( '%1$s, until %2$s', 'recurkit' ), $text, (string) $rule['until'] ); } return $text; } /** * Short weekday names keyed by ISO number (1 = Monday). * * @return string[] */ function recurkit_weekday_names(): array { return array( 1 => __( 'Mon', 'recurkit' ), 2 => __( 'Tue', 'recurkit' ), 3 => __( 'Wed', 'recurkit' ), 4 => __( 'Thu', 'recurkit' ), 5 => __( 'Fri', 'recurkit' ), 6 => __( 'Sat', 'recurkit' ), 7 => __( 'Sun', 'recurkit' ), ); }