如何在CK Editor(RTE)中将链接锚点从#cuid改为#title-of-contentelement?
Hey there! Great question—you can absolutely achieve this using RTE configuration, typolink processors, or TYPO3 hooks depending on your use case. Let's break down each approach with actionable steps:
1. RTE (CKEditor) Configuration Adjustment
If you want to fix this at the source—so users generate title-based anchors right when inserting them in CKEditor—customizing the RTE is the best approach. We'll build a tiny custom CKEditor plugin to replace the default anchor behavior:
Step 1: Create the custom anchor plugin
In your extension, add a JavaScript file atResources/Public/JavaScript/CustomAnchor.jswith this logic:CKEDITOR.plugins.add('customanchor', { init: function(editor) { editor.addCommand('customanchor', { exec: function(editor) { var selectedText = editor.getSelection().getSelectedText(); // Convert selected text to a clean slug (lowercase, hyphens instead of spaces) var anchorSlug = selectedText.toLowerCase() .replace(/\s+/g, '-') .replace(/[^a-z0-9-]/g, ''); // Insert the anchor with our slug instead of a cuid editor.insertHtml('<a id="' + anchorSlug + '"></a>'); } }); // Replace the default Anchor button with our custom command editor.ui.addButton('Anchor', { label: 'Insert Anchor', command: 'customanchor', toolbar: 'links' }); } });Step 2: Register the plugin in your RTE config
Update your RTE YAML config (e.g.,Configuration/RTE/Default.yaml) to load the custom plugin and disable the default anchor plugin:editor: externalPlugins: customanchor: '/typo3conf/ext/your_extension/Resources/Public/JavaScript/CustomAnchor.js' config: removePlugins: 'anchor' extraPlugins: 'customanchor'Note: Replace
your_extensionwith your actual extension key.
2. Use a Typolink Processor
If you need to fix existing anchors (or anchors generated via TYPO3's internal link system), a typolink processor will modify the anchor during link rendering. This works for all links generated via typolink (like content element links):
Step 1: Register the processor in TypoScript
Add this to your extension'sConfiguration/TypoScript/setup.typoscript:typolink.processors { 10 = Vendor\YourExtension\LinkProcessing\CustomAnchorProcessor }Step 2: Build the processor class
CreateClasses/LinkProcessing/CustomAnchorProcessor.phpwith this logic (we'll map cuids to content element titles and convert them to slugs):<?php namespace Vendor\YourExtension\LinkProcessing; use TYPO3\CMS\Core\LinkHandling\LinkProcessorInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Database\ConnectionPool; class CustomAnchorProcessor implements LinkProcessorInterface { public function process(array $linkParameters, array $configuration): array { // Check if the fragment is a cuid (UUID format) if (isset($linkParameters['fragment']) && preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/', $linkParameters['fragment'])) { $cuid = $linkParameters['fragment']; // Fetch the content element's header using the cuid (adjust the table/field if needed) $contentElement = GeneralUtility::makeInstance(ConnectionPool::class) ->getConnectionForTable('tt_content') ->select(['header'], 'tt_content', ['uid' => $cuid]) ->fetchAssociative(); if ($contentElement) { // Convert header to a clean slug $slug = strtolower(preg_replace('/\s+/', '-', preg_replace('/[^a-zA-Z0-9\s]/', '', $contentElement['header']))); $linkParameters['fragment'] = $slug; } } return $linkParameters; } }
3. TYPO3 Hooks for Global Replacement
Hooks give you maximum flexibility—you can modify anchors when content is saved, or when it's rendered. Here are two common use cases:
Option A: Modify Anchors When Content is Saved
This ensures anchors are updated immediately when a content element is created/edited:
- Register the hook in
Configuration/TCA/Overrides/tt_content.php:$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['your_extension'] = \Vendor\YourExtension\Hooks\ContentElementSaveHook::class; - Create the hook class at
Classes/Hooks/ContentElementSaveHook.php:<?php namespace Vendor\YourExtension\Hooks; use TYPO3\CMS\Core\DataHandling\DataHandler; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Database\ConnectionPool; class ContentElementSaveHook { public function processDatamap_postProcessFieldArray($status, $table, $id, &$fieldArray, DataHandler &$pObj) { if ($table === 'tt_content' && isset($fieldArray['header'])) { $header = $fieldArray['header']; $slug = strtolower(preg_replace('/\s+/', '-', preg_replace('/[^a-zA-Z0-9\s]/', '', $header))); // Replace any cuid anchors in the bodytext with our slug if (isset($fieldArray['bodytext'])) { // If it's a new record, $id will be a temporary string—we'll skip that for now if (is_numeric($id)) { $fieldArray['bodytext'] = str_replace('#' . $id, '#' . $slug, $fieldArray['bodytext']); } } } } }
Option B: Replace Anchors During RTE Rendering
This modifies anchors right before content is displayed on the frontend:
- Register the hook in TypoScript:
lib.parseFunc_RTE { hooks { postProcess = Vendor\YourExtension\Hooks\RteRenderHook->postProcess } } - Create the hook class at
Classes/Hooks/RteRenderHook.php:<?php namespace Vendor\YourExtension\Hooks; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Database\ConnectionPool; class RteRenderHook { public function postProcess(&$value, $conf, $obj) { // Match all #cuid anchors and replace them with title slugs $value = preg_replace_callback('/#([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/', function($matches) { $cuid = $matches[1]; $contentElement = GeneralUtility::makeInstance(ConnectionPool::class) ->getConnectionForTable('tt_content') ->select(['header'], 'tt_content', ['uid' => $cuid]) ->fetchAssociative(); if ($contentElement) { $slug = strtolower(preg_replace('/\s+/', '-', preg_replace('/[^a-zA-Z0-9\s]/', '', $contentElement['header']))); return '#' . $slug; } return $matches[0]; // Fallback to original if no content element found }, $value); } }
Which Approach Should You Use?
- RTE Configuration: Best for preventing cuid anchors from being inserted in the first place (user-facing fix).
- Typolink Processor: Ideal for batch-fixing existing internal links generated via TYPO3's link system.
- Hooks: Most flexible—use when you need to modify anchors during content save or rendering for edge cases.
内容的提问来源于stack exchange,提问作者Markus Dübbert

