271 lines
10 KiB
PHP
271 lines
10 KiB
PHP
<?php
|
||
/**
|
||
* Custom RSS Feed for profile_article posts
|
||
*/
|
||
|
||
// Защита от прямого доступа
|
||
if (!defined('ABSPATH')) {
|
||
exit;
|
||
}
|
||
|
||
class CustomProfileArticleRSS {
|
||
|
||
public function __construct() {
|
||
add_action('init', [$this, 'add_rss_endpoint']);
|
||
add_action('template_redirect', [$this, 'generate_rss_feed']);
|
||
}
|
||
|
||
/**
|
||
* Добавляем endpoint для RSS ленты
|
||
*/
|
||
public function add_rss_endpoint() {
|
||
add_rewrite_rule(
|
||
'^rss-feed/?$',
|
||
'index.php?custom_rss_feed=1',
|
||
'top'
|
||
);
|
||
|
||
add_rewrite_tag('%custom_rss_feed%', '([^&]+)');
|
||
add_rewrite_tag('%rss_date%', '([^&]+)');
|
||
}
|
||
|
||
/**
|
||
* Генерируем RSS ленту
|
||
*/
|
||
public function generate_rss_feed() {
|
||
if (get_query_var('custom_rss_feed') || isset($_GET['rss-feed'])) {
|
||
$date = isset($_GET['date']) ? sanitize_text_field($_GET['date']) : date('Y-m-d');
|
||
|
||
// Валидация даты
|
||
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
|
||
$date = date('Y-m-d');
|
||
}
|
||
|
||
$this->output_rss_feed($date);
|
||
exit;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Получаем URL иконки сайта
|
||
*/
|
||
private function get_site_icon_url() {
|
||
$site_icon_id = get_option('site_icon');
|
||
if ($site_icon_id) {
|
||
return wp_get_attachment_image_url($site_icon_id, 'full');
|
||
}
|
||
|
||
// Fallback на логотип или дефолтную иконку
|
||
$custom_logo_id = get_theme_mod('custom_logo');
|
||
if ($custom_logo_id) {
|
||
return wp_get_attachment_image_url($custom_logo_id, 'full');
|
||
}
|
||
|
||
return home_url('/wp-admin/images/wordpress-logo.png');
|
||
}
|
||
|
||
|
||
private function get_clean_post_content($post) {
|
||
|
||
$content = apply_filters('the_content', $post->post_content);
|
||
|
||
// Удаляем запрещенные для Турбо элементы
|
||
$content = preg_replace('/<script\b[^>]*>.*?<\/script>/is', '', $content);
|
||
$content = preg_replace('/<style\b[^>]*>.*?<\/style>/is', '', $content);
|
||
$content = preg_replace('/<iframe\b[^>]*>.*?<\/iframe>/is', '', $content);
|
||
$content = preg_replace('/<form\b[^>]*>.*?<\/form>/is', '', $content);
|
||
$content = preg_replace('/<input[^>]*>/is', '', $content);
|
||
$content = preg_replace('/<button[^>]*>.*?<\/button>/is', '', $content);
|
||
$content = preg_replace('/<select[^>]*>.*?<\/select>/is', '', $content);
|
||
$content = preg_replace('/<textarea[^>]*>.*?<\/textarea>/is', '', $content);
|
||
$content = str_replace('<p></p>', '', $content);
|
||
|
||
// Удаляем определенные классы
|
||
$content = preg_replace('/<div[^>]*class="[^"]*(ads|advert|banner|social|share|widget|comments)[^"]*"[^>]*>.*?<\/div>/is', '', $content);
|
||
|
||
// Разрешаем только турбо-совместимые теги
|
||
$allowed_tags = [
|
||
'p' => ['class' => [], 'style' => []],
|
||
'br' => [],
|
||
'strong' => [],
|
||
'em' => [],
|
||
'b' => [],
|
||
'i' => [],
|
||
'ul' => [],
|
||
'ol' => [],
|
||
'li' => [],
|
||
'h1' => [],
|
||
'h2' => [],
|
||
'h3' => [],
|
||
'h4' => [],
|
||
'h5' => [],
|
||
'h6' => [],
|
||
'a' => ['href' => [], 'title' => []],
|
||
'img' => ['src' => [], 'alt' => [], 'title' => [], 'width' => [], 'height' => []],
|
||
'blockquote' => [],
|
||
'figure' => [],
|
||
'header' => [],
|
||
];
|
||
|
||
$content = wp_kses($content, $allowed_tags);
|
||
|
||
return $content;
|
||
}
|
||
|
||
/**
|
||
* Формируем XML ленту
|
||
*/
|
||
private function output_rss_feed($date) {
|
||
global $wpdb;
|
||
|
||
// Определяем диапазон дат: 7 дней до указанной даты
|
||
$end_date = $date; // указанная дата
|
||
$start_date = date('Y-m-d', strtotime($date . ' -6 days')); // 7 дней назад (включая указанную дату)
|
||
|
||
//такая лента формируется на каждую дату и содержит все статьи за 7 дней до указанной даты
|
||
$posts = $wpdb->get_results($wpdb->prepare("
|
||
SELECT *
|
||
FROM {$wpdb->posts}
|
||
WHERE post_type = 'profile_article'
|
||
AND post_status = 'publish'
|
||
AND DATE(post_date) BETWEEN %s AND %s
|
||
AND post_password = ''
|
||
AND ID NOT IN (
|
||
SELECT post_id
|
||
FROM {$wpdb->postmeta}
|
||
WHERE meta_key IN ('_no_aeroflot', '_is_advertisement', '_only_link_access', '_hide_on_website', '_hide_on_mainpage')
|
||
AND meta_value = '1'
|
||
)
|
||
ORDER BY post_date DESC
|
||
", $start_date, $end_date));
|
||
|
||
// Конвертируем в объекты WP_Post
|
||
$posts = array_map(function($post) {
|
||
return new WP_Post($post);
|
||
}, $posts);
|
||
|
||
// Устанавливаем заголовки
|
||
header('Content-Type: application/rss+xml; charset=' . get_option('blog_charset'), true);
|
||
|
||
// Начинаем вывод XML
|
||
echo '<?xml version="1.0" encoding="' . get_option('blog_charset') . '"?>';
|
||
?>
|
||
<rss version="2.0"
|
||
xmlns:yandex="http://news.yandex.ru"
|
||
xmlns:media="http://search.yahoo.com/mrss/"
|
||
xmlns:turbo="http://turbo.yandex.ru">
|
||
|
||
<channel>
|
||
<title><?php echo esc_xml(get_bloginfo('name')); ?></title>
|
||
<link><?php echo esc_url(home_url()); ?></link>
|
||
<description><?php echo esc_xml(get_bloginfo('description')); ?></description>
|
||
<language><?php echo esc_xml(get_bloginfo('language')); ?></language>
|
||
<lastBuildDate><?php echo esc_xml(gmdate(DATE_RSS)); ?></lastBuildDate>
|
||
<pubDate><?php echo esc_xml(gmdate(DATE_RSS)); ?></pubDate>
|
||
<guid>https://profile.ru</guid>
|
||
<generator>Информационное агенство Деловой журнал Профиль</generator>
|
||
<image>
|
||
<url><?php echo esc_url($this->get_site_icon_url()); ?></url>
|
||
<title><?php echo esc_xml(get_bloginfo('name')); ?></title>
|
||
<link><?php echo esc_url(home_url()); ?></link>
|
||
</image>
|
||
<?php if (empty($posts)): ?>
|
||
<item>
|
||
<title>No posts for period <?php echo esc_xml($start_date); ?> to <?php echo esc_xml($end_date); ?></title>
|
||
<link><?php echo esc_url(home_url()); ?></link>
|
||
<description>No posts found for this period</description>
|
||
<pubDate><?php echo esc_xml(gmdate(DATE_RSS)); ?></pubDate>
|
||
<guid isPermaLink="false">no-posts-<?php echo esc_xml($start_date . '-to-' . $end_date); ?></guid>
|
||
</item>
|
||
<?php else: ?>
|
||
<?php foreach ($posts as $post):
|
||
$post = new WP_Post($post);
|
||
$post_url = get_permalink($post->ID);
|
||
$post_date = gmdate(DATE_RSS, strtotime($post->post_date_gmt));
|
||
$excerpt = get_the_excerpt($post->ID);
|
||
$content = $this->get_clean_post_content($post);
|
||
$thumbnail = get_the_post_thumbnail_url($post->ID, 'large');
|
||
// Получаем авторов из плагина Co-Authors
|
||
$authors = get_coauthors($post->ID);
|
||
?>
|
||
<item>
|
||
<title><?php echo esc_xml(get_the_title($post->ID)); ?></title>
|
||
<link><?php echo esc_url($post_url); ?></link>
|
||
<description><?php echo esc_xml($excerpt); ?></description>
|
||
<pubDate><?php echo esc_xml($post_date); ?></pubDate>
|
||
<?php if (!empty($authors)): ?>
|
||
<?php
|
||
$author_names = array();
|
||
foreach ($authors as $author) {
|
||
$author_names[] = $author->display_name;
|
||
}
|
||
?>
|
||
<author><?php echo esc_xml(implode(', ', $author_names)); ?></author>
|
||
<?php else: ?>
|
||
<?php $default_author = get_the_author_meta('display_name', $post->post_author); ?>
|
||
<author><?php echo esc_xml($default_author); ?></author>
|
||
<?php endif; ?>
|
||
<guid><?php echo esc_url($post_url); ?></guid>
|
||
<?php if ($thumbnail): ?>
|
||
<imageAnnounce>
|
||
<url><?php echo esc_url($thumbnail); ?></url>
|
||
<title><?php echo esc_xml(get_the_title($post->ID)); ?></title>
|
||
<description><?php echo esc_xml($excerpt); ?></description>
|
||
</imageAnnounce>
|
||
<?php endif; ?>
|
||
<?php if ($thumbnail): ?>
|
||
<image>
|
||
<url><?php echo esc_url($thumbnail); ?></url>
|
||
<title><?php echo esc_xml(get_the_title($post->ID)); ?></title>
|
||
<description><?php echo esc_xml($excerpt); ?></description>
|
||
<link><?php echo esc_url($post_url); ?></link>
|
||
</image>
|
||
<?php endif; ?>
|
||
<?php
|
||
$categories = get_the_category($post->ID);
|
||
foreach ($categories as $category) {
|
||
echo '<category>' . esc_xml($category->name) . '</category>';
|
||
}
|
||
?>
|
||
<content:encoded>
|
||
<![CDATA[<?php echo $content; ?>]]>
|
||
</content:encoded>
|
||
</item>
|
||
<?php endforeach; ?>
|
||
<?php endif; ?>
|
||
|
||
</channel>
|
||
</rss>
|
||
<?php
|
||
}
|
||
|
||
/**
|
||
* Получаем контент поста
|
||
*/
|
||
private function get_post_content($post) {
|
||
$content = apply_filters('the_content', $post->post_content);
|
||
$content = str_replace(']]>', ']]>', $content);
|
||
return $content;
|
||
}
|
||
|
||
/**
|
||
* Активация - сбрасываем rewrite rules
|
||
*/
|
||
public static function activate() {
|
||
flush_rewrite_rules();
|
||
}
|
||
|
||
/**
|
||
* Деактивация - чистим rewrite rules
|
||
*/
|
||
public static function deactivate() {
|
||
flush_rewrite_rules();
|
||
}
|
||
}
|
||
|
||
// Инициализация
|
||
new CustomProfileArticleRSS();
|
||
|
||
// Хуки активации/деактивации
|
||
register_activation_hook(__FILE__, ['CustomProfileArticleRSS', 'activate']);
|
||
register_deactivation_hook(__FILE__, ['CustomProfileArticleRSS', 'deactivate']);
|