ID ) ) ) {
$blog_page = get_post( $page_for_posts );
}
}
return $blog_page;
}
/**
* @param string $location
* @param string $title
* @param string $anchor
* @param string $target
* @param string $class
* @param string $id
*
* @return string
*/
static function get_upgrade_hyperlink( $location = '', $title = '', $anchor = '', $target = '', $class = '', $id = 'aio-pro-update' ) {
$affiliate_id = '';
// call during plugins_loaded
$affiliate_id = apply_filters( 'aiosp_aff_id', $affiliate_id );
// build URL
$url = 'https://semperplugins.com/all-in-one-seo-pack-pro-version/';
if ( $location ) {
$url .= '?loc=' . $location;
}
if ( $affiliate_id ) {
$url .= "?ap_id=$affiliate_id";
}
// build hyperlink
$hyperlink = '$anchor";
return $hyperlink;
}
/**
* Gets the upgrade to Pro version URL.
*/
static function get_upgrade_url() {
// put build URL stuff in here
}
/**
* Check whether a url is relative and if it is, make it absolute.
*
* @param string $url URL to check.
*
* @return string
*/
static function absolutize_url( $url ) {
if ( 0 !== strpos( $url, 'http' ) && '/' !== $url ) {
if ( 0 === strpos( $url, '//' ) ) {
// for ///resource type urls.
$scheme = parse_url( home_url(), PHP_URL_SCHEME );
$url = $scheme . ':' . $url;
} else {
// for /resource type urls.
$url = home_url( $url );
}
}
return $url;
}
/**
* Check whether a url is relative (does not contain a . before the first /) or absolute and makes it a valid url.
*
* @param string $url URL to check.
*
* @return string
*/
static function make_url_valid_smartly( $url ) {
$scheme = parse_url( home_url(), PHP_URL_SCHEME );
if ( 0 !== strpos( $url, 'http' ) ) {
if ( 0 === strpos( $url, '//' ) ) {
// for ///resource type urls.
$url = $scheme . ':' . $url;
} elseif ( strpos( $url, '.' ) !== false && strpos( $url, '/' ) !== false && strpos( $url, '.' ) < strpos( $url, '/' ) ) {
// if the . comes before the first / then this is absolute.
$url = $scheme . '://' . $url;
} else {
// for /resource type urls.
$url = home_url( $url );
}
} else if ( strpos( $url, 'http://' ) === false ) {
if ( 0 === strpos( $url, 'http:/' ) ) {
$url = $scheme . '://' . str_replace( 'http:/', '', $url );
} else if ( 0 === strpos( $url, 'http:' ) ) {
$url = $scheme . '://' . str_replace( 'http:', '', $url );
}
}
return $url;
}
/**
* Determines if the given image URL is an attachment and, if it is, gets the correct image URL according to the requested size.
*
* @param string $url The url of the image.
* @param string $size The size of the image to return.
*
* @return string
*/
public static function get_image_src_for_url( $url, $size = 'thumbnail' ) {
// let's check if this image is an attachment.
$dir = wp_get_upload_dir();
$path = $url;
$site_url = parse_url( $dir['url'] );
$image_path = parse_url( $path );
//force the protocols to match if needed
if ( isset( $image_path['scheme'] ) && ( $image_path['scheme'] !== $site_url['scheme'] ) ) {
$path = str_replace( $image_path['scheme'], $site_url['scheme'], $path );
}
if ( 0 === strpos( $path, $dir['baseurl'] . '/' ) ) {
$path = substr( $path, strlen( $dir['baseurl'] . '/' ) );
}
global $wpdb;
$attachment_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attachment_metadata' AND meta_value LIKE %s", '%' . basename( $path ) . '%' ) );
if ( $attachment_id ) {
$size = apply_filters( 'aioseop_attachment_size', apply_filters( 'aioseop_thumbnail_size', apply_filters( 'post_thumbnail_size', $size ) ) );
// if this is a valid attachment, get the correct size.
$image = wp_get_attachment_image_src( $attachment_id, $size );
if ( $image ) {
$url = $image[0];
}
}
return $url;
}
/**
* Fetch images from WP, Jetpack and WooCommerce galleries.
*
* @param string $post The post.
* @param array $images the array of images.
*
* @return void
* @since 2.4.2
*/
public static function get_gallery_images( $post, &$images ) {
if ( false === apply_filters( 'aioseo_include_images_in_wp_gallery', true ) ) {
return;
}
// Check images galleries in the content. DO NOT run the_content filter here as it might cause issues with other shortcodes.
if ( has_shortcode( $post->post_content, 'gallery' ) ) {
// Get the jetpack gallery images.
if ( class_exists( 'Jetpack_PostImages' ) ) {
// the method specifies default width and height so we need to provide these values to override the defaults.
// since there is no way to determine the original image's dimensions, we will fetch the 'large' size image here.
$jetpack = Jetpack_PostImages::get_images( $post->ID, self::get_dimensions_for_image_size( 'large' ) );
if ( $jetpack ) {
foreach ( $jetpack as $jetpack_image ) {
$images[] = $jetpack_image['src'];
}
}
}
// Get the default WP gallery images.
$galleries = get_post_galleries( $post, false );
if ( $galleries ) {
foreach ( $galleries as $gallery ) {
$images = array_merge( $images, $gallery['src'] );
}
}
}
// Check WooCommerce product gallery.
if ( class_exists( 'WooCommerce' ) ) {
$woo_images = get_post_meta( $post->ID, '_product_image_gallery', true );
if ( ! empty( $woo_images ) ) {
$woo_images = array_filter( explode( ',', $woo_images ) );
if ( is_array( $woo_images ) ) {
foreach ( $woo_images as $id ) {
$images[] = wp_get_attachment_url( $id );
}
}
}
}
$images = array_unique( $images );
}
/**
* Fetch the width and height for the specified image size.
*
* @param string $size The image size e.g. 'large', 'medium' etc.
*
* @since 2.4.3
*/
private function get_dimensions_for_image_size( $size ) {
$sizes = get_intermediate_image_sizes();
if ( ! in_array( $size, $sizes, true ) ) {
// our specified size does not exist in the registered sizes, so let's use the largest one available.
$size = end( $sizes );
}
if ( $size ) {
return array(
'width' => get_option( "{$size}_size_w" ),
'height' => get_option( "{$size}_size_h" ),
);
}
return null;
}
/**
* Parses the content to find out if specified images galleries exist and if they do, parse them for images.
* Supports NextGen.
*
* @param string $content The post content.
*
* @since 2.4.2
*
* @return string
*/
public static function get_content_from_galleries( $content ) {
// Support for NextGen Gallery.
static $gallery_types = array( 'ngg_images' );
$types = apply_filters( 'aioseop_gallery_shortcodes', $gallery_types );
$gallery_content = '';
if ( ! $types ) {
return $gallery_content;
}
$found = array();
if ( $types ) {
foreach ( $types as $type ) {
if ( has_shortcode( $content, $type ) ) {
$found[] = $type;
}
}
}
// If none of the shortcodes-of-interest are found, bail.
if ( empty( $found ) ) {
return $gallery_content;
}
$galleries = array();
if ( ! preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER ) ) {
return $gallery_content;
}
// Collect the shortcodes and their attributes.
foreach ( $found as $type ) {
foreach ( $matches as $shortcode ) {
if ( $type === $shortcode[2] ) {
$attributes = shortcode_parse_atts( $shortcode[3] );
if ( '' === $attributes ) { // Valid shortcode without any attributes.
$attributes = array();
}
$galleries[ $shortcode[2] ] = $attributes;
}
}
}
// Recreate the shortcodes and then render them to get the HTML content.
if ( $galleries ) {
foreach ( $galleries as $shortcode => $attributes ) {
$code = '[' . $shortcode;
foreach ( $attributes as $key => $value ) {
$code .= " $key=$value";
}
$code .= ']';
$gallery_content .= do_shortcode( $code );
}
}
return $gallery_content;
}
/**
* Parses the content of the post provided for images and galleries.
*
* @param WP_Post $post The post to parse.
* @return array
*/
public static function parse_content_for_images( WP_Post $post ) {
$images = array();
$content = $post->post_content;
self::get_gallery_images( $post, $images );
$content .= self::get_content_from_galleries( $content );
self::parse_dom_for_images( $content, $images );
return $images;
}
/**
* Parse the post for images.
*
* @param string $content the post content.
* @param array $images the array of images.
*
* @return void
*/
public static function parse_dom_for_images( $content, &$images ) {
// These tags should be WITHOUT trailing space because some plugins such as the nextgen gallery put newlines immediately after loadHTML( $content );
libxml_clear_errors();
$dom->preserveWhiteSpace = false;
$matches = $dom->getElementsByTagName( 'img' );
foreach ( $matches as $match ) {
$images[] = $match->getAttribute( 'src' );
}
} else {
// Fall back to regex, but also report an error.
global $img_err_msg;
if ( ! isset( $img_err_msg ) ) {
// we will log this error message only once, not per post.
$img_err_msg = true;
aiosp_log( 'DOMDocument not found; using REGEX' );
}
preg_match_all( '/get_col( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid='%s';", $url ) );
if ( $attachment && is_array( $attachment ) && is_numeric( $attachment[0] ) ) {
$attributes = array(
'image:caption' => self::get_image_caption( $attachment[0] ),
'image:title' => get_the_title( $attachment[0] ),
);
}
return $attributes;
}
/**
* Wrapper around `wp_get_attachment_caption` because it was introduced only in WP 4.6.0.
*
* @param int $attachment_id The attachment ID.
*/
public static function get_image_caption( $attachment_id ) {
global $wp_version;
if ( version_compare( $wp_version, '4.6.0', '<' ) ) {
$post_id = (int) $attachment_id;
if ( ! $post = get_post( $post_id ) ) {
return false;
}
if ( 'attachment' !== $post->post_type ) {
return false;
}
$caption = $post->post_excerpt;
return apply_filters( 'wp_get_attachment_caption', $caption, $post->ID );
}
return wp_get_attachment_caption( $attachment_id );
}
/**
* Cleans the URL so that its acceptable in the sitemap.
*
* @param string $url The image url.
*
* @since 2.4.1
*
* @return string
*/
public static function clean_url( $url ) {
// remove the query string.
$url = strtok( $url, '?' );
// make the url XML-safe.
$url = htmlspecialchars( $url );
// Make the url absolute, if its relative.
$url = aiosp_common::absolutize_url( $url );
return apply_filters( 'aioseop_clean_url', $url );
}
/**
* Validate the image.
* NOTE: We will use parse_url here instead of wp_parse_url as we will correct the URLs beforehand and
* this saves us the need to check PHP version support.
*
* @param string $image The image src.
*
* @since 2.4.1
* @since 2.4.3 Compatibility with Pre v4.7 wp_parse_url().
*
* @return bool
*/
public static function is_image_valid( $image ) {
global $wp_version;
// Bail if empty image.
if ( empty( $image ) ) {
return false;
}
global $wp_version;
if ( version_compare( $wp_version, '4.4', '<' ) ) {
$p_url = parse_url( $image );
$url = $p_url['scheme'] . $p_url['host'] . $p_url['path'];
} elseif ( version_compare( $wp_version, '4.7', '<' ) ) {
// Compatability for older WP version that don't have 4.7 changes.
// @link https://core.trac.wordpress.org/changeset/38726
$p_url = wp_parse_url( $image );
$url = $p_url['scheme'] . $p_url['host'] . $p_url['path'];
} else {
$component = PHP_URL_PATH;
$url = wp_parse_url( $image, $component );
}
// make the url absolute, if its relative.
$image = aiosp_common::absolutize_url( $image );
$extn = pathinfo( parse_url( $image, PHP_URL_PATH ), PATHINFO_EXTENSION );
$allowed = apply_filters( 'aioseop_allowed_image_extensions', self::$image_extensions );
// Bail if image does not refer to an image file otherwise google webmaster tools might reject the sitemap.
if ( ! in_array( $extn, $allowed, true ) ) {
return false;
}
$image_host = parse_url( $image, PHP_URL_HOST );
$host = parse_url( home_url(), PHP_URL_HOST );
if ( $image_host !== $host ) {
// Allowed hosts will be provided in a wildcard format i.e. img.yahoo.* or *.akamai.*.
// And we will convert that into a regular expression for matching.
$whitelist = apply_filters( 'aioseop_images_allowed_from_hosts', array() );
$allowed = false;
if ( $whitelist ) {
foreach ( $whitelist as $pattern ) {
if ( preg_match( '/' . str_replace( '*', '.*', $pattern ) . '/', $image_host ) === 1 ) {
$allowed = true;
break;
}
}
}
return $allowed;
}
return true;
}
/**
* Check whether a url is valid.
*
* @param string $url URL to check.
*
* @return bool
*/
public static function is_url_valid( $url ) {
return filter_var( filter_var( $url, FILTER_SANITIZE_URL ), FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED ) !== false;
}
}