diff --git a/src/packages/com_mokoog/mokoog.xml b/src/packages/com_mokoog/mokoog.xml
index 3089e4f..aa2ad47 100644
--- a/src/packages/com_mokoog/mokoog.xml
+++ b/src/packages/com_mokoog/mokoog.xml
@@ -42,6 +42,7 @@
provider.php
+ ContentType
Controller
Extension
Model
diff --git a/src/packages/com_mokoog/src/ContentType/ContentTypeInterface.php b/src/packages/com_mokoog/src/ContentType/ContentTypeInterface.php
new file mode 100644
index 0000000..c596ca0
--- /dev/null
+++ b/src/packages/com_mokoog/src/ContentType/ContentTypeInterface.php
@@ -0,0 +1,60 @@
+
+ * @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
+ * @license GNU General Public License version 3 or later; see LICENSE
+ */
+
+namespace Joomla\Component\MokoOG\Administrator\ContentType;
+
+defined('_JEXEC') or die;
+
+interface ContentTypeInterface
+{
+ /**
+ * Check if this adapter can handle the given component/view.
+ *
+ * @param string $option Component option (e.g. com_virtuemart)
+ * @param string $view View name (e.g. productdetails)
+ *
+ * @return bool
+ */
+ public function canHandle(string $option, string $view): bool;
+
+ /**
+ * Get the content type identifier for database storage.
+ *
+ * @return string
+ */
+ public function getContentType(): string;
+
+ /**
+ * Get the title for the content item.
+ *
+ * @param int $id Content item ID
+ *
+ * @return string
+ */
+ public function getTitle(int $id): string;
+
+ /**
+ * Get a description for the content item.
+ *
+ * @param int $id Content item ID
+ *
+ * @return string
+ */
+ public function getDescription(int $id): string;
+
+ /**
+ * Get the primary image for the content item.
+ *
+ * @param int $id Content item ID
+ *
+ * @return string Image path relative to JPATH_ROOT, or empty string
+ */
+ public function getImage(int $id): string;
+}
diff --git a/src/packages/com_mokoog/src/ContentType/HikaShopAdapter.php b/src/packages/com_mokoog/src/ContentType/HikaShopAdapter.php
new file mode 100644
index 0000000..595f6e4
--- /dev/null
+++ b/src/packages/com_mokoog/src/ContentType/HikaShopAdapter.php
@@ -0,0 +1,76 @@
+
+ * @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
+ * @license GNU General Public License version 3 or later; see LICENSE
+ */
+
+namespace Joomla\Component\MokoOG\Administrator\ContentType;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Factory;
+
+class HikaShopAdapter implements ContentTypeInterface
+{
+ public function canHandle(string $option, string $view): bool
+ {
+ return $option === 'com_hikashop' && $view === 'product';
+ }
+
+ public function getContentType(): string
+ {
+ return 'com_hikashop';
+ }
+
+ public function getTitle(int $id): string
+ {
+ $db = Factory::getDbo();
+ $query = $db->getQuery(true)
+ ->select($db->quoteName('product_name'))
+ ->from($db->quoteName('#__hikashop_product'))
+ ->where($db->quoteName('product_id') . ' = ' . $id);
+
+ $db->setQuery($query);
+
+ return $db->loadResult() ?: '';
+ }
+
+ public function getDescription(int $id): string
+ {
+ $db = Factory::getDbo();
+ $query = $db->getQuery(true)
+ ->select($db->quoteName('product_description'))
+ ->from($db->quoteName('#__hikashop_product'))
+ ->where($db->quoteName('product_id') . ' = ' . $id);
+
+ $db->setQuery($query);
+ $text = $db->loadResult() ?: '';
+ $text = strip_tags($text);
+ $text = trim(preg_replace('/\s+/', ' ', $text));
+
+ if (\strlen($text) > 160) {
+ $text = mb_substr($text, 0, 157) . '...';
+ }
+
+ return $text;
+ }
+
+ public function getImage(int $id): string
+ {
+ $db = Factory::getDbo();
+ $query = $db->getQuery(true)
+ ->select($db->quoteName('f.file_path'))
+ ->from($db->quoteName('#__hikashop_file', 'f'))
+ ->where($db->quoteName('f.file_ref_id') . ' = ' . $id)
+ ->where($db->quoteName('f.file_type') . ' = ' . $db->quote('product'))
+ ->order($db->quoteName('f.file_ordering') . ' ASC');
+
+ $db->setQuery($query, 0, 1);
+
+ return $db->loadResult() ?: '';
+ }
+}
diff --git a/src/packages/com_mokoog/src/ContentType/K2Adapter.php b/src/packages/com_mokoog/src/ContentType/K2Adapter.php
new file mode 100644
index 0000000..f8dcd5d
--- /dev/null
+++ b/src/packages/com_mokoog/src/ContentType/K2Adapter.php
@@ -0,0 +1,73 @@
+
+ * @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
+ * @license GNU General Public License version 3 or later; see LICENSE
+ */
+
+namespace Joomla\Component\MokoOG\Administrator\ContentType;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Factory;
+
+class K2Adapter implements ContentTypeInterface
+{
+ public function canHandle(string $option, string $view): bool
+ {
+ return $option === 'com_k2' && $view === 'item';
+ }
+
+ public function getContentType(): string
+ {
+ return 'com_k2';
+ }
+
+ public function getTitle(int $id): string
+ {
+ $db = Factory::getDbo();
+ $query = $db->getQuery(true)
+ ->select($db->quoteName('title'))
+ ->from($db->quoteName('#__k2_items'))
+ ->where($db->quoteName('id') . ' = ' . $id);
+
+ $db->setQuery($query);
+
+ return $db->loadResult() ?: '';
+ }
+
+ public function getDescription(int $id): string
+ {
+ $db = Factory::getDbo();
+ $query = $db->getQuery(true)
+ ->select($db->quoteName('introtext'))
+ ->from($db->quoteName('#__k2_items'))
+ ->where($db->quoteName('id') . ' = ' . $id);
+
+ $db->setQuery($query);
+ $text = $db->loadResult() ?: '';
+ $text = strip_tags($text);
+ $text = trim(preg_replace('/\s+/', ' ', $text));
+
+ if (\strlen($text) > 160) {
+ $text = mb_substr($text, 0, 157) . '...';
+ }
+
+ return $text;
+ }
+
+ public function getImage(int $id): string
+ {
+ // K2 stores images as media/k2/items/cache/{md5}_L.jpg
+ $imagePath = 'media/k2/items/cache/' . md5('Image' . $id) . '_L.jpg';
+
+ if (is_file(JPATH_ROOT . '/' . $imagePath)) {
+ return $imagePath;
+ }
+
+ return '';
+ }
+}
diff --git a/src/packages/com_mokoog/src/ContentType/VirtueMartAdapter.php b/src/packages/com_mokoog/src/ContentType/VirtueMartAdapter.php
new file mode 100644
index 0000000..60822ec
--- /dev/null
+++ b/src/packages/com_mokoog/src/ContentType/VirtueMartAdapter.php
@@ -0,0 +1,82 @@
+
+ * @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
+ * @license GNU General Public License version 3 or later; see LICENSE
+ */
+
+namespace Joomla\Component\MokoOG\Administrator\ContentType;
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Factory;
+
+class VirtueMartAdapter implements ContentTypeInterface
+{
+ public function canHandle(string $option, string $view): bool
+ {
+ return $option === 'com_virtuemart' && $view === 'productdetails';
+ }
+
+ public function getContentType(): string
+ {
+ return 'com_virtuemart';
+ }
+
+ public function getTitle(int $id): string
+ {
+ $db = Factory::getDbo();
+ $query = $db->getQuery(true)
+ ->select($db->quoteName('product_name'))
+ ->from($db->quoteName('#__virtuemart_products_' . $this->getLangTag()))
+ ->where($db->quoteName('virtuemart_product_id') . ' = ' . $id);
+
+ $db->setQuery($query);
+
+ return $db->loadResult() ?: '';
+ }
+
+ public function getDescription(int $id): string
+ {
+ $db = Factory::getDbo();
+ $query = $db->getQuery(true)
+ ->select($db->quoteName('product_s_desc'))
+ ->from($db->quoteName('#__virtuemart_products_' . $this->getLangTag()))
+ ->where($db->quoteName('virtuemart_product_id') . ' = ' . $id);
+
+ $db->setQuery($query);
+ $desc = $db->loadResult() ?: '';
+
+ return strip_tags($desc);
+ }
+
+ public function getImage(int $id): string
+ {
+ $db = Factory::getDbo();
+ $query = $db->getQuery(true)
+ ->select($db->quoteName('m.file_url'))
+ ->from($db->quoteName('#__virtuemart_product_medias', 'pm'))
+ ->join('INNER', $db->quoteName('#__virtuemart_medias', 'm') . ' ON ' . $db->quoteName('m.virtuemart_media_id') . ' = ' . $db->quoteName('pm.virtuemart_media_id'))
+ ->where($db->quoteName('pm.virtuemart_product_id') . ' = ' . $id)
+ ->order($db->quoteName('pm.ordering') . ' ASC');
+
+ $db->setQuery($query, 0, 1);
+
+ return $db->loadResult() ?: '';
+ }
+
+ /**
+ * Get the VirtueMart language table suffix.
+ *
+ * @return string
+ */
+ private function getLangTag(): string
+ {
+ $lang = Factory::getLanguage()->getTag();
+
+ return strtolower(str_replace('-', '_', $lang));
+ }
+}