/home/arranoyd/telegastro/wp-content/plugins/fv-wordpress-flowplayer/models/xml-video-sitemap.php
<?php
class FV_Xml_Video_Sitemap {
public function __construct() {
// Add our custom rewrite rules
add_filter('init', array($this, 'fv_check_xml_sitemap_rewrite_rules'), 999 );
add_action('do_feed_video-sitemap', array($this, 'fv_generate_video_sitemap'), 10, 1);
add_action('do_feed_video-sitemap-index', array($this, 'fv_generate_video_sitemap_index'), 10, 1);
add_action( 'parse_request', array($this, 'fix_query_vars') );
add_filter( 'query_vars', array($this, 'custom_query_vars') ); // we need to use custom query vars as otherwise Yoast SEO could stop the sitemap from working as it could be detected by $wp_query->is_date
add_filter( 'redirect_canonical', array( $this, 'redirect_canonical' ) ); // stop trailing slashes on sitemap URLs
add_filter( 'fv_flowplayer_settings_save', array($this, 'settings_save') ); // whitelist symbols
add_action( 'fv_flowplayer_admin_seo_after', array( $this, 'options' ) );
}
function custom_query_vars( $vars ) {
$vars[] = 'fvp_sitemap_year';
$vars[] = 'fvp_sitemap_monthnum';
return $vars;
}
function fix_query_vars( $query ) { // stop Yoast SEO from interferring
global $fv_fp;
if( !$fv_fp->_get_option('video_sitemap') ) return $query;
if( !empty($query->query_vars['sitemap']) && $query->query_vars['sitemap'] == 'video' ) {
unset($query->query_vars['sitemap']);
$query->query_vars['feed'] = 'video-sitemap-index';
}
return $query;
}
function get_meta_keys( $mode = false ) {
global $fv_fp;
if( !empty($fv_fp) && $fv_fp->_get_option('video_sitemap_meta') ) {
$keys = explode(',', esc_sql($fv_fp->_get_option('video_sitemap_meta')) );
if( $mode == 'sql' ) return "'".implode("','",$keys)."'";
return $keys;
}
return false;
}
function get_post_types() {
$types = get_post_types( array( 'public' => true ) );
unset($types['revision'], $types['attachment'], $types['topic'], $types['reply']);
return array_keys($types);
}
function get_video_details( $posts ) {
global $fv_fp;
$videos = array();
$dynamic_domains = apply_filters('fv_player_pro_video_ajaxify_domains', array());
$amazon = $fv_fp->_get_option('amazon_bucket');
if( $amazon && is_array($amazon) && count($amazon) > 0 ) {
foreach( $amazon AS $bucket ) {
$dynamic_domains[] = 'amazonaws.com/'.$bucket.'/';
$dynamic_domains[] = '//'.$bucket.'.s3';
}
}
$cf = $fv_fp->_get_option( array('pro','cf_domain') );
if( $cf ) {
$cf = explode( ',', $cf );
if( is_array($cf) && count($cf) > 0 ) {
foreach( $cf AS $cf_domain ) {
$dynamic_domains[] = $cf_domain;
}
}
}
foreach ($posts as $objPost) {
$count = 0;
$permalink = get_permalink($objPost);
$xml_loc = array(
// landing page
'loc' => $permalink,
'video' => array()
);
$used_videos = array();
$used_titles = array();
$used_descriptions = array();
$content = $objPost->post_content;
$content = preg_replace( '~<code.*?</code>~', '', $content );
$content = preg_replace( '~<pre[\s\S]*?</pre>~', '', $content );
$content = $this->strip_membership_content($content);
preg_match_all( '~\[(?:flowplayer|fvplayer).*?\]~', $content, $matches );
if( $this->get_meta_keys() ) {
foreach( $this->get_meta_keys() AS $meta_key ) {
$meta_values = implode( get_post_meta($objPost->ID, $meta_key) );
$meta_values = $this->strip_membership_content($meta_values);
preg_match_all( '~\[(?:flowplayer|fvplayer).*?\]~', $meta_values, $meta_matches );
if( is_array($meta_matches) && count($meta_matches) > 0 ) {
$matches[$meta_key] = $meta_matches[0];
}
}
}
$content_no_tags = preg_replace( '~</p>~', "</p>\n", $content );
$content_no_tags = preg_replace( '~\n+~', "\n", $content );
$content_no_tags = strip_tags( $content_no_tags );
$content_no_tags = explode( "\n", $content_no_tags );
// we apply the shortcodes to make sure any membership restrictions work, but we omit the FV Player shortcodes as we want to parse these elsewhere
$content = str_replace( array('[fvplayer','[flowplayer'), '[noplayer', $content );
$content = do_shortcode($content);
$content = str_replace( '[noplayer', '[fvplayer', $content );
if( $meta = get_post_meta($objPost->ID, '_aioseop_description', true ) ) {
$description = $meta;
} else if( $meta = get_post_meta($objPost->ID, '_yoast_wpseo_metadesc', true ) ) {
$description = $meta;
} else if( $meta = get_post_meta($objPost->ID, '_genesis_description', true ) ) {
$description = $meta;
} else {
$description = !empty($objPost->post_excerpt) ? $objPost->post_excerpt : wp_trim_words( strip_shortcodes($objPost->post_content),10, '...');
}
$description = htmlspecialchars( $description,ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE );
foreach ( $matches AS $meta_key => $partial ) {
foreach ( $partial AS $key => $shortcode ) {
$count++;
$xml_video = array();
$increment_video_counter = false;
$aArgs = shortcode_parse_atts( rtrim( $shortcode, ']' ) );
global $FV_Player_Db;
if( !empty($FV_Player_Db) ) {
$aArgs = $FV_Player_Db->getPlayerAttsFromDb( $aArgs );
}
if( empty($aArgs['embed']) ) $aArgs['embed'] = '';
if( empty($aArgs['src']) || !empty($used_videos[$aArgs['src']]) ) continue;
$used_videos[$aArgs['src']] = true;
// this crazyness needs to be first converted into non-html characters (so " becomes "), then
// stripped of them all and returned back HTML-encoded for the XML formatting to be correct
$splash = false;
if( !empty($aArgs['poster']) ) $splash = $aArgs['poster'];
if( !empty($aArgs['splash']) ) $splash = $aArgs['splash'];
$splash = htmlspecialchars(trim(html_entity_decode($splash), "\n\t\r\0\x0B".'"'));
// make sure the URLs are absolute
if( $splash ) {
if( stripos($splash,'http://') !== 0 && stripos($splash,'https://') !== 0 && stripos($splash,'//') !== 0 ) {
$splash = home_url($splash);
} else if( stripos($splash,'//') === 0 ) {
$splash = 'http:'.$splash;
}
} else {
$splash = get_the_post_thumbnail_url( $objPost->ID, 'thumbnail' );
if( !$splash ) $splash = plugins_url('css/img/play_white.png', __DIR__);
}
// check for caption - if none present, build it up from page title and video position
// note: html characters must be substituted or enclosed in CDATA, from which the first
// is easier to do correctly on a single line
$sanitized_caption = !empty($aArgs['caption']) ? htmlspecialchars(strip_tags($aArgs['caption']), ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE ) : false;
$sanitized_src = htmlspecialchars(strip_tags(trim($aArgs['src'])), ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE );
// make sure the URLs are absolute
if( $sanitized_src ) {
if( stripos($sanitized_src,'http://') !== 0 && stripos($sanitized_src,'https://') !== 0 && stripos($sanitized_src,'//') !== 0 ) {
$sanitized_src = home_url($sanitized_src);
} else if( stripos($sanitized_src,'//') === 0 ) {
$sanitized_src = 'https:'.$sanitized_src;
}
}
// sanitized post title, used when no video caption is provided
$sanitized_page_title = htmlspecialchars(strip_tags($objPost->post_title), ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE );
// set thumbnail
$xml_video['thumbnail_loc'] = apply_filters( 'fv_player_sitemap_thumbnail', $splash, $aArgs['src'], $objPost->ID );
// set video title
if (!empty($sanitized_caption)) {
$title = $sanitized_caption;
} else if (!empty($sanitized_page_title)) {
$title = $sanitized_page_title;
} else {
$title = 'Video';
}
if( !empty($used_titles[$title]) ) {
$used_titles[$title]++;
$title .= ' '.$used_titles[$title];
} else {
$used_titles[$title] = 1;
}
$xml_video['title'] = $title;
// don't return empty descriptions (can happen if the video tag it the only thing on the page)
if( strlen(trim($description)) == 0 ) {
$description = $xml_video['title'];
}
$xml_video['description'] = $description;
// if description is already in use try to find the previous sentence
if( !empty($used_descriptions[$description]) ) {
$last = false;
foreach( $content_no_tags AS $p ) {
if( stripos($p,$shortcode) !== false ) break;
$last = trim( strip_shortcodes($p) );
}
if( $last ) {
$xml_video['description'] = wp_trim_words($last,20,'...');
} else {
$used_descriptions[$description]++;
$xml_video['description'] .= ' '.$used_descriptions[$description];
}
} else {
$used_descriptions[$description] = 1;
}
if( $aCategories = get_the_category($objPost->ID) ) {
$categories = implode(', ',wp_list_pluck($aCategories,'name'));
if( function_exists('mb_substr') ) {
$xml_video['category'] = mb_substr( $categories, 0, 250 );
} else {
$xml_video['category'] = substr( $categories, 0, 250 );
}
}
$xml_video['publication_date'] = get_the_date(DATE_W3C, $objPost->ID);
if ((strpos($aArgs['src'], '.') !== false) && ($extension = substr(strrchr($aArgs['src'], "."), 1)) && strlen($extension) < 10) {
// filename URL
$xml_video['content_loc'] = $sanitized_src;
} else if( $aArgs['embed'] == 'false' || $aArgs['embed'] == 'off' || ( $fv_fp->_get_option('disableembedding') && $aArgs['embed'] != 'true' ) ) {
continue;
} else {
if( $player = $fv_fp->current_player() ) {
$embed_id = 'fvp-'.$player->getId();
} else {
$embed_id = 'fvp';
if( $count > 1 ) $embed_id .= $count;
}
$xml_video['player_loc'] = user_trailingslashit( trailingslashit($permalink).$embed_id );
}
$xml_loc['video'][] = $xml_video;
}
}
if ( count($xml_loc['video']) > 0 ) {
$videos[] = $xml_loc;
}
}
return $videos;
}
function get_video_years() {
global $wpdb;
// grouped by year and month, each row is year, month, count
$years_and_months = $wpdb->get_results( "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts FROM $wpdb->posts WHERE post_type IN(\"".implode('", "', $this->get_post_types())."\") AND post_status = 'publish' AND (post_content LIKE '%[flowplayer %' OR post_content LIKE '%[fvplayer %') GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date;" );
if( $this->get_meta_keys() ) { // if we have some postmeta values to process
$years_and_months_meta = $wpdb->get_results( "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts FROM $wpdb->posts AS p JOIN $wpdb->postmeta AS m ON p.ID = m.post_id WHERE post_type IN('post') AND post_status = 'publish' AND meta_key IN (".$this->get_meta_keys('sql').") GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date;" );
if( $years_and_months_meta ) { // we have to marge these year, month, count rows into one array
$years = array(); // multidimensional array year => month => count
foreach( array_merge( $years_and_months, $years_and_months_meta ) AS $date ) {
if( empty($years[$date->year]) ) $years[$date->year] = array();
if( empty($years[$date->year][$date->month]) ) $years[$date->year][$date->month] = 0;
$years[$date->year][$date->month] += $date->posts;
}
ksort($years);
foreach( $years AS $k => $v ) {
ksort($v);
$years[$k] = $v;
}
$years_and_months = array(); // back to year, month, count rows
foreach( $years AS $k => $year ) {
foreach( $year AS $month => $count ) {
$years_and_months[] = (object) array( 'year' => $k, 'month' => $month, 'posts' => $count );
}
}
}
}
return $years_and_months;
}
function fv_check_xml_sitemap_rewrite_rules() {
global $wp_rewrite, $fv_fp;
$rules = get_option( 'rewrite_rules' );
$aRules = array(
'video-sitemap\.xml$' => 'index.php?feed=video-sitemap-index',
'video-sitemap\.(\d\d\d\d)-(\d\d)\.xml$' => 'index.php?feed=video-sitemap&fvp_sitemap_year=$matches[1]&fvp_sitemap_monthnum=$matches[2]',
'video-sitemap\.(\d\d\d\d)\.xml$' => 'index.php?feed=video-sitemap&fvp_sitemap_year=$matches[1]',
);
$aKeys = array_keys($aRules);
// flush rules if option is enabled and the second rewrite rule is not found or not matching
if( $fv_fp->_get_option('video_sitemap') &&
( !isset($rules[$aKeys[1]]) ||
$rules[$aKeys[1]] != $aRules[$aKeys[1]] )
) {
$wp_rewrite->flush_rules();
foreach( $aRules AS $rewrite => $vars ) {
add_rewrite_rule( $rewrite, $vars, 'top');
}
} else if( !$fv_fp->_get_option('video_sitemap') && // remove the rules if found
isset($rules[$aKeys[1]]) &&
$rules[$aKeys[1]] == $aRules[$aKeys[1]] ) {
$wp_rewrite->flush_rules();
}
}
function fv_generate_video_sitemap() {
global $fv_fp;
if( !$fv_fp->_get_option('video_sitemap') ) return;
// if output buffering is active, clear it
if ( ob_get_level() ) ob_clean();
if ( !headers_sent($filename, $linenum) ) {
status_header('200'); // force header('HTTP/1.1 200 OK') for sites without posts
header('Content-Type: text/xml; charset=' . get_bloginfo('charset'), true);
header('X-Robots-Tag: noindex, follow', true);
}
// This is to prevent issues with New Relics stupid auto injection of code.
if ( extension_loaded( 'newrelic' ) && function_exists( 'newrelic_disable_autorum' ) ) {
newrelic_disable_autorum();
}
$year = intval(get_query_var('fvp_sitemap_year'));
$month = intval(get_query_var('fvp_sitemap_monthnum'));
echo $this->fv_generate_video_sitemap_do( $year, $month );
}
function fv_generate_video_sitemap_do( $year, $month ) {
global $wpdb, $fv_wp_flowplayer_ver;
$date_query = false;
if( $year && $month ) {
$date_query = " year(post_date) = ".$year." AND month(post_date) = ".$month." AND ";
} else if( get_query_var('year') ) {
$date_query = " year(post_date) = ".$year." AND ";
}
$videos = $wpdb->get_results( "SELECT ID, post_content, post_title, post_excerpt, post_date, post_name, post_status, post_parent, post_type, guid FROM $wpdb->posts WHERE $date_query post_type IN(\"".implode('", "', $this->get_post_types())."\") AND post_status = 'publish' AND (post_content LIKE '%[flowplayer %' OR post_content LIKE '%[fvplayer %')" );
if( $this->get_meta_keys() ) {
$videos_meta = $wpdb->get_results( "SELECT ID, post_content, post_title, post_excerpt, post_date, post_name, post_status, post_parent, post_type, guid FROM $wpdb->posts AS p JOIN $wpdb->postmeta AS m ON p.ID = m.post_id WHERE $date_query post_type IN(\"".implode('", "', $this->get_post_types())."\") AND post_status = 'publish' AND meta_key IN (".$this->get_meta_keys('sql').")" );
$videos = array_merge($videos,$videos_meta);
}
$get_post_array = array();
foreach ($videos as $vid) {
$get_post_array[] = $vid;
}
$data = $this->get_video_details($get_post_array);
if (count($data)) {
echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>'."\n";
echo '<'.'?xml-stylesheet type="text/xsl" href="'.flowplayer::get_plugin_url().'/css/sitemap-video.xsl?ver='.$fv_wp_flowplayer_ver.'"?'.'>'."\n";
echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">'."\n";
foreach ($data as $xml_loc) {
echo "\t<url>\n";
echo "\t\t<loc>".$xml_loc['loc']."</loc>\n";
foreach ($xml_loc['video'] as $xml_video ) {
echo "\t\t<video:video>\n";
foreach( $xml_video AS $videoTag => $videoTagValue) {
echo "\t\t\t<video:$videoTag>$videoTagValue</video:$videoTag>\n";
}
echo "\t\t</video:video>\n";
}
echo "\t</url>\n";
}
echo "</urlset>\n";
echo "<!-- XML Sitemap generated by FV Player -->\n";
}
}
function fv_generate_video_sitemap_index() {
global $wpdb, $fv_wp_flowplayer_ver, $fv_fp;
if( !$fv_fp->_get_option('video_sitemap') ) return;
// if output buffering is active, clear it
if ( ob_get_level() ) ob_clean();
if ( !headers_sent($filename, $linenum) ) {
status_header('200'); // force header('HTTP/1.1 200 OK') for sites without posts
header('Content-Type: text/xml; charset=' . get_bloginfo('charset'), true);
header('X-Robots-Tag: noindex, follow', true);
}
// This is to prevent issues with New Relic's stupid auto injection of code.
if ( extension_loaded( 'newrelic' ) && function_exists( 'newrelic_disable_autorum' ) ) {
newrelic_disable_autorum();
}
$years = $this->get_video_years();
if( $years ) :
echo '<'.'?xml version="1.0" encoding="UTF-8"?'.'>'."\n";
echo '<'.'?xml-stylesheet type="text/xsl" href="'.flowplayer::get_plugin_url().'/css/sitemap-index.xsl?ver='.$fv_wp_flowplayer_ver.'"?'.'>'."\n";
?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd">
<?php foreach( $years AS $objYear ) :
$filename = $objYear->year;
if( !empty($objYear->month) ) {
$filename .= '-';
if( strlen($objYear->month) == 1 ) $filename .= '0';
$filename .= $objYear->month;
}
$date_query = !empty($objYear->month) ? " AND month(post_date) = ".intval($objYear->month) : false;
$last_modified = $wpdb->get_var( "SELECT post_modified_gmt FROM $wpdb->posts WHERE post_type IN(\"".implode('", "', $this->get_post_types())."\") AND post_status = 'publish' AND (post_content LIKE '%[flowplayer %' OR post_content LIKE '%[fvplayer %') AND year(post_date) = ".intval($objYear->year)." $date_query ORDER BY post_modified_gmt DESC LIMIT 1" );
if( $this->get_meta_keys() ) {
$last_modified_meta = $wpdb->get_var( "SELECT post_modified_gmt FROM $wpdb->posts AS p JOIN $wpdb->postmeta AS m ON p.ID = m.post_id WHERE post_type IN(\"".implode('", "', $this->get_post_types())."\") AND post_status = 'publish' AND meta_key IN (".$this->get_meta_keys('sql').") AND year(post_date) = ".intval($objYear->year)." $date_query ORDER BY post_modified_gmt DESC LIMIT 1" );
if( strtotime($last_modified_meta) > strtotime($last_modified) ) $last_modified = $last_modified_meta;
}
?>
<sitemap>
<loc><?php echo home_url('/video-sitemap.'.$filename.'.xml'); ?></loc>
<lastmod><?php echo mysql2date('Y-m-d\TH:i:s+00:00', $last_modified, false); ?></lastmod>
</sitemap>
<?php endforeach; ?>
</sitemapindex><!-- XML Sitemap generated by FV Player -->
<?php
endif;
}
function options() {
global $fv_fp;
$fv_fp->_get_checkbox(__('Use XML Video Sitemap', 'fv-wordpress-flowplayer'), 'video_sitemap', sprintf( __('Creates <code>%s</code> which you can submit via Google Webmaster Tools.', 'fv-wordpress-flowplayer'), home_url('video-sitemap.xml') ), __('As feeds tend to be cached by web browser make sure you clear your browser cache if you are doing some testing.', 'fv-wordpress-flowplayer') );
if( $fv_fp->_get_option('disableembedding') ) : ?>
<tr>
<td></td>
<td><strong>Note:</strong> Since <a href="#fv_flowplayer_default_options">Disable Embed Button</a> setting is on the video sitemap can only present the bare MP4 or HLS videos. Disable that option to make it show your other video types too.</td>
</tr>
<?php endif;
$fv_fp->_get_input_text( array( 'name' => __('Sitemap Post Meta', 'fv-wordpress-flowplayer'), 'key' => 'video_sitemap_meta', 'help' => __('You can enter post meta keys here, use <code>,</code> to separate multiple values.', 'fv-wordpress-flowplayer') ) );
}
function redirect_canonical( $redirect ) {
if( get_query_var('fvp_sitemap_year') || get_query_var('fvp_sitemap_monthnum') || get_query_var('feed') && get_query_var('feed') == 'video-sitemap-index' ) {
return false;
}
return $redirect;
}
function settings_save( $settings ) {
if( !empty($_POST['video_sitemap_meta']) ) {
$settings['video_sitemap_meta'] = trim( preg_replace( '~[^A-Za-z0-9.:\-_\/,]~', '', $_POST['video_sitemap_meta']) );
}
return $settings;
}
function strip_membership_content( $content ) {
$content = preg_replace( '~\[is_paid[\s\S]*?\[/is_paid\]~', '', $content );
$content = preg_replace( '~\[restrict[\s\S]*?\[/restrict\]~', '', $content );
$content = preg_replace( '~\[am4show[\s\S]*?\[/am4show\]~', '', $content );
return $content;
}
}
global $FV_Xml_Video_Sitemap;
$FV_Xml_Video_Sitemap = new FV_Xml_Video_Sitemap();