-
Notifications
You must be signed in to change notification settings - Fork 134
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cleanup relationships when deleting questions and lessons, per #263
- Loading branch information
1 parent
2e8dc91
commit 3945837
Showing
3 changed files
with
301 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
<?php | ||
if ( ! defined( 'ABSPATH' ) ) { exit; } | ||
|
||
/** | ||
* Hooks and actions related to post relationships | ||
* @since [version] | ||
* @version [version] | ||
*/ | ||
class LLMS_Post_Relationships { | ||
|
||
/** | ||
* Configure relationships | ||
* @var array | ||
*/ | ||
private $relationships = array( | ||
|
||
'lesson' => array( | ||
array( | ||
'action' => 'unset', | ||
'meta_key' => '_llms_prerequisite', | ||
'meta_keys_additional' => array( '_llms_has_prerequisite' ), | ||
'post_type' => 'lesson', | ||
), | ||
array( | ||
'action' => 'unset', | ||
'meta_key' => '_llms_lesson_id', | ||
'post_type' => 'llms_quiz', | ||
), | ||
), | ||
|
||
'llms_quiz' => array( | ||
array( | ||
'action' => 'delete', // delete = force delete; trash = move to trash | ||
'meta_key' => '_llms_parent_id', | ||
'post_type' => 'llms_question', | ||
), | ||
array( | ||
'action' => 'unset', | ||
'meta_key' => '_llms_quiz', | ||
'meta_keys_additional' => array( '_llms_quiz_enabled' ), | ||
'post_type' => 'lesson', | ||
), | ||
), | ||
|
||
); | ||
|
||
public function __construct() { | ||
|
||
add_action( 'delete_post', array( $this, 'maybe_update_relationships' ) ); | ||
|
||
} | ||
|
||
/** | ||
* Delete / Trash posts related to the deleted post | ||
* @param obj $post WP Post that's been deleted | ||
* @param array $data relationship data array | ||
* @return void | ||
* @since [version] | ||
* @version [version] | ||
*/ | ||
private function delete_relationships( $post, $data ) { | ||
|
||
$relationships = $this->get_related_posts( $post->ID, $data['post_type'], $data['meta_key'] ); | ||
|
||
$force = ( 'delete' === $data['action'] ); | ||
|
||
foreach ( $relationships as $id ) { | ||
|
||
wp_delete_post( $id, $force ); | ||
|
||
} | ||
|
||
} | ||
|
||
/** | ||
* Get a list of post types with relationships that should be checked | ||
* @return array | ||
* @since [version] | ||
* @version [version] | ||
*/ | ||
private function get_post_types() { | ||
return array_keys( $this->get_relationships() ); | ||
} | ||
|
||
/** | ||
* Retrieve filtered LifterLMS post relatinoships array | ||
* @return array | ||
* @since [version] | ||
* @version [version] | ||
*/ | ||
private function get_relationships() { | ||
return apply_filters( 'llms_get_post_relationships', $this->relationships ); | ||
} | ||
|
||
/** | ||
* Retrieve an array of post ids related to the deleted post by post type and meta key | ||
* @param int $post_id WP Post ID of the deleted post | ||
* @param string $post_type WP Post type of the related post(s) | ||
* @param string $meta_key meta_key to check for relations by | ||
* @return array | ||
* @since [version] | ||
* @version [version] | ||
*/ | ||
private function get_related_posts( $post_id, $post_type, $meta_key ) { | ||
|
||
global $wpdb; | ||
return $wpdb->get_col( $wpdb->prepare( | ||
"SELECT p.ID | ||
FROM {$wpdb->posts} AS p | ||
LEFT JOIN {$wpdb->postmeta} AS pm | ||
ON p.ID = pm.post_id | ||
AND pm.meta_key = %s | ||
WHERE p.post_type = %s | ||
AND pm.meta_value = %d", | ||
$meta_key, | ||
$post_type, | ||
$post_id | ||
) ); | ||
|
||
|
||
} | ||
|
||
/** | ||
* Check relationships and delete / update related posts when a post is deleted | ||
* Called on `delete_post` hook (before a post is deleted) | ||
* @param int $post_id WP Post ID of the deleted post | ||
* @return void | ||
* @since [version] | ||
* @version [version] | ||
*/ | ||
public function maybe_update_relationships( $post_id ) { | ||
|
||
$post = get_post( $post_id ); | ||
if ( ! in_array( $post->post_type, $this->get_post_types() ) ) { | ||
return; | ||
} | ||
|
||
foreach ( $this->get_relationships() as $post_type => $relationships ) { | ||
|
||
foreach ( $relationships as $data ) { | ||
|
||
if ( in_array( $data['action'], array( 'delete', 'trash' ) ) ) { | ||
|
||
$this->delete_relationships( $post, $data ); | ||
|
||
} elseif ( 'unset' === $data['action'] ) { | ||
|
||
$this->unset_relationships( $post, $data ); | ||
|
||
} | ||
|
||
} | ||
|
||
} | ||
|
||
} | ||
|
||
/** | ||
* Unsets relationship data from post_meta when a post is deleted | ||
* @param obj $post WP Post that's been deleted | ||
* @param array $data relationship data array | ||
* @return void | ||
* @since [version] | ||
* @version [version] | ||
*/ | ||
private function unset_relationships( $post, $data ) { | ||
|
||
$relationships = $this->get_related_posts( $post->ID, $data['post_type'], $data['meta_key'] ); | ||
|
||
global $wpdb; | ||
|
||
foreach ( $relationships as $id ) { | ||
|
||
delete_post_meta( $id, $data['meta_key'], $post->ID ); | ||
|
||
if ( isset( $data['meta_keys_additional'] ) ) { | ||
foreach ( $data['meta_keys_additional'] as $key ) { | ||
delete_post_meta( $id, $key ); | ||
} | ||
} | ||
|
||
} | ||
|
||
} | ||
|
||
} | ||
|
||
return new LLMS_Post_Relationships(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
tests/unit-tests/class.llms.test.post.relationships.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
<?php | ||
/** | ||
* Tests for LLMS_Post_Instructors model & functions | ||
* @group post_relationships | ||
* @since [version] | ||
* @version [version] | ||
*/ | ||
class LLMS_Test_Post_Relationships extends LLMS_UnitTestCase { | ||
|
||
/** | ||
* When deleting lessons | ||
* A) Any lesson which has this lesson as a prereq should have that prereq removed | ||
* And the has_prereq metavalue should be unset returning "no" | ||
* B) Any quiz attached to this lesson should be detached (making it an orphan) | ||
* @return [type] | ||
* @since [version] | ||
* @version [version] | ||
*/ | ||
private function delete_lesson() { | ||
|
||
$courses = $this->generate_mock_courses( 1, 1, 4, 3, 1 ); | ||
$lessons = llms_get_post( $courses[0] )->get_lessons(); | ||
|
||
// add prereqs to all the lessons except the first | ||
foreach ( $lessons as $i => $lesson ) { | ||
|
||
if ( 0 === $i ) { | ||
continue; | ||
} | ||
|
||
$prev = $lessons[ $i - 1 ]; | ||
|
||
$lesson->set( 'has_prerequisite', 'yes' ); | ||
$lesson->set( 'prerequisite', $prev->get( 'id' ) ); | ||
|
||
} | ||
|
||
// delete posts and run tests | ||
foreach ( $lessons as $i => $lesson ) { | ||
|
||
$quiz = $lesson->get_quiz(); | ||
|
||
wp_delete_post( $lesson->get( 'id' ) ); | ||
|
||
// quizzes attached to the lesson should now be orphaned | ||
if ( $quiz ) { | ||
$this->assertTrue( $quiz->is_orphan() ); | ||
} | ||
|
||
if ( $i === count( $lessons ) - 1 ) { | ||
continue; | ||
} | ||
$next = $lessons[ $i + 1 ]; | ||
|
||
// prereqs should be removed | ||
$this->assertEquals( 'no', $next->get( 'has_prerequisite' ) ); | ||
$this->assertEquals( 0, $next->get( 'prerequisite' ) ); | ||
$this->assertFalse( $next->has_prerequisite() ); | ||
|
||
} | ||
|
||
} | ||
|
||
/** | ||
* When a quiz is deleted, all the child questions should be deleted too | ||
* Lesson should switch quiz_enabled to "no" | ||
* @return void | ||
* @since [version] | ||
* @version [version] | ||
*/ | ||
private function delete_quiz() { | ||
|
||
$courses = $this->generate_mock_courses( 1, 1, 1, 1, 20 ); | ||
$lesson = llms_get_post( llms_get_post( $courses[0] )->get_lessons( 'ids' )[0] ); | ||
$quiz = $lesson->get_quiz(); | ||
|
||
$questions = $quiz->get_questions( 'ids' ); | ||
|
||
wp_delete_post( $quiz->get( 'id' ), true ); | ||
|
||
foreach ( $questions as $question_id ) { | ||
|
||
$this->assertNull( get_post( $question_id ) ); | ||
|
||
} | ||
|
||
$this->assertFalse( $lesson->is_quiz_enabled() ); | ||
|
||
} | ||
|
||
/** | ||
* Test all relationships based on post types | ||
* @return void | ||
* @since [version] | ||
* @version [version] | ||
*/ | ||
public function test_maybe_update_relationships() { | ||
|
||
$funcs = array( | ||
'delete_quiz', | ||
'delete_lesson', | ||
); | ||
foreach ( $funcs as $func ) { | ||
|
||
call_user_func( array( $this, $func ) ); | ||
|
||
} | ||
|
||
} | ||
|
||
} |