8, 'show_search' => '1', 'show_mode_toggle' => '1', 'show_categories' => '1', 'primary_color' => '#1A5276', 'accent_color' => '#B7950B', 'sort_by' => 'date', 'sort_order' => 'DESC', 'enable_cache' => '0', 'cache_hours' => 12, ] ); } } ); register_deactivation_hook( __FILE__, function () { // Clear all transient cache on deactivation global $wpdb; $wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_abct_courses_%' OR option_name LIKE '_transient_timeout_abct_courses_%'" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery } ); // ────────────────────────────────────────────── // Helper: get option with default // ────────────────────────────────────────────── function abct_opt( $key, $default = '' ) { $opts = get_option( 'abct_settings', [] ); return isset( $opts[ $key ] ) && $opts[ $key ] !== '' ? $opts[ $key ] : $default; } // ────────────────────────────────────────────── // Admin Menu // ────────────────────────────────────────────── add_action( 'admin_menu', function () { add_options_page( __( 'LMS Courses Table Settings', 'ab-courses-table-tutor-lms' ), __( 'Courses Table', 'ab-courses-table-tutor-lms' ), 'manage_options', 'abct-settings', 'abct_render_settings_page' ); } ); // ────────────────────────────────────────────── // Register Settings // ────────────────────────────────────────────── add_action( 'admin_init', function () { register_setting( 'abct_settings_group', 'abct_settings', [ 'sanitize_callback' => 'abct_sanitize_settings', ] ); } ); function abct_sanitize_settings( $input ) { $clean = []; $clean['per_page'] = absint( $input['per_page'] ?? 8 ); $clean['show_search'] = isset( $input['show_search'] ) ? '1' : '0'; $clean['show_mode_toggle'] = isset( $input['show_mode_toggle'] ) ? '1' : '0'; $clean['show_categories'] = isset( $input['show_categories'] ) ? '1' : '0'; $clean['primary_color'] = sanitize_hex_color( $input['primary_color'] ?? '#1A5276' ); $clean['accent_color'] = sanitize_hex_color( $input['accent_color'] ?? '#B7950B' ); $clean['registration_page'] = esc_url_raw( $input['registration_page'] ?? '' ); $clean['show_seats'] = isset( $input['show_seats'] ) ? '1' : '0'; $clean['show_price'] = isset( $input['show_price'] ) ? '1' : '0'; $clean['show_students'] = isset( $input['show_students'] ) ? '1' : '0'; $clean['show_level'] = isset( $input['show_level'] ) ? '1' : '0'; $clean['show_duration'] = isset( $input['show_duration'] ) ? '1' : '0'; $clean['enable_cache'] = isset( $input['enable_cache'] ) ? '1' : '0'; $clean['cache_hours'] = absint( $input['cache_hours'] ?? 12 ); $clean['sort_by'] = sanitize_text_field( $input['sort_by'] ?? 'date' ); $clean['sort_order'] = sanitize_text_field( $input['sort_order'] ?? 'DESC' ); $clean['no_seats_label'] = sanitize_text_field( $input['no_seats_label'] ?? '' ); $clean['category_taxonomy'] = sanitize_text_field( $input['category_taxonomy'] ?? 'course-category' ); $clean['delivery_meta'] = sanitize_text_field( $input['delivery_meta'] ?? '_tutor_course_delivery' ); $clean['start_date_meta'] = sanitize_text_field( $input['start_date_meta'] ?? '_tutor_course_start_date' ); $clean['start_time_meta'] = sanitize_text_field( $input['start_time_meta'] ?? '_tutor_course_start_time' ); $clean['end_time_meta'] = sanitize_text_field( $input['end_time_meta'] ?? '_tutor_course_end_time' ); $clean['seats_meta'] = sanitize_text_field( $input['seats_meta'] ?? '_tutor_course_max_students' ); $clean['price_meta'] = sanitize_text_field( $input['price_meta'] ?? '_tutor_course_price' ); $clean['students_meta'] = sanitize_text_field( $input['students_meta'] ?? '_tutor_course_enrolled_users_count' ); $clean['level_meta'] = sanitize_text_field( $input['level_meta'] ?? '_tutor_course_level' ); $clean['duration_meta'] = sanitize_text_field( $input['duration_meta'] ?? '_tutor_course_duration' ); return $clean; } // ────────────────────────────────────────────── // Settings Page // ────────────────────────────────────────────── function abct_render_settings_page() { if ( ! current_user_can( 'manage_options' ) ) return; $updated = isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] === 'true'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
✅
' . esc_html__( 'Tutor LMS is not active or not installed.', 'ab-courses-table-tutor-lms' ) . '
'; } $courses = abct_get_courses( $atts ); $categories = abct_get_categories( $atts['category_taxonomy'] ); ob_start(); include ABCT_PATH . 'templates/table.php'; return ob_get_clean(); } ); // ────────────────────────────────────────────── // جلب الكتيجوريز // ────────────────────────────────────────────── function abct_get_categories( $taxonomy ) { $terms = get_terms( [ 'taxonomy' => $taxonomy, 'hide_empty' => true, 'orderby' => 'name', 'order' => 'ASC', ] ); if ( is_wp_error( $terms ) || empty( $terms ) ) return []; return $terms; } // ────────────────────────────────────────────── // جلب الكورسات (مع Cache) // ────────────────────────────────────────────── function abct_get_courses( $atts ) { $cache_key = 'abct_courses_' . md5( serialize( $atts ) ); if ( abct_opt( 'enable_cache', '0' ) === '1' ) { $cached = get_transient( $cache_key ); if ( $cached !== false ) return $cached; } $query_args = [ 'post_type' => 'courses', 'post_status' => 'publish', 'posts_per_page' => -1, 'orderby' => $atts['sort_by'] === 'meta_value' ? 'meta_value' : $atts['sort_by'], 'order' => $atts['sort_order'], ]; if ( $atts['sort_by'] === 'meta_value' ) { $query_args['meta_key'] = $atts['start_date_meta']; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key } $query = new WP_Query( $query_args ); $courses = []; foreach ( $query->posts as $post ) { $start_date = get_post_meta( $post->ID, $atts['start_date_meta'], true ); if ( empty( $start_date ) ) { $start_date = get_the_date( 'Y/m/d', $post->ID ); } else { $start_date = gmdate( 'Y/m/d', strtotime( $start_date ) ); } $day_ar = abct_day_arabic( $start_date ); $time_from = get_post_meta( $post->ID, $atts['start_time_meta'], true ); $time_to = get_post_meta( $post->ID, $atts['end_time_meta'], true ); $time_str = ( $time_from && $time_to ) ? 'من ' . $time_from . ' حتى ' . $time_to : ''; $delivery = get_post_meta( $post->ID, $atts['delivery_meta'], true ); if ( empty( $delivery ) ) $delivery = 'offline'; $terms = get_the_terms( $post->ID, $atts['category_taxonomy'] ); $cat_slugs = []; if ( $terms && ! is_wp_error( $terms ) ) { foreach ( $terms as $term ) $cat_slugs[] = $term->slug; } $max_seats = (int) get_post_meta( $post->ID, $atts['seats_meta'], true ); $enrolled = (int) get_post_meta( $post->ID, $atts['students_meta'], true ); $seats_left = $max_seats > 0 ? max( 0, $max_seats - $enrolled ) : -1; $seats_full = $max_seats > 0 && $seats_left === 0; $price = get_post_meta( $post->ID, $atts['price_meta'], true ); $is_free = empty( $price ) || (float) $price === 0.0; $level_map = [ 'beginner' => __( 'Beginner', 'ab-courses-table-tutor-lms' ), 'intermediate' => __( 'Intermediate', 'ab-courses-table-tutor-lms' ), 'expert' => __( 'Advanced', 'ab-courses-table-tutor-lms' ), ]; $level_raw = get_post_meta( $post->ID, $atts['level_meta'], true ); $level = $level_map[ $level_raw ] ?? $level_raw; $duration = get_post_meta( $post->ID, $atts['duration_meta'], true ); $courses[] = [ 'id' => $post->ID, 'title' => get_the_title( $post->ID ), 'date' => $day_ar . ' ' . __( 'corresponding to', 'ab-courses-table-tutor-lms' ) . ' ' . $start_date, 'date_raw' => $start_date, 'time' => $time_str, 'permalink' => get_permalink( $post->ID ), 'delivery' => $delivery, 'cat_slugs' => implode( ',', $cat_slugs ), 'seats_left' => $seats_left, 'seats_full' => $seats_full, 'enrolled' => $enrolled, 'price' => $price, 'is_free' => $is_free, 'level' => $level, 'duration' => $duration, ]; } if ( abct_opt( 'enable_cache', '0' ) === '1' ) { set_transient( $cache_key, $courses, abct_opt( 'cache_hours', 12 ) * HOUR_IN_SECONDS ); } return $courses; } // ────────────────────────────────────────────── // تحويل اليوم للعربي (قابل للترجمة) // ────────────────────────────────────────────── function abct_day_arabic( $date_str ) { $days = [ 'Saturday' => __( 'Saturday', 'ab-courses-table-tutor-lms' ), 'Sunday' => __( 'Sunday', 'ab-courses-table-tutor-lms' ), 'Monday' => __( 'Monday', 'ab-courses-table-tutor-lms' ), 'Tuesday' => __( 'Tuesday', 'ab-courses-table-tutor-lms' ), 'Wednesday' => __( 'Wednesday', 'ab-courses-table-tutor-lms' ), 'Thursday' => __( 'Thursday', 'ab-courses-table-tutor-lms' ), 'Friday' => __( 'Friday', 'ab-courses-table-tutor-lms' ), ]; $day_en = gmdate( 'l', strtotime( $date_str ) ); return $days[ $day_en ] ?? $day_en; } // ────────────────────────────────────────────── // Clear cache on course save // ────────────────────────────────────────────── add_action( 'save_post_courses', function () { global $wpdb; $wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_abct_courses_%'" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery } );