Jake Vanderwerf
2025-11-10 627056f72e761c1386e4ab4d72207008d9330a5e
=Cleaner base
4 files renamed
14 files deleted
6 files modified
18 files added
2416 ■■■■ changed files
ajakevan.php 142 ●●●●● patch | view | raw | blame | history
alegacy.php 254 ●●●●● patch | view | raw | blame | history
content/_setup.php 23 ●●●●● patch | view | raw | blame | history
content/art.php 46 ●●●●● patch | view | raw | blame | history
content/design.php 44 ●●●●● patch | view | raw | blame | history
content/development.php 45 ●●●●● patch | view | raw | blame | history
content/faq.php 143 ●●●●● patch | view | raw | blame | history
content/progress.php 129 ●●●●● patch | view | raw | blame | history
content/strategy.php 44 ●●●●● patch | view | raw | blame | history
content/support.php 27 ●●●●● patch | view | raw | blame | history
content/terms.php 67 ●●●●● patch | view | raw | blame | history
content/writing.php 44 ●●●●● patch | view | raw | blame | history
dashboard/_setup.php 83 ●●●●● patch | view | raw | blame | history
dashboard/setup.php 1 ●●●● patch | view | raw | blame | history
email/_setup.php 289 ●●●●● patch | view | raw | blame | history
files/fileManagement.php 52 ●●●● patch | view | raw | blame | history
forms/_setup.php 31 ●●●●● patch | view | raw | blame | history
forms/contact.php 60 ●●●●● patch | view | raw | blame | history
forms/get-an-estimate.php 92 ●●●●● patch | view | raw | blame | history
forms/nlp.php 123 ●●●●● patch | view | raw | blame | history
forms/partner.php 104 ●●●●● patch | view | raw | blame | history
forms/setup.php 1 ●●●● patch | view | raw | blame | history
login/_setup.php 40 ●●●●● patch | view | raw | blame | history
login/setup.php 18 ●●●●● patch | view | raw | blame | history
taxonomies/_setup.php 32 ●●●●● patch | view | raw | blame | history
taxonomies/age.php 29 ●●●●● patch | view | raw | blame | history
taxonomies/body-part.php 33 ●●●●● patch | view | raw | blame | history
taxonomies/city.php 37 ●●●●● patch | view | raw | blame | history
taxonomies/form.php 32 ●●●●● patch | view | raw | blame | history
taxonomies/goal.php 29 ●●●●● patch | view | raw | blame | history
taxonomies/media.php 34 ●●●●● patch | view | raw | blame | history
taxonomies/person.php 24 ●●●●● patch | view | raw | blame | history
taxonomies/progress.php 34 ●●●●● patch | view | raw | blame | history
taxonomies/section.php 17 ●●●●● patch | view | raw | blame | history
taxonomies/skin-type.php 30 ●●●●● patch | view | raw | blame | history
taxonomies/style.php 8 ●●●● patch | view | raw | blame | history
taxonomies/theme.php 12 ●●●● patch | view | raw | blame | history
taxonomies/timeline.php 27 ●●●●● patch | view | raw | blame | history
temp.php 92 ●●●● patch | view | raw | blame | history
users/_setup.php 20 ●●●● patch | view | raw | blame | history
users/client.php 22 ●●●● patch | view | raw | blame | history
users/enthusiast.php 2 ●●● patch | view | raw | blame | history
ajakevan.php
File was deleted
alegacy.php
New file
@@ -0,0 +1,254 @@
<?php
/*
Plugin Name: Legacy Extension
Plugin URI: https://legacytattooremoval.ca/
Description: An Extension of JakeVan Base, for Legacy Tattoo Removal.
Author: Jake Vanderwerf
Version: 1.0.0
Author URI: https://jakevan.ca/
Textdomain: altr
*/
//PLUGIN STRUCTURE
// /content/
//      art.php
//      design.php
//      development.php
//      _setup.php
//      strategy.php
//      writing.php
// /dashboard/
//      _setup.php
// /files/
//      fileManagement.php
// /forms/
//      _setup.php
// /login/
//      _setup.php
// /taxonomies/
//      city.php
//      form.php
//      media.php
//      progress.php
//      _setup.php
//      style.php
//      target.php
//      theme.php
// /users/
//      client.php
//      _setup.php
// ajakevan.php     <-- main plugin file
if (!defined('ABSPATH')) {
    exit;
}
use JVBase\managers\CacheManager;
add_filter('jvb_base', function () {
    return 'altr_';
});
const AJV_DIR = WP_PLUGIN_DIR . '/alegacy';
define('AJV_URL', plugin_dir_url(__FILE__));
require(AJV_DIR . '/content/_setup.php');
require(AJV_DIR . '/dashboard/_setup.php');
require(AJV_DIR . '/email/_setup.php');
require(AJV_DIR . '/forms/_setup.php');
require(AJV_DIR . '/login/_setup.php');
require(AJV_DIR . '/taxonomies/_setup.php');
require(AJV_DIR . '/users/_setup.php');
//require(AJV_DIR . '/files/fileManagement.php');
/**
 * Defines base options like:
 *         - directory & Membership
 *         - dashboard
 *         - membership settings (JVB_MEMBERSHIP)
 *         - post types (JVB_CONTENT)
 *         - taxonomies (JVB_TAXONOMY)
 *         - User Roles (JVB_USER)
 *         - enthusiast     = (bool) short form for a subscriber-like user that can collect content for reference
 *         - forum            = (bool) create a forum
 *         - member_only    = (bool) if forum and this is true, creates a member-only forum in the custom dashboard
 *
 * as well as central filters for
 *         - rewrite rules
 *         - archive title
 */
add_filter('jvb_site', 'altr_setup_site');
function altr_setup_site():array
{
    return [
        'icons'               => 'light',
        'is_directory'        => true,        //as in, a membership directory
        'has_membership'      => false,
        'has_map'             => true,
        'dashboard'           => true,
        'referrals'           => true,
        'magicLink'           => true,
        'support'         => false,
        'feed_block'      => true,
        'email_notifications' => false,
        'integrations'  => [
            'bluesky'     => true,
            'cloudflare'  => true,
            'facebook'    => true,
            'maps'        => true,
            'gmb'         => true,
            'helcim'      => false,
            'postmark'    => true,
            'instagram'   => true,
            'square'      => false,
            'umami'       => true,
        ],
        'is_restaurant'       => false,
        'limit_hours'         => false,
        'enthusiast'          => false,
        'favourites'          => false,    //optional flag to allow enthusiasts, but not favourites
    ];
}
/**
 * JVB_MEMBERSHIP defines the structure of the directory
 *         Options include:
 *         - membership_expires        = useful if members pay a yearly membership fee
 *         - hide_expired                = removes users once membership expired; only used if membership_expires is true
 *         - clip_expired                = keeps users once membership expires, but limits the information shown; only used if membership_expires is true
 *         - membership_approval        = verified users can approve other users
 *         - term_approval              = (bool) verified users can create new terms, but needs approval
 *          - member_only              = (array) if empty, open to any registered user. otherwise an array of registered user roles
 */
//add_filter('jvb_membership', 'altr_setup_membership');
//function altr_setup_membership():array
//{
//    return [
//        'member_content'  => true,
//        'can_invite'      => ['artist' => ['artist']],
//        'member_verified' => true,
//        'notifications'   => true,
//        'forum'           => true,
//        'member_only'     => [ 'artist' ],
//        'member_expires'  => false,
//        'hide_expired'    => false,
//        'clip_expired'    => false,
//        'term_approval'   => true,
//        'can_approve'     => [ 'artist' ]
//    ];
//}
//
//add_filter('jvbLoadingQuips', 'altr_loading_quips');
//function altr_loading_quips(array $quips):array
//{
//    return [];
//}
add_filter('jvbAboveHeader', 'altr_legacy_header');
function altr_legacy_header(string $header):string
{
    return '<p><b>WED - SUN</b> <span class="hide-small">&emsp;</span>10<span class="hide-small">:00</span>AM - 6<span class="hide-small">:00</span>PM</p><p>By Appointment<span class="hide-small"> Only</span></p>';
}
add_filter('jvbMenuExtra', 'altr_contact_nav', 10, 3);
function altr_contact_nav(string $nav, string $menuName, array $block):string
{
    if (array_key_exists('attrs', $block)
        && array_key_exists('className', $block['attrs'])
        && $block['attrs']['className'] === 'is-style-fixed'
        && $nav === '') {
        $call = '<li class="call"><a href="'.jvbPhoneLink(8259257398).'" title="Call Us">'.jvbIcon('phone').'<span class="screen-reader-text">Call Us</span></a></li>';
        $text = '<li><a href="'.jvbTextLink(8259257398).'" title="Text Us">'.jvbIcon('chat').'<span class="hide-small">825.925.7398</span><sup class="hide-small">PEWU</sup></a></li>';
        $email = '<li><a href="'.jvbMailToLink(
            'info@legacytattooremoval.ca',
                'Contact from Our Website'
            ).'" title="Email Us">'.jvbIcon('envelope').'<span class="hide-small">info@legacytattooremoval.ca</span></a></li>';
        return $call.$text.$email;
    }
    if (array_key_exists('attrs', $block)
        && array_key_exists('className', $block['attrs'])
        && $block['attrs']['className'] === 'is-style-floating'
    ) {
        return $nav.'<li><ul class="socials">
            <li>
                <a href="https://www.facebook.com/LegacyTattooRemoval/" target="_blank" rel="nofollow" title="Find us on Facebook">
                    '.jvbIcon('facebook-logo').'
                    <span class="screen-reader-text">
                        Find us on Facebook
                    </span>
                </a>
            </li>
            <li>
                <a href="https://www.instagram.com/LegacyTattooRemoval/" target="_blank" rel="nofollow" title="Find us on Instagram">
                    '.jvbIcon('instagram-logo').'
                    <span class="screen-reader-text">
                        Find us on Instagram
                    </span>
                </a>
            </li>
            <li>
                <a href="https://bsky.app/profile/legacyrebrand.test" target="_blank" rel="nofollow" title="Find us on Bluesky">
                    '.jvbIcon('butterfly').'
                    <span class="screen-reader-text">
                        Find us on Bluesky
                    </span>
                </a>
            </li>
        </ul></li>';
    }
    return $nav;
}
add_filter('jvbBeforeFooter', 'alyns_acknowledgement');
function alyns_acknowledgement():string
{
    return '<p>amiskwacîwâskahikan ᐊᒥᐢᑲᐧᒋᐋᐧᐢᑲᐦᐃᑲᐣ</p><p><a href="https://www.treatysix.org/#comp-lkljqlw1" title="Learn More">Treaty 6 territory</a></p><p>Edmonton, Alberta, Canada</p>';
}
add_action('jvbBlockStyles', 'altr_blockStyles');
function altr_blockStyles()
{
    register_block_style(
        'core/list',
        [
            'name'=>'blocky',
            'label' => __('Blocky', 'altr')
        ]
    );
    register_block_style(
        'core/group',
        [
            'name'=>'triangle',
            'label' => __('Triangle', 'altr')
        ]
    );
}
function altr_render_core_post_excerpt(array $block, string $content)
{
    global $post;
    if (!has_excerpt($post)) {
        return '';
    }
    $excerpt = $post->post_excerpt;
    $before = is_singular() ? '<span class="tldr" title="Too Long, Didn\'t Read">TLDR:</span>' : '';
    $excerpt = $before.$excerpt;
    return '<div class="excerpt">'.apply_filters('the_content', $excerpt).'</div>';
}
add_action( 'init', 'altr_add_excerpts_to_pages' );
function altr_add_excerpts_to_pages() {
    add_post_type_support( 'page', 'excerpt' );
}
content/_setup.php
File was renamed from content/setup.php
@@ -28,22 +28,17 @@
 *  - 'section' => (string) the slug of the section, as defined above
 */
require(AJV_DIR . '/content/art.php');
require(AJV_DIR . '/content/design.php');
require(AJV_DIR . '/content/development.php');
require(AJV_DIR . '/content/strategy.php');
require(AJV_DIR . '/content/support.php');
require(AJV_DIR . '/content/writing.php');
add_filter('jvb_content', 'ajv_content');
function ajv_content($content):array
require(AJV_DIR . '/content/faq.php');
require(AJV_DIR . '/content/progress.php');
require(AJV_DIR . '/content/terms.php');
add_filter('jvb_content', 'altr_content');
function altr_content($content):array
{
    return [
        'design'        => ajv_design(),
        'development'   => ajv_development(),
        'strategy'      => ajv_strategy(),
        'art'           => ajv_art(),
        'writing'       => ajv_writing(),
        'support'       => ajv_support(),
        'faq'       => altr_faq(),
        'progress'  => altr_progress(),
        'terms'     => altr_terms(),
    ];
}
content/art.php
File was deleted
content/design.php
File was deleted
content/development.php
File was deleted
content/faq.php
New file
@@ -0,0 +1,143 @@
<?php
// /content/faq.php
function altr_faq():array
{
    return [
        'singular'       => 'Frequently Asked Question',
        'plural'       => 'Frequently Asked Questions',
        'dash_description' => 'Manage your answers',
        'capability_type' => ['faq', 'faqs'],
        'breadcrumb'    => 'FAQ',
        'dash_title'    => 'FAQs',
        'icon'         => 'question',
        'rewrite_taxonomy' => 'section',
        'rewrite'      => [
            'slug'       => 'faq',
            'with_front' => false,
        ],
        'fields'       => [
            'post_title'     => [
                'type'  => 'text',
                'label' => 'Question',
            ],
            'post_status'         => [
                'type'      => 'radio',
                'label'     => 'Status',
                'hidden'    => true,
                'options'   => [
                    'publish'   => 'Show',
                    'draft'     => 'Hide',
                    'trash'     => 'Scrap',
                    'delete'    => 'Permanently Delete'
                ]
            ],
            'post_content'        => [
                'type'  => 'textarea',
                'label' => 'Answer',
                'quill' => true,
            ],
        ],
        'single_image' => false,
        'upload_title' => 'Upload Before & Afters',
    ];
}
add_action('wp_enqueue_scripts', 'nebDashScripts', 9999);
function nebDashScripts() {
    global $wp;
    $page = str_replace('dash/', '', $wp->request);
    if ($page === 'settings') {
        wp_enqueue_script('jvb-form');
        wp_enqueue_script('jvb-tabs');
        wp_enqueue_script('jvb-populate-form');
        wp_enqueue_script('jvb-copy-hours');
        wp_enqueue_script('jvb-quill');
        wp_enqueue_script('jvb-store');
        $script = 'function loadSettingsPage() {
            let tabs = new window.jvbTabs(document.querySelector(".replace"));
                        let store = new window.jvbStore({
                            name: "options",
                            endpoint: "options",
                            headers: {
                                "action_nonce": jvbSettings.dash,
                            }
                        });
                        let form = new window.jvbForm(store);
                        let forms = [ "#hours", "#menu-sections"];
                        let setForms = {};
                        forms.forEach(f => {
                            let gotF = document.querySelector(`form${f}`);
                            setForms[f] = form.registerForm(gotF);
                        });
                        form.subscribe((event, data) => {
                            switch (event) {
                                case "form-submit":
                                case "form-autosave":
                                    window.jvbQueue.addToQueue({
                                        endpoint: "options",
                                        headers: {
                                            "action_nonce": jvbSettings.dash,
                                        },
                                        data: data.changes,
                                        popup: `Saving options...`,
                                        title: "Saving Options"
                                    });
                                    break;
                            }
                        });
                    }
                    document.addEventListener("DOMContentLoaded", ()=>{
                       loadSettingsPage()
                    });
                    ';
        $output = wp_add_inline_script('jvb-form', $script, 'after');
    } elseif ($page === 'dash') {
        wp_enqueue_script('jvb-form');
        wp_enqueue_script('jvb-store');
        $script = 'function loadDashPage() {
                let store = new window.jvbStore({
                    name: "options",
                    endpoint: "options",
                    headers: {
                        "action_nonce": jvbSettings.dash,
                    }
                });
                let form = new window.jvbForm(store);
                let forms = [ "#options"];
                let setForms = {};
                forms.forEach(f => {
                    let gotF = document.querySelector(`form${f}`);
                    setForms[f] = form.registerForm(gotF);
                });
                form.subscribe((event, data) => {
                    switch (event) {
                        case "form-submit":
                        case "form-autosave":
                            window.jvbQueue.addToQueue({
                                endpoint: "options",
                                headers: {
                                    "action_nonce": jvbSettings.dash,
                                },
                                data: data.changes,
                                popup: `Saving options...`,
                                title: "Saving Options"
                            });
                            break;
                    }
                });
            }
            document.addEventListener("DOMContentLoaded", ()=>{
               loadDashPage()
            });
            ';
