Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add toggle to pre-publish panel to publish lessons when course is published #7536

Merged
merged 13 commits into from Mar 14, 2024
42 changes: 42 additions & 0 deletions assets/admin/course-pre-publish-panel/course-pre-publish-panel.js
@@ -0,0 +1,42 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { useEntityProp } from '@wordpress/core-data';
import { PluginPrePublishPanel } from '@wordpress/edit-post';
import { ToggleControl } from '@wordpress/components';

/**
* Internal dependencies
*/
import SenseiIcon from '../../icons/logo-tree.svg';

/**
* Course pre-publish panel.
*/
export const CoursePrePublishPanel = () => {
const [ meta, setMeta ] = useEntityProp( 'postType', 'course', 'meta' );
const { sensei_course_publish_lessons: publishLessons } = meta;

return (
<PluginPrePublishPanel
title={ __( 'Sensei LMS', 'sensei-lms' ) }
icon={ <SenseiIcon height="20" width="20" /> }
initialOpen={ true }
>
<ToggleControl
label={ __( 'Publish lessons', 'sensei-lms' ) }
help={ __(
'Publish lessons when the course is published.',
'sensei-lms'
) }
checked={ publishLessons }
onChange={ ( value ) =>
setMeta( { ...meta, sensei_course_publish_lessons: value } )
}
/>
</PluginPrePublishPanel>
);
};

export default CoursePrePublishPanel;
14 changes: 14 additions & 0 deletions assets/admin/course-pre-publish-panel/index.js
@@ -0,0 +1,14 @@
/**
* WordPress dependencies
*/
import { registerPlugin } from '@wordpress/plugins';

/**
* Internal dependencies
*/
import CoursePrePublishPanel from './course-pre-publish-panel';

