| @@ -34,8 +34,40 @@ | ||
| 34 | 34 | |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | 37 | /** |
| 38 | + * A CSV `payment_date` cell as the UTC `Y-m-d H:i:s` the table stores. | |
| 39 | + * | |
| 40 | + * The export writes the date in site time, in the site's date and time | |
| 41 | + * format (`Export`: `wp_date()`), so a cell without a timezone is read as | |
| 42 | + * site time and converted. It used to be stored as if it were UTC, so an | |
| 43 | + * export → import round trip moved every row by the site's UTC offset. A | |
| 44 | + * cell that names its own timezone (`Z`, `+06:00`, `UTC`, `GMT`) is honoured | |
| 45 | + * as given. An unparseable cell keeps the old result (the epoch). | |
| 46 | + * | |
| 47 | + * @since 2.4.1 | |
| 48 | + * | |
| 49 | + * @param string $value Cell value. | |
| 50 | + * @return string | |
| 51 | + */ | |
| 52 | + public static function payment_date_from_csv( $value ) { | |
| 53 | + $value = trim( (string) $value ); | |
| 54 | + $timestamp = strtotime( $value ); | |
| 55 | + | |
| 56 | + if ( false === $timestamp ) { | |
| 57 | + return gmdate( 'Y-m-d H:i:s', 0 ); | |
| 58 | + } | |
| 59 | + | |
| 60 | + if ( preg_match( '/(?:Z|[+-]\d{2}:?\d{2}|\bUTC|\bGMT)$/i', $value ) ) { | |
| 61 | + return gmdate( 'Y-m-d H:i:s', $timestamp ); | |
| 62 | + } | |
| 63 | + | |
| 64 | + // strtotime() read the wall-clock time as UTC (WordPress runs PHP in UTC); | |
| 65 | + // it is site time, so convert it. | |
| 66 | + return get_gmt_from_date( gmdate( 'Y-m-d H:i:s', $timestamp ), 'Y-m-d H:i:s' ); | |
| 67 | + } | |
| 68 | + | |
| 69 | + /** | |
| 38 | 70 | * Decode a CSV `form_fields_info` cell into an array. |
| 39 | 71 | * |
| 40 | 72 | * The cell comes from an uploaded file, so it is never handed to maybe_unserialize(): |
| 41 | 73 | * that instantiates any class a serialized payload names, which turns an import into an |
| @@ -117,9 +149,9 @@ | ||
| 117 | 149 | // 'payment_type' => sanitize_text_field( $record['payment_type'] ), |
| 118 | 150 | 'transaction_id' => sanitize_text_field( $record['transaction_id'] ), |
| 119 | 151 | 'source' => sanitize_text_field( $record['source'] ), |
| 120 | 152 | 'status' => sanitize_text_field( $record['status'] ), |
| 121 | - 'payment_date' => date( 'Y-m-d H:i:s', strtotime( sanitize_text_field( $record['payment_date'] ) ) ), | |
| 153 | + 'payment_date' => self::payment_date_from_csv( sanitize_text_field( $record['payment_date'] ) ), | |
| 122 | 154 | 'form_fields_info' => maybe_serialize( $better_form_fields ), |
| 123 | 155 | ); |
| 124 | 156 | } |
| 125 | 157 | |
| @@ -149,11 +181,9 @@ | ||
| 149 | 181 | * |
| 150 | 182 | * Lite keeps the name, email and source and marks the row imported. |
| 151 | 183 | * `better_payment/import/form_fields_info` receives that, the CSV row and the |
| 152 | 184 | * row's decoded `form_fields_info` cell: Pro adds the subscription keys of a |
| 153 | - * "Subscription" row there. Lite's copy of that | |
| 154 | - * (ProSubscriptionTransactionData::import_fields()) serves only an active Pro | |
| 155 | - * that does not (<= 1.4.3). | |
| 185 | + * "Subscription" row there. | |
| 156 | 186 | * |
| 157 | 187 | * @since 2.4.0 |
| 158 | 188 | * |
| 159 | 189 | * @param mixed $record CSV row keyed by header; anything else is treated as empty. |
| @@ -170,12 +200,8 @@ | ||
| 170 | 200 | ]; |
| 171 | 201 | |
| 172 | 202 | // Decoded without instantiating objects; see decode_form_fields_info(). |
| 173 | 203 | $decoded = isset( $record['form_fields_info'] ) ? self::decode_form_fields_info( $record['form_fields_info'] ) : []; |
| 174 | - | |
| 175 | - if ( ProSubscriptionTransactionData::lite_copy_applies() ) { | |
| 176 | - $better_form_fields = ProSubscriptionTransactionData::import_fields( $better_form_fields, $record, $decoded ); | |
| 177 | - } | |
| 178 | 204 | |
| 179 | 205 | $filtered = apply_filters( 'better_payment/import/form_fields_info', $better_form_fields, $record, $decoded ); |
| 180 | 206 | |
| 181 | 207 | return is_array( $filtered ) ? $filtered : $better_form_fields; |