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