Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion administrator/language/en-GB/plg_system_schemaorg.ini
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ PLG_SYSTEM_SCHEMAORG_BASETYPE_DESCRIPTION="Choose whether your website represent
PLG_SYSTEM_SCHEMAORG_BASETYPE_LABEL="Base Type"
PLG_SYSTEM_SCHEMAORG_BASETYPE_OPTION_ORGANIZATION="Organization"
PLG_SYSTEM_SCHEMAORG_BASETYPE_OPTION_PERSON="Person"
PLG_SYSTEM_SCHEMAORG_CONTACT_LABEL="Select Contact"
PLG_SYSTEM_SCHEMAORG_CONTACT_LABEL="Select Default Contact"
PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_DESCRIPTION="Structured data is a standardised format for organising and representing information on the web. It provides a way to describe the content and meaning of data in a structured manner, making it easier for search engines and other applications to understand and process the information. <a href=\"https://schema.org\" target=\"_blank\" rel=\"noopener noreferrer\">More information on schema.org</a>."
PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_DESCRIPTION_NOT_CONFIGURED="To use the schema.org functionality, you have to configure the plugin first. Please contact an administrator of the page to get it configured."
PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_DESCRIPTION_NOT_CONFIGURED_ADMIN="To use the schema.org functionality, you have to configure the plugin first. Please select <a href=\"index.php?option=com_plugins&amp;task=plugin.edit&amp;extension_id=%s\" target=\"_blank\">this link to open the plugin</a>, configure and save."
Expand All @@ -17,6 +17,8 @@ PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_LABEL="Schema"
PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_TYPE_LABEL="Schema Type"
PLG_SYSTEM_SCHEMAORG_IMAGE_LABEL="Image"
PLG_SYSTEM_SCHEMAORG_NAME_LABEL="Name"
PLG_SYSTEM_SCHEMAORG_PREFER_AUTHORS_CONTACT_LABEL="Prefer Author's Contact"
PLG_SYSTEM_SCHEMAORG_PREFER_AUTHORS_CONTACT_DESC="If enabled, the plugin will try to use the contact assigned to the article's author as the main contact. If no contact is assigned to the author, it will fall back to the default contact."
PLG_SYSTEM_SCHEMAORG_SOCIALMEDIA_LABEL="Social Media Accounts"
PLG_SYSTEM_SCHEMAORG_SOCIALMEDIA_URL_LABEL="URL"
PLG_SYSTEM_SCHEMAORG_USER_LABEL="Select User"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,15 @@
// Normalize simple contact object and trim strings
const contact = Object.assign({}, contactData);
let isDefaultContact = false;
let isAuthor = false;
Object.keys(contact).forEach((k) => {
if (typeof contact[k] === "string") contact[k] = contact[k].trim();
if (k === "isDefaultContact") {
isDefaultContact = Boolean(contact[k]);
}
if (k === "isAuthor") {
isAuthor = Boolean(contact[k]);
}
});

// find the role container (use nearby grouping)
Expand Down Expand Up @@ -143,7 +147,9 @@
roleContainer.querySelector(selector) ||
document.querySelector(selector);
let newValue = value;
if (isDefaultContact) {
if (isAuthor) {
newValue += ` — Inherited from author's contact "${contact.name}"`;
} else if (isDefaultContact) {
newValue += ` — Inherited from default contact "${contact.name}"`;
} else {
newValue += ` — Inherited from contact "${contact.name}"`;
Expand Down
9 changes: 9 additions & 0 deletions plugins/system/schemaorg/schemaorg.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@
edit="true"
clear="true"
/>
<field name="prefer_authors_contact"
type="radio"
label="PLG_SYSTEM_SCHEMAORG_PREFER_AUTHORS_CONTACT_LABEL"
description="PLG_SYSTEM_SCHEMAORG_PREFER_AUTHORS_CONTACT_DESC"
layout="joomla.form.field.radio.switcher"
default="1">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="name"
type="text"
Expand Down
104 changes: 102 additions & 2 deletions plugins/system/schemaorg/src/Extension/Schemaorg.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
use Joomla\CMS\Event\Plugin\System\Schemaorg\PrepareDataEvent;
use Joomla\CMS\Event\Plugin\System\Schemaorg\PrepareFormEvent;
use Joomla\CMS\Event\Plugin\System\Schemaorg\PrepareSaveEvent;
use Joomla\CMS\Factory;
use Joomla\CMS\Helper\ModuleHelper;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Plugin\PluginHelper;
Expand Down Expand Up @@ -242,6 +244,84 @@ public function onContentPrepareForm(Model\PrepareFormEvent $event)
}
}


