[ Avaa Bypassed ]




Upload:

Command:

hmhc3928@3.142.199.54: ~ $
<?php

namespace uncanny_pro_toolkit;

use uncanny_learndash_toolkit as toolkit;
use WP_Error;
use WP_User;

if ( ! defined( 'WPINC' ) ) {
	die;
}

/**
 * Class Sample
 *
 * @package uncanny_pro_toolkit
 */
class CourseTimer extends toolkit\Config implements toolkit\RequiredFunctions {

	/**
	 * @var string[]
	 */
	public static $timed_post_types = array(
		'sfwd-courses', 'sfwd-lessons', 'sfwd-topic', 'sfwd-quiz',
	);

	/**
	 * @var string[]
	 */
	public static $settings_metabox_key = [
		'learndash-course-display-content-settings',
		'learndash-lesson-display-content-settings',
		'learndash-topic-display-content-settings',
		'learndash-quiz-display-content-settings',
	];

	/**
	 * Class constructor
	 */
	public function __construct() {
		add_action( 'plugins_loaded', array(
			__CLASS__, 'run_frontend_hooks',
		) );
		add_action( 'rest_api_init', array( __CLASS__, 'rest_api_init' ) );
	}

	/*
	 * Initialize frontend actions and filters
	 */
	/**
	 * @return void
	 */
	public static function run_frontend_hooks() {

		if ( true === self::dependants_exist() ) {

			// Add timer idle setting to LearnDash Lessons, Topics, amd Quizzes
			add_filter( 'learndash_post_args', array(
				__CLASS__, 'add_idle_time_to_post_args_legacy',
			) );

			// Add minimum Course Time to quiz settings
			add_filter( 'learndash_post_args', array(
				__CLASS__, 'add_min_course_time_to_post_args',
			) );

			// 3.0+  - Add idle time field
			add_filter( 'learndash_settings_fields', array(
				__CLASS__,
				'add_idle_time_to_post_args',
			), 10, 2 ); // 3.0+

			// 3.0+ - Save custom settings field
			add_filter( 'learndash_metabox_save_fields', array(
				__CLASS__,
				'save_timer_custom_meta',
			), 60, 3 );

			$minimum_course_time_before_quiz_access = self::get_settings_value( 'minimum_course_time_before_quiz_access', __CLASS__ );

			if ( 'on' === $minimum_course_time_before_quiz_access ) {
				// 3.0+  - Add minimum course time field
				add_filter( 'learndash_settings_fields', array(
					__CLASS__,
					'add_minimum_course_time_to_post_args',
				), 10, 2 ); // 3.0+

				// 3.0+ - Save custom settings field
				add_filter( 'learndash_metabox_save_fields', array(
					__CLASS__,
					'save_minimum_course_time_custom_meta',
				), 60, 3 );
				// Filter quiz content
				add_filter( 'the_content', array(
					__CLASS__, 'filter_quiz_content',
				) );
			}

			// Enqueue script for timer functionality
			add_action( 'wp_enqueue_scripts', array(
				__CLASS__, 'add_timer_scripts',
			) );

			// Return time elapse
			add_shortcode( 'uo_time', array( __CLASS__, 'shortcode_uo_time' ) );

			// Return live timer
			add_shortcode( 'uo_time_live', array( __CLASS__, 'shortcode_uo_time_live' ) );

			// Return entire topic time elapsed
			add_shortcode( 'uo_time_topic', array(
				__CLASS__, 'shortcode_uo_time_topic',
			) );

			// Return enite lesson time elapsed
			add_shortcode( 'uo_time_lesson', array(
				__CLASS__, 'shortcode_uo_time_lesson',
			) );

			// Return quiz time elapsed
			add_shortcode( 'uo_time_quiz', array(
				__CLASS__, 'shortcode_uo_time_quiz',
			) );

			// Return user total time elapsed
			add_shortcode( 'uo_time_total', array(
				__CLASS__, 'shortcode_uo_time_total',
			) );

			// Return time elapse
			add_shortcode( 'uo_time_course_completed', array(
				__CLASS__, 'shortcode_uo_time_course_completed',
			) );

			// LD overhauled the course reports, there is now two version. One s before v2.3 upgrade and one after.
			// Validate that data upgrade completed
			$data_upgrade = get_option( 'learndash_data_settings', array() );

			// Data was upgraded
			if ( isset( $data_upgrade['user-meta-courses']['version'] ) ) {

				// Filter Report Headers which sets up the data values
				add_filter( 'learndash_data_reports_headers', array(
					__CLASS__,
					'course_export_upgraded_headers_filter',
				), 10, 2 );


			} else {

				// Data wasn't upgraded

				//There is now a filter for LearnDashMenu => Report
				add_filter( 'course_export_data', array(
					__CLASS__, 'course_export_data_filter',
				), 10, 1 );

			}


			//  Store timer when course completion get triggered
			add_action( 'learndash_course_completed', array(
				__CLASS__, 'uo_course_completed_store_timer',
			) );

			// Delete timer data when user LearnDash data is reset
			add_action( 'personal_options_update', array(
				__CLASS__, 'learndash_delete_user_data',
			) );
			add_action( 'edit_user_profile_update', array(
				__CLASS__, 'learndash_delete_user_data',
			) );
			if ( filter_has_var( INPUT_GET, 'page' ) && 'uncanny-toolkit' === filter_input( INPUT_GET, 'page' ) ) {
				add_action( 'admin_head', array(
					__CLASS__, 'uo_timer_interval_convert_text_to_number',
				) );
			}

			// Tincanny Integration
			add_filter( 'tc_api_get_courses_overview', array(
				__CLASS__, 'tc_api_get_courses_overview',
			), 10, 1 );
			add_filter( 'tc_api_get_courseSingleTable', array(
				__CLASS__, 'tc_api_get_courseSingleTable',
			), 10, 3 );
			add_filter( 'tc_api_get_userSingleCoursesOverviewTable', array(
				__CLASS__,
				'tc_api_get_userSingleCoursesOverviewTable',
			), 10, 3 );
			add_filter( 'tc_api_get_userSingleCourseProgressSummaryTable', array(
				__CLASS__,
				'tc_api_get_userSingleCourseProgressSummaryTable',
			), 10, 3 );
			add_action( 'wp_enqueue_scripts', array(
				__CLASS__, 'add_tc_timer_scripts',
			) );
			add_action( 'admin_enqueue_scripts', array(
				__CLASS__, 'add_tc_timer_scripts_admin',
			) );
		}
	}

	/**
	 * Does the plugin rely on another function or plugin
	 *
	 * @return boolean || string Return either true or name of function or
	 *     plugin
	 *
	 */
	public static function dependants_exist() {

		/* Checks for LearnDash */
		global $learndash_post_types;
		if ( ! isset( $learndash_post_types ) ) {
			return 'Plugin: LearnDash';
		}

		// Return true if no dependency or dependency is available
		return true;


	}

	/**
	 * @param $json_return
	 * @param $user_id
	 * @param $course_id
	 *
	 * @return array
	 */
	public static function tc_api_get_userSingleCourseProgressSummaryTable( $json_return, $user_id, $course_id ) {

		global $wpdb;

		//Users' Completed Timers
		$sql_string                          = "SELECT meta_value FROM $wpdb->usermeta WHERE meta_key = 'course_timer_completed_{$course_id}' AND user_id = {$user_id}";
		$timer                               = $wpdb->get_var( $sql_string );
		$json_return['data']['timeComplete'] = $timer;

		//Users' Time Spent
		$sql_string             = "SELECT meta_value FROM $wpdb->usermeta WHERE meta_key LIKE 'uo_timer_{$course_id}%' AND user_id = {$user_id}";
		$times_spent            = $wpdb->get_results( $sql_string );
		$times_spent_rearranged = 0;
		foreach ( $times_spent as $time_spent ) {
			$time    = $time_spent->meta_value;
			$seconds = (int) $time;

			$times_spent_rearranged += $seconds;
		}

		$json_return['data']['timeSpent'] = self::convert_second_to_time( $times_spent_rearranged );

		return $json_return;
	}

	/**
	 * @param $second
	 *
	 * @return string
	 */
	private static function convert_second_to_time( $second ) {


		if ( ! $second ) {
			return '';
		}

		$hours  = floor( $second / 3600 );
		$second -= $hours * 3600;

		$minutes = floor( $second / 60 );
		$second  -= $minutes * 60;

		if ( $hours < 10 ) {
			$hours = '0' . $hours;
		}
		if ( $minutes < 10 ) {
			$minutes = '0' . $minutes;
		}
		if ( $second < 10 ) {
			$second = '0' . $second;
		}

		$total_time = ( $hours ) ? $hours . ':' : '';
		$total_time = ( $minutes ) ? $total_time . $minutes . ':' : $total_time . '00:';
		$total_time = ( $second ) ? $total_time . $second : $total_time . '00';


		return $total_time;
	}

