<?php
|
namespace JVBase\managers\SEO\render;
|
|
use JVBase\managers\Cache;
|
use JVBase\managers\SEO\BreadcrumbManager;
|
use JVBase\managers\SEO\render\Thing\CreativeWork\WebSite;
|
use JVBase\managers\SEO\render\Thing\Intangible\OfferCatalog;
|
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->buildBasicWebsiteSchema();
|
}
|
if (is_singular($this->types)) {
|
$type = get_post_type();
|
$registrar = Registrar::getInstance($type);
|
if ($registrar && !empty($registrar->getConfig('seo')['schema']??[])) {
|
$seo = $registrar->getSEO();
|
$schema[] = $seo->schema()->outputSingularSchema();
|
}
|
}elseif (is_post_type_archive($this->types)) {
|
|
$type = get_queried_object();
|
$type = $type->name;
|
$registrar = Registrar::getInstance($type);
|
|
if ($registrar && !empty($registrar->getConfig('seo')['schema']??[])) {
|
$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 && !empty($registrar->getConfig('seo')['schema']??[])) {
|
$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));
|
$registrar = Registrar::getInstance($type);
|
if ($registrar) {
|
$schema[] = $registrar->getSEO()->schema()->outputContentTaxArchiveSchema();
|
}
|
}
|
|
|
|
$breadcrumbs = $this->buildBreadcrumbs();
|
if ($breadcrumbs) {
|
$schema[] = $breadcrumbs;
|
}
|
|
if (!empty($schema)) {
|
$website = get_option(BASE.'WebsiteSchema');
|
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 = get_option(BASE.'WebsiteSchema', apply_filters(BASE.'WebsiteSchema', []));
|
|
$seo = new WebSite();
|
foreach ($stored as $property => $value) {
|
$method = 'set'.ucfirst($property);
|
$seo->$method($value);
|
}
|
$seo->setUrl(get_home_url());
|
$seo->setName(get_bloginfo('name'));
|
|
$seo->setCreator($this->getCreator());
|
return $seo->outputSchema();
|
}
|
|
public function outputSchema():void
|
{
|
$schema = $this->buildSchema();
|
if (empty($schema)) {
|
return;
|
}
|
echo "\n<!-- SEO Schema by JakeVan -->\n";
|
echo '<script type="application/ld+json">' . "\n";
|
echo wp_json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
|
echo "\n" . '</script>' . "\n";
|
echo "\n" . '<!-- / SEO Schema by JakeVan -->'."\n";
|
}
|
|
public function buildBreadcrumbs():array
|
{
|
return BreadcrumbManager::getInstance()->toSchema();
|
}
|
|
public function buildBasicWebsiteSchema():array
|
{
|
if (JVB_TESTING){
|
Cache::for('websiteSchema')->flush();
|
}
|
|
return Cache::for('websiteSchema')->remember(
|
'reference',
|
function () {
|
$website = new WebSite();
|
$website->setName(get_bloginfo('name'));
|
$website->setUrl(get_home_url());
|
$website->setId(get_home_url().'/#website');
|
$website->setDescription(get_bloginfo('description'));
|
$website->setInLanguage('en-CA');
|
$publisher = $this->getOptionSchemaReference('organization');
|
if ($publisher){
|
$website->setPublisher($publisher);
|
}
|
|
$website->setCreator($this->getCreator(true));
|
|
return $website->outputSchema();
|
}
|
);
|
}
|
|
|
public function getCreator(bool $reference = false):LocalBusiness
|
{
|
if (JVB_TESTING){
|
Cache::for('JakeVanCreator')->flush();
|
}
|
|
if ($reference) {
|
return Cache::for('JakeVanCreator')->remember(
|
'reference',
|
function () {
|
$creator = new LocalBusiness();
|
$creator->setName('JakeVan');
|
$creator->setAlternateName('Jake Vanderwerf');
|
$creator->setUrl('https://jakevan.ca/');
|
$creator->setDescription('Let\'s bring your idea to life.');
|
return $creator;
|
}
|
);
|
}
|
|
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;
|
}
|
);
|
}
|
|
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;
|
}
|
$action = BASE.ucfirst($option).'Schema';
|
$stored = get_option($action, apply_filters($action, []));
|
// $stored = get_option($action, apply_filters($action, jvbDefaultSchema($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($action.'Reference', ['name', 'url', 'sameAs', 'logo']);
|
|
foreach ($minimal as $property) {
|
$method = 'set'.ucfirst($property);
|
$value = array_key_exists($property, $stored) ? $stored[$property] : null;
|
if (!$value) {continue;}
|
|
$class->$method(Resolver::resolve($property, $value));
|
}
|
return $class;
|
}
|
}
|