Merge pull request 'feat(api): Joomla Web Services API for OG tags (#27)' (#29) from feature/27-webservices-api into dev
Joomla: Repo Health / Access control (push) Successful in 1s
Joomla: Update Server / Update updates.xml (push) Successful in 29s
Joomla: Repo Health / Release configuration (push) Has been cancelled
Joomla: Repo Health / Scripts governance (push) Has been cancelled
Joomla: Repo Health / Repository health (push) Has been cancelled

This commit was merged in pull request #29.
This commit is contained in:
2026-05-24 03:44:50 +00:00
14 changed files with 419 additions and 0 deletions
@@ -0,0 +1,68 @@
<?php
/**
* @package MokoOpenGraph
* @subpackage com_mokoog.api
* @author Moko Consulting <hello@mokoconsulting.tech>
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Joomla\Component\MokoOG\Api\Controller;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Controller\ApiController;
class TagsController extends ApiController
{
/**
* The content type for JSON:API output.
*
* @var string
*/
protected $contentType = 'mokoogtags';
/**
* The default view for the API.
*
* @var string
*/
protected $default_view = 'tags';
/**
* Lookup an OG tag by content_type and content_id.
*
* GET /api/index.php/v1/mokoog/lookup/:content_type/:content_id
*
* @return static
*/
public function lookup(): static
{
$contentType = $this->input->getString('content_type', '');
$contentId = $this->input->getInt('content_id', 0);
if (empty($contentType) || $contentId <= 0) {
throw new \RuntimeException('content_type and content_id are required', 400);
}
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select($db->quoteName('id'))
->from($db->quoteName('#__mokoog_tags'))
->where($db->quoteName('content_type') . ' = ' . $db->quote($contentType))
->where($db->quoteName('content_id') . ' = ' . $contentId);
$db->setQuery($query);
$id = $db->loadResult();
if (!$id) {
throw new \RuntimeException('OG tag not found for ' . $contentType . ':' . $contentId, 404);
}
$this->input->set('id', $id);
return $this->displayItem();
}
}
@@ -0,0 +1,66 @@
<?php
/**
* @package MokoOpenGraph
* @subpackage com_mokoog.api
* @author Moko Consulting <hello@mokoconsulting.tech>
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Joomla\Component\MokoOG\Api\View\Tags;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
class JsonapiView extends BaseApiView
{
/**
* The fields to render in the API response.
*
* Whitelist of fields from #__mokoog_tags that are safe to expose.
*
* @var array
*/
protected $fieldsToRenderItem = [
'id',
'content_type',
'content_id',
'og_title',
'og_description',
'og_image',
'og_type',
'seo_title',
'meta_description',
'robots',
'canonical_url',
'language',
'published',
'created',
'modified',
];
/**
* The fields to render in list responses.
*
* @var array
*/
protected $fieldsToRenderList = [
'id',
'content_type',
'content_id',
'og_title',
'og_description',
'og_image',
'og_type',
'seo_title',
'meta_description',
'robots',
'canonical_url',
'language',
'published',
'created',
'modified',
];
}
+6
View File
@@ -69,4 +69,10 @@
<menu link="option=com_mokoog&amp;view=tags">COM_MOKOOG_SUBMENU_TAGS</menu>
</submenu>
</administration>
<api>
<files folder="api">
<folder>src</folder>
</files>
</api>
</extension>
@@ -0,0 +1,68 @@
<?php
/**
* @package MokoOpenGraph
* @subpackage com_mokoog
* @author Moko Consulting <hello@mokoconsulting.tech>
* @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\Model;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Model\AdminModel;
class TagModel extends AdminModel
{
/**
* Get the form for the item.
*
* @param array $data Form data
* @param bool $loadData Load data from state
*
* @return \Joomla\CMS\Form\Form|false
*/
public function getForm($data = [], $loadData = true)
{
$form = $this->loadForm(
'com_mokoog.tag',
'tag',
['control' => 'jform', 'load_data' => $loadData]
);
return $form ?: false;
}
/**
* Load the form data.
*
* @return object
*/
protected function loadFormData(): object
{
$data = Factory::getApplication()->getUserState('com_mokoog.edit.tag.data', []);
if (empty($data)) {
$data = $this->getItem();
}
return $data;
}
/**
* Get the table class name.
*
* @param string $name Table name
* @param string $prefix Table prefix
* @param array $options Table options
*
* @return \Joomla\CMS\Table\Table
*/
public function getTable($name = 'Tag', $prefix = 'Administrator', $options = [])
{
return parent::getTable($name, $prefix, $options);
}
}
@@ -0,0 +1,5 @@
; MokoOpenGraph - Web Services Plugin Language File
; Copyright (C) 2026 Moko Consulting. All rights reserved.
; License: GPL-3.0-or-later
PLG_WEBSERVICES_MOKOOG="Web Services - MokoOpenGraph"
@@ -0,0 +1,6 @@
; MokoOpenGraph - Web Services Plugin System Language File
; Copyright (C) 2026 Moko Consulting. All rights reserved.
; License: GPL-3.0-or-later
PLG_WEBSERVICES_MOKOOG="Web Services - MokoOpenGraph"
PLG_WEBSERVICES_MOKOOG_DESCRIPTION="Exposes MokoOpenGraph OG tag data via Joomla's REST API at /api/index.php/v1/mokoog/tags."
@@ -0,0 +1,5 @@
; MokoOpenGraph - Web Services Plugin Language File
; Copyright (C) 2026 Moko Consulting. All rights reserved.
; License: GPL-3.0-or-later
PLG_WEBSERVICES_MOKOOG="Web Services - MokoOpenGraph"
@@ -0,0 +1,6 @@
; MokoOpenGraph - Web Services Plugin System Language File
; Copyright (C) 2026 Moko Consulting. All rights reserved.
; License: GPL-3.0-or-later
PLG_WEBSERVICES_MOKOOG="Web Services - MokoOpenGraph"
PLG_WEBSERVICES_MOKOOG_DESCRIPTION="Exposes MokoOpenGraph OG tag data via Joomla's REST API at /api/index.php/v1/mokoog/tags."
@@ -0,0 +1,19 @@
<?php
/**
* @package MokoOpenGraph
* @subpackage plg_webservices_mokoog
* @author Moko Consulting <hello@mokoconsulting.tech>
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*
* Legacy entry point — not executed under DI container.
*/
defined('_JEXEC') or die;
use Joomla\CMS\Plugin\CMSPlugin;
class PlgWebservicesMokoog extends CMSPlugin
{
}
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
* @package MokoOpenGraph
* @subpackage plg_webservices_mokoog
* @author Moko Consulting <hello@mokoconsulting.tech>
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
-->
<extension type="plugin" group="webservices" method="upgrade">
<name>Web Services - MokoOpenGraph</name>
<version>01.00.00</version>
<creationDate>2026-05-23</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<copyright>Copyright (C) 2026 Moko Consulting. All rights reserved.</copyright>
<license>GPL-3.0-or-later</license>
<description>PLG_WEBSERVICES_MOKOOG_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\WebServices\MokoOG</namespace>
<files>
<filename plugin="mokoog">mokoog.php</filename>
<folder>src</folder>
<folder>services</folder>
<folder>language</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_webservices_mokoog.ini</language>
<language tag="en-GB">language/en-GB/plg_webservices_mokoog.sys.ini</language>
</languages>
</extension>
@@ -0,0 +1,44 @@
<?php
/**
* @package MokoOpenGraph
* @subpackage plg_webservices_mokoog
* @author Moko Consulting <hello@mokoconsulting.tech>
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\WebServices\MokoOG\Extension\MokoOGWebServices;
return new class () implements ServiceProviderInterface {
/**
* Register the service provider.
*
* @param Container $container The DI container
*
* @return void
*/
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new MokoOGWebServices(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('webservices', 'mokoog')
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};
@@ -0,0 +1,81 @@
<?php
/**
* @package MokoOpenGraph
* @subpackage plg_webservices_mokoog
* @author Moko Consulting <hello@mokoconsulting.tech>
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
namespace Joomla\Plugin\WebServices\MokoOG\Extension;
defined('_JEXEC') or die;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Router\ApiRouter;
use Joomla\Event\Event;
use Joomla\Event\SubscriberInterface;
use Joomla\Router\Route;
final class MokoOGWebServices extends CMSPlugin implements SubscriberInterface
{
/**
* @var bool
*/
protected $autoloadLanguage = true;
/**
* Returns the events this plugin subscribes to.
*
* @return array<string, string>
*/
public static function getSubscribedEvents(): array
{
return [
'onBeforeApiRoute' => 'onBeforeApiRoute',
];
}
/**
* Register API routes for MokoOpenGraph.
*
* Endpoints:
* GET /api/index.php/v1/mokoog/tags - List all OG tags
* GET /api/index.php/v1/mokoog/tags/:id - Get single OG tag
* POST /api/index.php/v1/mokoog/tags - Create OG tag
* PATCH /api/index.php/v1/mokoog/tags/:id - Update OG tag
* DELETE /api/index.php/v1/mokoog/tags/:id - Delete OG tag
*
* @param Event $event The event object
*
* @return void
*/
public function onBeforeApiRoute(Event $event): void
{
[$router] = array_values($event->getArguments());
$defaults = [
'component' => 'com_mokoog',
'public' => false,
];
// CRUD routes for OG tags
$router->createCRUDRoutes(
'v1/mokoog/tags',
'tags',
$defaults
);
// GET by content type + content ID (lookup endpoint)
$router->addRoute(
new Route(
['GET'],
'v1/mokoog/lookup/:content_type/:content_id',
'tags.lookup',
['content_type' => '[a-z_.]+', 'content_id' => '(\d+)'],
$defaults
)
);
}
}
+1
View File
@@ -23,6 +23,7 @@
<file type="component" id="com_mokoog">com_mokoog.zip</file>
<file type="plugin" id="mokoog" group="system">plg_system_mokoog.zip</file>
<file type="plugin" id="mokoog" group="content">plg_content_mokoog.zip</file>
<file type="plugin" id="mokoog" group="webservices">plg_webservices_mokoog.zip</file>
</files>
<languages>
+11
View File
@@ -73,6 +73,17 @@ class Pkg_MokoOGInstallerScript
$db->setQuery($query);
$db->execute();
// Enable the webservices plugin automatically
$query = $db->getQuery(true)
->update($db->quoteName('#__extensions'))
->set($db->quoteName('enabled') . ' = 1')
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
->where($db->quoteName('folder') . ' = ' . $db->quote('webservices'))
->where($db->quoteName('element') . ' = ' . $db->quote('mokoog'));
$db->setQuery($query);
$db->execute();
}
}
}