<p><img src="https://img.php.cn/upload/article/000/887/227/169364887365792.jpg" alt="資料匯出:自訂資料庫表"></p>
<p>如本系列的第一篇文章中所提到的,自訂資料庫表的主要問題之一是它們不由現有的匯入和匯出處理程序處理。本文旨在解決這個問題,但應該指出的是,目前還沒有完全令人滿意的解決方案。 </p>
<p>讓我們考慮兩種情況:</p>
<ol>
<li>自訂表格引用本機 WordPress 表格</li>
<li>自訂表格完全獨立於原生表格</li>
</ol>
<p>「最壞情況」是第一種情況。以保存使用者活動日誌的自訂表為例。它引用使用者 ID、物件 ID 和物件類型 - 所有這些都引用儲存在本機 WordPress 表中的資料。現在想像一下,有人想要將其 WordPress 網站中的所有資料匯入到第二個網站中。例如,完全有可能在匯入貼文時,WordPress 必須為其指派一個新的 ID,因為第二個網站中可能已經存在具有該 ID 的貼文。 </p>
<p>在這種情況下,有必要追蹤此類變更並更新表中引用的 ID。這本身就沒那麼困難。 <em>不幸的是</em>,用於處理從其他 WordPress 網站匯入資料的 WordPress Importer 外掛程式缺乏必要的掛鉤來實現這一點。正如此評論中所建議的,一種潛在的解決方法是將資料也儲存在後元中。不幸的是,這會導致重複數據,並且違反資料庫規範化——通常不是一個好主意。最後,它僅在少數用例中真正可行。 </p>
<p>第二種情況避免了這種複雜性,但仍需要自訂匯入和匯出處理程序。我們將在接下來的兩篇文章中示範這種情況。但是,為了與本系列的其餘部分保持一致,我們將堅持使用活動日誌表,即使它是情況 (1) 的範例。 </p>
<hr>
<h2>決定格式</h2>
<p>首先我們需要決定匯出文件採用的格式。最佳格式取決於資料的性質(或“結構”)及其使用方式。在我看來,XML 通常更好,因為它可以處理一對多關係。然而,有時如果數據是表格形式,那麼 CSV 可能更可取,特別是因為它易於與電子表格應用程式整合。在此範例中,我們將使用 XML。 </p>
<hr>
<h2>加價</h2>
<p>下一步是建立一個管理頁面,以允許使用者匯出日誌表中的資料。我們將建立一個類,該類將在「工具」選單項目下方新增一個頁面。此頁面僅包含一個按鈕,提示使用者下載匯出檔案。該類別還將添加一個處理程序來偵聽表單提交並觸發文件下載。 </p>
<p>首先讓我們來看看類別的結構,然後再填寫其方法的詳細資訊。 </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbal:false;">class WPTuts_Log_Export_Admin_Page{
/**
* The page hook suffix
*/
static $hook_suffix='';
static function load(){
add_action('admin_menu', array(__CLASS__,'add_submenu'));
add_action('admin_init', array(__CLASS__,'maybe_download'));
}
static function add_submenu(){}
static function maybe_download(){}
static function display(){}
}
WPTuts_Log_Export_Admin_Page::load();
</pre><div class="contentsignin">登入後複製</div></div>
<p><code>WPTuts_Log_Export_Admin_Page::load()</code> 初始化類別並將回呼掛鉤到適當的操作:</p>
<ul>
<li>
<code>add_submenu</code> – 負責在「工具」功能表下新增頁面的方法。 </li>
<li>
<code>maybe_download</code> – 此方法將監聽檢查是否已提交下載請求。這也將檢查權限和隨機數。 </li>
</ul>
<p>需要在發送任何標頭之前儘早呼叫匯出偵聽器,因為我們將自己設定這些標頭。我們可以將其掛接到 <code>init</code> 上,但由於我們只允許在管理中下載匯出文件,因此 <code>admin_init</code> 在這裡更合適。 </p>
<p>向選單新增頁面非常簡單。要在「工具」下新增頁面,我們只需呼叫 <code>add_management_page()</code>。 </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbal:false;">static function add_submenu(){
self::$hook_suffix = add_management_page( __('Export Logs','wptuts-log'), __('Export Logs','wptuts-log'), 'manage_options', 'wptuts-export', array(__CLASS__,'display') );
}
</pre><div class="contentsignin">登入後複製</div></div>
<p>這裡的 <code>$hook_suffix</code> 是用於各種螢幕特定鉤子的後綴,這裡討論。我們在這裡不使用它 - 但如果您使用它,最好將其值儲存在變數中,而不是對其進行硬編碼。 </p>
<p>在上面我們將方法 <code>display()</code> 設定為我們頁面的回調,接下來我們定義它:</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbal:false;">static function display(){
echo '<div class="wrap">';
screen_icon();
echo '<h2>' . __( 'Export Activity Logs', 'wptuts-log' ) . '</h2>';
?>
<form id="wptuts-export-log-form" method="post" action="">
<p>
<label><?php _e( 'Click to export the activity logs','wptuts-log' ); ?></label>
<input type="hidden" name="action" value="export-logs" />
</p>
<?php wp_nonce_field('wptuts-export-logs','_wplnonce') ;?>
<?php submit_button( __('Download Activity Logs','wptuts-log'), 'button' ); ?>
</form>
<?php
}
</pre><div class="contentsignin">登入後複製</div></div>
<p>最後,我們希望監聽上述表單何時提交並觸發匯出檔案下載。 </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbal:false;">static function maybe_download(){
/* Listen for form submission */
if( empty($_POST['action']) || 'export-logs' !== $_POST['action'] )
return;
/* Check permissions and nonces */
if( !current_user_can('manage_options') )
wp_die('');
check_admin_referer( 'wptuts-export-logs','_wplnonce');
/* Trigger download */
wptuts_export_logs();
}
</pre><div class="contentsignin">登入後複製</div></div>
<p>剩下的就是建立函數 <code>wptuts_export_logs()</code> 來建立並傳回我們的 .xml 檔案。 </p>
<hr>
<h2>建立匯出檔案</h2>
<p>我們希望函數做的第一件事是檢索日誌。如果有的話,我們需要設定適當的標頭並以 XML 格式列印它們。由於我們希望使用者下載 XML 文件,因此我們將 Content-Type 設定為 <code>text/xml</code>,將 Content-Description 設定為 <code>File Transfer</code>。我們還將為下載檔案產生合適的名稱。最後,我們將添加一些註釋 - 這些完全是可選的,但有助於指導用戶如何處理下載的檔案。 </p>
<p>由於在本系列的前一部分中,我們為表格建立了API,因此我們的匯出處理程序不需要直接接觸資料庫- 也不需要清理<code>$args</code> 數組,因為這是由<code> 處理的wptuts_get_logs()</code>。 </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbal:false;">function wptuts_export_logs( $args = array() ) {
/* Query logs */
$logs = wptuts_get_logs($args);
/* If there are no logs - abort */
if( !$logs )
return false;
/* Create a file name */
$sitename = sanitize_key( get_bloginfo( 'name' ) );
if ( ! empty($sitename) ) $sitename .= '.';
$filename = $sitename . 'wptuts-logs.' . date( 'Y-m-d' ) . '.xml';
/* Print header */
header( 'Content-Description: File Transfer' );
header( 'Content-Disposition: attachment; filename=' . $filename );
header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
/* Print comments */
echo "<!-- This is a export of the wptuts log table -->\n";
echo "<!-- (Demonstration purposes only) -->\n";
echo "<!-- (Optional) Included import steps here... -->\n";
/* Print the logs */
}
</pre><div class="contentsignin">登入後複製</div></div>
<p>您会注意到,我们已将实际查询数组作为参数传递给 <code>wptuts_export_logs()</code> 函数。我们可以对此进行硬编码,但不这样做也是有道理的。虽然这里的目的只是导出表中的<em>所有内容</em>,但将查询作为参数传递允许我们稍后添加在特定时间范围内或针对特定用户导出日志的选项。</ p>
<p>创建 XML 文件时,我们需要确保标签之间打印的值不包含字符 <code>&</code>、<code><</code> 或 <code>></code>。为了确保这一点,对于 ID,我们使用 <code>absint</code> 清理数据,并使用 <code>sanitize_key</code> 清理对象类型和活动(因为我们希望这些仅包含小写字母数字、下划线和连字符)。</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbal:false;">/* Print logs to file */
echo '<logs>';
foreach ( $logs as $log ) { ?>
<item>
<log_id><?php echo absint($log->log_id); ?></log_id>
<activity_date><?php echo mysql2date( 'Y-m-d H:i:s', $log->activity_date, false ); ?></activity_date>
<user_id><?php echo absint($log->user_id); ?></user_id>
<object_id><?php echo absint($log->object_id); ?></object_id>
<object_type><?php echo sanitize_key($log->object_type); ?></object_type>
<activity><?php echo sanitize_key($log->activity); ?></activity>
</item>
<?php }
echo '</logs>';
</pre><div class="contentsignin">登入後複製</div></div>
<p>更一般地,您可以使用以下函数将要打印的值包装在 <code>CDATA</code> 标记内来清理它们:</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbal:false;">/**
* Wraps the passed string in a XML CDATA tag.
*
* @param string $string String to wrap in a XML CDATA tag.
* @return string
*/
function wptuts_wrap_cdata( $string ) {
if ( seems_utf8( $string ) == false )
$string = utf8_encode( $string );
return '<![CDATA[' . str_replace( ']]>', ']]]]><![CDATA[>', $string ) . ']]>';
}
</pre><div class="contentsignin">登入後複製</div></div>
<p>最后我们 <code>exit()</code> 以防止任何进一步的处理:</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbal:false;"> /* Finished - now exit */
exit();
</pre><div class="contentsignin">登入後複製</div></div>
<p>导航到我们的导出页面,单击“下载活动日志”应提示下载 XML 文件。</p>
<hr>
<h2>摘要</h2>
<p>在本教程中,我们研究了从自定义表中导出数据。不幸的是,当数据引用本机 WordPress 表时,这充其量是有问题的。上述方法仅适用于数据无法做到这一点的情况。使用的示例(我们的活动日志)显然不属于此类,只是为了与本系列的其余部分保持一致而使用。</p>
<p>当数据<em>确实</em>引用本机表时,显然有必要将其与本机表一起导入,并在此过程中跟踪导入期间发生的 ID 任何更改。目前,现有的导入和导出处理程序无法实现这一点,因此唯一可行的选择是创建自己的处理程序。在自定义数据仅引用单个帖子类型的简单情况下,可以设计导入和导出处理程序来处理该帖子类型以及自定义数据,并通知用户不要使用该帖子类型的本机导出器。
</p>
<p>在本系列的下一部分中,我们将为导出的 .xml 文件创建一个简单的导入处理程序。</p>
以上是資料匯出:自訂資料庫表的詳細內容。更多資訊請關注PHP中文網其他相關文章!