	/**
	 * @param $json_return
	 * @param $user_id
	 * @param $rows
	 *
	 * @return mixed
	 */
	public static function tc_api_get_userSingleCoursesOverviewTable( $json_return, $user_id, $rows ) {

		global $wpdb;

		//Users' Completed Timers
		$sql_string       = "SELECT meta_value, meta_key FROM $wpdb->usermeta WHERE meta_key LIKE 'course_timer_completed_%' AND user_id = {$user_id}";
		$timers           = $wpdb->get_results( $sql_string );
		$timer_rearranged = [];
		foreach ( $timers as $timer ) {
			$timer_key = $timer->meta_key;
			$timer_key = explode( '_', $timer_key );
			$time      = $timer->meta_value;
			$seconds   = 0;
			if ( '' !== $time ) {
				$seconds = explode( ':', $time );
				$seconds = ( intval( $seconds[0] ) * 60 * 60 ) + ( intval( $seconds[1] ) * 60 ) + intval( $seconds[2] );
			}

			$timer_rearranged[ (int) $timer_key[3] ] = $seconds;
		}

		//Users' Time Spent
		$sql_string             = "SELECT meta_key, meta_value FROM $wpdb->usermeta WHERE meta_key LIKE 'uo_timer_%' AND user_id = {$user_id}";
		$times_spent            = $wpdb->get_results( $sql_string );
		$times_spent_rearranged = [];
		foreach ( $times_spent as $time_spent ) {

			$time_spent_key = $time_spent->meta_key;
			$time_key       = explode( '_', $time_spent_key );
			$time           = $time_spent->meta_value;
			$seconds        = (int) $time;

			if ( isset( $times_spent_rearranged[ (int) $time_key[2] ] ) ) {
				$times_spent_rearranged[ (int) $time_key[2] ] = $times_spent_rearranged[ (int) $time_key[2] ] + $seconds;
			} else {
				$times_spent_rearranged[ (int) $time_key[2] ] = $seconds;
			}
		}

		foreach ( $json_return['data'] as $row_id => &$row ) {
			$row['timeComplete'] = ( isset( $timer_rearranged[ $row['course_id'] ] ) ) ? self::convert_second_to_time( $timer_rearranged[ $row['course_id'] ] ) : '---';
			$row['timeSpent']    = ( isset( $times_spent_rearranged[ $row['course_id'] ] ) ) ? self::convert_second_to_time( $times_spent_rearranged[ $row['course_id'] ] ) : '---';
		}

		return $json_return;
	}

	/**
	 * @param $json_return
	 * @param $course_id
	 * @param $rows
	 *
	 * @return mixed
	 */
	public static function tc_api_get_courseSingleTable( $json_return, $course_id, $rows ) {

		global $wpdb;

		//Users' Completed Timers
		$sql_string       = "SELECT user_id, meta_value FROM $wpdb->usermeta WHERE meta_key = 'course_timer_completed_{$course_id}'";
		$timers           = $wpdb->get_results( $sql_string );
		$timer_rearranged = [];
		foreach ( $timers as $timer ) {

			$user_id = (int) $timer->user_id;
			$time    = $timer->meta_value;
			$seconds = 0;
			if ( '' !== $time ) {
				$seconds = explode( ':', $time );
				$seconds = ( intval( $seconds[0] ) * 60 * 60 ) + ( intval( $seconds[1] ) * 60 ) + intval( $seconds[2] );
			}

			$timer_rearranged[ $user_id ] = $seconds;
		}

		//Users' Time Spent
		$sql_string             = "SELECT user_id, meta_value FROM $wpdb->usermeta WHERE meta_key LIKE 'uo_timer_{$course_id}%'";
		$times_spent            = $wpdb->get_results( $sql_string );
		$times_spent_rearranged = [];
		foreach ( $times_spent as $time_spent ) {

			$user_id = (int) $time_spent->user_id;
			$time    = $time_spent->meta_value;
			$seconds = (int) $time;

			if ( isset( $times_spent_rearranged[ $user_id ] ) ) {
				$times_spent_rearranged[ $user_id ] = $times_spent_rearranged[ $user_id ] + $seconds;
			} else {
				$times_spent_rearranged[ $user_id ] = $seconds;
			}
		}

		foreach ( $json_return['data'] as $row_id => &$row ) {
			$row['timeComplete'] = ( isset( $timer_rearranged[ $row['user_id'] ] ) ) ? self::convert_second_to_time( $timer_rearranged[ $row['user_id'] ] ) : '---';
			$row['timeSpent']    = ( isset( $times_spent_rearranged[ $row['user_id'] ] ) ) ? self::convert_second_to_time( $times_spent_rearranged[ $row['user_id'] ] ) : '---';
		}

		return $json_return;
	}

	/**
	 * @param $return
	 *
	 * @return array
	 */
	public static function tc_api_get_courses_overview( $return ) {


		global $wpdb;

		//Users' Completed Timers
		$sql_string       = "SELECT user_id, meta_key, meta_value FROM $wpdb->usermeta WHERE meta_key LIKE 'course_timer_completed_%'";
		$timers           = $wpdb->get_results( $sql_string );
		$timer_rearranged = [];
		foreach ( $timers as $timer ) {

			$user_id   = (int) $timer->user_id;
			$timer_key = $timer->meta_key;
			$timer_key = explode( '_', $timer_key );
			$time      = $timer->meta_value;
			$seconds   = 0;
			if ( '' !== $time ) {
				$seconds = explode( ':', $time );
				$seconds = ( intval( $seconds[0] ) * 60 * 60 ) + ( intval( $seconds[1] ) * 60 ) + intval( $seconds[2] );
			}

			$timer_rearranged[ $user_id ][ (int) $timer_key[3] ] = $seconds;
		}

		//Users' Time Spent
		$sql_string             = "SELECT user_id, meta_key, meta_value FROM $wpdb->usermeta WHERE meta_key LIKE 'uo_timer_%'";
		$times_spent            = $wpdb->get_results( $sql_string );
		$times_spent_rearranged = [];
		foreach ( $times_spent as $time_spent ) {

			$user_id        = (int) $time_spent->user_id;
			$time_spent_key = $time_spent->meta_key;
			$time_key       = explode( '_', $time_spent_key );
			$time           = $time_spent->meta_value;
			$seconds        = (int) $time;

			if ( isset( $times_spent_rearranged[ $user_id ][ (int) $time_key[2] ] ) ) {
				$times_spent_rearranged[ $user_id ][ (int) $time_key[2] ] = $times_spent_rearranged[ $user_id ][ (int) $time_key[2] ] + $seconds;
			} else {
				$times_spent_rearranged[ $user_id ][ (int) $time_key[2] ] = $seconds;
			}
		}

		$course_avg_time_complete = [];
		$course_avg_time_spent    = [];

		foreach ( $return['data']['courseList'] as $course_id => $course ) {
			$user_access = $return['data']['userList']['course_access_list'][ $course_id ];
			foreach ( $user_access as $user_id ) {

				if ( isset( $times_spent_rearranged[ $user_id ][ $course_id ] ) ) {
					$course_avg_time_spent[ $course_id ][] = $times_spent_rearranged[ $user_id ][ $course_id ];
				}
				if ( isset( $timer_rearranged[ $user_id ][ $course_id ] ) ) {
					$course_avg_time_complete[ $course_id ][] = $timer_rearranged[ $user_id ][ $course_id ];
				}
			}

			if ( empty( $course_avg_time_complete[ $course_id ] ) ) {
				$avg_seconds = '---';
			} else {
				$avg_seconds = array_sum( $course_avg_time_complete[ $course_id ] ) / count( $course_avg_time_complete[ $course_id ] );
				$avg_seconds = sprintf( '%02d:%02d:%02d', ( $avg_seconds / 3600 ), ( $avg_seconds / 60 % 60 ), $avg_seconds % 60 );
			}

			$return['additionalData'][ $course_id ]['avgTimeComplete'] = $avg_seconds;

			if ( empty( $course_avg_time_spent[ $course_id ] ) ) {
				$avg_seconds = '---';
			} else {
				$avg_seconds = array_sum( $course_avg_time_spent[ $course_id ] ) / count( $course_avg_time_spent[ $course_id ] );
				$avg_seconds = sprintf( '%02d:%02d:%02d', ( $avg_seconds / 3600 ), ( $avg_seconds / 60 % 60 ), $avg_seconds % 60 );
			}

			$return['additionalData'][ $course_id ]['avgTimeSpent'] = $avg_seconds;
		}


		return $return;
	}

