Moving contacts from one CiviCRM wordpress server to another server with different domain name

I had to move our WordPress CiviCRM install to a new server with a new domain, and decided that I wanted to do a fresh/clean install on the new server, and then I would import all the contacts from the old server.

In order for this method to be successful, here are some things I that I had to consider:

– Make sure to update both installs to the same version of CiviCRM.

– Make sure to go thru the CUSTOMIZE DATA AND SCREENS options, and you will need to add the items to the new install (such as Custom Fields, Profiles, Activity Types, etc) before you import anything, so that they match exactly with the old server.

– The import feature of CiviCRM only lets you import one type of contact at a time (Individual, Household or Organization), so when you export contacts from the old server you will need to split it into three exports, one for each type of contact. Do not export all types together, as you will not be able to import properly.

EXPORT
– To start the Export process, go to Find Contacts and choose the contact type you want and click SEARCH.
– Then you need to select the box that says ALL XYZ RECORDS. NOTE: For initial testing purposes, you might just want to select two or three contacts instead of all of them, so that you can test them to see if they export correctly, and if they import correctly on the new server. If the export or import does not work as expected, then you can make adjustments until the process it working correctly.
– Then choose EXPORT CONTACTS from the Actions drop down.
– Choose SELECT FIELDS FOR EXPORT, and if its your first time, you will leave the Use Saved Field Mapping blank (unless you have already saved a Field Mapping you want to use), and click CONTINUE.
– Now comes the most work! You will need to use the ADD FIELD button, and add every single field, one at a time. Make sure to use the SAVE FIELDS button often, and name it something like all_fields_organizations, so that if you need to do the export again, you have the field mapping already set up.
– Once you have the field mapping setup, click on DOWNLOAD FILE and you should have a CSV file with all your contacts of this type.

IMPORT
– Now login to your new server, and to start the Import process, look for Import Contacts under the Contacts menu.
– Choose your Contact Type to match what you exported.
– For Duplicate Contacts choose NO DUPLICATE CHECKING (this makes sure everything in your CSV file is imported).
– For Date Format, choose the mm/dd/yyyy option with the 4-digit year.
– If you have already mapped an import, you can use a Saved Field Mapping, or leave it blank if this is your first import.
– CiviCRM will try to match up the Column names with correct fields, but you need to verify if they are correct or not, and adjust them as necessary.
– For example, I set the following Columns as follows:
Addressee = Organization Name
Display Name = Organization Name
Sort Name = Organization Name
Organization Name = Organization Name
External Identifier = DO NOT IMPORT
Contact ID = External Identifier
– NOTE: On the old server, the External Identifier field was not being used. So I am putting the old servers Contact ID into the new servers External Identifier column. This allows me to have a reference for the contact in the old database.
– Save/Update your Field Mapping so you have it for later and click on CONTINUE. This will NOT import anything yet, but will give you a preview of what data will look like, and will also advise you if there are any errors in the CSV file that need to be fixed.
– Click IMPORT NOW when you are ready to import. Again, I recommend you just initially export a couple of contacts and try importing them to make sure the whole process works properly.

OPTIONAL STEP
When you import a contact in CiviCRM, both it’s Created Date and Modified Date get set to the date/time of import.
This last step may not be required for some of you, but for us, it was important the each Contacts CREATED DATE and LAST MODIFIED DATE remained the same as in the old database.
This requires a PHP script to pull those dates from the old database, and then another PHP script to update them in the new database.
In order for these scripts to work, it is important that we somehow associate the Contact ID from the old database with the new contact, and this where I set the Contact ID = External Identifier on the import mapping above.

OLD SERVER SCRIPT (see below)
This script will grab the Contact ID, Created Date and Modified Date of every contact in the database, and write them to a CSV file.

NEW SERVER SCRIPT (see below)
This script will read the CSV file above. It will then look at the Contact ID it read from the file, and see if there is a match in the External Identifier field. If it finds this match, it will then update the Created Date and Modified Date of the contact to match the old server dates.

MINOR ISSUE with BR tag
I noticed that one my custom fields (text/notes) imported line returns as & l t ; br / & g t ; [spaces added so it displays] and then there was extra < br / > tag visible/showing up in the text.
What I did was run an UPDATE with REPLACE on the specific column in that table and replace it with blank BEFORE I ran the NEW SERVER SCRIPT below.

 

OLD SERVER SCRIPT PHP CODE

