WordPress Search and Replace ng Database URL nang Hindi Nasisira ang Serialized Data
Palitan ang site URL ng WordPress sa database nang hindi nabu-blangko ang widgets, menus o theme settings. Gamitin ang WP-CLI command na hindi sumisira sa serialized data.
Nailathala
Huwag magpatakbo ng plain na UPDATE ... SET column = REPLACE(column, 'oldurl', 'newurl') sa isang WordPress database. Tama ang magiging palit nito sa text at sasabay diyan ang pagkasira ng settings mo, dahil iniimbak ng WordPress ang mga array at object bilang PHP-serialized na string, at itinatala ng format na iyon ang byte length ng bawat string na nasa loob nito. Isinusulat ulit ng raw SQL replace ang text pero hindi nito ginagalaw ang naitalang haba, at hindi na nababasa ang value.
Gumamit ng serialization-aware na tool sa halip. Sa command line, wp search-replace iyon. I-backup muna ang database, patakbuhin bilang dry run, saka totohanin.
Ano ba talaga ang nasisira
Ganito ang itsura ng isang PHP-serialized na string:
s:18:"http://example.com"
Ang 18 ay ang byte length ng text na kasunod nito. Bilangin mo — eksaktong 18 karakter ang http://example.com.
Ngayon isipin mo ang isang naka-imbak na theme setting:
a:1:{s:4:"logo";s:18:"http://example.com";}
Magpatakbo ka ng plain SQL replace ng http:// papuntang https:// at makukuha mo ito:
a:1:{s:4:"logo";s:19:"https://example.com";}
Kaya lang, hindi. Ito ang makukuha mo:
a:1:{s:4:"logo";s:18:"https://example.com";}
19 bytes na ang string pero 18 pa rin ang inaangkin nito. Binabasa ng PHP ang idineklarang haba, lumakad ito ng 18 bytes pasulong, hindi nito nakita ang closing quote at semicolon sa inaasahang puwesto, at sumuko na. Pumalpak ang unserialize ng buong array.
Bakit tahimik itong pumapalya
Dito nagiging mahal ang bug na ito. Hindi nagtatapon ng error at hindi humihinto ang WordPress. Kapag binasa nito ang isang option, ipinapasa nito ang value sa unserialize helper, nagbabalik ng false ang PHP para sa maling data, at ang ibinibigay ng WordPress sa code mo ay isang value na parang hindi na-set kailanman ang option. Babalik naman sa default ang plugin o theme.
Kaya hindi error page ang sintomas. Ito ang sintomas:
- Nawawala ang widgets sa sidebars
- Nagre-reset sa theme defaults ang Customizer settings
- Blangko ang balik ng layout data ng page builder at walang laman ang na-render na page
- Mukhang bagong install ang mga plugin settings page
- Nawawala ang naka-assign na location ng mga menu
Walang sinasabi ang admin na may mali. Nandoon pa rin ang row sa database, puno pa rin ng mukhang tamang text. Ang length prefix lang ang mali nang isa o dalawang byte. Naglalabas naman ang PHP ng notice kapag pumalpak ang unserialization, pero sa production site na patay ang display errors, walang nakakakita niyon. Kapag binuksan mo ang WP_DEBUG na naka-enable ang WP_DEBUG_LOG at naka-false ang WP_DEBUG_DISPLAY, mapupunta ang mga notice na iyon sa isang log file na mababasa mo.
Hindi rin pantay ang pinsala. Ligtas na ligtas sa naive na replace ang mga simpleng scalar value — siteurl, home, plain post content, isang URL na nakaupo sa sarili nitong column. Serialized values lang ang nasisira. Kaya nga mukhang matagumpay sa unang tingin ang isang maling replace.
Tingnan ang wp-config.php bago galawin ang kahit ano
Kung may WP_HOME o WP_SITEURL na nakadefine sa wp-config.php, nananaig ang mga constant na iyon kaysa sa laman ng database. Magmumukhang walang epekto ang pagbabago sa wp_options. Hanapin mo ang ganitong mga linya bago mo sabihing database ang problema:
define( 'WP_HOME', 'http://example.com' );
define( 'WP_SITEURL', 'http://example.com' );
I-update mo ito sa bagong URL o alisin mo na at hayaan ang database ang magdikta.
Mag-backup muna, at seryosohin mo
Hindi laging madaling ibalik ang sirang serialization. Kapag hindi na magkatugma ang length prefix at ang nilalaman, hindi na mababawi ang orihinal na value mula sa sirang value — hindi mo malalaman kung ano dapat ang tamang haba nang hindi mo alam ang orihinal na string. Ang backup lang ang tunay na undo.
wp db export backup-before-replace.sql
O gamit ang mysqldump kung walang WP-CLI:
mysqldump -u USER -p DBNAME > backup-before-replace.sql
Kung kaya, ilabas mo ito sa server. Ang backup na nakatambak sa web root ay restore point at security problem nang sabay.
Ang ligtas na command
Ini-unserialize ng search-replace ng WP-CLI ang bawat value, nilalakad nito ang na-decode na structure, pinapalitan sa loob, at ini-serialize ulit nang tama ang haba. Dry run muna:
wp search-replace 'http://example.com' 'https://example.com' --dry-run --all-tables --skip-columns=guid
Basahin mo ang report. Sinasabi nito kung ilang palit ang mangyayari kada table at column. Kung mukhang mali ang listahan ng table, o may hindi mo kilalang table na libu-libo ang hit, huminto ka at tingnan bago mo totohanin.
Tapos patakbuhin:
wp search-replace 'http://example.com' 'https://example.com' --all-tables --skip-columns=guid --report-changed-only
Tapatan tayo tungkol sa mga flag:
- Sinasaklaw ng
--all-tablesang mga table na hindi mismo nirerehistro ng WordPress, at doon madalas nakatira ang data ng plugin. Kapag wala nito, may mga plugin table na lalaktawan nang tuluyan. - Mahalaga ang
--skip-columns=guid. Permanenteng identifier angguidpara sa mga feed reader, hindi ito buhay na URL. Kapag isinulat mo itong muli, puwedeng makita ng mga feed subscriber ang buong archive mo bilang bagong post. - Maghanap nang walang trailing slash at walang mga variant ng protocol na ayaw mong galawin. Kapag hubad na
example.comang pinalitan mo, tatamaan mo rin ang mga email address at kahit anong banggit nito sa post text.
Kung hindi mo magamit ang command line, ginagawa rin ng mga serialization-aware na migration plugin ang parehong decoding sa admin screen. Ang hinahanap mong ugali ay malinaw na nakasulat bilang paghawak sa serialized data; kung hindi ito sinasabi ng isang tool, ipagpalagay mong hindi nito kaya.
Aling mga table at column ang sangkot
| Table | Column | Panganib sa serialized data |
|---|---|---|
| wp_options | option_value | Mataas — widgets, theme mods, transients, karamihan ng plugin settings |
| wp_postmeta | meta_value | Mataas — layout ng page builder, custom field arrays |
| wp_usermeta | meta_value | Mataas — capabilities, screen at dashboard preferences |
| wp_termmeta | meta_value | Katamtaman — depende sa plugins |
| wp_posts | post_content, guid | Mababa para sa content, pero may dalang URL ang shortcode attributes at block markup |
| wp_comments | comment_content, comment_author_url | Mababa |
| wp_links | link_url, link_image | Mababa, at madalas hindi na ginagamit |
Sa multisite, idagdag ang wp_blogs, wp_site, wp_sitemeta, at ang per-site na wp_2_options, wp_3_options at iba pa. May dagdag na patakaran ang pagpapalit ng URL sa multisite na lampas sa search and replace — ituring mo iyon na hiwalay na trabaho.
Ang mga kasong hindi lubusang naaayos ng search-replace
Tapatan tayo sa mga limitasyon:
JSON na nakaimbak sa loob ng database. May mga page builder na iniimbak ang layout data bilang JSON na may escaped na forward slash, kaya lumalabas ang URL mo bilang https:\/\/example.com sa halip na https://example.com. Hindi ito maaabot ng paghahanap sa normal na anyo. Baka kailanganin mo ng pangalawang pasada sa escaped na string. Sa kopya ka mag-test.
Base64-encoded na mga value. Kung ini-encode ng isang plugin ang settings bago iimbak, walang text-based na replace ang makakakita ng URL. Kadalasan, kailangang i-type ulit ang mga setting na iyon sa sariling screen ng plugin.
Hardcoded na URL sa mga file. Kahit anong nakasulat sa functions.php, sa template ng child theme, o sa hardcoded na asset path ay wala sa database at hindi magagalaw. Hiwalay mong i-grep ang theme directory.
Naka-cache at generated na output. Patuloy na naghahain ng lumang URL ang object cache, page cache, at mga kopya sa CDN kahit tama ang replace. I-flush mo muna ang mga iyon, tapos tingnan ulit bago mo isipin na palpak ang replace.
Kung napatakbo mo na ang maling query
I-restore ang backup. Iyan ang sagot, at mas mabuti nang sabihin nang diretso kaysa mag-alok ng repair procedure na kadalasan naman ay hindi umuubra.
Kung walang backup, makitid ang daan pabalik: ayos ang mga value na hindi naman na-serialize, at ang mga sirang serialized ay kailangang buuin muli nang manu-mano o i-reset sa pamamagitan ng pag-save ulit ng kaukulang settings screen. Kapag ni-save mo ulit ang isang widget area, pinili ulit ang menu location, o inilagay ulit ang settings ng isang plugin, may bagong value na tama ang serialization na isusulat sa ibabaw ng sira. Nakakapagod, pero umuubra, at mas mabuti ito kaysa iwan ang mga sirang row na kakalituhin ng susunod na taong titingin sa site.
Para makabuo ng tamang mga statement bago ka magpatakbo ng kahit ano, gawin mo ito gamit ang WordPress search and replace SQL tool — ipinapakita nito kung aling column ang ligtas tamaan ng plain SQL at alin ang nangangailangan ng serialization-aware na paghawak, kaya makikita mo ang hati bago ka magpasya sa isang command.
FAQ
Mga Tanong
Bakit nasisira ng plain SQL REPLACE ang isang WordPress site?
Dahil iniimbak ng WordPress ang mga array at object bilang PHP-serialized na text, at itinatala ng format na iyon ang byte length ng bawat string sa loob nito. Binabago ng raw REPLACE ang text pero iniiwan nito ang lumang numero ng haba. Tumatanggi na ang PHP na i-unserialize ang value, babalik ang WordPress sa default, at magmumukhang blangko ang settings sa halip na mali.
Ano ang pinakaligtas na paraan para palitan ang WordPress site URL sa database?
Kumuha muna ng buong database backup, tapos patakbuhin ang WP-CLI command na wp search-replace na may dry run muna. Ini-unserialize ng WP-CLI ang bawat value, pinapalitan sa loob ng na-decode na structure, at ini-serialize ulit nang may tamang haba. Ganoon din ang ginagawa ng mga serialization-aware na migration plugin sa admin screen kung walang command line access.
Aling mga table ang may lumang URL?
Pangunahin ang wp_options, wp_posts, wp_postmeta, wp_usermeta, wp_termmeta at wp_comments. Nasa wp_options at sa kahit anong meta_value column ang panganib ng serialized data, dahil naka-imbak bilang array ang widgets, theme mods, transients at data ng page builder. Sa multisite, dala rin ng wp_blogs, wp_site at wp_sitemeta ang domain.
Naaayos ba ng pagbabago sa database ang URL kung nakatakda ito sa wp-config.php?
Hindi. Kung may WP_HOME o WP_SITEURL na nakadefine sa wp-config.php, nananaig ang mga constant na iyon kaysa sa laman ng siteurl at home sa wp_options. Walang makikitang pagbabago sa pag-edit ng database hangga't hindi na-update o naaalis ang mga constant. Tingnan muna ang wp-config.php, dahil iisang linyang iyon ang paliwanag sa maraming palpak na migration.
Dapat ko rin bang palitan ang guid column?
Hindi. Permanenteng identifier ang guid para sa mga feed reader, hindi ito gumaganang URL, at kapag binago mo ito puwedeng makita ulit ng mga feed subscriber ang lahat ng lumang post bilang bago. Ipasa ang skip-columns na may guid kapag nagpatakbo ng WP-CLI. Ang tanging karaniwang eksepsiyon ay ang site na walang public feed o subscriber kailanman.
Paano ko malalaman kung sira ang isang value pagkatapos ng maling replace?
Normal ang itsura ng sirang serialized value sa database pero blangko ang balik nito sa WordPress. Nawawala ang widgets, nagre-reset ang theme customizer settings, at bumabalik sa default ang plugin options nang walang anumang error message. Kapag binuksan ang WP_DEBUG at WP_DEBUG_LOG, lumalabas ang unserialize notice. Kumpirmado agad ito kapag inihambing mo ang idineklarang string length sa tunay na byte count.