diff --git a/redirects.map b/redirects.map new file mode 100644 index 0000000..cb48541 --- /dev/null +++ b/redirects.map @@ -0,0 +1,64 @@ +5 /features +7 /contact-us +11 /about-us +21 /blog/21 +28 /blog/inbound-calls-outbound-calls-and-email-blended +36 /blog/agents-anywhere +67 /comparisons +69 /vicihost-vs-justgocloud +75 /vicihost-vs-ytel +82 /vicihost-vs-five9 +94 /contact-form-error +96 /contact-form-success +107 /blog/agent-avatar-soundboards +131 /blog/high-level-data-encryption +157 /skills-based-routing-with-agent-ranking +164 /outbound-agent-controlled-broadcast-and-predictive-dialing +168 /integrated-call-recording +171 /three-way-calling-within-the-agent-screen +174 /scheduled-callbacks-agent-only-and-anyone +179 /web-configurable-ivrs-and-voicemail-boxes +182 /virtually-limitless-campaigns-lists-ivrs-inbound-queues +185 /immediate-or-scheduled-website-callbacks +188 /real-time-reports-with-click-to-listen-to-monitor-agent-phone-calls +191 /easy-importing-of-calling-lists-through-the-web-by-api-or-scheduled-by-ftp +203 /integrated-web-based-agent-phone-included-requires-no-agent-setup +206 /local-toll-free-and-international-inbound-phone-numbers-available +216 /full-usa-canada-and-uk-regulatory-compliance +219 /cellphone-filtering-for-tcpa-compliance +223 /ability-to-have-recordings-automatically-transferred-to-an-external-ftp-site +226 /quality-control-module-available +230 /pbx-features-allow-you-to-use-your-system-as-your-office-pbx +235 /included-support-time +238 /no-hidden-fees +241 /99-9-up-time-guarantee +244 /scalable-to-hundreds-of-logged-in-agents +247 /dedicated-dialing-server-hardware +250 /single-server-guaranteed-to-handle-at-least-25-agents-at-31-line-ratio +253 /moving-hosted-to-on-site-or-on-site-to-hosted +256 /month-to-month-terms-no-long-term-contracts +259 /agent-scripting-with-customer-data +262 /system-wide-per-campaign-and-inbound-dnc-lists +274 /internal-chat-and-broadcast-messaging-to-agents +286 /available-languages +294 /zoiper-webphone +301 /blog/crm-integration +324 /auto-generate-call-lists-based-on-dropped-inbound-queued-calls +327 /computer-ip-address-access-restrictions-for-web-resources +330 /dozens-of-standard-reports-which-can-be-emailed-out-on-a-set-schedule +350 /share-lead-data-across-vicidial-clusters-instantly-when-calls-are-transferred +354 /remote-api-control-of-agent-screens +372 /gdpr-compliance +376 /inbound-and-advanced-forecasting-reports +380 /inbound-post-call-customer-survey +383 /inbound-queue-preserve-place-in-line +386 /custom-data-field-forms-with-switchable-forms +390 /dnc-com-lead-filtering-and-inbound-call-filtering +395 /inbound-queue-closing-time-features +398 /outbound-callerid-groups-per-state-or-per-areacode +417 /call-quota-lead-ranking-for-multiple-contact-attempts +423 /multiple-configurable-options-for-leaving-messages-on-customer-voicemail-boxes +437 /two-factor-authentication-for-admin-web-users +441 /multi-country-international-dnc-list-filtering +452 /24-hour-called-count-limit-campaign-feature +475 /your-caller-id-numbers-and-spamscam-labels diff --git a/scripts/export-wp.mjs b/scripts/export-wp.mjs index e0caa0e..6c80b38 100644 --- a/scripts/export-wp.mjs +++ b/scripts/export-wp.mjs @@ -30,6 +30,7 @@ const UPLOADS_DEST = path.join(ROOT, 'src/assets/uploads'); const PAGES_DEST = path.join(ROOT, 'src/content/pages'); const POSTS_DEST = path.join(ROOT, 'src/content/posts'); const NAV_DEST = path.join(ROOT, 'src/data/nav.json'); +const REDIRECTS_DEST = path.join(ROOT, 'redirects.map'); const turndown = new TurndownService({ headingStyle: 'atx', codeBlockStyle: 'fenced' }); @@ -136,6 +137,17 @@ async function buildLinkMap(conn) { return new Map(rows.map((r) => [r.ID, r.post_type === 'post' ? `/blog/${r.post_name}` : `/${r.post_name}`])); } +// Apache RewriteMap (txt type) file: "" per line, one for every published +// page/post, not just the ones referenced from other content -- anyone on the web could have +// bookmarked or linked to any of them via the old ?page_id=N / ?p=N plain-permalink URLs. +async function writeRedirectMap(linkMap) { + const lines = [...linkMap.entries()] + .sort(([a], [b]) => a - b) + .map(([id, target]) => `${id} ${target}`); + await fs.writeFile(REDIRECTS_DEST, `${lines.join('\n')}\n`); + console.log(`Wrote ${linkMap.size} redirect entries to ${REDIRECTS_DEST}`); +} + async function copyAttachments() { // Copy the whole uploads tree rather than just the 82 attachment rows: WordPress generates // multiple resized variants per image (e.g. "-1008x1024.png") that content tags/srcsets @@ -251,6 +263,7 @@ async function main() { await copyAttachments(); const linkMap = await buildLinkMap(conn); const unresolved = new Set(); + await writeRedirectMap(linkMap); await exportPostType(conn, 'page', PAGES_DEST, { attachmentPaths, thumbnails, linkMap, unresolved }); await exportPostType(conn, 'post', POSTS_DEST, { attachmentPaths, thumbnails, linkMap, unresolved });