0) {
if ($_FILES['tsml_import']['error'] == 1) {
$error = __('The uploaded file exceeds the upload_max_filesize directive in php.ini.', '12-step-meeting-list');
} elseif ($_FILES['tsml_import']['error'] == 2) {
$error = __('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.', '12-step-meeting-list');
} elseif ($_FILES['tsml_import']['error'] == 3) {
$error = __('The uploaded file was only partially uploaded.', '12-step-meeting-list');
} elseif ($_FILES['tsml_import']['error'] == 4) {
$error = __('No file was uploaded.', '12-step-meeting-list');
} elseif ($_FILES['tsml_import']['error'] == 6) {
$error = __('Missing a temporary folder.', '12-step-meeting-list');
} elseif ($_FILES['tsml_import']['error'] == 7) {
$error = __('Failed to write file to disk.', '12-step-meeting-list');
} elseif ($_FILES['tsml_import']['error'] == 8) {
$error = __('A PHP extension stopped the file upload.', '12-step-meeting-list');
} else {
$error = sprintf(__('File upload error #%d', '12-step-meeting-list'), $_FILES['tsml_import']['error']);
}
} elseif (empty($extension)) {
$error = __('Uploaded file did not have a file extension. Please add .csv to the end of the file name.', '12-step-meeting-list');
} elseif (!in_array($extension, array('csv', 'txt'))) {
$error = sprintf(__('Please upload a csv file. Your file ended in .%s.', '12-step-meeting-list'), $extension);
} elseif (!$handle = fopen($_FILES['tsml_import']['tmp_name'], 'r')) {
$error = __('Error opening CSV file', '12-step-meeting-list');
} else {
//extract meetings from CSV
while (($data = fgetcsv($handle, 3000, ',')) !== false) {
//skip empty rows
if (strlen(trim(implode($data)))) {
$meetings[] = $data;
}
}
//remove any rows that aren't arrays
$meetings = array_filter($meetings, 'is_array');
//crash if no data
if (count($meetings) < 2) {
$error = __('Nothing was imported because no data rows were found.', '12-step-meeting-list');
} else {
//allow theme-defined function to reformat CSV prior to import (New Hampshire, Ventura)
if (function_exists('tsml_import_reformat')) {
$meetings = tsml_import_reformat($meetings);
}
//if it's FNV data, reformat it
$meetings = tsml_import_reformat_fnv($meetings);
//get header
$header = array_shift($meetings);
$header = array_map('sanitize_title_with_dashes', $header);
$header = str_replace('-', '_', $header);
$header_count = count($header);
//check header for required fields
if (!in_array('address', $header) && !in_array('city', $header)) {
$error = __('Either Address or City is required.', '12-step-meeting-list');
} else {
//loop through data and convert to array
foreach ($meetings as &$meeting) {
//check length
if ($header_count > count($meeting)) {
$meeting = array_pad($meeting, $header_count, null);
} elseif ($header_count < count($meeting)) {
$meeting = array_slice($meeting, 0, $header_count);
}
//associate
$meeting = array_combine($header, $meeting);
}
//import into buffer, also done this way in data source import
tsml_import_buffer_set($meetings);
//run deletes
if ($_POST['delete'] == 'regions') {
//get all regions present in array
$regions = array();
foreach ($meetings as $meeting) {
$regions[] = empty($meeting['sub_region']) ? $meeting['region'] : $meeting['sub_region'];
}
//get locations for those meetings
$location_ids = get_posts(array(
'post_type' => 'tsml_location',
'numberposts' => -1,
'fields' => 'ids',
'tax_query' => array(
array(
'taxonomy' => 'tsml_region',
'field' => 'name',
'terms' => array_unique($regions),
),
),
));
//get posts for those meetings
$meeting_ids = get_posts(array(
'post_type' => 'tsml_meeting',
'numberposts' => -1,
'fields' => 'ids',
'post_parent__in' => $location_ids,
));
tsml_delete($meeting_ids);
tsml_delete_orphans();
} elseif ($_POST['delete'] == 'no_data_source') {
tsml_delete(get_posts(array(
'post_type' => 'tsml_meeting',
'numberposts' => -1,
'fields' => 'ids',
'meta_query' => array(
array(
'key' => 'data_source',
'compare' => 'NOT EXISTS',
'value' => '',
),
),
)));
tsml_delete_orphans();
} elseif ($_POST['delete'] == 'all') {
tsml_delete('everything');
}
}
}
}
}
//add data source
if (!empty($_POST['tsml_add_data_source']) && isset($_POST['tsml_nonce']) && wp_verify_nonce($_POST['tsml_nonce'], $tsml_nonce)) {
//sanitize URL
$_POST['tsml_add_data_source'] = trim(esc_url_raw($_POST['tsml_add_data_source'], array('http', 'https')));
//try fetching
$response = wp_remote_get($_POST['tsml_add_data_source'], array(
'timeout' => 30,
'sslverify' => false,
));
if (is_array($response) && !empty($response['body']) && ($body = json_decode($response['body'], true))) {
//if already set, hard refresh
if (array_key_exists($_POST['tsml_add_data_source'], $tsml_data_sources)) {
tsml_delete(tsml_get_data_source_ids($_POST['tsml_add_data_source']));
tsml_delete_orphans();
}
$tsml_data_sources[$_POST['tsml_add_data_source']] = array(
'status' => 'OK',
'last_import' => current_time('timestamp'),
'count_meetings' => 0,
'name' => sanitize_text_field($_POST['tsml_add_data_source_name']),
'type' => 'JSON',
);
//import feed
tsml_import_buffer_set($body, $_POST['tsml_add_data_source']);
//save data source configuration
update_option('tsml_data_sources', $tsml_data_sources);
} elseif (!is_array($response)) {
tsml_alert(__('Invalid response,
' . print_r($response, true) . '.', '12-step-meeting-list'), 'error'); } elseif (empty($response['body'])) { tsml_alert(__('Data source gave an empty response, you might need to try again.', '12-step-meeting-list'), 'error'); } else { switch (json_last_error()) { case JSON_ERROR_NONE: tsml_alert(__('JSON: no errors.', '12-step-meeting-list'), 'error'); break; case JSON_ERROR_DEPTH: tsml_alert(__('JSON: Maximum stack depth exceeded.', '12-step-meeting-list'), 'error'); break; case JSON_ERROR_STATE_MISMATCH: tsml_alert(__('JSON: Underflow or the modes mismatch.', '12-step-meeting-list'), 'error'); break; case JSON_ERROR_CTRL_CHAR: tsml_alert(__('JSON: Unexpected control character found.', '12-step-meeting-list'), 'error'); break; case JSON_ERROR_SYNTAX: tsml_alert(__('JSON: Syntax error, malformed JSON.', '12-step-meeting-list'), 'error'); break; case JSON_ERROR_UTF8: tsml_alert(__('JSON: Malformed UTF-8 characters, possibly incorrectly encoded.', '12-step-meeting-list'), 'error'); break; default: tsml_alert(__('JSON: Unknown error.', '12-step-meeting-list'), 'error'); break; } } } //check for existing import buffer $meetings = get_option('tsml_import_buffer', array()); //remove data source if (!empty($_POST['tsml_remove_data_source'])) { //sanitize URL $_POST['tsml_remove_data_source'] = esc_url_raw($_POST['tsml_remove_data_source'], array('http', 'https')); if (array_key_exists($_POST['tsml_remove_data_source'], $tsml_data_sources)) { //remove all meetings for this data source tsml_delete(tsml_get_data_source_ids($_POST['tsml_remove_data_source'])); //clean up orphaned locations & groups tsml_delete_orphans(); //remove data source unset($tsml_data_sources[$_POST['tsml_remove_data_source']]); update_option('tsml_data_sources', $tsml_data_sources); tsml_alert(__('Data source removed.', '12-step-meeting-list')); } } //change program if (!empty($_POST['tsml_program']) && isset($_POST['tsml_nonce']) && wp_verify_nonce($_POST['tsml_nonce'], $tsml_nonce)) { $tsml_program = sanitize_text_field($_POST['tsml_program']); update_option('tsml_program', $tsml_program); tsml_alert(__('Program setting updated.', '12-step-meeting-list')); } //change distance units if (!empty($_POST['tsml_distance_units']) && isset($_POST['tsml_nonce']) && wp_verify_nonce($_POST['tsml_nonce'], $tsml_nonce)) { $tsml_distance_units = ($_POST['tsml_distance_units'] == 'mi') ? 'mi' : 'km'; update_option('tsml_distance_units', $tsml_distance_units); tsml_alert(__('Distance units updated.', '12-step-meeting-list')); } //change distance units if (!empty($_POST['tsml_contact_display']) && isset($_POST['tsml_nonce']) && wp_verify_nonce($_POST['tsml_nonce'], $tsml_nonce)) { $tsml_contact_display = ($_POST['tsml_contact_display'] == 'public') ? 'public' : 'private'; update_option('tsml_contact_display', $tsml_contact_display); tsml_cache_rebuild(); //this value affects what's in the cache tsml_alert(__('Contact privacy updated.', '12-step-meeting-list')); } //change sharing setting if (!empty($_POST['tsml_sharing']) && isset($_POST['tsml_nonce']) && wp_verify_nonce($_POST['tsml_nonce'], $tsml_nonce)) { $tsml_sharing = ($_POST['tsml_sharing'] == 'open') ? 'open' : 'restricted'; update_option('tsml_sharing', $tsml_sharing); tsml_alert(__('Sharing setting updated.', '12-step-meeting-list')); } //add a sharing key if (!empty($_POST['tsml_add_sharing_key']) && isset($_POST['tsml_nonce']) && wp_verify_nonce($_POST['tsml_nonce'], $tsml_nonce)) { $name = sanitize_text_field($_POST['tsml_add_sharing_key']); $key = md5(uniqid($name, true)); $tsml_sharing_keys[$key] = $name; asort($tsml_sharing_keys); update_option('tsml_sharing_keys', $tsml_sharing_keys); tsml_alert(__('Sharing key added.', '12-step-meeting-list')); //users might expect that if they add "meeting guide" that then they are added to the app if (strtolower($name) == 'meeting guide') { $current_user = wp_get_current_user(); $message = admin_url('admin-ajax.php?') . http_build_query(array( 'action' => 'meetings', 'key' => $key, )); tsml_email(TSML_CONTACT_EMAIL, 'Sharing Key', $message, $current_user->user_email); } } //remove a sharing key if (!empty($_POST['tsml_remove_sharing_key']) && isset($_POST['tsml_nonce']) && wp_verify_nonce($_POST['tsml_nonce'], $tsml_nonce)) { $key = sanitize_text_field($_POST['tsml_remove_sharing_key']); if (array_key_exists($key, $tsml_sharing_keys)) { unset($tsml_sharing_keys[$key]); if (empty($tsml_sharing_keys)) { delete_option('tsml_sharing_keys'); } else { update_option('tsml_sharing_keys', $tsml_sharing_keys); } tsml_alert(__('Sharing key removed.', '12-step-meeting-list')); } else { //theoretically should never get here, because user is choosing from a list tsml_alert(sprintf(esc_html__('
%s was not found in the list of sharing keys. Please try again.
%s is not a valid email address. Please try again.', '12-step-meeting-list'), $email), 'error');
} else {
$tsml_feedback_addresses[] = $email;
$tsml_feedback_addresses = array_unique($tsml_feedback_addresses);
sort($tsml_feedback_addresses);
update_option('tsml_feedback_addresses', $tsml_feedback_addresses);
tsml_alert(__('Feedback address added.', '12-step-meeting-list'));
}
}
//remove a feedback email
if (!empty($_POST['tsml_remove_feedback_address']) && isset($_POST['tsml_nonce']) && wp_verify_nonce($_POST['tsml_nonce'], $tsml_nonce)) {
$email = sanitize_text_field($_POST['tsml_remove_feedback_address']);
if (($key = array_search($email, $tsml_feedback_addresses)) !== false) {
unset($tsml_feedback_addresses[$key]);
if (empty($tsml_feedback_addresses)) {
delete_option('tsml_feedback_addresses');
} else {
update_option('tsml_feedback_addresses', $tsml_feedback_addresses);
}
tsml_alert(__('Feedback address removed.', '12-step-meeting-list'));
} else {
//theoretically should never get here, because user is choosing from a list
tsml_alert(sprintf(esc_html__('%s was not found in the list of addresses. Please try again.
%s is not a valid email address. Please try again.
%s was not found in the list of addresses. Please try again.
Formerly, this plugin came with Google Maps built in, but, due to a change in Google's pricing, that's no longer possible. Read more about the price increase here.
Now if you want to enable maps on your site you have two options: Mapbox or Google. They are both good options! In all likelihood neither one will charge you money. Mapbox gives 50,000 free map views / month, Google gives 28,500 free views. That's a lot of traffic!
To sign up for Mapbox go here. You will only need a valid email address, no credit card required. Copy your access token and paste it below:
Alternatively you may still use Google. Their interface is slightly more complex, because they offer more services. Go here to get a key from Google. The process should only take a few minutes, although you will have to enter a credit card. Here are some instructions.
Be sure to:
Enable the Google Maps Javascript API
Secure your credentials by adding your website URL to the list
of allowed referrers
Once you're done, paste your new key below.
ServiceNumber.', '12-step-meeting-list')?>
right here. More information is available at the Meeting Guide API Specification.', '12-step-meeting-list'), admin_url('admin-ajax.php') . '?action=meetings', 'https://github.com/meeting-guide/spec')?>
| • |
%s, while WordPress recommends PHP %s or above. This can cause unexpected errors. Please contact your host and upgrade!', '12-step-meeting-list'), PHP_VERSION, 'https://wordpress.org/about/requirements/', '5.6')?>
right here. Link that page from your site\'s nav menu to make it visible to the public.', '12-step-meeting-list'), get_post_type_archive_link('tsml_meeting'))?>
CSV format.', '12-step-meeting-list'), admin_url('admin-ajax.php') . '?action=csv')?>
half page and full page.', '12-step-meeting-list'), admin_url('admin-ajax.php') . '?action=tsml_pdf', admin_url('admin-ajax.php') . '?action=tsml_pdf&width=8.5')?>
Click here to see their email addresses.', '12-step-meeting-list'), admin_url('admin-ajax.php') . '?action=contacts')?>