// This script will get the Contact ID, Created Date and Modified Date of all contacts and write them to output.csv
$mysqli = new mysqli("localhost","db_user_name","db_password","db_name");
if ($mysqli -> connect_errno) {
  echo "Failed to connect to MySQL: " . $mysqli -> connect_error;
  exit();
}
echo "Connected to DB
"; if ($result = $mysqli -> query("SELECT id,modified_date,created_date FROM civicrm_contact ORDER BY id")) { echo "Number of rows found: " . $result -> num_rows."
"; if ($result -> num_rows > 0) { // FILE open $save_csv = "/path/to/public_html/output.csv"; // CHANGE ME ... Old server location wherever you put this script. Note that you have to move output.csv to the new server after its created. $csv_file_pointer = fopen($save_csv, "w"); // FILE Write CSV header $csv_data = "id,modified_date,created_date"; fwrite($csv_file_pointer, $csv_data.PHP_EOL); while ($row = $result->fetch_array()) { echo $row['id']." - ".$row['modified_date']." - ".$row['created_date']."
"; $csv_data = $row['id'].",".$row['modified_date'].",".$row['created_date']; // FILE Write CSV data fwrite($csv_file_pointer, $csv_data.PHP_EOL); } // FILE close fclose($csv_file_pointer); } } $mysqli -> close();

 

NEW SERVER SCRIPT PHP CODE

// This script will read output.csv file and then use the Contact ID from old database to look for a match in the new database External Identifer field. If a match is found, it will update the Created Date and Modified Date of the new contact to match the old database.
$mysqli = new mysqli("localhost","db_user","db_password","db_name");
if ($mysqli -> connect_errno) {
  echo "Failed to connect to MySQL: " . $mysqli -> connect_error;
  exit();
}
echo "Connected to DB
"; $file = fopen('/path/to/public_html/output.csv', 'r'); // CHANGE ME ... New server location wherever you put this script. Note that you have to move output.csv from the old server to this new server. while (($line = fgetcsv($file)) !== FALSE) { $extern_id = $line[0]; $modified_date = $line[1]; $created_date = $line[2]; if ($result = $mysqli -> query("SELECT id,modified_date,created_date FROM civicrm_contact WHERE external_identifier ='$extern_id' LIMIT 1 ")) { if ($result -> num_rows > 0) { //while ($row = $result->fetch_array()) { $row = $result->fetch_array(); $id = $row['id']; $old_modified_date = $row['modified_date']; $old_created_date = $row['created_date']; echo "FOUND id=$id with ext_id match=$extern_id :: old_mod=$old_modified_date old_created=$old_created_date new_mod=$modified_date new_created=$created_date"; // UPDATE here if ($result = $mysqli -> query("UPDATE civicrm_contact SET modified_date='$modified_date', created_date='$created_date' WHERE id='$id' ")) { echo " --UPDATED
"; } else { echo " --Error: could not update.
"; } //} } } } fclose($file); echo "
DONE
"; $mysqli -> close();

Importing WooCommerce products into WordPress with custom fields and multiple product categories

If you are trying to import products into WooCommerce that have custom fields, you can try the Really Simple CSV Importer plugin and follow my instructions below.

Note that the Really Simple CSV Importer plugin v1.3 has not been updated for years, however it still works fine as of WordPress v5.8 for importing WooCommerce products.
In order to use it, you go to TOOLS then IMPORT and you will see it in the list import tools to choose from.

Some caveats with Really Simple CSV Importer plugin:
– The CSV file needs to be UTF-8.
– The header row of CSV file should NOT have double-quotes around each field.
– Each row in the CSV file (except the header row) should have double-quotes around each field.
– Each field in each row must use a comma as the seperator.
– To import to a custom field (meta field) called my_custom_field just use that exact name in the header row field name.
– To import to a hidden custom field called (hidden meta field) _my_custom_hidden_field you need to put an _underscore_ in front of the header row field name.
– It appears that post_id and post_name are required in the header row fields, but you can leave them blank and they will be automatically be generated.
– post_category generates a category under POSTS instead of PRODUCTS, so leave post_category blank.
– To import to a woocommerce specific custom field, you can use the following in the header row fields (these are just some of them):
  For REGULAR PRICE use: _regular_price
  For SALE PRICE use: _sale_price
  For the displayed PRICE use: _price
  For SKU use: _sku
  For STOCK MANAGEMENT (yes or no) use: _manage_stock
  For STOCK QUANTITY use: _stock
  For PRODUCT CATEGORY use (can only specify a single category): tax_product_cat
  For PRODUCT TYPE use (simple): tax_product_type
  For SHOP CATALOG or SEARCH visibility use (can specify one of exclude-from-search or exclude-from-catalog): tax_product_visibility

