add files inc

This commit is contained in:
Profile Profile
2026-03-09 20:51:08 +03:00
parent 83ca6c638a
commit ed4d79b706
23 changed files with 3728 additions and 4 deletions

271
inc/article-rss-feed.php Normal file
View File

@@ -0,0 +1,271 @@
<?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(']]>', ']]&gt;', $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']);