function __construct() { if (func_num_args() == 1) { $args = func_get_args(); $lti_user_from_consumer = $args[0]; // Sharing --- this is Stephen's preference. $scope_userid = lti_get_scope($_SESSION[LTI_SESSION_PREFIX . 'userkey']); $user_login = $lti_user_from_consumer->getID($scope_userid); // Sanitize username stripping out unsafe characters $user_login = sanitize_user($user_login); // Apply the function pre_user_login before saving to the DB. $user_login = apply_filters('pre_user_login', $user_login); $this->username = $user_login; $this->firstname = $lti_user_from_consumer->firstname; $this->lastname = $lti_user_from_consumer->lastname; $this->fullname = $lti_user_from_consumer->fullname; $this->email = $lti_user_from_consumer->email; $role_name = ''; if (!empty($lti_user_from_consumer->roles)) { foreach ($lti_user_from_consumer->roles as $role) { $role_name .= $role . ','; } $this->roles = substr($role_name, 0, -1); } // Need to ensure that user who is both staff/student is treated as student $this->staff = $lti_user_from_consumer->isStaff() || $lti_user_from_consumer->isAdmin(); if ($lti_user_from_consumer->isLearner()) { $this->staff = FALSE; $this->learner = TRUE; } $this->provision = FALSE; $this->new_to_blog = FALSE; $this->changed = FALSE; $this->role_changed = ''; } if (func_num_args() == 0) { $this->username = ''; $this->delete = TRUE; } }
function lti_add_consumer() { global $wpdb; $options = get_site_option('lti_choices'); $editmode = $_REQUEST['action'] == 'edit'; if ($editmode) { $verb = 'Update'; } else { $verb = 'Add'; } ?> <script src="<?php echo plugins_url() . '/lti/js/GenKey.js'; ?> " language="javascript" type="text/javascript" > </script> <div id='form'> <h2><?php echo $verb . __(" Tool Consumer", 'lti-text'); ?> </h2> <p><?php echo $verb . __(' a tool consumer connecting to this site.', 'lti-text'); ?> </p> <form id="addlti" name="addlti" method="post" <?php if ($editmode) { ?> action="<?php echo plugins_url() . '/lti/includes/DoAddLTIConsumer.php?edit=true'; ?> " onsubmit="return verify()"> <?php } else { ?> action="" onsubmit="return createConsumer('<?php echo plugins_url(); ?> ')"> <?php } wp_nonce_field('add_lti', '_wpnonce_add_lti'); $button_text = __("{$verb} Tool Consumer", 'lti-text'); $type = "input"; if ($editmode) { $consumer = new LTI_Tool_Consumer($_REQUEST['lti'], array($wpdb->base_prefix)); } ?> <table class="form-table"> <tbody> <tr class="form-field form-required"> <th scope="row"> <label for="lti_name" id="lti_name_text"> <?php _e('Name', 'lti-text'); ?> <span id="req1" class="description"><?php _e('(required)', 'lti-text'); ?> </span> </label> </th> <td> <input id="lti_name" type="text" aria-required="true" value="<?php echo esc_attr($consumer->name); ?> " name="lti_name" class="regular-text"> </td> </tr> <tr class="form-field form-required"> <th scope="row"> <label for="lti_email_domain" id="lti_email_domain_text"> <?php _e('Primary Email Domain', 'lti-text'); ?> <span class="description"><?php _e('(The primary domain you expect your participant email addresses to originate from. If you expect student@example.edu, put example.edu in the field.)', 'lti-text'); ?> </span> </label> </th> <td> <input id="lti_email_domain" type="text" aria-required="true" value="<?php echo esc_attr($consumer->email_domain); ?> " name="lti_email_domain" class="regular-text"> </td> </tr> <?php if ($editmode) { ?> <tr class="form-field form-required"> <th scope="row"> <label for="lti_key" id="lti_key_text"> <?php _e('Key', 'lti-text'); ?> <span id="req2" class="description"><?php _e('(required)', 'lti-text'); ?> </span> </label> </th> <td> <?php echo esc_attr($consumer->getKey()); ?> <span class="description">(Consumer keys cannot be changed)</span> <input id="lti_key" type="hidden" aria-required="true" value="<?php echo esc_attr($consumer->getKey()); ?> " name="lti_key"> </td> </tr> <tr class="form-field form-required"> <th scope="row"> <label for="lti_secret" id="lti_secret_text"> <?php _e('Secret', 'lti-text'); ?> <span id="req3" class="description"><?php _e('(required)', 'lti-text'); ?> </span> </label> </th> <td> <input id="lti_secret" type="text" aria-required="true" value="<?php echo esc_attr($consumer->secret); ?> " name="lti_secret" class="regular-text"> </td> </tr> <?php } ?> <tr> <th scope="row"> <?php _e('Protected', 'lti-text'); ?> </th> <td> <fieldset> <legend class="screen-reader-text"> <span><?php _e('Protected', 'lti-text'); ?> </span> </legend> <label for="lti_protected"> <input name="lti_protected" type="checkbox" id="lti_protected" value="true" <?php checked(TRUE, $consumer->protected); ?> /> <?php _e('Restrict launch requests to the same tool consumer GUID parameter', 'lti-text'); ?> </label> </fieldset> </td> </tr> <tr> <th scope="row"> <?php _e('Enabled', 'lti-text'); ?> </th> <td> <fieldset> <legend class="screen-reader-text"> <span><?php _e('Enabled', 'lti-text'); ?> </span> </legend> <label for="lti_enabled"> <input name="lti_enabled" type="checkbox" id="lti_enabled" value="true" <?php checked(TRUE, $consumer->enabled); ?> /> <?php _e('Accept launch requests for this tool consumer', 'lti-text'); ?> </label> </fieldset> </td> </tr> <?php $from = $consumer->enable_from; if (is_null($from)) { $from = ''; } $until = $consumer->enable_until; if (is_null($until)) { $until = ''; } ?> <tr class="form-field"> <th scope="row"> <label for="lti_enable_form"> <?php _e('Enable From (e.g. 2013-01-26 12:34)', 'lti-text'); ?> </label> </th> <td> <input id="lti_enable_from" type="text" aria-required="true" value="<?php if (isset($from) && $from != "") { echo date('Y-m-d H:i', (int) $from); } ?> " name="lti_enable_from"> </td> <tr class="form-field"> <th scope="row"> <label for="lti_enable_until"> <?php _e('Enable Until (e.g. 2014-01-26 12:34)', 'lti-text'); ?> </label> </th> <td> <input id="lti_enable_until" type="text" aria-required="true" value="<?php if (isset($until) && $until != "") { echo date('Y-m-d H:i', (int) $until); } ?> " name="lti_enable_until"> </td> <tr> <?php if ($editmode) { ?> <tr> <th scope="row"> <?php _e('Username format', 'lti-text'); ?> </th> <td> <?php switch (lti_get_scope($consumer->getKey())) { case '4': _e('Global: Use email only', 'lti-text'); break; case '3': _e('Resource: Prefix the ID with the consumer key and resource link ID', 'lti-text'); break; case '2': _e('Context: Prefix the ID with the consumer key and context ID', 'lti-text'); break; case '1': _e('Consumer: Prefix the ID with the consumer key', 'lti-text'); break; case '0': _e('Global: Use ID value only', 'lti-text'); break; } ?> </td> <?php } else { ?> <th scope="row"> <?php _e('Username Format', 'lti-text'); ?> </th> <td> <fieldset> <legend class="screen-reader-text"> <span><?php _e('Resource: Prefix the ID with the consumer key and resource link ID', 'lti-text'); ?> </span> </legend> <!-- Swat Edit: Added lti_scope4 --> <label for="lti_scope4"> <input name="lti_scope" type="radio" id="lti_scope4" value="4" <?php checked('4', $options['scope']); ?> /> <?php _e('Global: Use Email Only', 'lti-text'); ?> </label><br /> <label for="lti_scope3"> <input name="lti_scope" type="radio" id="lti_scope3" value="3" <?php checked('3', $options['scope']); ?> /> <?php _e('Resource: Prefix the ID with the consumer key and resource link ID', 'lti-text'); ?> </label><br /> <legend class="screen-reader-text"> <span><?php _e('Context: Prefix the ID with the consumer key and context ID', 'lti-text'); ?> </span> </legend> <label for="lti_scope2"> <input name="lti_scope" type="radio" id="lti_scope2" value="2" <?php checked('2', $options['scope']); ?> /> <?php _e('Context: Prefix the ID with the consumer key and context ID', 'lti-text'); ?> </label><br /> <legend class="screen-reader-text"> <span><?php _e('Consumer: Prefix an ID with the consumer key', 'lti-text'); ?> </span> </legend> <label for="lti_scope1"> <input name="lti_scope" type="radio" id="lti_scope1" value="1" <?php checked('1', $options['scope']); ?> /> <?php _e('Consumer: Prefix the ID with the consumer key', 'lti-text'); ?> </label><br /> <legend class="screen-reader-text"> <span><?php _e('Global: Use ID value only', 'lti-text'); ?> </span> </legend> <label for="lti_scope0"> <input name="lti_scope" type="radio" id="lti_scope0" value="0" <?php checked('0', $options['scope']); ?> /> <?php _e('Global: Use ID value only', 'lti-text'); ?> </label> </fieldset> </td> </tr> <?php } ?> </tbody> </table> <p class="submit"> <input id="addltisub" class="button-primary" type="submit" value="<?php echo $button_text; ?> " name="addlti"> </p> </form> </div> <div id="keySecret" style="display:none"> <h2><?php _e('Details for LTI Tool Consumer: ', 'lti-text'); ?> <span id="lti_title" style="font-weight:bold"></span></h2> <table> <tr><td><?php echo __('Launch URL: ', 'lti-text') . '<b>' . get_option('siteurl') . '/?lti</b>'; ?> </td></tr> <tr><td><?php _e('Key: ', 'lti-text'); ?> <span id="key" style="font-weight:bold"></span></td></tr> <tr><td><?php _e('Secret: ', 'lti-text'); ?> <span id="secret" style="font-weight:bold"></span></td></tr> </table> <form action="<?php echo plugins_url() . '/lti/includes/XML.php'; ?> " name="download" id="download"> <input id="ltikey" type="hidden" value="" name="lti" /> <p class="submit"> <input id="xml" class="button-primary" type="submit" value="<?php _e('Download XML', 'lti-text'); ?> " name="xml" /> </p> </form> </div> <?php }
function lti_do_connect($tool_provider) { global $wpdb; // If multisite support isn't in play, go home if (!is_multisite()) { $tool_provider->message = __('The LTI Plugin requires a Multisite installation of WordPress', 'lti-text'); return FALSE; } // Clear any existing connections //wp_logout(); // Clear these before use $_SESSION[LTI_SESSION_PREFIX . 'return_url'] = ''; $_SESSION[LTI_SESSION_PREFIX . 'return_name'] = ''; // Store return URL for later use, if present if (!empty($tool_provider->return_url)) { $_SESSION[LTI_SESSION_PREFIX . 'return_url'] = strpos($tool_provider->return_url, '?') === FALSE ? $tool_provider->return_url . '?' : $tool_provider->return_url . '&'; $_SESSION[LTI_SESSION_PREFIX . 'return_name'] = 'Return to VLE'; if (!empty($tool_provider->consumer->name)) { $_SESSION[LTI_SESSION_PREFIX . 'return_name'] = 'Return to ' . $tool_provider->consumer->name; } } // Get what we are using as the username (unique_id-consumer_key, i.e. _21_1-stir.ac.uk) $options = get_site_option('lti_choices'); $scope_userid = lti_get_scope($tool_provider->consumer->getKey()); $user_login = $tool_provider->user->getID($scope_userid); //Swat edit: $idLoc = strpos(print_r($tool_provider->user, true), '[id:LTI_User:private] =>'); $idEOL = strpos(print_r($tool_provider->user, true), ')', $idLoc); $whatwewant = substr(print_r($tool_provider->user, true), $idLoc + 25, $idEOL); $matches = array(); if (preg_match('/\\d*/', $whatwewant, $matches)) { } if (sizeof($matches) > 0) { $moodleID = $matches[0]; } else { error_log("LTI Error: No Moodle ID found."); $tool_provider->reason = "No Moodle ID"; return FALSE; } error_log("!!!!!!!!!!!!!!!!!! Incoming Moodle User !!!!!!!!!!!!!!!!!!" . $moodleID); // Sanitize username stripping out unsafe characters $user_login = sanitize_user($user_login); // Apply the function pre_user_login before saving to the DB. $user_login = apply_filters('pre_user_login', $user_login); //Swat Edit: array of Banned Users $banned_users = array("www", "web", "root", "admin", "main", "invite", "administrator", "files", "blog"); $userEmail = $tool_provider->user->email; $defaultEmailDomain = $tool_provider->consumer->email_domain; list($emailUsername, $emailDomain) = explode('@', $tool_provider->user->email); if ($emailDomain !== $defaultEmailDomain) { error_log("!!!!!!!!!!!!!!!!!! default domain is !!!!!!!!!!!!!!!!!!" . $defaultEmailDomain); error_log("!!!!!!!!!!!!!!!!!!Not from default domain!!!!!!!!!!!!!!!!!!"); $user_login = $user_login . '-' . $moodleID; } // Check if this username, $user_login, is already defined $user = get_user_by('login', $user_login); if (!filter_var($tool_provider->user->email, FILTER_VALIDATE_EMAIL) || in_array($user_login, $banned_users)) { wp_logout(); } elseif ($user) { // If user exists, simply save the current details $result = wp_insert_user(array('ID' => $user->ID, 'user_login' => $user_login, 'user_nicename' => $user_login, 'first_name' => $tool_provider->user->firstname, 'last_name' => $tool_provider->user->lastname, 'user_email' => $tool_provider->user->email, 'display_name' => $tool_provider->user->fullname)); } else { // Create username if user provisioning is on $result = wp_insert_user(array('user_login' => $user_login, 'user_pass' => wp_generate_password(), 'user_nicename' => $user_login, 'first_name' => $tool_provider->user->firstname, 'last_name' => $tool_provider->user->lastname, 'user_email' => $tool_provider->user->email, 'display_name' => $tool_provider->user->fullname)); // Handle any errors by capturing and returning to the consumer if (is_wp_error($result)) { $tool_provider->reason = $result->get_error_message(); return FALSE; } else { // Get the new users details $user = get_user_by('login', $user_login); } } // Get user ID $user_id = $user->ID; // Staff or Learner $staff = FALSE; $learner = FALSE; $staff = $tool_provider->user->isStaff() || $tool_provider->user->isAdmin(); $learner = $tool_provider->user->isLearner(); // set up some useful variables $key = $tool_provider->resource_link->getKey(); $context_id = $tool_provider->context->getId(); //Swat Edit to get contect label $context_label = slugify($tool_provider->resource_link->context_label); $resource_id = $tool_provider->resource_link->getId(); // Create blog $use_context = FALSE; if (!empty($context_id)) { $use_context = $tool_provider->resource_link->getSetting('custom_use_context') == 'true' ? TRUE : FALSE; } if ($use_context) { // Create new blog, if does not exist. Note this gives one blog per context, the consumer supplies a context_id // otherwise it creates a blog per resource_id $path = $key . '_' . $context_id; } else { //swat Edit to get $content_label $path = $key . $resource_id; $path = $context_label; // Create new blog, if does not exist. Note this gives one blog per resource_id //$path = $key . $resource_id; } // Replace any non-allowed characters in WordPress with - $path = preg_replace('/[^_0-9a-zA-Z-]+/', '-', $path); // Sanity Check: Ensure that path is only _A-Za-z0-9- --- the above should stop this. if (preg_match('/[^_0-9a-zA-Z-]+/', $path) == 1) { $tool_provider->reason = __('No Blog has been created as the name contains non-alphanumeric: (_a-zA-Z0-9-) allowed', 'lti-text'); return FALSE; } // Get any folder(s) that WordPress might be living in $wppath = parse_url(get_option('siteurl'), PHP_URL_PATH); $path = $wppath . '/' . trailingslashit($path); // Get the id of the blog, if exists $blog_id = domain_exists(DOMAIN_CURRENT_SITE, $path, 1); // If Blog does not exist and this is a member of staff and blog provisioning is on, create blog if (!$blog_id && $staff) { $blog_id = wpmu_create_blog(DOMAIN_CURRENT_SITE, $path, $tool_provider->resource_link->title, $user_id, '', '1'); update_blog_option($blog_id, 'blogdescription', __('Provisioned by LTI', 'lti-text')); } // Blog will exist by this point unless this user is student/no role. if (!$blog_id) { $tool_provider->reason = __('No Blog has been created for this context', 'lti-text'); return FALSE; } // Create blog name if it doesn't have one defined, otherwise leave it alone. This allows admin to set a friendlier blogname in WP Settings if they'd like. if (!get_blog_option($blog_id, 'blogname')) { update_blog_option($blog_id, 'blogname', $tool_provider->consumer->name); } $role = 'subscriber'; if ($staff) { $role = 'administrator'; } if ($learner) { $role = 'author'; } // Add user to blog and set role if (!is_user_member_of_blog($user_id, $blog_id)) { add_user_to_blog($blog_id, $user_id, $role); } // Users added via this route should only have access to this // (path) site. Remove from the default blog. remove_user_from_blog($user_id, 1); // Login the user wp_set_current_user($user_id, $user_login); wp_set_auth_cookie($user_id); do_action('wp_login', $user_login); // Switch to blog switch_to_blog($blog_id); // Note this is an LTI provisioned Blog. add_option('ltisite', TRUE); // As this is an LTI provisioned Blog we store the consumer key and // context id as options with the session meaning we can access elsewhere // in the code. // Store lti key & context id in $_SESSION variables $_SESSION[LTI_SESSION_PREFIX . 'key'] = $key; $_SESSION[LTI_SESSION_PREFIX . 'resourceid'] = $resource_id; // Store the key/context in case we need to sync shares --- this ensures we return // to the correct consumer and not the primary consumer $_SESSION[LTI_SESSION_PREFIX . 'userkey'] = $tool_provider->user->getResourceLink()->getKey(); $_SESSION[LTI_SESSION_PREFIX . 'userresourcelink'] = $tool_provider->user->getResourceLink()->getId(); // If users role in consumer has changed (e.g. staff -> student), // then their role in the blog should change $user = new WP_User($user_id); if ($user->has_cap('administrator') && $role != 'administrator') { $user->add_role($role); $user->remove_role('administrator'); } if ($user->has_cap('author') && $role != 'author') { $user->add_role($role); $user->remove_role('author'); } if ($user->has_cap('subscriber') && $role != 'subscriber') { $user->add_role($role); $user->remove_role('subscriber'); } // Send login time to consumer if has outcomes service and can handle freetext $context = $tool_provider->resource_link; if ($context->hasOutcomesService()) { // Presently this is just a demo of the outcome services and updating the menu bar in WordPress $outcome = new LTI_Outcome($tool_provider->user->lti_result_sourcedid); $outcome->type = LTI_Resource_Link::EXT_TYPE_TEXT; $result = $context->doOutcomesService(LTI_Resource_Link::EXT_READ, $outcome); // If we have successfully read then update the user metadata if ($result) { update_user_meta($user_id, 'Last Login', $result); } $outcome->setValue(date('d-F-Y G:i', time())); $context->doOutcomesService(LTI_Resource_Link::EXT_WRITE, $outcome); } // Return URL for re-direction by Tool Provider class return get_bloginfo('url'); }
function lti_create_share_key() { global $wpdb, $current_user; // Get the context $consumer = new LTI_Tool_Consumer($_SESSION[LTI_SESSION_PREFIX . 'key'], array($wpdb->base_prefix)); $resource = new LTI_Resource_Link($consumer, $_SESSION[LTI_SESSION_PREFIX . 'resourceid']); if (!empty($_POST['email'])) { $share_key = new LTI_Resource_Link_Share_Key($resource); if (isset($_POST['life'])) { $share_key->life = $_POST['life']; } if (isset($_POST['enabled'])) { $_POST['enabled'] ? $share_key->auto_approve = TRUE : ($share_key->auto_approve = FALSE); } $share_key->save(); wp_get_current_user(); $senttext = __('Instructor: ', 'lti-text') . '<b>' . $current_user->display_name . '</b>' . __(' has shared', 'lti-text') . '<br /><br />' . __('Blog Name: ', 'lti-text') . '<b>' . get_bloginfo('name') . '</b>' . __(' with your module. To link up with this Blog:', 'lti-text') . '<br /><br />' . sprintf(__('Place this key (%s) in the custom parameters of the link to WordPress in your course as:', 'lti-text'), $share_key->getId()) . '<br /><br />' . sprintf(__('share_key=%s', 'lti-text'), $share_key->getId()); // Write friendly times if ($_POST['life'] <= 12) { $time = sprintf(_n('%s hour', '%s hours', $_POST['life'], 'lti-text'), $_POST['life']); } if ($_POST['life'] >= 24 && $_POST['life'] <= 144) { $days = intval($_POST['life'] / 24); $time = sprintf(_n('%s day', '%s days', $days, 'lti-text'), $days); } if ($_POST['life'] == 168) { $time = '1 week'; } if ($share_key->auto_approve) { $senttext .= '<br /><br />' . sprintf(__('The share key must be activated within %s.', 'lti-text'), $time); } else { $senttext .= '<br /><br />' . sprintf(__('The share key must be activated within %s and will only work after then being approved by an administrator of the site being shared.', 'lti-text'), $time); } // Send text/html $headers = 'Content-Type: text/html; charset=UTF-8'; if (wp_mail($_POST['email'], 'WordPress Share Key', $senttext, $headers)) { echo '<div class="wrap"><h2>' . __('Share this Site', 'lti-text') . '</h2>'; echo '<p>' . sprintf(__('The text below has been emailed to %s', 'lti-text'), $_POST['email']) . '</p>'; echo '<p1>' . $senttext . '</p1></div>'; } else { echo '<div class="wrap"><h2>' . __('Share this Site', 'lti-text') . '</h2>'; echo '<p>' . $senttext . '</p></div>'; } } else { ?> <h2><?php _e('Add Share Key', 'lti-text'); ?> </h2> <p><?php _e('You may share this site with users using other LTI links into WordPress. These might be:', 'lti-text'); ?> </p> <ul style="list-style-type: disc; margin-left: 15px; padding-left: 15px;"> <li><?php _e('other links from within the same course/module', 'lti-text'); ?> </li> <li><?php _e('links from other course/modules in the same VLE/LMS', 'lti-text'); ?> </li> <li><?php _e('links from a different VLE/LMS within your institution or outside', 'lti-text'); ?> </li> </ul> <p><?php _e('To invite another link to share this site:', 'lti-text'); ?> </p> <ul style="list-style-type: disc; margin-left: 15px; padding-left: 15px;"> <li><?php _e('use the button below to generate a new share key (you may choose to pre-approve the share or leave it to be approved once the key has been activated)', 'lti-text'); ?> </li> <li><?php _e('send the share key to an instructor for the other link', 'lti-text'); ?> </li> </ul> <?php if (lti_get_scope($_SESSION[LTI_SESSION_PREFIX . 'key']) == 0) { echo '<p><strong>' . __('The username format of this tool consumer is set to global and it is NOT recommended to share your site when user accounts are being created using this option.', 'lti-text') . '</strong></p>'; } ?> <form method="post" action="<?php get_admin_url(); ?> admin.php?page=lti_create_share_key"> <table class="form-table"> <tbody> <tr class="form-required"> <th scope="row"> <?php _e('Life', 'lti-text'); ?> <span class="description"><?php _e('(required)', 'lti-text'); ?> </span> </th> <td> <select name="life"> <option value="1">1 <?php _e('hour', 'lti-text'); ?> </option> <option value="2">2 <?php _e('hours', 'lti-text'); ?> </option> <option value="12">12 <?php _e('hours', 'lti-text'); ?> </option> <option value="24">1 <?php _e('day', 'lti-text'); ?> </option> <option value="48">2 <?php _e('days', 'lti-text'); ?> </option> <option value="72">3 <?php _e('days', 'lti-text'); ?> </option> <option value="96">4 <?php _e('days', 'lti-text'); ?> </option> <option value="120">5 <?php _e('days', 'lti-text'); ?> </option> <option value="144">6 <?php _e('days', 'lti-text'); ?> </option> <option value="168">1 <?php _e('week', 'lti-text'); ?> </option> </select> </td> </tr> <tr> <th scope="row"> <?php _e('Enabled', 'lti-text'); ?> </th> <td> <fieldset> <legend class="screen-reader-text"> <span><?php _e('Enabled', 'lti-text'); ?> </span> </legend> <label for="enabled"> <input name="enabled" type="checkbox" id="enabled" value="true" /> <?php _e('Automatically allow requests from this share without further approval', 'lti-text'); ?> </label> </fieldset> </td> </tr> <tr class="form-field form-required"> <th scope="row"> <label for="email"> <?php _e('Enter the email address for the sharing recipient:', 'lti-text'); ?> <span class="description"><?php _e('(required)', 'lti-text'); ?> </span> </label> </th> <td> <input id="email" type="text" aria-required="true" value="" name="email"> </td> </tr> </tbody> </table> <input type="hidden" name="action" value="continue" /> <p class="submit"> <input id="share" class="button-primary" type="submit" value="<?php _e('Add Share Key', 'lti-text'); ?> " name="sharekey"> </p> </form> <?php } }