Skip to content

Instantly share code, notes, and snippets.

@wpmudev-sls
Last active October 1, 2018 05:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wpmudev-sls/c1d9579172faabf64fef4f77a4912d08 to your computer and use it in GitHub Desktop.
Save wpmudev-sls/c1d9579172faabf64fef4f77a4912d08 to your computer and use it in GitHub Desktop.
CoursePress] - Clone Unit Modules
<?php
/**
* Plugin Name: [CoursePress] - Clone Unit Modules
* Plugin URI: https://premium.wpmudev.org/
* Description: Clones all Modules from a CoursePress Unit
* Author: Panos Lyrakis @ WPMUDEV
* Author URI: https://premium.wpmudev.org/
* License: GPLv2 or later
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'wpmudev_cp_clone_unit_modules_Modules' ) ) {
class wpmudev_cp_clone_unit_modules_Modules {
private static $_instance = null;
public static $slug = 'coursepress_clone_unit_module';
private static $title = '';
private static $menu_title = '';
private static $post_type;
private static $unit_type;
private $courses;
private $parent_slug;
public static function get_instance() {
if( is_null( self::$_instance ) ){
self::$_instance = new wpmudev_cp_clone_unit_modules_Modules();
}
return self::$_instance;
}
private function __construct() {
if ( ! class_exists( 'CoursePress_Admin_Controller_Menu' ) ) {
return;
}
self::$title = self::$menu_title = 'Copy Unit Modules';
self::$post_type = CoursePress_Data_Course::get_post_type_name();
self::$unit_type = CoursePress_Data_Unit::get_post_type_name();
$this->parent_slug = 'edit.php?post_type=' . self::$post_type;
add_action( 'admin_menu', array( $this, 'menu' ), 99 );
add_action( 'admin_footer', array( $this, 'js' ) );
add_action( 'wp_ajax_wpmudev_cp_clone_unit_modules', array( $this, 'clone_unit_ajax' ) );
}
public function menu() {
add_submenu_page(
$this->parent_slug,
self::$title,
self::$menu_title,
apply_filters( 'coursepress_capabilities', 'manage_options' ),
'coursepress-clone-unit-modules-page',
array( $this, 'admin_page' )
);
}
public static function clone_post( $post_id, $post_parent = null ) {
global $wpdb;
$post = get_post( $post_id );
$target_post = self::post_to_array( $post, $post_parent );
$new_post_id = wp_insert_post( $target_post );
/*
* Clone terms
*/
$taxonomies = get_object_taxonomies( $post->post_type ); // returns array of taxonomy names for post type, ex array("category", "post_tag");
foreach ($taxonomies as $taxonomy) {
$post_terms = wp_get_object_terms( $post_id, $taxonomy, array( 'fields' => 'slugs' ) );
wp_set_object_terms( $new_post_id, $post_terms, $taxonomy, false );
}
/*
* Clone meta
*/
$post_meta_infos = $wpdb->get_results( "SELECT meta_key, meta_value FROM {$wpdb->postmeta} WHERE post_id ={$post_id}" );
// Fix any double meta entries which may cause issues
$meta_keys = array();
foreach ( $post_meta_infos as $key => $meta ) {
$meta_key = trim( $meta->meta_key );
if ( ! in_array( $meta_key, $meta_keys ) ) {
$meta_keys[] = $meta_key;
}
else {
unset( $post_meta_infos[ $key ] );
}
}
if ( ! empty( $post_meta_infos ) ) {
$sql_query = "INSERT INTO $wpdb->postmeta (post_id, meta_key, meta_value) ";
foreach ( $post_meta_infos as $meta_info ) {
$meta_key = $meta_info->meta_key;
if (
'_wp_old_slug' == $meta_key ||
( 'module_type' == $meta_key && ! in_array( $meta_info->meta_value, array_keys( CoursePress_Helper_UI_Module::get_types() ) ) )
)
{
continue;
}
$meta_value = addslashes( $meta_info->meta_value );
$sql_query_sel[] = "SELECT $new_post_id, '$meta_key', '$meta_value'";
}
$sql_query.= implode( " UNION ALL ", $sql_query_sel );
$wpdb->query( $sql_query );
}
return $new_post_id;
}
public static function post_to_array( $post, $parent = null ) {
$post = (array) $post;
unset( $post['ID'] );
unset( $post['post_date'] );
unset( $post['post_date_gmt'] );
unset( $post['post_modified'] );
unset( $post['post_modified_gmt'] );
unset( $post['guid'] );
if ( ! is_null( $parent ) ) {
$post['post_parent'] = (int) $parent;
}
return $post;
}
public function clone_unit_ajax() {
check_ajax_referer( 'wpmudev_cp_clone_unit_modules', 'security' );
$source_unit_id = (int) $_POST['source_unit'];
$target_unit_id = (int) $_POST['target_unit'];
$mapped_modules = array();
$mapped_modules = array();
$source_unit = get_post( $source_unit_id );
$target_unit = get_post( $target_unit_id );
if (
! $source_unit instanceof WP_Post || self::$unit_type != $source_unit->post_type ||
! $target_unit instanceof WP_Post || self::$unit_type != $target_unit->post_type
){
$out = "One of the ids provided does not correspond to a unit";
$return = array(
'success' => false,
'content' => $out
);
wp_send_json($return);
}
$source_course = $source_unit->post_parent;
$target_course = $target_unit->post_parent;
$clone_students = apply_filters( '_cp_cloner/clone_students', ! ( $source_course == $target_course ) );
// 1. Fetch modules
$source_modules_ids = CoursePress_Data_Course::get_unit_modules( $source_unit_id, 'any' ,true );
foreach ( $source_modules_ids as $source_module_id ) {
$target_module_id = self::clone_post( $source_module_id, $target_unit_id );
$mapped_modules[ $source_module_id ] = $target_module_id;
}
// 2. Clone students and progress
// 2.1 Check if allowed to clone students
if ( $clone_students ) {
//.2 We need the students that exist in both courses
$source_students = CoursePress_Data_Course::get_student_ids( $source_course );
$target_students = CoursePress_Data_Course::get_student_ids( $target_course );
$student_ids = array_intersect( $source_students, $target_students );
foreach ( $student_ids as $student_id ) {
$progress_meta = get_user_meta( $student_id, "course_{$source_course}_progress", true );
$completion = $progress_meta['completion'][$source_unit_id];
// 3.3 Re-map progress completion
// There are 2 completion_items of the unit that contain modules: modules_seen and answered
foreach ( $completion as $item_key => $items ) {
if ( 'modules_seen' != $item_key && 'answered' != $item_key ) {
$progress_meta['completion'][$target_unit_id][$item_key] = $items;
continue;
}
foreach ( $items as $module_id => $value ) {
if ( isset( $mapped_modules[$module_id] ) ) {
$progress_meta['completion'][$target_unit_id][$item_key][ $mapped_modules[$module_id] ] = $value;
}
}
if ( $source_course != $target_course ) {
unset( $progress_meta['completion'][$source_unit_id] );
}
}
// 3.4 Re-map progress responses
// 3.4.1 Replace unit ids
$progress_meta['units'][$target_unit_id] = $progress_meta['units'][$source_unit_id];
// Maybe unset $source_unit_id
if ( $source_course != $target_course ) {
unset( $progress_meta['units'][$source_unit_id] );
}
// 3.4.2 Remap module in "responses"
if ( ! empty( $progress_meta['units'][$target_unit_id]['responses'] ) ) {
$responses = $progress_meta['units'][$target_unit_id]['responses'];
foreach ( $responses as $module_id => $value ) {
if ( isset( $mapped_modules[$module_id] ) ) {
$progress_meta['units'][$target_unit_id]['responses'][ $mapped_modules[$module_id] ] = $value;
unset( $progress_meta['units'][$target_unit_id]['responses'][ $module_id ] );
}
}
}
if ( $source_course != $target_course ) {
unset( $progress_meta['units'][$source_unit_id] );
}
if ( $source_course != $target_course ) {
unset( $progress_meta['units'][$source_unit_id]['responses'] );
}
update_user_meta( $student_id, "course_{$target_course}_progress", $progress_meta );
}
}
$out = 'Unit was cloned to selected course';
$return = array(
'success' => true,
'content' => $out
);
wp_send_json($return);
}
public function admin_page(){
?>
<div id="_cp_cloner">
<h2>Copy Unit Modules</h2>
<h4>Insert Source Module</h4>
<input type="text" id="cp_source_unit_id" />
<h4>Insert Target Module</h4>
<input type="text" id="cp_target_unit_id" />
<div style="margin-top: 30px;">
<a class="button" id="cp_clone_btn">Clone</a>
</div>
<div id="results_output"></div>
</div>
<?php
}
public function js() {
if ( ! function_exists( 'get_current_screen' ) || 'course_page_coursepress-clone-unit-modules-page' != get_current_screen()->id ) {
return;
}
?>
<script type="text/javascript">
(function($){
const cp_cloner = {
cloner_wrap : $( '#_cp_cloner' ),
source_unit: $( '#_cp_cloner #cp_source_unit_id' ),
target_unit: $( '#_cp_cloner #cp_target_unit_id' ),
clone_btn: $( '#_cp_cloner #cp_clone_btn' ),
nonce: '<?php echo wp_create_nonce( "wpmudev_cp_clone_unit_modules" ); ?>',
results_output: $( '#results_output' ),
clone: function( source_unit, target_unit ) {
cp_cloner.results_output.html( 'Please wait while cloning modules' );
let data = {
action: 'wpmudev_cp_clone_unit_modules',
security: this.nonce,
source_unit: source_unit,
target_unit: target_unit
};
$.post( ajaxurl, data, function( response ) {
if( response.success ){
cp_cloner.results_output.html( response.content );
}
else{
cp_cloner.results_output.html( response.content );
}
});
}
}
$(document).ready(function(){
$(cp_cloner.clone_btn).on('click',function(e){
e.preventDefault();
if ( '' == cp_cloner.source_unit.val() || '' == cp_cloner.target_unit.val() ) {
alert( 'You need to insert the id of the source unit and the id ofthe terget unit' );
}
cp_cloner.clone( cp_cloner.source_unit.val(), cp_cloner.target_unit.val() );
});
});
})(jQuery);
</script>
<?php
}
}
if ( ! function_exists( 'wpmudev_cp_clone_unit_modules' ) ) {
function wpmudev_cp_clone_unit_modules() {
return wpmudev_cp_clone_unit_modules_Modules::get_instance();
};
add_action( 'plugins_loaded', 'wpmudev_cp_clone_unit_modules', 10 );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment