Changeset 995609
- Timestamp:
- 09/23/2014 06:34:23 PM (12 years ago)
- Location:
- content-staging/trunk
- Files:
-
- 11 edited
-
assets/js/content-staging.js (modified) (2 diffs)
-
classes/class-import-batch.php (modified) (15 diffs)
-
classes/class-setup.php (modified) (5 diffs)
-
classes/controllers/class-batch-ctrl.php (modified) (15 diffs)
-
classes/db/class-postmeta-dao.php (modified) (2 diffs)
-
classes/view/class-post-table.php (modified) (1 diff)
-
content-staging.php (modified) (9 diffs)
-
readme.txt (modified) (1 diff)
-
scripts/import-batch.php (modified) (1 diff)
-
templates/deploy-batch.php (modified) (1 diff)
-
templates/edit-batch.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
content-staging/trunk/assets/js/content-staging.js
r990417 r995609 1 1 jQuery( document ).ready(function($) { 2 2 3 var batchImporterId = $('#sme-batch-importer-id').html(); 4 var nbrOfPrintedMsg = 0; 5 6 // Check if a batch importer ID has been found. 7 if (batchImporterId) { 8 var data = { 9 'action': 'sme_batch_import_status', 10 'importer_id': batchImporterId 11 }; 12 getBatchImporterStatus(); 13 } 14 15 function getBatchImporterStatus() { 16 setTimeout(function () { 17 18 /* 19 * Since WordPress 2.8 ajaxurl is always defined in the admin header and 20 * points to admin-ajax.php. 21 */ 3 /** 4 * Since WordPress 2.8 'ajaxurl' is always defined in the admin header 5 * and points to admin-ajax.php. 6 */ 7 var app = { 8 9 /** 10 * Init method of this application. Contains a simple router. 11 */ 12 init: function() { 13 14 // Check if global variable 'adminpage' is defined. 15 if (typeof adminpage !== 'undefined') { 16 17 /* 18 * Make sure posts in batch cookie is emptied if this is not the edit 19 * batch page. 20 */ 21 if (adminpage !== 'admin_page_sme-edit-batch') { 22 document.cookie = 'wp-sme-bpl='; 23 } 24 25 // Simple router. 26 switch (adminpage) { 27 case 'admin_page_sme-edit-batch': 28 this.editBatch(); 29 break; 30 case 'admin_page_sme-send-batch': 31 this.deployBatch(); 32 break; 33 } 34 } 35 }, 36 37 /** 38 * User is currently on the Edit Batch page. 39 * 40 * If this is a new batch we would only have data from cookie. If user 41 * goes to next page of posts all posts selected on the previous page will 42 * be stored in cookie and inserted into HTML form. 43 * 44 * If user visit any other (content staging) page, cookie should be 45 * cleared. 46 */ 47 editBatch: function() { 48 var self = this; 49 var batchId = $('#sme-batch-id').html(); 50 var posts = $('.sme-select-post'); 51 var postIdsObj = $('input[name="post_ids"]'); 52 var postIds = []; 53 var selectAll = $('[id^=cb-select-all-]'); 54 var cookie; 55 var batch; 56 57 // Get value from cookie. 58 cookie = document.cookie.replace(/(?:(?:^|.*;\s*)wp-sme-bpl\s*\=\s*([^;]*).*$)|^.*$/, '$1'); 59 60 if (cookie === '') { 61 /* 62 * Cookie is empty, use post IDs from HTML form as selected posts. 63 */ 64 postIds = postIdsObj.val().split(','); 65 } else { 66 /* 67 * Cookie has been populated. Use post IDs from cookie as selected posts. 68 */ 69 70 // Split batch and posts. 71 batch = cookie.split(':'); 72 73 /* 74 * We are not editing the same batch as cookie is referring to, reset 75 * cookie. 76 */ 77 if (batch[0] !== batchId) { 78 document.cookie = 'wp-sme-bpl='; 79 } else { 80 // Add posts to array. 81 postIds = batch[1].split(','); 82 } 83 } 84 85 // Convert all post IDs to integers. 86 postIds = this.arrayValuesToIntegers(postIds); 87 88 // Add currently selected post IDs to HTML form. 89 postIdsObj.val(postIds.join()); 90 91 // Go through all posts and determine which should be selected. 92 posts.each(function() { 93 if (postIds.indexOf(parseInt($(this).val())) > -1) { 94 $(this).prop('checked', true); 95 } else { 96 $(this).prop('checked', false); 97 } 98 }); 99 100 // User has selected/unselected a post. 101 posts.click(function() { 102 var postObj = $(this); 103 104 // Add post ID to array of post IDs. 105 self.selectPost(postIds, parseInt(postObj.val()), postObj.prop('checked')); 106 107 // Update selected posts. 108 self.updateSelectedPosts(batchId, postIds, postIdsObj); 109 }); 110 111 // User has selected/unselected all posts. 112 selectAll.click(function() { 113 var isChecked = $(this).prop('checked'); 114 115 posts.each(function() { 116 self.selectPost(postIds, parseInt($(this).val()), isChecked); 117 }); 118 119 // Update selected posts. 120 self.updateSelectedPosts(batchId, postIds, postIdsObj); 121 }); 122 }, 123 124 /** 125 * Select a post in Edit Batch view. 126 * 127 * @param {Array} postIds 128 * @param {int} postId 129 * @param {bool} checked 130 */ 131 selectPost: function(postIds, postId, checked) { 132 var i; 133 134 // Remove post ID from array of post IDs. 135 for (i = 0; i < postIds.length; i++) { 136 if (postIds[i] === postId) { 137 postIds.splice(i, 1); 138 } 139 } 140 141 // Add post ID to array of post IDs. 142 if (checked) { 143 postIds.push(parseInt(postId)); 144 } 145 }, 146 147 /** 148 * Update cookie and HTML form with currently selected posts. 149 * 150 * @param {int} batchId 151 * @param {Array} postIds 152 * @param {Object} postIdsObj 153 */ 154 updateSelectedPosts: function(batchId, postIds, postIdsObj) { 155 var str = postIds.join(); 156 157 // Add post IDs to HTML form. 158 postIdsObj.val(str); 159 160 // Add post IDs to cookie. 161 document.cookie = 'wp-sme-bpl=' + batchId + ':' + str; 162 }, 163 164 /** 165 * User is currently on the Deploy Batch page. 166 */ 167 deployBatch: function() { 168 169 var data = { 170 action: 'sme_import_request', 171 job_id: $('#sme-batch-import-job-id').html(), 172 importer: $('#sme-batch-importer-type').html() 173 }; 174 175 var printed = $('.sme-cs-message').length; 176 177 // Check if a batch importer ID has been found. 178 if (data.job_id && data.importer) { 179 this.deployStatus(data, printed); 180 } 181 }, 182 183 /** 184 * Get batch import status. 185 * 186 * @param data 187 * @param printed Number of messages that has been printed. 188 */ 189 deployStatus: function(data, printed) { 190 191 var self = this; 192 22 193 $.post(ajaxurl, data, function(response) { 23 24 console.log(response);25 194 26 195 // Number of messages in this response. … … 28 197 29 198 // Only print messages we haven't printed before. 30 for (var i = nbrOfPrintedMsg; i < nbrOfMsg; i++) {199 for (var i = printed; i < nbrOfMsg; i++) { 31 200 $('.wrap').append('<div class="sme-cs-message sme-cs-' + response.messages[i].level + '"><p>' + response.messages[i].message + '</p></div>'); 32 nbrOfPrintedMsg++; 33 } 34 201 printed++; 202 } 203 204 // If import is not completed, select import method. 35 205 if (response.status < 2) { 36 getBatchImporterStatus(); 37 } 38 }); 39 }, 3000); 40 } 206 switch (data.importer) { 207 case 'ajax': 208 self.ajaxImport(data, printed); 209 break; 210 case 'background': 211 self.backgroundImport(data, printed); 212 break; 213 } 214 } 215 }); 216 }, 217 218 ajaxImport: function(data, printed) { 219 this.deployStatus(data, printed); 220 }, 221 222 backgroundImport: function(data, printed) { 223 var self = this; 224 setTimeout(function() { 225 self.deployStatus(data, printed); 226 }, 3000); 227 }, 228 229 /** 230 * Convert array values to integers and sort out any values that are not 231 * a number. 232 * 233 * @param {Array} array 234 * @return {Array} 235 */ 236 arrayValuesToIntegers: function(array) { 237 var i; 238 var int; 239 var newArray = []; 240 241 for (i = 0; i < array.length; i++) { 242 int = parseInt(array[i]); 243 if ( ! isNaN(int)) { 244 newArray[i] = int; 245 } 246 } 247 248 return newArray; 249 } 250 }; 251 252 // Initialize application. 253 app.init(); 41 254 42 255 }); -
content-staging/trunk/classes/class-import-batch.php
r990417 r995609 2 2 namespace Me\Stenberg\Content\Staging; 3 3 4 use Me\Stenberg\Content\Staging\DB\Batch_Import er_DAO;4 use Me\Stenberg\Content\Staging\DB\Batch_Import_Job_DAO; 5 5 use Me\Stenberg\Content\Staging\DB\Post_DAO; 6 6 use Me\Stenberg\Content\Staging\DB\Postmeta_DAO; 7 7 use Me\Stenberg\Content\Staging\DB\Term_DAO; 8 8 use Me\Stenberg\Content\Staging\DB\User_DAO; 9 use Me\Stenberg\Content\Staging\Models\Batch_Import er;9 use Me\Stenberg\Content\Staging\Models\Batch_Import_Job; 10 10 use Me\Stenberg\Content\Staging\Models\Post; 11 11 use Me\Stenberg\Content\Staging\Models\Relationships\Post_Taxonomy; … … 19 19 * 20 20 * @todo Consider moving 'import_*' methods in this class to the 21 * Batch_Import ermodel. Might want an import per import type though,21 * Batch_Import_Job model. Might want an import per import type though, 22 22 * e.g. a Post_Importer etc. 23 23 */ 24 24 class Import_Batch { 25 25 26 private $ batch_importer_dao;26 private $import_job_dao; 27 27 private $post_dao; 28 28 private $postmeta_dao; … … 80 80 * Construct object, dependencies are injected. 81 81 * 82 * @param Batch_Import er_DAO $batch_importer_dao82 * @param Batch_Import_Job_DAO $import_job_dao 83 83 * @param Post_DAO $post_dao 84 84 * @param Postmeta_DAO $postmeta_dao … … 86 86 * @param User_DAO $user_dao 87 87 */ 88 public function __construct( Batch_Import er_DAO $batch_importer_dao, Post_DAO $post_dao,89 Postmeta_DAO $postmeta_dao,Term_DAO $term_dao, User_DAO $user_dao ) {90 $this-> batch_importer_dao = $batch_importer_dao;88 public function __construct( Batch_Import_Job_DAO $import_job_dao, Post_DAO $post_dao, Postmeta_DAO $postmeta_dao, 89 Term_DAO $term_dao, User_DAO $user_dao ) { 90 $this->import_job_dao = $import_job_dao; 91 91 $this->post_dao = $post_dao; 92 92 $this->postmeta_dao = $postmeta_dao; … … 106 106 107 107 // Make sure an importer ID has been provided. 108 if ( ! isset( $_GET['sme_batch_import er_id'] ) || ! $_GET['sme_batch_importer_id'] ) {108 if ( ! isset( $_GET['sme_batch_import_job_id'] ) || ! $_GET['sme_batch_import_job_id'] ) { 109 109 return; 110 110 } … … 115 115 } 116 116 117 $importer_id = intval( $_GET['sme_batch_import er_id'] );117 $importer_id = intval( $_GET['sme_batch_import_job_id'] ); 118 118 $import_key = $_GET['sme_import_batch_key']; 119 119 120 120 // Get batch importer from database. 121 $importer = $this-> batch_importer_dao->get_importer_by_id( $importer_id );121 $importer = $this->import_job_dao->get_job_by_id( $importer_id ); 122 122 123 123 // No importer found, error. … … 134 134 135 135 // Import running. 136 $importer->set_status( 1 );137 136 $importer->generate_key(); 138 $this-> batch_importer_dao->update_importer( $importer );137 $this->import_job_dao->update_job( $importer ); 139 138 140 139 // Get the batch. … … 157 156 // Import postmeta. 158 157 foreach ( $batch->get_posts() as $post ) { 159 $this->import_postmeta( $post ->get_meta());158 $this->import_postmeta( $post ); 160 159 } 161 160 … … 173 172 $importer->add_message( 'Batch has been successfully imported!', 'success' ); 174 173 $importer->set_status( 3 ); 175 $this-> batch_importer_dao->update_importer( $importer );174 $this->import_job_dao->update_job( $importer ); 176 175 177 176 /* … … 180 179 * us the status of the import even when import has finished. 181 180 */ 182 $this-> batch_importer_dao->delete_importer( $importer );181 $this->import_job_dao->delete_job( $importer ); 183 182 } 184 183 … … 289 288 // This post exists on production, update it. 290 289 $this->post_dao->update_post( $post ); 291 $this->postmeta_dao->delete_postmeta( array( 'post_id' => $post->get_id() ), array( '%d' ) );292 290 } 293 291 … … 309 307 310 308 /** 311 * Import postmeta .309 * Import postmeta for a specific post. 312 310 * 313 311 * Never call before all posts has been imported! In case you do … … 320 318 * array and the production post ID is used as value. 321 319 * 322 * @param array $postmeta 323 */ 324 private function import_postmeta( array $postmeta ) { 325 326 foreach ( $postmeta as $meta ) { 327 if ( in_array( $meta['meta_key'], $this->postmeta_keys ) ) { 320 * @param Post $post 321 */ 322 private function import_postmeta( Post $post ) { 323 324 $meta = $post->get_meta(); 325 326 for ( $i = 0; $i < count($meta); $i++ ) { 327 if ( in_array( $meta[$i]['meta_key'], $this->postmeta_keys ) ) { 328 328 329 329 /* 330 330 * The meta value must be an integer pointing at the ID of the post 331 * that the post whose post meta we are currently importing has a331 * that the post whose post meta we are currently importing has a 332 332 * relationship to. 333 333 */ 334 if ( isset( $this->post_relations[$meta[ 'meta_value']] ) ) {335 $meta[ 'meta_value'] = $this->post_relations[$meta['meta_value']];334 if ( isset( $this->post_relations[$meta[$i]['meta_value']] ) ) { 335 $meta[$i]['meta_value'] = $this->post_relations[$meta[$i]['meta_value']]; 336 336 } else { 337 error_log( 'Trying to update dependency between posts. Relationship is defined in postmeta (post_id: ' . $this->post_relations[$meta[ 'post_id']] . ', meta_key: ' . $meta['meta_key'] . ', meta_value: ' . $meta['meta_value'] . ') where post_id is the post ID that has a relationship to the post defined in meta_value. If meta_value does not contain a valid post ID relationship between posts cannot be maintained.' );337 error_log( 'Trying to update dependency between posts. Relationship is defined in postmeta (post_id: ' . $this->post_relations[$meta[$i]['post_id']] . ', meta_key: ' . $meta[$i]['meta_key'] . ', meta_value: ' . $meta[$i]['meta_value'] . ') where post_id is the post ID that has a relationship to the post defined in meta_value. If meta_value does not contain a valid post ID relationship between posts cannot be maintained.' ); 338 338 } 339 339 } 340 340 341 $meta['post_id'] = $this->post_relations[$meta['post_id']]; 342 $this->postmeta_dao->insert_postmeta( $meta ); 343 } 341 $meta[$i]['post_id'] = $this->post_relations[$meta[$i]['post_id']]; 342 } 343 344 $this->postmeta_dao->update_postmeta_by_post( $post->get_id(), $meta ); 344 345 } 345 346 … … 347 348 * Import attachments. 348 349 * 349 * @param Batch_Import er$importer350 */ 351 private function import_attachments( Batch_Import er$importer ) {350 * @param Batch_Import_Job $importer 351 */ 352 private function import_attachments( Batch_Import_Job $importer ) { 352 353 353 354 $attachments = $importer->get_batch()->get_attachments(); … … 465 466 * Import data added by a third-party. 466 467 * 467 * @param Batch_Import er$importer468 */ 469 private function import_custom_data( Batch_Import er$importer ) {468 * @param Batch_Import_Job $importer 469 */ 470 private function import_custom_data( Batch_Import_Job $importer ) { 470 471 foreach ( $importer->get_batch()->get_custom_data() as $addon => $data ) { 471 472 do_action( 'sme_import_' . $addon, $data, $importer ); -
content-staging/trunk/classes/class-setup.php
r990417 r995609 27 27 * dependencies. 28 28 */ 29 wp_register_script( 'content-staging', $this->plugin_url . '/assets/js/content-staging.js', array( 'jquery' ), '1. 0', false );29 wp_register_script( 'content-staging', $this->plugin_url . '/assets/js/content-staging.js', array( 'jquery' ), '1.1', false ); 30 30 31 31 // Register CSS stylesheet files for later use with wp_enqueue_style(). … … 70 70 71 71 // Arguments for batch importer post type 72 $import er= array(73 'label' => __( 'Batch Import ers', 'sme-content-staging' ),72 $import_job = array( 73 'label' => __( 'Batch Import Jobs', 'sme-content-staging' ), 74 74 'labels' => array( 75 'singular_name' => __( 'Batch Import ers', 'sme-content-staging' ),76 'add_new_item' => __( 'Add New Batch Import er', 'sme-content-staging' ),77 'edit_item' => __( 'Edit Batch Import er', 'sme-content-staging' ),78 'new_item' => __( 'New Batch Import er', 'sme-content-staging' ),79 'view_item' => __( 'View Batch Import er', 'sme-content-staging' ),80 'search_items' => __( 'Search Batch Import ers', 'sme-content-staging' ),81 'not_found' => __( 'No Batch Import ers found', 'sme-content-staging' ),82 'not_found_in_trash' => __( 'No Batch Import ers found in Trash', 'sme-content-staging' )75 'singular_name' => __( 'Batch Import Jobs', 'sme-content-staging' ), 76 'add_new_item' => __( 'Add New Batch Import Job', 'sme-content-staging' ), 77 'edit_item' => __( 'Edit Batch Import Job', 'sme-content-staging' ), 78 'new_item' => __( 'New Batch Import Job', 'sme-content-staging' ), 79 'view_item' => __( 'View Batch Import Job', 'sme-content-staging' ), 80 'search_items' => __( 'Search Batch Import Jobs', 'sme-content-staging' ), 81 'not_found' => __( 'No Batch Import Jobs found', 'sme-content-staging' ), 82 'not_found_in_trash' => __( 'No Batch Import Jobs found in Trash', 'sme-content-staging' ) 83 83 ), 84 'description' => __( 'Batches are imported by Batch Importers.', 'sme-content-staging' ),84 'description' => __( 'Batches are packaged in Batch Import Jobs that in turn is imported by Batch Importers.', 'sme-content-staging' ), 85 85 'public' => false, 86 86 'supports' => array( 'editor' ), … … 88 88 89 89 register_post_type( 'sme_content_batch', $batch ); 90 register_post_type( 'sme_batch_import er', $importer);90 register_post_type( 'sme_batch_import_job', $import_job ); 91 91 92 92 … … 97 97 add_submenu_page( null, 'Edit Batch', 'Edit', 'manage_options', 'sme-edit-batch', array( $this->batch_ctrl, 'edit_batch' ) ); 98 98 add_submenu_page( null, 'Delete Batch', 'Delete', 'manage_options', 'sme-delete-batch', array( $this->batch_ctrl, 'confirm_delete_batch' ) ); 99 add_submenu_page( null, ' Quick Deploy Batch', 'Quick Deploy', 'manage_options', 'sme-quick-deploy-batch', array( $this->batch_ctrl, 'quick_deploy_batch' ) );100 add_submenu_page( null, ' Pre-Flight Batch', 'Pre-Flight', 'manage_options', 'sme-preflight-batch', array( $this->batch_ctrl, 'preflight_batch' ) );101 add_submenu_page( null, 'Deploy Batch', 'Deploy', 'manage_options', 'sme-send-batch', array( $this->batch_ctrl, 'deploy _batch' ) );99 add_submenu_page( null, 'Pre-Flight Batch', 'Pre-Flight', 'manage_options', 'sme-preflight-batch', array( $this->batch_ctrl, 'prepare' ) ); 100 add_submenu_page( null, 'Quick Deploy Batch', 'Quick Deploy', 'manage_options', 'sme-quick-deploy-batch', array( $this->batch_ctrl, 'quick_deploy' ) ); 101 add_submenu_page( null, 'Deploy Batch', 'Deploy', 'manage_options', 'sme-send-batch', array( $this->batch_ctrl, 'deploy' ) ); 102 102 } 103 103 … … 123 123 public function register_xmlrpc_methods( $methods ) { 124 124 125 $methods['smeContentStaging.preflight'] = array( $this->batch_ctrl, 'preflight' ); 126 $methods['smeContentStaging.deploy'] = array( $this->batch_ctrl, 'deploy' ); 127 $methods['smeContentStaging.deployStatus'] = array( $this->batch_ctrl, 'deploy_status' ); 125 $methods['smeContentStaging.verify'] = array( $this->batch_ctrl, 'verify' ); 126 $methods['smeContentStaging.import'] = array( $this->batch_ctrl, 'import' ); 128 127 129 128 return $methods; -
content-staging/trunk/classes/controllers/class-batch-ctrl.php
r990417 r995609 4 4 use Me\Stenberg\Content\Staging\Background_Process; 5 5 use Me\Stenberg\Content\Staging\DB\Batch_DAO; 6 use Me\Stenberg\Content\Staging\DB\Batch_Importer_DAO; 6 use Me\Stenberg\Content\Staging\DB\Batch_Import_Job_DAO; 7 use Me\Stenberg\Content\Staging\Importers\Batch_Importer_Factory; 7 8 use Me\Stenberg\Content\Staging\Managers\Batch_Mgr; 8 9 use Me\Stenberg\Content\Staging\Models\Batch; 9 use Me\Stenberg\Content\Staging\Models\Batch_Import er;10 use Me\Stenberg\Content\Staging\Models\Batch_Import_Job; 10 11 use Me\Stenberg\Content\Staging\View\Batch_Table; 11 12 use Me\Stenberg\Content\Staging\DB\Post_DAO; … … 19 20 private $batch_mgr; 20 21 private $xmlrpc_client; 21 private $batch_importer_dao; 22 private $importer_factory; 23 private $batch_import_job_dao; 22 24 private $batch_dao; 23 25 private $post_dao; 24 26 25 27 public function __construct( Template $template, Batch_Mgr $batch_mgr, Client $xmlrpc_client, 26 Batch_Importer_DAO $batch_importer_dao, Batch_DAO $batch_dao, Post_DAO $post_dao ) { 27 $this->template = $template; 28 $this->batch_mgr = $batch_mgr; 29 $this->xmlrpc_client = $xmlrpc_client; 30 $this->batch_importer_dao = $batch_importer_dao; 31 $this->batch_dao = $batch_dao; 32 $this->post_dao = $post_dao; 28 Batch_Importer_Factory $importer_factory, Batch_Import_Job_DAO $batch_import_job_dao, 29 Batch_DAO $batch_dao, Post_DAO $post_dao ) { 30 $this->template = $template; 31 $this->batch_mgr = $batch_mgr; 32 $this->xmlrpc_client = $xmlrpc_client; 33 $this->importer_factory = $importer_factory; 34 $this->batch_import_job_dao = $batch_import_job_dao; 35 $this->batch_dao = $batch_dao; 36 $this->post_dao = $post_dao; 33 37 } 34 38 … … 138 142 } 139 143 144 $total_posts = $this->post_dao->get_published_posts_count(); 145 140 146 // Create and prepare table of posts. 141 147 $table = new Post_Table( $batch, $post_ids ); 142 148 $table->items = $posts; 149 $table->set_pagination_args( 150 array( 151 'total_items' => $total_posts, 152 'per_page' => $per_page, 153 ) 154 ); 143 155 $table->prepare_items(); 144 156 145 157 $data = array( 146 'batch' => $batch, 147 'table' => $table, 158 'batch' => $batch, 159 'table' => $table, 160 'post_ids' => implode( ',', $post_ids ), 148 161 ); 149 162 … … 172 185 173 186 /** 174 * Pre -flight batch.187 * Prepare batch for pre-flight. 175 188 * 176 189 * Send batch from content staging environment to production. Production … … 187 200 * @param Batch $batch 188 201 */ 189 public function pre flight_batch( $batch = null ) {202 public function prepare( $batch = null ) { 190 203 191 204 // Make sure a query param ID exists in current URL. … … 210 223 ); 211 224 212 $this->xmlrpc_client->query( 'smeContentStaging. preflight', $request );225 $this->xmlrpc_client->query( 'smeContentStaging.verify', $request ); 213 226 $response = $this->xmlrpc_client->get_response_data(); 214 227 … … 240 253 * @return string 241 254 */ 242 public function preflight( array $args ) {255 public function verify( array $args ) { 243 256 244 257 $this->xmlrpc_client->handle_request( $args ); … … 256 269 257 270 // Create importer. 258 $importer = new Batch_Import er();271 $importer = new Batch_Import_Job(); 259 272 $importer->set_batch( $batch ); 260 273 … … 307 320 * Send post directly to production. 308 321 */ 309 public function quick_deploy _batch() {322 public function quick_deploy() { 310 323 311 324 // Make sure a query param 'post_id' exists in current URL. … … 343 356 * would more closely resemble how we handle e.g. editing a batch. 344 357 */ 345 public function deploy _batch() {358 public function deploy() { 346 359 347 360 // Check that the current request carries a valid nonce. … … 362 375 ); 363 376 364 $this->xmlrpc_client->query( 'smeContentStaging. deploy', $request );377 $this->xmlrpc_client->query( 'smeContentStaging.import', $request ); 365 378 $response = $this->xmlrpc_client->get_response_data(); 366 379 … … 373 386 374 387 $data = array( 375 ' response' => $response,388 'messages' => $response['messages'], 376 389 ); 377 390 … … 381 394 /** 382 395 * Runs on production when a deploy request has been received. 383 *384 * @todo Checking if a batch has been provided is duplicated from385 * pre-flight, fix!386 *387 * Store background process ID.388 396 * 389 397 * @param array $args 390 398 * @return string 391 399 */ 392 public function deploy( array $args ) { 393 400 public function import( array $args ) { 401 402 $job = null; 403 $importer_type = null; 394 404 $this->xmlrpc_client->handle_request( $args ); 395 405 $result = $this->xmlrpc_client->get_request_data(); 396 406 397 // ----- Duplicated ----- 407 if ( isset( $result['job_id'] ) ) { 408 $job = $this->batch_import_job_dao->get_job_by_id( intval( $result['job_id'] ) ); 409 } 410 411 if ( ! $job ) { 412 $job = $this->create_import_job( $result ); 413 } 414 415 if ( $job->get_status() !== 2 ) { 416 417 if ( isset( $result['importer'] ) ) { 418 $importer_type = $result['importer']; 419 } 420 421 $importer = $this->importer_factory->get_importer( $job, $importer_type ); 422 423 if ( $job->get_status() === 0 ) { 424 $job->add_message( 425 sprintf( 426 'Starting batch import...<span id="sme-batch-importer-type" class="hidden">%s</span>', 427 $importer->get_type() 428 ), 429 'info' 430 ); 431 $this->batch_import_job_dao->update_job( $job ); 432 } 433 434 $importer->run(); 435 } 436 437 $response = array( 438 'status' => $job->get_status(), 439 'messages' => $job->get_messages(), 440 ); 441 442 // Prepare and return the XML-RPC response data. 443 return $this->xmlrpc_client->prepare_response( $response ); 444 } 445 446 /** 447 * Output the status of an import job together with any messages 448 * generated during import. 449 * 450 * Triggered by an AJAX call. 451 * 452 * Runs on staging environment. 453 */ 454 public function import_request() { 455 456 $request = array( 457 'job_id' => intval( $_POST['job_id'] ), 458 'importer' => $_POST['importer'], 459 ); 460 461 $this->xmlrpc_client->query( 'smeContentStaging.import', $request ); 462 $response = $this->xmlrpc_client->get_response_data(); 463 464 header( 'Content-Type: application/json' ); 465 echo json_encode( $response ); 466 467 die(); // Required to return a proper result. 468 } 469 470 /** 471 * Runs on production when an import status request has been received. 472 * 473 * @param array $result 474 * @return Batch_Import_Job 475 */ 476 private function create_import_job( $result ) { 477 478 $job = new Batch_Import_Job(); 398 479 399 480 // Check if a batch has been provided. 400 481 if ( ! isset( $result['batch'] ) || ! ( $result['batch'] instanceof Batch ) ) { 401 return $this->xmlrpc_client->prepare_response( 402 array( 'error' => array( 'Invalid batch!' ) ) 403 ); 482 $job->add_message( 'Failed creating import job.', 'error' ); 483 $job->set_status( 2 ); 484 return $job; 485 } 486 487 $job->set_batch( $result['batch'] ); 488 $this->batch_import_job_dao->insert_job( $job ); 489 $job->add_message( 490 sprintf( 491 'Created import job ID: <span id="sme-batch-import-job-id">%s</span>', 492 $job->get_id() 493 ), 494 'info' 495 ); 496 return $job; 497 } 498 499 /** 500 * Add a post ID to batch. 501 * 502 * Triggered by an AJAX call. 503 */ 504 public function include_post() { 505 506 if ( ! isset( $_POST['include'] ) || ! isset( $_POST['batch_id'] ) || ! isset( $_POST['post_id'] ) ) { 507 die(); 508 } 509 510 $batch_id = null; 511 $post_id = intval( $_POST['post_id'] ); 512 $is_selected = false; 513 514 if ( $_POST['batch_id'] ) { 515 $batch_id = intval( $_POST['batch_id'] ); 516 } 517 518 if ( $_POST['include'] === 'true' ) { 519 $is_selected = true; 404 520 } 405 521 406 522 // Get batch. 407 $batch = $result['batch']; 408 409 // ----- Duplicated ----- 410 411 $importer = new Batch_Importer(); 412 $importer->set_batch( $batch ); 413 $this->batch_importer_dao->insert_importer( $importer ); 414 415 // Default site path. 416 $site_path = '/'; 417 418 // Site path in multi-site setup. 419 if ( is_multisite() ) { 420 $site = get_blog_details(); 421 $site_path = $site->path; 422 } 423 424 // Trigger import script. 425 $import_script = dirname( dirname( dirname( __FILE__ ) ) ) . '/scripts/import-batch.php'; 426 $background_process = new Background_Process( 427 'php ' . $import_script . ' ' . ABSPATH . ' ' . get_site_url() . ' ' . $importer->get_id() . ' ' . $site_path . ' ' . $importer->get_key() 428 ); 429 430 if ( file_exists( $import_script ) ) { 431 $background_process->run(); 432 } 433 434 // @todo store background process ID: $background_process->get_pid(); 435 436 $response = array( 437 'info' => array( 438 'Import of batch has been started. Importer ID: <span id="sme-batch-importer-id">' . $importer->get_id() . '</span>', 439 ) 440 ); 441 442 // Prepare and return the XML-RPC response data. 443 return $this->xmlrpc_client->prepare_response( $response ); 444 } 445 446 /** 447 * Triggered by an AJAX call. Returns the status of the import together 448 * with any messages generated during import. 449 */ 450 public function get_import_status() { 451 452 $importer_id = intval( $_POST['importer_id'] ); 453 454 $request = array( 455 'importer_id' => $importer_id, 456 ); 457 458 $this->xmlrpc_client->query( 'smeContentStaging.deployStatus', $request ); 459 $response = $this->xmlrpc_client->get_response_data(); 523 $batch = $this->batch_mgr->get_batch( $batch_id, true ); 524 525 // Create new batch if needed. 526 if ( ! $batch->get_id() ) { 527 $this->batch_dao->insert_batch( $batch ); 528 } 529 530 // Get IDs of posts already included in the batch. 531 $post_ids = $this->batch_dao->get_post_meta( $batch->get_id(), 'sme_selected_post_ids', true ); 532 533 if ( ! $post_ids ) { 534 $post_ids = array(); 535 } 536 537 if ( $is_selected ) { 538 // Add post ID. 539 $post_ids[] = $post_id; 540 } else { 541 // Remove post ID. 542 if ( ( $key = array_search( $post_id, $post_ids ) ) !== false ) { 543 unset( $post_ids[$key] ); 544 } 545 } 546 547 $post_ids = array_unique( $post_ids ); 548 549 // Update batch meta with IDs of posts user selected to include in batch. 550 $this->batch_dao->update_post_meta( $batch->get_id(), 'sme_selected_post_ids', $post_ids ); 460 551 461 552 header( 'Content-Type: application/json' ); 462 echo json_encode( $response);553 echo json_encode( array( 'batchId' => $batch->get_id() ) ); 463 554 464 555 die(); // Required to return a proper result. 465 }466 467 /**468 * Runs on production when a deploy status request has been received.469 *470 * @param array $args471 * @return string472 */473 public function deploy_status( array $args ) {474 475 $response = array(476 'status' => 0,477 'messages' => array(),478 );479 480 $this->xmlrpc_client->handle_request( $args );481 $result = $this->xmlrpc_client->get_request_data();482 483 // Check if a batch has been provided.484 if ( ! isset( $result['importer_id'] ) ) {485 $response['messages']['error'] = array( 'No batch importer has been provided!' );486 return $this->xmlrpc_client->prepare_response( $response );487 }488 489 // Get batch importer ID.490 $importer_id = intval( $result['importer_id'] );491 492 // Get batch importer.493 $importer = $this->batch_importer_dao->get_importer_by_id( $importer_id );494 495 // Create response.496 $response['status'] = $importer->get_status();497 $response['messages'] = $importer->get_messages();498 499 // Prepare and return the XML-RPC response data.500 return $this->xmlrpc_client->prepare_response( $response );501 556 } 502 557 … … 586 641 private function handle_edit_batch_form_data( Batch $batch, $request_data ) { 587 642 588 // IDs of posts user has selected to include in this batch.589 $post_ids = array();590 591 643 // Check if a title has been set. 592 644 if ( isset( $request_data['batch_title'] ) ) { 593 645 $batch->set_title( $request_data['batch_title'] ); 594 }595 596 // Check if any posts to include in batch has been selected.597 if ( isset( $request_data['posts'] ) && is_array( $request_data['posts'] ) ) {598 $post_ids = $request_data['posts'];599 646 } 600 647 … … 605 652 // Update existing batch. 606 653 $this->batch_dao->update_batch( $batch ); 654 } 655 656 // IDs of posts user has selected to include in this batch. 657 $post_ids = array(); 658 659 // Check if any posts to include in batch has been selected. 660 if ( isset( $request_data['post_ids'] ) && $request_data['post_ids'] ) { 661 $post_ids = explode( ',', $request_data['post_ids'] ); 607 662 } 608 663 -
content-staging/trunk/classes/db/class-postmeta-dao.php
r990417 r995609 8 8 } 9 9 10 /** 11 * Get all post meta records for a specific post. 12 * 13 * @param int $post_id 14 * @return array 15 */ 10 16 public function get_postmetas_by_post_id( $post_id ) { 11 17 $query = $this->wpdb->prepare( … … 34 40 } 35 41 42 /** 43 * Update post meta. 44 * 45 * @param array $record 46 */ 47 public function update_postmeta( $record ) { 48 $this->wpdb->update( 49 $this->wpdb->postmeta, 50 array( 51 'post_id' => $record['post_id'], 52 'meta_key' => $record['meta_key'], 53 'meta_value' => $record['meta_value'], 54 ), 55 array( 'meta_id' => $record['meta_id'] ), 56 array( '%d', '%s', '%s' ), 57 array( '%d' ) 58 ); 59 } 60 36 61 public function delete_postmeta( $where, $where_format ) { 37 62 $this->wpdb->delete( $this->wpdb->postmeta, $where, $where_format ); 63 } 64 65 /** 66 * Update all post meta for a post. 67 * 68 * @param int $post_id 69 * @param array $stage_records 70 */ 71 public function update_postmeta_by_post( $post_id, array $stage_records ) { 72 73 $insert_keys = array(); 74 $stage_keys = array(); 75 76 $insert = array(); 77 $update = array(); 78 $delete = array(); 79 80 $prod_records = $this->get_postmetas_by_post_id( $post_id ); 81 82 /* 83 * Go through each meta record we got from stage. If a meta_key exists 84 * more then once, then we will not try to update any records with that 85 * meta key. 86 */ 87 foreach ( $stage_records as $key => $prod_record ) { 88 if ( in_array( $prod_record['meta_key'], $stage_keys ) ) { 89 $insert[] = $prod_record; 90 $insert_keys[] = $prod_record['meta_key']; 91 unset( $stage_records[$key] ); 92 } else { 93 $stage_keys[] = $prod_record['meta_key']; 94 } 95 } 96 97 /* 98 * Go through each meta record we got from production. If a meta_key 99 * exist that is already part of the keys scheduled for insertion or if a 100 * key that is found that is not part of the keys from stage, then 101 * schedule that record for deletion. 102 * 103 * Records left in $stage_records is candidates for being updated. Go 104 * through them and see if they already exist in $prod_records. 105 */ 106 foreach ( $prod_records as $prod_key => $prod_record ) { 107 if ( ! in_array( $prod_record['meta_key'], $stage_keys ) || in_array( $prod_record['meta_key'], $insert_keys ) ) { 108 $delete[] = $prod_record; 109 unset( $prod_records[$prod_key] ); 110 } else { 111 foreach ( $stage_records as $stage_key => $stage_record ) { 112 if ( $stage_record['meta_key'] == $prod_record['meta_key'] ) { 113 $stage_record['meta_id'] = $prod_record['meta_id']; 114 $update[] = $stage_record; 115 unset( $stage_records[$stage_key] ); 116 unset( $prod_records[$prod_key] ); 117 } 118 } 119 } 120 } 121 122 // Records left in $stage_records should be inserted. 123 foreach ( $stage_records as $record ) { 124 $insert[] = $record; 125 } 126 127 // Records left in $prod_records should be deleted. 128 foreach ( $prod_records as $record ) { 129 $delete[] = $record; 130 } 131 132 foreach( $delete as $record ) { 133 $this->delete_postmeta( 134 array( 'meta_id' => $record['meta_id'] ), 135 array( '%d' ) 136 ); 137 } 138 139 foreach ( $insert as $record ) { 140 $this->insert_postmeta( $record ); 141 } 142 143 foreach( $update as $record ) { 144 $this->update_postmeta( $record ); 145 } 38 146 } 39 147 -
content-staging/trunk/classes/view/class-post-table.php
r990417 r995609 75 75 */ 76 76 public function column_cb( Post $post ) { 77 78 $checked = '';79 80 /*81 * Set property 'checked' that will either be an empty string if the post82 * is not part of this batch or to a string indicating that the post83 * should be checked in the HTML form.84 */85 if ( in_array( $post->get_id(), $this->post_ids ) ) {86 $checked = 'checked="checked" ';87 }88 89 77 return sprintf( 90 '<input type="checkbox" name="%s[]" value="%s" %s/>',78 '<input type="checkbox" class="sme-select-post" name="%s[]" value="%s"/>', 91 79 $this->_args['plural'], 92 $post->get_id(), 93 $checked 80 $post->get_id() 94 81 ); 95 82 } -
content-staging/trunk/content-staging.php
r990417 r995609 33 33 require_once( 'classes/controllers/class-batch-ctrl.php' ); 34 34 require_once( 'classes/db/mappers/class-mapper.php' ); 35 require_once( 'classes/db/mappers/class-batch-import er-mapper.php' );35 require_once( 'classes/db/mappers/class-batch-import-job-mapper.php' ); 36 36 require_once( 'classes/db/mappers/class-batch-mapper.php' ); 37 37 require_once( 'classes/db/mappers/class-post-mapper.php' ); … … 40 40 require_once( 'classes/db/class-dao.php' ); 41 41 require_once( 'classes/db/class-batch-dao.php' ); 42 require_once( 'classes/db/class-batch-import er-dao.php' );42 require_once( 'classes/db/class-batch-import-job-dao.php' ); 43 43 require_once( 'classes/db/class-post-dao.php' ); 44 44 require_once( 'classes/db/class-postmeta-dao.php' ); 45 45 require_once( 'classes/db/class-term-dao.php' ); 46 46 require_once( 'classes/db/class-user-dao.php' ); 47 require_once( 'classes/importers/class-batch-importer.php' ); 48 require_once( 'classes/importers/class-batch-ajax-importer.php' ); 49 require_once( 'classes/importers/class-batch-background-importer.php' ); 50 require_once( 'classes/importers/class-batch-importer-factory.php' ); 47 51 require_once( 'classes/managers/class-batch-mgr.php' ); 48 52 require_once( 'classes/models/class-batch.php' ); 49 require_once( 'classes/models/class-batch-import er.php' );53 require_once( 'classes/models/class-batch-import-job.php' ); 50 54 require_once( 'classes/models/class-post.php' ); 51 55 require_once( 'classes/models/class-taxonomy.php' ); … … 67 71 */ 68 72 use Me\Stenberg\Content\Staging\API; 69 use Me\Stenberg\Content\Staging\DB\Batch_Import er_DAO;70 use Me\Stenberg\Content\Staging\DB\Mappers\Batch_Import er_Mapper;73 use Me\Stenberg\Content\Staging\DB\Batch_Import_Job_DAO; 74 use Me\Stenberg\Content\Staging\DB\Mappers\Batch_Import_Job_Mapper; 71 75 use Me\Stenberg\Content\Staging\Import_Batch; 72 76 use Me\Stenberg\Content\Staging\Setup; … … 82 86 use Me\Stenberg\Content\Staging\DB\Term_DAO; 83 87 use Me\Stenberg\Content\Staging\DB\User_DAO; 88 use Me\Stenberg\Content\Staging\Importers\Batch_Importer_Factory; 84 89 use Me\Stenberg\Content\Staging\Managers\Batch_Mgr; 85 90 use Me\Stenberg\Content\Staging\XMLRPC\Client; … … 118 123 119 124 // Database mappers 120 $batch_importer_mapper = new Batch_Import er_Mapper();125 $batch_importer_mapper = new Batch_Import_Job_Mapper(); 121 126 $batch_mapper = new Batch_Mapper(); 122 127 $post_mapper = new Post_Mapper(); … … 125 130 126 131 // Data access objects. 127 $batch_dao = new Batch_DAO( $wpdb, $batch_mapper );128 $ batch_importer_dao = new Batch_Importer_DAO( $wpdb, $batch_importer_mapper );129 $post_dao = new Post_DAO( $wpdb, $post_mapper );130 $postmeta_dao = new Postmeta_DAO( $wpdb );131 $term_dao = new Term_DAO( $wpdb, $term_mapper );132 $user_dao = new User_DAO( $wpdb, $user_mapper );132 $batch_dao = new Batch_DAO( $wpdb, $batch_mapper ); 133 $job_dao = new Batch_Import_Job_DAO( $wpdb, $batch_importer_mapper ); 134 $post_dao = new Post_DAO( $wpdb, $post_mapper ); 135 $postmeta_dao = new Postmeta_DAO( $wpdb ); 136 $term_dao = new Term_DAO( $wpdb, $term_mapper ); 137 $user_dao = new User_DAO( $wpdb, $user_mapper ); 133 138 134 139 // XML-RPC client. … … 136 141 137 142 // Managers. 138 $batch_mgr = new Batch_Mgr( $batch_dao, $post_dao, $postmeta_dao, $term_dao, $user_dao ); 143 $batch_mgr = new Batch_Mgr( $batch_dao, $post_dao, $postmeta_dao, $term_dao, $user_dao ); 144 $importer_factory = new Batch_Importer_Factory( $job_dao, $post_dao, $postmeta_dao, $term_dao, $user_dao ); 139 145 140 146 // Template engine. … … 143 149 // Controllers. 144 150 $batch_ctrl = new Batch_Ctrl( 145 $template, $batch_mgr, $xmlrpc_client, $ batch_importer_dao, $batch_dao, $post_dao151 $template, $batch_mgr, $xmlrpc_client, $importer_factory, $job_dao, $batch_dao, $post_dao 146 152 ); 147 153 148 154 // APIs. 149 155 $sme_content_staging_api = new API( $post_dao, $postmeta_dao ); 150 151 // Controller responsible for importing a batch to production.152 $import_batch = new Import_Batch( $batch_importer_dao, $post_dao, $postmeta_dao, $term_dao, $user_dao );153 156 154 157 // Plugin setup. … … 157 160 // Actions. 158 161 add_action( 'init', array( $setup, 'register_post_types' ) ); 159 add_action( 'init', array( $import _batch, 'init' ) );162 add_action( 'init', array( $importer_factory, 'run_background_import' ) ); 160 163 add_action( 'admin_menu', array( $setup, 'register_menu_pages' ) ); 161 164 add_action( 'admin_notices', array( $setup, 'quick_deploy_batch' ) ); 162 165 add_action( 'admin_enqueue_scripts', array( $setup, 'load_assets' ) ); 163 166 add_action( 'admin_post_sme-save-batch', array( $batch_ctrl, 'save_batch' ) ); 164 add_action( 'admin_post_sme-quick-deploy-batch', array( $batch_ctrl, 'quick_deploy _batch' ) );167 add_action( 'admin_post_sme-quick-deploy-batch', array( $batch_ctrl, 'quick_deploy' ) ); 165 168 add_action( 'admin_post_sme-delete-batch', array( $batch_ctrl, 'delete_batch' ) ); 166 add_action( 'wp_ajax_sme_batch_import_status', array( $batch_ctrl, 'get_import_status' ) ); 169 add_action( 'wp_ajax_sme_include_post', array( $batch_ctrl, 'include_post' ) ); 170 add_action( 'wp_ajax_sme_import_request', array( $batch_ctrl, 'import_request' ) ); 167 171 168 172 // Filters. -
content-staging/trunk/readme.txt
r990417 r995609 63 63 3. Pre-Flight your batch to make sure it is ready for deployment. 64 64 4. Deploy your batch from staging environment to your live site. 65 66 == Changelog == 67 68 = 1.1 = 69 * New AJAX importer to use when Background importer is not an option. 70 * Pagination on Edit Batch page. -
content-staging/trunk/scripts/import-batch.php
r990417 r995609 53 53 // Set up GET parameters. 54 54 $_GET = array( 55 'sme_batch_importer_id' => $argv[3], 56 'sme_import_batch_key' => $argv[5], 55 'sme_background_import' => true, 56 'sme_batch_import_job_id' => $argv[3], 57 'sme_import_batch_key' => $argv[5], 57 58 ); 58 59 -
content-staging/trunk/templates/deploy-batch.php
r990417 r995609 2 2 <h2>Deploying Batch</h2> 3 3 4 <?php foreach ( $ response as $level => $messages) { ?>5 <div class="sme-cs-message sme-cs-<?php echo $ level; ?>">4 <?php foreach ( $messages as $message ) { ?> 5 <div class="sme-cs-message sme-cs-<?php echo $message['level']; ?>"> 6 6 <ul> 7 <?php foreach ( $messages as $message ) { ?> 8 <li><?php echo $message; ?></li> 9 <?php } ?> 7 <li><?php echo $message['message']; ?></li> 10 8 </ul> 11 9 </div> -
content-staging/trunk/templates/edit-batch.php
r990417 r995609 1 1 <div class="wrap"> 2 3 <!-- Enable JavaScript to pick up the batch ID. --> 4 <span id="sme-batch-id" class="hidden"><?php echo $batch->get_id();?></span> 2 5 3 6 <?php if ( isset( $_GET['updated'] ) ) { ?> … … 10 13 11 14 <?php wp_nonce_field( 'sme-save-batch','sme_save_batch_nonce' ); ?> 15 <input type="hidden" name="post_ids" value="<?php echo $post_ids; ?>"> 12 16 13 17 <input type="text" name="batch_title" size="30" value="<?php echo $batch->get_title(); ?>" class="sme-input-text" placeholder="Batch Title" autocomplete="off">
Note: See TracChangeset
for help on using the changeset viewer.