How to migrate from Thinkific to WordPress. Part 4: Reviews import

How to migrate from Thinkific to WordPress. Part 4: Reviews import

3 weeks ago ·
· 5 min read

In the previous article, the third part of this 5-article series, I described the implementation of the WP-CLI command to import the progress of courses for users.

In part four, I will describe the functionality of the WP-CLI command to import reviews given by users to the courses. Below, I also provide you with the list of articles in the series:

Table of contents

Declaring the review import method

I start again with declaring the method and the helper variables for reading from the file:

public function import_reviews(): void {
    global $wp_filesystem, $wpdb;
    include_once ABSPATH . 'wp-admin/includes/file.php';
    $files = array( 'course-1-reviews.json', 'course-2-reviews.json', 'course-3-reviews', 'course-4-reviews.json' );

I also declared a variable of type array with the list of files containing reviews for courses, which I will iterate through using foreach ($files as $file).

Reading from file

JSON file structure

I'm putting here again the structure of the review file in JSON format:

  "@context": "",
  "@type": "Product",
  "name": "<course-name>",
  "aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.6", "reviewCount": 5 },
  "review": [
      "@type": "Review",
      "author": { "@type": "Person", "name": "<reviewer-name>" },
      "description": "<review-description>",
      "name": "<review-title>",
      "date": "November 26, 2021",
      "reviewRating": { "@type": "Rating", "bestRating": 5, "ratingValue": 5, "worstRating": 0 }
    // ...
    "image": "<course-image-url>"

As in the previous articles, reading from files is done in a similar way, but this time I won't use the helper method parse_csv_content to compose the vector with lines from the CSV file. Instead, I will use the json_decode function to interpret the JSON code:

$file_path    = plugin_dir_path( __FILE__ ) . '/data/reviews/' . $file;
$file_content = $wp_filesystem->get_contents( $file_path );
$json         = json_decode( $file_content );
$course_name  = $json->name;
$review_count = count( $json->review );
$course = get_page_by_title( $course_name, OBJECT, 'courses' );

I also declared a few more variables that will be useful later on. I made sure that the course names in the review files in the name field match the names of the courses created in Tutor LMS.

Processing reviews

I then started looping through the reviews in the review vector in the JSON and proceeded like this:

foreach ( $json->review as $review ) {
    $user_id = $this->search_user_by_name( $review->author->name );
    $new_comment  = wp_insert_comment(
            'comment_post_ID'  => $course->ID,
            'comment_author'   => $review->author->name,
            'comment_date'     => gmdate( 'Y-m-d H:i:s', strtotime( $review->date ) ),
            'comment_content'  => $review->description,
            'comment_agent'    => 'TutorLMSPlugin',
            'comment_type'     => 'tutor_course_rating',
            'comment_approved' => 'approved',
            'user_id'          => $user_id,
            'comment_meta'     => array( 'tutor_rating' => $review->reviewRating->ratingValue ), // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
    if ( is_wp_error( $new_comment ) ) {
        \WP_CLI::warning( sprintf( 'Review of "%s" for "%s" not imported.', $review->author->name, $course_name ) );

I performed a search for the user's name to retrieve their ID from the database using the helper method search_user_by_name, described below. Then, I used the wp_insert_comment function to create the review, to which I passed the necessary values:

The method for searching for a user by name and surname is here:

protected function search_user_by_name( string $name ): int {
    $normalized_name = str_replace( '  ', ' ', trim( $name ) );
    $names           = explode( ' ', $normalized_name );
    $last_name       = array_pop( $names );
    $first_name      = implode( ' ', $names );
    $wp_user_query = new WP_User_Query(
            'role'       => 'subscriber',
            'meta_query' => array(
                'relation' => 'AND',
                    'key'     => 'first_name',
                    'value'   => $first_name,
                    'compare' => '=',
                    'key'     => 'last_name',
                    'value'   => $last_name,
                    'compare' => '=',
    $authors = $wp_user_query->get_results();
    return $authors[0]->ID;

In the initial phase, I performed a small normalization of the name, specifically removing spaces from the ends and replacing double spaces in the name with a single space. I noticed many discrepancies of this kind in the JSON-exported file obtained from Thinkific course pages.

Then (in lines 3-5), I split the name by space to be able to obtain the first and last names, even when the full name consists of 3 names. In this case, I used ChatGPT, resulting in the combination of the explode, array_pop, and implode functions.

Furthermore, I used the WP_User_Query class for the complex query to find the user by their first and last names, and finally, I returned the ID.

Closing thoughts

With the execution of the last WP-CLI command, we now have the reviews added:

$ wp thinkific import reviews

The migration is complete, and in the next article, I will make a few adjustments to the theme, Tutor LMS, and WooCommerce templates."

If you need such a migration, click below, and let's discuss.

Contact me

Share on: