diff --git a/android/gradle.properties b/android/gradle.properties
index ed86f0f26922ea79f4d0c8e0e84f6d74259952bb..3487476dc637023e34426ce50caf3343f91e3038 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,5 +1,5 @@
 org.gradle.jvmargs=-Xmx1536M
 android.useAndroidX=true
 android.enableJetifier=true
-app.versionName=0.0.22
-app.versionCode=22
+app.versionName=0.0.23
+app.versionCode=23
diff --git a/fastlane/metadata/android/en-US/changelogs/23.txt b/fastlane/metadata/android/en-US/changelogs/23.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4746db60a14b3e1cb08d3b752020a7f33a45fc26
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/23.txt
@@ -0,0 +1 @@
+Add choose categories theme.
diff --git a/fastlane/metadata/android/fr-FR/changelogs/23.txt b/fastlane/metadata/android/fr-FR/changelogs/23.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f592cb695abdc80c0c78c1a231148e8f82ed450a
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/23.txt
@@ -0,0 +1 @@
+Ajout du choix du thème des catégories.
diff --git a/lib/config/default_game_settings.dart b/lib/config/default_game_settings.dart
index c4486031cf4e7ed40d95822ce17ee826fe84e4b2..72aed12fae08e985e25fd473bb66252da552fb46 100644
--- a/lib/config/default_game_settings.dart
+++ b/lib/config/default_game_settings.dart
@@ -1,8 +1,10 @@
+import 'package:sortgame/data/fetch_data_helper.dart';
 import 'package:sortgame/utils/tools.dart';
 
 class DefaultGameSettings {
   static const List<String> availableParameters = [
     'itemsCount',
+    'theme',
   ];
 
   static const int itemsCountValueLow = 5;
@@ -18,12 +20,20 @@ class DefaultGameSettings {
     itemsCountValueVeryHigh,
   ];
 
+  static const int defaultThemeValue = 0;
+
   static List<int> getAvailableValues(String parameterCode) {
     switch (parameterCode) {
       case 'itemsCount':
         return DefaultGameSettings.allowedItemsCountValues;
     }
 
+    switch (parameterCode) {
+      case 'theme':
+        final int count = FetchDataHelper().getThemes().length;
+        return List<int>.generate(count, (i) => i);
+    }
+
     printlog('Did not find any available value for game parameter "$parameterCode".');
     return [];
   }
diff --git a/lib/cubit/settings_game_cubit.dart b/lib/cubit/settings_game_cubit.dart
index a2c04ea96f915f709c25b31942c277bb742ade54..c411ae194035e0dece266f3434a7358cc3c55c19 100644
--- a/lib/cubit/settings_game_cubit.dart
+++ b/lib/cubit/settings_game_cubit.dart
@@ -12,11 +12,13 @@ class GameSettingsCubit extends HydratedCubit<GameSettingsState> {
 
   void setValues({
     int? itemsCount,
+    int? theme,
   }) {
     emit(
       GameSettingsState(
         settings: GameSettings(
           itemsCount: itemsCount ?? state.settings.itemsCount,
+          theme: theme ?? state.settings.theme,
         ),
       ),
     );
@@ -26,6 +28,8 @@ class GameSettingsCubit extends HydratedCubit<GameSettingsState> {
     switch (code) {
       case 'itemsCount':
         return GameSettings.getItemsCountValueFromUnsafe(state.settings.itemsCount);
+      case 'theme':
+        return GameSettings.getThemeValueFromUnsafe(state.settings.theme);
     }
     return 0;
   }
@@ -35,19 +39,23 @@ class GameSettingsCubit extends HydratedCubit<GameSettingsState> {
     printlog('code: $code  / value: $value');
 
     int itemsCount = code == 'itemsCount' ? value : getParameterValue('itemsCount');
+    int theme = code == 'theme' ? value : getParameterValue('theme');
 
     setValues(
       itemsCount: itemsCount,
+      theme: theme,
     );
   }
 
   @override
   GameSettingsState? fromJson(Map<String, dynamic> json) {
     int itemsCount = json['itemsCount'] as int;
+    int theme = json['theme'] as int;
 
     return GameSettingsState(
       settings: GameSettings(
         itemsCount: itemsCount,
+        theme: theme,
       ),
     );
   }
@@ -56,6 +64,7 @@ class GameSettingsCubit extends HydratedCubit<GameSettingsState> {
   Map<String, dynamic>? toJson(GameSettingsState state) {
     return <String, dynamic>{
       'itemsCount': state.settings.itemsCount,
+      'theme': state.settings.theme,
     };
   }
 }
diff --git a/lib/data/fetch_data_helper.dart b/lib/data/fetch_data_helper.dart
index fd7ac7ad4b769668e49a2174191195cab43eb513..9904c8bd319da185eac0194522624123f5773402 100644
--- a/lib/data/fetch_data_helper.dart
+++ b/lib/data/fetch_data_helper.dart
@@ -1,7 +1,9 @@
 import 'package:sortgame/data/game_data.dart';
 import 'package:sortgame/models/data/category.dart';
 import 'package:sortgame/models/data/game_item.dart';
+import 'package:sortgame/models/data/game_theme.dart';
 import 'package:sortgame/models/data/item.dart';
+import 'package:sortgame/models/settings_game.dart';
 import 'package:sortgame/utils/tools.dart';
 
 class FetchDataHelper {
@@ -13,6 +15,9 @@ class FetchDataHelper {
   final List<Item> _items = [];
   List<Item> get items => _items;
 
+  final List<GameTheme> _themes = [];
+  List<GameTheme> get themes => _themes;
+
   final List<GameItem> _mapping = [];
 
   void init() {
@@ -25,6 +30,16 @@ class FetchDataHelper {
         _categories.add(Category(key: element, text: element));
       }
 
+      final Map<String, dynamic> rawThemes = gameData['themes'] as Map<String, dynamic>;
+      rawThemes.forEach((code, rawCategories) {
+        final List<Category> categories = [];
+        for (var rawElement in rawCategories) {
+          final element = rawElement.toString();
+          categories.add(Category(key: element, text: element));
+        }
+        _themes.add(GameTheme(code: code, categories: categories));
+      });
+
       final List<dynamic> rawItems = gameData['items'] as List<dynamic>;
       for (var rawElement in rawItems) {
         final element = rawElement.toString();
@@ -64,13 +79,27 @@ class FetchDataHelper {
     }
   }
 
-  List<GameItem> getItems(int count) {
+  List<GameItem> getItems(GameSettings gameSettings) {
     if (_mapping.isEmpty) {
       init();
     }
 
+    final int count = gameSettings.itemsCount;
+    final int theme = gameSettings.theme;
+
     List<GameItem> items = _mapping;
 
+    // Remove unwanted categories if theme is selected
+    if (theme != 0) {
+      final GameTheme gameTheme = _themes[theme];
+      for (GameItem item in items) {
+        item.isCategory.removeWhere((Category category) =>
+            (!gameTheme.categories.map((c) => c.key).contains(category.key)));
+        item.isNotCategory.removeWhere((Category category) =>
+            (!gameTheme.categories.map((c) => c.key).contains(category.key)));
+      }
+    }
+
     // Remove items without enough data
     items.removeWhere((GameItem gameItem) =>
         (gameItem.isCategory.isEmpty || gameItem.isNotCategory.isEmpty));
@@ -79,4 +108,20 @@ class FetchDataHelper {
 
     return items.take(count).toList();
   }
+
+  List<GameTheme> getThemes() {
+    if (_themes.isEmpty) {
+      init();
+    }
+
+    return _themes.toList();
+  }
+
+  GameTheme getTheme(int themeIndex) {
+    if (_themes.isEmpty) {
+      init();
+    }
+
+    return _themes[themeIndex];
+  }
 }
diff --git a/lib/data/game_data.dart b/lib/data/game_data.dart
index a28b980432f11277a616ef11e76a2d660ec86724..99b5ea76cfa0f5a1515ee45eb7cb6f674f5fccd6 100644
--- a/lib/data/game_data.dart
+++ b/lib/data/game_data.dart
@@ -15,6 +15,12 @@ class GameData {
       ["inerte", "animal", "végétal"],
       ["naturel", "artificiel"]
     ],
+    "themes": {
+      "tout": [],
+      "état": ["liquide", "solide", "gazeux"],
+      "genre": ["inerte", "animal", "végétal"],
+      "vivant": ["animal", "végétal"]
+    },
     "items": [
       "ABEILLE",
       "AIGUILLE",
@@ -372,8 +378,8 @@ class GameData {
           "na": []
         },
         "BATEAU": {
-          "is": ["animal", "inerte"],
-          "isnot": ["végétal"],
+          "is": ["inerte"],
+          "isnot": ["animal", "végétal"],
           "na": []
         },
         "BAVOIR": {
@@ -477,8 +483,8 @@ class GameData {
           "na": []
         },
         "CAMION": {
-          "is": ["inerte", "végétal"],
-          "isnot": ["animal"],
+          "is": ["inerte"],
+          "isnot": ["animal", "végétal"],
           "na": []
         },
         "CANARD": {
@@ -522,8 +528,8 @@ class GameData {
           "na": []
         },
         "CHAISE": {
-          "is": ["animal", "artificiel", "inerte", "solide"],
-          "isnot": ["gazeux", "liquide", "naturel", "végétal"],
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["animal", "gazeux", "liquide", "naturel", "végétal"],
           "na": []
         },
         "CHAMPIGNON": {
@@ -537,8 +543,8 @@ class GameData {
           "na": []
         },
         "CHAUSSETTE": {
-          "is": ["inerte", "végétal"],
-          "isnot": ["animal"],
+          "is": ["inerte"],
+          "isnot": ["animal", "végétal"],
           "na": []
         },
         "CHAUSSURE": {
@@ -717,8 +723,8 @@ class GameData {
           "na": []
         },
         "FROMAGE": {
-          "is": ["animal", "artificiel", "inerte"],
-          "isnot": ["liquide", "naturel", "végétal"],
+          "is": ["artificiel", "inerte"],
+          "isnot": ["animal", "liquide", "naturel", "végétal"],
           "na": []
         },
         "FUSÉE": {
@@ -877,8 +883,8 @@ class GameData {
           "na": []
         },
         "LUNETTES": {
-          "is": ["animal", "inerte"],
-          "isnot": ["végétal"],
+          "is": ["inerte"],
+          "isnot": ["animal", "végétal"],
           "na": []
         },
         "MAISON": {
@@ -957,8 +963,8 @@ class GameData {
           "na": []
         },
         "OREILLER": {
-          "is": ["animal", "inerte"],
-          "isnot": ["végétal"],
+          "is": ["inerte"],
+          "isnot": ["animal", "végétal"],
           "na": []
         },
         "OURS": {
@@ -967,8 +973,8 @@ class GameData {
           "na": ["liquide", "solide"]
         },
         "PAIN": {
-          "is": ["inerte", "végétal"],
-          "isnot": ["animal"],
+          "is": ["inerte"],
+          "isnot": ["animal", "végétal"],
           "na": []
         },
         "PANDA": {
@@ -1052,8 +1058,8 @@ class GameData {
           "na": []
         },
         "PISCINE": {
-          "is": ["inerte", "végétal"],
-          "isnot": ["animal", "gazeux"],
+          "is": ["inerte"],
+          "isnot": ["animal", "gazeux", "végétal"],
           "na": []
         },
         "PIVERT": {
@@ -1067,8 +1073,8 @@ class GameData {
           "na": []
         },
         "PLAGE": {
-          "is": ["inerte", "naturel", "végétal"],
-          "isnot": ["animal", "artificiel"],
+          "is": ["inerte", "naturel"],
+          "isnot": ["animal", "artificiel", "végétal"],
           "na": []
         },
         "POIRE": {
@@ -1177,8 +1183,8 @@ class GameData {
           "na": ["inerte", "végétal"]
         },
         "ROBINET": {
-          "is": ["animal", "inerte"],
-          "isnot": ["végétal"],
+          "is": ["inerte"],
+          "isnot": ["animal", "végétal"],
           "na": []
         },
         "ROSE": {
@@ -1277,8 +1283,8 @@ class GameData {
           "na": []
         },
         "SOUS-MARIN": {
-          "is": ["artificiel", "inerte", "végétal"],
-          "isnot": ["animal", "naturel"],
+          "is": ["artificiel", "inerte"],
+          "isnot": ["animal", "naturel", "végétal"],
           "na": []
         },
         "STADE": {
@@ -1302,8 +1308,8 @@ class GameData {
           "na": []
         },
         "TABOURET": {
-          "is": ["animal", "artificiel", "inerte", "solide"],
-          "isnot": ["gazeux", "liquide", "naturel", "végétal"],
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["animal", "gazeux", "liquide", "naturel", "végétal"],
           "na": []
         },
         "TACHE": {
@@ -1367,8 +1373,8 @@ class GameData {
           "na": []
         },
         "TOURNEVIS": {
-          "is": ["animal", "inerte"],
-          "isnot": ["gazeux", "végétal"],
+          "is": ["inerte"],
+          "isnot": ["animal", "gazeux", "végétal"],
           "na": []
         },
         "TRACTEUR": {
@@ -1422,8 +1428,8 @@ class GameData {
           "na": []
         },
         "VOILIER": {
-          "is": ["animal", "artificiel", "inerte", "solide"],
-          "isnot": ["gazeux", "liquide", "naturel", "végétal"],
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["animal", "gazeux", "liquide", "naturel", "végétal"],
           "na": []
         },
         "VOITURE": {
diff --git a/lib/models/data/game_theme.dart b/lib/models/data/game_theme.dart
new file mode 100644
index 0000000000000000000000000000000000000000..e0ecc61546af53c8555bfa01e4ddd09043dbc171
--- /dev/null
+++ b/lib/models/data/game_theme.dart
@@ -0,0 +1,23 @@
+import 'package:sortgame/models/data/category.dart';
+
+class GameTheme {
+  final String code;
+  final List<Category> categories;
+
+  GameTheme({
+    required this.code,
+    required this.categories,
+  });
+
+  @override
+  String toString() {
+    return '$GameTheme(${toJson()})';
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{
+      'code': code,
+      'categories': categories.toString(),
+    };
+  }
+}
diff --git a/lib/models/game.dart b/lib/models/game.dart
index fcc9097db07c42cc69326884dc8032b799c4a720..74e9d0254eafc47b90eaa2ebb3a97e9a724332bb 100644
--- a/lib/models/game.dart
+++ b/lib/models/game.dart
@@ -38,7 +38,7 @@ class Game {
     GameSettings newGameSettings = gameSettings ?? GameSettings.createDefault();
     GlobalSettings newGlobalSettings = globalSettings ?? GlobalSettings.createDefault();
 
-    List<GameItem> items = FetchDataHelper().getItems(newGameSettings.itemsCount);
+    List<GameItem> items = FetchDataHelper().getItems(newGameSettings);
 
     return Game(
       items: items,
diff --git a/lib/models/settings_game.dart b/lib/models/settings_game.dart
index 67681ec8b9a761986cf41cc0db681fb39f82b8e0..3528fa4b15bfde064fb15d132c027e53e4127e8c 100644
--- a/lib/models/settings_game.dart
+++ b/lib/models/settings_game.dart
@@ -3,9 +3,11 @@ import 'package:sortgame/utils/tools.dart';
 
 class GameSettings {
   final int itemsCount;
+  final int theme;
 
   GameSettings({
     required this.itemsCount,
+    required this.theme,
   });
 
   static int getItemsCountValueFromUnsafe(int itemsCount) {
@@ -16,15 +18,25 @@ class GameSettings {
     return DefaultGameSettings.defaultItemsCountValue;
   }
 
+  static int getThemeValueFromUnsafe(int theme) {
+    if (DefaultGameSettings.getAvailableValues('theme').contains(theme)) {
+      return theme;
+    }
+
+    return DefaultGameSettings.defaultThemeValue;
+  }
+
   factory GameSettings.createDefault() {
     return GameSettings(
       itemsCount: DefaultGameSettings.defaultItemsCountValue,
+      theme: DefaultGameSettings.defaultThemeValue,
     );
   }
 
   void dump() {
     printlog('Settings: ');
     printlog('  itemsCount: $itemsCount');
+    printlog('  theme: $theme');
   }
 
   @override
@@ -35,6 +47,7 @@ class GameSettings {
   Map<String, dynamic>? toJson() {
     return <String, dynamic>{
       'itemsCount': itemsCount,
+      'theme': theme,
     };
   }
 }
diff --git a/lib/ui/painters/parameter_painter.dart b/lib/ui/painters/parameter_painter.dart
index fd4e3921d5fdecf4812a263148c4f1a3641b2c4e..3444bb36b1a44617b7c8fcb45560acec57ea1ee8 100644
--- a/lib/ui/painters/parameter_painter.dart
+++ b/lib/ui/painters/parameter_painter.dart
@@ -3,6 +3,8 @@ import 'dart:math';
 import 'package:flutter/material.dart';
 
 import 'package:sortgame/config/default_game_settings.dart';
+import 'package:sortgame/data/fetch_data_helper.dart';
+import 'package:sortgame/models/data/game_theme.dart';
 import 'package:sortgame/models/settings_game.dart';
 import 'package:sortgame/models/settings_global.dart';
 import 'package:sortgame/utils/tools.dart';
@@ -44,6 +46,9 @@ class ParameterPainter extends CustomPainter {
       case 'itemsCount':
         paintItemsCountParameterItem(value, canvas, canvasSize);
         break;
+      case 'theme':
+        paintThemeParameterItem(value, canvas, canvasSize);
+        break;
       default:
         printlog('Unknown parameter: $code/$value');
         paintUnknownParameterItem(value, canvas, canvasSize);
@@ -146,4 +151,46 @@ class ParameterPainter extends CustomPainter {
       ),
     );
   }
+
+  void paintThemeParameterItem(
+    final int value,
+    final Canvas canvas,
+    final double size,
+  ) {
+    final GameTheme theme = FetchDataHelper().getTheme(value);
+
+    final Color backgroundColor =
+        Color((theme.code.hashCode * 0xFFFFFF).toInt()).withOpacity(1.0);
+
+    final paint = Paint();
+    paint.strokeJoin = StrokeJoin.round;
+    paint.strokeWidth = 3 / 100 * size;
+
+    // Colored background
+    paint.color = backgroundColor;
+    paint.style = PaintingStyle.fill;
+    canvas.drawRect(Rect.fromPoints(const Offset(0, 0), Offset(size, size)), paint);
+
+    // centered text value
+    final textSpan = TextSpan(
+      text: theme.code,
+      style: TextStyle(
+        color: Colors.black,
+        fontSize: size / 4,
+        fontWeight: FontWeight.bold,
+      ),
+    );
+    final textPainter = TextPainter(
+      text: textSpan,
+      textDirection: TextDirection.ltr,
+    );
+    textPainter.layout();
+    textPainter.paint(
+      canvas,
+      Offset(
+        (size - textPainter.width) * 0.5,
+        (size - textPainter.height) * 0.5,
+      ),
+    );
+  }
 }
diff --git a/pubspec.yaml b/pubspec.yaml
index 220bed61660eee38dc7609059903093f782f0aa6..c1e8bb481e911e1deb2ca41a9b38c58c5c91fa7b 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@ description: A sorting game application.
 
 publish_to: 'none'
 
-version: 0.0.22+22
+version: 0.0.23+23
 
 environment:
   sdk: '^3.0.0'
diff --git a/scripts/data.json b/scripts/data.json
index a78c464bd8a89caf6b599ff02640e30f10727617..a3d3d25c65103e8be49102b7e61dd89906e2c6ba 100644
--- a/scripts/data.json
+++ b/scripts/data.json
@@ -25,6 +25,23 @@
       "artificiel"
     ]
   ],
+  "themes": {
+    "tout": [],
+    "état": [
+      "liquide",
+      "solide",
+      "gazeux"
+    ],
+    "genre": [
+      "inerte",
+      "animal",
+      "végétal"
+    ],
+    "vivant": [
+      "animal",
+      "végétal"
+    ]
+  },
   "items": [
     "ABEILLE",
     "AIGUILLE",
@@ -547,10 +564,10 @@
       },
       "BATEAU": {
         "is": [
-          "animal",
           "inerte"
         ],
         "isnot": [
+          "animal",
           "végétal"
         ],
         "na": []
@@ -798,11 +815,11 @@
       },
       "CAMION": {
         "is": [
-          "inerte",
-          "végétal"
+          "inerte"
         ],
         "isnot": [
-          "animal"
+          "animal",
+          "végétal"
         ],
         "na": []
       },
@@ -905,12 +922,12 @@
       },
       "CHAISE": {
         "is": [
-          "animal",
           "artificiel",
           "inerte",
           "solide"
         ],
         "isnot": [
+          "animal",
           "gazeux",
           "liquide",
           "naturel",
@@ -941,11 +958,11 @@
       },
       "CHAUSSETTE": {
         "is": [
-          "inerte",
-          "végétal"
+          "inerte"
         ],
         "isnot": [
-          "animal"
+          "animal",
+          "végétal"
         ],
         "na": []
       },
@@ -1378,11 +1395,11 @@
       },
       "FROMAGE": {
         "is": [
-          "animal",
           "artificiel",
           "inerte"
         ],
         "isnot": [
+          "animal",
           "liquide",
           "naturel",
           "végétal"
@@ -1767,10 +1784,10 @@
       },
       "LUNETTES": {
         "is": [
-          "animal",
           "inerte"
         ],
         "isnot": [
+          "animal",
           "végétal"
         ],
         "na": []
@@ -1961,10 +1978,10 @@
       },
       "OREILLER": {
         "is": [
-          "animal",
           "inerte"
         ],
         "isnot": [
+          "animal",
           "végétal"
         ],
         "na": []
@@ -1987,11 +2004,11 @@
       },
       "PAIN": {
         "is": [
-          "inerte",
-          "végétal"
+          "inerte"
         ],
         "isnot": [
-          "animal"
+          "animal",
+          "végétal"
         ],
         "na": []
       },
@@ -2202,12 +2219,12 @@
       },
       "PISCINE": {
         "is": [
-          "inerte",
-          "végétal"
+          "inerte"
         ],
         "isnot": [
           "animal",
-          "gazeux"
+          "gazeux",
+          "végétal"
         ],
         "na": []
       },
@@ -2242,12 +2259,12 @@
       "PLAGE": {
         "is": [
           "inerte",
-          "naturel",
-          "végétal"
+          "naturel"
         ],
         "isnot": [
           "animal",
-          "artificiel"
+          "artificiel",
+          "végétal"
         ],
         "na": []
       },
@@ -2513,10 +2530,10 @@
       },
       "ROBINET": {
         "is": [
-          "animal",
           "inerte"
         ],
         "isnot": [
+          "animal",
           "végétal"
         ],
         "na": []
@@ -2761,12 +2778,12 @@
       "SOUS-MARIN": {
         "is": [
           "artificiel",
-          "inerte",
-          "végétal"
+          "inerte"
         ],
         "isnot": [
           "animal",
-          "naturel"
+          "naturel",
+          "végétal"
         ],
         "na": []
       },
@@ -2817,12 +2834,12 @@
       },
       "TABOURET": {
         "is": [
-          "animal",
           "artificiel",
           "inerte",
           "solide"
         ],
         "isnot": [
+          "animal",
           "gazeux",
           "liquide",
           "naturel",
@@ -2978,10 +2995,10 @@
       },
       "TOURNEVIS": {
         "is": [
-          "animal",
           "inerte"
         ],
         "isnot": [
+          "animal",
           "gazeux",
           "végétal"
         ],
@@ -3107,12 +3124,12 @@
       },
       "VOILIER": {
         "is": [
-          "animal",
           "artificiel",
           "inerte",
           "solide"
         ],
         "isnot": [
+          "animal",
           "gazeux",
           "liquide",
           "naturel",
diff --git a/scripts/manage_data.php b/scripts/manage_data.php
index 525e57194be7e97d5c19527545a6e334a543e2bc..417d4513206ef1cc9a328eae89efd3c4a1fad186 100644
--- a/scripts/manage_data.php
+++ b/scripts/manage_data.php
@@ -106,8 +106,8 @@ if (!is_writable($jsonDataFile)) {
     die;
 }
 
-$categories = (\array_key_exists('categories', $data) && \is_array($data['categories'])) ? $data['categories'] : [];;
-$items = (\array_key_exists('items', $data) && \is_array($data['items'])) ? $data['items'] : [];;
+$categories = (\array_key_exists('categories', $data) && \is_array($data['categories'])) ? $data['categories'] : [];
+$items = (\array_key_exists('items', $data) && \is_array($data['items'])) ? $data['items'] : [];
 
 // Manage categories exclusions
 $exclusions = (\array_key_exists('exclusions', $data) && \is_array($data['exclusions'])) ? $data['exclusions'] : [];
@@ -121,14 +121,18 @@ foreach ($exclusions as $exclusionSet) {
 $categories = array_clean($categories);
 $items = array_clean($items);
 
+$themes = (\array_key_exists('themes', $data) && \is_array($data['themes'])) ? $data['themes'] : [];
+
 $data['categories'] = $categories;
 $data['items'] = $items;
 $data['exclusions'] = $exclusions;
+$data['themes'] = $themes;
 
 dump('');
 dump('Found ' . \count($categories) . ' unique categories.');
 dump('Found ' . \count($items) . ' unique items.');
 dump('Found ' . \count($exclusions) . ' exclusions sets.');
+dump('Found ' . \count($themes) . ' themes.');
 
 // Get/init mapping data
 $mapping = (\array_key_exists('mapping', $data) && \is_array($data['mapping'])) ? $data['mapping'] : [];
@@ -174,6 +178,13 @@ function showExclusions($exclusions)
     }
 }
 
+function showThemes($theme)
+{
+    foreach ($theme as $name => $categories) {
+        dump($name . ': ' . \join(', ', $categories));
+    }
+}
+
 function showMappings($mappingItems)
 {
     $columnsWidths = [
@@ -337,14 +348,15 @@ while ($exitMainLoop === false) {
     $missing = find_missing_associations($mappingItems, $categories, $items);
 
     $menu = [
-        '0: exit',
+        '0: save and exit',
         '',
         '1: show categories (' . \count($categories) . ' found)',
         '2: show items (' . \count($items) . ' found)',
         '3: show exclusions (' . \count($exclusions) . ' found)',
-        '4: show mappings (' . \count($mappingItems) . ' found)',
+        '4: show themes (' . \count($themes) . ' found)',
+        '5: show mappings (' . \count($mappingItems) . ' found)',
         '',
-        '5: complete mappings (' . \count($missing) . ' missing)',
+        '6: complete mappings (' . \count($missing) . ' missing)',
     ];
     $answer = ask(\join("\n", $menu));
 
@@ -362,9 +374,12 @@ while ($exitMainLoop === false) {
             showExclusions($exclusions);
             break;
         case '4':
-            showMappings($mappingItems);
+            showThemes($themes);
             break;
         case '5':
+            showMappings($mappingItems);
+            break;
+        case '6':
             $data['mapping']['items'] = editMappings($mappingItems, $categories, $items, $exclusions);
             break;
         default: