LLMS_Blocks_Migrate
Handle post migration to the block editor.
Contents
Source Source
File: libraries/lifterlms-blocks/includes/class-llms-blocks-migrate.php
class LLMS_Blocks_Migrate {
/**
* Constructor.
*
* @since 1.0.0
* @since 1.4.0 Add action for unmigrating posts from the Tools & Utilities status screen.
* @since 1.7.0 Perform migrations on `current_screen` instead of `admin_enqueue_scripts`.
*/
public function __construct() {
add_action( 'current_screen', array( $this, 'migrate_post' ) );
add_action( 'wp', array( $this, 'remove_template_hooks' ) );
add_action( 'llms_blocks_unmigrate_posts', array( $this, 'unmigrate_posts' ) );
add_filter( 'llms_blocks_is_post_migrated', array( __CLASS__, 'check_sales_page' ), 15, 2 );
}
/**
* Add a template to a post & save migration status in postmeta.
*
* @since 1.4.0
*
* @param WP_Post $post Post object.
* @return bool
*/
private function add_template_to_post( $post ) {
// Update the post.
if ( $this->update_post_content( $post->ID, $post->post_content . "\r\r" . $this->get_template( $post->post_type ) ) ) {
// Save migration state.
$this->update_migration_status( $post->ID );
return true;
}
return false;
}
/**
* Don't remove core template actions when a sales page is enabled and the page is restricted.
* @since 1.2.0
* @since 1.3.1 Unknown.
*
* @param bool $ret Default migration status.
* @param int $post_id WP_Post ID.
* @return bool
*/
public static function check_sales_page( $ret, $post_id ) {
$page_restricted = llms_page_restricted( $post_id );
if ( $page_restricted['is_restricted'] ) {
$sales_page = get_post_meta( $post_id, '_llms_sales_page_content_type', true );
if ( '' === $sales_page || 'content' === $sales_page ) {
$ret = false;
}
}
return $ret;
}
/**
* Get an array of post types which can be migrated.
*
* @since 1.3.3
* @since 1.7.0 Memberships are migrateable.
*
* @return array
*/
public function get_migrateable_post_types() {
/**
* Filters the post types that can be migrated
*
* @since 1.3.3
*
* @param string[] $post_types An array of string representing the post types that can be migrated.
*/
return apply_filters( 'llms_blocks_migrateable_post_types', array( 'course', 'lesson', 'llms_membership' ) );
}
/**
* Retrieve a WP_Query for posts which have already been migrated.
*
* @since 1.4.0
*
* @param array $args Optional query arguments to pass to WP_Query.
* @return WP_Query
*/
public function get_migrated_posts( $args = array() ) {
return new WP_Query(
wp_parse_args(
$args,
array(
'post_type' => $this->get_migrateable_post_types(),
'meta_query' => array(
array(
'key' => '_llms_blocks_migrated',
'value' => 'yes',
),
),
)
)
);
}
/**
* Retrieve the block template by post type.
*
* @since 1.0.0
* @since 1.7.0 Add membership template.
* @since 1.8.0 Updated course progress shortcode and added the `$merge_deprecated_versions` param.
* @since 1.9.1 Fix course progress block.
*
* @param string $post_type WP post type.
* @param boolean $merge_deprecated_versions Optional. Whether or not getting the deprecated blocks merged, useful when removing templates. Default `false`.
* @return string
*/
private function get_template( $post_type, $merge_deprecated_versions = false ) {
if ( 'course' === $post_type ) {
ob_start();
?><!-- wp:llms/course-information /-->
<!-- wp:llms/instructors /-->
<!-- wp:llms/pricing-table /-->
<!-- wp:llms/course-progress /-->
<?php if ( $merge_deprecated_versions ) : ?>
<!-- wp:llms/course-progress -->
<div class="wp-block-llms-course-progress">[lifterlms_course_progress check_enrollment=1]</div>
<div class="wp-block-llms-course-progress">[lifterlms_course_progress]</div>
<!-- /wp:llms/course-progress -->
<?php endif; ?>
<!-- wp:llms/course-continue-button -->
<div class="wp-block-llms-course-continue-button" style="text-align:center">[lifterlms_course_continue_button]</div>
<!-- /wp:llms/course-continue-button -->
<!-- wp:llms/course-syllabus /-->
<?php
return ob_get_clean();
}
if ( 'lesson' === $post_type ) {
ob_start();
?>
<!-- wp:llms/lesson-progression /-->
<!-- wp:llms/lesson-navigation /-->
<?php
return ob_get_clean();
}
if ( 'llms_membership' ) {
ob_start();
?>
<!-- wp:llms/pricing-table /-->
<?php
return ob_get_clean();
}
return '';
}
/**
* Migrate posts created prior to the block editor to have default LifterLMS templates
*
* @since 1.0.0
* @since 1.4.0 Moves content updating methods to it's own function.
* @since 1.7.0 Add Membership post type support.
* Update to handle being triggered by hook `current_screen` instead of `admin_enqueue_scripts`.
*
* @return void
*/
public function migrate_post() {
global $pagenow;
if ( 'post.php' !== $pagenow ) {
return;
}
$post_id = llms_filter_input( INPUT_GET, 'post', FILTER_SANITIZE_NUMBER_INT );
$post = $post_id ? get_post( $post_id ) : false;
if ( ! $post || ! $this->should_migrate_post( $post->ID ) ) {
return;
}
if ( 'llms_membership' === $post->post_type ) {
if ( has_block( 'llms/pricing-table', $post->post_content ) ) {
$this->update_migration_status( $post->ID );
return;
}
} elseif ( has_blocks( $post->post_content ) ) {
$this->update_migration_status( $post->ID );
return;
}
$this->add_template_to_post( $post );
// Reload.
wp_safe_redirect(
add_query_arg(
array(
'post' => $post->ID,
'action' => 'edit',
),
admin_url( 'post.php' )
)
);
exit;
}
/**
* Remove post type templates and any LifterLMS Blocks from a given post.
*
* @since 1.4.0
* @since 1.8.0 Get all post type's template with deprecated blocks versions merged.
*
* @param WP_Post $post Post object.
* @return bool
*/
private function remove_template_from_post( $post ) {
$template = $this->get_template( $post->post_type, true );
if ( ! $template ) {
return;
}
// explicitly remove template pieces.
$parts = array_filter( array_map( 'trim', explode( "\n", $template ) ) );
$content = str_replace( $parts, '', $post->post_content );
// replace any remaining LLMS blocks not found in the template (also grabs any openers that have block settings JSON).
$content = trim( preg_replace( '#<!-- \/?wp:llms\/.* \/?-->#', '', $content ) );
if ( $this->update_post_content( $post->ID, $content ) ) {
$this->update_migration_status( $post->ID, 'no' );
return true;
}
return false;
}
/**
* Removes core template action hooks from posts which have been migrated to the block editor
*
* @since 1.3.2 Unknown.
*
* @return void
* @since 1.1.0
*/
public function remove_template_hooks() {
if ( ! llms_blocks_is_post_migrated( get_the_ID() ) ) {
return;
}
// Course Information.
remove_action( 'lifterlms_single_course_after_summary', 'lifterlms_template_single_meta_wrapper_start', 5 );
remove_action( 'lifterlms_single_course_after_summary', 'lifterlms_template_single_length', 10 );
remove_action( 'lifterlms_single_course_after_summary', 'lifterlms_template_single_difficulty', 20 );
remove_action( 'lifterlms_single_course_after_summary', 'lifterlms_template_single_course_tracks', 25 );
remove_action( 'lifterlms_single_course_after_summary', 'lifterlms_template_single_course_categories', 30 );
remove_action( 'lifterlms_single_course_after_summary', 'lifterlms_template_single_course_tags', 35 );
remove_action( 'lifterlms_single_course_after_summary', 'lifterlms_template_single_meta_wrapper_end', 50 );
// Remove Course Progress.
remove_action( 'lifterlms_single_course_after_summary', 'lifterlms_template_single_course_progress', 60 );
// Course Syllabus.
remove_action( 'lifterlms_single_course_after_summary', 'lifterlms_template_single_syllabus', 90 );
// Instructors.
remove_action( 'lifterlms_single_course_after_summary', 'lifterlms_template_course_author', 40 );
// Lesson Navigation.
remove_action( 'lifterlms_single_lesson_after_summary', 'lifterlms_template_lesson_navigation', 20 );
// Lesson Progression.
remove_action( 'lifterlms_single_lesson_after_summary', 'lifterlms_template_complete_lesson_link', 10 );
// Pricing Table.
remove_action( 'lifterlms_single_course_after_summary', 'lifterlms_template_pricing_table', 60 );
remove_action( 'lifterlms_single_membership_after_summary', 'lifterlms_template_pricing_table', 10 );
}
/**
* Determine if a post should be migrated.
*
* @since 1.3.3
*
* @param int $post_id WP_Post ID.
* @return bool
*/
public function should_migrate_post( $post_id ) {
$ret = true;
// Not a valid post type.
if ( ! in_array( get_post_type( $post_id ), $this->get_migrateable_post_types(), true ) ) {
$ret = false;
// Classic is enabled, don't migrate.
} elseif ( llms_blocks_is_classic_enabled_for_post( $post_id ) ) {
$ret = false;
// Already Migrated.
} elseif ( llms_parse_bool( get_post_meta( $post_id, '_llms_blocks_migrated', true ) ) ) {
$ret = false;
}
/**
* Filters whether or not a post should be migrated
*
* @since 1.3.3
*
* @param bool $migrate Whether or not a post should be migrated.
* @param int $post_id WP_Post ID.
*/
return apply_filters( 'llms_blocks_should_migrate_post', $ret, $post_id );
}
/**
* Unmigrates migrated posts.
*
* @since 1.4.0
*
* @return void.
*/
public function unmigrate_posts() {
$posts = $this->get_migrated_posts( array( 'posts_per_page' => 250 ) ); // phpcs:ignore WordPress.WP.PostsPerPage.posts_per_page_posts_per_page
if ( $posts->posts ) {
foreach ( $posts->posts as $post ) {
$this->remove_template_from_post( $post );
}
}
}
/**
* Update post meta data to signal status of the editor migration.
*
* @since 1.1.0
*
* @param int $post_id WP_Post ID.
* @param string $status Yes or no.
* @return void
*/
private function update_migration_status( $post_id, $status = 'yes' ) {
update_post_meta( $post_id, '_llms_blocks_migrated', $status );
}
/**
* Update the post content for a given post.
*
* @since 1.4.0
*
* @param int $id WP_Post ID.
* @param string $content Post content to update.
* @return bool
*/
private function update_post_content( $id, $content ) {
global $wpdb;
$update = $wpdb->update(
$wpdb->posts,
array(
'post_content' => $content,
),
array(
'ID' => $id,
),
array( '%s' ),
array( '%d' )
); // db no-cache okay.
return false === $update ? false : true;
}
}
Expand full source code Collapse full source code View on GitHub
Methods Methods
- __construct — Constructor.
- add_template_to_post — Add a template to a post & save migration status in postmeta.
- check_sales_page — Don't remove core template actions when a sales page is enabled and the page is restricted.
- get_migrateable_post_types — Get an array of post types which can be migrated.
- get_migrated_posts — Retrieve a WP_Query for posts which have already been migrated.
- get_template — Retrieve the block template by post type.
- migrate_post — Migrate posts created prior to the block editor to have default LifterLMS templates
- remove_template_from_post — Remove post type templates and any LifterLMS Blocks from a given post.
- remove_template_hooks — Removes core template action hooks from posts which have been migrated to the block editor
- should_migrate_post — Determine if a post should be migrated.
- unmigrate_posts — Unmigrates migrated posts.
- update_migration_status — Update post meta data to signal status of the editor migration.
- update_post_content — Update the post content for a given post.
Changelog Changelog
| Version | Description |
|---|---|
| 1.9.1 | Fix course progress block. |
| 1.8.0 | Update course progress bar shortcode in the course block template. |
| 1.7.0 | Perform migrations on current_screen instead of admin_enqueue_scripts. Migrate membership post types to use pricing table blocks. |
| 1.4.0 | Added action for unmigrating posts from the Tools & Utilities status screen. |
| 1.0.0 | Introduced. |