<?php
class ZP_Seo_Sitemap_Do_Sitemap  {
    private $sitemap_prefix; // Changed from constant to a variable
    private $max_items_per_sitemap;
    const SITEMAP_ZPTHEME = 'zptheme_sitemap'; // 定义常量用于AJAX动作前缀
    
    function __construct() {
        // 获取配置项
        $settings = get_option('zptheme_seo_sitemap_settings', array());
        $this->sitemap_prefix = isset($settings['sitemap_prefix']) ? $settings['sitemap_prefix'] : 'sitemap'; // 默认值为'sitemap'
        $this->max_items_per_sitemap = isset($settings['max_items']) ? (int)$settings['max_items'] : 2000; // 默认值为2000

        // 注册AJAX处理钩子
        add_action('wp_ajax_' . self::SITEMAP_ZPTHEME . '_do_sitemap', array($this, 'ajax_do_sitemap'));
        add_action('wp_ajax_' . self::SITEMAP_ZPTHEME . '_delete_sitemap', array($this, 'ajax_delete_sitemap'));
        add_action('transition_post_status', array($this, 'publish_do_xml'), 999, 3);

        // 在后台添加脚本
        add_action('admin_footer', array($this, 'sitemap_jquery'));
    }

    // 输出前端JavaScript
    public function sitemap_jquery() {
        ?>
        <script type="text/javascript">
        jQuery(document).ready(function($){
            $('#generate-sitemap').click(function(){
                $('#sitemap-progress').html('<?php _e('正在生成,请稍后...', 'textdomain'); ?>');
                $.ajax({
                    url: ajaxurl,
                    type: 'POST',
                    data: {
                        action: '<?php echo self::SITEMAP_ZPTHEME; ?>_do_sitemap',
                        nonce: '<?php echo wp_create_nonce(self::SITEMAP_ZPTHEME . '_do_sitemap'); ?>'
                    },
                    success: function(res) {
                        $('#sitemap-progress').html('');
                        $('.wrap').prepend(res);
                        location.reload(); // 刷新显示最新文件信息
                    },
                    error: function() {
                        $('#sitemap-progress').html('<div class="error"><?php _e('请求失败,请重试', 'textdomain'); ?></div>');
                    }
                });
            });
            
            $('#delete-sitemap').click(function(){
                if(!confirm('<?php _e('确定要删除所有Sitemap文件吗?', 'textdomain'); ?>')) return;
                $('#sitemap-progress').html('<?php _e('正在删除,请稍后...', 'textdomain'); ?>');
                $.ajax({
                    url: ajaxurl,
                    type: 'POST',
                    data: {
                        action: '<?php echo self::SITEMAP_ZPTHEME; ?>_delete_sitemap',
                        nonce: '<?php echo wp_create_nonce(self::SITEMAP_ZPTHEME . '_delete_sitemap'); ?>'
                    },
                    success: function(res) {
                        $('#sitemap-progress').html('');
                        $('.wrap').prepend(res);
                        location.reload();
                    }
                });
            });
        });
        </script>
        <?php
    }

    // AJAX生成Sitemap
    public function ajax_do_sitemap() {
        check_ajax_referer(self::SITEMAP_ZPTHEME . '_do_sitemap', 'nonce');
        
        try {
            $this->clean_old_sitemaps();
            $this->generate_all_sitemaps();
            $this->submit_sitemap_to_engines();
            $this->show_success_message();
        } catch (Exception $e) {
            $this->show_error_message($e->getMessage());
        }
        wp_die();
    }

    // 生成所有类型Sitemap
    private function generate_all_sitemaps() {
        $this->generate_post_sitemaps();
        $this->generate_taxonomy_sitemaps();
        $this->generate_index_sitemap();
    }

    // 生成文章类型Sitemap
    private function generate_post_sitemaps() {
        $post_types = $this->get_enabled_post_types();
        foreach ($post_types as $post_type) {
            $posts = $this->query_posts($post_type);
            $chunks = array_chunk($posts, $this->max_items_per_sitemap);
            foreach ($chunks as $index => $chunk) {
                $this->generate_post_sitemap($post_type, $chunk, $index + 1);
            }
        }
    }

    // 查询指定文章类型的文章
    private function query_posts($post_type) {
        $args = [
            'post_type'      => $post_type,
            'post_status'    => 'publish',
            'posts_per_page' => -1, // 获取所有文章
            'orderby'        => 'modified',
            'order'          => 'DESC',
            'fields'         => 'ids', // 只获取ID以提高性能
        ];

        $query = new WP_Query($args);
        if ($query->have_posts()) {
            return $query->posts;
        }
        return [];
    }

