PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.4
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.4
4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 4.2.1 All 138 releases
learnpress / inc / Statistics / FilterOptionsProvider.php

FilterOptionsProvider.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.4, at inc/Statistics/FilterOptionsProvider.php

156 lines 4.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class FilterOptionsProvider
4 *
5 * @package LearnPress/Classes/Statistics
6 * @since 4.4.2
7 */
8
9 namespace LearnPress\Statistics;
10
11 defined( 'ABSPATH' ) || exit();
12
13 /**
14 * Options for the global statistics filters: instructor and category dropdowns.
15 *
16 * @since 4.4.2
17 */
18 class FilterOptionsProvider {
19 const TRANSIENT_KEY = 'lp_statistics_filter_options';
20
21 /**
22 * Register cache-invalidation hooks so a newly published course's author or a
23 * new/changed course category appears in the filter dropdowns promptly,
24 * instead of waiting out the transient TTL. Call once from the plugin bootstrap.
25 *
26 * @return void
27 * @since 4.4.2
28 */
29 public static function register_flush_hooks(): void {
30 // Publish/update/unpublish/trash a course → author list may change.
31 add_action( 'save_post_' . LP_COURSE_CPT, array( __CLASS__, 'flush' ) );
32 add_action( 'deleted_post', array( __CLASS__, 'flush_on_course_delete' ) );
33 // Category taxonomy changes → category list may change.
34 add_action( 'created_' . LP_COURSE_CATEGORY_TAX, array( __CLASS__, 'flush' ) );
35 add_action( 'edited_' . LP_COURSE_CATEGORY_TAX, array( __CLASS__, 'flush' ) );
36 add_action( 'delete_' . LP_COURSE_CATEGORY_TAX, array( __CLASS__, 'flush' ) );
37 }
38
39 /**
40 * Drop the cached options so the next request rebuilds them.
41 *
42 * @return void
43 * @since 4.4.2
44 */
45 public static function flush(): void {
46 delete_transient( self::TRANSIENT_KEY );
47 }
48
49 /**
50 * Flush only when the deleted post is a course ( deleted_post is global ).
51 *
52 * @param int $post_id
53 * @return void
54 * @since 4.4.2
55 */
56 public static function flush_on_course_delete( $post_id ): void {
57 if ( LP_COURSE_CPT === get_post_type( $post_id ) ) {
58 self::flush();
59 }
60 }
61
62 /**
63 * Get dropdown options, cached in a transient.
64 *
65 * Always returns both keys with arrays (possibly empty) — the JS iterates blindly.
66 *
67 * @return array [ 'instructors' => [ [ 'id' => int, 'name' => string ] ], 'categories' => [ [ 'id' => int, 'name' => string ] ] ]
68 */
69 public static function get_options(): array {
70 $cached = get_transient( self::TRANSIENT_KEY );
71 if ( is_array( $cached ) && isset( $cached['instructors'], $cached['categories'] ) ) {
72 return $cached;
73 }
74
75 $options = array(
76 'instructors' => self::get_instructors(),
77 'categories' => self::get_categories(),
78 );
79
80 $ttl = (int) apply_filters( 'learn-press/statistics/filter-options-ttl', 600 );
81 set_transient( self::TRANSIENT_KEY, $options, $ttl );
82
83 return $options;
84 }
85
86 /**
87 * Users having at least one published course.
88 *
89 * Author-based on purpose (no role check): StatisticsScope filters on
90 * post_author, so every author of a published course must be selectable.
91 * Only id + display_name are exposed — no emails/user_login (privacy).
92 *
93 * @return array [ [ 'id' => int, 'name' => string ] ] sorted by name.
94 */
95 private static function get_instructors(): array {
96 global $wpdb;
97
98 $results = $wpdb->get_results(
99 $wpdb->prepare(
100 "SELECT DISTINCT u.ID AS id, u.display_name AS name
101 FROM {$wpdb->users} AS u
102 INNER JOIN {$wpdb->posts} AS p ON p.post_author = u.ID
103 WHERE p.post_type = %s
104 AND p.post_status = %s
105 ORDER BY u.display_name ASC",
106 LP_COURSE_CPT,
107 'publish'
108 )
109 );
110
111 if ( ! is_array( $results ) ) {
112 return array();
113 }
114
115 $instructors = array();
116 foreach ( $results as $row ) {
117 $instructors[] = array(
118 'id' => (int) $row->id,
119 'name' => (string) $row->name,
120 );
121 }
122
123 return $instructors;
124 }
125
126 /**
127 * Non-empty course categories.
128 *
129 * @return array [ [ 'id' => int, 'name' => string ] ] sorted by name.
130 */
131 private static function get_categories(): array {
132 $terms = get_terms(
133 array(
134 'taxonomy' => LP_COURSE_CATEGORY_TAX,
135 'hide_empty' => true,
136 'fields' => 'id=>name',
137 )
138 );
139
140 if ( is_wp_error( $terms ) || ! is_array( $terms ) ) {
141 return array();
142 }
143
144 $categories = array();
145 foreach ( $terms as $term_id => $name ) {
146 $categories[] = array(
147 'id' => (int) $term_id,
148 // Term names are entity-encoded in the DB; JS renders via textContent, so decode here.
149 'name' => wp_specialchars_decode( (string) $name ),
150 );
151 }
152
153 return $categories;
154 }
155 }
156