registerPlugin( 'sensei-course-pre-publish-panel-plugin', {
render: CoursePrePublishPanel,
icon: null,
} );
2 changes: 1 addition & 1 deletion assets/icons/logo-tree.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions assets/js/admin/course-settings-plugin-sidebar.js
Expand Up @@ -51,14 +51,14 @@ export const CourseSidebar = () => {
<>
<PluginSidebarMoreMenuItem
target={ pluginSidebarHandle }
icon={ <SenseiIcon height="20" width="20" color="#43AF99" /> }
icon={ <SenseiIcon height="20" width="20" /> }
>
{ __( 'Course Settings', 'sensei-lms' ) }
</PluginSidebarMoreMenuItem>
<PluginSidebar
name={ pluginSidebarHandle }
title={ __( 'Course Settings', 'sensei-lms' ) }
icon={ <SenseiIcon height="20" width="20" color="#43AF99" /> }
icon={ <SenseiIcon height="20" width="20" /> }
>
{ ! hideCoursePricing && <CoursePricingPromoSidebar /> }
{ ! hideAccessPeriod && <CourseAccessPeriodPromoSidebar /> }
Expand Down
4 changes: 4 additions & 0 deletions changelog/update-save-lessons-on-course-save
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Add toggle to pre-publish panel to publish associated lessons when the course is published
6 changes: 6 additions & 0 deletions config/psalm/psalm-baseline.xml
Expand Up @@ -39,6 +39,12 @@
<code>DAY_IN_SECONDS</code>
</UndefinedConstant>
</file>
<file src="includes/admin/class-sensei-course-pre-publish-panel.php">
<DocblockTypeContradiction occurrences="2">
<code>! self::$instance</code>
<code>self::$instance</code>
</DocblockTypeContradiction>
</file>
<file src="includes/admin/class-sensei-editor-wizard.php">
<DocblockTypeContradiction occurrences="2">
<code>! self::$instance</code>
Expand Down
91 changes: 91 additions & 0 deletions includes/admin/class-sensei-course-pre-publish-panel.php
@@ -0,0 +1,91 @@
<?php
/**
* File containing the class Sensei_Course_Pre_Publish_Panel.
*
* @package sensei-lms
*/

if ( ! defined( 'ABSPATH' ) ) {
exit;

Check warning on line 9 in includes/admin/class-sensei-course-pre-publish-panel.php

View check run for this annotation

Codecov / codecov/patch

includes/admin/class-sensei-course-pre-publish-panel.php#L8-L9

Added lines #L8 - L9 were not covered by tests
}

/**
* Class that handles the pre-publish panel for courses.
*
* @since 4.5.0
donnapep marked this conversation as resolved.
Show resolved Hide resolved
*/
class Sensei_Course_Pre_Publish_Panel {
/**
* Instance of class.
*
* @var self
*/
private static $instance;

/**
* Sensei_Course_Pre_Publish_Panel constructor. Prevents other instances from being created outside of `self::instance()`.
*/
private function __construct() {
}

Check warning on line 29 in includes/admin/class-sensei-course-pre-publish-panel.php

View check run for this annotation

Codecov / codecov/patch

includes/admin/class-sensei-course-pre-publish-panel.php#L28-L29

Added lines #L28 - L29 were not covered by tests

/**
* Fetches an instance of the class.
*
* @return self
*/
public static function instance() {
if ( ! self::$instance ) {
self::$instance = new self();

Check warning on line 38 in includes/admin/class-sensei-course-pre-publish-panel.php

View check run for this annotation

Codecov / codecov/patch

includes/admin/class-sensei-course-pre-publish-panel.php#L36-L38

Added lines #L36 - L38 were not covered by tests
}

return self::$instance;

Check warning on line 41 in includes/admin/class-sensei-course-pre-publish-panel.php

View check run for this annotation

Codecov / codecov/patch

includes/admin/class-sensei-course-pre-publish-panel.php#L41

Added line #L41 was not covered by tests
}

/**
* Initializes the class.
donnapep marked this conversation as resolved.
Show resolved Hide resolved
*/
public function init() {
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_pre_publish_panel_assets' ) );
add_action( 'publish_course', array( $this, 'maybe_publish_lessons' ) );

Check warning on line 49 in includes/admin/class-sensei-course-pre-publish-panel.php

View check run for this annotation

Codecov / codecov/patch

includes/admin/class-sensei-course-pre-publish-panel.php#L47-L49

Added lines #L47 - L49 were not covered by tests
}

/**
* Enqueue pre-publish panel assets.
*/
public function enqueue_pre_publish_panel_assets() {
if ( 'course' !== get_post_type() ) {
return;

Check warning on line 57 in includes/admin/class-sensei-course-pre-publish-panel.php

View check run for this annotation

Codecov / codecov/patch

includes/admin/class-sensei-course-pre-publish-panel.php#L55-L57

Added lines #L55 - L57 were not covered by tests
}

Sensei()->assets->enqueue( 'sensei-course-pre-publish-panel-script', 'admin/course-pre-publish-panel/index.js' );

Check warning on line 60 in includes/admin/class-sensei-course-pre-publish-panel.php

View check run for this annotation

Codecov / codecov/patch

includes/admin/class-sensei-course-pre-publish-panel.php#L60

Added line #L60 was not covered by tests
}

/**
* Maybe publish associated lessons when the course is published.
*
donnapep marked this conversation as resolved.
Show resolved Hide resolved
* @param int $course_id Course ID.
*/
public function maybe_publish_lessons( $course_id ) {
if ( ! current_user_can( 'publish_post', $course_id ) ) {
return;
}

$publish_lessons = get_post_meta( $course_id, 'sensei_course_publish_lessons', true );

if ( ! $publish_lessons ) {
return;
}

// Publish all draft lessons for this course.
$lesson_ids = Sensei()->course->course_lessons( $course_id, 'draft', 'ids' );

foreach ( $lesson_ids as $lesson_id ) {
wp_update_post(
array(
'ID' => (int) $lesson_id,
'post_status' => 'publish',
)
);
}
}
}
4 changes: 2 additions & 2 deletions includes/block-patterns/class-sensei-block-patterns.php
Expand Up @@ -45,7 +45,7 @@ public function init() {
}

/**
* Sensei_Editor_Wizard constructor. Prevents other instances from being created outside of `self::instance()`.
* Sensei_Block_Patterns constructor. Prevents other instances from being created outside of `self::instance()`.
*/
private function __construct() {
}
Expand Down Expand Up @@ -137,7 +137,7 @@ public function maybe_register_pattern_block_polyfill() {
'core/pattern',
[
'editor_script' => 'sensei-core-pattern-polyfill-script',
'render_callback' => function( $attributes ) {
'render_callback' => function ( $attributes ) {
if ( empty( $attributes['slug'] ) ) {
return '';
}
Expand Down
12 changes: 12 additions & 0 deletions includes/class-sensei-course.php
Expand Up @@ -694,6 +694,18 @@
'auth_callback' => [ $this, 'post_meta_auth_callback' ],
]
);
register_post_meta(
'course',
'sensei_course_publish_lessons',
[
'show_in_rest' => true,
'single' => true,
'type' => 'boolean',
'default' => true,
'auth_callback' => [ $this, 'post_meta_auth_callback' ],
]
);

Check warning on line 707 in includes/class-sensei-course.php

View check run for this annotation

Codecov / codecov/patch

includes/class-sensei-course.php#L697-L707

Added lines #L697 - L707 were not covered by tests

/**
* Sets up the meta fields saved on course save in WP admin.
*
Expand Down
1 change: 1 addition & 0 deletions includes/class-sensei-data-cleaner.php
Expand Up @@ -262,6 +262,7 @@ class Sensei_Data_Cleaner {
'sensei_payment_complete',
'sensei_products_processed',
'_sensei_attachment_source_key',
'sensei_course_publish_lessons',
'sensei_course_video_autocomplete',
'sensei_course_video_autopause',
'sensei_course_video_required',
Expand Down
2 changes: 1 addition & 1 deletion includes/class-sensei.php
Expand Up @@ -658,7 +658,7 @@

Sensei_No_Users_Table_Relationship::instance()->init();
SenseiLMS_Plugin_Updater::init();

Sensei_Course_Pre_Publish_Panel::instance()->init();

Check warning on line 661 in includes/class-sensei.php

View check run for this annotation

Codecov / codecov/patch

includes/class-sensei.php#L661

Added line #L661 was not covered by tests
} else {

// Load Frontend Class
Expand Down
106 changes: 106 additions & 0 deletions tests/unit-tests/admin/test-class-sensei-course-pre-publish-panel.php
@@ -0,0 +1,106 @@
<?php
/**
* This file contains the Sensei_Course_Pre_Publish_Panel_Test class.
*
* @package sensei
*/

/**
* Tests for Sensei_Course_Pre_Publish_Panel class.
*/
class Sensei_Sensei_Course_Pre_Publish_Panel_Test extends WP_UnitTestCase {
use Sensei_Test_Login_Helpers;

/**
* Factory for setting up testing data.
*
* @var Sensei_Factory
*/
protected $factory;

/**
* Course ID.
*
* @var int
*/
private $course_id;

/**
* Lesson ID.
*
* @var int
*/
private $lesson_id;

public function setUp(): void {
parent::setUp();

$this->factory = new Sensei_Factory();
$this->course_id = $this->factory->course->create();
$this->lesson_id = $this->factory->lesson->create(
[
'post_status' => 'draft',
'meta_input' => [
'_lesson_course' => $this->course_id,
],
]
);
}

public function tearDown(): void {
parent::tearDown();

$this->factory->tearDown();
}

/**
* Lessons aren't published if the user doesn't have sufficient permissions.
*
* @covers Sensei_Course_Pre_Publish_Panel::maybe_publish_lessons
*/
public function testMaybePublishLessons_InsufficientPermissions_DoesNotPublishLessons() {
/* Arrange */
$this->login_as_student();
update_post_meta( $this->course_id, 'sensei_course_publish_lessons', true );

/* Act */
Sensei_Course_Pre_Publish_Panel::instance()->maybe_publish_lessons( $this->course_id );

/* Assert */
$this->assertEquals( 'draft', get_post_status( $this->lesson_id ) );
}

/**
* Lessons aren't published if the user has sufficient permissions but the meta value is false.
*
* @covers Sensei_Course_Pre_Publish_Panel::maybe_publish_lessons
*/
public function testMaybePublishLessons_MetaIsFalse_DoesNotPublishLessons() {
/* Arrange */
$this->login_as_admin();
update_post_meta( $this->course_id, 'sensei_course_publish_lessons', false );

/* Act */
Sensei_Course_Pre_Publish_Panel::instance()->maybe_publish_lessons( $this->course_id );

/* Assert */
$this->assertEquals( 'draft', get_post_status( $this->lesson_id ) );
}

/**
* Lessons are published if the user has sufficient permissions and the meta value is true.
*
* @covers Sensei_Course_Pre_Publish_Panel::maybe_publish_lessons
*/
public function testMaybePublishLessons_SufficientPermissionsAndMetaIsTrue_DoesPublishLessons() {
/* Arrange */
$this->login_as_admin();
update_post_meta( $this->course_id, 'sensei_course_publish_lessons', true );

/* Act */
Sensei_Course_Pre_Publish_Panel::instance()->maybe_publish_lessons( $this->course_id );

/* Assert */
$this->assertEquals( 'publish', get_post_status( $this->lesson_id ) );
}
}
1 change: 1 addition & 0 deletions webpack.config.js
Expand Up @@ -89,6 +89,7 @@ const files = [
'blocks/email-editor.js',
'css/email-notifications/email-editor-style.scss',
'css/email-notifications/email-style.scss',
'admin/course-pre-publish-panel/index.js',
'admin/editor-wizard/index.js',
'admin/editor-wizard/style.scss',
'admin/tour/course-tour/index.js',
Expand Down