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; } }