<?php
/**
* Frontend
*
* Handles the frontend display.
*
* @package Sensei\Frontend
* @since 1.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Sensei Frontend Class
*
* All functionality pertaining to the frontend of Sensei.
*
* @package Core
* @author Automattic
*
* @since 1.0.0
*/
class Sensei_Frontend {
/**
* Messages to display to the user.
*
* @var string $messages
*/
public $messages;
/**
* TODO: Eliminate this.
*
* @var stdClass $data
*/
public $data;
/**
* List of allowed HTML elements.
*
* @var array $allowed_html
*/
public $allowed_html;
const VIDEO_EMBED_CLASS = 'sensei-video-embed';
/**
* Constructor.
*
* @since 1.0.0
*/
public function __construct() {
$this->allowed_html = array(
'embed' => array(),
'iframe' => array(
'width' => array(),
'height' => array(),
'src' => array(),
'frameborder' => array(),
'allowfullscreen' => array(),
),
'video' => Sensei_Wp_Kses::get_video_html_tag_allowed_attributes(),
);
// Template output actions.
add_action( 'sensei_before_main_content', array( $this, 'sensei_output_content_wrapper' ), 10 );
add_action( 'sensei_after_main_content', array( $this, 'sensei_output_content_wrapper_end' ), 10 );
add_action( 'sensei_lesson_archive_lesson_title', array( $this, 'sensei_lesson_archive_lesson_title' ), 10 );
add_action( 'wp', array( $this, 'sensei_complete_lesson' ), 10 );
add_action( 'wp_head', array( $this, 'sensei_complete_course' ), 10 );
add_action( 'sensei_course_status_updated', array( $this, 'redirect_to_course_completed_page' ), 1000, 3 );
add_action( 'sensei_frontend_messages', array( $this, 'sensei_frontend_messages' ) );
add_action( 'sensei_lesson_video', array( $this, 'sensei_lesson_video' ), 10, 1 );
add_action( 'sensei_complete_lesson_button', array( $this, 'sensei_complete_lesson_button' ) );
add_action( 'sensei_reset_lesson_button', array( $this, 'sensei_reset_lesson_button' ) );
add_action( 'sensei_course_archive_meta', array( $this, 'sensei_course_archive_meta' ) );
add_action( 'sensei_lesson_meta', array( $this, 'sensei_lesson_meta' ), 10 );
add_action( 'wp', array( $this, 'sensei_course_start' ), 10 );
add_filter( 'wp_login_failed', array( $this, 'sensei_login_fail_redirect' ), 10 );
add_filter( 'init', array( $this, 'sensei_handle_login_request' ), 10 );
add_action( 'init', array( $this, 'sensei_process_registration' ), 2 );
add_action( 'sensei_pagination', array( $this, 'sensei_breadcrumb' ), 80, 1 );
// Fix pagination for course archive pages when filtering by course type.
add_filter( 'pre_get_posts', array( $this, 'sensei_course_archive_pagination' ) );
// Scripts and Styles.
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_styles' ) );
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
// Custom Menu Item filters.
add_filter( 'wp_setup_nav_menu_item', array( $this, 'sensei_setup_nav_menu_item' ) );
add_filter( 'wp_nav_menu_objects', array( $this, 'sensei_wp_nav_menu_objects' ) );
// Search Results filters.
add_filter( 'post_class', array( $this, 'sensei_search_results_classes' ), 10 );
// Only show course & lesson excerpts in search results.
add_filter( 'the_content', array( $this, 'sensei_search_results_excerpt' ) );
// Lesson tags.
add_action( 'sensei_lesson_meta_extra', array( $this, 'lesson_tags_display' ), 10, 1 );
add_action( 'pre_get_posts', array( $this, 'lesson_tag_archive_filter' ), 10, 1 );
add_filter( 'sensei_lessons_archive_text', array( $this, 'lesson_tag_archive_header' ) );
add_action( 'sensei_loop_lesson_inside_before', array( $this, 'lesson_tag_archive_description' ), 11 );
// Hide Sensei activity comments from lesson and course pages.
add_filter( 'wp_list_comments_args', array( $this, 'hide_sensei_activity' ) );
new Sensei_Guest_User();
new Sensei_Preview_User();
}
/**
* Graceful fallback for course and lesson variables on Frontend object.
*
* @param string $key Key to get.
* @since 1.7.3
* @return array|mixed
*/
public function __get( $key ) {
if ( 'lesson' == $key || 'course' == $key ) {
if ( WP_DEBUG ) {
trigger_error( sprintf( 'Sensei()->frontend->%1$s has been <strong>deprecated</strong> since version %2$s! Please use Sensei()->%1$s to access the instance.', esc_html( $key ), '1.7.3' ) );
}
return Sensei()->$key;
}
return null;
}
/**
* Enqueue frontend JavaScripts.
*
* @since 1.0.0
* @return void
*/
public function enqueue_scripts() {
$disable_js = Sensei_Utils::get_setting_as_flag( 'js_disable', 'sensei_settings_js_disable' );
if ( ! $disable_js ) {
// Course Archive javascript.
if ( is_post_type_archive( 'course' ) ) {
Sensei()->assets->register( 'sensei-course-archive-js', 'js/frontend/course-archive.js', [ 'jquery' ], true );
wp_enqueue_script( 'sensei-course-archive-js' );
}
Sensei()->assets->register( 'sensei-quiz-progress', 'blocks/progress-bar.js' );
Sensei()->assets->register( 'sensei-stop-double-submission', 'js/stop-double-submission.js', [], true );
Sensei()->assets->register( Sensei()->token . '-user-dashboard', 'js/user-dashboard.js', [ 'jquery-ui-tabs' ], true );
/**
* Fires when the frontend scripts are being enqueued.
* Allow additional scripts to be loaded.
*
* @hook sensei_additional_scripts
*/
do_action( 'sensei_additional_scripts' );
}
}
/**
* Enqueue frontend CSS files.
*
* @since 1.0.0
* @return void
*/
public function enqueue_styles() {
global $post;
$is_learning_mode_enabled = false;
$post_type = get_post_type( $post );
$disable_styles = Sensei_Utils::get_setting_as_flag( 'styles_disable', 'sensei_disable_styles' );
// Don't load frontend.css in Learning Mode as it's not needed and negatively impacts button styles.
if ( 'lesson' === $post_type ) {
$course_id = intval( get_post_meta( $post->ID, '_lesson_course', true ) );
$is_learning_mode_enabled = Sensei_Course_Theme_Option::has_learning_mode_enabled( $course_id );
}
Sensei()->assets->enqueue( 'pages-frontend', 'css/pages-frontend.css' );
if ( $disable_styles || $is_learning_mode_enabled ) {
return;
}
Sensei()->assets->enqueue( Sensei()->token . '-frontend', 'css/frontend.css', [], 'screen' );
/**
* Fires when the frontend styles are being enqueued.
* Allow additional stylesheets to be loaded.
*
* @hook sensei_additional_styles
*/
do_action( 'sensei_additional_styles' );
}
/**
* Output the start of the content wrapper.
*
* @access public
* @return void
*/
function sensei_output_content_wrapper() {
// backwards compatibility check for old location under the wrappers directory of the active theme.
$backwards_compatible_wrapper_location = array(
Sensei()->template_url . 'wrappers/wrapper-start.php',
'wrappers/wrapper-start.php',
);
$template = locate_template( $backwards_compatible_wrapper_location );
if ( ! empty( $template ) ) {
Sensei_Templates::get_template( 'wrappers/wrapper-start.php' );
return;
}
Sensei_Templates::get_template( 'globals/wrapper-start.php' );
}
/**
* Output the end of the content wrapper.
*
* @access public
* @return void
*/
function sensei_output_content_wrapper_end() {
// backwards compatibility check for old location under the wrappers directory of the active theme.
$backwards_compatible_wrapper_location = array(
Sensei()->template_url . 'wrappers/wrapper-end.php',
'wrappers/wrapper-end.php',
);
$backwards_compatible_template = locate_template( $backwards_compatible_wrapper_location );
if ( ! empty( $backwards_compatible_template ) ) {
Sensei_Templates::get_template( 'wrappers/wrapper-end.php' );
return;
}
Sensei_Templates::get_template( 'globals/wrapper-end.php' );
}
/**
* Load content pagination template.
*
* @access public
* @return void
*/
public static function load_content_pagination() {
if ( is_singular( 'course' ) ) {
// backwards compatibility check for old location under the wrappers directory of the active theme.
$template = locate_template( array( Sensei()->template_url . 'wrappers/pagination-posts.php' ) );
if ( ! empty( $template ) ) {
Sensei_Templates::get_template( 'wrappers/pagination-posts.php' );
return;
}
Sensei_Templates::get_template( 'globals/pagination-posts.php' );
} elseif ( is_tax( 'module' ) || is_singular( 'lesson' ) ) {
// Backwards compatibility check for old location under the wrappers directory of the active theme.
$template = locate_template( array( Sensei()->template_url . 'wrappers/pagination-lesson.php' ) );
if ( ! empty( $template ) ) {
Sensei_Templates::get_template( 'wrappers/pagination-lesson.php' );
return;
}
Sensei_Templates::get_template( 'globals/pagination-lesson.php' );
} elseif ( is_singular( 'quiz' ) ) {
// backwards compatibility check for old location under the wrappers directory of the active theme.
$template = locate_template( array( Sensei()->template_url . 'wrappers/pagination-quiz.php' ) );
if ( ! empty( $template ) ) {
Sensei_Templates::get_template( 'wrappers/pagination-quiz.php' );
return;
}
Sensei_Templates::get_template( 'globals/pagination-quiz.php' );
} elseif ( Sensei_Utils::is_course_results_page() ) {
// Pagination content for legacy course results page here.
return;
} else {
// backwards compatibility check for old location under the wrappers directory of the active theme.
$template = locate_template( array( Sensei()->template_url . 'wrappers/pagination.php' ) );
if ( ! empty( $template ) ) {
Sensei_Templates::get_template( 'wrappers/pagination.php' );
return;
}
Sensei_Templates::get_template( 'globals/pagination.php' );
}
}
/**
* Outputs comments for the specified pages.
*
* @deprecated
* @return void
*/
function sensei_output_comments() {
Sensei_Lesson::output_comments();
}
/**
* Generates URLs for custom menu items.
*
* @access public
* @param object $item Menu item.
* @return object $item Menu item.
*/
public function sensei_setup_nav_menu_item( $item ) {
global $pagenow, $wp_rewrite;
if ( 'nav-menus.php' != $pagenow && ! defined( 'DOING_AJAX' ) && isset( $item->url ) && 'custom' == $item->type ) {
// Set up Sensei menu links.
$my_account_page_id = Sensei()->settings->get_my_courses_page_id();
$course_page_url = Sensei_Course::get_courses_page_url();
$lesson_archive_url = get_post_type_archive_link( 'lesson' );
$my_courses_url = get_permalink( $my_account_page_id );
$my_messages_url = get_post_type_archive_link( 'sensei_message' );
switch ( $item->url ) {
case '#senseicourses':
$item->url = $course_page_url;
break;
case '#senseilessons':
$item->url = $lesson_archive_url;
break;
case '#senseimycourses':
$item->url = $my_courses_url;
break;
case '#senseimymessages':
$item->url = $my_messages_url;
// if no archive link exist for sensei_message
// set it back to the place holder.
if ( ! $item->url ) {
$item->url = '#senseimymessages';
}
break;
case '#senseilearnerprofile':
$item->url = esc_url( Sensei()->learner_profiles->get_permalink() );
break;
case '#senseiloginlogout':
$logout_url = wp_logout_url( home_url() );
// Login link links to the My Courses page, to avoid the WP dashboard.
$login_url = $my_courses_url;
$item->url = ( is_user_logged_in() ? $logout_url : $login_url );
// determine the menu title login or logout.
if ( is_user_logged_in() ) {
$menu_title = __( 'Logout', 'sensei-lms' );
} else {
$menu_title = __( 'Login', 'sensei-lms' );
}
/**
* Action Filter: login/logout menu title
*
* With this filter you can alter the login / login menu item title string
*
* @hook sensei_login_logout_menu_title
*
* @param {string} $menu_title The menu title.
* @return {string} The filtered menu title.
*/
$item->title = apply_filters( 'sensei_login_logout_menu_title', $menu_title );
break;
default:
break;
}
$_root_relative_current = untrailingslashit( $_SERVER['REQUEST_URI'] );
$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_root_relative_current );
$item_url = untrailingslashit( $item->url );
$_indexless_current = untrailingslashit( preg_replace( '/' . preg_quote( $wp_rewrite->index, '/' ) . '$/', '', $current_url ) );
// Highlight current menu item.
if ( $item_url && in_array( $item_url, array( $current_url, $_indexless_current, $_root_relative_current ) ) ) {
$item->classes[] = 'current-menu-item current_page_item';
}
} // endif nav
return $item;
}
/**
*
* Removes custom menu items depending on settings and logged in status.
*
* @access public
* @param object $sorted_menu_items Menu items, sorted by each menu item's menu order.
* @return object $sorted_menu_items Filtered list of menu items.
*/
public function sensei_wp_nav_menu_objects( $sorted_menu_items ) {
foreach ( $sorted_menu_items as $k => $item ) {
// Remove the My Messages link for logged out users or if Private Messages are disabled.
if ( ! get_post_type_archive_link( 'sensei_message' )
&& '#senseimymessages' == $item->url ) {
if ( ! is_user_logged_in() || ( isset( Sensei()->settings->settings['messages_disable'] ) && Sensei()->settings->settings['messages_disable'] ) ) {
unset( $sorted_menu_items[ $k ] );
}
}
// Remove the My Profile link for logged out users.
if ( Sensei()->learner_profiles->get_permalink() == $item->url ) {
if ( ! is_user_logged_in() || ! ( isset( Sensei()->settings->settings['learner_profile_enable'] ) && Sensei()->settings->settings['learner_profile_enable'] ) ) {
unset( $sorted_menu_items[ $k ] );
}
}
}
return $sorted_menu_items;
}
/**
* Adds category nicenames to the body and post class.
*
* @param array $classes CSS classes for the current post.
* @return array Filtered list of CSS classes for the current post.
*/
function sensei_search_results_classes( $classes ) {
global $post;
// Handle Search Classes for Courses, Lessons, and WC Products.
if ( isset( $post->post_type ) && ( ( 'course' == $post->post_type ) || ( 'lesson' == $post->post_type ) || ( 'product' == $post->post_type ) ) ) {
$classes[] = 'post';
}
return $classes;
}
/**
* Pagination for course archive pages when filtering by course type.
*
* @since 1.0.0
* @param WP_Query $query WP_Query instance.
*/
function sensei_course_archive_pagination( $query ) {
if ( ! is_admin() && $query->is_main_query() && isset( $_GET['action'] ) && in_array( $_GET['action'], array( 'newcourses', 'featuredcourses', 'freecourses', 'paidcourses' ) ) ) {
$amount = 0;
if ( isset( Sensei()->settings->settings['course_archive_amount'] ) && ( 0 < absint( Sensei()->settings->settings['course_archive_amount'] ) ) ) {
$amount = absint( Sensei()->settings->settings['course_archive_amount'] );
}
if ( $amount ) {
$query->set( 'posts_per_page', $amount );
}
$query->set( 'orderby', 'menu_order date' );
}
}
/**
* Output for course archive page individual course title.
*
* @since 1.2.0
* @param WP_Post $post_item Post.
* @return void
*/
function sensei_course_archive_course_title( $post_item ) {
if ( isset( $post_item->ID ) && ( 0 < $post_item->ID ) ) {
$post_id = absint( $post_item->ID );
$post_title = $post_item->post_title;
} else {
$post_id = get_the_ID();
$post_title = get_the_title();
}
?><header><h2><a href="<?php echo esc_url( get_permalink( $post_id ) ); ?>" title="<?php echo esc_attr( $post_title ); ?>"><?php echo esc_html( $post_title ); ?></a></h2></header>
<?php
}
/**
* Outputs the title on the course archive page.
*
* @since 1.2.1
* @return void
*/
public function sensei_lesson_archive_lesson_title() {
$post_id = get_the_ID();
$post_title = get_the_title();
?>
<header><h2><a href="<?php echo esc_url( get_permalink( $post_id ) ); ?>" title="<?php echo esc_attr( $post_title ); ?>"><?php echo esc_html( $post_title ); ?></a></h2></header>
<?php
}
/**
* Outputs the breadcrumb for lessons and quizzes.
*
* @since 1.7.0
* @param integer $id Course, lesson or quiz ID.
* @return void
*/
public function sensei_breadcrumb( $id = 0 ) {
// Only output on lesson, quiz and taxonomy (module) pages.
if ( ! ( is_tax( 'module' ) || is_singular( 'lesson' ) || is_singular( 'quiz' ) ) ) {
return;
}
if ( empty( $id ) ) {
$id = get_the_ID();
}
$sensei_breadcrumb_prefix = __( 'Back to: ', 'sensei-lms' );
/**
* Filter the breadcrumb separator.
*
* @hook sensei_breadcrumb_separator
*
* @param {string} $separator Breadcrumb separator.
* @return {string} Filtered separator.
*/
$separator = apply_filters( 'sensei_breadcrumb_separator', '>' );
$html = '<section class="sensei-breadcrumb">' . esc_html( $sensei_breadcrumb_prefix );
// Lesson.
if ( is_singular( 'lesson' ) && 0 < intval( $id ) ) {
$course_id = intval( get_post_meta( $id, '_lesson_course', true ) );
if ( ! $course_id ) {
return;
}
$html .= '<a href="' . esc_url( get_permalink( $course_id ) ) . '" title="' . esc_attr__( 'Back to the course', 'sensei-lms' ) . '">' . esc_html( get_the_title( $course_id ) ) . '</a>';
}
// Quiz.
if ( is_singular( 'quiz' ) && 0 < intval( $id ) ) {
$lesson_id = intval( get_post_meta( $id, '_quiz_lesson', true ) );
if ( ! $lesson_id ) {
return;
}
$html .= '<a href="' . esc_url( get_permalink( $lesson_id ) ) . '" title="' . esc_attr__( 'Back to the lesson', 'sensei-lms' ) . '">' . esc_html( get_the_title( $lesson_id ) ) . '</a>';
}
/**
* Filter the breadcrumb HTML.
*
* @hook sensei_breadcrumb_output
*
* @param {string} $html Breadcrumb HTML.
* @param {string} $separator Breadcrumb separator.
* @return {string} Filtered HTML.
*/
$html = apply_filters( 'sensei_breadcrumb_output', $html, $separator );
$html .= '</section>';
echo wp_kses_post( $html );
}
/**
* Outputs the lesson tags.
*
* @param int $lesson_id Lesson ID.
*/
public function lesson_tags_display( $lesson_id = 0 ) {
if ( $lesson_id ) {
$tags = wp_get_post_terms( $lesson_id, 'lesson-tag' );
if ( $tags ) {
$tag_list = '';
foreach ( $tags as $tag ) {
$tag_link = get_term_link( $tag, 'lesson-tag' );
if ( ! is_wp_error( $tag_link ) ) {
if ( $tag_list ) {
$tag_list .= ', '; }
$tag_list .= '<a href="' . esc_url( $tag_link ) . '">' . esc_html( $tag->name ) . '</a>';
}
}
if ( $tag_list ) {
?>
<section class="lesson-tags">
<?php
// translators: Placeholder is a comma-separated list of links to the tags.
printf( esc_html__( 'Lesson tags: %1$s', 'sensei-lms' ), wp_kses_post( $tag_list ) );
?>
</section>
<?php
}
}
}
}
/**
* Filters the query variable object to only return lessons.
*
* @param WP_Query $query WP_Query instance.
*/
public function lesson_tag_archive_filter( $query ) {
if ( $query->is_main_query() && is_tax( 'lesson-tag' ) ) {
// Limit to lessons only.
$query->set( 'post_type', 'lesson' );
// Set order of lessons.
$query->set( 'orderby', 'menu_order' );
$query->set( 'order', 'ASC' );
}
}
/**
* Gets the lesson tag archive title.
*
* @param string $title Lesson tag title.
* @return string Lesson tag title.
*/
public function lesson_tag_archive_header( $title ) {
if ( is_tax( 'lesson-tag' ) ) {
/**
* Filters the lesson tag archive title.
*
* @hook sensei_lesson_tag_archive_title
*
* @param {string} $title Lesson tag archive title.
* @return {string} Filtered title.
*/
$lesson_tag_archive_title = apply_filters( 'sensei_lesson_tag_archive_title', get_queried_object()->name );
// translators: Placeholder is the filtered tag name.
$title = sprintf( __( 'Lesson tag: %1$s', 'sensei-lms' ), $lesson_tag_archive_title );
}
return $title;
}
/**
* Outputs the lesson tag archive description.
*/
public function lesson_tag_archive_description() {
if ( is_tax( 'lesson-tag' ) ) {
$tag = get_queried_object();
/**
* Filters the lesson tag archive description.
*
* @hook sensei_lesson_tag_archive_description
*
* @param {string} $description Lesson tag archive description.
* @param {int} $tag_id Lesson tag ID.
* @return {string} Filtered description.
*/
echo '<p class="archive-description lesson-description">' . wp_kses_post( apply_filters( 'sensei_lesson_tag_archive_description', nl2br( $tag->description ), $tag->term_id ) ) . '</p>';
}
}
/**
* Marks a lesson as complete.
*/
public function sensei_complete_lesson() {
global $post, $current_user;
if ( ! isset( $_POST['quiz_action'] ) ) {
return;
}
if ( ! wp_verify_nonce( $_POST['woothemes_sensei_complete_lesson_noonce'], 'woothemes_sensei_complete_lesson_noonce' ) ) {
return;
}
$lesson_id = $post->ID;
if ( 0 >= $lesson_id ) {
return;
}
// Handle Quiz Completion.
$sanitized_submit = esc_html( $_POST['quiz_action'] );
switch ( $sanitized_submit ) {
case 'lesson-complete':
Sensei_Utils::sensei_start_lesson( $lesson_id, $current_user->ID, true );
$this->maybe_redirect_to_next_lesson( $lesson_id );
break;
case 'lesson-reset':
Sensei_Utils::sensei_remove_user_from_lesson( $lesson_id, $current_user->ID );
$this->messages = '<div class="sensei-message note">' . __( 'Lesson Reset Successfully.', 'sensei-lms' ) . '</div>';
break;
default:
// Nothing.
break;
}
}
/**
* Redirect to the next lesson, if applicable.
*
* @since 1.12.0
*
* @param int $lesson_id Lesson ID.
*/
private function maybe_redirect_to_next_lesson( $lesson_id = 0 ) {
if ( 0 >= $lesson_id ) {
return;
}
$nav_links = sensei_get_prev_next_lessons( $lesson_id );
$redirect_url = false;
if ( isset( $nav_links['next'] ) ) {
$redirect_url = $nav_links['next']['url'];
}
/**
* Filter the URL that students are redirected to after completing a lesson.
*
* @since 1.12.0
*
* @hook sensei_complete_lesson_redirect_url
*
* @param {string|bool} $redirect_url URL to redirect students to after completing a lesson. False to skip redirect.
* @param {int} $lesson_id Current lesson ID.
* @param {array} $nav_links Navigation links found for the current lesson.
* @return {string|bool} Filtered URL to redirect students to after completing a lesson. False to skip redirect.
*/
$redirect_url = apply_filters( 'sensei_complete_lesson_redirect_url', $redirect_url, $lesson_id, $nav_links );
if ( $redirect_url ) {
wp_safe_redirect( esc_url_raw( $redirect_url ) );
exit;
}
}
/**
* Redirect to the course completed page, if applicable.
*
* @since 3.13.0
* @access private
*
* @param string $status Course status.
* @param int $user_id The user ID (unused).
* @param int $course_id The course ID.
*/
public function redirect_to_course_completed_page( $status, $user_id, $course_id ) {
if ( 'complete' !== $status || ! $course_id || Sensei_Utils::is_rest_request() ) {
return;
}
$url = Sensei_Course::get_course_completed_page_url( $course_id );
if ( $url ) {
/**
* Fires when a user completes a course and is redirected to the course completed page.
*
* @hook sensei_user_course_end
*
* @param {int} $user_id The user ID.
* @param {int} $course_id The course ID.
*/
do_action( 'sensei_user_course_end', $user_id, $course_id );
wp_safe_redirect( esc_url_raw( $url ) );
exit;
}
}
/**
* Marks a course as complete.
*/
public function sensei_complete_course() {
global $current_user;
if ( isset( $_POST['course_complete'] ) && wp_verify_nonce( $_POST['woothemes_sensei_complete_course_noonce'], 'woothemes_sensei_complete_course_noonce' ) ) {
$sanitized_submit = esc_html( $_POST['course_complete'] );
$sanitized_course_id = absint( esc_html( $_POST['course_complete_id'] ) );
// Handle submit data.
switch ( $sanitized_submit ) {
case __( 'Mark as Complete', 'sensei-lms' ):
$course_progress = Sensei()->course_progress_repository->get( $sanitized_course_id, $current_user->ID );
if ( null === $course_progress ) {
$course_progress = Sensei()->course_progress_repository->create( $sanitized_course_id, $current_user->ID );
}
$course_lesson_ids = Sensei()->course->course_lessons( $sanitized_course_id, 'any', 'ids' );
foreach ( $course_lesson_ids as $lesson_id ) {
Sensei_Utils::sensei_start_lesson( $lesson_id, $current_user->ID, true );
}
$course_progress->complete();
Sensei()->course_progress_repository->save( $course_progress );
$course_metadata = [
'percent' => 100,
'complete' => count( $course_lesson_ids ),
];
foreach ( $course_metadata as $key => $value ) {
update_comment_meta( $course_progress->get_id(), $key, $value );
}
/**
* Fires when a user completes a course.
*
* @hook sensei_user_course_end
*
* @param {int} $user_id The user ID.
* @param {int} $course_id The course ID.
*/
do_action( 'sensei_user_course_end', $current_user->ID, $sanitized_course_id );
// Success message.
$this->messages = '<header class="archive-header"><div class="sensei-message tick">'
// translators: Placeholder is the Course title.
. sprintf( __( '%1$s marked as complete.', 'sensei-lms' ), get_the_title( $sanitized_course_id ) )
. '</div></header>';
break;
default:
// Nothing.
break;
}
}
}
/**
* Gets the quiz answers for the current user.
*
* @deprecated 3.10.0 use Sensei_Quiz::get_user_answers
* @param int $lesson_id Lesson ID.
* @return array Quiz answers for the current user.
*/
public function sensei_get_user_quiz_answers( $lesson_id = 0 ) {
global $current_user;
_deprecated_function( __METHOD__, '3.10.0', 'Sensei_Quiz::get_user_answers' );
$user_answers = array();
if ( 0 < intval( $lesson_id ) ) {
$lesson_quiz_questions = Sensei()->lesson->lesson_quiz_questions( $lesson_id );
foreach ( $lesson_quiz_questions as $question ) {
$answer = maybe_unserialize(
base64_decode(
Sensei_Utils::sensei_get_activity_value(
array(
'post_id' => $question->ID,
'user_id' => $current_user->ID,
'type' => 'sensei_user_answer',
'field' => 'comment_content',
)
)
)
);
$user_answers[ $question->ID ] = $answer;
}
}
return $user_answers;
}
/**
* Outputs all notices.
*/
public function sensei_frontend_messages() {
Sensei()->notices->maybe_print_notices();
}
/**
* Outputs the video for a lesson.
*
* @param int $post_id Optional. Lesson ID. Default 0.
*/
public function sensei_lesson_video( $post_id = 0 ) {
if ( 0 < intval( $post_id ) && sensei_can_user_view_lesson( $post_id ) ) {
$lesson_video_embed = get_post_meta( $post_id, '_lesson_video_embed', true );
$lesson_video_embed = Sensei_Utils::render_video_embed( $lesson_video_embed );
if ( '' != $lesson_video_embed ) {
?>
<div class="video <?php echo esc_attr( self::VIDEO_EMBED_CLASS ); ?>"><?php echo wp_kses( $lesson_video_embed, $this->allowed_html ); ?></div>
<?php
}
}
}
/**
* Outputs the "Complete Lesson" button.
*/
public function sensei_complete_lesson_button() {
global $post;
$lesson_id = $post->ID;
// make sure user is taking course.
$course_id = Sensei()->lesson->get_course_id( $lesson_id );
if ( ! Sensei_Course::is_user_enrolled( $course_id ) ) {
return;
}
if ( false === Sensei()->lesson->lesson_has_quiz_with_questions_and_pass_required( $lesson_id ) ) {
wp_enqueue_script( 'sensei-stop-double-submission' );
?>
<form class="lesson_button_form" data-id="complete-lesson-form" method="POST" action="<?php echo esc_url( get_permalink() ); ?>">
<input type="hidden"
name="woothemes_sensei_complete_lesson_noonce"
id="woothemes_sensei_complete_lesson_noonce"
value="<?php echo esc_attr( wp_create_nonce( 'woothemes_sensei_complete_lesson_noonce' ) ); ?>"
/>
<input type="hidden" name="quiz_action" value="lesson-complete" />
<input type="submit"
name="quiz_complete"
class="quiz-submit complete sensei-stop-double-submission"
data-id="complete-lesson-button"
value="<?php esc_attr_e( 'Complete Lesson', 'sensei-lms' ); ?>"
/>
</form>
<?php
}
}
/**
* Outputs the "Reset Lesson" button.
*/
public function sensei_reset_lesson_button() {
global $post;
// Lesson quizzes.
$quiz_id = Sensei()->lesson->lesson_quizzes( $post->ID );
$reset_allowed = true;
if ( $quiz_id ) {
// Get quiz pass setting.
$reset_allowed = get_post_meta( $quiz_id, '_enable_quiz_reset', true );
}
if ( ! $quiz_id || ! empty( $reset_allowed ) ) {
wp_enqueue_script( 'sensei-stop-double-submission' );
?>
<form method="POST" action="<?php echo esc_url( get_permalink() ); ?>">
<input
type="hidden"
name="<?php echo esc_attr( 'woothemes_sensei_complete_lesson_noonce' ); ?>"
id="<?php echo esc_attr( 'woothemes_sensei_complete_lesson_noonce' ); ?>"
value="<?php echo esc_attr( wp_create_nonce( 'woothemes_sensei_complete_lesson_noonce' ) ); ?>" />
<input type="hidden" name="quiz_action" value="lesson-reset" />
<input type="submit" name="quiz_complete" class="quiz-submit reset sensei-stop-double-submission" value="<?php esc_attr_e( 'Reset Lesson', 'sensei-lms' ); ?>"/>
</form>
<?php
}
}
public function sensei_course_archive_meta() {
// Meta data.
$post_id = get_the_ID();
$category_output = get_the_term_list( $post_id, 'course-category', '', ', ', '' );
$free_lesson_count = intval( Sensei()->course->course_lesson_preview_count( $post_id ) );
$lesson_count = Sensei()->course->course_lesson_count( $post_id );
?>
<section class="entry">
<p class="sensei-course-meta">
<?php
/**
* Fires before course meta is displayed.
*
* @since 2.0.0
*
* @hook sensei_course_meta_inside_before
*
* @param {int} $course_id Course post ID.
*/
do_action( 'sensei_course_meta_inside_before', $post_id );
if ( isset( Sensei()->settings->settings['course_author'] ) && ( Sensei()->settings->settings['course_author'] ) ) {
?>
<span class="course-author"><?php esc_html_e( 'by', 'sensei-lms' ); ?><?php the_author_link(); ?></span>
<?php
}
?>
<span class="course-lesson-count">
<?php
// translators: Placeholder %d is the lesson count.
echo esc_html( sprintf( _n( '%d Lesson', '%d Lessons', $lesson_count, 'sensei-lms' ), $lesson_count ) );
?>
</span>
<?php
if ( ! empty( $category_output ) ) {
?>
<span class="course-category">
<?php
// translators: Placeholder is a comma-separated list of the Course categories.
echo sprintf( esc_html__( 'in %s', 'sensei-lms' ), wp_kses_post( $category_output ) );
?>
</span>
<?php
}
/**
* Fires after course meta is displayed.
*
* @since 2.0.0
*
* @hook sensei_course_meta_inside_after
*
* @param {int} $course_id Course post ID.
*/
do_action( 'sensei_course_meta_inside_after', $post_id );
?>
</p>
<p class="course-excerpt"><?php the_excerpt(); ?></p>
<?php
if ( 0 < $free_lesson_count ) {
// translators: Placeholder is the number of free lessons in the course.
$free_lessons = sprintf( __( 'You can access %d of this course\'s lessons for free', 'sensei-lms' ), $free_lesson_count );
?>
<p class="sensei-free-lessons"><a href="<?php echo esc_url( get_permalink( $post_id ) ); ?>"><?php esc_html_e( 'Preview this course', 'sensei-lms' ); ?></a> - <?php echo esc_html( $free_lessons ); ?></p>
<?php } ?>
</section>
<?php
}
public function sensei_course_category_main_content() {
global $post;
if ( have_posts() ) {
?>
<section id="main-course" class="course-container">
<?php sensei_do_deprecated_action( 'sensei_course_archive_header', '3.0.0', 'sensei_course_content_inside_before' ); ?>
<?php
while ( have_posts() ) {
the_post();
?>
<article class="<?php echo esc_attr( implode( ' ', get_post_class( array( 'course', 'post' ), get_the_ID() ) ) ); ?>">
<?php
/**
* Fires when course meta is displayed.
*
* @hook sensei_course_archive_meta
*/
do_action( 'sensei_course_archive_meta' );
?>
</article>
<?php } ?>
</section>
<?php } else { ?>
<p>
<?php esc_html_e( 'No courses found that match your selection.', 'sensei-lms' ); ?>
</p>
<?php
}
}
public function sensei_login_form() {
/*
* It is safe to ignore nonce verification below because we are just
* using the POST data to display values in the form, not to change any
* data on the server.
*/
?>
<div id="my-courses">
<?php Sensei()->notices->maybe_print_notices(); ?>
<div class="col2-set" id="customer_login">
<div class="col-1">
<?php
// output the actual form markup.
Sensei_Templates::get_template( 'user/login-form.php' );
?>
</div>
<?php
if ( get_option( 'users_can_register' ) ) {
?>
<div class="col-2">
<h2><?php esc_html_e( 'Register', 'sensei-lms' ); ?></h2>
<form method="post" class="register">
<?php
/**
* Fires at the start of the register form.
*
* @hook sensei_register_form_start
*/
do_action( 'sensei_register_form_start' );
?>
<p class="form-row form-row-wide">
<label for="sensei_reg_username"><?php esc_html_e( 'Username', 'sensei-lms' ); ?> <span class="required">*</span></label>
<input type="text" class="input-text" name="sensei_reg_username" id="sensei_reg_username" value="<?php echo ( ! empty( $_POST['sensei_reg_username'] ) ) ? esc_attr( $_POST['sensei_reg_username'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification ?>" />
</p>
<p class="form-row form-row-wide">
<label for="sensei_reg_email"><?php esc_html_e( 'Email address', 'sensei-lms' ); ?> <span class="required">*</span></label>
<input type="email" class="input-text" name="sensei_reg_email" id="sensei_reg_email" value="<?php echo ( ! empty( $_POST['sensei_reg_email'] ) ) ? esc_attr( $_POST['sensei_reg_email'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification ?>" />
</p>
<p class="form-row form-row-wide">
<label for="sensei_reg_password"><?php esc_html_e( 'Password', 'sensei-lms' ); ?> <span class="required">*</span></label>
<input type="password" class="input-text" name="sensei_reg_password" id="sensei_reg_password" value="<?php echo ( ! empty( $_POST['sensei_reg_password'] ) ) ? esc_attr( $_POST['sensei_reg_password'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification ?>" />
</p>
<!-- Spam Trap -->
<div style="left:-999em; position:absolute;"><label for="trap"><?php esc_html_e( 'Anti-spam', 'sensei-lms' ); ?></label><input type="text" name="email_2" id="trap" tabindex="-1" /></div>
<?php
/**
* Fires at the end of the register form.
* Allows adding extra fields to the registration form.
*
* @hook sensei_register_form_fields
*/
do_action( 'sensei_register_form_fields' );
?>
<?php do_action( 'register_form' ); ?>
<?php wp_nonce_field( 'sensei-register' ); ?>
<p class="form-row">
<input type="submit" class="button wp-element-button" name="register" value="<?php esc_attr_e( 'Register', 'sensei-lms' ); ?>" />
</p>
<?php
/**
* Fires at the end of the register form.
*
* @hook sensei_register_form_end
*/
do_action( 'sensei_register_form_end' );
?>
</form>
</div>
<?php
}
?>
</div>
</div>
<?php
}
public function sensei_lesson_meta( $post_id = 0 ) {
if ( 0 < intval( $post_id ) ) {
$lesson_course_id = absint( get_post_meta( $post_id, '_lesson_course', true ) );
?>
<section class="entry">
<p class="sensei-course-meta">
<?php if ( isset( Sensei()->settings->settings['lesson_author'] ) && ( Sensei()->settings->settings['lesson_author'] ) ) { ?>
<span class="course-author"><?php esc_html_e( 'by', 'sensei-lms' ); ?><?php the_author_link(); ?></span>
<?php } ?>
<?php if ( 0 < intval( $lesson_course_id ) ) { ?>
<span class="lesson-course">
<?php
echo ' ' . wp_kses_post(
sprintf(
// translators: Placeholder is a link to the Course permalink.
__( 'Part of: %s', 'sensei-lms' ),
'<a href="' . esc_url( get_permalink( $lesson_course_id ) ) . '" title="' . esc_attr__( 'View course', 'sensei-lms' ) . '"><em>' . esc_html( get_the_title( $lesson_course_id ) ) . '</em></a>'
)
);
?>
</span>
<?php } ?>
</p>
<p class="lesson-excerpt"><?php the_excerpt(); ?></p>
</section>
<?php
}
} // sensei_lesson_meta()
public function sensei_lesson_preview_title_text( $course_id ) {
$preview_text = __( 'Preview', 'sensei-lms' );
/**
* The lesson preview indicator text. Defaults to "Preview".
*
* @since 1.11.0
*
* @hook sensei_lesson_preview_title_text
*
* @param {string} $preview_text
* @param {int} $course_id
* @return {string} Filtered text.
*/
return apply_filters( 'sensei_lesson_preview_title_text', $preview_text, $course_id );
}
public function sensei_lesson_preview_title_tag( $course_id ) {
return '<span class="preview-label">'
. $this->sensei_lesson_preview_title_text( $course_id )
. '</span>';
}
public function sensei_lesson_preview_title( $title = '', $id = 0 ) {
global $post;
// Limit to lessons and check if lesson ID matches filtered post ID.
// @see https://github.com/woothemes/sensei/issues/574.
if ( isset( $post->ID ) && $id == $post->ID && 'lesson' == get_post_type( $post ) ) {
// Limit to main query only.
if ( is_main_query() ) {
// Get the course ID.
$course_id = get_post_meta( $post->ID, '_lesson_course', true );
// Check if the user is taking the course.
if ( is_singular( 'lesson' ) && Sensei_Utils::is_preview_lesson( $post->ID ) && ! Sensei_Course::is_user_enrolled( $course_id ) && $post->ID == $id ) {
$title .= ' ' . $this->sensei_lesson_preview_title_tag( $course_id );
}
}
}
return $title;
} // sensei_lesson_preview_title
/**
* Start a course.
*/
public function sensei_course_start() {
global $post, $current_user;
/**
* Filter the course ID for the course being started.
*
* @since 4.23.1
*
* @hook sensei_course_start_course_id
*
* @param {int} $course_id Course post ID.
* @return {int} Filtered course ID.
*/
$course_id = (int) apply_filters( 'sensei_course_start_course_id', $post->ID ?? 0 );
$nonce = isset( $_POST['woothemes_sensei_start_course_noonce'] )
? sanitize_text_field( wp_unslash( (string) $_POST['woothemes_sensei_start_course_noonce'] ) )
: '';
if ( ! is_singular( 'course' )
|| ! isset( $_POST['course_start'] )
|| ! wp_verify_nonce( $nonce, 'woothemes_sensei_start_course_noonce' )
|| ! Sensei_Course::can_current_user_manually_enrol( $course_id )
|| ! Sensei_Course::is_prerequisite_complete( $course_id )
|| post_password_required( $course_id )
) {
return;
}
/**
* Lets providers give their own course sign-up handler.
*
* @since 3.0.0
*
* @hook sensei_frontend_learner_enrolment_handler
*
* @param {callback(int, int):bool} $handler Frontend enrolment handler. Takes two arguments: $user_id and $course_id. Returns `true` if successful; `false` if not.
* @param {int} $user_id User ID.
* @param {int} $course_id Course post ID.
* @return {callback(int, int):bool} Filtered handler.
*/
$learner_enrollment_handler = apply_filters(
'sensei_frontend_learner_enrolment_handler',
array( $this, 'manually_enrol_learner' ),
$current_user->ID,
$course_id
);
$student_enrolled = false;
if ( is_callable( $learner_enrollment_handler ) ) {
$student_enrolled = call_user_func( $learner_enrollment_handler, $current_user->ID, $course_id );
}
$this->data = new stdClass();
$this->data->is_user_taking_course = false;
if ( ! $student_enrolled ) {
return;
}
$this->data->is_user_taking_course = true;
// Refresh page to avoid re-posting.
/**
* Filter the URL that students are redirected to after starting a course.
*
* @since 1.10.0
*
* @hook sensei_start_course_redirect_url
*
* @param {string|bool} $redirect_url URL to redirect students to after starting course. Return `false` to prevent redirect.
* @param {WP_Post} $post Post object for course.
* @return {string|bool} Filtered URL to redirect students to after starting course. Return `false` to prevent redirect.
*/
$redirect_url = apply_filters( 'sensei_start_course_redirect_url', get_permalink( $post->ID ), $post );
if ( 'publish' !== get_post_status( $post ) ) {
wp_safe_redirect( add_query_arg( 'draftcourse', 'true', $redirect_url ) );
exit();
}
if ( false !== $redirect_url ) {
?>
<script type="text/javascript"> window.location = '<?php echo esc_url_raw( $redirect_url ); ?>'; </script>
<?php
}
}
/**
* Handle the frontend manual enrollment of a learner.
*
* @since 3.0.0
* @access private
*
* @param int $user_id User ID.
* @param int $course_id Course post ID.
*
* @return bool True if successful.
*/
public function manually_enrol_learner( $user_id, $course_id ) {
$course_enrolment = Sensei_Course_Enrolment::get_course_instance( $course_id );
// If user is removed, just restore it.
if ( $course_enrolment->is_learner_removed( $user_id ) ) {
$course_enrolment->restore_learner( $user_id );
}
$enrolment_manager = Sensei_Course_Enrolment_Manager::instance();
$manual_enrolment_provider = $enrolment_manager->get_manual_enrolment_provider();
if ( ! ( $manual_enrolment_provider instanceof Sensei_Course_Manual_Enrolment_Provider ) ) {
return false;
}
return $manual_enrolment_provider->enrol_learner( $user_id, $course_id );
}
/**
* Only show excerpts for lessons and courses in search results.
*
* @param string $content Original content.
* @return string Modified content.
*/
public function sensei_search_results_excerpt( $content ) {
global $post;
if ( is_search() && in_array( $post->post_type, array( 'course', 'lesson' ) ) ) {
// Prevent infinite loop, because wp_trim_excerpt calls the_content filter again.
remove_filter( 'the_content', array( $this, 'sensei_search_results_excerpt' ) );
// Don't echo the excerpt.
$content = '<p class="course-excerpt">' . get_the_excerpt() . '</p>';
}
return $content;
}
/**
* Hide Sensei activity comments from frontend (requires WordPress 4.0+).
*
* @param array $args Default arguments.
* @return array Modified arguments.
*/
public function hide_sensei_activity( $args = array() ) {
if ( is_singular( 'lesson' ) || is_singular( 'course' ) ) {
$args['type'] = 'comment';
}
return $args;
}
/**
* Redirect failed login attempts to the front end login page
* in the case where the login fields are not left empty.
*
* @return void redirect
*/
function sensei_login_fail_redirect() {
// if not posted from the sensei login form let
// WordPress or any other party handle the failed request.
if ( ! isset( $_REQUEST['form'] ) || 'sensei-login' != $_REQUEST['form'] ) {
return;
}
// Get the reffering page, where did the post submission come from?
$referrer = add_query_arg( 'login', false, $_SERVER['HTTP_REFERER'] );
// if there's a valid referrer, and it's not the default log-in screen.
if ( ! empty( $referrer ) && ! strstr( $referrer, 'wp-login' ) && ! strstr( $referrer, 'wp-admin' ) ) {
// let's append some information (login=failed) to the URL for the theme to use.
wp_safe_redirect( esc_url_raw( add_query_arg( 'login', 'failed', $referrer ) ) );
exit;
}
}
/**
* Handle the login reques from all sensei intiated login forms.
*
* @return void redirect
*/
function sensei_handle_login_request() {
// Check that it is a sensei login request and if it has a valid nonce.
if ( isset( $_REQUEST['form'] ) && 'sensei-login' == $_REQUEST['form'] ) {
// Validate the login request nonce.
if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'sensei-login' ) ) {
return;
}
// get the page where the sensei log form is located.
$referrer = $_REQUEST['_wp_http_referer'];
if ( ( isset( $_REQUEST['log'] ) && ! empty( $_REQUEST['log'] ) )
&& ( isset( $_REQUEST['pwd'] ) && ! empty( $_REQUEST['pwd'] ) ) ) {
// when the user has entered a password or username do the sensei login.
$creds = array();
// check if the requests login is an email address.
if ( is_email( trim( $_REQUEST['log'] ) ) ) {
$login = sanitize_email( $_REQUEST['log'] );
// Occasionally a user's username IS an email,
// but they have changed their actual email, so check for this case.
$user = get_user_by( 'login', $login );
if ( ! $user ) {
// Ok, fallback to checking by email.
$user = get_user_by( 'email', $login );
}
// validate the user object.
if ( ! $user ) {
// the email doesnt exist.
wp_safe_redirect( esc_url_raw( add_query_arg( 'login', 'failed', $referrer ) ) );
exit;
}
// assigne the username to the creds array for further processing.
$creds['user_login'] = $user->user_login;
} else {
// process this as a default username login.
$creds['user_login'] = sanitize_text_field( $_REQUEST['log'] );
}
// get setup the rest of the creds array.
$creds['user_password'] = $_REQUEST['pwd'];
$creds['remember'] = isset( $_REQUEST['rememberme'] ) ? true : false;
// attempt logging in with the given details.
$secure_cookie = is_ssl() ? true : false;
$user = wp_signon( $creds, $secure_cookie );
if ( is_wp_error( $user ) ) { // on login failure.
wp_safe_redirect( esc_url_raw( add_query_arg( 'login', 'failed', $referrer ) ) );
exit;
} else { // on login success.
$redirect_to = isset( $_REQUEST['redirect_to'] ) ? esc_url_raw( wp_unslash( $_REQUEST['redirect_to'] ) ) : remove_query_arg( 'login', $referrer );
/**
* Change the redirect url programatically.
*
* @since 1.6.1
* @deprecated 3.15.0 Use `sensei_login_success_redirect_url` instead.
*
* @param string $referrer the page where the current url where sensei login form was posted from.
*/
$success_redirect_url = apply_filters_deprecated( 'sesei_login_success_redirect_url', [ $redirect_to ], 'sensei_login_success_redirect_url', 'Use `sensei_login_success_redirect_url` instead' );
/**
* Change the redirect url programatically.
*
* The redirect URL if login is successful. Note that if this URL points to an external domain, it may need to be whitelisted using the `allowed_redirect_hosts` filter.
*
* @since 3.15.0
*
* @hook sensei_login_success_redirect_url
*
* @param {string} $referrer The page where the current url wheresensei login form was posted from.
* @return {string} The redirect URL.
*/
$success_redirect_url = apply_filters( 'sensei_login_success_redirect_url', $success_redirect_url );
wp_safe_redirect( esc_url_raw( $success_redirect_url ) );
exit;
}
} else { // if username or password is empty.
wp_safe_redirect( esc_url_raw( add_query_arg( 'login', 'emptyfields', $referrer ) ) );
exit;
}
} elseif ( ( isset( $_GET['login'] ) ) ) {
// else if this request is a redircect from a previously faile login request.
$this->login_message_process();
// exit the handle login request function.
return;
}
// if none of the above.
return;
}
/**
* Handles Sensei specific registration requests.
*
* @return void redirect
*/
public function sensei_process_registration() {
global $current_user;
// check the for the sensei specific registration requests.
// phpcs:ignore WordPress.Security.NonceVerification -- We are just checking whether to return here.
if ( ! isset( $_POST['sensei_reg_username'] ) && ! isset( $_POST['sensei_reg_email'] ) && ! isset( $_POST['sensei_reg_password'] ) ) {
// exit if this is not a sensei registration request.
return;
}
// Validate the registration request nonce.
if ( ! wp_verify_nonce( $_POST['_wpnonce'], 'sensei-register' ) ) {
return;
}
// check for spam throw cheating huh.
if ( isset( $_POST['email_2'] ) && '' !== $_POST['email_2'] ) {
$message = 'Error: The spam field should be empty';
Sensei()->notices->add_notice( $message, 'alert' );
return;
}
// retreive form variables.
$new_user_name = sanitize_user( $_POST['sensei_reg_username'] );
$new_user_email = $_POST['sensei_reg_email'];
$new_user_password = $_POST['sensei_reg_password'];
// Check the username.
$username_error_notice = '';
if ( $new_user_name == '' ) {
$username_error_notice = __( '<strong>ERROR</strong>: Please enter a username.', 'sensei-lms' );
} elseif ( ! validate_username( $new_user_name ) ) {
$username_error_notice = __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.', 'sensei-lms' );
} elseif ( username_exists( $new_user_name ) ) {
$username_error_notice = __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.', 'sensei-lms' );
}
// exit on username error.
if ( '' !== $username_error_notice ) {
Sensei()->notices->add_notice( $username_error_notice, 'alert' );
return;
}
// Check the e-mail address.
$email_error_notice = '';
if ( $new_user_email == '' ) {
$email_error_notice = __( '<strong>ERROR</strong>: Please enter an email address.', 'sensei-lms' );
} elseif ( ! is_email( $new_user_email ) ) {
$email_error_notice = __( '<strong>ERROR</strong>: The email address isn’t correct.', 'sensei-lms' );
} elseif ( email_exists( $new_user_email ) ) {
$email_error_notice = __( '<strong>ERROR</strong>: This email is already registered, please choose another one.', 'sensei-lms' );
}
// exit on email address error.
if ( '' !== $email_error_notice ) {
Sensei()->notices->add_notice( $email_error_notice, 'alert' );
return;
}
// check user password
// exit on email address error.
if ( empty( $new_user_password ) ) {
Sensei()->notices->add_notice( __( '<strong>ERROR</strong>: The password field is empty.', 'sensei-lms' ), 'alert' );
return;
}
// register user.
$user_id = wp_create_user( $new_user_name, $new_user_password, $new_user_email );
if ( ! $user_id || is_wp_error( $user_id ) ) {
// translators: Placeholder is the admin email address.
Sensei()->notices->add_notice( sprintf( __( '<strong>ERROR</strong>: Couldn’t register you… please contact the <a href="mailto:%s">webmaster</a> !', 'sensei-lms' ), get_option( 'admin_email' ) ), 'alert' );
}
wp_new_user_notification( $user_id, null, 'admin' );
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Log in recently registered user.
$current_user = get_user_by( 'id', $user_id );
wp_set_auth_cookie( $user_id, true );
// Redirect.
global $wp;
if ( wp_get_referer() ) {
$redirect = esc_url( wp_get_referer() );
} else {
$redirect = esc_url( home_url( $wp->request ) );
}
$redirect_to = isset( $_REQUEST['redirect_to'] ) ? esc_url_raw( wp_unslash( $_REQUEST['redirect_to'] ) ) : $redirect;
/**
* Filter the URL that students are redirected to after registering.
*
* @hook sensei_registration_redirect
*
* @param {string} $redirect_to URL to redirect students to after registering.
* @return {string} Filtered URL to redirect students to after registering.
*/
wp_safe_redirect( apply_filters( 'sensei_registration_redirect', $redirect_to ) );
exit;
}
/**
* Displays an appropriate message for a failed login attempt.
*
* @return void redirect
* @since 1.7.0
*/
public function login_message_process() {
// setup the message variables.
$message = '';
// only output message if the url contains login=failed and login=emptyfields.
if ( $_GET['login'] == 'failed' ) {
$message = __( 'Incorrect login details', 'sensei-lms' );
} elseif ( $_GET['login'] == 'emptyfields' ) {
$message = __( 'Please enter your username and password', 'sensei-lms' );
}
if ( '' !== $message ) {
// If it's a login failure, don't print the notices from the wp_body_open hook. Because on non-block
// themes, the notices are printed in the top, even above the header or nav, which breaks it.
// We show the notice on the login form instead.
remove_action( 'wp_body_open', [ Sensei()->notices, 'maybe_print_notices' ] );
}
Sensei()->notices->add_notice( $message, 'alert' );
}
}
/**
* Class WooThemes_Sensei_Frontend
*
* @ignore only for backward compatibility
* @since 1.9.0
*/
class WooThemes_Sensei_Frontend extends Sensei_Frontend{}