stylesheet = '';
if( ! empty( $_SERVER['SERVER_PROTOCOL'] ) ) {
$this->http_protocol = sanitize_text_field( $_SERVER['SERVER_PROTOCOL'] );
}
$this->init();
}
public function init() {
$this->init_defaults();
$this->init_options();
$this->init_hooks();
}
private function init_defaults() {
$this->default = new stdClass();
$this->default->options = [
'sitemap_items_per_page' => 1000,
'allow_ping' => 1,
'ping_immediately' => 0,
];
}
private function init_options() {
$this->options = apply_filters( 'wpforo_seo_options', $this->default->options );
}
private function init_hooks() {
add_filter( 'wpforo_before_init_current_object', [ $this, 'redirect' ], 10, 2 );
add_action( 'wpforo_ping_search_engines', [ $this, 'ping_search_engines' ] );
add_action( 'wpforo_hit_sitemap_index', [ $this, 'hit_sitemap_index' ] );
add_action( 'wpforo_after_init_classes', function() {
if( WPF()->board->get_current( 'is_standalone' ) ) add_action( 'wp_sitemaps_enabled', '__return_false' );
}, 1 );
}
public function sitemap_url( $url ) {
$date = ( ! empty( $url['lastmod'] ) ? gmdate( 'c', strtotime( $url['lastmod'] . ' GMT' ) ) : null );
$url['loc'] = htmlspecialchars( $url['loc'] );
$output = "\t\n";
$output .= "\t\t" . $this->encode_url_rfc3986( $url['loc'] ) . "\n";
$output .= empty( $date ) ? '' : "\t\t" . htmlspecialchars( $date ) . "\n";
$output .= "\t\n";
return apply_filters( 'wpforo_sitemap_url', $output, $url );
}
public function members_sitemap( $paged ) {
$paged = absint( $paged );
$sitemap = '';
if( $paged && $profiles = $this->get_public_profiles( $paged ) ) {
foreach( $profiles as $profile ) {
if( $profile['loc'] = wpforo_member( $profile['userid'], 'profile_url' ) ) {
$sitemap .= $this->sitemap_url( $profile );
}
}
}
return $sitemap;
}
public function forums_sitemap() {
$sitemap = '';
if( $forums = $this->get_public_forums() ) {
foreach( $forums as $forum ) {
$forum['loc'] = wpforo_forum( $forum['forumid'], 'url' );
$sitemap .= $this->sitemap_url( $forum );
}
}
return $sitemap;
}
public function topics_sitemap( $paged ) {
$paged = absint( $paged );
$sitemap = '';
if( $paged && $topics = $this->get_public_topics( $paged ) ) {
foreach( $topics as $topic ) {
$topic['loc'] = wpforo_topic( $topic['topicid'], 'url' );
$sitemap .= $this->sitemap_url( $topic );
}
}
return $sitemap;
}
private function encode_url_rfc3986( $url ) {
if( filter_var( $url, FILTER_VALIDATE_URL ) ) {
return $url;
}
$path = wp_parse_url( $url, PHP_URL_PATH );
if( ! empty( $path ) && '/' !== $path ) {
$encoded_path = explode( '/', $path );
$encoded_path = array_map( 'rawurldecode', $encoded_path );
$encoded_path = array_map( 'rawurlencode', $encoded_path );
$encoded_path = implode( '/', $encoded_path );
$encoded_path = str_replace( '%7E', '~', $encoded_path ); // PHP <5.3.
$url = str_replace( $path, $encoded_path, $url );
}
$query = wp_parse_url( $url, PHP_URL_QUERY );
if( ! empty( $query ) ) {
parse_str( $query, $parsed_query );
if( defined( 'PHP_QUERY_RFC3986' ) ) { // PHP 5.4+.
$parsed_query = http_build_query( $parsed_query, null, '&', PHP_QUERY_RFC3986 );
} else {
$parsed_query = http_build_query( $parsed_query, null, '&' );
$parsed_query = str_replace( '+', '%20', $parsed_query );
$parsed_query = str_replace( '%7E', '~', $parsed_query );
}
$url = str_replace( $query, $parsed_query, $url );
}
return $url;
}
private function get_public_profiles( $paged = 0 ) {
$profiles = [];
if( $groupids = WPF()->usergroup->get_visible_usergroup_ids() ) {
$items_per_page = $this->options['sitemap_items_per_page'];
$sql = "SELECT `userid`, FROM_UNIXTIME( IFNULL(`online_time`, UNIX_TIMESTAMP()) ) AS lastmod
FROM " . WPF()->tables->profiles . "
WHERE `groupid` IN(" . implode( ',', $groupids ) . ")
OR `secondary_groupids` REGEXP '(,|^)(" . implode( '|', $groupids ) . ")(,|$)'
ORDER BY `userid` ASC";
if( $paged ) $sql .= " LIMIT " . ( -- $paged * $items_per_page ) . ", $items_per_page";
$profiles = (array) WPF()->db->get_results( $sql, ARRAY_A );
}
return $profiles;
}
private function get_public_forums() {
$forums = [];
if( $forumids = $this->get_public_forumids() ) {
$sql = "SELECT `forumid`,
CASE
WHEN `last_post_date` = '0000-00-00 00:00:00'
THEN NOW()
ELSE `last_post_date`
END AS lastmod
FROM " . WPF()->tables->forums . "
WHERE `forumid` IN(" . implode( ',', $forumids ) . ")
ORDER BY `parentid` ASC, `title` ASC";
$forums = (array) WPF()->db->get_results( $sql, ARRAY_A );
}
return $forums;
}
private function get_public_forumids() {
$forumids = [];
$sql = "SELECT `forumid` FROM " . WPF()->tables->forums . " ORDER BY `parentid` ASC, `title` ASC";
if( $_forumids = WPF()->db->get_col( $sql ) ) {
foreach( $_forumids as $_forumid ) {
if( WPF()->perm->forum_can( 'vf', $_forumid ) ) {
$forumids[] = $_forumid;
}
}
}
return $forumids;
}
private function get_public_topics( $paged = 0 ) {
$topics = [];
if( $forumids = $this->get_public_forumids() ) {
$items_per_page = $this->options['sitemap_items_per_page'];
$sql = "SELECT `topicid`, `modified` as lastmod
FROM " . WPF()->tables->topics . "
WHERE `private` = 0
AND `status` = 0
AND `forumid` IN(" . implode( ',', $forumids ) . ")
ORDER BY `topicid` ASC";
if( $paged ) $sql .= " LIMIT " . ( -- $paged * $items_per_page ) . ", $items_per_page";
$topics = (array) WPF()->db->get_results( $sql, ARRAY_A );
}
return $topics;
}
private function get_public_profiles_count() {
$count = 0;
if( $groupids = WPF()->usergroup->get_visible_usergroup_ids() ) {
$sql = "SELECT COUNT(*)
FROM " . WPF()->tables->profiles . "
WHERE `groupid` IN(" . implode( ',', $groupids ) . ")
OR `secondary_groupids` REGEXP '(,|^)(" . implode( '|', $groupids ) . ")(,|$)'";
$count = (int) WPF()->db->get_var( $sql );
}
return $count;
}
private function get_public_topics_count() {
$count = 0;
if( $forumids = $this->get_public_forumids() ) {
$sql = "SELECT COUNT(*)
FROM " . WPF()->tables->topics . "
WHERE `private` = 0
AND `status` = 0
AND `forumid` IN(" . implode( ',', $forumids ) . ")";
$count = (int) WPF()->db->get_var( $sql );
}
return $count;
}
public function get_root_map() {
$links = [];
$items_per_page = $this->options['sitemap_items_per_page'];
if( wpforo_setting( 'seo', 'topics_sitemap' ) ) {
if( $topics_count = $this->get_public_topics_count() ) {
$pages_count = ceil( $topics_count / $items_per_page );
for( $i = 1; $i <= $pages_count; $i ++ ) {
$links[] = trim( wpforo_home_url( 'topic-sitemap' . $i . '.xml' ), '/' );
}
}
}
if( wpforo_setting( 'seo', 'members_sitemap' ) ) {
if( $profiles_count = $this->get_public_profiles_count() ) {
$pages_count = ceil( $profiles_count / $items_per_page );
for( $i = 1; $i <= $pages_count; $i ++ ) {
$links[] = trim( wpforo_home_url( 'profile-sitemap' . $i . '.xml' ), '/' );
}
}
}
$links[] = trim( wpforo_home_url( 'forum-sitemap.xml' ), '/' );
// make sitemap index
$xml = '' . "\n";
foreach( $links as $link ) {
$link = htmlspecialchars( $link );
$xml .= "\t\n";
$xml .= "\t\t" . $link . "\n";
$xml .= "\t\n";
}
$xml .= apply_filters( 'wpforo_sitemap_index', '' );
$xml .= '';
return $xml;
}
public function get_sitemap( $type, $paged ) {
$transient_key = 'wpforo_seo_sitemap_' . WPF()->board->get_current( 'boardid' ) . $type . $paged;
if( ! $xml = get_transient( $transient_key ) ) {
if( $type ) {
$urls = '';
switch( $type ) {
case 'topic':
if( wpforo_setting( 'seo', 'topics_sitemap' ) ) $urls = $this->topics_sitemap( $paged );
break;
case 'forum':
if( wpforo_setting( 'seo', 'forums_sitemap' ) ) $urls = $this->forums_sitemap();
break;
case 'profile':
if( wpforo_setting( 'seo', 'members_sitemap' ) ) $urls = $this->members_sitemap( $paged );
break;
}
if( $urls ) {
$urlset = '' . "\n";
$xml = apply_filters( "wpforo_sitemap_{$type}_urlset", $urlset );
$xml .= $urls;
$xml .= '';
}
} else {
$xml = $this->get_root_map();
}
set_transient( $transient_key, $xml, DAY_IN_SECONDS );
}
return (string) $xml;
}
public function get_output( $sitemap ) {
$output = '';
if( $this->stylesheet ) {
$output .= apply_filters( 'wpforo_stylesheet_url', $this->stylesheet ) . "\n";
}
$output .= $sitemap;
$output .= "\n";
return $output;
}
public function output( $sitemap ) {
if( ! headers_sent() ) {
header( $this->http_protocol . ' 200 OK', true, 200 );
// Prevent the search engines from indexing the XML Sitemap.
header( 'X-Robots-Tag: noindex, follow', true );
header( 'Content-Type: text/xml; charset=UTF-8' );
}
echo $this->get_output( $sitemap );
}
public function sitemap_close() {
remove_all_actions( 'wp_footer' );
die();
}
public function redirect( $current_object, $wpf_url_parse ) {
$pattern = '#^[\r\n\t\s\0]*(?\w*)-?sitemap(?:(?\d*)|_index)\.xml[\r\n\t\s\0]*$#iu';
if( ! empty( $wpf_url_parse[0] ) && preg_match( $pattern, basename( (string) $wpf_url_parse[0] ), $match ) ) {
$current_object['template'] = 'sitemap';
$query = [ 'type' => '', 'paged' => 1 ];
$query = wpforo_parse_args( $match, $query );
$type = trim( (string) $query['type'] );
$paged = absint( $query['paged'] );
if( ! $paged ) $paged = 1;
if( $sitemap = $this->get_sitemap( $type, $paged ) ) {
$this->output( $sitemap );
$this->sitemap_close();
} else {
$current_object['is_404'] = true;
}
}
return $current_object;
}
public function hit_sitemap_index() {
wp_remote_get( trim( wpforo_home_url( 'sitemap_index.xml' ), '/' ) );
}
public function ping_search_engines( $url = '' ) {
if( ! $this->options['allow_ping'] || ! $this->get_public_forumids() ) return;
if( ! $url ) $url = urlencode( trim( wpforo_home_url( 'sitemap_index.xml' ), '/' ) );
wp_remote_get( 'https://www.google.com/webmasters/sitemaps/ping?sitemap=' . $url, [ 'blocking' => false ] );
wp_remote_get( 'https://www.bing.com/ping?sitemap=' . $url, [ 'blocking' => false ] );
}
public function clear_cache( $type = '', $paged = 1 ) {
if( $type == '' && $paged = 1 ) {
$like = 'wpforo_seo_sitemap_%';
$wheres = [];
$wheres[] = sprintf( "option_name LIKE '%s'", addcslashes( '_transient_' . $like, '_' ) );
$wheres[] = sprintf( "option_name LIKE '%s'", addcslashes( '_transient_timeout_' . $like, '_' ) );
// Delete transients.
$sql = sprintf( 'DELETE FROM %1$s WHERE %2$s', WPF()->db->options, implode( ' OR ', $wheres ) );
WPF()->db->query( $sql );
} else {
$transient_key = 'wpforo_seo_sitemap_' . $type . $paged;
delete_transient( $transient_key );
}
switch( $type ) {
case 'profile':
if( ! wpforo_setting( 'seo', 'members_sitemap' ) ) return;
break;
case 'forum':
if( ! wpforo_setting( 'seo', 'forums_sitemap' ) ) return;
break;
case 'topic':
if( ! wpforo_setting( 'seo', 'topics_sitemap' ) ) return;
break;
case '':
break;
default:
return;
}
wp_schedule_single_event( ( time() + 300 ), 'wpforo_hit_sitemap_index' );
if( ! $this->options['allow_ping'] ) return;
if( $this->options['ping_immediately'] ) {
$this->ping_search_engines();
} elseif( ! wp_next_scheduled( 'wpforo_ping_search_engines' ) ) {
wp_schedule_single_event( ( time() + 300 ), 'wpforo_ping_search_engines' );
}
}
}