	/**
	 * @return void
	 */
	public static function uo_timer_interval_convert_text_to_number() {
		?>
		<script>jQuery(document).ready(function ($) {
				$(document).on("click",".ult-directory-module-settings",function() {
					var timerSetting = $(this).data("settings");
					var timerSettingVal = parseInt($('input[name="uo_timer_interval"]').val());
					if(timerSetting=='uncanny_pro_toolkitCourseTimer' && isNaN(timerSettingVal)){
						$('input[name="uo_timer_interval"]').val(20);
					}
				});
				$('input[name="uo_timer_interval"]').blur(function () {
					var val = parseInt($(this).val());
					if (val < 5 || isNaN(val)) {
						$(this).val(20);
					}
				})
			})</script><?php
	}

	/**
	 * Description of class in Admin View
	 *
	 * @return array
	 */
	public static function get_details() {
		$module_id = 'simple-course-timer';

		$class_title = esc_html__( 'Simple Course Timer', 'uncanny-pro-toolkit' );

		$kb_link = 'http://www.uncannyowl.com/knowledge-base/simple-course-timer/';

		/* Sample Simple Description with shortcode */
		$class_description = esc_html__( 'Tracks time spent in all LearnDash courses and detects when a user is idle. Course completion time and total course time are both added to LearnDash reports. Enables blocking access to quizzes until minimum time spent in course.', 'uncanny-pro-toolkit' );

		/* Icon as fontawesome icon */
		$class_icon = '<i class="uo_icon_pro_fa uo_icon_fa fa fa-clock-o"></i><span class="uo_pro_text">PRO</span>';

		$category = 'learndash';
		$type     = 'pro';

		return array(
			'id'               => $module_id,
			'title'            => $class_title,
			'type'             => $type,
			'category'         => $category,
			'kb_link'          => $kb_link, // OR set as null not to display
			'description'      => $class_description,
			'dependants_exist' => self::dependants_exist(),
			/*'settings' => false, // OR */
			'settings'         => self::get_class_settings( $class_title ),
			'icon'             => $class_icon,
		);

	}

	/* Add Idle time to LeearnDash Options Meta Box
	 *@param array $post_args array of options from the LearnDash custom post type option meta box
	 */

	/**
	 * HTML for modal to create settings
	 *
	 * @static
	 *
	 * @param $class_title
	 *
	 * @return HTML
	 */
	public static function get_class_settings( $class_title ) {

		// Get pages to populate drop down
		$args = array(
			'sort_order'  => 'asc',
			'sort_column' => 'post_title',
			'post_type'   => 'page',
			'post_status' => 'publish',
		);

		$pages     = get_pages( $args );
		$drop_down = array();
		array_push( $drop_down, array(
			'value' => '',
			'text'  => esc_attr__( 'Select a Page', 'uncanny-pro-toolkit' ),
		) );

		foreach ( $pages as $page ) {
			if ( empty( $page->post_title ) ) {
				$page->post_title = esc_attr__( '(no title)', 'uncanny-pro-toolkit' );
			}

			array_push( $drop_down, array(
				'value' => $page->ID, 'text' => $page->post_title,
			) );
		}

		// Create options
		$options = array(

			array(
				'type'        => 'text',
				'label'       => esc_attr__( 'Idle Time (in seconds)', 'uncanny-pro-toolkit' ),
				'option_name' => 'default_idle_time',
			),
			array(
				'type'        => 'text',
				'label'       => esc_attr__( 'Idle Message', 'uncanny-pro-toolkit' ),
				'option_name' => 'timed_out_message',
			),
			array(
				'type'        => 'text',
				'label'       => esc_attr__( 'Active Button Label', 'uncanny-pro-toolkit' ),
				'option_name' => 'active_button_text',
			),
			array(
				'type'        => 'text',
				'label'       => esc_attr__( 'Inactive Button Label', 'uncanny-pro-toolkit' ),
				'option_name' => 'inactive_button_text',
			),
			array(
				'type'        => 'select',
				'label'       => esc_attr__( 'Inactive Redirect', 'uncanny-pro-toolkit' ),
				'select_name' => 'timed_out_redirect',
				'options'     => $drop_down,
			),
			array(
				'type'        => 'checkbox',
				'label'       => esc_attr__( 'Enable Quizzes after X time', 'uncanny-pro-toolkit' ),
				'option_name' => 'minimum_course_time_before_quiz_access',
			),
			array(
				'type'       => 'html',
				'class'      => 'uo-additional-information',
				'inner_html' => '<div style="margin-top: -16px;font-style: italic;">' .
								esc_attr__( 'Enable minimum course time before learners can attempt quizzes. Minimum course time value is set in quizzes.', 'uncanny-pro-toolkit' ) .
								'</div>',
			),
			array(
				'type'        => 'text',
				'label'       => esc_attr__( 'Timer Polling Interval (in seconds)', 'uncanny-pro-toolkit' ),
				'option_name' => 'uo_timer_interval',
			),
			array(
				'type'       => 'html',
				'class'      => 'uo-additional-information',
				'inner_html' => '<div style="margin-top: -15px;font-style: italic;">' .
								esc_attr__( 'The minimum polling interval is 5 seconds. Lower values use more server resources.', 'uncanny-pro-toolkit' ) .
								'</div>',
			),
			array(
				'type'        => 'checkbox',
				'label'       => esc_attr__( 'Disable Performance Mode', 'uncanny-pro-toolkit' ),
				'option_name' => 'disable_performance_timer',
			),
			array(
				'type'       => 'html',
				'class'      => 'uo-additional-information',
				'inner_html' => '<div style="margin-top: -13px;font-style: italic;">' .
								esc_attr__( 'Performance Mode uses a simplified REST API call that reduces load on the server.', 'uncanny-pro-toolkit' ) .
								'</div>',
			),
			array(
				'type'        => 'checkbox',
				'label'       => esc_attr__( 'Enable Debug Mode', 'uncanny-pro-toolkit' ),
				'option_name' => 'enable_debug_mode',
			),

		);

		// Build html
		$html = self::settings_output( array(
			'class'   => __CLASS__,
			'title'   => $class_title,
			'options' => $options,
		) );

		return $html;
	}

	/* Add minimum Course Time to LeearnDash Options Meta Box
	 * @since 1.3
	 *
	 *@param array $post_args array of options from the LearnDash custom post type option meta box
	 */

	/**
	 * @param $post_args
	 *
	 * @return array
	 */
	public static function add_idle_time_to_post_args_legacy( $post_args ) {

		if ( class_exists( 'LearnDash_Theme_Register' ) ) {
			return $post_args;
		}
		// Push existing and new fields
		$new_post_args = array();

		// Loop through all post arguments
		foreach ( $post_args as $key => $val ) {

			$new_post_args[ $key ] = $val;
			// add option on LD post type settings meta box
			if ( in_array( $val['post_type'], self::$timed_post_types ) ) {
				//Add new field to top
				$new_post_args[ $key ]['fields']['uo_timer_idle'] = array(
					'name'      => esc_attr__( 'Idle time (seconds)', 'uncanny-pro-toolkit' ),
					'type'      => 'text',
					'help_text' => esc_attr__( 'Set the time in seconds until a user is flagged as inactive for time tracking purposes', 'uncanny-pro-toolkit' ),
					'default'   => '0',
				);
			}
		}

		return $new_post_args;
	}

	/**
	 * @param $post_args
	 *
	 * @return array
	 */
	public static function add_min_course_time_to_post_args( $post_args ) {

		if ( class_exists( 'LearnDash_Theme_Register' ) ) {
			return $post_args;
		}

		$minimum_course_time_before_quiz_access = self::get_settings_value( 'minimum_course_time_before_quiz_access', __CLASS__ );

		if ( 'on' === $minimum_course_time_before_quiz_access ) {

			// Push existing and new fields
			$new_post_args = array();

			// Loop through all post arguments
			foreach ( $post_args as $key => $val ) {

				$new_post_args[ $key ] = $val;

				// add option on LD post type settings meta box
				if ( 'sfwd-quiz' === $val['post_type'] ) {

					//Add new field to top
					$new_post_args[ $key ]['fields']['minimum_course_time_before_quiz_access'] = array(
						'name'      => esc_attr__( 'Minimum Course Time (in minutes)', 'uncanny-pro-toolkit' ),
						'type'      => 'text',
						'help_text' => esc_attr__( 'Only allow access to the quiz when the user\'s time spent in the course EQUALS OR EXCEEDS this value in minutes.', 'uncanny-pro-toolkit' ),
						'default'   => '0',
					);
				}
			}

			return $new_post_args;

		} else {
			return $post_args;
		}

	}

