setup_hooks(); } /** * Setup Hooks. * * @since 4.11.0 */ private function setup_hooks() { if (!$this->is_subscriptions_import_page()) { return; } // Do not render main import tools page. remove_action('give_admin_field_tools_import', ['Give_Settings_Import', 'render_import_field']); // Render subscriptions import page add_action('give_admin_field_tools_import', [$this, 'render_page']); // Print the HTML. add_action('give_tools_import_subscriptions_form_start', [$this, 'html'], 10); // Handle submit add_action('give-tools_save_import', [$this, 'save']); add_action('give-tools_update_notices', [$this, 'update_notices'], 11, 1); // Used to add submit button. add_action('give_tools_import_subscriptions_form_end', [$this, 'submit'], 10); } /** * Update notice * * @since 4.11.0 * @param $messages * * @return mixed */ public function update_notices($messages) { if (!empty($_GET['tab']) && 'import' === give_clean($_GET['tab'])) { unset($messages['give-setting-updated']); } return $messages; } /** * Print submit and nonce button. * * @since 4.11.0 */ public function submit() { wp_nonce_field('give-save-settings', '_give-save-settings'); ?> get_step(); // Show progress. $this->render_progress(); ?>
is_csv_valid) ? 'give-hidden' : '')); ?> " id=""> render_media_csv(); break; case 2: $this->render_dropdown(); break; case 3: $this->start_import(); break; case 4: $this->import_success(); } if (false === $this->check_for_dropdown_or_import()) { ?>
" id="recount-stats-submit" value=" " />
get_report(); $total = (int)$_GET['total']; --$total; $success = (bool)$_GET['success']; $dry_run = empty($_GET['dry_run']) ? 0 : absint($_GET['dry_run']); ?>

{$total}" ); } else { printf( _n('Import complete! %s row processed', 'Import complete! %s rows processed', $total, 'give'), "{$total}" ); } } else { printf( _n('Failed to import %s row', 'Failed to import %s rows', $total, 'give'), "{$total}" ); } ?>

