134 lines
5.0 KiB
PHP
134 lines
5.0 KiB
PHP
<?php
|
|
namespace AIOSEO\Plugin\Pro\Sitemap;
|
|
|
|
// Exit if accessed directly.
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
use AIOSEO\Plugin\Common\Sitemap as CommonSitemap;
|
|
|
|
/**
|
|
* Handles all complex queries for the sitemap.
|
|
*
|
|
* @since 4.0.0
|
|
*/
|
|
class Query extends CommonSitemap\Query {
|
|
/**
|
|
* Returns all eligible sitemap entries for a given taxonomy.
|
|
*
|
|
* @since 4.0.0
|
|
*
|
|
* @param string $taxonomy The taxonomy.
|
|
* @param array $additionalArgs Any additional arguments for the term query.
|
|
* @return array|int The term objects or the term count.
|
|
*/
|
|
public function terms( $taxonomy, $additionalArgs = [] ) {
|
|
// Let's just make sure the tables exist. This should never be a problem outside of our dev environments.
|
|
if ( ! aioseo()->core->db->tableExists( 'aioseo_terms' ) ) {
|
|
aioseo()->updates->addInitialCustomTablesForV4();
|
|
}
|
|
|
|
// Set defaults.
|
|
$fields = 't.term_id, at.priority, at.frequency, tt.count';
|
|
$offset = aioseo()->sitemap->offset;
|
|
|
|
// Include term name for llms sitemap type
|
|
if ( 'llms' === aioseo()->sitemap->type ) {
|
|
$fields .= ', t.name';
|
|
}
|
|
|
|
// Override defaults if passed as additional arg.
|
|
foreach ( $additionalArgs as $name => $value ) {
|
|
$$name = esc_sql( $value );
|
|
if ( 'root' === $name && $value ) {
|
|
$fields = 't.term_id';
|
|
}
|
|
if ( 'count' === $name && $value ) {
|
|
$fields = 'count(t.term_id) as total';
|
|
}
|
|
}
|
|
|
|
$termRelationshipsTable = aioseo()->core->db->db->prefix . 'term_relationships';
|
|
|
|
// Determine the robots meta conditions based on whether the taxonomy is noindexed.
|
|
// For noindexed taxonomies, we only include terms that have explicitly set robots_noindex to false.
|
|
// For indexed taxonomies, we include terms where robots_noindex is null, default, or explicitly false.
|
|
$isTaxonomyNoindexed = aioseo()->helpers->isTaxonomyNoindexed( $taxonomy );
|
|
|
|
// Include all terms that have assigned posts or whose children have assigned posts.
|
|
// The term also needs to be indexed and not excluded.
|
|
// Optimized query: replaced IN subquery with direct JOIN on term_taxonomy,
|
|
// and replaced EXISTS subquery with LEFT JOIN for child term checking.
|
|
if ( $isTaxonomyNoindexed ) {
|
|
// For noindexed taxonomies, only include terms that have explicitly opted in (robots_default = 0 AND robots_noindex = 0).
|
|
// Use INNER JOIN since we need matching records in aioseo_terms.
|
|
$query = aioseo()->core->db
|
|
->start( aioseo()->core->db->db->terms . ' as t', true )
|
|
->select( $fields )
|
|
->join( 'aioseo_terms as at', '`at`.`term_id` = `t`.`term_id` AND `at`.`robots_default` = 0 AND `at`.`robots_noindex` = 0' )
|
|
->join( 'term_taxonomy as tt', "`tt`.`term_id` = `t`.`term_id` AND `tt`.`taxonomy` = '$taxonomy'" )
|
|
->leftJoin( 'term_taxonomy as child', '`child`.`parent` = `tt`.`term_id` AND `child`.`count` > 0' );
|
|
} else {
|
|
// For indexed taxonomies, include terms where noindex is null, default, or explicitly false.
|
|
// Use LEFT JOIN on aioseo_terms to include terms without AIOSEO records.
|
|
$query = aioseo()->core->db
|
|
->start( aioseo()->core->db->db->terms . ' as t', true )
|
|
->select( $fields )
|
|
->leftJoin( 'aioseo_terms as at', '`at`.`term_id` = `t`.`term_id`' )
|
|
->join( 'term_taxonomy as tt', "`tt`.`term_id` = `t`.`term_id` AND `tt`.`taxonomy` = '$taxonomy'" )
|
|
->leftJoin( 'term_taxonomy as child', '`child`.`parent` = `tt`.`term_id` AND `child`.`count` > 0' );
|
|
|
|
// For indexed taxonomies, filter to include terms where noindex is null, default, or explicitly false.
|
|
$query->whereRaw( '( `at`.`robots_noindex` IS NULL OR `at`.`robots_default` = 1 OR `at`.`robots_noindex` = 0 )' );
|
|
}
|
|
|
|
// Include terms that have posts or whose children have posts.
|
|
$query->whereRaw( '( `tt`.`count` > 0 OR `child`.`term_id` IS NOT NULL )' );
|
|
|
|
// Group by term_id to prevent duplicate rows from the LEFT JOIN on child terms.
|
|
$query->groupBy( 't.term_id' );
|
|
|
|
// Exclude terms with custom canonical URLs pointing to different URLs.
|
|
$query->whereRaw( "( `at`.`canonical_url` IS NULL OR `at`.`canonical_url` = '' )" );
|
|
|
|
$excludedTerms = aioseo()->sitemap->helpers->excludedTerms();
|
|
if ( $excludedTerms ) {
|
|
$query->whereRaw("
|
|
( `t`.`term_id` NOT IN
|
|
(
|
|
SELECT `tr`.`term_taxonomy_id`
|
|
FROM `$termRelationshipsTable` as tr
|
|
WHERE `tr`.`term_taxonomy_id` IN ( $excludedTerms )
|
|
)
|
|
)" );
|
|
}
|
|
|
|
if (
|
|
aioseo()->sitemap->indexes &&
|
|
empty( $additionalArgs['root'] ) &&
|
|
( empty( $additionalArgs['count'] ) || ! $additionalArgs['count'] )
|
|
) {
|
|
$query->limit( aioseo()->sitemap->linksPerIndex, $offset );
|
|
}
|
|
|
|
// Return the total if we are just counting the terms.
|
|
if ( ! empty( $additionalArgs['count'] ) && $additionalArgs['count'] ) {
|
|
return (int) $query->run( true, 'var' )
|
|
->result();
|
|
}
|
|
|
|
$terms = $query->orderBy( 't.term_id ASC' )
|
|
->run()
|
|
->result();
|
|
|
|
foreach ( $terms as $term ) {
|
|
// Convert ID from string to int.
|
|
$term->term_id = (int) $term->term_id;
|
|
// Add taxonomy name to object manually instead of querying it to prevent redundant join.
|
|
$term->taxonomy = $taxonomy;
|
|
}
|
|
|
|
return $terms;
|
|
}
|
|
} |