new post types. */ function azlinkpro_upgrade_post_types() { return array( 'atp_table' => 'azlinkpro_table', 'azp_product_image' => 'azlinkpro_image', 'atps_showcase' => 'azlinkpro_showcase', 'atppc_card' => 'azlinkpro_proscons', ); } /** Old => new post meta key prefixes. */ function azlinkpro_upgrade_meta_prefixes() { return array( '_atp_' => '_azlinkpro_tbl_', '_atps_' => '_azlinkpro_sc_', '_atppc_' => '_azlinkpro_pc_', '_azp_img_' => '_azlinkpro_img_', '_azp_mig_' => '_azlinkpro_mig_', '_azpai_' => '_azlinkpro_ai_', ); } /** Old => new option names. */ function azlinkpro_upgrade_options() { return array( 'atp_settings' => 'azlinkpro_amazon_settings', 'atp_azlink_disclosure_migrated_112' => 'azlinkpro_disclosure_migrated_112', 'azp_migration_latest_run' => 'azlinkpro_migration_latest_run', 'azpai_openai_key' => 'azlinkpro_ai_openai_key', 'azpai_anthropic_key' => 'azlinkpro_ai_anthropic_key', 'azpai_custom_style' => 'azlinkpro_ai_custom_style', ); } /** * Whether anything still uses a pre-1.5.14 name. After the first move this is * checked at most once a day, in the admin only: an older version that was * reinstalled or restored from a backup can save items under the old names again. */ function azlinkpro_upgrade_needed() { if ((int) get_option('azlinkpro_data_version', 0) < AZLINKPRO_DATA_VERSION) { return true; } if (!is_admin() || get_transient('azlinkpro_legacy_checked')) { return false; } set_transient('azlinkpro_legacy_checked', 1, DAY_IN_SECONDS); global $wpdb; // Values are written out one by one (they match the lists above) so each placeholder has its own argument. // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- a daily existence check, uncached on purpose. $found = $wpdb->get_var($wpdb->prepare( "SELECT 1 FROM {$wpdb->posts} WHERE post_type IN (%s, %s, %s, %s) LIMIT 1", 'atp_table', 'azp_product_image', 'atps_showcase', 'atppc_card' )) || $wpdb->get_var($wpdb->prepare( "SELECT 1 FROM {$wpdb->postmeta} WHERE meta_key LIKE %s OR meta_key LIKE %s OR meta_key LIKE %s OR meta_key LIKE %s OR meta_key LIKE %s OR meta_key LIKE %s LIMIT 1", $wpdb->esc_like('_atp_') . '%', $wpdb->esc_like('_atps_') . '%', $wpdb->esc_like('_atppc_') . '%', $wpdb->esc_like('_azp_img_') . '%', $wpdb->esc_like('_azp_mig_') . '%', $wpdb->esc_like('_azpai_') . '%' )) || $wpdb->get_var($wpdb->prepare( "SELECT 1 FROM {$wpdb->options} WHERE option_name IN (%s, %s, %s, %s, %s, %s) LIMIT 1", 'atp_settings', 'atp_azlink_disclosure_migrated_112', 'azp_migration_latest_run', 'azpai_openai_key', 'azpai_anthropic_key', 'azpai_custom_style' )) || $wpdb->get_var($wpdb->prepare( "SELECT 1 FROM {$wpdb->usermeta} WHERE meta_key = %s LIMIT 1", 'azp_pcg_choice' )); // phpcs:enable return (bool) $found; } function azlinkpro_upgrade_data() { if (!azlinkpro_upgrade_needed()) { return; } // One request at a time; a second request simply waits for the next page load. if (get_transient('azlinkpro_data_upgrade_lock')) { return; } set_transient('azlinkpro_data_upgrade_lock', 1, 60); global $wpdb; // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- one-time bulk rename; there is no API for renaming post types or meta keys. foreach (azlinkpro_upgrade_post_types() as $old => $new) { $wpdb->update($wpdb->posts, array('post_type' => $new), array('post_type' => $old)); } foreach (azlinkpro_upgrade_meta_prefixes() as $old => $new) { $wpdb->query($wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_key = CONCAT(%s, SUBSTRING(meta_key, %d)) WHERE meta_key LIKE %s", $new, strlen($old) + 1, $wpdb->esc_like($old) . '%' )); } $wpdb->query($wpdb->prepare( "UPDATE {$wpdb->usermeta} SET meta_key = %s WHERE meta_key = %s", 'azlinkpro_pcg_choice', 'azp_pcg_choice' )); // phpcs:enable $missing = new stdClass(); foreach (azlinkpro_upgrade_options() as $old => $new) { $value = get_option($old, $missing); if ($value === $missing) { continue; } $current = get_option($new, $missing); // An empty settings row (from an activation before this upgrade ran) must not hide the saved one. $current_empty = is_array($current) && !array_filter($current, function ($v) { return $v !== '' && $v !== 'www.amazon.com'; }); if ($current === $missing) { add_option($new, $value, '', false); } elseif ($current_empty) { update_option($new, $value, false); } elseif ($value !== $current) { // Both names hold different values (an older version ran again): keep the current one and a copy of the other. update_option($new . '_previous', $value, false); } delete_option($old); } update_option('azlinkpro_data_version', AZLINKPRO_DATA_VERSION, true); delete_transient('azlinkpro_data_upgrade_lock'); wp_cache_flush(); } // Before the post types are registered on init. add_action('plugins_loaded', 'azlinkpro_upgrade_data', 5); /** * Posts written with the old AmaTablePro shortcode names keep working: the * tags are renamed in the text just before WordPress runs shortcodes, so the * plugin only registers azlinkpro_* shortcodes. Saved post content is not changed. */ function azlinkpro_legacy_shortcodes($content) { if (!is_string($content) || strpos($content, '[') === false || !preg_match('/\[(?:amatablepro|atp_showcase)/i', $content)) { return $content; } $map = array( 'amatablepro_showcase' => 'azlinkpro_showcase', 'amatablepro_pros_cons' => 'azlinkpro_pros_cons', 'amatablepro_procon' => 'azlinkpro_procon', 'atp_showcase' => 'azlinkpro_showcase', 'amatablepro' => 'azlinkpro_table', ); return preg_replace_callback('/\[(\/?)(amatablepro_showcase|amatablepro_pros_cons|amatablepro_procon|atp_showcase|amatablepro)(?=[\s\]\/])/i', function ($m) use ($map) { return '[' . $m[1] . $map[strtolower($m[2])]; }, $content); } // do_shortcode runs at priority 11 on the_content and widget_text. add_filter('the_content', 'azlinkpro_legacy_shortcodes', 8); add_filter('widget_text', 'azlinkpro_legacy_shortcodes', 8); add_filter('widget_block_content', 'azlinkpro_legacy_shortcodes', 8);