| 1 |
<?php |
| 2 |
/** |
| 3 |
* One-time migration of the listing identity into protected meta (issue #286). |
| 4 |
* |
| 5 |
* Older versions stored each Managed Listing's identity in the visible |
| 6 |
* 'ListingKey' post meta. WordPress compares meta keys case-insensitively, so |
| 7 |
* that row is the SAME database row as the theme-projected 'listingkey' custom |
| 8 |
* field; WPResidence's edit screen saved that field blank and erased the |
| 9 |
* identity, making the next import duplicate the listing. Identity now lives |
| 10 |
* in '_mlsimport_listing_key' (underscore = protected meta, invisible to theme |
| 11 |
* custom-field saves and the Custom Fields box). |
| 12 |
* |
| 13 |
* Step by step: |
| 14 |
* 1. On init, bail immediately when the 'mlsimport_listing_key_migrated' |
| 15 |
* option says the copy already ran. |
| 16 |
* 2. Otherwise copy every non-empty legacy 'ListingKey' value into a new |
| 17 |
* '_mlsimport_listing_key' row for posts that do not have one yet, in a |
| 18 |
* single INSERT..SELECT so a 16k-listing site migrates in one statement. |
| 19 |
* 3. Record the flag so the copy never runs again. The legacy rows are left |
| 20 |
* in place untouched; nothing reads them any more. |
| 21 |
* |
| 22 |
* @package MLSImport |
| 23 |
*/ |
| 24 |
|
| 25 |
if ( ! defined( 'ABSPATH' ) ) { |
| 26 |
exit; |
| 27 |
} |
| 28 |
|
| 29 |
/** |
| 30 |
* Copy legacy 'ListingKey' identities into '_mlsimport_listing_key' once. |
| 31 |
* |
| 32 |
* Safe to call on every request: after the first successful run the option |
| 33 |
* flag short-circuits it before any database work. |
| 34 |
* |
| 35 |
* @return void |
| 36 |
*/ |
| 37 |
function mlsimport_migrate_listing_key_identity(): void { |
| 38 |
// Step 1: the copy is one-time; the option flag makes later calls free. |
| 39 |
if ( get_option( 'mlsimport_listing_key_migrated' ) ) { |
| 40 |
return; |
| 41 |
} |
| 42 |
|
| 43 |
global $wpdb; |
| 44 |
|
| 45 |
// Step 2: copy each post's non-empty legacy identity into the protected |
| 46 |
// key, skipping posts that already carry one (re-runs stay idempotent). |
| 47 |
// Intentional direct query: update_post_meta() per post would issue tens of |
| 48 |
// thousands of statements on large sites. |
| 49 |
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching |
| 50 |
$wpdb->query( |
| 51 |
"INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value) |
| 52 |
SELECT legacy.post_id, '_mlsimport_listing_key', legacy.meta_value |
| 53 |
FROM {$wpdb->postmeta} legacy |
| 54 |
LEFT JOIN {$wpdb->postmeta} protected_key |
| 55 |
ON protected_key.post_id = legacy.post_id |
| 56 |
AND protected_key.meta_key = '_mlsimport_listing_key' |
| 57 |
WHERE legacy.meta_key = 'ListingKey' |
| 58 |
AND legacy.meta_value != '' |
| 59 |
AND protected_key.meta_id IS NULL" |
| 60 |
); |
| 61 |
|
| 62 |
// Step 3: mark the copy done so it never runs again. |
| 63 |
update_option( 'mlsimport_listing_key_migrated', defined( 'MLSIMPORT_VERSION' ) ? MLSIMPORT_VERSION : '1' ); |
| 64 |
} |
| 65 |
|
| 66 |
// Run before any import work can happen in the same request: both admin |
| 67 |
// screens and cron entry points pass through init. |
| 68 |
add_action( 'init', 'mlsimport_migrate_listing_key_identity', 5 ); |
| 69 |
|