    // 生成单个文章类型Sitemap
    private function generate_post_sitemap($post_type, $posts, $page_num = 1) {
        $xml = '<?xml version="1.0" encoding="UTF-8"?>';
        $xml .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" 
                        xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
                        xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">';

        foreach ($posts as $post_id) {
            $post = get_post($post_id);
            $xml .= '<url>';
            $xml .= '<loc>' . esc_url(get_permalink($post)) . '</loc>';
            $xml .= '<lastmod>' . mysql2date('c', $post->post_modified_gmt) . '</lastmod>';
            $xml .= '<changefreq>' . $this->get_change_frequency($post) . '</changefreq>';
            $xml .= '<priority>' . $this->get_priority($post) . '</priority>';
            
            // 添加图片
            if ($this->include_images()) {
                foreach ($this->get_post_images($post->ID) as $image) {
                    $xml .= '<image:image><image:loc>' . esc_url($image) . '</image:loc></image:image>';
                }
            }
            
            $xml .= '</url>';
        }

        $xml .= '</urlset>';
        $filename = $this->sitemap_prefix . "-posts-{$post_type}-{$page_num}.xml";
        $this->save_sitemap($filename, $xml);
    }

    // 生成分类法Sitemap
    private function generate_taxonomy_sitemaps() {
        $taxonomies = $this->get_enabled_taxonomies();
        foreach ($taxonomies as $taxonomy) {
            $terms = get_terms(['taxonomy' => $taxonomy, 'hide_empty' => false]);
            $chunks = array_chunk($terms, $this->max_items_per_sitemap);
            foreach ($chunks as $index => $chunk) {
                $this->generate_taxonomy_sitemap($taxonomy, $chunk, $index + 1);
            }
        }
    }

    // 生成单个分类法Sitemap
    private function generate_taxonomy_sitemap($taxonomy, $terms, $page_num = 1) {
        $xml = '<?xml version="1.0" encoding="UTF-8"?>';
        $xml .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';

        foreach ($terms as $term) {
            $xml .= '<url>';
            $xml .= '<loc>' . esc_url(get_term_link($term)) . '</loc>';
            $xml .= '<lastmod>' . current_time('c') . '</lastmod>';
            $xml .= '<changefreq>weekly</changefreq>';
            $xml .= '<priority>0.5</priority>';
            $xml .= '</url>';
        }

        $xml .= '</urlset>';
        $filename = $this->sitemap_prefix . "-taxonomy-{$taxonomy}-{$page_num}.xml";
        $this->save_sitemap($filename, $xml);
    }

    // 生成索引Sitemap
    private function generate_index_sitemap() {
        $files = glob(ABSPATH . $this->sitemap_prefix . '*.xml');
        $xml = '<?xml version="1.0" encoding="UTF-8"?>';
        $xml .= '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemapindex/0.9">';

        foreach ($files as $file) {
            if (strpos($file, 'index') !== false) continue;
            $xml .= '<sitemap>';
            $xml .= '<loc>' . home_url('/' . basename($file)) . '</loc>';
            $xml .= '<lastmod>' . date('c', filemtime($file)) . '</lastmod>';
            $xml .= '</sitemap>';
        }

        $xml .= '</sitemapindex>';
        $this->save_sitemap($this->sitemap_prefix . '.xml', $xml);
    }

    // 提交Sitemap到搜索引擎
    private function submit_sitemap_to_engines() {
        $sitemap_url = home_url('/' . $this->sitemap_prefix . '.xml');
        
        // Google Ping
        wp_remote_get('https://www.google.com/webmasters/tools/ping?sitemap=' . urlencode($sitemap_url));
        
        // Bing Ping
        wp_remote_get('https://www.bing.com/webmaster/ping.aspx?sitemap=' . urlencode($sitemap_url));
        
        // 百度提交
        $settings = get_option('zptheme_seo_sitemap_settings', array());
        if (!empty($settings['baidu_token'])) {
            $api_url = "http://data.zz.baidu.com/urls?site=" . urlencode(home_url()) . "&token={$settings['baidu_token']}";
            $response = wp_remote_post($api_url, [
                'body'    => implode("\n", $this->get_all_urls()),
                'headers' => ['Content-Type' => 'text/plain']
            ]);
        }
    }

    // 获取所有URL
    private function get_all_urls() {
        $urls = [];
        $files = glob(ABSPATH . $this->sitemap_prefix . '*.xml');
        foreach ($files as $file) {
            if (strpos($file, 'index') !== false) continue;
            $xml = simplexml_load_file($file);
            foreach ($xml->url as $url) {
                $urls[] = (string)$url->loc;
            }
        }
        return $urls;
    }

    // 保存Sitemap文件
    private function save_sitemap($filename, $content) {
        $file = ABSPATH . $filename;
        if (!is_writable(ABSPATH)) {
            throw new Exception(__('网站根目录不可写,请检查权限!', 'textdomain'));
        }
        if (file_put_contents($file, $content) === false) {
            throw new Exception(sprintf(__('无法写入文件:%s,请检查权限!', 'textdomain'), $filename));
        }
    }

    // 清理旧的Sitemap文件
    private function clean_old_sitemaps() {
        $files = glob(ABSPATH . $this->sitemap_prefix . '*.xml');
        foreach ($files as $file) {
            if (is_file($file)) unlink($file);
        }
    }

