Changeset 3424368
- Timestamp:
- 12/20/2025 08:17:54 PM (6 weeks ago)
- Location:
- easy-bulk-date-editor
- Files:
-
- 2 added
- 6 edited
- 1 copied
-
tags/1.2 (copied) (copied from easy-bulk-date-editor/trunk)
-
tags/1.2/bde.js (modified) (4 diffs)
-
tags/1.2/changelog.md (added)
-
tags/1.2/easy-bulk-date-editor.php (modified) (5 diffs)
-
tags/1.2/readme.txt (modified) (1 diff)
-
trunk/bde.js (modified) (4 diffs)
-
trunk/changelog.md (added)
-
trunk/easy-bulk-date-editor.php (modified) (5 diffs)
-
trunk/readme.txt (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
easy-bulk-date-editor/tags/1.2/bde.js
r3415608 r3424368 1 1 (function($){ 2 var EasyBDEState = { 3 filter_by: 'category', 4 filter_val: 0, 5 paged: 1, 6 max_num_pages: 1 7 }; 8 2 9 function renderTable(rows){ 3 10 if(!rows || rows.length === 0){ 4 11 $('#easybde_controls').hide(); 5 $('#easybde_table_wrap').html( '<p>'+EasyBDEData.i18n.no_posts+'</p>');12 $('#easybde_table_wrap').html(renderPagination() + '<p>'+EasyBDEData.i18n.no_posts+'</p>' + renderPagination()); 6 13 return; 7 14 } 8 15 $('#easybde_controls').show(); 9 16 var html = []; 17 html.push(renderPagination()); 10 18 html.push('<form id="easybde_form"><table class="wp-list-table widefat fixed striped"><thead><tr>'); 11 19 html.push('<th style="width:30px"><input type="checkbox" id="easybde_select_all" /></th>'); … … 21 29 }); 22 30 html.push('</tbody></table><p><button id="easybde_save" class="button button-primary">Save changes</button> <span id="easybde_result" style="margin-left:10px"></span></p></form>'); 31 html.push(renderPagination()); 23 32 $('#easybde_table_wrap').html(html.join('')); 33 } 34 35 function renderPagination(){ 36 var paged = EasyBDEState.paged || 1; 37 var max = EasyBDEState.max_num_pages || 1; 38 if(max <= 1){ 39 return ''; 40 } 41 42 var html = []; 43 html.push('<div class="easybde_pagination" style="margin:12px 0; display:flex; gap:8px; align-items:center; flex-wrap:wrap;">'); 44 html.push('<button type="button" class="button easybde_page" data-page="' + Math.max(1, paged - 1) + '" ' + (paged <= 1 ? 'disabled' : '') + '>« Prev</button>'); 45 46 // Compact page range around current (max 7 buttons) 47 var start = Math.max(1, paged - 3); 48 var end = Math.min(max, paged + 3); 49 if(end - start < 6){ 50 start = Math.max(1, end - 6); 51 end = Math.min(max, start + 6); 52 } 53 54 if(start > 1){ 55 html.push('<button type="button" class="button easybde_page" data-page="1">1</button>'); 56 if(start > 2){ 57 html.push('<span style="padding:0 4px;">…</span>'); 58 } 59 } 60 61 for(var p = start; p <= end; p++){ 62 if(p === paged){ 63 html.push('<span class="button button-primary" style="cursor:default;">' + p + '</span>'); 64 } else { 65 html.push('<button type="button" class="button easybde_page" data-page="' + p + '">' + p + '</button>'); 66 } 67 } 68 69 if(end < max){ 70 if(end < max - 1){ 71 html.push('<span style="padding:0 4px;">…</span>'); 72 } 73 html.push('<button type="button" class="button easybde_page" data-page="' + max + '">' + max + '</button>'); 74 } 75 76 html.push('<button type="button" class="button easybde_page" data-page="' + Math.min(max, paged + 1) + '" ' + (paged >= max ? 'disabled' : '') + '>Next »</button>'); 77 html.push('<span style="margin-left:6px; opacity:.8;">Page ' + paged + ' of ' + max + '</span>'); 78 html.push('</div>'); 79 return html.join(''); 24 80 } 25 81 … … 52 108 } 53 109 54 $(document).on('click', '#easybde_load', function(e){ 55 e.preventDefault(); 56 var cat = $('#easybde_category').val(); 110 function getFilterValue(){ 111 if(EasyBDEState.filter_by === 'author'){ 112 return parseInt($('#easybde_author').val() || 0, 10); 113 } 114 return parseInt($('#easybde_category').val() || 0, 10); 115 } 116 117 function loadPosts(page){ 118 EasyBDEState.paged = page || 1; 119 EasyBDEState.filter_by = $('#easybde_filter_by').val() || 'category'; 120 EasyBDEState.filter_val = getFilterValue(); 121 57 122 $('#easybde_status').text(EasyBDEData.i18n.loading); 58 $.post(EasyBDEData.ajax_url, {action:'easybde_load_posts', cat:cat, nonce:EasyBDEData.nonce}, function(resp){ 123 $.post(EasyBDEData.ajax_url, { 124 action: 'easybde_load_posts', 125 filter_by: EasyBDEState.filter_by, 126 filter_val: EasyBDEState.filter_val, 127 paged: EasyBDEState.paged, 128 nonce: EasyBDEData.nonce 129 }, function(resp){ 59 130 if(resp && resp.success){ 60 $('#easybde_status').text('Loaded ' + resp.data.count + ' posts'); 131 var meta = (resp.data && resp.data.meta) ? resp.data.meta : {}; 132 EasyBDEState.paged = meta.paged || EasyBDEState.paged; 133 EasyBDEState.max_num_pages = meta.max_num_pages || 1; 134 135 var total = meta.found_posts || 0; 136 $('#easybde_status').text('Loaded ' + (resp.data.count || 0) + ' posts (page ' + EasyBDEState.paged + ' of ' + EasyBDEState.max_num_pages + ', total ' + total + ')'); 61 137 renderTable(resp.data.rows); 62 138 } else { … … 64 140 } 65 141 }); 142 } 143 144 $(document).on('change', '#easybde_filter_by', function(){ 145 var by = $(this).val(); 146 if(by === 'author'){ 147 $('#easybde_filter_category_wrap').hide(); 148 $('#easybde_filter_author_wrap').show(); 149 } else { 150 $('#easybde_filter_author_wrap').hide(); 151 $('#easybde_filter_category_wrap').show(); 152 } 153 }); 154 155 $(document).on('click', '#easybde_load', function(e){ 156 e.preventDefault(); 157 loadPosts(1); 158 }); 159 160 $(document).on('click', '.easybde_page', function(e){ 161 e.preventDefault(); 162 var page = parseInt($(this).data('page') || 1, 10); 163 if(!page || page < 1){ 164 page = 1; 165 } 166 loadPosts(page); 66 167 }); 67 168 -
easy-bulk-date-editor/tags/1.2/easy-bulk-date-editor.php
r3421759 r3424368 3 3 * Plugin Name: Easy Bulk Date Editor 4 4 * Description: Bulk edit post publish dates by category from a single admin screen, including an optional "shift by" tool. 5 * Version: 1. 1.15 * Version: 1.2 6 6 * Author: Andre Moura 7 7 * Author URI: https://www.andremoura.com … … 27 27 * @var int 28 28 */ 29 protected $max_posts = 500;29 protected $max_posts = 25; 30 30 31 31 /** … … 105 105 <p><?php esc_html_e( 'Filter posts and edit their publish dates in bulk. Remember to back up your database before performing bulk changes.', 'easy-bulk-date-editor' ); ?></p> 106 106 107 <div id="easybde_filter"> 108 <label for="easybde_category"> 109 <?php esc_html_e( 'Category:', 'easy-bulk-date-editor' ); ?> 110 </label> 111 <?php 112 wp_dropdown_categories( 113 array( 114 'show_option_all' => __( 'All categories', 'easy-bulk-date-editor' ), 115 'hide_empty' => 0, 116 'name' => 'easybde_category', 117 'id' => 'easybde_category', 118 ) 119 ); 120 ?> 121 <button class="button button-secondary" id="easybde_load"> 122 <?php esc_html_e( 'Load posts', 'easy-bulk-date-editor' ); ?> 123 </button> 124 <span id="easybde_status" style="margin-left:10px;"></span> 125 </div> 107 <div id="easybde_filter"> 108 <label for="easybde_filter_by"> 109 <?php esc_html_e( 'Filter by:', 'easy-bulk-date-editor' ); ?> 110 </label> 111 <select id="easybde_filter_by" name="easybde_filter_by" style="min-width:160px;"> 112 <option value="category"><?php esc_html_e( 'Category', 'easy-bulk-date-editor' ); ?></option> 113 <option value="author"><?php esc_html_e( 'Author', 'easy-bulk-date-editor' ); ?></option> 114 </select> 115 116 <span id="easybde_filter_category_wrap" style="margin-left:10px;"> 117 <label for="easybde_category" class="screen-reader-text"> 118 <?php esc_html_e( 'Category', 'easy-bulk-date-editor' ); ?> 119 </label> 120 <?php 121 wp_dropdown_categories( 122 array( 123 'show_option_all' => __( 'All categories', 'easy-bulk-date-editor' ), 124 'hide_empty' => 0, 125 'name' => 'easybde_category', 126 'id' => 'easybde_category', 127 ) 128 ); 129 ?> 130 </span> 131 132 <span id="easybde_filter_author_wrap" style="margin-left:10px; display:none;"> 133 <label for="easybde_author" class="screen-reader-text"> 134 <?php esc_html_e( 'Author', 'easy-bulk-date-editor' ); ?> 135 </label> 136 <?php 137 wp_dropdown_users( 138 array( 139 'name' => 'easybde_author', 140 'id' => 'easybde_author', 141 'show_option_all' => __( 'All authors', 'easy-bulk-date-editor' ), 142 'role__in' => array( 'administrator', 'editor', 'author', 'contributor' ), 143 'orderby' => 'display_name', 144 'order' => 'ASC', 145 'include_selected' => true, 146 ) 147 ); 148 ?> 149 </span> 150 151 <button class="button button-secondary" id="easybde_load" style="margin-left:10px;"> 152 <?php esc_html_e( 'Load posts', 'easy-bulk-date-editor' ); ?> 153 </button> 154 <span id="easybde_status" style="margin-left:10px;"></span> 155 </div> 156 126 157 127 158 <div id="easybde_controls" style="margin-top:15px; display:none;"> … … 154 185 */ 155 186 public function easybde_ajax_load_posts() { 187 check_ajax_referer( 'easybde_nonce', 'nonce' ); 188 189 if ( ! current_user_can( 'edit_posts' ) ) { 190 wp_send_json_error( 191 array( 192 'message' => __( 'You do not have permission to edit posts.', 'easy-bulk-date-editor' ), 193 ) 194 ); 195 } 196 197 $filter_by = filter_input( INPUT_POST, 'filter_by', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); 198 $filter_by = is_string( $filter_by ) ? sanitize_key( $filter_by ) : 'category'; 199 if ( ! in_array( $filter_by, array( 'category', 'author' ), true ) ) { 200 $filter_by = 'category'; 201 } 202 203 $filter_val = filter_input( INPUT_POST, 'filter_val', FILTER_SANITIZE_NUMBER_INT ); 204 $filter_val = ( null === $filter_val ) ? 0 : (int) $filter_val; 205 206 $paged = filter_input( INPUT_POST, 'paged', FILTER_SANITIZE_NUMBER_INT ); 207 $paged = ( null === $paged || (int) $paged <= 0 ) ? 1 : (int) $paged; 208 209 $args = array( 210 'post_type' => 'post', 211 'posts_per_page' => $this->per_page, 212 'orderby' => 'date', 213 'order' => 'DESC', 214 'paged' => $paged, 215 ); 216 217 if ( 'category' === $filter_by && $filter_val > 0 ) { 218 $args['cat'] = $filter_val; 219 } 220 221 if ( 'author' === $filter_by && $filter_val > 0 ) { 222 $args['author'] = $filter_val; 223 } 224 225 $query = new WP_Query( $args ); 226 $rows = array(); 227 228 if ( $query->have_posts() ) { 229 foreach ( $query->posts as $post ) { 230 $post_id = (int) $post->ID; 231 232 // Datetime-local expects "YYYY-MM-DDTHH:MM". 233 $dt = get_post_datetime( $post ); 234 if ( $dt instanceof DateTimeInterface ) { 235 $value = $dt->format( 'Y-m-d\TH:i' ); 236 } else { 237 $value = ''; 238 } 239 240 $rows[] = array( 241 'ID' => $post_id, 242 'title' => get_the_title( $post_id ), 243 'permalink' => get_edit_post_link( $post_id, '' ), 244 'post_date_display' => get_the_time( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $post_id ), 245 'post_date' => $value, 246 ); 247 } 248 } 249 250 wp_send_json_success( 251 array( 252 'count' => count( $rows ), 253 'rows' => $rows, 254 'meta' => array( 255 'paged' => (int) $paged, 256 'per_page' => (int) $this->per_page, 257 'found_posts' => (int) $query->found_posts, 258 'max_num_pages' => (int) $query->max_num_pages, 259 'filter_by' => $filter_by, 260 'filter_val' => (int) $filter_val, 261 ), 262 ) 263 ); 264 } 265 266 267 /** 268 * AJAX handler to save new dates. 269 */ 270 public function easybde_ajax_save_dates() { 156 271 check_ajax_referer( 'easybde_nonce', 'nonce' ); 157 272 … … 164 279 } 165 280 166 $cat = filter_input( INPUT_POST, 'cat', FILTER_SANITIZE_NUMBER_INT );167 if ( null === $cat ) {168 $cat = 0;169 }170 171 $args = array(172 'post_type' => 'post',173 'posts_per_page' => $this->max_posts,174 'orderby' => 'date',175 'order' => 'DESC',176 );177 178 if ( $cat > 0 ) {179 $args['cat'] = (int) $cat;180 }181 182 $query = new WP_Query( $args );183 $rows = array();184 185 if ( $query->have_posts() ) {186 foreach ( $query->posts as $post ) {187 $post_id = (int) $post->ID;188 189 // Datetime-local expects "YYYY-MM-DDTHH:MM".190 $dt = get_post_datetime( $post );191 if ( $dt instanceof DateTimeInterface ) {192 $value = $dt->format( 'Y-m-d\TH:i' );193 } else {194 $value = '';195 }196 197 $rows[] = array(198 'ID' => $post_id,199 'title' => get_the_title( $post_id ),200 'permalink' => get_edit_post_link( $post_id, '' ),201 'post_date_display' => get_the_time( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $post_id ),202 'post_date' => $value,203 );204 }205 }206 207 wp_send_json_success(208 array(209 'count' => count( $rows ),210 'rows' => $rows,211 )212 );213 }214 215 /**216 * AJAX handler to save new dates.217 */218 public function easybde_ajax_save_dates() {219 check_ajax_referer( 'easybde_nonce', 'nonce' );220 221 if ( ! current_user_can( 'edit_posts' ) ) {222 wp_send_json_error(223 array(224 'message' => __( 'You do not have permission to edit posts.', 'easy-bulk-date-editor' ),225 )226 );227 }228 229 281 // Get changes from POST as an array, without directly touching $_POST. 230 282 $raw_changes = filter_input( -
easy-bulk-date-editor/tags/1.2/readme.txt
r3421759 r3424368 1 1 === Easy Bulk Date Editor === 2 Contributors: andremoura 3 Requires at least: 4.6 4 Tested up to: 6.9 5 Stable tag: 1.1.1 6 Requires PHP: 7.2 2 Contributors: andreluizmoura 3 Tags: posts, bulk edit, dates, scheduling, wordpress admin 4 Requires at least: 5.8 5 Tested up to: 6.6 6 Requires PHP: 7.4 7 Author URI: https://www.andremoura.com 8 Plugin URI: https://wordpress.andremoura.com 9 Stable tag: 1.2 7 10 License: GPLv2 or later 8 License URI: http ://www.gnu.org/licenses/gpl-2.0.html11 License URI: https://www.gnu.org/licenses/gpl-2.0.html 9 12 10 Bulk edit post publish dates by author or category from a single screen.13 Bulk edit WordPress post dates safely and efficiently, now with filtering by category or author and paginated loading for better performance. 11 14 12 15 == Description == 13 16 14 Easy Bulk Date Editor lets you update post publish dates in bulk from a single, focused admin screen.17 Easy Bulk Date Editor is a lightweight WordPress admin plugin that allows editors and administrators to bulk edit post publication dates with precision and control. 15 18 16 You can: 17 * Filter posts by category. 18 * Load up to a few hundred posts at once. 19 * Edit individual publish dates directly in a table. 20 * Select posts and shift all their dates by a number of days or hours. 19 The plugin was designed to avoid common performance pitfalls of bulk actions by loading posts incrementally and applying changes only to the selected rows. 21 20 22 This is especially useful when: 23 * You are migrating content and need to adjust dates. 24 * An author’s posts need to be moved forward or backward in time. 25 * You want to clean up an old content calendar without opening each post one by one. 21 ### Key Features 26 22 27 The plugin works with standard WordPress posts and uses the built-in datetime picker from your browser. 23 * Bulk edit post publication dates 24 * Shift dates forward or backward by days and/or hours 25 * Filter posts before editing: 26 * By category 27 * By author 28 * Paginated loading (25 posts per page) for improved database performance 29 * Uses native WordPress date and time formats 30 * Safe AJAX-based operations with nonce validation 31 * No front-end impact — admin-only tool 32 33 == How It Works == 34 35 1. Choose how you want to filter posts (by category or author) 36 2. Load posts in manageable pages of 25 items 37 3. Select the posts you want to edit 38 4. Adjust individual dates or apply bulk shifts 39 5. Save changes securely 40 41 Pagination ensures the plugin remains fast and reliable even on large sites with thousands of posts. 28 42 29 43 == Installation == 30 44 31 1. Upload the plugin folder `easy-bulk-date-editor` to the `/wp-content/plugins/` directory, or install it via **Plugins → Add New → Upload Plugin**. 32 2. Ensure the main plugin file is named `easy-bulk-date-editor.php` inside that folder. 33 3. Activate the plugin through the **Plugins** menu in WordPress. 34 4. In the admin menu, go to **Tools → Easy Bulk Date Editor**. 35 5. Select a category and click **Load posts**. 36 6. Edit the dates directly in the table or use **Shift selected by** to move dates in bulk, then click **Save changes**. 45 1. Upload the plugin folder to `/wp-content/plugins/` 46 2. Activate the plugin through the "Plugins" menu in WordPress 47 3. Navigate to the plugin page under the WordPress admin menu 48 4. Start editing post dates 49 50 == Frequently Asked Questions == 51 52 = Does this plugin edit posts across multiple pages at once? = 53 54 No. Changes apply only to the posts loaded on the current page. This is intentional to prevent accidental bulk changes and ensure data safety. 55 56 = Can I filter by both category and author at the same time? = 57 58 Not at this time. You can choose one filter type (category or author) before loading posts. 59 60 = Why is pagination limited to 25 posts? = 61 62 To protect WordPress performance and avoid large, expensive database queries. This limit can be adjusted by developers if needed. 63 64 = Does this plugin modify post content or metadata? = 65 66 No. It only updates the post publication date fields. 67 68 == Screenshots == 69 70 1. Filter selection (category or author) 71 2. Paginated post list with editable dates 72 3. Bulk date shift controls 37 73 38 74 == Changelog == 39 75 40 = 1.1.1 (2025-12-17) = 41 * Add plugin icons. 76 See changelog.md for detailed version history. 42 77 43 = 1.1 (2025-11-30) = 44 * Initial public release. 78 == Upgrade Notice == 45 79 46 == License == 47 48 This plugin is free for everyone! Since it's released under the GPL, you can use it free of charge on your personal or commercial site. 80 = 1.2 = 81 Introduces filtering by author and paginated post loading for better performance and scalability. -
easy-bulk-date-editor/trunk/bde.js
r3415608 r3424368 1 1 (function($){ 2 var EasyBDEState = { 3 filter_by: 'category', 4 filter_val: 0, 5 paged: 1, 6 max_num_pages: 1 7 }; 8 2 9 function renderTable(rows){ 3 10 if(!rows || rows.length === 0){ 4 11 $('#easybde_controls').hide(); 5 $('#easybde_table_wrap').html( '<p>'+EasyBDEData.i18n.no_posts+'</p>');12 $('#easybde_table_wrap').html(renderPagination() + '<p>'+EasyBDEData.i18n.no_posts+'</p>' + renderPagination()); 6 13 return; 7 14 } 8 15 $('#easybde_controls').show(); 9 16 var html = []; 17 html.push(renderPagination()); 10 18 html.push('<form id="easybde_form"><table class="wp-list-table widefat fixed striped"><thead><tr>'); 11 19 html.push('<th style="width:30px"><input type="checkbox" id="easybde_select_all" /></th>'); … … 21 29 }); 22 30 html.push('</tbody></table><p><button id="easybde_save" class="button button-primary">Save changes</button> <span id="easybde_result" style="margin-left:10px"></span></p></form>'); 31 html.push(renderPagination()); 23 32 $('#easybde_table_wrap').html(html.join('')); 33 } 34 35 function renderPagination(){ 36 var paged = EasyBDEState.paged || 1; 37 var max = EasyBDEState.max_num_pages || 1; 38 if(max <= 1){ 39 return ''; 40 } 41 42 var html = []; 43 html.push('<div class="easybde_pagination" style="margin:12px 0; display:flex; gap:8px; align-items:center; flex-wrap:wrap;">'); 44 html.push('<button type="button" class="button easybde_page" data-page="' + Math.max(1, paged - 1) + '" ' + (paged <= 1 ? 'disabled' : '') + '>« Prev</button>'); 45 46 // Compact page range around current (max 7 buttons) 47 var start = Math.max(1, paged - 3); 48 var end = Math.min(max, paged + 3); 49 if(end - start < 6){ 50 start = Math.max(1, end - 6); 51 end = Math.min(max, start + 6); 52 } 53 54 if(start > 1){ 55 html.push('<button type="button" class="button easybde_page" data-page="1">1</button>'); 56 if(start > 2){ 57 html.push('<span style="padding:0 4px;">…</span>'); 58 } 59 } 60 61 for(var p = start; p <= end; p++){ 62 if(p === paged){ 63 html.push('<span class="button button-primary" style="cursor:default;">' + p + '</span>'); 64 } else { 65 html.push('<button type="button" class="button easybde_page" data-page="' + p + '">' + p + '</button>'); 66 } 67 } 68 69 if(end < max){ 70 if(end < max - 1){ 71 html.push('<span style="padding:0 4px;">…</span>'); 72 } 73 html.push('<button type="button" class="button easybde_page" data-page="' + max + '">' + max + '</button>'); 74 } 75 76 html.push('<button type="button" class="button easybde_page" data-page="' + Math.min(max, paged + 1) + '" ' + (paged >= max ? 'disabled' : '') + '>Next »</button>'); 77 html.push('<span style="margin-left:6px; opacity:.8;">Page ' + paged + ' of ' + max + '</span>'); 78 html.push('</div>'); 79 return html.join(''); 24 80 } 25 81 … … 52 108 } 53 109 54 $(document).on('click', '#easybde_load', function(e){ 55 e.preventDefault(); 56 var cat = $('#easybde_category').val(); 110 function getFilterValue(){ 111 if(EasyBDEState.filter_by === 'author'){ 112 return parseInt($('#easybde_author').val() || 0, 10); 113 } 114 return parseInt($('#easybde_category').val() || 0, 10); 115 } 116 117 function loadPosts(page){ 118 EasyBDEState.paged = page || 1; 119 EasyBDEState.filter_by = $('#easybde_filter_by').val() || 'category'; 120 EasyBDEState.filter_val = getFilterValue(); 121 57 122 $('#easybde_status').text(EasyBDEData.i18n.loading); 58 $.post(EasyBDEData.ajax_url, {action:'easybde_load_posts', cat:cat, nonce:EasyBDEData.nonce}, function(resp){ 123 $.post(EasyBDEData.ajax_url, { 124 action: 'easybde_load_posts', 125 filter_by: EasyBDEState.filter_by, 126 filter_val: EasyBDEState.filter_val, 127 paged: EasyBDEState.paged, 128 nonce: EasyBDEData.nonce 129 }, function(resp){ 59 130 if(resp && resp.success){ 60 $('#easybde_status').text('Loaded ' + resp.data.count + ' posts'); 131 var meta = (resp.data && resp.data.meta) ? resp.data.meta : {}; 132 EasyBDEState.paged = meta.paged || EasyBDEState.paged; 133 EasyBDEState.max_num_pages = meta.max_num_pages || 1; 134 135 var total = meta.found_posts || 0; 136 $('#easybde_status').text('Loaded ' + (resp.data.count || 0) + ' posts (page ' + EasyBDEState.paged + ' of ' + EasyBDEState.max_num_pages + ', total ' + total + ')'); 61 137 renderTable(resp.data.rows); 62 138 } else { … … 64 140 } 65 141 }); 142 } 143 144 $(document).on('change', '#easybde_filter_by', function(){ 145 var by = $(this).val(); 146 if(by === 'author'){ 147 $('#easybde_filter_category_wrap').hide(); 148 $('#easybde_filter_author_wrap').show(); 149 } else { 150 $('#easybde_filter_author_wrap').hide(); 151 $('#easybde_filter_category_wrap').show(); 152 } 153 }); 154 155 $(document).on('click', '#easybde_load', function(e){ 156 e.preventDefault(); 157 loadPosts(1); 158 }); 159 160 $(document).on('click', '.easybde_page', function(e){ 161 e.preventDefault(); 162 var page = parseInt($(this).data('page') || 1, 10); 163 if(!page || page < 1){ 164 page = 1; 165 } 166 loadPosts(page); 66 167 }); 67 168 -
easy-bulk-date-editor/trunk/easy-bulk-date-editor.php
r3421759 r3424368 3 3 * Plugin Name: Easy Bulk Date Editor 4 4 * Description: Bulk edit post publish dates by category from a single admin screen, including an optional "shift by" tool. 5 * Version: 1. 1.15 * Version: 1.2 6 6 * Author: Andre Moura 7 7 * Author URI: https://www.andremoura.com … … 27 27 * @var int 28 28 */ 29 protected $max_posts = 500;29 protected $max_posts = 25; 30 30 31 31 /** … … 105 105 <p><?php esc_html_e( 'Filter posts and edit their publish dates in bulk. Remember to back up your database before performing bulk changes.', 'easy-bulk-date-editor' ); ?></p> 106 106 107 <div id="easybde_filter"> 108 <label for="easybde_category"> 109 <?php esc_html_e( 'Category:', 'easy-bulk-date-editor' ); ?> 110 </label> 111 <?php 112 wp_dropdown_categories( 113 array( 114 'show_option_all' => __( 'All categories', 'easy-bulk-date-editor' ), 115 'hide_empty' => 0, 116 'name' => 'easybde_category', 117 'id' => 'easybde_category', 118 ) 119 ); 120 ?> 121 <button class="button button-secondary" id="easybde_load"> 122 <?php esc_html_e( 'Load posts', 'easy-bulk-date-editor' ); ?> 123 </button> 124 <span id="easybde_status" style="margin-left:10px;"></span> 125 </div> 107 <div id="easybde_filter"> 108 <label for="easybde_filter_by"> 109 <?php esc_html_e( 'Filter by:', 'easy-bulk-date-editor' ); ?> 110 </label> 111 <select id="easybde_filter_by" name="easybde_filter_by" style="min-width:160px;"> 112 <option value="category"><?php esc_html_e( 'Category', 'easy-bulk-date-editor' ); ?></option> 113 <option value="author"><?php esc_html_e( 'Author', 'easy-bulk-date-editor' ); ?></option> 114 </select> 115 116 <span id="easybde_filter_category_wrap" style="margin-left:10px;"> 117 <label for="easybde_category" class="screen-reader-text"> 118 <?php esc_html_e( 'Category', 'easy-bulk-date-editor' ); ?> 119 </label> 120 <?php 121 wp_dropdown_categories( 122 array( 123 'show_option_all' => __( 'All categories', 'easy-bulk-date-editor' ), 124 'hide_empty' => 0, 125 'name' => 'easybde_category', 126 'id' => 'easybde_category', 127 ) 128 ); 129 ?> 130 </span> 131 132 <span id="easybde_filter_author_wrap" style="margin-left:10px; display:none;"> 133 <label for="easybde_author" class="screen-reader-text"> 134 <?php esc_html_e( 'Author', 'easy-bulk-date-editor' ); ?> 135 </label> 136 <?php 137 wp_dropdown_users( 138 array( 139 'name' => 'easybde_author', 140 'id' => 'easybde_author', 141 'show_option_all' => __( 'All authors', 'easy-bulk-date-editor' ), 142 'role__in' => array( 'administrator', 'editor', 'author', 'contributor' ), 143 'orderby' => 'display_name', 144 'order' => 'ASC', 145 'include_selected' => true, 146 ) 147 ); 148 ?> 149 </span> 150 151 <button class="button button-secondary" id="easybde_load" style="margin-left:10px;"> 152 <?php esc_html_e( 'Load posts', 'easy-bulk-date-editor' ); ?> 153 </button> 154 <span id="easybde_status" style="margin-left:10px;"></span> 155 </div> 156 126 157 127 158 <div id="easybde_controls" style="margin-top:15px; display:none;"> … … 154 185 */ 155 186 public function easybde_ajax_load_posts() { 187 check_ajax_referer( 'easybde_nonce', 'nonce' ); 188 189 if ( ! current_user_can( 'edit_posts' ) ) { 190 wp_send_json_error( 191 array( 192 'message' => __( 'You do not have permission to edit posts.', 'easy-bulk-date-editor' ), 193 ) 194 ); 195 } 196 197 $filter_by = filter_input( INPUT_POST, 'filter_by', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); 198 $filter_by = is_string( $filter_by ) ? sanitize_key( $filter_by ) : 'category'; 199 if ( ! in_array( $filter_by, array( 'category', 'author' ), true ) ) { 200 $filter_by = 'category'; 201 } 202 203 $filter_val = filter_input( INPUT_POST, 'filter_val', FILTER_SANITIZE_NUMBER_INT ); 204 $filter_val = ( null === $filter_val ) ? 0 : (int) $filter_val; 205 206 $paged = filter_input( INPUT_POST, 'paged', FILTER_SANITIZE_NUMBER_INT ); 207 $paged = ( null === $paged || (int) $paged <= 0 ) ? 1 : (int) $paged; 208 209 $args = array( 210 'post_type' => 'post', 211 'posts_per_page' => $this->per_page, 212 'orderby' => 'date', 213 'order' => 'DESC', 214 'paged' => $paged, 215 ); 216 217 if ( 'category' === $filter_by && $filter_val > 0 ) { 218 $args['cat'] = $filter_val; 219 } 220 221 if ( 'author' === $filter_by && $filter_val > 0 ) { 222 $args['author'] = $filter_val; 223 } 224 225 $query = new WP_Query( $args ); 226 $rows = array(); 227 228 if ( $query->have_posts() ) { 229 foreach ( $query->posts as $post ) { 230 $post_id = (int) $post->ID; 231 232 // Datetime-local expects "YYYY-MM-DDTHH:MM". 233 $dt = get_post_datetime( $post ); 234 if ( $dt instanceof DateTimeInterface ) { 235 $value = $dt->format( 'Y-m-d\TH:i' ); 236 } else { 237 $value = ''; 238 } 239 240 $rows[] = array( 241 'ID' => $post_id, 242 'title' => get_the_title( $post_id ), 243 'permalink' => get_edit_post_link( $post_id, '' ), 244 'post_date_display' => get_the_time( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $post_id ), 245 'post_date' => $value, 246 ); 247 } 248 } 249 250 wp_send_json_success( 251 array( 252 'count' => count( $rows ), 253 'rows' => $rows, 254 'meta' => array( 255 'paged' => (int) $paged, 256 'per_page' => (int) $this->per_page, 257 'found_posts' => (int) $query->found_posts, 258 'max_num_pages' => (int) $query->max_num_pages, 259 'filter_by' => $filter_by, 260 'filter_val' => (int) $filter_val, 261 ), 262 ) 263 ); 264 } 265 266 267 /** 268 * AJAX handler to save new dates. 269 */ 270 public function easybde_ajax_save_dates() { 156 271 check_ajax_referer( 'easybde_nonce', 'nonce' ); 157 272 … … 164 279 } 165 280 166 $cat = filter_input( INPUT_POST, 'cat', FILTER_SANITIZE_NUMBER_INT );167 if ( null === $cat ) {168 $cat = 0;169 }170 171 $args = array(172 'post_type' => 'post',173 'posts_per_page' => $this->max_posts,174 'orderby' => 'date',175 'order' => 'DESC',176 );177 178 if ( $cat > 0 ) {179 $args['cat'] = (int) $cat;180 }181 182 $query = new WP_Query( $args );183 $rows = array();184 185 if ( $query->have_posts() ) {186 foreach ( $query->posts as $post ) {187 $post_id = (int) $post->ID;188 189 // Datetime-local expects "YYYY-MM-DDTHH:MM".190 $dt = get_post_datetime( $post );191 if ( $dt instanceof DateTimeInterface ) {192 $value = $dt->format( 'Y-m-d\TH:i' );193 } else {194 $value = '';195 }196 197 $rows[] = array(198 'ID' => $post_id,199 'title' => get_the_title( $post_id ),200 'permalink' => get_edit_post_link( $post_id, '' ),201 'post_date_display' => get_the_time( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $post_id ),202 'post_date' => $value,203 );204 }205 }206 207 wp_send_json_success(208 array(209 'count' => count( $rows ),210 'rows' => $rows,211 )212 );213 }214 215 /**216 * AJAX handler to save new dates.217 */218 public function easybde_ajax_save_dates() {219 check_ajax_referer( 'easybde_nonce', 'nonce' );220 221 if ( ! current_user_can( 'edit_posts' ) ) {222 wp_send_json_error(223 array(224 'message' => __( 'You do not have permission to edit posts.', 'easy-bulk-date-editor' ),225 )226 );227 }228 229 281 // Get changes from POST as an array, without directly touching $_POST. 230 282 $raw_changes = filter_input( -
easy-bulk-date-editor/trunk/readme.txt
r3421759 r3424368 1 1 === Easy Bulk Date Editor === 2 Contributors: andremoura 3 Requires at least: 4.6 4 Tested up to: 6.9 5 Stable tag: 1.1.1 6 Requires PHP: 7.2 2 Contributors: andreluizmoura 3 Tags: posts, bulk edit, dates, scheduling, wordpress admin 4 Requires at least: 5.8 5 Tested up to: 6.6 6 Requires PHP: 7.4 7 Author URI: https://www.andremoura.com 8 Plugin URI: https://wordpress.andremoura.com 9 Stable tag: 1.2 7 10 License: GPLv2 or later 8 License URI: http ://www.gnu.org/licenses/gpl-2.0.html11 License URI: https://www.gnu.org/licenses/gpl-2.0.html 9 12 10 Bulk edit post publish dates by author or category from a single screen.13 Bulk edit WordPress post dates safely and efficiently, now with filtering by category or author and paginated loading for better performance. 11 14 12 15 == Description == 13 16 14 Easy Bulk Date Editor lets you update post publish dates in bulk from a single, focused admin screen.17 Easy Bulk Date Editor is a lightweight WordPress admin plugin that allows editors and administrators to bulk edit post publication dates with precision and control. 15 18 16 You can: 17 * Filter posts by category. 18 * Load up to a few hundred posts at once. 19 * Edit individual publish dates directly in a table. 20 * Select posts and shift all their dates by a number of days or hours. 19 The plugin was designed to avoid common performance pitfalls of bulk actions by loading posts incrementally and applying changes only to the selected rows. 21 20 22 This is especially useful when: 23 * You are migrating content and need to adjust dates. 24 * An author’s posts need to be moved forward or backward in time. 25 * You want to clean up an old content calendar without opening each post one by one. 21 ### Key Features 26 22 27 The plugin works with standard WordPress posts and uses the built-in datetime picker from your browser. 23 * Bulk edit post publication dates 24 * Shift dates forward or backward by days and/or hours 25 * Filter posts before editing: 26 * By category 27 * By author 28 * Paginated loading (25 posts per page) for improved database performance 29 * Uses native WordPress date and time formats 30 * Safe AJAX-based operations with nonce validation 31 * No front-end impact — admin-only tool 32 33 == How It Works == 34 35 1. Choose how you want to filter posts (by category or author) 36 2. Load posts in manageable pages of 25 items 37 3. Select the posts you want to edit 38 4. Adjust individual dates or apply bulk shifts 39 5. Save changes securely 40 41 Pagination ensures the plugin remains fast and reliable even on large sites with thousands of posts. 28 42 29 43 == Installation == 30 44 31 1. Upload the plugin folder `easy-bulk-date-editor` to the `/wp-content/plugins/` directory, or install it via **Plugins → Add New → Upload Plugin**. 32 2. Ensure the main plugin file is named `easy-bulk-date-editor.php` inside that folder. 33 3. Activate the plugin through the **Plugins** menu in WordPress. 34 4. In the admin menu, go to **Tools → Easy Bulk Date Editor**. 35 5. Select a category and click **Load posts**. 36 6. Edit the dates directly in the table or use **Shift selected by** to move dates in bulk, then click **Save changes**. 45 1. Upload the plugin folder to `/wp-content/plugins/` 46 2. Activate the plugin through the "Plugins" menu in WordPress 47 3. Navigate to the plugin page under the WordPress admin menu 48 4. Start editing post dates 49 50 == Frequently Asked Questions == 51 52 = Does this plugin edit posts across multiple pages at once? = 53 54 No. Changes apply only to the posts loaded on the current page. This is intentional to prevent accidental bulk changes and ensure data safety. 55 56 = Can I filter by both category and author at the same time? = 57 58 Not at this time. You can choose one filter type (category or author) before loading posts. 59 60 = Why is pagination limited to 25 posts? = 61 62 To protect WordPress performance and avoid large, expensive database queries. This limit can be adjusted by developers if needed. 63 64 = Does this plugin modify post content or metadata? = 65 66 No. It only updates the post publication date fields. 67 68 == Screenshots == 69 70 1. Filter selection (category or author) 71 2. Paginated post list with editable dates 72 3. Bulk date shift controls 37 73 38 74 == Changelog == 39 75 40 = 1.1.1 (2025-12-17) = 41 * Add plugin icons. 76 See changelog.md for detailed version history. 42 77 43 = 1.1 (2025-11-30) = 44 * Initial public release. 78 == Upgrade Notice == 45 79 46 == License == 47 48 This plugin is free for everyone! Since it's released under the GPL, you can use it free of charge on your personal or commercial site. 80 = 1.2 = 81 Introduces filtering by author and paginated post loading for better performance and scalability.
Note: See TracChangeset
for help on using the changeset viewer.