	/**
	 * @param $content
	 *
	 * @return false|string
	 */
	public static function filter_quiz_content( $content ) {

		$current_post = $GLOBALS['post'];

		if ( ! is_object($current_post) || ! isset($current_post->post_type) || 'sfwd-quiz' !== $current_post->post_type ) {
			return $content;
		}

		global $wpdb;

		$user_ID = get_current_user_id();

		$timer_results = self::get_course_time_in_seconds( $current_post->ID, $user_ID );

		if ( $timer_results ) {
			$current_minutes = floor( $timer_results / 60 );
		} else {
			$current_minutes = 0;
		}

		$post_options = learndash_get_setting( $current_post );

		if ( ! isset( $post_options['minimum_course_time_before_quiz_access'] ) || 0 === (int) $post_options['minimum_course_time_before_quiz_access'] ) {
			return $content;
		}

		$current_post = $GLOBALS['post'];

		$quiz_post_html_id = 'post-' . $current_post->ID;

		$ld_quiz_post_html_class = 'learndash_post_' . $current_post->ID;

		$min_minutes = $post_options['minimum_course_time_before_quiz_access'];

		if ( $min_minutes <= $current_minutes ) {
			return $content;
		}

		$course_id = learndash_get_course_id();

		if ( ! $course_id ) {
			$lesson_id = learndash_get_lesson_id();
			$course_id = learndash_get_course_id( $lesson_id );
		}

		if( true !== self::is_course_timer_enabled( $course_id ) ) {
			return $content;
		}

		$course_name = get_the_title( $course_id );
		$permalink   = esc_url( get_permalink( $course_id ) );


		$course_link = '<a href="' . $permalink . '">' . $course_name . '</a>';

		$message = '<div id="ultp-course-timer-quiz-can-not-access">';
		$message .= '<p>' . sprintf( esc_attr__( 'You must spend %1$s minutes in the course before you can attempt the quiz. You have currently spent %2$s minutes. Please go back and review course material before attempting the quiz.', 'uncanny-pro-toolkit' ), $min_minutes, $current_minutes ) . '</p>';
		$message .= '<p>' . sprintf( esc_attr__( 'Return to %s', 'uncanny-pro-toolkit' ), $course_link ) . '</p>';
		$message .= '</div>';

		ob_start();
		?>
		<script>

			var i;

			var lduoQuizContainer = document.getElementById('<?php echo $quiz_post_html_id; ?>');

			if (lduoQuizContainer !== null) {

				lduoQuizContainer.innerHTML = '<?php echo $message; ?>';

			} else {

				// Sometimes theme may forget the id attribute in the article tag ex. Avada... check class
				lduoQuizContainer = document.getElementsByClassName('<?php echo $quiz_post_html_id; ?>');

				// The theme didn't add it as a class either
				if (0 === lduoQuizContainer.length) {
					// check for a learndash ID that was added recently
					var ldQuizPostHtmlClass = document.getElementById('<?php echo $ld_quiz_post_html_class; ?>');

					ldQuizPostHtmlClass.style.display = 'none';

					jQuery(document).ready(function () {
						var ldQuizPostHtmlClass = document.getElementById('<?php echo $ld_quiz_post_html_class; ?>');
						if (null !== ldQuizPostHtmlClass) {
							ldQuizPostHtmlClass.innerHTML = '<?php echo $message; ?>';
							ldQuizPostHtmlClass.style.display = 'block';
						}
					});

				} else {
					for (i = 0; i < lduoQuizContainer.length; i++) {
						lduoQuizContainer[i].innerHTML = '<?php echo $message; ?>';
					}
				}

			}
		</script>
		<?php

		return ob_get_clean();
	}

	/**
	 * @param $course_id
	 * @param $user_ID
	 *
	 * @return string|null
	 */
	public static function get_course_time_in_seconds( $course_id, $user_ID ) {

		global $wpdb;

		$completed_on_meta_key = 'uo_timer_' . learndash_get_course_id( $course_id ) . '_%';

		$query_results = $wpdb->prepare( "SELECT SUM( meta_value ) FROM $wpdb->usermeta WHERE meta_key LIKE %s AND user_id = %d", $completed_on_meta_key, $user_ID );

		$timer_results = $wpdb->get_var( $query_results );

		return $timer_results;

	}

	/**
	 * @param $course_id
	 *
	 * @return bool
	 */
	public static function is_course_timer_enabled( $course_id ) {
		return (bool) apply_filters( 'uo_course_timer_enabled', true, $course_id );
	}

	/**
	 * @return void
	 */
	public static function add_timer_scripts() {


		global $post_type;
		global $post;

		if ( ! is_404() && ! is_archive() && in_array( $post_type, self::$timed_post_types ) && is_user_logged_in() ) {

			$course_id = learndash_get_course_id( $post->ID );

			if ( '0' === $course_id || '' === $course_id ) {
				$lesson_id = learndash_get_lesson_id( $post->ID, $course_id );
				if ( '0' === $lesson_id || '' === $lesson_id ) {
					$course_id = 1;
				} else {
					$course_id = learndash_get_course_id( $lesson_id );
				}
			}

			if ( 'sfwd-courses' === $post->post_type ) {
				$course_id = $post->ID;
			}

			if( true !== self::is_course_timer_enabled( $course_id ) ) {
				return;
			}

			// Set Time out
			$idle_time_out            = 900;
			$feature_time_out_default = self::get_settings_value( 'default_idle_time', __CLASS__ );

			if ( '' !== $feature_time_out_default ) {
				$idle_time_out = (int) $feature_time_out_default;
			}

			$post_options_timeout = learndash_get_setting( $post );

			if ( isset( $post_options_timeout['uo_timer_idle'] ) && 0 !== (int) $post_options_timeout['uo_timer_idle'] ) {
				$idle_time_out = (int) $post_options_timeout['uo_timer_idle'];
			}

			// Set Dialog Text
			$active_button_text         = esc_attr__( 'Still here', 'uncanny-pro-toolkit' );
			$feature_active_button_text = self::get_settings_value( 'active_button_text', __CLASS__ );

			if ( '' !== $feature_active_button_text ) {
				$active_button_text = $feature_active_button_text;
			}

			$inactive_button_text         = esc_attr__( 'I\'m done', 'uncanny-pro-toolkit' );
			$feature_inactive_button_text = self::get_settings_value( 'inactive_button_text', __CLASS__ );

			if ( '' !== $feature_inactive_button_text ) {
				$inactive_button_text = $feature_inactive_button_text;
			}

			$timed_out_message         = esc_attr__( 'Are you still working on this section?', 'uncanny-pro-toolkit' );
			$feature_timed_out_message = self::get_settings_value( 'timed_out_message', __CLASS__ );

			if ( '' !== $feature_timed_out_message ) {
				$timed_out_message = $feature_timed_out_message;
			}

			$timed_out_redirect         = home_url();
			$feature_timed_out_redirect = self::get_settings_value( 'timed_out_redirect', __CLASS__ );

			if ( '' !== $feature_timed_out_redirect ) {
				$timed_out_redirect = get_permalink( $feature_timed_out_redirect );
			}

			$disable_performance_timer         = 'true';
			$feature_disable_performance_timer = self::get_settings_value( 'disable_performance_timer', __CLASS__ );

			if ( '' !== $feature_disable_performance_timer ) {
				$disable_performance_timer = 'false';
			}

			$enable_debug_mode         = 'false';
			$feature_enable_debug_mode = self::get_settings_value( 'enable_debug_mode', __CLASS__ );

			if ( '' !== $feature_enable_debug_mode ) {
				$enable_debug_mode = 'true';
			}

			// Dialog Box Style
			$dialog_box_style = plugins_url( basename( dirname( UO_FILE ) ) ) . '/src/assets/legacy/frontend/css/jquery.dialogbox.css';
			wp_enqueue_style( 'jquery-dialog-box-style', $dialog_box_style, array(), UNCANNY_TOOLKIT_PRO_VERSION );

			// Dialog Box Script @ http://www.jqueryscript.net/lightbox/Simple-Flexible-jQuery-Dialog-Popup-Plugin-dialogBox.html
			$idle_timer_url = plugins_url( basename( dirname( UO_FILE ) ) ) . '/src/assets/legacy/frontend/js/jquery.dialogBox.js';
			wp_enqueue_script( 'jquery-dialog-box', $idle_timer_url, array( 'jquery' ), '0.0.2', true );

			// Throst Idle Timer @ https://github.com/thorst/jquery-idletimer
			$idle_timer_url = plugins_url( basename( dirname( UO_FILE ) ) ) . '/src/assets/legacy/frontend/js/idle-timer.js';
			wp_enqueue_script( 'throst-idle-timer', $idle_timer_url, array( 'jquery' ), '1.1.0', true );

			// Timer Script
			$uo_timer_url = plugins_url( basename( dirname( UO_FILE ) ) ) . '/src/assets/legacy/frontend/js/uo-timer.js';
			wp_register_script( 'uo-timer-js', $uo_timer_url, array(
				'throst-idle-timer',
				'jquery-dialog-box',
			), UNCANNY_TOOLKIT_PRO_VERSION, true );

			add_filter( 'nonce_life', array(
				__CLASS__, 'change_course_timer_nonce_life',
			) );
			remove_filter( 'nonce_life', array(
				__CLASS__, 'change_course_timer_nonce_life',
			) );

			// Amount of time added every call // JS interval must match
			$timer_interval = self::get_settings_value( 'uo_timer_interval', __CLASS__ );

			//  Set timer default, mininum interval is 20 seconds
			if ( '' === $timer_interval || (int) $timer_interval < 5 ) {
				$timer_interval = 20;
			}

			$localize_data_array = array(
				'courseID'               => $course_id,
				'postID'                 => $post->ID,
				'idleTimeOut'            => $idle_time_out,
				'apiUrl'                 => esc_url_raw( rest_url() . 'uo_pro/v1/add_timer/' ),
				'nonce'                  => wp_create_nonce( 'wp_rest' ),
				'redirect'               => $timed_out_redirect,
				'inactiveButtonText'     => $inactive_button_text,
				'activeButtonText'       => $active_button_text,
				'timedOutMessage'        => $timed_out_message,
				'uoHeartBeatInterval'    => (int) $timer_interval,
				'enablePerformanceTimer' => $disable_performance_timer,
				'enableDebugMode'        => $enable_debug_mode,
				'performanceApiUrl'      => apply_filters( 'performance_timer_url', plugins_url( basename( dirname( UO_FILE ) ) ) . '/src/includes/simple_timer_performance.php' ),


			);

			wp_localize_script( 'uo-timer-js', 'uoTimer', $localize_data_array );
			wp_enqueue_script( 'uo-timer-js' );

		}

	}

	/**
	 * @return void
	 */
	public static function add_tc_timer_scripts() {

		global $post;

		if ( empty( $post->ID ) ) {
			return;
		}

		if ( ! has_shortcode( $post->post_content, 'tincanny' ) && ! has_block( 'tincanny/course-user-report', $post ) ) {
			return;
		}

		$plugin_base_url = plugins_url( basename( dirname( UO_FILE ) ) );

		wp_enqueue_script( 'hooks', $plugin_base_url . '/src/assets/legacy/backend/js/hooks.min.js?ver=2.0.4' );

		$script_url = $plugin_base_url . '/src/assets/legacy/backend/js/tincany-timer.js';
		wp_register_script( 'tincany-timer', $script_url, array(
			'jquery',
			'wp-hooks',
			'wp-i18n',
		), UNCANNY_TOOLKIT_PRO_VERSION, true );
		$tincanny_timer = array(
			'localizedStrings' => self::get_js_localized_strings(),
		);


		wp_localize_script( 'tincany-timer', 'tincannyTimer', $tincanny_timer );

		wp_enqueue_script( 'tincany-timer' );

	}

	/**
	 * @return array
	 */
	private static function get_js_localized_strings() {

		/**
		 * listed as they appear in file order under \plugins\tin-canny-learndash-reporting\src\assets\admin\js\scripts\components\*.js
		 */
		return array(
			// tables.js
			'Avg Time To Complete' => esc_attr__( 'Avg Time To Complete', 'uncanny-pro-toolkit' ),
			'Avg Time Spent'       => esc_attr__( 'Avg Time Spent', 'uncanny-pro-toolkit' ),
			'Avg Time To Complete' => esc_attr__( 'Avg Time To Complete', 'uncanny-pro-toolkit' ),
			'Time To Complete'     => esc_attr__( 'Time To Complete', 'uncanny-pro-toolkit' ),
			'Time Spent'           => esc_attr__( 'Time Spent', 'uncanny-pro-toolkit' ),
		);
	}

	/*
	 * Api call to add seconds spent on a module
	 * @param array $data data parse by api call
	 * @return object success or error
	 */

	/**
	 * @param $hook
	 *
	 * @return void
	 */
	public static function add_tc_timer_scripts_admin( $hook ) {

		if ( 'toplevel_page_uncanny-learnDash-reporting' === $hook ) {

			global $wp_version;

			$plugin_base_url = plugins_url( basename( dirname( UO_FILE ) ) );


			if ( ! wp_script_is( 'wp-hooks', $list = 'enqueued' ) ) {
				if ( version_compare( $wp_version, '5', '<' ) ) {
					wp_enqueue_script( 'hooks', $plugin_base_url . '/src/assets/legacy/backend/js/hooks.min.js?ver=2.0.4' );
				} else {
					wp_enqueue_script( 'wp-hooks' );
				}
			}

			$script_url = $plugin_base_url . '/src/assets/legacy/backend/js/tincany-timer.js';
			wp_register_script( 'tincany-timer', $script_url, array(
				'jquery',
				'wp-hooks',
				'wp-i18n',
			), UNCANNY_TOOLKIT_PRO_VERSION, true );
			$tincanny_timer = array(
				'localizedStrings' => self::get_js_localized_strings(),
			);

			wp_localize_script( 'tincany-timer', 'tincannyTimer', $tincanny_timer );


			wp_enqueue_script( 'tincany-timer' );
		}
	}

	/*
	 * Shortcode that displays time spent on course or learndash module
	 *
	 * @param array $attributes Optional wp user id and post id can be passed
	 * @return string Time spent on a single module or all modules in course in formatted seconds
	 */

	/**
	 * @return void
	 */
	public static function rest_api_init() {

		// Call to store the answer in DB
		// if a field is text (?P<whatever>\w+), if a field is int (?P<whatever>\d+)
		register_rest_route( 'uo_pro/v1', '/add_timer/(?P<course_ID>\w+)/(?P<post_ID>\w+)', array(
			'methods'             => 'GET',
			'callback'            => array( __CLASS__, 'add_timer' ),
			'permission_callback' => function () {
				if ( is_user_logged_in() ) {
					return true;
				}

				return new WP_Error( 'rest_forbidden', esc_attr__( 'You are not allowed to use this resource.', 'uncanny-pro-toolkit' ) );
			},
		) );

	}

	/*
	 * Shortcode that displays time spent on course or learndash module
	 *
	 * @param array $attributes Optional wp user id and post id can be passed
	 * @return string Time spent on a single module or all modules in course in formatted seconds
	 */

	/**
	 * @param $data
	 *
	 * @return array
	 */
	public static function add_timer( $data ) {

		$return_object = array();

		$current_user_id = get_current_user_id();

		// validate inputs
		$course_ID = absint( $data['course_ID'] );
		$post_ID   = absint( $data['post_ID'] );

		// if any of the values are 0 then they didn't validate, storage is not possible
		if ( 0 === $course_ID || 0 === $post_ID ) {
			$return_object['success']             = false;
			$return_object['message']             = esc_attr__( 'One or more the the fields did not validate as a absolute integer', 'uncanny-pro-toolkit' );
			$return_object['fields']['course_ID'] = $data['course_ID'];
			$return_object['fields']['post_ID']   = $data['post_ID'];

			return $return_object;
		}

		if( true !== self::is_course_timer_enabled( $course_ID ) ) {
			$return_object['success']             = false;
			$return_object['message']             = esc_attr__( 'Disabled', 'uncanny-pro-toolkit' );
			$return_object['fields']['course_ID'] = $data['course_ID'];
			$return_object['fields']['post_ID']   = $data['post_ID'];

			return $return_object;
		}

		$meta_key = 'uo_timer_' . $course_ID . '_' . $post_ID;
		$timer    = get_user_meta( $current_user_id, $meta_key, true );

		//  Set timer default
		if ( '' === $timer ) {
			$timer = 0;
		}

		// Amount of time added every call // JS interval must match
		$timer_interval = self::get_settings_value( 'uo_timer_interval', __CLASS__ );

		//  Set timer default, minimum is 20 seconds
		if ( '' === $timer_interval || (int) $timer_interval < 5 ) {
			$timer_interval = 20;
		}


		$timer += $timer_interval;

		update_user_meta( $current_user_id, $meta_key, $timer );

		do_action( 'uo_course_timer_add_timer', $course_ID, $post_ID, $timer_interval );

		$return_object['success'] = true;
		$return_object['time']    = $timer;

		global $uo_time_pre;
		$time_post                  = microtime( true );
		$exec_time                  = $time_post - $uo_time_pre;
		$return_object['exec_time'] = $exec_time;

		return $return_object;
	}

	/*
	 * Get the amount of time it took to complete a course or single module
	 *
	 * @param object $post_object A WP post object
	 * @param int $user_ID WP user ID
	 *
	 * return string Time spent on a single module or all modules on course in formatted seconds
	 */

	/**
	 * @param $attributes
	 *
	 * @return mixed|string|null
	 */
	public static function shortcode_uo_time( $attributes ) {


		$request = shortcode_atts( array(
			'user-id'   => '',
			'course-id' => '',
		), $attributes );

		if ( '' === $request['user-id'] ) {
			$request['user-id'] = get_current_user_id();
		}

		$user_ID = absint( $request['user-id'] );
		$post_ID = absint( $request['course-id'] );

		if ( '' == $request['course-id'] ) {
			global $post;

			if ( ( ! is_404() && ! is_archive() && is_a( $post, 'WP_Post' ) ) ) {
				$course_post = get_post( learndash_get_course_id( $post->ID ) );

				return self::get_uo_time( $course_post, $user_ID );
			}

		} elseif ( $post_ID ) {

			$requested_post = get_post( $post_ID );

			return self::get_uo_time( $requested_post, $user_ID );
		}

		return '';
	}

