fromInvite()) {
$data = JVB()->routes('invites')->verifyInvitation(sanitize_text_field($_GET['invite']), sanitize_email($_GET['email']));
$name = $data->name;
$inviters = json_decode($data->inviters, true);
$names = [];
foreach ($inviters as $inviter) {
$artist = jvbContentFromUser((int)$inviter['user_id']);
$names[] = ($artist['name'] === '') ? $artist['display_name'] : $artist['name'];
}
$message = (count($names) > 1) ? 'are already here, and have invited you to join in!' : ' is already here, and inivited you to join in!';
return '
Join the Scene, '.$name.'
'.jvbCommaList($names).$message.'
';
}
if ($this->fromFavourites()) {
return '
Join the scene; keep your collection.
';
}
return '
Join the Scene
';
} else {
return '
Enter the Scene
';
}
}
/**
* @param string $login
*
* @return string
*/
public function setUserLogin(string $login):string
{
$user_type = isset($_POST['user_type']) ? $_POST['user_type'] : '';
if (!empty($user_type)) {
$email_field = $user_type . '_email';
if (isset($_POST[$email_field])) {
$email = sanitize_email($_POST[$email_field]);
if (is_email($email)) {
return $email;
}
}
}
return $login;
}
/**
* @param string $email
*
* @return string
*/
public function setUserEmail(string $email):string
{
$user_type = isset($_POST['user_type']) ? $_POST['user_type'] : '';
if (!empty($user_type)) {
$email_field = $user_type . '_email';
if (isset($_POST[$email_field])) {
$email = sanitize_email($_POST[$email_field]);
if (is_email($email)) {
return $email;
}
}
}
return $email;
}
/**
* @return void
*/
public function modifyRegistrationForm():void
{
if (!isset($_GET['action']) || $_GET['action'] !== 'register') {
return;
}
?>
routes('invites')->verifyInvitation($token, $email);
?>
document.querySelector('input#artist').checked = true;
document.querySelector('#artist_first_name').value = '=$data->name?>';
document.querySelector('#artist_email').value = '=$email?>';
to_shop) {
?>
document.querySelector('#artist_shop').value = '=$data->shop?>';
let form = document.getElementById('registerform')
let input = document.createElement('input');
let email = input.cloneNode(true);
input.type = 'hidden';
input.name = 'invite_token';
input.value = '= $token ?>';
email.type = 'hidden';
email.name = 'invite_email';
email.value = '= $email?>';
form.append(input);
form.append(email);
'jvb_shop',
'hide_empty' => true
));
// Get list of cities from your taxonomy
$cities = get_terms(array(
'taxonomy' => 'jvb_city',
'hide_empty' => false,
));
echo '';
?>
No algorithm.No BS.Just Art.
Drop by. Get Lost. Find your next artist.
fromFavourites()) {
?>
Save designs you love
Get personalized recommendations
Connect with artists
Build your inspiration collection
Bonus: It's all free!
Choose how you wish to interact with the community:
fromFavourites()) ? 'checked' : '' ?>>
Save your favourites. Get notified.
Show off your work.
Support the community.
Welcome to the scene.
Sign up with your email to:
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
BONUS: Everything's free. And always will be. We work with partners chosen by and for the community to keep the lights on.
Welcome to the scene!
We'll start small, with the basics. Before your profile goes live, we need to verify:
you are who you say you are
you work at the shop you listed
your certification
Optional — If you've been certified in bloodborne pathogen safety, or any other tattoo safety course, pass along your certificate. This just eases the verification process.
Click to upload or drag and drop
JPG, PNG, GIF or PDF (max. 5MB)
Once you click register:
We'll start looking into your information (usually within 24-48 hours)
You'll get a password reset email
Upon setting your password, you can start filling in your profile - but it won't go live until we've verified your information.
If you have any questions or concerns - or anything you'd like to follow up on - email us at get@edmonton.ink or message us on Instagram.
BONUS: Everything's free. And always will be. We work with partners chosen by and for the community to keep the lights on.
Howdy, partner!
We appreciate your interest!
edmonton.ink is a great place to showcase what you do, whether you:
provide goods or services that tattoo artists could use
provide goods or services that are tattoo adjacent (such as art, merch, etc)
provide goods or services that folks who love tattoos could also love
We'll start with some basics, then we'll reach out to follow up (usually within 24-48 hours).
Note: — you must have good standing in the tattoo community to stay a partner of edmonton.ink.
If we receive multiple requests to terminate a partnership with you from member artists, we reserve the right to cancel your listings.
invitation_data) {
// Pre-select artist type and populate email
?>
add('user_type_error', 'Please select your user type.');
return $errors;
}
// Get email based on user type
$email_field = $user_type . '_email';
$email = isset($_POST[$email_field]) ? sanitize_email($_POST[$email_field]) : '';
// Remove WordPress's default username error
$errors = new WP_Error();
// If this is an invited artist, validate the invitation
$invite = (array_key_exists('invite_token', $_POST)) ? sanitize_text_field($_POST['invite_token']) : false;
if ($invite&& $user_type === 'artist') {
$handler = JVB()->routes('invites');
$invitation = $handler->validateInvitation($invite, sanitize_email($_POST['invite_email']), sanitize_text_field($_POST['role']));
if (!$invitation) {
$errors->add('invalid_invitation', 'Invalid invitation token.');
} elseif (strtotime($invitation->expires_at) < current_time('timestamp')) {
$errors->add('expired_invitation', 'This invitation has expired.');
}
}
// Validate email first
if (empty($email)) {
$errors->add('email_error', 'Email is required.');
} elseif (!is_email($email)) {
$errors->add('email_error', 'Please enter a valid email address.');
} elseif (email_exists($email)) {
$errors->add('email_error', 'This email is already registered.');
}
switch ($user_type) {
case 'enthusiast':
if (empty($_POST['enthusiast_first_name'])) {
$errors->add('first_name_error', 'First name is required.');
}
break;
case 'artist':
$required_fields = array(
'artist_first_name' => 'First name',
'artist_last_name' => 'Last name',
'artist_shop' => 'Shop',
'artist_city' => 'City',
'artist_type' => 'Type',
);
foreach ($required_fields as $field => $label) {
if (empty($_POST[$field])) {
$errors->add($field . '_error', $label . ' is required.');
}
}
break;
case 'partner':
$required_fields = array(
'partner_name' => 'Contact name',
'partner_business' => 'Business name'
);
foreach ($required_fields as $field => $label) {
if (empty($_POST[$field])) {
$errors->add($field . '_error', $label . ' is required.');
}
}
break;
}
if (isset($_POST['user_type']) && $_POST['user_type'] === 'artist' && !empty($_FILES['certification_file']['name'])) {
$file = $_FILES['certification_file'];
// Validate file type
if (!in_array($file['type'], $this->allowed_file_types)) {
$errors->add('file_type_error', 'Please upload a valid file type (JPG, PNG, GIF, or PDF)');
}
// Validate file size
if ($file['size'] > $this->max_file_size) {
$errors->add('file_size_error', 'File size must be less than 5MB');
}
}
return $errors;
}
/**
* @param int $user_id
* @param array $userdata
*
* @return void
*/
public function saveRegistrationFields(int $user_id, array $userdata):void
{
$user_type = isset($_POST['user_type']) ? $_POST['user_type'] : false;
if (!$user_type) {
return;
}
$shop_id = $_POST['shop_id'] ?? false;
// Set user role based on type
$user = new WP_User($user_id);
$caps = JVB()->roles();
$email = false;
$upload_dir = wp_upload_dir();
$base_dir = $upload_dir['basedir'];
switch ($user_type) {
case 'artist':
$user->set_role('jvb_artist');
$user->remove_role('subscriber');
$email = sanitize_email($_POST['artist_email']);
$first = sanitize_text_field($_POST['artist_first_name']);
$last = sanitize_text_field($_POST['artist_last_name']);
$display_name = $first . ' ' . $last;
// Save artist fields
$temp = wp_update_user([
'ID' => $user_id,
'first_name' => $first,
'last_name' => $last,
'display_name' => $display_name
]);
$user = get_userdata($temp);
$link = $caps->addUserLink($user, 'artist');
$meta = new MetaManager($link, 'post');
$meta->updateValue('first_name', $first);
$meta->updateValue('email', $email);
// If this was an invited artist, handle the invitation
if (array_key_exists('invite_token', $_POST)) {
$handler = JVB()->routes('invites');
$handler->acceptInvitation(sanitize_text_field($_POST['invite_token']), sanitize_email($_POST['invite_email']), $user->ID);
$user->add_cap('skip_moderation', true);
}
if (absint($_POST['artist_shop']) > 0) {
JVB()->routes('shop')->requestShopAdmission($user_id, absint($_POST['artist_shop']));
}
if (absint($_POST['artist_city']) >0) {
wp_set_post_terms($link, (int)absint($_POST['artist_city']), BASE.'city');
}
//Create approval request and notify verified users
JVB()->routes('approvals')->createArtistApprovalRequest($user_id);
//Make base directories
$artist_dir = $base_dir . '/artists/' . $user_id;
wp_mkdir_p($artist_dir);
// Directories for all artists
wp_mkdir_p($artist_dir . '/artwork');
wp_mkdir_p($artist_dir . '/events');
// Add a directory for profile images
wp_mkdir_p($artist_dir . '/profile');
// Add a temp directory for uploads in progress
wp_mkdir_p($artist_dir . '/temp');
switch ($_POST['artist_type']) {
case 'tattoo-artist':
$caps->setUserAs($user, 'tattoo-artist');
$term = get_term_by('name', 'Tattoo Artists', BASE.'type');
if ($term && !is_wp_error($term)) {
wp_set_post_terms($link, $term->term_id, BASE.'type');
}
wp_mkdir_p($artist_dir . '/tattoos');
break;
case 'piercer':
$caps->setUserAs($user, 'piercer');
$term = get_term_by('name', 'Piercers', BASE.'type');
if ($term && !is_wp_error($term)) {
wp_set_post_terms($link, $term->term_id, BASE.'type');
}
wp_mkdir_p($artist_dir . '/piercings');
break;
}
break;
case 'partner':
$user->set_role('jvb_partner');
$user->remove_role('subscriber');
$name = sanitize_text_field($_POST['partner_name']);
$email = sanitize_email($_POST['partner_email']);
$caps->setUserAs($user, 'partner');
$link = $caps->addUserLink($user, 'partner');
// Save partner fields
update_user_meta($user_id, 'contact_name', sanitize_text_field($_POST['partner_name']));
update_user_meta($user_id, 'business_name', sanitize_text_field($_POST['partner_business']));
update_user_meta($user_id, 'business_website', esc_url_raw($_POST['partner_website']));
// Create partner base directory
$partner_dir = $base_dir . '/partners/' . $user_id;
wp_mkdir_p($partner_dir);
// Partner subdirectories
wp_mkdir_p($partner_dir . '/offers');
wp_mkdir_p($partner_dir . '/events');
wp_mkdir_p($partner_dir . '/profile');
wp_mkdir_p($partner_dir . '/temp');
break;
case 'enthusiast':
$user->set_role('jvb_enthusiast');
$user->remove_role('subscriber');
$caps->setUserAs($user, 'enthusiast');
$name = sanitize_text_field($_POST['enthusiast_first_name']);
$email = sanitize_email($_POST['enthusiast_email']);
// Save artist fields
$temp = wp_update_user([
'ID' => $user_id,
'first_name' => $name,
'user_email' => $email,
]);
break;
default:
break;
}
if (isset($_POST['user_type']) && $_POST['user_type'] === 'artist' && !empty($_FILES['certification_file']['name'])) {
$file = $_FILES['certification_file'];
// Setup upload directory
$upload_dir = wp_upload_dir();
$user_directory = 'artist-certifications/' . $user_id;
$target_dir = $upload_dir['basedir'] . '/' . $user_directory;
// Create directory if it doesn't exist
wp_mkdir_p($target_dir);
// Generate unique filename
$file_extension = pathinfo($file['name'], PATHINFO_EXTENSION);
$filename = 'certification-' . time() . '.' . $file_extension;
$target_file = $target_dir . '/' . $filename;
// Move uploaded file
if (move_uploaded_file($file['tmp_name'], $target_file)) {
// Save file information in user meta
update_user_meta($user_id, 'certification_file', array(
'url' => $upload_dir['baseurl'] . '/' . $user_directory . '/' . $filename,
'file' => $target_file,
'type' => $file['type'],
'original_name' => $file['name']
));
}
}
if (isset($_GET['list_token']) && !empty($_GET['list_token']) && isset($_GET['email'])) {
$token = sanitize_text_field($_GET['list_token']);
$email = sanitize_email($_GET['email']);
// Accept the list invitation for this new user
if ($email) {
JVB()->routes('favourites')->acceptListInvitation(
$token,
$email,
$user_id
);
}
}
}
/**
* @param WP_Error $errors
* @param string $redirect_to
*
* @return WP_Error
*/
public function registrationSuccessMessage(WP_Error $errors, string $redirect_to):WP_Error
{
if (isset($errors->errors['registered']) && isset($_POST['invitation_token'])) {
// Custom message for invited artists
$message = "WELCOME ABOARD!
" .
"Password setup is in your inbox. " .
"Since you were invited by a shop, you can skip the verification wait and start building your profile right away! ♡";
unset($errors->errors['registered']);
$errors->add('registered', $message, 'message');
}
if (isset($errors->errors['registered'])) {
$user_type = isset($_POST['user_type']) ? $_POST['user_type'] : 'user';
switch ($user_type) {
case 'enthusiast':
$message = "YOU'RE IN!
Check your inbox - we've sent password setup details. Get ready to build your dream artist collection! ♡";
break;
case 'artist':
$message = "HELL YEAH!
Password setup is in your inbox. While we verify your info (24-48hrs), you can start building your profile. Just remember - it stays underground until you're cleared. ♡";
break;
case 'partner':
$message = "ROCK ON!
Check your inbox - we've sent password setup details. We'll check out your pitch in the next 24-48hrs.
Meanwhile, you can start prepping your presence - but you won't hit the streets until we give the nod. ♡";
break;
default:
$message = "YOU'RE ON THE LIST!
Check your inbox for the next steps. ♡";
}
// Replace the default message
unset($errors->errors['registered']);
$errors->add('registered', $message, 'message');
}
return $errors;
}
/**
* @return bool
*/
protected function fromFavourites():bool
{
return isset($_GET['type']) && $_GET['type'] === 'favourites';
}
/**
* @return bool
*/
protected function fromInvite():bool
{
return isset($_GET['invite']) && isset($_GET['email']);
}
/**
* @param string $message
*
* @return string
*/
public function customRegisterMessage(string $message):string
{
return "Join Edmonton's tattoo community";
}
}
// Initialize the registration customizer
new RegisterManager();