Changeset 3367871
- Timestamp:
- 09/25/2025 02:05:08 PM (6 months ago)
- Location:
- btw-importer
- Files:
-
- 18 added
- 5 edited
-
tags/2.1.0 (added)
-
tags/2.1.0/LICENSE (added)
-
tags/2.1.0/assets (added)
-
tags/2.1.0/assets/screenshot-1.png (added)
-
tags/2.1.0/assets/screenshot-2.png (added)
-
tags/2.1.0/assets/screenshot-3.png (added)
-
tags/2.1.0/assets/screenshot-4.png (added)
-
tags/2.1.0/btw-importer.js (added)
-
tags/2.1.0/btw-importer.php (added)
-
tags/2.1.0/changelog.md (added)
-
tags/2.1.0/importer.php (added)
-
tags/2.1.0/index.php (added)
-
tags/2.1.0/languages (added)
-
tags/2.1.0/readme.md (added)
-
tags/2.1.0/readme.txt (added)
-
tags/2.1.0/redirect-log.php (added)
-
tags/2.1.0/redirect.php (added)
-
trunk/btw-importer.php (modified) (2 diffs)
-
trunk/changelog.md (modified) (1 diff)
-
trunk/importer.php (added)
-
trunk/readme.md (modified) (3 diffs)
-
trunk/readme.txt (modified) (4 diffs)
-
trunk/redirect-log.php (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
btw-importer/trunk/btw-importer.php
r3359514 r3367871 1 1 <?php 2 2 /* 3 Plugin Name: BtW Importer 3 Plugin Name: BtW Importer - Blogger to WordPress Importer 4 4 Plugin URI: https://github.com/mnasikin/btw-importer 5 5 Description: Simple yet powerful plugin to Migrate Blogger to WordPress in one click. Import .atom from Google Takeout and the plugin will scan & download first image, replace URLs, set featured image, show live progress. 6 Version: 2. 0.06 Version: 2.1.0 7 7 Author: Nasikin 8 8 Author URI: https://github.com/mnasikin/ … … 15 15 */ 16 16 17 class Btw_Importer { 18 private $downloaded_images = []; // cache 19 20 public function __construct() { 21 add_action('admin_menu', [$this, 'add_menu']); 22 add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts']); 23 add_action('wp_ajax_btw_importer_prepare_import', [$this, 'ajax_prepare_import']); 24 add_action('wp_ajax_btw_importer_import_single_post', [$this, 'ajax_import_single_post']); 25 } 26 27 public function add_menu() { // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 28 add_menu_page( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 29 'BtW Importer', 'BtW Importer', 'manage_options', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 30 'btw-importer', [$this, 'import_page'], 'dashicons-upload' // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 31 ); 32 } 33 34 public function enqueue_scripts($hook) { 35 if ($hook !== 'toplevel_page_btw-importer') return; 36 wp_enqueue_script('btw-importer', plugin_dir_url(__FILE__).'btw-importer.js', ['jquery'], '1.2.2', true); 37 wp_localize_script('btw-importer', 'btwImporter', [ 38 'ajaxUrl' => admin_url('admin-ajax.php'), 39 'nonce' => wp_create_nonce('btw_importer_importer_nonce') 40 ]); 41 } 42 43 public function import_page() { 44 echo '<div class="wrap"> 45 <h1>BtW Importer</h1> 46 <p>A powerful yet simple migration tool, BtW Importer helps you seamlessly transfer posts, images, and formatting from Blogger (Blogspot) to WordPress. Don't forget to share this plugin if you found it's usefull</p> 47 <div id="importNotice" style="margin:20px;"> 48 <h2>⚠️ Please Read Before Importing ⚠️</h2> 49 <ul> 50 <li>🛑 ️This plugin doesn't overwrite existing posts with the same name. If you've previously used an importer, it's recommended to manually delete the previously imported content.</li> 51 <li>🛑 301 redirects only work if you previously used a custom domain on Blogspot and you're moving that domain to WordPress.</li> 52 <li>🛑 Make sure not to leave this page while the process is underway, or the import will stop, and you'll need to start from the beginning.</li> 53 <li>🛑 301 redirects work if this plugin is active and you have already run the importer.</li> 54 <li>🛑 Only image from Google/Blogspot will be downloaded.</li> 55 <li>🛑 Be sure to manually check your content after the import process is complete.</li> 56 </ul> 57 <input type="checkbox" id="agreeNotice"> 58 <label for="agreeNotice"> 59 I've read all of them and I want to start the importer. 60 </label> 61 </div> 62 <input type="file" id="atomFile" accept=".xml,.atom" /> 63 <button id="startImport" class="button button-primary" disabled>Start Import</button><br> 64 <label for="atomFile">Accepted File: .xml,.atom</label> 65 <hr> 66 <div id="importOverlay" style="display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.7); color: #fff; font-size: 20px; z-index: 9999; text-align: center; padding-top: 20%;"> 67 ⚠ Import in progress... Please don’t close, reload, or navigate away. 68 </div> 69 <div id="progress" style="margin-top:20px; max-height:100vh; max-width;100%; overflow:auto; background:#fff; padding:10px; border:1px solid #ddd;"></div> 70 </div>'; 71 } 72 73 public function ajax_prepare_import() { 74 check_ajax_referer('btw_importer_importer_nonce', 'nonce'); 75 $atom_content = isset($_POST['atom_content']) ? wp_unslash($_POST['atom_content']) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized 76 if (!$atom_content) wp_send_json_error('No data received.'); 77 78 libxml_use_internal_errors(true); 79 $xml = simplexml_load_string($atom_content); 80 if (!$xml) wp_send_json_error('Failed to parse XML.'); 81 82 $posts = []; 83 foreach ($xml->entry as $entry) { 84 $bloggerType = strtolower((string)$entry->children('blogger', true)->type); 85 $post_type = ($bloggerType === 'page') ? 'page' : 'post'; 86 87 $title = sanitize_text_field((string)$entry->title); 88 $content = (string)$entry->content; 89 $author = isset($entry->author->name) ? sanitize_text_field((string)$entry->author->name) : ''; 90 91 $published_raw = (string)$entry->published; 92 $date_gmt = gmdate('Y-m-d H:i:s', strtotime($published_raw)); 93 $date_local = get_date_from_gmt($date_gmt, 'Y-m-d H:i:s'); 94 95 // get categories 96 $categories = []; 97 foreach ($entry->category as $cat) { 98 $term = (string)$cat['term']; 99 if ($term && strpos($term, '#') !== 0) { 100 $categories[] = sanitize_text_field($term); 101 } 102 } 103 104 // get old permalink from <blogger:filename> 105 $filename = (string)$entry->children('blogger', true)->filename; 106 $filename = trim($filename); 107 108 $posts[] = [ 109 'title' => $title, 110 'content' => $content, 111 'author' => $author, 112 'post_type' => $post_type, 113 'date' => $date_local, 114 'date_gmt' => $date_gmt, 115 'categories' => $categories, 116 'filename' => $filename 117 ]; 118 } 119 120 wp_send_json_success(['posts' => $posts]); 121 } 122 123 public function ajax_import_single_post() { 124 check_ajax_referer('btw_importer_importer_nonce', 'nonce'); 125 $raw_post = isset($_POST['post']) ? wp_unslash($_POST['post']) : []; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized 126 if (!$raw_post) wp_send_json_error('Missing post data.'); 127 128 $title = sanitize_text_field($raw_post['title'] ?? ''); 129 $author = sanitize_text_field($raw_post['author'] ?? ''); 130 $post_type = in_array($raw_post['post_type'], ['post','page']) ? $raw_post['post_type'] : 'post'; 131 $date = sanitize_text_field($raw_post['date'] ?? ''); 132 $date_gmt = sanitize_text_field($raw_post['date_gmt'] ?? ''); 133 $categories = $raw_post['categories'] ?? []; 134 $filename = sanitize_text_field($raw_post['filename'] ?? ''); 135 $allowed_tags = wp_kses_allowed_html('post'); 136 $allowed_tags['iframe'] = ['src'=>true,'width'=>true,'height'=>true,'frameborder'=>true,'allowfullscreen'=>true,'class'=>true,'youtube-src-id'=>true]; 137 $content = wp_kses($raw_post['content'] ?? '', $allowed_tags); 138 139 $msgs = []; 140 141 $author_id = 1; 142 if ($author) { 143 $user = get_user_by('login', sanitize_user($author, true)); 144 if ($user) $author_id = $user->ID; 145 } 146 147 require_once ABSPATH.'wp-admin/includes/image.php'; 148 require_once ABSPATH.'wp-admin/includes/file.php'; 149 require_once ABSPATH.'wp-admin/includes/media.php'; 150 151 $post_id = wp_insert_post([ 152 'post_title' => $title, 153 'post_content' => $content, 154 'post_status' => 'publish', 155 'post_date' => $date, 156 'post_date_gmt' => $date_gmt, 157 'post_author' => $author_id, 158 'post_type' => $post_type 159 ]); 160 161 if (is_wp_error($post_id)) wp_send_json_error('❌ Failed to insert: '.$title); 162 163 // add redirect meta & log redirect creation 164 if ($filename) { 165 if ($filename[0] !== '/') $filename = '/' . $filename; 166 add_post_meta($post_id, '_btw_importer_old_permalink', $filename, true); 167 $new_url = get_permalink($post_id); 168 $msgs[] = '✅ Finished create 301 redirect: '.$filename.' → '.$new_url; 169 } 170 171 // create categories 172 if (!empty($categories) && $post_type === 'post') { 173 $cat_ids = []; 174 foreach ($categories as $cat_name) { 175 $term = term_exists($cat_name, 'category'); 176 if (!$term) { 177 $new_term = wp_create_category($cat_name); 178 if (!is_wp_error($new_term)) { 179 $cat_ids[] = $new_term; 180 $msgs[] = '✅ Created category: '.$cat_name; 181 } 182 } else { 183 $cat_ids[] = $term['term_id']; 184 $msgs[] = '✅ Using category: '.$cat_name; 185 } 186 } 187 if (!empty($cat_ids)) wp_set_post_categories($post_id, $cat_ids); 188 } 189 190 // find unique blogger/googleusercontent images by basename (after /sXXX/) 191 preg_match_all('/https?:\/\/[^"\']+\.(jpg|jpeg|png|gif|webp|bmp|svg)/i', $content, $matches); 192 $image_by_basename = []; 193 foreach (array_unique($matches[0]) as $img_url) { 194 if (!preg_match('/(blogspot|googleusercontent)/i', $img_url)) continue; 195 196 if (preg_match('#/s\d+/(.+)$#', $img_url, $m)) { 197 $basename = $m[1]; 198 } else { 199 $basename = basename(wp_parse_url($img_url, PHP_URL_PATH)); 200 } 201 202 if (!isset($image_by_basename[$basename])) { 203 $image_by_basename[$basename] = $img_url; 204 } else { 205 // prefer bigger /sXXX/ number 206 if (preg_match('#/s(\d+)/#', $img_url, $m1) && preg_match('#/s(\d+)/#', $image_by_basename[$basename], $m2)) { 207 if ((int)$m1[1] > (int)$m2[1]) { 208 $image_by_basename[$basename] = $img_url; 209 } 210 } 211 } 212 } 213 214 $first_media_id = null; 215 foreach ($image_by_basename as $img_url) { 216 if (isset($this->downloaded_images[$img_url])) { 217 $new_url = $this->downloaded_images[$img_url]; 218 $content = str_replace($img_url, $new_url, $content); 219 $msgs[]='✅ Used cached: '.$new_url; 220 continue; 221 } 222 223 $msgs[]='⏳ Downloading: '.$img_url; 224 $tmp = download_url($img_url); 225 if (is_wp_error($tmp)) { $msgs[]='⚠ Failed to download'; continue; } 226 227 $file = ['name'=>basename(wp_parse_url($img_url, PHP_URL_PATH)),'tmp_name'=>$tmp]; 228 $media_id = media_handle_sideload($file,$post_id); 229 if (is_wp_error($media_id)) { wp_delete_file($tmp); $msgs[]='⚠ Failed to attach'; continue; } 230 231 $new_url = wp_get_attachment_url($media_id); 232 if ($new_url) { 233 $this->downloaded_images[$img_url] = $new_url; 234 $content = str_replace($img_url, $new_url, $content); 235 $msgs[]='✅ Replaced: '.$img_url.' → '.$new_url; 236 if (!$first_media_id) $first_media_id = $media_id; 237 } 238 } 239 240 wp_update_post(['ID'=>$post_id,'post_content'=>$content]); 241 if ($first_media_id) { 242 set_post_thumbnail($post_id, $first_media_id); 243 $msgs[]='⭐ Successfully Set featured image'; 244 } 245 246 $msgs[]='✅ Finished '.$post_type.': '.$title; 247 wp_send_json_success($msgs); 248 } 17 function btw_importer_include_files() { 18 require_once plugin_dir_path(__FILE__) . 'importer.php'; 19 require_once plugin_dir_path(__FILE__) . 'redirect.php'; 20 require_once plugin_dir_path(__FILE__) . 'redirect-log.php'; 249 21 } 250 251 new Btw_Importer(); 252 require_once plugin_dir_path(__FILE__) . 'redirect.php'; 253 require_once plugin_dir_path(__FILE__) . 'redirect-log.php'; 22 add_action('plugins_loaded', 'btw_importer_include_files'); -
btw-importer/trunk/changelog.md
r3359514 r3367871 7 7 8 8 ## 🧾 Changelog 9 10 ### 2.1.0 11 - Fix draft and deleted content on .atom imported as published in WordPress 9 12 10 13 ### 2.0.0 -
btw-importer/trunk/readme.md
r3359514 r3367871 1 [](https:// github.com/mnasikin/btw-importer/releases/tag/v2.0.0)1 [](https://wordpress.org/plugins/btw-importer) 2 2 3 3 # BtW Importer … … 63 63 ## 🧾 Changelog 64 64 65 ### 2.1.0 66 - Draft, Published, Trash Post in Blogspot now keep as Draft, Published, Trash in WordPress 67 65 68 ### 2.0.0 66 69 🔥 Major Update 🔥 … … 85 88 86 89 ### 2.0.0 87 88 Major Update! This release adds many features for your import process including add notice before import, add warning on leaving page while import in process, add redirect 301 from old blogspot permalink, add redirect log and clear redirect log, sync post and page published date, add or use category based on .atom file, only download image hosted on blogspot/google, only download original image to avoid duplicated image, security update, and some UI change. 90 Please check the changelog tab to check what's new. -
btw-importer/trunk/readme.txt
r3359514 r3367871 1 === BtW Importer ===1 === BtW Importer - Blogger to WordPress Importer === 2 2 Contributors: silversh 3 3 Tags: blogger, blogspot, blogger importer, blogspot importer, import blogspot 4 Requires at least: 6.8. 14 Requires at least: 6.8.0 5 5 Tested up to: 6.8 6 Stable tag: 2. 0.06 Stable tag: 2.1.0 7 7 Requires PHP: 7.4 8 8 License: MIT … … 51 51 * PHP 7.4 or later 52 52 * cURL PHP Extension 53 * `SimpleXML` PHP Extension 53 54 * `allow_url_fopen` enabled 54 55 * Writable `wp-content/uploads` folder (default setting already meets this) … … 60 61 61 62 == Screenshots == 62 1. Preview of the import process interface 63 1. Importer Page 64 2. Import Process 65 3. Done Importing 66 4. Redirect Log 63 67 64 68 == Changelog == 69 = 2.1.0 = 70 * Draft, Published, Trash Post in Blogspot now keep as Draft, Published, Trash in WordPress 71 72 65 73 = 2.0.0 = 66 74 🔥 Major Update 🔥 … … 77 85 == Upgrade Notice == 78 86 = 2.0.0 = 79 Major Update! Please check the Changelog for more information87 Please check the changelog tab to check what's new. -
btw-importer/trunk/redirect-log.php
r3359514 r3367871 2 2 if (!defined('ABSPATH')) exit; 3 3 4 class Btw_Importer_Redirect_Log {4 class btw_importer_Redirect_Log { 5 5 public function __construct() { 6 add_action('admin_menu', [$this, ' add_redirect_log_menu']);7 add_action('admin_init', [$this, ' handle_clear_log']);6 add_action('admin_menu', [$this, 'btw_importer_add_redirect_log_menu']); 7 add_action('admin_init', [$this, 'btw_importer_handle_clear_log']); 8 8 } 9 9 10 public function add_redirect_log_menu() {10 public function btw_importer_add_redirect_log_menu() { 11 11 add_submenu_page( 12 12 'btw-importer', … … 15 15 'manage_options', 16 16 'btw-redirect-log', 17 [$this, ' render_redirect_log_page']17 [$this, 'btw_importer_render_redirect_log_page'] 18 18 ); 19 19 } 20 20 21 public function handle_clear_log() {21 public function btw_importer_handle_clear_log() { 22 22 if (!current_user_can('manage_options')) return; 23 23 … … 35 35 } 36 36 37 public function render_redirect_log_page() {37 public function btw_importer_render_redirect_log_page() { 38 38 global $wpdb; 39 39 … … 43 43 $orderby = sanitize_sql_orderby((string) filter_input(INPUT_GET, 'orderby')); 44 44 $order = (strtoupper((string) filter_input(INPUT_GET, 'order')) === 'ASC') ? 'ASC' : 'DESC'; 45 // Cache removed to fix SQL preparation error45 $post_type_filter = sanitize_text_field((string) filter_input(INPUT_GET, 'post_type', FILTER_SANITIZE_FULL_SPECIAL_CHARS)); 46 46 47 48 $allowed_orderby = ['p.post_date', 'p.post_type']; 47 $allowed_orderby = ['post_date', 'post_type']; 49 48 if (!in_array($orderby, $allowed_orderby, true)) { 50 $orderby = 'p .post_date';49 $orderby = 'post_date'; 51 50 } 52 51 53 52 $per_page = 25; 54 53 $offset = ($paged - 1) * $per_page; 54 55 // Get distinct post types for filter dropdown 56 $post_types = $wpdb->get_col( $wpdb->prepare("SELECT DISTINCT p.post_type FROM {$wpdb->postmeta} pm JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE pm.meta_key = %s ORDER BY p.post_type", '_btw_importer_old_permalink') ); 55 57 56 58 echo '<div class="wrap">'; … … 60 62 $clear_nonce = wp_create_nonce('btw_importer_clear_log'); 61 63 62 // Search + clear form64 // Search + filter form 63 65 echo '<form method="get" style="margin-bottom:10px; display:inline-block; margin-right:10px;"> 64 66 <input type="hidden" name="page" value="btw-redirect-log" /> 65 67 <input type="search" name="s" placeholder="Search slug..." value="' . esc_attr($search) . '" /> 66 <input type="submit" class="button" value="Search" /> 68 <select name="post_type"> 69 <option value="">All Post Types</option>'; 70 foreach ($post_types as $type) { 71 echo '<option value="' . esc_attr($type) . '" ' . selected($post_type_filter, $type, false) . '>' . esc_html($type) . '</option>'; 72 } 73 echo '</select> 74 <input type="submit" class="button" value="Filter" /> 67 75 </form>'; 68 76 … … 72 80 </form>'; 73 81 74 // Build query safely 75 $params = ['_btw_importer_old_permalink']; 76 if ($search) { 77 if ($orderby === 'p.post_date' && $order === 'ASC') { 78 $results = $wpdb->get_results( $wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS p.ID, p.post_type, p.post_date, pm.meta_value as old_slug FROM {$wpdb->postmeta} pm JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE pm.meta_key = %s AND pm.meta_value LIKE %s ORDER BY p.post_date ASC LIMIT %d OFFSET %d", ['_btw_importer_old_permalink', '%' . $wpdb->esc_like($search) . '%', $per_page, $offset]) ); 79 } elseif ($orderby === 'p.post_date' && $order === 'DESC') { 80 $results = $wpdb->get_results( $wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS p.ID, p.post_type, p.post_date, pm.meta_value as old_slug FROM {$wpdb->postmeta} pm JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE pm.meta_key = %s AND pm.meta_value LIKE %s ORDER BY p.post_date DESC LIMIT %d OFFSET %d", ['_btw_importer_old_permalink', '%' . $wpdb->esc_like($search) . '%', $per_page, $offset]) ); 81 } elseif ($orderby === 'p.post_type' && $order === 'ASC') { 82 $results = $wpdb->get_results( $wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS p.ID, p.post_type, p.post_date, pm.meta_value as old_slug FROM {$wpdb->postmeta} pm JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE pm.meta_key = %s AND pm.meta_value LIKE %s ORDER BY p.post_type ASC LIMIT %d OFFSET %d", ['_btw_importer_old_permalink', '%' . $wpdb->esc_like($search) . '%', $per_page, $offset]) ); 83 } elseif ($orderby === 'p.post_type' && $order === 'DESC') { 84 $results = $wpdb->get_results( $wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS p.ID, p.post_type, p.post_date, pm.meta_value as old_slug FROM {$wpdb->postmeta} pm JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE pm.meta_key = %s AND pm.meta_value LIKE %s ORDER BY p.post_type DESC LIMIT %d OFFSET %d", ['_btw_importer_old_permalink', '%' . $wpdb->esc_like($search) . '%', $per_page, $offset]) ); 85 } else { 86 $results = $wpdb->get_results( $wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS p.ID, p.post_type, p.post_date, pm.meta_value as old_slug FROM {$wpdb->postmeta} pm JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE pm.meta_key = %s AND pm.meta_value LIKE %s ORDER BY p.post_date DESC LIMIT %d OFFSET %d", ['_btw_importer_old_permalink', '%' . $wpdb->esc_like($search) . '%', $per_page, $offset]) ); 87 } 88 } else { 89 if ($orderby === 'p.post_date' && $order === 'ASC') { 90 $results = $wpdb->get_results( $wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS p.ID, p.post_type, p.post_date, pm.meta_value as old_slug FROM {$wpdb->postmeta} pm JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE pm.meta_key = %s ORDER BY p.post_date ASC LIMIT %d OFFSET %d", ['_btw_importer_old_permalink', $per_page, $offset]) ); 91 } elseif ($orderby === 'p.post_date' && $order === 'DESC') { 92 $results = $wpdb->get_results( $wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS p.ID, p.post_type, p.post_date, pm.meta_value as old_slug FROM {$wpdb->postmeta} pm JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE pm.meta_key = %s ORDER BY p.post_date DESC LIMIT %d OFFSET %d", ['_btw_importer_old_permalink', $per_page, $offset]) ); 93 } elseif ($orderby === 'p.post_type' && $order === 'ASC') { 94 $results = $wpdb->get_results( $wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS p.ID, p.post_type, p.post_date, pm.meta_value as old_slug FROM {$wpdb->postmeta} pm JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE pm.meta_key = %s ORDER BY p.post_type ASC LIMIT %d OFFSET %d", ['_btw_importer_old_permalink', $per_page, $offset]) ); 95 } elseif ($orderby === 'p.post_type' && $order === 'DESC') { 96 $results = $wpdb->get_results( $wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS p.ID, p.post_type, p.post_date, pm.meta_value as old_slug FROM {$wpdb->postmeta} pm JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE pm.meta_key = %s ORDER BY p.post_type DESC LIMIT %d OFFSET %d", ['_btw_importer_old_permalink', $per_page, $offset]) ); 97 } else { 98 $results = $wpdb->get_results( $wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS p.ID, p.post_type, p.post_date, pm.meta_value as old_slug FROM {$wpdb->postmeta} pm JOIN {$wpdb->posts} p ON p.ID = pm.post_id WHERE pm.meta_key = %s ORDER BY p.post_date DESC LIMIT %d OFFSET %d", ['_btw_importer_old_permalink', $per_page, $offset]) ); 99 } 82 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $orderby and $order are whitelisted (ASC/DESC, allowed columns only) 83 $allowed_orderby = ['post_date', 'post_type']; 84 if ( ! in_array( $orderby, $allowed_orderby, true ) ) { 85 $orderby = 'post_date'; 100 86 } 101 87 102 $total_items = (int) $wpdb->get_var( "SELECT FOUND_ROWS()" ); 103 104 88 $order = ( 'ASC' === strtoupper( $order ) ) ? 'ASC' : 'DESC'; 89 $results = $wpdb->get_results( 90 $wpdb->prepare( 91 " 92 SELECT SQL_CALC_FOUND_ROWS p.ID, p.post_type, p.post_date, pm.meta_value as old_slug 93 FROM {$wpdb->postmeta} pm 94 JOIN {$wpdb->posts} p ON p.ID = pm.post_id 95 WHERE pm.meta_key = %s 96 ORDER BY p.{$orderby} {$order} 97 LIMIT %d OFFSET %d 98 ", 99 '_btw_importer_old_permalink', 100 $per_page, 101 $offset 102 ) 103 ); 105 104 106 105 if (!$results) { … … 112 111 $base_url = add_query_arg('s', urlencode($search), $base_url); 113 112 } 113 if ($post_type_filter) { 114 $base_url = add_query_arg('post_type', urlencode($post_type_filter), $base_url); 115 } 114 116 115 117 $columns = [ 116 'p .post_date' => 'Date',117 'p .post_type' => 'Post Type',118 'post_date' => 'Date', 119 'post_type' => 'Post Type', 118 120 ]; 119 121 … … 160 162 'orderby' => $orderby, 161 163 'order' => $order, 164 'post_type' => $post_type_filter, 162 165 ], 163 166 'prev_text' => esc_html__('« Prev', 'btw-importer'),
Note: See TracChangeset
for help on using the changeset viewer.