'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('the_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 = Meta::forPost($post_id); $schema = [ '@type' => 'Event', 'name' => get_the_title($post_id), 'url' => get_permalink($post_id), ]; $date = $meta->get('event_date'); if ($date) { $schema['startDate'] = date('c', strtotime($date)); } $venue = $meta->get('venue'); $venue_address = $meta->get('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 = Meta::forTerm($term_id); $city_id = $meta->get('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 = Meta::forTerm($term_id); $tagline = $meta->get('tagline'); return $tagline ? " - {$tagline}" : ''; }], 'established_text' => ['callback' => function ($term_id) { $meta = Meta::forTerm($term_id); $established = $meta->get('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 = Meta::forTerm($term_id); $website = $meta->get('website'); return $website ?: get_term_link($term_id); }], 'sameAs' => ['callback' => function ($term_id) { $meta = Meta::forTerm($term_id); $links = []; if ($ig = $meta->get('instagram')) $links[] = $ig; if ($fb = $meta->get('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 = Meta::forTerm($term_id); $alts = $meta->get('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 = Meta::forTerm($term_id); $alts = $meta->get('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 = Meta::forTerm($term_id); $similar = $meta->get('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; });