Plugin Directory

Changeset 2563515


Ignore:
Timestamp:
07/13/2021 12:17:00 PM (5 years ago)
Author:
eighty20results
Message:

Update to version v3.0.6 from GitHub

Location:
pmpro-import-members-from-csv
Files:
8 added
2 deleted
50 edited
1 copied

Legend:

Unmodified
Added
Removed
  • pmpro-import-members-from-csv/tags/v3.0.6/CHANGELOG.md

    r2555218 r2563515  
    66
    77## [Unreleased]
     8
     9## v3.0.6 - 2021-07-13
     10- BUG FIX: Updates to presence check for test types (Thomas Sjolshagen)
     11- BUG FIX: Didn't install the ruleset when in GitHub Action (Thomas Sjolshagen)
     12- BUG FIX: Fatal error during install of production composer dependencies (Thomas Sjolshagen)
     13- BUG FIX: acceptance-test target didn't work (Thomas Sjolshagen)
     14- BUG FIX: TTYs in docker-compose.yml (Thomas Sjolshagen)
     15- BUG FIX: Adding a stripped down data file for the WP Unit tests (Thomas Sjolshagen)
     16- BUG FIX: Refactor of the Makefile (Thomas Sjolshagen)
     17- BUG FIX: Didn't exclude inc/ in codeception.dist.yml (Thomas Sjolshagen)
     18- BUG FIX: Handle DB Dump if present (Thomas Sjolshagen)
     19- BUG FIX: Reverted inclusion of SQL file in repo (Thomas Sjolshagen)
     20- BUG FIX: Wrong path to the DB file we need for testing (Thomas Sjolshagen)
     21- BUG FIX: Add Docker Hub login to release-plugin.yml (Thomas Sjolshagen)
     22- BUG FIX: Include SQL so it can be used by WP Unit ++ tests (Thomas Sjolshagen)
     23- BUG FIX: Fix issue with TTY during GitHub action execution (Thomas Sjolshagen)
     24- BUG FIX: Adding COMPOSE_INTERACTIVE_NO_CLI=1 to work around 'The input device is not a TTY' errors/warnings (Thomas Sjolshagen)
     25- BUG FIX: Make sure we use the correct Docker Hub login approach (Thomas Sjolshagen)
     26- BUG FIX: Use log file if it's available (Thomas Sjolshagen)
     27- BUG FIX: Use action recipe for docker hub login (Thomas Sjolshagen)
     28- BUG FIX: More testing of docker hub login (Thomas Sjolshagen)
     29- BUG FIX: Split remote and local removal of tags (Thomas Sjolshagen)
     30- BUG FIX: Updates to debug Docker Hub login issues (Thomas Sjolshagen)
     31- BUG FIX: Make sure the file check works w/o error as a GitHub action (Thomas Sjolshagen)
     32- BUG FIX: Revert the shell based check for phpcs presence (shouldn't be needed) (Thomas Sjolshagen)
     33- BUG FIX: Troubleshooting the Makefile (Thomas Sjolshagen)
     34- BUG FIX: Use BASH by default when running commands (Thomas Sjolshagen)
     35- BUG FIX: Clean up PHONY targets and enable curl output (Thomas Sjolshagen)
     36- BUG FIX: Add PHPStan testing (Thomas Sjolshagen)
     37- BUG FIX: Enable parallel execution for PHPStan and omit a couple of error types (Thomas Sjolshagen)
     38- BUG FIX: PHPStan fixes to handle different versions of the Licensing module (Thomas Sjolshagen)
     39- BUG FIX: PHPStan related fixes in the Users class-column-validation.php file (Thomas Sjolshagen)
     40- BUG FIX: PHPStan related fixes in class-import-sponsors.php (Thomas Sjolshagen)
     41- BUG FIX: Incomplete argument type definition for Sponsor::get() method (Thomas Sjolshagen)
     42- BUG FIX: PHPStan related fixes in the PMPro class-import-member.php file (Thomas Sjolshagen)
     43- BUG FIX: Various logic and PHPStan related fixes in the PMPro class-column-validation.php file (Thomas Sjolshagen)
     44- BUG FIX: Various PHPStan related fixes in the BuddyPress class-column-validation.php file (Thomas Sjolshagen)
     45- BUG FIX: Various PHPStan related fixes for class-csv.php (Thomas Sjolshagen)
     46- BUG FIX: Remove unneeded exit() calls - PHPStan fixes for class-ajax.php (Thomas Sjolshagen)
     47- BUG FIX: Incorrect PHPStan errors for add_filter() function (Thomas Sjolshagen)
     48- BUG FIX: The $id parameter wasn't defined for all code paths in class-import-user.php (Thomas Sjolshagen)
     49- BUG FIX: Fixed PMPro related ignore/revert ignore comments in class-email-templates.php (Thomas Sjolshagen)
     50- BUG FIX: Ignored a PHPStan non-error in class-data.php (Thomas Sjolshagen)
     51- BUG FIX: Return value in PHPDoc wrong for load_actions() method (Thomas Sjolshagen)
     52- BUG FIX: PHPStan fixes for class-base-validation.php (Thomas Sjolshagen)
     53- BUG FIX: PHPStan fixes for class-activateutilitiesplugin.php (Thomas Sjolshagen)
     54- BUG FIX: Fatal errors due to poor error recovery in autoloader (Thomas Sjolshagen)
     55- BUG FIX: Clean up config for phpstan-test target (Thomas Sjolshagen)
     56- BUG FIX: code-standards-test target depends on plugin and composer modules (Thomas Sjolshagen)
     57- BUG FIX: Add WP Neutron code standards config (Thomas Sjolshagen)
     58- BUG FIX: PHPCS ignored some of the plugin source files (Thomas Sjolshagen)
     59- BUG FIX: Add WP Neutron code standards config (Thomas Sjolshagen)
     60- BUG FIX: Code sniffer updates for Buddypress version of class-column-validation.php (Thomas Sjolshagen)
     61- BUG FIX: Code sniffer updates for class-buddypress.php (Thomas Sjolshagen)
     62- BUG FIX: Code sniffer updates for class-import-buddypress.php (Thomas Sjolshagen)
     63- BUG FIX: Code sniffer updates for class-import-member.php (Thomas Sjolshagen)
     64- BUG FIX: Code sniffer updates for class-pmpro.php (Thomas Sjolshagen)
     65- BUG FIX: Code sniffer updates for class-ajax.php (Thomas Sjolshagen)
     66- BUG FIX: Code sniffer updates for class-column-validation.php (Thomas Sjolshagen)
     67- BUG FIX: Include the ActivateUtilitiesPlugin class path and clean up paths to scan/include (Thomas Sjolshagen)
     68- BUG FIX: PHPStan test execution settings (Thomas Sjolshagen)
     69- BUG FIX: Didn't autoload classes we expected to load (Thomas Sjolshagen)
     70- BUG FIX: PHPStan test command updated, making sure the inc/wp_plugins dir exists, and more info for some of the testing tagets (Thomas Sjolshagen)
     71- BUG FIX: php-composer target didn't work and phpstan memory limit set to 'unlimited' (Thomas Sjølshagen)
     72- BUG FIX: Renamed deps to wp-deps (Thomas Sjolshagen)
     73- BUG FIX: per_partial is an integer and not a float (Thomas Sjolshagen)
     74- BUG FIX: PHPStan test doesn't need a docker container to run (Thomas Sjolshagen)
     75- BUG FIX: PHPStan errors we don't care about (PMPro functions / class members, etc) (Thomas Sjolshagen)
     76- BUG FIX: PHPStan errors we don't care about (Thomas Sjolshagen)
     77- BUG FIX: PHPDoc string was incorrect (Thomas Sjolshagen)
     78- BUG FIX: Fatal error because we attempted to use Data::get_instance() plus PHPCS nits (Thomas Sjolshagen)
     79- BUG FIX: PHPStan complained about require_once call for Utility loader (Thomas Sjolshagen)
     80- BUG FIX: Make config more dynamic for testing (Thomas Sjolshagen)
     81- BUG FIX: Fix config for PHPStan testing (Thomas Sjolshagen)
     82- BUG FIX: Updates in support of PHPStan testing (Thomas Sjolshagen)
     83- BUG FIX: User Validation class was only partially implemented (Thomas Sjolshagen)
     84- BUG FIX: Wrong file name for plugin file (Thomas Sjolshagen)
     85- BUG FIX: Re-inverted the DOWNLOAD logic (Thomas Sjolshagen)
     86- BUG FIX: Use the get_plugin_version.sh script (Thomas Sjolshagen)
     87- BUG FIX: Made the wrong assumption about the location of the Version string (Thomas Sjolshagen)
     88- BUG FIX: Clean up build vs download for E20R plugins (Thomas Sjolshagen)
     89- BUG FIX: Refactored utility module build process (Thomas Sjolshagen)
     90- BUG FIX: Refactored build target (Thomas Sjolshagen)
     91- BUG FIX: More errors when determining local presence for Utilities (Thomas Sjolshagen)
     92- BUG FIX: Annoying errors in the Makefile (including -z vs -n issues) (Thomas Sjolshagen)
     93- BUG FIX: Build target updates to be .php file change triggered (Thomas Sjolshagen)
     94- BUG FIX: Wrong build target for custom E20R modules (Thomas Sjolshagen)
     95- BUG FIX: Utilities module dependency build fixes (Thomas Sjolshagen)
     96- BUG FIX: Didn't handle when Utilities module is in local git repo (Thomas Sjolshagen)
     97
     98## v3.0.5 - 2021-07-05
     99- BUG FIX: Reformatted README.md (Thomas Sjolshagen)
     100- BUG FIX: Duplicate entries in CHANGELOG.md (Thomas Sjolshagen)
     101- BUG FIX: Using template for metadata.json (Thomas Sjolshagen)
     102- BUG FIX: Build script for readme files updated (Thomas Sjolshagen)
     103- BUG FIX: Typo and formatting updates (Thomas Sjolshagen)
     104- BUG FIX: Don't clean up E20R custom plugins unless in one of the clean-up targets (Thomas Sjolshagen)
     105- BUG FIX: Unit tests do not require WordPress (Thomas Sjolshagen)
     106- BUG FIX: Wrong path for database container volume (Thomas Sjolshagen)
     107- BUG FIX: Typo in comments (Thomas Sjolshagen)
     108- BUG FIX: Old file name for plugin activation of 00-e20r-utilities (Thomas Sjolshagen)
     109- BUG FIX: Missing class definition for assertEquals() call in class-csv-UnitTest.php and class-import-members-UnitTest.php (Thomas Sjolshagen)
     110- BUG FIX: Errors when building the 00-e20r-utilities plugin as a dependency and add clean-up target (Thomas Sjolshagen)
     111- BUG FIX: Simplify config of make/build scripts (Thomas Sjolshagen)
     112- BUG FIX: Potentially inconsistent port use in test environment (Thomas Sjolshagen)
     113- BUG FIX: Initial commit - extracts version info for plugin (Thomas Sjolshagen)
     114- BUG FIX: Shift to PHPUnit 8.x (from 9.x) (Thomas Sjolshagen)
     115- BUG FIX: Use local repo to build 00-e20r-utilities plugin when possible (Thomas Sjolshagen)
     116- BUG FIX: Fixed the WP Unit test suite config for Codeception testing (Thomas Sjolshagen)
     117- BUG FIX: Pasted the wrong path to the Docker key file (Thomas Sjolshagen)
     118- BUG FIX: Be explicit about priorities and args when loading filter/action hooks (Thomas Sjolshagen)
     119- BUG FIX: Setting to handle WP's multi-site testing (Thomas Sjolshagen)
     120- BUG FIX: Use configurable vendor directory for composer (Thomas Sjolshagen)
     121- BUG FIX: Didn't account for the different possibilities for the Utilities/Licensing module (Thomas Sjolshagen)
     122- BUG FIX: A bit too aggressive when clearing inc/ directory (Thomas Sjolshagen)
     123- BUG FIX: Use custom gitignore file for inc/ directory (Thomas Sjolshagen)
     124- BUG FIX: Change log script fixed to avoid duplicate entries, blank line errors, etc (Thomas Sjolshagen)
     125- BUG FIX: Fixed the messed up autoloader and coding standard errors (Thomas Sjolshagen)
     126- BUG FIX: Removed unneeded variables in Makefile (Thomas Sjolshagen)
     127- BUG FIX: Refactored Makefile to be a bit more generic (Thomas Sjolshagen)
     128- BUG FIX: Update data file location for manual testing (Thomas Sjolshagen)
     129- BUG FIX: Renamed ActivateUtilitiesPlugin.php to fix coding standards errors (Thomas Sjolshagen)
     130- BUG FIX: Fix Coding Standard errors in class.pmpro-import-members.php (Thomas Sjolshagen)
     131- BUG FIX: Fix Coding Standard errors in class-validate.php (Thomas Sjolshagen)
     132- BUG FIX: Fix Coding Standard errors in class-date-format.php (Thomas Sjolshagen)
     133- BUG FIX: Fix Coding Standard problems (Thomas Sjolshagen)
     134- BUG FIX: Handle exporting the plugin as a git archive (Thomas Sjolshagen)
     135- BUG FIX: Calculated the wrong timeout value for the JS based background import (Thomas Sjolshagen)
     136- BUG FIX: Updated copyright notice (Thomas Sjolshagen)
     137- BUG FIX: PHPCS was a bit too inclusive (Thomas Sjolshagen)
     138- BUG FIX: Include the README.md file (Thomas Sjolshagen)
     139- BUG FIX: Relocate build status badge (Thomas Sjolshagen)
     140- BUG FIX: Splitting log/doc/updater json generation further (Thomas Sjolshagen)
     141- BUG FIX: Updated CHANGELOG (v3.0.5 for WP 5.7.2) (Thomas Sjolshagen)
     142- BUG FIX: Error generating documentation (Thomas Sjolshagen)
     143- BUG FIX: Use command for git (Thomas Sjolshagen)
     144- BUG FIX: Updating changelog source (Thomas Sjolshagen)
     145- BUG FIX: Reverted CHANGELOG status (Thomas Sjolshagen)
     146- BUG FIX: Separate CHANGELOG and README file generation (Thomas Sjolshagen)
     147- BUG FIX: Updated version number (v3.0.5) (Thomas Sjolshagen)
     148- BUG FIX: Create README.md from the README.txt file (Thomas Sjolshagen)
     149- BUG FIX: Separate CHANGELOG and README file generation (Thomas Sjolshagen)
     150- BUG FIX: Updated README info (v3.0.5 for WP 5.7.2) (Thomas Sjolshagen)
     151- BUG FIX: Updated version (v3.0.5 for WP 5.7.2) (Thomas Sjolshagen)
     152- BUG FIX: Didn't include a README.md file for the plugin (Thomas Sjolshagen)
     153- BUG FIX: Update repository name (Thomas Sjolshagen)
     154- BUG FIX: Action triggered twice (Thomas Sjolshagen)
     155- Bug fix/remove debug logging (#6) (Thomas Sjølshagen)
     156- BUG FIX: Re-activate the installed_paths setting for phpcs (Thomas Sjolshagen)
    8157
    9158## v3.0.4 - 2021-06-28
     
    151300- BUG FIX: Added action hook documentation (Thomas Sjolshagen)
    152301- BUG FIX: Fix PHPCS warnings (Thomas Sjolshagen)
    153 - BUG FIX: Fix PHPCS warnings (Thomas Sjolshagen)
    154302- BUG FIX: Rename e20r_import_load_licensed_modules action hook (Thomas Sjolshagen)
    155303- BUG FIX: Rename e20r_import_load_licensed_modules action hook and fix PHPCS warnings (Thomas Sjolshagen)
     
    224372- BUG FIX: Refactored docker-compose.override files for manual testing (Thomas Sjolshagen)
    225373- BUG FIX: Adding/Updating *ignore files (Thomas Sjolshagen)
    226 - BUG FIX: Adding/Updating *ignore files (Thomas Sjolshagen)
    227374- BUG FIX: More updates to support WP Unit testing (Thomas Sjolshagen)
    228375- BUG FIX: Various updates to support WordPress 'Unit' testing (Thomas Sjolshagen)
     
    491638* Fixed bugs with static/non-static function calls
    492639* Enhancement: JavaScript based async loading (for large imports)
     640- BUG FIX: Calculated the wrong timeout value for the JS based background import (Thomas Sjolshagen)
     641- BUG FIX: Updated copyright notice (Thomas Sjolshagen)
     642- BUG FIX: PHPCS was a bit too inclusive (Thomas Sjolshagen)
     643- BUG FIX: Include the README.md file (Thomas Sjolshagen)
     644- BUG FIX: Relocate build status badge (Thomas Sjolshagen)
     645- BUG FIX: Splitting log/doc/updater json generation further (Thomas Sjolshagen)
     646- BUG FIX: Updated CHANGELOG (v3.0.5 for WP 5.7.2) (Thomas Sjolshagen)
     647- BUG FIX: Error generating documentation (Thomas Sjolshagen)
     648- BUG FIX: Use command for git (Thomas Sjolshagen)
     649- BUG FIX: Updating changelog source (Thomas Sjolshagen)
     650- BUG FIX: Reverted CHANGELOG status (Thomas Sjolshagen)
     651- BUG FIX: Separate CHANGELOG and README file generation (Thomas Sjolshagen)
     652- BUG FIX: Updated version number (v3.0.5) (Thomas Sjolshagen)
     653- BUG FIX: Create README.md from the README.txt file (Thomas Sjolshagen)
     654- BUG FIX: Separate CHANGELOG and README file generation (Thomas Sjolshagen)
     655- BUG FIX: Updated README info (v3.0.5 for WP 5.7.2) (Thomas Sjolshagen)
     656- BUG FIX: Updated version (v3.0.5 for WP 5.7.2) (Thomas Sjolshagen)
     657- BUG FIX: Didn't include a README.md file for the plugin (Thomas Sjolshagen)
     658- BUG FIX: Update repository name (Thomas Sjolshagen)
     659- BUG FIX: Action triggered twice (Thomas Sjolshagen)
     660- Bug fix/remove debug logging (#6) (Thomas Sjølshagen)
     661- BUG FIX: Re-activate the installed_paths setting for phpcs (Thomas Sjolshagen)
  • pmpro-import-members-from-csv/tags/v3.0.6/README.txt

    r2555218 r2563515  
    44Requires at least: 5.0
    55Tested up to: 5.7.2
    6 Stable tag: 3.0.4
     6Stable tag: 3.0.6
    77License: GPLv2
    88License URI: http://www.gnu.org/licenses/gpl
    99
    10 Import and create user + PMPro member records from a CSV file to your WordPress with Paid Memberships Pro website. Can import the membership information, user meta data, PMPro order data and will link any pre-existing recurring payment records for your payment gateway integration.
     10[![Release to wordpress.org](https://github.com/eighty20results/pmpro-import-members-from-csv/actions/workflows/release-plugin.yml/badge.svg)](https://github.com/eighty20results/pmpro-import-members-from-csv/actions/workflows/release-plugin.yml)
     11
     12Import and create user + PMPro member records from a CSV file on your WordPress with Paid Memberships Pro website.
     13The plugin will import the membership information, user meta data, PMPro order data, Sponsored Members information and
     14can even link pre-existing recurring payment records for your payment gateway integration.
    1115
    1216== Description ==
    1317
    14 ![Release to wordpress.org](https://github.com/eighty20results/pmpro-import-members-from-csv/workflows/Release%20to%20wordpress.org/badge.svg?branch=main)
    15 
    16 This plugin is designed to give you an error free import of a user/member to a WordPress/Paid Memberships Pro site. It supports both adding and changing user data.
    17 
    18 Unlike the "Import User From CSV Integration" add-on by Paid Memberships Pro, this "Import Members from CSV" plugin will verify the data you are trying to import during the import operation. This is done to reduce the probability of problem after the import. If there are any errors/issues,information about the problem will be logged to the pmp_updates.log saved in the `wp-content/uploads/` directory.
    19 
    20 *NOTE*: You can run the import multiple times with the same/slightly modified import .csv file and the appropriate settings (see the FAQ/description below). If you configure the plugin settings correctly, this will only result in overwriting/changing the existing member data.
    21 
    22 Using a CSV (Comma Separated Values) file, the will add users with basic user information as well as user meta data fields, the user role (if applicable) and the specified Paid Memberships Pro member configuration/information. It can also generate an order record to ensure your recurring subscriptions continue to get attributed to the imported member.
    23 
    24 If you've exported the user's passwords as hashed strings, you can import them without re-encrypting them again (by setting the option).
     18We designed this plugin to give you an error free import of a user/member to a WordPress/Paid Memberships Pro site.
     19It supports both adding and changing user data.
     20
     21Unlike the "Import User From CSV Integration" add-on by Paid Memberships Pro, this "Import Members from CSV" plugin
     22will verify the data you are trying to import during the import operation. This is done to reduce the probability of
     23problem after the import. If there are any errors/issues, information about the problem will be logged to the
     24`e20r_im_errors.log` saved in the `wp-content/uploads/` directory.
     25
     26**NOTE**: You can run the import multiple times with the same/slightly modified import .csv file and the appropriate
     27settings (see the FAQ/description below). If you configure the plugin settings correctly, this will only result in
     28overwriting/changing the existing member data.
     29
     30Using a CSV (Comma Separated Values) file, the will add users with basic user information as well as user meta data
     31fields, the user role (if applicable) and the specified Paid Memberships Pro member configuration/information. It can
     32also generate an order record to ensure your recurring subscriptions continue to get attributed to the imported member.
     33
     34If you've exported the user's passwords as hashed strings, you can import them without re-encrypting them again
     35(by setting the option).
    2536
    2637You can also choose to send a notification to the new users and to display password nag on user login.
    2738
    28 This plugin supports Network Activation on a WordPress Multisite (WPMU) installation (see the settings page when using in a multisite configuration)
     39This plugin supports Network Activation on a WordPress Multisite (WPMU) installation (see the settings page when
     40using in a multisite configuration)
     41
    2942[Check out my other plugins.](http://eighty20results.com/wordpress-plugins/)
    3043
     
    4356* Import hashed password for new/updating users (if the option is selected)
    4457
    45 *NOTE*: The plugin may not import some of data if it detects a problem. To find out what the problem was, read this documentation and the FAQ section to ensure you have correctly formatted _all_ of your import data.
    46 
    47 For feature request and bug reports, [please use the issues section on GitHub](https://github.com/eighty20results/import-members-from-csv/issues).
    48 Code contributions are welcome [on Github](https://github.com/eighty20results/import-members-from-csv).
    49 
    50 NOTE: In order to hide the "Donation" button after a donation, this plugin will attempt to track the admin's IP address. This action may have GDPR implications for you or your administrators.
    51 
    52 The tracking information is stored in the WordPress options table (wp_options) using the `e20r_import_has_donated` option name and can safely be deleted in the database if you do not wish to leave it. Deleting the option from the database will obviously re-enable the Donation nag.
     58**NOTE**: The plugin may not import some of data if it detects a problem. To find out what the problem was, read this
     59documentation and the FAQ section to ensure you have correctly formatted _all_ of your import data.
     60
     61For feature request and bug reports, [please use the issues section on GitHub](https://github.com/eighty20results/pmpro-import-members-from-csv/issues).
     62Code contributions are welcome [on Github](https://github.com/eighty20results/pmpro-import-members-from-csv).
     63
     64**NOTE**: In order to hide the "Donation" button after a donation, this plugin will attempt to track the admin's IP
     65address. This action may have GDPR implications for you or your administrators.
     66
     67The tracking information is stored in the WordPress options table (wp_options) using the `e20r_import_has_donated`
     68option name and can safely be deleted in the database if you do not wish to leave it. Deleting the option from the
     69database will obviously re-enable the Donation nag.
    5370
    5471The Nag tracking can be disabled altogether with the `e20r_import_donation_tracking_disabled` filter:
     
    6885Or use a nifty tool by WordPress lead developer Mark Jaquith:
    6986
    70 1. Visit [this link](http://coveredwebservices.com/wp-plugin-install/?plugin=pmpro-import-members-from-csv) and follow the instructions.
     871. Visit [this link](http://coveredwebservices.com/wp-plugin-install/?plugin=pmpro-import-members-from-csv) and
     88follow the instructions.
    7189
    7290
     
    831011. Upload your CSV file in the 'Memberships' menu, under 'Import Members'
    84102
    85 == Frequently Asked Questions ==
    86 
    87 = How to use? =
     103= Frequently Asked Questions =
     104
     105== How to use? ==
    88106
    89107Click on the 'Import Members' link in the 'Membership' menu, then select your CSV file.
    90108Next you have to decide whether you:
    91109
    92 1. want to deactivate previously existing member record(s) for the user - The CSV record has to specify the same membership as the user previously had so this is most useful when having to reimport/update data (default: enabled and recommended),
    93 1. update the existing user/member's information (default: enabled and recommended)
    94 1. send a notification email to new users (default: disabled),
    95 1. want the password nag to be displayed when the user logs in (default: disabled),
    96 1. have included a hashed (encoded) password specified in the import file and (default: disabled)
    97 1. want to use the background import option (default: enabled and recommended)
    98 1. create a PMPro order record based on supplied payment info in the .csv file (default: disabled)
     1101. want to deactivate previously existing member record(s) for the user - The CSV record has to specify the same
     111membership as the user previously had so this is most useful when having to reimport/update data (default: enabled and
     112recommended),
     1132. update the existing user/member's information (default: enabled and recommended)
     1143. send a notification email to new users (default: disabled),
     1154. want the password nag to be displayed when the user logs in (default: disabled),
     1165. have included a hashed (encoded) password specified in the import file and (default: disabled)
     1176. want to use the background import option (default: enabled and recommended)
     1187. create a PMPro order record based on supplied payment info in the .csv file (default: disabled)
    99119
    100120Then click the 'Import' button.
    101121
    102122Each row in your CSV file should represent a user; each column identifies user data, user meta data or user membership data
    103 If a column name matches a field in the user table, data from this column is imported in that field; if not, data is imported in a user meta field with the name of the column or into the PMPro custom membership tables.
    104 
    105 Look at the examples/import.csv file in the plugin directory (also linked on the "Import Members" page) to have a better understanding of how the your CSV file should be organized and what the data fields need to contain as far as formatting/values go.
    106 
    107 You can always try importing the examples/import.csv file and look at the result, assuming the values specified for the membership_id in the example file match your membership level configuration.
    108 
    109 = The .CSV file from the "Export to CSV" button on the "Members List" page won't import? =
    110 
    111 The purpose of the resulting .CSV file from the "Export to CSV" is to generate reports that are meaningful to a human, not a file that can be imported easily. This is true for any of the available Import from .CSV plugins/add-ons for Paid Memberships Pro.
    112 
    113 Basically there are a few key differences between the file resulting from the Export function and the file contents needed to import the same member.
     123If a column name matches a field in the user table, data from this column is imported in that field; if not, data is
     124imported in a user meta field with the name of the column or into the PMPro custom membership tables.
     125
     126Look at the examples/import.csv file in the plugin directory (also linked on the "Import Members" page) to have a
     127better understanding of how the your CSV file should be organized and what the data fields need to contain as far as
     128formatting/values go.
     129
     130You can always try importing the examples/import.csv file and look at the result, assuming the values specified for the
     131membership_id in the example file match your membership level configuration.
     132
     133== The .CSV file from the "Export to CSV" button on the "Members List" page won't import? ==
     134
     135The purpose of the resulting .CSV file from the "Export to CSV" is to generate reports that are meaningful to a human,
     136not a file that can be imported easily. This is true for any of the available Import from .CSV plugins/add-ons for
     137Paid Memberships Pro.
     138
     139Basically there are a few key differences between the file resulting from the Export function and the file contents
     140needed to import the same member.
    114141
    115142As of version 2.5, this plugin includes data checks for some of the more common mistakes I've seen in the .CSV file(s).
     
    117144You should also check out the import example file that is linked on the "Import Members" page (under the "Choose File" button).
    118145
    119 = My import fails, what is wrong? =
    120 
    121 This is almost always related to the data in the file being imported. As a result, I've added some data tests for some of the typical mistakes I've seen in the .CSV file(s) being imported. There is also a link to an example file on the "Import Members" page (under the "Choose File" button) that illustrates a functional import file. Things lik what the field names are and the format you'll most likely need to use for the data in that column.
    122 
    123 Check the wp-content/uploads/pmp_im_errors.log log file for details on the import operations (link should also be included in a wp-admin dashboard notice if there are errors/warnings). The log should contain suggestions on some of the more common mistakes in the data being imported.
    124 
    125 = Do I need to include all the columns from the sample file? =
    126 
    127 No. _Only_ include the columns where you have data to import. I.e, if none of your members need to have their membership end date defined (i.e the membership you're importing doesn't have an expiration or it's a recurring membership with a linked Payment Gateway subscription plan), just remove the column(s) you don't need. That way, the plugin doesn't try to import data that isn't there.
     146== My import fails, what is wrong? ==
     147
     148This is almost always related to the data in the file being imported. As a result, I've added some data tests for some
     149of the typical mistakes I've seen in the .CSV file(s) being imported. There is also a link to an example file on the
     150"Import Members" page (under the "Choose File" button) that illustrates a functional import file. Things lik what the
     151field names are and the format you'll most likely need to use for the data in that column.
     152
     153Check the wp-content/uploads/pmp_im_errors.log log file for details on the import operations (link should also be
     154included in a wp-admin dashboard notice if there are errors/warnings). The log should contain suggestions on some of
     155the more common mistakes in the data being imported.
     156
     157== Do I need to include all the columns from the sample file? ==
     158
     159No. __Only__ include the columns where you have data to import. I.e, if none of your members need to have their
     160membership end date defined (i.e the membership you're importing doesn't have an expiration or it's a recurring
     161membership with a linked Payment Gateway subscription plan), just remove the column(s) you don't need. That way,
     162the plugin doesn't try to import data that isn't there.
    128163
    129164If a column has no data, you should remove the column and it's column header from the import file!
    130165
    131 = The plugin didn't import any membership data!?! =
    132 
    133 This is a pretty common question and the reason is almost always because there is something unexpected in the `membership_` portion of the row being imported.
    134 
    135 Most often it's the date/time format for the membership_startdate and membership_enddate columns.
     166== The plugin didn't import any membership data!?! ==
     167
     168This is a pretty common question and the reason is almost always because there is something unexpected in the
     169`membership_` portion of the row being imported.
     170
     171Most often it's the date/time format for the `membership_startdate` and `membership_enddate` columns.
    136172
    137173If you use MS Excel(tm) to prepare your .CSV file, you're in for a treat...
    138174
    139 In my experience, MS Excel(tm) is _really_ good at changing the date format in a spreadsheet column to whatever it thinks works best (i.e. human readable).
    140 
    141 However, human readable is often problematic for CSV imports, so you *have to ensure* the format follows the YYYY-MM-DD HH:ii:ss (where ii = 2 digit minute value). For startdate I'd recommend using `00:00:00` and for the enddate I'd suggest using `23:59:59`.
    142 
    143 Just to be clear: The _only_ date format for the *membership_startdate*, *membership_enddate* and the *user_registered* columns that this plugin will accept is the MySQL datetime format: YYYY-MM-DD HH:ii:ss.
     175In my experience, MS Excel(tm) is _really_ good at changing the date format in a spreadsheet column to whatever it
     176thinks works best (i.e. human readable). (If my sarcasm doesn't shine through; This actually __isn't__ a good thing!)
     177
     178However, human readable is often problematic for CSV imports, so you **have to make sure** the date format follows the
     179`YYYY-MM-DD HH:ii:ss` template (where ii = 2 digit minute value). For startdate I'd recommend using `00:00:00` and
     180for the enddate I'd suggest using `23:59:59`.
     181
     182Just to be clear: The __only__ date format for the `membership_startdate`, `membership_enddate` and the
     183`user_registered` columns that this plugin will accept is the MySQL datetime format: YYYY-MM-DD HH:ii:ss.
    144184
    145185*Use anything else and your membership data will not be imported*!
    146186
    147 You can change the way Microsoft Excel(tm) handles date and time data in the Regional settings, but I've yet to figure out what the ideal settings are here. Truth be told, I'm using Apple Numbers and others have had great success using Google Sheets to process and export their .CSV files. Because there are alternatives to Microsoft Excel(tm) and they seem to work a lot better for this specific task, I'm not at all inclined to spend more time on fixing something that I view to be a rather significant "bug"[1] in Excel(tm).
    148 
    149  [1] = Being that it's an intentional usability feature, I realize Microsoft is unlikely to be all that interested in fixing this "as designed" capability they've implemented.
    150 = Can this plugin be used to link sponsored members with their sponsors? =
     187You can change the way Microsoft Excel(tm) handles date and time data in the Regional settings, but I've yet to
     188figure out what the ideal settings are here. Truth be told, I'm using Apple Numbers and others have had great
     189success using Google Sheets to process and export their .CSV files. Because there are alternatives to Microsoft
     190Excel(tm) and they seem to work a lot better for this specific task, I'm not at all inclined to spend more time
     191on fixing something that I view to be a rather significant "bug"[1] in Excel(tm).
     192
     193 [1] = Being that it's an intentional usability feature, I realize Microsoft is unlikely to be all that interested
     194 in fixing this "as designed" capability they've implemented.
     195
     196== Can this plugin be used to link sponsored members with their sponsors? ==
    151197
    152198Yes.
    153199
    154 In version 2.60, we added support for importing Sponsors and their sponsored members. So, if you have the PMPro Sponsored Members add-on installed, active and need to link sponsors and their sponsored members during the import with this plugin.
     200In version 2.60, we added support for importing Sponsors and their sponsored members. So, if you have the
     201PMPro Sponsored Members add-on installed, active and need to link sponsors and their sponsored members
     202during the import with this plugin.
    155203
    156204== Importing the Sponsored user ==
     
    158206To link sponsored users with their sponsors, add the `pmprosm_sponsor` column to your import file.
    159207
    160 On the data row for the _sponsored_ user, the pmprosm_sponsor column must contain the user key for the sponsor you want to link them with.
     208On the data row for the __sponsored__ user, the `pmprosm_sponsor` column must contain the user key for the sponsor
     209you want to link them with.
    161210
    162211Or, if they don't have a sponsor, that column must be blank.
    163212
    164 The sponsor key is either the email address they used when registering on your system - or the user_email column value for their user record if they're also being imported at the same time, the WordPress user ID value (numeric), or the login name used (user_login value).
     213The sponsor key is either the email address they used when registering on your system - or the user_email column
     214value for their user record if they're also being imported at the same time, the WordPress user ID value (numeric),
     215or the login name used (user_login value).
    165216
    166217== Importing the Sponsor ==
    167218
    168 First of all, you will need to include a `pmprosm_seats` column as well. This column contains a numeric value to indicate the number of seats (sponsored users) this user has paid to sponsor.
     219First of all, you will need to include a `pmprosm_seats` column as well. This column contains a numeric value to
     220indicate the number of seats (sponsored users) this user has paid to sponsor.
    169221
    170222When importing a sponsor there are a couple of scenarios;
    171223
    172 1) The system already contains the sponsor code (a sponsor code is a PMPro discount code prefixed with the letter 'S') and you simply need to link the sponsor to their code.
     2241) The system already contains the sponsor code (a sponsor code is a PMPro discount code prefixed with the letter 'S')
     225and you simply need to link the sponsor to their code.
    173226
    1742272) The system lacks the sponsor code, so you'll need one to be created.
    175228
    176 For scenario 1; The sponsor code (discount code) already has a Discount Code ID (integer value, found on the PMPro "Discount Codes" settings page). This ID needs to be added in the `membership_code_id` column of the import file for the sponsor (user record), along with a numeric value in the `pmprosm_seats` column.
    177 
    178 For scenario 2; The sponsor code is created by this plugin. It happens automatically if the sponsor user exists - or is being imported at the same time as - when the *sponsored* user is attempted imported and linked. The discount code created attempts to use the settings from the PMPro Sponsored Members add-on for the discount code.
     229For scenario 1; The sponsor code (discount code) already has a Discount Code ID (integer value, found on the PMPro
     230"Discount Codes" settings page). This ID needs to be added in the `membership_code_id` column of the import file for
     231the sponsor (user record), along with a numeric value in the `pmprosm_seats` column.
     232
     233For scenario 2; The sponsor code is created by this plugin. It happens automatically if the sponsor user exists - or
     234is being imported at the same time as - when the **sponsored** user is attempted imported and linked. The discount
     235code created attempts to use the settings from the PMPro Sponsored Members add-on for the discount code.
    179236
    180237=== Caveat ===
     
    182239The order in which users are listed in the .csv import file can matter when importing sponsors and their sponsored user.
    183240
    184 Although this plugin tries to re-import sponsored users if the import fails the first time, as part of the clean-up process, this retry does not guarantee success!
     241Although this plugin tries to re-import sponsored users if the import fails the first time, as part of the
     242clean-up process, this retry does not guarantee success!
    185243
    186244As a result, it is possible that a sponsored user is imported without being linked to their sponsor.
     
    198256As of version 2.20, we have an option to create member orders at the same time as we update the membership record.
    199257
    200 That means you can now include some of the order table fields to import custom values as needed for each user/member, along with updating/adding their membership level information.
     258That means you can now include some of the order table fields to import custom values as needed for each
     259user/member, along with updating/adding their membership level information.
    201260
    202261The supported order record columns are:
     
    2312901. billing_phone (*)
    232291
    233 All of these columns/fields should be prefixed with 'membership_'. I.e. 'membership_paypal_token' or 'membership_tax', etc. The exceptions are the 'user_id' and 'membership_id' columns/fields which should be left as 'user_id' and 'membership_id' respectively if you want to include them in the import operation(s).
    234 
    235 The 'status' column has a limited number of valid values. By default, we recommend using either 'success' or 'cancelled'
    236 
    237 All timestamp values ('timestamp') must use the same format as the one used by the MySQL database's 'DATETIME' format: `YYYY-MM-DD HH:MM:SS`
    238 
    239 *PLEASE NOTE:*
    240 
    241 Although you _can_ specify an account number (accountnumber) in the import file, doing that will *not* result in this plugin importing and activating subscriptions or payments by credit card.
    242 
    243 You CANNOT use this tool to import and *create* subscription plans, or transactions, on the payment gateway for your Paid Memberships Pro users.
    244 
    245 Including anything other than a masked Credit Card number for the "membership_accountnumber" column *is a really bad idea*[1]!
    246 
    247 A masked credit card number = Only the last 4 digits are real and the rest are repetitions of the 'X' character (XXXXXXXXXXXX1234).
    248 
    249 [1] = Importing a full credit card number will exponentially increase the probability that you, in the event of a security problem on your site, will have to pay the Payment Card Industry (PCI) massive fines. Simply put; Don't import Credit Card information! Instead, ask your members to resubmit their information when the site is back online/live.
    250 
    251 *This plugin does NOT mask your credit card numbers for you!*
    252 
    253 = Supported membership_gateway options =
    254 
    255 The Import Members from CSV plugin supports specifying different payment gateways for the user record(s) when importing order data (i.e. the "Attempt to create PMPro Order record" option has been selected). At present, the payment gateways that can be specified in the `membership_gateway` column are:
     292All of these columns/fields should be prefixed with `membership_`. I.e. `membership_paypal_token` or `membership_tax`,
     293etc. The exceptions are the `user_id` and `membership_id` columns/fields which should be left as `user_id` and
     294`membership_id` respectively if you want to include them in the import operation(s).
     295
     296The `status` column has a limited number of valid values. By default, we recommend using either `success` or `cancelled`
     297
     298All timestamp values ('timestamp') must use the same format as the one used by the MySQL database's 'DATETIME'
     299format: `YYYY-MM-DD HH:MM:SS`
     300
     301**PLEASE NOTE:**
     302
     303Although you _can_ specify an account number (`accountnumber`) in the import file, doing that will *not* result in
     304this plugin importing and activating subscriptions or payments by credit card.
     305
     306You CANNOT use this tool to import and **create** subscription plans, or transactions, on the payment gateway for
     307your Paid Memberships Pro users.
     308
     309Including anything other than a masked Credit Card number for the `membership_accountnumber` column *is a really
     310bad idea*[1]!
     311
     312A masked credit card number = Only the last 4 digits are real and the rest are repetitions of the 'X'
     313character (`XXXXXXXXXXXX1234`).
     314
     315[1] = Importing a full credit card number will exponentially increase the probability that you, in the event of a
     316security problem on your site, will have to pay the Payment Card Industry (PCI) massive fines. Simply put; Don't import
     317Credit Card information! Instead, ask your members to resubmit their information when the site is back online/live.
     318
     319**This plugin does NOT mask your credit card numbers for you!**
     320
     321== Supported membership_gateway options ==
     322
     323The Import Members from CSV plugin supports specifying different payment gateways for the user record(s) when
     324importing order data (i.e. the "Attempt to create PMPro Order record" option has been selected). At present, the
     325payment gateways that can be specified in the `membership_gateway` column are:
    256326
    2573271. authorizenet
    258 1. braintree
    259 1. check
    260 1. cybersource
    261 1. payflowpro
    262 1. paypal
    263 1. paypalexpress
    264 1. paypalstandard
    265 1. stripe
    266 1. twocheckout
    267 
    268 During the import operation, the plugin will verify that the specified payment gateway integration is one of the supported payment gateway integrations for Paid Memberships Pro.
    269 
    270 Specifying a Payment Gateway Integration that has not been configured for use during the PMPro checkout process would render the order record invalid.
    271 
    272 NOTE: The limitations to how Paid Memberships Pro supports/handles multiple payment gateway integrations at the same time still apply.
    273 
    274 = Adding billing address information to the PMPro Order import =
    275 
    276 The normal way to import billing address data to the database for a member/user is to use the `pmpro_b[*]` fields (pmpro_bfirstname, pmpro_blastname, pmpro_baddress1, pmpro_baddress2, pmpro_bcity, pmpro_bstate, pmpro_bzipcode, pmpro_bcountry and pmpro_bphone).
    277 
    278 If the pmpro_b* field data is present in the row and the 'Add order' option is selected for the import file, the import will attempt to populate the order billing information using the pmpro_b* data.
     3282. braintree
     3293. check
     3304. cybersource
     3315. payflowpro
     3326. paypal
     3337. paypalexpress
     3348. paypalstandard
     3359. stripe
     33610. twocheckout
     33711. payfast
     338
     339During the import operation, the plugin will verify that the specified payment gateway integration is one of the
     340supported payment gateway integrations for Paid Memberships Pro.
     341
     342Specifying a Payment Gateway Integration that has not been configured for use during the PMPro checkout process would
     343render the order record invalid.
     344
     345**NOTE:** The limitations to how Paid Memberships Pro supports/handles multiple payment gateway integrations at the
     346same time still apply.
     347
     348== Adding billing address information to the PMPro Order import ==
     349
     350The normal way to import billing address data to the database for a member/user is to use the `pmpro_b[*]` fields
     351(`pmpro_bfirstname`, `pmpro_blastname`, `pmpro_baddress1`, `pmpro_baddress2`, `pmpro_bcity`, `pmpro_bstate`,
     352`pmpro_bzipcode`, `pmpro_bcountry` and `pmpro_bphone`).
     353
     354If the `pmpro_b*` field data is present in the row and the 'Add order' option is selected for the import file, the
     355import will attempt to populate the order billing information using the `pmpro_b*` data.
    279356
    280357= How should the .csv file be defined? =
     
    287364
    288365For example;
    289 To have a 2 column .csv file, each row **after** the header row, the row should look something like this: `"my first column data","my second \"escaped\" column data"`.
    290 
    291 The application you use to edit and export your .CSV file will need to be configured appropriately before you export the .csv file.
     366To have a 2 column .csv file, each row **after** the header row, the row should look something like this:
     367`"my first column data","my second \"escaped\" column data"`.
     368
     369The application you use to edit and export your .CSV file will need to be configured appropriately before you
     370export the .csv file.
    292371
    293372= Why am I or my users not receiving New user notifications =
    294373
    295 There are a couple of possible reasons, as far as I can tell. The functionality in WordPress that generates the "new user notification" message is what they call "pluggable". That means that it's possible for a plugin (any plugin!) to override the behavior of the functionality. So the first thing I'd suggest investigating is whether you have a pluing active that intentionally changes/modifies/updates how the `wp_new_user_notification()` function works/behaves.
    296 
    297 Next, it's (very) possible that your hosting environment doesn't want you to be sending out a lot of email messages from their servers. As a result, the import operation could potentially trip their anti-spam measures and blocking you from sending any messages.
    298 
    299 Third, the recipient email server may be using a SBL (Spam Black List) and have your web server IP listed as a typical source of Spam messages (it happens, a lot).
    300 
    301 = I've set the 'membership_status' column to 'inactive', but the user's imported membership level is currently 'active'? =
     374There are a couple of possible reasons, as far as I can tell. The functionality in WordPress that generates the
     375"new user notification" message is what they call "pluggable". That means that it's possible for a plugin (any plugin!)
     376to override the behavior of the functionality. So the first thing I'd suggest investigating is whether you have a
     377plugin active that intentionally changes/modifies/updates how the `wp_new_user_notification()` function works/behaves.
     378
     379Next, it's (very) possible that your hosting environment doesn't want you to be sending out a lot of email messages
     380from their servers. As a result, the import operation could potentially trip their anti-spam measures and blocking
     381you from sending any messages.
     382
     383Third, the recipient email server may be using a SBL (Spam Black List) and have your web server IP listed as a
     384typical source of Spam messages (it happens, a lot).
     385
     386== I've set the 'membership_status' column to 'inactive', but the user's imported membership level is currently 'active'? ==
    302387
    303388This is due to what I'd term a bug in Paid Memberships Pro. This issue doesn't currently have a fix.
    304389
    305 Basically, the 'inactive' status will only apply to the order record (if it's created, see above) and *not* to the user's membership status.
    306 
    307 NOTE: Assigning a membership level for a user will cause them to be given an active membership on the site when the import operation is complete, regardless of the value supplied for the 'membership_status' column.
    308 
    309 = How do I import an existing payment plan (recurring billing plan) for a user? =
     390Basically, the 'inactive' status will only apply to the order record (if it's created, see above) and *not* to the
     391user's membership status.
     392
     393**NOTE:** Assigning a membership level for a user will cause them to be given an active membership on the site when
     394the import operation is complete, regardless of the value supplied for the 'membership_status' column.
     395
     396== How do I import an existing payment plan (recurring billing plan) for a user? ==
    310397
    311398This only works if the plan already exists on the payment gateway itself.
    312399
    313 There is no way to use this plugin to import a new member/user and have the system create a recurring billing plan for them.
    314 
    315 = Can I use this plugin to create new billing plans or trigger charges on the payment gateway for an imported user? =
     400There is no way to use this plugin to import a new member/user and have the system create a recurring billing plan
     401for them.
     402
     403== Can I use this plugin to create new billing plans or trigger charges on the payment gateway for an imported user? ==
    316404
    317405No.
    318406
    319 = What are the constraints for WordPress Multisite import operations? =
     407== What are the constraints for WordPress Multisite import operations? ==
    320408
    321409As documented by Paid Memberships Pro, the PMPro plugin cannot be Network Activated.
    322410
    323 This import plugin will work from the site(s) where PMPro is active _and_ have the same membership level IDs identified as are listed in the `membership_id` column of the import file you're using.
    324 
    325 If your primary site has a configured and active Paid Memberships Pro installation, you could theoretically start the plugin from the Network Admin dashboard (which will send you to the primary site anyway).
    326 
    327 The users being imported will only be linked to the site you import them to. Their membership data will only be visible on the PMPro site(s) that have the membership level ID(s) configured that match those in the import file.
     411This import plugin will work from the site(s) where PMPro is active _and_ have the same membership level IDs
     412identified as are listed in the `membership_id` column of the import file you're using.
     413
     414If your primary site has a configured and active Paid Memberships Pro installation, you could theoretically start
     415the plugin from the Network Admin dashboard (which will send you to the primary site anyway).
     416
     417The users being imported will only be linked to the site you import them to. Their membership data will only be
     418visible on the PMPro site(s) that have the membership level ID(s) configured that match those in the import file.
    328419
    329420= Welcome Email Message (imported_welcome.html template) issues =
     
    332423please make sure the 'membership_status' field is included in the import .csv file and contains the `active` value.
    333424
    334 As a design philosophy, we treat an inactive member as somebody who should _not_  receive welcome messages (you may disagree..?)
    335 
    336 = What GDPR impacted data is stored by this plugin? =
    337 
    338 Obviously, there's the user data that this plugin is designed to import. This plugin does _not_ track, report, or allow download/deletion of any data it imports. There are (now or soon) other plugin options to handle those requirements from the GDPR legislation.
    339 
    340 In an attempt to make the "Donation" button less intrusive, we attempt to track the computer (IP) address when somebody clicks the button. This plugin does _not_ link the IP address to a user account, so it should be a little more challenging to identify the person who clicked the "Donate" button for any 3rd party who gets access to your database than simply looking at the options saved by this plugin.
    341 
    342 The IP tracking information (the IP address) is stored in the WordPress options table (`wp_options`) using the `e20r_import_has_donated` option name. That option can safely be deleted in the database if you do not wish to have IPs tracked. Deleting the option from the database will obviously re-enable the Donation nag.
    343 
    344 As long as this plugin remains installed and active on the server, the tracked IP address will automatically be removed from the option 2 months after the admin clicked the Donation button.
     425As a design philosophy, we treat an inactive member as somebody who should _not_  receive welcome messages
     426(you may disagree..?)
     427
     428== What GDPR impacted data is stored by this plugin? ==
     429
     430Obviously, there's the user data that this plugin is designed to import. This plugin does _not_ track, report, or
     431allow download/deletion of any data it imports. There are (now or soon) other plugin options to handle those
     432requirements from the GDPR legislation.
     433
     434In an attempt to make the "Donation" button less intrusive, we attempt to track the computer (IP) address when
     435somebody clicks the button. This plugin does _not_ link the IP address to a user account, so it should be a little
     436more challenging to identify the person who clicked the "Donate" button for any 3rd party who gets access to your
     437database than simply looking at the options saved by this plugin.
     438
     439The IP tracking information (the IP address) is stored in the WordPress options table (`wp_options`) using the
     440`e20r_import_has_donated` option name. That option can safely be deleted in the database if you do not wish to have
     441IPs tracked. Deleting the option from the database will obviously re-enable the Donation nag.
     442
     443As long as this plugin remains installed and active on the server, the tracked IP address will automatically be
     444removed from the option 2 months after the admin clicked the Donation button.
    345445
    346446The option is removed when the plugin is deactivated in the "Plugins" admin panel.
    347447
    348 Nag tracking can be disabled altogether with the `e20r_import_donation_tracking_disabled` filter: `add_filter( 'e20r_import_donation_tracking_disabled', '__return_true' );'`
     448Nag tracking can be disabled altogether with the `e20r_import_donation_tracking_disabled` filter:
     449`add_filter( 'e20r_import_donation_tracking_disabled', '__return_true' );'`
    349450
    350451== Installation ==
    351452
    3524531. Upload the `pmpro-import-members-from-csv` folder to the `/wp-content/plugins/` directory.
    353 1. Activate the plugin through the 'Plugins' menu in WordPress.
     4542. Activate the plugin through the 'Plugins' menu in WordPress.
    354455
    355456== Screenshots ==
    356457
    3574581. User import screen
    358 1. Ongoing (background) import screen
    359 1. Default settings on the user import screen
     4592. Ongoing (background) import screen
     4603. Default settings on the user import screen
    360461
    361462== Known Issues ==
     
    369470== Supported Filters and Actions ==
    370471
    371 The list of filters and actions supported by this plugin can be found in the [Filters](./docs/FILTERS.md) and [Actions](./docs/ACTIONS.md) documentation.
     472The list of filters and actions supported by this plugin can be found in the [Filters](./docs/FILTERS.md) and
     473[Actions](./docs/ACTIONS.md) documentation.
  • pmpro-import-members-from-csv/tags/v3.0.6/class.pmpro-import-members.php

    r2555218 r2563515  
    1 <?php
     1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
    22/**
    33Plugin Name: Import Paid Memberships Pro Members from CSV
    44Plugin URI: http://wordpress.org/plugins/pmpro-import-members-from-csv/
    55Description: Import Users and their metadata from a csv file.
    6 Version: 3.0.4
     6Version: 3.0.6
    77Requires PHP: 7.3
    88Author: <a href="https://eighty20results.com/thomas-sjolshagen/">Thomas Sjolshagen <[email protected]></a>
     
    4242use function plugin_dir_path;
    4343use function add_action;
    44 use function error_log;
     44use function error_log; // phpcs:ignore
    4545
    4646if ( ! defined( 'E20R_IM_CSV_DELIMITER' ) ) {
     
    5555
    5656if ( ! defined( 'E20R_IMPORT_VERSION' ) ) {
    57     define( 'E20R_IMPORT_VERSION', '3.0.4' );
    58 }
    59 
    60 require_once plugin_dir_path( __FILE__ ) . '/ActivateUtilitiesPlugin.php';
     57    define( 'E20R_IMPORT_VERSION', '3.0.6' );
     58}
     59
     60require_once plugin_dir_path( __FILE__ ) . 'class-activateutilitiesplugin.php';
    6161
    6262/**
     
    107107        foreach ( $base_paths as $base_path ) {
    108108
    109             $iterator = new RecursiveDirectoryIterator(
    110                 $base_path,
    111                 RecursiveDirectoryIterator::SKIP_DOTS |
    112                 RecursiveIteratorIterator::SELF_FIRST |
    113                 RecursiveIteratorIterator::CATCH_GET_CHILD |
    114                 RecursiveDirectoryIterator::FOLLOW_SYMLINKS
    115             );
    116 
    117             $filter = new RecursiveCallbackFilterIterator(
    118                 $iterator,
    119                 function ( $current, $key, $iterator ) use ( $filename ) {
    120 
    121                     // Skip hidden files and directories.
    122                     if ( $current->getFilename()[0] === '.' || $current->getFilename() === '..' ) {
    123                         return false;
     109            try {
     110                $iterator = new RecursiveDirectoryIterator(
     111                    $base_path,
     112                    RecursiveDirectoryIterator::SKIP_DOTS |
     113                    RecursiveIteratorIterator::SELF_FIRST |
     114                    RecursiveIteratorIterator::CATCH_GET_CHILD |
     115                    RecursiveDirectoryIterator::FOLLOW_SYMLINKS
     116                );
     117            } catch ( \Exception $e ) {
     118                print 'Error: ' . $e->getMessage(); // phpcs:ignore
     119                return;
     120            }
     121
     122            try {
     123                $filter = new RecursiveCallbackFilterIterator(
     124                    $iterator,
     125                    function ( $current, $key, $iterator ) use ( $filename ) {
     126
     127                        // Skip hidden files and directories.
     128                        if ( '.' === $current->getFilename()[0] || '..' === $current->getFilename() ) {
     129                            return false;
     130                        }
     131
     132                        if ( $current->isDir() ) {
     133                            // Only recurse into intended subdirectories.
     134                            return $current->getFilename() === $filename;
     135                        } else {
     136                            // Only consume files of interest.
     137                            return str_starts_with( $current->getFilename(), $filename );
     138                        }
    124139                    }
    125 
    126                     if ( $current->isDir() ) {
    127                         // Only recurse into intended subdirectories.
    128                         return $current->getFilename() === $filename;
    129                     } else {
    130                         // Only consume files of interest.
    131                         return str_starts_with( $current->getFilename(), $filename );
    132                     }
    133                 }
    134             );
     140                );
     141            } catch ( \Exception $e ) {
     142                echo 'Autoloader error: ' . $e->getMessage(); // phpcs:ignore
     143                return;
     144            }
    135145
    136146            foreach ( new RecursiveIteratorIterator( $iterator ) as $f_filename => $f_file ) {
  • pmpro-import-members-from-csv/tags/v3.0.6/docker-compose.yml

    r2554806 r2563515  
    1919    ports:
    2020      - ${WP_PORT}:80
     21    stdin_open: true # docker run -i
     22    tty: true        # docker run -t
    2123    command:
    2224      - /bin/sh
     
    5759      MYSQL_RANDOM_ROOT_PASSWORD: ${MYSQL_RANDOM_ROOT_PASSWORD}
    5860    volumes:
    59       - ${LOCAL_PLUGIN_DIR}:/docker-entrypoint-initdb.d
     61      - ${LOCAL_PLUGIN_DIR}/tests/_data:/docker-entrypoint-initdb.d
  • pmpro-import-members-from-csv/tags/v3.0.6/javascript/pmpro-import-members-from-csv.js

    r2554806 r2563515  
    11/**
    2  * Copyright (c) 2018-2019 - Eighty / 20 Results by Wicked Strong Chicks.
     2 * Copyright (c) 2018 - 2021 - Eighty / 20 Results by Wicked Strong Chicks.
    33 * ALL RIGHTS RESERVED
    44 *
  • pmpro-import-members-from-csv/tags/v3.0.6/src/class-data.php

    r2554806 r2563515  
    8282        // Add PMPro info as applicable
    8383        if ( ! empty( $user ) ) {
     84            // @phpstan-ignore-next-line
    8485            $user->membership_level = (
    8586            function_exists( 'pmpro_getMembershipLevelForUser' ) ?
     
    8889            );
    8990
     91            // @phpstan-ignore-next-line
    9092            $user->membership_levels = (
    9193            function_exists( 'pmpro_getMembershipLevelsForUser' ) ?
     
    332334
    333335        if ( ! in_array( $billing_field_name, array_keys( $billing_fields ), true ) ) {
    334             return null;
     336            return false;
    335337        }
    336338
  • pmpro-import-members-from-csv/tags/v3.0.6/src/class-email-templates.php

    r2554806 r2563515  
    7676
    7777        // Email 'your membership account is active' to member if they were imported with an active member status
    78         if ( true === (bool) $send_email &&
    79              isset( $fields['membership_status'] ) && 'active' === $fields['membership_status'] &&
    80              1 === version_compare( PMPRO_VERSION, '1.9.5' )
     78        if (
     79            true === (bool) $send_email &&
     80            isset( $fields['membership_status'] ) && 'active' === $fields['membership_status'] &&
     81            // @phpstan-ignore-next-line
     82            1 === version_compare( PMPRO_VERSION, '1.9.5' )
    8183        ) {
    8284            $subject = null;
     
    103105            $this->error_log->debug( "Using {$template_name} template for '{$subject}' message" );
    104106
     107            // PMPro is not good at defining properties in classes (badly reliant on the historically dynamic nature of PHP)
     108            // so will have PHPStan ignore these lines until PMPro cleans up their stuff
     109            // (i.e. TODO when PMPro takes better advantage of PHP)
    105110            $email           = new \PMProEmail();
    106             $email->email    = $user->user_email;
    107             $email->data     = apply_filters( 'pmp_im_imported_member_message_data', array() );
    108             $email->subject  = $subject;
    109             $email->template = $template_name;
     111            $email->email    = $user->user_email; // @phpstan-ignore-line
     112            $email->data     = apply_filters( 'pmp_im_imported_member_message_data', array() ); // @phpstan-ignore-line
     113            $email->subject  = $subject; // @phpstan-ignore-line
     114            $email->template = $template_name; // @phpstan-ignore-line
    110115
    111116            if ( ! empty( $body ) ) {
    112                 $email->body = $body;
     117                $email->body = $body; // @phpstan-ignore-line
    113118            } else {
    114                 $email->body = $this->load_email_body( null, $email->template );
     119                $email->body = $this->load_email_body( null, $email->template ); // @phpstan-ignore-line
    115120            }
    116121
    117122            $email->body = apply_filters( 'pmp_im_imported_member_message_body', $email->body );
     123            $email->body = apply_filters( 'e20r_import_member_message_body', $email->body );
    118124
    119125            // Process and send email
     
    228234            foreach ( $locations as $path ) {
    229235                if ( true === file_exists( $path ) ) {
    230                     $body = file_get_contents( $path );
     236                    $body = file_get_contents( $path ); // phpcs:ignore
    231237                    break;
    232238                }
     
    265271            'subject'     => __( 'Welcome to my new website', 'pmpro-import-members-from-csv' ),
    266272            'description' => __( 'Import: Welcome Member', 'pmpro-import-members-from-csv' ),
     273            // phpcs:ignore
    267274            'body'        => file_get_contents( Import_Members::$plugin_path . '/emails/imported_member.html' ),
    268275        );
  • pmpro-import-members-from-csv/tags/v3.0.6/src/class-error-log.php

    r2554806 r2563515  
    6767                'error'
    6868            );
    69 
     69            return;
    7070        }
    7171
     
    146146     * Identify the calling function (used in debug logger
    147147     *
    148      * @return array|string
     148     * @return string
    149149     *
    150150     * @access public
    151151     */
    152     private function who_called_me() {
     152    private function who_called_me() : string {
    153153        $trace  = debug_backtrace(); // phpcs:ignore
    154154        $caller = $trace[2];
  • pmpro-import-members-from-csv/tags/v3.0.6/src/class-import-members.php

    r2554946 r2563515  
    144144
    145145        if ( false === apply_filters( 'e20r_utilities_module_installed', false ) ) {
    146             add_action( 'init', '\E20R\Import\Loader::is_utilities_module_active', 10 );
    147         }
    148         add_action( 'plugins_loaded', array( Email_Templates::get_instance(), 'load_hooks' ), 99 );
    149         add_action( 'plugins_loaded', array( Ajax::get_instance(), 'load_hooks' ), 99 );
    150         add_action( 'plugins_loaded', array( Page::get_instance(), 'load_hooks' ), 99 );
     146            add_action( 'init', '\E20R\Import\Loader::is_utilities_module_active', 10, 0 );
     147        }
     148        add_action( 'plugins_loaded', array( Email_Templates::get_instance(), 'load_hooks' ), 99, 0 );
     149        add_action( 'plugins_loaded', array( Ajax::get_instance(), 'load_hooks' ), 99, 0 );
     150        add_action( 'plugins_loaded', array( Page::get_instance(), 'load_hooks' ), 99, 0 );
    151151
    152152        // Add validation logic for all modules
    153         add_action( 'plugins_loaded', array( User_Validation::get_instance(), 'load_actions' ), 30 );
    154         add_action( 'plugins_loaded', array( PMPro_Validation::get_instance(), 'load_actions' ), 31 );
    155         add_action( 'plugins_loaded', array( BuddyPress_Validation::get_instance(), 'load_actions' ), 32 );
    156 
    157         add_action( 'init', array( $this, 'load_i18n' ), 5 );
    158         add_action( 'init', array( $this->data, 'process_csv' ) );
    159 
    160         add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
    161 
    162         // PMPro specific import functionality
    163         // phpcs:ignore - We do this in the CSV() class as it's a clean-up operation
    164         // add_action( 'e20r_before_user_import', array( $this->csv, 'pre_import' ), 10, 2 );
     153        add_action( 'plugins_loaded', array( User_Validation::get_instance(), 'load_actions' ), 30, 0 );
     154        add_action( 'plugins_loaded', array( PMPro_Validation::get_instance(), 'load_actions' ), 31, 0 );
     155        add_action( 'plugins_loaded', array( BuddyPress_Validation::get_instance(), 'load_actions' ), 32, 0 );
     156
     157        add_action( 'init', array( $this, 'load_i18n' ), 5, 0 );
     158        add_action( 'init', array( $this->data, 'process_csv' ), 10, 0 );
     159
     160        add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ), 10, 0 );
     161
     162        // PMPro specific capabilities
     163        // We do this in the CSV() class as it's a clean-up operation
     164        // add_action( 'e20r_before_user_import', array( $this->csv, 'pre_import' ), 10, 2 ); // phpcs:ignore
    165165        add_filter( 'e20r_import_usermeta', array( $this->import_user, 'import_usermeta' ), 10, 2 );
    166166        add_action(
     
    179179
    180180        // Clear action handler(s) from the Import Users from CSV Integration Add-on for PMPro
    181         add_action( 'wp_loaded', array( $this, 'remove_iucsv_support' ), 10 );
     181        add_action( 'wp_loaded', array( $this, 'remove_iucsv_support' ), 10, 0 );
    182182
    183183        // Remove Import action for Sponsored Members add-on (handled directly by this plugin)
    184184        remove_action( 'is_iu_post_user_import', 'pmprosm_is_iu_post_user_import', 20 );
    185185
    186         if ( class_exists( 'E20R\Utilities\Licensing\Licensing' ) ) {
    187             $licensing = new Licensing( self::E20R_LICENSE_SKU );
    188 
    189             if ( $licensing->is_licensed( self::E20R_LICENSE_SKU, false ) ) {
    190                 do_action( 'e20r_import_load_licensed_modules' );
    191             }
     186        if ( ! class_exists( 'E20R\Utilities\Licensing\Licensing' ) ) {
     187            return;
     188        }
     189
     190        $check = new \ReflectionMethod( 'E20R\Utilities\Licensing\Licensing', '__construct' );
     191
     192        if ( false === $check->isPrivate() ) {
     193            $licensing   = new Licensing( self::E20R_LICENSE_SKU );
     194            $is_licensed = $licensing->is_licensed( self::E20R_LICENSE_SKU, false );
     195        } else {
     196            // @phpstan-ignore-next-line
     197            $is_licensed = Licensing::is_licensed( self::E20R_LICENSE_SKU, false );
     198        }
     199
     200        if ( true === $is_licensed ) {
     201            do_action( 'e20r_import_load_licensed_modules' );
    192202        }
    193203    }
     
    249259         */
    250260        $max_run_time = (
    251             apply_filters( 'pmp_im_import_time_per_record', 3 ) *
    252             apply_filters( 'pmp_im_import_records_per_scan', $this->variables->get( 'per_partial' ) )
     261            $this->variables->calculate_per_record_time() *
     262            apply_filters( 'e20r_import_records_per_scan', $this->variables->get( 'per_partial' ) )
    253263        );
    254264
     
    261271            'pmpro-import-members-from-csv',
    262272            plugins_url( 'css/pmpro-import-members-from-csv.css', E20R_IMPORT_PLUGIN_FILE ),
    263             null,
     273            array(),
    264274            E20R_IMPORT_VERSION
    265275        );
     276
    266277        // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter
    267278        wp_register_script(
     
    358369    public function plugin_row_meta( $links, $file ) {
    359370
    360         if ( true === stripos( $file, 'class.pmpro-import-members.php' ) ) {
     371        if ( false !== stripos( $file, 'class.pmpro-import-members.php' ) ) {
    361372            // Add (new) 'Import Users from CSV' links to plugin listing
    362373            $new_links = array(
  • pmpro-import-members-from-csv/tags/v3.0.6/src/class-variables.php

    r2554806 r2563515  
    302302        $this->error_log->debug( "File name from transient is {$this->filename} vs tmp name of {$tmp_name}" );
    303303
    304         if ( empty( $filename ) && ( ! empty( $tmp_name ) && file_exists( $tmp_name ) ) ) {
     304        if ( empty( $this->filename ) && ( ! empty( $tmp_name ) && file_exists( $tmp_name ) ) ) {
    305305
    306306            $this->error_log->debug( "Update/move the {$tmp_name} file!" );
     
    312312                exit();
    313313            }
    314         } elseif ( ! empty( $filename ) ) {
    315             $this->filename = $filename;
    316314        }
    317315
     
    345343
    346344        if ( ! empty( $max_exec_time ) && ( is_numeric( $per_record_time ) ) ) {
    347             $this->per_partial = round( ceil( $max_exec_time / (float) $per_record_time ), 0 );
     345            $this->per_partial = intval( round( ceil( $max_exec_time / (float) $per_record_time ), 0 ) );
    348346        }
    349347
  • pmpro-import-members-from-csv/tags/v3.0.6/src/import/class-ajax.php

    r2554946 r2563515  
    119119                $this->error_log->debug( "Visitor ({$client_ip}) clicked the 'Donate' button" );
    120120                wp_send_json_success();
    121                 exit();
    122121            }
    123122        }
    124123
    125124        wp_send_json_error();
    126         exit();
    127125    }
    128126
     
    162160        if ( false === $this->delete_file( $logfile_path ) ) {
    163161            wp_send_json_error();
    164             exit();
    165162        }
    166163
    167164        // Return success
    168165        wp_send_json_success();
    169         exit();
    170166    }
    171167
     
    186182            $this->error_log->debug( 'File not found/not available. Nothing to clean!' );
    187183            wp_send_json_success();
    188             exit();
    189184        }
    190185
     
    197192
    198193            wp_send_json_error();
    199             exit();
    200194        }
    201195
     
    208202
    209203        wp_send_json_success();
    210         exit();
    211204    }
    212205
     
    244237        $this->error_log->debug( 'Nonce verified in import_members_from_csv()' );
    245238
    246         /*
     239        /* @codingStandardsIgnoreStart
     240         *
    247241        if ( false === wp_verify_nonce( $_REQUEST['e20r-im-import-members-wpnonce'], 'e20r-im-import-members' ) ) {
    248242
    249243            $msg = __( 'Insecure connection attempted!', 'pmpro-import-members-from-csv' );
    250244
    251             wp_send_json_error( array( 'status'  => - 1,
    252                                        'message' => $msg,
    253             ) );
    254             exit();
    255         }
    256         */
     245            wp_send_json_error(
     246                array(
     247                    'status'  => - 1,
     248                    'message' => $msg,
     249                )
     250            );
     251        }
     252         * @codingStandardsIgnoreEnd
     253         */
    257254
    258255        // Get our settings
     
    268265                )
    269266            );
    270             exit();
    271267        }
    272268
     
    287283                )
    288284            );
    289             exit();
    290285        }
    291286
     
    371366        }
    372367
    373         $buffered_text = ob_get_clean();
     368        $buffered_text  = ob_get_clean();
     369        $display_errors = $this->variables->get( 'display_errors' );
    374370
    375371        // No users imported (or done)
     
    383379            //Clear position
    384380            delete_option( "e20rcsv_{$file}" );
    385             $display_errors = $this->variables->get( 'display_errors' );
    386381
    387382            // Delete the transient storing the file name
     
    397392                )
    398393            );
    399             exit();
    400394
    401395        } elseif ( ! empty( $results['errors'] ) ) {
     
    425419                )
    426420            );
    427             exit();
    428421        } else {
    429422
     
    462455                )
    463456            );
    464             exit();
    465457        }
    466458    }
  • pmpro-import-members-from-csv/tags/v3.0.6/src/import/class-csv.php

    r2554806 r2563515  
    2121
    2222use E20R\Import_Members\Error_Log;
    23 use E20R\Import_Members\Modules\Users\Column_Validation as User_Validation;
    2423use E20R\Import_Members\Modules\Users\Import_User;
    2524use E20R\Import_Members\Status;
     
    3736
    3837    /**
    39      * The CSV file (as a SplFileObject() class )
    40      *
    41      * @var SplFileObject $file_object
    42      */
    43     private $file_object;
    44 
    45     /**
    4638     * Error log class
    4739     * @var Error_Log|null $error_log = null;
     
    6052     * @var null|CSV $csv
    6153     */
    62     private $csv = null;
     54    private $csv;
    6355
    6456    /**
     
    201193        }
    202194
     195        // @phpstan-ignore-next-line
     196        $this->error_log->debug( 'Directory error? ' . ( $directory_error ? 'Yes' : 'No' ) );
     197        $this->error_log->debug( 'File upload not selected error? ' . ( $no_file_error ? 'Yes' : 'No' ) );
     198        $this->error_log->debug( 'File limit error? ' . ( $clean_file_error ? 'Yes' : 'No' ) );
     199
     200        // @phpstan-ignore-next-line
    203201        if ( ( true === $no_file_error || true === $directory_error || true === $clean_file_error ) ) {
    204 
    205202            $this->error_log->debug( 'Error: Problem with uploaded file...' );
    206             $this->error_log->debug( 'Directory error? ' . ( $directory_error ? 'Yes' : 'No' ) );
    207             $this->error_log->debug( 'File upload not selected error? ' . ( $no_file_error ? 'Yes' : 'No' ) );
    208             $this->error_log->debug( 'File limit error? ' . ( $clean_file_error ? 'Yes' : 'No' ) );
    209 
    210203            return false;
    211204        }
     
    333326
    334327        // Mac CR+LF fix
    335         ini_set( 'auto_detect_line_endings', true );
     328        ini_set( 'auto_detect_line_endings', '1' );
    336329
    337330        $file        = basename( $file_name );
     
    414407
    415408            $this->error_log->debug( "Processing next user data. (previous line #: {$active_line_number})" );
    416 
    417409            $this->extract_data(
    418410                $line,
     
    493485            $user_id = $import_user->import( $user_data, $user_meta, $headers );
    494486
    495             if ( false === $user_ids ) {
     487            if ( ! $user_ids ) {
    496488
    497489                $msg = sprintf(
     
    519511        // Close the file (done by the destructor for the SplFileObject() class)
    520512        $file_object = null;
    521         ini_set( 'auto_detect_line_endings', true );
     513        ini_set( 'auto_detect_line_endings', '1' );
    522514
    523515        // One more thing to do after all imports?
  • pmpro-import-members-from-csv/tags/v3.0.6/src/modules/BuddyPress/class-buddypress.php

    r2554806 r2563515  
    7272     * @access private
    7373     */
    74     private function __construct() {
     74    public function __construct() {
    7575        $this->data      = new Data();
    7676        $this->error_log = new Error_Log(); // phpcs:ignore
     
    8484        );
    8585    }
    86 
    87     /**
    88      * Get or instantiate and return this class (BuddyPress)
    89      *
    90      * @return BuddyPress|null
    91      */
    92 //  public static function get_instance() {
    93 //      if ( null === self::$instance ) {
    94 //          self::$instance = new self();
    95 //      }
    96 //      return self::$instance;
    97 //  }
    9886
    9987    /**
     
    149137        return $field_list + $this->field_list;
    150138    }
    151 
    152     /**
    153      * Clone the class (Singleton)
    154      *
    155      * @access private
    156      */
    157     private function __clone() {
    158         // TODO: Implement __clone() method.
    159     }
    160139}
  • pmpro-import-members-from-csv/tags/v3.0.6/src/modules/BuddyPress/class-column-validation.php

    r2554806 r2563515  
    3838namespace E20R\Import_Members\Modules\BuddyPress;
    3939
    40 
    4140use E20R\Import_Members\Error_Log;
    4241use E20R\Import_Members\Validate\Base_Validation;
     42use E20R\Import_Members\Modules\BuddyPress\BuddyPress;
    4343
    4444class Column_Validation extends Base_Validation {
    45    
     45
    4646    /**
    4747     * Get or instantiate and get the current class
    4848     *
    49      * @return Column_Validation|null
     49     * @return Column_Validation|Base_Validation|null
    5050     */
    5151    public static function get_instance() {
     
    5353        if ( true === is_null( self::$instance ) ) {
    5454            self::$instance = new self();
    55            
     55
    5656            add_filter(
    5757                'e20r_import_errors_to_ignore',
    5858                array( self::$instance, 'load_ignored_module_errors' ),
    5959                10,
    60             2
     60                2
    6161            );
    62            
     62
    6363            // Add list of errors to ignore for the BuddyPress module
    6464            self::$instance->errors_to_ignore = apply_filters(
     
    7171        return self::$instance;
    7272    }
    73    
     73
    7474    /**
    7575     * Define the module specific errors to ignore
     
    8181     */
    8282    public function load_ignored_module_errors( $ignored_error_list, $module_name = 'buddypress' ) {
    83        
    84         if ( $module_name !== 'buddypress' ) {
     83
     84        if ( 'buddypress' !== $module_name ) {
    8585            return $ignored_error_list;
    8686        }
    87        
    88         $this->error_log->debug("Loading BuddyPress specific error(s) when it's safe to can continue importing");
    89        
     87
     88        $this->error_log->debug( "Loading BuddyPress specific error(s) when it's safe to can continue importing" );
     89
    9090        $this->errors_to_ignore = array(
    9191            'bp_field_name' => true,
    9292        );
    93        
     93
    9494        return $ignored_error_list + $this->errors_to_ignore;
    9595    }
    96    
     96
    9797    /**
    9898     * Load action and filter handlers for PMPro validation
     
    103103            return;
    104104        }
    105        
     105
    106106        add_filter( 'e20r_import_members_validate_field_data', array( $this, 'bp_field_exists' ), 1, 3 );
    107107    }
     
    117117     */
    118118    public function bp_field_exists( $has_error, $user_id, $fields ) {
    119        
    120         $buddy_press = BuddyPress::get_instance();
     119
     120        $buddy_press = new BuddyPress();
    121121        $buddy_press->load_fields( array() );
    122122
    123         if ( ! isset( $fields['bp_field_name'])) {
    124             $this->error_log->debug("No need to process 'bp_field_name' column");
     123        if ( ! isset( $fields['bp_field_name'] ) ) {
     124            $this->error_log->debug( "No need to process 'bp_field_name' column" );
    125125            return $has_error;
    126126        }
    127127
    128         if ( ! isset( $fields['bp_field_name'] ) && in_array( 'bp_field_name', array_keys( $fields ) ) ) {
     128        if ( ! isset( $fields['bp_field_name'] ) && in_array( 'bp_field_name', array_keys( $fields ), true ) ) {
    129129            $this->error_log->debug( "'bp_field_name' is doesn't need to be processed..." );
    130130            return $has_error;
     
    132132
    133133        if ( isset( $fields['bp_field_name'] ) && empty( $fields['bp_field_name'] ) ) {
    134             $has_error = $has_error && ( true && ! $this->ignore_validation_error( 'bp_field_name' ) );
     134            $has_error = $has_error && ( ! $this->ignore_validation_error( 'bp_field_name' ) );
    135135        }
    136136
    137137        // FIXME: Add check for 'bp_field_exists' for the supplied fields/data
    138        
     138
    139139        return $has_error;
    140140    }
    141 
    142     /**
    143      * Disable the __clone() magic method
    144      *
    145      * @access private
    146      */
    147     private function __clone() {
    148         // TODO: Implement __clone() method.
    149     }
    150141}
  • pmpro-import-members-from-csv/tags/v3.0.6/src/modules/BuddyPress/class-import-buddypress.php

    r2554806 r2563515  
    2020namespace E20R\Import_Members\Modules\BuddyPress;
    2121
    22 
    2322class Import_BuddyPress {
    24 
     23    // TODO: Create BuddyPress import class
    2524}
  • pmpro-import-members-from-csv/tags/v3.0.6/src/modules/PMPro/class-column-validation.php

    r2554806 r2563515  
    3232     * Instance of the PMPro Column_Validation class
    3333     *
    34      * @var null|Column_Validation $instance
     34     * @var null|Column_Validation|Base_Validation $instance
    3535     */
    3636    protected static $instance = null;
     
    3939     * Get or instantiate and get the current class
    4040     *
    41      * @return Column_Validation|null
    42      */
    43     public static function get_instance() : \E20R\Import_Members\Modules\PMPro\Column_Validation {
     41     * @return Column_Validation|Base_Validation|null
     42     */
     43    public static function get_instance() {
    4444
    4545        if ( true === is_null( self::$instance ) ) {
     
    165165        $e20r_import_err['invalid_membership_id'] = new WP_Error( 'e20r_im_member', $msg );
    166166
    167         $has_error = true && ( ! $this->ignore_validation_error( 'invalid_membership_id' ) );
     167        $has_error = ( ! $this->ignore_validation_error( 'invalid_membership_id' ) );
    168168
    169169        return $has_error;
     
    173173     * Can't import membership data when user has incorrect start date format
    174174     *
    175      * @param $has_error
    176      * @param $user_id
    177      * @param $fields
     175     * @param bool $has_error
     176     * @param int $user_id
     177     * @param array $fields
    178178     *
    179179     * @return bool
     
    228228            );
    229229
    230             $has_error = true && ( ! $this->ignore_validation_error( 'startdate_format' ) );
     230            $has_error = ( ! $this->ignore_validation_error( 'startdate_format' ) );
    231231        }
    232232
     
    237237     * Can't import membership data when user has incorrect start date format or value
    238238     *
    239      * @param $has_error
    240      * @param $user_id
    241      * @param $fields
     239     * @param bool $has_error
     240     * @param int $user_id
     241     * @param array $fields
    242242     *
    243243     * @return bool
     
    289289
    290290            $e20r_import_err['no_startdate'] = new WP_Error( 'e20r_im_member', $msg );
    291             $has_error                       = true && ( ! $this->ignore_validation_error( 'no_startdate' ) );
     291            $has_error                       = ( ! $this->ignore_validation_error( 'no_startdate' ) );
    292292        }
    293293        return $has_error;
     
    297297     * Possible problem for membership data when user has incorrect end date format or value
    298298     *
    299      * @param $has_error
    300      * @param $user_id
    301      * @param $fields
     299     * @param bool $has_error
     300     * @param int $user_id
     301     * @param array $fields
    302302     *
    303303     * @return bool
     
    335335
    336336            $e20r_import_err['bad_format_enddate'] = new WP_Error( 'e20r_im_member', $msg );
    337             $has_error                             = true && ( ! $this->ignore_validation_error( 'bad_format_enddate' ) );
     337            $has_error                             = ( ! $this->ignore_validation_error( 'bad_format_enddate' ) );
    338338
    339339            $should_be = Time::convert( $fields['membership_enddate'] );
     
    378378        if (
    379379            ! empty( $fields['membership_enddate'] ) &&
    380             isset( $fields['membership_status'] ) && 'inactive' === $fields['membership_status'] &&
     380            ! empty( $fields['membership_status'] ) &&
     381            'inactive' === $fields['membership_status'] &&
    381382            ( time() < strtotime( $fields['membership_enddate'], time() ) )
    382383        ) {
     
    395396
    396397            $e20r_import_err['inactive_and_enddate'] = new WP_Error( 'e20r_im_member', $msg );
    397             $has_error                               = true && ( ! $this->ignore_validation_error( 'inactive_and_enddate' ) );
     398            $has_error                               = ( ! $this->ignore_validation_error( 'inactive_and_enddate' ) );
    398399        }
    399400
     
    450451
    451452            $e20r_import_err['valid_status'] = new WP_Error( 'e20r_im_member', $msg );
    452             $has_error                       = true && ( ! $this->ignore_validation_error( 'valid_status' ) );
     453            $has_error                       = ( ! $this->ignore_validation_error( 'valid_status' ) );
    453454        }
    454455
     
    505506
    506507            $e20r_import_err['link_subscription'] = new WP_Error( 'e20r_im_member', $msg );
    507             $has_error                            = true && ( ! $this->ignore_validation_error( 'link_subscription' ) );
     508            $has_error                            = ( ! $this->ignore_validation_error( 'link_subscription' ) );
    508509        }
    509510
     
    552553
    553554            $e20r_import_err['invalid_recurring_config'] = new WP_Error( 'e20r_im_member', $msg );
    554             $has_error                                   = true && ( ! $this->ignore_validation_error( 'invalid_recurring_config' ) );
     555            $has_error                                   = ( ! $this->ignore_validation_error( 'invalid_recurring_config' ) );
    555556        }
    556557
     
    594595            );
    595596            $e20r_import_err['sub_id_no_paym_id'] = new WP_Error( 'e20r_im_member', $msg );
     597            $has_error                            = ( ! $this->ignore_validation_error( 'sub_id_no_paym_id' ) );
    596598        }
    597599
     
    674676            $e20r_import_err[ "no_membership_id_column_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    675677
    676             $has_error = true && ( ! $this->ignore_validation_error( 'no_membership_id_column' ) );
     678            $has_error = ( ! $this->ignore_validation_error( 'no_membership_id_column' ) );
    677679        }
    678680
     
    690692            $e20r_import_err[ "no_membership_id_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    691693
    692             $has_error = true && ( ! $this->ignore_validation_error( 'no_membership_id' ) );
     694            $has_error = ( ! $this->ignore_validation_error( 'no_membership_id' ) );
    693695        }
    694696
     
    707709            $e20r_import_err[ "cancelling_membership_level_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    708710
    709             $has_error = false;
     711            $has_error = ( ! $this->ignore_validation_error( 'cancelling_membership_level' ) );
    710712        }
    711713
     
    752754            $e20r_import_err[ "level_exists_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    753755
    754             $has_error = true && ( ! $this->ignore_validation_error( 'level_exists' ) );
     756            $has_error = ( ! $this->ignore_validation_error( 'level_exists' ) );
    755757        }
    756758        return $has_error;
     
    799801            $e20r_import_err[ "recurring_w_enddate_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    800802
    801             $has_error = true && ( ! $this->ignore_validation_error( 'recurring_w_enddate' ) );
     803            $has_error = ( ! $this->ignore_validation_error( 'recurring_w_enddate' ) );
    802804        }
    803805        return $has_error;
     
    845847            $e20r_import_err[ "correct_gw_env_variable_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    846848
    847             $has_error = true && ( ! $this->ignore_validation_error( 'correct_gw_env_variable' ) );
     849            $has_error = ( ! $this->ignore_validation_error( 'correct_gw_env_variable' ) );
    848850        }
    849851
     
    893895                $e20r_import_err[ "supported_gateway_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    894896
    895                 $has_error = true && ( ! $this->ignore_validation_error( 'supported_gateway' ) );
     897                $has_error = ( ! $this->ignore_validation_error( 'supported_gateway' ) );
    896898            }
    897899        }
  • pmpro-import-members-from-csv/tags/v3.0.6/src/modules/PMPro/class-import-member.php

    r2554806 r2563515  
    176176        $has_error              = false;
    177177        $membership_in_the_past = false;
    178 
    179         // Define table names
    180         $pmpro_member_table = "{$wpdb->prefix}pmpro_memberships_users";
    181         $pmpro_dc_table     = "{$wpdb->prefix}pmpro_discount_codes";
    182 
    183         $current_blog_id = get_current_blog_id();
     178        $current_blog_id        = get_current_blog_id();
    184179
    185180        $this->error_log->debug( "Current blog ID: {$current_blog_id}" );
     
    266261                $wpdb->prepare(
    267262                    "SELECT dc.id
    268                               FROM {$pmpro_dc_table} AS dc
     263                              FROM {$wpdb->prefix}pmpro_discount_codes AS dc
    269264                              WHERE dc.code = %s
    270265                              LIMIT 1",
     
    291286                // Update all currently active memberships with the specified ID for the specified user
    292287                $updated = $wpdb->update(
    293                     $pmpro_member_table,
     288                    "{$wpdb->prefix}pmpro_memberships_users",
    294289                    array( 'status' => 'admin_cancelled' ),
    295290                    array(
     
    392387                    $wpdb->prepare(
    393388                        "SELECT mt.id
    394                                       FROM {$pmpro_member_table} AS mt
     389                                      FROM {$wpdb->prefix}pmpro_memberships_users AS mt
    395390                                      WHERE mt.user_id = %d AND mt.membership_id = %d AND mt.status = %s
    396391                                      ORDER BY mt.id DESC LIMIT 1",
     
    404399                    $wpdb->prepare(
    405400                        "SELECT mt.id
    406                                       FROM {$pmpro_member_table} AS mt
     401                                      FROM {$wpdb->prefix}pmpro_memberships_users AS mt
    407402                                      WHERE mt.user_id = %d AND mt.membership_id = %d
    408403                                      ORDER BY mt.id DESC LIMIT 1",
     
    430425
    431426                if ( false !== $wpdb->update(
    432                     $pmpro_member_table,
     427                    "{$wpdb->prefix}pmpro_memberships_users",
    433428                    array(
    434429                        'status'  => 'inactive',
     
    469464
    470465                if ( false === $wpdb->update(
    471                     $pmpro_member_table,
     466                    "{$wpdb->prefix}pmpro_memberships_users",
    472467                    array(
    473468                        'status'  => 'active',
     
    515510
    516511        // Update the error status
    517         if ( true === $has_error ) {
    518             update_option( 'e20r_import_errors', $has_error );
    519         }
     512        update_option( 'e20r_import_errors', $has_error );
    520513
    521514        if ( is_multisite() ) {
     
    592585            }
    593586
    594             $order                 = new \MemberOrder();
    595             $order->user_id        = $user_id;
    596             $order->membership_id  = isset( $record['membership_id'] ) ?? $record['membership_id'];
    597             $order->InitialPayment = ! empty( $record['membership_initial_payment'] ) ? $record['membership_initial_payment'] : null;
     587            $order                = new \MemberOrder();
     588            $order->user_id       = $user_id; // @phpstan-ignore-line
     589            $order->membership_id = isset( $record['membership_id'] ) ?? $record['membership_id']; // @phpstan-ignore-line
     590
     591            // phpcs:ignore
     592            $order->InitialPayment = ! empty( $record['membership_initial_payment'] ) ? $record['membership_initial_payment'] : null; // @phpstan-ignore-line
    598593
    599594            /**
     
    616611
    617612                    if ( ! isset( $order->billing ) ) {
    618                         $order->billing = new \stdClass();
     613                        $order->billing = new \stdClass();  // @phpstan-ignore-line
    619614                    }
    620615
     
    635630                    if ( 'total' === $field_name && ! empty( $record['membership_initial_payment'] ) ) {
    636631
    637                         $order->total = $record['membership_initial_payment'];
     632                        $order->total = $record['membership_initial_payment']; // @phpstan-ignore-line
    638633
    639634                    } elseif ( 'total' === $field_name && (
     
    642637                        ) ) {
    643638
    644                         $order->total = $record['membership_billing_amount'];
     639                        $order->total = $record['membership_billing_amount']; // @phpstan-ignore-line
    645640
    646641                    } elseif ( 'total' !== $field_name ) {
    647642
    648643                        if ( 'status' === $field_name ) {
     644                            // @phpstan-ignore-next-line
    649645                            $order->{$field_name} = ( isset( $record[ $full_field_name ] ) && 'active' === $record[ $full_field_name ] ? 'success' : 'cancelled' );
    650646                        } else {
     
    663659
    664660            if ( isset( $record['membership_gateway_environment'] ) && strtolower( $default_environment ) !== strtolower( $record['membership_gateway_environment'] ) ) {
    665                 $order->gateway_environment = strtolower( $record['membership_gateway_environment'] );
     661                $order->gateway_environment = strtolower( $record['membership_gateway_environment'] ); // @phpstan-ignore-line
    666662            }
    667663
    668664            if ( true === $membership_in_the_past ) {
    669                 $order->status = 'cancelled';
     665                $order->status = 'cancelled'; // @phpstan-ignore-line
    670666            }
    671667
  • pmpro-import-members-from-csv/tags/v3.0.6/src/modules/PMPro/class-import-sponsors.php

    r2554806 r2563515  
    7474     */
    7575    public function load_sponsor_import() {
    76         if ( true === Licensing::is_licensed( 'import_sponsors' ) ) {
     76        $check = new \ReflectionMethod( 'E20R\Utilities\Licensing\Licensing', '__construct' );
     77
     78        if ( false === $check->isPrivate() ) {
     79            $licensing   = new Licensing( Import_Members::E20R_LICENSE_SKU );
     80            $is_licensed = $licensing->is_licensed( Import_Members::E20R_LICENSE_SKU, false );
     81        } else {
     82            // @phpstan-ignore-next-line
     83            $is_licensed = Licensing::is_licensed( Import_Members::E20R_LICENSE_SKU, false );
     84        }
     85
     86        if ( true === $is_licensed ) {
    7787            add_action( 'e20r_after_user_import', array( $this, 'maybe_add_sponsor_info' ), 100, 3 );
    7888        }
     
    169179     *
    170180     * @param int     $sponsored_user_id
    171      * @param Sponsor $sponsor
     181     * @param Sponsor|\WP_User $sponsor
    172182     * @param bool    $last_try
    173183     *
     
    196206
    197207        // Get user info and ensure they have a current membership level
    198         $sponsored_user                   = get_userdata( $sponsored_user_id );
     208        $sponsored_user = get_userdata( $sponsored_user_id );
     209
     210        // @phpstan-ignore-next-line
    199211        $sponsored_user->membership_level = pmpro_getMembershipLevelForUser( $sponsored_user_id, true );
    200212        $delayed_sponsor_link             = $this->variables->get( 'delayed_sponsor_link' );
     
    235247
    236248        //Make sure the sponsor has a discount code
    237         $code_id = pmprosm_getCodeByUserID( $sponsor_id );
     249        $code_id = pmprosm_getCodeByUserID( $sponsor_id ); // @phpstan-ignore-line
    238250
    239251        $this->error_log->debug( "Got sponsor code {$code_id} for sponsor {$sponsor_id}" );
     
    295307            $this->error_log->debug( "Have to create a sponsor code for {$sponsor_id}" );
    296308
     309            // @phpstan-ignore-next-line
    297310            $code_id = pmprosm_createSponsorCode( $sponsor_id, $sponsor_level_id, $uses );
    298311        }
     
    317330            'code_id'       => $code_id,
    318331            'user_id'       => $sponsored_user_id,
    319             'membership_id' => $sponsored_user->membership_level->id,
     332            'membership_id' => $sponsored_user->membership_level->id, // @phpstan-ignore-line
    320333            'status'        => 'active',
    321334        );
     
    342355        $this->error_log->debug( "Updated member record for {$sponsored_user_id} with sponsor info" );
    343356
     357        // @phpstan-ignore-next-line
    344358        pmprosm_addDiscountCodeUse( $sponsored_user_id, $sponsored_user->membership_level->ID, $code_id );
    345359
    346360        $this->error_log->debug( "Updated the usage of {$code_id}" );
    347361
    348         if ( empty( $error ) ) {
     362        if ( empty( $e20r_import_err ) ) {
    349363            $status = true;
    350364
     
    353367
    354368        } else {
    355             $error->log_errors(
    356                 array( $error ),
     369            $this->error_log->log_errors(
     370                $e20r_import_err,
    357371                $this->variables->get( 'log_file_path' ),
    358372                $this->variables->get( 'log_file_url' )
     
    398412            }
    399413
     414            // @phpstan-ignore-next-line
    400415            $sponsor->membership_level = pmpro_getMembershipLevelForUser( $sponsor_id, true );
    401416
  • pmpro-import-members-from-csv/tags/v3.0.6/src/modules/PMPro/class-pmpro.php

    r2554806 r2563515  
    1818 */
    1919namespace E20R\Import_Members\Modules\PMPro;
    20 
    2120
    2221use E20R\Import_Members\Error_Log;
  • pmpro-import-members-from-csv/tags/v3.0.6/src/modules/PMPro/class-sponsor.php

    r2554806 r2563515  
    2020namespace E20R\Import_Members\Modules\PMPro;
    2121
    22 
    2322use E20R\Import_Members\Data;
    2423
    2524class Sponsor {
    26    
     25
    2726    /**
    2827     * The sponsor's WP_User ID
     
    3130     */
    3231    private $ID = null;
    33    
     32
    3433    /**
    3534     * User Record for the sponsor
     
    3837     */
    3938    private $user = null;
    40    
     39
    4140    /**
    4241     * The membership level information for the sponsor
     
    4544     */
    4645    private $membership_level = null;
    47    
     46
    4847    /**
    4948     * Sponsor constructor.
    5049     *
    51      * @param $user_id
     50     * @param int|string $user_id
    5251     *
    5352     * @throws \Exception
    5453     */
    5554    public function __construct( $user_id = null ) {
    56        
    57         $data = Data::get_instance();
    58        
     55
     56        $data = new Data();
     57
    5958        if ( ! empty( $user_id ) ) {
    6059            $this->user = $data->get_user_info( $user_id );
    6160        }
    62        
    63         if ( !empty( $user_id ) && empty( $this->user ) ) {
    64             throw new \Exception( sprintf( __( 'No user with that ID (%s) found!', 'pmpro-import-members-from-csv' ), $user_id ) );
     61
     62        if ( ! empty( $user_id ) && empty( $this->user ) ) {
     63            throw new \Exception(
     64                sprintf(
     65                    // translators: %s - Supplied User ID, email or login name
     66                    __( 'No user with that ID (%s) found!', 'pmpro-import-members-from-csv' ),
     67                    $user_id
     68                )
     69            );
    6570        }
    6671    }
    67    
     72
    6873    /**
    6974     * Set Sponsor parameter by type
     
    7681     */
    7782    public function set( $param, $value, $type = null ) {
    78        
     83
    7984        $attributes = get_class_vars( __CLASS__ );
    80        
    81         if ( ! in_array( $param, $attributes ) && ! in_array( $type, $attributes ) ) {
     85
     86        if ( ! in_array( $param, $attributes, true ) && ! in_array( $type, $attributes, true ) ) {
    8287            return false;
    8388        }
    84        
     89
    8590        switch ( $type ) {
    86            
     91
    8792            case 'user':
    8893                if ( isset( $this->user->{$param} ) ) {
     
    9297                }
    9398                break;
    94            
     99
    95100            case 'membership':
    96                
    97101                if ( isset( $this->membership_level->{$param} ) ) {
    98102                    $this->membership_level->{$param} = $value;
     
    101105                }
    102106                break;
    103            
     107
    104108            default:
    105109                $this->{$param} = $value;
    106110        }
    107        
     111
    108112        return true;
    109113    }
    110    
     114
    111115    /**
    112116     * Return the type specific parameter (membership info, user info, class variable)
    113117     *
    114      * @param string $type
     118     * @param string|null $type
    115119     * @param string $param
    116120     *
     
    118122     */
    119123    public function get( $type, $param ) {
    120        
     124
    121125        $attributes = get_class_vars( __CLASS__ );
    122126        $value      = null;
    123        
    124         if ( ! in_array( $param, $attributes ) ) {
     127
     128        if ( ! in_array( $param, $attributes, true ) ) {
    125129            return false;
    126130        }
    127        
     131
    128132        switch ( $type ) {
    129            
     133
    130134            case 'user':
    131135                $value = $this->user->{$param};
    132136                break;
    133            
     137
    134138            case 'membership':
    135                
    136139                $value = $this->membership_level->{$param};
    137140                break;
    138            
     141
    139142            default:
    140143                $value = $this->{$param};
    141144        }
    142        
     145
    143146        return $value;
    144147    }
  • pmpro-import-members-from-csv/tags/v3.0.6/src/modules/Users/class-column-validation.php

    r2554806 r2563515  
    3636     * Get or instantiate and get the current class
    3737     *
    38      * @return Column_Validation|null
     38     * @return Column_Validation|Base_Validation|null
    3939     */
    4040    public static function get_instance() {
     
    134134     * @param null|string|string[] $field_name
    135135     *
    136      * @return bool|int|false
     136     * @return bool|int
    137137     */
    138138    public function validate_user_id( $has_error, $user_id, $record, $field_name = null ) {
     
    147147            $this->error_log->debug( 'Cannot find one of the expected column(s): ID, user_email, user_login' );
    148148            return $has_error;
    149         }
    150 
    151         if ( is_array( $field_name ) ) {
    152             // TODO: Process list of fields
    153149        }
    154150
     
    190186        return true;
    191187    }
    192 
    193     /**
    194      * Disable the __clone() magic method
    195      *
    196      * @access private
    197      */
    198     private function __clone() {
    199         // TODO: Implement __clone() method.
    200     }
    201188}
  • pmpro-import-members-from-csv/tags/v3.0.6/src/modules/Users/class-import-user.php

    r2554806 r2563515  
    353353        } else {
    354354            $update = false;
     355            $id     = null;
    355356            // Here we're supposed to hash the password
    356357            // $user_pass = wp_hash_password( $userdata['user_pass'] );
     
    555556
    556557        if ( true === $update ) {
    557             $wpdb->update( $wpdb->users, $data, compact( 'ID' ) );
     558            $wpdb->update( $wpdb->users, $data, compact( 'id' ) );
    558559            $user_id = (int) $id;
    559560        } else {
  • pmpro-import-members-from-csv/tags/v3.0.6/src/modules/Users/class-user-validation.php

    r2554806 r2563515  
    2020namespace E20R\Import_Members\Validate;
    2121
    22 
    2322use E20R\Import_Members\Import_Members;
    2423use E20R\Import_Members\Status;
    2524
    2625class User_Validation extends Validate {
    27    
    28    
     26
     27    /**
     28     * Return the User_Validation class instance
     29     *
     30     * @return Base_Validation|User_Validation|null
     31     */
     32    public static function get_instance() {
     33        if ( null === self::$instance ) {
     34            self::$instance = new self();
     35        }
     36
     37        return self::$instance;
     38    }
     39
     40    /**
     41     * Return list of validation errors we'll ignore (only warn for)
     42     *
     43     * @param array $ignored_error_list
     44     * @param string $module_name
     45     *
     46     * @return array
     47     */
     48    public function load_ignored_module_errors( $ignored_error_list, $module_name = 'users' ) {
     49        return $ignored_error_list;
     50    }
     51
     52    /**
     53     * Load action and filter handlers for PMPro validation
     54     */
     55    public function load_actions() {
     56
     57        add_filter(
     58            'e20r_import_users_validate_field_data',
     59            array( $this, 'validate' ),
     60            1,
     61            3
     62        );
     63    }
     64
    2965    /**
    3066     * Process the status for user validations and set a status message
     
    3672     */
    3773    public static function status_msg( $status, $allow_update ) {
    38        
     74
    3975        global $e20r_import_err;
    4076        global $active_line_number;
    41        
     77
    4278        $should_exit = false;
    4379
     
    5187
    5288            case Status::E20R_ERROR_UPDATE_NEEDED_NOT_ALLOWED:
    53                 $msg = __(
     89                $msg         = __(
    5490                    'User ID specified and user record exists but the "Update User Record" option is not selected',
    5591                    'pmpro-import-members-from-csv'
     
    67103                break;
    68104            default:
    69                
    70                 $msg = null;
     105                $msg         = null;
    71106                $should_exit = false;
    72107        }
    73        
     108
    74109        // Process the resulting error/warning message
    75110        if ( ! empty( $msg ) ) {
    76            
     111
    77112            // Save the error message (based on the supplied status)
    78             $e20r_import_err["user_check_{$active_line_number}"] = $msg;
    79            
     113            $e20r_import_err[ "user_check_{$active_line_number}" ] = $msg;
     114
    80115            return $should_exit;
    81116        }
    82        
     117
    83118        return false;
    84119    }
    85    
     120
    86121    /**
    87122     * Validate the User information in the record
     
    93128     */
    94129    public static function validate( $record, $allow_update ) {
    95        
    96         return false;
     130
     131        // TODO: Implement validation logic for User record(s)
     132        return ! empty( $record );
    97133    }
    98134}
  • pmpro-import-members-from-csv/tags/v3.0.6/src/validate/class-base-validation.php

    r2554806 r2563515  
    2323
    2424use E20R\Import_Members\Error_Log;
     25use E20R\Import_Members\Modules\PMPro\Column_Validation as PMPro_Validation;
     26use E20R\Import_Members\Modules\Users\Column_Validation as User_Validation;
     27use E20R\Import_Members\Modules\BuddyPress\Column_Validation as BP_Validation;
    2528
    2629abstract class Base_Validation {
     
    2932     * Instance of the column validation logic for PMPro
    3033     *
    31      * @var null|Base_Validation
     34     * @var null|Base_Validation|PMPro_Validation|User_Validation|BP_Validation
    3235     */
    3336    protected static $instance = null;
     
    7578     * Get or instantiate and get the current class
    7679     *
    77      * @return Column_Validation|Base_Validation|null
     80     * @return User_Validation|PMPro_Validation|BP_Validation|Base_Validation|null
    7881     */
    7982    abstract public static function get_instance();
     
    8184    /**
    8285     * Load all validation actions for the specific module
    83      *
    84      * @return null
    8586     */
    8687    abstract public function load_actions();
  • pmpro-import-members-from-csv/tags/v3.0.6/src/validate/class-date-format.php

    r2554806 r2563515  
    2121
    2222class Date_Format {
    23    
     23
    2424    /**
    2525     * Test the date supplied for MySQL compliance
     
    3333     */
    3434    public static function validate( $date, $format ) {
    35        
     35
    3636        $check_date = \DateTime::createFromFormat( $format, $date );
    37         $retval     = ( false !== $check_date ) && ( $check_date->format( $format ) == $date );
    38        
    39         return $retval;
     37
     38        return ( false !== $check_date ) && ( $check_date->format( $format ) === $date );
    4039    }
    41    
     40
    4241}
  • pmpro-import-members-from-csv/trunk/CHANGELOG.md

    r2555218 r2563515  
    66
    77## [Unreleased]
     8
     9## v3.0.6 - 2021-07-13
     10- BUG FIX: Updates to presence check for test types (Thomas Sjolshagen)
     11- BUG FIX: Didn't install the ruleset when in GitHub Action (Thomas Sjolshagen)
     12- BUG FIX: Fatal error during install of production composer dependencies (Thomas Sjolshagen)
     13- BUG FIX: acceptance-test target didn't work (Thomas Sjolshagen)
     14- BUG FIX: TTYs in docker-compose.yml (Thomas Sjolshagen)
     15- BUG FIX: Adding a stripped down data file for the WP Unit tests (Thomas Sjolshagen)
     16- BUG FIX: Refactor of the Makefile (Thomas Sjolshagen)
     17- BUG FIX: Didn't exclude inc/ in codeception.dist.yml (Thomas Sjolshagen)
     18- BUG FIX: Handle DB Dump if present (Thomas Sjolshagen)
     19- BUG FIX: Reverted inclusion of SQL file in repo (Thomas Sjolshagen)
     20- BUG FIX: Wrong path to the DB file we need for testing (Thomas Sjolshagen)
     21- BUG FIX: Add Docker Hub login to release-plugin.yml (Thomas Sjolshagen)
     22- BUG FIX: Include SQL so it can be used by WP Unit ++ tests (Thomas Sjolshagen)
     23- BUG FIX: Fix issue with TTY during GitHub action execution (Thomas Sjolshagen)
     24- BUG FIX: Adding COMPOSE_INTERACTIVE_NO_CLI=1 to work around 'The input device is not a TTY' errors/warnings (Thomas Sjolshagen)
     25- BUG FIX: Make sure we use the correct Docker Hub login approach (Thomas Sjolshagen)
     26- BUG FIX: Use log file if it's available (Thomas Sjolshagen)
     27- BUG FIX: Use action recipe for docker hub login (Thomas Sjolshagen)
     28- BUG FIX: More testing of docker hub login (Thomas Sjolshagen)
     29- BUG FIX: Split remote and local removal of tags (Thomas Sjolshagen)
     30- BUG FIX: Updates to debug Docker Hub login issues (Thomas Sjolshagen)
     31- BUG FIX: Make sure the file check works w/o error as a GitHub action (Thomas Sjolshagen)
     32- BUG FIX: Revert the shell based check for phpcs presence (shouldn't be needed) (Thomas Sjolshagen)
     33- BUG FIX: Troubleshooting the Makefile (Thomas Sjolshagen)
     34- BUG FIX: Use BASH by default when running commands (Thomas Sjolshagen)
     35- BUG FIX: Clean up PHONY targets and enable curl output (Thomas Sjolshagen)
     36- BUG FIX: Add PHPStan testing (Thomas Sjolshagen)
     37- BUG FIX: Enable parallel execution for PHPStan and omit a couple of error types (Thomas Sjolshagen)
     38- BUG FIX: PHPStan fixes to handle different versions of the Licensing module (Thomas Sjolshagen)
     39- BUG FIX: PHPStan related fixes in the Users class-column-validation.php file (Thomas Sjolshagen)
     40- BUG FIX: PHPStan related fixes in class-import-sponsors.php (Thomas Sjolshagen)
     41- BUG FIX: Incomplete argument type definition for Sponsor::get() method (Thomas Sjolshagen)
     42- BUG FIX: PHPStan related fixes in the PMPro class-import-member.php file (Thomas Sjolshagen)
     43- BUG FIX: Various logic and PHPStan related fixes in the PMPro class-column-validation.php file (Thomas Sjolshagen)
     44- BUG FIX: Various PHPStan related fixes in the BuddyPress class-column-validation.php file (Thomas Sjolshagen)
     45- BUG FIX: Various PHPStan related fixes for class-csv.php (Thomas Sjolshagen)
     46- BUG FIX: Remove unneeded exit() calls - PHPStan fixes for class-ajax.php (Thomas Sjolshagen)
     47- BUG FIX: Incorrect PHPStan errors for add_filter() function (Thomas Sjolshagen)
     48- BUG FIX: The $id parameter wasn't defined for all code paths in class-import-user.php (Thomas Sjolshagen)
     49- BUG FIX: Fixed PMPro related ignore/revert ignore comments in class-email-templates.php (Thomas Sjolshagen)
     50- BUG FIX: Ignored a PHPStan non-error in class-data.php (Thomas Sjolshagen)
     51- BUG FIX: Return value in PHPDoc wrong for load_actions() method (Thomas Sjolshagen)
     52- BUG FIX: PHPStan fixes for class-base-validation.php (Thomas Sjolshagen)
     53- BUG FIX: PHPStan fixes for class-activateutilitiesplugin.php (Thomas Sjolshagen)
     54- BUG FIX: Fatal errors due to poor error recovery in autoloader (Thomas Sjolshagen)
     55- BUG FIX: Clean up config for phpstan-test target (Thomas Sjolshagen)
     56- BUG FIX: code-standards-test target depends on plugin and composer modules (Thomas Sjolshagen)
     57- BUG FIX: Add WP Neutron code standards config (Thomas Sjolshagen)
     58- BUG FIX: PHPCS ignored some of the plugin source files (Thomas Sjolshagen)
     59- BUG FIX: Add WP Neutron code standards config (Thomas Sjolshagen)
     60- BUG FIX: Code sniffer updates for Buddypress version of class-column-validation.php (Thomas Sjolshagen)
     61- BUG FIX: Code sniffer updates for class-buddypress.php (Thomas Sjolshagen)
     62- BUG FIX: Code sniffer updates for class-import-buddypress.php (Thomas Sjolshagen)
     63- BUG FIX: Code sniffer updates for class-import-member.php (Thomas Sjolshagen)
     64- BUG FIX: Code sniffer updates for class-pmpro.php (Thomas Sjolshagen)
     65- BUG FIX: Code sniffer updates for class-ajax.php (Thomas Sjolshagen)
     66- BUG FIX: Code sniffer updates for class-column-validation.php (Thomas Sjolshagen)
     67- BUG FIX: Include the ActivateUtilitiesPlugin class path and clean up paths to scan/include (Thomas Sjolshagen)
     68- BUG FIX: PHPStan test execution settings (Thomas Sjolshagen)
     69- BUG FIX: Didn't autoload classes we expected to load (Thomas Sjolshagen)
     70- BUG FIX: PHPStan test command updated, making sure the inc/wp_plugins dir exists, and more info for some of the testing tagets (Thomas Sjolshagen)
     71- BUG FIX: php-composer target didn't work and phpstan memory limit set to 'unlimited' (Thomas Sjølshagen)
     72- BUG FIX: Renamed deps to wp-deps (Thomas Sjolshagen)
     73- BUG FIX: per_partial is an integer and not a float (Thomas Sjolshagen)
     74- BUG FIX: PHPStan test doesn't need a docker container to run (Thomas Sjolshagen)
     75- BUG FIX: PHPStan errors we don't care about (PMPro functions / class members, etc) (Thomas Sjolshagen)
     76- BUG FIX: PHPStan errors we don't care about (Thomas Sjolshagen)
     77- BUG FIX: PHPDoc string was incorrect (Thomas Sjolshagen)
     78- BUG FIX: Fatal error because we attempted to use Data::get_instance() plus PHPCS nits (Thomas Sjolshagen)
     79- BUG FIX: PHPStan complained about require_once call for Utility loader (Thomas Sjolshagen)
     80- BUG FIX: Make config more dynamic for testing (Thomas Sjolshagen)
     81- BUG FIX: Fix config for PHPStan testing (Thomas Sjolshagen)
     82- BUG FIX: Updates in support of PHPStan testing (Thomas Sjolshagen)
     83- BUG FIX: User Validation class was only partially implemented (Thomas Sjolshagen)
     84- BUG FIX: Wrong file name for plugin file (Thomas Sjolshagen)
     85- BUG FIX: Re-inverted the DOWNLOAD logic (Thomas Sjolshagen)
     86- BUG FIX: Use the get_plugin_version.sh script (Thomas Sjolshagen)
     87- BUG FIX: Made the wrong assumption about the location of the Version string (Thomas Sjolshagen)
     88- BUG FIX: Clean up build vs download for E20R plugins (Thomas Sjolshagen)
     89- BUG FIX: Refactored utility module build process (Thomas Sjolshagen)
     90- BUG FIX: Refactored build target (Thomas Sjolshagen)
     91- BUG FIX: More errors when determining local presence for Utilities (Thomas Sjolshagen)
     92- BUG FIX: Annoying errors in the Makefile (including -z vs -n issues) (Thomas Sjolshagen)
     93- BUG FIX: Build target updates to be .php file change triggered (Thomas Sjolshagen)
     94- BUG FIX: Wrong build target for custom E20R modules (Thomas Sjolshagen)
     95- BUG FIX: Utilities module dependency build fixes (Thomas Sjolshagen)
     96- BUG FIX: Didn't handle when Utilities module is in local git repo (Thomas Sjolshagen)
     97
     98## v3.0.5 - 2021-07-05
     99- BUG FIX: Reformatted README.md (Thomas Sjolshagen)
     100- BUG FIX: Duplicate entries in CHANGELOG.md (Thomas Sjolshagen)
     101- BUG FIX: Using template for metadata.json (Thomas Sjolshagen)
     102- BUG FIX: Build script for readme files updated (Thomas Sjolshagen)
     103- BUG FIX: Typo and formatting updates (Thomas Sjolshagen)
     104- BUG FIX: Don't clean up E20R custom plugins unless in one of the clean-up targets (Thomas Sjolshagen)
     105- BUG FIX: Unit tests do not require WordPress (Thomas Sjolshagen)
     106- BUG FIX: Wrong path for database container volume (Thomas Sjolshagen)
     107- BUG FIX: Typo in comments (Thomas Sjolshagen)
     108- BUG FIX: Old file name for plugin activation of 00-e20r-utilities (Thomas Sjolshagen)
     109- BUG FIX: Missing class definition for assertEquals() call in class-csv-UnitTest.php and class-import-members-UnitTest.php (Thomas Sjolshagen)
     110- BUG FIX: Errors when building the 00-e20r-utilities plugin as a dependency and add clean-up target (Thomas Sjolshagen)
     111- BUG FIX: Simplify config of make/build scripts (Thomas Sjolshagen)
     112- BUG FIX: Potentially inconsistent port use in test environment (Thomas Sjolshagen)
     113- BUG FIX: Initial commit - extracts version info for plugin (Thomas Sjolshagen)
     114- BUG FIX: Shift to PHPUnit 8.x (from 9.x) (Thomas Sjolshagen)
     115- BUG FIX: Use local repo to build 00-e20r-utilities plugin when possible (Thomas Sjolshagen)
     116- BUG FIX: Fixed the WP Unit test suite config for Codeception testing (Thomas Sjolshagen)
     117- BUG FIX: Pasted the wrong path to the Docker key file (Thomas Sjolshagen)
     118- BUG FIX: Be explicit about priorities and args when loading filter/action hooks (Thomas Sjolshagen)
     119- BUG FIX: Setting to handle WP's multi-site testing (Thomas Sjolshagen)
     120- BUG FIX: Use configurable vendor directory for composer (Thomas Sjolshagen)
     121- BUG FIX: Didn't account for the different possibilities for the Utilities/Licensing module (Thomas Sjolshagen)
     122- BUG FIX: A bit too aggressive when clearing inc/ directory (Thomas Sjolshagen)
     123- BUG FIX: Use custom gitignore file for inc/ directory (Thomas Sjolshagen)
     124- BUG FIX: Change log script fixed to avoid duplicate entries, blank line errors, etc (Thomas Sjolshagen)
     125- BUG FIX: Fixed the messed up autoloader and coding standard errors (Thomas Sjolshagen)
     126- BUG FIX: Removed unneeded variables in Makefile (Thomas Sjolshagen)
     127- BUG FIX: Refactored Makefile to be a bit more generic (Thomas Sjolshagen)
     128- BUG FIX: Update data file location for manual testing (Thomas Sjolshagen)
     129- BUG FIX: Renamed ActivateUtilitiesPlugin.php to fix coding standards errors (Thomas Sjolshagen)
     130- BUG FIX: Fix Coding Standard errors in class.pmpro-import-members.php (Thomas Sjolshagen)
     131- BUG FIX: Fix Coding Standard errors in class-validate.php (Thomas Sjolshagen)
     132- BUG FIX: Fix Coding Standard errors in class-date-format.php (Thomas Sjolshagen)
     133- BUG FIX: Fix Coding Standard problems (Thomas Sjolshagen)
     134- BUG FIX: Handle exporting the plugin as a git archive (Thomas Sjolshagen)
     135- BUG FIX: Calculated the wrong timeout value for the JS based background import (Thomas Sjolshagen)
     136- BUG FIX: Updated copyright notice (Thomas Sjolshagen)
     137- BUG FIX: PHPCS was a bit too inclusive (Thomas Sjolshagen)
     138- BUG FIX: Include the README.md file (Thomas Sjolshagen)
     139- BUG FIX: Relocate build status badge (Thomas Sjolshagen)
     140- BUG FIX: Splitting log/doc/updater json generation further (Thomas Sjolshagen)
     141- BUG FIX: Updated CHANGELOG (v3.0.5 for WP 5.7.2) (Thomas Sjolshagen)
     142- BUG FIX: Error generating documentation (Thomas Sjolshagen)
     143- BUG FIX: Use command for git (Thomas Sjolshagen)
     144- BUG FIX: Updating changelog source (Thomas Sjolshagen)
     145- BUG FIX: Reverted CHANGELOG status (Thomas Sjolshagen)
     146- BUG FIX: Separate CHANGELOG and README file generation (Thomas Sjolshagen)
     147- BUG FIX: Updated version number (v3.0.5) (Thomas Sjolshagen)
     148- BUG FIX: Create README.md from the README.txt file (Thomas Sjolshagen)
     149- BUG FIX: Separate CHANGELOG and README file generation (Thomas Sjolshagen)
     150- BUG FIX: Updated README info (v3.0.5 for WP 5.7.2) (Thomas Sjolshagen)
     151- BUG FIX: Updated version (v3.0.5 for WP 5.7.2) (Thomas Sjolshagen)
     152- BUG FIX: Didn't include a README.md file for the plugin (Thomas Sjolshagen)
     153- BUG FIX: Update repository name (Thomas Sjolshagen)
     154- BUG FIX: Action triggered twice (Thomas Sjolshagen)
     155- Bug fix/remove debug logging (#6) (Thomas Sjølshagen)
     156- BUG FIX: Re-activate the installed_paths setting for phpcs (Thomas Sjolshagen)
    8157
    9158## v3.0.4 - 2021-06-28
     
    151300- BUG FIX: Added action hook documentation (Thomas Sjolshagen)
    152301- BUG FIX: Fix PHPCS warnings (Thomas Sjolshagen)
    153 - BUG FIX: Fix PHPCS warnings (Thomas Sjolshagen)
    154302- BUG FIX: Rename e20r_import_load_licensed_modules action hook (Thomas Sjolshagen)
    155303- BUG FIX: Rename e20r_import_load_licensed_modules action hook and fix PHPCS warnings (Thomas Sjolshagen)
     
    224372- BUG FIX: Refactored docker-compose.override files for manual testing (Thomas Sjolshagen)
    225373- BUG FIX: Adding/Updating *ignore files (Thomas Sjolshagen)
    226 - BUG FIX: Adding/Updating *ignore files (Thomas Sjolshagen)
    227374- BUG FIX: More updates to support WP Unit testing (Thomas Sjolshagen)
    228375- BUG FIX: Various updates to support WordPress 'Unit' testing (Thomas Sjolshagen)
     
    491638* Fixed bugs with static/non-static function calls
    492639* Enhancement: JavaScript based async loading (for large imports)
     640- BUG FIX: Calculated the wrong timeout value for the JS based background import (Thomas Sjolshagen)
     641- BUG FIX: Updated copyright notice (Thomas Sjolshagen)
     642- BUG FIX: PHPCS was a bit too inclusive (Thomas Sjolshagen)
     643- BUG FIX: Include the README.md file (Thomas Sjolshagen)
     644- BUG FIX: Relocate build status badge (Thomas Sjolshagen)
     645- BUG FIX: Splitting log/doc/updater json generation further (Thomas Sjolshagen)
     646- BUG FIX: Updated CHANGELOG (v3.0.5 for WP 5.7.2) (Thomas Sjolshagen)
     647- BUG FIX: Error generating documentation (Thomas Sjolshagen)
     648- BUG FIX: Use command for git (Thomas Sjolshagen)
     649- BUG FIX: Updating changelog source (Thomas Sjolshagen)
     650- BUG FIX: Reverted CHANGELOG status (Thomas Sjolshagen)
     651- BUG FIX: Separate CHANGELOG and README file generation (Thomas Sjolshagen)
     652- BUG FIX: Updated version number (v3.0.5) (Thomas Sjolshagen)
     653- BUG FIX: Create README.md from the README.txt file (Thomas Sjolshagen)
     654- BUG FIX: Separate CHANGELOG and README file generation (Thomas Sjolshagen)
     655- BUG FIX: Updated README info (v3.0.5 for WP 5.7.2) (Thomas Sjolshagen)
     656- BUG FIX: Updated version (v3.0.5 for WP 5.7.2) (Thomas Sjolshagen)
     657- BUG FIX: Didn't include a README.md file for the plugin (Thomas Sjolshagen)
     658- BUG FIX: Update repository name (Thomas Sjolshagen)
     659- BUG FIX: Action triggered twice (Thomas Sjolshagen)
     660- Bug fix/remove debug logging (#6) (Thomas Sjølshagen)
     661- BUG FIX: Re-activate the installed_paths setting for phpcs (Thomas Sjolshagen)
  • pmpro-import-members-from-csv/trunk/README.txt

    r2555218 r2563515  
    44Requires at least: 5.0
    55Tested up to: 5.7.2
    6 Stable tag: 3.0.4
     6Stable tag: 3.0.6
    77License: GPLv2
    88License URI: http://www.gnu.org/licenses/gpl
    99
    10 Import and create user + PMPro member records from a CSV file to your WordPress with Paid Memberships Pro website. Can import the membership information, user meta data, PMPro order data and will link any pre-existing recurring payment records for your payment gateway integration.
     10[![Release to wordpress.org](https://github.com/eighty20results/pmpro-import-members-from-csv/actions/workflows/release-plugin.yml/badge.svg)](https://github.com/eighty20results/pmpro-import-members-from-csv/actions/workflows/release-plugin.yml)
     11
     12Import and create user + PMPro member records from a CSV file on your WordPress with Paid Memberships Pro website.
     13The plugin will import the membership information, user meta data, PMPro order data, Sponsored Members information and
     14can even link pre-existing recurring payment records for your payment gateway integration.
    1115
    1216== Description ==
    1317
    14 ![Release to wordpress.org](https://github.com/eighty20results/pmpro-import-members-from-csv/workflows/Release%20to%20wordpress.org/badge.svg?branch=main)
    15 
    16 This plugin is designed to give you an error free import of a user/member to a WordPress/Paid Memberships Pro site. It supports both adding and changing user data.
    17 
    18 Unlike the "Import User From CSV Integration" add-on by Paid Memberships Pro, this "Import Members from CSV" plugin will verify the data you are trying to import during the import operation. This is done to reduce the probability of problem after the import. If there are any errors/issues,information about the problem will be logged to the pmp_updates.log saved in the `wp-content/uploads/` directory.
    19 
    20 *NOTE*: You can run the import multiple times with the same/slightly modified import .csv file and the appropriate settings (see the FAQ/description below). If you configure the plugin settings correctly, this will only result in overwriting/changing the existing member data.
    21 
    22 Using a CSV (Comma Separated Values) file, the will add users with basic user information as well as user meta data fields, the user role (if applicable) and the specified Paid Memberships Pro member configuration/information. It can also generate an order record to ensure your recurring subscriptions continue to get attributed to the imported member.
    23 
    24 If you've exported the user's passwords as hashed strings, you can import them without re-encrypting them again (by setting the option).
     18We designed this plugin to give you an error free import of a user/member to a WordPress/Paid Memberships Pro site.
     19It supports both adding and changing user data.
     20
     21Unlike the "Import User From CSV Integration" add-on by Paid Memberships Pro, this "Import Members from CSV" plugin
     22will verify the data you are trying to import during the import operation. This is done to reduce the probability of
     23problem after the import. If there are any errors/issues, information about the problem will be logged to the
     24`e20r_im_errors.log` saved in the `wp-content/uploads/` directory.
     25
     26**NOTE**: You can run the import multiple times with the same/slightly modified import .csv file and the appropriate
     27settings (see the FAQ/description below). If you configure the plugin settings correctly, this will only result in
     28overwriting/changing the existing member data.
     29
     30Using a CSV (Comma Separated Values) file, the will add users with basic user information as well as user meta data
     31fields, the user role (if applicable) and the specified Paid Memberships Pro member configuration/information. It can
     32also generate an order record to ensure your recurring subscriptions continue to get attributed to the imported member.
     33
     34If you've exported the user's passwords as hashed strings, you can import them without re-encrypting them again
     35(by setting the option).
    2536
    2637You can also choose to send a notification to the new users and to display password nag on user login.
    2738
    28 This plugin supports Network Activation on a WordPress Multisite (WPMU) installation (see the settings page when using in a multisite configuration)
     39This plugin supports Network Activation on a WordPress Multisite (WPMU) installation (see the settings page when
     40using in a multisite configuration)
     41
    2942[Check out my other plugins.](http://eighty20results.com/wordpress-plugins/)
    3043
     
    4356* Import hashed password for new/updating users (if the option is selected)
    4457
    45 *NOTE*: The plugin may not import some of data if it detects a problem. To find out what the problem was, read this documentation and the FAQ section to ensure you have correctly formatted _all_ of your import data.
    46 
    47 For feature request and bug reports, [please use the issues section on GitHub](https://github.com/eighty20results/import-members-from-csv/issues).
    48 Code contributions are welcome [on Github](https://github.com/eighty20results/import-members-from-csv).
    49 
    50 NOTE: In order to hide the "Donation" button after a donation, this plugin will attempt to track the admin's IP address. This action may have GDPR implications for you or your administrators.
    51 
    52 The tracking information is stored in the WordPress options table (wp_options) using the `e20r_import_has_donated` option name and can safely be deleted in the database if you do not wish to leave it. Deleting the option from the database will obviously re-enable the Donation nag.
     58**NOTE**: The plugin may not import some of data if it detects a problem. To find out what the problem was, read this
     59documentation and the FAQ section to ensure you have correctly formatted _all_ of your import data.
     60
     61For feature request and bug reports, [please use the issues section on GitHub](https://github.com/eighty20results/pmpro-import-members-from-csv/issues).
     62Code contributions are welcome [on Github](https://github.com/eighty20results/pmpro-import-members-from-csv).
     63
     64**NOTE**: In order to hide the "Donation" button after a donation, this plugin will attempt to track the admin's IP
     65address. This action may have GDPR implications for you or your administrators.
     66
     67The tracking information is stored in the WordPress options table (wp_options) using the `e20r_import_has_donated`
     68option name and can safely be deleted in the database if you do not wish to leave it. Deleting the option from the
     69database will obviously re-enable the Donation nag.
    5370
    5471The Nag tracking can be disabled altogether with the `e20r_import_donation_tracking_disabled` filter:
     
    6885Or use a nifty tool by WordPress lead developer Mark Jaquith:
    6986
    70 1. Visit [this link](http://coveredwebservices.com/wp-plugin-install/?plugin=pmpro-import-members-from-csv) and follow the instructions.
     871. Visit [this link](http://coveredwebservices.com/wp-plugin-install/?plugin=pmpro-import-members-from-csv) and
     88follow the instructions.
    7189
    7290
     
    831011. Upload your CSV file in the 'Memberships' menu, under 'Import Members'
    84102
    85 == Frequently Asked Questions ==
    86 
    87 = How to use? =
     103= Frequently Asked Questions =
     104
     105== How to use? ==
    88106
    89107Click on the 'Import Members' link in the 'Membership' menu, then select your CSV file.
    90108Next you have to decide whether you:
    91109
    92 1. want to deactivate previously existing member record(s) for the user - The CSV record has to specify the same membership as the user previously had so this is most useful when having to reimport/update data (default: enabled and recommended),
    93 1. update the existing user/member's information (default: enabled and recommended)
    94 1. send a notification email to new users (default: disabled),
    95 1. want the password nag to be displayed when the user logs in (default: disabled),
    96 1. have included a hashed (encoded) password specified in the import file and (default: disabled)
    97 1. want to use the background import option (default: enabled and recommended)
    98 1. create a PMPro order record based on supplied payment info in the .csv file (default: disabled)
     1101. want to deactivate previously existing member record(s) for the user - The CSV record has to specify the same
     111membership as the user previously had so this is most useful when having to reimport/update data (default: enabled and
     112recommended),
     1132. update the existing user/member's information (default: enabled and recommended)
     1143. send a notification email to new users (default: disabled),
     1154. want the password nag to be displayed when the user logs in (default: disabled),
     1165. have included a hashed (encoded) password specified in the import file and (default: disabled)
     1176. want to use the background import option (default: enabled and recommended)
     1187. create a PMPro order record based on supplied payment info in the .csv file (default: disabled)
    99119
    100120Then click the 'Import' button.
    101121
    102122Each row in your CSV file should represent a user; each column identifies user data, user meta data or user membership data
    103 If a column name matches a field in the user table, data from this column is imported in that field; if not, data is imported in a user meta field with the name of the column or into the PMPro custom membership tables.
    104 
    105 Look at the examples/import.csv file in the plugin directory (also linked on the "Import Members" page) to have a better understanding of how the your CSV file should be organized and what the data fields need to contain as far as formatting/values go.
    106 
    107 You can always try importing the examples/import.csv file and look at the result, assuming the values specified for the membership_id in the example file match your membership level configuration.
    108 
    109 = The .CSV file from the "Export to CSV" button on the "Members List" page won't import? =
    110 
    111 The purpose of the resulting .CSV file from the "Export to CSV" is to generate reports that are meaningful to a human, not a file that can be imported easily. This is true for any of the available Import from .CSV plugins/add-ons for Paid Memberships Pro.
    112 
    113 Basically there are a few key differences between the file resulting from the Export function and the file contents needed to import the same member.
     123If a column name matches a field in the user table, data from this column is imported in that field; if not, data is
     124imported in a user meta field with the name of the column or into the PMPro custom membership tables.
     125
     126Look at the examples/import.csv file in the plugin directory (also linked on the "Import Members" page) to have a
     127better understanding of how the your CSV file should be organized and what the data fields need to contain as far as
     128formatting/values go.
     129
     130You can always try importing the examples/import.csv file and look at the result, assuming the values specified for the
     131membership_id in the example file match your membership level configuration.
     132
     133== The .CSV file from the "Export to CSV" button on the "Members List" page won't import? ==
     134
     135The purpose of the resulting .CSV file from the "Export to CSV" is to generate reports that are meaningful to a human,
     136not a file that can be imported easily. This is true for any of the available Import from .CSV plugins/add-ons for
     137Paid Memberships Pro.
     138
     139Basically there are a few key differences between the file resulting from the Export function and the file contents
     140needed to import the same member.
    114141
    115142As of version 2.5, this plugin includes data checks for some of the more common mistakes I've seen in the .CSV file(s).
     
    117144You should also check out the import example file that is linked on the "Import Members" page (under the "Choose File" button).
    118145
    119 = My import fails, what is wrong? =
    120 
    121 This is almost always related to the data in the file being imported. As a result, I've added some data tests for some of the typical mistakes I've seen in the .CSV file(s) being imported. There is also a link to an example file on the "Import Members" page (under the "Choose File" button) that illustrates a functional import file. Things lik what the field names are and the format you'll most likely need to use for the data in that column.
    122 
    123 Check the wp-content/uploads/pmp_im_errors.log log file for details on the import operations (link should also be included in a wp-admin dashboard notice if there are errors/warnings). The log should contain suggestions on some of the more common mistakes in the data being imported.
    124 
    125 = Do I need to include all the columns from the sample file? =
    126 
    127 No. _Only_ include the columns where you have data to import. I.e, if none of your members need to have their membership end date defined (i.e the membership you're importing doesn't have an expiration or it's a recurring membership with a linked Payment Gateway subscription plan), just remove the column(s) you don't need. That way, the plugin doesn't try to import data that isn't there.
     146== My import fails, what is wrong? ==
     147
     148This is almost always related to the data in the file being imported. As a result, I've added some data tests for some
     149of the typical mistakes I've seen in the .CSV file(s) being imported. There is also a link to an example file on the
     150"Import Members" page (under the "Choose File" button) that illustrates a functional import file. Things lik what the
     151field names are and the format you'll most likely need to use for the data in that column.
     152
     153Check the wp-content/uploads/pmp_im_errors.log log file for details on the import operations (link should also be
     154included in a wp-admin dashboard notice if there are errors/warnings). The log should contain suggestions on some of
     155the more common mistakes in the data being imported.
     156
     157== Do I need to include all the columns from the sample file? ==
     158
     159No. __Only__ include the columns where you have data to import. I.e, if none of your members need to have their
     160membership end date defined (i.e the membership you're importing doesn't have an expiration or it's a recurring
     161membership with a linked Payment Gateway subscription plan), just remove the column(s) you don't need. That way,
     162the plugin doesn't try to import data that isn't there.
    128163
    129164If a column has no data, you should remove the column and it's column header from the import file!
    130165
    131 = The plugin didn't import any membership data!?! =
    132 
    133 This is a pretty common question and the reason is almost always because there is something unexpected in the `membership_` portion of the row being imported.
    134 
    135 Most often it's the date/time format for the membership_startdate and membership_enddate columns.
     166== The plugin didn't import any membership data!?! ==
     167
     168This is a pretty common question and the reason is almost always because there is something unexpected in the
     169`membership_` portion of the row being imported.
     170
     171Most often it's the date/time format for the `membership_startdate` and `membership_enddate` columns.
    136172
    137173If you use MS Excel(tm) to prepare your .CSV file, you're in for a treat...
    138174
    139 In my experience, MS Excel(tm) is _really_ good at changing the date format in a spreadsheet column to whatever it thinks works best (i.e. human readable).
    140 
    141 However, human readable is often problematic for CSV imports, so you *have to ensure* the format follows the YYYY-MM-DD HH:ii:ss (where ii = 2 digit minute value). For startdate I'd recommend using `00:00:00` and for the enddate I'd suggest using `23:59:59`.
    142 
    143 Just to be clear: The _only_ date format for the *membership_startdate*, *membership_enddate* and the *user_registered* columns that this plugin will accept is the MySQL datetime format: YYYY-MM-DD HH:ii:ss.
     175In my experience, MS Excel(tm) is _really_ good at changing the date format in a spreadsheet column to whatever it
     176thinks works best (i.e. human readable). (If my sarcasm doesn't shine through; This actually __isn't__ a good thing!)
     177
     178However, human readable is often problematic for CSV imports, so you **have to make sure** the date format follows the
     179`YYYY-MM-DD HH:ii:ss` template (where ii = 2 digit minute value). For startdate I'd recommend using `00:00:00` and
     180for the enddate I'd suggest using `23:59:59`.
     181
     182Just to be clear: The __only__ date format for the `membership_startdate`, `membership_enddate` and the
     183`user_registered` columns that this plugin will accept is the MySQL datetime format: YYYY-MM-DD HH:ii:ss.
    144184
    145185*Use anything else and your membership data will not be imported*!
    146186
    147 You can change the way Microsoft Excel(tm) handles date and time data in the Regional settings, but I've yet to figure out what the ideal settings are here. Truth be told, I'm using Apple Numbers and others have had great success using Google Sheets to process and export their .CSV files. Because there are alternatives to Microsoft Excel(tm) and they seem to work a lot better for this specific task, I'm not at all inclined to spend more time on fixing something that I view to be a rather significant "bug"[1] in Excel(tm).
    148 
    149  [1] = Being that it's an intentional usability feature, I realize Microsoft is unlikely to be all that interested in fixing this "as designed" capability they've implemented.
    150 = Can this plugin be used to link sponsored members with their sponsors? =
     187You can change the way Microsoft Excel(tm) handles date and time data in the Regional settings, but I've yet to
     188figure out what the ideal settings are here. Truth be told, I'm using Apple Numbers and others have had great
     189success using Google Sheets to process and export their .CSV files. Because there are alternatives to Microsoft
     190Excel(tm) and they seem to work a lot better for this specific task, I'm not at all inclined to spend more time
     191on fixing something that I view to be a rather significant "bug"[1] in Excel(tm).
     192
     193 [1] = Being that it's an intentional usability feature, I realize Microsoft is unlikely to be all that interested
     194 in fixing this "as designed" capability they've implemented.
     195
     196== Can this plugin be used to link sponsored members with their sponsors? ==
    151197
    152198Yes.
    153199
    154 In version 2.60, we added support for importing Sponsors and their sponsored members. So, if you have the PMPro Sponsored Members add-on installed, active and need to link sponsors and their sponsored members during the import with this plugin.
     200In version 2.60, we added support for importing Sponsors and their sponsored members. So, if you have the
     201PMPro Sponsored Members add-on installed, active and need to link sponsors and their sponsored members
     202during the import with this plugin.
    155203
    156204== Importing the Sponsored user ==
     
    158206To link sponsored users with their sponsors, add the `pmprosm_sponsor` column to your import file.
    159207
    160 On the data row for the _sponsored_ user, the pmprosm_sponsor column must contain the user key for the sponsor you want to link them with.
     208On the data row for the __sponsored__ user, the `pmprosm_sponsor` column must contain the user key for the sponsor
     209you want to link them with.
    161210
    162211Or, if they don't have a sponsor, that column must be blank.
    163212
    164 The sponsor key is either the email address they used when registering on your system - or the user_email column value for their user record if they're also being imported at the same time, the WordPress user ID value (numeric), or the login name used (user_login value).
     213The sponsor key is either the email address they used when registering on your system - or the user_email column
     214value for their user record if they're also being imported at the same time, the WordPress user ID value (numeric),
     215or the login name used (user_login value).
    165216
    166217== Importing the Sponsor ==
    167218
    168 First of all, you will need to include a `pmprosm_seats` column as well. This column contains a numeric value to indicate the number of seats (sponsored users) this user has paid to sponsor.
     219First of all, you will need to include a `pmprosm_seats` column as well. This column contains a numeric value to
     220indicate the number of seats (sponsored users) this user has paid to sponsor.
    169221
    170222When importing a sponsor there are a couple of scenarios;
    171223
    172 1) The system already contains the sponsor code (a sponsor code is a PMPro discount code prefixed with the letter 'S') and you simply need to link the sponsor to their code.
     2241) The system already contains the sponsor code (a sponsor code is a PMPro discount code prefixed with the letter 'S')
     225and you simply need to link the sponsor to their code.
    173226
    1742272) The system lacks the sponsor code, so you'll need one to be created.
    175228
    176 For scenario 1; The sponsor code (discount code) already has a Discount Code ID (integer value, found on the PMPro "Discount Codes" settings page). This ID needs to be added in the `membership_code_id` column of the import file for the sponsor (user record), along with a numeric value in the `pmprosm_seats` column.
    177 
    178 For scenario 2; The sponsor code is created by this plugin. It happens automatically if the sponsor user exists - or is being imported at the same time as - when the *sponsored* user is attempted imported and linked. The discount code created attempts to use the settings from the PMPro Sponsored Members add-on for the discount code.
     229For scenario 1; The sponsor code (discount code) already has a Discount Code ID (integer value, found on the PMPro
     230"Discount Codes" settings page). This ID needs to be added in the `membership_code_id` column of the import file for
     231the sponsor (user record), along with a numeric value in the `pmprosm_seats` column.
     232
     233For scenario 2; The sponsor code is created by this plugin. It happens automatically if the sponsor user exists - or
     234is being imported at the same time as - when the **sponsored** user is attempted imported and linked. The discount
     235code created attempts to use the settings from the PMPro Sponsored Members add-on for the discount code.
    179236
    180237=== Caveat ===
     
    182239The order in which users are listed in the .csv import file can matter when importing sponsors and their sponsored user.
    183240
    184 Although this plugin tries to re-import sponsored users if the import fails the first time, as part of the clean-up process, this retry does not guarantee success!
     241Although this plugin tries to re-import sponsored users if the import fails the first time, as part of the
     242clean-up process, this retry does not guarantee success!
    185243
    186244As a result, it is possible that a sponsored user is imported without being linked to their sponsor.
     
    198256As of version 2.20, we have an option to create member orders at the same time as we update the membership record.
    199257
    200 That means you can now include some of the order table fields to import custom values as needed for each user/member, along with updating/adding their membership level information.
     258That means you can now include some of the order table fields to import custom values as needed for each
     259user/member, along with updating/adding their membership level information.
    201260
    202261The supported order record columns are:
     
    2312901. billing_phone (*)
    232291
    233 All of these columns/fields should be prefixed with 'membership_'. I.e. 'membership_paypal_token' or 'membership_tax', etc. The exceptions are the 'user_id' and 'membership_id' columns/fields which should be left as 'user_id' and 'membership_id' respectively if you want to include them in the import operation(s).
    234 
    235 The 'status' column has a limited number of valid values. By default, we recommend using either 'success' or 'cancelled'
    236 
    237 All timestamp values ('timestamp') must use the same format as the one used by the MySQL database's 'DATETIME' format: `YYYY-MM-DD HH:MM:SS`
    238 
    239 *PLEASE NOTE:*
    240 
    241 Although you _can_ specify an account number (accountnumber) in the import file, doing that will *not* result in this plugin importing and activating subscriptions or payments by credit card.
    242 
    243 You CANNOT use this tool to import and *create* subscription plans, or transactions, on the payment gateway for your Paid Memberships Pro users.
    244 
    245 Including anything other than a masked Credit Card number for the "membership_accountnumber" column *is a really bad idea*[1]!
    246 
    247 A masked credit card number = Only the last 4 digits are real and the rest are repetitions of the 'X' character (XXXXXXXXXXXX1234).
    248 
    249 [1] = Importing a full credit card number will exponentially increase the probability that you, in the event of a security problem on your site, will have to pay the Payment Card Industry (PCI) massive fines. Simply put; Don't import Credit Card information! Instead, ask your members to resubmit their information when the site is back online/live.
    250 
    251 *This plugin does NOT mask your credit card numbers for you!*
    252 
    253 = Supported membership_gateway options =
    254 
    255 The Import Members from CSV plugin supports specifying different payment gateways for the user record(s) when importing order data (i.e. the "Attempt to create PMPro Order record" option has been selected). At present, the payment gateways that can be specified in the `membership_gateway` column are:
     292All of these columns/fields should be prefixed with `membership_`. I.e. `membership_paypal_token` or `membership_tax`,
     293etc. The exceptions are the `user_id` and `membership_id` columns/fields which should be left as `user_id` and
     294`membership_id` respectively if you want to include them in the import operation(s).
     295
     296The `status` column has a limited number of valid values. By default, we recommend using either `success` or `cancelled`
     297
     298All timestamp values ('timestamp') must use the same format as the one used by the MySQL database's 'DATETIME'
     299format: `YYYY-MM-DD HH:MM:SS`
     300
     301**PLEASE NOTE:**
     302
     303Although you _can_ specify an account number (`accountnumber`) in the import file, doing that will *not* result in
     304this plugin importing and activating subscriptions or payments by credit card.
     305
     306You CANNOT use this tool to import and **create** subscription plans, or transactions, on the payment gateway for
     307your Paid Memberships Pro users.
     308
     309Including anything other than a masked Credit Card number for the `membership_accountnumber` column *is a really
     310bad idea*[1]!
     311
     312A masked credit card number = Only the last 4 digits are real and the rest are repetitions of the 'X'
     313character (`XXXXXXXXXXXX1234`).
     314
     315[1] = Importing a full credit card number will exponentially increase the probability that you, in the event of a
     316security problem on your site, will have to pay the Payment Card Industry (PCI) massive fines. Simply put; Don't import
     317Credit Card information! Instead, ask your members to resubmit their information when the site is back online/live.
     318
     319**This plugin does NOT mask your credit card numbers for you!**
     320
     321== Supported membership_gateway options ==
     322
     323The Import Members from CSV plugin supports specifying different payment gateways for the user record(s) when
     324importing order data (i.e. the "Attempt to create PMPro Order record" option has been selected). At present, the
     325payment gateways that can be specified in the `membership_gateway` column are:
    256326
    2573271. authorizenet
    258 1. braintree
    259 1. check
    260 1. cybersource
    261 1. payflowpro
    262 1. paypal
    263 1. paypalexpress
    264 1. paypalstandard
    265 1. stripe
    266 1. twocheckout
    267 
    268 During the import operation, the plugin will verify that the specified payment gateway integration is one of the supported payment gateway integrations for Paid Memberships Pro.
    269 
    270 Specifying a Payment Gateway Integration that has not been configured for use during the PMPro checkout process would render the order record invalid.
    271 
    272 NOTE: The limitations to how Paid Memberships Pro supports/handles multiple payment gateway integrations at the same time still apply.
    273 
    274 = Adding billing address information to the PMPro Order import =
    275 
    276 The normal way to import billing address data to the database for a member/user is to use the `pmpro_b[*]` fields (pmpro_bfirstname, pmpro_blastname, pmpro_baddress1, pmpro_baddress2, pmpro_bcity, pmpro_bstate, pmpro_bzipcode, pmpro_bcountry and pmpro_bphone).
    277 
    278 If the pmpro_b* field data is present in the row and the 'Add order' option is selected for the import file, the import will attempt to populate the order billing information using the pmpro_b* data.
     3282. braintree
     3293. check
     3304. cybersource
     3315. payflowpro
     3326. paypal
     3337. paypalexpress
     3348. paypalstandard
     3359. stripe
     33610. twocheckout
     33711. payfast
     338
     339During the import operation, the plugin will verify that the specified payment gateway integration is one of the
     340supported payment gateway integrations for Paid Memberships Pro.
     341
     342Specifying a Payment Gateway Integration that has not been configured for use during the PMPro checkout process would
     343render the order record invalid.
     344
     345**NOTE:** The limitations to how Paid Memberships Pro supports/handles multiple payment gateway integrations at the
     346same time still apply.
     347
     348== Adding billing address information to the PMPro Order import ==
     349
     350The normal way to import billing address data to the database for a member/user is to use the `pmpro_b[*]` fields
     351(`pmpro_bfirstname`, `pmpro_blastname`, `pmpro_baddress1`, `pmpro_baddress2`, `pmpro_bcity`, `pmpro_bstate`,
     352`pmpro_bzipcode`, `pmpro_bcountry` and `pmpro_bphone`).
     353
     354If the `pmpro_b*` field data is present in the row and the 'Add order' option is selected for the import file, the
     355import will attempt to populate the order billing information using the `pmpro_b*` data.
    279356
    280357= How should the .csv file be defined? =
     
    287364
    288365For example;
    289 To have a 2 column .csv file, each row **after** the header row, the row should look something like this: `"my first column data","my second \"escaped\" column data"`.
    290 
    291 The application you use to edit and export your .CSV file will need to be configured appropriately before you export the .csv file.
     366To have a 2 column .csv file, each row **after** the header row, the row should look something like this:
     367`"my first column data","my second \"escaped\" column data"`.
     368
     369The application you use to edit and export your .CSV file will need to be configured appropriately before you
     370export the .csv file.
    292371
    293372= Why am I or my users not receiving New user notifications =
    294373
    295 There are a couple of possible reasons, as far as I can tell. The functionality in WordPress that generates the "new user notification" message is what they call "pluggable". That means that it's possible for a plugin (any plugin!) to override the behavior of the functionality. So the first thing I'd suggest investigating is whether you have a pluing active that intentionally changes/modifies/updates how the `wp_new_user_notification()` function works/behaves.
    296 
    297 Next, it's (very) possible that your hosting environment doesn't want you to be sending out a lot of email messages from their servers. As a result, the import operation could potentially trip their anti-spam measures and blocking you from sending any messages.
    298 
    299 Third, the recipient email server may be using a SBL (Spam Black List) and have your web server IP listed as a typical source of Spam messages (it happens, a lot).
    300 
    301 = I've set the 'membership_status' column to 'inactive', but the user's imported membership level is currently 'active'? =
     374There are a couple of possible reasons, as far as I can tell. The functionality in WordPress that generates the
     375"new user notification" message is what they call "pluggable". That means that it's possible for a plugin (any plugin!)
     376to override the behavior of the functionality. So the first thing I'd suggest investigating is whether you have a
     377plugin active that intentionally changes/modifies/updates how the `wp_new_user_notification()` function works/behaves.
     378
     379Next, it's (very) possible that your hosting environment doesn't want you to be sending out a lot of email messages
     380from their servers. As a result, the import operation could potentially trip their anti-spam measures and blocking
     381you from sending any messages.
     382
     383Third, the recipient email server may be using a SBL (Spam Black List) and have your web server IP listed as a
     384typical source of Spam messages (it happens, a lot).
     385
     386== I've set the 'membership_status' column to 'inactive', but the user's imported membership level is currently 'active'? ==
    302387
    303388This is due to what I'd term a bug in Paid Memberships Pro. This issue doesn't currently have a fix.
    304389
    305 Basically, the 'inactive' status will only apply to the order record (if it's created, see above) and *not* to the user's membership status.
    306 
    307 NOTE: Assigning a membership level for a user will cause them to be given an active membership on the site when the import operation is complete, regardless of the value supplied for the 'membership_status' column.
    308 
    309 = How do I import an existing payment plan (recurring billing plan) for a user? =
     390Basically, the 'inactive' status will only apply to the order record (if it's created, see above) and *not* to the
     391user's membership status.
     392
     393**NOTE:** Assigning a membership level for a user will cause them to be given an active membership on the site when
     394the import operation is complete, regardless of the value supplied for the 'membership_status' column.
     395
     396== How do I import an existing payment plan (recurring billing plan) for a user? ==
    310397
    311398This only works if the plan already exists on the payment gateway itself.
    312399
    313 There is no way to use this plugin to import a new member/user and have the system create a recurring billing plan for them.
    314 
    315 = Can I use this plugin to create new billing plans or trigger charges on the payment gateway for an imported user? =
     400There is no way to use this plugin to import a new member/user and have the system create a recurring billing plan
     401for them.
     402
     403== Can I use this plugin to create new billing plans or trigger charges on the payment gateway for an imported user? ==
    316404
    317405No.
    318406
    319 = What are the constraints for WordPress Multisite import operations? =
     407== What are the constraints for WordPress Multisite import operations? ==
    320408
    321409As documented by Paid Memberships Pro, the PMPro plugin cannot be Network Activated.
    322410
    323 This import plugin will work from the site(s) where PMPro is active _and_ have the same membership level IDs identified as are listed in the `membership_id` column of the import file you're using.
    324 
    325 If your primary site has a configured and active Paid Memberships Pro installation, you could theoretically start the plugin from the Network Admin dashboard (which will send you to the primary site anyway).
    326 
    327 The users being imported will only be linked to the site you import them to. Their membership data will only be visible on the PMPro site(s) that have the membership level ID(s) configured that match those in the import file.
     411This import plugin will work from the site(s) where PMPro is active _and_ have the same membership level IDs
     412identified as are listed in the `membership_id` column of the import file you're using.
     413
     414If your primary site has a configured and active Paid Memberships Pro installation, you could theoretically start
     415the plugin from the Network Admin dashboard (which will send you to the primary site anyway).
     416
     417The users being imported will only be linked to the site you import them to. Their membership data will only be
     418visible on the PMPro site(s) that have the membership level ID(s) configured that match those in the import file.
    328419
    329420= Welcome Email Message (imported_welcome.html template) issues =
     
    332423please make sure the 'membership_status' field is included in the import .csv file and contains the `active` value.
    333424
    334 As a design philosophy, we treat an inactive member as somebody who should _not_  receive welcome messages (you may disagree..?)
    335 
    336 = What GDPR impacted data is stored by this plugin? =
    337 
    338 Obviously, there's the user data that this plugin is designed to import. This plugin does _not_ track, report, or allow download/deletion of any data it imports. There are (now or soon) other plugin options to handle those requirements from the GDPR legislation.
    339 
    340 In an attempt to make the "Donation" button less intrusive, we attempt to track the computer (IP) address when somebody clicks the button. This plugin does _not_ link the IP address to a user account, so it should be a little more challenging to identify the person who clicked the "Donate" button for any 3rd party who gets access to your database than simply looking at the options saved by this plugin.
    341 
    342 The IP tracking information (the IP address) is stored in the WordPress options table (`wp_options`) using the `e20r_import_has_donated` option name. That option can safely be deleted in the database if you do not wish to have IPs tracked. Deleting the option from the database will obviously re-enable the Donation nag.
    343 
    344 As long as this plugin remains installed and active on the server, the tracked IP address will automatically be removed from the option 2 months after the admin clicked the Donation button.
     425As a design philosophy, we treat an inactive member as somebody who should _not_  receive welcome messages
     426(you may disagree..?)
     427
     428== What GDPR impacted data is stored by this plugin? ==
     429
     430Obviously, there's the user data that this plugin is designed to import. This plugin does _not_ track, report, or
     431allow download/deletion of any data it imports. There are (now or soon) other plugin options to handle those
     432requirements from the GDPR legislation.
     433
     434In an attempt to make the "Donation" button less intrusive, we attempt to track the computer (IP) address when
     435somebody clicks the button. This plugin does _not_ link the IP address to a user account, so it should be a little
     436more challenging to identify the person who clicked the "Donate" button for any 3rd party who gets access to your
     437database than simply looking at the options saved by this plugin.
     438
     439The IP tracking information (the IP address) is stored in the WordPress options table (`wp_options`) using the
     440`e20r_import_has_donated` option name. That option can safely be deleted in the database if you do not wish to have
     441IPs tracked. Deleting the option from the database will obviously re-enable the Donation nag.
     442
     443As long as this plugin remains installed and active on the server, the tracked IP address will automatically be
     444removed from the option 2 months after the admin clicked the Donation button.
    345445
    346446The option is removed when the plugin is deactivated in the "Plugins" admin panel.
    347447
    348 Nag tracking can be disabled altogether with the `e20r_import_donation_tracking_disabled` filter: `add_filter( 'e20r_import_donation_tracking_disabled', '__return_true' );'`
     448Nag tracking can be disabled altogether with the `e20r_import_donation_tracking_disabled` filter:
     449`add_filter( 'e20r_import_donation_tracking_disabled', '__return_true' );'`
    349450
    350451== Installation ==
    351452
    3524531. Upload the `pmpro-import-members-from-csv` folder to the `/wp-content/plugins/` directory.
    353 1. Activate the plugin through the 'Plugins' menu in WordPress.
     4542. Activate the plugin through the 'Plugins' menu in WordPress.
    354455
    355456== Screenshots ==
    356457
    3574581. User import screen
    358 1. Ongoing (background) import screen
    359 1. Default settings on the user import screen
     4592. Ongoing (background) import screen
     4603. Default settings on the user import screen
    360461
    361462== Known Issues ==
     
    369470== Supported Filters and Actions ==
    370471
    371 The list of filters and actions supported by this plugin can be found in the [Filters](./docs/FILTERS.md) and [Actions](./docs/ACTIONS.md) documentation.
     472The list of filters and actions supported by this plugin can be found in the [Filters](./docs/FILTERS.md) and
     473[Actions](./docs/ACTIONS.md) documentation.
  • pmpro-import-members-from-csv/trunk/class.pmpro-import-members.php

    r2555218 r2563515  
    1 <?php
     1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
    22/**
    33Plugin Name: Import Paid Memberships Pro Members from CSV
    44Plugin URI: http://wordpress.org/plugins/pmpro-import-members-from-csv/
    55Description: Import Users and their metadata from a csv file.
    6 Version: 3.0.4
     6Version: 3.0.6
    77Requires PHP: 7.3
    88Author: <a href="https://eighty20results.com/thomas-sjolshagen/">Thomas Sjolshagen <[email protected]></a>
     
    4242use function plugin_dir_path;
    4343use function add_action;
    44 use function error_log;
     44use function error_log; // phpcs:ignore
    4545
    4646if ( ! defined( 'E20R_IM_CSV_DELIMITER' ) ) {
     
    5555
    5656if ( ! defined( 'E20R_IMPORT_VERSION' ) ) {
    57     define( 'E20R_IMPORT_VERSION', '3.0.4' );
    58 }
    59 
    60 require_once plugin_dir_path( __FILE__ ) . '/ActivateUtilitiesPlugin.php';
     57    define( 'E20R_IMPORT_VERSION', '3.0.6' );
     58}
     59
     60require_once plugin_dir_path( __FILE__ ) . 'class-activateutilitiesplugin.php';
    6161
    6262/**
     
    107107        foreach ( $base_paths as $base_path ) {
    108108
    109             $iterator = new RecursiveDirectoryIterator(
    110                 $base_path,
    111                 RecursiveDirectoryIterator::SKIP_DOTS |
    112                 RecursiveIteratorIterator::SELF_FIRST |
    113                 RecursiveIteratorIterator::CATCH_GET_CHILD |
    114                 RecursiveDirectoryIterator::FOLLOW_SYMLINKS
    115             );
    116 
    117             $filter = new RecursiveCallbackFilterIterator(
    118                 $iterator,
    119                 function ( $current, $key, $iterator ) use ( $filename ) {
    120 
    121                     // Skip hidden files and directories.
    122                     if ( $current->getFilename()[0] === '.' || $current->getFilename() === '..' ) {
    123                         return false;
     109            try {
     110                $iterator = new RecursiveDirectoryIterator(
     111                    $base_path,
     112                    RecursiveDirectoryIterator::SKIP_DOTS |
     113                    RecursiveIteratorIterator::SELF_FIRST |
     114                    RecursiveIteratorIterator::CATCH_GET_CHILD |
     115                    RecursiveDirectoryIterator::FOLLOW_SYMLINKS
     116                );
     117            } catch ( \Exception $e ) {
     118                print 'Error: ' . $e->getMessage(); // phpcs:ignore
     119                return;
     120            }
     121
     122            try {
     123                $filter = new RecursiveCallbackFilterIterator(
     124                    $iterator,
     125                    function ( $current, $key, $iterator ) use ( $filename ) {
     126
     127                        // Skip hidden files and directories.
     128                        if ( '.' === $current->getFilename()[0] || '..' === $current->getFilename() ) {
     129                            return false;
     130                        }
     131
     132                        if ( $current->isDir() ) {
     133                            // Only recurse into intended subdirectories.
     134                            return $current->getFilename() === $filename;
     135                        } else {
     136                            // Only consume files of interest.
     137                            return str_starts_with( $current->getFilename(), $filename );
     138                        }
    124139                    }
    125 
    126                     if ( $current->isDir() ) {
    127                         // Only recurse into intended subdirectories.
    128                         return $current->getFilename() === $filename;
    129                     } else {
    130                         // Only consume files of interest.
    131                         return str_starts_with( $current->getFilename(), $filename );
    132                     }
    133                 }
    134             );
     140                );
     141            } catch ( \Exception $e ) {
     142                echo 'Autoloader error: ' . $e->getMessage(); // phpcs:ignore
     143                return;
     144            }
    135145
    136146            foreach ( new RecursiveIteratorIterator( $iterator ) as $f_filename => $f_file ) {
  • pmpro-import-members-from-csv/trunk/docker-compose.yml

    r2554806 r2563515  
    1919    ports:
    2020      - ${WP_PORT}:80
     21    stdin_open: true # docker run -i
     22    tty: true        # docker run -t
    2123    command:
    2224      - /bin/sh
     
    5759      MYSQL_RANDOM_ROOT_PASSWORD: ${MYSQL_RANDOM_ROOT_PASSWORD}
    5860    volumes:
    59       - ${LOCAL_PLUGIN_DIR}:/docker-entrypoint-initdb.d
     61      - ${LOCAL_PLUGIN_DIR}/tests/_data:/docker-entrypoint-initdb.d
  • pmpro-import-members-from-csv/trunk/javascript/pmpro-import-members-from-csv.js

    r2554806 r2563515  
    11/**
    2  * Copyright (c) 2018-2019 - Eighty / 20 Results by Wicked Strong Chicks.
     2 * Copyright (c) 2018 - 2021 - Eighty / 20 Results by Wicked Strong Chicks.
    33 * ALL RIGHTS RESERVED
    44 *
  • pmpro-import-members-from-csv/trunk/src/class-data.php

    r2554806 r2563515  
    8282        // Add PMPro info as applicable
    8383        if ( ! empty( $user ) ) {
     84            // @phpstan-ignore-next-line
    8485            $user->membership_level = (
    8586            function_exists( 'pmpro_getMembershipLevelForUser' ) ?
     
    8889            );
    8990
     91            // @phpstan-ignore-next-line
    9092            $user->membership_levels = (
    9193            function_exists( 'pmpro_getMembershipLevelsForUser' ) ?
     
    332334
    333335        if ( ! in_array( $billing_field_name, array_keys( $billing_fields ), true ) ) {
    334             return null;
     336            return false;
    335337        }
    336338
  • pmpro-import-members-from-csv/trunk/src/class-email-templates.php

    r2554806 r2563515  
    7676
    7777        // Email 'your membership account is active' to member if they were imported with an active member status
    78         if ( true === (bool) $send_email &&
    79              isset( $fields['membership_status'] ) && 'active' === $fields['membership_status'] &&
    80              1 === version_compare( PMPRO_VERSION, '1.9.5' )
     78        if (
     79            true === (bool) $send_email &&
     80            isset( $fields['membership_status'] ) && 'active' === $fields['membership_status'] &&
     81            // @phpstan-ignore-next-line
     82            1 === version_compare( PMPRO_VERSION, '1.9.5' )
    8183        ) {
    8284            $subject = null;
     
    103105            $this->error_log->debug( "Using {$template_name} template for '{$subject}' message" );
    104106
     107            // PMPro is not good at defining properties in classes (badly reliant on the historically dynamic nature of PHP)
     108            // so will have PHPStan ignore these lines until PMPro cleans up their stuff
     109            // (i.e. TODO when PMPro takes better advantage of PHP)
    105110            $email           = new \PMProEmail();
    106             $email->email    = $user->user_email;
    107             $email->data     = apply_filters( 'pmp_im_imported_member_message_data', array() );
    108             $email->subject  = $subject;
    109             $email->template = $template_name;
     111            $email->email    = $user->user_email; // @phpstan-ignore-line
     112            $email->data     = apply_filters( 'pmp_im_imported_member_message_data', array() ); // @phpstan-ignore-line
     113            $email->subject  = $subject; // @phpstan-ignore-line
     114            $email->template = $template_name; // @phpstan-ignore-line
    110115
    111116            if ( ! empty( $body ) ) {
    112                 $email->body = $body;
     117                $email->body = $body; // @phpstan-ignore-line
    113118            } else {
    114                 $email->body = $this->load_email_body( null, $email->template );
     119                $email->body = $this->load_email_body( null, $email->template ); // @phpstan-ignore-line
    115120            }
    116121
    117122            $email->body = apply_filters( 'pmp_im_imported_member_message_body', $email->body );
     123            $email->body = apply_filters( 'e20r_import_member_message_body', $email->body );
    118124
    119125            // Process and send email
     
    228234            foreach ( $locations as $path ) {
    229235                if ( true === file_exists( $path ) ) {
    230                     $body = file_get_contents( $path );
     236                    $body = file_get_contents( $path ); // phpcs:ignore
    231237                    break;
    232238                }
     
    265271            'subject'     => __( 'Welcome to my new website', 'pmpro-import-members-from-csv' ),
    266272            'description' => __( 'Import: Welcome Member', 'pmpro-import-members-from-csv' ),
     273            // phpcs:ignore
    267274            'body'        => file_get_contents( Import_Members::$plugin_path . '/emails/imported_member.html' ),
    268275        );
  • pmpro-import-members-from-csv/trunk/src/class-error-log.php

    r2554806 r2563515  
    6767                'error'
    6868            );
    69 
     69            return;
    7070        }
    7171
     
    146146     * Identify the calling function (used in debug logger
    147147     *
    148      * @return array|string
     148     * @return string
    149149     *
    150150     * @access public
    151151     */
    152     private function who_called_me() {
     152    private function who_called_me() : string {
    153153        $trace  = debug_backtrace(); // phpcs:ignore
    154154        $caller = $trace[2];
  • pmpro-import-members-from-csv/trunk/src/class-import-members.php

    r2554946 r2563515  
    144144
    145145        if ( false === apply_filters( 'e20r_utilities_module_installed', false ) ) {
    146             add_action( 'init', '\E20R\Import\Loader::is_utilities_module_active', 10 );
    147         }
    148         add_action( 'plugins_loaded', array( Email_Templates::get_instance(), 'load_hooks' ), 99 );
    149         add_action( 'plugins_loaded', array( Ajax::get_instance(), 'load_hooks' ), 99 );
    150         add_action( 'plugins_loaded', array( Page::get_instance(), 'load_hooks' ), 99 );
     146            add_action( 'init', '\E20R\Import\Loader::is_utilities_module_active', 10, 0 );
     147        }
     148        add_action( 'plugins_loaded', array( Email_Templates::get_instance(), 'load_hooks' ), 99, 0 );
     149        add_action( 'plugins_loaded', array( Ajax::get_instance(), 'load_hooks' ), 99, 0 );
     150        add_action( 'plugins_loaded', array( Page::get_instance(), 'load_hooks' ), 99, 0 );
    151151
    152152        // Add validation logic for all modules
    153         add_action( 'plugins_loaded', array( User_Validation::get_instance(), 'load_actions' ), 30 );
    154         add_action( 'plugins_loaded', array( PMPro_Validation::get_instance(), 'load_actions' ), 31 );
    155         add_action( 'plugins_loaded', array( BuddyPress_Validation::get_instance(), 'load_actions' ), 32 );
    156 
    157         add_action( 'init', array( $this, 'load_i18n' ), 5 );
    158         add_action( 'init', array( $this->data, 'process_csv' ) );
    159 
    160         add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
    161 
    162         // PMPro specific import functionality
    163         // phpcs:ignore - We do this in the CSV() class as it's a clean-up operation
    164         // add_action( 'e20r_before_user_import', array( $this->csv, 'pre_import' ), 10, 2 );
     153        add_action( 'plugins_loaded', array( User_Validation::get_instance(), 'load_actions' ), 30, 0 );
     154        add_action( 'plugins_loaded', array( PMPro_Validation::get_instance(), 'load_actions' ), 31, 0 );
     155        add_action( 'plugins_loaded', array( BuddyPress_Validation::get_instance(), 'load_actions' ), 32, 0 );
     156
     157        add_action( 'init', array( $this, 'load_i18n' ), 5, 0 );
     158        add_action( 'init', array( $this->data, 'process_csv' ), 10, 0 );
     159
     160        add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ), 10, 0 );
     161
     162        // PMPro specific capabilities
     163        // We do this in the CSV() class as it's a clean-up operation
     164        // add_action( 'e20r_before_user_import', array( $this->csv, 'pre_import' ), 10, 2 ); // phpcs:ignore
    165165        add_filter( 'e20r_import_usermeta', array( $this->import_user, 'import_usermeta' ), 10, 2 );
    166166        add_action(
     
    179179
    180180        // Clear action handler(s) from the Import Users from CSV Integration Add-on for PMPro
    181         add_action( 'wp_loaded', array( $this, 'remove_iucsv_support' ), 10 );
     181        add_action( 'wp_loaded', array( $this, 'remove_iucsv_support' ), 10, 0 );
    182182
    183183        // Remove Import action for Sponsored Members add-on (handled directly by this plugin)
    184184        remove_action( 'is_iu_post_user_import', 'pmprosm_is_iu_post_user_import', 20 );
    185185
    186         if ( class_exists( 'E20R\Utilities\Licensing\Licensing' ) ) {
    187             $licensing = new Licensing( self::E20R_LICENSE_SKU );
    188 
    189             if ( $licensing->is_licensed( self::E20R_LICENSE_SKU, false ) ) {
    190                 do_action( 'e20r_import_load_licensed_modules' );
    191             }
     186        if ( ! class_exists( 'E20R\Utilities\Licensing\Licensing' ) ) {
     187            return;
     188        }
     189
     190        $check = new \ReflectionMethod( 'E20R\Utilities\Licensing\Licensing', '__construct' );
     191
     192        if ( false === $check->isPrivate() ) {
     193            $licensing   = new Licensing( self::E20R_LICENSE_SKU );
     194            $is_licensed = $licensing->is_licensed( self::E20R_LICENSE_SKU, false );
     195        } else {
     196            // @phpstan-ignore-next-line
     197            $is_licensed = Licensing::is_licensed( self::E20R_LICENSE_SKU, false );
     198        }
     199
     200        if ( true === $is_licensed ) {
     201            do_action( 'e20r_import_load_licensed_modules' );
    192202        }
    193203    }
     
    249259         */
    250260        $max_run_time = (
    251             apply_filters( 'pmp_im_import_time_per_record', 3 ) *
    252             apply_filters( 'pmp_im_import_records_per_scan', $this->variables->get( 'per_partial' ) )
     261            $this->variables->calculate_per_record_time() *
     262            apply_filters( 'e20r_import_records_per_scan', $this->variables->get( 'per_partial' ) )
    253263        );
    254264
     
    261271            'pmpro-import-members-from-csv',
    262272            plugins_url( 'css/pmpro-import-members-from-csv.css', E20R_IMPORT_PLUGIN_FILE ),
    263             null,
     273            array(),
    264274            E20R_IMPORT_VERSION
    265275        );
     276
    266277        // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter
    267278        wp_register_script(
     
    358369    public function plugin_row_meta( $links, $file ) {
    359370
    360         if ( true === stripos( $file, 'class.pmpro-import-members.php' ) ) {
     371        if ( false !== stripos( $file, 'class.pmpro-import-members.php' ) ) {
    361372            // Add (new) 'Import Users from CSV' links to plugin listing
    362373            $new_links = array(
  • pmpro-import-members-from-csv/trunk/src/class-variables.php

    r2554806 r2563515  
    302302        $this->error_log->debug( "File name from transient is {$this->filename} vs tmp name of {$tmp_name}" );
    303303
    304         if ( empty( $filename ) && ( ! empty( $tmp_name ) && file_exists( $tmp_name ) ) ) {
     304        if ( empty( $this->filename ) && ( ! empty( $tmp_name ) && file_exists( $tmp_name ) ) ) {
    305305
    306306            $this->error_log->debug( "Update/move the {$tmp_name} file!" );
     
    312312                exit();
    313313            }
    314         } elseif ( ! empty( $filename ) ) {
    315             $this->filename = $filename;
    316314        }
    317315
     
    345343
    346344        if ( ! empty( $max_exec_time ) && ( is_numeric( $per_record_time ) ) ) {
    347             $this->per_partial = round( ceil( $max_exec_time / (float) $per_record_time ), 0 );
     345            $this->per_partial = intval( round( ceil( $max_exec_time / (float) $per_record_time ), 0 ) );
    348346        }
    349347
  • pmpro-import-members-from-csv/trunk/src/import/class-ajax.php

    r2554946 r2563515  
    119119                $this->error_log->debug( "Visitor ({$client_ip}) clicked the 'Donate' button" );
    120120                wp_send_json_success();
    121                 exit();
    122121            }
    123122        }
    124123
    125124        wp_send_json_error();
    126         exit();
    127125    }
    128126
     
    162160        if ( false === $this->delete_file( $logfile_path ) ) {
    163161            wp_send_json_error();
    164             exit();
    165162        }
    166163
    167164        // Return success
    168165        wp_send_json_success();
    169         exit();
    170166    }
    171167
     
    186182            $this->error_log->debug( 'File not found/not available. Nothing to clean!' );
    187183            wp_send_json_success();
    188             exit();
    189184        }
    190185
     
    197192
    198193            wp_send_json_error();
    199             exit();
    200194        }
    201195
     
    208202
    209203        wp_send_json_success();
    210         exit();
    211204    }
    212205
     
    244237        $this->error_log->debug( 'Nonce verified in import_members_from_csv()' );
    245238
    246         /*
     239        /* @codingStandardsIgnoreStart
     240         *
    247241        if ( false === wp_verify_nonce( $_REQUEST['e20r-im-import-members-wpnonce'], 'e20r-im-import-members' ) ) {
    248242
    249243            $msg = __( 'Insecure connection attempted!', 'pmpro-import-members-from-csv' );
    250244
    251             wp_send_json_error( array( 'status'  => - 1,
    252                                        'message' => $msg,
    253             ) );
    254             exit();
    255         }
    256         */
     245            wp_send_json_error(
     246                array(
     247                    'status'  => - 1,
     248                    'message' => $msg,
     249                )
     250            );
     251        }
     252         * @codingStandardsIgnoreEnd
     253         */
    257254
    258255        // Get our settings
     
    268265                )
    269266            );
    270             exit();
    271267        }
    272268
     
    287283                )
    288284            );
    289             exit();
    290285        }
    291286
     
    371366        }
    372367
    373         $buffered_text = ob_get_clean();
     368        $buffered_text  = ob_get_clean();
     369        $display_errors = $this->variables->get( 'display_errors' );
    374370
    375371        // No users imported (or done)
     
    383379            //Clear position
    384380            delete_option( "e20rcsv_{$file}" );
    385             $display_errors = $this->variables->get( 'display_errors' );
    386381
    387382            // Delete the transient storing the file name
     
    397392                )
    398393            );
    399             exit();
    400394
    401395        } elseif ( ! empty( $results['errors'] ) ) {
     
    425419                )
    426420            );
    427             exit();
    428421        } else {
    429422
     
    462455                )
    463456            );
    464             exit();
    465457        }
    466458    }
  • pmpro-import-members-from-csv/trunk/src/import/class-csv.php

    r2554806 r2563515  
    2121
    2222use E20R\Import_Members\Error_Log;
    23 use E20R\Import_Members\Modules\Users\Column_Validation as User_Validation;
    2423use E20R\Import_Members\Modules\Users\Import_User;
    2524use E20R\Import_Members\Status;
     
    3736
    3837    /**
    39      * The CSV file (as a SplFileObject() class )
    40      *
    41      * @var SplFileObject $file_object
    42      */
    43     private $file_object;
    44 
    45     /**
    4638     * Error log class
    4739     * @var Error_Log|null $error_log = null;
     
    6052     * @var null|CSV $csv
    6153     */
    62     private $csv = null;
     54    private $csv;
    6355
    6456    /**
     
    201193        }
    202194
     195        // @phpstan-ignore-next-line
     196        $this->error_log->debug( 'Directory error? ' . ( $directory_error ? 'Yes' : 'No' ) );
     197        $this->error_log->debug( 'File upload not selected error? ' . ( $no_file_error ? 'Yes' : 'No' ) );
     198        $this->error_log->debug( 'File limit error? ' . ( $clean_file_error ? 'Yes' : 'No' ) );
     199
     200        // @phpstan-ignore-next-line
    203201        if ( ( true === $no_file_error || true === $directory_error || true === $clean_file_error ) ) {
    204 
    205202            $this->error_log->debug( 'Error: Problem with uploaded file...' );
    206             $this->error_log->debug( 'Directory error? ' . ( $directory_error ? 'Yes' : 'No' ) );
    207             $this->error_log->debug( 'File upload not selected error? ' . ( $no_file_error ? 'Yes' : 'No' ) );
    208             $this->error_log->debug( 'File limit error? ' . ( $clean_file_error ? 'Yes' : 'No' ) );
    209 
    210203            return false;
    211204        }
     
    333326
    334327        // Mac CR+LF fix
    335         ini_set( 'auto_detect_line_endings', true );
     328        ini_set( 'auto_detect_line_endings', '1' );
    336329
    337330        $file        = basename( $file_name );
     
    414407
    415408            $this->error_log->debug( "Processing next user data. (previous line #: {$active_line_number})" );
    416 
    417409            $this->extract_data(
    418410                $line,
     
    493485            $user_id = $import_user->import( $user_data, $user_meta, $headers );
    494486
    495             if ( false === $user_ids ) {
     487            if ( ! $user_ids ) {
    496488
    497489                $msg = sprintf(
     
    519511        // Close the file (done by the destructor for the SplFileObject() class)
    520512        $file_object = null;
    521         ini_set( 'auto_detect_line_endings', true );
     513        ini_set( 'auto_detect_line_endings', '1' );
    522514
    523515        // One more thing to do after all imports?
  • pmpro-import-members-from-csv/trunk/src/modules/BuddyPress/class-buddypress.php

    r2554806 r2563515  
    7272     * @access private
    7373     */
    74     private function __construct() {
     74    public function __construct() {
    7575        $this->data      = new Data();
    7676        $this->error_log = new Error_Log(); // phpcs:ignore
     
    8484        );
    8585    }
    86 
    87     /**
    88      * Get or instantiate and return this class (BuddyPress)
    89      *
    90      * @return BuddyPress|null
    91      */
    92 //  public static function get_instance() {
    93 //      if ( null === self::$instance ) {
    94 //          self::$instance = new self();
    95 //      }
    96 //      return self::$instance;
    97 //  }
    9886
    9987    /**
     
    149137        return $field_list + $this->field_list;
    150138    }
    151 
    152     /**
    153      * Clone the class (Singleton)
    154      *
    155      * @access private
    156      */
    157     private function __clone() {
    158         // TODO: Implement __clone() method.
    159     }
    160139}
  • pmpro-import-members-from-csv/trunk/src/modules/BuddyPress/class-column-validation.php

    r2554806 r2563515  
    3838namespace E20R\Import_Members\Modules\BuddyPress;
    3939
    40 
    4140use E20R\Import_Members\Error_Log;
    4241use E20R\Import_Members\Validate\Base_Validation;
     42use E20R\Import_Members\Modules\BuddyPress\BuddyPress;
    4343
    4444class Column_Validation extends Base_Validation {
    45    
     45
    4646    /**
    4747     * Get or instantiate and get the current class
    4848     *
    49      * @return Column_Validation|null
     49     * @return Column_Validation|Base_Validation|null
    5050     */
    5151    public static function get_instance() {
     
    5353        if ( true === is_null( self::$instance ) ) {
    5454            self::$instance = new self();
    55            
     55
    5656            add_filter(
    5757                'e20r_import_errors_to_ignore',
    5858                array( self::$instance, 'load_ignored_module_errors' ),
    5959                10,
    60             2
     60                2
    6161            );
    62            
     62
    6363            // Add list of errors to ignore for the BuddyPress module
    6464            self::$instance->errors_to_ignore = apply_filters(
     
    7171        return self::$instance;
    7272    }
    73    
     73
    7474    /**
    7575     * Define the module specific errors to ignore
     
    8181     */
    8282    public function load_ignored_module_errors( $ignored_error_list, $module_name = 'buddypress' ) {
    83        
    84         if ( $module_name !== 'buddypress' ) {
     83
     84        if ( 'buddypress' !== $module_name ) {
    8585            return $ignored_error_list;
    8686        }
    87        
    88         $this->error_log->debug("Loading BuddyPress specific error(s) when it's safe to can continue importing");
    89        
     87
     88        $this->error_log->debug( "Loading BuddyPress specific error(s) when it's safe to can continue importing" );
     89
    9090        $this->errors_to_ignore = array(
    9191            'bp_field_name' => true,
    9292        );
    93        
     93
    9494        return $ignored_error_list + $this->errors_to_ignore;
    9595    }
    96    
     96
    9797    /**
    9898     * Load action and filter handlers for PMPro validation
     
    103103            return;
    104104        }
    105        
     105
    106106        add_filter( 'e20r_import_members_validate_field_data', array( $this, 'bp_field_exists' ), 1, 3 );
    107107    }
     
    117117     */
    118118    public function bp_field_exists( $has_error, $user_id, $fields ) {
    119        
    120         $buddy_press = BuddyPress::get_instance();
     119
     120        $buddy_press = new BuddyPress();
    121121        $buddy_press->load_fields( array() );
    122122
    123         if ( ! isset( $fields['bp_field_name'])) {
    124             $this->error_log->debug("No need to process 'bp_field_name' column");
     123        if ( ! isset( $fields['bp_field_name'] ) ) {
     124            $this->error_log->debug( "No need to process 'bp_field_name' column" );
    125125            return $has_error;
    126126        }
    127127
    128         if ( ! isset( $fields['bp_field_name'] ) && in_array( 'bp_field_name', array_keys( $fields ) ) ) {
     128        if ( ! isset( $fields['bp_field_name'] ) && in_array( 'bp_field_name', array_keys( $fields ), true ) ) {
    129129            $this->error_log->debug( "'bp_field_name' is doesn't need to be processed..." );
    130130            return $has_error;
     
    132132
    133133        if ( isset( $fields['bp_field_name'] ) && empty( $fields['bp_field_name'] ) ) {
    134             $has_error = $has_error && ( true && ! $this->ignore_validation_error( 'bp_field_name' ) );
     134            $has_error = $has_error && ( ! $this->ignore_validation_error( 'bp_field_name' ) );
    135135        }
    136136
    137137        // FIXME: Add check for 'bp_field_exists' for the supplied fields/data
    138        
     138
    139139        return $has_error;
    140140    }
    141 
    142     /**
    143      * Disable the __clone() magic method
    144      *
    145      * @access private
    146      */
    147     private function __clone() {
    148         // TODO: Implement __clone() method.
    149     }
    150141}
  • pmpro-import-members-from-csv/trunk/src/modules/BuddyPress/class-import-buddypress.php

    r2554806 r2563515  
    2020namespace E20R\Import_Members\Modules\BuddyPress;
    2121
    22 
    2322class Import_BuddyPress {
    24 
     23    // TODO: Create BuddyPress import class
    2524}
  • pmpro-import-members-from-csv/trunk/src/modules/PMPro/class-column-validation.php

    r2554806 r2563515  
    3232     * Instance of the PMPro Column_Validation class
    3333     *
    34      * @var null|Column_Validation $instance
     34     * @var null|Column_Validation|Base_Validation $instance
    3535     */
    3636    protected static $instance = null;
     
    3939     * Get or instantiate and get the current class
    4040     *
    41      * @return Column_Validation|null
    42      */
    43     public static function get_instance() : \E20R\Import_Members\Modules\PMPro\Column_Validation {
     41     * @return Column_Validation|Base_Validation|null
     42     */
     43    public static function get_instance() {
    4444
    4545        if ( true === is_null( self::$instance ) ) {
     
    165165        $e20r_import_err['invalid_membership_id'] = new WP_Error( 'e20r_im_member', $msg );
    166166
    167         $has_error = true && ( ! $this->ignore_validation_error( 'invalid_membership_id' ) );
     167        $has_error = ( ! $this->ignore_validation_error( 'invalid_membership_id' ) );
    168168
    169169        return $has_error;
     
    173173     * Can't import membership data when user has incorrect start date format
    174174     *
    175      * @param $has_error
    176      * @param $user_id
    177      * @param $fields
     175     * @param bool $has_error
     176     * @param int $user_id
     177     * @param array $fields
    178178     *
    179179     * @return bool
     
    228228            );
    229229
    230             $has_error = true && ( ! $this->ignore_validation_error( 'startdate_format' ) );
     230            $has_error = ( ! $this->ignore_validation_error( 'startdate_format' ) );
    231231        }
    232232
     
    237237     * Can't import membership data when user has incorrect start date format or value
    238238     *
    239      * @param $has_error
    240      * @param $user_id
    241      * @param $fields
     239     * @param bool $has_error
     240     * @param int $user_id
     241     * @param array $fields
    242242     *
    243243     * @return bool
     
    289289
    290290            $e20r_import_err['no_startdate'] = new WP_Error( 'e20r_im_member', $msg );
    291             $has_error                       = true && ( ! $this->ignore_validation_error( 'no_startdate' ) );
     291            $has_error                       = ( ! $this->ignore_validation_error( 'no_startdate' ) );
    292292        }
    293293        return $has_error;
     
    297297     * Possible problem for membership data when user has incorrect end date format or value
    298298     *
    299      * @param $has_error
    300      * @param $user_id
    301      * @param $fields
     299     * @param bool $has_error
     300     * @param int $user_id
     301     * @param array $fields
    302302     *
    303303     * @return bool
     
    335335
    336336            $e20r_import_err['bad_format_enddate'] = new WP_Error( 'e20r_im_member', $msg );
    337             $has_error                             = true && ( ! $this->ignore_validation_error( 'bad_format_enddate' ) );
     337            $has_error                             = ( ! $this->ignore_validation_error( 'bad_format_enddate' ) );
    338338
    339339            $should_be = Time::convert( $fields['membership_enddate'] );
     
    378378        if (
    379379            ! empty( $fields['membership_enddate'] ) &&
    380             isset( $fields['membership_status'] ) && 'inactive' === $fields['membership_status'] &&
     380            ! empty( $fields['membership_status'] ) &&
     381            'inactive' === $fields['membership_status'] &&
    381382            ( time() < strtotime( $fields['membership_enddate'], time() ) )
    382383        ) {
     
    395396
    396397            $e20r_import_err['inactive_and_enddate'] = new WP_Error( 'e20r_im_member', $msg );
    397             $has_error                               = true && ( ! $this->ignore_validation_error( 'inactive_and_enddate' ) );
     398            $has_error                               = ( ! $this->ignore_validation_error( 'inactive_and_enddate' ) );
    398399        }
    399400
     
    450451
    451452            $e20r_import_err['valid_status'] = new WP_Error( 'e20r_im_member', $msg );
    452             $has_error                       = true && ( ! $this->ignore_validation_error( 'valid_status' ) );
     453            $has_error                       = ( ! $this->ignore_validation_error( 'valid_status' ) );
    453454        }
    454455
     
    505506
    506507            $e20r_import_err['link_subscription'] = new WP_Error( 'e20r_im_member', $msg );
    507             $has_error                            = true && ( ! $this->ignore_validation_error( 'link_subscription' ) );
     508            $has_error                            = ( ! $this->ignore_validation_error( 'link_subscription' ) );
    508509        }
    509510
     
    552553
    553554            $e20r_import_err['invalid_recurring_config'] = new WP_Error( 'e20r_im_member', $msg );
    554             $has_error                                   = true && ( ! $this->ignore_validation_error( 'invalid_recurring_config' ) );
     555            $has_error                                   = ( ! $this->ignore_validation_error( 'invalid_recurring_config' ) );
    555556        }
    556557
     
    594595            );
    595596            $e20r_import_err['sub_id_no_paym_id'] = new WP_Error( 'e20r_im_member', $msg );
     597            $has_error                            = ( ! $this->ignore_validation_error( 'sub_id_no_paym_id' ) );
    596598        }
    597599
     
    674676            $e20r_import_err[ "no_membership_id_column_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    675677
    676             $has_error = true && ( ! $this->ignore_validation_error( 'no_membership_id_column' ) );
     678            $has_error = ( ! $this->ignore_validation_error( 'no_membership_id_column' ) );
    677679        }
    678680
     
    690692            $e20r_import_err[ "no_membership_id_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    691693
    692             $has_error = true && ( ! $this->ignore_validation_error( 'no_membership_id' ) );
     694            $has_error = ( ! $this->ignore_validation_error( 'no_membership_id' ) );
    693695        }
    694696
     
    707709            $e20r_import_err[ "cancelling_membership_level_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    708710
    709             $has_error = false;
     711            $has_error = ( ! $this->ignore_validation_error( 'cancelling_membership_level' ) );
    710712        }
    711713
     
    752754            $e20r_import_err[ "level_exists_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    753755
    754             $has_error = true && ( ! $this->ignore_validation_error( 'level_exists' ) );
     756            $has_error = ( ! $this->ignore_validation_error( 'level_exists' ) );
    755757        }
    756758        return $has_error;
     
    799801            $e20r_import_err[ "recurring_w_enddate_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    800802
    801             $has_error = true && ( ! $this->ignore_validation_error( 'recurring_w_enddate' ) );
     803            $has_error = ( ! $this->ignore_validation_error( 'recurring_w_enddate' ) );
    802804        }
    803805        return $has_error;
     
    845847            $e20r_import_err[ "correct_gw_env_variable_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    846848
    847             $has_error = true && ( ! $this->ignore_validation_error( 'correct_gw_env_variable' ) );
     849            $has_error = ( ! $this->ignore_validation_error( 'correct_gw_env_variable' ) );
    848850        }
    849851
     
    893895                $e20r_import_err[ "supported_gateway_{$active_line_number}" ] = new WP_Error( 'e20r_im_member', $msg );
    894896
    895                 $has_error = true && ( ! $this->ignore_validation_error( 'supported_gateway' ) );
     897                $has_error = ( ! $this->ignore_validation_error( 'supported_gateway' ) );
    896898            }
    897899        }
  • pmpro-import-members-from-csv/trunk/src/modules/PMPro/class-import-member.php

    r2554806 r2563515  
    176176        $has_error              = false;
    177177        $membership_in_the_past = false;
    178 
    179         // Define table names
    180         $pmpro_member_table = "{$wpdb->prefix}pmpro_memberships_users";
    181         $pmpro_dc_table     = "{$wpdb->prefix}pmpro_discount_codes";
    182 
    183         $current_blog_id = get_current_blog_id();
     178        $current_blog_id        = get_current_blog_id();
    184179
    185180        $this->error_log->debug( "Current blog ID: {$current_blog_id}" );
     
    266261                $wpdb->prepare(
    267262                    "SELECT dc.id
    268                               FROM {$pmpro_dc_table} AS dc
     263                              FROM {$wpdb->prefix}pmpro_discount_codes AS dc
    269264                              WHERE dc.code = %s
    270265                              LIMIT 1",
     
    291286                // Update all currently active memberships with the specified ID for the specified user
    292287                $updated = $wpdb->update(
    293                     $pmpro_member_table,
     288                    "{$wpdb->prefix}pmpro_memberships_users",
    294289                    array( 'status' => 'admin_cancelled' ),
    295290                    array(
     
    392387                    $wpdb->prepare(
    393388                        "SELECT mt.id
    394                                       FROM {$pmpro_member_table} AS mt
     389                                      FROM {$wpdb->prefix}pmpro_memberships_users AS mt
    395390                                      WHERE mt.user_id = %d AND mt.membership_id = %d AND mt.status = %s
    396391                                      ORDER BY mt.id DESC LIMIT 1",
     
    404399                    $wpdb->prepare(
    405400                        "SELECT mt.id
    406                                       FROM {$pmpro_member_table} AS mt
     401                                      FROM {$wpdb->prefix}pmpro_memberships_users AS mt
    407402                                      WHERE mt.user_id = %d AND mt.membership_id = %d
    408403                                      ORDER BY mt.id DESC LIMIT 1",
     
    430425
    431426                if ( false !== $wpdb->update(
    432                     $pmpro_member_table,
     427                    "{$wpdb->prefix}pmpro_memberships_users",
    433428                    array(
    434429                        'status'  => 'inactive',
     
    469464
    470465                if ( false === $wpdb->update(
    471                     $pmpro_member_table,
     466                    "{$wpdb->prefix}pmpro_memberships_users",
    472467                    array(
    473468                        'status'  => 'active',
     
    515510
    516511        // Update the error status
    517         if ( true === $has_error ) {
    518             update_option( 'e20r_import_errors', $has_error );
    519         }
     512        update_option( 'e20r_import_errors', $has_error );
    520513
    521514        if ( is_multisite() ) {
     
    592585            }
    593586
    594             $order                 = new \MemberOrder();
    595             $order->user_id        = $user_id;
    596             $order->membership_id  = isset( $record['membership_id'] ) ?? $record['membership_id'];
    597             $order->InitialPayment = ! empty( $record['membership_initial_payment'] ) ? $record['membership_initial_payment'] : null;
     587            $order                = new \MemberOrder();
     588            $order->user_id       = $user_id; // @phpstan-ignore-line
     589            $order->membership_id = isset( $record['membership_id'] ) ?? $record['membership_id']; // @phpstan-ignore-line
     590
     591            // phpcs:ignore
     592            $order->InitialPayment = ! empty( $record['membership_initial_payment'] ) ? $record['membership_initial_payment'] : null; // @phpstan-ignore-line
    598593
    599594            /**
     
    616611
    617612                    if ( ! isset( $order->billing ) ) {
    618                         $order->billing = new \stdClass();
     613                        $order->billing = new \stdClass();  // @phpstan-ignore-line
    619614                    }
    620615
     
    635630                    if ( 'total' === $field_name && ! empty( $record['membership_initial_payment'] ) ) {
    636631
    637                         $order->total = $record['membership_initial_payment'];
     632                        $order->total = $record['membership_initial_payment']; // @phpstan-ignore-line
    638633
    639634                    } elseif ( 'total' === $field_name && (
     
    642637                        ) ) {
    643638
    644                         $order->total = $record['membership_billing_amount'];
     639                        $order->total = $record['membership_billing_amount']; // @phpstan-ignore-line
    645640
    646641                    } elseif ( 'total' !== $field_name ) {
    647642
    648643                        if ( 'status' === $field_name ) {
     644                            // @phpstan-ignore-next-line
    649645                            $order->{$field_name} = ( isset( $record[ $full_field_name ] ) && 'active' === $record[ $full_field_name ] ? 'success' : 'cancelled' );
    650646                        } else {
     
    663659
    664660            if ( isset( $record['membership_gateway_environment'] ) && strtolower( $default_environment ) !== strtolower( $record['membership_gateway_environment'] ) ) {
    665                 $order->gateway_environment = strtolower( $record['membership_gateway_environment'] );
     661                $order->gateway_environment = strtolower( $record['membership_gateway_environment'] ); // @phpstan-ignore-line
    666662            }
    667663
    668664            if ( true === $membership_in_the_past ) {
    669                 $order->status = 'cancelled';
     665                $order->status = 'cancelled'; // @phpstan-ignore-line
    670666            }
    671667
  • pmpro-import-members-from-csv/trunk/src/modules/PMPro/class-import-sponsors.php

    r2554806 r2563515  
    7474     */
    7575    public function load_sponsor_import() {
    76         if ( true === Licensing::is_licensed( 'import_sponsors' ) ) {
     76        $check = new \ReflectionMethod( 'E20R\Utilities\Licensing\Licensing', '__construct' );
     77
     78        if ( false === $check->isPrivate() ) {
     79            $licensing   = new Licensing( Import_Members::E20R_LICENSE_SKU );
     80            $is_licensed = $licensing->is_licensed( Import_Members::E20R_LICENSE_SKU, false );
     81        } else {
     82            // @phpstan-ignore-next-line
     83            $is_licensed = Licensing::is_licensed( Import_Members::E20R_LICENSE_SKU, false );
     84        }
     85
     86        if ( true === $is_licensed ) {
    7787            add_action( 'e20r_after_user_import', array( $this, 'maybe_add_sponsor_info' ), 100, 3 );
    7888        }
     
    169179     *
    170180     * @param int     $sponsored_user_id
    171      * @param Sponsor $sponsor
     181     * @param Sponsor|\WP_User $sponsor
    172182     * @param bool    $last_try
    173183     *
     
    196206
    197207        // Get user info and ensure they have a current membership level
    198         $sponsored_user                   = get_userdata( $sponsored_user_id );
     208        $sponsored_user = get_userdata( $sponsored_user_id );
     209
     210        // @phpstan-ignore-next-line
    199211        $sponsored_user->membership_level = pmpro_getMembershipLevelForUser( $sponsored_user_id, true );
    200212        $delayed_sponsor_link             = $this->variables->get( 'delayed_sponsor_link' );
     
    235247
    236248        //Make sure the sponsor has a discount code
    237         $code_id = pmprosm_getCodeByUserID( $sponsor_id );
     249        $code_id = pmprosm_getCodeByUserID( $sponsor_id ); // @phpstan-ignore-line
    238250
    239251        $this->error_log->debug( "Got sponsor code {$code_id} for sponsor {$sponsor_id}" );
     
    295307            $this->error_log->debug( "Have to create a sponsor code for {$sponsor_id}" );
    296308
     309            // @phpstan-ignore-next-line
    297310            $code_id = pmprosm_createSponsorCode( $sponsor_id, $sponsor_level_id, $uses );
    298311        }
     
    317330            'code_id'       => $code_id,
    318331            'user_id'       => $sponsored_user_id,
    319             'membership_id' => $sponsored_user->membership_level->id,
     332            'membership_id' => $sponsored_user->membership_level->id, // @phpstan-ignore-line
    320333            'status'        => 'active',
    321334        );
     
    342355        $this->error_log->debug( "Updated member record for {$sponsored_user_id} with sponsor info" );
    343356
     357        // @phpstan-ignore-next-line
    344358        pmprosm_addDiscountCodeUse( $sponsored_user_id, $sponsored_user->membership_level->ID, $code_id );
    345359
    346360        $this->error_log->debug( "Updated the usage of {$code_id}" );
    347361
    348         if ( empty( $error ) ) {
     362        if ( empty( $e20r_import_err ) ) {
    349363            $status = true;
    350364
     
    353367
    354368        } else {
    355             $error->log_errors(
    356                 array( $error ),
     369            $this->error_log->log_errors(
     370                $e20r_import_err,
    357371                $this->variables->get( 'log_file_path' ),
    358372                $this->variables->get( 'log_file_url' )
     
    398412            }
    399413
     414            // @phpstan-ignore-next-line
    400415            $sponsor->membership_level = pmpro_getMembershipLevelForUser( $sponsor_id, true );
    401416
  • pmpro-import-members-from-csv/trunk/src/modules/PMPro/class-pmpro.php

    r2554806 r2563515  
    1818 */
    1919namespace E20R\Import_Members\Modules\PMPro;
    20 
    2120
    2221use E20R\Import_Members\Error_Log;
  • pmpro-import-members-from-csv/trunk/src/modules/PMPro/class-sponsor.php

    r2554806 r2563515  
    2020namespace E20R\Import_Members\Modules\PMPro;
    2121
    22 
    2322use E20R\Import_Members\Data;
    2423
    2524class Sponsor {
    26    
     25
    2726    /**
    2827     * The sponsor's WP_User ID
     
    3130     */
    3231    private $ID = null;
    33    
     32
    3433    /**
    3534     * User Record for the sponsor
     
    3837     */
    3938    private $user = null;
    40    
     39
    4140    /**
    4241     * The membership level information for the sponsor
     
    4544     */
    4645    private $membership_level = null;
    47    
     46
    4847    /**
    4948     * Sponsor constructor.
    5049     *
    51      * @param $user_id
     50     * @param int|string $user_id
    5251     *
    5352     * @throws \Exception
    5453     */
    5554    public function __construct( $user_id = null ) {
    56        
    57         $data = Data::get_instance();
    58        
     55
     56        $data = new Data();
     57
    5958        if ( ! empty( $user_id ) ) {
    6059            $this->user = $data->get_user_info( $user_id );
    6160        }
    62        
    63         if ( !empty( $user_id ) && empty( $this->user ) ) {
    64             throw new \Exception( sprintf( __( 'No user with that ID (%s) found!', 'pmpro-import-members-from-csv' ), $user_id ) );
     61
     62        if ( ! empty( $user_id ) && empty( $this->user ) ) {
     63            throw new \Exception(
     64                sprintf(
     65                    // translators: %s - Supplied User ID, email or login name
     66                    __( 'No user with that ID (%s) found!', 'pmpro-import-members-from-csv' ),
     67                    $user_id
     68                )
     69            );
    6570        }
    6671    }
    67    
     72
    6873    /**
    6974     * Set Sponsor parameter by type
     
    7681     */
    7782    public function set( $param, $value, $type = null ) {
    78        
     83
    7984        $attributes = get_class_vars( __CLASS__ );
    80        
    81         if ( ! in_array( $param, $attributes ) && ! in_array( $type, $attributes ) ) {
     85
     86        if ( ! in_array( $param, $attributes, true ) && ! in_array( $type, $attributes, true ) ) {
    8287            return false;
    8388        }
    84        
     89
    8590        switch ( $type ) {
    86            
     91
    8792            case 'user':
    8893                if ( isset( $this->user->{$param} ) ) {
     
    9297                }
    9398                break;
    94            
     99
    95100            case 'membership':
    96                
    97101                if ( isset( $this->membership_level->{$param} ) ) {
    98102                    $this->membership_level->{$param} = $value;
     
    101105                }
    102106                break;
    103            
     107
    104108            default:
    105109                $this->{$param} = $value;
    106110        }
    107        
     111
    108112        return true;
    109113    }
    110    
     114
    111115    /**
    112116     * Return the type specific parameter (membership info, user info, class variable)
    113117     *
    114      * @param string $type
     118     * @param string|null $type
    115119     * @param string $param
    116120     *
     
    118122     */
    119123    public function get( $type, $param ) {
    120        
     124
    121125        $attributes = get_class_vars( __CLASS__ );
    122126        $value      = null;
    123        
    124         if ( ! in_array( $param, $attributes ) ) {
     127
     128        if ( ! in_array( $param, $attributes, true ) ) {
    125129            return false;
    126130        }
    127        
     131
    128132        switch ( $type ) {
    129            
     133
    130134            case 'user':
    131135                $value = $this->user->{$param};
    132136                break;
    133            
     137
    134138            case 'membership':
    135                
    136139                $value = $this->membership_level->{$param};
    137140                break;
    138            
     141
    139142            default:
    140143                $value = $this->{$param};
    141144        }
    142        
     145
    143146        return $value;
    144147    }
  • pmpro-import-members-from-csv/trunk/src/modules/Users/class-column-validation.php

    r2554806 r2563515  
    3636     * Get or instantiate and get the current class
    3737     *
    38      * @return Column_Validation|null
     38     * @return Column_Validation|Base_Validation|null
    3939     */
    4040    public static function get_instance() {
     
    134134     * @param null|string|string[] $field_name
    135135     *
    136      * @return bool|int|false
     136     * @return bool|int
    137137     */
    138138    public function validate_user_id( $has_error, $user_id, $record, $field_name = null ) {
     
    147147            $this->error_log->debug( 'Cannot find one of the expected column(s): ID, user_email, user_login' );
    148148            return $has_error;
    149         }
    150 
    151         if ( is_array( $field_name ) ) {
    152             // TODO: Process list of fields
    153149        }
    154150
     
    190186        return true;
    191187    }
    192 
    193     /**
    194      * Disable the __clone() magic method
    195      *
    196      * @access private
    197      */
    198     private function __clone() {
    199         // TODO: Implement __clone() method.
    200     }
    201188}
  • pmpro-import-members-from-csv/trunk/src/modules/Users/class-import-user.php

    r2554806 r2563515  
    353353        } else {
    354354            $update = false;
     355            $id     = null;
    355356            // Here we're supposed to hash the password
    356357            // $user_pass = wp_hash_password( $userdata['user_pass'] );
     
    555556
    556557        if ( true === $update ) {
    557             $wpdb->update( $wpdb->users, $data, compact( 'ID' ) );
     558            $wpdb->update( $wpdb->users, $data, compact( 'id' ) );
    558559            $user_id = (int) $id;
    559560        } else {
  • pmpro-import-members-from-csv/trunk/src/modules/Users/class-user-validation.php

    r2554806 r2563515  
    2020namespace E20R\Import_Members\Validate;
    2121
    22 
    2322use E20R\Import_Members\Import_Members;
    2423use E20R\Import_Members\Status;
    2524
    2625class User_Validation extends Validate {
    27    
    28    
     26
     27    /**
     28     * Return the User_Validation class instance
     29     *
     30     * @return Base_Validation|User_Validation|null
     31     */
     32    public static function get_instance() {
     33        if ( null === self::$instance ) {
     34            self::$instance = new self();
     35        }
     36
     37        return self::$instance;
     38    }
     39
     40    /**
     41     * Return list of validation errors we'll ignore (only warn for)
     42     *
     43     * @param array $ignored_error_list
     44     * @param string $module_name
     45     *
     46     * @return array
     47     */
     48    public function load_ignored_module_errors( $ignored_error_list, $module_name = 'users' ) {
     49        return $ignored_error_list;
     50    }
     51
     52    /**
     53     * Load action and filter handlers for PMPro validation
     54     */
     55    public function load_actions() {
     56
     57        add_filter(
     58            'e20r_import_users_validate_field_data',
     59            array( $this, 'validate' ),
     60            1,
     61            3
     62        );
     63    }
     64
    2965    /**
    3066     * Process the status for user validations and set a status message
     
    3672     */
    3773    public static function status_msg( $status, $allow_update ) {
    38        
     74
    3975        global $e20r_import_err;
    4076        global $active_line_number;
    41        
     77
    4278        $should_exit = false;
    4379
     
    5187
    5288            case Status::E20R_ERROR_UPDATE_NEEDED_NOT_ALLOWED:
    53                 $msg = __(
     89                $msg         = __(
    5490                    'User ID specified and user record exists but the "Update User Record" option is not selected',
    5591                    'pmpro-import-members-from-csv'
     
    67103                break;
    68104            default:
    69                
    70                 $msg = null;
     105                $msg         = null;
    71106                $should_exit = false;
    72107        }
    73        
     108
    74109        // Process the resulting error/warning message
    75110        if ( ! empty( $msg ) ) {
    76            
     111
    77112            // Save the error message (based on the supplied status)
    78             $e20r_import_err["user_check_{$active_line_number}"] = $msg;
    79            
     113            $e20r_import_err[ "user_check_{$active_line_number}" ] = $msg;
     114
    80115            return $should_exit;
    81116        }
    82        
     117
    83118        return false;
    84119    }
    85    
     120
    86121    /**
    87122     * Validate the User information in the record
     
    93128     */
    94129    public static function validate( $record, $allow_update ) {
    95        
    96         return false;
     130
     131        // TODO: Implement validation logic for User record(s)
     132        return ! empty( $record );
    97133    }
    98134}
  • pmpro-import-members-from-csv/trunk/src/validate/class-base-validation.php

    r2554806 r2563515  
    2323
    2424use E20R\Import_Members\Error_Log;
     25use E20R\Import_Members\Modules\PMPro\Column_Validation as PMPro_Validation;
     26use E20R\Import_Members\Modules\Users\Column_Validation as User_Validation;
     27use E20R\Import_Members\Modules\BuddyPress\Column_Validation as BP_Validation;
    2528
    2629abstract class Base_Validation {
     
    2932     * Instance of the column validation logic for PMPro
    3033     *
    31      * @var null|Base_Validation
     34     * @var null|Base_Validation|PMPro_Validation|User_Validation|BP_Validation
    3235     */
    3336    protected static $instance = null;
     
    7578     * Get or instantiate and get the current class
    7679     *
    77      * @return Column_Validation|Base_Validation|null
     80     * @return User_Validation|PMPro_Validation|BP_Validation|Base_Validation|null
    7881     */
    7982    abstract public static function get_instance();
     
    8184    /**
    8285     * Load all validation actions for the specific module
    83      *
    84      * @return null
    8586     */
    8687    abstract public function load_actions();
  • pmpro-import-members-from-csv/trunk/src/validate/class-date-format.php

    r2554806 r2563515  
    2121
    2222class Date_Format {
    23    
     23
    2424    /**
    2525     * Test the date supplied for MySQL compliance
     
    3333     */
    3434    public static function validate( $date, $format ) {
    35        
     35
    3636        $check_date = \DateTime::createFromFormat( $format, $date );
    37         $retval     = ( false !== $check_date ) && ( $check_date->format( $format ) == $date );
    38        
    39         return $retval;
     37
     38        return ( false !== $check_date ) && ( $check_date->format( $format ) === $date );
    4039    }
    41    
     40
    4241}
Note: See TracChangeset for help on using the changeset viewer.