' . sxseo_json( array( '@context' => 'https://schema.org', '@graph' => $graph ) ) . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput
}
}
private static function id( $frag ) {
return home_url( '/' ) . '#' . $frag;
}
public static function organisation() {
$s = SXSEO_Settings::all();
$type = in_array( $s['org_type'], array( 'Organization', 'LocalBusiness', 'Person', 'Corporation', 'ProfessionalService', 'Store', 'Restaurant', 'EducationalOrganization', 'NGO' ), true ) ? $s['org_type'] : 'Organization';
$local = ! in_array( $type, array( 'Organization', 'Person', 'Corporation', 'NGO', 'EducationalOrganization' ), true );
$org = array(
// Business types are also LocalBusiness so maps and local results can use them.
'@type' => ( $local && 'LocalBusiness' !== $type ) ? array( $type, 'LocalBusiness' ) : $type,
'@id' => self::id( 'organization' ),
'name' => $s['org_name'] ?: get_bloginfo( 'name' ),
'url' => home_url( '/' ),
);
if ( $s['org_legal_name'] ) {
$org['legalName'] = $s['org_legal_name'];
}
if ( $s['org_description'] ) {
$org['description'] = $s['org_description'];
}
$topics = array_values( array_filter( array_map( 'trim', explode( ',', (string) $s['org_knows_about'] ) ) ) );
if ( $topics ) {
$org['knowsAbout'] = $topics;
}
if ( $s['org_logo'] ) {
$org['logo'] = array( '@type' => 'ImageObject', '@id' => self::id( 'logo' ), 'url' => $s['org_logo'], 'contentUrl' => $s['org_logo'] );
$org['image'] = array( '@id' => self::id( 'logo' ) );
}
if ( $s['org_phone'] ) {
$org['telephone'] = $s['org_phone'];
}
if ( $s['org_email'] ) {
$org['email'] = $s['org_email'];
}
$profiles = array_values( array_filter( array_map( 'esc_url_raw', preg_split( '/\r\n|\r|\n/', (string) $s['org_profiles'] ) ) ) );
if ( $profiles ) {
$org['sameAs'] = $profiles;
}
if ( $s['org_street'] || $s['org_city'] || $s['org_postcode'] ) {
$org['address'] = array_filter(
array(
'@type' => 'PostalAddress',
'streetAddress' => $s['org_street'],
'addressLocality' => $s['org_city'],
'addressRegion' => $s['org_region'],
'postalCode' => $s['org_postcode'],
'addressCountry' => $s['org_country'],
)
);
}
if ( $local ) {
if ( $s['org_lat'] && $s['org_lng'] ) {
$org['geo'] = array( '@type' => 'GeoCoordinates', 'latitude' => (float) $s['org_lat'], 'longitude' => (float) $s['org_lng'] );
}
if ( $s['org_price_range'] ) {
$org['priceRange'] = $s['org_price_range'];
}
$hours = array_values( array_filter( array_map( 'trim', preg_split( '/\r\n|\r|\n/', (string) $s['org_hours'] ) ) ) );
if ( $hours ) {
$org['openingHours'] = $hours;
}
$areas = array_values( array_filter( array_map( 'trim', explode( ',', (string) $s['org_area'] ) ) ) );
if ( $areas ) {
$org['areaServed'] = array_map( function ( $a ) {
return array( '@type' => 'Place', 'name' => $a );
}, $areas );
}
}
return $org;
}
public static function graph( array $c ) {
$g = array();
$g[] = self::organisation();
$site = array(
'@type' => 'WebSite',
'@id' => self::id( 'website' ),
'url' => home_url( '/' ),
'name' => get_bloginfo( 'name' ),
'publisher' => array( '@id' => self::id( 'organization' ) ),
'inLanguage'=> str_replace( '_', '-', get_locale() ),
);
if ( get_bloginfo( 'description' ) ) {
$site['description'] = get_bloginfo( 'description' );
}
$site['potentialAction'] = array(
'@type' => 'SearchAction',
'target' => array( '@type' => 'EntryPoint', 'urlTemplate' => home_url( '/' ) . '?s={search_term_string}' ),
'query-input' => 'required name=search_term_string',
);
$g[] = $site;
// Services offered, on the home page only (the site-wide organisation node already identifies the business).
$services = array_values( array_filter( array_map( 'trim', preg_split( '/\r\n|\r|\n/', (string) SXSEO_Settings::get( 'org_services' ) ) ) ) );
if ( $services && in_array( $c['type'], array( 'home', 'front' ), true ) ) {
$areas = array_values( array_filter( array_map( 'trim', explode( ',', (string) SXSEO_Settings::get( 'org_area' ) ) ) ) );
$items = array();
foreach ( $services as $i => $name ) {
$svc = array( '@type' => 'Service', 'position' => $i + 1, 'name' => $name, 'provider' => array( '@id' => self::id( 'organization' ) ) );
if ( $areas ) {
$svc['areaServed'] = array_map( function ( $a ) {
return array( '@type' => 'AdministrativeArea', 'name' => $a );
}, $areas );
}
$items[] = $svc;
}
$g[] = array( '@type' => 'ItemList', '@id' => self::id( 'services' ), 'name' => ( SXSEO_Settings::get( 'org_name' ) ?: get_bloginfo( 'name' ) ) . ' services', 'itemListElement' => $items );
}
if ( '' === $c['url'] ) {
return $g;
}
$page_id = $c['url'] . '#webpage';
$page = array(
'@type' => 'WebPage',
'@id' => $page_id,
'url' => $c['url'],
'name' => $c['title'],
'isPartOf' => array( '@id' => self::id( 'website' ) ),
'inLanguage' => str_replace( '_', '-', get_locale() ),
);
if ( $c['desc'] ) {
$page['description'] = $c['desc'];
}
if ( in_array( $c['type'], array( 'term', 'archive', 'author', 'date' ), true ) ) {
$page['@type'] = 'CollectionPage';
} elseif ( 'home' === $c['type'] || 'front' === $c['type'] ) {
$page['@type'] = 'WebPage';
} elseif ( 'page' === $c['type'] && $c['post'] instanceof WP_Post ) {
$slug = $c['post']->post_name;
if ( preg_match( '/(^|-)(contact)(-|$)/', $slug ) ) {
$page['@type'] = 'ContactPage';
} elseif ( preg_match( '/(^|-)(about)(-|$)/', $slug ) ) {
$page['@type'] = 'AboutPage';
}
}
$img_id = null;
if ( $c['image'] ) {
$img_id = $c['url'] . '#primaryimage';
$g[] = array( '@type' => 'ImageObject', '@id' => $img_id, 'url' => $c['image'], 'contentUrl' => $c['image'] );
$page['primaryImageOfPage'] = array( '@id' => $img_id );
$page['image'] = array( '@id' => $img_id );
}
$crumbs = self::breadcrumbs( $c );
if ( count( $crumbs ) > 1 ) {
$items = array();
foreach ( $crumbs as $i => $cr ) {
$items[] = array( '@type' => 'ListItem', 'position' => $i + 1, 'name' => $cr['name'], 'item' => $cr['url'] );
}
$g[] = array( '@type' => 'BreadcrumbList', '@id' => $c['url'] . '#breadcrumb', 'itemListElement' => $items );
$page['breadcrumb'] = array( '@id' => $c['url'] . '#breadcrumb' );
}
$post = $c['post'];
if ( $post instanceof WP_Post && in_array( $c['type'], array( 'post', 'page', 'front' ), true ) ) {
$page['datePublished'] = get_post_time( 'c', true, $post );
$page['dateModified'] = get_post_modified_time( 'c', true, $post );
$schema_type = $c['ctx']['custom']['schema_type'] ?? '';
$is_article = 'post' === $post->post_type || in_array( $schema_type, array( 'Article', 'BlogPosting', 'NewsArticle' ), true );
if ( $is_article && 'page' !== $post->post_type ) {
$author_id = self::id( 'author-' . $post->post_author );
$g[] = array(
'@type' => 'Person',
'@id' => $author_id,
'name' => get_the_author_meta( 'display_name', $post->post_author ),
'url' => get_author_posts_url( $post->post_author ),
);
$art = array(
'@type' => in_array( $schema_type, array( 'Article', 'BlogPosting', 'NewsArticle' ), true ) ? $schema_type : sxseo_opt( 'article_type', 'BlogPosting' ),
'@id' => $c['url'] . '#article',
'isPartOf' => array( '@id' => $page_id ),
'mainEntityOfPage' => array( '@id' => $page_id ),
'headline' => sxseo_trim( sxseo_title_text( $post ), 110 ),
'datePublished' => get_post_time( 'c', true, $post ),
'dateModified' => get_post_modified_time( 'c', true, $post ),
'author' => array( '@id' => $author_id ),
'publisher' => array( '@id' => self::id( 'organization' ) ),
'inLanguage' => str_replace( '_', '-', get_locale() ),
'wordCount' => str_word_count( sxseo_plain( $post->post_content ) ),
);
if ( $c['desc'] ) {
$art['description'] = $c['desc'];
}
if ( $img_id ) {
$art['image'] = array( '@id' => $img_id );
}
if ( ! empty( $c['ctx']['terms']['primary'] ) ) {
$art['articleSection'] = $c['ctx']['terms']['primary'];
}
if ( $c['keywords'] ) {
$art['keywords'] = implode( ', ', $c['keywords'] );
}
$g[] = $art;
$page['@type'] = 'WebPage';
} elseif ( in_array( $schema_type, array( 'Service', 'Product' ), true ) ) {
$node = array(
'@type' => $schema_type,
'@id' => $c['url'] . '#main',
'name' => sxseo_title_text( $post ),
'description' => $c['desc'],
'url' => $c['url'],
);
$node['Service' === $schema_type ? 'provider' : 'brand'] = array( '@id' => self::id( 'organization' ) );
if ( $img_id ) {
$node['image'] = array( '@id' => $img_id );
}
$g[] = $node;
}
$faq = $c['ctx']['custom']['faq'] ?? array();
if ( $faq ) {
$qa = array();
foreach ( $faq as $row ) {
$qa[] = array( '@type' => 'Question', 'name' => $row['q'], 'acceptedAnswer' => array( '@type' => 'Answer', 'text' => $row['a'] ) );
}
$g[] = array( '@type' => 'FAQPage', '@id' => $c['url'] . '#faq', 'isPartOf' => array( '@id' => $page_id ), 'mainEntity' => $qa );
}
}
$g[] = $page;
return $g;
}
/** Trail of {name,url} from home to the current page. Shared with the [sxseo_breadcrumbs] shortcode. */
public static function breadcrumbs( array $c ) {
$trail = array( array( 'name' => __( 'Home', 'sentrixa-seo' ), 'url' => home_url( '/' ) ) );
$post = $c['post'];
if ( $post instanceof WP_Post && ! in_array( $c['type'], array( 'front' ), true ) ) {
if ( 'post' === $post->post_type ) {
$cats = get_the_category( $post->ID );
if ( $cats ) {
$primary = $cats[0];
foreach ( array_reverse( get_ancestors( $primary->term_id, 'category' ) ) as $anc ) {
$t = get_term( $anc, 'category' );
if ( $t && ! is_wp_error( $t ) ) {
$trail[] = array( 'name' => $t->name, 'url' => get_term_link( $t ) );
}
}
if ( 'uncategorized' !== $primary->slug ) {
$trail[] = array( 'name' => $primary->name, 'url' => get_term_link( $primary ) );
}
}
} elseif ( 'page' !== $post->post_type ) {
$pto = get_post_type_object( $post->post_type );
if ( $pto && $pto->has_archive ) {
$trail[] = array( 'name' => $pto->labels->name, 'url' => get_post_type_archive_link( $post->post_type ) );
}
}
foreach ( array_reverse( get_post_ancestors( $post ) ) as $anc ) {
$trail[] = array( 'name' => sxseo_title_text( $anc ), 'url' => get_permalink( $anc ) );
}
$trail[] = array( 'name' => sxseo_title_text( $post ), 'url' => get_permalink( $post ) );
} elseif ( 'term' === $c['type'] && $c['object'] instanceof WP_Term ) {
foreach ( array_reverse( get_ancestors( $c['object']->term_id, $c['object']->taxonomy ) ) as $anc ) {
$t = get_term( $anc, $c['object']->taxonomy );
if ( $t && ! is_wp_error( $t ) ) {
$trail[] = array( 'name' => $t->name, 'url' => get_term_link( $t ) );
}
}
$trail[] = array( 'name' => $c['object']->name, 'url' => get_term_link( $c['object'] ) );
} elseif ( in_array( $c['type'], array( 'archive', 'author', 'date' ), true ) ) {
$trail[] = array( 'name' => trim( wp_strip_all_tags( get_the_archive_title() ) ), 'url' => $c['url'] );
}
return $trail;
}
}
function sxseo_breadcrumbs_html() {
$c = SXSEO_Context::current();
$trail = SXSEO_Schema::breadcrumbs( $c );
if ( count( $trail ) < 2 ) {
return '';
}
$sep = ' ' . esc_html( sxseo_opt( 'breadcrumb_sep', '›' ) ) . ' ';
$out = array();
$last = count( $trail ) - 1;
foreach ( $trail as $i => $t ) {
$out[] = $i === $last ? '' . esc_html( $t['name'] ) . '' : '' . esc_html( $t['name'] ) . '';
}
return '';
}
add_shortcode( 'sxseo_breadcrumbs', 'sxseo_breadcrumbs_html' );