<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>DOMDocument &#8211; 小豬日常</title>
	<atom:link href="https://piglife.tw/tag/domdocument/feed/" rel="self" type="application/rss+xml" />
	<link>https://piglife.tw</link>
	<description>Hello World，一個紀錄生活與學習的地方</description>
	<lastBuildDate>Fri, 12 Dec 2025 22:20:47 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>

<image>
	<url>https://piglife.tw/wp-content/uploads/2017/10/cropped-logo-1-32x32.png</url>
	<title>DOMDocument &#8211; 小豬日常</title>
	<link>https://piglife.tw</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>使用 PHP 與 DOMDocument 自動產生 WordPress 文章預覽內容</title>
		<link>https://piglife.tw/technical-notes/php-domdocument-wordpress-preview/</link>
					<comments>https://piglife.tw/technical-notes/php-domdocument-wordpress-preview/#respond</comments>
		
		<dc:creator><![CDATA[小豬]]></dc:creator>
		<pubDate>Fri, 12 Dec 2025 22:20:47 +0000</pubDate>
				<category><![CDATA[技術筆記]]></category>
		<category><![CDATA[acf]]></category>
		<category><![CDATA[DOMDocument]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">https://piglife.tw/technical-notes/php-domdocument-wordpress-preview/</guid>

					<description><![CDATA[介紹如何使用 PHP 的 DOMDocument 在 WordPress 中自動擷取文章內容第一個區...]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">前言</h2>
<p>在 WordPress 開發中，有時候需要自動從文章內容擷取一部分作為預覽，方便在前台或後台顯示摘要。這段程式碼示範如何利用 PHP 的 DOMDocument 解析文章 HTML，並將第一個區塊內容存入自訂欄位，適合希望自動管理文章預覽的開發者或自學者。</p>
<h2 class="wp-block-heading">主要功能說明</h2>
<p>這段程式碼的核心目標是：</p>
<ul>
<li>避免在自動儲存或文章修訂版本時重複執行</li>
<li>只處理文章(post)類型</li>
<li>取得文章內容並套用 WordPress 內建的內容過濾器（the_content）</li>
<li>使用 DOMDocument 將 HTML 內容解析為節點樹</li>
<li>擷取第一個 HTML 區塊（元素節點）作為預覽內容</li>
<li>將擷取結果寫入 Advanced Custom Fields (ACF) 的自訂欄位</li>
</ul>
<p>這樣的設計能確保預覽內容是有效的 HTML 片段，且不會因為純文字截斷而破壞標籤結構。</p>
<h2 class="wp-block-heading">程式碼解析</h2>
<h3 class="wp-block-heading">避免不必要的觸發</h3>
<pre><code class="lang-php language-php php">if (defined(&#039;DOING_AUTOSAVE&#039;) &amp;&amp; DOING_AUTOSAVE) return;
if (wp_is_post_revision($post_id)) return;</code></pre>
<p>這兩個判斷用來避免在 WordPress 自動儲存或文章修訂版本時執行預覽生成，減少不必要的資源消耗。</p>
<h3 class="wp-block-heading">文章類型與內容驗證</h3>
<pre><code class="lang-php language-php php">$post = get_post($post_id);
if ($post-&gt;post_type !== &#039;post&#039;) return;
$content = $post-&gt;post_content;
if (empty($content)) return;</code></pre>
<p>確保只處理標準文章(post)，且內容不為空。</p>
<h3 class="wp-block-heading">套用內容過濾器</h3>
<pre><code class="lang-php language-php php">$filtered_content = apply_filters(&#039;the_content&#039;, $content);</code></pre>
<p>這步驟會讓內容經過 WordPress 內建的過濾器處理，例如短碼解析、自動換行等，確保後續解析的 HTML 是完整且符合前台顯示的狀態。</p>
<h3 class="wp-block-heading">使用 DOMDocument 解析 HTML</h3>
<pre><code class="lang-php language-php php">libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc-&gt;loadHTML(&#039;&lt;?xml encoding=&quot;utf-8&quot; ?&gt;&#039; . $filtered_content);
libxml_clear_errors();</code></pre>
<p>因為 HTML 可能不完全符合 XML 規範，先抑制 libxml 錯誤，並在字串前加上 XML 編碼宣告，確保 UTF-8 正確處理。</p>
<h3 class="wp-block-heading">擷取第一個區塊元素</h3>
<pre><code class="lang-php language-php php">$body = $doc-&gt;getElementsByTagName(&#039;body&#039;)-&gt;item(0);
$output_blocks = [];
$count = 0;
$max_blocks = 1;

foreach ($body-&gt;childNodes as $node) {
    if ($node-&gt;nodeType === XML_ELEMENT_NODE) {
        $output_blocks[] = $doc-&gt;saveHTML($node);
        $count++;
        if ($count &gt;= $max_blocks) break;
    }
}

$preview_html = implode(&quot;\n&quot;, $output_blocks);</code></pre>
<p>這段程式碼從 body 標籤下取得第一個元素節點（例如第一個段落或區塊標籤），並將其轉成 HTML 字串。這樣做的好處是避免截取不完整的 HTML，保持標籤結構完整。</p>
<h3 class="wp-block-heading">寫入自訂欄位</h3>
<pre><code class="lang-php language-php php">update_field(&#039;ks_post_preview&#039;, $preview_html, $post_id);</code></pre>
<p>利用 ACF 提供的 update_field 函式，將預覽內容寫入名為 ks_post_preview 的自訂欄位，方便後續在前台或後台調用。</p>
<h2 class="wp-block-heading">實務應用與優化建議</h2>
<ul>
<li>可依需求調整 $max_blocks 參數，擷取多個區塊作為預覽</li>
<li>若文章內容包含複雜結構，DOMDocument 解析可確保 HTML 不會因截斷而破損</li>
<li>可結合 WordPress 的鉤子（如 save_post）自動更新預覽，減少手動維護成本</li>
<li>注意 ACF 欄位名稱需與後台設定一致，否則無法成功更新</li>
</ul>
<h2 class="wp-block-heading">常見問題與注意事項</h2>
<ul>
<li>DOMDocument 解析 HTML 時可能因不標準標籤產生警告，使用 libxml_use_internal_errors 可避免影響</li>
<li>若文章內容過短或無有效區塊，預覽欄位可能為空，需在前端做好容錯處理</li>
<li>自動儲存與修訂版本判斷是避免重複觸發的關鍵，缺少可能導致效能問題</li>
</ul>
<h2 class="wp-block-heading">完整程式碼</h2>
<pre><code class="lang-php language-php php">&lt;?php
function ks_generate_post_preview($post_id) {
    // 避免自動儲存時觸發
    if (defined(&#039;DOING_AUTOSAVE&#039;) &amp;&amp; DOING_AUTOSAVE) return;
    if (wp_is_post_revision($post_id)) return;

    $post = get_post($post_id);
    if ($post-&gt;post_type !== &#039;post&#039;) return;

    $content = $post-&gt;post_content;
    if (empty($content)) return;

    // 套用 the_content 濾鏡
    $filtered_content = apply_filters(&#039;the_content&#039;, $content);

    // 使用 DOMDocument 分析 HTML
    libxml_use_internal_errors(true);
    $doc = new DOMDocument();
    $doc-&gt;loadHTML(&#039;&lt;?xml encoding=&quot;utf-8&quot; ?&gt;&#039; . $filtered_content);
    libxml_clear_errors();

    $body = $doc-&gt;getElementsByTagName(&#039;body&#039;)-&gt;item(0);
    $output_blocks = [];
    $count = 0;
    $max_blocks = 1;

    foreach ($body-&gt;childNodes as $node) {
        if ($node-&gt;nodeType === XML_ELEMENT_NODE) {
            $output_blocks[] = $doc-&gt;saveHTML($node);
            $count++;
            if ($count &gt;= $max_blocks) break;
        }
    }

    $preview_html = implode(&quot;\n&quot;, $output_blocks);

    // 寫入 ACF 欄位
    update_field(&#039;ks_post_preview&#039;, $preview_html, $post_id);
}
add_action(&#039;save_post&#039;, &#039;ks_generate_post_preview&#039;);</code></pre>]]></content:encoded>
					
					<wfw:commentRss>https://piglife.tw/technical-notes/php-domdocument-wordpress-preview/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
