LLMS_Membership

LLMS_Membership model class


Source Source

File: includes/models/model.llms.membership.php

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
class LLMS_Membership extends LLMS_Post_Model implements LLMS_Interface_Post_Instructors {
 
    use LLMS_Trait_Sales_Page;
 
    /**
     * Membership post meta.
     *
     * @var array
     */
    protected $properties = array(
        'auto_enroll'               => 'array',
        'instructors'               => 'array',
        'redirect_page_id'          => 'absint',
        'restriction_add_notice'    => 'yesno',
        'restriction_notice'        => 'html',
        'restriction_redirect_type' => 'text',
        'redirect_custom_url'       => 'text',
    );
 
    /**
     * Database post type.
     *
     * @var string
     */
    protected $db_post_type = 'llms_membership';
 
    /**
     * Model name.
     *
     * @var string
     */
    protected $model_post_type = 'membership';
 
    /**
     * Constructor for this class and the traits it uses.
     *
     * @since 5.3.0
     *
     * @param string|int|LLMS_Post_Model|WP_Post $model 'new', WP post id, instance of an extending class, instance of WP_Post.
     * @param array                              $args  Args to create the post, only applies when $model is 'new'.
     */
    public function __construct( $model, $args = array() ) {
 
        $this->construct_sales_page();
        parent::__construct( $model, $args );
    }
 
    /**
     * Add courses to autoenrollment by id
     *
     * @since 3.0.0
     * @since 3.30.0 Added optional `$replace` argument.
     *
     * @param array|int $course_ids Array of course id or course id as int.
     * @param bool      $replace    Optional. When `true`, replaces all existing courses with `$course_ids`, when false merges `$course_ids` with existing courses. Default `false`.
     * @return boolean Returns `true` on success, and `false` on error or if the value in the db is unchanged.
     */
    public function add_auto_enroll_courses( $course_ids, $replace = false ) {
 
        // allow a single course_id to be passed in.
        if ( ! is_array( $course_ids ) ) {
            $course_ids = array( $course_ids );
        }
 
        // add existing courses to the array if replace is false.
        if ( ! $replace ) {
            $course_ids = array_merge( $course_ids, $this->get_auto_enroll_courses() );
        }
 
        return $this->set( 'auto_enroll', array_unique( $course_ids ) );
 
    }
 
    /**
     * Retrieve a list of posts associated with the membership
     *
     * An associated post is:
     * + A post, page, or custom post type which supports `llms-membership-restrictions` and has restrictions enabled to this membership
     * + A course that exists in the memberships list of auto-enroll courses
     * + A course that has at least one access plan with members-only availability linked to this membership
     *
     * @since 3.38.1
     * @since 4.15.0 Minor restructuring to only query post type data when it's needed.
     *
     * @param string $post_type If supplied, returns only associations of this post type, otherwise returns an associative array of all associations.
     * @return array[]|int[] An array of arrays of post IDs. The array keys are the post type and the array values are arrays of integers.
     *                       If `$post_type` is supplied returns an array of associated post ids as integers.
     */
    public function get_associated_posts( $post_type = null ) {
 
        // If we're querying only posts, we can skip these associations entirely because courses don't support them.
        $post_types = 'course' !== $post_type ? get_post_types_by_support( 'llms-membership-restrictions' ) : array();
 
        // If we're looking at a single post type we only have to query associations for that post type.
        $post_types = $post_type ? array_intersect( $post_types, array( $post_type ) ) : $post_types;
 
        // Our return array.
        $posts = array();
 
        // Retrieve all posts that are restricted to a membership via a LifterLMS Membership Restriction setting.
        foreach ( $post_types as $type ) {
            $posts[ $type ] = $this->query_associated_posts( $type, '_llms_is_restricted', 'yes', '_llms_restricted_levels' );
        }
 
        // Include courses if courses were requested or if no specific post type was requested.
        if ( ! $post_type || 'course' === $post_type ) {
            $posts['course'] = $this->query_associated_courses();
        }
 
        /**
         * Filter the list of posts associated with the membership.
         *
         * @since 3.38.1
         *
         * @param array[]         $posts     An array of arrays of post IDs. The array keys are the post type and the array values are arrays of integers.
         * @param string|null     $post_type The requested post type if only a specific post type was requested, otherwise `null` to indicate all associated post types.
         * @param LLMS_Membership $this      Membership object.
         */
        $posts = apply_filters( 'llms_membership_get_associated_posts', $posts, $post_type, $this );
 
        // If a single post type was requested, return only that.
        if ( $post_type ) {
            // Return the request post type array and fallback to an empty array if that post type doesn't exist.
            return isset( $posts[ $post_type ] ) ? $posts[ $post_type ] : array();
        }
 
        // Remove empty arrays and return the rest.
        return array_filter( $posts );
 
    }
 
