update
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
use GRIM_SG\Vendor\Controller;
|
||||
|
||||
class Cache extends Controller {
|
||||
private static $max_chunk_size = 500000;
|
||||
private static $prefix = 'sgg_cache_';
|
||||
|
||||
public static $sitemaps = array(
|
||||
'sitemap',
|
||||
'inner-sitemap',
|
||||
'google-news',
|
||||
'image-sitemap',
|
||||
'video-sitemap',
|
||||
);
|
||||
|
||||
public $sitemap;
|
||||
|
||||
public $inner_sitemap;
|
||||
public $current_page;
|
||||
|
||||
public function __construct( $sitemap = 'sitemap', $inner_sitemap = null, $current_page = null ) {
|
||||
$this->sitemap = $this->get_multilingual_sitemap_name( $sitemap );
|
||||
$this->inner_sitemap = $inner_sitemap;
|
||||
$this->current_page = $current_page ?? '';
|
||||
}
|
||||
|
||||
public function set( $urls ) {
|
||||
$expiration = self::get_expiration( $this->get_settings() );
|
||||
$option_name = self::$prefix . $this->sitemap;
|
||||
|
||||
if ( $this->inner_sitemap ) {
|
||||
$cached_urls = get_transient( $option_name );
|
||||
|
||||
if ( empty( $cached_urls ) ) {
|
||||
$cached_urls = array();
|
||||
}
|
||||
|
||||
if ( ! empty( $urls[ $this->inner_sitemap ] ) ) {
|
||||
$cached_urls[ $this->inner_sitemap . $this->current_page ] = $urls[ $this->inner_sitemap ];
|
||||
}
|
||||
|
||||
$urls = $cached_urls;
|
||||
}
|
||||
|
||||
// Only apply splitting for Media Sitemaps.
|
||||
if ( strpos( $this->sitemap, 'media-' ) === 0 ) {
|
||||
$serialized = maybe_serialize( $urls );
|
||||
if ( strlen( $serialized ) > self::$max_chunk_size ) {
|
||||
$chunks = str_split( $serialized, self::$max_chunk_size );
|
||||
|
||||
foreach ( $chunks as $i => $chunk ) {
|
||||
set_transient( $option_name . '_chunk_' . $i, $chunk, $expiration );
|
||||
}
|
||||
|
||||
set_transient( $option_name . '_chunks', count( $chunks ), $expiration );
|
||||
set_transient( $option_name . '_time', time(), $expiration );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
set_transient( $option_name, $urls, $expiration );
|
||||
set_transient( $option_name . '_time', time(), $expiration );
|
||||
}
|
||||
|
||||
public function get() {
|
||||
$option_name = self::$prefix . $this->sitemap;
|
||||
|
||||
// Check if the data was saved in chunks.
|
||||
$chunks_count = get_transient( $option_name . '_chunks' );
|
||||
if ( false !== $chunks_count ) {
|
||||
$serialized = '';
|
||||
|
||||
for ( $i = 0; $i < $chunks_count; $i ++ ) {
|
||||
$chunk = get_transient( $option_name . '_chunk_' . $i );
|
||||
if ( false === $chunk ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$serialized .= $chunk;
|
||||
}
|
||||
|
||||
$urls = maybe_unserialize( $serialized );
|
||||
} else {
|
||||
$urls = get_transient( $option_name );
|
||||
}
|
||||
|
||||
if ( $this->inner_sitemap ) {
|
||||
if ( empty( $urls[ $this->inner_sitemap . $this->current_page ] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return array(
|
||||
$this->inner_sitemap => $urls[ $this->inner_sitemap . $this->current_page ],
|
||||
);
|
||||
}
|
||||
|
||||
return $urls;
|
||||
}
|
||||
|
||||
public static function get_time( $sitemap ) {
|
||||
return get_transient( self::$prefix . $sitemap . '_time' );
|
||||
}
|
||||
|
||||
public static function get_time_formatted( $sitemap ) {
|
||||
$time = self::get_time( $sitemap );
|
||||
|
||||
return $time
|
||||
// translators: %s is Cached Time
|
||||
? sprintf( __( '%s ago', 'xml-sitemap-generator-for-google' ), human_time_diff( $time, time() ) )
|
||||
: __( 'No Cache', 'xml-sitemap-generator-for-google' );
|
||||
}
|
||||
|
||||
public static function delete( $sitemap ): void {
|
||||
$option_name = self::$prefix . $sitemap;
|
||||
|
||||
delete_transient( $option_name );
|
||||
delete_transient( $option_name . '_time' );
|
||||
|
||||
// Delete chunks if they exist.
|
||||
$chunks_count = get_transient( $option_name . '_chunks' );
|
||||
if ( false !== $chunks_count ) {
|
||||
for ( $i = 0; $i < $chunks_count; $i ++ ) {
|
||||
delete_transient( $option_name . '_chunk_' . $i );
|
||||
}
|
||||
}
|
||||
|
||||
delete_transient( $option_name . '_chunks' );
|
||||
}
|
||||
|
||||
public static function clear(): void {
|
||||
foreach ( self::$sitemaps as $sitemap ) {
|
||||
self::delete( $sitemap );
|
||||
}
|
||||
}
|
||||
|
||||
public static function maybe_clear( $expiration ): void {
|
||||
foreach ( self::$sitemaps as $sitemap ) {
|
||||
if ( $expiration < time() - self::get_time( $sitemap ) ) {
|
||||
self::delete( $sitemap );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_expiration( $settings ) {
|
||||
return intval( $settings->cache_timeout ?? 24 ) * intval( $settings->cache_timeout_period ?? 3600 );
|
||||
}
|
||||
|
||||
public function get_multilingual_sitemap_name( $sitemap ) {
|
||||
$suffix = '';
|
||||
|
||||
if ( function_exists( 'pll_current_language' ) ) {
|
||||
$suffix = pll_current_language();
|
||||
}
|
||||
|
||||
if ( function_exists( 'trp_get_languages' ) ) {
|
||||
$trp_settings = get_option( 'trp_settings' );
|
||||
$suffix = $trp_settings['default-language'] ?? null;
|
||||
}
|
||||
|
||||
if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
|
||||
$suffix = apply_filters( 'wpml_current_language', null );
|
||||
}
|
||||
|
||||
if ( ! empty( $suffix ) ) {
|
||||
$sitemap = "{$sitemap}_{$suffix}";
|
||||
}
|
||||
|
||||
return $sitemap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,503 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
use GRIM_SG\Vendor\Controller;
|
||||
use SGG_PRO\Classes\Video_Sitemap;
|
||||
use SGG_PRO\Classes\Video_Data_Cache;
|
||||
|
||||
class Dashboard extends Controller {
|
||||
/**
|
||||
* Dashboard constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'admin_init', array( $this, 'register_settings' ) );
|
||||
add_action( 'admin_menu', array( $this, 'admin_menu_pages' ) );
|
||||
add_filter( 'plugin_action_links_' . GRIM_SG_BASENAME, array( $this, 'plugin_action_links' ) );
|
||||
add_filter( 'plugin_row_meta', array( $this, 'plugin_meta_links' ), 10, 2 );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
||||
add_action( 'admin_print_footer_scripts', array( $this, 'add_plugin_logo_script' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu
|
||||
*/
|
||||
public function admin_menu_pages() {
|
||||
add_options_page(
|
||||
esc_html__( 'Google XML Sitemaps Generator Settings', 'xml-sitemap-generator-for-google' ),
|
||||
esc_html__( 'XML Sitemaps', 'xml-sitemap-generator-for-google' ),
|
||||
'manage_options',
|
||||
self::$slug,
|
||||
array( $this, 'render_settings_page' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue admin styles and scripts for plugin
|
||||
*/
|
||||
public function admin_enqueue_scripts( $hook ) {
|
||||
wp_register_style(
|
||||
'sgg-rate-banner',
|
||||
GRIM_SG_URL . 'assets/css/rate-banner.min.css',
|
||||
array(),
|
||||
GRIM_SG_VERSION
|
||||
);
|
||||
|
||||
wp_register_style(
|
||||
'sgg-icons',
|
||||
GRIM_SG_URL . 'assets/fonts/icons/style.css',
|
||||
array(),
|
||||
GRIM_SG_VERSION
|
||||
);
|
||||
|
||||
if ( 'settings_page_xml-sitemap-generator-for-google' === $hook ) {
|
||||
wp_enqueue_style( 'sgg-fonts', GRIM_SG_URL . 'assets/fonts/albert_sans/fonts.css', array(), GRIM_SG_VERSION );
|
||||
wp_enqueue_style( 'sgg-icons', GRIM_SG_URL . 'assets/fonts/icons/style.css', array(), GRIM_SG_VERSION );
|
||||
wp_enqueue_style( 'sgg-styles', GRIM_SG_URL . 'assets/css/styles.min.css', array( 'sgg-fonts' ), GRIM_SG_VERSION );
|
||||
wp_enqueue_script( 'jquery-ui', GRIM_SG_URL . 'assets/js/jquery-ui.min.js', array( 'jquery' ), GRIM_SG_VERSION, true );
|
||||
wp_enqueue_script( 'sgg-scripts', GRIM_SG_URL . 'assets/js/scripts.js', array( 'jquery' ), GRIM_SG_VERSION, true );
|
||||
|
||||
if ( function_exists( 'xml_sitemap_generate_settings' ) ) {
|
||||
$settings_array = xml_sitemap_generate_settings() ?? array();
|
||||
|
||||
wp_localize_script(
|
||||
'sgg-scripts',
|
||||
'grimData',
|
||||
array(
|
||||
'settingsArray' => $settings_array,
|
||||
'noSettingsFound' => esc_html__( 'Settings not found', 'xml-sitemap-generator-for-google' ),
|
||||
'NoUrls' => esc_html__( 'No URLs added yet!', 'xml-sitemap-generator-for-google' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
wp_localize_script(
|
||||
'sgg-scripts',
|
||||
'sgg',
|
||||
array(
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings page
|
||||
*/
|
||||
public function render_settings_page() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->save_settings();
|
||||
|
||||
self::render(
|
||||
'settings.php',
|
||||
array(
|
||||
'settings' => $this->get_settings(),
|
||||
'cpt' => $this->get_cpt( 'objects' ),
|
||||
'taxonomies' => $this->get_taxonomy_types( 'objects' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Settings
|
||||
*/
|
||||
public function register_settings() {
|
||||
register_setting( self::$slug, self::$slug );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save Settings
|
||||
*/
|
||||
public function save_settings() {
|
||||
if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ?? '' ) || ! isset( $_POST['save_settings'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! isset( $_POST['sgg_settings_nonce'] ) || ! wp_verify_nonce( $_POST['sgg_settings_nonce'], GRIM_SG_BASENAME . '-settings' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Run Tools Actions
|
||||
if ( Tools::run_tools_actions( $_POST ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Change IndexNow API Key
|
||||
if ( ! empty( $_POST['change_indexnow_key'] ) ) {
|
||||
IndexNow::delete_api_key();
|
||||
|
||||
add_settings_error(
|
||||
self::$slug,
|
||||
'indexnow_api_key',
|
||||
esc_html__( 'IndexNow API Key changed successfully.', 'xml-sitemap-generator-for-google' ),
|
||||
'success'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear Media Sitemap Cache on every save
|
||||
if ( empty( $_POST['disable_media_sitemap_cache'] ) ) {
|
||||
MediaSitemap::delete_all_cache();
|
||||
}
|
||||
|
||||
// Clear Sitemaps Cache
|
||||
if ( ! empty( $_POST['clear_cache'] ) ) {
|
||||
Cache::clear();
|
||||
|
||||
add_settings_error(
|
||||
self::$slug,
|
||||
'sitemap_cache',
|
||||
esc_html__( 'Sitemaps Cache cleared.', 'xml-sitemap-generator-for-google' ),
|
||||
'success'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Import Settings
|
||||
if ( ! empty( $_POST['import_settings'] ) ) {
|
||||
ImportExport::import_settings();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear Video Data Cache
|
||||
if ( ! empty( $_POST['clear_video_api_cache'] ) && is_callable( 'SGG_PRO\Classes\Video_Data_Cache::delete' ) ) {
|
||||
Video_Data_Cache::delete();
|
||||
|
||||
add_settings_error(
|
||||
self::$slug,
|
||||
'video_api_cache',
|
||||
esc_html__( 'Video API Data Cache cleared.', 'xml-sitemap-generator-for-google' ),
|
||||
'success'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = new Settings();
|
||||
$saved_settings = $this->get_settings();
|
||||
|
||||
// Check YouTube API Key
|
||||
if ( ( ! empty( $_POST['youtube_check_api_key'] ) || $saved_settings->youtube_api_key !== $_POST['youtube_api_key'] )
|
||||
&& ! empty( $_POST['youtube_api_key'] ) && is_callable( 'SGG_PRO\Classes\Video_Sitemap::request_youtube_data' ) ) {
|
||||
$youtube_data = Video_Sitemap::request_youtube_data( 'dQw4w9WgXcQ', sanitize_text_field( $_POST['youtube_api_key'] ) );
|
||||
|
||||
if ( ! empty( $youtube_data ) && is_array( $youtube_data ) ) {
|
||||
add_settings_error( self::$slug, 'youtube_api_key_success', esc_html__( 'YouTube API key passed the check successfully.', 'xml-sitemap-generator-for-google' ), 'success' );
|
||||
} else {
|
||||
add_settings_error( self::$slug, 'youtube_api_key_error', "YouTube API: $youtube_data" );
|
||||
}
|
||||
|
||||
if ( ! empty( $_POST['youtube_check_api_key'] ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check Vimeo API Key
|
||||
if ( ( ! empty( $_POST['vimeo_check_api_key'] ) || $saved_settings->vimeo_api_key !== $_POST['vimeo_api_key'] )
|
||||
&& ! empty( $_POST['vimeo_api_key'] ) && is_callable( 'SGG_PRO\Classes\Video_Sitemap::request_vimeo_data' ) ) {
|
||||
$vimeo_data = Video_Sitemap::request_vimeo_data( '22439234', sanitize_text_field( $_POST['vimeo_api_key'] ) );
|
||||
|
||||
if ( ! empty( $vimeo_data ) && is_array( $vimeo_data ) ) {
|
||||
add_settings_error( self::$slug, 'vimeo_api_key_success', esc_html__( 'Vimeo Access Token passed the check successfully.', 'xml-sitemap-generator-for-google' ), 'success' );
|
||||
} else {
|
||||
add_settings_error( self::$slug, 'vimeo_api_key_error', "Vimeo API: $vimeo_data" );
|
||||
}
|
||||
|
||||
if ( ! empty( $_POST['vimeo_check_api_key'] ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Change Cron Job if Runtime is changed
|
||||
if ( ! isset( $_POST['enable_cronjob'] ) || ! $_POST['enable_cronjob'] || ( ! empty( $_POST['cronjob_runtime'] ) && $saved_settings->cronjob_runtime !== $_POST['cronjob_runtime'] ) ) {
|
||||
wp_clear_scheduled_hook( 'xml_sitemap_cronjob' );
|
||||
}
|
||||
|
||||
$settings->enable_sitemap = sanitize_text_field( $_POST['enable_sitemap'] ?? 0 );
|
||||
$settings->sitemap_url = sanitize_text_field( $_POST['sitemap_url'] ?? $settings->sitemap_url );
|
||||
$settings->links_per_page = sanitize_text_field( $_POST['links_per_page'] ?? $settings->links_per_page );
|
||||
$settings->html_sitemap_url = sanitize_text_field( $_POST['html_sitemap_url'] ?? $settings->html_sitemap_url );
|
||||
$settings->enable_html_sitemap = sanitize_text_field( $_POST['enable_html_sitemap'] ?? 0 );
|
||||
$settings->sitemap_to_robots = sanitize_text_field( $_POST['sitemap_to_robots'] ?? 0 );
|
||||
$settings->enable_indexnow = sanitize_text_field( $_POST['enable_indexnow'] ?? 0 );
|
||||
$settings->sitemap_view = sanitize_text_field( $_POST['sitemap_view'] ?? '' );
|
||||
$settings->exclude_posts = apply_filters( 'sanitize_post_array', $_POST['exclude_posts'] ?? '' );
|
||||
$settings->exclude_terms = apply_filters( 'sanitize_post_array', $_POST['exclude_terms'] ?? '' );
|
||||
$settings->include_only_terms = apply_filters( 'sanitize_post_array', $_POST['include_only_terms'] ?? '' );
|
||||
$settings->posts_priority = sanitize_text_field( $_POST['posts_priority'] ?? '' );
|
||||
|
||||
$settings->enable_google_news = sanitize_text_field( $_POST['enable_google_news'] ?? 0 );
|
||||
$settings->google_news_old_posts = sanitize_text_field( $_POST['google_news_old_posts'] ?? 0 );
|
||||
$settings->google_news_name = sanitize_text_field( $_POST['google_news_name'] ?? '' );
|
||||
$settings->google_news_url = sanitize_text_field( $_POST['google_news_url'] ?? $settings->google_news_url );
|
||||
$settings->google_news_keywords = sanitize_text_field( $_POST['google_news_keywords'] ?? '' );
|
||||
$settings->google_news_stocks = sanitize_text_field( $_POST['google_news_stocks'] ?? 0 );
|
||||
$settings->google_news_exclude = apply_filters( 'sanitize_post_array', $_POST['google_news_exclude'] ?? '' );
|
||||
$settings->google_news_exclude_terms = apply_filters( 'sanitize_post_array', $_POST['google_news_exclude_terms'] ?? '' );
|
||||
$settings->google_news_include_only_terms = apply_filters( 'sanitize_post_array', $_POST['google_news_include_only_terms'] ?? '' );
|
||||
|
||||
$settings->enable_image_sitemap = sanitize_text_field( $_POST['enable_image_sitemap'] ?? 0 );
|
||||
$settings->enable_video_sitemap = sanitize_text_field( $_POST['enable_video_sitemap'] ?? 0 );
|
||||
$settings->image_sitemap_url = sanitize_text_field( $_POST['image_sitemap_url'] ?? $settings->image_sitemap_url );
|
||||
$settings->video_sitemap_url = sanitize_text_field( $_POST['video_sitemap_url'] ?? $settings->video_sitemap_url );
|
||||
$settings->hide_image_previews = sanitize_text_field( $_POST['hide_image_previews'] ?? 0 );
|
||||
$settings->hide_image_sitemap_xsl = sanitize_text_field( $_POST['hide_image_sitemap_xsl'] ?? 0 );
|
||||
$settings->hide_video_sitemap_xsl = sanitize_text_field( $_POST['hide_video_sitemap_xsl'] ?? 0 );
|
||||
$settings->image_mime_types = apply_filters( 'sanitize_post_array', $_POST['image_mime_types'] ?? $settings->image_mime_types );
|
||||
$settings->youtube_api_key = sanitize_text_field( $_POST['youtube_api_key'] ?? $settings->youtube_api_key );
|
||||
$settings->vimeo_api_key = sanitize_text_field( $_POST['vimeo_api_key'] ?? $settings->vimeo_api_key );
|
||||
$settings->exclude_broken_images = sanitize_text_field( $_POST['exclude_broken_images'] ?? 0 );
|
||||
$settings->include_featured_images = sanitize_text_field( $_POST['include_featured_images'] ?? 0 );
|
||||
$settings->include_woo_gallery = sanitize_text_field( $_POST['include_woo_gallery'] ?? 0 );
|
||||
|
||||
$settings->enable_cache = sanitize_text_field( $_POST['enable_cache'] ?? 0 );
|
||||
$settings->cache_timeout = sanitize_text_field( $_POST['cache_timeout'] ?? $settings->cache_timeout );
|
||||
$settings->cache_timeout_period = sanitize_text_field( $_POST['cache_timeout_period'] ?? $settings->cache_timeout_period );
|
||||
$settings->clear_cache_on_save_post = sanitize_text_field( $_POST['clear_cache_on_save_post'] ?? 0 );
|
||||
$settings->enable_video_api_cache = sanitize_text_field( $_POST['enable_video_api_cache'] ?? 0 );
|
||||
$settings->disable_media_sitemap_cache = sanitize_text_field( $_POST['disable_media_sitemap_cache'] ?? 0 );
|
||||
$settings->minimize_sitemap = sanitize_text_field( $_POST['minimize_sitemap'] ?? 0 );
|
||||
$settings->colors = apply_filters( 'sanitize_post_array', $_POST['colors'] ?? $settings->colors );
|
||||
$settings->hide_branding = sanitize_text_field( $_POST['hide_branding'] ?? 0 );
|
||||
$settings->enable_cronjob = sanitize_text_field( $_POST['enable_cronjob'] ?? 0 );
|
||||
$settings->cronjob_runtime = sanitize_text_field( $_POST['cronjob_runtime'] ?? $settings->cronjob_runtime );
|
||||
|
||||
$settings->home = $settings->get_row_value( 'home' );
|
||||
$settings->page = $settings->get_row_value( 'page' );
|
||||
$settings->post = $settings->get_row_value( 'post' );
|
||||
$settings->archive = $settings->get_row_value( 'archive' );
|
||||
$settings->archive_older = $settings->get_row_value( 'archive_older' );
|
||||
$settings->authors = $settings->get_row_value( 'authors' );
|
||||
$settings->media = $settings->get_row_value( 'media' );
|
||||
|
||||
foreach ( $this->get_cpt() as $cpt ) {
|
||||
$settings->cpt[ $cpt ] = $settings->get_row_value( $cpt );
|
||||
}
|
||||
|
||||
foreach ( $this->get_taxonomy_types() as $taxonomy_type ) {
|
||||
$settings->taxonomies[ $taxonomy_type ] = $settings->get_row_value( $taxonomy_type );
|
||||
}
|
||||
|
||||
$custom_sitemap_urls = apply_filters( 'sanitize_post_array', $_POST['custom_sitemap_urls'] ?? array() );
|
||||
$custom_sitemap_lastmods = apply_filters( 'sanitize_post_array', $_POST['custom_sitemap_lastmods'] ?? array() );
|
||||
|
||||
foreach ( $custom_sitemap_urls as $key => $value ) {
|
||||
$custom_sitemap = array(
|
||||
'url' => $value,
|
||||
'lastmod' => $custom_sitemap_lastmods[ $key ],
|
||||
);
|
||||
|
||||
$settings->custom_sitemaps[] = $custom_sitemap;
|
||||
}
|
||||
|
||||
$additional_urls = apply_filters( 'sanitize_post_array', $_POST['additional_urls'] ?? array() );
|
||||
$additional_priorities = apply_filters( 'sanitize_post_array', $_POST['additional_priorities'] ?? array() );
|
||||
$additional_frequencies = apply_filters( 'sanitize_post_array', $_POST['additional_frequencies'] ?? array() );
|
||||
$additional_lastmods = apply_filters( 'sanitize_post_array', $_POST['additional_lastmods'] ?? array() );
|
||||
|
||||
foreach ( $additional_urls as $key => $value ) {
|
||||
$page = array(
|
||||
'url' => $value,
|
||||
'priority' => $additional_priorities[ $key ],
|
||||
'frequency' => $additional_frequencies[ $key ],
|
||||
'lastmod' => $additional_lastmods[ $key ],
|
||||
);
|
||||
|
||||
$settings->additional_pages[] = $page;
|
||||
}
|
||||
|
||||
update_option( self::$slug, $settings );
|
||||
|
||||
$new_cache_expires = Cache::get_expiration( $settings );
|
||||
if ( Cache::get_expiration( $saved_settings ) !== $new_cache_expires ) {
|
||||
Cache::maybe_clear( $new_cache_expires );
|
||||
}
|
||||
|
||||
if ( ( $settings->sitemap_view !== $saved_settings->sitemap_view ) || ( $settings->links_per_page !== $saved_settings->links_per_page ) ) {
|
||||
Cache::clear();
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
|
||||
add_settings_error(
|
||||
self::$slug,
|
||||
'sitemap_settings',
|
||||
esc_html__( 'Changes saved!', 'xml-sitemap-generator-for-google' ),
|
||||
'success'
|
||||
);
|
||||
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Sitemap Post Row
|
||||
* @param $title
|
||||
* @param $option
|
||||
* @param $data
|
||||
*/
|
||||
public static function render_post_row( $title, $option, $data ) {
|
||||
self::render(
|
||||
'fields/post-row.php',
|
||||
array(
|
||||
'title' => $title,
|
||||
'option' => $option,
|
||||
'data' => $data,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Priority Selectbox
|
||||
* @param $name
|
||||
* @param $value
|
||||
*/
|
||||
public static function render_priority_field( $name, $value ) {
|
||||
self::render(
|
||||
'fields/priority.php',
|
||||
array(
|
||||
'name' => $name,
|
||||
'value' => $value,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Frequency Selectbox
|
||||
* @param $name
|
||||
* @param $value
|
||||
*/
|
||||
public static function render_frequency_field( $name, $value ) {
|
||||
self::render(
|
||||
'fields/frequency.php',
|
||||
array(
|
||||
'name' => $name,
|
||||
'value' => $value,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Google News Selectbox
|
||||
* @param $title
|
||||
* @param $name
|
||||
* @param $value
|
||||
*/
|
||||
public static function render_content_field( $title, $name, $value, $class = '' ) {
|
||||
self::render(
|
||||
'fields/content.php',
|
||||
array(
|
||||
'title' => $title,
|
||||
'name' => $name,
|
||||
'value' => $value,
|
||||
'class' => $class,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Template
|
||||
* @param $template_name
|
||||
* @param $args
|
||||
*/
|
||||
public static function render( $template_name, $args = array() ) {
|
||||
global $wp_version;
|
||||
|
||||
if ( version_compare( $wp_version, '5.5.0', '<' ) ) {
|
||||
set_query_var( 'args', $args );
|
||||
}
|
||||
|
||||
load_template( GRIM_SG_PATH . "/templates/{$template_name}", false, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting Link
|
||||
*
|
||||
* @param $links
|
||||
* @return mixed
|
||||
*/
|
||||
public function plugin_action_links( $links ) {
|
||||
$settings_link = sprintf(
|
||||
'<a href="%1$s">%2$s</a>',
|
||||
admin_url( 'options-general.php?page=' . self::$slug ),
|
||||
esc_html__( 'Settings', 'xml-sitemap-generator-for-google' )
|
||||
);
|
||||
|
||||
$docs_link = sprintf(
|
||||
'<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>',
|
||||
esc_url( 'https://wpgrim.com/docs/google-xml-sitemaps-generator/general/xml-sitemap/' ),
|
||||
esc_html__( 'Docs', 'xml-sitemap-generator-for-google' )
|
||||
);
|
||||
|
||||
if ( ! sgg_pro_enabled() ) {
|
||||
$pro_link = sprintf(
|
||||
'<a href="%1$s" style="font-weight: 600; color: #ff7113;" target="_blank">%2$s</a>',
|
||||
sgg_get_pro_url( 'plugin-action-link' ),
|
||||
esc_html__( 'Get Pro Version', 'xml-sitemap-generator-for-google' )
|
||||
);
|
||||
|
||||
$links = array_merge( array( $pro_link, $settings_link, $docs_link ), $links );
|
||||
} else {
|
||||
$links = array_merge( array( $settings_link, $docs_link ), $links );
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Meta Links
|
||||
*
|
||||
* @param $links
|
||||
* @return mixed
|
||||
*/
|
||||
public function plugin_meta_links( $links, $file ) {
|
||||
if ( GRIM_SG_BASENAME === $file ) {
|
||||
$links[] = '<a href="' . esc_url( sgg_get_support_url() ) . '" target="_blank">' . __( 'Support', 'xml-sitemap-generator-for-google' ) . '</a>';
|
||||
$links[] = '<a href="' . esc_url( sgg_get_review_url() ) . '" target="_blank">' . __( 'Rate ★★★★★', 'xml-sitemap-generator-for-google' ) . '</a>';
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add plugin logo script to plugins page
|
||||
*/
|
||||
public function add_plugin_logo_script() {
|
||||
global $pagenow;
|
||||
|
||||
// Only add script on plugins page
|
||||
if ( 'plugins.php' !== $pagenow ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Find the plugin row for XML Sitemap Generator
|
||||
const pluginRow = document.querySelector('tr[data-slug="xml-sitemap-generator-for-google"]');
|
||||
|
||||
if (pluginRow) {
|
||||
const pluginTitle = pluginRow.querySelector('.plugin-title strong');
|
||||
|
||||
if (pluginTitle) {
|
||||
// Create logo element
|
||||
const logo = document.createElement('img');
|
||||
logo.src = '<?php echo esc_url( GRIM_SG_URL . 'assets/images/sgg-logo.svg' ); ?>';
|
||||
logo.alt = 'XML Sitemap Generator Logo';
|
||||
logo.style.width = '20px';
|
||||
logo.style.height = '20px';
|
||||
logo.style.paddingRight = '10px';
|
||||
logo.style.verticalAlign = 'middle';
|
||||
|
||||
// Insert logo before the plugin title
|
||||
pluginTitle.insertBefore(logo, pluginTitle.firstChild);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
use GRIM_SG\Vendor\Controller;
|
||||
|
||||
class Frontend extends Controller {
|
||||
private static $rules_option = 'grim_sg_rules';
|
||||
private static $rules_version = '1.1';
|
||||
|
||||
/**
|
||||
* Sitemap constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::set_rewrite_hooks();
|
||||
|
||||
add_filter( 'query_vars', array( $this, 'register_query_vars' ), 1 );
|
||||
add_action( 'parse_request', array( $this, 'render_sitemaps' ), 1 );
|
||||
add_action( 'do_robots', array( $this, 'do_robots_link' ), 100 );
|
||||
add_action( 'admin_init', array( $this, 'reset_rewrite_rules' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Sitemap Query Variable
|
||||
* @param $query_vars
|
||||
* @return mixed
|
||||
*/
|
||||
public function register_query_vars( $query_vars ) {
|
||||
$query_vars[] = 'sitemap_xsl';
|
||||
$query_vars[] = 'sitemap_xml';
|
||||
$query_vars[] = 'sitemap_html';
|
||||
$query_vars[] = 'google_news';
|
||||
$query_vars[] = 'image_sitemap';
|
||||
$query_vars[] = 'video_sitemap';
|
||||
$query_vars[] = 'inner_sitemap';
|
||||
$query_vars[] = 'multilingual_sitemap';
|
||||
$query_vars[] = 'page';
|
||||
|
||||
return $query_vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Redirect
|
||||
*/
|
||||
public function render_sitemaps( $wp ) {
|
||||
global $wp_query;
|
||||
|
||||
$is_xsl_sitemap = ! empty( $wp->query_vars['sitemap_xsl'] );
|
||||
$is_xml_sitemap = ! empty( $wp->query_vars['sitemap_xml'] );
|
||||
$is_html_sitemap = ! empty( $wp->query_vars['sitemap_html'] );
|
||||
$is_google_news = ! empty( $wp->query_vars['google_news'] );
|
||||
$is_image_sitemap = ! empty( $wp->query_vars['image_sitemap'] );
|
||||
$is_video_sitemap = ! empty( $wp->query_vars['video_sitemap'] );
|
||||
$is_multilingual = ! empty( $wp->query_vars['multilingual_sitemap'] );
|
||||
|
||||
if ( $is_xsl_sitemap || $is_xml_sitemap || $is_html_sitemap || $is_google_news || $is_image_sitemap || $is_video_sitemap || $is_multilingual ) {
|
||||
$wp_query->is_404 = false;
|
||||
$wp_query->is_feed = true;
|
||||
$inner_sitemap = $wp->query_vars['inner_sitemap'] ?? null;
|
||||
$current_page = $wp->query_vars['page'] ?? null;
|
||||
|
||||
if ( ! empty( $inner_sitemap ) && empty( $current_page ) ) {
|
||||
$current_page = 0;
|
||||
}
|
||||
|
||||
if ( $is_xsl_sitemap ) {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
Sitemap::generate_sitemap_xsl( sanitize_text_field( $_GET['template'] ?? $wp->query_vars['sitemap_xsl'] ) );
|
||||
} elseif ( $is_google_news ) {
|
||||
( new GoogleNews() )->show_sitemap( GoogleNews::$template );
|
||||
} elseif ( $is_image_sitemap || 'image' === $inner_sitemap ) {
|
||||
( new ImageSitemap() )->show_sitemap( ImageSitemap::$template, true, $inner_sitemap, $current_page );
|
||||
} elseif ( $is_video_sitemap || 'video' === $inner_sitemap ) {
|
||||
( new VideoSitemap() )->show_sitemap( VideoSitemap::$template, true, $inner_sitemap, $current_page );
|
||||
} elseif ( $is_multilingual ) {
|
||||
( new MultilingualSitemap() )->show_sitemap( MultilingualSitemap::$template );
|
||||
} else {
|
||||
( new Sitemap() )->show_sitemap( 'sitemap', $is_xml_sitemap, $inner_sitemap, $current_page );
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Sitemap Links to Robots
|
||||
*/
|
||||
public function do_robots_link() {
|
||||
$settings = $this->get_settings();
|
||||
$home_url = get_site_url();
|
||||
|
||||
if ( $settings->sitemap_to_robots ) {
|
||||
echo "\nSitemap: {$home_url}/{$settings->sitemap_url}\n"; // phpcs:ignore
|
||||
|
||||
if ( $settings->enable_google_news ) {
|
||||
echo "Sitemap: {$home_url}/{$settings->google_news_url}\n"; // phpcs:ignore
|
||||
}
|
||||
|
||||
if ( empty( $settings->sitemap_view ) ) {
|
||||
if ( $settings->enable_image_sitemap ) {
|
||||
echo "Sitemap: {$home_url}/{$settings->image_sitemap_url}\n"; // phpcs:ignore
|
||||
}
|
||||
|
||||
if ( $settings->enable_video_sitemap ) {
|
||||
echo "Sitemap: {$home_url}/{$settings->video_sitemap_url}\n"; // phpcs:ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Custom Rewrite Rules
|
||||
*
|
||||
* @param $wp_rules
|
||||
* @return array
|
||||
*/
|
||||
public static function add_rewrite_rules( $wp_rules ) {
|
||||
$settings = get_option( self::$slug, new Settings() );
|
||||
$stylesheet_url = str_replace( '.', '\.', apply_filters( 'sitemap_xsl_template_path', 'sitemap-stylesheet.xsl' ) ) . '$';
|
||||
$sitemap_types = array( 'page', 'post', 'category', 'author', 'archive', 'media', 'additional', 'image', 'video' );
|
||||
$custom_posts = ( new Controller() )->get_cpt();
|
||||
|
||||
$grim_sg_rules = array(
|
||||
$stylesheet_url => 'index.php?sitemap_xsl=true',
|
||||
);
|
||||
|
||||
if ( ! empty( $settings->enable_sitemap ) && ! apply_filters( 'sgg_disable_xml_sitemap', false ) ) {
|
||||
$sitemap_url = str_replace( '.', '\.', $settings->sitemap_url ) . '$';
|
||||
$grim_sg_rules[ $sitemap_url ] = 'index.php?sitemap_xml=true';
|
||||
|
||||
if ( ! empty( $settings->sitemap_view ) ) {
|
||||
foreach ( $sitemap_types as $type ) {
|
||||
$regex_pattern = in_array( $type, array( 'image', 'video' ) )
|
||||
? "{$type}-sitemap([0-9]+)\.xml$"
|
||||
: "{$type}-sitemap([0-9]+)?\.xml$";
|
||||
|
||||
$grim_sg_rules[ $regex_pattern ] = "index.php?sitemap_xml=true&inner_sitemap={$type}&page=\$matches[1]";
|
||||
}
|
||||
|
||||
foreach ( $custom_posts as $cpt ) {
|
||||
$grim_sg_rules[ "{$cpt}-sitemap([0-9]+)?\.xml$" ] = "index.php?sitemap_xml=true&inner_sitemap={$cpt}&page=\$matches[1]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( sgg_pro_enabled() && $settings->enable_html_sitemap ) {
|
||||
$html_sitemap_url = str_replace( '.', '\.', $settings->html_sitemap_url ) . '$';
|
||||
$grim_sg_rules[ $html_sitemap_url ] = 'index.php?sitemap_html=true';
|
||||
|
||||
foreach ( $sitemap_types as $type ) {
|
||||
$regex_pattern = in_array( $type, array( 'image', 'video' ) )
|
||||
? "{$type}-sitemap([0-9]+)\.html$"
|
||||
: "{$type}-sitemap([0-9]+)?\.html$";
|
||||
|
||||
$grim_sg_rules[ $regex_pattern ] = "index.php?sitemap_html=true&inner_sitemap={$type}&page=\$matches[1]";
|
||||
}
|
||||
|
||||
foreach ( $custom_posts as $cpt ) {
|
||||
$grim_sg_rules[ "{$cpt}-sitemap([0-9]+)?\.html$" ] = "index.php?sitemap_html=true&inner_sitemap={$cpt}&page=\$matches[1]";
|
||||
}
|
||||
}
|
||||
|
||||
if ( $settings->enable_google_news ) {
|
||||
$google_news_url = str_replace( '.', '\.', $settings->google_news_url ) . '$';
|
||||
$grim_sg_rules[ $google_news_url ] = 'index.php?google_news=true';
|
||||
}
|
||||
|
||||
if ( $settings->enable_image_sitemap ) {
|
||||
$image_sitemap_url = str_replace( '.', '\.', $settings->image_sitemap_url ) . '$';
|
||||
$grim_sg_rules[ $image_sitemap_url ] = 'index.php?image_sitemap=true';
|
||||
}
|
||||
|
||||
if ( $settings->enable_video_sitemap ) {
|
||||
$video_sitemap_url = str_replace( '.', '\.', $settings->video_sitemap_url ) . '$';
|
||||
$grim_sg_rules[ $video_sitemap_url ] = 'index.php?video_sitemap=true';
|
||||
}
|
||||
|
||||
if ( sgg_is_multilingual() ) {
|
||||
$languages = sgg_get_languages( true );
|
||||
if ( ! empty( $languages ) ) {
|
||||
global $wp_rewrite;
|
||||
|
||||
$lang_slug = $wp_rewrite->root . '^(' . implode( '|', $languages ) . ')?/?';
|
||||
$lang_rules = array();
|
||||
|
||||
foreach ( $grim_sg_rules as $key => $rule ) {
|
||||
$lang_rules[ $lang_slug . $key ] = preg_replace( '/matches\[1\]/', 'matches[2]', $rule );
|
||||
}
|
||||
|
||||
$grim_sg_rules = $lang_rules;
|
||||
}
|
||||
|
||||
$grim_sg_rules['multilingual-sitemap.xml'] = 'index.php?multilingual_sitemap=true';
|
||||
}
|
||||
|
||||
if ( empty( $wp_rules ) ) {
|
||||
return $grim_sg_rules;
|
||||
}
|
||||
|
||||
return array_merge( $grim_sg_rules, $wp_rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Rewrite Hooks
|
||||
*/
|
||||
public static function set_rewrite_hooks() {
|
||||
add_filter( 'option_rewrite_rules', array( self::class, 'add_rewrite_rules' ), 100, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate Rewrite Rules
|
||||
*/
|
||||
public static function activate_rewrite_rules() {
|
||||
global $wp_rewrite;
|
||||
|
||||
$wp_rewrite->flush_rules( false );
|
||||
|
||||
update_option( self::$rules_option, self::$rules_version );
|
||||
}
|
||||
|
||||
/**
|
||||
* Run on Plugin Activate
|
||||
*/
|
||||
public static function activate_plugin() {
|
||||
self::set_rewrite_hooks();
|
||||
self::activate_rewrite_rules();
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run on Rules Version Updated
|
||||
*/
|
||||
public function reset_rewrite_rules() {
|
||||
$rules_version = get_option( self::$rules_option, false );
|
||||
|
||||
if ( $rules_version !== self::$rules_version ) {
|
||||
self::activate_plugin();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
use GRIM_SG\Vendor\QueryBuilder;
|
||||
|
||||
class GoogleNews extends Sitemap {
|
||||
public static $template = 'google-news';
|
||||
|
||||
private $blog_language = null;
|
||||
|
||||
/**
|
||||
* Add URLS Callback function
|
||||
*/
|
||||
public function urlsCallback() {
|
||||
return 'addNewsUrl';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding Google News Sitemap Headers
|
||||
*/
|
||||
public function extraSitemapHeader() {
|
||||
return array( 'xmlns:news' => 'http://www.google.com/schemas/sitemap-news/0.9' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect Sitemap URLs
|
||||
*/
|
||||
public function collect_urls( $template = 'sitemap', $inner_sitemap = null, $current_page = null ) {
|
||||
$this->add_posts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all Posts to Sitemap
|
||||
*/
|
||||
public function add_posts( $post_type = null, $current_page = null, $is_sitemap_index = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$front_page_id = get_option( 'page_on_front' );
|
||||
$post_types = array( 'page', 'post' );
|
||||
$exclude_post_ids = apply_filters( 'sgg_sitemap_exclude_post_ids', apply_filters( 'sgg_sitemap_exclude_ids', array(), $this->settings->google_news_exclude ?? '' ) );
|
||||
$exclude_term_ids = apply_filters( 'sgg_sitemap_exclude_term_ids', apply_filters( 'sgg_sitemap_exclude_ids', array(), $this->settings->google_news_exclude_terms ?? '' ) );
|
||||
$include_term_ids = apply_filters( 'sgg_sitemap_include_only_term_ids', apply_filters( 'sgg_sitemap_exclude_ids', array(), $this->settings->google_news_include_only_terms ?? '' ) );
|
||||
|
||||
if ( ! empty( $front_page_id ) ) {
|
||||
$exclude_post_ids[] = $front_page_id;
|
||||
}
|
||||
|
||||
foreach ( $post_types as $key => $post_type ) {
|
||||
if ( isset( $this->settings->{$post_type}->google_news ) && ! $this->settings->{$post_type}->google_news ) {
|
||||
unset( $post_types[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( sgg_pro_enabled() ) {
|
||||
foreach ( $this->get_cpt() as $cpt ) {
|
||||
if ( ! empty( $this->settings->cpt[ $cpt ] ) && ! empty( $this->settings->cpt[ $cpt ]->google_news ) ) {
|
||||
$post_types[] = $cpt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $post_types ) ) {
|
||||
$post_types = array( 'post' );
|
||||
}
|
||||
|
||||
$exclude_old_posts_sql = '';
|
||||
if ( empty( $this->settings->google_news_old_posts ) ) {
|
||||
$exclude_old_posts_sql = 'AND post_date_gmt >= DATE_SUB(NOW(), INTERVAL 48 HOUR)';
|
||||
}
|
||||
|
||||
$exclude_posts_sql = '';
|
||||
if ( ! empty( $exclude_post_ids ) ) {
|
||||
$exclude_posts_sql = 'AND posts.ID NOT IN (' . implode( ',', array_unique( $exclude_post_ids ) ) . ')';
|
||||
}
|
||||
|
||||
$terms_join_sql = '';
|
||||
$terms_where_sql = '';
|
||||
|
||||
if ( ! empty( $include_term_ids ) ) {
|
||||
$terms_join_sql = "INNER JOIN (
|
||||
SELECT DISTINCT tr.object_id
|
||||
FROM {$wpdb->term_relationships} tr
|
||||
INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
|
||||
WHERE tt.term_id IN (" . implode( ',', array_unique( $include_term_ids ) ) . ')
|
||||
) included_posts ON posts.ID = included_posts.object_id';
|
||||
} elseif ( ! empty( $exclude_term_ids ) ) {
|
||||
$terms_join_sql = "LEFT JOIN (
|
||||
SELECT DISTINCT tr.object_id
|
||||
FROM {$wpdb->term_relationships} tr
|
||||
INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
|
||||
WHERE tt.term_id IN (" . implode( ',', array_unique( $exclude_term_ids ) ) . ')
|
||||
) excluded_posts ON posts.ID = excluded_posts.object_id';
|
||||
$terms_where_sql = ' AND excluded_posts.object_id IS NULL';
|
||||
}
|
||||
|
||||
$sql_post_types = "('" . implode( "','", $post_types ) . "')";
|
||||
$multilingual_sql = $this->multilingual_sql( $post_types );
|
||||
$where_clause = ! empty( $multilingual_sql ) ? 'AND ' : 'WHERE ';
|
||||
$sql = "SELECT
|
||||
posts.ID,
|
||||
posts.post_title,
|
||||
posts.post_name,
|
||||
posts.post_parent,
|
||||
posts.post_type,
|
||||
posts.post_date,
|
||||
posts.post_date_gmt
|
||||
FROM $wpdb->posts as posts
|
||||
$terms_join_sql
|
||||
$multilingual_sql
|
||||
$where_clause post_status = 'publish' AND post_type IN $sql_post_types AND posts.post_password = ''
|
||||
$exclude_old_posts_sql
|
||||
$exclude_posts_sql
|
||||
$terms_where_sql
|
||||
GROUP BY posts.ID
|
||||
ORDER BY posts.post_modified DESC";
|
||||
|
||||
$posts = QueryBuilder::run_query( $sql );
|
||||
|
||||
foreach ( $posts as $post ) {
|
||||
if ( apply_filters( 'xml_sitemap_include_post', true, $post->ID ) ) {
|
||||
$post_date = '0000-00-00 00:00:00' !== $post->post_date_gmt ? $post->post_date_gmt : $post->post_date;
|
||||
$this->add_url(
|
||||
get_permalink( $post ),
|
||||
$post->ID,
|
||||
apply_filters( 'xml_sitemap_google_news_title', $post->post_title, $post->ID ),
|
||||
gmdate( DATE_W3C, strtotime( $post_date ) ),
|
||||
$post->post_type
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Google News Sitemap Url
|
||||
*
|
||||
* @param string $url
|
||||
* @param int $id
|
||||
* @param string $title
|
||||
* @param string $last_modified
|
||||
* @param string $post_type
|
||||
*/
|
||||
public function add_url( $url, $id, $title, $last_modified = '', $post_type = 'post' ) {
|
||||
$this->urls[] = array(
|
||||
$url, // URL
|
||||
! empty( $this->settings->google_news_name ) ? $this->settings->google_news_name : get_bloginfo( 'name' ), // Publication Name
|
||||
apply_filters( 'xml_sitemap_news_language', $this->get_blog_language(), $id, $post_type ), // Publication Language
|
||||
$title, // Title
|
||||
$last_modified, // Last Modified
|
||||
$id, // ID
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Blog Language
|
||||
*/
|
||||
public function get_blog_language() {
|
||||
if ( null === $this->blog_language ) {
|
||||
$this->blog_language = sgg_parse_language( get_bloginfo( 'language' ) );
|
||||
}
|
||||
|
||||
return $this->blog_language;
|
||||
}
|
||||
|
||||
public static function is_older_than_48h( $date ) {
|
||||
$accepted_time = time() - ( 48 * 3600 );
|
||||
$last_modified = strtotime( $date );
|
||||
|
||||
return $last_modified < $accepted_time;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
class ImageSitemap extends MediaSitemap {
|
||||
public static $template = 'image-sitemap';
|
||||
|
||||
private $image_mime_types = array(
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/bmp',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
'image/avif',
|
||||
);
|
||||
|
||||
/**
|
||||
* Adding Google News Sitemap Headers
|
||||
*/
|
||||
public function extraSitemapHeader() {
|
||||
return array( 'xmlns:image' => 'http://www.google.com/schemas/sitemap-image/1.1' );
|
||||
}
|
||||
|
||||
public function get_post_media( int $post_id, string $post_type ): array {
|
||||
return apply_filters( 'sgg_image_sitemap_urls', array(), $post_id, $post_type );
|
||||
}
|
||||
|
||||
public function add_urls( string $url, array $media ): void {
|
||||
// Remove old URL if it exists
|
||||
$this->urls = array_filter(
|
||||
$this->urls,
|
||||
function( $item ) use ( $url ) {
|
||||
return $item[0] !== $url;
|
||||
}
|
||||
);
|
||||
|
||||
$this->urls[] = array(
|
||||
$url, // URL
|
||||
$media, // Images
|
||||
);
|
||||
}
|
||||
|
||||
public function filter_value( string $value ): bool {
|
||||
$value = strtok( $value, '?' );
|
||||
$filetype = wp_check_filetype( $value );
|
||||
$filtered = in_array( $filetype['type'], $this->image_mime_types, true );
|
||||
|
||||
return apply_filters( 'sgg_filter_image_url', $filtered, $value );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
use GRIM_SG\Vendor\Controller;
|
||||
|
||||
class ImportExport extends Controller {
|
||||
public function __construct() {
|
||||
add_action( 'wp_ajax_export_sitemap_settings', array( $this, 'export_settings' ) );
|
||||
}
|
||||
|
||||
public static function import_settings() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! empty( $_FILES['import_file']['tmp_name'] ) ) {
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
|
||||
$import_data = file_get_contents( $_FILES['import_file']['tmp_name'] );
|
||||
|
||||
if ( ! empty( $import_data ) ) {
|
||||
$import_data = json_decode( $import_data, true );
|
||||
|
||||
if ( ! empty( $import_data ) ) {
|
||||
update_option( self::$slug, $import_data );
|
||||
|
||||
add_settings_error( self::$slug, 'import_settings', esc_html__( 'Settings imported successfully.', 'xml-sitemap-generator-for-google' ), 'success' );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_settings_error(
|
||||
self::$slug,
|
||||
'import_settings',
|
||||
esc_html__( 'Invalid settings file or data.', 'xml-sitemap-generator-for-google' ),
|
||||
);
|
||||
}
|
||||
|
||||
public function export_settings() {
|
||||
if ( ! current_user_can( 'manage_options' ) || ! wp_verify_nonce( $_REQUEST['nonce'], 'sgg_export_settings' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = get_option( self::$slug );
|
||||
$export_data = wp_json_encode( $settings );
|
||||
|
||||
header( 'Content-Description: File Transfer' );
|
||||
header( 'Content-type: application/txt' );
|
||||
header( 'Content-Disposition: attachment; filename="sitemap_settings.json"' );
|
||||
header( 'Content-Transfer-Encoding: binary' );
|
||||
header( 'Expires: 0' );
|
||||
header( 'Cache-Control: must-revalidate' );
|
||||
header( 'Pragma: public' );
|
||||
|
||||
//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $export_data;
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
use GRIM_SG\Vendor\Controller;
|
||||
|
||||
class IndexNow extends Controller {
|
||||
private $site_url;
|
||||
private $api_key;
|
||||
private static $api_name = 'sgg_indexnow_api_key';
|
||||
|
||||
public function __construct() {
|
||||
$this->set_site_url();
|
||||
$this->set_api_key();
|
||||
}
|
||||
|
||||
public function ping_site_url() {
|
||||
return $this->ping_url( $this->site_url );
|
||||
}
|
||||
|
||||
public function ping_url( $url ) {
|
||||
$response = $this->request( $url );
|
||||
|
||||
return $this->handle_response( $response );
|
||||
}
|
||||
|
||||
public function request( $index_url ) {
|
||||
$data = wp_json_encode(
|
||||
array(
|
||||
'host' => $this->remove_url_scheme( $this->site_url ),
|
||||
'key' => $this->api_key,
|
||||
'keyLocation' => $this->get_api_key_location(),
|
||||
'urlList' => array( $index_url ),
|
||||
)
|
||||
);
|
||||
|
||||
return wp_remote_post(
|
||||
'https://api.indexnow.org/indexnow/',
|
||||
array(
|
||||
'body' => $data,
|
||||
'headers' => array(
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function handle_response( $response ) {
|
||||
$error = array(
|
||||
'status' => 'error',
|
||||
'message' => __( 'IndexNow Protocol unknown error occurred', 'google-sitemap-generator' ),
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return array(
|
||||
'status' => 'error',
|
||||
'message' => $response->get_error_message(),
|
||||
);
|
||||
}
|
||||
|
||||
if ( isset( $response['errors'] ) ) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
if ( ! empty( $response['response']['code'] ) ) {
|
||||
if ( in_array( $response['response']['code'], array( 200, 202 ), true ) ) {
|
||||
return array(
|
||||
'status' => 'success',
|
||||
'message' => __( 'Changes successfully submitted to IndexNow', 'google-sitemap-generator' ),
|
||||
);
|
||||
} else {
|
||||
if ( 400 === $response['response']['code'] ) {
|
||||
$error['message'] = __( 'IndexNow Protocol Invalid Request', 'google-sitemap-generator' );
|
||||
} elseif ( 403 === $response['response']['code'] ) {
|
||||
$error['message'] = __( 'IndexNow Protocol Invalid Api Key', 'google-sitemap-generator' );
|
||||
} elseif ( 422 === $response['response']['code'] ) {
|
||||
$error['message'] = __( 'IndexNow Protocol Invalid URL', 'google-sitemap-generator' );
|
||||
} elseif ( ! empty( $response['response']['message'] ) ) {
|
||||
$error['message'] = sprintf(
|
||||
/* translators: %s: error message */
|
||||
__( 'IndexNow Protocol Error: %s', 'google-sitemap-generator' ),
|
||||
$response['response']['message']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
public function get_api_key() {
|
||||
if ( ! empty( $this->api_key ) ) {
|
||||
return $this->api_key;
|
||||
}
|
||||
|
||||
$api_key = is_multisite() ? get_site_option( self::$api_name ) : get_option( self::$api_name );
|
||||
|
||||
if ( $api_key ) {
|
||||
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
|
||||
return base64_decode( $api_key );
|
||||
}
|
||||
|
||||
return apply_filters( 'sgg_indexnow_api_key', $api_key );
|
||||
}
|
||||
|
||||
public function set_api_key() {
|
||||
$api_key = $this->get_api_key();
|
||||
|
||||
if ( empty( $api_key ) ) {
|
||||
$api_key = preg_replace( '[-]', '', wp_generate_uuid4() );
|
||||
|
||||
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
|
||||
$base64_api_key = base64_encode( $api_key );
|
||||
|
||||
if ( is_multisite() ) {
|
||||
update_site_option( self::$api_name, $base64_api_key );
|
||||
} else {
|
||||
update_option( self::$api_name, $base64_api_key );
|
||||
}
|
||||
}
|
||||
|
||||
$this->api_key = $api_key;
|
||||
}
|
||||
|
||||
public static function delete_api_key() {
|
||||
if ( is_multisite() ) {
|
||||
delete_site_option( self::$api_name );
|
||||
} else {
|
||||
delete_option( self::$api_name );
|
||||
}
|
||||
}
|
||||
|
||||
public function set_site_url() {
|
||||
$this->site_url = get_home_url();
|
||||
}
|
||||
|
||||
public function get_api_key_location() {
|
||||
return trailingslashit( $this->site_url ) . $this->api_key . '.txt';
|
||||
}
|
||||
|
||||
public function remove_url_scheme( $url ) {
|
||||
return preg_replace( '/^https?:\/\//', '', $url );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
use GRIM_SG\Vendor\QueryBuilder;
|
||||
|
||||
abstract class MediaSitemap extends Sitemap {
|
||||
abstract public function add_urls( string $url, array $media ): void;
|
||||
|
||||
abstract public function filter_value( string $value ): bool;
|
||||
|
||||
/**
|
||||
* Add URLS Callback function
|
||||
*/
|
||||
public function urlsCallback() {
|
||||
return 'addMediaUrl';
|
||||
}
|
||||
|
||||
public function get_post_media( int $post_id, string $post_type ): array {
|
||||
return apply_filters( 'sgg_media_post_urls', array(), $post_id, $post_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect Media URLs for Sitemap
|
||||
*/
|
||||
public function collect_urls( $template = 'sitemap', $inner_sitemap = null, $current_page = null ) {
|
||||
global $wpdb;
|
||||
|
||||
$post_types = array( 'page', 'post' );
|
||||
$template = sgg_maybe_remove_inner_suffix( $template );
|
||||
$cache_enabled = ! $this->settings->disable_media_sitemap_cache;
|
||||
|
||||
if ( $cache_enabled ) {
|
||||
$cache = new Cache( "media-$template" );
|
||||
|
||||
// Set URLs from cache if available.
|
||||
$cached_urls = $cache->get();
|
||||
if ( $cached_urls ) {
|
||||
$this->urls = $cached_urls;
|
||||
}
|
||||
}
|
||||
|
||||
$sitemap_key = 'video-sitemap' === $template ? 'video_sitemap' : 'image_sitemap';
|
||||
|
||||
foreach ( $post_types as $key => $post_type ) {
|
||||
if ( isset( $this->settings->{$post_type}->{$sitemap_key} ) && ! $this->settings->{$post_type}->{$sitemap_key} ) {
|
||||
unset( $post_types[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( sgg_pro_enabled() ) {
|
||||
foreach ( $this->get_cpt() as $cpt ) {
|
||||
if ( ! empty( $this->settings->cpt[ $cpt ] ) && ! empty( $this->settings->cpt[ $cpt ]->{$sitemap_key} ) ) {
|
||||
$post_types[] = $cpt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sql_post_types = "('" . implode( "','", $post_types ) . "')";
|
||||
$multilingual_sql = $this->multilingual_sql( $post_types );
|
||||
$where_clause = ! empty( $multilingual_sql ) ? 'AND ' : 'WHERE ';
|
||||
$limit = 5000;
|
||||
|
||||
if ( $cache_enabled ) {
|
||||
$last_mod_time = get_option( $this->get_option_name( $template, 'latest_mod_time' ), '1970-01-01 00:00:00' );
|
||||
$last_id = get_option( $this->get_option_name( $template, 'latest_post_id' ), 0 );
|
||||
}
|
||||
|
||||
while ( true ) {
|
||||
$last_mod_sql = '';
|
||||
$limit_sql = '';
|
||||
if ( $cache_enabled ) {
|
||||
$last_mod_sql = $wpdb->prepare(
|
||||
'AND (posts.post_modified > %s OR (posts.post_modified = %s AND posts.ID > %d))',
|
||||
$last_mod_time,
|
||||
$last_mod_time,
|
||||
$last_id
|
||||
);
|
||||
$limit_sql = $wpdb->prepare( 'LIMIT %d', $limit );
|
||||
}
|
||||
|
||||
$sql = "SELECT posts.ID, posts.post_name, posts.post_parent, posts.post_content, posts.post_type, posts.post_modified
|
||||
FROM {$wpdb->posts} as posts $multilingual_sql $where_clause posts.post_status = 'publish'
|
||||
AND posts.post_type IN $sql_post_types AND posts.post_password = ''
|
||||
$last_mod_sql ORDER BY posts.post_modified ASC, posts.ID ASC $limit_sql";
|
||||
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
$posts = $wpdb->get_results( $sql );
|
||||
|
||||
// If no posts are returned, then all posts have been processed.
|
||||
if ( empty( $posts ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Loop through the posts and add the URLs to the sitemap.
|
||||
foreach ( $posts as $post ) {
|
||||
if ( ! apply_filters( 'xml_sitemap_include_post', true, $post->ID ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$content = apply_filters( 'xml_media_sitemap_post_content', $post->post_content, $post );
|
||||
if ( ! empty( $content ) && preg_match( '/\[.+?\]/im', $content ) ) {
|
||||
preg_match_all( '/\[.+?\]/im', $content, $shortcode_matches );
|
||||
|
||||
foreach ( $shortcode_matches as $shortcodes ) {
|
||||
foreach ( $shortcodes as $shortcode ) {
|
||||
// Skip HTML Sitemap Shortcode
|
||||
if ( 0 !== strpos( $shortcode, '[html-sitemap' ) ) {
|
||||
ob_start();
|
||||
|
||||
$do_shortcode = do_shortcode( $shortcode );
|
||||
$output = ob_get_clean();
|
||||
$final_output = $do_shortcode . $output;
|
||||
$content = str_replace( $shortcode, $final_output, $content );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$media = $this->get_post_media( $post->ID, $post->post_type );
|
||||
$urls = array();
|
||||
|
||||
if ( preg_match_all( '(https?://[-_.!~*()a-zA-Z0-9;/?:@&=+$%#纊-黑亜-熙ぁ-んァ-ヶ]+)', $content, $result ) !== false ) {
|
||||
$unique_urls = array();
|
||||
|
||||
// Remove duplicate Image sizes URLs
|
||||
foreach ( array_unique( $result[0] ) as $url ) {
|
||||
$base_url = preg_replace( '/-\d+x\d+(?=\.\w{3,4}$)/', '', $url );
|
||||
|
||||
if ( ! isset( $unique_urls[ $base_url ] ) ) {
|
||||
$unique_urls[ $base_url ] = strtok( $url, '#' );
|
||||
}
|
||||
}
|
||||
|
||||
$urls = array_values( $unique_urls );
|
||||
}
|
||||
|
||||
$urls = apply_filters( 'sgg_sitemap_post_media_urls', $urls, $post->ID );
|
||||
|
||||
if ( ! empty( $urls ) ) {
|
||||
foreach ( $urls as $url ) {
|
||||
if ( $this->filter_value( $url ) ) {
|
||||
$media[] = $url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $media ) ) {
|
||||
$this->add_urls( get_permalink( $post ), array_unique( $media ) );
|
||||
}
|
||||
|
||||
$last_mod_time = $post->post_modified;
|
||||
$last_id = $post->ID;
|
||||
}
|
||||
|
||||
if ( $cache_enabled ) {
|
||||
// Cache the collected URLs.
|
||||
$cache->set( $this->urls );
|
||||
|
||||
// Save the new markers for the latest post processed.
|
||||
update_option( $this->get_option_name( $template, 'latest_mod_time' ), $last_mod_time );
|
||||
update_option( $this->get_option_name( $template, 'latest_post_id' ), $last_id );
|
||||
}
|
||||
|
||||
// If fewer posts than the limit were returned, we've reached the final batch.
|
||||
if ( ! $cache_enabled || count( $posts ) < $limit ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set cached URLs to the sitemap URLs.
|
||||
if ( $cache_enabled ) {
|
||||
$this->urls = $cache->get();
|
||||
|
||||
if ( is_array( $this->urls ) ) {
|
||||
$this->urls = array_reverse( $this->urls );
|
||||
} else {
|
||||
$this->urls = array();
|
||||
|
||||
// Delete cache if no URLs are found
|
||||
self::delete_all_cache();
|
||||
}
|
||||
}
|
||||
|
||||
// Check Index Sitemap
|
||||
$links_per_page = $this->settings->links_per_page ?? 1000;
|
||||
$has_many_links = count( $this->urls ) > $links_per_page;
|
||||
|
||||
// Update Media Sitemap Structure option
|
||||
update_option( "sgg_{$template}_structure", $has_many_links ? 'multiple' : 'single' );
|
||||
|
||||
if ( sgg_is_sitemap_index( $template, $this->settings ) && $has_many_links ) {
|
||||
if ( ! empty( $inner_sitemap ) && ! empty( $current_page ) ) {
|
||||
$chunks = array_chunk( $this->urls, $links_per_page );
|
||||
$this->urls = $chunks[ $current_page - 1 ] ?? array();
|
||||
} else {
|
||||
$this->urls = array(
|
||||
str_replace( '-sitemap', '', $template ) =>
|
||||
array_map(
|
||||
function ( $chunk ) {
|
||||
return $chunk[0] ?? array();
|
||||
},
|
||||
array_chunk( $this->urls, $links_per_page )
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function get_option_name( string $template, string $name ): string {
|
||||
return "sgg_{$template}_{$name}";
|
||||
}
|
||||
|
||||
public static function delete_all_cache(): void {
|
||||
delete_option( 'sgg_image-sitemap_latest_mod_time' );
|
||||
delete_option( 'sgg_image-sitemap_latest_post_id' );
|
||||
delete_option( 'sgg_video-sitemap_latest_mod_time' );
|
||||
delete_option( 'sgg_video-sitemap_latest_post_id' );
|
||||
|
||||
Cache::delete( 'image-sitemap' );
|
||||
Cache::delete( 'media-image-sitemap' );
|
||||
Cache::delete( 'video-sitemap' );
|
||||
Cache::delete( 'media-video-sitemap' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
use GRIM_SG\Vendor\SitemapGenerator;
|
||||
|
||||
class MultilingualSitemap extends Sitemap {
|
||||
public static $template = 'multilingual-sitemap';
|
||||
|
||||
public function show_sitemap( $template, $is_xml = true, $inner_sitemap = null, $current_page = null ) {
|
||||
remove_all_filters( 'pre_get_posts' );
|
||||
|
||||
$sitemap = new SitemapGenerator( sgg_get_home_url() );
|
||||
|
||||
$this->collect_urls( $template, $inner_sitemap, $current_page );
|
||||
|
||||
try {
|
||||
$sitemap->createMultilingualSitemap( $this->urls );
|
||||
} catch ( \Exception $exc ) {
|
||||
echo $exc->getTraceAsString(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
try {
|
||||
$sitemap->outputSitemap( $template, $is_xml, $inner_sitemap );
|
||||
} catch ( \Exception $exc ) {
|
||||
echo $exc->getTraceAsString(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect Sitemap URLs
|
||||
*/
|
||||
public function collect_urls( $template = 'sitemap', $inner_sitemap = null, $current_page = null ) {
|
||||
$this->urls[] = sgg_get_sitemap_url( $this->settings->sitemap_url, 'sitemap_xml' );
|
||||
|
||||
// Polylang, TranslatePress
|
||||
$languages = sgg_get_languages();
|
||||
$default_language = sgg_get_default_language_code();
|
||||
|
||||
if ( ! empty( $languages ) ) {
|
||||
foreach ( $languages as $language ) {
|
||||
$url = sgg_get_sitemap_url( "{$language}/{$this->settings->sitemap_url}", 'sitemap_xml' );
|
||||
$this->urls[] = ! empty( $default_language )
|
||||
? str_replace( "/{$default_language}/", '/', $url )
|
||||
: $url;
|
||||
}
|
||||
}
|
||||
|
||||
// WPML
|
||||
if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
|
||||
$wpml_languages = apply_filters( 'wpml_active_languages', array() );
|
||||
foreach ( $wpml_languages as $language ) {
|
||||
if ( apply_filters( 'wpml_default_language', null ) === $language['code'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->urls[] = esc_url( "{$language['url']}{$this->settings->sitemap_url}" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
use GRIM_SG\Vendor\Controller;
|
||||
|
||||
class Notices extends Controller {
|
||||
private const RATE = 'sgg_rate';
|
||||
private const BUY_PRO = 'sgg_buy_pro';
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'admin_init', array( $this, 'init_notices' ) );
|
||||
add_action( 'wp_ajax_sgg_disable_notice', array( $this, 'disable_notice' ) );
|
||||
}
|
||||
|
||||
public function disable_notice() {
|
||||
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'sgg-notice' ) ) {
|
||||
wp_send_json_error( array( 'message' => esc_html__( 'Invalid nonce.', 'xml-sitemap-generator-for-google' ) ) );
|
||||
}
|
||||
|
||||
$notice = sanitize_text_field( $_POST['notice'] ?? '' );
|
||||
|
||||
if ( in_array( $notice, array( self::RATE, self::BUY_PRO ), true ) ) {
|
||||
update_option( "sgg_disable_notice_{$notice}", true, false );
|
||||
}
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
public function init_notices() {
|
||||
$installation_time = get_option( 'sgg_installation_time' );
|
||||
|
||||
if ( ! $installation_time ) {
|
||||
update_option( 'sgg_installation_time', time() );
|
||||
} else {
|
||||
$days = round( ( time() - $installation_time ) / DAY_IN_SECONDS );
|
||||
$disable_rate = get_option( 'sgg_disable_notice_' . self::RATE, false );
|
||||
$disable_pro = get_option( 'sgg_disable_notice_' . self::BUY_PRO, false );
|
||||
|
||||
add_action( 'current_screen', function ( $screen ) use ( $days, $disable_rate, $disable_pro ) {
|
||||
if ( strpos( $screen->id, 'xml-sitemap-generator-for-google' ) === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
remove_all_actions( 'admin_notices' );
|
||||
remove_all_actions( 'all_admin_notices' );
|
||||
|
||||
if ( $days >= 3 && ! $disable_rate ) {
|
||||
add_action( 'admin_notices', array( $this, 'rate_notice' ) );
|
||||
}
|
||||
|
||||
if ( $days >= 5 && ! sgg_pro_enabled() && ! $disable_pro ) {
|
||||
add_action( 'admin_notices', array( $this, 'pro_notice' ) );
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function rate_notice() {
|
||||
$this->enqueue_scripts();
|
||||
|
||||
Dashboard::render(
|
||||
'partials/rate-banner.php',
|
||||
array(
|
||||
'label' => esc_html__( 'Hi, thank you for using Google XML Sitemaps Generator!', 'xml-sitemap-generator-for-google' ),
|
||||
'description' => sprintf(
|
||||
esc_html__( 'If you like the plugin, please leave us a %s rating. A huge thank you from the team in advance!', 'xml-sitemap-generator-for-google' ),
|
||||
'<span><a href="' . esc_url( sgg_get_review_url() ) . '" target="_blank">★★★★★</a></span>'
|
||||
),
|
||||
'button_text' => esc_html__( 'Yes, Rate Now', 'xml-sitemap-generator-for-google' ),
|
||||
'button_url' => esc_url( sgg_get_review_url() ),
|
||||
'data_notice' => self::RATE,
|
||||
'notice_class' => 'grim-dynamic-notice',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function pro_notice() {
|
||||
$this->enqueue_scripts();
|
||||
|
||||
Dashboard::render(
|
||||
'partials/rate-banner.php',
|
||||
array(
|
||||
'label' => esc_html__( 'Hi, thank you for using Google XML Sitemaps Generator!', 'xml-sitemap-generator-for-google' ),
|
||||
'description' => sprintf(
|
||||
esc_html__( 'If you want to unlock more features, please check out our %s.', 'xml-sitemap-generator-for-google' ),
|
||||
'<a href="' . esc_url( sgg_get_pro_url( 'notice' ) ) . '" target="_blank">' . esc_html__( 'Pro version', 'xml-sitemap-generator-for-google' ) . '</a>'
|
||||
),
|
||||
'button_text' => esc_html__( 'Yes, Read More', 'xml-sitemap-generator-for-google' ),
|
||||
'button_url' => esc_url( sgg_get_pro_url( 'notice' ) ),
|
||||
'data_notice' => self::BUY_PRO,
|
||||
'notice_class' => 'grim-pro-notice grim-dynamic-notice',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function enqueue_scripts() {
|
||||
wp_enqueue_script( 'sgg-notices', GRIM_SG_URL . 'assets/js/notices.js', array( 'jquery' ), GRIM_SG_VERSION, true );
|
||||
wp_localize_script(
|
||||
'sgg-notices',
|
||||
'sggNotice',
|
||||
array(
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'nonce' => wp_create_nonce( 'sgg-notice' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
class PostSettings {
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'register_post_meta' ) );
|
||||
add_action( 'enqueue_block_editor_assets', array( $this, 'register_plugin_sidebar_block' ) );
|
||||
add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );
|
||||
add_action( 'save_post', array( $this, 'save_meta_box' ) );
|
||||
add_action( 'edit_attachment', array( $this, 'save_meta_box' ) );
|
||||
add_filter( 'user_has_cap', array( $this, 'allow_edit_post_meta' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers protected Post Meta fields.
|
||||
*/
|
||||
public function register_post_meta() {
|
||||
register_post_meta(
|
||||
'',
|
||||
'_sitemap_exclude',
|
||||
array(
|
||||
'show_in_rest' => true,
|
||||
'single' => true,
|
||||
'type' => 'boolean',
|
||||
)
|
||||
);
|
||||
register_post_meta(
|
||||
'',
|
||||
'_sitemap_priority',
|
||||
array(
|
||||
'show_in_rest' => true,
|
||||
'single' => true,
|
||||
'type' => 'string',
|
||||
)
|
||||
);
|
||||
register_post_meta(
|
||||
'',
|
||||
'_sitemap_frequency',
|
||||
array(
|
||||
'show_in_rest' => true,
|
||||
'single' => true,
|
||||
'type' => 'string',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers Gutenberg Plugin Sidebar Block.
|
||||
*/
|
||||
public function register_plugin_sidebar_block() {
|
||||
$assets_file = GRIM_SG_PATH . '/assets/gutenberg/build/plugin-sidebar.asset.php';
|
||||
|
||||
if ( file_exists( $assets_file ) ) {
|
||||
$assets = include $assets_file;
|
||||
|
||||
wp_enqueue_script(
|
||||
'sitemap-settings',
|
||||
GRIM_SG_URL . 'assets/gutenberg/build/plugin-sidebar.js',
|
||||
$assets['dependencies'],
|
||||
$assets['version'],
|
||||
true
|
||||
);
|
||||
wp_localize_script(
|
||||
'sitemap-settings',
|
||||
'sitemapSettings',
|
||||
array(
|
||||
'isProEnabled' => sgg_pro_enabled(),
|
||||
'isExcludeEnabled' => intval( ! apply_filters( 'xml_sitemap_disable_post_meta__exclude_sitemap', false ) ),
|
||||
'isPriorityEnabled' => intval( ! apply_filters( 'xml_sitemap_disable_post_meta__sitemap_priority', false ) ),
|
||||
'isFrequencyEnabled' => intval( ! apply_filters( 'xml_sitemap_disable_post_meta__sitemap_frequency', false ) ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers Post Metabox.
|
||||
*/
|
||||
public function add_meta_box() {
|
||||
// Disable Meta Box fields.
|
||||
if ( apply_filters( 'xml_sitemap_disable_post_meta_fields', false ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$public_post_types = get_post_types(
|
||||
array(
|
||||
'public' => true,
|
||||
)
|
||||
);
|
||||
|
||||
foreach ( $public_post_types as $post_type ) {
|
||||
add_meta_box(
|
||||
'sgg_pro_meta_box',
|
||||
esc_html__( 'XML Sitemap Options', 'xml-sitemap-generator-for-google' ),
|
||||
array( $this, 'meta_box_render' ),
|
||||
$post_type,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders Post Metabox.
|
||||
*/
|
||||
public function meta_box_render( $post ) {
|
||||
load_template(
|
||||
GRIM_SG_PATH . '/templates/post-meta-box.php',
|
||||
false,
|
||||
compact( 'post' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves Post Metabox.
|
||||
*/
|
||||
public function save_meta_box( $post_id ) {
|
||||
if ( ! isset( $_POST['sgg_pro_meta_box_nonce'] ) || ! wp_verify_nonce( $_POST['sgg_pro_meta_box_nonce'], 'sgg_pro_meta_box' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || ! current_user_can( 'edit_posts' ) || ! sgg_pro_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
update_post_meta( $post_id, '_sitemap_exclude', $_POST['_sitemap_exclude'] ?? '' );
|
||||
|
||||
if ( isset( $_POST['_sitemap_priority'] ) ) {
|
||||
update_post_meta( $post_id, '_sitemap_priority', sanitize_text_field( $_POST['_sitemap_priority'] ) );
|
||||
}
|
||||
|
||||
if ( isset( $_POST['_sitemap_frequency'] ) ) {
|
||||
update_post_meta( $post_id, '_sitemap_frequency', sanitize_text_field( $_POST['_sitemap_frequency'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow editing protected Post Meta fields.
|
||||
*/
|
||||
public function allow_edit_post_meta( $allcaps, $caps, $args ) {
|
||||
if ( ! empty( $args[0] ) && ! empty( $args[3] ) && 'edit_post_meta' === $args[0]
|
||||
&& in_array( $args[3], array( '_sitemap_exclude', '_sitemap_priority', '_sitemap_frequency' ), true ) ) {
|
||||
$allcaps['edit_post_meta'] = current_user_can( 'edit_posts' );
|
||||
}
|
||||
|
||||
return $allcaps;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,906 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
use GRIM_SG\Vendor\Controller;
|
||||
use GRIM_SG\Vendor\QueryBuilder;
|
||||
use GRIM_SG\Vendor\SitemapGenerator;
|
||||
|
||||
class Sitemap extends Controller {
|
||||
public static $template = 'sitemap';
|
||||
|
||||
public $urls = array();
|
||||
|
||||
public $settings;
|
||||
|
||||
public function __construct() {
|
||||
$this->settings = $this->get_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Sitemap
|
||||
*/
|
||||
public function show_sitemap( $template, $is_xml = true, $inner_sitemap = null, $current_page = null ) {
|
||||
if ( sgg_is_sitemap_index( $template, $this->settings ) && ! empty( $inner_sitemap ) ) {
|
||||
if ( in_array( $template, array( ImageSitemap::$template, VideoSitemap::$template ), true ) ) {
|
||||
$template .= '-inner-sitemap';
|
||||
} else {
|
||||
$template = 'inner-sitemap';
|
||||
}
|
||||
}
|
||||
|
||||
$sitemap = $this->generate_sitemap( $template, $is_xml, $inner_sitemap, $current_page );
|
||||
|
||||
try {
|
||||
$sitemap->outputSitemap( $template, $is_xml, $inner_sitemap );
|
||||
} catch ( \Exception $exc ) {
|
||||
echo $exc->getTraceAsString(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Sitemap
|
||||
*/
|
||||
public function generate_sitemap( $template = 'sitemap', $is_xml = true, $inner_sitemap = null, $current_page = null ) {
|
||||
remove_all_filters( 'pre_get_posts' );
|
||||
|
||||
$sitemap = new SitemapGenerator( sgg_get_home_url() );
|
||||
|
||||
if ( $this->settings->enable_cache ) {
|
||||
$cache = new Cache( $template, $inner_sitemap, $current_page );
|
||||
$urls = $cache->get();
|
||||
|
||||
if ( $urls ) {
|
||||
$this->urls = $urls;
|
||||
} else {
|
||||
$this->collect_urls( $template, $inner_sitemap, $current_page );
|
||||
$cache->set( $this->urls );
|
||||
}
|
||||
} else {
|
||||
$this->collect_urls( $template, $inner_sitemap, $current_page );
|
||||
}
|
||||
|
||||
$sitemap->addUrls( apply_filters( 'sgg_sitemap_urls', $this->urls ), $this->urlsCallback(), $template );
|
||||
|
||||
try {
|
||||
$sitemap->createSitemap( $template, $this->extraSitemapHeader(), $is_xml );
|
||||
} catch ( \Exception $exc ) {
|
||||
echo $exc->getTraceAsString(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
return $sitemap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Sitemap XSL Template
|
||||
*/
|
||||
public static function generate_sitemap_xsl( $template = 'sitemap' ) {
|
||||
ob_get_clean();
|
||||
|
||||
header( 'Content-Type: text/xsl; charset=utf-8' );
|
||||
header( 'X-Robots-Tag: noindex' );
|
||||
|
||||
ob_start();
|
||||
|
||||
global $wp_version;
|
||||
|
||||
if ( version_compare( $wp_version, '5.5.0', '<' ) ) {
|
||||
set_query_var( 'args', array( 'template' => $template ) );
|
||||
}
|
||||
|
||||
load_template(
|
||||
GRIM_SG_PATH . '/templates/xsl/sitemap.php',
|
||||
false,
|
||||
compact( 'template' )
|
||||
);
|
||||
|
||||
ob_end_flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Sitemap Table by Template
|
||||
*/
|
||||
public static function get_sitemap_table( $template = 'sitemap', $args = array() ) {
|
||||
switch ( $template ) {
|
||||
case GoogleNews::$template:
|
||||
$table = 'google-news';
|
||||
break;
|
||||
case ImageSitemap::$template:
|
||||
$table = 'image-sitemap';
|
||||
break;
|
||||
case VideoSitemap::$template:
|
||||
$table = 'video-sitemap';
|
||||
break;
|
||||
case 'sitemap-index':
|
||||
case MultilingualSitemap::$template:
|
||||
$table = 'sitemap-index';
|
||||
break;
|
||||
default:
|
||||
$table = 'sitemap';
|
||||
break;
|
||||
}
|
||||
|
||||
load_template( GRIM_SG_PATH . "/templates/xsl/tables/{$table}.php", false, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Sitemap Title by Template
|
||||
*/
|
||||
public static function get_sitemap_title( $template ) {
|
||||
$title = __( 'Sitemap', 'xml-sitemap-generator-for-google' );
|
||||
|
||||
switch ( $template ) {
|
||||
case \GRIM_SG\GoogleNews::$template:
|
||||
$title = __( 'Google News', 'xml-sitemap-generator-for-google' );
|
||||
break;
|
||||
case \GRIM_SG\ImageSitemap::$template:
|
||||
$title = __( 'Image Sitemap', 'xml-sitemap-generator-for-google' );
|
||||
break;
|
||||
case \GRIM_SG\VideoSitemap::$template:
|
||||
$title = __( 'Video Sitemap', 'xml-sitemap-generator-for-google' );
|
||||
break;
|
||||
case \GRIM_SG\MultilingualSitemap::$template:
|
||||
$title = __( 'Multilingual Sitemap', 'xml-sitemap-generator-for-google' );
|
||||
break;
|
||||
case 'inner-sitemap':
|
||||
$title = __( 'Sitemap', 'xml-sitemap-generator-for-google' );
|
||||
break;
|
||||
case 'sitemap-index':
|
||||
$title = __( 'Sitemap Index', 'xml-sitemap-generator-for-google' );
|
||||
break;
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add URLS Callback function
|
||||
*/
|
||||
public function urlsCallback() {
|
||||
return 'addUrl';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding Google News Sitemap Headers
|
||||
*/
|
||||
public function extraSitemapHeader() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect Sitemap URLs
|
||||
*/
|
||||
public function collect_urls( $template = 'sitemap', $inner_sitemap = null, $current_page = null ) {
|
||||
if ( $this->settings->home->include && ! $this->settings->page->include ) {
|
||||
$this->add_home();
|
||||
}
|
||||
|
||||
if ( sgg_is_sitemap_index( $template, $this->settings ) ) {
|
||||
$current_page = ! empty( $current_page ) ? intval( $current_page ) - 1 : $current_page;
|
||||
|
||||
if ( 'sitemap' === $template ) {
|
||||
$post_types = $this->get_post_types_list( array( 'page', 'post' ), $this->settings );
|
||||
foreach ( $post_types as $post_type ) {
|
||||
$this->add_posts( $post_type, $current_page, true );
|
||||
}
|
||||
$this->add_categories( $current_page, true );
|
||||
$this->add_authors( $current_page, true );
|
||||
$this->add_archives( true );
|
||||
$this->add_media( $current_page, true );
|
||||
$this->add_additional_pages( true );
|
||||
} else {
|
||||
switch ( $inner_sitemap ) {
|
||||
case 'category':
|
||||
$this->add_categories( $current_page );
|
||||
break;
|
||||
case 'author':
|
||||
$this->add_authors( $current_page );
|
||||
break;
|
||||
case 'archive':
|
||||
$this->add_archives();
|
||||
break;
|
||||
case 'media':
|
||||
$this->add_media( $current_page );
|
||||
break;
|
||||
case 'additional':
|
||||
$this->add_additional_pages();
|
||||
break;
|
||||
default:
|
||||
$this->add_posts( $inner_sitemap, $current_page );
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->add_posts();
|
||||
$this->add_not_translatable_posts(); // Add Not Translatable Post Types to All Sitemaps
|
||||
$this->add_categories();
|
||||
$this->add_authors();
|
||||
$this->add_archives();
|
||||
$this->add_media();
|
||||
$this->add_additional_pages();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Home Page to Sitemap
|
||||
*/
|
||||
public function add_home() {
|
||||
$home = $this->settings->home;
|
||||
|
||||
if ( $home->include ) {
|
||||
$front_page_id = get_option( 'page_on_front' );
|
||||
$last_modified = ( $front_page_id ) ? get_post_modified_time( DATE_W3C, false, $front_page_id ) : gmdate( 'c' );
|
||||
|
||||
$this->add_url(
|
||||
sgg_get_home_url_with_trailing_slash(),
|
||||
$home->priority,
|
||||
$home->frequency,
|
||||
$last_modified,
|
||||
'page'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all Posts to Sitemap
|
||||
*/
|
||||
public function add_posts( $post_type = null, $current_page = null, $is_sitemap_index = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$front_page_id = get_option( 'page_on_front' );
|
||||
$exclude_post_ids = apply_filters( 'sgg_sitemap_exclude_post_ids', apply_filters( 'sgg_sitemap_exclude_ids', array(), $this->settings->exclude_posts ?? '' ) );
|
||||
$exclude_term_ids = apply_filters( 'sgg_sitemap_exclude_term_ids', apply_filters( 'sgg_sitemap_exclude_ids', array(), $this->settings->exclude_terms ?? '' ) );
|
||||
$include_term_ids = apply_filters( 'sgg_sitemap_include_only_term_ids', apply_filters( 'sgg_sitemap_exclude_ids', array(), $this->settings->include_only_terms ?? '' ) );
|
||||
$per_page = intval( $this->settings->links_per_page ?? 1000 );
|
||||
|
||||
if ( ! empty( $front_page_id ) ) {
|
||||
$exclude_post_ids[] = $front_page_id;
|
||||
}
|
||||
|
||||
$exclude_posts_sql = '';
|
||||
if ( ! empty( $exclude_post_ids ) ) {
|
||||
$exclude_posts_sql = 'AND posts.ID NOT IN (' . implode( ',', array_unique( $exclude_post_ids ) ) . ')';
|
||||
}
|
||||
|
||||
$terms_join_sql = '';
|
||||
$terms_where_sql = '';
|
||||
if ( ! empty( $include_term_ids ) ) {
|
||||
$terms_join_sql = "INNER JOIN (
|
||||
SELECT DISTINCT tr.object_id
|
||||
FROM {$wpdb->term_relationships} tr
|
||||
INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
|
||||
WHERE tt.term_id IN (" . implode( ',', array_unique( $include_term_ids ) ) . ')
|
||||
) included_posts ON posts.ID = included_posts.object_id';
|
||||
} elseif ( ! empty( $exclude_term_ids ) ) {
|
||||
$terms_join_sql = "LEFT JOIN (
|
||||
SELECT DISTINCT tr.object_id
|
||||
FROM {$wpdb->term_relationships} tr
|
||||
INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
|
||||
WHERE tt.term_id IN (" . implode( ',', array_unique( $exclude_term_ids ) ) . ')
|
||||
) excluded_posts ON posts.ID = excluded_posts.object_id';
|
||||
$terms_where_sql = ' AND excluded_posts.object_id IS NULL';
|
||||
}
|
||||
|
||||
if ( ! empty( $post_type ) ) {
|
||||
if ( ( isset( $this->settings->{$post_type}->include ) && $this->settings->{$post_type}->include )
|
||||
|| ( ! empty( $this->settings->cpt[ $post_type ] ) && ! empty( $this->settings->cpt[ $post_type ]->include ) ) ) {
|
||||
$post_types = array( $post_type );
|
||||
}
|
||||
} else {
|
||||
$post_types = $this->get_post_types_list( array( 'page', 'post' ), $this->settings );
|
||||
}
|
||||
|
||||
if ( empty( $post_types ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( in_array( 'page', $post_types, true ) && 1 > $current_page ) {
|
||||
$this->add_home();
|
||||
}
|
||||
|
||||
$sql_extra_select = '';
|
||||
$sql_post_types = "('" . implode( "','", $post_types ) . "')";
|
||||
$multilingual_sql = $this->multilingual_sql( $post_types );
|
||||
$where_clause = ! empty( $multilingual_sql ) ? 'AND ' : 'WHERE ';
|
||||
|
||||
if ( sgg_pro_enabled() && ! empty( $this->settings->posts_priority ) ) {
|
||||
$sql_extra_select .= ', posts.comment_count';
|
||||
}
|
||||
|
||||
$sql = "SELECT
|
||||
posts.ID,
|
||||
posts.post_name,
|
||||
posts.post_parent,
|
||||
posts.post_type,
|
||||
posts.post_date,
|
||||
posts.post_modified
|
||||
$sql_extra_select
|
||||
FROM $wpdb->posts as posts
|
||||
$terms_join_sql
|
||||
$multilingual_sql
|
||||
$where_clause posts.post_status = 'publish' AND posts.post_type IN $sql_post_types AND posts.post_password = ''
|
||||
$exclude_posts_sql
|
||||
$terms_where_sql
|
||||
GROUP BY posts.ID
|
||||
ORDER BY posts.post_modified DESC";
|
||||
|
||||
if ( is_null( $current_page ) && ! $is_sitemap_index ) {
|
||||
$this->add_post_urls( $sql, false );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $is_sitemap_index ) {
|
||||
// Calculate total number of posts
|
||||
$total_posts_sql = "SELECT COUNT(*) FROM $wpdb->posts as posts
|
||||
$terms_join_sql
|
||||
$multilingual_sql
|
||||
$where_clause posts.post_status = 'publish' AND posts.post_type IN $sql_post_types AND posts.post_password = ''
|
||||
$exclude_posts_sql
|
||||
$terms_where_sql
|
||||
ORDER BY posts.post_modified DESC";
|
||||
$total_posts = $wpdb->get_var( $total_posts_sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
|
||||
// Calculate the number of chunks
|
||||
$num_chunks = ceil( $total_posts / $per_page );
|
||||
|
||||
for ( $chunk_index = 0; $chunk_index < $num_chunks; $chunk_index++ ) {
|
||||
$offset = $chunk_index * $per_page;
|
||||
$chunk_sql = $sql . " LIMIT $offset, 1";
|
||||
|
||||
$this->add_post_urls( $chunk_sql, true );
|
||||
}
|
||||
} else {
|
||||
$offset = $current_page * $per_page;
|
||||
$sql .= " LIMIT $offset, $per_page";
|
||||
|
||||
$this->add_post_urls( $sql, false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Post URLs to Sitemap
|
||||
*/
|
||||
public function add_post_urls( $sql, $is_sitemap_index ) {
|
||||
$priority_provider = $this->get_posts_priority_provider();
|
||||
$posts = QueryBuilder::run_query( $sql );
|
||||
|
||||
foreach ( $posts as $post ) {
|
||||
if ( $is_sitemap_index || apply_filters( 'xml_sitemap_include_post', true, $post->ID ) ) {
|
||||
$this->add_url(
|
||||
get_permalink( $post ),
|
||||
( null !== $priority_provider && 'post' === $post->post_type )
|
||||
? apply_filters( 'sitemap_post_priority', $priority_provider->get_post_priority( $post->comment_count ), $post->ID )
|
||||
: apply_filters( 'sitemap_post_priority', $this->get_post_settings( $post->post_type, 'priority' ), $post->ID ),
|
||||
apply_filters( 'sitemap_post_frequency', $this->get_post_settings( $post->post_type, 'frequency' ), $post->ID ),
|
||||
gmdate( DATE_W3C, strtotime( $post->post_modified ) ),
|
||||
$post->post_type
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all Categories & Tags
|
||||
*/
|
||||
public function add_categories( $current_page = null, $is_sitemap_index = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$taxonomy_types = array();
|
||||
$per_page = intval( $this->settings->links_per_page ?? 1000 );
|
||||
|
||||
foreach ( $this->get_taxonomy_types( 'names' ) as $taxonomy_type ) {
|
||||
if ( ! empty( $this->settings->taxonomies[ $taxonomy_type ] ) && $this->settings->taxonomies[ $taxonomy_type ]->include ) {
|
||||
$taxonomy_types[] = $taxonomy_type;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $taxonomy_types ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$exclude_term_ids = apply_filters( 'sgg_sitemap_exclude_ids', array(), $this->settings->exclude_terms ?? '' );
|
||||
$include_term_ids = apply_filters( 'sgg_sitemap_exclude_ids', array(), $this->settings->include_only_terms ?? '' );
|
||||
$terms_where_sql = '';
|
||||
if ( ! empty( $include_term_ids ) ) {
|
||||
$terms_where_sql = 'AND terms.term_id IN (' . implode( ',', array_unique( $include_term_ids ) ) . ')';
|
||||
} elseif ( ! empty( $exclude_term_ids ) ) {
|
||||
$terms_where_sql = 'AND terms.term_id NOT IN (' . implode( ',', array_unique( $exclude_term_ids ) ) . ')';
|
||||
}
|
||||
|
||||
$post_types = $this->get_post_types_list( array( 'post' ), $this->settings );
|
||||
$sql_post_types = "('" . implode( "','", $post_types ) . "')";
|
||||
$sql_taxonomies = "('" . implode( "','", $taxonomy_types ) . "')";
|
||||
$multilingual_sql = $this->multilingual_sql( $taxonomy_types, true );
|
||||
$where_clause = ! empty( $multilingual_sql ) ? 'AND ' : 'WHERE ';
|
||||
$terms_query = "
|
||||
SELECT terms.*, term_taxonomy.taxonomy, term_taxonomy.count, (
|
||||
SELECT MAX(p.post_modified)
|
||||
FROM $wpdb->posts AS p
|
||||
INNER JOIN $wpdb->term_relationships AS tr ON p.ID = tr.object_id
|
||||
WHERE p.post_type IN $sql_post_types
|
||||
AND p.post_status = 'publish'
|
||||
AND tr.term_taxonomy_id = term_taxonomy.term_taxonomy_id
|
||||
) AS post_modified
|
||||
FROM $wpdb->terms AS terms
|
||||
INNER JOIN $wpdb->term_taxonomy AS term_taxonomy ON terms.term_id = term_taxonomy.term_id
|
||||
$multilingual_sql
|
||||
$where_clause term_taxonomy.taxonomy IN $sql_taxonomies
|
||||
$terms_where_sql
|
||||
AND term_taxonomy.count > 0
|
||||
GROUP BY terms.term_id
|
||||
ORDER BY post_modified DESC, terms.name ASC
|
||||
";
|
||||
|
||||
if ( is_null( $current_page ) && ! $is_sitemap_index ) {
|
||||
$this->add_category_urls( $terms_query, false );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $is_sitemap_index ) {
|
||||
// Calculate total number of terms
|
||||
$total_terms_sql = "
|
||||
SELECT COUNT(*) FROM $wpdb->terms AS terms
|
||||
INNER JOIN $wpdb->term_taxonomy AS term_taxonomy ON terms.term_id = term_taxonomy.term_id
|
||||
$multilingual_sql
|
||||
$where_clause term_taxonomy.taxonomy IN $sql_taxonomies
|
||||
$terms_where_sql
|
||||
AND term_taxonomy.count > 0
|
||||
";
|
||||
$total_terms = $wpdb->get_var( $total_terms_sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
|
||||
// Calculate the number of chunks
|
||||
$num_chunks = ceil( $total_terms / $per_page );
|
||||
|
||||
for ( $chunk_index = 0; $chunk_index < $num_chunks; $chunk_index++ ) {
|
||||
$offset = $chunk_index * $per_page;
|
||||
$chunk_sql = $terms_query . " LIMIT $offset, 1";
|
||||
|
||||
$this->add_category_urls( $chunk_sql, true );
|
||||
}
|
||||
} else {
|
||||
$offset = $current_page * $per_page;
|
||||
$terms_query .= " LIMIT $offset, $per_page";
|
||||
|
||||
$this->add_category_urls( $terms_query, false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Category URLs to Sitemap
|
||||
*/
|
||||
public function add_category_urls( $terms_query, $is_sitemap_index ) {
|
||||
global $wpdb;
|
||||
|
||||
$terms = $wpdb->get_results( $terms_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
|
||||
foreach ( $terms as $term ) {
|
||||
if ( ! $is_sitemap_index && apply_filters( 'sgg_sitemap_exclude_single_term', false, intval( $term->term_id ), $term->taxonomy ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$term_modified = ! empty( $term->post_modified )
|
||||
? strtotime( $term->post_modified )
|
||||
: time();
|
||||
|
||||
$this->add_url(
|
||||
get_term_link( $term ),
|
||||
apply_filters( 'sitemap_term_priority', $this->get_taxonomy_settings( $term->taxonomy, 'priority' ), $term->term_id ),
|
||||
apply_filters( 'sitemap_term_frequency', $this->get_taxonomy_settings( $term->taxonomy, 'frequency' ), $term->term_id ),
|
||||
gmdate( DATE_W3C, $term_modified ),
|
||||
'category'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all Authors of Posts
|
||||
*/
|
||||
public function add_authors( $current_page = null, $is_sitemap_index = false ) {
|
||||
if ( ! $this->settings->authors->include ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'has_published_posts' => $this->get_post_types_list( array( 'post' ), $this->settings ),
|
||||
'fields' => 'ids',
|
||||
'orderby' => 'post_count',
|
||||
'order' => 'DESC',
|
||||
'number' => -1,
|
||||
);
|
||||
|
||||
if ( is_null( $current_page ) && ! $is_sitemap_index ) {
|
||||
$this->add_author_urls( $args );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$per_page = intval( $this->settings->links_per_page ?? 1000 );
|
||||
|
||||
if ( $is_sitemap_index ) {
|
||||
$authors_query = new \WP_User_Query( $args );
|
||||
|
||||
if ( empty( $authors_query->get_total() ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$num_chunks = ceil( $authors_query->get_total() / $per_page );
|
||||
|
||||
for ( $chunk_index = 0; $chunk_index < $num_chunks; $chunk_index++ ) {
|
||||
$offset = $chunk_index * $per_page;
|
||||
$args = array_merge(
|
||||
$args,
|
||||
array(
|
||||
'number' => 1,
|
||||
'offset' => $offset,
|
||||
)
|
||||
);
|
||||
|
||||
$this->add_author_urls( $args );
|
||||
}
|
||||
} else {
|
||||
$offset = $current_page * $per_page;
|
||||
$args = array_merge(
|
||||
$args,
|
||||
array(
|
||||
'number' => $per_page,
|
||||
'offset' => $offset,
|
||||
)
|
||||
);
|
||||
|
||||
$this->add_author_urls( $args );
|
||||
}
|
||||
}
|
||||
|
||||
public function add_author_urls( $args ) {
|
||||
$authors_query = new \WP_User_Query( $args );
|
||||
$authors = $authors_query->get_results();
|
||||
|
||||
if ( ! empty( $authors ) ) {
|
||||
global $wpdb;
|
||||
|
||||
foreach ( $authors as $author_id ) {
|
||||
$latest_post_query = "SELECT ID, post_modified
|
||||
FROM {$wpdb->posts}
|
||||
WHERE post_author = {$author_id}
|
||||
AND post_type = 'post' AND post_status = 'publish'
|
||||
ORDER BY post_modified DESC
|
||||
LIMIT 1";
|
||||
|
||||
$latest_post = $wpdb->get_row( $latest_post_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
$modified_time = ! empty( $latest_post->post_modified )
|
||||
? gmdate( DATE_W3C, strtotime( $latest_post->post_modified ) )
|
||||
: gmdate( DATE_W3C );
|
||||
|
||||
$this->add_url(
|
||||
get_author_posts_url( $author_id ),
|
||||
$this->settings->authors->priority,
|
||||
$this->settings->authors->frequency,
|
||||
$modified_time,
|
||||
'author'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all Archives
|
||||
*/
|
||||
public function add_archives( $is_sitemap_index = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$sql_multilingual = $this->multilingual_sql( array( 'post' ) );
|
||||
$where_clause = ! empty( $sql_multilingual ) ? 'AND ' : 'WHERE ';
|
||||
$sql = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, post_date AS post_date, count(ID) as count_posts
|
||||
FROM $wpdb->posts as posts
|
||||
$sql_multilingual
|
||||
$where_clause post_type = 'post' AND post_status = 'publish' AND post_password = ''
|
||||
GROUP BY YEAR(post_date), MONTH(post_date)
|
||||
ORDER BY post_date DESC";
|
||||
|
||||
if ( $is_sitemap_index ) {
|
||||
$sql .= ' LIMIT 1';
|
||||
}
|
||||
|
||||
$archives = QueryBuilder::run_query( $sql );
|
||||
|
||||
foreach ( $archives as $archive ) {
|
||||
$option = ( gmdate( 'n' ) === $archive->month && gmdate( 'Y' ) === $archive->year ) ? 'archive' : 'archive_older';
|
||||
if ( $this->settings->{$option}->include ) {
|
||||
$this->add_url(
|
||||
get_month_link( $archive->year, $archive->month ),
|
||||
$this->settings->{$option}->priority,
|
||||
$this->settings->{$option}->frequency,
|
||||
gmdate( DATE_W3C, strtotime( $archive->post_date ) ),
|
||||
'archive'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Media Pages (Attachments)
|
||||
*/
|
||||
public function add_media( $current_page = null, $is_sitemap_index = false ) {
|
||||
if ( ! $this->settings->media->include ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! get_option( 'wp_attachment_pages_enabled' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$per_page = intval( $this->settings->links_per_page ?? 1000 );
|
||||
$multilingual_sql = $this->multilingual_sql( array( 'attachment' ) );
|
||||
$where_clause = ! empty( $multilingual_sql ) ? 'AND ' : 'WHERE ';
|
||||
|
||||
$sql = "SELECT
|
||||
posts.ID,
|
||||
posts.post_name,
|
||||
posts.post_parent,
|
||||
posts.post_type,
|
||||
posts.post_date,
|
||||
posts.post_modified
|
||||
FROM $wpdb->posts as posts
|
||||
$multilingual_sql
|
||||
$where_clause posts.post_status = 'inherit' AND posts.post_type = 'attachment' AND posts.post_password = ''
|
||||
GROUP BY posts.ID
|
||||
ORDER BY posts.post_modified DESC";
|
||||
|
||||
if ( is_null( $current_page ) && ! $is_sitemap_index ) {
|
||||
$this->add_media_urls( $sql, false );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $is_sitemap_index ) {
|
||||
// Calculate total number of attachments
|
||||
$total_media_sql = "SELECT COUNT(*) FROM $wpdb->posts as posts
|
||||
$multilingual_sql
|
||||
$where_clause posts.post_status = 'inherit' AND posts.post_type = 'attachment' AND posts.post_password = ''
|
||||
ORDER BY posts.post_modified DESC";
|
||||
$total_media = $wpdb->get_var( $total_media_sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
|
||||
// Calculate the number of chunks
|
||||
$num_chunks = ceil( $total_media / $per_page );
|
||||
|
||||
for ( $chunk_index = 0; $chunk_index < $num_chunks; $chunk_index++ ) {
|
||||
$offset = $chunk_index * $per_page;
|
||||
$chunk_sql = $sql . " LIMIT $offset, 1";
|
||||
|
||||
$this->add_media_urls( $chunk_sql, true );
|
||||
}
|
||||
} else {
|
||||
$offset = $current_page * $per_page;
|
||||
$sql .= " LIMIT $offset, $per_page";
|
||||
|
||||
$this->add_media_urls( $sql, false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Media URLs to Sitemap
|
||||
*/
|
||||
public function add_media_urls( $sql, $is_sitemap_index ) {
|
||||
$attachments = QueryBuilder::run_query( $sql );
|
||||
|
||||
foreach ( $attachments as $attachment ) {
|
||||
if ( $is_sitemap_index || apply_filters( 'xml_sitemap_include_post', true, $attachment->ID ) ) {
|
||||
$attachment_link = get_attachment_link( $attachment->ID );
|
||||
|
||||
// Only add if attachment link is valid (attachment pages are enabled)
|
||||
if ( $attachment_link ) {
|
||||
$this->add_url(
|
||||
$attachment_link,
|
||||
apply_filters( 'sitemap_media_priority', apply_filters( 'sitemap_post_priority', $this->settings->media->priority, $attachment->ID ), $attachment->ID ),
|
||||
apply_filters( 'sitemap_media_frequency', apply_filters( 'sitemap_post_frequency', $this->settings->media->frequency, $attachment->ID ), $attachment->ID ),
|
||||
gmdate( DATE_W3C, strtotime( $attachment->post_modified ) ),
|
||||
'media'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Additional Pages
|
||||
*/
|
||||
public function add_additional_pages( $is_sitemap_index = false ) {
|
||||
$pages = $this->settings->additional_pages;
|
||||
|
||||
if ( empty( $pages ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $is_sitemap_index ) {
|
||||
usort(
|
||||
$pages,
|
||||
function ( $a, $b ) {
|
||||
return strtotime( $b['lastmod'] ) - strtotime( $a['lastmod'] );
|
||||
}
|
||||
);
|
||||
|
||||
$pages = array( $pages[0] );
|
||||
}
|
||||
|
||||
foreach ( $pages as $page ) {
|
||||
if ( empty( $page['url'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$last_modified = ! empty( $page['lastmod'] )
|
||||
? gmdate( DATE_W3C, strtotime( $page['lastmod'] ) )
|
||||
: gmdate( DATE_W3C );
|
||||
|
||||
$this->add_url(
|
||||
$page['url'],
|
||||
$page['priority'],
|
||||
$page['frequency'],
|
||||
$last_modified,
|
||||
'additional'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Sitemap Url
|
||||
*
|
||||
* @param $url
|
||||
* @param $priority
|
||||
* @param $frequency
|
||||
* @param string $last_modified
|
||||
*/
|
||||
public function add_url( $url, $priority, $frequency, $last_modified = '', $inner_sitemap = '' ) {
|
||||
$item = array(
|
||||
$url, // URL
|
||||
$last_modified, // Last Modified
|
||||
$frequency, // Frequency
|
||||
number_format( floatval( $priority / 10 ), 1, '.', '' ), // Priority
|
||||
);
|
||||
|
||||
if ( sgg_is_sitemap_index( 'sitemap', $this->settings ) ) {
|
||||
$this->urls[ $inner_sitemap ][] = $item;
|
||||
} else {
|
||||
$this->urls[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function multilingual_sql( $element_types, $is_taxonomy = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$multilingual_sql = '';
|
||||
$element_id_column = $is_taxonomy ? 'term_taxonomy.term_taxonomy_id' : 'posts.ID';
|
||||
|
||||
if ( function_exists( 'pll_languages_list' ) && ! empty( $GLOBALS['polylang'] ) ) {
|
||||
global $polylang;
|
||||
|
||||
$current_language = pll_current_language();
|
||||
$polylang_model = $polylang->model;
|
||||
$lang_model = $polylang_model->get_language( $current_language );
|
||||
$tax_language = $is_taxonomy ? $polylang_model->term->get_tax_language() : $polylang_model->post->get_tax_language();
|
||||
$polylang_term_ids = array();
|
||||
|
||||
foreach ( $element_types as $key => $element_type ) {
|
||||
$translatable = $is_taxonomy
|
||||
? $polylang_model->is_translated_taxonomy( $element_type )
|
||||
: $polylang_model->is_translated_post_type( $element_type );
|
||||
|
||||
if ( ! $translatable ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $lang_model ) {
|
||||
$polylang_term_ids[] = absint( $lang_model->get_tax_prop( $tax_language, 'term_taxonomy_id' ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $polylang_term_ids ) ) {
|
||||
$polylang_term_ids = '(' . implode( ',', array_unique( $polylang_term_ids ) ) . ')';
|
||||
$multilingual_sql = "INNER JOIN {$wpdb->term_relationships} AS pll_tr ON $element_id_column = pll_tr.object_id WHERE ( pll_tr.term_taxonomy_id IN $polylang_term_ids )";
|
||||
}
|
||||
}
|
||||
|
||||
if ( defined( 'ICL_SITEPRESS_VERSION' ) && ! empty( $element_types ) ) {
|
||||
$current_language = apply_filters( 'wpml_current_language', null );
|
||||
$element_type = $is_taxonomy ? 'tax' : 'post';
|
||||
$wpml_element_types = array_map(
|
||||
function ( $post_type ) use ( $element_type ) {
|
||||
return "{$element_type}_{$post_type}";
|
||||
},
|
||||
$element_types
|
||||
);
|
||||
$sql_element_types = "('" . implode( "','", $wpml_element_types ) . "')";
|
||||
$multilingual_sql = "INNER JOIN {$wpdb->prefix}icl_translations AS translations ON $element_id_column = translations.element_id
|
||||
WHERE translations.language_code = '$current_language' AND translations.element_type IN $sql_element_types";
|
||||
}
|
||||
|
||||
return $multilingual_sql;
|
||||
}
|
||||
|
||||
public function add_not_translatable_posts() {
|
||||
// Add Polylang Not Translatable Post Types
|
||||
if ( function_exists( 'pll_languages_list' ) && ! empty( $GLOBALS['polylang'] ) ) {
|
||||
$options = get_option( 'polylang' );
|
||||
$post_types = $this->get_post_types_list( array(), $this->settings );
|
||||
$not_translatable = ! empty( $options['post_types'] ) && ! empty( $post_types )
|
||||
? array_diff( $post_types, $options['post_types'] )
|
||||
: array();
|
||||
|
||||
if ( ! empty( $not_translatable ) ) {
|
||||
foreach ( $not_translatable as $post_type ) {
|
||||
$this->add_posts( $post_type );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts Priority
|
||||
*/
|
||||
public function get_posts_priority_provider() {
|
||||
$class_name = str_replace( '/', '\\', $this->settings->posts_priority ?? '' );
|
||||
|
||||
return class_exists( $class_name ) ? new $class_name( $this->get_comments_count(), $this->get_posts_count() ) : null;
|
||||
}
|
||||
|
||||
public function get_comments_count() {
|
||||
global $wpdb;
|
||||
|
||||
$cache_key = self::$slug . '_comments_count';
|
||||
$comments_count = wp_cache_get( $cache_key, self::$slug );
|
||||
|
||||
if ( false === $comments_count ) {
|
||||
$comments_count = $wpdb->get_var( "SELECT COUNT(*) as `comments_count` FROM {$wpdb->comments} WHERE `comment_approved`='1'" );
|
||||
wp_cache_set( $cache_key, $comments_count, self::$slug, 20 );
|
||||
}
|
||||
|
||||
return $comments_count;
|
||||
}
|
||||
|
||||
public function get_posts_count() {
|
||||
global $wpdb;
|
||||
|
||||
$cache_key = self::$slug . '_posts_count';
|
||||
$posts_count = wp_cache_get( $cache_key, self::$slug );
|
||||
|
||||
if ( false === $posts_count ) {
|
||||
$posts_count = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->posts} p WHERE p.post_password = '' AND p.post_type = 'post' AND p.post_status = 'publish' " );
|
||||
wp_cache_set( $cache_key, $posts_count, self::$slug, 20 );
|
||||
}
|
||||
|
||||
return $posts_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Post Field Value
|
||||
*
|
||||
* @param $post_type
|
||||
* @param $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_post_settings( $post_type, $field ) {
|
||||
if ( ! empty( $this->settings->cpt ) && in_array( $post_type, array_keys( $this->settings->cpt ), true ) ) {
|
||||
return $this->settings->cpt[ $post_type ]->{$field} ?? null;
|
||||
}
|
||||
|
||||
return $this->settings->{$post_type}->{$field} ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Taxonomy Field Value
|
||||
*
|
||||
* @param $taxonomy_type
|
||||
* @param $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_taxonomy_settings( $taxonomy_type, $field ) {
|
||||
if ( ! empty( $this->settings->taxonomies ) && in_array( $taxonomy_type, array_keys( $this->settings->taxonomies ), true ) ) {
|
||||
return $this->settings->taxonomies[ $taxonomy_type ]->{$field} ?? null;
|
||||
}
|
||||
|
||||
return $this->settings->{$taxonomy_type}->{$field} ?? null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
|
||||
return;
|
||||
}
|
||||
|
||||
use \WP_CLI;
|
||||
|
||||
class SitemapCLI {
|
||||
/**
|
||||
* Generate a sitemap.
|
||||
*
|
||||
* ## OPTIONS
|
||||
*
|
||||
* [--template=<template>]
|
||||
* : The sitemap template to use. Default: 'sitemap'
|
||||
*
|
||||
* ## EXAMPLES
|
||||
*
|
||||
* # Generate a sitemap
|
||||
* $ wp sitemap generate
|
||||
*
|
||||
* # Generate a specific Sitemap type
|
||||
* $ wp sitemap generate --template=sitemap
|
||||
* $ wp sitemap generate --template=image-sitemap
|
||||
* $ wp sitemap generate --template=video-sitemap
|
||||
* $ wp sitemap generate --template=google-news
|
||||
*
|
||||
* @param array $args Command arguments
|
||||
* @param array $assoc_args Command associative arguments
|
||||
*/
|
||||
public function generate( $args, $assoc_args ) {
|
||||
$template = $assoc_args['template'] ?? 'sitemap';
|
||||
$inner_sitemap = null;
|
||||
$current_page = null;
|
||||
$allowed_templates = array(
|
||||
'sitemap',
|
||||
'image-sitemap',
|
||||
'video-sitemap',
|
||||
'google-news',
|
||||
);
|
||||
|
||||
if ( ! in_array( $template, $allowed_templates, true ) ) {
|
||||
WP_CLI::error( 'Invalid Sitemap Template. Allowed templates: ' . implode( ', ', $allowed_templates ) );
|
||||
}
|
||||
|
||||
// Initialize the Sitemap class
|
||||
$sitemap = null;
|
||||
if ( 'sitemap' === $template ) {
|
||||
$sitemap = new Sitemap();
|
||||
} elseif ( 'image-sitemap' === $template ) {
|
||||
$sitemap = new ImageSitemap();
|
||||
} elseif ( 'video-sitemap' === $template ) {
|
||||
$sitemap = new VideoSitemap();
|
||||
} elseif ( 'google-news' === $template ) {
|
||||
$sitemap = new GoogleNews();
|
||||
}
|
||||
|
||||
if ( ! $sitemap ) {
|
||||
WP_CLI::error( 'Sitemap class not found.' );
|
||||
}
|
||||
|
||||
if ( $sitemap->settings->enable_cache ) {
|
||||
$cache = new Cache( $template, $inner_sitemap, $current_page );
|
||||
|
||||
$sitemap->collect_urls( $template, $inner_sitemap, $current_page );
|
||||
$cache->set( $sitemap->urls );
|
||||
} else {
|
||||
$sitemap->collect_urls( $template, $inner_sitemap, $current_page );
|
||||
}
|
||||
|
||||
WP_CLI::success(
|
||||
"Sitemap generated successfully for template: {$template}. URLs count: " . count( $sitemap->urls )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Register the command
|
||||
WP_CLI::add_command( 'sitemap', 'GRIM_SG\SitemapCLI' );
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
use GRIM_SG\Vendor\Controller;
|
||||
|
||||
class Tools extends Controller {
|
||||
public function __construct() {
|
||||
add_action( 'transition_post_status', array( $this, 'transition_post_status' ), 100, 3 );
|
||||
}
|
||||
|
||||
public function transition_post_status( $new_status, $old_status, $post ) {
|
||||
$settings = $this->get_settings();
|
||||
|
||||
// Ping IndexNow
|
||||
if ( $settings->enable_indexnow && 'publish' === $new_status ) {
|
||||
( new IndexNow() )->ping_url( get_permalink( $post ) );
|
||||
}
|
||||
}
|
||||
|
||||
public static function run_tools_actions( $data = array() ) {
|
||||
if ( ! empty( $data['sgg-indexnow'] ) ) {
|
||||
$response = ( new IndexNow() )->ping_site_url();
|
||||
|
||||
add_settings_error(
|
||||
Controller::$slug,
|
||||
'indexnow_notice',
|
||||
$response['message'],
|
||||
$response['status']
|
||||
);
|
||||
|
||||
return true;
|
||||
} elseif ( ! empty( $data['sgg-flush-rewrite-rules'] ) ) {
|
||||
Frontend::activate_plugin();
|
||||
|
||||
self::add_admin_notice( __( 'WordPress Rewrite Rules flushed.', 'xml-sitemap-generator-for-google' ) );
|
||||
|
||||
return true;
|
||||
} elseif ( ! empty( $data['sgg-clear-cache'] ) ) {
|
||||
Cache::clear();
|
||||
|
||||
self::add_admin_notice( __( 'Sitemaps Cache cleared.', 'xml-sitemap-generator-for-google' ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function add_admin_notice( $message ) {
|
||||
add_settings_error( Controller::$slug, 'sitemap_tools', $message, 'success' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
use SGG_PRO\Classes\Video_Sitemap;
|
||||
|
||||
class VideoSitemap extends MediaSitemap {
|
||||
public static $template = 'video-sitemap';
|
||||
|
||||
/**
|
||||
* Adding Google News Sitemap Headers
|
||||
*/
|
||||
public function extraSitemapHeader() {
|
||||
return array( 'xmlns:video' => 'http://www.google.com/schemas/sitemap-video/1.1' );
|
||||
}
|
||||
|
||||
public function add_urls( string $url, array $media ): void {
|
||||
$videos = array();
|
||||
|
||||
foreach ( $media as $video ) {
|
||||
$extensions = explode( '.', $video );
|
||||
$extension = end( $extensions );
|
||||
|
||||
if ( 'video' === wp_ext2type( $extension ) ) {
|
||||
$attachment_id = attachment_url_to_postid( $video );
|
||||
if ( $attachment_id ) {
|
||||
$thumbnail = get_the_post_thumbnail_url( $attachment_id, 'thumbnail' );
|
||||
$metadata = get_post_meta( $attachment_id, '_wp_attachment_metadata', true );
|
||||
$videos[] = array(
|
||||
'thumbnail' => ! empty( $thumbnail ) ? $thumbnail : trailingslashit( includes_url() ) . 'images/media/video.png',
|
||||
'title' => get_the_title( $attachment_id ),
|
||||
'description' => wp_get_attachment_caption( $attachment_id ),
|
||||
'player_loc' => $video,
|
||||
'duration' => $metadata['length'] ?? '',
|
||||
);
|
||||
}
|
||||
} elseif ( sgg_pro_enabled() && class_exists( 'SGG_PRO\Classes\Video_Sitemap' ) ) {
|
||||
if ( ! empty( $this->settings->youtube_api_key ) && $this->is_youtube_url( $video ) ) {
|
||||
$youtube_data = Video_Sitemap::get_youtube_data( $video, $this->settings->youtube_api_key, $this->settings->enable_video_api_cache );
|
||||
|
||||
if ( ! empty( $youtube_data ) ) {
|
||||
$videos[] = $youtube_data;
|
||||
}
|
||||
} elseif ( ! empty( $this->settings->vimeo_api_key ) && $this->is_vimeo_url( $video ) ) {
|
||||
$vimeo_data = Video_Sitemap::get_vimeo_data( $video, $this->settings->vimeo_api_key, $this->settings->enable_video_api_cache );
|
||||
|
||||
if ( ! empty( $vimeo_data ) ) {
|
||||
$videos[] = $vimeo_data;
|
||||
}
|
||||
} elseif ( $this->is_twitter_url( $video ) ) {
|
||||
$twitter_data = Video_Sitemap::get_twitter_data( $video, $this->settings->enable_video_api_cache );
|
||||
|
||||
if ( ! empty( $twitter_data ) ) {
|
||||
$videos[] = $twitter_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $videos ) ) {
|
||||
// Remove old URL if it exists
|
||||
$this->urls = array_filter(
|
||||
$this->urls,
|
||||
function( $item ) use ( $url ) {
|
||||
return $item[0] !== $url;
|
||||
}
|
||||
);
|
||||
|
||||
$this->urls[] = array(
|
||||
$url, // URL
|
||||
$videos, // Videos
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function filter_value( string $value ): bool {
|
||||
$extensions = explode( '.', $value );
|
||||
$extension = end( $extensions );
|
||||
|
||||
return 'video' === wp_ext2type( $extension )
|
||||
|| ( sgg_pro_enabled() && (
|
||||
$this->is_youtube_url( $value ) ||
|
||||
$this->is_vimeo_url( $value ) ||
|
||||
$this->is_twitter_url( $value )
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect a YouTube video URL
|
||||
*/
|
||||
public function is_youtube_url( $url ) {
|
||||
return (
|
||||
false !== strpos( $url, 'https://www.youtube.com/embed/' ) ||
|
||||
false !== strpos( $url, 'https://youtu.be/' ) ||
|
||||
false !== strpos( $url, 'https://www.youtube.com/watch?v=' ) ||
|
||||
false !== strpos( $url, '//www.youtube.com/embed/' ) ||
|
||||
false !== strpos( $url, '//youtu.be/' ) ||
|
||||
false !== strpos( $url, '//www.youtube.com/watch?v=' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect a Vimeo video URL
|
||||
*/
|
||||
public function is_vimeo_url( $url ) {
|
||||
return (
|
||||
false !== strpos( $url, 'https://vimeo.com/' ) ||
|
||||
false !== strpos( $url, 'https://player.vimeo.com/video/' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect a Twitter post URL
|
||||
*/
|
||||
public function is_twitter_url( $url ) {
|
||||
return preg_match( '#https?://(?:www\.)?(?:twitter\.com|x\.com)/[^/]+/status/(\d+)#i', $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect an Instagram post, Reel or IGTV URL
|
||||
*/
|
||||
public function is_instagram_url( $url ) {
|
||||
return preg_match( '#https?://(?:www\.)?instagram\.com/(?:p|reel|tv)/([A-Za-z0-9_-]+)/?#i', $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect a TikTok video URL (full or "vm." shortlink)
|
||||
*/
|
||||
public function is_tiktok_url( $url ): bool {
|
||||
return (bool) preg_match( '~^https?://(?:www\.|m\.)?tiktok\.com/@[A-Za-z0-9._-]+/video/\d+(?:[/?].*)?$~i', $url )
|
||||
|| (bool) preg_match( '~^https?://vm\.tiktok\.com/[A-Za-z0-9_-]+/?$~i', $url );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
class Wizard extends Dashboard {
|
||||
public static $activation_redirect = 'sgg_activation_redirect';
|
||||
|
||||
private static $wizard_completed = 'sgg_wizard_completed';
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
|
||||
add_action( 'admin_init', array( $this, 'maybe_redirect_to_wizard' ) );
|
||||
add_action( 'wp_ajax_save_wizard_settings', array( $this, 'save_wizard_settings' ) );
|
||||
}
|
||||
|
||||
public function add_admin_menu() {
|
||||
add_submenu_page(
|
||||
self::$slug,
|
||||
esc_html__( 'Google XML Sitemaps Generator Wizard', 'xml-sitemap-generator-for-google' ),
|
||||
esc_html__( 'Sitemaps Wizard', 'xml-sitemap-generator-for-google' ),
|
||||
'manage_options',
|
||||
$this->get_wizard_page_slug(),
|
||||
array( $this, 'render_wizard_page' )
|
||||
);
|
||||
}
|
||||
|
||||
public function render_wizard_page() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_style( 'sgg-wizard-styles', GRIM_SG_URL . 'assets/css/wizard.min.css', array(), GRIM_SG_VERSION );
|
||||
wp_enqueue_style( 'sgg-icons', GRIM_SG_URL . 'assets/fonts/icons/style.css', array(), GRIM_SG_VERSION );
|
||||
wp_enqueue_script( 'sgg-wizard-scripts', GRIM_SG_URL . 'assets/js/wizard.js', array( 'jquery' ), GRIM_SG_VERSION, true );
|
||||
wp_localize_script(
|
||||
'sgg-wizard-scripts',
|
||||
'sggWizard',
|
||||
array(
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'nonce' => wp_create_nonce( 'sgg_wizard_nonce' ),
|
||||
'continue' => esc_html__( 'Continue', 'xml-sitemap-generator-for-google' ),
|
||||
'finish' => esc_html__( 'Finish', 'xml-sitemap-generator-for-google' ),
|
||||
)
|
||||
);
|
||||
|
||||
self::render(
|
||||
'wizard/main.php',
|
||||
array(
|
||||
'settings' => $this->get_settings(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function maybe_redirect_to_wizard() {
|
||||
if ( ! get_transient( self::$activation_redirect ) || ! current_user_can( 'manage_options' )
|
||||
|| wp_doing_ajax() || is_network_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete_transient( self::$activation_redirect );
|
||||
|
||||
if ( ! get_option( self::$wizard_completed ) ) {
|
||||
wp_safe_redirect( admin_url( 'admin.php?page=' . $this->get_wizard_page_slug() ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
public function save_wizard_settings() {
|
||||
if ( ! current_user_can( 'manage_options' ) || ! wp_verify_nonce( $_POST['nonce'] ?? '', 'sgg_wizard_nonce' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = $this->get_settings();
|
||||
|
||||
$settings->enable_sitemap = sanitize_text_field( $_POST['enable_sitemap'] ?? 0 );
|
||||
$settings->enable_html_sitemap = sanitize_text_field( $_POST['enable_html_sitemap'] ?? 0 );
|
||||
$settings->enable_google_news = sanitize_text_field( $_POST['enable_google_news'] ?? 0 );
|
||||
$settings->enable_image_sitemap = sanitize_text_field( $_POST['enable_image_sitemap'] ?? 0 );
|
||||
$settings->enable_video_sitemap = sanitize_text_field( $_POST['enable_video_sitemap'] ?? 0 );
|
||||
$settings->sitemap_view = sanitize_text_field( $_POST['sitemap_view'] ?? '' );
|
||||
$settings->enable_cache = sanitize_text_field( $_POST['enable_cache'] ?? 0 );
|
||||
$settings->cache_timeout = sanitize_text_field( $_POST['cache_timeout'] ?? $settings->cache_timeout );
|
||||
$settings->cache_timeout_period = sanitize_text_field( $_POST['cache_timeout_period'] ?? $settings->cache_timeout_period );
|
||||
|
||||
update_option( self::$slug, $settings );
|
||||
|
||||
flush_rewrite_rules();
|
||||
|
||||
wp_send_json(
|
||||
array(
|
||||
'success' => true,
|
||||
'redirect' => admin_url( 'admin.php?page=' . self::$slug ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function get_wizard_page_slug() {
|
||||
return self::$slug . '-wizard';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Language Files
|
||||
if ( ! is_textdomain_loaded( 'xml-sitemap-generator-for-google' ) ) {
|
||||
load_plugin_textdomain( 'xml-sitemap-generator-for-google', false, 'xml-sitemap-generator-for-google/languages' );
|
||||
}
|
||||
|
||||
// Autoload Files
|
||||
require_once GRIM_SG_INCLUDES . 'hooks.php';
|
||||
require_once GRIM_SG_INCLUDES . 'helpers.php';
|
||||
require_once GRIM_SG_INCLUDES . 'search-settings.php';
|
||||
|
||||
// Autoload
|
||||
require_once GRIM_SG_INCLUDES . 'vendor/Controller.php';
|
||||
require_once GRIM_SG_INCLUDES . 'vendor/SitemapGenerator.php';
|
||||
require_once GRIM_SG_INCLUDES . 'vendor/QueryBuilder.php';
|
||||
require_once GRIM_SG_INCLUDES . 'vendor/PTSettings.php';
|
||||
require_once GRIM_SG_INCLUDES . 'vendor/Settings.php';
|
||||
require_once GRIM_SG_INCLUDES . 'vendor/Migration.php';
|
||||
require_once GRIM_SG_INCLUDES . 'IndexNow.php';
|
||||
require_once GRIM_SG_INCLUDES . 'Cache.php';
|
||||
require_once GRIM_SG_INCLUDES . 'Sitemap.php';
|
||||
require_once GRIM_SG_INCLUDES . 'Frontend.php';
|
||||
require_once GRIM_SG_INCLUDES . 'GoogleNews.php';
|
||||
require_once GRIM_SG_INCLUDES . 'MediaSitemap.php';
|
||||
require_once GRIM_SG_INCLUDES . 'ImageSitemap.php';
|
||||
require_once GRIM_SG_INCLUDES . 'VideoSitemap.php';
|
||||
require_once GRIM_SG_INCLUDES . 'MultilingualSitemap.php';
|
||||
require_once GRIM_SG_INCLUDES . 'Tools.php';
|
||||
require_once GRIM_SG_INCLUDES . 'ImportExport.php';
|
||||
require_once GRIM_SG_INCLUDES . 'PostSettings.php';
|
||||
require_once GRIM_SG_INCLUDES . 'SitemapCLI.php';
|
||||
|
||||
function sgg_init() {
|
||||
new GRIM_SG\Vendor\Migration();
|
||||
new GRIM_SG\Frontend();
|
||||
new GRIM_SG\Tools();
|
||||
new GRIM_SG\PostSettings();
|
||||
|
||||
// WP Admin
|
||||
if ( is_admin() ) {
|
||||
require_once GRIM_SG_INCLUDES . 'Dashboard.php';
|
||||
require_once GRIM_SG_INCLUDES . 'Notices.php';
|
||||
require_once GRIM_SG_INCLUDES . 'Wizard.php';
|
||||
|
||||
new GRIM_SG\Dashboard();
|
||||
new GRIM_SG\Notices();
|
||||
new GRIM_SG\ImportExport();
|
||||
new GRIM_SG\Wizard();
|
||||
}
|
||||
}
|
||||
add_action( 'plugins_loaded', 'sgg_init', 1 );
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
use GRIM_SG\ImageSitemap;
|
||||
use GRIM_SG\VideoSitemap;
|
||||
|
||||
function sgg_pro_enabled() {
|
||||
return defined( 'SGG_PRO_VERSION' );
|
||||
}
|
||||
|
||||
function sgg_get_pro_url( $utm = 'buy-now' ) {
|
||||
return "https://wpgrim.com/google-xml-sitemaps-generator-pro/?utm_source=sgg-plugin&utm_medium={$utm}&utm_campaign=xml_sitemap";
|
||||
}
|
||||
|
||||
function sgg_get_support_url() {
|
||||
return 'https://wordpress.org/support/plugin/xml-sitemap-generator-for-google/';
|
||||
}
|
||||
|
||||
function sgg_get_review_url() {
|
||||
return sgg_get_support_url() . 'reviews/?filter=5#new-post';
|
||||
}
|
||||
|
||||
function sgg_show_pro_badge() {
|
||||
if ( ! sgg_pro_enabled() ) {
|
||||
load_template( GRIM_SG_PATH . '/templates/partials/pro-badge.php', false );
|
||||
}
|
||||
}
|
||||
|
||||
function sgg_show_pro_overlay( $args = array() ) {
|
||||
if ( ! sgg_pro_enabled() ) {
|
||||
load_template( GRIM_SG_PATH . '/templates/partials/pro-overlay.php', false, $args );
|
||||
}
|
||||
}
|
||||
|
||||
function sgg_pro_class() {
|
||||
return sgg_pro_enabled() ? 'active' : 'inactive';
|
||||
}
|
||||
|
||||
function sgg_parse_language( $lang ) {
|
||||
$lang = str_replace( '_', '-', convert_chars( strtolower( strip_tags( $lang ) ) ) );
|
||||
|
||||
if ( 0 === strpos( $lang, 'zh' ) ) {
|
||||
$lang = strpos( $lang, 'hk' ) || strpos( $lang, 'hant' ) || strpos( $lang, 'tw' ) ? 'zh-tw' : 'zh-cn';
|
||||
} else {
|
||||
$explode = explode( '-', $lang );
|
||||
$lang = $explode[0];
|
||||
}
|
||||
|
||||
return ! empty( $lang ) ? $lang : 'en';
|
||||
}
|
||||
|
||||
function sgg_is_sitemap_index( $template, $settings = null ) {
|
||||
if ( ! $settings ) {
|
||||
$settings = ( new \GRIM_SG\Vendor\Controller() )->get_settings();
|
||||
}
|
||||
|
||||
// Detect Media Sitemap Structure
|
||||
if ( in_array( $template, array( ImageSitemap::$template, VideoSitemap::$template ), true ) && ! empty( $settings->sitemap_view ) ) {
|
||||
$sitemap_structure = get_option( "sgg_{$template}_structure" );
|
||||
|
||||
return 'multiple' === $sitemap_structure;
|
||||
}
|
||||
|
||||
return in_array( $template, array( 'sitemap', 'inner-sitemap' ), true ) && ! empty( $settings->sitemap_view );
|
||||
}
|
||||
|
||||
function sgg_get_home_url( $path = '' ) {
|
||||
$home_url = function_exists( 'pll_home_url' ) ? pll_home_url() : get_home_url();
|
||||
$home_url = trim( apply_filters( 'wpml_home_urls', $home_url ), '/' );
|
||||
|
||||
if ( function_exists( 'trp_get_locale' ) ) {
|
||||
$trp_settings = get_option( 'trp_settings' );
|
||||
$current_locale = trp_get_locale();
|
||||
|
||||
if ( $current_locale !== $trp_settings['default-language'] ?? null ) {
|
||||
$lang = substr( $current_locale, 0, 2 );
|
||||
$home_url = get_site_url( null, $lang );
|
||||
}
|
||||
}
|
||||
|
||||
if ( defined( 'ICL_SITEPRESS_VERSION' ) && ! empty( $path ) && ! empty( $_GET['lang'] ) && false !== strpos( $home_url, '?lang=' ) ) {
|
||||
$home_url = trim( strtok( $home_url, '?' ), '/' );
|
||||
$home_url = add_query_arg( 'lang', sanitize_text_field( $_GET['lang'] ), "{$home_url}/{$path}" );
|
||||
$path = ''; // Reset path to avoid duplication
|
||||
}
|
||||
|
||||
$home_url = apply_filters( 'xml_sitemaps_site_url', $home_url );
|
||||
|
||||
return ! empty( $path ) ? "{$home_url}/{$path}" : $home_url;
|
||||
}
|
||||
|
||||
function sgg_get_home_url_with_trailing_slash() {
|
||||
return trailingslashit( untrailingslashit( sgg_get_home_url() ) );
|
||||
}
|
||||
|
||||
function sgg_is_nginx() {
|
||||
return isset( $_SERVER['SERVER_SOFTWARE'] ) && stristr( sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ), 'nginx' ) !== false;
|
||||
}
|
||||
|
||||
function sgg_is_using_mod_rewrite() {
|
||||
global $wp_rewrite;
|
||||
|
||||
return $wp_rewrite->using_mod_rewrite_permalinks();
|
||||
}
|
||||
|
||||
function sgg_get_sitemap_url( $sitemap_url, $sitemap_type, $suffix = true ) {
|
||||
if ( sgg_is_using_mod_rewrite() ) {
|
||||
return sgg_get_home_url( $sitemap_url );
|
||||
} else {
|
||||
return sgg_get_home_url( "index.php?{$sitemap_type}" . ( $suffix ? '=true' : '' ) );
|
||||
}
|
||||
}
|
||||
|
||||
function sgg_get_languages( $with_default = false ) {
|
||||
$languages = array();
|
||||
|
||||
if ( function_exists( 'pll_languages_list' ) ) {
|
||||
$languages = pll_languages_list( array( 'fields' => 'slug' ) );
|
||||
$default_lang = array_search( pll_default_language(), $languages, true );
|
||||
|
||||
if ( false !== $default_lang && ! $with_default ) {
|
||||
unset( $languages[ $default_lang ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( function_exists( 'trp_get_languages' ) ) {
|
||||
$trp_settings = get_option( 'trp_settings' );
|
||||
$trp_slugs = $trp_settings['url-slugs'] ?? array();
|
||||
|
||||
if ( ! $with_default ) {
|
||||
unset( $trp_slugs[ $trp_settings['default-language'] ?? '' ] );
|
||||
}
|
||||
|
||||
$languages = array_values( $trp_slugs );
|
||||
}
|
||||
|
||||
return $languages;
|
||||
}
|
||||
|
||||
function sgg_get_default_language_code() {
|
||||
if ( function_exists( 'pll_default_language' ) ) {
|
||||
return pll_default_language();
|
||||
}
|
||||
|
||||
return apply_filters( 'wpml_default_language', null );
|
||||
}
|
||||
|
||||
function sgg_is_multilingual() {
|
||||
return function_exists( 'pll_languages_list' )
|
||||
|| function_exists( 'trp_get_languages' )
|
||||
|| defined( 'ICL_SITEPRESS_VERSION' );
|
||||
}
|
||||
|
||||
function sgg_maybe_remove_inner_suffix( $template ) {
|
||||
if ( strpos( $template, '-inner-sitemap' ) !== false ) {
|
||||
$template = str_replace( '-inner-sitemap', '', $template );
|
||||
}
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
function sgg_pro_features_page_tab( $tabs ) {
|
||||
if ( ! sgg_pro_enabled() ) {
|
||||
$tabs['xml_sitemap_generator_for_google_pro'] = sprintf(
|
||||
'<a href="%s" target="_blank" class="sgg-plugin-pro-feature">%s</a>',
|
||||
esc_url( 'https://wpgrim.com/google-xml-sitemaps-generator-pro/?utm_source=sgg-plugin&utm_medium=plugins&utm_campaign=xml_sitemap' ),
|
||||
esc_html__( 'XML Sitemaps Generator Pro Features', 'xml-sitemap-generator-for-google' )
|
||||
);
|
||||
wp_enqueue_style( 'sgg-styles', GRIM_SG_URL . 'assets/css/styles.min.css', array(), GRIM_SG_VERSION );
|
||||
}
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
add_filter( 'install_plugins_tabs', 'sgg_pro_features_page_tab' );
|
||||
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Activation Hook
|
||||
*/
|
||||
function sgg_activation() {
|
||||
\GRIM_SG\Frontend::activate_plugin();
|
||||
|
||||
\GRIM_SG\Vendor\Migration::update_version();
|
||||
|
||||
( new \GRIM_SG\IndexNow() )->set_api_key();
|
||||
|
||||
update_option( 'sgg_installation_time', time(), false );
|
||||
|
||||
// Set the activation redirect transient.
|
||||
set_transient( 'sgg_activation_redirect', true, MINUTE_IN_SECONDS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin Deactivation Hook
|
||||
*/
|
||||
function sgg_deactivation() {
|
||||
\GRIM_SG\IndexNow::delete_api_key();
|
||||
|
||||
delete_option( 'sgg_installation_time' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Polylang language for a post.
|
||||
*/
|
||||
function sgg_polylang_post_language( $language, $post_id ) {
|
||||
if ( function_exists( 'pll_get_post_language' ) ) {
|
||||
$language = pll_get_post_language( $post_id, 'slug' );
|
||||
}
|
||||
|
||||
return $language;
|
||||
}
|
||||
add_filter( 'xml_sitemap_news_language', 'sgg_polylang_post_language', 10, 2 );
|
||||
|
||||
/**
|
||||
* Get the WPML language for a post.
|
||||
*/
|
||||
function sgg_wpml_post_language( $language, $post_id, $post_type = 'post' ) {
|
||||
global $sitepress;
|
||||
|
||||
if ( $sitepress ) {
|
||||
$language = apply_filters(
|
||||
'wpml_element_language_code',
|
||||
$language,
|
||||
array(
|
||||
'element_id' => $post_id,
|
||||
'element_type' => $post_type,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $language;
|
||||
}
|
||||
add_filter( 'xml_sitemap_news_language', 'sgg_wpml_post_language', 10, 3 );
|
||||
|
||||
/**
|
||||
* Exclude posts with noindex from the sitemap.
|
||||
*/
|
||||
function sgg_exclude_noindex_posts( $value, $post_id ) {
|
||||
// Yoast SEO noindex
|
||||
if ( defined( 'WPSEO_VERSION' ) && '1' === get_post_meta( $post_id, '_yoast_wpseo_meta-robots-noindex', true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Rank Math noindex
|
||||
if ( class_exists( 'RankMath' ) ) {
|
||||
$rank_math_robots = get_post_meta( $post_id, 'rank_math_robots', true );
|
||||
if ( ! empty( $rank_math_robots ) && is_array( $rank_math_robots ) && in_array( 'noindex', $rank_math_robots, true ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// SEO Framework noindex
|
||||
if ( defined( 'THE_SEO_FRAMEWORK_VERSION' ) ) {
|
||||
$seo_framework_noindex = get_post_meta( $post_id, '_genesis_noindex', true );
|
||||
if ( '1' === $seo_framework_noindex ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
add_filter( 'xml_sitemap_include_post', 'sgg_exclude_noindex_posts', 99, 2 );
|
||||
|
||||
/**
|
||||
* Exclude terms with noindex from the sitemap.
|
||||
*/
|
||||
function sgg_exclude_noindex_terms( $value, $term_id, $taxonomy ) {
|
||||
// Yoast SEO noindex
|
||||
if ( is_callable( '\WPSEO_Taxonomy_Meta::get_term_meta' ) ) {
|
||||
$noindex = \WPSEO_Taxonomy_Meta::get_term_meta( $term_id, $taxonomy, 'noindex' );
|
||||
if ( 'noindex' === $noindex ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Rank Math noindex
|
||||
if ( class_exists( 'RankMath' ) ) {
|
||||
$rank_math_robots = get_term_meta( $term_id, 'rank_math_robots', true );
|
||||
if ( ! empty( $rank_math_robots ) && is_array( $rank_math_robots ) && in_array( 'noindex', $rank_math_robots, true ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// SEO Framework noindex
|
||||
if ( defined( 'THE_SEO_FRAMEWORK_VERSION' ) ) {
|
||||
$seo_framework_meta = get_term_meta( $term_id, 'autodescription-term-settings', true );
|
||||
if ( ! empty( $seo_framework_meta ) && isset( $seo_framework_meta['noindex'] ) && 1 === $seo_framework_meta['noindex'] ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
add_filter( 'sgg_sitemap_exclude_single_term', 'sgg_exclude_noindex_terms', 99, 3 );
|
||||
|
||||
/**
|
||||
* Add FooGallery image URLs to the sitemap.
|
||||
*/
|
||||
function sgg_add_foogallery_image_urls( $urls, $post_id ) {
|
||||
if ( defined( 'FOOGALLERY_CPT_GALLERY' ) && class_exists( 'FooGallery' ) ) {
|
||||
$content = get_post_field( 'post_content', $post_id );
|
||||
|
||||
if ( false !== strpos( $content, FOOGALLERY_CPT_GALLERY ) ) {
|
||||
$gallery_ids = array();
|
||||
|
||||
preg_match_all( '/<!--\s*wp:fooplugins\/foogallery\s*{"id":\s*(\d+)\s*}\s*\/-->/', $content, $matches );
|
||||
|
||||
if ( ! empty( $matches[1] ) ) {
|
||||
$gallery_ids = array_map( 'intval', $matches[1] );
|
||||
}
|
||||
|
||||
if ( ! empty( $gallery_ids ) ) {
|
||||
$gallery_ids = array_unique( $gallery_ids );
|
||||
|
||||
foreach ( $gallery_ids as $gallery_id ) {
|
||||
$gallery = FooGallery::get_by_id( $gallery_id );
|
||||
if ( $gallery ) {
|
||||
foreach ( $gallery->attachments() as $attachment ) {
|
||||
$urls[] = wp_get_attachment_url( $attachment->ID );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $urls;
|
||||
}
|
||||
add_filter( 'sgg_sitemap_post_media_urls', 'sgg_add_foogallery_image_urls', 10, 2 );
|
||||
|
||||
/**
|
||||
* BeeTheme Compatibility
|
||||
*/
|
||||
function sgg_be_theme_compatibility( $content, $post ) {
|
||||
if ( defined( 'MFN_THEME_VERSION' ) ) {
|
||||
$mfn_items = get_post_meta( $post->ID, 'mfn-builder-preview', true );
|
||||
|
||||
if ( ! empty( $mfn_items ) ) {
|
||||
if ( ! is_array( $mfn_items ) ) {
|
||||
$mfn_items = call_user_func( 'base64_decode', $mfn_items );
|
||||
}
|
||||
|
||||
if ( ! empty( $mfn_items ) ) {
|
||||
$content = is_array( $mfn_items ) ? implode( '', $mfn_items ) : $mfn_items;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
add_filter( 'xml_media_sitemap_post_content', 'sgg_be_theme_compatibility', 10, 2 );
|
||||
|
||||
/**
|
||||
* Serve IndexNow API key.
|
||||
*/
|
||||
function sgg_serve_indexnow_api_key() {
|
||||
global $wp;
|
||||
|
||||
$indexnow = new \GRIM_SG\IndexNow();
|
||||
$current_url = home_url( $wp->request );
|
||||
|
||||
if ( ! empty( $current_url ) && $indexnow->get_api_key_location() === $current_url ) {
|
||||
header( 'Content-Type: text/plain' );
|
||||
header( 'X-Robots-Tag: noindex' );
|
||||
status_header( 200 );
|
||||
|
||||
echo esc_html( $indexnow->get_api_key() );
|
||||
|
||||
exit();
|
||||
}
|
||||
}
|
||||
add_action( 'wp', 'sgg_serve_indexnow_api_key' );
|
||||
|
||||
/**
|
||||
* Clear Media Sitemap cache when a post status is changed.
|
||||
*/
|
||||
function sgg_clear_media_sitemap_cache( $new_status, $old_status, $post ) {
|
||||
$settings = get_option( \GRIM_SG\Vendor\Controller::$slug );
|
||||
if ( is_object( $settings ) && ! empty( $settings->disable_media_sitemap_cache ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( 'publish' === $old_status && 'publish' !== $new_status )
|
||||
|| ( 'publish' === $new_status && 'publish' !== $old_status ) ) {
|
||||
\GRIM_SG\MediaSitemap::delete_all_cache();
|
||||
}
|
||||
}
|
||||
add_action( 'transition_post_status', 'sgg_clear_media_sitemap_cache', 10, 3 );
|
||||
|
||||
/**
|
||||
* Disable default WordPress Sitemaps.
|
||||
*/
|
||||
add_filter( 'wp_sitemaps_enabled', '__return_false' );
|
||||
|
||||
/**
|
||||
* Google New Title Filter
|
||||
*/
|
||||
function sgg_google_news_title( $title, $post_id ) {
|
||||
// SEO Framework title
|
||||
if ( defined( 'THE_SEO_FRAMEWORK_VERSION' ) ) {
|
||||
$seo_title = get_post_meta( $post_id, '_genesis_title', true );
|
||||
if ( ! empty( $seo_title ) ) {
|
||||
$title = $seo_title;
|
||||
}
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
add_filter( 'xml_sitemap_google_news_title', 'sgg_google_news_title', 10, 2 );
|
||||
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
function xml_sitemap_generate_settings() {
|
||||
$settings_array = array(
|
||||
'general' => array(
|
||||
array(
|
||||
'id' => 'sitemap_to_robots',
|
||||
'label' => 'Add Sitemap Output URLs to site "robots.txt" file',
|
||||
'tags' => 'robots.txt',
|
||||
),
|
||||
array(
|
||||
'id' => 'enable_indexnow',
|
||||
'label' => 'Enable IndexNow Protocol (Microsoft Bing, Seznam.cz, Naver, Yandex)',
|
||||
'tags' => 'Posts',
|
||||
),
|
||||
array(
|
||||
'id' => 'enable_sitemap',
|
||||
'label' => 'XML Sitemap',
|
||||
),
|
||||
array(
|
||||
'id' => 'enable_html_sitemap',
|
||||
'label' => 'HTML Sitemap',
|
||||
),
|
||||
array(
|
||||
'id' => 'webserver_configuration',
|
||||
'label' => 'Webserver Configuration' ,
|
||||
),
|
||||
array(
|
||||
'id' => 'sitemap_structure',
|
||||
'label' => 'Sitemap Structure' ,
|
||||
),
|
||||
array(
|
||||
'id' => 'links_per_page',
|
||||
'label' => 'Links per page:' ,
|
||||
),
|
||||
array(
|
||||
'id' => 'custom_sitemaps',
|
||||
'label' => 'Custom Sitemaps' ,
|
||||
),
|
||||
array(
|
||||
'id' => 'additional_urls',
|
||||
'label' => 'Additional URLs',
|
||||
),
|
||||
array(
|
||||
'id' => 'general_exclude_posts',
|
||||
'label' => 'Exclude',
|
||||
),
|
||||
array(
|
||||
'id' => 'general_include_only_terms',
|
||||
'label' => 'Include only selected Terms',
|
||||
),
|
||||
array(
|
||||
'id' => 'posts_priority',
|
||||
'label' => 'Posts Priority',
|
||||
),
|
||||
array(
|
||||
'id' => 'sitemap_options',
|
||||
'label' => 'Sitemap Options',
|
||||
),
|
||||
array(
|
||||
'id' => 'general_custom_post_types',
|
||||
'label' => 'General Custom Post Types',
|
||||
),
|
||||
),
|
||||
'google-news' => array(
|
||||
array(
|
||||
'id' => 'enable_google_news',
|
||||
'label' => 'Google News',
|
||||
'tags' => '',
|
||||
),
|
||||
array(
|
||||
'id' => 'google_news_name',
|
||||
'label' => 'Publication Name',
|
||||
),
|
||||
array(
|
||||
'id' => 'google_news_old_posts',
|
||||
'label' => 'Include Older Posts',
|
||||
),
|
||||
array(
|
||||
'id' => 'google__url',
|
||||
'label' => 'Google News URL',
|
||||
),
|
||||
array(
|
||||
'id' => 'google_keywords',
|
||||
'label' => 'Keywords',
|
||||
),
|
||||
array(
|
||||
'id' => 'google_news_stocks',
|
||||
'label' => 'Stock Tickers',
|
||||
),
|
||||
array(
|
||||
'id' => 'google_exclude',
|
||||
'label' => 'Exclude',
|
||||
),
|
||||
array(
|
||||
'id' => 'google_include',
|
||||
'label' => 'Include only selected Terms',
|
||||
),
|
||||
array(
|
||||
'id' => 'google_content_post',
|
||||
'label' => 'Content Options',
|
||||
),
|
||||
array(
|
||||
'id' => 'google_custom_post_types',
|
||||
'label' => 'Google Custom Post Types',
|
||||
),
|
||||
),
|
||||
'image-sitemap' => array(
|
||||
array(
|
||||
'id' => 'enable_image_sitemap',
|
||||
'label' => 'Image Sitemap',
|
||||
),
|
||||
array(
|
||||
'id' => 'image_sitemap_url',
|
||||
'label' => 'Image Sitemap URL:',
|
||||
),
|
||||
array(
|
||||
'id' => 'hide_image_previews',
|
||||
'label' => 'Hide Image Previews',
|
||||
),
|
||||
array(
|
||||
'id' => 'hide_image_sitemap_xsl',
|
||||
'label' => 'Hide XSL Template',
|
||||
),
|
||||
array(
|
||||
'id' => 'image_mime_types',
|
||||
'label' => 'Image MIME Types',
|
||||
),
|
||||
array(
|
||||
'id' => 'exclude_broken_images',
|
||||
'label' => 'Exclude Broken Images',
|
||||
),
|
||||
array(
|
||||
'id' => 'include_featured_images',
|
||||
'label' => 'Include Featured Images',
|
||||
),
|
||||
array(
|
||||
'id' => 'include_woo_gallery',
|
||||
'label' => 'Include WooCommerce Gallery Images',
|
||||
),
|
||||
array(
|
||||
'id' => 'image_content_option',
|
||||
'label' => 'Content Options',
|
||||
),
|
||||
array(
|
||||
'id' => 'image_custom_post_types',
|
||||
'label' => 'Image Custom Post Types',
|
||||
),
|
||||
),
|
||||
'video-sitemap' => array(
|
||||
array(
|
||||
'id' => 'enable_video_sitemap',
|
||||
'label' => 'Enable Video Sitemap',
|
||||
),
|
||||
array(
|
||||
'id' => 'video_sitemap_url',
|
||||
'label' => 'Video Sitemap URL:',
|
||||
),
|
||||
array(
|
||||
'id' => 'hide_video_sitemap_xsl',
|
||||
'label' => 'Hide XSL Template',
|
||||
),
|
||||
array(
|
||||
'id' => 'sgg_youtube',
|
||||
'label' => 'YouTube',
|
||||
),
|
||||
array(
|
||||
'id' => 'youtube_api_key',
|
||||
'label' => 'YouTube Data API v3 Key:',
|
||||
),
|
||||
array(
|
||||
'id' => 'sgg_vimeo',
|
||||
'label' => 'Vimeo',
|
||||
),
|
||||
array(
|
||||
'id' => 'vimeo_check_api_key',
|
||||
'label' => 'Vimeo Access Token:',
|
||||
),
|
||||
array(
|
||||
'id' => 'enable_video_api_cache',
|
||||
'label' => 'API Data Cache',
|
||||
),
|
||||
array(
|
||||
'id' => 'video_content_option',
|
||||
'label' => 'Content Options',
|
||||
),
|
||||
array(
|
||||
'id' => 'video_custom_post_types',
|
||||
'label' => 'Custom Post Types',
|
||||
),
|
||||
),
|
||||
'advanced' => array(
|
||||
array(
|
||||
'id' => 'enable_cache',
|
||||
'label' => 'Cache',
|
||||
),
|
||||
array(
|
||||
'id' => 'cache_timeout_period',
|
||||
'label' => 'Cache Expiration Time:',
|
||||
),
|
||||
array(
|
||||
'id' => 'last_cached_time',
|
||||
'label' => 'Last Cached Time:',
|
||||
),
|
||||
array(
|
||||
'id' => 'clear_cache',
|
||||
'label' => 'Clear Cache',
|
||||
),
|
||||
array(
|
||||
'id' => 'clear_cache_on_save_post',
|
||||
'label' => 'Smart Caching',
|
||||
),
|
||||
array(
|
||||
'id' => 'disable_media_sitemap_cache',
|
||||
'label' => 'Disable Media Sitemap Cache Collection',
|
||||
),
|
||||
array(
|
||||
'id' => 'minimize_sitemap',
|
||||
'label' => 'Minimize Sitemap source code',
|
||||
),
|
||||
array(
|
||||
'id' => 'advanced_sitemap_styles',
|
||||
'label' => 'Sitemap Styles',
|
||||
),
|
||||
array(
|
||||
'id' => 'hide_branding',
|
||||
'label' => 'Hide Branding Marks',
|
||||
),
|
||||
array(
|
||||
'id' => 'enable_cronjob',
|
||||
'label' => 'Cron Job',
|
||||
),
|
||||
array(
|
||||
'id' => 'cronjob_runtime',
|
||||
'label' => 'Cron Job Run Time:',
|
||||
),
|
||||
array(
|
||||
'id' => 'advanced_wp_cli',
|
||||
'label' => 'WP CLI',
|
||||
),
|
||||
array(
|
||||
'id' => 'advanced_import_settings',
|
||||
'label' => 'Import Settings',
|
||||
),
|
||||
array(
|
||||
'id' => 'advanced_export_settings',
|
||||
'label' => 'Export Settings',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$flat_settings_array = array();
|
||||
foreach ( $settings_array as $tab => $settings ) {
|
||||
foreach ( $settings as $setting ) {
|
||||
$setting['tab'] = $tab;
|
||||
$flat_settings_array[] = $setting;
|
||||
}
|
||||
}
|
||||
|
||||
return $flat_settings_array;
|
||||
}
|
||||
87
wp-content/plugins/xml-sitemap-generator-for-google/includes/vendor/Controller.php
vendored
Normal file
87
wp-content/plugins/xml-sitemap-generator-for-google/includes/vendor/Controller.php
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG\Vendor;
|
||||
|
||||
use GRIM_SG\Settings;
|
||||
|
||||
class Controller {
|
||||
public static $slug = 'xml-sitemap-generator-for-google';
|
||||
|
||||
public function get_settings() {
|
||||
$settings = new Settings();
|
||||
$saved_options = get_option( self::$slug );
|
||||
|
||||
// TODO Remove this after Refactoring
|
||||
if ( is_array( $saved_options ) ) {
|
||||
$saved_options = (object) $saved_options;
|
||||
}
|
||||
|
||||
if ( ! empty( $saved_options ) ) {
|
||||
foreach ( $settings as $key => &$option ) {
|
||||
if ( isset( $saved_options->{$key} ) ) {
|
||||
if ( in_array( $key, array( 'cpt', 'taxonomies' ), true ) ) {
|
||||
if ( is_array( $saved_options->{$key} ) ) {
|
||||
foreach ( $saved_options->{$key} as $inner_key => $value ) {
|
||||
$option[ $inner_key ] = is_array( $value )
|
||||
? (object) $value // TODO Remove this after Refactoring
|
||||
: $value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$option = ( is_object( $option ) && is_array( $saved_options->{$key} ) )
|
||||
? (object) $saved_options->{$key} // TODO Remove this after Refactoring
|
||||
: $saved_options->{$key};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Custom Post Types
|
||||
* @return string[]|\WP_Post_Type[]
|
||||
*/
|
||||
public function get_cpt( $output = 'names' ) {
|
||||
$args = array(
|
||||
'public' => true,
|
||||
'_builtin' => false,
|
||||
);
|
||||
|
||||
return get_post_types( $args, $output );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Taxonomy Types
|
||||
* @return string[]|\WP_Taxonomy[]
|
||||
*/
|
||||
public function get_taxonomy_types( $output = 'names' ) {
|
||||
$args = array(
|
||||
'public' => true,
|
||||
'show_ui' => true,
|
||||
);
|
||||
|
||||
return get_taxonomies( $args, $output );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Allowed Post Types List
|
||||
* @return array
|
||||
*/
|
||||
public function get_post_types_list( $post_types, $settings ) {
|
||||
foreach ( $post_types as $key => $post_type ) {
|
||||
if ( isset( $settings->{$post_type}->include ) && ! $settings->{$post_type}->include ) {
|
||||
unset( $post_types[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $this->get_cpt() as $cpt ) {
|
||||
if ( ! empty( $settings->cpt[ $cpt ] ) && ! empty( $settings->cpt[ $cpt ]->include ) ) {
|
||||
$post_types[] = $cpt;
|
||||
}
|
||||
}
|
||||
|
||||
return $post_types;
|
||||
}
|
||||
}
|
||||
97
wp-content/plugins/xml-sitemap-generator-for-google/includes/vendor/Migration.php
vendored
Normal file
97
wp-content/plugins/xml-sitemap-generator-for-google/includes/vendor/Migration.php
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG\vendor;
|
||||
|
||||
class Migration extends Controller {
|
||||
const DB_VERSION_KEY = 'sgg_version';
|
||||
|
||||
/**
|
||||
* Database updates and callbacks that need to be run per Migration version.
|
||||
*/
|
||||
private $migrations = array(
|
||||
'1.8.4' => array(
|
||||
'migrate_settings_dynamic_created_objects',
|
||||
),
|
||||
'1.9.9' => array(
|
||||
'migrate_video_settings',
|
||||
),
|
||||
);
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'admin_init', array( $this, 'run_migrations' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all the necessary migrations.
|
||||
*/
|
||||
public function run_migrations() {
|
||||
$current_db_version = get_option( self::DB_VERSION_KEY, '' );
|
||||
|
||||
if ( version_compare( $current_db_version, GRIM_SG_VERSION, '>=' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $this->migrations as $version => $update_callbacks ) {
|
||||
if ( version_compare( $current_db_version, $version, '<' ) ) {
|
||||
foreach ( $update_callbacks as $update_callback ) {
|
||||
$this->{$update_callback}();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self::update_version();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Version in Database
|
||||
*/
|
||||
public static function update_version() {
|
||||
update_option( self::DB_VERSION_KEY, GRIM_SG_VERSION );
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate Dynamic created CPT and Taxonomies to array
|
||||
*/
|
||||
public function migrate_settings_dynamic_created_objects() {
|
||||
$settings = get_option( self::$slug, array() );
|
||||
|
||||
if ( ! empty( $settings ) ) {
|
||||
$settings->cpt = array();
|
||||
$settings->taxonomies = array();
|
||||
|
||||
foreach ( $this->get_cpt() as $cpt ) {
|
||||
if ( ! empty( $settings->{$cpt} ) ) {
|
||||
$settings->cpt[ $cpt ] = $settings->{$cpt};
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $this->get_taxonomy_types() as $taxonomy ) {
|
||||
if ( ! empty( $settings->{$taxonomy} ) ) {
|
||||
$settings->taxonomies[ $taxonomy ] = $settings->{$taxonomy};
|
||||
}
|
||||
}
|
||||
|
||||
update_option( Controller::$slug, $settings );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate Video Sitemap Settings
|
||||
*/
|
||||
public function migrate_video_settings() {
|
||||
$settings = get_option( self::$slug, array() );
|
||||
|
||||
if ( ! empty( $settings ) ) {
|
||||
$settings->enable_video_api_cache = $settings->enable_youtube_cache ?? true;
|
||||
|
||||
update_option( Controller::$slug, $settings );
|
||||
}
|
||||
|
||||
// Migrate YouTube Data to Video API Data
|
||||
$youtube_data = get_option( 'sgg_youtube_data', array() );
|
||||
|
||||
if ( ! empty( $youtube_data ) ) {
|
||||
update_option( 'sgg_video_api_data', $youtube_data );
|
||||
}
|
||||
}
|
||||
}
|
||||
35
wp-content/plugins/xml-sitemap-generator-for-google/includes/vendor/PTSettings.php
vendored
Normal file
35
wp-content/plugins/xml-sitemap-generator-for-google/includes/vendor/PTSettings.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
class PTSettings {
|
||||
public $include = true;
|
||||
public $priority = 3;
|
||||
public $frequency = 'weekly';
|
||||
public $google_news = false;
|
||||
public $image_sitemap = true;
|
||||
public $video_sitemap = true;
|
||||
|
||||
// Frequencies
|
||||
public static $ALWAYS = 'always';
|
||||
public static $HOURLY = 'hourly';
|
||||
public static $DAILY = 'daily';
|
||||
public static $WEEKLY = 'weekly';
|
||||
public static $MONTHLY = 'monthly';
|
||||
public static $YEARLY = 'yearly';
|
||||
public static $NEVER = 'never';
|
||||
|
||||
/**
|
||||
* DefaultSettings constructor.
|
||||
*
|
||||
* @param int $priority
|
||||
* @param int $frequency
|
||||
*/
|
||||
public function __construct( $priority = 3, $frequency = 1, $google_news = false, $image_sitemap = false, $video_sitemap = false ) {
|
||||
$this->priority = $priority;
|
||||
$this->frequency = $frequency;
|
||||
$this->google_news = $google_news;
|
||||
$this->image_sitemap = $image_sitemap;
|
||||
$this->video_sitemap = $video_sitemap;
|
||||
}
|
||||
}
|
||||
17
wp-content/plugins/xml-sitemap-generator-for-google/includes/vendor/QueryBuilder.php
vendored
Normal file
17
wp-content/plugins/xml-sitemap-generator-for-google/includes/vendor/QueryBuilder.php
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG\Vendor;
|
||||
|
||||
class QueryBuilder {
|
||||
/**
|
||||
* Run SQL Query
|
||||
*
|
||||
* @param $sql
|
||||
* @return array|null|object
|
||||
*/
|
||||
public static function run_query( $sql ) {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->get_results( $sql );
|
||||
}
|
||||
}
|
||||
130
wp-content/plugins/xml-sitemap-generator-for-google/includes/vendor/Settings.php
vendored
Normal file
130
wp-content/plugins/xml-sitemap-generator-for-google/includes/vendor/Settings.php
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG;
|
||||
|
||||
use GRIM_SG\Vendor\Controller;
|
||||
|
||||
class Settings extends Controller {
|
||||
// Global Settings
|
||||
public $sitemap_url = 'sitemap.xml';
|
||||
public $html_sitemap_url = 'sitemap.html';
|
||||
public $enable_sitemap = true;
|
||||
public $links_per_page = 1000;
|
||||
public $enable_html_sitemap = false;
|
||||
public $sitemap_to_robots = true;
|
||||
public $enable_indexnow = true;
|
||||
public $sitemap_view = 'sitemap-index';
|
||||
|
||||
// Sitemap Data Settings
|
||||
public $home;
|
||||
public $page;
|
||||
public $post;
|
||||
public $archive;
|
||||
public $archive_older;
|
||||
public $authors;
|
||||
public $media;
|
||||
public $exclude_posts;
|
||||
public $exclude_terms;
|
||||
public $include_only_terms;
|
||||
public $posts_priority;
|
||||
public $custom_sitemaps = array();
|
||||
public $additional_pages = array();
|
||||
public $cpt = array();
|
||||
public $taxonomies = array();
|
||||
|
||||
// Google News Data Settings
|
||||
public $enable_google_news = false;
|
||||
public $google_news_old_posts = false;
|
||||
public $google_news_name = '';
|
||||
public $google_news_url = 'google-news.xml';
|
||||
public $google_news_keywords = '';
|
||||
public $google_news_stocks = false;
|
||||
public $google_news_exclude;
|
||||
public $google_news_exclude_terms;
|
||||
public $google_news_include_only_terms;
|
||||
|
||||
// Media Sitemap Data Settings
|
||||
public $enable_image_sitemap = false;
|
||||
public $enable_video_sitemap = false;
|
||||
public $image_sitemap_url = 'image-sitemap.xml';
|
||||
public $video_sitemap_url = 'video-sitemap.xml';
|
||||
public $hide_image_previews = false;
|
||||
public $hide_image_sitemap_xsl = false;
|
||||
public $hide_video_sitemap_xsl = false;
|
||||
public $image_mime_types = array(
|
||||
'image/jpeg' => true,
|
||||
'image/png' => true,
|
||||
'image/gif' => true,
|
||||
'image/bmp' => true,
|
||||
'image/webp' => true,
|
||||
'image/avif' => true,
|
||||
);
|
||||
public $youtube_api_key = '';
|
||||
public $vimeo_api_key = '';
|
||||
public $exclude_broken_images = false;
|
||||
public $include_featured_images = false;
|
||||
public $include_woo_gallery = false;
|
||||
|
||||
// Cache Settings
|
||||
public $enable_cache = false;
|
||||
public $cache_timeout = 24;
|
||||
public $cache_timeout_period = 3600;
|
||||
public $clear_cache_on_save_post = false;
|
||||
public $enable_video_api_cache = true;
|
||||
public $disable_media_sitemap_cache = false;
|
||||
|
||||
public $minimize_sitemap = false;
|
||||
public $hide_branding = true;
|
||||
public $enable_cronjob = false;
|
||||
public $cronjob_runtime = 'daily';
|
||||
public $colors = array(
|
||||
'header_background_color' => '#82a745',
|
||||
'header_text_color' => '#ffffff',
|
||||
'sitemap_background_color' => '#ecf4db',
|
||||
'sitemap_text_color' => '#444444',
|
||||
'sitemap_link_color' => '#2d89c7',
|
||||
'footer_text_color' => '#666666',
|
||||
);
|
||||
|
||||
/**
|
||||
* Settings constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->home = new PTSettings( 10, PTSettings::$DAILY );
|
||||
$this->page = new PTSettings( 6, PTSettings::$WEEKLY, false, true, true );
|
||||
$this->post = new PTSettings( 6, PTSettings::$MONTHLY, true, true, true );
|
||||
$this->archive = new PTSettings( 6, PTSettings::$DAILY );
|
||||
$this->archive_older = new PTSettings( 3, PTSettings::$YEARLY );
|
||||
$this->authors = new PTSettings( 3, PTSettings::$WEEKLY );
|
||||
$this->media = new PTSettings( 3, PTSettings::$WEEKLY );
|
||||
|
||||
// Media Pages are disabled by default
|
||||
$this->media->include = false;
|
||||
|
||||
foreach ( $this->get_cpt() as $cpt ) {
|
||||
$this->cpt[ $cpt ] = new PTSettings( 6, PTSettings::$MONTHLY );
|
||||
}
|
||||
|
||||
foreach ( $this->get_taxonomy_types() as $taxonomy ) {
|
||||
$this->taxonomies[ $taxonomy ] = new PTSettings( 3, PTSettings::$WEEKLY );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Default Settings
|
||||
* @param $option
|
||||
* @return PTSettings
|
||||
*/
|
||||
public function get_row_value( $option ) {
|
||||
$settings = new PTSettings();
|
||||
|
||||
$settings->include = isset( $_POST[ $option . '_include' ] ) ? sanitize_text_field( $_POST[ $option . '_include' ] ) : false;
|
||||
$settings->priority = isset( $_POST[ $option . '_priority' ] ) ? sanitize_text_field( $_POST[ $option . '_priority' ] ) : 0;
|
||||
$settings->frequency = isset( $_POST[ $option . '_frequency' ] ) ? sanitize_text_field( $_POST[ $option . '_frequency' ] ) : $settings->frequency;
|
||||
$settings->google_news = isset( $_POST[ $option . '_google_news' ] ) ? sanitize_text_field( $_POST[ $option . '_google_news' ] ) : 0;
|
||||
$settings->image_sitemap = isset( $_POST[ $option . '_image_sitemap' ] ) ? sanitize_text_field( $_POST[ $option . '_image_sitemap' ] ) : 0;
|
||||
$settings->video_sitemap = isset( $_POST[ $option . '_video_sitemap' ] ) ? sanitize_text_field( $_POST[ $option . '_video_sitemap' ] ) : 0;
|
||||
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
636
wp-content/plugins/xml-sitemap-generator-for-google/includes/vendor/SitemapGenerator.php
vendored
Normal file
636
wp-content/plugins/xml-sitemap-generator-for-google/includes/vendor/SitemapGenerator.php
vendored
Normal file
@@ -0,0 +1,636 @@
|
||||
<?php
|
||||
|
||||
namespace GRIM_SG\Vendor;
|
||||
|
||||
use GRIM_SG\GoogleNews;
|
||||
use GRIM_SG\ImageSitemap;
|
||||
use GRIM_SG\MultilingualSitemap;
|
||||
use GRIM_SG\VideoSitemap;
|
||||
|
||||
class SitemapGenerator {
|
||||
public $sitemapFileName = 'sitemap.xml';
|
||||
|
||||
public $sitemapIndexFileName = 'sitemap-index.xml';
|
||||
|
||||
public $robotsFileName = 'robots.txt';
|
||||
|
||||
public $maxURLsPerSitemap = 50000;
|
||||
|
||||
public $createGZipFile = false;
|
||||
|
||||
private $baseURL;
|
||||
|
||||
private $searchEngines = array(
|
||||
array(
|
||||
'https://search.yahooapis.com/SiteExplorerService/V1/updateNotification?appid=USERID&url=',
|
||||
'https://search.yahooapis.com/SiteExplorerService/V1/ping?sitemap=',
|
||||
),
|
||||
'https://www.google.com/webmasters/tools/ping?sitemap=',
|
||||
'https://submissions.ask.com/ping?sitemap=',
|
||||
'https://www.bing.com/webmaster/ping.aspx?siteMap=',
|
||||
);
|
||||
|
||||
private $urls = array();
|
||||
|
||||
private $sitemaps;
|
||||
|
||||
private $sitemapIndex;
|
||||
|
||||
private $sitemapFullURL;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $baseURL You site URL, with / at the end.
|
||||
*/
|
||||
public function __construct( $baseURL ) {
|
||||
$this->baseURL = $baseURL;
|
||||
}
|
||||
|
||||
public function addUrls( $urls_array, $callback = 'addUrl', $template = 'sitemap' ) {
|
||||
if ( ! is_array( $urls_array ) ) {
|
||||
throw new \InvalidArgumentException( 'Array as argument should be given.' );
|
||||
}
|
||||
|
||||
if ( sgg_is_sitemap_index( $template ) ) {
|
||||
foreach ( $urls_array as $sitemap => $inner_urls ) {
|
||||
foreach ( $inner_urls as $url ) {
|
||||
$this->{$callback}( $url, $sitemap );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ( $urls_array as $url ) {
|
||||
$this->{$callback}( $url );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to add single URL to Google News Sitemap.
|
||||
*/
|
||||
public function addNewsUrl( $item ) {
|
||||
$url = $item[0] ?? null;
|
||||
|
||||
$this->validateUrl( $url );
|
||||
|
||||
$tmp = array();
|
||||
$tmp['loc'] = $url;
|
||||
$tmp['publication_name'] = $item[1] ?? null;
|
||||
$tmp['language'] = $item[2] ?? null;
|
||||
$tmp['title'] = $item[3] ?? null;
|
||||
|
||||
if ( isset( $item[4] ) ) {
|
||||
$tmp['lastmod'] = $item[4];
|
||||
}
|
||||
|
||||
if ( sgg_pro_enabled() ) {
|
||||
$tmp['keywords'] = implode( ', ', apply_filters( 'sgg_news_keywords', array(), $item[5] ?? null ) );
|
||||
$tmp['stock_tickers'] = implode( ', ', apply_filters( 'sgg_news_stock_tickers', array(), $item[5] ?? null ) );
|
||||
}
|
||||
|
||||
$this->urls[] = $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to add single URL to Sitemap.
|
||||
*/
|
||||
public function addMediaUrl( $item, $sitemap = null ) {
|
||||
$url = $item[0] ?? null;
|
||||
|
||||
$this->validateUrl( $url );
|
||||
|
||||
$tmp = array();
|
||||
$tmp['loc'] = $url;
|
||||
|
||||
if ( isset( $item[1] ) ) {
|
||||
$tmp['media'] = $item[1];
|
||||
}
|
||||
|
||||
if ( ! empty( $sitemap ) ) {
|
||||
$tmp['lastmod'] = gmdate( 'c' );
|
||||
$this->urls[ $sitemap ][] = $tmp;
|
||||
} else {
|
||||
$this->urls[] = $tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to add single URL to Sitemap.
|
||||
*/
|
||||
public function addUrl( $item, $sitemap = null ) {
|
||||
$url = $item[0] ?? null;
|
||||
|
||||
$this->validateUrl( $url );
|
||||
|
||||
$tmp = array();
|
||||
$tmp['loc'] = $url;
|
||||
|
||||
if ( isset( $item[1] ) ) {
|
||||
$tmp['lastmod'] = $item[1];
|
||||
}
|
||||
if ( isset( $item[2] ) ) {
|
||||
$tmp['changefreq'] = $item[2];
|
||||
}
|
||||
if ( isset( $item[3] ) ) {
|
||||
$tmp['priority'] = $item[3];
|
||||
}
|
||||
|
||||
if ( ! empty( $sitemap ) ) {
|
||||
$this->urls[ $sitemap ][] = $tmp;
|
||||
} else {
|
||||
$this->urls[] = $tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Sitemap Item URL
|
||||
*/
|
||||
public function validateUrl( $url ) {
|
||||
if ( null === $url ) {
|
||||
throw new \InvalidArgumentException( 'URL is mandatory. At least one argument should be given.' );
|
||||
}
|
||||
|
||||
$urlLenght = extension_loaded( 'mbstring' ) ? mb_strlen( $url ) : strlen( $url );
|
||||
if ( $urlLenght > 2048 ) {
|
||||
throw new \InvalidArgumentException(
|
||||
"URL lenght can't be bigger than 2048 characters.
|
||||
Note, that precise url length check is guaranteed only using mb_string extension.
|
||||
Make sure Your server allow to use mbstring extension."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create sitemap in memory.
|
||||
*/
|
||||
public function createSitemap( $template = 'sitemap', $headers = array(), $is_xml = true ) {
|
||||
if ( ! isset( $this->urls ) ) {
|
||||
throw new \BadMethodCallException( 'To create sitemap, call addUrl or addUrls function first.' );
|
||||
}
|
||||
|
||||
if ( $this->maxURLsPerSitemap > 50000 ) {
|
||||
throw new \InvalidArgumentException( 'More than 50,000 URLs per single sitemap is not allowed.' );
|
||||
}
|
||||
|
||||
$settings = ( new Controller() )->get_settings();
|
||||
$stylesheet_template = sgg_maybe_remove_inner_suffix( $template );
|
||||
|
||||
$stylesheet_path = apply_filters( 'sitemap_xsl_template_path', 'sitemap-stylesheet.xsl' );
|
||||
$stylesheet_url = sgg_get_sitemap_url( "{$stylesheet_path}?template={$stylesheet_template}", "sitemap_xsl={$stylesheet_template}", false );
|
||||
$stylesheet_url = strtok( $stylesheet_url, '&' ); // remove & query string
|
||||
$is_sitemap_index = sgg_is_sitemap_index( $template, $settings );
|
||||
$is_media_template = in_array( $template, array( 'image-sitemap', 'video-sitemap' ), true );
|
||||
$is_index_template = $is_media_template || 'sitemap' === $template;
|
||||
|
||||
$sitemap_urls = $is_sitemap_index
|
||||
? $this->urls
|
||||
: array_chunk( $this->urls, $this->maxURLsPerSitemap );
|
||||
|
||||
foreach ( $sitemap_urls as $sitemap_key => $sitemap ) {
|
||||
$dom = $this->create_sitemap_dom( $stylesheet_url, $template, $settings );
|
||||
$urlset = $this->create_sitemap_urlset( $dom, $headers );
|
||||
|
||||
$dom->appendChild( $urlset );
|
||||
|
||||
foreach ( $sitemap as $url ) {
|
||||
$url_element = $dom->createElement( 'url' );
|
||||
|
||||
$url_element->appendChild(
|
||||
$dom->createElement( 'loc', htmlspecialchars( $url['loc'], ENT_QUOTES, 'UTF-8' ) )
|
||||
);
|
||||
|
||||
if ( GoogleNews::$template === $template ) {
|
||||
if ( $settings->google_news_old_posts && GoogleNews::is_older_than_48h( $url['lastmod'] ) ) {
|
||||
$url_element->appendChild(
|
||||
$dom->createElement( 'lastmod', $url['lastmod'] )
|
||||
);
|
||||
} else {
|
||||
$news = $url_element->appendChild( $dom->createElement( 'news:news' ) );
|
||||
|
||||
if ( isset( $url['publication_name'] ) ) {
|
||||
$publication = $dom->createElement( 'news:publication' );
|
||||
$news->appendChild( $publication );
|
||||
|
||||
$publication->appendChild(
|
||||
$dom->createElement( 'news:name', esc_html( $url['publication_name'] ) )
|
||||
);
|
||||
$publication->appendChild(
|
||||
$dom->createElement( 'news:language', $url['language'] )
|
||||
);
|
||||
}
|
||||
if ( isset( $url['lastmod'] ) ) {
|
||||
$news->appendChild(
|
||||
$dom->createElement( 'news:publication_date', $url['lastmod'] )
|
||||
);
|
||||
}
|
||||
if ( isset( $url['title'] ) ) {
|
||||
$news->appendChild(
|
||||
$dom->createElement( 'news:title', esc_html( $url['title'] ) )
|
||||
);
|
||||
}
|
||||
if ( sgg_pro_enabled() ) {
|
||||
$news->appendChild(
|
||||
$dom->createElement( 'news:keywords', $url['keywords'] )
|
||||
);
|
||||
$news->appendChild(
|
||||
$dom->createElement( 'news:stock_tickers', $url['stock_tickers'] )
|
||||
);
|
||||
}
|
||||
}
|
||||
} elseif ( strpos( $template, ImageSitemap::$template ) !== false ) {
|
||||
if ( isset( $url['lastmod'] ) ) {
|
||||
$url_element->appendChild(
|
||||
$dom->createElement( 'lastmod', $url['lastmod'] )
|
||||
);
|
||||
} else {
|
||||
if ( ! empty( $url['media'] ) ) {
|
||||
foreach ( $url['media'] as $image ) {
|
||||
$image_element = $url_element->appendChild( $dom->createElement( 'image:image' ) );
|
||||
$image_element->appendChild(
|
||||
$dom->createElement( 'image:loc', $image )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ( strpos( $template, VideoSitemap::$template ) !== false ) {
|
||||
if ( isset( $url['lastmod'] ) ) {
|
||||
$url_element->appendChild(
|
||||
$dom->createElement( 'lastmod', $url['lastmod'] )
|
||||
);
|
||||
} else {
|
||||
if ( ! empty( $url['media'] ) ) {
|
||||
foreach ( $url['media'] as $video ) {
|
||||
$video_element = $url_element->appendChild( $dom->createElement( 'video:video' ) );
|
||||
$video_element->appendChild(
|
||||
$dom->createElement( 'video:thumbnail_loc', esc_url( $video['thumbnail'] ?? '' ) )
|
||||
);
|
||||
// Decode HTML entities first, then DOMDocument will handle XML escaping properly
|
||||
$video_title = html_entity_decode( $video['title'] ?? '', ENT_QUOTES | ENT_HTML5, 'UTF-8' );
|
||||
$video_element->appendChild(
|
||||
$dom->createElement( 'video:title', $video_title )
|
||||
);
|
||||
// Decode HTML entities first, then DOMDocument will handle XML escaping properly
|
||||
$video_description = html_entity_decode( $video['description'] ?? '', ENT_QUOTES | ENT_HTML5, 'UTF-8' );
|
||||
$video_element->appendChild(
|
||||
$dom->createElement( 'video:description', $video_description )
|
||||
);
|
||||
$video_element->appendChild(
|
||||
$dom->createElement( 'video:player_loc', esc_url( $video['player_loc'] ?? '' ) )
|
||||
);
|
||||
// Decode HTML entities first, then DOMDocument will handle XML escaping properly
|
||||
$video_duration = html_entity_decode( $video['duration'] ?? '', ENT_QUOTES | ENT_HTML5, 'UTF-8' );
|
||||
$video_element->appendChild(
|
||||
$dom->createElement( 'video:duration', $video_duration )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( isset( $url['lastmod'] ) ) {
|
||||
$url_element->appendChild(
|
||||
$dom->createElement( 'lastmod', $url['lastmod'] )
|
||||
);
|
||||
}
|
||||
if ( isset( $url['changefreq'] ) ) {
|
||||
$url_element->appendChild(
|
||||
$dom->createElement( 'changefreq', $url['changefreq'] )
|
||||
);
|
||||
}
|
||||
if ( isset( $url['priority'] ) ) {
|
||||
$url_element->appendChild(
|
||||
$dom->createElement( 'priority', $url['priority'] )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$urlset->appendChild( $url_element );
|
||||
|
||||
if ( $is_sitemap_index && $is_index_template ) {
|
||||
$this->sitemaps[ $sitemap_key ][] = array(
|
||||
'loc' => $url['loc'],
|
||||
'lastmod' => $url['lastmod'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! sgg_pro_enabled() || ! $settings->minimize_sitemap ) {
|
||||
$dom->formatOutput = true;
|
||||
}
|
||||
|
||||
if ( ! $is_index_template || ! $is_sitemap_index ) {
|
||||
$ready_sitemap = $dom->saveXML();
|
||||
|
||||
if ( $is_sitemap_index ) {
|
||||
$this->sitemaps[ $sitemap_key ][] = $ready_sitemap;
|
||||
$this->sitemaps[ $sitemap_key ]['lastmod'] = $url['lastmod'] ?? gmdate( 'c' );
|
||||
} else {
|
||||
$this->sitemaps[] = $ready_sitemap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( null === $this->sitemaps ) {
|
||||
$dom = $this->create_sitemap_dom( $stylesheet_url, $template, $settings );
|
||||
$urlset = $this->create_sitemap_urlset( $dom, $headers );
|
||||
|
||||
$dom->appendChild( $urlset );
|
||||
|
||||
$this->sitemaps[] = $dom->saveXML();
|
||||
}
|
||||
|
||||
if ( count( $this->sitemaps ) > 1000 ) {
|
||||
throw new \LengthException( 'Sitemap index can contains 1000 single sitemaps. Perhaps You trying to submit too many URLs.' );
|
||||
}
|
||||
|
||||
$is_media_index = $is_media_template && $is_sitemap_index;
|
||||
if ( ! empty( $settings->sitemap_view ) && ( ( 'sitemap' === $template && count( $this->sitemaps ) > 0 ) || $is_media_index ) ) {
|
||||
$stylesheet_url = sgg_get_sitemap_url( "{$stylesheet_path}?template=sitemap-index", 'sitemap_xsl=sitemap-index', false );
|
||||
$stylesheet_url = strtok( $stylesheet_url, '&' ); // remove & query string
|
||||
|
||||
$dom = $this->create_sitemap_dom( $stylesheet_url, $template, $settings );
|
||||
|
||||
$sitemapindex = $dom->createElement( 'sitemapindex' );
|
||||
$sitemapindex->setAttribute( 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance' );
|
||||
$sitemapindex->setAttribute( 'xsi:schemaLocation', 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd' );
|
||||
$sitemapindex->setAttribute( 'xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9' );
|
||||
$dom->appendChild( $sitemapindex );
|
||||
|
||||
foreach ( $this->sitemaps as $sitemap_key => $sitemap ) {
|
||||
if ( ! empty( $sitemap ) && is_array( $sitemap ) ) {
|
||||
if ( 'page' === $sitemap_key && sgg_get_home_url_with_trailing_slash() === ( $sitemap[0]['loc'] ?? '' ) && 1 < count( $sitemap ) ) {
|
||||
$sitemap[0] = array(
|
||||
'loc' => $sitemap[0]['loc'],
|
||||
'lastmod' => max( $sitemap[0]['lastmod'] ?? '', $sitemap[1]['lastmod'] ?? '' ),
|
||||
);
|
||||
|
||||
if ( ! empty( $sitemap[1] ) ) {
|
||||
unset( $sitemap[1] );
|
||||
}
|
||||
|
||||
$sitemap = array_values( $sitemap );
|
||||
}
|
||||
|
||||
foreach ( $sitemap as $index => $url ) {
|
||||
$sitemap_element = $dom->createElement( 'sitemap' );
|
||||
$sitemap_type = $is_xml ? 'xml' : 'html';
|
||||
$default_number = $is_media_template ? 1 : '';
|
||||
$sitemap_number = 0 < $index ? intval( $index ) + 1 : $default_number;
|
||||
$page_param = 0 < $sitemap_number ? "&page={$sitemap_number}" : '';
|
||||
|
||||
$sitemap_element->appendChild(
|
||||
$dom->createElement(
|
||||
'loc',
|
||||
esc_url( sgg_get_sitemap_url( "{$sitemap_key}-sitemap{$sitemap_number}.{$sitemap_type}", "sitemap_{$sitemap_type}=true&inner_sitemap={$sitemap_key}{$page_param}", false ) )
|
||||
)
|
||||
);
|
||||
|
||||
$sitemap_element->appendChild(
|
||||
$dom->createElement( 'lastmod', $url['lastmod'] ?? gmdate( 'c' ) )
|
||||
);
|
||||
|
||||
$sitemapindex->appendChild( $sitemap_element );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $is_xml && 'sitemap' === $template ) {
|
||||
$additional_sitemaps = apply_filters( 'sgg_additional_index_sitemaps', $settings->custom_sitemaps ?? array() );
|
||||
|
||||
if ( $settings->enable_image_sitemap ) {
|
||||
$additional_sitemaps[] = array(
|
||||
'url' => sgg_get_sitemap_url( $settings->image_sitemap_url, 'image_sitemap' ),
|
||||
);
|
||||
}
|
||||
|
||||
if ( $settings->enable_video_sitemap ) {
|
||||
$additional_sitemaps[] = array(
|
||||
'url' => sgg_get_sitemap_url( $settings->video_sitemap_url, 'video_sitemap' ),
|
||||
);
|
||||
}
|
||||
|
||||
foreach ( $additional_sitemaps as $additional_sitemap ) {
|
||||
$sitemap_element = $dom->createElement( 'sitemap' );
|
||||
$sitemap_url = ! empty( $additional_sitemap['url'] ) ? esc_url( $additional_sitemap['url'] ) : $additional_sitemap;
|
||||
|
||||
if ( ! is_string( $sitemap_url ) ) {
|
||||
continue;
|
||||
}
|
||||
$sitemap_element->appendChild(
|
||||
$dom->createElement( 'loc', $sitemap_url )
|
||||
);
|
||||
|
||||
$sitemap_element->appendChild(
|
||||
$dom->createElement(
|
||||
'lastmod',
|
||||
! empty( $additional_sitemap['lastmod'] ) ? $additional_sitemap['lastmod'] : gmdate( 'c' )
|
||||
)
|
||||
);
|
||||
|
||||
$sitemapindex->appendChild( $sitemap_element );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! sgg_pro_enabled() || ! $settings->minimize_sitemap ) {
|
||||
$dom->formatOutput = true;
|
||||
}
|
||||
|
||||
$this->sitemapFullURL = $this->baseURL . $this->sitemapIndexFileName;
|
||||
$this->sitemapIndex = array(
|
||||
$this->sitemapIndexFileName,
|
||||
$dom->saveXML(),
|
||||
);
|
||||
} else {
|
||||
if ( $this->createGZipFile ) {
|
||||
$this->sitemapFullURL = $this->baseURL . $this->sitemapFileName . '.gz';
|
||||
} else {
|
||||
$this->sitemapFullURL = $this->baseURL . $this->sitemapFileName;
|
||||
}
|
||||
|
||||
if ( ! empty( $this->sitemaps[0] ) ) {
|
||||
$this->sitemaps[0] = array(
|
||||
$this->sitemapFileName,
|
||||
$this->sitemaps[0],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create Multilingual Sitemap in memory.
|
||||
*/
|
||||
public function createMultilingualSitemap( $urls = array(), $is_xml = true ) {
|
||||
if ( ! isset( $this->urls ) ) {
|
||||
throw new \BadMethodCallException( 'To create sitemap, call addUrl or addUrls function first.' );
|
||||
}
|
||||
|
||||
if ( $this->maxURLsPerSitemap > 50000 ) {
|
||||
throw new \InvalidArgumentException( 'More than 50,000 URLs per single sitemap is not allowed.' );
|
||||
}
|
||||
|
||||
$stylesheet_path = apply_filters( 'sitemap_xsl_template_path', 'sitemap-stylesheet.xsl' );
|
||||
$settings = ( new Controller() )->get_settings();
|
||||
|
||||
$dom = $this->create_sitemap_dom(
|
||||
sgg_get_sitemap_url( "{$stylesheet_path}?template=multilingual-sitemap", 'sitemap_xsl=sitemap-index', false ),
|
||||
'',
|
||||
$settings
|
||||
);
|
||||
|
||||
$sitemapindex = $dom->createElement( 'sitemapindex' );
|
||||
$sitemapindex->setAttribute( 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance' );
|
||||
$sitemapindex->setAttribute( 'xsi:schemaLocation', 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd' );
|
||||
$sitemapindex->setAttribute( 'xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9' );
|
||||
$dom->appendChild( $sitemapindex );
|
||||
|
||||
foreach ( $urls as $url ) {
|
||||
$sitemap_element = $dom->createElement( 'sitemap' );
|
||||
|
||||
$sitemap_element->appendChild(
|
||||
$dom->createElement(
|
||||
'loc',
|
||||
esc_url( $url )
|
||||
)
|
||||
);
|
||||
|
||||
$sitemap_element->appendChild(
|
||||
$dom->createElement( 'lastmod', gmdate( DATE_W3C ) )
|
||||
);
|
||||
|
||||
$sitemapindex->appendChild( $sitemap_element );
|
||||
}
|
||||
|
||||
if ( ! sgg_pro_enabled() || ! $settings->minimize_sitemap ) {
|
||||
$dom->formatOutput = true;
|
||||
}
|
||||
|
||||
$this->sitemapFullURL = $this->baseURL . $this->sitemapIndexFileName;
|
||||
$this->sitemapIndex = array(
|
||||
$this->sitemapIndexFileName,
|
||||
$dom->saveXML(),
|
||||
);
|
||||
}
|
||||
|
||||
public function create_sitemap_dom( $stylesheet_url, $template = '', $settings = null ) {
|
||||
$generator_info = 'sitemap-generator-url="https://wpgrim.com" sitemap-generator-version="' . GRIM_SG_VERSION . '"';
|
||||
|
||||
$dom = new \DOMDocument( '1.0', 'UTF-8' );
|
||||
|
||||
// Get settings if not provided
|
||||
if ( null === $settings ) {
|
||||
$settings = ( new Controller() )->get_settings();
|
||||
}
|
||||
|
||||
// Skip XSL stylesheet reference based on settings
|
||||
$is_index_sitemap = strpos( $stylesheet_url, 'sitemap-index' ) !== false;
|
||||
$skip_xsl = false;
|
||||
|
||||
if ( ! $is_index_sitemap ) {
|
||||
if ( strpos( $template, VideoSitemap::$template ) !== false ) {
|
||||
$skip_xsl = ! empty( $settings->hide_video_sitemap_xsl );
|
||||
} elseif ( strpos( $template, ImageSitemap::$template ) !== false ) {
|
||||
$skip_xsl = ! empty( $settings->hide_image_sitemap_xsl );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $skip_xsl ) {
|
||||
$dom->appendChild(
|
||||
$dom->createProcessingInstruction(
|
||||
'xml-stylesheet',
|
||||
'type="text/xsl" href="' . $stylesheet_url . '"'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$dom->appendChild( $dom->createComment( $generator_info ) );
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
public function create_sitemap_urlset( $dom, $headers = array() ) {
|
||||
$urlset = $dom->createElement( 'urlset' );
|
||||
|
||||
$urlset->setAttribute( 'xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9' );
|
||||
if ( ! empty( $headers ) ) {
|
||||
foreach ( $headers as $key => $header ) {
|
||||
$urlset->setAttribute( $key, $header );
|
||||
}
|
||||
}
|
||||
|
||||
return $urlset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns created sitemaps as array of strings.
|
||||
* Use it You want to work with sitemap without saving it as files.
|
||||
* @return array of strings
|
||||
* @access public
|
||||
*/
|
||||
public function toArray() {
|
||||
if ( isset( $this->sitemapIndex ) ) {
|
||||
return array_merge( array( $this->sitemapIndex ), $this->sitemaps );
|
||||
} else {
|
||||
return $this->sitemaps;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will print sitemaps.
|
||||
* @access public
|
||||
*/
|
||||
public function outputSitemap( $template, $is_xml, $inner_sitemap = null ) {
|
||||
add_filter( 'trp_stop_translating_page', '__return_true' );
|
||||
|
||||
ob_get_clean();
|
||||
|
||||
if ( $is_xml ) {
|
||||
header( 'Content-Type: text/xml; charset=utf-8' );
|
||||
} else {
|
||||
ob_start();
|
||||
}
|
||||
|
||||
if ( ! empty( $inner_sitemap ) && sgg_is_sitemap_index( $template ) && ! empty( $this->sitemaps[ $inner_sitemap ][0] ) ) {
|
||||
echo $this->sitemaps[ $inner_sitemap ][0];
|
||||
} else {
|
||||
if ( ! empty( $this->sitemapIndex[1] ) ) {
|
||||
$template = 'sitemap-index';
|
||||
echo $this->sitemapIndex[1];
|
||||
} else {
|
||||
echo $this->sitemaps[0][1] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $is_xml ) {
|
||||
$xml_source = ob_get_clean();
|
||||
|
||||
$xml = new \DOMDocument();
|
||||
$xml->loadXML( $xml_source );
|
||||
|
||||
ob_start();
|
||||
|
||||
load_template(
|
||||
GRIM_SG_PATH . '/templates/xsl/sitemap.php',
|
||||
false,
|
||||
compact( 'template', 'is_xml' )
|
||||
);
|
||||
|
||||
$xsl_content = ob_get_clean();
|
||||
|
||||
$xsl = new \DOMDocument();
|
||||
$xsl->loadXML( $xsl_content );
|
||||
|
||||
$proc = new \XSLTProcessor();
|
||||
$proc->importStyleSheet( $xsl );
|
||||
|
||||
$dom_tran_obj = $proc->transformToDoc( $xml );
|
||||
|
||||
foreach ( $dom_tran_obj->childNodes as $node ) {
|
||||
echo $dom_tran_obj->saveXML( $node ) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ( ob_get_contents() ) {
|
||||
ob_end_flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user