	/**
	 * @param $post_object
	 * @param $user_ID
	 * @param $raw
	 *
	 * @return mixed|string|null
	 */
	public static function get_uo_time( $post_object, $user_ID, $raw = false ) {

		if ( $post_object->post_type == 'sfwd-courses' ) {

			// count all timed sections of course
			$course_cumulative_time = self::get_course_time_in_seconds( $post_object->ID, $user_ID );

			if ( $raw ) {
				return $course_cumulative_time;
			}

			return self::convert_second_to_time( $course_cumulative_time );

		} elseif ( in_array( $post_object->post_type, self::$timed_post_types ) ) {
			// return specific time
			$course_ID = learndash_get_course_id( $post_object->ID );
			$meta_key  = 'uo_timer_' . $course_ID . '_' . $post_object->ID;
			$timer     = get_user_meta( (int) $user_ID, $meta_key, true );

			if ( $raw ) {
				return $timer;
			}

			return self::convert_second_to_time( (int) $timer );

		}

		return '';

	}

	/**
	 * @return string
	 */
	public static function shortcode_uo_time_live() {

		global $post;
		$course_post = false;
		if ( ! is_404() && ! is_archive() && is_a( $post, 'WP_Post' ) ) {

			// Check this is a LearnDash Post Type
			if ( ! in_array( $post->post_type, self::$timed_post_types ) ) {
				return '';
			}

			$course_post = get_post( learndash_get_course_id( $post->ID ) );
			if ( ! is_a( $course_post, 'WP_Post' ) ) {
				return '';
			}
		}

		$time = self::get_uo_time( $course_post, get_current_user_id() );
		$time = empty( $time ) ? '00:00:00' : $time; // If time is empty, set it to 00:00:00

		return '<span class="uotp-time-live">' . $time . '</span>';
	}

	/**
	 * @param $attributes
	 *
	 * @return mixed|string
	 */
	public static function shortcode_uo_time_course_completed( $attributes ) {

		$request = shortcode_atts( array(
			'user-id'   => '',
			'course-id' => '',
		), $attributes );

		if ( '' === $request['user-id'] ) {
			$request['user-id'] = get_current_user_id();
		}

		$user_ID   = absint( $request['user-id'] );
		$course_ID = absint( $request['course-id'] );

		if ( ! $course_ID ) {
			global $post;

			if ( ( ! is_404() && ! is_archive() && is_a( $post, 'WP_Post' ) ) ) {

				if ( 'sfwd-courses' !== $post->post_type ) {
					return '';
				}

				$course_ID = $post->ID;
			}

		} else {

			$post_type = get_post_type( $course_ID );
			if ( 'sfwd-courses' !== $post_type ) {
				return '';
			}
		}

		if( true !== self::is_course_timer_enabled( $course_ID ) ) {
			return '';
		}

		$meta_key           = 'course_timer_completed_' . $course_ID;
		$time_at_completion = get_user_meta( $user_ID, $meta_key, true );

		return $time_at_completion;

	}

	/**
	 * Filter Before LearnDash CVS is loaded
	 *
	 * @param array $content
	 *
	 * @return array $content
	 */
	public static function course_export_data_filter( $content ) {

		// In this peculiar case, the organization of the key value pairs plays a huge role in organization
		// of the csv file. The CEU value can't popped at the end because there will be a variable number of
		// 'lessons completed' columns for each course/user combo. The CEU value must immediately follow
		// the "course_completed_on" column.

		foreach ( $content as &$data ) {
			$user_ID   = (int) $data['user_id'];
			$course_id = (int) $data['course_id'];

			$new_row_data = array();

			// Re-organize array key value pairs so that CEU comes after course_completed_on.
			// If other filters are present and using the same organization they may push CEU after them
			// depending on the order of the filter execution.
			foreach ( $data as $key => $value ) {
				$new_row_data[ $key ] = $value;
				if ( $key === 'course_completed_on' ) {
					$new_row_data['total_time']      = self::get_uo_time( get_post( $course_id ), $user_ID );
					$meta_key                        = 'course_timer_completed_' . $course_id;
					$new_row_data['completion_time'] = get_user_meta( $user_ID, $meta_key, true );
				}
			}

			$data = $new_row_data;
		}

		return $content;
	}

	/**
	 * Filter Headers Before LearnDash CVS is loaded
	 *
	 * The header filter does to things. It creates the CSV heading and defined
	 * the function that will return the value of the column row.
	 *
	 * @param array $data_headers column definitions
	 * @param string $data_slug The report type
	 *
	 * @return array $data_headers
	 */
	public static function course_export_upgraded_headers_filter( $data_headers, $data_slug ) {

		if ( 'user-courses' === $data_slug ) {

			$data_headers['total_time'] = array(
				'label'   => 'total_time',
				'default' => '',
				'display' => [ __CLASS__, 'report_column' ],
			);

			$data_headers['completion_time'] = array(
				'label'   => 'completion_time',
				'default' => '',
				'display' => [ __CLASS__, 'report_column' ],
			);

		}


		return $data_headers;
	}

	/*
	 * Fetches the sum of all posts associated with the course including the course page
	 *
	 * @param int $course_id The ID of the course
	 * @param int $user_ID The users ID
	 * $return string $total_time Total time in seconds for the course
	 */

	/**
	 * This function defines the content value
	 *
	 * The header filter does to things. It creates the CSV heading and defined
	 * the function that will return the value of the column row.
	 *
	 * @param string $column_value The value of the column
	 * @param string $column_key The key set by $data_headers['sample_key'] @
	 *     course_export_upgraded_headers_filter()
	 * @param object $report_item The LD activity object
	 * @param object $report_user WP_User object
	 *
	 * @return mixed $column_value
	 */
	public static function report_column( $column_value = '', $column_key = '', $report_item = null, $report_user = null ) {

		if ( ! is_object( $report_item ) ) {
			return $column_value;
		}

		switch ( $column_key ) {
			case 'total_time':
				if ( $report_user instanceof WP_User ) {
					$column_value = self::get_uo_time( get_post( $report_item->post_id ), $report_user->ID );
				}
				break;

			case 'completion_time':
				if ( $report_user instanceof WP_User ) {

					$meta_key     = 'course_timer_completed_' . $report_item->post_id;
					$column_value = get_user_meta( $report_user->ID, $meta_key, true );
				}
				break;

			default:
				break;
		}

		return $column_value;

	}

	/*
	 * Convert Seconds to 00:00:00 (hours : minutes : seconds ) Format
	 *
	 * @param int $seconds time in seconds
	 * $return string $total_time seconds formatted
	 */

	/**
	 * @param $data
	 *
	 * @return void
	 */
	public static function uo_course_completed_store_timer( $data ) {

		$user_ID    = $data['user']->ID;
		$course     = $data['course'];
		$meta_key   = 'course_timer_completed_' . $course->ID;
		$meta_value = self::get_uo_time( $course, $user_ID );

		update_user_meta( $user_ID, $meta_key, $meta_value );

	}

	/**
	 * Delete user data
	 *
	 * @param int $user_id
	 *
	 * @since 2.1.0
	 *
	 */
	public static function learndash_delete_user_data( $user_id ) {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		$user = get_user_by( 'id', $user_id );

		if ( ! empty( $user->ID ) && ! empty( filter_input( INPUT_POST, 'learndash_delete_user_data' ) ) && $user->ID == filter_input( INPUT_POST, 'learndash_delete_user_data' ) ) {

			global $wpdb;

			// Delete timer
			$timer_meta_key = 'uo_timer_%';

			$query_results = $wpdb->prepare( "DELETE FROM $wpdb->usermeta WHERE meta_key LIKE %s AND user_id = %d", $timer_meta_key, $user_id );

			// Delete time set at user completions
			$wpdb->query( $query_results );

			$completed_timer_meta_key = 'course_timer_completed_%';

			$query_results = $wpdb->prepare( "DELETE FROM $wpdb->usermeta WHERE meta_key LIKE %s AND user_id = %d", $completed_timer_meta_key, $user_id );

			$wpdb->query( $query_results );


		}
	}