'give_forms', 'page' => 'give-tools', 'tab' => 'import', ]; if ($success) { if ($dry_run) { $query_arg = [ 'post_type' => 'give_forms', 'page' => 'give-tools', 'tab' => 'import', 'importer-type' => 'import_subscriptions', ]; $text = __('Start Import', 'give'); } else { $query_arg = [ 'post_type' => 'give_forms', 'page' => 'give-subscriptions', ]; $text = __('View Subscriptions', 'give'); } } if (!empty($report)) { if (isset($report['create_subscription'])) { echo '

' . sprintf(_n('%s subscription created', '%s subscriptions created', (int)$report['create_subscription'], 'give'), (int)$report['create_subscription']) . '

'; } if (isset($report['failed_subscription'])) { echo '

' . sprintf(_n('%s subscription failed', '%s subscriptions failed', (int)$report['failed_subscription'], 'give'), (int)$report['failed_subscription']) . '

'; } if (!empty($report['failed_subscription_initial_donation'])) { echo '

' . sprintf(_n('%s initial donation failed', '%s initial donations failed', (int)$report['failed_subscription_initial_donation'], 'give'), (int)$report['failed_subscription_initial_donation']) . '

'; } if (!empty($report['errors']) && is_array($report['errors'])) { echo '
'; echo '

' . esc_html__('Errors', 'give') . ':

'; echo ''; echo '
'; } } ?>

reset_report(); $csv = absint($_REQUEST['csv']); $delimiter = (!empty($_REQUEST['delimiter']) ? give_clean($_REQUEST['delimiter']) : 'csv'); $index_start = 1; $next = true; $total = self::get_csv_total($csv); if (self::$per_page < $total) { $total_ajax = ceil($total / self::$per_page); $index_end = self::$per_page; } else { $total_ajax = 1; $index_end = $total; $next = false; } $current_percentage = 100 / ($total_ajax + 1); ?>

' name="mapto" class="mapto"> is_nonce_valid()) { Give_Admin_Settings::add_error('give-import-csv', __('Something went wrong.', 'give')); ?> is_valid_csv($csv)) { $url = give_import_page_url(); ?>

get_importer($csv, 0, $delimiter); $mapto = (array)(isset($_REQUEST['mapto']) ? $_REQUEST['mapto'] : []); foreach ($raw_key as $index => $value) { ?> get_columns($index, $value, $mapto, $selectedOptions); ?> $option_value) { $ignore = []; if (isset($option_value['ignore']) && is_array($option_value['ignore'])) { $ignore = $option_value['ignore']; unset($option_value['ignore']); } $option_value_texts = (array)$option_value; $option_text = $option_value_texts[0]; $selected = false; if ($current_mapto === $option && !in_array($option, $selectedOptions)) { $selected = 'selected'; $selectedOptions[] = $option; } else { if (!in_array($value, $ignore) && !in_array($option, $selectedOptions)) { foreach ($option_value_texts as $option_value_text) { $selected = $this->selected($option_value_text, $value); if ($selected) { $selectedOptions[] = $option; break; } } // Extra heuristics: match header to option key by normalized token if (!$selected) { $normalize = static function ($str) { $str = strtolower((string)$str); return preg_replace('/[^a-z0-9]/', '', $str); }; $valueNorm = $normalize($value); $optionNorm = $normalize($option); if ($valueNorm && $optionNorm && $valueNorm === $optionNorm) { $selected = 'selected'; $selectedOptions[] = $option; } else { // Try normalized match against visible label too $labelNorm = $normalize($option_text); if ($labelNorm && $valueNorm && $labelNorm === $valueNorm) { $selected = 'selected'; $selectedOptions[] = $option; } } } } } ?> get_csv_data_from_file_dir($file_dir); } } return $total; } /** * Get data from File */ public function get_csv_data_from_file_dir($file_dir) { $total = false; if ($file_dir) { $file = new SplFileObject($file_dir, 'r'); $file->seek(PHP_INT_MAX); $total = $file->key() + 1; } return $total; } /** * Read a slice of CSV rows for subscriptions import */ public function get_subscription_data_from_csv($file_id, $start, $end, $delimiter = 'csv') { $delimiter = (string)apply_filters('give_import_delimiter_set', $delimiter); $file_dir = give_get_file_data_by_file_id($file_id); return give_get_raw_data_from_file($file_dir, $start, $end, $delimiter); } /** * Get the CSV fields title from the CSV. */ public function get_importer($file_id, $index = 0, $delimiter = 'csv') { $delimiter = (string)apply_filters('give_import_delimiter_set', $delimiter); $raw_data = false; $file_dir = get_attached_file($file_id); if ($file_dir) { if (false !== ($handle = fopen($file_dir, 'r'))) { $raw_data = fgetcsv($handle, $index, $delimiter); if (isset($raw_data[0])) { $raw_data[0] = $this->remove_utf8_bom($raw_data[0]); } } } return $raw_data; } /** * Remove UTF-8 BOM signature. */ public function remove_utf8_bom($string) { if ('efbbbf' === substr(bin2hex($string), 0, 6)) { $string = substr($string, 3); } return $string; } /** * Render progress steps */ public function render_progress() { $step = $this->get_step(); ?>
check_for_dropdown_or_import()) { $on_step = 3; } elseif (2 === $step) { $on_step = 2; } elseif (4 === $step) { $on_step = 4; } return $on_step; } /** * Render subscriptions import page */ public function render_page() { include_once GIVE_PLUGIN_DIR . 'includes/admin/tools/views/html-admin-page-import-subscriptions.php'; } /** * Dry Run checkbox and helper */ public function give_import_subscription_submit_button_render_media_csv() { $dry_run = isset($_POST['dry_run']) ? absint($_POST['dry_run']) : 1; ?>

is_valid_csv($csv_id, $csv)) { $csv_id = $csv = ''; } $per_page = isset($_POST['per_page']) ? absint($_POST['per_page']) : self::$per_page; $sample_file_text = sprintf( '%s %s.', __('Download the sample file', 'give'), esc_url(GIVE_PLUGIN_URL . 'sample-data/sample-subscriptions.csv'), __('here', 'give') ); $csv_description = sprintf( '%1$s %2$s', __('The file must be a Comma Separated Values (CSV) file type only.', 'give'), $sample_file_text ); $settings = [ [ 'id' => 'csv', 'name' => __('Choose a CSV file:', 'give'), 'type' => 'file', 'attributes' => [ 'editing' => 'false', 'library' => 'text', ], 'description' => $csv_description, 'fvalue' => 'url', 'default' => $csv, ], [ 'id' => 'csv_id', 'type' => 'hidden', 'value' => $csv_id, ], [ 'id' => 'delimiter', 'name' => __('CSV Delimiter:', 'give'), 'description' => __('If your CSV uses a different delimiter (like a tab), set that here.', 'give'), 'default' => $delimiter, 'type' => 'select', 'options' => [ 'csv' => __('Comma', 'give'), 'tab-separated-values' => __('Tab', 'give'), ], ], [ 'id' => 'mode', 'name' => __('Test Mode:', 'give'), 'description' => __('Select whether these subscriptions should be marked as "test".', 'give'), 'default' => $mode, 'type' => 'radio_inline', 'options' => [ 'enabled' => __('Enabled', 'give'), 'disabled' => __('Disabled', 'give'), ], ], [ 'id' => 'create_user', 'name' => __('Create WP users for new donors:', 'give'), 'description' => __('Automatically create a WordPress user account for newly created donors. This is required for donors to access their Donor Dashboard and manage their subscriptions.', 'give'), 'default' => $create_user, 'type' => 'radio_inline', 'options' => [ 'enabled' => __('Enabled', 'give'), 'disabled' => __('Disabled', 'give'), ], ], [ 'id' => 'delete_csv', 'name' => __('Delete CSV after import:', 'give'), 'description' => __('Delete the uploaded CSV from the Media Library after import.', 'give'), 'default' => $delete_csv, 'type' => 'radio_inline', 'options' => [ 'enabled' => __('Enabled', 'give'), 'disabled' => __('Disabled', 'give'), ], ], [ 'id' => 'per_page', 'name' => __('Process Rows Per Batch:', 'give'), 'type' => 'number', 'description' => __('Determine how many rows you would like to import per cycle.', 'give'), 'default' => $per_page, 'class' => 'give-text-small', ], ]; $settings = apply_filters('give_import_file_upload_html', $settings); if (empty($this->is_csv_valid)) { Give_Admin_Settings::output_fields($settings, 'give_settings'); } else { ?> is_nonce_valid()) { wp_die(); } $step = $this->get_step(); if (1 === $step) { $csv_id = absint($_POST['csv_id']); if ($this->is_valid_csv($csv_id, esc_url($_POST['csv']))) { $url = give_import_page_url( [ 'step' => '2', 'importer-type' => $this->importer_type, 'csv' => $csv_id, 'delimiter' => isset($_REQUEST['delimiter']) ? give_clean($_REQUEST['delimiter']) : 'csv', 'mode' => empty($_POST['mode']) ? '0' : (give_is_setting_enabled(give_clean($_POST['mode'])) ? '1' : '0'), 'create_user' => empty($_POST['create_user']) ? '0' : (give_is_setting_enabled(give_clean($_POST['create_user'])) ? '1' : '0'), 'delete_csv' => empty($_POST['delete_csv']) ? '1' : (give_is_setting_enabled(give_clean($_POST['delete_csv'])) ? '1' : '0'), 'per_page' => isset($_POST['per_page']) ? absint($_POST['per_page']) : self::$per_page, 'dry_run' => isset($_POST['dry_run']) ? absint($_POST['dry_run']) : 0, ] ); $this->is_csv_valid = wp_nonce_url($url, 'give-save-settings', '_give-save-settings'); } } } /** * Check if user uploaded csv is valid or not. */ private function is_valid_csv($csv = false, $match_url = '') { $is_valid_csv = true; if ($csv) { $csv_url = wp_get_attachment_url($csv); $delimiter = (!empty($_REQUEST['delimiter']) ? give_clean($_REQUEST['delimiter']) : 'csv'); if ( !$csv_url || (!empty($match_url) && ($csv_url !== $match_url)) || (($mime_type = get_post_mime_type($csv)) && !strpos($mime_type, $delimiter)) ) { $is_valid_csv = false; Give_Admin_Settings::add_error('give-import-csv', __('Please upload or provide a valid CSV file.', 'give')); } } else { $is_valid_csv = false; Give_Admin_Settings::add_error('give-import-csv', __('Please upload or provide a valid CSV file.', 'give')); } return $is_valid_csv; } /** * Get if current page import donations page or not */ private function is_subscriptions_import_page() { return 'import' === give_get_current_setting_tab() && isset($_GET['importer-type']) && $this->importer_type === give_clean($_GET['importer-type']); } /** * Nonce validation */ private function is_nonce_valid() { return !empty($_REQUEST['_give-save-settings']) && wp_verify_nonce($_REQUEST['_give-save-settings'], 'give-save-settings'); } /** * Import a single subscription row from CSV * * @param array $raw_key * @param array $row_data * @param array $main_key * @param array $import_setting * @return bool|int|string */ public function import_row($raw_key, $row_data, $main_key = [], $import_setting = []) { $report = $this->get_report(); $dry_run = isset($import_setting['dry_run']) ? (bool)$import_setting['dry_run'] : false; if ( empty($row_data) || (is_array($row_data) && 0 === count(array_filter($row_data, function ($v) { return $v !== null && $v !== ''; }))) ) { return true; } if (!is_array($row_data) || count($row_data) !== count($raw_key)) { $report['failed_subscription'] = (!empty($report['failed_subscription']) ? (absint($report['failed_subscription']) + 1) : 1); $this->update_report($report); return false; } $data = array_combine($raw_key, $row_data); $required = ['form_id', 'period', 'frequency', 'amount', 'status']; foreach ($required as $key) { if (empty($data[$key]) && '0' !== (string)(isset($data[$key]) ? $data[$key] : '')) { $report['failed_subscription'] = (!empty($report['failed_subscription']) ? (absint($report['failed_subscription']) + 1) : 1); $report['errors'][] = sprintf(__('Row %1$d: Missing required field "%2$s"', 'give'), (int)(isset($import_setting['row_key']) ? $import_setting['row_key'] : 0), $key); $this->update_report($report); return 'Missing required field ' . $key; } } if (empty($data['donor_id']) && empty($data['email'])) { $report['failed_subscription'] = (!empty($report['failed_subscription']) ? (absint($report['failed_subscription']) + 1) : 1); $report['errors'][] = sprintf(__('Row %d: Either donor_id or email is required to resolve the donor', 'give'), (int)(isset($import_setting['row_key']) ? $import_setting['row_key'] : 0)); $this->update_report($report); return 'Missing donor identifier (donor_id or email)'; } try { $currency = !empty($data['currency']) && array_key_exists($data['currency'], give_get_currencies_list()) ? $data['currency'] : give_get_currency(); $attributes = []; $attributes['donationFormId'] = (int)$data['form_id']; $resolvedDonorId = 0; if (!empty($data['donor_id'])) { $resolvedDonorId = (int)$data['donor_id']; } else { try { $email = (string)$data['email']; $firstNameCsv = (string)(isset($data['first_name']) ? $data['first_name'] : ''); $lastNameCsv = (string)(isset($data['last_name']) ? $data['last_name'] : ''); $donorModel = give(\Give\DonationForms\Actions\GetOrCreateDonor::class)(null, $email, $firstNameCsv, $lastNameCsv, null, null); if (!empty($import_setting['create_user']) && (int)$import_setting['create_user'] === 1) { try { $donorModel = give(\Give\Donors\Actions\CreateUserFromDonor::class)($donorModel); } catch (\Throwable $e) { } } $resolvedDonorId = (int)$donorModel->id; } catch (\Throwable $e) { $report['failed_subscription'] = (!empty($report['failed_subscription']) ? (absint($report['failed_subscription']) + 1) : 1); $this->update_report($report); return false; } } $attributes['donorId'] = $resolvedDonorId; $rawPeriod = strtolower(trim((string)$data['period'])); $periodAliases = [ 'daily' => 'day', 'days' => 'day', 'day' => 'day', 'weekly' => 'week', 'weeks' => 'week', 'week' => 'week', 'monthly' => 'month', 'months' => 'month', 'month' => 'month', 'quarterly' => 'quarter', 'quarters' => 'quarter', 'qtr' => 'quarter', 'qtrs' => 'quarter', 'quarter' => 'quarter', 'yearly' => 'year', 'annually' => 'year', 'annual' => 'year', 'yrs' => 'year', 'yr' => 'year', 'years' => 'year', 'year' => 'year', ]; $normalizedPeriod = isset($periodAliases[$rawPeriod]) ? $periodAliases[$rawPeriod] : $rawPeriod; if (!\Give\Subscriptions\ValueObjects\SubscriptionPeriod::isValid($normalizedPeriod)) { throw new \UnexpectedValueException(sprintf( __('Invalid subscription period "%1$s". Valid options: %2$s. You can also use: daily, weekly, monthly, quarterly, yearly.', 'give'), (string)$data['period'], implode(', ', array_values(\Give\Subscriptions\ValueObjects\SubscriptionPeriod::toArray())) )); } $attributes['period'] = new \Give\Subscriptions\ValueObjects\SubscriptionPeriod($normalizedPeriod); $attributes['frequency'] = (int)$data['frequency']; $attributes['installments'] = isset($data['installments']) ? (int)$data['installments'] : 0; $attributes['transactionId'] = isset($data['transaction_id']) ? (string)$data['transaction_id'] : ''; if (!empty($data['mode'])) { $mode = strtolower((string)$data['mode']); } else { $mode = (isset($import_setting['mode']) && $import_setting['mode']) ? 'test' : (give_is_test_mode() ? 'test' : 'live'); } $attributes['mode'] = new \Give\Subscriptions\ValueObjects\SubscriptionMode($mode); $amountDecimal = is_string($data['amount']) ? preg_replace('/[\$,]/', '', $data['amount']) : $data['amount']; $attributes['amount'] = \Give\Framework\Support\ValueObjects\Money::fromDecimal($amountDecimal, $currency); if (isset($data['fee_amount_recovered']) && $data['fee_amount_recovered'] !== '') { $feeDecimal = is_string($data['fee_amount_recovered']) ? preg_replace('/[\$,]/', '', $data['fee_amount_recovered']) : $data['fee_amount_recovered']; $attributes['feeAmountRecovered'] = \Give\Framework\Support\ValueObjects\Money::fromDecimal($feeDecimal, $currency); } $attributes['status'] = new \Give\Subscriptions\ValueObjects\SubscriptionStatus(strtolower(trim((string)$data['status']))); if (!empty($data['gateway_id'])) { $attributes['gatewayId'] = (string)$data['gateway_id']; } if (!empty($data['gateway_subscription_id'])) { $attributes['gatewaySubscriptionId'] = (string)$data['gateway_subscription_id']; } if (!empty($data['created_at'])) { $attributes['createdAt'] = new \DateTime((string)$data['created_at']); } if (!empty($data['renews_at'])) { $attributes['renewsAt'] = new \DateTime((string)$data['renews_at']); } if ($dry_run) { $report['create_subscription'] = (!empty($report['create_subscription']) ? (absint($report['create_subscription']) + 1) : 1); $this->update_report($report); return true; } $subscription = \Give\Subscriptions\Models\Subscription::create($attributes); if ($subscription && $subscription->id) { try { $donorModel = null; try { $donorModel = \Give\Donors\Models\Donor::find($subscription->donorId); } catch (\Throwable $e) { $donorModel = null; } $donorEmail = ($donorModel && isset($donorModel->email)) ? (string)$donorModel->email : ''; $donorName = ($donorModel && isset($donorModel->name)) ? (string)$donorModel->name : ''; $firstName = ''; $lastName = ''; if ($donorName) { $parts = preg_split('/\s+/', trim($donorName)); if ($parts) { $firstName = (string)array_shift($parts); $lastName = (string)trim(implode(' ', $parts)); } } $donationAttributes = [ 'subscriptionId' => $subscription->id, 'gatewayId' => !empty($attributes['gatewayId']) ? $attributes['gatewayId'] : 'manual', 'amount' => $subscription->amount, 'status' => \Give\Donations\ValueObjects\DonationStatus::COMPLETE(), 'type' => \Give\Donations\ValueObjects\DonationType::SUBSCRIPTION(), 'donorId' => $subscription->donorId, 'formId' => $subscription->donationFormId, 'feeAmountRecovered' => $subscription->feeAmountRecovered, 'mode' => $subscription->mode->isLive() ? \Give\Donations\ValueObjects\DonationMode::LIVE() : \Give\Donations\ValueObjects\DonationMode::TEST(), 'firstName' => $firstName, 'lastName' => $lastName, 'email' => $donorEmail, ]; if (!empty($data['first_name'])) { $donationAttributes['firstName'] = (string)$data['first_name']; } if (!empty($data['last_name'])) { $donationAttributes['lastName'] = (string)$data['last_name']; } if (!empty($data['email'])) { $donationAttributes['email'] = (string)$data['email']; } if (!empty($attributes['transactionId'])) { $donationAttributes['gatewayTransactionId'] = (string)$attributes['transactionId']; } if (!empty($subscription->createdAt)) { $donationAttributes['createdAt'] = $subscription->createdAt; } $initialDonation = \Give\Donations\Models\Donation::create($donationAttributes); if ($initialDonation && $initialDonation->id) { give()->subscriptions->updateLegacyParentPaymentId($subscription->id, $initialDonation->id); $this->update_legacy_after_initial_donation($initialDonation); } } catch (\Throwable $e) { $report['failed_subscription_initial_donation'] = (!empty($report['failed_subscription_initial_donation']) ? (absint($report['failed_subscription_initial_donation']) + 1) : 1); $report['errors'][] = sprintf(__('Row %1$d: Initial donation creation failed (%2$s)', 'give'), (int)(isset($import_setting['row_key']) ? $import_setting['row_key'] : 0), $e->getMessage()); } $report['create_subscription'] = (!empty($report['create_subscription']) ? (absint($report['create_subscription']) + 1) : 1); $this->update_report($report); return (int)$subscription->id; } $report['failed_subscription'] = (!empty($report['failed_subscription']) ? (absint($report['failed_subscription']) + 1) : 1); $this->update_report($report); return false; } catch (\Throwable $e) { $report['failed_subscription'] = (!empty($report['failed_subscription']) ? (absint($report['failed_subscription']) + 1) : 1); $report['errors'][] = sprintf(__('Row %1$d: %2$s', 'give'), (int)(isset($import_setting['row_key']) ? $import_setting['row_key'] : 0), $e->getMessage()); $this->update_report($report); return $e->getMessage(); } } /** * Get current import report * @since 4.11.0 */ public function get_report() { return get_option('give_import_subscription_report', []); } /** * Update import report * @since 4.11.0 */ private function update_report($value = []) { update_option('give_import_subscription_report', $value, false); } /** * Reset import report * @since 4.11.0 */ public function reset_report() { update_option('give_import_subscription_report', [], false); } /** * Update legacy donor totals and fee meta for newly created initial donation * @since 4.11.0 */ private function update_legacy_after_initial_donation(Donation $donation) { try { $donor = $donation->donor; if ($donor && isset($donor->id)) { give()->donors->updateLegacyColumns( $donor->id, [ 'purchase_value' => $this->get_donor_total_intended_amount((int)$donor->id), 'purchase_count' => $donor->totalDonations(), ] ); } if (null !== $donation->feeAmountRecovered) { give()->payment_meta->update_meta( $donation->id, '_give_fee_donation_amount', give_sanitize_amount_for_db( $donation->intendedAmount()->formatToDecimal(), ['currency' => $donation->amount->getCurrency()] ) ); } } catch (\Throwable $e) { } } /** * Calculate donor total intended amount across donations * @since 4.11.0 */ private function get_donor_total_intended_amount($donorId) { return (float)DB::table('posts', 'posts') ->join(function ($join) { $join->leftJoin('give_donationmeta', 'donor_meta') ->on('posts.ID', 'donor_meta.donation_id') ->andOn('donor_meta.meta_key', DonationMetaKeys::DONOR_ID, true); }) ->join(function ($join) { $join->leftJoin('give_donationmeta', 'amount_meta') ->on('posts.ID', 'amount_meta.donation_id') ->andOn('amount_meta.meta_key', DonationMetaKeys::AMOUNT, true); }) ->join(function ($join) { $join->leftJoin('give_donationmeta', 'fee_meta') ->on('posts.ID', 'fee_meta.donation_id') ->andOn('fee_meta.meta_key', DonationMetaKeys::FEE_AMOUNT_RECOVERED, true); }) ->where('posts.post_type', 'give_payment') ->where('donor_meta.meta_value', (int)$donorId) ->whereIn('posts.post_status', ['publish', 'give_subscription']) ->sum('IFNULL(amount_meta.meta_value, 0) - IFNULL(fee_meta.meta_value, 0)'); } /** * Subscription mapping options for CSV column selection * @since 4.11.0 */ public function get_subscription_options() { return (array)apply_filters( 'give_import_subscription_options', [ 'form_id' => [__('Donation Form ID', 'give'), __('Form ID', 'give')], 'donor_id' => [__('Donor ID', 'give')], 'first_name' => [__('Donor First Name', 'give'), __('First Name', 'give')], 'last_name' => [__('Donor Last Name', 'give'), __('Last Name', 'give')], 'email' => [__('Donor Email', 'give'), __('Email', 'give')], 'period' => [__('Period', 'give'), __('Subscription Period', 'give')], 'frequency' => [__('Frequency', 'give')], 'installments' => [__('Installments', 'give')], 'amount' => [__('Amount', 'give'), __('Recurring Amount', 'give')], 'fee_amount_recovered' => [__('Recovered Fee Amount', 'give')], 'status' => [__('Status', 'give')], 'mode' => [__('Mode', 'give'), __('Payment Mode', 'give')], 'transaction_id' => [__('Transaction ID', 'give')], 'gateway_id' => [__('Gateway ID', 'give'), __('Gateway', 'give')], 'gateway_subscription_id' => [__('Gateway Subscription ID', 'give')], 'created_at' => [__('Created At', 'give'), __('Start Date', 'give')], 'renews_at' => [__('Renews At', 'give'), __('Next Renewal Date', 'give')], 'currency' => [__('Currency', 'give')], ] ); } } Give_Import_Subscriptions::get_instance()->setup(); }