    /**
     * Get an array of the auto enrollment course ids
     *
     * Uses a custom function due to the default "get_array" returning an array with an empty string
     *
     * @since 3.0.0
     * @since 4.15.0 Exclude unpublished courses from the return array.
     *
     * @return array
     */
    public function get_auto_enroll_courses() {
 
        // Ensure an array when metadata is not set.
        $courses = isset( $this->auto_enroll ) ? $this->get( 'auto_enroll' ) : array();
 
        // Exclude unpublished courses.
        $courses = array_values(
            array_filter(
                $courses,
                function( $id ) {
                    return 'publish' === get_post_status( $id );
                }
            )
        );
 
        /**
         * Filters the list of the membership's auto enroll courses
         *
         * @since 3.0.0
         *
         * @param int[]           $courses    List of LLMS_Course IDs.
         * @param LLMS_Membership $membership Membership post object.
         */
        return apply_filters( 'llms_membership_get_auto_enroll_courses', $courses, $this );
    }
 
    /**
     * Retrieve membership categories.
     *
     * @since 3.36.3
     *
     * @param array $args Array of args passed to `wp_get_post_terms()`.
     * @return array
     */
    public function get_categories( $args = array() ) {
        return wp_get_post_terms( $this->get( 'id' ), 'membership_cat', $args );
    }
 
    /**
     * Retrieve course instructor information
     *
     * @since 3.13.0
     *
     * @param boolean $exclude_hidden If true, excludes hidden instructors from the return array.
     * @return array
     */
    public function get_instructors( $exclude_hidden = false ) {
 
        return apply_filters(
            'llms_membership_get_instructors',
            $this->instructors()->get_instructors( $exclude_hidden ),
            $this,
            $exclude_hidden
        );
 
    }
 
    /**
     * Retrieve an instance of the LLMS_Product for this course
     *
     * @since 3.3.0
     * @return LLMS_Product
     */
    public function get_product() {
        return new LLMS_Product( $this->get( 'id' ) );
    }
 
    /**
     * Retrieve the number of enrolled students in the membership.
     *
     * @since 3.32.0
     * @since 6.0.0 Don't access `LLMS_Student_Query` properties directly.
     *
     * @return int
     */
    public function get_student_count() {
 
        $query = new LLMS_Student_Query(
            array(
                'post_id'  => $this->get( 'id' ),
                'statuses' => array( 'enrolled' ),
                'per_page' => 1,
            )
        );
 
        return $query->get_found_results();
 
    }
 
    /**
     * Get an array of student IDs based on enrollment status in the membership
     *
     * @since 3.0.0
     *
     * @param string|string[] $statuses Optional. List of enrollment statuses to query by status query is an OR relationship. Default is 'enrolled'.
     * @param int             $limit    Optional. Number of results. Default is `50`.
     * @param int             $skip     Optional. Number of results to skip (for pagination). Default is `0`.
     * @return array
     */
    public function get_students( $statuses = 'enrolled', $limit = 50, $skip = 0 ) {
        return llms_get_enrolled_students( $this->get( 'id' ), $statuses, $limit, $skip );
    }
 
    /**
     * Retrieve membership tags.
     *
     * @since 3.36.3
     *
     * @param array $args Array of args passed to `wp_get_post_terms()`.
     * @return array
     */
    public function get_tags( $args = array() ) {
        return wp_get_post_terms( $this->get( 'id' ), 'membership_tag', $args );
    }
 
    /**
     * Retrieve an instance of the Post Instructors model
     *
     * @since 3.13.0
     *
     * @return LLMS_Post_Instructors
     */
    public function instructors() {
        return new LLMS_Post_Instructors( $this );
    }
 
    /**
     * Retrieve courses associated with the membership
     *
     * @since 3.38.1
     * @since 4.15.0 Exclude unpublished courses.
     *
     * @see LLMS_Membership::get_associated_posts()
     *
     * @return int[]
     */
    protected function query_associated_courses() {
 
        // Start with autoenroll courses.
        $courses = $this->get_auto_enroll_courses();
 
        // Retrieve all access plans with a members-only availability restriction for this membership.
        foreach ( $this->query_associated_posts( 'llms_access_plan', '_llms_availability', 'members', '_llms_availability_restrictions' ) as $plan_id ) {
            $plan = llms_get_post( $plan_id );
            if ( $plan ) {
                $id = $plan->get( 'product_id' );
                if ( 'publish' === get_post_status( $id ) ) {
                    $courses[] = $id;
                }
            }
        }
 
        return array_unique( $courses );
 
    }
 
