array( /* translators: {title} is replaced with the lesson's or course's title: keep it as it is. */ 'subject' => __( 'Invitation: {title}', 'rooster-lms' ), /* translators: {first_name}, {title}, {course} and {when} are replaced with the recipient's first name, the lesson, the course and the date: keep them as they are. */ 'body' => __( "Hello {first_name},\n\nYou are invited to {title} ({course}).\nWhen: {when}\n\nPlease let us know whether you will attend.", 'rooster-lms' ), ); return '' === $lang ? $make() : Switcher::with( $lang, $make ); } public static function template_defaults(): array { $text = self::defaults(); $map = array( '{first_name}' => '{{ recipient.first_name }}', '{title}' => '{{ invitation.title }}', '{course}' => '{{ course.title }}', '{when}' => '{{ invitation.when }}', '{rsvp_until}' => '{{ invitation.rsvp_until }}', '{site}' => '{{ site.name }}', ); $paras = preg_split( '/\n{2,}/', trim( str_replace( "\r", '', $text['body'] ) ) ); $paras = is_array( $paras ) ? $paras : array( $text['body'] ); if ( count( $paras ) > 1 && str_contains( $paras[0], '{first_name}' ) ) { array_shift( $paras ); } $html = array(); foreach ( $paras as $para ) { $html[] = strtr( nl2br( esc_html( trim( $para ) ), false ), $map ); } return array( 'subject' => strtr( $text['subject'], $map ), 'body' => implode( '

', $html ), ); } public static function for_language( Invitation $inv, string $lang ): array { if ( '' !== $inv->subject || '' !== $inv->body ) { $base = self::defaults( $lang ); $own = array( 'subject' => '' !== $inv->subject ? $inv->subject : $base['subject'], 'body' => '' !== $inv->body ? $inv->body : $base['body'], ); $stored = '' !== $inv->lang ? $inv->lang : Names::default_language(); $plugin = Strings::via_plugin( TextObject::INVITATION, 'body' ) && Providers::current()->supports_strings(); $is_other = $lang !== $stored; if ( $is_other && $plugin ) { $found = Services::strings()->translate_fields( TextObject::INVITATION, $inv->id, array( 'title' => $own['subject'], 'body' => $own['body'], ), $lang ); return array( 'subject' => (string) $found['title'], 'body' => (string) $found['body'], ); } return $own; } $text = self::defaults( $lang ); $filtered = apply_filters( 'rooster_lms_invitation_text', $text, $inv->id, $inv->template_id, $lang ); if ( is_array( $filtered ) && is_string( $filtered['subject'] ?? null ) && is_string( $filtered['body'] ?? null ) && '' !== trim( $filtered['subject'] ) ) { $out = array( 'subject' => $filtered['subject'], 'body' => $filtered['body'], ); if ( (int) ( $filtered['template_id'] ?? 0 ) > 0 ) { $out['template_id'] = (int) $filtered['template_id']; $out['format'] = (int) ( $filtered['format'] ?? 2 ); } return $out; } return $text; } public static function register_strings( Invitation $inv ): void { if ( ( '' === $inv->subject && '' === $inv->body ) || ! Providers::current()->supports_strings() ) { return; } Services::strings()->register( TextObject::INVITATION, $inv->id, $inv->subject, 'title' ); Services::strings()->register( TextObject::INVITATION, $inv->id, $inv->body, 'body' ); } public static function facts( Invitation $inv, string $lang ): array { $key = $inv->id . ':' . $inv->occurrence_id . ':' . $lang; if ( isset( self::$facts[ $key ] ) ) { return self::$facts[ $key ]; } if ( $inv->is_cohort_only() ) { $cohort = Services::cohort_repo()->get( $inv->target_cohort_id ); $title = null === $cohort ? '' : $cohort->name; $course = null === $cohort ? '' : (string) ( Services::org_repo()->names( array( $cohort->org_id ), $lang )[ $cohort->org_id ] ?? '' ); } else { $course = (string) ( Services::posts()->titles( ObjectType::COURSE, array( $inv->course_id ), $lang )[ $inv->course_id ]['title'] ?? '' ); $title = $inv->unit_id > 0 ? (string) ( Services::posts()->titles( ObjectType::UNIT, array( $inv->unit_id ), $lang )[ $inv->unit_id ]['title'] ?? $course ) : $course; } $occurrence = $inv->occurrence_id > 0 ? Services::live_session_repo()->occurrence( $inv->occurrence_id ) : null; $session = null === $occurrence ? null : Services::live_session_repo()->get( $occurrence->session_id ); $when = ''; if ( null !== $occurrence && null !== $session ) { $when = Switcher::with( $lang, static fn(): string => LiveMarkup::when( $session, $occurrence->start() ) ); } self::$facts[ $key ] = array( 'title' => $title, 'course' => $course, 'when' => $when, 'start' => null === $occurrence ? 0 : $occurrence->start()->getTimestamp(), 'end' => null === $occurrence ? 0 : $occurrence->end()->getTimestamp(), 'timezone' => null === $session ? '' : $session->timezone, 'session' => $session, 'occurrence' => $occurrence, ); return self::$facts[ $key ]; } public static function forget(): void { self::$facts = array(); } public static function values( Invitation $inv, string $first_name, string $lang ): array { $facts = self::facts( $inv, $lang ); $until = RsvpService::closes_at( $inv ); return array( '{first_name}' => $first_name, '{title}' => $facts['title'], '{course}' => $facts['course'], '{when}' => '' !== $facts['when'] ? $facts['when'] : __( 'Date to be announced', 'rooster-lms' ), '{rsvp_until}' => '' === $until ? '' : (string) wp_date( (string) get_option( 'date_format', 'j F Y' ) . ' ' . (string) get_option( 'time_format', 'H:i' ), (int) strtotime( $until . ' UTC' ) ), '{site}' => wp_specialchars_decode( (string) get_bloginfo( 'name' ), ENT_QUOTES ), ); } public static function fill( string $text, array $values ): string { $out = strtr( $text, $values ); return '' === ( $values['{first_name}'] ?? '' ) ? (string) preg_replace( '/[ \t]+([,!.])/u', '$1', $out ) : $out; } public static function clean( $subject, $body ): array { return array( 'subject' => mb_substr( trim( sanitize_text_field( is_string( $subject ) ? $subject : '' ) ), 0, self::SUBJECT_MAX ), 'body' => mb_substr( trim( str_replace( "\r", '', sanitize_textarea_field( is_string( $body ) ? $body : '' ) ) ), 0, self::BODY_MAX ), ); } }