<?php
|
namespace JVBase\managers\SEO\render;
|
|
use JVBase\inc\managers\SEO\render\Thing\Intangible\ItemList\OfferCatalog;
|
use JVBase\managers\Cache;
|
use JVBase\managers\SEO\BreadcrumbManager;
|
use JVBase\managers\SEO\render\Thing\Intangible\Service;
|
use JVBase\managers\SEO\render\Thing\Organization\LocalBusiness\LocalBusiness;
|
use JVBase\registrar\config\seo\Resolver;
|
use JVBase\registrar\Registrar;
|
|
class SchemaOutput {
|
protected array $types;
|
public function __construct() {
|
add_action('wp_head', [$this, 'outputSchema'], 0);
|
$this->init();
|
}
|
|
protected function init(): void {
|
$this->types = array_map(function ($type) { return jvbCheckBase($type); }, Registrar::getRegistered());
|
}
|
public function buildSchema():array
|
{
|
$schema = [];
|
|
|
if (is_front_page()) {
|
$schema[] = $this->buildWebsiteSchema(true);
|
$test = $this->buildOrganizationSchema();
|
if (!empty($test)) {
|
$schema[] = $test;
|
}
|
}
|
if (is_singular($this->types)) {
|
$type = get_post_type();
|
$registrar = Registrar::getInstance($type);
|
if ($registrar) {
|
$seo = $registrar->getSEO();
|
$schema[] = $seo->schema()->outputSingularSchema();
|
}
|
}elseif (is_post_type_archive($this->types)) {
|
error_log('It is a post type archive');
|
$type = get_queried_object();
|
$type = $type->name;
|
$registrar = Registrar::getInstance($type);
|
|
if ($registrar) {
|
$seo = $registrar->getSEO();
|
$schema[] =$seo->schema()->outputArchiveSchema();
|
}
|
} elseif (is_tax($this->types)) {
|
$type = get_queried_object();
|
$type = jvbNoBase($type->taxonomy);
|
$registrar = Registrar::getInstance($type);
|
if ($registrar ) {
|
$seo = $registrar->getSEO();
|
error_log('SEO: '.print_r($seo->schema(), true));
|
$schema[] = $seo->schema()->outputArchiveSchema();
|
}
|
}
|
$isContent = array_values(array_filter(array_map(function($item) {
|
return intval(get_option(BASE.$item.'_archive', false));
|
},Registrar::getFeatured('is_content', 'term'))));
|
|
if (is_page($isContent)){
|
$type = get_post_meta(get_the_id(), BASE.'for_type', true);
|
error_log('Type: '.print_r($type, true));
|
if (!empty($type)) {
|
$registrar = Registrar::getInstance($type);
|
if ($registrar) {
|
$schema[] = $registrar->getSEO()->schema()->outputContentTaxArchiveSchema();
|
}
|
}
|
|
}
|
|
|
|
$breadcrumbs = $this->buildBreadcrumbs();
|
if ($breadcrumbs) {
|
$schema[] = $breadcrumbs;
|
}
|
|
if (!empty($schema)) {
|
if (!is_front_page()) {
|
$website = JVB()->schemaHelper()::schema('website');
|
if (!empty($website)) {
|
if (JVB_TESTING) {
|
Cache::for('websiteSchema')->flush();
|
}
|
$website = Cache::for('websiteSchema')->remember(
|
'schema',
|
function () {
|
return $this->websiteSchema();
|
}
|
);
|
array_unshift($schema, $website);
|
}
|
}
|
|
$schema = [
|
'@context' => 'https://schema.org',
|
'@graph' => $schema
|
];
|
}
|
return $schema;
|
}
|
|
protected function websiteSchema():array
|
{
|
$stored = JVB()->schemaHelper()::schema('website');
|
$website = JVB()->schemaHelper()::classFromConfig($stored);
|
|
if (!$website->getUrl() || empty($website->getUrl())){
|
$website->setUrl(get_home_url());
|
}
|
|
if (!$website->getName() || empty($website->getName())){
|
$website->setName(get_bloginfo('name'));
|
}
|
if(!$website->getCreator() || empty($website->getCreator(true))) {
|
$website->setCreator($this->getCreator(true));
|
}
|
return $website->outputSchema();
|
}
|
|
public function outputSchema():void
|
{
|
$schema = $this->buildSchema();
|
if (empty($schema)) {
|
return;
|
}
|
// $encoded = wp_json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
|
// $encoded = wp_json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT, 1024);
|
$encoded = wp_json_encode($schema, JSON_UNESCAPED_SLASHES, 512);
|
if ($encoded === false) {
|
error_log('wp_json_encode failed: ' . json_last_error_msg());
|
return;
|
}
|
echo "\n<!-- SEO Schema by JakeVan -->\n";
|
echo '<script type="application/ld+json">' . "\n";
|
|
echo $encoded;
|
echo "\n" . '</script>' . "\n";
|
echo "\n" . '<!-- / SEO Schema by JakeVan -->'."\n";
|
}
|
|
public function buildBreadcrumbs():array
|
{
|
return BreadcrumbManager::getInstance()->toSchema();
|
}
|
|
public function buildWebsiteSchema(bool $full = true):array
|
{
|
if (JVB_TESTING){
|
Cache::for('websiteSchema')->flush();
|
}
|
$storedWebsite = JVB()->schemaHelper()::schema('website');
|
|
if (!$full) {
|
return Cache::for('websiteSchema')->remember(
|
'reference',
|
function () use ($storedWebsite) {
|
$allowed = ['type','name', 'url', 'description', 'inLanguage'];
|
$storedWebsite = array_filter($storedWebsite, function ($key) use ($allowed) {
|
return in_array($key, $allowed);
|
}, ARRAY_FILTER_USE_KEY);
|
|
$website = JVB()->schemaHelper()::classFromConfig($storedWebsite);
|
if (!$website->getName() || empty($website->getName())) {
|
$website->setName(get_bloginfo('name'));
|
}
|
if (!$website->getUrl() || empty($website->getUrl())) {
|
$website->setUrl(get_home_url());
|
}
|
if (!$website->getId() || empty($website->getId())) {
|
$website->setId(get_home_url().'/#website');
|
}
|
if (!$website->getDescription() || empty($website->getDescription())) {
|
$website->setDescription(get_bloginfo('description'));
|
}
|
if (!$website->getInLanguage() || empty($website->getInLanguage())) {
|
$website->setInLanguage('en-CA');
|
}
|
if (!$website->getPublisher() || empty($website->getPublisher())) {
|
$publisher = $this->getOptionSchemaReference('organization');
|
if ($publisher){
|
$website->setPublisher($publisher);
|
}
|
}
|
|
$website->setCreator($this->getCreator(true));
|
|
return $website->outputSchema();
|
}
|
);
|
}
|
return Cache::for('websiteSchema')->remember(
|
'full',
|
function () use ($storedWebsite) {
|
$website = JVB()->schemaHelper()::classFromConfig($storedWebsite);
|
if (!$website->getName() || empty($website->getName())) {
|
$website->setName(get_bloginfo('name'));
|
}
|
if (!$website->getUrl() || empty($website->getUrl())) {
|
$website->setUrl(get_home_url());
|
}
|
if (!$website->getId() || empty($website->getId())) {
|
$website->setId(get_home_url().'/#website');
|
}
|
if (!$website->getDescription() || empty($website->getDescription())) {
|
$website->setDescription(get_bloginfo('description'));
|
}
|
if (!$website->getInLanguage() || empty($website->getInLanguage())) {
|
$website->setInLanguage('en-CA');
|
}
|
if (!$website->getPublisher() || empty($website->getPublisher())) {
|
$publisher = $this->getOptionSchemaReference('organization');
|
if ($publisher){
|
$website->setPublisher($publisher);
|
}
|
}
|
|
$website->setCreator($this->getCreator(true));
|
|
return $website->outputSchema();
|
}
|
);
|
}
|
|
|
public function getCreator(bool $reference = false, bool $jakeVan = false):LocalBusiness
|
{
|
if (JVB_TESTING){
|
Cache::for('JakeVanCreator')->flush();
|
}
|
|
if ($reference && $jakeVan) {
|
return Cache::for('JakeVanCreator')->remember(
|
'reference',
|
function () {
|
$creator = new LocalBusiness();
|
$creator->setId('jakevan');
|
$creator->setName('JakeVan');
|
$creator->setUrl('https://jakevan.ca/');
|
$creator->setDescription('Let\'s bring your idea to life.');
|
return $creator;
|
}
|
);
|
}
|
if ($jakeVan) {
|
return Cache::for('JakeVanCreator')->remember(
|
'full',
|
function () {
|
$creator = new LocalBusiness();
|
$creator->setName('JakeVan');
|
$creator->setId('https://jakevan.ca/#localbusiness');
|
$creator->setAlternateName(['Jake Vanderwerf', 'Rooted Romantic', 'Jacob Vanderwerf']);
|
$creator->setUrl('https://jakevan.ca');
|
$creator->setSameAs([
|
'https://bsky.app/profile/jakevan.ca',
|
]);
|
$creator->setAreaServed(['Edmonton, Alberta', 'Alberta', 'Canada']);
|
$offers = new OfferCatalog();
|
$offers->setName('Services');
|
$offers->setUrl('https://jakevan.ca/services');
|
|
$graphicDesign = new Service();
|
$graphicDesign->setName('Graphic Design');
|
$graphicDesign->setUrl('https://jakevan.ca/services/design/');
|
$graphicDesign->setDescription('From print to digital design.');
|
$websiteDesign = new Service();
|
$websiteDesign->setName('Development');
|
$websiteDesign->setUrl('https://jakevan.ca/services/development/');
|
$websiteDesign->setDescription('From basic websites to custom functionality.');
|
$strategy = new Service();
|
$strategy->setName('Strategy');
|
$strategy->setUrl('https://jakevan.ca/services/strategy/');
|
$strategy->setDescription('From developing your business plan to SEO.');
|
$art = new Service();
|
$art->setName('Art');
|
$art->setUrl('https://jakevan.ca/services/art/');
|
$art->setDescription('From unique, custom, handmade pieces to small-scale wholesale.');
|
|
$offers->setItemListElement([
|
$graphicDesign,
|
$websiteDesign,
|
$strategy,
|
$art
|
]);
|
|
|
$creator->setHasOfferCatalog($offers);
|
return $creator;
|
}
|
);
|
}
|
if ($reference) {
|
return $this->getOptionSchemaReference('organization');
|
}
|
$config = JVB()->schemaHelper()::schema('organization');
|
|
return JVB()->schemaHelper()::classFromConfig($config);
|
}
|
|
public function getOptionSchemaReference(string $option):mixed
|
{
|
if (!in_array(strtolower($option), array_merge(
|
['organization',
|
'website'],
|
Registrar::getRegistered()
|
))) {
|
error_log('Attempted to get schema reference for: '.$option.', but it does not exist');
|
return null;
|
}
|
|
$stored = JVB()->schemaHelper()::reference($option);
|
|
if (empty($stored)){
|
error_log('Attempted to get schema reference for: '.$option.', but defaults not set.');
|
return null;
|
}
|
$type = $stored['type'];
|
if (!class_exists($type)){
|
error_log('Attempted to get schema reference, but class does not exist: '.$type);
|
return null;
|
}
|
$class = new $type();
|
unset($stored['type']);
|
$minimal = apply_filters(BASE.'OrganizationReference', ['name', 'url', 'sameAs', 'logo']);
|
|
foreach ($minimal as $property) {
|
$method = 'set'.ucfirst($property);
|
$value = array_key_exists($property, $stored) ? $stored[$property] : null;
|
if (!$value) {continue;}
|
|
if (str_contains($value, '{{')) {
|
$meta = null;
|
$value = Resolver::resolve($property, $value);
|
}
|
$class->$method($value);
|
}
|
return $class;
|
}
|
|
public function buildOrganizationSchema():array
|
{
|
$config = JVB()->schemaHelper()::schema('organization');
|
|
$class = JVB()->schemaHelper()::classFromConfig($config);
|
return ($class)? $class->outputSchema() : [];
|
}
|
}
|