{"id":76,"date":"2026-10-21T17:00:00","date_gmt":"2026-10-21T15:00:00","guid":{"rendered":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/"},"modified":"2026-10-16T14:00:12","modified_gmt":"2026-10-16T12:00:12","slug":"replacing-realurl-with-site-configuration-slugs-and-redirects","status":"publish","type":"post","link":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/","title":{"rendered":"Replacing realurl with site configuration, slugs and redirects"},"content":{"rendered":"<p>Hi folks,<\/p>\n<p>When I moved my own site hoja.in from TYPO3 7.6 to a fresh TYPO3 14.3 project this year, one extension worried me more than the others: realurl. For years it built every speaking URL of the site. In TYPO3 14 it simply does not exist, and since 9.5 the core has its own routing with site configuration and page slugs. The code part of the move is easy. The scary part is the URLs that Google, old emails and other people&#8217;s bookmarks still point to. They must not break.<\/p>\n<p>In this post I show what I did: read what realurl really produced, let the core generate slugs, keep the old paths alive with redirects, and check the status codes with curl instead of trusting my eyes.<\/p>\n<h2>Problems I faced<\/h2>\n<p>realurl had a habit of hiding its decisions. Mine used <code>realurl_autoconf.php<\/code>, the file realurl writes itself, so nobody had looked at it for years. Before deleting anything I opened it from the legacy copy:<\/p>\n<pre><code class=\"language-php\">$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl'] = [\n    'hoja.in' =&gt; [\n        'init' =&gt; [\n            'appendMissingSlash' =&gt; 'ifNotFile,redirect',\n            'emptyUrlReturnValue' =&gt; '\/',\n        ],\n        'pagePath' =&gt; ['rootpage_id' =&gt; '6'],\n        'fileName' =&gt; [\n            'defaultToHTMLsuffixOnPrev' =&gt; 0,\n            'acceptHTMLsuffix' =&gt; 1,\n        ],\n    ],\n];<\/code><\/pre>\n<p>Three facts came out of it. The root page was uid 6. URLs ended with a slash, like <code>\/about\/<\/code>. And realurl also <em>accepted<\/em> <code>\/about.html<\/code>, even if it never generated it. So the new site has to answer for three shapes of the same page.<\/p>\n<h2>Step 1: the site configuration<\/h2>\n<p>In TYPO3 14 the site lives in <code>config\/sites\/main\/config.yaml<\/code>. For hoja.in it is short, because the site is one language and has no plugins with URL parameters:<\/p>\n<pre><code class=\"language-yaml\">rootPageId: 6\nbase: 'https:\/\/hoja.in\/'\nbaseVariants:\n  -\n    base: 'https:\/\/myport.ddev.site\/'\n    condition: 'applicationContext == \"Development\/Ddev\"'\nwebsiteTitle: 'hoja.in'\ndependencies:\n  - harvisoft\/sitepackage\nlanguages:\n  -\n    title: English\n    enabled: true\n    languageId: 0\n    base: \/\n    locale: en_US.UTF-8\n    hreflang: en-US<\/code><\/pre>\n<p>The <code>baseVariants<\/code> entry is what lets the same file work in DDEV and on the server. No route enhancers are needed here. If your old realurl config appended <code>.html<\/code> to every page and you want to keep that, the core has the <code>PageType<\/code> decorator for it:<\/p>\n<pre><code class=\"language-yaml\">routeEnhancers:\n  PageTypeSuffix:\n    type: PageType\n    default: '.html'\n    map:\n      '.html': 0<\/code><\/pre>\n<p>I did not use it. Keeping a suffix forever only to match an old extension felt wrong when the old site itself did not generate it.<\/p>\n<h2>Step 2: generate the slugs like the backend does<\/h2>\n<p>The content came over with an import script, not with the seven-hop upgrade chain, so the <code>pages.slug<\/code> field started empty. I did not want to invent slugs by hand. TYPO3 has <code>SlugHelper<\/code>, which is the same class the backend uses when an editor saves a page. The import script calls it for every page and then makes the result unique inside the site:<\/p>\n<pre><code class=\"language-php\">$slugHelper = GeneralUtility::makeInstance(\n    SlugHelper::class,\n    'pages',\n    'slug',\n    $GLOBALS['TCA']['pages']['columns']['slug']['config']\n);\nforeach ($pageUids as $uid) {\n    $record = BackendUtility::getRecord('pages', $uid);\n    $slug = $uid === ROOT_PAGE ? '\/' : $slugHelper-&gt;generate($record, (int)$record['pid']);\n    $state = RecordStateFactory::forName('pages')\n        -&gt;fromArray($record, (int)$record['pid'], $uid);\n    $slug = $slugHelper-&gt;buildSlugForUniqueInSite($slug, $state);\n    $connection-&gt;update('pages', ['slug' =&gt; $slug], ['uid' =&gt; $uid]);\n}<\/code><\/pre>\n<p>The real script fetches the record with a QueryBuilder without restrictions, because hidden pages need slugs too, but the idea is the same. Because the slug config uses the page title, &#8220;About&#8221; became <code>\/about<\/code>, which is exactly the old path without the slash. Lucky me.<\/p>\n<h2>Step 3: redirects for everything else<\/h2>\n<p>EXT:redirects stores redirects in the table <code>sys_redirect<\/code>, and its middleware runs before the page is resolved. That means a redirect wins even if a page with the same path exists. For a handful of URLs you can use the Redirects backend module. For a list from an old sitemap or a log file, I prefer a small command, so the mapping lives in a CSV file in git and can be reviewed.<\/p>\n<pre><code class=\"language-php\">&lt;?php\n\ndeclare(strict_types=1);\n\nnamespace HarvisoftSitepackageCommand;\n\nuse SymfonyComponentConsoleAttributeAsCommand;\nuse SymfonyComponentConsoleCommandCommand;\nuse SymfonyComponentConsoleInputInputArgument;\nuse SymfonyComponentConsoleInputInputInterface;\nuse SymfonyComponentConsoleOutputOutputInterface;\nuse TYPO3CMSCoreDatabaseConnectionPool;\nuse TYPO3CMSRedirectsServiceRedirectCacheService;\n\n#[AsCommand('sitepackage:redirects:import', 'Creates 301 redirects from a CSV file: old path, page uid')]\nfinal class ImportRedirectsCommand extends Command\n{\n    public function __construct(\n        private readonly ConnectionPool $connectionPool,\n        private readonly RedirectCacheService $redirectCacheService,\n    ) {\n        parent::__construct();\n    }\n\n    protected function configure(): void\n    {\n        $this-&gt;addArgument('file', InputArgument::REQUIRED, 'CSV file');\n        $this-&gt;addArgument('host', InputArgument::OPTIONAL, 'Source host', '*');\n    }\n\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        $connection = $this-&gt;connectionPool-&gt;getConnectionForTable('sys_redirect');\n        $host = (string)$input-&gt;getArgument('host');\n        $created = 0;\n\n        $file = new SplFileObject((string)$input-&gt;getArgument('file'));\n        $file-&gt;setFlags(SplFileObject::READ_CSV | SplFileObject::SKIP_EMPTY | SplFileObject::READ_AHEAD);\n        $file-&gt;setCsvControl(',', '\"', '');\n\n        foreach ($file as $row) {\n            [$path, $pageUid] = array_map('trim', $row) + [1 =&gt; ''];\n            if ($path === '' || str_starts_with($path, '#') || (int)$pageUid === 0) {\n                continue;\n            }\n            $exists = $connection-&gt;count('uid', 'sys_redirect', [\n                'source_host' =&gt; $host,\n                'source_path' =&gt; $path,\n                'deleted' =&gt; 0,\n            ]);\n            if ($exists &gt; 0) {\n                continue;\n            }\n            $connection-&gt;insert('sys_redirect', [\n                'pid' =&gt; 0,\n                'createdon' =&gt; time(),\n                'updatedon' =&gt; time(),\n                'source_host' =&gt; $host,\n                'source_path' =&gt; $path,\n                'target' =&gt; 't3:\/\/page?uid=' . (int)$pageUid,\n                'target_statuscode' =&gt; 301,\n                'force_https' =&gt; 1,\n            ]);\n            $created++;\n        }\n\n        \/\/ Redirects are cached per host; rows inserted by SQL are not seen until the cache is rebuilt\n        $this-&gt;redirectCacheService-&gt;rebuildForHost($host);\n        $output-&gt;writeln(sprintf('%d redirects created.', $created));\n\n        return Command::SUCCESS;\n    }\n}<\/code><\/pre>\n<p>Two details matter. The target is a <code>t3:\/\/page<\/code> link, so the redirect still works when somebody renames the page later. And the redirect cache must be rebuilt, otherwise you insert rows and wonder why nothing happens. The command is registered by its <code>#[AsCommand]<\/code> attribute as long as the extension has the usual <code>Configuration\/Services.yaml<\/code> with <code>autowire<\/code> and <code>autoconfigure<\/code> enabled.<\/p>\n<p>The CSV is boring on purpose:<\/p>\n<pre><code class=\"language-text\"># old path, page uid\n\/about.html,7\n\/resume.html,10\n\/contact.html,13<\/code><\/pre>\n<pre><code class=\"language-bash\">ddev exec vendor\/bin\/typo3 sitepackage:redirects:import redirects.csv<\/code><\/pre>\n<p>Run it against a copy with a fresh dump first. Writing to the database is the one step git cannot undo.<\/p>\n<h2>Step 4: check status codes, not screenshots<\/h2>\n<p>A page that &#8220;looks fine&#8221; in the browser can still be a 404 with a nice error page, or a 302 where you wanted a 301. So I ask curl:<\/p>\n<pre><code class=\"language-bash\">for path in \/about \/about\/ \/about.html \/contact\/ '\/index.php?id=7'; do\n  printf '%-18s ' \"$path\"\n  curl -sk -o \/dev\/null -w '%{http_code} %{redirect_url}n' \"https:\/\/myport.ddev.site$path\"\ndone<\/code><\/pre>\n<p>Before the redirects, my local copy answered like this: <code>\/about<\/code>, <code>\/about\/<\/code>, <code>\/contact\/<\/code> and <code>\/index.php?id=7<\/code> with 200, and <code>\/about.html<\/code> with 404. The trailing slash version still resolves, so the old realurl links keep working, and the canonical tag tells search engines which URL counts (on hoja.in the section pages even point to the one-page root, because that is where their content is shown). The <code>.html<\/code> variant is honestly still open on my list: realurl accepted it, but I have no proof anybody ever linked to it. The CSV above is ready for the day the server log shows those requests.<\/p>\n<p>The bigger check was the smoke test. Before touching anything, I captured status code, size and title of the old 7.6 site&#8217;s URLs as a baseline, and after the move the same URLs were compared against it. All of them answered 200 with the expected titles. That baseline gave me more peace of mind than any amount of clicking.<\/p>\n<h2>What I would do again<\/h2>\n<ul>\n<li>Read the realurl config before deleting the extension. It tells you which URL shapes exist in the wild.<\/li>\n<li>Let <code>SlugHelper<\/code> generate slugs instead of writing them by hand.<\/li>\n<li>Keep the old-path mapping in a file in git and import it with a command.<\/li>\n<li>Prove the result with curl and a baseline, not with a screenshot.<\/li>\n<\/ul>\n<p>If this post helped you, I will be really happy. Cheers!<\/p>\n<h2>Further reading<\/h2>\n<ul>\n<li><a href=\"https:\/\/docs.typo3.org\/m\/typo3\/reference-coreapi\/main\/en-us\/ApiOverview\/Routing\/Index.html\">TYPO3 documentation: Routing<\/a><\/li>\n<li><a href=\"https:\/\/docs.typo3.org\/m\/typo3\/reference-coreapi\/main\/en-us\/ApiOverview\/SiteHandling\/Index.html\">TYPO3 documentation: Site handling<\/a><\/li>\n<li><a href=\"https:\/\/docs.typo3.org\/c\/typo3\/cms-redirects\/main\/en-us\/\">EXT:redirects manual<\/a><\/li>\n<li><a href=\"https:\/\/docs.typo3.org\/m\/typo3\/reference-coreapi\/main\/en-us\/ApiOverview\/CommandControllers\/Index.html\">TYPO3 documentation: Console commands<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>My old TYPO3 7.6 site got its URLs from realurl. Here is how I moved them to site configuration, slugs and sys_redirect records in TYPO3 14, and checked every URL with curl.<\/p>\n","protected":false},"author":1,"featured_media":77,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17],"tags":[41,5,24,25],"class_list":["post-76","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-typo3","tag-seo","tag-typo3","tag-typo3-v14","tag-upgrades"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Replacing realurl with site config, slugs and redirects<\/title>\n<meta name=\"description\" content=\"Move a TYPO3 7.6 realurl setup to TYPO3 14: site configuration, generated page slugs, sys_redirect records from a small command and curl checks.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Replacing realurl with site config, slugs and redirects\" \/>\n<meta property=\"og:description\" content=\"Move a TYPO3 7.6 realurl setup to TYPO3 14: site configuration, generated page slugs, sys_redirect records from a small command and curl checks.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/\" \/>\n<meta property=\"og:site_name\" content=\"Hoja Mustaffa Abdul Latheef \u2013 Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-21T15:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/hoja.in\/blog\/wp-content\/uploads\/2026\/10\/replacing-realurl-with-site-configuration-slugs-and-redirects.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Hoja Mustaffa Abdul Latheef\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@hojaonline\" \/>\n<meta name=\"twitter:site\" content=\"@hojaonline\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Hoja Mustaffa Abdul Latheef\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/replacing-realurl-with-site-configuration-slugs-and-redirects\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/replacing-realurl-with-site-configuration-slugs-and-redirects\\\/\"},\"author\":{\"name\":\"Hoja Mustaffa Abdul Latheef\",\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#\\\/schema\\\/person\\\/e6fbd54c2061674d8ea3e7861d858c7b\"},\"headline\":\"Replacing realurl with site configuration, slugs and redirects\",\"datePublished\":\"2026-10-21T15:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/replacing-realurl-with-site-configuration-slugs-and-redirects\\\/\"},\"wordCount\":848,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#\\\/schema\\\/person\\\/e6fbd54c2061674d8ea3e7861d858c7b\"},\"image\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/replacing-realurl-with-site-configuration-slugs-and-redirects\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/hoja.in\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/replacing-realurl-with-site-configuration-slugs-and-redirects.jpg\",\"keywords\":[\"SEO\",\"TYPO3\",\"TYPO3 v14\",\"Upgrades\"],\"articleSection\":[\"TYPO3\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/hoja.in\\\/blog\\\/replacing-realurl-with-site-configuration-slugs-and-redirects\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/replacing-realurl-with-site-configuration-slugs-and-redirects\\\/\",\"url\":\"https:\\\/\\\/hoja.in\\\/blog\\\/replacing-realurl-with-site-configuration-slugs-and-redirects\\\/\",\"name\":\"Replacing realurl with site config, slugs and redirects\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/replacing-realurl-with-site-configuration-slugs-and-redirects\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/replacing-realurl-with-site-configuration-slugs-and-redirects\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/hoja.in\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/replacing-realurl-with-site-configuration-slugs-and-redirects.jpg\",\"datePublished\":\"2026-10-21T15:00:00+00:00\",\"description\":\"Move a TYPO3 7.6 realurl setup to TYPO3 14: site configuration, generated page slugs, sys_redirect records from a small command and curl checks.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/replacing-realurl-with-site-configuration-slugs-and-redirects\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/hoja.in\\\/blog\\\/replacing-realurl-with-site-configuration-slugs-and-redirects\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/replacing-realurl-with-site-configuration-slugs-and-redirects\\\/#primaryimage\",\"url\":\"https:\\\/\\\/hoja.in\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/replacing-realurl-with-site-configuration-slugs-and-redirects.jpg\",\"contentUrl\":\"https:\\\/\\\/hoja.in\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/replacing-realurl-with-site-configuration-slugs-and-redirects.jpg\",\"width\":1200,\"height\":630,\"caption\":\"Goodbye realurl, hello slugs\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/replacing-realurl-with-site-configuration-slugs-and-redirects\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/hoja.in\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Replacing realurl with site configuration, slugs and redirects\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/hoja.in\\\/blog\\\/\",\"name\":\"Hoja Mustaffa Abdul Latheef \u2013 Blog\",\"description\":\"Notes from daily work with TYPO3, PHP and AI-assisted engineering\",\"publisher\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#\\\/schema\\\/person\\\/e6fbd54c2061674d8ea3e7861d858c7b\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/hoja.in\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#\\\/schema\\\/person\\\/e6fbd54c2061674d8ea3e7861d858c7b\",\"name\":\"Hoja Mustaffa Abdul Latheef\",\"logo\":{\"@id\":\"https:\\\/\\\/hoja.in\\\/blog\\\/#\\\/schema\\\/person\\\/image\\\/\"},\"description\":\"Senior TYPO3 Developer at jweiland.net, TYPO3 CMS Certified Developer. I write about TYPO3 upgrades, extension development, PHP and AI-assisted engineering with Claude Code.\",\"sameAs\":[\"https:\\\/\\\/hoja.in\\\/\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Replacing realurl with site config, slugs and redirects","description":"Move a TYPO3 7.6 realurl setup to TYPO3 14: site configuration, generated page slugs, sys_redirect records from a small command and curl checks.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/","og_locale":"en_US","og_type":"article","og_title":"Replacing realurl with site config, slugs and redirects","og_description":"Move a TYPO3 7.6 realurl setup to TYPO3 14: site configuration, generated page slugs, sys_redirect records from a small command and curl checks.","og_url":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/","og_site_name":"Hoja Mustaffa Abdul Latheef \u2013 Blog","article_published_time":"2026-10-21T15:00:00+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/hoja.in\/blog\/wp-content\/uploads\/2026\/10\/replacing-realurl-with-site-configuration-slugs-and-redirects.jpg","type":"image\/jpeg"}],"author":"Hoja Mustaffa Abdul Latheef","twitter_card":"summary_large_image","twitter_creator":"@hojaonline","twitter_site":"@hojaonline","twitter_misc":{"Written by":"Hoja Mustaffa Abdul Latheef","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/#article","isPartOf":{"@id":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/"},"author":{"name":"Hoja Mustaffa Abdul Latheef","@id":"https:\/\/hoja.in\/blog\/#\/schema\/person\/e6fbd54c2061674d8ea3e7861d858c7b"},"headline":"Replacing realurl with site configuration, slugs and redirects","datePublished":"2026-10-21T15:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/"},"wordCount":848,"commentCount":0,"publisher":{"@id":"https:\/\/hoja.in\/blog\/#\/schema\/person\/e6fbd54c2061674d8ea3e7861d858c7b"},"image":{"@id":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/#primaryimage"},"thumbnailUrl":"https:\/\/hoja.in\/blog\/wp-content\/uploads\/2026\/10\/replacing-realurl-with-site-configuration-slugs-and-redirects.jpg","keywords":["SEO","TYPO3","TYPO3 v14","Upgrades"],"articleSection":["TYPO3"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/","url":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/","name":"Replacing realurl with site config, slugs and redirects","isPartOf":{"@id":"https:\/\/hoja.in\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/#primaryimage"},"image":{"@id":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/#primaryimage"},"thumbnailUrl":"https:\/\/hoja.in\/blog\/wp-content\/uploads\/2026\/10\/replacing-realurl-with-site-configuration-slugs-and-redirects.jpg","datePublished":"2026-10-21T15:00:00+00:00","description":"Move a TYPO3 7.6 realurl setup to TYPO3 14: site configuration, generated page slugs, sys_redirect records from a small command and curl checks.","breadcrumb":{"@id":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/#primaryimage","url":"https:\/\/hoja.in\/blog\/wp-content\/uploads\/2026\/10\/replacing-realurl-with-site-configuration-slugs-and-redirects.jpg","contentUrl":"https:\/\/hoja.in\/blog\/wp-content\/uploads\/2026\/10\/replacing-realurl-with-site-configuration-slugs-and-redirects.jpg","width":1200,"height":630,"caption":"Goodbye realurl, hello slugs"},{"@type":"BreadcrumbList","@id":"https:\/\/hoja.in\/blog\/replacing-realurl-with-site-configuration-slugs-and-redirects\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/hoja.in\/blog\/"},{"@type":"ListItem","position":2,"name":"Replacing realurl with site configuration, slugs and redirects"}]},{"@type":"WebSite","@id":"https:\/\/hoja.in\/blog\/#website","url":"https:\/\/hoja.in\/blog\/","name":"Hoja Mustaffa Abdul Latheef \u2013 Blog","description":"Notes from daily work with TYPO3, PHP and AI-assisted engineering","publisher":{"@id":"https:\/\/hoja.in\/blog\/#\/schema\/person\/e6fbd54c2061674d8ea3e7861d858c7b"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/hoja.in\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/hoja.in\/blog\/#\/schema\/person\/e6fbd54c2061674d8ea3e7861d858c7b","name":"Hoja Mustaffa Abdul Latheef","logo":{"@id":"https:\/\/hoja.in\/blog\/#\/schema\/person\/image\/"},"description":"Senior TYPO3 Developer at jweiland.net, TYPO3 CMS Certified Developer. I write about TYPO3 upgrades, extension development, PHP and AI-assisted engineering with Claude Code.","sameAs":["https:\/\/hoja.in\/"]}]}},"_links":{"self":[{"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/posts\/76","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/comments?post=76"}],"version-history":[{"count":1,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/posts\/76\/revisions"}],"predecessor-version":[{"id":161,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/posts\/76\/revisions\/161"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/media\/77"}],"wp:attachment":[{"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/media?parent=76"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/categories?post=76"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hoja.in\/blog\/wp-json\/wp\/v2\/tags?post=76"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}