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 { // translators: %d is the error $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, ['csv', 'txt'])) { // translators: %s is the file extension $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')) { // phpcs:ignore $meetings = tsml_import_reformat($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 $meetings = tsml_import_sanitize_meetings($meetings); tsml_import_buffer_set($meetings); // run deletes if ($_POST['delete'] == 'regions') { // get all regions present in array $regions = []; foreach ($meetings as $meeting) { $regions[] = empty($meeting['sub_region']) ? $meeting['region'] : $meeting['sub_region']; } // get locations for those meetings $location_ids = get_posts([ 'post_type' => 'tsml_location', 'numberposts' => -1, 'fields' => 'ids', 'tax_query' => [ [ 'taxonomy' => 'tsml_region', 'field' => 'name', 'terms' => array_unique($regions), ], ], ]); // get posts for those meetings $meeting_ids = get_posts([ '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([ 'post_type' => 'tsml_meeting', 'numberposts' => -1, 'fields' => 'ids', 'meta_query' => [ [ 'key' => 'data_source', 'compare' => 'NOT EXISTS', 'value' => '', ], ], ])); tsml_delete_orphans(); } elseif ($_POST['delete'] == 'all') { tsml_delete('everything'); } } } } } // add or refresh a data source if (!empty($_POST['tsml_add_data_source']) && $valid_nonce) { tsml_import_data_source( $_POST['tsml_add_data_source'], $_POST['tsml_add_data_source_name'], $_POST['tsml_add_data_source_parent_region_id'], 'disabled' ); } // check for existing import buffer $meetings = tsml_get_option_array('tsml_import_buffer'); // remove data source if (!empty($_POST['tsml_remove_data_source']) && $valid_nonce) { // sanitize URL $_POST['tsml_remove_data_source'] = esc_url_raw($_POST['tsml_remove_data_source'], ['http', 'https']); if (array_key_exists($_POST['tsml_remove_data_source'], $tsml_data_sources)) { // get data source for log entry $data_source = $tsml_data_sources[$_POST['tsml_remove_data_source']]; // 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_log('data_source', __('Removed', '12-step-meeting-list'), $data_source['name']); tsml_alert(__('Data source removed.', '12-step-meeting-list')); } } // change auto import if (isset($_POST['tsml_auto_import']) && $valid_nonce) { $tsml_auto_import = !!($_POST['tsml_auto_import']) ? 'on' : ''; update_option('tsml_auto_import', $tsml_auto_import); tsml_alert(__('Automatic imports setting updated.', '12-step-meeting-list')); } // ensure cron follows setting tsml_import_cron_check(); ?>

$properties) { ?>
name; if ($parent_region == null) { $parent_region = __('Top-level region', '12-step-meeting-list'); $parent_region = 'Missing Parent Region: ' . $properties['parent_region_id']; } } else { $parent_region = $regions[$properties['parent_region_id']]; } echo esc_html($parent_region); ?>
__('District or Intergroup Name', '12-step-meeting-list')]); tsml_input_url('tsml_add_data_source'); wp_dropdown_categories( [ 'name' => 'tsml_add_data_source_parent_region_id', 'taxonomy' => 'tsml_region', 'hierarchical' => true, 'hide_empty' => false, 'orderby' => 'name', 'selected' => null, 'title' => __('Append regions created by this data source to… (top-level, if none selected)', '12-step-meeting-list'), 'show_option_none' => __('Parent Region…', '12-step-meeting-list'), ] ); ?>

