From 13bc9c89d6d984c2fd34d3c9c16a3b8065b31707 Mon Sep 17 00:00:00 2001 From: Dejan Markovic Date: Thu, 4 Apr 2024 01:27:11 +0200 Subject: [PATCH] [DM] adding Batch Import plugin to repo. (#860) * [DM] adding Batch Import plugin o repo. * [DM] 1. Batch Import plugin moved to its own folder. 2. Added example .csv file 3. Added plugin path to gitignore --------- Co-authored-by: jaspercroome <128058464+jaspercroome@users.noreply.github.com> --- .gitignore | 1 + .../batch-upload-plugin.php | 384 ++++++++++++++++++ plugins/batch-upload-plugin/example.csv | 2 + 3 files changed, 387 insertions(+) create mode 100644 plugins/batch-upload-plugin/batch-upload-plugin.php create mode 100644 plugins/batch-upload-plugin/example.csv diff --git a/.gitignore b/.gitignore index d8712170..50650654 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,4 @@ client-mu-plugins/goodbids/config.local.json !/client-mu-plugins/goodbids/vendor/bshaffer/ !/plugins/wp-mail-smtp-pro/ !/plugins/wp-mail-smtp-pro/vendor/ +!/plugins/batch-upload-plugin/ diff --git a/plugins/batch-upload-plugin/batch-upload-plugin.php b/plugins/batch-upload-plugin/batch-upload-plugin.php new file mode 100644 index 00000000..e9f29e4d --- /dev/null +++ b/plugins/batch-upload-plugin/batch-upload-plugin.php @@ -0,0 +1,384 @@ +'; + echo '

' . __( 'Batch Upload', 'goodbids' ) . '

'; + + if ( isset( $_POST['batch_upload_nonce'] ) && wp_verify_nonce( $_POST['batch_upload_nonce'], 'batch_upload_action' ) ) { + if ( isset( $_FILES['batch_upload_csv'] ) ) { + $file = $_FILES['batch_upload_csv']; + $filename = $file['tmp_name']; + + if ( ( $handle = fopen( $filename, 'r' ) ) !== false ) { + fgetcsv( $handle, 1000, ',' ); // Skip the header row + + $errors = []; + $success_sites = []; + $failed_sites = []; + $row_number = 1; + + // Disable the "New Site Registration" email + add_filter( 'wpmu_welcome_notification', '__return_false' ); + + // Disable the "Admin Email Changed" email + add_filter( 'update_option_new_admin_email', '__return_false', 10, 2 ); + + while ( ( $data = fgetcsv( $handle, 1000, ',' ) ) !== false ) { + $row_number ++; + + if ( count( $data ) !== 11 ) { + $errors[] = sprintf( __( 'Error on row %d: incorrect number of columns', 'goodbids' ), $row_number ); + continue; + } + + $fileName = trim( $data[0] ); + $ein = trim( $data[1] ); + $website = trim( $data[2] ); + $contactName = trim( $data[3] ); + $contactEmail = trim( $data[4] ); + $contactTitle = trim( $data[5] ); + $blogName = trim( $data[6] ); + $blogDescription = trim( $data[7] ); + $timezone = trim( $data[8] ); + $site_url = trim( $data[9] ); + $home = trim( $data[10] ); + + // Skip empty rows + if ( empty( $fileName ) && empty( $ein ) && empty( $website ) && empty( $contactName ) && empty( $contactEmail ) && empty( $contactTitle ) && empty( $blogName ) && empty( $blogDescription ) && empty( $timezone ) && empty( $site_url ) && empty( $home ) ) { + continue; + } + + $row_errors = []; + + if ( empty( $fileName ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: Legal Name is missing', 'goodbids' ), $row_number ); + } + + if ( empty( $ein ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: EIN is missing', 'goodbids' ), $row_number ); + } + elseif ( ! preg_match( '/^\d{2}-\d{7}$/', $ein ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: EIN format is incorrect', 'goodbids' ), $row_number ); + } + + if ( empty( $website ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: Website is missing', 'goodbids' ), $row_number ); + } + elseif ( ! goodbids_validate_domain( $website ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: Website value is invalid', 'goodbids' ), $row_number ); + } + + if ( empty( $contactName ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: Primary Contact legal_name is missing', 'goodbids' ), $row_number ); + } + + if ( empty( $contactEmail ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: Primary Contact Email Address is missing', 'goodbids' ), $row_number ); + } + elseif ( ! filter_var( $contactEmail, FILTER_VALIDATE_EMAIL ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: Primary Contact Email Address is invalid', 'goodbids' ), $row_number ); + } + + if ( empty( $contactTitle ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: Primary Contact Job Title is missing', 'goodbids' ), $row_number ); + } + + if ( empty( $blogName ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: Blog Name is missing', 'goodbids' ), $row_number ); + } + + if ( empty( $blogDescription ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: Blog Description is missing', 'goodbids' ), $row_number ); + } + + if ( empty( $timezone ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: timezone_string is missing', 'goodbids' ), $row_number ); + } + elseif ( ! in_array( $timezone, timezone_identifiers_list() ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: timezone_string is invalid', 'goodbids' ), $row_number ); + } + + if ( empty( $site_url ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: site_url is missing', 'goodbids' ), $row_number ); + } + elseif ( ! goodbids_validateUrl( $site_url ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: site_url is invalid', 'goodbids' ), $row_number ); + } + + if ( empty( $home ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: home value is missing', 'goodbids' ), $row_number ); + } + elseif ( ! goodbids_validateUrl( $home ) ) { + $row_errors[] = sprintf( __( 'Error on row %d: home value is invalid', 'goodbids' ), $row_number ); + } + + // Skip site creation if there are any validation errors + if ( ! empty( $row_errors ) ) { + $errors = array_merge( $errors, $row_errors ); + $failed_sites[] = $site_url; + continue; + } + + $main_domain = get_network()->domain; + $user_id = get_current_user_id(); + $path = parse_url( $site_url, PHP_URL_PATH ); + + $result = wpmu_create_blog( $main_domain, $path, $blogName, $user_id, [ 'public' => 1 ], get_current_network_id() ); + + if ( $result instanceof WP_Error ) { + $errors[] = sprintf( __( 'Error on row %d: error creating site for domain: %s. Error message: %s', 'goodbids' ), $row_number, esc_html( $main_domain . $path ), $result->get_error_message() ); + $failed_sites[] = $site_url; + } + else { + $success_sites[] = $site_url; + + $processed_data = [ + 'legal_name' => $fileName, + 'EIN' => $ein, + 'website' => $website, + 'primary_contact_name' => $contactName, + 'primary_contact_email' => $contactEmail, + 'primary_contact_job_title' => $contactTitle, + 'blog_name' => $blogName, + 'blog_description' => $blogDescription, + 'timezone_string' => $timezone, + 'subdirectory_path' => $path, + ]; + + goodbids_update_site_options( $result, $processed_data ); + } + } + + // Re-enable the "New Site Registration" email + remove_filter( 'wpmu_welcome_notification', '__return_false' ); + + // Re-enable the "Admin Email Changed" email + remove_filter( 'update_option_new_admin_email', '__return_false', 10 ); + + fclose( $handle ); + + if ( ! empty( $errors ) ) { + echo '

' . __( 'CSV file contains errors. Please correct the data and try again.', 'goodbids' ) . '

'; + echo '
'; + } + + if ( ! empty( $success_sites ) ) { + echo '

' . sprintf( __( '%d site(s) created successfully:', 'goodbids' ), count( $success_sites ) ) . '

'; + echo '
'; + } + + if ( ! empty( $failed_sites ) ) { + echo '

' . sprintf( __( '%d site(s) failed to be created:', 'goodbids' ), count( $failed_sites ) ) . '

'; + echo '
'; + } + + $subject = 'Batch Upload Results'; + $message = "Batch upload completed.\n\n"; + + if ( ! empty( $success_sites ) ) { + $message .= "The following sites were created successfully:\n"; + $message .= implode( "\n", $success_sites ); + $message .= "\n\n"; + } + + if ( ! empty( $failed_sites ) ) { + $message .= "The following sites failed to be created:\n"; + $message .= implode( "\n", $failed_sites ); + $message .= "\n\n"; + } + + if ( ! empty( $errors ) ) { + $message .= "The following errors occurred:\n"; + $message .= implode( "\n", array_map( function ( $error ) { + return '- ' . $error; + }, $errors ) ); + $message .= "\n\n"; + } + + wp_mail( $toEmail, $subject, $message, '', [ 'cc' => $ccEmail ] ); + } + } + } + + echo '
'; + wp_nonce_field( 'batch_upload_action', 'batch_upload_nonce' ); + echo ''; + submit_button( __( 'Upload CSV', 'goodbids' ) ); + echo '
'; + + // Add a link to the CSV file + $csv_file_url = plugins_url( 'example.csv', __FILE__ ); + echo '

Download the example CSV file: example.csv

'; + + echo ''; +} + +function goodbids_validateUrl( $url ) { + + // Validate the modified URL + if ( filter_var( $url, FILTER_VALIDATE_URL ) ) { + + return true; + + } + else { + + return false; + + } +} + +// Function to update site options based on dynamic fields +function goodbids_update_site_options( $blog_id, $data ) { + + $legalName = $data['legal_name']; + $EIN = $data['EIN']; + $website = $data['website']; + $contactName = $data['primary_contact_name']; + $contactEmail = $data['primary_contact_email']; + $contactTitle = $data['primary_contact_job_title']; + $blogName = $data['blog_name']; + $blogDescription = $data['blog_description']; + $subdirectoryPath = $data['subdirectory_path']; // Get subdirectory path from processed data + $timezone_string = $data['timezone_string']; + + $dynamic_fields = [ + 'EIN' => 'EIN', + 'legal_name' => 'legal_name', + 'primary_contact_email_address' => 'same as primary contact email address', + 'primary_contact_job_title' => 'same as primary primary contact job title', + 'home' => 'same as site url', + 'siteurl' => 'same as site url', + 'finance_contact_legal_name' => 'legal_name', + 'finance_contact_email_address' => 'same as primary contact email address', + 'finance_contact_job_title' => 'same as primary primary contact job title', + 'admin_email' => 'same as primary contact email', + 'woocommerce_email_from_name' => 'blogname', + 'woocommerce_stock_email_recipient' => 'same as primary contact email', + 'goodbids_onboarded' => 'upload time', + 'new_admin_email' => 'same as admin email', + 'blogdescription' => 'blogdescription', + 'timezone_string' => 'timezone string', + 'primary_contact_legal_name' => 'primary contact legal name', + 'website' => 'website', + + ]; + + foreach ( $dynamic_fields as $field => $default_value ) { + $value = ''; + + switch ( $default_value ) { + case 'legal_name': + $value = $legalName; + break; + case 'EIN': + $value = $EIN; + break; + case 'same as primary contact email address': + $value = $contactEmail; + break; + case 'same as primary primary contact job title': + $value = $contactTitle; + break; + case 'same as site url': + $value = network_site_url( $subdirectoryPath ); // Use subdirectory path to generate site URL + break; + case 'blogname': + $value = $blogName; + break; + case 'upload time': + $value = current_time( 'mysql' ); + break; + case 'same as primary contact email': + case 'same as admin email': + $value = $contactEmail; + break; + case 'blogdescription': + $value = $blogDescription; + break; + case 'timezone string': + $value = $timezone_string; + break; + case 'primary contact legal name': + $value = $contactName; + break; + case 'website': + $value = $website; + break; + default: + $value = $default_value; + } + + update_blog_option( $blog_id, $field, $value ); + } +} + + +function goodbids_validate_domain( $domain ) { + // Remove any leading/trailing spaces + $domain = trim( $domain ); + + // Convert to lowercase for consistent comparison + $domain = strtolower( $domain ); + + // Check if the domain starts with "www." and contains valid characters + if ( strpos( $domain, 'www.' ) === 0 && preg_match( '/^[a-z0-9.-]+$/', $domain ) ) { + return true; // Valid domain + } + else { + return false; // Invalid domain + } +} + +?> diff --git a/plugins/batch-upload-plugin/example.csv b/plugins/batch-upload-plugin/example.csv new file mode 100644 index 00000000..14307288 --- /dev/null +++ b/plugins/batch-upload-plugin/example.csv @@ -0,0 +1,2 @@ +Legal Name,EIN,website,primary contact legal name,primary contact email address,primary contact job title,blogname,blogdescription,timezone_string,site_url,home +Friends of The Columbia Gorge,93-0782467,WWW.GORGEFRIENDS.ORG,Jasper Croome,tech@goodbids.org,Software Developer,Friends of the Columbia Gorge,"For Decades, Friends of the Gorge has been advocating on behalf of the Columbia River Gorge",America/New_York,https://goodbids.org/friends-of-the-gorge,https://goodbids.org/friends-of-the-gorge \ No newline at end of file