diff --git a/administrator/language/en-GB/plg_system_schemaorg.ini b/administrator/language/en-GB/plg_system_schemaorg.ini index 6b78d4e3a79..cadc757b420 100644 --- a/administrator/language/en-GB/plg_system_schemaorg.ini +++ b/administrator/language/en-GB/plg_system_schemaorg.ini @@ -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. More information on schema.org." 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 this link to open the plugin, configure and save." @@ -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" diff --git a/build/media_source/plg_system_schemaorg/js/schemaorg-contact.es6.js b/build/media_source/plg_system_schemaorg/js/schemaorg-contact.es6.js index ca321415325..a79b84b7b33 100644 --- a/build/media_source/plg_system_schemaorg/js/schemaorg-contact.es6.js +++ b/build/media_source/plg_system_schemaorg/js/schemaorg-contact.es6.js @@ -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) @@ -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}"`; diff --git a/plugins/system/schemaorg/schemaorg.xml b/plugins/system/schemaorg/schemaorg.xml index 26db5645641..f533e7410b6 100644 --- a/plugins/system/schemaorg/schemaorg.xml +++ b/plugins/system/schemaorg/schemaorg.xml @@ -51,6 +51,15 @@ edit="true" clear="true" /> + + + + 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. @@ -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; @@ -291,6 +381,7 @@ private function loadContactFieldAssets(int $contactId = 0): void 'telephone' => $contact->telephone ?? '', 'webpage' => $contact->webpage ?? '', 'isDefaultContact' => $isDefaultContact, + 'isAuthor' => $isAuthor, ]; } } @@ -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); + } + } } } }