    /**
     * Performs a WPDB query to retrieve posts associated with the membership
     *
     * @since 3.38.1
     * @since 4.0.0 Escape `{` character in SQL query to add MySQL 8.0 support.
     *
     * @see LLMS_Membesrhip::get_associated_posts()
     *
     * @param string $post_type     Post type to query for an association with.
     * @param string $enabled_key   A meta key name, used to check if the association is enabled for the associated post. For example: "_llms_is_restricted"
     * @param string $enabled_value The meta value of the `$enabled_key` when the association is enabled. For example "yes" when checking "_llms_is_restricted"..
     * @param string $list_key      The meta key name where associations are stored as a serialized array of WP_Post IDs. For example "_llms_restricted_levels".
     * @return int[]
     */
    protected function query_associated_posts( $post_type, $enabled_key, $enabled_value, $list_key ) {
 
        global $wpdb;
 
        // See if we have a cached result first.
        $cache = sprintf( 'membership_%1$d_associated_%2$s', $this->get( 'id' ), $post_type );
        $found = null;
        $ids   = wp_cache_get( $cache, '', false, $found );
 
        // We don't, perform a query.
        if ( ! $found ) {
 
            $ids = $wpdb->get_col( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
                $wpdb->prepare(
                    "SELECT metas.post_id
                 FROM {$wpdb->postmeta} AS metas
                 JOIN {$wpdb->postmeta} AS metas2 ON metas2.post_id = metas.post_id
                 JOIN {$wpdb->posts} AS posts ON posts.ID = metas.post_id
                 WHERE 1
                   AND posts.post_status = 'publish'
                   AND posts.post_type = %s
                   AND metas2.meta_key = %s
                   AND metas2.meta_value = %s
                   AND metas.meta_key = %s
                   AND metas.meta_value REGEXP %s;",
                    $post_type,
                    $enabled_key,
                    $enabled_value,
                    $list_key,
                    'a:[0-9][0-9]*:\{(i:[0-9][0-9]*;(i|s:[0-9][0-9]*):"?[0-9][0-9]*"?;)*(i:[0-9][0-9]*;(i|s:[0-9][0-9]*):"?' . $this->get( 'id' ) . '"?;)'
                )
            );
 
            // Only return ints.
            $ids = array_map( 'absint', $ids );
 
            // Cache the result.
            wp_cache_set( $cache, $ids );
 
        }
 
        return $ids;
 
    }
 
    /**
     * Remove a course from auto enrollment
     *
     * @since 3.0.0
     *
     * @param int $course_id WP_Post ID of the course.
     * @return bool
     */
    public function remove_auto_enroll_course( $course_id ) {
        return $this->set( 'auto_enroll', array_diff( $this->get_auto_enroll_courses(), array( $course_id ) ) );
    }
 
    /**
     * Save instructor information
     *
     * @since 3.13.0
     *
     * @param array $instructors Array of course instructor information.
     * @return array
     */
    public function set_instructors( $instructors = array() ) {
 
        return $this->instructors()->set_instructors( $instructors );
 
    }
 
    /**
     * Add data to the membership model when converted to array.
     *
     * Called before data is sorted and returned by `$this->jsonSerialize()`.
     *
     * @since 3.36.3
     *
     * @param array $arr Data to be serialized.
     * @return array
     */
    public function toArrayAfter( $arr ) {
        $arr['categories'] = $this->get_categories(
            array(
                'fields' => 'names',
            )
        );
 
        $arr['tags'] = $this->get_tags(
            array(
                'fields' => 'names',
            )
        );
 
        return $arr;
    }
 
}


Top ↑

Properties Properties

The following post and post meta properties are accessible for this class. See LLMS_Post_Model::get() and LLMS_Post_Model::set() for more information.

$auto_enroll

(int[]) Array of course IDs that users will be autoenrolled in upon successful enrollment in this membership.

$instructors

(array) Course instructor user information.

$restriction_redirect_type

(string) What type of redirect action to take when content is restricted by this membership [none|membership|page|custom].

$redirect_page_id

(int) WP Post ID of a page to redirect users to when $restriction_redirect_type is 'page'.

$redirect_custom_url

(string) Arbitrary URL to redirect users to when $restriction_redirect_type is 'custom'.

$restriction_add_notice

(string) Whether or not to add an on screen message when content is restricted by this membership [yes|no].

$restriction_notice

(string) Notice to display when $restriction_add_notice is 'yes'.

$sales_page_content_page_id

(int) WP Post ID of the WP page to redirect to when $sales_page_content_type is 'page'.

$sales_page_content_type

(string) Sales page behavior [none,content,page,url].

$sales_page_content_url

(string) Redirect URL for a sales page, when $sales_page_content_type is 'url'.


Top ↑

Methods Methods


Top ↑

Changelog Changelog

Changelog
Version Description
5.3.0 Move sales page methods to LLMS_Trait_Sales_Page.
5.2.1 Check for an empty sales page URL or ID.
4.0.0 Added MySQL 8.0 compatibility.
3.38.1 Added methods for retrieving posts associated with the membership.
3.36.3 Added get_categories(), get_tags() and toArrayAfter() methods.
3.32.0 Added get_student_count() method.
3.30.0 Added optional argument to add_auto_enroll_courses() method.
3.0.0 Introduced.

Top ↑

User Contributed Notes User Contributed Notes

You must log in before being able to contribute a note or feedback.