//        $output = wp_add_inline_script('jvb-form', $script, 'after');
    }
}
content/progress.php
New file
@@ -0,0 +1,129 @@
<?php
// /content/progress.php
function altr_progress():array
{
    return [
        'singular'       => 'Before & After',
        'plural'       => 'Before & Afters',
        'dash_title'    => 'Progress',
        'dash_description' => 'Manage your before and after posts',
        'breadcrumb'    => 'Before & Afters',
        'capability_type' => ['progress', 'progress'],
        'hide_children' => true,
        'is_timeline'   => true,
        'show_feed'    => true,
        'hierarchical'  => true,
        'icon'         => 'arrows-left-right',
        'rewrite'      => [
            'slug'       => 'before-and-after',
            'with_front' => false,
        ],
        'sections'  => [
            'progression'   => [
                'label' => 'Progression',
            ]
        ],
        'fields'       => [
            'post_title'     => [
                'type'  => 'text',
                'label' => 'Title',
                'quickEdit' => true,
                'section'   => 'progression',
                'for_all'   => true,
            ],
            'post_status'         => [
                'type'      => 'radio',
                'label'     => 'Status',
                'hidden'    => true,
                'options'   => [
                    'publish'   => 'Show',
                    'draft'     => 'Hide',
                    'trash'     => 'Scrap',
                    'delete'    => 'Permanently Delete'
                ],
                'section'   => 'progression',
                'for_all'   => true,
            ],
            'post_thumbnail'                => [
                'type'      => 'image',
                'label'     => 'Image',
                'quickEdit' => true,
                'section'   => 'progression',
                'for_all'   => true,
            ],
            'person' => [
                'type'  => 'taxonomy',
                'taxonomy'  => 'person',
                'autocomplete' => true,
                'label' => 'Person',
                'quickEdit' => true,
                'createNew' => true,
                'section'   => 'progression',
                'hint'      => 'Not public, just to make it easier to find'
            ],
            'goal' => [
                'type'  => 'taxonomy',
                'taxonomy'  => 'goal',
                'autocomplete' => true,
                'label' => 'Goal',
                'quickEdit' => true,
                'createNew' => true,
                'section'   => 'progression'
            ],
            'timeline' => [
                'type'  => 'taxonomy',
                'taxonomy'  => 'timeline',
                'autocomplete' => true,
                'label' => 'Timeline',
                'quickEdit' => true,
                'createNew' => true,
                'section'   => 'progression',
                'for_all'   => true,
            ],
            'body-part' => [
                'type'  => 'taxonomy',
                'taxonomy'  => 'body-part',
                'label' => 'Body Part',
                'autocomplete' => true,
                'quickEdit' => true,
                'createNew' => true,
                'section'   => 'progression'
            ],
            'style' => [
                'type'  => 'taxonomy',
                'taxonomy'  => 'style',
                'autocomplete' => true,
                'label' => 'Tattoo Style',
                'quickEdit' => true,
                'createNew' => true,
                'section'   => 'progression'
            ],
            'skin-type' => [
                'type'  => 'taxonomy',
                'taxonomy'  => 'skin-type',
                'label' => 'Skin Type',
                'autocomplete' => true,
                'quickEdit' => true,
                'createNew' => true,
                'section'   => 'progression'
            ],
            'age' => [
                'type'  => 'taxonomy',
                'taxonomy'  => 'age',
                'autocomplete'      => true,
                'label' => 'Age of Tattoo',
                'quickEdit' => true,
                'createNew' => true,
                'section'   => 'progression'
            ],
            'post_content'   => [
                'type'  => 'textarea',
                'quill' => true,
                'label' => 'Notes',
                'section'   => 'progression',
                'for_all'   => true,
            ]
        ],
        'upload_title' => 'Upload Before & Afters',
    ];
}
content/strategy.php
File was deleted
content/support.php
File was deleted
content/terms.php
New file
@@ -0,0 +1,67 @@
<?php
// /content/terms.php
function altr_terms():array
{
    return [
        'singular'       => 'Term',
        'plural'       => 'Terms',
        'dash_title'    => 'Glossary',
        'dash_description' => 'Manage your terms',
        'breadcrumb'    => 'Glossary',
        'hide_single'  => true,
        'icon'         => 'asterisk',
        'is_gallery'    => true,
        'rewrite'      => [
            'slug'       => 'glossary',
            'with_front' => false,
        ],
        'fields'       => [
            'post_title'     => [
                'type'  => 'text',
                'label' => 'Title',
            ],
            'post_status'         => [
                'type'      => 'radio',
                'label'     => 'Status',
                'hidden'    => true,
                'options'   => [
                    'publish'   => 'Show',
                    'draft'     => 'Hide',
                    'trash'     => 'Scrap',
                    'delete'    => 'Permanently Delete'
                ]
            ],
            'post_slug' => [
                'type'  => 'text',
                'label' => 'Slug'
            ],
            'post_content'        => [
                'type'  => 'textarea',
                'label' => 'Definition',
                'quill' => true,
            ],
            'pronunciation' => [
                'type'  => 'repeater',
                'label' => 'Pronunciation',
                'fields' => [
                    'part'  => [
                        'type'  => 'text',
                        'label' => 'Part',
                    ]
                ]
            ],
            'type'  => [
                'type'  => 'radio',
                'label' => 'Type',
                'options' => [
                    'adjective',
                    'noun',
                    'verb'
                ]
            ]
        ],
        'single_image' => false,
        'upload_title' => 'Upload Before & Afters',
    ];
}
content/writing.php
File was deleted
dashboard/_setup.php
New file
@@ -0,0 +1,83 @@
<?php
add_filter('jvb_options', function() {
    return [
        'fields' => [
            'today_hours'  => [
                'type'  => 'group',
                'label' => 'Hours',
                'fields' => [
                    'time_start'    => [
                        'type'   => 'time',
                        'label' => 'Open'
                    ],
                    'time_end'    => [
                        'type'   => 'time',
                        'label' => 'Closed'
                    ],
                ]
            ],
            'common' => ['hours'],
            'open_to_public' => [
                'type'   => 'true_false',
                'label' => 'Open to Public?'
            ],
        ]
    ];
});
add_filter('jvbAdminDashboard', 'nebAdminDashboard');
function nebAdminDashboard(string $content):string
{
    $user = wp_get_current_user()->display_name;
    $meta = new JVBase\meta\MetaManager(null, 'options');
    $fields = ['today_hours', 'open_to_public'];
    $temp = [];
    $saved = jvbGetFields('options', 'options');
    foreach ($fields as $field) {
        $temp[$field] = $saved[$field];
    }
    $fields = $temp;
    return $meta->renderForm(
        'options',
        [
            'heading' => 'Hi '.$user.'!',
            'description'   => 'Do you have availability today?',
            'submit'    => true,
            'classes'   => ['col']
        ],
        $fields,
        false,
        true
    );
}
add_filter('jvbDashboardSettings', 'nebDashboardSettings');
function nebDashboardSettings(string $content):string
{
    $meta = new JVBase\meta\MetaManager(null, 'options');
    ob_start();
    $meta->render('render', 'hours');
    ?>
    <form id="hours" data-save="options" data-form-id="set-hours">
        <?php
        $meta->render('form', 'hours',null,false,false);
        ?>
    </form>
    <?php
    $hours = ob_get_clean();
    $tabs = [
        'hours' => [
            'title'         => 'Hours',
            'description'   => 'If you are open regular hours you can list your hours here. When you log in to set your location, it pulls from this record first. Updates your Google Business Listing automatically.',
            'content'       => $hours,
        ],
    ];
    return jvbRenderTabs($tabs, true);
}
dashboard/setup.php
File was deleted
email/_setup.php
New file
@@ -0,0 +1,289 @@
<?php
$jvbEmail = add_filter('jvb_email', 'altr_email');
function altr_email(array $defaults):array
{
    return [
        'colours'       => [
            'action-0'      => '#ff0080',
            'action-50'     => '#ff2492',
            'action-100'    => '#ff47a4',
            'action-200'    => '#ff6bb5',
            'secondary-0'   => '#D69121',
            'secondary-50'  => '#ffc421',
            'secondary-100' => '#ffcd44',
            'secondary-200' => '#ffd768',
            'light'         => '#efefef',
            'light-50'      => '#e2e2e2',
            'light-100'     => '#d5d5d5',
            'light-200'     => '#c9c9c9',
            'dark'          => '#151515',
            'dark-50'       => '#222222',
            'dark-100'      => '#2e2e2e',
            'dark-200'      => '#3b3b3b',
            'action-contrast'=> '',
            'secondary-contrast'=> '',
        ],
        'content'       => [
            'title'             => get_bloginfo('name'),
            'subjectPrefix'     => '['.get_bloginfo('name').']',
            'signature'         => '<p>&emsp; —  ♡ the edmonton.ink crew</p>',
            'footer'    => [
                '<p>&copy; ' . date('Y') . ' edmonton.ink — Your tattoo scene on your screen.</p>',
                '<p><a href="' . get_home_url() . '" class="text-link">edmonton.ink</a></p>'
            ]
        ],
        'types' => [
            'newUser' => [
                'subject'       => 'Welcome to Legacy! Finish creating your account.',
                'showPrefix'    => true,
            ],
            'resetPass' => [
                'subject'   => 'Reset your Password'
            ],
            'emailChange'   => [
                'subject'   => 'Successfully Changed Email'
            ],
            'passwordChange'    => [
                'subject'   => 'Successfully Changed Password',
            ]
        ]
    ];
}
/*
 * EXTEND WITH:
 *      {string} $message: email content
*       {WP_User} $user: user
 * apply_filters
 *      jvbNewUserEmail         ->  New user email content
 *          add_filter('jvbNewUserEmail', 'customFunction', 10, 2);
 *      jvbNewUserAdminEmail    ->  New User notification for admin
 *          add_filter('jvbNewUserAdminEmail', 'customFunction', 10, 2);
 *      jvbPasswordResetEmail   ->  Password Reset Email
 *          {string} $message: email content
 *          {string} $key
 *          {string} $user_login,
 *          {WP_User} $user_data
 *          add_filter('jvbPasswordResetEmail', 'customFunction', 10, 4);
 *      jvbEmailChangeRequestEmail      ->  Request for email change
 *          {string} $message
 *          {array} $oldUser
 *          {array} newUser
 *          add_filter('jvbEmailChangeRequestEmail', 'customFunction', 10, 3);
 *      jvbEmailChangedEmail    ->  Notification that email successfully changed
 *          {string} $message
 *          {string} $confirm_url
            add_filter('jvbEmailChangedEmail', 'customFunction', 10, 2);
 *      jvbPasswordChangeEmail  ->  Request for password change
 *          {string} $message
 *          {array} $oldUser
 *          {array} $newUser
 *          add_filter('jvbPasswordChangeEmail', 'customFunction', 10, 3);
 *      jvbPersonalDataExport   ->  Request for User Data
 *          {string} $message
 *          {string} $request_type
 *          {string} $confirmation_url
 *          {array} $emailData, from the original filter
 *          add_filter('jvbPersonalDataExport', 'customFunction', 10, 4);
 *      jvbPersonalDataExported ->  Notification that data is ready for download
 *          {string} $message
 *          {string} $downloadURL
 *          {string} $expiresAt
 *          {array} $emailData, from the original filter
 *          add_filter('jvbPersonalDataExported', 'customFunction', 10, );
 *
 */
