Nội dung
- shares
- Facebook Messenger
- Gmail
- Viber
- Skype
Di chuyển dữ liệu bài viết wordpress sang hosting khác. Khi tạo xong xuôi website trên localhost cả nhập dữ liệu đầy đủ đã đến lúc bạn đưa website lên host. Một website bao gồm phần code và database.
Bài viết này cũng áp dụng cho công việc di chuyển website từ nơi này sang nơi khác không chỉ localhost. Quan trọng nhất là di chuyển dữ liệu. Thực hiện các bước dưới đây.
Backup Code và Attachments
Đầu tiên bạn download toàn bộ code wordpress gồm có các file hệ thống, plugins, theme và thư mục uploads chứa các tài nguyên ảnh, ..các attachment khác.
Tiếp đó upload các files code cơ bản lên host mới sử dụng trình tải file FTP lên server, trong đó có:
- Các files hệ thống của wordpress : wp-content, wp-admin, các files ngoài root, wp-includes. Chú ý: trong folder wp-content bạn trừ folder
uploads
ra, vì có thể web trước có kích hoạt và tạo nhiều multisite nên các file ảnh tài nguyên được lưu dưới thư mục theo tên sites khác nhau. Phần nội dung này chúng ta sẽ chỉ lấy những attachments được đăng bởi website bạn đang muốn di chuyển.
Lấy tất cả các folders trong folder có tên là ID của site , giả sử trên hình là site ID= 21. Bạn copy thêm vào thư mục uploads/ của web mới.
Export – Import WordPress Database
Bước tiếp theo, bạn export dữ liệu của website bằng cách đăng nhập vào quản trị wordpress, truy cập công cụ Tools->export. Chúng ta được file .xml lưu toàn bộ dữ liệu bài viết + taxonomy + custom post type. Nếu website có nhiều kiểu dữ liệu, bạn xuất ra từng files xml cho mỗi kiểu dữ liệu được quy định bởi công cụ này.
Ví dụ: cài plugin tạo slideshow trong wordpress có plugin Meta Slidertrong tính năng export sẽ có thêm lựa chọn xuất dữ liệu của Meta Slider như thế này,.
Bạn có thể dùng lựa chọn đầu tiên All content
cho phép lưu ra toàn bộ dữ liệu có trong wordpress bao gồm dữ liệu của plugin.. vào một file XML.
Sau đó sử dụng file này để Import XML vào website wordpress mới.
Sửa lại dữ liệu cũ
Nếu file đính kèm trong post/page lên tới hàng trăm file ảnh,..thì plugin wordpress importer không thể nào up hết toàn bộ ảnh đó được vì số lượng quá lớn và code PHP có thể báo lỗi thời gian thực thi quá 30s. Lúc này bạn cần tăng thời gian thực thi PHP. Hoặc bạn sử dụng cách chia file XML kích thước lớn thành nhiều files XML có kích thước nhỏ hơn (<=2mb). Xem thêm mẹo này tại đây.
Cách khôn ngoan hơn là up database của nội dung bài viết trước và các files attachments (ie:jpg, gif,zip,rar,…) sau. Đừng check tùy chọn “Download and import file attachments” trong bước import. Chúng ta sẽ upload các files tài nguyên này về sau.
Nhấn Save bình thường.
Sau đó bước tiếp theo đây, bạn kiểm tra các files đã tải lên thư mục wp-content/uploads
chưa, nếu chưa làm thì thực hiện tại bước Backup Code và Attachments ở trên.
Bạn mở mục quản trị database phpmyadmin của web trên trình duyệt và sửa lại cho đúng với domain. Ban đầu bỏ qua bước import attachment địa chỉ URL của attachment vẫn lưu của domain cũ.
Sửa lại giá trị một số trường của các bảng có lưu domain cũ, ví dụ: wp-posts, ..Thay địa chỉ domain cũ bằng domain hiện tại bằng cách sử dụng câu lệnh SQL. Ví dụ sau tôi thay chuỗi domain “http://demo.hoangweb.com/baoholaodong/” tìm trong nội dung trường guid
của bảng wp_posts
, bởi giá trị domain mới hiện tại của web là “http://baohohaan.com/”, có thể lọc thêm field như chỉ thực hiện với các record có giá trị field post_type=”post”. Nghĩa là áp dụng cho các bài viết (post).
update wp_posts set guid=REPLACE(guid,"http://demo.hoangweb.com/baoholaodong/","http://baohohaan.com/") where post_type="post"
Tuy nhiên sử dụng mệnh đề where là không cần thiết, đánh nhầm còn hơn bỏ xót. Mình lấy ví dụ như vậy để cho bạn hiểu mà thôi.
Ví dụ khác cho multisite, địa chỉ attachment có dạng:
http://demo.hoangweb.com/baoholaodong/wp-content/uploads/sites/21/2014/09/4024853qua_n_a_o_ba_o_ho__va_i_kaki_nam_di_nh_loa_i_11.jpg
Trong đó 21 là ID của site. Như vậy đối với trường hợp này bạn thay thế cả chuỗi “http://demo.hoangweb.com/baoholaodong/wp-content/uploads/sites/21”.
update wp_posts set post_content=REPLACE(post_content,"http://demo.hoangweb.com/baoholaodong/wp-content/uploads/sites/21/","http://baohohaan.com/wp-content/uploads/") where post_type="post"
Chú ý: xem qua trước nội dung bảng CSDL rồi đưa ra quyết định dùng lệnh SQL cho phù hợp. Chẳng hạn, Nếu Field trong table có nội dung chứa attachment URL thì không nên chạy lệnh “update” thay thế nguyên địa chỉ domain, như minh họa ở trên chúng ta phải xóa cả đến phân đoạn URL ‘/sites/{siteID}’.
Danh sách các bảng và trường thay đổi giá trị là:
- wp_posts:
post_content
(tìm thay thế attachment URL),guid
(tìm thay thế địa chỉ domain trang chủ/base url) - wp_postmeta:
meta_value
(tìm thay thế base url. Kết quả tìm thấy giá trị meta_key=’_menu_item_url’)
Khai báo vào file tài nguyên vào media attachment
Sau khi trỏ các file lưu trong database vào domain mới, mình vào thử quản lý Media thì vẫn không thấy các attachments xuất hiện. Như vậy wordpress không trích xuất attachment trong nội dung wp_posts, việc sửa lại domain dễ hiểu là không có tác dụng nó được lưu ở bảng khác.
Để thử nghiệm tính năng feature image thiết lập cho post và xem trong csdl lưu thông tin đó như thế nào. Tôi sẽ thiết lập post thumbnail cho một bài viết, ảnh này có ID=1273
Còn lại tất cả các bài viết khác không có ảnh thumbnail.
Việc tiếp theo, mình sẽ tìm kiếm giá trị “1273” trong database wordpress, sử dụng công cụ quản lý CSDL MySQL HeidiSQL.
Để cho nhanh, tôi export csdl trên website về máy tính và import vào một CSDL mới để tiến hành kiểm tra.
Mở phần mềm HeidiSQL, nhập tài khoản kết nối mysql trong ví dụ này mình dùng XAMP. Chuột phải vào tên database bạn vừa import, chọn tiếp “Find text on server”.
Nhập chuỗi 1273 tại mục Text to find rồi nhấn nút Find. Kết quả tìm thấy ở bảng wp_postmeta
, wp_posts
.
Đúng rồi, chúng ta tìm ID của file tất nhiên mọi file upload lên web đều tồn tại ở wp_posts. Tìm tiếp một custom field nữa là ‘_thumbnail_id’.
Kết quả 2 thật ngạc nhiên.
Như vậy đây là feature image/post thumbnail được thiết lập cho post vẫn được bảo toàn, như vì phải xuất hiện trong Media hay được coi là attachment của website thì tính năng feature image của bài viết mới sử dụng được và trong cửa sổ edit post bạn mới thấy ảnh trong metabox Feature Image.
Quay trở lại kết quả 1, tìm tiếp chuỗi “_wp_attached_file” ah, nghe tên thì có vẻ đúng rồi field này là khai báo attachments quản lý trong menu Media đây. Kết quả 3 cho ra.
Thôi đúng rồi, đó là các files nằm trong Media.
Còn chuỗi cuối “_wp_attachment_metadata”, kết quả 4:
Đó là field mô tả thông tin của attachment là ảnh như width, height, mime-type..hình trên tìm thấy 3 attachment, đúng rồi tương đương với 3 ảnh tìm thấy trong kết quả 3, các file không pải ảnh sẽ không có thuộc tính trên.
Kết luận: Tổng số có 3 trường tạo giúp tạo attachment và post thumbnail cho post, chúng ta phải thêm 2 trường ‘_wp_attached_file
‘ và ‘_wp_attachment_metadata
‘ chèn record vào bảng wp_postmeta. Table wp_posts không cần phải thêm vì đã có rồi. Việc khai báo này công nhận các file đăng vào wp_posts là attachments của wordpress.
Phát hiện thêm: các post thumbnail tìm được ở bảng wp_postmeta có liên kết với post thể hiện thông qua field meta_key=’_thumbnail_id’, không tìm thấy ở trong wp_posts có post_type=’attachment’. Thông thường mọi kiểu attachment và post đều chứa dữ liệu ở đây.
Do chúng ta bỏ qua optioon download và import media trong bước nhập dữ liệu vào wordpress, nên khuyết dữ liệu này. Nhưng bảng wp_postmeta cho ta thấy điều đó.
(trường meta_value thể hiển field wp_posts.ID của attachment nhưng không tìm thấy ở wp_posts)
Đính chính lại, như vậy chúng ta khai báo nội dung attachment bằng cách phải chèn thêm record vào bảng wp_posts với post_type=attachment. Nhưng còn meta_value của meta_key=’_wp_attachment_metadata’ thì lấy giá trị ở đâu?
Ý nghĩ: tạo metadata từ attachment URL, cái này không có hàm hỗ trợ trong wordpress. Mình tìm thấy hàm tạo metadata từ attachment id wp_generate_attachment_metadata
. Nhưng vô tác dụng vì để có thể sử dụng được hàm đó thì ta biết attachment phải thuộc về dữ liệu media trong wordpress rồi.
Còn một file XML lưu dữ liệu mà ta quên mất, file export được export từ wordpress chứa đầy đủ thông số của attachment, thậm trí liên kết với post, custom post type.
Mỗi record trong wp_posts thể hiện bởi tag item
. VD:
<item> <title>3651922quan_ao_vai_pawngzim_han_quoc[1]</title> <link>http://demo.hoangweb.com/baoholaodong/quan-ao-bao-ho-lao-dong/quan-ao-bao-ho-vai-kaki- nhat.html/attachment/3651922quan_ao_vai_pawngzim_han_quoc1</link> <pubDate>Thu, 25 Sep 2014 07:39:10 +0000</pubDate> <dc:creator><![CDATA[admin]]></dc:creator> <guid isPermaLink="false">http://demo.hoangweb.com/baoholaodong/wp- content/uploads/sites/21/2014/09/3651922quan_ao_vai_pawngzim_han_quoc1.jpg</guid> <description></description> <content:encoded><![CDATA[]]></content:encoded> <excerpt:encoded><![CDATA[]]></excerpt:encoded> <wp:post_id>16</wp:post_id> <wp:post_date>2014-09-25 07:39:10</wp:post_date> <wp:post_date_gmt>2014-09-25 07:39:10</wp:post_date_gmt> <wp:comment_status>open</wp:comment_status> <wp:ping_status>open</wp:ping_status> <wp:post_name>3651922quan_ao_vai_pawngzim_han_quoc1</wp:post_name> <wp:status>inherit</wp:status> <wp:post_parent>15</wp:post_parent> <wp:menu_order>0</wp:menu_order> <wp:post_type>attachment</wp:post_type> <wp:post_password></wp:post_password> <wp:is_sticky>0</wp:is_sticky> <wp:attachment_url>http://demo.hoangweb.com/baoholaodong/wp- content/uploads/sites/21/2014/09/3651922quan_ao_vai_pawngzim_han_quoc1.jpg</wp:attachment_url> <wp:postmeta> <wp:meta_key>_wp_attached_file</wp:meta_key> <wp:meta_value><![CDATA[2014/09/3651922quan_ao_vai_pawngzim_han_quoc1.jpg]]></wp:meta_value> </wp:postmeta> <wp:postmeta> <wp:meta_key>_wp_attachment_metadata</wp:meta_key> <wp:meta_value><![CDATA[a:5:{s:5:"width";i:261;s:6:"height";i:420;s:4:"file";s:49:"2014/09/3651922quan_ao_vai_pawngzim_han_quoc1.jpg";s:5:"sizes";a:3:{s:9:"thumbnail";a:4:{s:4:"file";s:49:"3651922quan_ao_vai_pawngzim_han_quoc1-150x150.jpg";s:5:"width";i:150;s:6:"height";i:150;s:9:"mime-type";s:10:"image/jpeg";}s:6:"medium";a:4:{s:4:"file";s:49:"3651922quan_ao_vai_pawngzim_han_quoc1-186x300.jpg";s:5:"width";i:186;s:6:"height";i:300;s:9:"mime-type";s:10:"image/jpeg";}s:14:"post-thumbnail";a:4:{s:4:"file";s:49:"3651922quan_ao_vai_pawngzim_han_quoc1-261x372.jpg";s:5:"width";i:261;s:6:"height";i:372;s:9:"mime-type";s:10:"image/jpeg";}}s:10:"image_meta";a:10:{s:8:"aperture";i:0;s:6:"credit";s:0:"";s:6:"camera";s:0:"";s:7:"caption";s:0:"";s:17:"created_timestamp";i:0;s:9:"copyright";s:0:"";s:12:"focal_length";i:0;s:3:"iso";i:0;s:13:"shutter_speed";i:0;s:5:"title";s:0:"";}}]]></wp:meta_value> </wp:postmeta> </item>
Các bạn sử dụng PHP đọc nội dung XML này. Sau mỗi tag item nhận dạng là ‘attachment’ bởi element tag wp:post_type
chúng ta cần chèn thêm record vào wp_postmeta khai báo cho attachment với custom field ‘_wp_attached_file’, có giá trị là path đến file. ie: 2014/09/3651922quan_ao_vai_pawngzim_han_quoc1.jpg
Tiếp theo, bạn cũng chèn tiếp vào wp_postmeta cho custom field ‘_wp_attachment_metadata’ của attachment. Cuối cùng thêm mới vào bảng wp_posts. Toàn bộ trường trong bảng lấy giá trị từ tag item của nội dung file export XML, trừ guid
phải trỏ vào domain mới. Lưu ý: field post_parent
là để tạo galleries cho bài viết và tính năng post thumbnail đã thiết lập cho post trong khi import dữ liệu qua wordpress importer rồi, giá trị trường meta_key=’_thumbnail_id’ liên kết giữa post (post_id = wp_posts.ID) và attachment (meta_value = wp_posts.ID)
CODE
Bạn có thể tương tác dữ liệu vào database MySQL bằng thư viện PHP ADOdb. Tham khảo đoạn script trương trình mình có viết ra sau đây, giúp bạn thực hiện công việc import dữ liệu media như plugin wordpress importer.
updated: 05/10/2014
<?php session_start(); ini_set('max_execution_time', 300); ini_set('memory_limit', '3G'); if (ob_get_level() == 0) ob_start(); ?> <html> <head> <title>Fixed wordpress importing attachments missing - Hoangweb.com</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> <style> body{background:#fefefe;padding:10px;} #logs{ width:50%; overflow:auto; max-height:500px; border:1px solid gray; } .item-result{ border:1px solid red; background:#D8D8D8; margin-bottom:5px; } </style> </head> <body> <table> <tr><td valign="top"> <form method="POST" enctype="multipart/form-data"> <fieldset> <legend>Enter File:</legend> <span>Choose File</span>: <input type="file" name="file" id="file"/><br/> <span>OR URL</span> <input type="text" name="file_path" value="<?php echo isset($_POST['file_path'])? $_POST['file_path']:'';?>"/> </fieldset> <span>Limit</span>: <input name="dolimit" value="<?php echo isset($_POST['dolimit'])? $_POST['dolimit']:'2';?>"/><br/> <span>Reset session</span>: <input type="checkbox" name="reset_storage" <?php echo isset($_POST['reset_storage']) && $_POST['reset_storage']=='on'? 'checked="checked"':''?>/><br/> <input type="submit" value="Submit" name="submit"/> </form> </td> <td valign="top"> <?php global $conn; function _print($txt){ ECHO '<textarea>'; print_r($txt); ECHO '</textarea>'; } /** update all attachment */ function update_attachments($filexml){ global $conn; //vars $base_url='http://baohohaan.com'; $count=0; $dolimit=isset($_POST['dolimit']) && is_numeric($_POST['dolimit'])? $_POST['dolimit'] :0; $once_reset=1; if(isset($_POST['reset_storage']) && $_POST['reset_storage']=='on' && $once_reset){ $not_in_ID=save_attachments(null,true); $once_reset=0; }else{ $not_in_ID=save_attachments(); } print_r($not_in_ID); if(file_exists($filexml)): $xml=new SimpleXmlElement(file_get_contents($filexml)); $remain=count($xml->channel->item)-count($not_in_ID); ?> <ul> <li>Total found (<?php echo $remain?>) attachments.</li> <?php if($dolimit){?><li>Limit <?php echo $dolimit?></li><?php }?> </ul> <?php foreach($xml->channel->item as $item){ $wp = $item->children('http://wordpress.org/export/1.2/');//_print(($wp->post_id.','.$wp->post_type.','.$wp->status)); if($wp->post_type!='attachment' && $wp->status!='inherit') continue; if(in_array($wp->post_id,$not_in_ID)){ continue; } //$post_id=(string)$wp->post_id; echo '<div class="item-result" style="">'; $attachment_url=(string)$wp->attachment_url; $d=date('Y-m-d H:i:s'); $mime_type=''; $guid=''; if(count($wp->postmeta)){ foreach($wp->postmeta as $meta){ $wp1=$meta->children('http://wordpress.org/export/1.2/'); if($wp1->meta_key=='_wp_attached_file' && (string)$wp1->meta_value){ //add _wp_attached_file $t=$conn->Execute('insert into wp_postmeta(post_id,meta_key,meta_value) values("'.strval($wp->post_id).'","_wp_attached_file","'.mysql_real_escape_string(strval($wp1->meta_value)).'")'); $guid=rtrim($base_url,'/').'/'.ltrim($wp1->meta_value,'/'); } if($wp1->meta_key=='_wp_attachment_metadata' && $wp1->meta_value){ //add _wp_attachment_metadata $t=$conn->Execute('insert into wp_postmeta(post_id,meta_key,meta_value) values("'.strval($wp->post_id).'","_wp_attachment_metadata","'.mysql_real_escape_string(strval($wp1->meta_value)).'")'); //get attachment mime type $arr=@unserialize((string)$wp1->meta_value); if(is_array($arr)) $mime_type=$arr['sizes']['thumbnail']['mime-type']; } } //insert new attachment to wp_posts $data=array( 'ID'=>(string)$wp->post_id, 'post_author'=>'1', 'post_date'=>(string)$wp->post_date, 'post_date_gmt'=>(string)$wp->post_date_gmt, 'post_title'=>mysql_real_escape_string((string)$item->title), 'post_excerpt'=>mysql_real_escape_string((string)$item->excerpt), 'post_status'=>(string)$wp->status, 'comment_status'=>(string)$wp->comment_status, 'ping_status'=>(string)$wp->ping_status, 'post_password'=>(string)$wp->post_password, 'post_name'=>mysql_real_escape_string((string)$wp->post_name), 'post_modified'=>$d, 'post_modified_gmt'=>$d, 'post_parent'=>(string)$wp->post_parent, 'menu_order'=>(string)$wp->menu_order, 'guid'=>$guid, 'post_type'=>(string)$wp->post_type, 'post_mime_type'=>$mime_type ); $data=array_filter($data); $escape_vals=array_map(function($v){return '"'.mysql_real_escape_string($v).'"';},array_values(($data))); $values=join(',',$escape_vals); //$ok=$conn->Execute('insert into wp_posts('.join(',',array_keys($data)).') values('.$values.')'); //if(!$ok){ $q=array(); while (list($var, $val) = each(($data))) { if($var=='ID') continue; $q[]=$var.'="'.mysql_real_escape_string($val).'"'; } $conn->Execute('insert into wp_posts('.join(',',array_keys($data)).') values('.$values.') on duplicate key update '.join(',',$q)); //} //save attachment save_attachments((string)$wp->post_id); //get post attached thumbnail $rs=$conn->Execute('select ID,post_name from wp_posts inner join (select post_id from wp_postmeta where meta_key="_thumbnail_id" and meta_value="'.strVal($wp->post_id).'") as A1 on wp_posts.ID=A1.post_id'); if(count($rs)) while ($row = $rs->FetchRow()) { echo '<p style="padding:5px;background:#dadada;font-weight:bold;">Set galleries and post thumbnail successful for post with ID='.$row['ID'].', title=['.$row['post_name'].']</p>'; } else{ echo '<p style="padding:5px;background:#dadada;font-weight:bold;">Không có post nào gắn với thumbnail này.</p>'; } } echo "added media ID {$wp->post_id} into wp_postmeta"; echo '</div>'; if($dolimit && $count++>=$dolimit-1) break; ob_flush(); flush(); sleep(2); } endif; exit(); } /** list exists attachments */ function get_exists_attachments(){ global $conn; $not_in_ID=array(); $rs=$conn->Execute("select post_id from wp_postmeta where meta_key='_wp_attachment_metadata' "); while ($array = $rs->FetchRow()) { $not_in_ID[]=$array['post_id']; } return $not_in_ID; } /** make mysql connection */ function connection($host,$user,$pass,$db){ if(!class_exists('ADONewConnection')) include('libs/ADOdb-master/adodb.inc.php'); global $conn; if(empty($conn)){ $conn = ADONewConnection('mysql'); # eg. 'mysql' or 'oci8' $conn->debug = true; $conn->Connect($host, $user, $pass, $db); } return $conn; } //update_attachments('baoholaodong.wordpress.2014-10-04.xml'); function save_attachments($id=null,$reset=false){ static $not_in_ID; if($reset) unset($_SESSION['attachments']); if(!isset($_SESSION['attachments'])) $_SESSION['attachments']=array(); if(!$not_in_ID){ $not_in_ID=get_exists_attachments(); //merge $_SESSION['attachments']=array_unique(array_merge($not_in_ID,$_SESSION['attachments'])); } //add new if(!empty($id)) $_SESSION['attachments'][]=$id; return $_SESSION['attachments']; } //----------------------------------------------- //on submit form if(isset($_POST['submit'])){ if ($_FILES["file"]["error"] > 0) { echo "Form File Error: " . $_FILES["file"]["error"] . "<br>"; if(isset($_POST['file_path']) && file_exists($_POST['file_path'])){ $file=$_POST['file_path']; } } else { echo '<div style="background:link;">[Form Upload]<br/>'; echo "Upload: " . $_FILES["file"]["name"] . "<br>"; echo "Type: " . $_FILES["file"]["type"] . "<br>"; echo "Size: " . ($_FILES["file"]["size"] / 1024) . " kB<br>"; $file=$_FILES["file"]["tmp_name"]; echo '</div>'; } if(isset($file)) { //connect to mysql $db=connection('localhost', 'root', '', 'wordpress'); echo '<div id="logs">'; update_attachments($file); echo '</div>'; //echo '<textarea>'.$t.'</textarea>'; } } ?> </td> </tr> </table> </body> </html> <?php ob_end_flush(); ?>
Cách sử dụng: Copy đoạn code trên vào file fix_media.php
và tải lên host của bạn. Chạy fix_media.php trên trình duyệt, lấy nội dung XML bằng cách nhấn nút Choose File và trỏ vào file XML bạn export từ website wordpress cũ. Sau đó ấn nút Submit để trương trình bắt đầu sửa lại các bảng mysql vào CSDL hiện tại website mới đang sử dụng.
Nếu số lượng attachments lớn cần tạo lại, bạn có thể chia làm nhiều đợt import bằng cách điền giá trị vào ô Limit. Những attachment đã được sửa rồi trong lần chạy tiếp công cụ này sẽ bỏ qua và tìm sửa những attachment lỗi tiếp theo.
Tác giả: hoangweb.com
Nếu bạn thích bài viết này, hãy ủng hộ chúng tôi bằng cách đăng ký nhận bài viết mới ở bên dưới và đừng quên chia sẻ kiến thức này với bạn bè của bạn nhé. Bạn cũng có thể theo dõi blog này trên Twitter và Facebook
- shares
- Facebook Messenger
- Gmail
- Viber
- Skype