/**
* Resolve the contact ID linked to the author of a given article.
*
* This method loads the com_content Article model to fetch the
* article's `created_by` user. It then attempts to find a published contact
* linked to that user via com_contact.
*
* @param int $itemId The content item (article) ID.
*
* @return int The resolved contact ID, or 0 if no match is found.
*
* @since __DEPLOY_VERSION__
*/
protected function getContactIdFromArticle(int $itemId): int
{
$contactId = 0;
$app = $this->getApplication();
try {
$component = $app->bootComponent('com_content');
/** @var \Joomla\CMS\Extension\MVCComponent $component */
$mvcFactory = $component->getMVCFactory();
// Load com_content's Article model
/** @var \Joomla\Component\Content\Administrator\Model\ArticleModel $articleModel */
$articleModel = $mvcFactory->createModel('Article', 'Administrator', ['ignore_request' => true]);
$article = $articleModel->getItem($itemId);

if ($article && $article->created_by > 0) {
$createdBy = (int) $article->created_by;
// Single, parameter-bound DB query to find a published contact for that user

/** @var \Joomla\CMS\MVC\Factory\MVCFactoryInterface $mvcFactory */
$mvcFactory = Factory::getApplication()->bootComponent('com_contact')->getMVCFactory();

// Create the Contact table
$table = $mvcFactory->createTable('Contact', 'Administrator');
$key = $table->getKeyName();
$db = $this->getDatabase();
$tableName = $table->getTableName();

$query = $db->getQuery(true)
->select($db->quoteName([$key, 'language', 'published']))
->from($db->quoteName($tableName))
->where($db->quoteName('user_id') . ' = :userid')
->bind(':userid', $createdBy, ParameterType::INTEGER)
->order($db->quoteName('published') . ' DESC, ' . $db->quoteName('language') . ' ASC');

$db->setQuery($query);
$contactItems = $db->loadObjectList();

if (empty($contactItems)) {
return 0;
}
$chosen = $contactItems[0];

if (Multilanguage::isEnabled()) {
// If any item has specific language (not '*'), prefer exact language match
$currentLang = $app->getLanguage()->getTag();

$matches = array_values(array_filter($contactItems, function ($it) use ($currentLang) {
return $it->language === $currentLang;
}));

if (!empty($matches)) {
$chosen = $matches[0];
}
}
$contactId = isset($chosen->id) ? (int) $chosen->id : null;

return $contactId ?? 0;
}
} catch (\Throwable $e) {
}

return (int) $contactId;
}


/**
 * Load JavaScript and CSS assets for contact field functionality
     * and pass pre-loaded contact data if it exists.
Expand All @@ -263,6 +343,16 @@ private function loadContactFieldAssets(int $contactId = 0): void
}
$defaultContactId = (int) $this->params->get('defaultContact', 0);
$isDefaultContact = false;
$isAuthor = false;
if ($contactId <= 0 && $this->params->get('prefer_authors_contact', 1) == 1) {
$currentItemId = (int) $app->input->getInt('id', 0);
$authorContactId = (int) $this->getContactIdFromArticle($currentItemId);

if ($authorContactId > 0) {
$contactId = $authorContactId;
$isAuthor = true;
}
}
if ($contactId <= 0 && $defaultContactId > 0) {
$contactId = $defaultContactId;
$isDefaultContact = true;
Expand Down Expand Up @@ -291,6 +381,7 @@ private function loadContactFieldAssets(int $contactId = 0): void
'telephone' => $contact->telephone ?? '',
'webpage' => $contact->webpage ?? '',
'isDefaultContact' => $isDefaultContact,
'isAuthor' => $isAuthor,
];
}
}
Expand Down Expand Up @@ -428,11 +519,20 @@ private function enrichGraphContacts(array &$graph): void

if ($filledNodes == 0) {
$defaultContactId = (int) $this->params->get('defaultContact', 0);
if ($defaultContactId > 0) {
$contact = $this->getContactById($defaultContactId);
$authorContactId = $this->getContactIdFromArticle((int) $this->getApplication()->input->getInt('id', 0));
// If no role nodes were filled, and we have a default contact or author contact, use that
if ($authorContactId > 0 && $this->params->get('prefer_authors_contact', 1) == 1) {
$contact = $this->getContactById($authorContactId);
if ($contact) {
$this->fillNodeFromContact($roleNode, $contact);
}
} else {
if ($defaultContactId > 0) {
$contact = $this->getContactById($defaultContactId);
if ($contact) {
$this->fillNodeFromContact($roleNode, $contact);
}
}
}
}
}
Expand Down
Loading