add_filter('jvbNewUserEmail', 'altr_new_user_email', 10, 2);
function altr_new_user_email(string $message, WP_User $user):string
{
    $user_login = $user->user_login;
    // Only create the password key if the user can change their password
    $key = get_password_reset_key($user);
    if (!is_wp_error($key)) {
        $reset_url = network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login');
        $message = sprintf(
            '<p>Hey %s!</p>
            <p>Thanks for signing up for our referral program at Legacy.</p>
            <p><b>Login with your email: </b> %s</p>
            <p>To set your password and access your account, click the button below:</p>%s
            <p>Or copy and paste this link into your browser: %s</p>
            <p>Or go passwordless, and just sign on with a magic link.</p>
            <div class="divider"></div>
            <p>If you didn\'t create this account, just ignore this email and the link will expire.</p>',
            $user->display_name,
            $user->user_login,
            jvbMailButton($reset_url, 'Set Your Password'),
            jvbEmailLink($reset_url)
        );
    }
    return $message;
}
/*** EDMONTON INK VERSIONS: ***/
function eink_new_user_email(string $message, WP_User $user):string
{
    $user_login = $user->user_login;
    // Only create the password key if the user can change their password
    $key = get_password_reset_key($user);
    if (!is_wp_error($key)) {
        $reset_url = network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login');
        $message = sprintf('<p>Hey %s!</p>', $user->first_name);
        $message .= '<p>Thanks for joining Edmonton\'s tattoo scene. Here\'s your login information:</p>';
        $message .= sprintf('<p><strong>Username:</strong> %s</p>', $user_login);
        $message .= '<p>To set your password and access your account, click the button below:</p>';
        $message .= sprintf('<p style="text-align: center;"><a href="%s" class="button">Set Your Password</a></p>', $reset_url);
        $message .= '<p>Or copy and paste this link into your browser:</p>';
        $message .= sprintf('<p style="user-select:all;">%s</p>', $reset_url);
        $message .= '<p>This link will expire in 24 hours, for security reasons.</p>';
        if (in_array('jvb_artist', array_values($user->roles))) {
            $message .= '<div class="divider"></div>';
            $message .= '<h3>NOTE:</h3>
                    <p>Once you set your password, you\'ll have access to your custom dashboard where you can:</p>
                    <ul>
                        <li>Manage your profile information</li>
                        <li>Upload tattoos/piercings, and artwork</li>
                    </ul>
                    <p>Nothing will be published until you\'ve been approved by 3 already approved artists, or the admin.</p>
                    <p>Admins check every day or three, but, if you are in a rush, you can contact us directly by replying to this email, or texting us at 825-925-9916.</p>';
        } elseif (in_array('jvb_partner', array_values($user->roles))) {
            $message .= '<div class="divider"></div>';
            $message .= '<h3>NOTE:</h3>
                    <p>Once you set your password, you\'ll have access to your custom dashboard where you can:</p>
                    <ul>
                        <li>Manage your profile information</li>
                        <li>Create offers for enthusiasts or partners or both</li>
                    </ul>
                    <p>Nothing will be published until you\'ve been approved by the admin.</p>
                    <p>Admins check every day or three, but, if you are in a rush, you can contact us directly by replying to this email, or texting us at 825-925-9916.</p>
                    <p><strong>Note:</strong>Even after approval by admin, your ability to publish depends on your karmic standing by artists. Artists each have a vote they can cast (UP or DOWN) - if your karmic score dips too far in the negative, you account is subject to reconsideration or even a ban.</p>';
        }
        $message .= '<div class="divider"></div>';
        $message .= '<p>If you didn\'t create this account, please ignore this email and the link will expire.</p>';
        $message .= sprintf('<p>Ink on, %s</p>', $user->first_name);
    }
    return $message;
}
function eink_new_user_admin_email(string $message, WP_User $user):string
{
    $message .= sprintf(
        '<p><strong>Role:</strong> %s</p>',
        str_replace(BASE, '', array_values($user->roles)[0])
    );
    return $message;
}
function eink_password_reset_email(string $message, string $user_login, WP_User $user, string $resetUrl):string
{
    return sprintf(
        '<p>Hi bud,</p>
            <p>We received a request to reset the password for an account associated with this email:</p>
            <p><strong>Username:</strong> %s</p>
            <p>If you didn\'t make this request, you can safely ignore this email and nothing will happen to your account.</p>
            <p>To reset your password, click the button below:</p>
            %s
            <p>Or copy and paste this link into your browser:</p>
            %s
            <div class="divider"></div>
            <p>This password reset link is only valid for 24 hours.</p>',
        $user_login,
        jvbMailButton($resetUrl,'Reset Password'),
        jvbEmailLink($resetUrl)
    );
}
function eink_email_change_request_email(string $message, array $oldUser, array $newUser)
{
    return sprintf(
        '<p>Hi %s,</p>
        <p>Ideally you already know this: someone asked to change your email, and here we are.</p>
        <p><strong>Old Email:</strong> %s</p>
        <p><strong>New Email:</strong> %s</p>
        <div class="divider"></div>
        <p>If this is news to you, or you did not request this - please contact us immediately. You can <a href="sms:+18258239916">text us</a> or reply to this email."></a></p>
        %s',
        $newUser['first_name'],
        $oldUser['user_email'],
        $newUser['user_email'],
        jvbMailButton(wp_login_url(), 'Log In To Your Account')
    );
}
function eink_email_changed_email(string $message, string $confirmURL):string
{
    return sprintf(
        '<p>Hey human,</p>
            <p>Seems you want to change the email associated with your account.</p>
            <p>If you really want this, please confirm this change by clicking the button below:</p>
            %s
            <p>Or copy and paste this link into your browser:</p>
            %s',
        jvbMailButton($confirmURL, 'Confirm this Email'),
        jvbEmailLink($confirmURL)
    );
}
function eink_password_changed_email(string $message, array $oldUser, array $newUser):string
{
    return sprintf(
        '<p>Hey bud,</p>
            <p>This is a confirmation email to let you know your password has successfully been changed.</p>
            <p>Ideally, you\'re expecting this email. You wanted to change your password, and this is to let you know that it\'s definitely updated.</p>
            <p>If you\'re not expecting this email, and did not change your password - please <strong>contact us immediately</strong></p>
            <p>You can <a href="sms:+18259257398">text us</a>, or reply to this email.</p>
            %s',
        jvbMailButton(wp_login_url(), 'Log In to Your Account')
    );
}
function eink_personal_data_export(string $message, string $requestType, string $confirmURL, array $emailData):string
{
    switch ($requestType) {
        case 'export_personal_data':
            $request_name = 'Export Personal Data';
            break;
        case 'remove_personal_data':
            $request_name = 'Erase Personal Data';
            break;
        default:
            $request_name = 'Data Request';
    }
    return sprintf(
        '<p>Hi privacy enthusiast,</p>
            <p>You\'re receiving this email because a request has been made to <strong>%s</strong></p>
            <p>If you\'re the one who made this request, you can confirm it by clicking the button below:</p>
            %s
            <p>Or copy and paste this link into your browser:</p>
            %s',
        $request_name,
        jvbMailButton($confirmURL, 'Confirm'),
        jvbEmailLink($confirmURL)
    );
}
function eink_personal_data_exported_email(string $message, string $downloadURL, string $expiresAt, array $emailData):string
{
    return sprintf(
        '<p>Hi again,</p>
            <p>You\'re receiving this email because you requested an export of your personal data.</p>
            <p>You can download your personal data by clicking the button below:</p>
            %s
            <p>Or you can copy and paste this link into your browser:</p>
            %s
            <div class="divider"></div>
            <p><strong>Important:</strong> For privacy and security, this link will expire at %s.</p>',
        jvbMailButton($downloadURL, 'Download Your Data'),
        jvbEmailLink($downloadURL),
        $expiresAt
    );
}
files/fileManagement.php
@@ -4,8 +4,8 @@
 * Custom upload directory structure for edmonton.ink
 * Recreates the original directory logic with shops, artists, partners, etc.
 */
add_filter('jvb_upload_directory', 'ajv_upload_directory', 10, 4);
function ajv_upload_directory($path, $post_type, $user_id, $term_id)
add_filter('jvb_upload_directory', 'altr_upload_directory', 10, 4);
function altr_upload_directory($path, $post_type, $user_id, $term_id)
{
    switch ($post_type) {
        case 'shop':
@@ -37,8 +37,8 @@
 * Custom filename generation for edmonton.ink
 * Recreates the original SEO-friendly filename logic
 */
add_filter('jvb_upload_filename', 'ajv_filename', 10, 6);
function ajv_filename($filename, $original_name, $user_data, $post_type, $user_id, $term_id)
add_filter('jvb_upload_filename', 'altr_filename', 10, 6);
function altr_filename($filename, $original_name, $user_data, $post_type, $user_id, $term_id)
{
    // Get artist/shop/partner details
    $post = (int)get_user_meta($user_id, BASE . 'link', true);
@@ -61,13 +61,13 @@
                '%s-best-tattoo-shop-%s-%s',
                sanitize_title($city),
                sanitize_title($shop_term->name),
                ajv_get_counter($user_id, $post_type)
                altr_get_counter($user_id, $post_type)
            );
        case 'artist':
            // Profile images: {city}-best-{type}-{specialties}-{name}
            $type = jvbArtistType($post);
            $specialties = ajv_get_artist_top_styles($post);
            $specialties = altr_get_artist_top_styles($post);
            return sprintf(
                '%s-best-%s-%s-%s-%s',
@@ -75,7 +75,7 @@
                sanitize_title($type),
                sanitize_title($specialties),
                sanitize_title($user_data->display_name),
                ajv_get_counter($user_id, $post_type)
                altr_get_counter($user_id, $post_type)
            );
        case 'partner':
@@ -87,13 +87,13 @@
                sanitize_title($city),
                sanitize_title($service_type),
                sanitize_title($user_data->display_name),
                ajv_get_counter($user_id, $post_type)
                altr_get_counter($user_id, $post_type)
            );
        case 'tattoo':
            // Get style and subject if available
            $style = ajv_get_primary_taxonomy($post, BASE . 'style');
            $subject = ajv_get_primary_taxonomy($post, BASE . 'theme');
            $style = altr_get_primary_taxonomy($post, BASE . 'style');
            $subject = altr_get_primary_taxonomy($post, BASE . 'theme');
            return sprintf(
                '%s-%s-%s-tattoo-by-%s-%s',
@@ -101,13 +101,13 @@
                sanitize_title($style),
                sanitize_title($subject),
                sanitize_title($user_data->display_name),
                ajv_get_counter($user_id, $post_type)
                altr_get_counter($user_id, $post_type)
            );
        case 'artwork':
            // Get style and subject if available
            $style = ajv_get_primary_taxonomy($post, BASE . 'artstyle');
            $subject = ajv_get_primary_taxonomy($post, BASE . 'arttheme');
            $style = altr_get_primary_taxonomy($post, BASE . 'artstyle');
            $subject = altr_get_primary_taxonomy($post, BASE . 'arttheme');
            return sprintf(
                '%s-%s-%s-artwork-by-%s-%s',
@@ -115,19 +115,19 @@
                sanitize_title($style),
                sanitize_title($subject),
                sanitize_title($user_data->display_name),
                ajv_get_counter($user_id, $post_type)
                altr_get_counter($user_id, $post_type)
            );
        case 'piercing':
            // Get style if available
            $style = ajv_get_primary_taxonomy($post, BASE . 'pstyle');
            $style = altr_get_primary_taxonomy($post, BASE . 'pstyle');
            return sprintf(
                '%s-%s-piercing-by-%s-%s',
                sanitize_title($city),
                sanitize_title($style),
                sanitize_title($user_data->display_name),
                ajv_get_counter($user_id, $post_type)
                altr_get_counter($user_id, $post_type)
            );
        default:
@@ -139,7 +139,7 @@
                sanitize_title($city),
                sanitize_title($content_type),
                sanitize_title($user_data->display_name),
                ajv_get_counter($user_id, $post_type)
                altr_get_counter($user_id, $post_type)
            );
    }
}
@@ -148,8 +148,8 @@
 * Custom alt text generation for edmonton.ink
 * Recreates the original detailed alt text logic
 */
add_filter('jvb_upload_alt_text', 'ajv_alt_text', 10, 7);
function ajv_alt_text($alt_text, $file, $user_data, $post_id, $post_type, $user_id, $term_id)
add_filter('jvb_upload_alt_text', 'altr_alt_text', 10, 7);
function altr_alt_text($alt_text, $file, $user_data, $post_id, $post_type, $user_id, $term_id)
{
    $post = get_user_meta($user_id, BASE . 'link', true);
@@ -174,7 +174,7 @@
            );
        case 'artist':
            $specialties = ajv_get_artist_top_styles($post);
            $specialties = altr_get_artist_top_styles($post);
            return sprintf(
                'A photo of %s %s %s, specializing in %s tattoos',
@@ -237,8 +237,8 @@
 * Custom image title generation for edmonton.ink
 * Recreates the original SEO-friendly title logic
 */
add_filter('jvb_upload_image_title', 'ajv_image_title', 10, 7);
function ajv_image_title($title, $file, $user_data, $post_id, $post_type, $user_id, $term_id)
add_filter('jvb_upload_image_title', 'altr_image_title', 10, 7);
function altr_image_title($title, $file, $user_data, $post_id, $post_type, $user_id, $term_id)
{
    $post = get_user_meta($user_id, BASE . 'link', true);
@@ -342,7 +342,7 @@
/**
 * Get the next file counter for edmonton.ink style counters
 */
function ajv_get_counter($user_id, $post_type)
function altr_get_counter($user_id, $post_type)
{
    // Get counter key for this post type
    $counter_key = BASE . str_replace(BASE, '', $post_type) . '_counter';
@@ -363,7 +363,7 @@
/**
 * Get artist's top styles for filename generation
 */
function ajv_get_artist_top_styles($post_id)
function altr_get_artist_top_styles($post_id)
{
    if (!function_exists('JVBase\\meta\\MetaManager')) {
        // Fallback if MetaManager not available
@@ -403,7 +403,7 @@
/**
 * Get primary taxonomy term for content
 */
function ajv_get_primary_taxonomy($post_id, $taxonomy)
function altr_get_primary_taxonomy($post_id, $taxonomy)
{
    $terms = wp_get_post_terms($post_id, $taxonomy, array('fields' => 'names'));
    if (is_wp_error($terms) || empty($terms)) {
@@ -416,7 +416,7 @@
 * Get partner type (placeholder - implement based on your edmonton.ink logic)
 * This function was referenced in the original but not provided
 */
function ajv_partner_type($post_id)
function altr_partner_type($post_id)
{
    // Implement based on your edmonton.ink logic
    // This might look at a taxonomy or meta field
forms/_setup.php
New file
@@ -0,0 +1,31 @@
<?php
/*************************************************************
 *
 *  Filters the forms for the form block
 *      Must contain an array with:
 *          'title'         => {string} optional
 *          'description    => {array} of strings, each entry becoming its own <p></p>
 *          'submit'        => {string} submit button text
 *          'success_title' => {string} a custom heading for the success message
 *          'success_message'=> {array} of strings, each entry becoming its own <p></p>
 *          'email_subject' => {string} subject for admin's email
 *          'fields'        => {array} as per MetaManager.php
 *          'sections'      => {array} optional array of sections, as per MetaManager.php, for a tabbed form
 *
 ************************************************************/
require(AJV_DIR . '/forms/get-an-estimate.php');
require(AJV_DIR . '/forms/nlp.php');
require(AJV_DIR . '/forms/contact.php');
require(AJV_DIR . '/forms/partner.php');
add_filter('jvb_register_forms', 'altr_register_forms');
function altr_register_forms($forms) {
    $forms['get_an_estimate']   = altr_get_an_estimate();
    $forms['nlp']               = altr_nlp();
    $forms['contact']           = altr_contact();
    $forms['partner']           = altr_nlp_partner();
    return $forms;
}
forms/contact.php
New file
@@ -0,0 +1,60 @@
<?php
function altr_contact():array
{
    return [
        'title'         => 'Contact',
        'description'   => [
            'You can always text, call, or email.',
            'Or you can fill out this form and we\'ll get back to you as soon as we can.',
        ],
        'submit'        => 'Contact',
        'success_title' => 'Success!',
        'success_description'   => [
            'We got it.',
            'We\'ll get back to you as soon as we can - usually pretty quick (unless it\'s a Monday or a Tuesday)'
        ],
        'email_subject' => '[CONTACT]',
        'fields'        => [
            'first_name'    => [
                'type'  => 'text',
                'label' => 'First Name',
                'required' => true,
                'section'   => 'about_you',
            ],
            'last_name'     => [
                'type'  => 'text',
                'label' => 'Last Name',
                'required' => true,
                'section'   => 'about_you',
            ],
            'email'         => [
                'type'  => 'email',
                'label' => 'Email',
                'required' => true,
                'section'   => 'about_you',
            ],
            'phone'         => [
                'type'  => 'tel',
                'label' => 'Phone',
                'required' => true,
                'section'   => 'about_you',
            ],
            'contact'       => [
                'type'  => 'checkbox',
                'label' => 'Preferred Contact',
                'options'   => [
                    'text'      => 'Text',
                    'email'     => 'Email',
                    'call'      => 'Call',
                ],
                'section'   => 'about_you',
            ],
            'message'   => [
                'type'  => 'textarea',
                'quill' => true,
                'label' => 'What do you want to say?'
            ]
        ]
    ];
}
forms/get-an-estimate.php
New file
@@ -0,0 +1,92 @@
<?php
function altr_get_an_estimate():array
{
    return [
        'title'         => 'Get an Estimate',
        'submit'        => 'Get your estimate',
        'success_title' => 'Success!',
        'success_description'   => [
            'We got it.',
            'We\'ll get back to you as soon as we can - usually pretty quick (unless it\'s a Monday or a Tuesday)'
        ],
        'email_subject' => 'New Estimate Request',
        'fields'        => [
            'first_name'    => [
                'type'  => 'text',
                'label' => 'First Name',
                'required' => true,
                'section'   => 'about_you',
            ],
            'last_name'     => [
                'type'  => 'text',
                'label' => 'Last Name',
                'required' => true,
                'section'   => 'about_you',
            ],
            'email'         => [
                'type'  => 'email',
                'label' => 'Email',
                'required' => true,
                'section'   => 'about_you',
            ],
            'phone'         => [
                'type'  => 'tel',
                'label' => 'Phone',
                'required' => true,
                'section'   => 'about_you',
            ],
            'contact'       => [
                'type'  => 'checkbox',
                'label' => 'Preferred Contact',
                'options'   => [
                    'text'      => 'Text',
                    'email'     => 'Email',
                    'call'      => 'Call',
                ],
                'section'   => 'about_you',
            ],
            'age'   => [
                'type'      => 'text',
                'subtype'   => 'number',
                'label'     => 'How old is your tattoo?',
                'section'   => 'tattoo',
            ],
            'location'  => [
                'type'      => 'radio',
                'label'     => 'Location on Body',
                'options'   => [
                    'face'      => 'Face',
                    'neck'      => 'Neck',
                    'scalp'     => 'Scalp',
                    'chest'     => 'Chest',
                    'back'      => 'Back',
                    'arm'       => 'Arm',
                    'hand'      => 'Hand',
                    'finger'    => 'Finger',
                    'butt'      => 'Butt',
                    'genitals'  => 'Genitals',
                    'leg'       => 'Leg',
                    'foot'      => 'Foot'
                ],
                'section'   => 'tattoo',
            ],
            'goal'      => [
                'type'      => 'radio',
                'label'     => 'Removal Goal',
                'options'   => [
                    'cover_up'          => 'Fading for a Cover Up Tattoo',
                    'complete_removal'  => 'Complete Removal',
                    'clean_up'          => 'Clean Up',
                ],
                'section'   => 'tattoo',
            ],
            'photos'        => [
                'type'  => 'gallery',
                'label' => 'Photo(s) of Tattoo',
                'section'   => 'tattoo',
                'description'   => 'Make sure we can get a sense of scale.'
            ]
        ]
    ];
}
forms/nlp.php
New file
@@ -0,0 +1,123 @@
<?php
function altr_nlp():array
{
    return [
        'title'         => 'New Legacy Program',
//        'description'   => '',
        'submit'        => 'Apply Now',
        'success_title' => 'Success!',
        'success_description'   => [
            'We got it.',
            'We\'ll get back to you as soon as we can - usually pretty quick (unless it\'s a Monday or a Tuesday)'
        ],
        'email_subject' => '[NLP] Application',
        'fields'        => [
            'first_name'    => [
                'type'  => 'text',
                'label' => 'First Name',
                'required' => true,
                'section'   => 'about_you',
            ],
            'last_name'     => [
                'type'  => 'text',
                'label' => 'Last Name',
                'required' => true,
                'section'   => 'about_you',
            ],
            'email'         => [
                'type'  => 'email',
                'label' => 'Email',
                'required' => true,
                'section'   => 'about_you',
            ],
            'phone'         => [
                'type'  => 'tel',
                'label' => 'Phone',
                'required' => true,
                'section'   => 'about_you',
            ],
            'contact'       => [
                'type'  => 'checkbox',
                'label' => 'Preferred Contact',
                'options'   => [
                    'text'      => 'Text',
                    'email'     => 'Email',
                    'call'      => 'Call',
                ],
                'section'   => 'about_you',
            ],
            'type'   => [
                'type'      => 'checkbox',
                'label'     => 'Type of Tattoo',
                'options'   => [
                    'gang'  => 'Gang Affiliated',
                    'hate'  => 'Hateful Symbolism',
                    'dv'    => 'Domestic Violence',
                    'trafficking'   => 'Human Trafficking',
                    'prison'        => 'Prison or Jail',
                    'other'
                ],
                'section'   => 'tattoo',
            ],
            'referred'   => [
                'type'      => 'checkbox',
                'label'     => 'Referred By',
                'options'   => [
                    'po'        => 'Parole Officer',
                    'sw'  => 'Social Worker',
                    'cow'    => 'Community Outreach Worker',
                    'doctor'   => 'Doctor',
                    'mental_health' => 'Mental Health Worker',
                    'sponsor' => 'Sponsor',
                    'other'
                ],
                'section'   => 'tattoo',
            ],
            'age'   => [
                'type'      => 'text',
                'subtype'   => 'number',
                'label'     => 'How old is your tattoo?',
                'section'   => 'tattoo',
            ],
            'location'  => [
                'type'      => 'radio',
                'label'     => 'Location on Body',
                'options'   => [
                    'face'      => 'Face',
                    'neck'      => 'Neck',
                    'scalp'     => 'Scalp',
                    'chest'     => 'Chest',
                    'back'      => 'Back',
                    'arm'       => 'Arm',
                    'hand'      => 'Hand',
                    'finger'    => 'Finger',
                    'butt'      => 'Butt',
                    'genitals'  => 'Genitals',
                    'leg'       => 'Leg',
                    'foot'      => 'Foot'
                ],
                'section'   => 'tattoo',
            ],
            'photos'        => [
                'type'  => 'gallery',
                'label' => 'Photo(s) of Tattoo',
                'section'   => 'tattoo',
                'hint'   => 'Make sure we can get a sense of scale.'
            ],
            'docs'        => [
                'type'  => 'files',
                'subtype'   => '.doc,.pdf,.txt,.jpg',
                'label' => 'Letter of Support',
                'section'   => 'tattoo',
                'hint'   => 'Please provide a letter written by one of the above mentioned people that referred you who are working alongside you building your New Legacy.'
            ],
            'notes' => [
                'type'  => 'textarea',
                'label' => 'Anything else to add?',
                'quill' => true,
                'section'   => 'tattoo',
            ]
        ]
    ];
}
forms/partner.php
New file
@@ -0,0 +1,104 @@
<?php
function altr_nlp_partner():array
{
    return [
        'title'         => 'Partner with Us',
//        'description'   => '',
        'submit'        => 'Submit Form',
        'success_title' => 'Success!',
        'success_description'   => [
            'We got it.',
            'We\'ll get back to you as soon as we can - usually pretty quick (unless it\'s a Monday or a Tuesday)'
        ],
        'email_subject' => '[Partner] Inquiry',
        'fields'        => [
            'your_name'     => [
                'type'  => 'text',
                'label' => 'Your Name',
                'required'=> true,
                'section'   => 'about_you',
            ],
            'your_role'     => [
                'type'  => 'text',
                'label' => 'Your Role/Title',
                'required'=> true,
                'section'   => 'about_you',
            ],
            'email'         => [
                'type'  => 'email',
                'label' => 'Email',
                'required' => true,
                'section'   => 'about_you',
            ],
            'phone'         => [
                'type'  => 'tel',
                'label' => 'Phone',
                'required' => true,
                'section'   => 'about_you',
            ],
            'contact'       => [
                'type'  => 'checkbox',
                'label' => 'Preferred Contact',
                'options'   => [
                    'text'      => 'Text',
                    'email'     => 'Email',
                    'call'      => 'Call',
                ],
                'section'   => 'about_you',
            ],
            'organization_name'    => [
                'type'  => 'text',
                'label' => 'Organization Name',
                'required' => true,
                'section'   => 'organization',
            ],
            'website'     => [
                'type'  => 'url',
                'label' => 'Organization Website',
                'section'   => 'organization',
            ],
            'type'   => [
                'type'      => 'checkbox',
                'label'     => 'Organization Type',
                'options'   => [
                    'po'        => 'Parole Officer',
                    'sw'  => 'Social Services',
                    'cow'    => 'Community Outreach',
                    'doctor'   => 'Healthcare Provider',
                    'mental_health' => 'Mental Health Services',
                    'indigenous' => 'Indigenous Services',
                    'other'
                ],
                'section' => 'organization'
            ],
            'location'  => [
                'type'      => 'radio',
                'label'     => 'Where are your clients located?',
                'options'   => [
                    'yeg'      => 'Edmonton Area',
                    'elsewhere'=> 'Elsewhere in Alberta',
                    'other'=> 'Other'
                ],
                'section'   => 'organization',
            ],
            'intent'        => [
                'type'  => 'radio',
                'label' => 'Are you',
                'options'   => [
                    'individual'    => 'Referring a specific individual right now',
                    'partner'       => 'Exploring partnership opportunities',
                    'both'          => 'Both',
                ],
                'section'   => 'referrals',
            ],
            'notes' => [
                'type'  => 'textarea',
                'label' => 'Tell us more',
                'quill' => true,
                'section'   => 'referrals',
                'hint'  => 'What would be most helpful for us to know about your organization and the people you serve?'
            ]
        ]
    ];
}
forms/setup.php
File was deleted
login/_setup.php
New file
@@ -0,0 +1,40 @@
<?php
// /login/setup.php
add_filter('jvb_login', 'altr_setup_login');
function altr_setup_login():array
{
    return [
        'login' => [
            'title'        => 'Log in',
            'description'   => ['Log in to your account to see your referral balance and get your unique code!'],
            'submit'        => 'Log in',
        ],
        'favourites'    => [
            'title'         => 'Save your favourites'
        ],
        'lostpassword' => [
            'title'    => 'Forgot Your Password?',
            'description'   => 'No worries, we\'ll send you a reset link to your email.'
        ],
        'register'  => [
            'title'        => 'Create your Account',
            'submit'        => 'Create Account',
            'email'     => [
                'subject'   => '[Legacy] Finish Creating Your Account'
            ],
            'success'       => [
                'title' => 'Success!',
                'description' => [
                    'See your email for next steps.',
                    '(If you can\'t find it, check your junk!)',
                ],
            ]
        ],
        'magic' => [
            'title' => 'Log in, auto-magically!',
            'description' => [
                'Enter your email, click the link in your email, and bibbity bobbity boo - you\'re logged in!'
            ],
        ]
    ];
}
login/setup.php
File was deleted
taxonomies/_setup.php
File was renamed from taxonomies/setup.php
@@ -20,24 +20,28 @@
 *             -> add use_in_stats (bool) to use the field in user statistics
 */
require(AJV_DIR . '/taxonomies/city.php');
require(AJV_DIR . '/taxonomies/form.php');
require(AJV_DIR . '/taxonomies/media.php');
require(AJV_DIR . '/taxonomies/progress.php');
require(AJV_DIR . '/taxonomies/age.php');
require(AJV_DIR . '/taxonomies/body-part.php');
require(AJV_DIR . '/taxonomies/goal.php');
require(AJV_DIR . '/taxonomies/person.php');
require(AJV_DIR . '/taxonomies/section.php');
require(AJV_DIR . '/taxonomies/skin-type.php');
require(AJV_DIR . '/taxonomies/style.php');
require(AJV_DIR . '/taxonomies/target.php');
require(AJV_DIR . '/taxonomies/theme.php');
require(AJV_DIR . '/taxonomies/timeline.php');
//add_filter('jvb_taxonomy', 'ajv_taxonomy');
function ajv_taxonomy():array
add_filter('jvb_taxonomy', 'altr_taxonomy');
function altr_taxonomy():array
{
    return [
        'city'      => ajv_city(),
        'style'     => ajv_style(),
        'theme'     => ajv_theme(),
        'form'      => ajv_form(),
        'medium'    => ajv_media(),
        'target'    => ajv_target(),
        'progress'  => ajv_progress(),
        'age'       => altr_age(),
        'body-part' => altr_body_part(),
        'goal'      => altr_goal(),
        'person'    => altr_person(),
        'skin-type' => altr_skin_type(),
        'timeline'  => altr_timeline(),
        'style'     => altr_style(),
        'theme'     => altr_theme(),
        'section'   => altr_section(),
    ];
}
taxonomies/age.php
New file
@@ -0,0 +1,29 @@
<?php
// /taxonomies/target.php
function altr_age():array
{
    return [
        'singular'     => 'Age of Tattoo',
        'plural'       => 'Ages of Tattoo',
        'icon'         => 'cake',
        'show_feed'    => true,
        'rewrite'      => [
            'slug'         => 'age',
            'with_front'   => false,
            'hierarchical' => false,
        ],
        'hierarchical' => false,
        'for_content'  => [
            'progress',
        ],
        'fields'       => [
            'term_name' => [
                'label'     => 'Name',
                'type'      => 'text',
                'subtype'   => 'number',
                'quickEdit' => true,
            ],
            'common'    => [ 'wiki' ]
        ]
    ];
}
taxonomies/body-part.php
New file
@@ -0,0 +1,33 @@
<?php
// /taxonomies/form.php
function altr_body_part():array
{
    return [
        'singular'       => 'Location',
        'plural'         => 'Locations',
        'description'    => [
            'Location of the tattoo on body.'
        ],
        'icon'           => 'person',
        'show_feed'      => true,
        'show_directory' => true,
        'approve_new'    => false,
        'rewrite'        => [
            'slug'       => 'location',
            'with_front' => false,
            'hierarchical' => true,
        ],
        'hierarchical'   => true,
        'for_content'    => [
            'progress',
        ],
        'fields'         => [
            'term_name' => [
                'label'     => 'Name',
                'type'      => 'text',
                'quickEdit' => true,
            ],
            'common'    => [ 'wiki' ]
        ]
    ];
}
taxonomies/city.php
File was deleted
taxonomies/form.php
File was deleted
taxonomies/goal.php
New file
@@ -0,0 +1,29 @@
<?php
// /taxonomies/goal.php
function altr_goal():array
{
    return [
        'singular'       => 'Goal',
        'plural'         => 'Goals',
        'icon'           => 'crosshair',
        'description'    => [
            'Complete tattoo removal or fading for a cover up tattoo (or unknown)'
        ],
        'show_feed'      => true,
        'rewrite'        => [
            'slug'         => 'goal',
            'with_front'   => false,
        ],
        'for_content'    => [
            'progress',
        ],
        'fields'         => [
            'term_name' => [
                'label'     => 'Name',
                'type'      => 'text',
                'quickEdit' => true,
            ],
            'common'    => [ 'wiki' ]
        ]
    ];
}
taxonomies/media.php
File was deleted
taxonomies/person.php
New file
@@ -0,0 +1,24 @@
<?php
// /taxonomies/target.php
function altr_person():array
{
    return [
        'singular'     => 'Person',
        'plural'       => 'People',
        'icon'         => 'user',
        'show_feed'    => false,
        'public'        => false,
        'show_ui'       => true,
        'hierarchical' => false,
        'for_content'  => [
            'progress',
        ],
        'fields'       => [
            'term_name' => [
                'label'     => 'Name',
                'type'      => 'text',
                'quickEdit' => true,
            ]
        ]
    ];
}
taxonomies/progress.php
File was deleted
taxonomies/section.php
File was renamed from taxonomies/target.php
@@ -1,29 +1,26 @@
<?php
// /taxonomies/target.php
function ajv_target():array
function altr_section():array
{
    return [
        'singular'     => 'Target Audience',
        'plural'       => 'Target Audiences',
        'icon'         => 'crosshair-simple',
        'singular'     => 'Section',
        'plural'       => 'Sections',
        'icon'         => 'folder',
        'show_feed'    => false,
        'rewrite'      => [
            'slug'         => 'target',
            'slug'         => 'faq',
            'with_front'   => false,
            'hierarchical' => true,
        ],
        'hierarchical' => true,
        'for_content'  => [
            'art',
            'design',
            'development',
            'strategy',
            'writing',
            'faq',
        ],
        'fields'       => [
            'term_name' => [
                'label'     => 'Name',
                'type'      => 'text',
                'subtype'   => 'number',
                'quickEdit' => true,
            ],
            'common'    => [ 'wiki' ]
taxonomies/skin-type.php
New file
@@ -0,0 +1,30 @@
<?php
// /taxonomies/media.php
function altr_skin_type():array
{
    return [
        'singular'       => 'Skin Type',
        'plural'         => 'Skin Types',
        'description'    => [
            'According to the FitzPatrick Scale (1 - 6)',
        ],
        'icon'           => 'dots-six',
        'show_feed'      => true,
        'show_directory' => true,
        'rewrite'        => [
            'slug'         => 'skin-type',
            'with_front'   => false,
        ],
        'for_content'    => [
            'progress'
        ],
        'fields'         => [
            'term_name' => [
                'label'     => 'Name',
                'type'      => 'text',
                'quickEdit' => true,
            ],
            'common'    => [ 'wiki' ]
        ]
    ];
}
taxonomies/style.php
@@ -1,6 +1,6 @@
<?php
// /taxonomies/style.php
function ajv_style():array
function altr_style():array
{
    return [
        'directory'    => 'Styles',
@@ -21,11 +21,7 @@
        ],
        'hierarchical' => true,
        'for_content'  => [
            'art',
            'design',
            'development',
            'strategy',
            'writing',
            'progress',
        ],
        'fields'       => [
            'term_name'       => [
taxonomies/theme.php
@@ -1,6 +1,6 @@
<?php
// /taxonomies/theme.php
function ajv_theme():array
function altr_theme():array
{
    return [
        'directory'    => 'Themes',
@@ -12,10 +12,8 @@
        ],
        'singular'     => 'Theme',
        'plural'       => 'Themes',
        'icon'         => 'hashtag',
        'favouritable' => true,
        'icon'         => 'hash',
        'show_feed'    => true,
        'approve_new'  => false,
        'rewrite'      => [
            'slug'         => 'themes',
            'with_front'   => false,
@@ -23,11 +21,7 @@
        ],
        'hierarchical' => true,
        'for_content'  => [
            'art',
            'design',
            'development',
            'strategy',
            'writing',
            'progress',
        ],
        'fields'       => [
            'term_name'       => [
taxonomies/timeline.php
New file
@@ -0,0 +1,27 @@
<?php
// /taxonomies/progress.php
function altr_timeline():array
{
    return [
        'singular'       => 'Timeline',
        'plural'         => 'Timelines',
        'icon'           => 'hourglass',
        'show_feed'      => true,
        'show_directory' => true,
        'rewrite'        => [
            'slug'         => 'timeline',
            'with_front'   => false,
        ],
        'for_content'    => [
            'progress',
        ],
        'fields'         => [
            'term_name' => [
                'label'     => 'Name',
                'type'      => 'text',
                'quickEdit' => true,
            ],
            'common'    => [ 'wiki' ]
        ]
    ];
}
temp.php
@@ -36,7 +36,7 @@
use JVBase\managers\CacheManager;
add_filter('jvb_base', function () {
    return 'ajv_';
    return 'altr_';
});
@@ -68,8 +68,8 @@
 *         - rewrite rules
 *         - archive title
 */
add_filter('jvb_site', 'ajv_setup_site');
function ajv_setup_site(): array
add_filter('jvb_site', 'altr_setup_site');
function altr_setup_site(): array
{
    return [
        'icons' => 'light',
@@ -108,8 +108,8 @@
 *         - term_approval              = (bool) verified users can create new terms, but needs approval
 *          - member_only              = (array) if empty, open to any registered user. otherwise an array of registered user roles
 */
//add_filter('jvb_membership', 'ajv_setup_membership');
//function ajv_setup_membership():array
//add_filter('jvb_membership', 'altr_setup_membership');
//function altr_setup_membership():array
//{
//    return [
//        'member_content'  => true,
@@ -126,15 +126,15 @@
//    ];
//}
add_filter('jvbLoadingQuips', 'ajv_loading_quips');
function ajv_loading_quips(array $quips): array
add_filter('jvbLoadingQuips', 'altr_loading_quips');
function altr_loading_quips(array $quips): array
{
    return [];
}
// /content/art.php
function ajv_art(): array
function altr_art(): array
{
    return [
        'singular' => 'Art',
@@ -181,7 +181,7 @@
// /content/design.php
function ajv_design(): array
function altr_design(): array
{
    return [
        'singular' => 'Graphic Design',
@@ -226,7 +226,7 @@
// /content/development.php
function ajv_development(): array
function altr_development(): array
{
    return [
        'singular' => 'Development',
@@ -306,22 +306,22 @@
require(AJV_DIR . '/content/support.php');
require(AJV_DIR . '/content/writing.php');
add_filter('jvb_content', 'ajv_content');
function ajv_content($content): array
add_filter('jvb_content', 'altr_content');
function altr_content($content): array
{
    return [
        'design' => ajv_design(),
        'development' => ajv_development(),
        'strategy' => ajv_strategy(),
        'art' => ajv_art(),
        'writing' => ajv_writing(),
        'support' => ajv_support(),
        'design' => altr_design(),
        'development' => altr_development(),
        'strategy' => altr_strategy(),
        'art' => altr_art(),
        'writing' => altr_writing(),
        'support' => altr_support(),
    ];
}
// /content/strategy.php
function ajv_strategy(): array
function altr_strategy(): array
{
    return [
        'singular' => 'Strategy',
@@ -366,7 +366,7 @@
// /content/support.php
function ajv_support(): array
function altr_support(): array
{
    return [
        'singular' => 'Support',
@@ -394,7 +394,7 @@
// /content/writing.php
function ajv_writing(): array
function altr_writing(): array
{
    return [
        'singular' => 'Writing',
@@ -439,8 +439,8 @@
// /login/setup.php
add_filter('jvb_login', 'ajv_setup_login');
function ajv_setup_login(): array
add_filter('jvb_login', 'altr_setup_login');
function altr_setup_login(): array
{
    return [
        'login_from_favourite_header' => 'Join the scene; <small>keep your collection.</small>',
@@ -458,7 +458,7 @@
// /taxonomies/city.php
function ajv_city(): array
function altr_city(): array
{
    return [
        'singular' => 'City',
@@ -495,7 +495,7 @@
}
// /taxonomies/form.php
function ajv_form(): array
function altr_form(): array
{
    return [
        'singular' => 'Form',
@@ -527,7 +527,7 @@
}
// /taxonomies/media.php
function ajv_media(): array
function altr_media(): array
{
    return [
        'singular' => 'Medium',
@@ -561,7 +561,7 @@
}
// /taxonomies/progress.php
function ajv_progress(): array
function altr_progress(): array
{
    return [
        'singular' => 'Progress',
@@ -623,22 +623,22 @@
require(AJV_DIR . '/taxonomies/target.php');
require(AJV_DIR . '/taxonomies/theme.php');
add_filter('jvb_taxonomy', 'ajv_taxonomy');
function ajv_taxonomy(): array
add_filter('jvb_taxonomy', 'altr_taxonomy');
function altr_taxonomy(): array
{
    return [
        'city' => ajv_city(),
        'style' => ajv_style(),
        'theme' => ajv_theme(),
        'form' => ajv_form(),
        'medium' => ajv_media(),
        'target' => ajv_target(),
        'progress' => ajv_progress(),
        'city' => altr_city(),
        'style' => altr_style(),
        'theme' => altr_theme(),
        'form' => altr_form(),
        'medium' => altr_media(),
        'target' => altr_target(),
        'progress' => altr_progress(),
    ];
}
// /taxonomies/style.php
function ajv_style(): array
function altr_style(): array
{
    return [
        'directory' => 'Styles',
@@ -677,7 +677,7 @@
}
// /taxonomies/target.php
function ajv_target(): array
function altr_target(): array
{
    return [
        'singular' => 'Target Audience',
@@ -709,7 +709,7 @@
}
// /taxonomies/theme.php
function ajv_theme(): array
function altr_theme(): array
{
    return [
        'directory' => 'Themes',
@@ -721,7 +721,7 @@
        ],
        'singular' => 'Theme',
        'plural' => 'Themes',
        'icon' => 'hashtag',
        'icon' => 'hash',
        'favouritable' => true,
        'show_feed' => true,
        'approve_new' => false,
@@ -767,7 +767,7 @@
// /users/client.php
function ajv_user_client(): array
function altr_user_client(): array
{
    return [
        'label' => 'Client',
@@ -788,7 +788,7 @@
}
// /users/enthusiast.php
function ajv_user_enthusiast(): array
function altr_user_enthusiast(): array
{
    return [
        'label' => 'Enthusiast',
@@ -838,12 +838,12 @@
require(AJV_DIR . '/users/client.php');
require(AJV_DIR . '/users/enthusiast.php');
add_filter('jvb_user', 'ajv_user');
add_filter('jvb_user', 'altr_user');
function ajv_user():array
function altr_user():array
{
    return [
        'enthusiast'    => ajv_user_enthusiast(),
        'client'        => ajv_user_client(),
        'enthusiast'    => altr_user_enthusiast(),
        'client'        => altr_user_client(),
    ];
}
users/_setup.php
File was renamed from users/setup.php
@@ -25,15 +25,15 @@
 *                             -> description of the user role. Used in the registration page
 */
//require(AJV_DIR . '/users/client.php');
require(AJV_DIR . '/users/client.php');
//require(AJV_DIR . '/users/enthusiast.php');
//add_filter('jvb_user', 'ajv_user');
//
//function ajv_user():array
//{
//    return [
////        'enthusiast'    => ajv_user_enthusiast(),
//        'client'        => ajv_user_client(),
//    ];
//}
add_filter('jvb_user', 'altr_user');
function altr_user():array
{
    return [
//        'enthusiast'    => altr_user_enthusiast(),
        'client'        => altr_user_client(),
    ];
}
users/client.php
@@ -1,21 +1,23 @@
<?php
// /users/client.php
function ajv_user_client():array
function altr_user_client():array
{
    return [
        'label'            => 'Client',
        'has_dashboard'    => true,
        'can_create'       => ['support'],
        'can_register'     => true,
        'keep_stats'       => true,
        'join_text'        => 'Save your favourites. Get Notified.',
        'join_title'       => 'Welcome to the Scene.',
        'join_description' => [
            'Save your favourites for easy access',
            'Get notified when your favourite artists add new content',
            'Stay in the loop with local flash days and events',
            'Discover styles and artists that match your vision'
        'keep_stats'       => false,
        'icon'             => 'user',
        'register'          => [
            'text'      => 'Refer your friends. Get rewarded.',
            'title'     => 'Create Your Account',
            'description'   => [
                'Get your unique share code',
                'Share it with your friends',
                'Get notified when you get your credit'
            ],
            'submit'    => 'Create Your Account',
        ],
        'join_bonus'       => '<strong>BONUS: </strong>Everything\'s free. And always will be. We work with partners vetted by the community to keep the lights on.',
    ];
}
users/enthusiast.php
@@ -1,6 +1,6 @@
<?php
// /users/enthusiast.php
function ajv_user_enthusiast():array
function altr_user_enthusiast():array
{
    return [
        'label'            => 'Enthusiast',