On this page
- শুরুটা যেখানে - একটি index bleed, যা আমরা থামাতে পারিনি
- বিল্ড পরিকল্পনা - আর যেসব ধারণাকে আমরা সত্যি ভেবেছিলাম, কিন্তু সেগুলো সত্যি ছিল না
- প্রথম বিল্ডে যে CLS regression আমরা তৈরি করেছিলাম
- ৫২৮K পেজজুড়ে Schema.org - কেন এটিই শেষ পর্যন্ত সবচেয়ে বড় ranking lever হয়ে উঠল
- llms.txt - যে LLM-search কৌশল আমরা না জেনেই তৈরি করেছিলাম
- যেসব Cloudflare setting সত্যিই গুরুত্বপূর্ণ ছিল
- ৪-tier partitioned rebuild - অপারেশনের গোপন কৌশল
- ফলাফল - কী বদলেছে এবং কী বদলায়নি
- Productization - Stretch LLC এবং Wordpress Escape
- আমরা কী ভিন্নভাবে করতাম
- Frequently asked questions
এপ্রিল ২০২৬-এ পাঁচ কর্মদিবসের মধ্যে Unlimited Charters-এর ৭-ব্র্যান্ডের পরিবহন পোর্টফোলিওর ৫২৮,৩১৫টি WordPress পেজ Hugo-তে মাইগ্রেট করা হয় এবং Cloudflare-এর edge থেকে পরিবেশন করা হয়। প্রতিটি URL অক্ষুণ্ণ রাখা হয়েছে, প্রতিটি schema block যাচাই করা হয়েছে, আর ছয় মাস পর index recovery হয়েছে ১০ গুণ। এরপরের লেখাটি পুরো সত্যিটাই তুলে ধরে - প্রথমবার আমরা কী কী ভুল করেছিলাম, সেটিও বাদ যায়নি।
শুরুটা যেখানে - একটি index bleed, যা আমরা থামাতে পারিনি
মাইগ্রেশনের ছয় মাস আগে Unlimited Charters-এর মূল ব্র্যান্ডের Google index থেকে প্রতিদিন প্রায় ৪০০টি পেজ কমে যাচ্ছিল। কিছুই নষ্ট হয়নি। Search Console-এ কোনো coverage error ছিল না। Wordfence-ও পরিষ্কার ছিল। পেজগুলো তখনও ছিল, 200 OK দিয়ে পরিবেশিত হচ্ছিল এবং বৈধ meta-ও ছিল।
শুধু আর ranking হচ্ছিল না। Google ধীরে ধীরে পাতলা WordPress-জেনারেটেড doorway content index থেকে বাদ দিচ্ছিল। মার্চ ২০২৬-এর spam update এই পতন আরও ত্বরান্বিত করে। আগস্টে indexed পেজের সংখ্যা প্রায় ৪৪৪K spun Gen-1 পেজ থেকে কমে প্রায় ১৭K-তে নেমে আসে। অর্থাৎ লাইভ corpus-এর ৯৬% index collapse।
এটি কোনো WordPress plugin দিয়ে "ঠিক" করা যায় না। সমস্যা শব্দে ছিল না; সমস্যা ছিল container-এ। Google ক্রমশ stacked-plugin WordPress corpus - LiteSpeed + Yoast + Elementor + WooCommerce + একটি slider + একটি chat widget + একটি cache warmer + একটি form builder - কে প্রতি byte-এ কম signal-যুক্ত হিসেবে বিবেচনা করছে। প্রতিটি plugin নিজের প্রয়োজনমতো JS যোগ করে। প্রতিটি plugin database round-trip বাড়ায়। প্রতিটি plugin-এর schema নিয়ে নিজস্ব মত থাকে, যা অন্য plugin-এর schema-এর সঙ্গে বিরোধ তৈরি করে। ফলে সাইটটি দেখতে বাস্তব information architecture-এর মতো হলেও crawler-এর কাছে সেটি পড়তে থাকে একধরনের জগাখিচুড়ি হিসেবে।
মাইগ্রেশন কোনো পছন্দের বিষয় ছিল না। এটি ছিল জরুরি উদ্ধারকাজ।
বিল্ড পরিকল্পনা - আর যেসব ধারণাকে আমরা সত্যি ভেবেছিলাম, কিন্তু সেগুলো সত্যি ছিল না
কাগজে-কলমে পরিকল্পনা ছিল: source crawl করা, প্রতিটি URL-এর জন্য 1:1 Hugo output তৈরি করা, redirect map সংযুক্ত করা এবং সাইট চালু করা। বাস্তবে প্রথম কার্যকর বিল্ডে চারটি ভুল ধারণা মিশে ছিল।
ধারণা ১: "Preserve URLs" মানে প্রতিটি WordPress path Hugo-তে অপরিবর্তিতভাবে render হবে। ভুল। WordPress permalink structure নীরবে rewrite করে। /category/casino-shuttle/ এবং /casino-shuttle/ - দুটিই WP-তে কাজ করে। Hugo-তে একটিকে বেছে নিয়ে অন্যটিতে redirect দিতে হয়, আর সেই সিদ্ধান্ত হাজার হাজার internal link-কে প্রভাবিত করে। source markdown-এর internal cross-link নতুন করে লেখাতেই আমাদের পুরো এক দিন লেগেছে, যাতে কোনো পেজ non-canonical version-এ link না করে।
ধারণা ২: ২১টি WordPress plugin-এর প্রতিটিই বাস্তব কোনো সমস্যার সমাধান করত। এটিও ভুল। প্রতিটি plugin আসলে কী দিচ্ছে তা যাচাই করে দেখলাম, প্রায় এক-তৃতীয়াংশ কিছুই করছিল না (বছরের পর বছর ইনস্টল করা, কখনও ব্যবহার করা হয়নি) এবং আরেক-তৃতীয়াংশ এমন কাজ করছিল, যা Hugo নিজেই স্বাভাবিকভাবে করতে পারে। LiteSpeed Cache-এর কোনো বিকল্প দরকার নেই - cache-এর কাজ Cloudflare-ই করে। Yoast SEO-এর প্রকৃত মূল্য ছিল schema output; Hugo partial হিসেবে সেটি তৈরি করা যায় এবং subscription-এর প্রয়োজন থাকে না। শুধু WPML (multilingual) এবং WooCommerce (checkout) নিয়ে সত্যিকারের পরিকল্পনা দরকার হয়েছিল।
ধারণা ৩: একটি Hugo build যুক্তিসঙ্গত সময়ে ৫২৮K পেজ render করতে পারবে। না। প্রথম সরল build বন্ধ করার আগে ১১ ঘণ্টা চলেছিল। প্রতি পেজে Hugo দ্রুত হলেও ৫২৮K পেজের সম্পূর্ণ render graph RAM-এ ধরে রাখার memory footprint বিনামূল্যে নয়। সমাধান ছিল partitioning: corpus-কে চারটি tier-এ ভাগ করা - সবচেয়ে নতুন hub, মূল service page, state hub এবং গভীর long-tail - এবং প্রতিটিকে আলাদা cadence-এ rebuild করা। এখন full-corpus rebuild প্রায় ৭ ঘণ্টায় সম্পন্ন হয়।
ধারণা ৪: Redirect সহজ। প্রথম .htaccess-এ এমন একটি rewrite loop ছিল, যা live হওয়ার আগে কেউ ধরতে পারেনি। trailing slash canonicalize করার জন্য তৈরি pattern-টি প্রথম hop-এর পর নিজের target-কেই match করছিল। আমরা বিষয়টি ধরার আগে Cloudflare loop intercept করে প্রায় ৮ মিনিট 526 পরিবেশন করেছিল। সমাধান ছিল একটি lookahead - (?!rental-)-এর বদলে (?!rental[-/]) - এবং এখন এটি Wordpress Escape playbook-এর নিয়মিত ধাপ। যে কোনো rewrite target-এ slash থাকলে lookahead-এ slash-টিও অন্তর্ভুক্ত করতে হবে। বিস্তৃত debugging pattern জানতে দেখুন কীভাবে সঠিকভাবে page speed ঠিক করি।
প্রথম বিল্ডে যে CLS regression আমরা তৈরি করেছিলাম
staging build-এ PageSpeed বেশ ভালো ছিল - mobile-এ ৯৪+, CLS ০.০২, আর LCP ২.৫ সেকেন্ডের অনেক নিচে। তাই আমরা সাইট চালু করে দিই। কিন্তু production PageSpeed mobile-এ CLS ০.৩১ দেখায়। কিছু template-এ তা ০.৪২ পর্যন্ত উঠেছিল।
কারণ: Cloudflare-এর email obfuscation post-load অবস্থায় mailto: link rewrite করে একটি wrapper span যোগ করছিল। প্রতিটি wrapper সামান্য reflow ঘটাচ্ছিল। যেসব পেজে ৮টির বেশি contact link ছিল, সেখানে cumulative shift সীমা ছাড়িয়ে যায় এবং PageSpeed স্কোর কমিয়ে দেয়।
সমাধান করতে ৩০ সেকেন্ডই লেগেছিল - Cloudflare dashboard → Scrape Shield → Email Address Obfuscation → OFF। কিন্তু কোথায় খুঁজতে হবে, তা আমরা জানতাম না। নতুন Hugo সাইটে Cloudflare CLS যোগ করবে - এটি সন্দেহ করার কারণ নেই, কারণ HTML আপনি layout-stable করেই তৈরি করেছেন। WordPress developer-রা একে অপরকে এমন ফাঁদের কথা সাধারণত বলেন না, কারণ WordPress-এ অন্য সব shift-এর ভিড়ে এই shift আলাদা করে চোখেই পড়ে না।
দ্বিতীয় CLS regression ছিল web font swap। primary font-এ display=swap ব্যবহারের ফলে প্রায় ২০০ms-এ দৃশ্যমান reflow হচ্ছিল। সমাধান ছিল <link rel="preload" as="font" crossorigin> দিয়ে font preload করা এবং size-adjust ব্যবহার করে fallback font-এর metrics এমনভাবে নির্ধারণ করা, যাতে swap বোঝাই না যায়।
CLS staging-এ নয়, production-এ পরীক্ষা করুন। যেসব Cloudflare feature post-load content inject করে, Cloudflare সামনে না থাকলে staging origin-এ সেগুলো দেখা যায় না। প্রতিটি Hugo migration-এর launch checklist-এ ২৪ ঘণ্টার real-user CrUX watch থাকা উচিত।
৫২৮K পেজজুড়ে Schema.org - কেন এটিই শেষ পর্যন্ত সবচেয়ে বড় ranking lever হয়ে উঠল
WordPress-এ schema ছিল post-ভিত্তিক এবং অসামঞ্জস্যপূর্ণ। কিছু schema Yoast সামলাত। কিছু করত custom plugin। কিছু পেজে কিছুই ছিল না। বাস্তবে rich results পাওয়ার যোগ্যতা ছিল অনেকটা ভাগ্যের ব্যাপার।
Hugo-তে schema একটি partial। প্রতিটি template family-এর প্রতিটি পেজে একই @graph structure থাকে: Organization + WebSite + template-specific entity (Service, LocalBusiness, city hub-এর জন্য Product) + BreadcrumbList + যেখানে FAQ আছে সেখানে FAQPage। একবার validate করলেই ৫২৮K URL-এ তা প্রযোজ্য হয়।
ছয় মাস পর rich results পাওয়ার যোগ্যতায় প্রভাবটি নাটকীয়। প্রতিটি hub page FAQ-rich results-এর জন্য যোগ্য। প্রতিটি city page-এ LocalBusiness markup আছে, যা Google local pack-এর জন্য ব্যবহার করতে পারে। প্রতিটি service page-এ Service + Offer আছে, যা AI overview-এও দেখা যায়। এটি কোনো WordPress plugin subscription নয় - এটি Hugo template-এর ৪০ লাইনের code।
Stretch LLC-এর productization stack-এর একই schema partial library প্রতিটি customer-এর জন্য সরবরাহ করে। এটাই প্রতিযোগিতামূলক শক্তি।
llms.txt - যে LLM-search কৌশল আমরা না জেনেই তৈরি করেছিলাম
লঞ্চের সপ্তাহে site root-এ হাতে লেখা একটি /llms.txt তৈরি করেছিলাম। এটি ছিল checklist-এর একটি ধাপ, কোনো কৌশল নয়। দুই মাস পর Perplexity, Bing Copilot, Claude এবং ChatGPT পরিবহন-সম্পর্কিত query-তে UC পেজগুলোর নাম উল্লেখ করে citation দিতে শুরু করে।
পদ্ধতিটি হলো: LLM search engine-গুলো ক্রমশ llms.txt-কে traditional search-এর robots.txt + sitemap.xml-এর সম্মিলিত সংস্করণের মতো ব্যবহার করছে - কোনো সাইট কী নিয়ে এবং সেখানে কী আছে, তার হাতে লেখা index হিসেবে। WordPress-এ ভালো llms.txt তৈরি করতে এমন plugin দরকার, যা কেউ ভালোভাবে তৈরি করেনি। Hugo-তে এটি একটি মাত্র file।
আপনার traffic mix যদি শুধু Google-এর ওপর নির্ভর করে, তাহলে আপনি ইতিমধ্যেই পিছিয়ে আছেন। উচ্চ-intent commercial query-এর আনুমানিক ৩০% এখন LLM interface থেকে আসে। সেখানে discoverable হওয়ার জন্য llms.txt হলো সবচেয়ে কম খরচের কার্যকর পদক্ষেপগুলোর একটি। প্রতিটি Wordpress Escape migration-এ এটি default হিসেবে দেওয়া হয়।
যেসব Cloudflare setting সত্যিই গুরুত্বপূর্ণ ছিল
Cloudflare-এ শত শত toggle আছে। এই migration-এর জন্য ছয়টি গুরুত্বপূর্ণ ছিল:
- Cache Level: Cache Everything - static HTML-এর জন্য। Cookie থাকলে default হিসেবে bypass হয়; static HTML-এ cookie নেই, তাই এটি নিরাপদ এবং cache hit rate চারগুণ বাড়ায়।
- Browser Cache TTL: 4 hours। repeat visitor-এর জন্য যথেষ্ট দীর্ঘ, আবার re-deploy করলে একটি session-এর মধ্যেই পরিবর্তন ছড়িয়ে পড়ার মতো সংক্ষিপ্ত।
- Origin Cache Control: Respect। Hugo-কে নিজের Cache-Control পাঠাতে দিন, যাতে hashed asset-গুলো immutable এবং HTML must-revalidate থাকে।
- Auto Minify: OFF। Hugo ইতিমধ্যে minify করে। দুইবার minify করার ফলে একটি edge case-এ syntax error হয়েছিল।
- Rocket Loader: OFF। এটি script-এর ক্রম বদলে দেয় এবং schema validation নষ্ট করেছিল।
- Email Address Obfuscation: OFF। উপরের CLS section দেখুন।
প্রতিটি Wordpress Escape migration-এর launch checklist-এ Cloudflare configuration audit থাকে। ঠিক এই তালিকাটিই।
৪-tier partitioned rebuild - অপারেশনের গোপন কৌশল
কষ্ট ছাড়া একবারে ৫২৮K পেজ একক Hugo build-এ publish করা যায় না। partitioning scheme ছিল এমন:
- Tier 1 - Hubs (প্রায় ২০০ পেজ)। মূল city hub, state hub এবং homepage। প্রতি ৬ ঘণ্টায় rebuild হয়। এখানে কোনো content change হলে দ্রুত দেখা যায়।
- Tier 2 - Service pages (প্রায় ৪০K পেজ)। Party bus, wedding, corporate, shuttle, casino। প্রতি রাতে rebuild হয়।
- Tier 3 - State + long-tail Gen 4 (প্রায় ৫০K পেজ)। প্রতি ৪৮ ঘণ্টায় rebuild হয়।
- Tier 4 - Gen 1 spun long-tail (প্রায় ৪৪০K পেজ)। প্রতি সপ্তাহে rebuild হয়।
প্রতিটি tier build-এর নিজস্ব flock, timeout, log এবং alert আছে। Tier 4 আটকে গেলেও (একবার Imunify360 signature reload race-এর কারণে এমন হয়েছিল), Tier 1-3 নিয়মিত publish হতে থাকে এবং শুধু গভীর long-tail পুরোনো থাকে। user-facing কোনো অংশ ক্ষতিগ্রস্ত হয় না।
এটি WordPress করতে পারে না। WordPress প্রতিটি request-এ প্রতিটি পেজ rebuild করে। সেখানে partitioning নেই; আছে শুধু cache invalidation - যা computing-এর সবচেয়ে কঠিন সমস্যাগুলোর একটি হিসেবে পরিচিত।
ফলাফল - কী বদলেছে এবং কী বদলায়নি
cutover-এর ছয় মাস পর:
- Index count: প্রায় ১৭K → প্রায় ১৬৭K। ১০ গুণ recovery।
- PageSpeed mobile: গড়ে প্রায় ৪০ → প্রতিটি template family-তে ৯০+। Baltimore Trips নির্দিষ্টভাবে ৩৫ → ৯৯।
- TTFB: বিশ্বব্যাপী প্রায় ৮০০ms → প্রায় ৩০ms (Cloudflare edge)।
- Reviews: মূল ব্র্যান্ডে ১,২০০+ review জুড়ে ৪.৭ star, যা বাড়ছে।
- Sister brands: ছয়টি - Baltim, District, Philly, UCW, US Bus, Stretch XL - এখন একই Hugo stack থেকে পরিবেশিত হয়, কোনো site-specific drift ছাড়াই।
- Security incidents: cutover-এর পর WordPress-ধাঁচের incident শূন্য। কোনো wp-admin নেই।
যা বদলায়নি: content। প্রতিটি পেজে WordPress-এর সময়কার একই লেখা এবং মোটামুটি একই layout রয়েছে। migration ছিল container swap, rewrite নয়। বিষয়টি গুরুত্বপূর্ণ - কারণ এর মানে ফলাফল container-এর কারণে হয়েছে, নতুন content-এর কারণে নয়।
Productization - Stretch LLC এবং Wordpress Escape
UC migration চালানো playbook এখন দুই জায়গায় productized:
- stretch-llc.com - operator brand। এখানেই transportation-family case study থাকে এবং multi-site enterprise engagement শুরু হয়।
- wordpressescape.com - productized migration service। Single-domain এবং multi-domain migration চারটি tier-এ: DIY (বিনামূল্যের playbook), Assisted ($5K-$15K), Managed ($25K-$50K), Enterprise / Family ($100K+/yr retainer)।
আপনার WordPress site-এ index-bleed problem, plugin-security problem অথবা PageSpeed floor problem থাকলে বিনামূল্যের audit দিয়ে শুরু করুন। এটি ৬০ সেকেন্ডে চলে, আপনার প্রকৃত সংখ্যা জানায় এবং migration-এ কী অক্ষুণ্ণ থাকবে বনাম কী নতুন করে তৈরি হবে - তা স্পষ্টভাবে দেখায়। UC-এর quote দেওয়ার আগে আমরা একই tool ব্যবহার করেছিলাম।
আমরা কী ভিন্নভাবে করতাম
প্রতিটি migration কিছু না কিছু শেখায়। কতটা সময় বাঁচাতে পারত - সে অনুযায়ী তালিকাটি সাজানো হলো:
- CLS test-এর আগেই Cloudflare email obfuscation বন্ধ করা। এতে debugging-এর এক দিন বাঁচত।
- Redirect map-এর lookahead-এ সবসময় slash form রাখা। (?!rental-) নয়, (?!rental[-/])। দুই অক্ষরের fix, loop-debugging-এর কয়েক ঘণ্টা বাঁচত।
- প্রথম দিন থেকেই build partition করা। ১১ ঘণ্টার naive build ছিল শেখার একটি ধাপ, কিন্তু শুরুতেই partition করা উচিত ছিল এবং সেটি কখনও দেখতে হতো না।
- পরের ধাপ হিসেবে নয়, initial cutover-এই llms.txt publish করা। LLM-search traffic-এর দুই মাস শুরু থেকেই পাওয়া যেত।
- Launch checklist-এ real-user CrUX watch রাখা। staging PageSpeed production সম্পর্কে ভুল ধারণা দেয় ঠিক সেই কারণেই, যে কারণে staging site তৈরি করার সময় production-এর মতো দেখায় না - সামনে Cloudflare থাকে না।
এই পাঁচটি বিষয়ই পরবর্তী প্রতিটি Wordpress Escape migration-এর নিয়মিত অংশ করা হয়েছে।
Frequently asked questions
UC migration কোন Hugo version-এ চালু করা হয়েছিল?
Hugo v0.124 extended, builds চালানোর জন্য cron-সহ একটি standard cPanel VPS-এ চলছিল। বিশেষ কিছু নয়। Hugo বেছে নেওয়ার উদ্দেশ্যই ছিল toolchain-কে সহজ ও নির্ভরযোগ্য রাখা।
WordPress → Hugo migration-এ engineering time হিসেবে আসলে কত খরচ হয়েছিল?
প্রাথমিক ৫২৮,৩১৫-পেজের cutover end-to-end সম্পন্ন করতে পাঁচ কর্মদিবস লেগেছিল। চলমান operational burden সপ্তাহে আনুমানিক এক engineer-hour - build monitoring এবং content ops-এর জন্য।
WooCommerce-এর কী হয়েছিল?
WooCommerce বাদ দেওয়া হয়েছে। Payment flow সরিয়ে এমন একটি purpose-built checkout-এ নেওয়া হয়েছে, যা সরাসরি payment gateway-এর সঙ্গে যোগাযোগ করে। আপনার site যদি WooCommerce-এর ওপর ব্যাপকভাবে নির্ভরশীল হয়, তাহলে migration cost বেশি হবে এবং Managed tier-ই উপযুক্ত শুরু।
এটি কার্যকর করতে কি Cloudflare ব্যবহার করতেই হবে?
না, তবে ব্যবহার করা উচিত। Edge cache-ই TTFB-কে গুরুত্বহীন করে তোলে। Edge caching-সমৃদ্ধ যেকোনো CDN কাজ করবে; launch করার জন্য Cloudflare-এর free tier-ই যথেষ্ট।
৫২৮K পেজের চেয়ে ছোট site-এর জন্যও কি Wordpress Escape এই কাজ করতে পারে?
হ্যাঁ। অধিকাংশ engagement ১K-৫০K পেজের, এবং Assisted বা Managed tier-এ সম্পন্ন হয়। ৫২৮K case-টি সক্ষমতার প্রমাণ, minimum নয়।
WordPress → Hugo content extraction-এর জন্য কী ব্যবহার করেছিলেন?
WordPress database-এর ওপর custom extraction script ব্যবহার করা হয়েছিল, পাশাপাশি DB-তে ধরা না পড়া বিষয়গুলো খুঁজতে saturating Screaming Frog crawl চালানো হয়েছিল - যেমন custom-post-type edge case, plugin-generated page এবং spun long-tail। Hugo generation শুরুর আগে দুই পথের ফল মিলিয়ে নেওয়া হয়েছিল।
আপনার সাইটও একইভাবে উপযুক্ত কি না দেখুন
বিনামূল্যের ৬০-সেকেন্ডের অডিটে আপনার প্রকৃত PageSpeed স্কোর, সঠিক পেজ সংখ্যা, SEO ঘাটতি এবং কোন WordPress ফিচারগুলোর বিকল্প দরকার - সব দেখা যায়। এরপর Wordpress Escape আপনাকে Hugo-তে নতুন করে তৈরি করে, প্রতিটি URL অপরিবর্তিত রাখে এবং প্রথম দিন থেকেই সোর্স কোড আপনার হাতে তুলে দেয় - UC-কে যেভাবে পুনর্নির্মাণ করা হয়েছিল ঠিক সেভাবেই।
Scan my site free

