PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / trunk
Yoast SEO – Advanced SEO with real-time guidance and built-in AI vtrunk
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
wordpress-seo / src / schema-aggregator / infrastructure / schema_map / schema-map-wordpress-repository.php

schema-map-wordpress-repository.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI trunk, at src/schema-aggregator/infrastructure/schema_map/schema-map-wordpress-repository.php

113 lines 3.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure.
3 namespace Yoast\WP\SEO\Schema_Aggregator\Infrastructure\Schema_Map;
4
5 use Exception;
6 use Yoast\WP\SEO\Repositories\Indexable_Repository;
7 use Yoast\WP\SEO\Schema_Aggregator\Domain\Indexable_Count;
8 use Yoast\WP\SEO\Schema_Aggregator\Domain\Indexable_Count_Collection;
9
10 /**
11 * Class Schema_Map_WordPress_Repository
12 *
13 * Maps indexable repository queries for schema map needs.
14 */
15 class Schema_Map_WordPress_Repository implements Schema_Map_Repository_Interface {
16
17 /**
18 * The indexable repository.
19 *
20 * @var Indexable_Repository
21 */
22 private $indexable_repository;
23
24 /**
25 * Schema_Map_Indexable_Repository constructor.
26 *
27 * @param Indexable_Repository $indexable_repository The indexable repository.
28 */
29 public function __construct( Indexable_Repository $indexable_repository ) {
30 $this->indexable_repository = $indexable_repository;
31 }
32
33 /**
34 * Gets the indexable count per post type.
35 *
36 * @param array<string> $post_types The post types to get the indexable count for.
37 *
38 * @return Indexable_Count_Collection The indexable count per post type.
39 */
40 public function get_indexable_count_per_post_type( array $post_types ): Indexable_Count_Collection {
41 $post_type_counts = new Indexable_Count_Collection();
42 foreach ( $post_types as $post_type ) {
43 $count = (int) \wp_count_posts( $post_type )->publish;
44 $post_type_counts->add_indexable_count( new Indexable_Count( $post_type, $count ) );
45 }
46
47 return $post_type_counts;
48 }
49
50 /**
51 * Gets the indexable count for a single post type.
52 *
53 * @param string $post_type The post type to get the indexable count for.
54 *
55 * @return Indexable_Count The indexable count for the post type.
56 */
57 public function get_indexable_count_for_post_type( string $post_type ): Indexable_Count {
58
59 $count = (int) \wp_count_posts( $post_type )->publish;
60 if ( empty( $count ) ) {
61 return new Indexable_Count( $post_type, 0 );
62 }
63
64 return new Indexable_Count( $post_type, $count );
65 }
66
67 /**
68 * Get lastmod timestamp for a post type and page range
69 *
70 * Returns the latest post_modified_gmt timestamp for posts in the given range.
71 * Used for schemamap index to enable selective updates.
72 *
73 * @param string $post_type Post type slug.
74 * @param int $page Page number (1-indexed).
75 * @param int $per_page Items per page.
76 * @return string ISO 8601 timestamp (e.g., "2025-10-21T14:23:17Z").
77 */
78 public function get_lastmod_for_post_type( string $post_type, int $page, int $per_page ): string {
79 global $wpdb;
80 $fallback = \gmdate( 'Y-m-d\TH:i:s\Z' );
81
82 try {
83 $offset = ( ( $page - 1 ) * $per_page );
84 // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
85 // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: Most performant way.
86 $lastmod = $wpdb->get_var(
87 $wpdb->prepare(
88 "SELECT MAX(post_modified_gmt)
89 FROM (
90 SELECT post_modified_gmt
91 FROM {$wpdb->posts}
92 WHERE post_type = %s
93 AND post_status = 'publish'
94 ORDER BY ID
95 LIMIT %d OFFSET %d
96 ) AS posts_range",
97 $post_type,
98 $per_page,
99 $offset,
100 ),
101 );
102 // phpcs:enable
103 // Convert to ISO 8601 format or use current time if no posts.
104 if ( $lastmod && ! empty( $lastmod ) ) {
105 return \gmdate( 'Y-m-d\TH:i:s\Z', \strtotime( $lastmod ) );
106 }
107 return $fallback;
108 } catch ( Exception $e ) {
109 return $fallback;
110 }
111 }
112 }
113