diff --git a/cleanup-orphaned-page-folders.md b/cleanup-orphaned-page-folders.md
new file mode 100644
index 0000000..99bc02c
--- /dev/null
+++ b/cleanup-orphaned-page-folders.md
@@ -0,0 +1,173 @@
+---
+
+title: "Clean up orphaned page folders and their content"
+
+---
+
+version: 1.0.0
+
+---
+
+authors: Olaf Gleba
+
+---
+
+tags: pages, files
+
+---
+
+date: 2026-01-25
+
+---
+
+
+
+## Problem
+
+For your new project you duplicate a old installation so you don't have to start from scratch. While building the new website your `assets/files` folder gets messy,- there are a growing number of orphaned page id folders with obsolete content you want to get rid of.
+
+## Solution
+
+Create a new document, copy&paste the code below, save it to the root of your PW installation and open it in a browser. Initially it performs a dry run, so your are save before actual deletion take place.
+
+Because we are dealing with actual files, make a backup of you `files` folder and double check the output results before changing the mode.
+
+```php
+Orphaned page folder cleanup
";
+echo "Mode: " . ($dryRun ? "DRY RUN - NO DELETION" : "LIVE - ACTUAL DELETION") . "
";
+
+/**
+ * Load existing Page-Ids from database
+ */
+$existingPageIds = [];
+
+$sql = $database->query("SELECT id FROM pages");
+while ($row = $sql->fetch(\PDO::FETCH_ASSOC)) {
+ $existingPageIds[(int)$row['id']] = true;
+}
+
+// Print to browser
+echo "Existing pages loaded: " . count($existingPageIds) . "
";
+
+/**
+ * Iterate over the `files` folder
+ */
+// Get files root
+$filesRoot = realpath($config->paths->files);
+
+$removedFolders = 0;
+
+$dirs = scandir($filesRoot);
+
+foreach ($dirs as $dir) {
+
+ // Only nummeric folders (Page-IDs)
+ if (!ctype_digit($dir)) {
+ continue;
+ }
+
+ $pageId = (int)$dir;
+ $pageDir = $filesRoot . DIRECTORY_SEPARATOR . $dir;
+
+ if (!is_dir($pageDir)) {
+ continue;
+ }
+
+ // Skip if page exists
+ if (isset($existingPageIds[$pageId])) {
+ continue;
+ }
+
+ // Print to browser
+ echo "Orphaned page folder: {$pageDir}
";
+
+ // List folder files
+ $iterator = new \RecursiveIteratorIterator(
+ new \RecursiveDirectoryIterator(
+ $pageDir,
+ \FilesystemIterator::SKIP_DOTS
+ ),
+ \RecursiveIteratorIterator::CHILD_FIRST
+ );
+
+ foreach ($iterator as $item) {
+ if ($item->isFile()) {
+ echo " File: " . $item->getRealPath() . "
";
+ }
+ }
+
+ // Delete folder (if args `--delete` is present, s.above)
+ if (!$dryRun) {
+ deleteDirectory($pageDir);
+ echo " FOLDER DELETED
";
+ } else {
+ echo " (DRY RUN - NO DELETION)
";
+ }
+
+ echo "
";
+ $removedFolders++;
+}
+
+/**
+ * Print summary to browser
+ */
+echo "";
+echo "---------------------------------
";
+echo "Done
";
+echo "Orphaned page folders: {$removedFolders}
";
+echo "---------------------------------
";
+echo "
";
+
+/**
+ * Recursive deletion
+ */
+function deleteDirectory(string $dir): void
+{
+ if (!is_dir($dir)) {
+ return;
+ }
+
+ $items = scandir($dir);
+
+ foreach ($items as $item) {
+ if ($item === '.' || $item === '..') {
+ continue;
+ }
+
+ $path = $dir . DIRECTORY_SEPARATOR . $item;
+
+ if (is_dir($path)) {
+ deleteDirectory($path);
+ } else {
+ unlink($path);
+ }
+ }
+
+ rmdir($dir);
+}
+```
\ No newline at end of file
diff --git a/swap-multilanguage-content.md b/swap-multilanguage-content.md
new file mode 100644
index 0000000..62cec9e
--- /dev/null
+++ b/swap-multilanguage-content.md
@@ -0,0 +1,220 @@
+---
+
+title: "Swap the content of multilingual fields between two languages"
+
+---
+
+version: 1.0.0
+
+---
+
+authors: Olaf Gleba
+
+---
+
+tags: pages, languages, multilingual, multilanguages
+
+---
+
+date: 2026-01-25
+
+---
+
+
+
+## Problem
+
+On Launch the defined default language of a website is e.g. `german` (`/`). Beside e.g. `english` as a second language (`/en/`). After a while eventually the client wants to have `english` as the default language and `german` as second.
+
+Usually this gives the editorial staff a really hard time, because every bit of multilingual content has to be replaced by hand. Beside approaches that imposes redirects.
+
+
+## Solution
+
+The script iterates recursively over multilingual fields of different types and swap the content between two languages.
+
+Create a new document, copy&paste the code below, save it to the root of your PW installation, adapt params (s. instructions within the script file) and open it in a browser.
+
+```php
+` with the name of the language that should
+ * become default.
+ * 2. Adapt `` with the required template names
+ * (assuming that multiple templates are to consider). Execute the script
+ * file (e.g. reload the browser) ``each time`` you adapt the template name.
+ *
+ * Code example:
+ *
+ * $_pages = wire('pages')->find("template=");
+ * swapMultiLanguageContent($_pages, 'default', '');
+ *
+ */
+
+/**
+ * MANDATORY STEPS AFTER FINAL EXECUTION
+ *
+ * After you run all considered templates you need to do:
+ *
+ * 1. Assuming `german` was your default language so far (name `default`)
+ * and you want to define a second language, for example `english`
+ * (name `english`), as the new default, adapt the name (and surely the
+ * title too) on both related languages (e.g. english => default,
+ * german => german).
+ *
+ * 2. Go to your Homepage ("/") and in the settings tab, adapt the url of your
+ * new default language and the url of your swapped language (e.g. english
+ * => /, german => /de/).
+ */
+
+
+// bootstrap processwire
+require_once './index.php';
+
+
+/**
+ * Function to swap the content of multilingual fields between two languages
+ *
+ * 1. Page name swap
+ * 2. Execute recursive function `swapFieldValuesRecursive`
+ * 3. Save pages array
+ */
+
+function swapMultiLanguageContent($pages, $langA = 'default', $langB = 'deutsch') {
+
+ $languages = wire('languages');
+ $lA = $languages->get($langA);
+ $lB = $languages->get($langB);
+
+ if(!$lA || !$lB) throw new WireException("Language not found");
+
+ foreach($pages as $page) {
+
+ if(!$page instanceof Page || !$page->id) continue;
+
+ $page->of(false);
+
+ /* 1 */
+ try {
+ $nameA = $page->localName($lA);
+ $nameB = $page->localName($lB);
+
+ if($nameA !== $nameB) {
+
+ $page->set("status$langB", 1);
+
+ $page->set("name$langA", $nameB);
+ $page->set("name$langB", $nameA);
+ }
+ } catch(Exception $e) {
+ wire('log')->save('swap-lang', "Page {$page->id}: Name swap error: " . $e->getMessage());
+ }
+
+ /* 2 */
+ swapFieldValuesRecursive($page, $lA, $lB);
+
+ /* 3 */
+ try {
+ $page->save();
+ } catch(Exception $e) {
+ wire('log')->save('swap-lang', "Page {$page->id}: Save error: " . $e->getMessage());
+ }
+
+ $page->of(true);
+ }
+
+ return "Done.";
+}
+
+
+/**
+ * Internal function to swap field values recursively
+ *
+ * NOT intended to use as stand-alone, s. func `swapMultiLanguageContent`
+ *
+ * 1. Ordinary field type
+ * 2. Repeater field type
+ * 3. RepeaterMatrix field type
+ */
+
+function swapFieldValuesRecursive(Page $page, Language $lA, Language $lB) {
+
+ foreach($page->template->fieldgroup as $field) {
+
+ $fieldname = $field->name;
+ if(!$page->hasField($fieldname)) continue;
+
+ $value = $page->$fieldname;
+
+ if($value === null) continue;
+
+ /* 1 */
+ $type = $field->type;
+
+ if($type instanceof FieldtypeLanguageInterface) {
+
+ try {
+ $valueA = $value->getLanguageValue($lA);
+ $valueB = $value->getLanguageValue($lB);
+
+ if($valueA != $valueB) {
+ $value->setLanguageValue($lA, $valueB);
+ $value->setLanguageValue($lB, $valueA);
+ }
+
+ } catch(Exception $e) {
+ wire('log')->save('swap-lang', "Field {$fieldname} error: " . $e->getMessage());
+ }
+
+ continue;
+ }
+
+ /* 2 */
+ if($type instanceof FieldtypeRepeater && $value->count()) {
+
+ foreach($value as $repItem) {
+ $repItem->of(false);
+ swapFieldValuesRecursive($repItem, $lA, $lB);
+ $repItem->save();
+ $repItem->of(true);
+ }
+
+ continue;
+ }
+
+ /* 3 */
+ if($type instanceof FieldtypeRepeaterMatrix && $value->count()) {
+
+ foreach($value as $matrixItem) {
+ $matrixItem->of(false);
+ swapFieldValuesRecursive($matrixItem, $lA, $lB);
+ $matrixItem->save();
+ $matrixItem->of(true);
+ }
+
+ continue;
+ }
+
+ // Ignore all other field types...
+ }
+}
+```
\ No newline at end of file