| Current Path : /home/x/b/o/xbodynamge/namtation/wp-content/ |
| Current File : /home/x/b/o/xbodynamge/namtation/wp-content/Html.tar |
Query.php 0000666 00000014575 15114700360 0006377 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Sitemap\Html;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles all queries for the HTML sitemap.
*
* @since 4.1.3
*/
class Query {
/**
* Returns all eligible sitemap entries for a given post type.
*
* @since 4.1.3
*
* @param string $postType The post type.
* @param array $attributes The attributes.
* @return array The post objects.
*/
public function posts( $postType, $attributes ) {
$fields = '`ID`, `post_title`,';
$fields .= '`post_parent`, `post_date_gmt`, `post_modified_gmt`';
$orderBy = '';
switch ( $attributes['order_by'] ) {
case 'last_updated':
$orderBy = 'post_modified_gmt';
break;
case 'alphabetical':
$orderBy = 'post_title';
break;
case 'id':
$orderBy = 'ID';
break;
case 'publish_date':
default:
$orderBy = 'post_date_gmt';
break;
}
switch ( strtolower( $attributes['order'] ) ) {
case 'desc':
$orderBy .= ' DESC';
break;
default:
$orderBy .= ' ASC';
}
$query = aioseo()->core->db
->start( 'posts' )
->select( $fields )
->where( 'post_status', 'publish' )
->where( 'post_type', $postType );
$excludedPosts = $this->getExcludedObjects( $attributes );
if ( $excludedPosts ) {
$query->whereRaw( "( `ID` NOT IN ( $excludedPosts ) )" );
}
$posts = $query->orderBy( $orderBy )
->run()
->result();
foreach ( $posts as $post ) {
$post->ID = (int) $post->ID;
}
return $posts;
}
/**
* Returns all eligble sitemap entries for a given taxonomy.
*
* @since 4.1.3
*
* @param string $taxonomy The taxonomy name.
* @param array $attributes The attributes.
* @return array The term objects.
*/
public function terms( $taxonomy, $attributes = [] ) {
$fields = 't.term_id, t.name, tt.parent';
$termRelationshipsTable = aioseo()->core->db->db->prefix . 'term_relationships';
$termTaxonomyTable = aioseo()->core->db->db->prefix . 'term_taxonomy';
$orderBy = '';
switch ( $attributes['order_by'] ) {
case 'alphabetical':
$orderBy = 't.name';
break;
// We can only sort by date after getting the terms.
case 'id':
case 'publish_date':
case 'last_updated':
default:
$orderBy = 't.term_id';
break;
}
switch ( strtolower( $attributes['order'] ) ) {
case 'desc':
$orderBy .= ' DESC';
break;
default:
$orderBy .= ' ASC';
}
$query = aioseo()->core->db
->start( 'terms as t' )
->select( $fields )
->join( 'term_taxonomy as tt', 't.term_id = tt.term_id' )
->whereRaw( "
( `t`.`term_id` IN
(
SELECT `tt`.`term_id`
FROM `$termTaxonomyTable` as tt
WHERE `tt`.`taxonomy` = '$taxonomy'
AND `tt`.`count` > 0
)
)" );
$excludedTerms = $this->getExcludedObjects( $attributes, false );
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 )
)
)" );
}
$terms = $query->orderBy( $orderBy )
->run()
->result();
foreach ( $terms as $term ) {
$term->term_id = (int) $term->term_id;
$term->taxonomy = $taxonomy;
}
$shouldSort = false;
if ( 'last_updated' === $attributes['order_by'] ) {
$shouldSort = true;
foreach ( $terms as $term ) {
$term->timestamp = strtotime( aioseo()->sitemap->content->getTermLastModified( $term->term_id ) );
}
}
if ( 'publish_date' === $attributes['order_by'] ) {
$shouldSort = true;
foreach ( $terms as $term ) {
$term->timestamp = strtotime( $this->getTermPublishDate( $term->term_id ) );
}
}
if ( $shouldSort ) {
if ( 'asc' === strtolower( $attributes['order'] ) ) {
usort( $terms, function( $term1, $term2 ) {
return $term1->timestamp > $term2->timestamp ? 1 : 0;
} );
} else {
usort( $terms, function( $term1, $term2 ) {
return $term1->timestamp < $term2->timestamp ? 1 : 0;
} );
}
}
return $terms;
}
/**
* Returns a list of date archives that can be included.
*
* @since 4.1.3
*
* @return array The date archives.
*/
public function archives() {
$result = aioseo()->core->db
->start( 'posts', false, 'SELECT DISTINCT' )
->select( 'YEAR(post_date) AS year, MONTH(post_date) AS month' )
->where( 'post_type', 'post' )
->where( 'post_status', 'publish' )
->whereRaw( "post_password=''" )
->orderBy( 'year DESC' )
->orderBy( 'month DESC' )
->run()
->result();
$dates = [];
foreach ( $result as $date ) {
$dates[ $date->year ][ $date->month ] = 1;
}
return $dates;
}
/**
* Returns the publish date for a given term.
* This is the publish date of the oldest post that is assigned to the term.
*
* @since 4.1.3
*
* @param int $termId The term ID.
* @return int The publish date timestamp.
*/
public function getTermPublishDate( $termId ) {
$termRelationshipsTable = aioseo()->core->db->db->prefix . 'term_relationships';
$post = aioseo()->core->db
->start( 'posts as p' )
->select( 'MIN(`p`.`post_date_gmt`) as publish_date' )
->whereRaw( "
( `p`.`ID` IN
(
SELECT `tr`.`object_id`
FROM `$termRelationshipsTable` as tr
WHERE `tr`.`term_taxonomy_id` = '$termId'
)
)" )
->run()
->result();
return ! empty( $post[0]->publish_date ) ? strtotime( $post[0]->publish_date ) : 0;
}
/**
* Returns a comma-separated string of excluded object IDs.
*
* @since 4.1.3
*
* @param array $attributes The attributes.
* @param boolean $posts Whether the objects are posts.
* @return string The excluded object IDs.
*/
private function getExcludedObjects( $attributes, $posts = true ) {
$excludedObjects = $posts
? aioseo()->sitemap->helpers->excludedPosts()
: aioseo()->sitemap->helpers->excludedTerms();
$key = $posts ? 'excluded_posts' : 'excluded_terms';
if ( ! empty( $attributes[ $key ] ) ) {
$ids = explode( ',', $excludedObjects );
$extraIds = [];
if ( is_array( $attributes[ $key ] ) ) {
$extraIds = $attributes[ $key ];
}
if ( is_string( $attributes[ $key ] ) ) {
$extraIds = array_map( 'trim', explode( ',', $attributes[ $key ] ) );
}
$ids = array_filter( array_merge( $ids, $extraIds ), 'is_numeric' );
$excludedObjects = esc_sql( implode( ', ', $ids ) );
}
return $excludedObjects;
}
} Shortcode.php 0000666 00000001336 15114700360 0007213 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Sitemap\Html;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles the HTML sitemap shortcode.
*
* @since 4.1.3
*/
class Shortcode {
/**
* Class constructor.
*
* @since 4.1.3
*/
public function __construct() {
add_shortcode( 'aioseo_html_sitemap', [ $this, 'render' ] );
}
/**
* Shortcode callback.
*
* @since 4.1.3
*
* @param array $attributes The shortcode attributes.
* @return string|void The HTML sitemap.
*/
public function render( $attributes ) {
$attributes = aioseo()->htmlSitemap->frontend->getAttributes( $attributes );
return aioseo()->htmlSitemap->frontend->output( false, $attributes );
}
} Frontend.php 0000666 00000031777 15114700360 0007054 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Sitemap\Html;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles the output of the HTML sitemap.
*
* @since 4.1.3
*/
class Frontend {
/**
* Instance of Query class.
*
* @since 4.1.3
*
* @var Query
*/
public $query;
/**
* The attributes for the block/widget/shortcode.
*
* @since 4.1.3
*
* @var array
*/
private $attributes = [];
/**
* Class constructor.
*
* @since 4.1.3
*/
public function __construct() {
$this->query = new Query();
}
/**
* Returns the attributes.
*
* @since 4.1.3
*
* @param array $attributes The user-defined attributes
* @return array The defaults with user-defined attributes merged.
*/
public function getAttributes( $attributes = [] ) {
aioseo()->sitemap->type = 'html';
$defaults = [
'label_tag' => 'h4',
'show_label' => true,
'order' => aioseo()->options->sitemap->html->sortDirection,
'order_by' => aioseo()->options->sitemap->html->sortOrder,
'nofollow_links' => false,
'publication_date' => aioseo()->options->sitemap->html->publicationDate,
'archives' => aioseo()->options->sitemap->html->compactArchives,
'post_types' => aioseo()->sitemap->helpers->includedPostTypes(),
'taxonomies' => aioseo()->sitemap->helpers->includedTaxonomies(),
'excluded_posts' => [],
'excluded_terms' => [],
'is_admin' => false
];
$attributes = shortcode_atts( $defaults, $attributes );
$attributes['show_label'] = filter_var( $attributes['show_label'], FILTER_VALIDATE_BOOLEAN );
$attributes['nofollow_links'] = filter_var( $attributes['nofollow_links'], FILTER_VALIDATE_BOOLEAN );
$attributes['is_admin'] = filter_var( $attributes['is_admin'], FILTER_VALIDATE_BOOLEAN );
return $attributes;
}
/**
* Formats the publish date according to what's set under Settings > General.
*
* @since 4.1.3
*
* @param string $date The date that should be formatted.
* @return string The formatted date.
*/
private function formatDate( $date ) {
$dateFormat = apply_filters( 'aioseo_html_sitemap_date_format', get_option( 'date_format' ) );
return date_i18n( $dateFormat, strtotime( $date ) );
}
/**
* Returns the posts of a given post type that should be included.
*
* @since 4.1.3
*
* @param string $postType The post type.
* @param array $additionalArgs Additional arguments for the post query (optional).
* @return array The post entries.
*/
private function posts( $postType, $additionalArgs = [] ) {
$posts = $this->query->posts( $postType, $additionalArgs );
if ( ! $posts ) {
return [];
}
$entries = [];
foreach ( $posts as $post ) {
$entry = [
'id' => $post->ID,
'title' => get_the_title( $post ),
'loc' => get_permalink( $post->ID ),
'date' => $this->formatDate( $post->post_date_gmt ),
'parent' => ! empty( $post->post_parent ) ? $post->post_parent : null
];
$entries[] = $entry;
}
return apply_filters( 'aioseo_html_sitemap_posts', $entries, $postType );
}
/**
* Returns the terms of a given taxonomy that should be included.
*
* @since 4.1.3
*
* @param string $taxonomy The taxonomy name.
* @param array $additionalArgs Additional arguments for the query (optional).
* @return array The term entries.
*/
private function terms( $taxonomy, $additionalArgs = [] ) {
$terms = $this->query->terms( $taxonomy, $additionalArgs );
if ( ! $terms ) {
return [];
}
$entries = [];
foreach ( $terms as $term ) {
$entries[] = [
'id' => $term->term_id,
'title' => $term->name,
'loc' => get_term_link( $term->term_id ),
'parent' => ! empty( $term->parent ) ? $term->parent : null
];
}
return apply_filters( 'aioseo_html_sitemap_terms', $entries, $taxonomy );
}
/**
* Outputs the sitemap to the frontend.
*
* @since 4.1.3
*
* @param bool $echo Whether the sitemap should be printed to the screen.
* @param array $attributes The shortcode attributes.
* @return string|void The HTML sitemap.
*/
public function output( $echo = true, $attributes = [] ) {
$this->attributes = $attributes;
if ( ! aioseo()->options->sitemap->html->enable ) {
return;
}
aioseo()->sitemap->type = 'html';
if ( filter_var( $attributes['archives'], FILTER_VALIDATE_BOOLEAN ) ) {
return ( new CompactArchive() )->output( $attributes, $echo );
}
if ( ! empty( $attributes['default'] ) ) {
$attributes = $this->getAttributes();
}
$noResultsMessage = esc_html__( 'No posts/terms could be found.', 'all-in-one-seo-pack' );
if ( empty( $this->attributes['post_types'] ) && empty( $this->attributes['taxonomies'] ) ) {
if ( $echo ) {
echo $noResultsMessage; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
return $noResultsMessage;
}
// TODO: Consider moving all remaining HTML code below to a dedicated view instead of printing it in PHP.
$sitemap = sprintf(
'<div class="aioseo-html-sitemap%s">',
! $this->attributes['show_label'] ? ' labels-hidden' : ''
);
$sitemap .= '<style>.aioseo-html-sitemap.labels-hidden ul { margin: 0; }</style>';
$hasPosts = false;
$postTypes = $this->getIncludedObjects( $this->attributes['post_types'] );
foreach ( $postTypes as $postType ) {
if ( 'attachment' === $postType ) {
continue;
}
// Check if post type is still registered.
if ( ! in_array( $postType, aioseo()->helpers->getPublicPostTypes( true ), true ) ) {
continue;
}
$posts = $this->posts( $postType, $attributes );
if ( empty( $posts ) ) {
continue;
}
$hasPosts = true;
$postTypeObject = get_post_type_object( $postType );
$label = ! empty( $postTypeObject->label ) ? $postTypeObject->label : ucfirst( $postType );
$sitemap .= '<div class="aioseo-html-' . esc_attr( $postType ) . '-sitemap">';
$sitemap .= $this->generateLabel( $label );
if ( is_post_type_hierarchical( $postType ) ) {
$sitemap .= $this->generateHierarchicalList( $posts ) . '</div>';
if ( $this->attributes['show_label'] ) {
$sitemap .= '<br />';
}
continue;
}
$sitemap .= $this->generateList( $posts );
if ( $this->attributes['show_label'] ) {
$sitemap .= '<br />';
}
}
$hasTerms = false;
$taxonomies = $this->getIncludedObjects( $this->attributes['taxonomies'], false );
foreach ( $taxonomies as $taxonomy ) {
// Check if post type is still registered.
if ( ! in_array( $taxonomy, aioseo()->helpers->getPublicTaxonomies( true ), true ) ) {
continue;
}
$terms = $this->terms( $taxonomy, $attributes );
if ( empty( $terms ) ) {
continue;
}
$hasTerms = true;
$taxonomyObject = get_taxonomy( $taxonomy );
$label = ! empty( $taxonomyObject->label ) ? $taxonomyObject->label : ucfirst( $taxonomy );
$sitemap .= '<div class="aioseo-html-' . esc_attr( $taxonomy ) . '-sitemap">';
$sitemap .= $this->generateLabel( $label );
if ( is_taxonomy_hierarchical( $taxonomy ) ) {
$sitemap .= $this->generateHierarchicalList( $terms ) . '</div>';
if ( $this->attributes['show_label'] ) {
$sitemap .= '<br />';
}
continue;
}
$sitemap .= $this->generateList( $terms );
if ( $this->attributes['show_label'] ) {
$sitemap .= '<br />';
}
}
$sitemap .= '</div>';
// Check if we actually were able to fetch any results.
if ( ! $hasPosts && ! $hasTerms ) {
$sitemap = $noResultsMessage;
}
if ( $echo ) {
echo $sitemap; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
return $sitemap;
}
/**
* Generates the label for a section of the sitemap.
*
* @since 4.1.3
*
* @param string $label The label.
* @return string The HTML code for the label.
*/
private function generateLabel( $label ) {
$labelTag = ! empty( $this->attributes['label_tag'] ) ? $this->attributes['label_tag'] : 'h4';
return $this->attributes['show_label']
? wp_kses_post( sprintf( '<%2$s>%1$s</%2$s>', $label, $labelTag ) )
: '';
}
/**
* Generates the HTML for a non-hierarchical list of objects.
*
* @since 4.1.3
*
* @param array $objects The object.
* @return string The HTML code.
*/
private function generateList( $objects ) {
$list = '<ul>';
foreach ( $objects as $object ) {
$list .= $this->generateListItem( $object ) . '</li>';
}
return $list . '</ul></div>';
}
/**
* Generates a list item for an object (without the closing tag).
* We cannot close it as the caller might need to generate a hierarchical structure inside the list item.
*
* @since 4.1.3
*
* @param array $object The object.
* @return string The HTML code.
*/
private function generateListItem( $object ) {
$li = '';
if ( ! empty( $object['title'] ) ) {
$li .= '<li>';
// add nofollow to the link.
if ( filter_var( $this->attributes['nofollow_links'], FILTER_VALIDATE_BOOLEAN ) ) {
$li .= sprintf(
'<a href="%1$s" %2$s %3$s>',
esc_url( $object['loc'] ),
'rel="nofollow"',
$this->attributes['is_admin'] ? 'target="_blank"' : ''
);
} else {
$li .= sprintf(
'<a href="%1$s" %2$s>',
esc_url( $object['loc'] ),
$this->attributes['is_admin'] ? 'target="_blank"' : ''
);
}
$li .= sprintf( '%s', esc_attr( $object['title'] ) );
// add publication date on the list item.
if ( ! empty( $object['date'] ) && filter_var( $this->attributes['publication_date'], FILTER_VALIDATE_BOOLEAN ) ) {
$li .= sprintf( ' (%s)', esc_attr( $object['date'] ) );
}
$li .= '</a>';
}
return $li;
}
/**
* Generates the HTML for a hierarchical list of objects.
*
* @since 4.1.3
*
* @param array $objects The objects.
* @return string The HTML of the hierarchical objects section.
*/
private function generateHierarchicalList( $objects ) {
if ( empty( $objects ) ) {
return '';
}
$objects = $this->buildHierarchicalTree( $objects );
$list = '<ul>';
foreach ( $objects as $object ) {
$list .= $this->generateListItem( $object );
if ( ! empty( $object['children'] ) ) {
$list .= $this->generateHierarchicalTree( $object );
}
$list .= '</li>';
}
$list .= '</ul>';
return $list;
}
/**
* Recursive helper function for generateHierarchicalList().
* Generates hierarchical structure for objects with child objects.
*
* @since 4.1.3
*
* @param array $object The object.
* @return string The HTML code of the hierarchical tree.
*/
private function generateHierarchicalTree( $object ) {
static $nestedLevel = 0;
$tree = '<ul>';
foreach ( $object['children'] as $child ) {
$nestedLevel++;
$tree .= $this->generateListItem( $child );
if ( ! empty( $child['children'] ) ) {
$tree .= $this->generateHierarchicalTree( $child );
}
$tree .= '</li>';
}
$tree .= '</ul>';
return $tree;
}
/**
* Builds the structure for hierarchical objects that have a parent.
*
* @since 4.1.3
* @version 4.2.8
*
* @param array $objects The list of hierarchical objects.
* @return array Multidimensional array with the hierarchical structure.
*/
private function buildHierarchicalTree( $objects ) {
$topLevelIds = [];
$objects = json_decode( wp_json_encode( $objects ) );
foreach ( $objects as $listItem ) {
// Create an array of top level IDs for later reference.
if ( empty( $listItem->parent ) ) {
array_push( $topLevelIds, $listItem->id );
}
// Create an array of children that belong to the current item.
$children = array_filter( $objects, function( $child ) use ( $listItem ) {
if ( ! empty( $child->parent ) ) {
return absint( $child->parent ) === absint( $listItem->id );
}
} );
if ( ! empty( $children ) ) {
$listItem->children = $children;
}
}
// Remove child objects from the root level since they've all been nested.
$objects = array_filter( $objects, function ( $item ) use ( $topLevelIds ) {
return in_array( $item->id, $topLevelIds, true );
} );
return array_values( json_decode( wp_json_encode( $objects ), true ) );
}
/**
* Returns the names of the included post types or taxonomies.
*
* @since 4.1.3
*
* @param array|string $objects The included post types/taxonomies.
* @param boolean $arePostTypes Whether the objects are post types.
* @return array The names of the included post types/taxonomies.
*/
private function getIncludedObjects( $objects, $arePostTypes = true ) {
if ( is_array( $objects ) ) {
return $objects;
}
if ( empty( $objects ) ) {
return [];
}
$exploded = explode( ',', $objects );
$objects = array_map( function( $object ) {
return trim( $object );
}, $exploded );
$publicObjects = $arePostTypes
? aioseo()->helpers->getPublicPostTypes( true )
: aioseo()->helpers->getPublicTaxonomies( true );
$objects = array_filter( $objects, function( $object ) use ( $publicObjects ) {
return in_array( $object, $publicObjects, true );
});
return $objects;
}
} Block.php 0000666 00000006636 15114700360 0006323 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Sitemap\Html;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles the HTML sitemap block.
*
* @since 4.1.3
*/
class Block {
/**
* Class constructor.
*
* @since 4.1.1
*/
public function __construct() {
add_action( 'init', [ $this, 'register' ] );
}
/**
* Registers the block.
*
* @since 4.1.3
*
* @return void
*/
public function register() {
aioseo()->blocks->registerBlock(
'aioseo/html-sitemap', [
'attributes' => [
'default' => [
'type' => 'boolean',
'default' => true
],
'post_types' => [
'type' => 'string',
'default' => wp_json_encode( [ 'post', 'page' ] )
],
'post_types_all' => [
'type' => 'boolean',
'default' => true
],
'taxonomies' => [
'type' => 'string',
'default' => wp_json_encode( [ 'category', 'post_tag' ] )
],
'taxonomies_all' => [
'type' => 'boolean',
'default' => true
],
'show_label' => [
'type' => 'boolean',
'default' => true
],
'archives' => [
'type' => 'boolean',
'default' => false
],
'publication_date' => [
'type' => 'boolean',
'default' => true
],
'nofollow_links' => [
'type' => 'boolean',
'default' => false
],
'order_by' => [
'type' => 'string',
'default' => 'publish_date'
],
'order' => [
'type' => 'string',
'default' => 'asc'
],
'excluded_posts' => [
'type' => 'string',
'default' => wp_json_encode( [] )
],
'excluded_terms' => [
'type' => 'string',
'default' => wp_json_encode( [] )
],
'is_admin' => [
'type' => 'boolean',
'default' => false
]
],
'render_callback' => [ $this, 'render' ],
'editor_style' => 'aioseo-html-sitemap'
]
);
}
/**
* Renders the block.
*
* @since 4.1.3
*
* @param array $attributes The attributes.
* @return string The HTML sitemap code.
*/
public function render( $attributes ) {
if ( ! $attributes['default'] ) {
$jsonFields = [ 'post_types', 'taxonomies', 'excluded_posts', 'excluded_terms' ];
foreach ( $attributes as $k => $v ) {
if ( in_array( $k, $jsonFields, true ) ) {
$attributes[ $k ] = json_decode( $v );
}
}
$attributes['excluded_posts'] = $this->extractIds( $attributes['excluded_posts'] );
$attributes['excluded_terms'] = $this->extractIds( $attributes['excluded_terms'] );
if ( ! empty( $attributes['post_types_all'] ) ) {
$attributes['post_types'] = aioseo()->helpers->getPublicPostTypes( true );
}
if ( ! empty( $attributes['taxonomies_all'] ) ) {
$attributes['taxonomies'] = aioseo()->helpers->getPublicTaxonomies( true );
}
} else {
$attributes = [];
}
$attributes = aioseo()->htmlSitemap->frontend->getAttributes( $attributes );
return aioseo()->htmlSitemap->frontend->output( false, $attributes );
}
/**
* Extracts the IDs from the excluded objects.
*
* @since 4.1.3
*
* @param array $objects The objects.
* @return array The object IDs.
*/
private function extractIds( $objects ) {
return array_map( function ( $object ) {
$object = json_decode( $object );
return (int) $object->value;
}, $objects );
}
} Sitemap.php 0000666 00000014025 15114700360 0006662 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Sitemap\Html {
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Main class for the HTML sitemap.
*
* @since 4.1.3
*/
class Sitemap {
/** Instance of the frontend class.
*
* @since 4.1.3
*
* @var Frontend
*/
public $frontend;
/**
* Instance of the shortcode class.
*
* @since 4.1.3
*
* @var Shortcode
*/
public $shortcode;
/**
* Instance of the block class.
*
* @since 4.1.3
*
* @var Block
*/
public $block;
/**
* Whether the current queried page is the dedicated sitemap page.
*
* @since 4.1.3
*
* @var bool
*/
public $isDedicatedPage = false;
/**
* Class constructor.
*
* @since 4.1.3
*/
public function __construct() {
$this->frontend = new Frontend();
$this->shortcode = new Shortcode();
$this->block = new Block();
add_action( 'widgets_init', [ $this, 'registerWidget' ] );
add_filter( 'aioseo_canonical_url', [ $this, 'getCanonicalUrl' ] );
if ( ! is_admin() || wp_doing_ajax() || wp_doing_cron() ) {
add_action( 'template_redirect', [ $this, 'checkForDedicatedPage' ] );
}
}
/**
* Register our HTML sitemap widget.
*
* @since 4.1.3
*
* @return void
*/
public function registerWidget() {
if ( aioseo()->helpers->canRegisterLegacyWidget( 'aioseo-html-sitemap-widget' ) ) {
register_widget( 'AIOSEO\Plugin\Common\Sitemap\Html\Widget' );
}
}
/**
* Checks whether the current request is for our dedicated HTML sitemap page.
*
* @since 4.1.3
*
* @return void
*/
public function checkForDedicatedPage() {
if ( ! aioseo()->options->sitemap->html->enable ) {
return;
}
global $wp;
$sitemapUrl = aioseo()->options->sitemap->html->pageUrl;
if ( ! $sitemapUrl || empty( $wp->request ) ) {
return;
}
$sitemapUrl = wp_parse_url( $sitemapUrl );
if ( empty( $sitemapUrl['path'] ) ) {
return;
}
$sitemapUrl = trim( $sitemapUrl['path'], '/' );
if ( trim( $wp->request, '/' ) === $sitemapUrl ) {
$this->isDedicatedPage = true;
$this->generatePage();
}
}
/**
* Checks whether the current request is for our dedicated HTML sitemap page.
*
* @since 4.1.3
*
* @return void
*/
private function generatePage() {
global $wp_query, $wp, $post; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$postId = -1337; // Set a negative ID to prevent conflicts with existing posts.
$sitemapUrl = aioseo()->options->sitemap->html->pageUrl;
$path = trim( wp_parse_url( $sitemapUrl )['path'], '/' );
$fakePost = new \stdClass();
$fakePost->ID = $postId;
$fakePost->post_author = 1;
$fakePost->post_date = current_time( 'mysql' );
$fakePost->post_date_gmt = current_time( 'mysql', 1 );
$fakePost->post_title = apply_filters( 'aioseo_html_sitemap_page_title', __( 'Sitemap', 'all-in-one-seo-pack' ) );
$fakePost->post_content = '[aioseo_html_sitemap archives=false]';
// We're using post instead of page to prevent calls to get_ancestors(), which will trigger errors.
// To loead the page template, we set is_page to true on the WP_Query object.
$fakePost->post_type = 'post';
$fakePost->post_status = 'publish';
$fakePost->comment_status = 'closed';
$fakePost->ping_status = 'closed';
$fakePost->post_name = $path;
$fakePost->filter = 'raw'; // Needed to prevent calls to the database when creating the WP_Post object.
$postObject = new \WP_Post( $fakePost );
$post = $postObject;
// We'll set as much properties on the WP_Query object as we can to prevent conflicts with other plugins/themes.
// phpcs:disable Squiz.NamingConventions.ValidVariableName
$wp_query->is_404 = false;
$wp_query->is_page = true;
$wp_query->is_singular = true;
$wp_query->post = $postObject;
$wp_query->posts = [ $postObject ];
$wp_query->queried_object = $postObject;
$wp_query->queried_object_id = $postId;
$wp_query->found_posts = 1;
$wp_query->post_count = 1;
$wp_query->max_num_pages = 1;
unset( $wp_query->query['error'] );
$wp_query->query_vars['error'] = '';
// phpcs:enable Squiz.NamingConventions.ValidVariableName
// We need to add the post object to the cache so that get_post() calls don't trigger database calls.
wp_cache_add( $postId, $postObject, 'posts' );
$GLOBALS['wp_query'] = $wp_query; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$wp->register_globals();
// Setting is_404 is not sufficient, so we still need to change the status code.
status_header( 200 );
}
/**
* Get the canonical URL for the dedicated HTML sitemap page.
*
* @since 4.5.7
*
* @param string $originalUrl The canonical URL.
* @return string The canonical URL.
*/
public function getCanonicalUrl( $originalUrl ) {
$sitemapOptions = aioseo()->options->sitemap->html;
if ( ! $sitemapOptions->enable || ! $this->isDedicatedPage ) {
return $originalUrl;
}
// If the user has set a custom URL for the sitemap page, use that.
if ( $sitemapOptions->pageUrl ) {
return $sitemapOptions->pageUrl;
}
// Return the current URL of WP.
global $wp;
return home_url( $wp->request );
}
}
}
namespace {
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! function_exists( 'aioseo_html_sitemap' ) ) {
/**
* Global function that can be used to print the HTML sitemap.
*
* @since 4.1.3
*
* @param array $attributes User-defined attributes that override the default settings.
* @param boolean $echo Whether to echo the output or return it.
* @return string The HTML sitemap code.
*/
function aioseo_html_sitemap( $attributes = [], $echo = true ) {
$attributes = aioseo()->htmlSitemap->frontend->getAttributes( $attributes );
return aioseo()->htmlSitemap->frontend->output( $echo, $attributes );
}
}
} CompactArchive.php 0000666 00000005677 15114700360 0010165 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Sitemap\Html;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles the Compact Archive's output.
*
* @since 4.1.3
*/
class CompactArchive {
/**
* The shortcode attributes.
*
* @since 4.1.3
*
* @var array
*/
private $attributes;
/**
* Outputs the compact archives sitemap.
*
* @since 4.1.3
*
* @param array $attributes The shortcode attributes.
* @param boolean $echo Whether the HTML code should be printed or returned.
* @return string The HTML for the compact archive.
*/
public function output( $attributes, $echo = true ) {
$dateArchives = ( new Query() )->archives();
$this->attributes = $attributes;
if ( 'asc' === strtolower( $this->attributes['order'] ) ) {
$dateArchives = array_reverse( $dateArchives, true );
}
$data = [
'dateArchives' => $dateArchives,
'lines' => ''
];
foreach ( $dateArchives as $year => $months ) {
$data['lines'] .= $this->generateYearLine( $year, $months ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
ob_start();
aioseo()->templates->getTemplate( 'sitemap/html/compact-archive.php', $data );
$output = ob_get_clean();
if ( $echo ) {
echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
return $output;
}
// phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
/**
* Generates the HTML for a year line.
*
* @since 4.1.3
*
* @param int $year The year archive.
* @param array $months The month archives for the current year.
* @return string The HTML code for the year.
*/
protected function generateYearLine( $year, $months ) {
$html = '<li><strong><a href="' . get_year_link( $year ) . '">' . esc_html( $year ) . '</a>: </strong> ';
for ( $month = 1; $month <= 12; $month++ ) {
$html .= $this->generateMonth( $year, $months, $month );
}
$html .= '</li>' . "\n";
return wp_kses_post( $html );
}
/**
* Generates the HTML for a month.
*
* @since 4.1.3
*
* @param int $year The year archive.
* @param array $months All month archives for the current year.
* @param int $month The month archive.
* @return string The HTML code for the month.
*/
public function generateMonth( $year, $months, $month ) {
$hasPosts = isset( $months[ $month ] );
$dummyDate = strtotime( "2009/{$month}/25" );
$monthAbbrevation = date_i18n( 'M', $dummyDate );
$html = '<span class="aioseo-empty-month">' . esc_html( $monthAbbrevation ) . '</span> ';
if ( $hasPosts ) {
$noFollow = filter_var( $this->attributes['nofollow_links'], FILTER_VALIDATE_BOOLEAN );
$html = sprintf(
'<a href="%1$s" title="%2$s"%3$s>%4$s</a> ',
get_month_link( $year, $month ),
esc_attr( date_i18n( 'F Y', $dummyDate ) ),
$noFollow ? ' rel="nofollow"' : '',
esc_html( $monthAbbrevation )
);
}
return $html;
}
} Widget.php 0000666 00000013607 15114700360 0006510 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Sitemap\Html;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Class Widget.
*
* @since 4.1.3
*/
class Widget extends \WP_Widget {
/**
* The default attributes.
*
* @since 4.2.7
*
* @var array
*/
private $defaults = [];
/**
* Class constructor.
*
* @since 4.1.3
*/
public function __construct() {
// The default widget settings.
$this->defaults = [
'title' => '',
'show_label' => 'on',
'archives' => '',
'nofollow_links' => '',
'order' => 'asc',
'order_by' => 'publish_date',
'publication_date' => 'on',
'post_types' => [ 'post', 'page' ],
'taxonomies' => [ 'category', 'post_tag' ],
'excluded_posts' => '',
'excluded_terms' => ''
];
$widgetSlug = 'aioseo-html-sitemap-widget';
$widgetOptions = [
'classname' => $widgetSlug,
// Translators: The short plugin name ("AIOSEO").
'description' => sprintf( esc_html__( '%1$s HTML sitemap widget.', 'all-in-one-seo-pack' ), AIOSEO_PLUGIN_SHORT_NAME )
];
$controlOptions = [
'id_base' => $widgetSlug
];
// Translators: 1 - The plugin short name ("AIOSEO").
$name = sprintf( esc_html__( '%1$s - HTML Sitemap', 'all-in-one-seo-pack' ), AIOSEO_PLUGIN_SHORT_NAME );
$name .= ' ' . esc_html__( '(legacy)', 'all-in-one-seo-pack' );
parent::__construct( $widgetSlug, $name, $widgetOptions, $controlOptions );
}
/**
* Callback for the widget.
*
* @since 4.1.3
*
* @param array $args The widget arguments.
* @param array $instance The widget instance options.
* @return void
*/
public function widget( $args, $instance ) {
if ( ! aioseo()->options->sitemap->html->enable ) {
return;
}
// Merge with defaults.
$instance = wp_parse_args( (array) $instance, $this->defaults );
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
if ( ! empty( $instance['title'] ) ) {
echo $args['before_title'] . apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped,Generic.Files.LineLength.MaxExceeded
}
$instance = aioseo()->htmlSitemap->frontend->getAttributes( $instance );
aioseo()->htmlSitemap->frontend->output( true, $instance );
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* Callback to update the widget options.
*
* @since 4.1.3
*
* @param array $newOptions The new options.
* @param array $oldOptions The old options.
* @return array The new options.
*/
public function update( $newOptions, $oldOptions ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
$settings = [
'title',
'order',
'order_by',
'show_label',
'publication_date',
'archives',
'excluded_posts',
'excluded_terms'
];
foreach ( $settings as $setting ) {
$newOptions[ $setting ] = ! empty( $newOptions[ $setting ] ) ? wp_strip_all_tags( $newOptions[ $setting ] ) : '';
}
$includedPostTypes = [];
if ( ! empty( $newOptions['post_types'] ) ) {
$postTypes = $this->getPublicPostTypes( true );
foreach ( $newOptions['post_types'] as $v ) {
if ( is_numeric( $v ) ) {
$includedPostTypes[] = $postTypes[ $v ];
} else {
$includedPostTypes[] = $v;
}
}
}
$newOptions['post_types'] = $includedPostTypes;
$includedTaxonomies = [];
if ( ! empty( $newOptions['taxonomies'] ) ) {
$taxonomies = aioseo()->helpers->getPublicTaxonomies( true );
foreach ( $newOptions['taxonomies'] as $v ) {
if ( is_numeric( $v ) ) {
$includedTaxonomies[] = $taxonomies[ $v ];
} else {
$includedTaxonomies[] = $v;
}
}
}
$newOptions['taxonomies'] = $includedTaxonomies;
if ( ! empty( $newOptions['excluded_posts'] ) ) {
$newOptions['excluded_posts'] = $this->sanitizeExcludedIds( $newOptions['excluded_posts'] );
}
if ( ! empty( $newOptions['excluded_terms'] ) ) {
$newOptions['excluded_terms'] = $this->sanitizeExcludedIds( $newOptions['excluded_terms'] );
}
return $newOptions;
}
/**
* Callback for the widgets options form.
*
* @since 4.1.3
*
* @param array $instance The widget options.
* @return void
*/
public function form( $instance ) {
// phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
$instance = wp_parse_args( (array) $instance, $this->defaults );
$postTypeObjects = $this->getPublicPostTypes();
$postTypes = $this->getPublicPostTypes( true );
$taxonomyObjects = aioseo()->helpers->getPublicTaxonomies();
// phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
include AIOSEO_DIR . '/app/Common/Views/sitemap/html/widget-options.php';
}
/**
* Returns the public post types (without attachments).
*
* @since 4.1.3
*
* @param boolean $namesOnly Whether only the names should be returned.
* @return array The public post types.
*/
private function getPublicPostTypes( $namesOnly = false ) {
$postTypes = aioseo()->helpers->getPublicPostTypes( $namesOnly );
foreach ( $postTypes as $k => $postType ) {
if ( is_array( $postType ) && 'attachment' === $postType['name'] ) {
unset( $postTypes[ $k ] );
break;
}
if ( ! is_array( $postType ) && 'attachment' === $postType ) {
unset( $postTypes[ $k ] );
break;
}
}
return array_values( $postTypes );
}
/**
* Sanitizes the excluded IDs by removing any non-integer values.
*
* @since 4.1.3
*
* @param string $ids The IDs as a string, comma-separated.
* @return string The sanitized IDs as a string, comma-separated.
*/
private function sanitizeExcludedIds( $ids ) {
$ids = array_map( 'trim', explode( ',', $ids ) );
$ids = array_filter( $ids, 'is_numeric' );
$ids = esc_sql( implode( ', ', $ids ) );
return $ids;
}
}