__('don\'t delete anything', '12-step-meeting-list'), 'regions' => __('delete only the meetings, locations, and groups for the regions present in this CSV', '12-step-meeting-list'), 'all' => __('delete all meetings, locations, groups, districts, and regions', '12-step-meeting-list'), ]; if (!empty($tsml_data_sources)) { $delete_options['no_data_source'] = __('delete all meetings, locations, and groups not from a data source', '12-step-meeting-list'); } $delete_selected = (empty($_POST['delete']) || !array_key_exists($_POST['delete'], $delete_options)) ? 'nothing' : $_POST['delete']; foreach ($delete_options as $key => $value) { ?>

Time, if present, should be in a standard date format such as 6:00 AM or 06:00. Non-standard or empty dates will be imported as "by appointment."', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

End Time, if present, should be in a standard date format such as 6:00 AM or 06:00.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Day if present, should either Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, or Saturday. Meetings that occur on multiple days should be listed separately. \'Daily\' or \'Mondays\' will not work. Non-standard days will be imported as "by appointment."', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Name is the name of the meeting, and is optional, although it\'s valuable information for the user. If it\'s missing, a name will be created by combining the location, day, and time.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Slug optional, and sets the meeting post\'s "slug" or unique string, which is used in the URL. This should be unique to the meeting. Setting this helps preserve user bookmarks.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Location is the name of the location, and is optional. Generally it\'s the group or building name. If it\'s missing, the address will be used. In the event that there are multiple location names for the same address, the first location name will be used.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Address is strongly encouraged and will be corrected by Google, so it may look different afterward. Ideally, every address for the same location should be exactly identical, and not contain extra information about the address, such as the building name or descriptors like "around back."', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Address is specified, then City, State, and Country are optional, but they might be useful if your addresses sound ambiguous to Google. If address is not specified, then these fields are required.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Notes are freeform notes that are specific to the meeting. For example, last Saturday is birthday night.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Conference URL is an optional URL to a specific public videoconference meeting. This should be a common videoconferencing service such as Zoom or Google Hangouts. It should launch directly into the meeting and not link to an intermediary page.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Conference URL Notes is an optional string which contains metadata about the Conference URL (e.g. meeting password in plain text for those groups unwilling to publish a one-tap URL).', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Conference Phone is the telephone number to dial into a specific meeting. Should be numeric, except a plus(\'+\') symbol may be used for international dialers, and the comma(\',\'), asterisk(\'*\'), and pound(\'#\') symbols can be used to form one-tap phone links.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Conference Phone Notes is an optional string with metadata about the \'Conference Phone\' (e.g. a numeric meeting password or other user instructions).', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Region is user-defined and can be anything. Often this is a small municipality or neighborhood. Since these go in a dropdown, ideally you would have 10 to 20 regions, although it\'s ok to be over or under.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Sub Region makes the Region hierarchical; in San Jose we have sub regions for East San Jose, West San Jose, etc. New York City might have Manhattan be a Region, and Greenwich Village be a Sub Region.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Location Notes are freeform notes that will show up on every meeting that this location. For example, "Enter from the side."', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Group is a way of grouping contacts. Meetings with the same group name will be linked and share contact information.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

District is user-defined and can be anything, but should be a string rather than an integer (e.g. District 01 rather than 1). A group name must also be specified.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Sub District makes the District hierachical.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Group Notes is for stuff like a short group history, or when the business meeting meets.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Website and Website 2 are optional.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Email is optional. This is a public email address.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Phone is optional. This is a public phone number.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Venmo is an optional string and should be a valid Venmo handle, (e.g. @AAGroupName). This is understood to be the address for 7th Tradition contributions to the meeting, and not any other entity.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Square is an optional string and should be a valid Square Cash App cashtag, (e.g. $AAGroupName). This is understood to be the address for 7th Tradition contributions to the meeting, and not any other entity.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

PayPal is an optional string and should be a valid PayPal username, (e.g. AAGroupName). This is understood to be the address for 7th Tradition contributions to the meeting, and not any other entity.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Homegroup Online is an optional string and should be a Homegroup Online group code, (e.g. tbc). This is understood to be the address for 7th Tradition contributions to the meeting, and not any other entity.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

URL is optional and should point to the meeting\'s listing on the area website.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Feedback URL is an optional string URL that can be used to provide feedback about the meeting. These could be local links (e.g. https://mywebsite.org/feedback?meeting=meeting-slug-1), remote links (e.g. https://typeform.com/to/23904203?meeting=meeting-slug-1), or email links (e.g. mailto:webservant@domain.org?subject=meeting-slug-1).', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Edit URL is an optional string URL that trusted servants can use to edit the specific meeting\'s listing.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Contact 1/2/3 Name/Email/Phone (nine fields in total) are all optional. By default, contact information is only visible inside the WordPress dashboard.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Last Contact is an optional date.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

Types should be a comma-separated list of the following options. This list is determined by which program is selected on the Settings tab.', '12-step-meeting-list'), TSML_ALLOWED_HTML) ?>

admin_url('admin-ajax.php') . '?' . http_build_query([ 'action' => 'meetings', 'nonce' => $tsml_sharing === 'restricted' ? wp_create_nonce($tsml_nonce) : null ]) ]); ?>

right here. Link that page from your site\'s nav menu to make it visible to the public.', '12-step-meeting-list'), tsml_meetings_url() ), TSML_ALLOWED_HTML) ?>

class="hidden" >

 

Click here to see their email addresses.', '12-step-meeting-list'), admin_url('admin-ajax.php') . '?action=contacts&nonce=' . wp_create_nonce($tsml_nonce) ), TSML_ALLOWED_HTML) ?>

5, 'type' => 'data_source']); if (count($log_entries)) { ?>

' . PHP_EOL . $msg; } ?>