    // 获取启用的文章类型
    private function get_enabled_post_types() {
        $settings = get_option('zptheme_seo_sitemap_settings', array());
        return isset($settings['post_types']) ? (array)$settings['post_types'] : ['post', 'page'];
    }

    // 获取启用的分类法
    private function get_enabled_taxonomies() {
        $settings = get_option('zptheme_seo_sitemap_settings', array());
        return isset($settings['taxonomies']) ? (array)$settings['taxonomies'] : ['category', 'post_tag'];
    }

    // 是否包含图片
    private function include_images() {
        $settings = get_option('zptheme_seo_sitemap_settings', array());
        return isset($settings['include_images']);
    }

    // 获取文章中的图片
    private function get_post_images($post_id) {
        $images = [];
        $content = get_post_field('post_content', $post_id);
        preg_match_all('/<img.+?src=[\'"]([^\'"]+)[\'"].*?>/i', $content, $matches);
        if (!empty($matches[1])) {
            $images = $matches[1];
        }
        return array_map([$this, 'normalize_image_url'], $images);
    }

    // 标准化图片URL
    private function normalize_image_url($url) {
        if (strpos($url, 'http') !== 0) {
            $url = home_url($url);
        }
        return $url;
    }

    // 获取更新频率
    private function get_change_frequency($post) {
        $diff = time() - strtotime($post->post_modified_gmt);
        if ($diff < 86400) return 'daily';
        if ($diff < 604800) return 'weekly';
        return 'monthly';
    }

    // 获取优先级
    private function get_priority($post) {
        if (is_front_page($post->ID)) return '1.0';
        if ($post->post_type === 'page') return '0.8';
        return '0.6';
    }

    // AJAX删除Sitemap
    public function ajax_delete_sitemap() {
        check_ajax_referer(self::SITEMAP_ZPTHEME . '_delete_sitemap', 'nonce');
        $this->clean_old_sitemaps();
        $this->show_success_message(__('Sitemap文件已成功删除', 'textdomain'));
        wp_die();
    }

    // 显示成功消息
    private function show_success_message($message = '') {
        $message = $message ?: __('Sitemap生成成功!', 'textdomain');
        echo '<div class="notice notice-success"><p>' . $message . '</p></div>';
    }

    // 显示错误消息
    private function show_error_message($message) {
        echo '<div class="notice notice-error"><p>' . $message . '</p></div>';
    }

    // 文章发布时自动更新Sitemap
    public function publish_do_xml($new_status, $old_status, $post) {
        $settings = get_option('zptheme_seo_sitemap_settings', array());
        if (isset($settings['auto_update']) && $new_status === 'publish') {
            try {
                $this->generate_all_sitemaps();
                $this->submit_sitemap_to_engines();
            } catch (Exception $e) {
                error_log('自动更新Sitemap失败:' . $e->getMessage());
            }
        }
    }
    
    /**
     * 获取 Sitemap 文件路径
     *
     * @return string Sitemap 文件的完整路径
     */
    static function get_sitemap_file() {
        $settings = get_option('zptheme_seo_sitemap_settings', array()); // 使用正确的选项名称
        $sitemap = isset($settings['sitemap_file']) ? $settings['sitemap_file'] : 'sitemap'; // 修正选项键名
        $file = ABSPATH . $sitemap . '.xml';
        return $file;
    }

    /**
     * 显示 Sitemap 文件消息
     */
    static function xml_notice() {
        $file = self::get_sitemap_file();
        if (file_exists($file)) {
            $size = @filesize($file);
            date_default_timezone_set(get_option('timezone_string'));
            $time = date('Y-m-d H:i:s', @filemtime($file));
            $notice = '<div id="setting-error-settings_updated" class="updated settings-error notice notice-success is-dismissible">';
            $notice .= '<p style="color:green;">Sitemap 文件已生成,大小:<strong>' . number_format($size / 1024, 2) . 'KB</strong>,生成时间:<strong>' . $time . '</strong>。</p>';
            $notice .= '<p>Sitemap 地址:<a href="' . esc_url(home_url('/' . basename($file))) . '" target="_blank">' . esc_url(home_url('/' . basename($file))) . '</a></p>';
            $notice .= '</div>';
        } else {
            $notice = '<div id="setting-error-settings_updated" class="error settings-error notice notice-error is-dismissible">';
            $notice .= '<p>Sitemap 文件未找到,请点击“生成 Sitemap”按钮创建。</p>';
            $notice .= '</div>';
        }
        echo $notice;
    }
}

new ZP_Seo_Sitemap_Do_Sitemap ();

 

版权声明:原创作品,未经允许不得转载,否则将追究法律责任。
本站资源有的自互联网收集整理,如果侵犯了您的合法权益,请联系本站我们会及时删除。
本站资源仅供研究、学习交流之用,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担。
本文链接:源头网https://www.58588885.com/24864.html
许可协议:《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权