| |
| <?php
|
|
|
|
|
|
|
|
|
|
|
|
|
| defined( 'ABSPATH' ) || exit;
|
|
|
|
|
| add_action( 'admin_bar_menu', function( $wp_admin_bar ) {
|
| if ( ! current_user_can( 'manage_options' ) ) return;
|
|
|
| $wp_admin_bar->add_node( [
|
| 'id' => 'llms-content-sync',
|
| 'title' => '🔄 Sync LMS Content',
|
| 'href' => wp_nonce_url(
|
| admin_url( 'admin.php?llms_content_sync=1' ),
|
| 'llms_content_sync'
|
| ),
|
| ] );
|
| }, 999 );
|
|
|
|
|
| add_action( 'admin_init', function() {
|
| if ( ! isset( $_GET['llms_content_sync'] ) ) return;
|
| if ( ! current_user_can( 'manage_options' ) ) wp_die( 'Unauthorized' );
|
| if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'llms_content_sync' ) ) wp_die( 'Invalid nonce' );
|
|
|
|
|
| if ( ! class_exists( 'LifterLMS' ) ) {
|
| wp_die( 'LifterLMS is not active!' );
|
| }
|
|
|
|
|
| $lock_time = get_option( '_transient_timeout_llms_content_sync_lock' );
|
| if ( $lock_time && $lock_time < time() ) {
|
|
|
| delete_transient( 'llms_content_sync_lock' );
|
| }
|
|
|
|
|
| if ( get_transient( 'llms_content_sync_lock' ) ) {
|
|
|
| $lock_set_time = get_option( 'llms_content_sync_lock_time', 0 );
|
| if ( $lock_set_time && ( time() - $lock_set_time ) > 600 ) {
|
|
|
| delete_transient( 'llms_content_sync_lock' );
|
| delete_option( 'llms_content_sync_lock_time' );
|
| } else {
|
| wp_die( 'A sync is already in progress. Please wait. If this persists for more than 10 minutes, the lock will auto-clear.' );
|
| }
|
| }
|
|
|
|
|
| set_transient( 'llms_content_sync_lock', true, 10 * MINUTE_IN_SECONDS );
|
| update_option( 'llms_content_sync_lock_time', time() );
|
|
|
| try {
|
|
|
| llms_content_cleanup_orphaned();
|
|
|
|
|
| $result = llms_content_sync_all();
|
|
|
|
|
| delete_transient( 'llms_content_sync_lock' );
|
| delete_option( 'llms_content_sync_lock_time' );
|
|
|
|
|
| wp_redirect( admin_url( 'edit.php?post_type=llms_content_sync&synced=' . $result['total'] ) );
|
| exit;
|
|
|
| } catch ( Exception $e ) {
|
|
|
| delete_transient( 'llms_content_sync_lock' );
|
| delete_option( 'llms_content_sync_lock_time' );
|
| wp_die( 'Sync failed: ' . esc_html( $e->getMessage() ) );
|
| }
|
| } );
|
|
|
|
|
| add_action( 'admin_notices', function() {
|
| if ( isset( $_GET['synced'] ) && $_GET['post_type'] === 'llms_content_sync' ) {
|
| $count = intval( $_GET['synced'] );
|
| echo '<div class="notice notice-success"><p>✅ Synced ' . $count . ' courses!</p></div>';
|
| }
|
| } );
|
|
|
|
|
|
|
|
|
| function llms_content_cleanup_orphaned() {
|
|
|
| $synced_posts = new WP_Query( [
|
| 'post_type' => 'llms_content_sync',
|
| 'posts_per_page' => -1,
|
| 'fields' => 'ids',
|
| ] );
|
|
|
| $deleted_count = 0;
|
|
|
| foreach ( $synced_posts->posts as $post_id ) {
|
| $item_id = intval( get_post_meta( $post_id, 'item_id', true ) );
|
| $content_type = get_post_meta( $post_id, 'content_type', true );
|
|
|
|
|
| $exists = false;
|
|
|
| if ( $content_type === 'course' ) {
|
| $exists = ( get_post_status( $item_id ) !== false );
|
| }
|
|
|
| if ( ! $exists ) {
|
| wp_delete_post( $post_id, true );
|
| $deleted_count++;
|
| error_log( "LLMS_SYNC: Deleted orphaned course (post {$post_id})" );
|
| }
|
| }
|
|
|
| if ( $deleted_count > 0 ) {
|
| error_log( "LLMS_SYNC: Cleaned up {$deleted_count} orphaned items" );
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| function llms_content_sync_all() {
|
| $counts = [
|
| 'courses' => 0,
|
| 'total' => 0
|
| ];
|
|
|
|
|
| $courses_query = new WP_Query( [
|
| 'post_type' => 'course',
|
| 'posts_per_page' => -1,
|
| 'post_status' => 'any',
|
| ] );
|
|
|
| foreach ( $courses_query->posts as $course_post ) {
|
| $course = llms_get_post( $course_post->ID );
|
|
|
|
|
| $course_sync_id = llms_content_sync_item( [
|
| 'content_type' => 'course',
|
| 'item_id' => $course->get( 'id' ),
|
| 'title' => $course->get( 'title' ),
|
| 'data' => llms_content_prepare_comprehensive_course_data( $course )
|
| ] );
|
|
|
| if ( $course_sync_id ) {
|
| $counts['courses']++;
|
|
|
|
|
| do_action( 'llms_content_sync_complete', $course->get( 'id' ), $course_sync_id, true );
|
| }
|
| }
|
|
|
| $counts['total'] = $counts['courses'];
|
|
|
| error_log( "LLMS_SYNC: Synced {$counts['courses']} courses" );
|
|
|
| return $counts;
|
| }
|
|
|
|
|
|
|
|
|
| function llms_content_sync_item( $args ) {
|
|
|
| $existing_query = new WP_Query( [
|
| 'post_type' => 'llms_content_sync',
|
| 'posts_per_page' => 1,
|
| 'fields' => 'ids',
|
| 'meta_query' => [
|
| 'relation' => 'AND',
|
| [
|
| 'key' => 'content_type',
|
| 'value' => $args['content_type'],
|
| ],
|
| [
|
| 'key' => 'item_id',
|
| 'value' => $args['item_id'],
|
| ]
|
| ]
|
| ] );
|
|
|
| $post_data = [
|
| 'post_type' => 'llms_content_sync',
|
| 'post_status' => 'publish',
|
| 'post_title' => $args['title'],
|
| ];
|
|
|
| if ( $existing_query->have_posts() ) {
|
| $post_data['ID'] = $existing_query->posts[0];
|
| $post_id = wp_update_post( $post_data );
|
| } else {
|
| $post_id = wp_insert_post( $post_data );
|
| }
|
|
|
| if ( $post_id && ! is_wp_error( $post_id ) ) {
|
|
|
| foreach ( $args['data'] as $key => $value ) {
|
| update_post_meta( $post_id, $key, $value );
|
| }
|
|
|
|
|
| update_post_meta( $post_id, 'content_type', $args['content_type'] );
|
| update_post_meta( $post_id, 'item_id', $args['item_id'] );
|
| update_post_meta( $post_id, 'last_sync', current_time( 'mysql' ) );
|
| update_post_meta( $post_id, 'sync_status', 'synced' );
|
|
|
|
|
| update_post_meta( $post_id, '_source_course_id', $args['item_id'] );
|
|
|
| return $post_id;
|
| }
|
|
|
| return false;
|
| }
|
|
|
|
|
|
|
|
|
| function llms_content_prepare_comprehensive_course_data( $course ) {
|
|
|
| $instructors = $course->get_instructors();
|
| $instructor_names = [];
|
|
|
| foreach ( $instructors as $instructor ) {
|
| $user = get_userdata( $instructor['id'] );
|
| if ( $user ) {
|
| $instructor_names[] = $user->display_name;
|
| }
|
| }
|
|
|
|
|
| $course_content = $course->get( 'content' );
|
| $course_excerpt = $course->get( 'excerpt' );
|
|
|
|
|
| $sections = $course->get_sections( 'sections' );
|
| $section_count = count( $sections );
|
| $section_titles = [];
|
| $all_section_content = [];
|
|
|
| foreach ( $sections as $section ) {
|
| $section_title = $section->get( 'order' ) . '. ' . $section->get( 'title' );
|
| $section_titles[] = $section_title;
|
|
|
| $section_content = $section->get( 'content' );
|
| if ( ! empty( $section_content ) ) {
|
| $all_section_content[] = "=== Section: " . $section_title . " ===\n" . strip_tags( $section_content );
|
| }
|
| }
|
|
|
|
|
| $lessons = $course->get_lessons( 'lessons' );
|
| $lesson_titles = [];
|
| $all_lesson_content = [];
|
| $total_quizzes = 0;
|
| $total_assignments = 0;
|
|
|
| foreach ( $lessons as $lesson ) {
|
| $lesson_title = $lesson->get( 'title' );
|
| $lesson_titles[] = $lesson_title;
|
|
|
|
|
| $lesson_content = $lesson->get( 'content' );
|
| if ( ! empty( $lesson_content ) ) {
|
| $all_lesson_content[] = "=== Lesson: " . $lesson_title . " ===\n" . strip_tags( $lesson_content );
|
| }
|
|
|
|
|
| if ( $lesson->has_quiz() ) {
|
| $total_quizzes++;
|
| $quiz = $lesson->get_quiz();
|
| if ( $quiz ) {
|
| $quiz_content = $quiz->get( 'content' );
|
| if ( ! empty( $quiz_content ) ) {
|
| $all_lesson_content[] = "--- Quiz: " . $quiz->get( 'title' ) . " ---\n" . strip_tags( $quiz_content );
|
| }
|
| }
|
| }
|
|
|
|
|
| $assignment_id = $lesson->get( 'assignment' );
|
| if ( $assignment_id && get_post_type( $assignment_id ) === 'llms_assignment' ) {
|
| $total_assignments++;
|
| $assignment = get_post( $assignment_id );
|
| if ( $assignment && ! empty( $assignment->post_content ) ) {
|
| $all_lesson_content[] = "--- Assignment: " . $assignment->post_title . " ---\n" . strip_tags( $assignment->post_content );
|
| }
|
| }
|
| }
|
|
|
|
|
| $has_certificate = false;
|
| $certificate_id = 0;
|
| $certificate_title = '';
|
|
|
|
|
| global $wpdb;
|
| $engagements = $wpdb->get_results( $wpdb->prepare(
|
| "SELECT * FROM {$wpdb->posts}
|
| WHERE post_type = 'llms_engagement'
|
| AND post_status = 'publish'
|
| AND ID IN (
|
| SELECT post_id FROM {$wpdb->postmeta}
|
| WHERE meta_key = '_llms_engagement_trigger_post'
|
| AND meta_value = %d
|
| )",
|
| $course->get( 'id' )
|
| ) );
|
|
|
|
|
| foreach ( $engagements as $engagement ) {
|
| $type = get_post_meta( $engagement->ID, '_llms_engagement_type', true );
|
| if ( 'certificate' === $type ) {
|
| $has_certificate = true;
|
| $cert_template_id = get_post_meta( $engagement->ID, '_llms_engagement', true );
|
| if ( $cert_template_id ) {
|
| $certificate_id = $cert_template_id;
|
| $cert_post = get_post( $certificate_id );
|
| if ( $cert_post ) {
|
| $certificate_title = $cert_post->post_title;
|
| }
|
| }
|
| break;
|
| }
|
| }
|
|
|
|
|
| $engagements = [];
|
| $engagement_posts = $wpdb->get_results( $wpdb->prepare(
|
| "SELECT p.*, pm.meta_value as engagement_type, pm2.meta_value as engagement_id
|
| FROM {$wpdb->posts} p
|
| LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = '_llms_engagement_type'
|
| LEFT JOIN {$wpdb->postmeta} pm2 ON p.ID = pm2.post_id AND pm2.meta_key = '_llms_engagement'
|
| WHERE p.post_type = 'llms_engagement'
|
| AND p.post_status = 'publish'
|
| AND p.ID IN (
|
| SELECT post_id FROM {$wpdb->postmeta}
|
| WHERE meta_key = '_llms_engagement_trigger_post'
|
| AND meta_value = %d
|
| )",
|
| $course->get( 'id' )
|
| ) );
|
|
|
| foreach ( $engagement_posts as $eng ) {
|
| $type = $eng->engagement_type;
|
| $template_id = $eng->engagement_id;
|
|
|
| if ( $template_id ) {
|
| $template_post = get_post( $template_id );
|
| if ( $template_post ) {
|
| $type_label = '';
|
| switch ( $type ) {
|
| case 'certificate':
|
| $type_label = 'Certificate';
|
| break;
|
| case 'email':
|
| $type_label = 'Email';
|
| break;
|
| case 'achievement':
|
| $type_label = 'Achievement';
|
| break;
|
| }
|
|
|
| if ( $type_label ) {
|
| $engagements[] = $type_label . ': ' . $template_post->post_title;
|
| }
|
| }
|
| }
|
| }
|
|
|
|
|
| $is_free = 0;
|
| $is_free_meta = get_post_meta( $course->get( 'id' ), '_llms_is_free', true );
|
| if ( $is_free_meta === 'yes' ) {
|
| $is_free = 1;
|
| }
|
|
|
|
|
| $has_prerequisite = $course->has_prerequisite( 'course' ) ? 1 : 0;
|
| $prerequisite_id = 0;
|
| if ( $has_prerequisite ) {
|
| $prereq = $course->get_prerequisite_id( 'course' );
|
| if ( $prereq ) {
|
| $prerequisite_id = $prereq;
|
| }
|
| }
|
|
|
|
|
| $drip_method = get_post_meta( $course->get( 'id' ), '_llms_drip_method', true );
|
| $drip_value = get_post_meta( $course->get( 'id' ), '_llms_days_before_available', true );
|
|
|
| return [
|
|
|
| 'status' => $course->get( 'status' ),
|
| 'excerpt' => $course_excerpt,
|
| 'course_content' => $course_content,
|
|
|
|
|
| 'course_duration' => $course->get( 'length' ),
|
| 'course_capacity' => $course->get( 'capacity' ),
|
| 'course_instructors' => implode( "\n", $instructor_names ),
|
| 'is_free' => $is_free,
|
|
|
|
|
| 'section_count' => $section_count,
|
| 'section_list' => implode( "\n", $section_titles ),
|
| 'total_lessons' => count( $lessons ),
|
| 'lesson_list' => implode( "\n", $lesson_titles ),
|
| 'total_quizzes' => $total_quizzes,
|
| 'total_assignments' => $total_assignments,
|
|
|
|
|
| 'has_certificate' => $has_certificate ? 1 : 0,
|
| 'certificate_id' => $certificate_id,
|
| 'certificate_title' => $certificate_title,
|
|
|
|
|
| 'engagements_list' => implode( "\n", $engagements ),
|
| 'engagements_count' => count( $engagements ),
|
|
|
|
|
| 'has_prerequisite' => $has_prerequisite,
|
| 'prerequisite_id' => $prerequisite_id,
|
|
|
|
|
| 'drip_method' => $drip_method ?: '',
|
| 'drip_value' => $drip_value ?: '',
|
|
|
|
|
| 'all_section_content' => implode( "\n\n", $all_section_content ),
|
| 'all_lesson_content' => implode( "\n\n", $all_lesson_content ),
|
|
|
|
|
| 'steps_details_list' => '',
|
| 'quizzes_details_list' => '',
|
| 'assignments_details_list' => '',
|
| 'sections_details_list' => '',
|
| 'certificates_details_list' => '',
|
| 'engagements_details_list' => '',
|
| ];
|
| }
|
| |
| |
Comments