ID : absint( $GLOBALS['post_ID'] ?? 0 );
if ( $post_id <= 0 || Services::course_repo()->id_for_post( $post_id ) <= 0 || ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
add_meta_box( self::BOX, __( 'Invitations and RSVP', 'rooster-lms' ), array( $this, 'render_box' ), PostTypes::COURSE, 'normal', 'low' );
}
public function render_box( $post ): void {
$course_id = $post instanceof \WP_Post ? Services::course_repo()->id_for_post( (int) $post->ID ) : 0;
$html = self::html( $course_id, 0, true );
if ( '' !== $html ) {
$html .= '
' . esc_html__( 'All invitations', 'rooster-lms' ) . '
';
}
echo wp_kses( $html, Kses::admin() );
}
public static function enqueue(): void {
wp_enqueue_script( self::SCRIPT, plugins_url( 'assets/ui/invitations.js', ROOSTER_LMS_FILE ), array( Assets::ask() ), ROOSTER_LMS_VERSION, true );
Assets::enqueue_table( 'rest' );
}
public static function html( int $course_id, int $unit_id, bool $admin, array $opts = array() ): string {
if ( $course_id <= 0 || ! InvitationService::may_manage( $course_id, get_current_user_id() ) ) {
return '';
}
return self::panel(
array(
'course' => $course_id,
'unit' => $unit_id,
) + self::options( $opts ),
$admin,
trim(
( $unit_id > 0
? __( 'Invite people to this lesson with personal "Yes / No" buttons: people who asked to be notified, earlier learners who agreed to hear from us, an organisation, a Newsletter list or a CSV list. Everyone is invited once, in their own language, with a one-click unsubscribe.', 'rooster-lms' )
: __( 'Invite people to this course with personal "Yes / No" buttons: people who asked to be notified, earlier learners who agreed to hear from us, an organisation, a Newsletter list or a CSV list. Everyone is invited once, in their own language, with a one-click unsubscribe; answers close at the deadline you set.', 'rooster-lms' ) )
. ' ' . \RoosterLMS\Newsletter\NewsletterModule::panel_note()
),
true,
$admin || ! empty( $opts['open'] ) || ! empty( $opts['compose'] )
);
}
private static function options( array $opts ): array {
$out = array();
if ( ! empty( $opts['compose'] ) ) {
$out['compose'] = true;
}
foreach ( array( 'occurrence', 'open', 'edit' ) as $key ) {
if ( (int) ( $opts[ $key ] ?? 0 ) > 0 ) {
$out[ $key ] = (int) $opts[ $key ];
}
}
if ( 'rooster' === ( $opts['buttons'] ?? '' ) ) {
$out['buttons'] = 'rooster';
}
return $out;
}
public static function cohort_html( int $cohort_id, bool $compose = false, array $opts = array() ): string {
$cohort = $cohort_id > 0 ? Services::cohort_repo()->get( $cohort_id ) : null;
if ( null === $cohort || ! InvitationService::may_manage( 0, get_current_user_id(), $cohort->id ) ) {
return '';
}
unset( $opts['compose'], $opts['occurrence'] );
return self::panel(
array(
'course' => 0,
'unit' => 0,
'cohort' => $cohort->id,
'cohortName' => $cohort->name,
'compose' => $compose && $cohort->is_active(),
) + self::options( $opts ),
true,
__( 'Invite people to join this cohort with personal "Yes / No" buttons: the members of a cohort or of part of the organisation, the organisation, or a CSV list. A "yes" makes the person a learner of the organisation (when they are not one yet) and a member of this cohort; the funnel shows who was invited, who accepted and who joined.', 'rooster-lms' ),
$cohort->is_active(),
true,
\RoosterLMS\Orgs\CohortWords::panel_texts( $cohort->org_id )
);
}
private static function panel( array $target, bool $admin, string $help, bool $offer, bool $open, array $texts = array() ): string {
self::enqueue();
$config = array(
'rest' => esc_url_raw( rest_url( 'rooster-lms/v1/' ) ),
'nonce' => wp_create_nonce( 'wp_rest' ),
'csv' => \RoosterLMS\Rest\DownloadRoute::url( 'invitees', '/invitations/' . \RoosterLMS\Rest\DownloadRoute::ID_PLACEHOLDER . '/invitees', array( 'format' => 'csv' ) ),
'admin' => $admin,
'locale' => str_replace( '_', '-', determine_locale() ),
'i18n' => $texts + self::strings(),
) + $target;
$rooster = ! $admin || 'rooster' === ( $target['buttons'] ?? '' );
$button = $rooster ? \RoosterLMS\UI\Ui::button_class( 'secondary', array( 'size' => 'sm' ) ) : 'button';
$html = '';
$html .= '' . esc_html__( 'Invitations and RSVP', 'rooster-lms' ) . '
';
$html .= '' . esc_html( $help ) . '
';
$html .= '';
if ( $offer ) {
$html .= '';
}
$html .= '';
$html .= '';
$html .= '';
return $html . ' ';
}
private static function strings(): array {
return array(
'loading' => __( 'Loading…', 'rooster-lms' ),
'none' => __( 'No invitation yet.', 'rooster-lms' ),
'failed' => __( 'That did not work. Try again.', 'rooster-lms' ),
'saved' => __( 'Saved.', 'rooster-lms' ),
'subject' => __( 'Subject', 'rooster-lms' ),
'body' => __( 'Message', 'rooster-lms' ),
'placeholders' => __( 'You can use these placeholders:', 'rooster-lms' ),
'defaultText' => __( 'Leave empty to use the default wording, in each person\'s language.', 'rooster-lms' ),
'answers' => __( 'Answers offered', 'rooster-lms' ),
'yes' => __( 'Yes', 'rooster-lms' ),
'no' => __( 'No', 'rooster-lms' ),
'maybe' => __( 'Maybe', 'rooster-lms' ),
'noAnswer' => __( 'No answer', 'rooster-lms' ),
/* translators: %d: hours. */
'until' => sprintf( __( 'Answers close (UTC; empty = %d hours after the lesson)', 'rooster-lms' ), RsvpService::close_hours() ),
'yesAction' => __( 'A "yes"', 'rooster-lms' ),
'yesNone' => __( 'is counted only', 'rooster-lms' ),
'yesRegister' => __( 'offers guests an account', 'rooster-lms' ),
'yesEnrol' => __( 'enrols the person', 'rooster-lms' ),
'places' => __( 'Places (0 = the lesson\'s)', 'rooster-lms' ),
'attachments' => __( 'Programme: media library file IDs, separated by commas', 'rooster-lms' ),
'save' => __( 'Save', 'rooster-lms' ),
'close' => __( 'Close', 'rooster-lms' ),
'edit' => __( 'Edit', 'rooster-lms' ),
'addPeople' => __( 'Add people', 'rooster-lms' ),
'source' => __( 'From', 'rooster-lms' ),
'organisation' => __( 'Organisation', 'rooster-lms' ),
'list' => __( 'List', 'rooster-lms' ),
'csvFile' => __( 'CSV file (e-mail, first name, last name, language)', 'rooster-lms' ),
'csvConsent' => __( 'The people on this list agreed to get invitations from us.', 'rooster-lms' ),
'csvMax' => (string) InvitationsController::CSV_MAX_BYTES,
'csvHint' => Upload::hint( 'CSV', (string) size_format( InvitationsController::CSV_MAX_BYTES ) ),
'csvType' => Upload::type_message( 'CSV' ),
'csvSize' => Upload::size_message( (string) size_format( InvitationsController::CSV_MAX_BYTES ) ),
'check' => __( 'Check', 'rooster-lms' ),
'add' => __( 'Add', 'rooster-lms' ),
/* translators: 1: number found, 2: number new. */
'checked' => __( '%1$s found, %2$s new.', 'rooster-lms' ),
/* translators: %s: number of people. */
'added' => __( '%s added.', 'rooster-lms' ),
'skipInvalid' => __( 'invalid address', 'rooster-lms' ),
'skipDuplicate' => __( 'duplicate', 'rooster-lms' ),
'skipAlready' => __( 'already invited to this lesson', 'rooster-lms' ),
'skipSuppressed' => __( 'does not want our e-mails', 'rooster-lms' ),
/* translators: %s: line number. */
'line' => __( 'line %s', 'rooster-lms' ),
'preview' => __( 'Preview', 'rooster-lms' ),
'send' => __( 'Send now', 'rooster-lms' ),
/* translators: %s: number of people. */
'confirm' => __( 'Send this invitation now to %s people?', 'rooster-lms' ),
'sending' => __( 'Sending: the e-mails go out in the next minutes.', 'rooster-lms' ),
'report' => __( 'Answers', 'rooster-lms' ),
'export' => __( 'Export CSV', 'rooster-lms' ),
'cancel' => __( 'Stop invitation', 'rooster-lms' ),
'confirmCancel' => __( 'Stop this invitation? Nothing more is sent and its links stop working.', 'rooster-lms' ),
'dismiss' => __( 'Cancel', 'rooster-lms' ),
'toSend' => __( 'will get it now', 'rooster-lms' ),
'sentCurrent' => __( 'already have it', 'rooster-lms' ),
'noConsent' => __( 'no consent', 'rooster-lms' ),
'unsubscribed' => __( 'unsubscribed', 'rooster-lms' ),
'weeklyCap' => __( 'had enough e-mails this week', 'rooster-lms' ),
'invited' => __( 'invited', 'rooster-lms' ),
'announcement' => __( 'E-mail to earlier learners', 'rooster-lms' ),
'stateDraft' => __( 'Draft', 'rooster-lms' ),
'stateScheduled' => __( 'Scheduled', 'rooster-lms' ),
'stateSending' => __( 'Sending', 'rooster-lms' ),
'stateSent' => __( 'Sent', 'rooster-lms' ),
'stateCancelled' => __( 'Stopped', 'rooster-lms' ),
'earlier' => __( 'Earlier learners', 'rooster-lms' ),
'interest' => __( 'People who asked to be notified', 'rooster-lms' ),
'csv' => __( 'CSV list', 'rooster-lms' ),
'newsletter' => __( 'Newsletter list', 'rooster-lms' ),
'yesJoin' => __( 'joins a cohort', 'rooster-lms' ),
'targetCohort' => __( 'Cohort a "yes" joins', 'rooster-lms' ),
'funnel' => __( 'From invitation to outcome', 'rooster-lms' ),
/* translators: %s: number of people invited. */
'funnelInvited' => __( 'Invited: %s', 'rooster-lms' ),
/* translators: 1: number of people who accepted, 2: their share of the people invited, e.g. 40%. */
'funnelAccepted' => __( 'Accepted: %1$s (%2$s)', 'rooster-lms' ),
/* translators: 1: number of people who attended, 2: their share of the people invited, e.g. 40%. */
'funnelAttended' => __( 'Attended: %1$s (%2$s)', 'rooster-lms' ),
/* translators: 1: number of people who enrolled, 2: their share of the people invited, e.g. 40%. */
'funnelEnrolled' => __( 'Enrolled: %1$s (%2$s)', 'rooster-lms' ),
/* translators: 1: number of people who joined the cohort, 2: their share of the people invited, e.g. 40%. */
'funnelJoined' => __( 'Joined: %1$s (%2$s)', 'rooster-lms' ),
'untilCohort' => __( 'Answers close (UTC)', 'rooster-lms' ),
'placesCohort' => __( 'Places (0 = no limit)', 'rooster-lms' ),
/* translators: %s: cohort name. */
'joinsCohort' => __( 'A "yes" joins the cohort %s.', 'rooster-lms' ),
);
}
}