Here is a sample CSV file you can copy and paste:

post_id,post_name,post_title,post_content,post_author,post_date,post_tags,post_category,post_thumbnail,post_type,post_status,_sku,_regular_price,_price,_stock,_manage_stock,_visibility,tax_product_visibility,tax_product_type,tax_product_cat,_custom_field_hidden,custom_field_meta
"","my-first-product-url-slug","My first product name","description","","","","","https://mywordpresssite.com/wp-content/uploads/first-product-featured-image.jpg","product","publish","first-product-sku","50","50","3","yes","hidden","exclude-from-search","simple","my-product-category","hidden meta field","meta field"
"","my-second-product-url","My second product name","description","","","","","https://mywordpresssite.com/wp-content/uploads/second-product-featured-image.jpg","product","publish","second-product-sku","20","20","4","yes","hidden","exclude-from-catalog","simple","another-product-category","hidden meta field","meta field"

MODIFICATIONS TO CODE
I have created a couple modifications to the Really Simple CSV Importer code that will allow the following:
– Add multiple product categories seperated by the pipe | character: “my-product-cat|another-product-cat”
– Add both product visibility options seperated by the pipe | character: “exclude-from-catalog|exclude-from-search”
– Add a new header row option called “tax_search_exclude” which will allow you use the SEARCH EXCLUDE plugin: “yes”
NOTE: The exclude-from-search option will only hide products from the WooCommerce search but not from the WordPress search. In order to also hide products from the WordPress search, you need to use the SEARCH EXCLUDE plugin https://wordpress.org/plugins/search-exclude/

In order to make these modifications work, you need to modify the following file around line 289: class-rscsv_import_post_helper.php

Look for this code:

