<?php
|
|
/**
|
* Edmonton.ink Configuration
|
*
|
* Add this to your edmonton.ink child theme/plugin
|
* This replaces all the hardcoded logic in SchemaManager and SEOMetaManager
|
*/
|
|
// ==================================================
|
// SITE-WIDE SCHEMA CONFIGURATION
|
// ==================================================
|
|
add_filter('jvb_schema', function ($schema) {
|
return array_merge($schema, [
|
'site_type' => 'directory',
|
'organization' => [
|
'type' => 'Organization',
|
'name' => 'edmonton.ink',
|
'url' => 'https://edmonton.ink',
|
'description' => 'Your tattoo scene on your screen. Discover Edmonton\'s best tattoo artists, shops, and styles.',
|
'publisher' => [
|
'type' => 'Organization',
|
'name' => 'Legacy Tattoo Removal',
|
'url' => 'https://legacytattooremoval.ca',
|
'logo' => 'https://legacytattooremoval.ca/wp-content/uploads/2024/09/legacy-tattoo-removal.webp',
|
'same_as' => [
|
'https://www.instagram.com/legacytattooremoval',
|
'https://www.facebook.com/legacytattooremoval',
|
]
|
]
|
],
|
'attribution' => [
|
'enabled' => true,
|
]
|
]);
|
});
|
|
// ==================================================
|
// CONTENT TYPES CONFIGURATION
|
// ==================================================
|
|
add_filter('jvb_content', function ($content) {
|
|
// ARTIST
|
$content['artist'] = array_merge($content['artist'] ?? [], [
|
'seo' => [
|
'title_template' => '{{name}} | {{primary_style}} Tattoo Artist in {{city}}',
|
'description_template' => '{{name}} is a {{primary_style}} tattoo artist {{location_text}}. {{bio}} Browse portfolio and book appointments.',
|
'variables' => [
|
'name' => 'post_title',
|
'primary_style' => ['taxonomy' => BASE . 'style', 'primary' => true],
|
'styles' => ['taxonomy' => BASE . 'style'],
|
'city' => ['taxonomy' => BASE . 'city', 'primary' => true],
|
'primary_shop' => ['taxonomy' => BASE . 'shop', 'primary' => true],
|
'bio' => ['meta' => 'bio', 'truncate' => 100],
|
'location_text' => ['callback' => function ($post_id, $context) {
|
$city_terms = get_the_terms($post_id, BASE . 'city');
|
$shop_terms = get_the_terms($post_id, BASE . 'shop');
|
|
if ($shop_terms && !is_wp_error($shop_terms)) {
|
$shop = $shop_terms[0];
|
return "working at {$shop->name}";
|
} elseif ($city_terms && !is_wp_error($city_terms)) {
|
$city = $city_terms[0];
|
return "in {$city->name}";
|
}
|
return "in Edmonton";
|
}],
|
],
|
'archive_title' => 'Edmonton\'s Best Tattoo Artists | Browse by Style & Shop',
|
'archive_description' => 'Explore Edmonton\'s top tattoo artists. Filter by style, shop, or location. View portfolios and book your next tattoo today.'
|
],
|
|
'schema' => [
|
'type' => 'Person',
|
'additional_types' => ['Artist'],
|
'properties' => [
|
'jobTitle' => ['callback' => function ($id, $context, $meta) {
|
$job = $meta['job_title'] ?? null;
|
if ($job) return $job;
|
|
// Try to build from specialties
|
$styles = get_the_terms($id, BASE . 'style');
|
if ($styles && !is_wp_error($styles) && count($styles) > 0) {
|
$primary = $styles[0]->name;
|
return "{$primary} Tattoo Artist";
|
}
|
return "Tattoo Artist";
|
}],
|
'telephone' => 'phone',
|
'email' => 'email',
|
'url' => ['callback' => function ($id) {
|
return get_permalink($id);
|
}],
|
'image' => ['callback' => function ($id) {
|
return get_the_post_thumbnail_url($id, 'full');
|
}],
|
'knowsAbout' => ['taxonomy' => BASE . 'style'],
|
'worksFor' => ['callback' => function ($id, $context, $meta) {
|
$shops = get_the_terms($id, BASE . 'shop');
|
if (!$shops || is_wp_error($shops)) {
|
return null;
|
}
|
|
return array_map(function ($shop) {
|
return [
|
'@type' => 'LocalBusiness',
|
'@id' => get_term_link($shop) . '#business',
|
'name' => $shop->name,
|
'url' => get_term_link($shop)
|
];
|
}, $shops);
|
}],
|
'memberOf' => [
|
'@id' => 'https://edmonton.ink/#organization'
|
],
|
]
|
]
|
]);
|
|
// PARTNER (Shops/Organizations)
|
$content['partner'] = array_merge($content['partner'] ?? [], [
|
'seo' => [
|
'title_template' => '{{name}} | Community Partner',
|
'description_template' => '{{name}} - {{excerpt}}',
|
'variables' => [
|
'name' => 'post_title',
|
'excerpt' => ['callback' => function ($id) {
|
return get_the_excerpt($id);
|
}],
|
],
|
'archive_title' => 'Our Community Partners | Supporting Edmonton\'s Tattoo Scene',
|
'archive_description' => 'Meet the businesses and organizations supporting Edmonton\'s tattoo community. Our partners help make edmonton.ink possible.'
|
],
|
|
'schema' => [
|
'type' => 'Organization',
|
'properties' => [
|
'name' => ['callback' => function ($id) {
|
return get_the_title($id);
|
}],
|
'description' => ['callback' => function ($id) {
|
return get_the_excerpt($id);
|
}],
|
'url' => ['callback' => function ($id, $context, $meta) {
|
$website = $meta['website'] ?? null;
|
return $website ?: get_permalink($id);
|
}],
|
'logo' => ['callback' => function ($id, $context, $meta) {
|
$image_id = $meta['image'] ?? null;
|
if ($image_id) {
|
return wp_get_attachment_image_url($image_id, 'full');
|
}
|
return get_the_post_thumbnail_url($id, 'full');
|
}],
|
'telephone' => 'phone',
|
'email' => 'email',
|
'address' => 'address',
|
'sameAs' => ['callback' => function ($id, $context, $meta) {
|
$links = [];
|
if (!empty($meta['instagram'])) $links[] = $meta['instagram'];
|
if (!empty($meta['facebook'])) $links[] = $meta['facebook'];
|
if (!empty($meta['twitter'])) $links[] = $meta['twitter'];
|
return !empty($links) ? $links : null;
|
}],
|
'memberOf' => [
|
'@id' => 'https://edmonton.ink/#organization'
|
],
|
]
|
]
|
]);
|
|
// TATTOO
|
$content['tattoo'] = array_merge($content['tattoo'] ?? [], [
|
'seo' => [
|
'title_template' => '{{style}} Tattoo by {{artist}} | Edmonton',
|
'description_template' => 'Beautiful {{style}} tattoo by {{artist}}{{location}}. View more work from Edmonton\'s talented artists.',
|
'variables' => [
|
'style' => ['taxonomy' => BASE . 'style', 'primary' => true],
|
'artist' => ['callback' => function ($id) {
|
$artist_id = get_post_meta($id, BASE . 'link', true);
|
if ($artist_id) {
|
return get_the_title($artist_id);
|
}
|
return 'Edmonton Artist';
|
}],
|
'location' => ['callback' => function ($id) {
|
$artist_id = get_post_meta($id, BASE . 'link', true);
|
if (!$artist_id) return '';
|
|
$shops = get_the_terms($artist_id, BASE . 'shop');
|
if ($shops && !is_wp_error($shops)) {
|
return ' at ' . $shops[0]->name;
|
}
|
return '';
|
}],
|
],
|
'archive_title' => 'Edmonton Tattoos | Browse by Style, Artist & Shop',
|
'archive_description' => 'Browse tattoos from Edmonton\'s best artists. Filter by style, theme, or artist to find inspiration for your next piece.'
|
],
|
|
'schema' => [
|
'type' => 'CreativeWork',
|
'additional_types' => ['VisualArtwork'],
|
'properties' => [
|
'creator' => ['callback' => function ($id) {
|
$artist_id = get_post_meta($id, BASE . 'link', true);
|
if ($artist_id) {
|
return [
|
'@type' => 'Person',
|
'@id' => get_permalink($artist_id) . '#person',
|
'name' => get_the_title($artist_id),
|
'url' => get_permalink($artist_id)
|
];
|
}
|
return null;
|
}],
|
'image' => ['callback' => function ($id) {
|
return get_the_post_thumbnail_url($id, 'full');
|
}],
|
'about' => ['taxonomy' => BASE . 'theme'],
|
'artform' => 'Tattoo',
|
]
|
]
|
]);
|
|
// PIERCING
|
$content['piercing'] = array_merge($content['piercing'] ?? [], [
|
'seo' => [
|
'title_template' => '{{type}} Piercing by {{artist}} | Edmonton',
|
'description_template' => 'Professional {{type}} piercing by {{artist}}. View more piercing work from Edmonton\'s skilled professionals.',
|
'variables' => [
|
'type' => ['taxonomy' => BASE . 'pstyle', 'primary' => true],
|
'artist' => ['callback' => function ($id) {
|
$artist_id = get_post_meta($id, BASE . 'link', true);
|
return $artist_id ? get_the_title($artist_id) : 'Edmonton Professional';
|
}],
|
]
|
],
|
|
'schema' => [
|
'type' => 'CreativeWork',
|
'properties' => [
|
'creator' => ['callback' => function ($id) {
|
$artist_id = get_post_meta($id, BASE . 'link', true);
|
if ($artist_id) {
|
return [
|
'@type' => 'Person',
|
'@id' => get_permalink($artist_id) . '#person',
|
'name' => get_the_title($artist_id),
|
'url' => get_permalink($artist_id)
|
];
|
}
|
return null;
|
}],
|
'image' => ['callback' => function ($id) {
|
return get_the_post_thumbnail_url($id, 'full');
|
}],
|
]
|
]
|
]);
|
|
// EVENT
|
$content['event'] = array_merge($content['event'] ?? [], [
|
'seo' => [
|
'title_builder' => function ($post_id, $meta) {
|
$title = get_the_title($post_id);
|
$date = $meta->getValue('event_date');
|
if ($date) {
|
$formatted_date = date('F j, Y', strtotime($date));
|
return "{$title} | {$formatted_date}";
|
}
|
return "{$title} | Edmonton Tattoo Event";
|
},
|
'description_builder' => function ($post_id, $meta) {
|
$excerpt = get_the_excerpt($post_id);
|
$venue = $meta->getValue('venue');
|
$date = $meta->getValue('event_date');
|
|
$desc = $excerpt;
|
if ($venue) $desc .= " Location: {$venue}.";
|
if ($date) {
|
$formatted = date('F j, Y', strtotime($date));
|
$desc .= " Date: {$formatted}.";
|
}
|
return $desc;
|
}
|
],
|
|
'schema' => [
|
'custom_builder' => function ($post_id) {
|
$meta = new \JVBase\meta\MetaManager($post_id, 'post');
|
|
$schema = [
|
'@type' => 'Event',
|
'name' => get_the_title($post_id),
|
'url' => get_permalink($post_id),
|
];
|
|
$date = $meta->getValue('event_date');
|
if ($date) {
|
$schema['startDate'] = date('c', strtotime($date));
|
}
|
|
$venue = $meta->getValue('venue');
|
$venue_address = $meta->getValue('venue_address');
|
if ($venue) {
|
$schema['location'] = [
|
'@type' => 'Place',
|
'name' => $venue,
|
];
|
if ($venue_address) {
|
$schema['location']['address'] = $venue_address;
|
}
|
}
|
|
$image_id = get_post_thumbnail_id($post_id);
|
if ($image_id) {
|
$schema['image'] = wp_get_attachment_image_url($image_id, 'full');
|
}
|
|
return $schema;
|
}
|
]
|
]);
|
|
return $content;
|
});
|
|
// ==================================================
|
// TAXONOMY CONFIGURATION
|
// ==================================================
|
|
add_filter('jvb_taxonomy', function ($taxonomies) {
|
|
// SHOP
|
$taxonomies['shop'] = array_merge($taxonomies['shop'] ?? [], [
|
'seo' => [
|
'title_template' => '{{name}} | Tattoo Shop in {{city}}',
|
'description_template' => '{{name}}{{tagline_text}}{{established_text}} in {{city}}. Featuring {{artist_count}} talented artists. Book your appointment today.',
|
'variables' => [
|
'name' => 'term_name',
|
'city' => ['callback' => function ($term_id, $context) {
|
$meta = new \JVBase\meta\MetaManager($term_id, 'term');
|
$city_id = $meta->getValue('city');
|
if ($city_id && term_exists((int)$city_id, BASE . 'city')) {
|
$city_term = get_term($city_id, BASE . 'city');
|
if ($city_term && !is_wp_error($city_term)) {
|
return $city_term->name;
|
}
|
}
|
return 'Edmonton';
|
}],
|
'tagline_text' => ['callback' => function ($term_id) {
|
$meta = new \JVBase\meta\MetaManager($term_id, 'term');
|
$tagline = $meta->getValue('tagline');
|
return $tagline ? " - {$tagline}" : '';
|
}],
|
'established_text' => ['callback' => function ($term_id) {
|
$meta = new \JVBase\meta\MetaManager($term_id, 'term');
|
$established = $meta->getValue('established');
|
return $established ? " Established in {$established}" : '';
|
}],
|
'artist_count' => ['callback' => function ($term_id) {
|
$artists = get_posts([
|
'post_type' => BASE . 'artist',
|
'tax_query' => [[
|
'taxonomy' => BASE . 'shop',
|
'terms' => $term_id
|
]],
|
'posts_per_page' => -1,
|
'fields' => 'ids'
|
]);
|
return count($artists);
|
}],
|
]
|
],
|
|
'schema' => [
|
'type' => 'LocalBusiness',
|
'additional_types' => ['TattooParlor'],
|
'properties' => [
|
'address' => 'address',
|
'telephone' => 'phone',
|
'email' => 'email',
|
'openingHours' => 'hours',
|
'priceRange' => 'price_range',
|
'image' => 'logo',
|
'url' => ['callback' => function ($term_id) {
|
$meta = new \JVBase\meta\MetaManager($term_id, 'term');
|
$website = $meta->getValue('website');
|
return $website ?: get_term_link($term_id);
|
}],
|
'sameAs' => ['callback' => function ($term_id) {
|
$meta = new \JVBase\meta\MetaManager($term_id, 'term');
|
$links = [];
|
if ($ig = $meta->getValue('instagram')) $links[] = $ig;
|
if ($fb = $meta->getValue('facebook')) $links[] = $fb;
|
return !empty($links) ? $links : null;
|
}],
|
'memberOf' => [
|
'@id' => 'https://edmonton.ink/#organization'
|
],
|
]
|
]
|
]);
|
|
// STYLE
|
$taxonomies['style'] = array_merge($taxonomies['style'] ?? [], [
|
'seo' => [
|
'title_template' => 'Edmonton {{name}} Tattoo Artists | Specialists in {{name}}',
|
'description_template' => '{{name}}{{alt_names}} is a distinctive tattoo style. {{characteristics}} Find Edmonton artists specializing in {{name}} tattoos.',
|
'variables' => [
|
'name' => 'term_name',
|
'alt_names' => ['callback' => function ($term_id) {
|
$meta = new \JVBase\meta\MetaManager($term_id, 'term');
|
$alts = $meta->getValue('alternate_name');
|
if (!empty($alts) && is_array($alts)) {
|
$names = array_filter(array_column($alts, 'name'));
|
if (!empty($names)) {
|
return ' (also known as ' . implode(', ', array_slice($names, 0, 2)) . ')';
|
}
|
}
|
return '';
|
}],
|
'characteristics' => ['meta' => 'characteristics', 'truncate' => 100],
|
]
|
],
|
|
'schema' => [
|
'type' => 'CreativeWork',
|
'properties' => [
|
'name' => ['callback' => function ($term_id) {
|
return get_term($term_id)->name . ' Tattoo Style';
|
}],
|
'description' => 'characteristics',
|
'about' => ['meta' => 'description'],
|
'alternateName' => ['callback' => function ($term_id) {
|
$meta = new \JVBase\meta\MetaManager($term_id, 'term');
|
$alts = $meta->getValue('alternate_name');
|
if (!empty($alts) && is_array($alts)) {
|
return array_filter(array_column($alts, 'name'));
|
}
|
return null;
|
}],
|
]
|
]
|
]);
|
|
// THEME
|
$taxonomies['theme'] = array_merge($taxonomies['theme'] ?? [], [
|
'seo' => [
|
'title_template' => 'Edmonton {{name}} Tattoos | Find {{name}} Tattoo Designs',
|
'description_template' => 'Explore {{name}} tattoos, a popular motif in Edmonton\'s tattoo scene. {{similar}}Find artists specializing in {{name}} designs.',
|
'variables' => [
|
'name' => 'term_name',
|
'similar' => ['callback' => function ($term_id) {
|
$meta = new \JVBase\meta\MetaManager($term_id, 'term');
|
$similar = $meta->getValue('similar');
|
if (!empty($similar)) {
|
$similar_names = [];
|
foreach ((array)$similar as $similar_id) {
|
$term = get_term($similar_id, BASE . 'theme');
|
if ($term && !is_wp_error($term)) {
|
$similar_names[] = html_entity_decode($term->name);
|
}
|
}
|
if (!empty($similar_names)) {
|
return 'Similar themes include ' . implode(', ', array_slice($similar_names, 0, 2)) . '. ';
|
}
|
}
|
return '';
|
}],
|
]
|
],
|
|
'schema' => [
|
'type' => 'CreativeWork',
|
'properties' => [
|
'name' => ['callback' => function ($term_id) {
|
return get_term($term_id)->name . ' Tattoo Theme';
|
}],
|
'description' => ['meta' => 'description'],
|
]
|
]
|
]);
|
|
// CITY
|
$taxonomies['city'] = array_merge($taxonomies['city'] ?? [], [
|
'seo' => [
|
'title_template' => '{{name}} Tattoo Artists & Shops | edmonton.ink',
|
'description_template' => 'Discover {{name}}\'s vibrant tattoo scene featuring {{shop_count}} local shops and {{artist_count}} talented artists. Find top local talent and book your next tattoo today.',
|
'variables' => [
|
'name' => 'term_name',
|
'shop_count' => ['callback' => function ($term_id) {
|
$shops = get_terms([
|
'taxonomy' => BASE . 'shop',
|
'meta_key' => BASE . 'city',
|
'meta_value' => $term_id,
|
'fields' => 'count'
|
]);
|
return is_wp_error($shops) ? 0 : $shops;
|
}],
|
'artist_count' => ['callback' => function ($term_id) {
|
$artists = get_posts([
|
'post_type' => BASE . 'artist',
|
'tax_query' => [[
|
'taxonomy' => BASE . 'city',
|
'terms' => $term_id
|
]],
|
'posts_per_page' => -1,
|
'fields' => 'ids'
|
]);
|
return count($artists);
|
}],
|
]
|
],
|
|
'schema' => [
|
'type' => 'Place',
|
'properties' => [
|
'address' => ['callback' => function ($term_id) {
|
$term = get_term($term_id);
|
return [
|
'@type' => 'PostalAddress',
|
'addressLocality' => html_entity_decode($term->name),
|
'addressRegion' => 'Alberta',
|
'addressCountry' => 'CA'
|
];
|
}],
|
]
|
]
|
]);
|
|
return $taxonomies;
|
});
|