如何在博客文章内容中间自动插入带链接的横幅模板片段
Got it, let's break this down. You want to inject your pre-built template part (with a linked banner) into the middle of all your blog posts automatically—no manual shortcodes required—based on specific rules like after the 3rd paragraph, 300 words, or 900 characters.
We'll use WordPress's the_content filter for this, since it's the standard way to modify post content before it's rendered. Below are solutions for each insertion rule:
1. Insert After the Nth Paragraph (e.g., 3rd Paragraph)
This is perfect if you want to place the banner at a consistent structural point in your posts.
Add this code to your theme's functions.php file (use a child theme to avoid losing changes when you update the parent theme):
add_filter('the_content', 'insert_banner_after_specific_paragraph'); function insert_banner_after_specific_paragraph($content) { // Only run on single post pages (adjust this condition if needed) if (!is_single()) return $content; // Set your target paragraph number (e.g., 3 for the 3rd paragraph) $target_paragraph = 3; // Capture the output of your template part (replace the path with yours) ob_start(); get_template_part('parts/banner'); // Example: if your template is parts/banner.php $banner_html = ob_get_clean(); // Split content into paragraphs using closing </p> tags $paragraphs = explode('</p>', $content); $updated_content = ''; foreach ($paragraphs as $index => $paragraph) { // Add the current paragraph back to the content $updated_content .= $paragraph . '</p>'; // Insert the banner after the target paragraph (skip if it's the last paragraph) if (($index + 1) === $target_paragraph && isset($paragraphs[$index + 1])) { $updated_content .= $banner_html; } } return $updated_content; }
Note: If your posts use a different block/paragraph tag (like
<div>), adjust theexplodeparameter to match that closing tag. Also double-check your template part path—get_template_part('parts/banner')will loadparts/banner.phpfrom your theme folder.
2. Insert After X Words (e.g., 300 Words)
Use this to place the banner after readers have consumed a specific amount of text. This counts plain text words (ignores HTML tags).
Add this to your functions.php:
add_filter('the_content', 'insert_banner_after_specific_word_count'); function insert_banner_after_specific_word_count($content) { if (!is_single()) return $content; $target_word_count = 300; // Number of words to wait before inserting ob_start(); get_template_part('parts/banner'); $banner_html = ob_get_clean(); // Get plain text from content to count words accurately $plain_text = strip_tags($content); $total_words = str_word_count($plain_text); // Skip insertion if post is shorter than target word count if ($total_words < $target_word_count) return $content; // Use DOMDocument to safely modify HTML without breaking structure $current_word_count = 0; $dom = new DOMDocument(); // Handle UTF-8 encoding to avoid messy characters @$dom->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8')); $body_nodes = $dom->getElementsByTagName('body')->item(0)->childNodes; foreach ($body_nodes as $node) { if ($node->nodeType === XML_TEXT_NODE) { $node_words = str_word_count($node->nodeValue); if ($current_word_count + $node_words >= $target_word_count) { // Split the text node at the target word $remaining_words = $target_word_count - $current_word_count; $split_text = explode(' ', $node->nodeValue, $remaining_words + 1); $first_part = implode(' ', array_slice($split_text, 0, $remaining_words)); $second_part = implode(' ', array_slice($split_text, $remaining_words)); // Update the current text node to the first part $node->nodeValue = $first_part; // Insert the banner HTML after this node $banner_fragment = $dom->createDocumentFragment(); $banner_fragment->appendXML($banner_html); $node->parentNode->insertBefore($banner_fragment, $node->nextSibling); // Add the remaining text as a new node $new_text_node = $dom->createTextNode(' ' . $second_part); $node->parentNode->insertBefore($new_text_node, $banner_fragment->nextSibling); // Exit loop once banner is inserted break; } else { $current_word_count += $node_words; } } } // Clean up extra HTML tags added by DOMDocument $updated_content = preg_replace('/<!DOCTYPE.+?>/', '', $dom->saveHTML()); $updated_content = preg_replace('/<html.*?>|<body.*?>|<\/html>|<\/body>/', '', $updated_content); return $updated_content; }
3. Insert After X Characters (e.g., 900 Characters)
Similar to word count, but counts every character (including spaces, ignoring HTML tags). Great for consistent visual placement across posts with varying word lengths.
Add this code to functions.php:
add_filter('the_content', 'insert_banner_after_specific_char_count'); function insert_banner_after_specific_char_count($content) { if (!is_single()) return $content; $target_char_count = 900; // Number of characters to wait before inserting ob_start(); get_template_part('parts/banner'); $banner_html = ob_get_clean(); $plain_text = strip_tags($content); $total_chars = mb_strlen($plain_text, 'UTF-8'); if ($total_chars < $target_char_count) return $content; $current_char_count = 0; $dom = new DOMDocument(); @$dom->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8')); $body_nodes = $dom->getElementsByTagName('body')->item(0)->childNodes; foreach ($body_nodes as $node) { if ($node->nodeType === XML_TEXT_NODE) { $node_chars = mb_strlen($node->nodeValue, 'UTF-8'); if ($current_char_count + $node_chars >= $target_char_count) { $remaining_chars = $target_char_count - $current_char_count; $first_part = mb_substr($node->nodeValue, 0, $remaining_chars, 'UTF-8'); $second_part = mb_substr($node->nodeValue, $remaining_chars, null, 'UTF-8'); $node->nodeValue = $first_part; $banner_fragment = $dom->createDocumentFragment(); $banner_fragment->appendXML($banner_html); $node->parentNode->insertBefore($banner_fragment, $node->nextSibling); $new_text_node = $dom->createTextNode($second_part); $node->parentNode->insertBefore($new_text_node, $banner_fragment->nextSibling); break; } else { $current_char_count += $node_chars; } } } $updated_content = preg_replace('/<!DOCTYPE.+?>/', '', $dom->saveHTML()); $updated_content = preg_replace('/<html.*?>|<body.*?>|<\/html>|<\/body>/', '', $updated_content); return $updated_content; }
We use
mb_strlenandmb_substrhere to handle multi-byte characters (like Chinese, Japanese, or accented letters) correctly—no more broken text or weird encoding issues!
Quick Tips
- Test first: Always test these changes on a staging site or local environment before pushing to production.
- Adjust conditions: Modify
is_single()to target specific post types (e.g.,is_singular('post')) or even pages if needed. - Dynamic banners: If your banner needs dynamic links or content, just update your template part—this code will pull in whatever you've built there automatically.
内容的提问来源于stack exchange,提问作者IXN

