Wyodrębnianie i zastępowanie treści postów HTML za pomocą PHP DOM
Pracuję nad aktualizacją/zastąpieniem niektórych danych w postach na blogu WordPress (ponad 1000) z 2 kategorii, z których muszę wyodrębnić określoną treść HTML z dwóch tagów p i zastąpić jeden z tagów p nową treścią. Próbuję kierować reklamy na określone elementy w kodzie HTML, takie jak link/obraz i cena/obniżona cena. Jakakolwiek pomoc byłaby bardzo mile widziana.
Próbuję wydobyć z tego elementu rabat i pierwotną cenę. Z innej kategorii ten element jest opakowany w tagi del.
<p><span style="font-weight:bold;font-style: italic"><a target="_blank" href="
" rel="nofollow sponsored noopener">117 EUR</a></span> instead of 296 EUR</p>
<p><span style="font-weight:bold;font-style: italic"><a target="_blank" href="
" rel="nofollow sponsored noopener"><del>117 EUR</del></a></span> instead of 296 EUR</p>
Próbuję także wyodrębnić adres URL i link do obrazu z tego elementu i zastąpić go nową strukturą HTML.
<p><a style="font-size: 26px;text-decoration: none" target="_blank" href="
" rel="nofollow sponsored noopener">Go to: <img decoding="async" width="130" style="border-radius:20px" src="wp-content/uploads/2023/07/image.png"></a> </p>
The new replace structure for the second HTML element is
To jest moja próba osiągnięcia pożądanego rezultatu, jednak z jakiegoś powodu pierwsze 6, 7 postów zostaje poprawnie zastąpionych, a następnie inne posty są zastępowane, ale zepsute. Treść jest taka sama w każdym poście, z wyjątkiem cen… Próbowałem z datą i zapytaniem podatkowym i bez nich, ale wynik był taki sam. Nie jestem zbyt dobry we wzorach wyrażeń regularnych, nie jestem pewien, czy to lub co jest przyczyną takiego zachowania.
$args = [
'post_type' => 'post',
'posts_per_page' => $limit,
'offset' => $offset,
'date_query' => [['after' => '1 month ago']],
'tax_query' => [[
'relation' => 'OR',
[ 'taxonomy' => 'category', 'field' => 'slug', 'terms' => ['category-1', 'category-2']],
]],
];
$query = new WP_Query($args);
if ($query->have_posts()) {
$processed_posts = 0;
while ($query->have_posts()) {
$query->the_post();
$post_id = get_the_ID();
$post_content = get_post_field('post_content', $post_id);
$dom = new DOMDocument();
@$dom->loadHTML(mb_convert_encoding($post_content, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);
error_log("Processing post ID: " . $post_id);
$oldStructure = $xpath->query("//a[contains(text(), 'Go to:') and @target="_blank" and @rel="nofollow sponsored noopener"]")->item(0);
error_log("XPath query result for post ID: " . $post_id . ": " . ($oldStructure ? "Found" : "Not found"));
if ($oldStructure) {
error_log("Old structure found!");
$productUrlNode = $xpath->query('//a[@style="font-size: 26px;text-decoration: none"]/@href')->item(0);
$productUrl = $productUrlNode ? $productUrlNode->nodeValue : '';
$imageSrcNode = $xpath->query('//p/a[@style="font-size: 26px;text-decoration: none"]/img/@src')->item(0);
$imageSrc = $imageSrcNode ? $imageSrcNode->nodeValue : '';
$discountPriceNodeQuery = "//p/span/a/del/text() | //p/span/a[not(del)]/text()";
$discountPriceNodes = $xpath->query($discountPriceNodeQuery);
$discountPrice="";
foreach ($discountPriceNodes as $node) {
$textContent = $node->nodeValue;
if (preg_match('/(\d+)/', $textContent, $matches)) {
$discountPrice = $matches[1];
break;
}
}
$originalPrice="";
$pNodeTexts = $xpath->query("//p[contains(., 'instead of')]");
foreach ($pNodeTexts as $textNode) {
if (preg_match('/instead of (\d+)/', $textNode->nodeValue, $matches)) {
$originalPrice = $matches[1];
break;
}
}
$pElement = $dom->createElement('p');
$anchor = $dom->createElement('a');
$anchor->setAttribute('href', esc_url($productUrl));
$anchor->setAttribute('class', 'product-link_wrap');
$anchor->setAttribute('target', '_blank');
$buttonBlock = $dom->createElement('div');
$buttonBlock->setAttribute('class', 'button-block');
$anchor->appendChild($buttonBlock);
$buttonImage = $dom->createElement('div');
$buttonImage->setAttribute('class', 'button-image');
$img = $dom->createElement('img');
$img->setAttribute('src', esc_url($imageSrc));
$img->setAttribute('alt', 'Product Image');
$img->setAttribute('class', 'webpexpress-processed');
$buttonImage->appendChild($img);
$buttonBlock->appendChild($buttonImage);
$productTitle = $dom->createElement('div');
$productTitle->setAttribute('class', 'product-title');
$productName = $dom->createElement('span', esc_html(get_the_title($post_id)));
$productName->setAttribute('class', 'product-name');
$productTitle->appendChild($productName);
$buttonBlock->appendChild($productTitle);
$productPrices = $dom->createElement('div');
$productPrices->setAttribute('class', 'prices-container');
$productOriginalPrice = $dom->createElement('span', esc_html($originalPrice));
$productDiscountPrice = $dom->createElement('span', esc_html($discountPrice));
$productPrices->appendChild($productOriginalPrice);
$productPrices->appendChild($productDiscountPrice);
$buttonBlock->appendChild($productPrices);
$buttonContainer = $dom->createElement('div');
$buttonContainer->setAttribute('class', 'button-container');
$button = $dom->createElement('button');
$button->setAttribute('class', 'product-button');
$span = $dom->createElement('span', 'Go to Product');
$button->appendChild($span);
$svg = $dom->createElement('svg');
$svg->setAttribute('xmlns', '
$svg->setAttribute('enable-background', 'new 0 0 24 24');
$svg->setAttribute('viewBox', '0 0 24 24');
$path = $dom->createElement('path');
$path->setAttribute('d', 'M15.5,11.3L9.9,5.6c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l4.9,4.9l-4.9,4.9c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.6,0.4,1,1,1c0.3,0,0.5-0.1,0.7-0.3l5.7-5.7c0,0,0,0,0,0C15.9,12.3,15.9,11.7,15.5,11.3z');
$svg->appendChild($path);
$button->appendChild($svg);
$buttonContainer->appendChild($button);
$buttonBlock->appendChild($buttonContainer);
$pElement->appendChild($anchor);
$oldStructure->parentNode->replaceChild($anchor, $oldStructure);
$updated_content = $dom->saveHTML();
error_log("New content: " . $updated_content);
$result = wp_update_post([
'ID' => $post_id,
'post_content' => $updated_content,
]);
if ($result === 0 || $result === false) {
error_log("Failed to update post ID: " . $post_id);
} else {
error_log("Successfully updated post ID: " . $post_id);
}
To jest poprawnie zastąpiony element:
[29-Feb-2024 11:26:21 UTC] Processing post ID: 56526
[29-Feb-2024 11:26:21 UTC] XPath query result for post ID: 56526: Found
[29-Feb-2024 11:26:21 UTC] Old structure found!
[29-Feb-2024 11:26:21 UTC] Img:
[29-Feb-2024 11:26:21 UTC] URL:
[29-Feb-2024 11:26:21 UTC] discount: 12
[29-Feb-2024 11:26:21 UTC] original: 133
Nieprawidłowo wymieniony element:
[29-Feb-2024 11:26:21 UTC] Processing post ID: 56510
[29-Feb-2024 11:26:21 UTC] XPath query result for post ID: 56510: Found
[29-Feb-2024 11:26:21 UTC] Old structure found!
[29-Feb-2024 11:26:21 UTC] Img:
[29-Feb-2024 11:26:21 UTC] URL:
[29-Feb-2024 11:26:21 UTC] discount:
[29-Feb-2024 11:26:21 UTC] original: 340
Zakładam, że niepoprawnie wymieniony element jest usuwany ze znacznika p, co powoduje jego uszkodzenie…
<span style="font-weight: bold; font-style: italic;"><a href="" target="_blank" rel="nofollow sponsored noopener">28 EUR</a></span> instead of 340 EUR