Make Sure Important Emails Reach Your Customers
Solve common email deliverability issues for good. Get WP Mail SMTP!
/** * Regenerate Thumbnails: Attachment regenerator class * * @package RegenerateThumbnails * @since 3.0.0 */ /** * Regenerates the thumbnails for a given attachment. * * @since 3.0.0 */ class RegenerateThumbnails_Regenerator { /** * The WP_Post object for the attachment that is being operated on. * * @since 3.0.0 * * @var WP_Post */ public $attachment; /** * The full path to the original image so that it can be passed between methods. * * @since 3.0.0 * * @var string */ public $fullsizepath; /** * An array of thumbnail size(s) that were skipped during regeneration due to already existing. * A class variable is used so that the data can later be used to merge the size(s) back in. * * @since 3.0.0 * * @var array */ public $skipped_thumbnails = array(); /** * The metadata for the attachment before the regeneration process starts. * * @since 3.1.6 * * @var array */ private $old_metadata = array(); /** * Generates an instance of this class after doing some setup. * * MIME type is purposefully not validated in order to be more future proof and * to avoid duplicating a ton of logic that already exists in WordPress core. * * @since 3.0.0 * * @param int $attachment_id Attachment ID to process. * * @return RegenerateThumbnails_Regenerator|WP_Error A new instance of RegenerateThumbnails_Regenerator on success, or WP_Error on error. */ public static function get_instance( $attachment_id ) { $attachment = get_post( $attachment_id ); if ( ! $attachment ) { return new WP_Error( 'regenerate_thumbnails_regenerator_attachment_doesnt_exist', __( 'No attachment exists with that ID.', 'regenerate-thumbnails' ), array( 'status' => 404, ) ); } // We can only regenerate thumbnails for attachments. if ( 'attachment' !== get_post_type( $attachment ) ) { return new WP_Error( 'regenerate_thumbnails_regenerator_not_attachment', __( 'This item is not an attachment.', 'regenerate-thumbnails' ), array( 'status' => 400, ) ); } // Don't touch any attachments that are being used as a site icon. Their thumbnails are usually custom cropped. if ( self::is_site_icon( $attachment ) ) { return new WP_Error( 'regenerate_thumbnails_regenerator_is_site_icon', __( "This attachment is a site icon and therefore the thumbnails shouldn't be touched.", 'regenerate-thumbnails' ), array( 'status' => 415, 'attachment' => $attachment, ) ); } return new RegenerateThumbnails_Regenerator( $attachment ); } /** * The constructor for this class. Don't call this directly, see get_instance() instead. * This is done so that WP_Error objects can be returned during class initiation. * * @since 3.0.0 * * @param WP_Post $attachment The WP_Post object for the attachment that is being operated on. */ private function __construct( WP_Post $attachment ) { $this->attachment = $attachment; } /** * Returns whether the attachment is or was a site icon. * * @since 3.0.0 * * @param WP_Post $attachment The WP_Post object for the attachment that is being operated on. * * @return bool Whether the attachment is or was a site icon. */ public static function is_site_icon( WP_Post $attachment ) { return ( 'site-icon' === get_post_meta( $attachment->ID, '_wp_attachment_context', true ) ); } /** * Get the path to the fullsize attachment. * * @return string|WP_Error The path to the fullsize attachment, or a WP_Error object on error. */ public function get_fullsizepath() { if ( $this->fullsizepath ) { return $this->fullsizepath; } if ( function_exists( 'wp_get_original_image_path' ) ) { $this->fullsizepath = wp_get_original_image_path( $this->attachment->ID ); } else { $this->fullsizepath = get_attached_file( $this->attachment->ID ); } if ( false === $this->fullsizepath || ! file_exists( $this->fullsizepath ) ) { $error = new WP_Error( 'regenerate_thumbnails_regenerator_file_not_found', sprintf( /* translators: The relative upload path to the attachment. */ __( "The fullsize image file cannot be found in your uploads directory at %s. Without it, new thumbnail images can't be generated.", 'regenerate-thumbnails' ), _wp_relative_upload_path( $this->fullsizepath ) ), array( 'status' => 404, 'fullsizepath' => _wp_relative_upload_path( $this->fullsizepath ), 'attachment' => $this->attachment, ) ); $this->fullsizepath = $error; } return $this->fullsizepath; } /** * Regenerate the thumbnails for this instance's attachment. * * @since 3.0.0 * * @param array|string $args { * Optional. Array or string of arguments for thumbnail regeneration. * * @type bool $only_regenerate_missing_thumbnails Skip regenerating existing thumbnail files. Default true. * @type bool $delete_unregistered_thumbnail_files Delete any thumbnail sizes that are no longer registered. Default false. * } * * @return mixed|WP_Error Metadata for attachment (see wp_generate_attachment_metadata()), or WP_Error on error. */ public function regenerate( $args = array() ) { global $wpdb; $args = wp_parse_args( $args, array( 'only_regenerate_missing_thumbnails' => true, 'delete_unregistered_thumbnail_files' => false, ) ); $fullsizepath = $this->get_fullsizepath(); if ( is_wp_error( $fullsizepath ) ) { $fullsizepath->add_data( array( 'attachment' => $this->attachment ) ); return $fullsizepath; } $this->old_metadata = wp_get_attachment_metadata( $this->attachment->ID ); if ( $args['only_regenerate_missing_thumbnails'] ) { add_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_image_sizes_to_only_missing_thumbnails' ), 10, 2 ); } require_once( ABSPATH . 'wp-admin/includes/admin.php' ); $new_metadata = wp_generate_attachment_metadata( $this->attachment->ID, $fullsizepath ); if ( $args['only_regenerate_missing_thumbnails'] ) { // Thumbnail sizes that existed were removed and need to be added back to the metadata. foreach ( $this->skipped_thumbnails as $skipped_thumbnail ) { if ( ! empty( $this->old_metadata['sizes'][ $skipped_thumbnail ] ) ) { $new_metadata['sizes'][ $skipped_thumbnail ] = $this->old_metadata['sizes'][ $skipped_thumbnail ]; } } $this->skipped_thumbnails = array(); remove_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_image_sizes_to_only_missing_thumbnails' ), 10 ); } $wp_upload_dir = dirname( $fullsizepath ) . DIRECTORY_SEPARATOR; if ( $args['delete_unregistered_thumbnail_files'] ) { // Delete old sizes that are still in the metadata. $intermediate_image_sizes = get_intermediate_image_sizes(); foreach ( $this->old_metadata['sizes'] as $old_size => $old_size_data ) { if ( in_array( $old_size, $intermediate_image_sizes ) ) { continue; } wp_delete_file( $wp_upload_dir . $old_size_data['file'] ); unset( $new_metadata['sizes'][ $old_size ] ); } $relative_path = dirname( $new_metadata['file'] ) . DIRECTORY_SEPARATOR; // It's possible to upload an image with a filename like image-123x456.jpg and it shouldn't be deleted. $whitelist = $wpdb->get_col( $wpdb->prepare( " SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = '_wp_attached_file' AND meta_value REGEXP %s /* Regenerate Thumbnails */ ", '^' . preg_quote( $relative_path ) . '[^' . preg_quote( DIRECTORY_SEPARATOR ) . ']+-[0-9]+x[0-9]+\.' ) ); $whitelist = array_map( 'basename', $whitelist ); $filelist = array(); foreach ( scandir( $wp_upload_dir ) as $file ) { if ( '.' == $file || '..' == $file || ! is_file( $wp_upload_dir . $file ) ) { continue; } $filelist[] = $file; } $registered_thumbnails = array(); foreach ( $new_metadata['sizes'] as $size ) { $registered_thumbnails[] = $size['file']; } $fullsize_parts = pathinfo( $fullsizepath ); foreach ( $filelist as $file ) { if ( in_array( $file, $whitelist ) || in_array( $file, $registered_thumbnails ) ) { continue; } if ( ! preg_match( '#^' . preg_quote( $fullsize_parts['filename'], '#' ) . '-[0-9]+x[0-9]+\.' . preg_quote( $fullsize_parts['extension'], '#' ) . '$#', $file ) ) { continue; } wp_delete_file( $wp_upload_dir . $file ); } } elseif ( ! empty( $this->old_metadata ) && ! empty( $this->old_metadata['sizes'] ) && is_array( $this->old_metadata['sizes'] ) ) { // If not deleting, rename any size conflicts to avoid them being lost if the file still exists. foreach ( $this->old_metadata['sizes'] as $old_size => $old_size_data ) { if ( empty( $new_metadata['sizes'][ $old_size ] ) ) { $new_metadata['sizes'][ $old_size ] = $this->old_metadata['sizes'][ $old_size ]; continue; } $new_size_data = $new_metadata['sizes'][ $old_size ]; if ( $new_size_data['width'] !== $old_size_data['width'] && $new_size_data['height'] !== $old_size_data['height'] && file_exists( $wp_upload_dir . $old_size_data['file'] ) ) { $new_metadata['sizes'][ $old_size . '_old_' . $old_size_data['width'] . 'x' . $old_size_data['height'] ] = $old_size_data; } } } wp_update_attachment_metadata( $this->attachment->ID, $new_metadata ); return $new_metadata; } /** * Filters the list of thumbnail sizes to only include those which have missing files. * * @since 3.0.0 * * @param array $sizes An associative array of registered thumbnail image sizes. * @param array $fullsize_metadata An associative array of fullsize image metadata: width, height, file. * * @return array An associative array of image sizes. */ public function filter_image_sizes_to_only_missing_thumbnails( $sizes, $fullsize_metadata ) { if ( ! $sizes ) { return $sizes; } $fullsizepath = $this->get_fullsizepath(); if ( is_wp_error( $fullsizepath ) ) { return $sizes; } $editor = wp_get_image_editor( $fullsizepath ); if ( is_wp_error( $editor ) ) { return $sizes; } $metadata = $this->old_metadata; // This is based on WP_Image_Editor_GD::multi_resize() and others. foreach ( $sizes as $size => $size_data ) { if ( empty( $metadata['sizes'][ $size ] ) ) { continue; } if ( ! isset( $size_data['width'] ) && ! isset( $size_data['height'] ) ) { continue; } if ( ! isset( $size_data['width'] ) ) { $size_data['width'] = null; } if ( ! isset( $size_data['height'] ) ) { $size_data['height'] = null; } if ( ! isset( $size_data['crop'] ) ) { $size_data['crop'] = false; } $thumbnail = $this->get_thumbnail( $editor, $fullsize_metadata['width'], $fullsize_metadata['height'], $size_data['width'], $size_data['height'], $size_data['crop'] ); // The false check filters out thumbnails that would be larger than the fullsize image. // The size comparison makes sure that the size is also correct. if ( false === $thumbnail || ( $thumbnail['width'] === $metadata['sizes'][ $size ]['width'] && $thumbnail['height'] === $metadata['sizes'][ $size ]['height'] && file_exists( $thumbnail['filename'] ) ) ) { $this->skipped_thumbnails[] = $size; unset( $sizes[ $size ] ); } } /** * Filters the list of missing thumbnail sizes if you want to add/remove any. * * @since 3.1.0 * * @param array $sizes An associative array of image sizes that are missing. * @param array $fullsize_metadata An associative array of fullsize image metadata: width, height, file. * @param object $this The current instance of this class. * * @return array An associative array of image sizes. */ return apply_filters( 'regenerate_thumbnails_missing_thumbnails', $sizes, $fullsize_metadata, $this ); } /** * Generate the thumbnail filename and dimensions for a given set of constraint dimensions. * * @since 3.0.0 * * @param WP_Image_Editor|WP_Error $editor An instance of WP_Image_Editor, as returned by wp_get_image_editor(). * @param int $fullsize_width The width of the fullsize image. * @param int $fullsize_height The height of the fullsize image. * @param int $thumbnail_width The width of the thumbnail. * @param int $thumbnail_height The height of the thumbnail. * @param bool $crop Whether to crop or not. * * @return array|false An array of the filename, thumbnail width, and thumbnail height, * or false on failure to resize such as the thumbnail being larger than the fullsize image. */ public function get_thumbnail( $editor, $fullsize_width, $fullsize_height, $thumbnail_width, $thumbnail_height, $crop ) { $dims = image_resize_dimensions( $fullsize_width, $fullsize_height, $thumbnail_width, $thumbnail_height, $crop ); if ( ! $dims ) { return false; } list( , , , , $dst_w, $dst_h ) = $dims; $suffix = "{$dst_w}x{$dst_h}"; $file_ext = strtolower( pathinfo( $this->get_fullsizepath(), PATHINFO_EXTENSION ) ); return array( 'filename' => $editor->generate_filename( $suffix, null, $file_ext ), 'width' => $dst_w, 'height' => $dst_h, ); } /** * Update the post content of any public post types (posts and pages by default) * that make use of this attachment. * * @since 3.0.0 * * @param array|string $args { * Optional. Array or string of arguments for controlling the updating. * * @type array $post_type The post types to update. Defaults to public post types (posts and pages by default). * @type array $post_ids Specific post IDs to update as opposed to any that uses the attachment. * @type int $posts_per_loop How many posts to query at a time to keep memory usage down. You shouldn't need to modify this. * } * * @return array|WP_Error List of post IDs that were modified. The key is the post ID and the value is either the post ID again or a WP_Error object if wp_update_post() failed. */ public function update_usages_in_posts( $args = array() ) { // Temporarily disabled until it can be even better tested for edge cases return array(); $args = wp_parse_args( $args, array( 'post_type' => array(), 'post_ids' => array(), 'posts_per_loop' => 10, ) ); if ( empty( $args['post_type'] ) ) { $args['post_type'] = array_values( get_post_types( array( 'public' => true ) ) ); unset( $args['post_type']['attachment'] ); } $offset = 0; $posts_updated = array(); while ( true ) { $posts = get_posts( array( 'numberposts' => $args['posts_per_loop'], 'offset' => $offset, 'orderby' => 'ID', 'order' => 'ASC', 'include' => $args['post_ids'], 'post_type' => $args['post_type'], 's' => 'wp-image-' . $this->attachment->ID, // For faster queries. 'update_post_meta_cache' => false, 'update_post_term_cache' => false, ) ); if ( ! $posts ) { break; } $offset += $args['posts_per_loop']; foreach ( $posts as $post ) { $content = $post->post_content; $search = array(); $replace = array(); // Find all tags for this attachment and update them. preg_match_all( '#]+wp-image-' . $this->attachment->ID . '[^>]+/>#i', $content, $matches, PREG_SET_ORDER ); if ( $matches ) { foreach ( $matches as $img_tag ) { preg_match( '# class="([^"]+)?size-([^" ]+)#i', $img_tag[0], $thumbnail_size ); if ( $thumbnail_size ) { $thumbnail = image_downsize( $this->attachment->ID, $thumbnail_size[2] ); if ( ! $thumbnail ) { continue; } $search[] = $img_tag[0]; $img_tag[0] = preg_replace( '# src="[^"]+"#i', ' src="' . esc_url( $thumbnail[0] ) . '"', $img_tag[0] ); $img_tag[0] = preg_replace( '# width="[^"]+" height="[^"]+"#i', ' width="' . esc_attr( $thumbnail[1] ) . '" height="' . esc_attr( $thumbnail[2] ) . '"', $img_tag[0] ); $replace[] = $img_tag[0]; } } } $content = str_replace( $search, $replace, $content ); $search = array(); $replace = array(); // Update the width in any [caption] shortcodes. preg_match_all( '#\[caption id="attachment_' . $this->attachment->ID . '"([^\]]+)? width="[^"]+"\]([^\[]+)size-([^" ]+)([^\[]+)\[\/caption\]#i', $content, $matches, PREG_SET_ORDER ); if ( $matches ) { foreach ( $matches as $match ) { $thumbnail = image_downsize( $this->attachment->ID, $match[3] ); if ( ! $thumbnail ) { continue; } $search[] = $match[0]; $replace[] = '[caption id="attachment_' . $this->attachment->ID . '"' . $match[1] . ' width="' . esc_attr( $thumbnail[1] ) . '"]' . $match[2] . 'size-' . $match[3] . $match[4] . '[/caption]'; } } $content = str_replace( $search, $replace, $content ); $updated_post_object = (object) array( 'ID' => $post->ID, 'post_content' => $content, ); $posts_updated[ $post->ID ] = wp_update_post( $updated_post_object, true ); } } return $posts_updated; } /** * Returns information about the current attachment for use in the REST API. * * @since 3.0.0 * * @return array|WP_Error The attachment name, fullsize URL, registered thumbnail size status, and any unregistered sizes, or WP_Error on error. */ public function get_attachment_info() { $fullsizepath = $this->get_fullsizepath(); if ( is_wp_error( $fullsizepath ) ) { $fullsizepath->add_data( array( 'attachment' => $this->attachment ) ); return $fullsizepath; } $editor = wp_get_image_editor( $fullsizepath ); if ( is_wp_error( $editor ) ) { // Display a more helpful error message. if ( 'image_no_editor' === $editor->get_error_code() ) { $editor = new WP_Error( 'image_no_editor', __( 'The current image editor cannot process this file type.', 'regenerate-thumbnails' ) ); } $editor->add_data( array( 'attachment' => $this->attachment, 'status' => 415, ) ); return $editor; } $metadata = wp_get_attachment_metadata( $this->attachment->ID ); if ( false === $metadata || ! is_array( $metadata ) ) { return new WP_Error( 'regenerate_thumbnails_regenerator_no_metadata', __( 'Unable to load the metadata for this attachment.', 'regenerate-thumbnails' ), array( 'status' => 404, 'attachment' => $this->attachment, ) ); } if ( ! isset( $metadata['sizes'] ) ) { $metadata['sizes'] = array(); } // PDFs don't have width/height set. $width = ( isset( $metadata['width'] ) ) ? $metadata['width'] : null; $height = ( isset( $metadata['height'] ) ) ? $metadata['height'] : null; require_once( ABSPATH . '/wp-admin/includes/image.php' ); $preview = false; if ( file_is_displayable_image( $fullsizepath ) ) { $preview = wp_get_attachment_url( $this->attachment->ID ); } elseif ( is_array( $metadata['sizes'] ) && is_array( $metadata['sizes']['full'] ) && ! empty( $metadata['sizes']['full']['file'] ) ) { $preview = str_replace( wp_basename( $fullsizepath ), $metadata['sizes']['full']['file'], wp_get_attachment_url( $this->attachment->ID ) ); if ( ! file_exists( $preview ) ) { $preview = false; } } $response = array( 'name' => ( $this->attachment->post_title ) ? $this->attachment->post_title : sprintf( __( 'Attachment %d', 'regenerate-thumbnails' ), $this->attachment->ID ), 'preview' => $preview, 'relative_path' => _wp_get_attachment_relative_path( $fullsizepath ) . DIRECTORY_SEPARATOR . wp_basename( $fullsizepath ), 'edit_url' => get_edit_post_link( $this->attachment->ID, 'raw' ), 'width' => $width, 'height' => $height, 'registered_sizes' => array(), 'unregistered_sizes' => array(), ); $wp_upload_dir = dirname( $fullsizepath ) . DIRECTORY_SEPARATOR; $registered_sizes = RegenerateThumbnails()->get_thumbnail_sizes(); if ( 'application/pdf' === get_post_mime_type( $this->attachment ) ) { $registered_sizes = array_intersect_key( $registered_sizes, array( 'thumbnail' => true, 'medium' => true, 'large' => true, ) ); } // Check the status of all currently registered sizes. foreach ( $registered_sizes as $size ) { // Width and height are needed to generate the thumbnail filename. if ( $width && $height ) { $thumbnail = $this->get_thumbnail( $editor, $width, $height, $size['width'], $size['height'], $size['crop'] ); if ( $thumbnail ) { $size['filename'] = wp_basename( $thumbnail['filename'] ); $size['fileexists'] = file_exists( $thumbnail['filename'] ); } else { $size['filename'] = false; $size['fileexists'] = false; } } elseif ( ! empty( $metadata['sizes'][ $size['label'] ]['file'] ) ) { $size['filename'] = wp_basename( $metadata['sizes'][ $size['label'] ]['file'] ); $size['fileexists'] = file_exists( $wp_upload_dir . $metadata['sizes'][ $size['label'] ]['file'] ); } else { $size['filename'] = false; $size['fileexists'] = false; } $response['registered_sizes'][] = $size; } if ( ! $width && ! $height && is_array( $metadata['sizes']['full'] ) ) { $response['registered_sizes'][] = array( 'label' => 'full', 'width' => $metadata['sizes']['full']['width'], 'height' => $metadata['sizes']['full']['height'], 'filename' => $metadata['sizes']['full']['file'], 'fileexists' => file_exists( $wp_upload_dir . $metadata['sizes']['full']['file'] ), ); } // Look at the attachment metadata and see if we have any extra files from sizes that are no longer registered. foreach ( $metadata['sizes'] as $label => $size ) { if ( ! file_exists( $wp_upload_dir . $size['file'] ) ) { continue; } // An unregistered size could match a registered size's dimensions. Ignore these. foreach ( $response['registered_sizes'] as $registered_size ) { if ( $size['file'] === $registered_size['filename'] ) { continue 2; } } if ( ! empty( $registered_sizes[ $label ] ) ) { /* translators: Used for listing old sizes of currently registered thumbnails */ $label = sprintf( __( '%s (old)', 'regenerate-thumbnails' ), $label ); } $response['unregistered_sizes'][] = array( 'label' => $label, 'width' => $size['width'], 'height' => $size['height'], 'filename' => $size['file'], 'fileexists' => true, ); } return $response; } } 16 Most Popular Online Learning Platforms for Kids – Skoop Singapore | One stop platform for kids education, enrichment and resources
  • You have no bookmark.

Your Wishlist : 0 listings

Sign In

16 Most Popular Online Learning Platforms for Kids

From boosting academic results to offering interactive and fun learning experience, these platforms have it all covered.

Digital learning platforms are becoming a key part of education in Singapore. Many schools now use tools to assign homework and strengthen skills through interactive exercises and personalised learning, keeping kids engaged while they learn.

 

Online learning can generally be categorized into 3 categories –

Interactive learning provides real-time engagement with content through quizzes, games, and interactive exercises, enhancing the learning experience.

Self-paced learning allows individuals to learn at their own speed using pre-recorded videos, reading materials, and quizzes. Learners can access these resources anytime and proceed according to their schedules.

Online tuition features live, real-time instruction from tutors or teachers, typically in one-on-one or small group settings, enabling direct interaction and personalized guidance during scheduled sessions.

As parents, we’re always looking for the best ways to help our children learn and grow. In recent years, online learning has transformed education and become increasingly popular among Singaporean kids. With the help of technology, it bridges the gaps that traditional classrooms sometimes miss. Here’s why more parents are embracing this trend

 

1. Eliminating Travel Hassles

One big perk of online learning? No more rushing to and from enrichment classes. Kids can learn comfortably from home on weekdays, saving precious time and freeing up weekends for rest and family bonding. It’s a win for both learning and family life.

2. Parental Involvement and Peace of Mind

Online classes make learning more transparent and inclusive, giving parents the chance to be part of their child’s education. By sitting in, we get to see how lessons are taught and better support learning at home. For instance, Connected Learning, which offers online Chinese tuition, encourages parents to observe classes — giving peace of mind while helping us understand and guide our child’s progress.

 

3. Engaging and Interactive Lessons

Online classes often go beyond traditional teaching with interactive tools like quizzes, videos, and games that make learning fun and engaging. For example, Vocab King  uses AI to turn Chinese learning into an exciting experience — with personalized quizzes, pet battle games, and animated stories based on the MOE curriculum. This gamified approach keeps kids motivated and helps them learn more effectively.

 

4. Personalized Learning

One of the biggest advantages of online learning is that it can be tailored to each child’s needs. Students can learn at their own pace, revisiting challenging topics or moving quickly through concepts they grasp well. Many platforms use adaptive technologies to adjust lessons based on performance, creating a truly personalized learning experience.

For example, Playwrite empowers children to master PSLE English independently with instant AI feedback and personalized weekly exercises targeting each child’s weaknesses. Similarly, Sino-bus offers one-on-one Chinese lessons, using gamified multimedia to engage students and tailor instruction to their individual needs. With real-time progress tracking, tutors can provide focused guidance, ensuring each child gets the support they need to excel.

 

5. Accessibility and flexibility

Online learning platforms provide the flexibility to access lesson highlights and past videos anytime, anywhere, ensuring that students can review crucial information and never miss essential content. 

Some platforms like Superstar Teacher (https://www.superstarteacher.com.sg/) allows students to revisit lessons and study materials at their convenience. Students can access a vast library of recorded lessons and supplementary materials whenever they need. This flexibility helps them review and digest complex concepts at their own pace, making learning more manageable and tailored to individual needs.

 

6. Cost effective

Many online courses offer lower fees than in-person programs due to reduced overhead costs. Additionally, online learning platforms often provide flexible enrollment options, like pay-per-course or subscription models, allowing parents to choose the most cost-effective approach based on their child’s learning needs and family budget.

While online learning has many benefits, it isn’t ideal for every child. Some children thrive on face-to-face interaction and hands-on activities, and may struggle with the independence required in online classes. Those who need more structure, supervision, or social engagement may find it challenging to stay motivated.

On the other hand, online learning works well for self-motivated children who can manage their time, enjoy interactive, multimedia lessons, and prefer learning at their own pace. For these students, it offers flexibility, personalized experiences, and access to innovative educational tools.

In short, online learning isn’t one-size-fits-all, but for the right child, it provides a highly effective and engaging way to learn.

 

Check out these popular online learning platforms!

1.  LingoAce

Subject: Chinese

Level: Preschool, Primary

Type of learning: 1-to-1 Online lesson

An online Chinese class that makes learning Mandarin fun and effective for children aged 3–15. Your child learns 1-to-1 with certified native-speaking teachers through interactive games and AI-driven assessments, creating a personalized learning experience that helps them build language skills quickly while having fun.

 

2.  Playwrite

Subject: English

Level: Primary

Type of learning: Self-paced, interactive

An AI-powered online English practice platform for students in Primary 3 to 6. What sets it apart is its AI-powered feedback system, giving students instant, personalized insights on their writing. This immediate feedback helps them improve their skills efficiently.

The platform also offers weekly challenges tailored to each student’s weak areas, ensuring targeted practice. Developed by a team of former MOE teachers and technologists, Playwrite aims to make high-quality English education accessible and affordable.

 

3. Sino-bus

Subject: Chinese

Level: Preschool, Primary

Type of learning: Online lesson

Sino-bus offers 1-to-1 online Chinese lessons for kids aged 3–16, designed around the MOE syllabus. Lessons focus on composition, oral skills, and exam prep using interactive activities and multimedia tools to make learning practical, engaging, and results-driven.

 

4. Connected Learning 

Subject: Chinese

Level: Primary, Secondary

Type of learning: Online lesson

Connected Learning offers live, small-group online Chinese classes for Primary 1 to Secondary 5 students. MOE-aligned and taught by qualified native-speaking tutors, their interactive lessons focus on speaking, writing, and vocabulary, making learning effective, engaging, and convenient. To give parents peace of mind, they allow parents to sit in their Chinese online tuition class.

5. Superstar Teacher

Subject: English, Chinese, Maths, Science

Level: Primary, Secondary

Type of learning: Self-paced, interactive, 1-1 lesson

Superstar Teacher is an online learning platform offering MOE-aligned video lessons for Primary and Secondary students. Developed by experienced educators, it uses the latest educational technology to create an engaging, effective learning environment where children can learn efficiently, access bite-sized lessons anytime, get on-demand homework help, and practice for exams. A gamified rewards system encourages self-directed learning and builds confidence.

6. Ottodot

Subject: Science

Level: Primary

Type of learning: Self-paced, interactive

Ottodot brings PSLE Science and Math to life for Primary 1–6 students. Certified MOE teachers guide lessons that blend core concepts with interactive Roblox games, making learning hands-on, fun, and MOE-aligned. Built for kids, safe for Learning, Ottodot helps students master problem-solving, literacy, and inquiry skills in a secure, flexible environment.

 

7. E.Wiz.SG

Subject: English

Level: Primary

Type of learning: Online lesson

A dynamic online English tuition platform specializing in PSLE English for Primary 3 to 6 students. Led by experienced ex-MOE teachers and PSLE examiners, E.Wiz offers engaging, skill-based workshops and live masterclasses designed to address specific areas of need. The curriculum focuses on building strong English foundations with precision and heart, ensuring students not only improve academically but also develop a genuine interest in the language.

8.  Geniebook

Subject: English, Maths, Science

Level: Primary, Secondary

Type of learning: Online lesson, self-paced, interactive

An AI-powered online learning platform for Primary and Secondary students, Geniebook combines personalized AI worksheets, live online classes, and real-time teacher support to create an engaging and effective learning experience.

Lessons adapt to each student’s pace and areas of improvement, while features like homework help and interactive classes reinforce key concepts. Designed to complement traditional tuition, Geniebook makes learning flexible, efficient, and enjoyable.

9. Big Ideaz

Subject: English Composition Writing

Level: Primary

Type of learning:  Online lesson

Specializes in English composition writing for Primary 1–6 students, Big Ideaz offers live online classes and self-paced courses designed to improve writing skills through structured lessons and personalized feedback. Their Writing Academy provides weekly video lessons and assignments, with compositions marked by experienced former MOE teachers. Students receive constructive feedback to enhance their writing.

 

10. Spark Education 

Subject: Maths

Level: Preschool, Primary

Type of learning: Self-paced, interactive, online lesson

Spark Education makes learning fun and effective for young learners through small-group classes that blend interactive technology with proven teaching methods. Their award-winning Math programmes combine the best of the Singapore Math and Australian curriculum to help children build strong foundations and think critically. Lessons are engaging, gamified, and hands-on, keeping kids excited to learn.

 

11. Yi Dian Tong

Subject: Chinese

Level: Primary, Secondary

Type of learning: Online lesson, interactive

Yi Dian Tong offers live, interactive online Chinese lessons aligned with the MOE syllabus. Classes are kept small (1 to 4 students) and taught by experienced, bilingual teachers who make learning fun and engaging. Students receive personalized feedback and tailored support each week, while friendly peer interaction keeps them motivated.

With a proven methodology and focus on building confidence, Yi Dian Tong helps children develop strong Chinese skills in a supportive, laughter-filled environment.

 

12. Koobits

Subject: English, Math, Chinese, Science

Level: Primary

Type of learning: Self-paced, interactive lesson

An award-winning, AI-powered online learning platform for children aged 6 to 12. It makes learning Math, Science, English, and Chinese fun and engaging in just 20 minutes a day. The platform delivers personalized daily questions, interactive tutorials, and gamified rewards to motivate students and build confidence. Trusted by parents and educators, KooBits’ bite-sized lessons and flexible schedule make it perfect for busy families seeking an effective and enjoyable learning experience.

 

13. Edoovo

Subject: Chinese, English, Maths

Level: Preschool, Primary (age 3 to 8)

Type of learning:  Online lesson, interactive

An award-winning online enrichment platform tailored for preschoolers and early primary school kids to build a solid academic foundation in preparation for formal education. It offers live, interactive classes in English, Chinese, and Math, taught by qualified educators in small groups of up to four students. Classes focus on developing bilingual language skills and critical thinking through play-based learning and are conducted via Edoovo’s proprietary online platform, accessible anytime, anywhere.

 

14.  Elite Kid 

Subject: Chinese

Level: Primary

Type of learning: Online lesson

EliteKid offers live-streaming and in-person Chinese lessons for children aged 4–12, taught by highly qualified native Chinese teachers. Unlike traditional tuition, lessons focus on igniting a child’s passion and self-motivation for learning Chinese. Using technology and multimedia, the classes make learning engaging and effective. Students can learn comfortably from home via a high-tech platform or in a conducive environment at the Bugis and Chinatown centres.

15. Thinker Learning

Subject: Science

Level: Primary

Type of learning: Online lesson, self-paced

An online tuition platform specializing in PSLE Science for Primary 3–6 students. Its structured, bite-sized courses are designed for quick 7-day revision, perfect for busy schedules. Lessons include downloadable guidebooks, topical worksheets, and answering techniques, all aligned with the MOE curriculum. Recorded lessons are available anytime, giving students and parents maximum flexibility.

 

16. Learning Gems

Subject: English

Level: Primary

Type of learning: Online lesson

MOE-trained teachers deliver live, interactive lessons in small classes, ensuring personalized attention for each student. The curriculum is fully aligned with the latest MOE syllabus, and students receive individualized feedback to track progress effectively. With a proven track record, Learning Gems combines expert teaching with an engaging, supportive learning environment.

 

 

 

assessment books Prev Post
The Ultimate Guide: 5 Best Assessment Books for Primary School Subjects
popular school bag brands in singapore Next Post
Most Popular School Bag Brands in Singapore

Add Comment

Your email is safe with us.

0
Close

Your cart

No products in the cart.