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 = 'name?>'; document.querySelector('#artist_email').value = ''; to_shop) { ?> document.querySelector('#artist_shop').value = '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 = ''; email.type = 'hidden'; email.name = 'invite_email'; email.value = ''; 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()) { ?>

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:

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:

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:

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:

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();