diff --git a/local/modules/Front/Config/front.xml b/local/modules/Front/Config/front.xml
index 4f32372a3..0a987eaa2 100644
--- a/local/modules/Front/Config/front.xml
+++ b/local/modules/Front/Config/front.xml
@@ -200,6 +200,15 @@
+
+
+ Front\Controller\FeedController::generateAction
+ catalog
+
+
+
+
+
Thelia\Controller\Front\DefaultController::noAction
diff --git a/local/modules/Front/Controller/FeedController.php b/local/modules/Front/Controller/FeedController.php
new file mode 100644
index 000000000..d9e3a5c5c
--- /dev/null
+++ b/local/modules/Front/Controller/FeedController.php
@@ -0,0 +1,200 @@
+
+ */
+class FeedController extends BaseFrontController {
+
+
+ /**
+ * Folder name for feeds cache
+ */
+ const FEED_CACHE_DIR = "feeds";
+
+ /**
+ * Key prefix for feed cache
+ */
+ const FEED_CACHE_KEY = "feed";
+
+
+ /**
+ * render the RSS feed
+ *
+ * @param $context string The context of the feed : catalog, content. default: catalog
+ * @param $lang string The lang of the feed : fr_FR, en_US, ... default: default language of the site
+ * @param $id string The id of the parent element. The id of the main parent category for catalog context.
+ * The id of the content folder for content context
+ * @return Response
+ */
+ public function generateAction($context, $lang, $id)
+ {
+
+ /** @var Request $request */
+ $request = $this->getRequest();
+
+ // context
+ if ("" === $context){
+ $context = "catalog";
+ } else if (! in_array($context, array("catalog", "content")) ){
+ $this->pageNotFound();
+ }
+
+ // the locale : fr, en,
+ if ("" !== $lang) {
+ if (! $this->checkLang($lang)){
+ $this->pageNotFound();
+ }
+ } else {
+ try{
+ $lang = Lang::getDefaultLanguage();
+ $lang = $lang->getLocale();
+ } catch (\RuntimeException $ex){
+ // @todo generate error page
+ throw new \RuntimeException("No default language is defined. Please define one.");
+ }
+ }
+ if (null === $lang = LangQuery::create()->findOneByLocale($lang)){
+ $this->pageNotFound();
+ }
+ $lang = $lang->getId();
+
+ // check if element exists and is visible
+ if ("" !== $id){
+ if (false === $this->checkId($context, $id)){
+ $this->pageNotFound();
+ }
+ }
+
+ $flush = $request->query->get("flush", "");
+
+ // check if feed already in cache
+ $cacheContent = false;
+
+ $cacheDir = $this->getCacheDir();
+ $cacheKey = self::FEED_CACHE_KEY . $lang . $context . $id;
+ $cacheExpire = intval(ConfigQuery::read("feed_ttl", '7200')) ?: 7200;
+
+ $cacheDriver = new FilesystemCache($cacheDir);
+ if (!($this->checkAdmin() && "" !== $flush)){
+ $cacheContent = $cacheDriver->fetch($cacheKey);
+ } else {
+ $cacheDriver->delete($cacheKey);
+ }
+
+ // if not in cache
+ if (false === $cacheContent){
+ // render the view
+ $cacheContent = $this->renderRaw(
+ "feed",
+ array(
+ "_context_" => $context,
+ "_lang_" => $lang,
+ "_id_" => $id
+ )
+ );
+ // save cache
+ $cacheDriver->save($cacheKey, $cacheContent, $cacheExpire);
+ }
+
+ $response = new Response();
+ $response->setContent($cacheContent);
+ $response->headers->set('Content-Type', 'application/rss+xml');
+
+ return $response;
+ }
+
+
+ /**
+ * get the cache directory for feeds
+ *
+ * @return mixed|string
+ */
+ protected function getCacheDir()
+ {
+ $cacheDir = $this->container->getParameter("kernel.cache_dir");
+ $cacheDir = rtrim($cacheDir, '/');
+ $cacheDir .= '/' . self::FEED_CACHE_DIR . '/';
+
+ return $cacheDir;
+ }
+
+ /**
+ * Check if current user has ADMIN role
+ *
+ * @return bool
+ */
+ protected function checkAdmin(){
+ return $this->getSecurityContext()->hasAdminUser();
+ }
+
+
+ /**
+ * Check if a lang is used
+ *
+ * @param $lang The lang code. e.g.: fr
+ * @return bool true if the language is used, otherwise false
+ */
+ private function checkLang($lang)
+ {
+ // load locals
+ $lang = LangQuery::create()
+ ->findOneByLocale($lang);
+
+ return (null !== $lang);
+ }
+
+
+ /**
+ * Ckeck if the element exists and is visible
+ *
+ * @param $context string catalog or content
+ * @param $id string id of the element
+ * @return bool
+ */
+ private function checkId($context, $id)
+ {
+ $ret = false;
+ if (is_numeric($id)){
+ if ("catalog" === $context){
+ $cat = CategoryQuery::create()->findPk($id);
+ $ret = (null !== $cat && $cat->getVisible());
+ } else {
+ $folder = FolderQuery::create()->findPk($id);
+ $ret = (null !== $folder && $folder->getVisible());
+ }
+ }
+ return $ret;
+ }
+
+}
\ No newline at end of file