	/**
	 * Delete user course data
	 *
	 * @param $user_id
	 * @param $course_id
	 *
	 * @return void
	 */
	public static function delete_user_course_data( $user_id, $course_id ) {

		$user = get_user_by( 'id', $user_id );


		if ( ! empty( $user->ID ) && ! empty( $course_id ) ) {

			global $wpdb;

			// Delete timer
			$timer_meta_key = 'uo_timer_' . $course_id . '_%%';

			$query_results = $wpdb->prepare( "DELETE FROM $wpdb->usermeta WHERE meta_key LIKE %s AND user_id = %d", $timer_meta_key, $user_id );

			// Delete time set at user completions
			$wpdb->query( $query_results );

			$completed_timer_meta_key = 'course_timer_completed_' . $course_id;

			$query_results = $wpdb->prepare( "DELETE FROM $wpdb->usermeta WHERE meta_key LIKE %s AND user_id = %d", $completed_timer_meta_key, $user_id );

			$wpdb->query( $query_results );
		}
	}

	/*
	 * Update nonce life for timer rest api calls
	 *
	 * @since 1.2.0
	 *
	 * @return int
	 */
	/**
	 * @return int
	 */
	public static function change_course_timer_nonce_life() {
		// 48 hours in seconds
		return 172800;
	}

	/**
	 * Add Idle time to LeearnDash Options Meta Box
	 *
	 * @param $setting_option_fields
	 * @param $settings_metabox_key
	 *
	 * @return mixed
	 */
	public static function add_idle_time_to_post_args( $setting_option_fields, $settings_metabox_key ) {

		if ( in_array( $settings_metabox_key, self::$settings_metabox_key ) ) {

			global $post;

			// add option on LD post type settings meta box

			if ( is_object( $post ) && isset( $post->post_type ) && in_array( $post->post_type, self::$timed_post_types ) ) {

				$learndash_post_settings = learndash_get_setting( $post, null );

				$value = '';
				if ( isset( $learndash_post_settings['uo_timer_idle'] ) ) {
					if ( ! empty( $learndash_post_settings['uo_timer_idle'] ) ) {
						$value = $learndash_post_settings['uo_timer_idle'];
					}
				}

				$setting_option_fields['uo_timer_idle'] = [
					'name'      => 'uo_timer_idle',
					'label'     => esc_attr__( 'Idle Time(seconds)', 'uncanny-pro-toolkit' ),
					'type'      => 'text',
					'help_text' => esc_attr__( 'Set the time in seconds until a user is flagged as inactive for time tracking purposes', 'uncanny-pro-toolkit' ),

					'default' => '0',
					'value'   => $value,
				];
			}
		}

		return $setting_option_fields;

	}

	/**
	 * Save post metadata when a post is saved.
	 *
	 * @param int $post_id The post ID.
	 * @param post $post The post object.
	 * @param bool $update Whether this is an existing post being updated or
	 *     not.
	 */
	public static function save_timer_custom_meta( $settings_field_updates, $settings_metabox_key, $settings_screen_id ) {

		global $post;

		if ( in_array( $settings_metabox_key, self::$settings_metabox_key ) ) {
			// - Update the post's metadata. Nonce already verified by LearnDash
			if (
				filter_has_var( INPUT_POST, 'learndash-course-display-content-settings' ) &&
				isset( $_POST['learndash-course-display-content-settings']['uo_timer_idle'] )
			) {
				$auto_complete_setting_value = sanitize_text_field( $_POST['learndash-course-display-content-settings']['uo_timer_idle'] );
				learndash_update_setting( $post, 'uo_timer_idle', $auto_complete_setting_value );
			}

			if (
				filter_has_var( INPUT_POST, 'learndash-lesson-display-content-settings' ) &&
				isset( $_POST['learndash-lesson-display-content-settings']['uo_timer_idle'] )
			) {
				$auto_complete_setting_value = sanitize_text_field( $_POST['learndash-lesson-display-content-settings']['uo_timer_idle'] );
				learndash_update_setting( $post, 'uo_timer_idle', $auto_complete_setting_value );
			}

			if (
				filter_has_var( INPUT_POST, 'learndash-topic-display-content-settings' ) &&
				isset( $_POST['learndash-topic-display-content-settings']['uo_timer_idle'] )
			) {
				$auto_complete_setting_value = sanitize_text_field( $_POST['learndash-topic-display-content-settings']['uo_timer_idle'] );
				learndash_update_setting( $post, 'uo_timer_idle', $auto_complete_setting_value );
			}

			if (
				filter_has_var( INPUT_POST, 'learndash-quiz-display-content-settings' ) &&
				isset( $_POST['learndash-quiz-display-content-settings']['uo_timer_idle'] )
			) {
				$auto_complete_setting_value = sanitize_text_field( $_POST['learndash-quiz-display-content-settings']['uo_timer_idle'] );
				learndash_update_setting( $post, 'uo_timer_idle', $auto_complete_setting_value );
			}
		}

		return $settings_field_updates;
	}

	/**
	 * Add minimum course time to LeearnDash Options Meta Box
	 *
	 * @param $setting_option_fields
	 * @param $settings_metabox_key
	 *
	 * @return mixed
	 */
	public static function add_minimum_course_time_to_post_args( $setting_option_fields, $settings_metabox_key ) {

		if ( 'learndash-quiz-display-content-settings' === $settings_metabox_key ) {
			global $post;

			// add option on LD post type settings meta box

			if ( $post instanceof \WP_Post && in_array( $post->post_type, self::$timed_post_types ) ) {

				$learndash_post_settings = learndash_get_setting( $post, null );

				$value = '';
				if ( isset( $learndash_post_settings['minimum_course_time_before_quiz_access'] ) ) {
					if ( ! empty( $learndash_post_settings['minimum_course_time_before_quiz_access'] ) ) {
						$value = $learndash_post_settings['minimum_course_time_before_quiz_access'];
					}
				}

				$setting_option_fields['minimum_course_time_before_quiz_access'] = [
					'name'      => 'minimum_course_time_before_quiz_access',
					'label'     => esc_attr__( 'Minimum Course Time (in minutes)', 'uncanny-pro-toolkit' ),
					'type'      => 'text',
					'help_text' => esc_attr__( 'Only allow access to the quiz when the user\'s time spent in the course EQUALS OR EXCEEDS this value in minutes.', 'uncanny-pro-toolkit' ),

					'default' => '0',
					'value'   => $value,
				];
			}
		}

		return $setting_option_fields;

	}

	/**
	 * Save post metadata when a post is saved.
	 *
	 * @param int $post_id The post ID.
	 * @param post $post The post object.
	 * @param bool $update Whether this is an existing post being updated or
	 *     not.
	 */
	public static function save_minimum_course_time_custom_meta( $settings_field_updates, $settings_metabox_key, $settings_screen_id ) {

		global $post;

		if ( 'learndash-quiz-display-content-settings' === $settings_metabox_key ) {
			// - Update the post's metadata. Nonce already verified by LearnDash
			if (
				filter_has_var( INPUT_POST, 'learndash-quiz-display-content-settings' ) &&
				isset( $_POST['learndash-quiz-display-content-settings']['minimum_course_time_before_quiz_access'] )
			) {
				$auto_complete_setting_value = sanitize_text_field( $_POST['learndash-quiz-display-content-settings']['minimum_course_time_before_quiz_access'] );
				learndash_update_setting( $post, 'minimum_course_time_before_quiz_access', $auto_complete_setting_value );
			}
		}

		return $settings_field_updates;
	}

	/*
	 * Get the amount of time it took to complete a topic
	 *
	 * @param object $post_object A WP post object
	 * @param int $user_ID WP user ID
	 *
	 * return string Time spent on a topic formatted seconds
	 */

	/**
	 * @param $attributes
	 *
	 * @return mixed|string|null
	 */
	public static function shortcode_uo_time_topic( $attributes ) {

		$request = shortcode_atts( array(
			'user-id'  => '',
			'topic-id' => '',
		), $attributes );

		if ( '' === $request['user-id'] ) {
			$request['user-id'] = get_current_user_id();
		}

		$user_ID = absint( $request['user-id'] );
		$post_ID = absint( $request['topic-id'] );

		$topic_post = null;
		if ( '' == $request['topic-id'] ) {
			global $post;

			if ( ( ! is_404() && ! is_archive() && is_a( $post, 'WP_Post' ) ) ) {
				if ( 'sfwd-topic' == $post->post_type ) {
					$topic_post = $post;
				}
			}

		} elseif ( $post_ID ) {
			$requested_post = get_post( $post_ID );

			if ( is_a( $requested_post, 'WP_Post' ) ) {
				if ( 'sfwd-topic' == $requested_post->post_type ) {
					$topic_post = $requested_post;
				}
			}
		}

		if ( null !== $topic_post && $user_ID > 0 ) {
			$raw_time      = self::get_topic_time( $topic_post, $user_ID );
			$uo_time_topic = self::convert_second_to_time( $raw_time );

			return apply_filters( 'uo_time_topic', $uo_time_topic, $raw_time, $topic_post, $user_ID );
		}

		return '';
	}

	/**
	 * @param $topic_post
	 * @param $user_ID
	 *
	 * @return int|mixed|string|null
	 */
	protected static function get_topic_time( $topic_post, $user_ID ) {

		$uo_time = '';

		if ( is_a( $topic_post, 'WP_Post' ) ) {

			$uo_time = (int) self::get_uo_time( $topic_post, $user_ID, true );

			$topic_id  = $topic_post->ID;
			$course_id = learndash_get_course_id( $topic_id );
			$quizzes   = learndash_get_lesson_quiz_list( $topic_id, null, $course_id );
			if ( ! empty( $quizzes ) ) {
				foreach ( $quizzes as $quiz ) {
					$quiz_time = self::get_uo_time( $quiz['post'], $user_ID, true );
					if ( '' !== $quiz_time ) {
						$uo_time = $uo_time + $quiz_time;
					}
				}
			}
		}

		return $uo_time;
	}

	/*
	 * Get the amount of time it took to complete a lesson
	 *
	 * @param object $post_object A WP post object
	 * @param int $user_ID WP user ID
	 *
	 * return string Time spent on a lesson formatted seconds
	 */

	/**
	 * @param $attributes
	 *
	 * @return mixed|string|null
	 */
	public static function shortcode_uo_time_lesson( $attributes ) {

		$request = shortcode_atts( array(
			'user-id'   => '',
			'lesson-id' => '',
		), $attributes );

		if ( '' === $request['user-id'] ) {
			$request['user-id'] = get_current_user_id();
		}

		$user_ID     = absint( $request['user-id'] );
		$post_ID     = absint( $request['lesson-id'] );
		$raw_time    = '';
		$lesson_post = 0;
		if ( '' == $request['lesson-id'] ) {
			global $post;

			if ( ( ! is_404() && ! is_archive() && is_a( $post, 'WP_Post' ) ) ) {
				if ( 'sfwd-lessons' == $post->post_type ) {
					$lesson_post = $post;
				}
			}

		} elseif ( $post_ID ) {
			$requested_post = get_post( $post_ID );

			if ( is_a( $requested_post, 'WP_Post' ) ) {
				if ( 'sfwd-lessons' == $requested_post->post_type ) {
					$lesson_post = $requested_post;
				}
			}
		}

		if ( is_a( $lesson_post, 'WP_Post' ) && $user_ID > 0 ) {

			$raw_time = (int) self::get_uo_time( $lesson_post, $user_ID, true );

			$course_id = learndash_get_course_id( $lesson_post->ID );

			$quizzes = learndash_get_lesson_quiz_list( $lesson_post, null, $course_id );

			if ( ! empty( $quizzes ) ) {
				foreach ( $quizzes as $quiz ) {
					if ( is_a( $quiz['post'], 'WP_Post' ) ) {
						$quiz_time = self::get_uo_time( $quiz['post'], $user_ID, true );
						if ( '' !== $quiz_time ) {
							$raw_time = $raw_time + $quiz_time;
						}
					}
				}
			}

			$topics = learndash_course_get_topics(
				$course_id,
				$lesson_post->ID,
				array(
					'return_type' => 'WP_Post',
					'per_page'    => 0,
				)
			);

			if ( ! empty( $topics ) ) {
				foreach ( $topics as $topic ) {
					if ( is_a( $topic, 'WP_Post' ) ) {
						$topic_time = self::get_topic_time( $topic, $user_ID );
						if ( '' !== $topic_time ) {
							$raw_time = $raw_time + $topic_time;
						}
					}
				}
			}

			$uo_time_lesson = self::convert_second_to_time( $raw_time );

			return apply_filters( 'uo_time_lesson', $uo_time_lesson, $raw_time, $lesson_post, $user_ID );
		}

		return $raw_time;
	}

	/*
	 * Get the amount of time it took to complete a lesson
	 *
	 * @param object $post_object A WP post object
	 * @param int $user_ID WP user ID
	 *
	 * return string Time spent on a quiz formatted seconds
	 */

	/**
	 * @param $attributes
	 *
	 * @return mixed|string|null
	 */
	public static function shortcode_uo_time_quiz( $attributes ) {

		$request = shortcode_atts( array(
			'user-id' => '',
			'quiz-id' => '',
		), $attributes );

		if ( '' === $request['user-id'] ) {
			$request['user-id'] = get_current_user_id();
		}

		$user_ID = absint( $request['user-id'] );
		$post_ID = absint( $request['quiz-id'] );

		$quiz_post = null;

		if ( '' == $request['quiz-id'] ) {
			global $post;

			if ( ( ! is_404() && ! is_archive() && is_a( $post, 'WP_Post' ) ) ) {
				if ( 'sfwd-quiz' == $post->post_type ) {
					$quiz_post = $post;
				}
			}

		} elseif ( $post_ID ) {
			$requested_post = get_post( $post_ID );

			if ( is_a( $requested_post, 'WP_Post' ) ) {
				if ( 'sfwd-quiz' == $requested_post->post_type ) {
					$quiz_post = $requested_post;
				}
			}
		}

		if ( null !== $quiz_post && $user_ID > 0 ) {
			return apply_filters( 'uo_time_quiz', self::get_uo_time( $quiz_post, $user_ID ), $quiz_post, $user_ID );
		}

		return '';
	}

	/*
	 * Get the amount of total the user has spent across ALL courses on the site.
	 *
	 * @param object $post_object A WP post object
	 * @param int $user_ID WP user ID
	 *
	 * return string Time spent by user across everything.
	 */

	/**
	 * @param $attributes
	 *
	 * @return mixed|string|null
	 */
	public static function shortcode_uo_time_total( $attributes ) {

		$request = shortcode_atts( array(
			'user-id' => '',
		), $attributes );

		if ( '' === $request['user-id'] ) {
			$request['user-id'] = get_current_user_id();
		}

		$user_ID = absint( $request['user-id'] );
		if ( $user_ID > 0 ) {
			return apply_filters( 'uo_user_time_total', self::get_user_time_in_seconds( $user_ID ), $user_ID );
		} else {
			return '';
		}
	}

	/**
	 * @param $user_ID
	 *
	 * @return string
	 */
	private static function get_user_time_in_seconds( $user_ID ) {

		global $wpdb;

		$timer_results = '';

		if ( $user_ID > 0 ) {
			$meta_key      = 'uo_timer_%';
			$query_results = $wpdb->prepare( "SELECT SUM( meta_value ) FROM $wpdb->usermeta WHERE meta_key LIKE %s AND user_id = %d", $meta_key, $user_ID );
			$timer_results = $wpdb->get_var( $query_results );

			return self::convert_second_to_time( $timer_results );
		}

		return $timer_results;

	}

}

Filemanager

Name Type Size Permission Actions
bbpress-learndash-groups-access.php File 2.34 KB 0644
certificate-preview.php File 5.99 KB 0644
clone-posts-pages-learn-dash-contents.php File 26.86 KB 0644
course-access-expiry.php File 6.57 KB 0644
course-completion-certificate.php File 21.26 KB 0644
course-timer.php File 59.49 KB 0644
download-certificates-in-bulk.php File 65.26 KB 0644
enhanced-learndash-report.php File 31.31 KB 0644
fluentform-lesson-topic-auto-complete.php File 21 KB 0644
frm-lesson-topic-auto-complete.php File 22.55 KB 0644
generate-p-d-f-email.php File 23.65 KB 0644
gf-lesson-topic-auto-complete.php File 23.79 KB 0644
group-completion-certificate.php File 20.16 KB 0644
group-leader-access.php File 10.79 KB 0644
group-login-redirect.php File 12.7 KB 0644
group-logo-list.php File 8.51 KB 0644
import-learndash-users-from-csv.php File 59.08 KB 0644
learn-dash-group-expiration.php File 32.36 KB 0644
learn-dash-group-sign-up.php File 39.88 KB 0644
learn-dash-my-courses.php File 53.17 KB 0644
learn-dash-reset.php File 16.77 KB 0644
learn-dash-table-color.php File 4.38 KB 0644
learn-dash-transcript.php File 35.79 KB 0644
learndash-course-navigation.php File 11.07 KB 0644
lesson-topic-auto-complete-on-quiz-end.php File 8.73 KB 0644
lesson-topic-auto-complete-on-quiz-graded.php File 9.12 KB 0644
lesson-topic-auto-complete.php File 35.35 KB 0644
lesson-topic-grid.php File 28.88 KB 0644
one-page-course-step.php File 17.5 KB 0644
restrict-page-access.php File 27.88 KB 0644
sample-tag.php File 5.34 KB 0644
sample.php File 4.71 KB 0644
show-all-courses.php File 52.17 KB 0644
uncanny-drip-lessons-by-group.php File 60.04 KB 0644
uncanny-drip-topics-by-group.php File 58.86 KB 0644
wpf-lesson-topic-auto-complete.php File 22.46 KB 0644