public function setObjectTerms($taxonomy, $terms)
{
$post = $this->getPost();

And replace with this code:

public function setObjectTerms($taxonomy, $terms)
{

//// MOD by jsherk //////////////////////////////////////////////////////////////////////////////////////

////////////// MULTIPLE terms for a TAXONOMY
// Check if taxonomy has more than one term (use | to specify multiple terms).
// For example import "tax_product_cat" as: "myCategory1|anotherCategory2" to add it to two categories.
// For example import "tax_product_visibility" as: "exclude-from-search|exclude-from-catalog" to hide from both shop catalog and search
$new_terms = array();
foreach ($terms as $term) {
$terms_split = false;
if (strpos($term, "|") == true ) {
$terms_split = true; // Yes the term contained multiple terms seperated by the pipe| character.
$split_terms = explode("|", $term);
foreach ($split_terms as $split_term ) {
// Add each split as a seperate term
$new_terms[] = $split_term;
}
}
if ($terms_split == false) {
// No the term did not contain multiple terms.
$new_terms[] = $term;
}
}
$terms = $new_terms; // Replace orignal terms with split up terms
//////////////

////////////// SEARCH EXCLUDE PLUGIN https://wordpress.org/plugins/search-exclude/
// If you use a plugin called SEARCH EXCLUDE then we need to create an OPTION instead of a TAXONOMY.
// In the csv file, use a csv header of "tax_search_exclude" and then set a value of either "yes" or "no". If the value is "yes" then we will add the option to the options table.
if ($taxonomy == "search_exclude") {
if (strtolower($terms[0]) == "yes") {
$server_path_array = explode("wp-content", __FILE__);
$server_path = $server_path_array[0];
$wp_load = $server_path.'wp-load.php';
require_once( $wp_load );
$wp_option = $server_path.'wp-includes/option.php';
require_once($wp_option);
$post = $this->getPost();
$new_option_id = intval($post->ID); // get the post_id
$search_exclude_options = get_option("sep_exclude"); // read the current values from the options table
if (empty($search_exclude_options)) {
// if the option is empty, then it does not exist and needs to be added
$new_search_exclude_option = array($new_option_id);
delete_option("sep_exclude"); // option may exist but be empty so we need to delete it first otherwise add_option will not update (add_option will only work if the option does not exist at all).
add_option("sep_exclude", $new_search_exclude_option, " ", "yes");
} else {
$search_exclude_options[] = $new_option_id;
update_option("sep_exclude", $search_exclude_options);
}
$search_exclude_options = get_option("sep_exclude"); // re-read the current values from the options table
}
}
//////////////

//// end MOD by jsherk //////////////////////////////////////////////////////////////////////////////////////

$post = $this->getPost();

Here is a sample CSV file with MODIFICATIONS you can copy and paste:

post_id,post_name,post_title,post_content,post_author,post_date,post_tags,post_category,post_thumbnail,post_type,post_status,_sku,_regular_price,_price,_stock,_manage_stock,_visibility,tax_search_exclude,tax_product_visibility,tax_product_type,tax_product_cat,_custom_field_hidden,custom_field_meta
"","my-first-product-url-slug","My first product name","description","","","","","https://mywordpresssite.com/wp-content/uploads/first-product-featured-image.jpg","product","publish","first-product-sku","50","50","3","yes","hidden","yes","exclude-from-search|exclude-from-catalog","simple","my-product-category|another-product-category","hidden meta field","meta field"
"","my-second-product-url","My second product name","description","","","","","https://mywordpresssite.com/wp-content/uploads/second-product-featured-image.jpg","product","publish","second-product-sku","20","20","4","yes","hidden","no","exclude-from-catalog","simple","another-product-category","hidden meta field","meta field"

Simple POS setup for WooCommerce – Point Of Sale plugins for WordPress

I was looking for a simple Point Of Sale (POS) solution that would allow me to take in-person Cash payments as well as Credit Card payments for my WooCommerce store.

There are several free POS plugins available that allow Cash payments, but you need to pay for the Pro versions if you also want to take Credit Cards as well.

There are also several free POS plugins that will allow you to take both Cash and Credit Card payments, but you need to use their credit processor and not your own.

The following is a very simple POS setup that will allow you to take both Cash payments on your WooCommerce store, as well as Credit Card payments using whatever credit card processor and gateway you already have setup.

There are a few issues that you need to be aware of if you are going to use this method:
(1) This setup assumes that you are currently NOT using the Cash On Delivery payment method in WooCommerce. If you are already using this payment method, then this setup will not work for you.
(2) This method will not calculate change due from cash tendered. You will manually need to do this.
(3) With this method, you can not split a payment as partial cash and partial credit card. It needs to be all cash or all credit card.

If those issues are not a problem for you, then below are the steps you need to set it up and make it work for you.

In summary, what we are going to do is add a new user with a new/unique user role called SHOP CASHIER. We will then make the Cash On Delivery method availble during the checkout process, but only if this user with SHOP CASHIER role is logged in. If any other user is logged in, or if no user is logged in, then the Cash On Delivery method will not be available.

STEP 1 – Install and Activate plugins
Install and activate the following two plugins:
Members (MemberPress) https://wordpress.org/plugins/members/
Payment Gateways by User Roles for WooCommerce (Imaginate Solutions) https://wordpress.org/plugins/payment-gateways-by-user-roles-for-woocommerce/

STEP 2 – Create a new role
Go to Members tab then to Roles.
Look for the Subscriber role, and click on CLONE.
Change the Cloned Role name to something like “SHOP CASHIER” and click on ADD ROLE.
NOTE: You can actually clone any role you want, but I chose the Subscriber role because my Shop Cashier does not need to access anything else within WordPress.
NOTE: The Members plugin has a setting (which is ON by default) that will allow you to assign multiple roles to the same user. You can disable this if would prefer to leave it the WordPress default way, where they can only be assigned a single role at a time.

STEP 3 – Add a new user with new role
Go to Users tab and then Add New.
Create a new user and assign them the new role of SHOP CASHIER and click ADD NEW USER.

STEP 4 – Set CASH ON DELIVERY as only availble to new role
Go to WooCommerce tab then to Settings then to Payment Gateways By User Roles.
Under the CASH ON DELIVERY method, click in the INCLUDE USER ROLES box and select the SHOP CASHIER role.
Scroll to bottom and click on SAVE CHANGES.

STEP 5 – Activate the Cash On Delivery payment method
Go to WooCommerce tab then to Settings then to Payments.
Click on the Set Up/Manage button for the Cash On Delivery method.
Check the box to ENABLE this method.
Set the title to something like: CASH
Set the description to something like: When customer has PAID in FULL with cash, click on PLACE ORDER.
Set the instructions to something like: Pay with cash, in-person.
Click on SAVE CHANGES.

STEP 6 – Test your changes
Now to test your setup, log out from WordPress and go to your WooCommerce store and add a product to your cart and the proceed to checkout.
Since you are logged out, you should NOT see the CASH method available. Only the regular payments methods that are normally available to your customers should be availble.
You can also try to login with any user except the new SHOP CASHIER user. When you log in with any other except the SHOP CASHIER user, you should still NOT see the CASH method available.
Now finally you want to login with the SHOP CASHIER user. When you proceed to checkout, you should now see the option for CASH available along with all your other regular payment methods, so you will be able to accept in-person cash payments as well as your any of your other payment methods.

Per Product Flat Rate Shipping for WooCommerce

Per Product Flat Rate Shipping for WC has just been released!

Set seperate flat-rate shipping costs for both Domestic and International shipping on a per product basis in WooCommerce.

This plugin will allow to set a flat-rate domestic shipping price and also a flat-rate international shipping price for each WooCommerce product that you have.

Find it here: https://wordpress.org/plugins/per-product-flat-rate-shipping-for-wc/

Automatically Rename Media On Upload Plugin

Automatically Rename Media on Upload plugin has just been released.

This plugin will automatically rename any media files you upload to the Media Library, by adding a prefix to the beginning of the filename based on the filetype.

For example, you can tell it to add the prefix “pic-” to the beginning of all .jpg files that you upload. So uploading an image called car.jpg would get renamed to pic-car.jpg

And since it changes the name of the file, it will also change the “slug” that wordpress uses based on this new name.

You can set an individual/unique prefix for each of the following filetypes:
jpg jpeg png bmp gif tif mp4 avi m4v mov flv mkv 3gp pdf doc docx xls xlsx ppt pptx mp3 ogg wav zip csv txt

You will need to go to the settings page and set the prefix you want to use for each of the filetypes.

The default behavior is that it will NOT rename any uploaded files until you have set the prefix on the settings page.

== Frequently Asked Questions ==

= Can I manually rename the files when I upload them? =
No. In the settings you can set how the filename will be renamed when it is uploaded. File will be automatically renamed during the upload process.

= Can I choose whether a file will be renamed when I upload it? =
No. In the settings you can set how the filename will be renamed when it is uploaded. File will be automatically renamed during the upload process.

= How do I disable renaming files of only certain types? =
On the settings page, you can remove the prefix from the textbox and set it empty/blank for any filetype that you do not want to be renamed when it is uploaded. If a particular filetype has an empty/blank textbox, then it will not be renamed when it is uploaded.

= How do I rename only files of one specific filetype, but not all the other filetypes? =
On the settings page, you can remove the prefix from the textbox and set it empty/blank for any filetype that you do not want to be renamed when it is uploaded. If a particular filetype has an empty/blank textbox, then it will not be renamed when it is uploaded.

= For what filetypes can I modify the prefix for the renaming of the file? =
You can set an individual/unique prefix for each of the following filetypes: jpg jpeg png bmp gif tif mp4 avi m4v mov flv mkv 3gp pdf doc docx xls xlsx ppt pptx mp3 ogg wav zip csv txt

= The filetype I need to rename is not listed. What can I do? =
Submit a support request and I will see if I can get that filetype added for you.

= I have uploaded a file to the Media Library, but it was not renamed? What happened? =
Make sure you go to the settings page and set the prefix you want to use for the particular filetype you are uploading and want renamed. And don’t forget to hit the SAVE button to make sure your changes are saved.

Easy Option for WooCommerce WordPress plugin

Access hidden options such as: Disable Confirm Logout, Change Minimum Password Strength, Show Empty Product Categories, Hide Product Category Name/Count, Disable New User Registration from wp-login.php screen.

Easy Options for WooCommerce will allow you to access some hidden options that are not normally available to you.

* CONFIRM LOGOUT: Allows you to disable to the Confirm Logout question on the WooCommerce My-Account page.

* MINIMUM PASSWORD STRENGTH: Allows you to change the Minimum Password Strength required for users. You can choose Strong, Medium, Weak or Very Weak.

* EMPTY PRODUCT CATEGORIES: Let’s you choose to show or hide empty product categories on the Shop pages.

* PRODUCT CATEGORY TEXT: Let’s you choose to show or hide the title/text that appears under each product category image on the Shop pages.

* PRODUCT CATEGORY COUNT: Let’s you choose to show or hide the count of items that appears under each product category image on the Shop pages.

* DISABLE NEW USER REGISTRATION: If you are using the WooCommerce registration pages on My-Account page and/or during checkout, you can choose to disable the new user registration form that appears on wp-login.php?action=register . This can help reduce spam bot sign ups.

Minimum Password Strength for WooCommerce

This plugin is DEPRECATED and is no longer under development.

New WordPress plugin available:
Minimum Password Strength for WooCommerce

Adjust the minimum password strength required by WooCommerce. Choose from strong, medium, weak or very weak.

WooCommerce minimum password strength can be set to Very Weak, Weak, Medium or Strong. A setting of Very Weak will also disable the strength meter used on WooCommerce pages.