| Current Path : /home/ereika83/public_html/wp-content/plugins/squirrly-seo/models/services/ |
| Current File : /home/ereika83/public_html/wp-content/plugins/squirrly-seo/models/services/JsonLD.php |
<?php
defined( 'ABSPATH' ) || die( 'Cheatin\' uh?' );
class SQ_Models_Services_JsonLD extends SQ_Models_Abstract_Seo {
private $_data = array();
private $_types = array();
private $_markups = array();
public function __construct() {
parent::__construct();
if ( isset( $this->_post->sq->doseo ) && $this->_post->sq->doseo ) {
if ( ! $this->_post->sq->do_jsonld ) {
add_filter( 'sq_json_ld', array( $this, 'returnFalse' ) );
return;
}
//decode the URL for json format
if ( $this->_post->url ) {
$this->_post->url = urldecode( esc_url( $this->_post->url ) );
}
//If not yet set
$this->_post->sq->jsonld_types = array_filter( (array) $this->_post->sq->jsonld_types );
if ( empty( $this->_post->sq->jsonld_types ) ) {
//If not set, get the type saved by Open Graph
if ( $this->_post->sq->og_type <> '' ) {
$this->_post->sq->jsonld_types = array( $this->_post->sq->og_type );
}
}
if ( ! empty( $this->_post->sq->jsonld_types ) ) {
add_filter( 'sq_json_ld', array( $this, 'generateStructuredData' ) );
add_filter( 'sq_json_ld', array( $this, 'generateJsonLd' ) );
add_filter( 'sq_json_ld', array( $this, 'packJsonLd' ), 99 );
}
} else {
add_filter( 'sq_json_ld', array( $this, 'returnFalse' ) );
}
}
/**
* Sanitizes, encodes and outputs structured data.
*
* @return array|string
*/
public function generateJsonLd() {
return $this->clean( $this->getStructuredData( $this->getDataTypes() ) );
}
/**
* Pack the Structured Data
*/
public function packJsonLd( $data = array() ) {
if ( ! empty( $data ) ) {
//If custom JSON-LD and not Auto Draft
if ( $this->_post->sq->jsonld && strpos( $this->_post->sq->jsonld, '"name":"Auto Draft"' ) === false ) {
//If contains script, return the custom jsonld
if ( strpos( $this->_post->sq->jsonld, 'application/ld+json' ) !== false ) {
return $this->_post->sq->jsonld;
}
return '<script type="application/ld+json">' . $this->_post->sq->jsonld . '</script>';
} else {
//Compatibility with ACF
if ( SQ_Classes_Helpers_Tools::isPluginInstalled( 'advanced-custom-fields/acf.php' ) ) {
if ( isset( $this->_post->ID ) && $this->_post->ID ) {
if ( $_sq_jsonld_custom = get_post_meta( $this->_post->ID, '_sq_jsonld_custom', true ) ) {
if ( strpos( $_sq_jsonld_custom, 'application/ld+json' ) !== false ) {
return $_sq_jsonld_custom;
} else {
return '<script type="application/ld+json">' . $_sq_jsonld_custom . '</script>';
}
}
}
}
return '<script type="application/ld+json">' . wp_json_encode( $data, SQ_DEBUG && ! SQ_Classes_Helpers_Tools::isAjax() ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES : JSON_UNESCAPED_SLASHES ) . '</script>';
}
}
return false;
}
/**
* Sets data.
*
* @param array $data Structured data.
* @param bool $reset Unset data (default: false).
*
* @return bool
*/
public function setData( $data, $reset = false ) {
if ( ! isset( $data['@type'] ) || ! preg_match( '|^[a-zA-Z]{1,20}$|', $data['@type'] ) ) {
return false;
} else {
if ( $data['@type'] <> 'Review' && in_array( strtolower( $data['@type'] ), $this->_types ) ) {
return false;
}
$this->_types[] = strtolower( $data['@type'] );
}
if ( $reset && isset( $this->_data ) ) {
unset( $this->_data );
}
$this->_data[] = $data;
return true;
}
/**
* Gets data.
*
* @return array
*/
public function getData() {
return apply_filters( 'sq_json_ld_data', $this->_data );
}
/**
* Structures and returns data.
*
* List of types available by default for specific request:
*
* 'product',
* 'review',
* 'breadcrumblist',
* 'website',
* 'order',
*
* @param array $types Structured data types.
*
* @return array
*/
public function getStructuredData( $types ) {
$data = array();
// Put together the values of same type of structured data.
foreach ( $this->getData() as $type => $value ) {
if ( is_numeric( $type ) ) {
$data[ $value['@type'] ][] = $value;
$data[ strtolower( $value['@type'] ) ][] = $value;
} else {
$data[ $type ][] = $value;
}
}
//mage array unique
$types = array_unique( $types );
// Wrap the multiple values of each type inside a graph... Then add context to each type.
foreach ( $data as $type => $value ) {
$data[ $type ] = count( (array) $value ) > 1 ? array( '@graph' => $value ) : $value[0];
}
// If requested types, pick them up... Finally, change the associative array to an indexed one.
$data = $types ? array_values( array_intersect_key( $data, array_flip( $types ) ) ) : array_values( $data );
if ( ! empty( $data ) ) {
$data = array( '@context' => 'https://schema.org', '@graph' => $data );
}
return $data;
}
/**
* Get data types for pages.
*
* @return array
*/
public function getDataTypes() {
return array_filter( apply_filters( 'sq_structured_data_type_for_page', $this->_types ) );
}
/**
* Make sure the data is sanitized
*
* @param $var
*
* @return array|string
*/
public function clean( $var ) {
if ( is_array( $var ) ) {
return array_map( array( $this, 'clean' ), $var );
} else {
return is_scalar( $var ) ? sanitize_text_field( $var ) : $var;
}
}
/**
* Set custom JsonLD from database postmeta
*
* @param $markup
* @param $post
* @param $type
*
* @return mixed
*/
public function setCustomJsonLd( $markup, $post, $type ) {
//Custom jsonld for this post id
$sq_jsonld = get_post_meta( $post->ID, '_sq_jsonld_builder', true );
if ( is_string( $sq_jsonld ) && ! empty( $sq_jsonld ) ) {
$sq_jsonld = json_decode( $sq_jsonld, true );
}
if ( ! empty( $sq_jsonld ) && isset( $sq_jsonld[ strtolower( $type ) ] ) ) {
foreach ( $sq_jsonld[ strtolower( $type ) ] as $key => $value ) {
if ( is_array( $value ) ) {
$value = @array_filter( $value );
if ( empty( $value ) ) {
continue;
}
foreach ( $value as $index => $value1 ) {
if ( is_array( $value1 ) ) {
$value1 = @array_filter( $value1 );
if ( empty( $value1 ) ) {
unset( $value[ $index ] );
}
}
}
if ( count( $value ) == 1 ) {
continue;
}
//don't let numeric indexing
if ( current( array_keys( $value ) ) == 0 ) {
$value = array_values( $value );
}
}
if ( $value ) {
$markup[ $key ] = $value;
}
}
}
return $markup;
}
/**
* Generate JSON-LD Structured data based on jsonld types and post type
*/
public function generateStructuredData() {
if ( $this->_post->post_type == 'home' ) {
$jsonld_type = SQ_Classes_Helpers_Tools::getOption( 'sq_jsonld_type' );
$this->_markups[] = $this->getPublisherMarkup( $jsonld_type );
}
if ( in_array( 'website', $this->_post->sq->jsonld_types ) ) {
$this->_markups[] = $this->getWebsiteMarkup();
}
if ( in_array( 'newsarticle', $this->_post->sq->jsonld_types ) ) {
$this->_markups[] = $this->getArticleMarkup( 'NewsArticle' );
}
if ( in_array( 'article', $this->_post->sq->jsonld_types ) ) {
$this->_markups[] = $this->getArticleMarkup( 'Article' );
}
if ( in_array( 'QA Page', $this->_post->sq->jsonld_types ) ) {
$this->_markups[] = $this->getQAMarkup();
}
if ( in_array( 'question', $this->_post->sq->jsonld_types ) || in_array( 'FAQ page', $this->_post->sq->jsonld_types ) ) {
$this->_markups[] = $this->getQuestionMarkup();
}
if ( in_array( 'movie', $this->_post->sq->jsonld_types ) ) {
$this->_markups[] = $this->getMovieMarkup();
}
if ( in_array( 'video', $this->_post->sq->jsonld_types ) ) {
$this->_markups[] = $this->getVideoMarkup();
}
if ( in_array( 'recipe', $this->_post->sq->jsonld_types ) ) {
$this->_markups[] = $this->getRecipeMarkup();
}
if ( in_array( 'review', $this->_post->sq->jsonld_types ) ) {
$this->_markups[] = $this->getReviewMarkup();
}
if ( in_array( 'local store', $this->_post->sq->jsonld_types ) ) {
$this->_markups[] = $this->getLocalBusinessMarkup( 'Store' );
}
if ( in_array( 'local restaurant', $this->_post->sq->jsonld_types ) ) {
$this->_markups[] = $this->getLocalBusinessMarkup( 'Restaurant' );
}
if ( $this->_post->post_type == 'profile' || in_array( 'profile', $this->_post->sq->jsonld_types ) ) {
if ( $this->_post->post_author <> '' ) {
$markup['@type'] = 'Person';
$markup['@id'] = $this->getAuthor( 'user_url' ) . '#person';
$markup['url'] = $this->getAuthor( 'user_url' );
$markup['name'] = $this->cleanText( $this->getAuthor( 'display_name' ) );
$this->_markups[] = $markup;
}
}
if ( SQ_Classes_Helpers_Tools::getOption( 'sq_jsonld_woocommerce' ) ) {
if ( SQ_Classes_Helpers_Tools::isPluginInstalled( 'woocommerce/woocommerce.php' ) ) {
// Generate structured data for Woocommerce 3+.
if ( $this->_post->post_type == 'product' || in_array( 'product', $this->_post->sq->jsonld_types ) ) {
$this->_markups[] = $this->getWoocommerceProductMarkup();
}
}
}
if ( SQ_Classes_Helpers_Tools::getOption( 'sq_jsonld_breadcrumbs' ) ) {
$this->_markups[] = $this->getBreadcrumbsMarkup();
}
//register the markup
foreach ( $this->_markups as $markup ) {
$this->setData( $markup );
}
}
public function cleanText( $text ) {
$text = str_replace( array( '"', '“', '”' ), '"', $text );
return $text;
}
/**
* Set the markup for the Article, NewsArticle Schema
*
* @param $post_type
*
* @return mixed
*/
public function getArticleMarkup( $post_type ) {
$markup = array();
$markup['@type'] = $post_type;
$markup['@id'] = $this->_post->url . '#' . strtolower( $post_type );
$markup['url'] = $this->_post->url;
if ( isset( $this->_post->sq->title ) ) {
$markup['headline'] = $this->cleanText( $this->truncate( $this->_post->sq->title, 0, $this->_post->sq->jsonld_title_maxlength ) );
}
$markup['mainEntityOfPage'] = array(
'@type' => 'WebPage',
'url' => $this->_post->url
);
if ( $this->_post->sq->og_media <> '' ) {
$markup['thumbnailUrl'] = $this->_post->sq->og_media;
}
if ( isset( $this->_post->post_date ) ) {
$markup['datePublished'] = gmdate( 'c', strtotime( $this->_post->post_date ) );
}
if ( isset( $this->_post->post_modified ) ) {
$markup['dateModified'] = gmdate( 'c', strtotime( $this->_post->post_modified ) );
}
if ( $this->_post->sq->og_media <> '' ) {
$markup['image'] = array(
"@type" => "ImageObject",
"url" => $this->_post->sq->og_media,
"height" => 500,
"width" => 500,
);
} else {
$this->_setMedia( $markup );
}
$markup['author'] = $this->getAuthorMarkup();
if ( $publisher = $this->getPublisherMarkup( 'Organization' ) ) {
$markup['publisher'] = $publisher;
}
if ( $this->_post->sq->keywords <> '' ) {
$markup['keywords'] = $this->_post->sq->keywords;
}
return apply_filters( 'sq_jsonld_article_markup', $markup, $this->_post, $post_type );
}
/**
* Get Question Markup
*
* @return mixed
*/
public function getQAMarkup() {
$type = 'QAPage';
$markup = array();
$markup['@type'] = $type;
$markup['@id'] = $this->_post->url . '#' . strtolower( $type );
$markup['url'] = $this->_post->url;
if ( isset( $this->_post->sq->title ) && isset( $this->_post->sq->description ) ) {
$markup['mainEntity'][] = array(
"@type" => "Question",
"name" => $this->cleanText( $this->_post->sq->title ),
"text" => $this->cleanText( $this->_post->sq->title ),
"answerCount" => 1,
"upvoteCount" => 0,
"dateCreated" => gmdate( 'c', strtotime( $this->_post->post_date ) ),
"author" => $this->getAuthorMarkup(),
"acceptedAnswer" => array(
"@type" => "Answer",
"text" => $this->cleanText( $this->_post->sq->description ),
"upvoteCount" => 0,
"url" => $this->_post->url,
"author" => $this->getAuthorMarkup(),
"dateCreated" => gmdate( 'c', strtotime( $this->_post->post_date ) ),
)
);
}
return apply_filters( 'sq_jsonld_' . strtolower( $type ) . '_markup', $markup, $this->_post, $type );
}
/**
* Get Question Markup
*
* @return mixed
*/
public function getQuestionMarkup() {
$type = 'FAQPage';
$markup = array();
$markup['@type'] = $type;
$markup['@id'] = $this->_post->url . '#' . strtolower( $type );
$markup['url'] = $this->_post->url;
if ( isset( $this->_post->sq->title ) && isset( $this->_post->sq->description ) ) {
$markup['mainEntity'][] = array(
"@type" => "Question",
"name" => $this->cleanText( $this->truncate( $this->_post->sq->title, 0, $this->_post->sq->jsonld_title_maxlength ) ),
"acceptedAnswer" => array(
"@type" => "Answer",
"text" => $this->cleanText( $this->truncate( $this->_post->sq->description, 0, $this->_post->sq->jsonld_description_maxlength ) ),
)
);
}
return apply_filters( 'sq_jsonld_' . strtolower( $type ) . '_markup', $markup, $this->_post, $type );
}
/**
* Get Movie Markup
*
* @return mixed
*/
public function getVideoMarkup() {
$markup = array();
$type = 'VideoObject';
if ( $videos = $this->getPostVideos() ) {
$markup['@type'] = $type;
$markup['@id'] = $this->_post->url . '#' . strtolower( $type );
$markup['url'] = $this->_post->url;
if ( isset( $this->_post->sq->title ) ) {
$markup['name'] = $this->cleanText( $this->truncate( $this->_post->sq->title, 0, $this->_post->sq->jsonld_title_maxlength ) );
}
if ( isset( $this->_post->sq->description ) ) {
$markup['description'] = $this->cleanText( $this->truncate( $this->_post->sq->description, 0, $this->_post->sq->jsonld_description_maxlength ) );
}
if ( isset( $this->_post->post_date ) ) {
$markup['uploadDate'] = gmdate( 'c', strtotime( $this->_post->post_date ) );
}
if ( ! empty( $videos ) ) {
foreach ( $videos as $index => $video ) {
if ( $video['src'] <> '' ) {
$markup['thumbnailUrl'] = array(
$video['thumbnail']
);
$markup['embedUrl'] = $video['src'];
}
}
}
$markup['publisher'] = $this->getPublisherMarkup( 'Organization' );
}
return apply_filters( 'sq_jsonld_' . strtolower( $type ) . '_markup', $markup, $this->_post, $type );
}
/**
* Get Movie Markup
*
* @return mixed
*/
public function getMovieMarkup() {
$type = 'Movie';
$markup = array();
$markup['@type'] = $type;
$markup['@id'] = $this->_post->url . '#' . strtolower( $type );
$markup['url'] = $this->_post->url;
if ( isset( $this->_post->sq->title ) ) {
$markup['name'] = $this->cleanText( $this->truncate( $this->_post->sq->title, 0, $this->_post->sq->jsonld_title_maxlength ) );
}
if ( isset( $this->_post->sq->description ) ) {
$markup['description'] = $this->cleanText( $this->truncate( $this->_post->sq->description, 0, $this->_post->sq->jsonld_description_maxlength ) );
}
if ( isset( $this->_post->post_date ) ) {
$markup['dateCreated'] = gmdate( 'c', strtotime( $this->_post->post_date ) );
}
if ( $this->_post->sq->og_media <> '' ) {
$markup['image'] = array(
"@type" => "ImageObject",
"url" => $this->_post->sq->og_media,
"height" => 500,
"width" => 500,
);
} else {
$this->_setMedia( $markup );
}
$markup['director'] = $this->getAuthorMarkup();
$markup['publisher'] = $this->getPublisherMarkup( 'Organization' );
return apply_filters( 'sq_jsonld_' . strtolower( $type ) . '_markup', $markup, $this->_post, $type );
}
/**
* Get Recipe Markup
*
* @return mixed
*/
public function getRecipeMarkup() {
$type = 'Recipe';
$markup = array();
$markup['@type'] = $type;
$markup['@id'] = $this->_post->url . '#' . strtolower( $type );
$markup['url'] = $this->_post->url;
if ( isset( $this->_post->sq->title ) ) {
$markup['name'] = $this->cleanText( $this->truncate( $this->_post->sq->title, 0, $this->_post->sq->jsonld_title_maxlength ) );
$markup['headline'] = $this->cleanText( $this->truncate( $this->_post->sq->title, 0, $this->_post->sq->jsonld_title_maxlength ) );
$markup['keywords'] = $this->cleanText( $this->truncate( $this->_post->sq->title, 0, $this->_post->sq->jsonld_title_maxlength ) );
}
if ( isset( $this->_post->sq->description ) ) {
$markup['description'] = $this->cleanText( $this->truncate( $this->_post->sq->description, 0, $this->_post->sq->jsonld_description_maxlength ) );
}
if ( isset( $this->_post->post_date ) ) {
$markup['datePublished'] = gmdate( 'c', strtotime( $this->_post->post_date ) );
}
if ( $this->_post->sq->og_media <> '' ) {
$markup['image'] = array(
"@type" => "ImageObject",
"url" => $this->_post->sq->og_media,
"height" => 500,
"width" => 500,
);
} else {
$this->_setMedia( $markup );
}
$markup['mainEntityOfPage'] = array(
'@type' => 'WebPage',
'url' => $this->_post->url
);
$markup['prepTime'] = 'PT10M';
$markup['cookTime'] = 'PT20M';
$markup['totalTime'] = 'PT30M';
$markup['nutrition'] = array(
'@type' => 'NutritionInformation',
'calories' => '0 calories'
);
if ( $this->_post->sq->keywords <> '' ) {
$markup['keywords'] = $this->_post->sq->keywords;
}
if ( $videos = $this->getPostVideos() ) {
foreach ( $videos as $index => $video ) {
if ( $video['src'] <> '' ) {
$markup['video'] = array(
"@type" => "VideoObject",
"embedUrl" => $videos['src'],
"name" => ( isset( $markup['name'] ) ? $markup['name'] : '' ),
"description" => ( isset( $markup['description'] ) ? $markup['description'] : '' ),
"thumbnailUrl" => array(
$video['thumbnail']
),
"height" => 500,
"width" => 500,
);
break;
}
}
}
$markup['author'] = $this->getAuthorMarkup();
$markup['publisher'] = $this->getPublisherMarkup( 'Organization' );
if ( $this->_post->sq->keywords <> '' ) {
$markup['keywords'] = $this->_post->sq->keywords;
}
return apply_filters( 'sq_jsonld_' . strtolower( $type ) . '_markup', $markup, $this->_post, $type );
}
/**
* Get Review Markup
*
* @param array $reviewObject
*
* @return mixed
*/
public function getReviewMarkup( $reviewObject = false ) {
$type = 'Review';
$markup = array();
$markup['@type'] = $type;
$markup['@id'] = $this->_post->url . '#' . strtolower( $type );
$markup['url'] = $this->_post->url;
if ( isset( $this->_post->sq->title ) ) {
$markup['name'] = $this->cleanText( $this->truncate( $this->_post->sq->title, 0, $this->_post->sq->jsonld_title_maxlength ) );
}
if ( isset( $this->_post->sq->description ) ) {
$markup['reviewBody'] = $this->cleanText( $this->truncate( $this->_post->sq->description, 0, $this->_post->sq->jsonld_description_maxlength ) );
}
$markup['author'] = $this->getAuthorMarkup();
$markup['publisher'] = $this->getPublisherMarkup( 'Organization' );
if ( ! $reviewObject ) {
$reviewObject = $this->getPublisherMarkup( 'Organization' );
}
$markup['itemReviewed'] = $reviewObject;
$markup['reviewRating'] = array(
'@type' => 'Rating',
'ratingValue' => 5,
);
return apply_filters( 'sq_jsonld_' . strtolower( $type ) . '_markup', $markup, $this->_post, $type );
}
/**
* Get Local Business Markup
*
* @param string $type
*
* @return mixed
*/
public function getLocalBusinessMarkup( $type = 'Store' ) {
$organization = $this->getPublisherMarkup( 'Organization' );
$markup = array();
$markup['@type'] = $type;
$markup['@id'] = $this->_post->url . '#' . strtolower( $type );
$markup['url'] = $this->_post->url;
if ( isset( $organization['name'] ) && $organization['name'] ) {
$markup['name'] = $organization['name'];
} elseif ( isset( $this->_post->sq->title ) ) {
$markup['name'] = $this->_post->sq->title;
$markup['name'] = str_replace( '"', '\"', $markup['name'] );
}
if ( isset( $organization['logo'] ) && ! empty( $organization['logo'] ) ) {
$markup['image'] = $organization['logo'];
}
if ( isset( $organization['address'] ) && ! empty( $organization['address'] ) ) {
$markup['address'] = $organization['address'];
}
if ( isset( $organization['place']['geo'] ) && ! empty( $organization['place']['geo'] ) ) {
$markup['geo'] = $organization['place']['geo'];
}
if ( isset( $organization['contactPoint']['telephone'] ) && ! empty( $organization['contactPoint']['telephone'] ) ) {
$markup['telephone'] = $organization['contactPoint']['telephone'];
}
$markup['priceRange'] = "$";
$markup['menu'] = $this->_post->url;
//Set default local SEO data
$jsonldLocal = SQ_Classes_Helpers_Tools::getOption( 'sq_jsonld_local' );
if ( ! empty( $jsonldLocal ) ) {
foreach ( $jsonldLocal as $key => $value ) {
if ( is_array( $value ) ) {
$value = @array_filter( $value );
if ( empty( $value ) ) {
continue;
}
foreach ( $value as $index => $value1 ) {
if ( is_array( $value1 ) ) {
$value1 = @array_filter( $value1 );
if ( $key == 'openingHoursSpecification' ) {
if ( count( $value1 ) < 3 ) {
unset( $value[ $index ] );
}
} elseif ( count( $value1 ) < 2 ) {
unset( $value[ $index ] );
}
}
}
if ( count( $value ) == 1 ) {
continue;
}
if ( current( array_keys( $value ) ) == 0 ) {
$value = array_values( $value );
}
}
if ( $value ) {
//create cuisine array
if ( $key == 'servesCuisine' && is_string( $value ) ) {
$value = explode( ',', $value );
}
$markup[ $key ] = $value;
}
}
}
return apply_filters( 'sq_jsonld_' . strtolower( $type ) . '_markup', $markup, $this->_post, $type );
}
/**
* Get the markup for the website Schema
*
* @return mixed
*/
public function getWebsiteMarkup() {
$jsonld = SQ_Classes_Helpers_Tools::getOption( 'sq_jsonld' );
$jsonld_type = SQ_Classes_Helpers_Tools::getOption( 'sq_jsonld_type' );
$type = 'WebSite';
$markup = array();
$markup['@type'] = $type;
$markup['@id'] = $this->_post->url . '#' . strtolower( $type );
$markup['url'] = $this->_post->url;
if ( $jsonld[ $jsonld_type ]['name'] ) {
$markup['name'] = $jsonld[ $jsonld_type ]['name'];
} elseif ( isset( $this->_post->sq->title ) ) {
$markup['name'] = $this->cleanText( $this->truncate( $this->_post->sq->title, 0, $this->_post->sq->jsonld_title_maxlength ) );
}
if ( isset( $this->_post->sq->description ) ) {
$markup['headline'] = $this->cleanText( $this->truncate( $this->_post->sq->description, 0, $this->_post->sq->jsonld_description_maxlength ) );
}
$markup['mainEntityOfPage'] = array(
'@type' => 'WebPage',
'url' => $this->_post->url
);
if ( $this->_post->sq->og_media <> '' ) {
$markup['thumbnailUrl'] = $this->_post->sq->og_media;
}
if ( isset( $this->_post->post_date ) ) {
$markup['datePublished'] = gmdate( 'c', strtotime( $this->_post->post_date ) );
}
if ( isset( $this->_post->post_modified ) ) {
$markup['dateModified'] = gmdate( 'c', strtotime( $this->_post->post_modified ) );
}
if ( $this->_post->sq->og_media <> '' ) {
$markup['image'] = array(
"@type" => "ImageObject",
"url" => $this->_post->sq->og_media,
"height" => 500,
"width" => 700,
);
} else {
$this->_setMedia( $markup );
}
//Show search bar for products and shops
//the str_replace is added for compatibility with WPML plugin
if ( $this->_post->post_type == 'product' || $this->_post->post_type == 'shop' ) {
$markup['potentialAction'] = array(
'@type' => 'SearchAction',
'target' => str_replace( 'search_term_string', '{search_term_string}', home_url( '?s=search_term_string&post_type=product' ) ),
'query-input' => 'required name=search_term_string',
);
} else {
$markup['potentialAction'] = array(
'@type' => 'SearchAction',
'target' => str_replace( 'search_term_string', '{search_term_string}', home_url( '?s=search_term_string' ) ),
'query-input' => 'required name=search_term_string',
);
}
if ( $author = $this->getAuthorMarkup() ) {
$markup['author'] = $author;
}
if ( $publisher = $this->getPublisherMarkup( $jsonld_type ) ) {
$markup['publisher'] = $publisher;
}
if ( $this->_post->sq->keywords <> '' ) {
$markup['keywords'] = $this->_post->sq->keywords;
}
return apply_filters( 'sq_jsonld_' . strtolower( $type ) . '_markup', $markup, $this->_post, $type );
}
/**
* Get the markup for the Author Schema
*/
public function getAuthorMarkup() {
$markup = array();
if ( SQ_Classes_Helpers_Tools::getOption( 'sq_jsonld_global_person' ) ) {
$markup = $this->getPublisherMarkup( 'Person' );
} else {
$user_url = $this->getAuthor( 'user_url' );
$display_name = $this->getAuthor( 'display_name' );
if ( $user_url <> '' && $display_name <> '' ) {
$markup = array(
"@type" => "Person",
"@id" => $user_url . "#person",
"url" => $user_url,
"name" => $display_name,
);
}
}
return apply_filters( 'sq_jsonld_author_markup', $markup, $this->_post, 'author', $this->_author );
}
/**
* Get the publisher markup
*
* @param $jsonld_type
*
* @return array|bool
*/
public function getPublisherMarkup( $jsonld_type ) {
$jsonld = SQ_Classes_Helpers_Tools::getOption( 'sq_jsonld' );
$markup['@type'] = $jsonld_type;
$markup['@id'] = $this->_post->url . '#' . strtolower( $jsonld_type );
$markup['url'] = $this->_post->url;
if ( isset( $jsonld[ $jsonld_type ] ) ) {
$markup = array(
"@type" => $jsonld_type,
"@id" => $this->_post->url . "#$jsonld_type",
"url" => $this->_post->url,
"name" => ( $jsonld[ $jsonld_type ]['name'] ? $jsonld[ $jsonld_type ]['name'] : get_bloginfo( 'title' ) ),
);
foreach ( $jsonld[ $jsonld_type ] as $key => $value ) {
if ( $key == 'place' ) {
continue;
} //don't show geo for the organization schema
if ( is_array( $value ) ) {
$value = @array_filter( $value );
if ( empty( $value ) ) {
continue;
}
foreach ( $value as $key1 => $value1 ) {
if ( is_array( $value1 ) ) {
$value1 = @array_filter( $value1 );
if ( count( $value1 ) == 1 ) {
unset( $value[ $key1 ] );
}
}
}
if ( count( $value ) == 1 ) {
continue;
}
$value['@id'] = $this->_post->url . "#" . strtolower( $key );
}
if ( $value ) {
if ( $key == 'logo' && isset( $value['url'] ) && $value['url'] <> '' ) {
if ( defined( 'WP_CONTENT_DIR' ) && $imagepath = str_replace( content_url(), WP_CONTENT_DIR, $value['url'] ) ) {
if ( file_exists( $imagepath ) ) {
list( $width, $height ) = @getimagesize( $imagepath );
$value['width'] = $width;
$value['height'] = $height;
}
}
if ( $jsonld[ $jsonld_type ]['name'] ) {
$value['caption'] = $jsonld[ $jsonld_type ]['name'];
}
}
$markup[ $key ] = $value;
}
}
$socials = SQ_Classes_Helpers_Tools::getOption( 'socials' );
//Load the social media
$jsonld_socials = array();
if ( isset( $socials['facebook_site'] ) && $socials['facebook_site'] <> '' ) {
$jsonld_socials[] = $socials['facebook_site'];
}
if ( isset( $socials['twitter_site'] ) && $socials['twitter_site'] <> '' ) {
$jsonld_socials[] = $socials['twitter_site'];
}
if ( isset( $socials['instagram_url'] ) && $socials['instagram_url'] <> '' ) {
$jsonld_socials[] = $socials['instagram_url'];
}
if ( isset( $socials['linkedin_url'] ) && $socials['linkedin_url'] <> '' ) {
$jsonld_socials[] = $socials['linkedin_url'];
}
if ( isset( $socials['pinterest_url'] ) && $socials['pinterest_url'] <> '' ) {
$jsonld_socials[] = $socials['pinterest_url'];
}
if ( isset( $socials['youtube_url'] ) && $socials['youtube_url'] <> '' ) {
$jsonld_socials[] = $socials['youtube_url'];
}
if ( ! empty( $jsonld_socials ) ) {
$markup['sameAs'] = $jsonld_socials;
}
}
return apply_filters( 'sq_jsonld_publisher_markup', $markup, $this->_post, $jsonld_type );
}
/**
* Generates BreadcrumbList structured data.
*/
public function getBreadcrumbsMarkup() {
$root = $crumbs = $lists = $markup = array();
//show the breadcrumbs
if ( $this->_post->post_type <> 'home' ) {
///////////////////////////// Home Page
$post = SQ_Classes_ObjController::getClass( 'SQ_Models_Snippet' )->setHomePage();
if ( $post->ID == 0 || $this->_post->ID <> $post->ID ) {
$root[] = array(
( $post->sq->title <> '' ? $post->sq->title : $post->post_title ),
$post->url,
);
}
if ( $this->_post->post_type == 'category' && isset( $this->_post->term_id ) && isset( $this->_post->taxonomy ) ) {
$parents = get_ancestors( $this->_post->term_id, $this->_post->taxonomy );
if ( ! empty( $parents ) ) {
$parents = array_reverse( $parents );
foreach ( $parents as $parent ) {
$parent = get_term( $parent );
if ( ! is_wp_error( $parent ) ) {
$crumbs[] = array(
$parent->name,
get_term_link( $parent->term_id, $this->_post->taxonomy ),
);
}
}
$lists[] = $crumbs;
}
} elseif ( $this->_post->post_type == 'product' ) {
if ( class_exists( 'WC_Product' ) ) {
$product = new WC_Product( $this->_post->ID );
//Get all categories
if ( $product instanceof WC_Product ) {
$taxonomy = 'product_cat';
if ( (int) $this->_post->sq->primary_category > 0 ) {
//check if the primary category was selected by the client
$category_ids = array( (int) $this->_post->sq->primary_category );
} else {
$category_ids = $product->get_category_ids();
}
if ( ! empty( $category_ids ) ) {
foreach ( $category_ids as $category ) {
$parents = get_ancestors( $category, $taxonomy );
if ( ! empty( $parents ) ) {
foreach ( $parents as $parent ) {
$parent = get_term( $parent );
if ( ! is_wp_error( $parent ) ) {
$crumbs[] = array(
$parent->name,
get_term_link( $parent->term_id, $taxonomy ),
);
}
}
$category = get_term( $category, $taxonomy );
if ( isset( $category->name ) && $category->name <> '' ) {
$crumbs[] = array(
$category->name,
get_term_link( $category->term_id, $taxonomy ),
);
}
$lists[] = $crumbs;
} else {
$category = get_term( $category, $taxonomy );
if ( isset( $category->name ) && $category->name <> '' ) {
$crumbs[] = array(
$category->name,
get_term_link( $category->term_id, $taxonomy ),
);
}
$lists[] = $crumbs;
}
}
}
}
}
} else {
/////////////////////// Parent Categories
if ( (int) $this->_post->sq->primary_category > 0 ) {
$categories = array( get_category( (int) $this->_post->sq->primary_category ) );
} else {
$categories = get_the_category( $this->_post->ID );
}
if ( ! empty( $categories ) ) {
foreach ( $categories as $category ) {
if ( isset( $category->term_id ) && isset( $category->taxonomy ) ) {
$crumbs = [];
$parents = get_ancestors( $category->term_id, $category->taxonomy );
if ( ! empty( $parents ) ) {
$parents = array_reverse( $parents );
foreach ( $parents as $parent ) {
$parent = get_term( $parent );
if ( isset( $parent->name ) && $parent->name <> '' ) {
$crumbs[] = array(
$parent->name,
get_term_link( $parent->term_id, $category->taxonomy ),
);
}
}
if ( isset( $category->name ) && $category->name <> '' ) {
$crumbs[] = array(
$category->name,
get_term_link( $category->term_id, $category->taxonomy ),
);
}
$lists[] = $crumbs;
} elseif ( isset( $category->name ) && $category->name <> '' ) {
$crumbs[] = array(
$category->name,
get_term_link( $category->term_id, $category->taxonomy ),
);
$lists[] = $crumbs;
}
}
}
}
}
if ( ! empty( $crumbs ) ) {
$markup['@type'] = 'BreadcrumbList';
$markup['@id'] = $this->_post->url . '#' . 'breadcrumblist';
$markup['itemListElement'] = array();
foreach ( $lists as $list ) {
//merge and reset the keys
$list = array_merge( $root, $list );
$list = array_values( $list );
////////////////////// Current post
$list[] = array(
( $this->_post->sq->title <> '' ? $this->_post->sq->title : $this->_post->post_title ),
$this->_post->url,
);
$itemListElement = array();
foreach ( $list as $key => $crumb ) {
$itemListElement[ $key ] = array(
'@type' => 'ListItem',
'position' => $key + 1,
'item' => array(
'@id' => $crumb[1],
'name' => $this->cleanText( $crumb[0] )
),
);
}
$markup['itemListElement'][] = $itemListElement;
}
}
}
return apply_filters( 'sq_jsonld_breadcrumbs_markup', $markup, $this->_post, 'breadcrumbs' );
}
/**
*
* Set the Image from Feature image
*
* @param $markup
*/
public function _setMedia( &$markup ) {
$images = $this->getPostImages();
if ( ! empty( $images ) ) {
$image = current( $images );
if ( isset( $image['src'] ) ) {
$markup['image'] = array(
"@type" => "ImageObject",
"url" => $image['src'],
"height" => 500,
"width" => 500,
);
if ( isset( $image['width'] ) ) {
$markup['image']["width"] = $image['width'];
}
if ( isset( $image['height'] ) ) {
$markup['image']["height"] = $image['height'];
}
}
}
}
/**
* Generates Product structured data.
*
* @return array|void
*/
public function getWoocommerceProductMarkup() {
$markup = array();
try {
if ( ! function_exists( 'wc_get_product' ) ) {
return $markup;
}
if ( ! $product = wc_get_product( $this->_post->ID ) ) {
return $markup;
}
if ( ! method_exists( $product, 'get_id' ) || ! method_exists( $product, 'get_price' ) ) {
return $markup;
}
$shop_name = get_bloginfo( 'name' );
$shop_url = home_url();
if ( function_exists( 'get_woocommerce_currency' ) ) {
$currency = get_woocommerce_currency();
}
$sq_woocommerce = get_post_meta( $this->_post->ID, '_sq_woocommerce', true );
$wc_fields = array( 'mpn' => 'mpn',
'gtin' => 'gtin',
'ean' => 'gtin13',
'upc' => 'gtin12',
'isbn' => 'isbn'
);
$markup['@type'] = 'Product';
$markup['url'] = get_permalink( $product->get_id() );
$markup['@id'] = $markup['url'] . '#' . 'product';
if ( method_exists( $product, 'get_name' ) ) {
$markup['name'] = $this->cleanText( $product->get_name() );
} else {
$markup['name'] = $this->cleanText( $product->get_title() );
}
if ( method_exists( $product, 'get_short_description' ) ) {
$markup['description'] = $this->cleanText( wp_strip_all_tags( $product->get_short_description() ? $product->get_short_description() : $product->get_description() ) );
}
if ( method_exists( $product, 'get_image_id' ) ) {
if ( $image = wp_get_attachment_url( $product->get_image_id() ) ) {
$markup['image'] = $image;
}
}
//By default, set the price available for 1 year
$price_valid_until = gmdate( 'Y-m-d', strtotime( '+12 Month' ) );
if ( method_exists( $product, 'get_date_on_sale_to' ) && method_exists( $product, 'get_date_on_sale_from' ) && is_object( $product->get_date_on_sale_to() ) && is_object( $product->get_date_on_sale_from() ) ) {
if ( $product->get_date_on_sale_from() && method_exists( $product->get_date_on_sale_from(), 'getTimestamp' ) ) {
if ( $product->get_date_on_sale_from() && gmdate( 'Y-m-d', $product->get_date_on_sale_from()->getTimestamp() ) <= gmdate( 'Y-m-d' ) ) {
if ( method_exists( $product->get_date_on_sale_to(), 'getTimestamp' ) ) {
//Set the price available until the offer ends
$price_valid_until = gmdate( 'Y-m-d', $product->get_date_on_sale_to()->getTimestamp() );
}
}
}
}
//Get the product price
$price = $product->get_price();
//Get the price with VAT if exists
if ( function_exists( 'wc_get_price_including_tax' ) && function_exists( 'wc_tax_enabled' ) && function_exists( 'wc_prices_include_tax' ) ) {
if ( wc_tax_enabled() && ! wc_prices_include_tax() && 'incl' === get_option( 'woocommerce_tax_display_shop' ) ) {
$price = wc_get_price_including_tax( $product, array( 'price' => $price ) );
}
}
$offer_price = 0;
if ( function_exists( 'wc_format_decimal' ) && function_exists( 'wc_get_price_decimals' ) ) {
$offer_price = wc_format_decimal( $price, wc_get_price_decimals() );
}
$markup_offer = array(
'@type' => 'Offer',
'price' => $offer_price,
'priceValidUntil' => $price_valid_until,
'url' => get_permalink( $product->get_id() ),
'priceCurrency' => $currency,
'availability' => 'https://schema.org/' . $stock = ( $product->is_in_stock() ? 'InStock' : 'OutOfStock' ),
'sku' => ( method_exists( $product, 'get_sku' ) ) ? ( $product->get_sku() <> '' ? $product->get_sku() : '' ) : '',
'image' => ( method_exists( $product, 'get_image_id' ) ) ? wp_get_attachment_url( $product->get_image_id() ) : '-',
'description' => ( method_exists( $product, 'get_description' ) ? $this->cleanText( $product->get_description() ) : $this->cleanText( $product->get_title() ) ),
'seller' => array(
'@type' => 'Organization',
'name' => $shop_name,
'url' => $shop_url,
),
);
//Get the variation prices
if ( $product->is_type( 'variable' ) && method_exists( $product, 'get_variation_prices' ) && method_exists( $product, 'get_variation_regular_price' ) && method_exists( $product, 'get_variation_sale_price' ) ) {
$prices = $product->get_variation_prices();
if ( isset( $prices['price'] ) ) {
//Get the product price
$price = $product->get_price();
$minprice = $product->get_variation_price();
$maxprice = $product->get_variation_price( 'max' );
//Get the price with VAT if exists
if ( function_exists( 'wc_get_price_including_tax' ) && function_exists( 'wc_tax_enabled' ) && function_exists( 'wc_prices_include_tax' ) ) {
if ( wc_tax_enabled() && ! wc_prices_include_tax() && 'incl' === get_option( 'woocommerce_tax_display_shop' ) ) {
$price = wc_get_price_including_tax( $product, array( 'price' => $price ) );
$minprice = wc_get_price_including_tax( $product, array( 'price' => $minprice ) );
$maxprice = wc_get_price_including_tax( $product, array( 'price' => $maxprice ) );
}
}
if ( function_exists( 'wc_format_decimal' ) && function_exists( 'wc_get_price_decimals' ) ) {
$markup_offer['priceSpecification'] = array(
'@type' => 'UnitPriceSpecification',
'price' => wc_format_decimal( $price, wc_get_price_decimals() ),
'minPrice' => wc_format_decimal( $minprice, wc_get_price_decimals() ),
'maxPrice' => wc_format_decimal( $maxprice, wc_get_price_decimals() ),
'priceCurrency' => $currency,
'valueAddedTaxIncluded' => wc_prices_include_tax() ? 'true' : 'false'
);
}
unset( $markup_offer['price'] );
unset( $markup_offer['priceCurrency'] );
}
} elseif ( function_exists( 'wc_prices_include_tax' ) && function_exists( 'wc_format_decimal' ) && function_exists( 'wc_get_price_decimals' ) ) {
$markup_offer['priceSpecification'] = array(
'@type' => 'UnitPriceSpecification',
'price' => wc_format_decimal( $product->get_price(), wc_get_price_decimals() ),
'priceCurrency' => $currency,
'valueAddedTaxIncluded' => wc_prices_include_tax() ? 'true' : 'false'
);
unset( $markup_offer['price'] );
unset( $markup_offer['priceCurrency'] );
}
$markup['sku'] = ( method_exists( $product, 'get_sku' ) ) ? ( $product->get_sku() <> '' ? $product->get_sku() : '' ) : '';
//Set default values if WooCommerce default is active
if ( SQ_Classes_Helpers_Tools::getOption( 'sq_jsonld_product_defaults' ) ) {
//Get all categories
$categories = $product->get_category_ids();
if ( ! empty( $categories ) ) {
foreach ( $categories as $category ) {
$category = get_term( $category, 'product_cat' );
if ( isset( $category->name ) && $category->name <> '' ) {
$markup['brand'] = array(
'@type' => 'Brand',
'name' => $category->name,
);
}
}
}
if ( $markup['sku'] == '' ) {
$markup['sku'] = '-';
}
if ( $markup_offer['sku'] == '' ) {
$markup_offer['sku'] = '-';
}
$markup['mpn'] = '-';
$markup_offer['mpn'] = '-';
}
//Set custom values if WooCommerce custom is active
if ( SQ_Classes_Helpers_Tools::getOption( 'sq_jsonld_product_custom' ) ) {
foreach ( $wc_fields as $field => $jsonkey ) {
if ( isset( $sq_woocommerce[ $field ] ) && $sq_woocommerce[ $field ] <> '' ) {
$markup[ $jsonkey ] = $sq_woocommerce[ $field ];
$markup_offer[ $jsonkey ] = $sq_woocommerce[ $field ];
}
}
if ( isset( $sq_woocommerce['brand'] ) && $sq_woocommerce['brand'] <> '' ) {
$markup['brand'] = array(
'@type' => 'Brand',
'name' => $sq_woocommerce['brand'],
);
}
}
//Set the offer
$markup['offers'] = $markup_offer;
if ( SQ_Classes_Helpers_Tools::getOption( 'sq_jsonld_product_defaults' ) ) {
//If rating and reviews
if ( method_exists( $product, 'get_rating_count' ) && $product->get_rating_count() ) {
//Only if it's set in Squirrly to remove duplicates
//otherwise let Woocommerce show the reviews
if ( SQ_Classes_Helpers_Tools::getOption( 'sq_jsonld_clearcode' ) ) {
$markup['aggregateRating'] = array(
'@type' => 'AggregateRating',
'ratingValue' => $product->get_average_rating(),
'ratingCount' => $product->get_rating_count(),
'reviewCount' => $product->get_review_count(),
);
//Set the reviews
$markup['review'] = $this->getProductReviewMarkup( $product );
}
} else { //add default data?
//Add data if no reviews for Google validation
$markup['aggregateRating'] = array(
'@type' => 'AggregateRating',
'ratingValue' => 5,
'ratingCount' => 1,
'reviewCount' => 1,
);
$markup['review'][] = array(
'@type' => 'Review',
'reviewRating' => array(
'@type' => 'Rating',
'ratingValue' => 5,
),
'author' => array(
'@type' => 'Person',
'name' => ( isset( $markup['name'] ) ? $markup['name'] : 'John Doe' ),
),
'reviewBody' => ( isset( $markup['description'] ) ? $markup['description'] : '-' ),
'datePublished' => ( method_exists( $product, 'get_date_created' ) && $product->get_date_created() && method_exists( $product->get_date_created(), 'getTimestamp' ) ) ? gmdate( 'Y-m-d', $product->get_date_created()->getTimestamp() ) : '',
);
}
}
$otherbrands = array();
//compatible with Perfect Woocommerce Brands
if ( SQ_Classes_Helpers_Tools::isPluginInstalled( 'perfect-woocommerce-brands/perfect-woocommerce-brands.php' ) ) {
$brands = wp_get_post_terms( $product->get_id(), 'pwb-brand' );
foreach ( $brands as $brand ) {
$otherbrands[] = $brand->name;
}
}
//compatible with YITH WooCommerce Brands Add-on
if ( SQ_Classes_Helpers_Tools::isPluginInstalled( 'yith-woocommerce-brands-add-on/init.php' ) ) {
$brands = wp_get_post_terms( $product->get_id(), 'yith_product_brand' );
foreach ( $brands as $brand ) {
$otherbrands[] = $brand->name;
}
}
if ( ! empty( $otherbrands ) ) {
$markup['brand'] = $otherbrands;
}
return $markup;
} catch ( Exception $e ) {
}
}
/**
* Generates Review structured data.
*
* @param $product
*
* @return array | false
*/
public function getProductReviewMarkup( $product ) {
$markup = array();
if ( ! method_exists( $product, 'get_id' ) ) {
return false;
}
if ( function_exists( 'wc_review_ratings_enabled' ) && wc_review_ratings_enabled() && function_exists( 'get_comments' ) && function_exists( 'get_comment_meta' ) ) {
$reviews = get_comments( array(
'number' => 10,
'post_id' => $product->get_id(),
'status' => 'approve',
'post_status' => 'publish',
'post_type' => 'product',
'parent' => 0,
'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
array(
'key' => 'rating',
'type' => 'NUMERIC',
'compare' => '>',
'value' => 0,
),
),
) );
if ( ! empty( $reviews ) ) {
foreach ( $reviews as $review ) {
if ( method_exists( $review, 'comment_ID' ) ) {
$markup[] = array(
'@type' => 'Review',
'reviewRating' => array(
'@type' => 'Rating',
'bestRating' => '5',
'ratingValue' => get_comment_meta( $review->comment_ID, 'rating', true ),
'worstRating' => '1',
),
'author' => array(
'@type' => 'Person',
'name' => get_comment_author( $review ),
),
'reviewBody' => get_comment_text( $review ),
'datePublished' => get_comment_date( 'c', $review ),
);
}
}
}
}
return $markup;
}
}