NicholasB

includes/modules/sitemap/html-sitemap/class-posts.php

Nov 14th, 2023 (edited)
35
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 8.59 KB | None | 0 0
  1. <?php
  2. /**
  3.  * The HTML sitemap generator for posts.
  4.  *
  5.  * @since      1.0.104
  6.  * @package    RankMath
  7.  * @subpackage RankMath\Sitemap
  8.  * @author     Rank Math <support@rankmath.com>
  9.  */
  10.  
  11. namespace RankMath\Sitemap\Html;
  12.  
  13. use RankMath\Helper;
  14. use RankMath\Traits\Hooker;
  15. use RankMath\Admin\Database\Database;
  16. use RankMath\Sitemap\Sitemap as SitemapBase;
  17.  
  18. defined( 'ABSPATH' ) || exit;
  19.  
  20. /**
  21.  * Posts class.
  22.  */
  23. class Posts {
  24.  
  25.     use Hooker;
  26.  
  27.     private $children = [];
  28.  
  29.     /**
  30.      * Get all posts from a given post type.
  31.      *
  32.      * @param string $post_type   Post type.
  33.      * @param int    $post_parent Post parent.
  34.      *
  35.      * @return array
  36.      */
  37.     private function get_posts( $post_type, $post_parent = 0 ) {
  38.         global $wpdb;
  39.         $sort_map = [
  40.             'published' => [
  41.                 'field' => 'post_date',
  42.                 'order' => 'DESC',
  43.             ],
  44.             'modified'  => [
  45.                 'field' => 'post_modified',
  46.                 'order' => 'DESC',
  47.             ],
  48.             'alphabetical' => [
  49.                 'field' => 'post_title',
  50.                 'order' => 'ASC',
  51.             ],
  52.             'post_id' => [
  53.                 'field' => 'ID',
  54.                 'order' => 'DESC',
  55.             ],
  56.         ];
  57.  
  58.         $sort_setting = Helper::get_settings( 'sitemap.html_sitemap_sort' );
  59.         $sort = ( isset( $sort_map[ $sort_setting ] ) ) ? $sort_map[ $sort_setting ] : $sort_map['published'];
  60.  
  61.         /**
  62.          * Filter: 'rank_math/sitemap/html_sitemap/sort_items' - Allow changing the sort order of the HTML sitemap.
  63.          *
  64.          * @var array $sort {
  65.          *    @type string $field The field to sort by.
  66.          *    @type string $order The sort order.
  67.          * }
  68.          * @var string $post_type The post type name.
  69.          * @var string $order     The item type.
  70.          */
  71.         $sort = $this->do_filter( 'sitemap/html_sitemap/sort_items', $sort, 'posts', $post_type );
  72.  
  73.         $statuses = [ 'publish' ];
  74.  
  75.         /**
  76.          * Filter: 'rank_math/sitemap/html_sitemap_post_statuses' - Allow changing the post statuses that should be included in the sitemap.
  77.          *
  78.          * @var array  $statuses Post statuses.
  79.          * @var string $post_type Post type name.
  80.          */
  81.         $statuses = $this->do_filter( 'sitemap/html_sitemap_post_statuses', $statuses, $post_type );
  82.         //$get_child = ( 0 !== $post_parent ) ? ' WHERE post_parent = ' . $post_parent : '';
  83.         $get_child = ! empty( $post_parent) ?   ' WHERE post_parent IN (' . join(',',$post_parent) . ')' : '';
  84.         $sql       = "
  85.             SELECT l.ID, post_title, post_name, post_parent, post_date, post_type, l.post_modified
  86.             FROM (
  87.                 SELECT DISTINCT p.ID, p.post_modified FROM {$wpdb->posts} as p
  88.                 LEFT JOIN {$wpdb->postmeta} AS pm ON ( p.ID = pm.post_id AND pm.meta_key = 'rank_math_robots' )
  89.                 WHERE (
  90.                     ( pm.meta_key = 'rank_math_robots' AND pm.meta_value NOT LIKE '%noindex%' ) OR
  91.                     pm.post_id IS NULL
  92.                 )
  93.                 AND p.post_type IN ( '" . $post_type . "' ) AND p.post_status IN ( '" . join( "', '", esc_sql( $statuses ) ) . "' )
  94.                 ORDER BY p.post_modified DESC
  95.             )
  96.             o JOIN {$wpdb->posts} l ON l.ID = o.ID " . $get_child . " ORDER BY " . $sort['field'] . " " . $sort['order']; // phpcs:ignore
  97.         $posts = $wpdb->get_results( $wpdb->prepare( $sql ) ); // phpcs:ignore
  98.         return $posts;
  99.     }
  100.  
  101.     /**
  102.      * Generate the HTML sitemap for a given post type.
  103.      *
  104.      * @param string $post_type Post type name.
  105.      * @param bool   $show_dates Whether to show dates.
  106.      *
  107.      * @return string
  108.      */
  109.     public function generate_sitemap( $post_type, $show_dates ) {
  110.         $posts = $this->get_posts( $post_type );
  111.  
  112.         if ( empty( $posts ) ) {
  113.             return '';
  114.         }
  115.  
  116.         $output[] = '<div class="rank-math-html-sitemap__section rank-math-html-sitemap__section--post-type rank-math-html-sitemap__section--' . $post_type . '">';
  117.         $output[] = '<h2 class="rank-math-html-sitemap__title">' . esc_html( get_post_type_object( $post_type )->labels->name ) . '</h2>';
  118.         $output[] = '<ul class="rank-math-html-sitemap__list">';
  119.         $output[] = $this->generate_posts_list( $posts, $show_dates, $post_type );
  120.         $output[] = '</ul>';
  121.         $output[] = '</div>';
  122.  
  123.         $output = implode( '', $output );
  124.  
  125.         return $output;
  126.     }
  127.  
  128.     /**
  129.      * Generate the post list HTML.
  130.      *
  131.      * @param array  $posts Array of posts.
  132.      * @param bool   $show_dates Whether to show dates.
  133.      * @param string $post_type Post type name.
  134.      *
  135.      * @return string
  136.      */
  137.     private function generate_posts_list( $posts, $show_dates, $post_type ) {
  138.         if ( empty( $posts ) ) {
  139.             return '';
  140.         }
  141.  
  142.         if ( is_post_type_hierarchical( $post_type ) ) {
  143.             $post_ids = array_map(function ($post){
  144.                 return $post->ID;
  145.             }, $posts);
  146.             // @TODO have the parents as the index keys.
  147.             $children = $this->get_posts( $post_type, $post_ids );
  148.             foreach ( $children as $child ) {
  149.                 $this->children[ $child->post_parent ][] = $child;
  150.             }
  151.  
  152.             // Just a hack like GROUP BY @TODO implement group by instead
  153.             // No need to GROUP BY as a parent can have multiple children
  154.             $posts = $this->remove_with_parent($posts);
  155.             return $this->generate_posts_list_hierarchical( $posts, $show_dates, $post_type );
  156.         }
  157.  
  158.         return $this->generate_posts_list_flat( $posts, $show_dates );
  159.     }
  160.  
  161.     /**
  162.      * Get the post list HTML for non-hierarchical post types.
  163.      *
  164.      * @param array $posts The posts to output.
  165.      * @param bool  $show_dates Whether to show the post dates.
  166.      *
  167.      * @return string
  168.      */
  169.     private function generate_posts_list_flat( $posts, $show_dates ) {
  170.         $output = [];
  171.         foreach ( $posts as $post ) {
  172.             $url = $this->do_filter( 'sitemap/entry', esc_url( $this->get_post_link( $post ) ), 'post', $post );
  173.             if ( empty( $url ) ) {
  174.                 continue;
  175.             }
  176.  
  177.             $output[] = '<li class="rank-math-html-sitemap__item">'
  178.                 . '<a href="' . esc_url( $this->get_post_link( $post ) ) . '" class="rank-math-html-sitemap__link">'
  179.                 . esc_html( $this->get_post_title( $post ) )
  180.                 . '</a>'
  181.                 . ( $show_dates ? ' <span class="rank-math-html-sitemap__date">(' . esc_html( mysql2date( get_option( 'date_format' ), $post->post_date ) ) . ')</span>' : '' )
  182.                 . '</li>';
  183.         }
  184.  
  185.         return implode( '', $output );
  186.     }
  187.  
  188.     /**
  189.      * Get the post list HTML for hierarchical post types. This will output the
  190.      * posts in a nested list.
  191.      *
  192.      * @param array  $posts      The posts to output.
  193.      * @param bool   $show_dates Whether to show the post dates.
  194.      * @param string $post_type  Post type name.
  195.      *
  196.      * @return string
  197.      */
  198.     private function generate_posts_list_hierarchical( $posts, $show_dates, $post_type, $child = false ) {
  199.         $output  = [];
  200.         $exclude = wp_parse_id_list( Helper::get_settings( 'sitemap.exclude_posts' ) );
  201.  
  202.         foreach ( $posts as $post ) {
  203.             $check_parent_index = empty( $post->post_parent ) ? 0 : SitemapBase::is_object_indexable( $post->post_parent );
  204.             if ( ( ! $check_parent_index || $child ) && ! in_array( $post->ID, $exclude ) ) {
  205.                 $output[] = '<li class="rank-math-html-sitemap__item">'
  206.                 . '<a href="' . esc_url( get_permalink( $post->ID ) ) . '" class="rank-math-html-sitemap__link">'
  207.                 . esc_html( $this->get_post_title( $post ) )
  208.                 . '</a>'
  209.                 . ( $show_dates ? ' <span class="rank-math-html-sitemap__date">(' . esc_html( mysql2date( get_option( 'date_format' ), $post->post_date ) ) . ')</span>' : '' );
  210.             }
  211.  
  212.             if ( ! empty( $this->children ) && ! empty(  $this->children[ $post->ID ] ) ) {
  213.                 ! in_array( $post->ID, $exclude ) ? $output[] = '<ul class="rank-math-html-sitemap__list">' : '';
  214.                 $output[] = $this->generate_posts_list_hierarchical(  $this->children[ $post->ID ], $show_dates, $post_type, true ); // phpcs:ignore
  215.                 ! in_array( $post->ID, $exclude ) ? $output[] = '</ul>' : '';
  216.             }
  217.  
  218.             ( ! $check_parent_index || $child ) && ! in_array( $post->ID, $exclude ) ? $output[] = '</li>' : '';
  219.         }
  220.  
  221.         return implode( '', $output );
  222.     }
  223.  
  224.     /**
  225.      * Get the post permalink.
  226.      *
  227.      * @param object $post The post object.
  228.      *
  229.      * @return string
  230.      */
  231.     private function get_post_link( $post ) {
  232.         return get_permalink( $post->ID );
  233.     }
  234.  
  235.     /**
  236.      * Get the post title.
  237.      *
  238.      * @param object $post The post data.
  239.      *
  240.      * @return string
  241.      */
  242.     private function get_post_title( $post ) {
  243.         if ( Helper::get_settings( 'sitemap.html_sitemap_seo_titles' ) !== 'seo_titles' ) {
  244.             return $post->post_title;
  245.         }
  246.  
  247.         // Custom SEO title.
  248.         $meta = get_post_meta( $post->ID, 'rank_math_title', true );
  249.         if ( ! empty( $meta ) ) {
  250.             return Helper::replace_vars( $meta, get_post( $post->ID ) );
  251.         }
  252.  
  253.         // Default SEO title from the global settings.
  254.         $template = Helper::get_settings( "titles.pt_{$post->post_type}_title" );
  255.         if ( ! empty( $template ) ) {
  256.             return Helper::replace_vars( $template, get_post( $post->ID ) );
  257.         }
  258.  
  259.         // Fallback to post title.
  260.         return $post->post_title;
  261.     }
  262.  
  263.     private function remove_with_parent($posts) {
  264.         return array_filter( $posts, function ( $post ) {
  265.             return ! $post->post_parent;
  266.         });
  267.     }
  268. }
  269.  
Add Comment
Please, Sign In to add comment