isset( $attributes['coursePost'] ) ? max( 0, (int) $attributes['coursePost'] ) : 0 );
}
public static function render( array $attributes, string $content = '', ?\WP_Block $block = null ): string {
unset( $content );
$course = Context::course_id( self::attributes( $attributes ), $block );
$user = get_current_user_id();
if ( $course <= 0 || Services::online_tests()->is_course( $course ) ) {
return '';
}
if ( ! empty( $attributes['invite'] ) && ( $user <= 0 || in_array( Services::reviews()->refusal( $user, $course ), array( 'login', 'not_enrolled' ), true ) ) ) {
return '
' . esc_html__( 'Enrol in the course to leave a review.', 'rooster-lms' ) . '
';
}
if ( $user <= 0 ) {
return '';
}
$inner = self::form( $course, $user, Services::reviews()->of_user( $user, $course ), true );
return '' === $inner ? '' : ' 'rooster-lms-review' ) ) . '>' . $inner . '
';
}
public static function form( int $course, int $user, ?array $review, bool $heading ): string {
$why = Services::reviews()->refusal( $user, $course );
if ( null === $review && '' !== $why ) {
$line = match ( $why ) {
'not_completed' => __( 'You can review this course once you have completed it.', 'rooster-lms' ),
/* translators: %s: a percentage. */
'not_enough_progress' => sprintf( __( 'You can review this course once you have completed %s of it.', 'rooster-lms' ), Format::percent( (int) CommunitySettings::get( 'reviews_min_percent' ) ) ),
default => '',
};
return '' === $line ? '' : '' . esc_html( $line ) . '
';
}
Front::enqueue( self::NAME );
$id = 'rl-review-' . $course;
$rating = null === $review ? 0 : (int) $review['rating'];
$config = Front::config(
array(
'course' => $course,
'i18n' => self::texts(),
)
);
$html = '';
}
$html .= '' . esc_html__( 'Your rating', 'rooster-lms' ) . ' ';
for ( $i = 1; $i <= 5; $i++ ) {
$html .= ' '
/* translators: %s: number of stars (1 to 5). */
. '★ ' . esc_html( sprintf( _n( '%s star', '%s stars', $i, 'rooster-lms' ), Format::number( $i ) ) ) . ' ';
}
$html .= ' ';
$html .= '' . esc_html__( 'Title', 'rooster-lms' ) . ' '
. '
';
$html .= '' . esc_html__( 'Your review', 'rooster-lms' ) . ' '
. '
';
if ( true === CommunitySettings::get( 'reviews_approval' ) ) {
$html .= '' . esc_html__( 'Reviews are published after the course staff approve them.', 'rooster-lms' ) . '
';
}
$html .= '' . Ui::button( null === $review ? __( 'Publish review', 'rooster-lms' ) : __( 'Update review', 'rooster-lms' ), 'primary', array( 'type' => 'submit' ) ) . '
'
. '
';
return $html;
}
public static function status( array $review ): string {
$state = (int) $review['state'];
$reply = null === ( $review['reply'] ?? null ) ? '' : trim( wp_strip_all_tags( (string) $review['reply'] ) );
if ( \RoosterLMS\Community\ReviewState::APPROVED->value === $state ) {
$html = Ui::notice( __( 'Your review is published.', 'rooster-lms' ), 'success' );
if ( '' !== $reply ) {
$html .= '' . esc_html__( 'Reply from the course staff:', 'rooster-lms' ) . ' ' . esc_html( $reply ) . '
';
}
return $html;
}
if ( \RoosterLMS\Community\ReviewState::REJECTED->value === $state ) {
$html = Ui::notice( __( 'Your review was not published. You can change it and send it again.', 'rooster-lms' ), 'warning' );
if ( '' !== $reply ) {
$html .= '' . esc_html__( 'Reason:', 'rooster-lms' ) . ' ' . esc_html( $reply ) . '
';
}
return $html;
}
return Ui::notice( __( 'Your review is waiting for approval by the course staff.', 'rooster-lms' ), 'info' );
}
private static function read_only( ?array $review ): string {
if ( null === $review ) {
return '';
}
return '';
}
public static function account( $sections ) {
if ( ! is_array( $sections ) ) {
return $sections;
}
$sections[] = new Section(
self::SECTION,
__( 'My reviews', 'rooster-lms' ),
'progress',
'learner',
30,
static fn( AccountViewer $v ): bool => $v->enrolments > 0,
self::account_render( ... ),
null,
'pencil'
);
return $sections;
}
public static function account_render( AccountViewer $viewer ): string {
$user = $viewer->id();
$reviews = self::reviews_of( $user );
$courses = array_values( array_unique( array_merge( array_keys( $reviews ), self::reviewable( $user ) ) ) );
if ( array() === $courses ) {
return Ui::empty_state( __( 'No reviews yet', 'rooster-lms' ), __( 'When you complete a course, you can review it here.', 'rooster-lms' ) );
}
$titles = Services::posts()->titles( ObjectType::COURSE, $courses );
\RoosterLMS\Community\CourseFacts::prime( $courses );
Services::enrolment_repo()->for_user( $user, $courses );
$html = '';
}
public static function reviews_of( int $user ): array {
$out = array();
foreach ( Db::rows( 'SELECT * FROM %i WHERE user_id = %d AND state <> %d ORDER BY updated_at DESC LIMIT %d', Db::table( 'course_reviews' ), $user, \RoosterLMS\Community\ReviewState::TRASHED->value, self::ACCOUNT_LIMIT ) as $row ) {
$out[ (int) $row['course_id'] ] = $row;
}
return $out;
}
public static function reviewable( int $user ): array {
$site = true === CommunitySettings::get( 'reviews_enabled' );
$rule = (string) CommunitySettings::get( 'reviews_eligibility' );
global $wpdb;
$cond = match ( $rule ) {
'enrolled' => SqlPart::of( '1=1' ),
'progress' => SqlPart::of( '( p.status = %d OR p.percent >= %d )', ProgressStatus::COMPLETED->value, (int) CommunitySettings::get( 'reviews_min_percent' ) ),
default => SqlPart::of( 'p.status = %d', ProgressStatus::COMPLETED->value ),
};
$on = $site ? SqlPart::of( 'c.reviews_mode <> %d', 1 ) : SqlPart::of( 'c.reviews_mode = %d', 2 );
$rows = Db::col(
SqlPart::of(
'SELECT e.course_id FROM %i e JOIN %i c ON c.id = e.course_id AND c.state = 1 LEFT JOIN %i p ON p.user_id = e.user_id AND p.course_id = e.course_id AND p.cycle = e.cycle WHERE e.user_id = %d AND e.status = %d AND e.course_id <> %d AND ',
Db::table( 'enrolments' ),
Db::table( 'courses' ),
Db::table( 'progress' ),
$user,
EnrolmentStatus::ACTIVE->value,
Services::online_tests()->course_id()
)->add( $on )->add( ' AND ' )->add( 'enrolled' === $rule ? SqlPart::of( '1=1' ) : SqlPart::of( 'p.user_id IS NOT NULL AND ' )->add( $cond ) )->add( SqlPart::of( ' ORDER BY e.enrolled_at DESC LIMIT %d', self::ACCOUNT_LIMIT ) )
);
return array_values( array_map( 'intval', $rows ) );
}
public static function texts(): array {
return array(
'rating' => __( 'Choose a rating from 1 to 5 stars.', 'rooster-lms' ),
'saved' => __( 'Thank you. Your review is saved.', 'rooster-lms' ),
'pending' => __( 'Your review is waiting for approval by the course staff.', 'rooster-lms' ),
'approved' => __( 'Your review is published.', 'rooster-lms' ),
'rejected' => __( 'Your review was not published. You can change it and send it again.', 'rooster-lms' ),
'update' => __( 'Update review', 'rooster-lms' ),
'failed' => __( 'Something went wrong. Please try again.', 'rooster-lms' ),
);
}
}