From 0ce3cc89bb5c3ad1550fa394e5ab48681be38b74 Mon Sep 17 00:00:00 2001 From: shahzan01 Date: Mon, 1 Sep 2025 19:20:42 +0530 Subject: [PATCH 1/9] Work in progress : Added contact selection in Schema.org --- plugins/schemaorg/article/forms/schemaorg.xml | 333 +++++++----------- .../article/src/Extension/Article.php | 69 ++++ 2 files changed, 206 insertions(+), 196 deletions(-) diff --git a/plugins/schemaorg/article/forms/schemaorg.xml b/plugins/schemaorg/article/forms/schemaorg.xml index df464544719..cdf4709147a 100644 --- a/plugins/schemaorg/article/forms/schemaorg.xml +++ b/plugins/schemaorg/article/forms/schemaorg.xml @@ -1,199 +1,140 @@
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - -
- - - - - - - -
-
-
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ + + + + +
+
+
diff --git a/plugins/schemaorg/article/src/Extension/Article.php b/plugins/schemaorg/article/src/Extension/Article.php index 2e966a59b61..816192ef567 100644 --- a/plugins/schemaorg/article/src/Extension/Article.php +++ b/plugins/schemaorg/article/src/Extension/Article.php @@ -10,11 +10,14 @@ namespace Joomla\Plugin\Schemaorg\Article\Extension; +use Joomla\CMS\Document\Factory; +use Joomla\CMS\Event\Model\PrepareFormEvent; use Joomla\CMS\Event\Plugin\System\Schemaorg\BeforeCompileHeadEvent; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Schemaorg\SchemaorgPluginTrait; use Joomla\CMS\Schemaorg\SchemaorgPrepareDateTrait; use Joomla\CMS\Schemaorg\SchemaorgPrepareImageTrait; +use Joomla\Database\DatabaseInterface; use Joomla\Event\Priority; use Joomla\Event\SubscriberInterface; @@ -33,6 +36,14 @@ final class Article extends CMSPlugin implements SubscriberInterface use SchemaorgPrepareDateTrait; use SchemaorgPrepareImageTrait; + + /** + * The application object. + * + * @var CMSApplication + */ + protected $app; + /** * Load the language file on instantiation. * @@ -79,7 +90,41 @@ public function onSchemaBeforeCompileHead(BeforeCompileHeadEvent $event): void $graph = $schema->get('@graph'); + $app = $this->app; + $contactId = null; + + foreach ($graph as $entry) { + // Loop through each property inside the entry + foreach ($entry as $key => $value) { + // If the property itself is an array (like author, organiser etc.) + if (is_array($value)) { + if (isset($value['contact'])) { + $contactId = $value['contact']; + // You can break out here if you only need the first contact + break 2; + } + } + } + } + + $contact = null; + if ($contactId) { + /** @var MVCComponent $component */ + $component = $app->bootComponent('com_contact'); + /** @var MVCFactoryInterface $mvcFactory */ + $mvcFactory = $component->getMVCFactory(); + /** @var ContactModel $model */ + $contactModel = $mvcFactory->createModel('Contact', 'Site', ['ignore_request' => true]); + + $contactModel->setState('params', \Joomla\CMS\Factory::getApplication()->getParams()); + $contactModel->setState('contact.id', 1); + + + $contact = $contactModel->getItem(); + } + foreach ($graph as &$entry) { + if (!isset($entry['@type']) || $entry['@type'] !== 'Article') { continue; } @@ -95,6 +140,30 @@ public function onSchemaBeforeCompileHead(BeforeCompileHeadEvent $event): void if (!empty($entry['image'])) { $entry['image'] = $this->prepareImage($entry['image']); } + if ($contact) { + // Make sure author exists first + if (empty($entry['author'])) { + $entry['author'] = [ + '@type' => 'Person' + ]; + } + + if (empty($entry['author']['name']) && !empty($contact->name)) { + $entry['author']['name'] = $contact->name; + } + + if (empty($entry['author']['email']) && !empty($contact->email_to)) { + $entry['author']['email'] = $contact->email_to; + } + + if (empty($entry['author']['url']) && !empty($contact->webpage)) { + $entry['author']['url'] = $contact->webpage; + } + + if (empty($entry['author']['address']) && !empty($contact->address)) { + $entry['author']['address'] = $contact->address; + } + } } $schema->set('@graph', $graph); From 79541849ec7890ef626941ce4d5e739c3e9ee9b5 Mon Sep 17 00:00:00 2001 From: shahzan01 Date: Fri, 5 Sep 2025 09:09:10 +0530 Subject: [PATCH 2/9] feat : added contact selection to schemaorg plugin --- plugins/schemaorg/article/forms/schemaorg.xml | 17 -- .../article/src/Extension/Article.php | 69 ----- .../schemaorg/src/Extension/Schemaorg.php | 244 +++++++++++++++++- 3 files changed, 242 insertions(+), 88 deletions(-) diff --git a/plugins/schemaorg/article/forms/schemaorg.xml b/plugins/schemaorg/article/forms/schemaorg.xml index cdf4709147a..2b9b922b15c 100644 --- a/plugins/schemaorg/article/forms/schemaorg.xml +++ b/plugins/schemaorg/article/forms/schemaorg.xml @@ -37,23 +37,6 @@ - get('@graph'); - $app = $this->app; - $contactId = null; - - foreach ($graph as $entry) { - // Loop through each property inside the entry - foreach ($entry as $key => $value) { - // If the property itself is an array (like author, organiser etc.) - if (is_array($value)) { - if (isset($value['contact'])) { - $contactId = $value['contact']; - // You can break out here if you only need the first contact - break 2; - } - } - } - } - - $contact = null; - if ($contactId) { - /** @var MVCComponent $component */ - $component = $app->bootComponent('com_contact'); - /** @var MVCFactoryInterface $mvcFactory */ - $mvcFactory = $component->getMVCFactory(); - /** @var ContactModel $model */ - $contactModel = $mvcFactory->createModel('Contact', 'Site', ['ignore_request' => true]); - - $contactModel->setState('params', \Joomla\CMS\Factory::getApplication()->getParams()); - $contactModel->setState('contact.id', 1); - - - $contact = $contactModel->getItem(); - } - foreach ($graph as &$entry) { - if (!isset($entry['@type']) || $entry['@type'] !== 'Article') { continue; } @@ -140,30 +95,6 @@ public function onSchemaBeforeCompileHead(BeforeCompileHeadEvent $event): void if (!empty($entry['image'])) { $entry['image'] = $this->prepareImage($entry['image']); } - if ($contact) { - // Make sure author exists first - if (empty($entry['author'])) { - $entry['author'] = [ - '@type' => 'Person' - ]; - } - - if (empty($entry['author']['name']) && !empty($contact->name)) { - $entry['author']['name'] = $contact->name; - } - - if (empty($entry['author']['email']) && !empty($contact->email_to)) { - $entry['author']['email'] = $contact->email_to; - } - - if (empty($entry['author']['url']) && !empty($contact->webpage)) { - $entry['author']['url'] = $contact->webpage; - } - - if (empty($entry['author']['address']) && !empty($contact->address)) { - $entry['author']['address'] = $contact->address; - } - } } $schema->set('@graph', $graph); diff --git a/plugins/system/schemaorg/src/Extension/Schemaorg.php b/plugins/system/schemaorg/src/Extension/Schemaorg.php index a3c1dc7f10f..1fab0e01108 100644 --- a/plugins/system/schemaorg/src/Extension/Schemaorg.php +++ b/plugins/system/schemaorg/src/Extension/Schemaorg.php @@ -50,6 +50,29 @@ final class Schemaorg extends CMSPlugin implements SubscriberInterface, Dispatch use SchemaorgPrepareImageTrait; use UserFactoryAwareTrait; + /** + * Map of schema types to their role fields + * + * @var array + * + * @since __DEPLOY_VERSION__ + */ + private const ROLE_CONTACT_MAP = [ + 'Article' => [ + 'author' + ], + 'BlogPosting' => [ + 'author' + ], + 'Book' => [ + 'illustrator' + ], + 'Event' => [ + 'organizer', + ], + + ]; + /** * Returns an array of events this subscriber will listen to. * @@ -150,7 +173,6 @@ public function onContentPrepareForm(Model\PrepareFormEvent $event) // Load the form fields $form->loadFile(JPATH_PLUGINS . '/' . $this->_type . '/' . $this->_name . '/forms/schemaorg.xml'); - // The user should configure the plugin first if (!$this->params->get('baseType')) { $form->removeField('schemaType', 'schema'); @@ -181,6 +203,221 @@ public function onContentPrepareForm(Model\PrepareFormEvent $event) PluginHelper::importPlugin('schemaorg', null, true, $dispatcher); $dispatcher->dispatch('onSchemaPrepareForm', $event); + + // Inject contact fields into relevant roles + foreach (self::ROLE_CONTACT_MAP as $type => $roles) { + foreach ($roles as $role) { + $this->injectContactField($form, $type, $role); + } + } + } + + /** + * Inject a Contact selector field into a role subform for a given Schema.org type. + * + * @param \Joomla\CMS\Form\Form $form The active form being prepared. + * @param string $type Schema.org type name (e.g. "Article", "Book"). + * @param string $role Role field name under that type (e.g. "author", "illustrator"). + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + private function injectContactField(\Joomla\CMS\Form\Form $form, string $type, string $role): void + { + + $xml = $form->getXml(); + $nodes = $xml->xpath("//fieldset[@name='schema']/field[@name='{$type}']/form/field[@name='{$role}']"); + if (!$nodes || !isset($nodes[0])) { + return; // no such role in this type + } + + $roleField = $nodes[0]; + + $contact = new \SimpleXMLElement(''); + $contact->addAttribute('name', 'contact'); + $contact->addAttribute('type', 'modal_contact'); + $contact->addAttribute('label', 'COM_CONTACT_SELECT_CONTACT_LABEL'); + $contact->addAttribute('hiddenLabel', 'true'); + $contact->addAttribute('select', 'true'); + $contact->addAttribute('new', 'true'); + $contact->addAttribute('edit', 'true'); + $contact->addAttribute('clear', 'true'); + $contact->addAttribute('addfieldprefix', 'Joomla\Component\Contact\Administrator\Field'); + + // Prepend into the role’s inner
so it’s the first control + $domForm = dom_import_simplexml($roleField->form); + $domContact = $domForm->ownerDocument->importNode(dom_import_simplexml($contact), true); + $domForm->insertBefore($domContact, $domForm->firstChild); + } + + /** + * Enrich top-level @graph entries for configured types/roles using com_contact data. + * + * @param array $graph + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + private function enrichGraphContacts(array &$graph): void + { + + + foreach ($graph as &$entry) { + if (!is_array($entry) || empty($entry['@type'])) { + continue; + } + + $type = $entry['@type']; + + if (!isset(self::ROLE_CONTACT_MAP[$type])) { + continue; + } + + foreach (self::ROLE_CONTACT_MAP[$type] as $role) { + if (!isset($entry[$role])) { + continue; + } + + // Normalize to list of role nodes by reference + $roleNodes = []; + $roleNodes = [&$entry[$role]]; + + // Enrich each role node when it has a contact id + foreach ($roleNodes as &$roleNode) { + if (!isset($roleNode['contact']) || (int) $roleNode['contact'] <= 0) { + continue; + } + $contact = $this->getContactById((int) $roleNode['contact']); + + if ($contact) { + $this->fillNodeFromContact($roleNode, $contact); + unset($roleNode['contact']); + } + } + } + } + } + + + + /** + * Fetch a com_contact record by its ID. + * + * @param int $id + * + * @return stdClass|null + * + * @since __DEPLOY_VERSION__ + */ + private function getContactById(int $id) + { + try { + $app = $this->getApplication(); + + /** @var \Joomla\CMS\Extension\MVCComponent $component */ + $component = $app->bootComponent('com_contact'); + $mvcFactory = $component->getMVCFactory(); + + /** @var \Joomla\Component\Contact\Site\Model\ContactModel $model */ + $model = $mvcFactory->createModel('Contact', 'Site', ['ignore_request' => true]); + + // Set state as com_contact does in front-end + $model->setState('params', $app->getParams()); + $model->setState('contact.id', $id); + + $contact = $model->getItem(); + + // Basic sanity check + if (!empty($contact) && (int) ($contact->id ?? 0) === $id) { + return $contact; + } + } catch (\Throwable $e) { + } + + return null; + } + + /** + * Copy contact details into the role node. + * + * @param array $node Role node array (passed by reference). + * @param stdClass $contact com_contact record. + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + private function fillNodeFromContact(array &$node, $contact): void + { + // Core fields (fill only if missing) + if (empty($node['name']) && !empty($contact->name)) { + $node['name'] = $contact->name; + } + if (empty($node['email']) && !empty($contact->email_to)) { + $node['email'] = $contact->email_to; + } + if (empty($node['url']) && !empty($contact->webpage)) { + $node['url'] = $contact->webpage; + } + + // Build a PostalAddress object as "address" + + if (isset($node['address']) && is_array($node['address'])) { + $addr = $node['address']; + } else { + $addr = []; + } + + $addr['@type'] = 'PostalAddress'; + + + // Only set if missing to avoid overriding manually filled values + if (empty($addr['addressLocality'])) { + if (!empty($node['addressLocality'])) { + $addr['addressLocality'] = $node['addressLocality']; + } elseif (!empty($contact->suburb)) { + $addr['addressLocality'] = $contact->suburb; + } + } + + if (empty($addr['postalCode'])) { + if (!empty($node['postalCode'])) { + $addr['postalCode'] = $node['postalCode']; + } elseif (!empty($contact->postcode)) { + $addr['postalCode'] = $contact->postcode; + } + } + + if (empty($addr['streetAddress'])) { + if (!empty($node['streetAddress'])) { + $addr['streetAddress'] = $node['streetAddress']; + } elseif (!empty($contact->street)) { + $addr['streetAddress'] = $contact->street; + } elseif (!empty($contact->address)) { + // As a fallback, use the flat address if street isn’t split out + $addr['streetAddress'] = $contact->address; + } + } + + if (empty($addr['addressRegion'])) { + if (!empty($node['addressRegion'])) { + $addr['addressRegion'] = $node['addressRegion']; + } elseif (!empty($contact->state)) { + $addr['addressRegion'] = $contact->state; + } + } + + if (empty($addr['addressCountry'])) { + if (!empty($node['addressCountry'])) { + $addr['addressCountry'] = $node['addressCountry']; + } elseif (!empty($contact->country)) { + $addr['addressCountry'] = $contact->country; + } + } + + $node['address'] = $addr; } /** @@ -428,7 +665,10 @@ public function onBeforeCompileHead(): void PluginHelper::importPlugin('schemaorg', null, true, $dispatcher); $dispatcher->dispatch('onSchemaBeforeCompileHead', $event); - $data = $schema->get('@graph'); + $data = $schema->get('@graph') ?: []; + + // Enrich contacts from com_contact + $this->enrichGraphContacts($data); foreach ($data as $key => $entry) { $data[$key] = $this->cleanupSchema($entry); From fccd3f392c1f99347b6a5862042bd110d649c858 Mon Sep 17 00:00:00 2001 From: shahzan01 Date: Fri, 5 Sep 2025 09:34:46 +0530 Subject: [PATCH 3/9] Revert Article-schemaorg.xml to original --- plugins/schemaorg/article/forms/schemaorg.xml | 316 +++++++++++------- 1 file changed, 196 insertions(+), 120 deletions(-) diff --git a/plugins/schemaorg/article/forms/schemaorg.xml b/plugins/schemaorg/article/forms/schemaorg.xml index 2b9b922b15c..df464544719 100644 --- a/plugins/schemaorg/article/forms/schemaorg.xml +++ b/plugins/schemaorg/article/forms/schemaorg.xml @@ -1,123 +1,199 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - -
- - - - - -
-
-
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+
+
From 4b155db0580fa36bffdb85e8553b2e1496937f1a Mon Sep 17 00:00:00 2001 From: shahzan01 Date: Thu, 11 Sep 2025 22:53:42 +0530 Subject: [PATCH 4/9] feat : added the placeholder for the contact data in the schema.org plugin --- .../plg_system_schemaorg/joomla.asset.json | 19 ++ .../js/schemaorg-contact.es6.js | 166 ++++++++++++++++++ .../schemaorg/src/Extension/Schemaorg.php | 99 +++++++++++ 3 files changed, 284 insertions(+) create mode 100644 build/media_source/plg_system_schemaorg/joomla.asset.json create mode 100644 build/media_source/plg_system_schemaorg/js/schemaorg-contact.es6.js diff --git a/build/media_source/plg_system_schemaorg/joomla.asset.json b/build/media_source/plg_system_schemaorg/joomla.asset.json new file mode 100644 index 00000000000..8b2c6833726 --- /dev/null +++ b/build/media_source/plg_system_schemaorg/joomla.asset.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json", + "name": "plg_system_schemaorg", + "version": "1.0.0", + "description": "Schema.org System Plugin Assets", + "license": "GPL-2.0-or-later", + "assets": [ + { + "name": "plg_system_schemaorg.contact", + "type": "script", + "uri": "plg_system_schemaorg/schemaorg-contact.js", + "dependencies": ["core"], + "attributes": { + "defer": true + }, + "version": "1.0.0" + } + ] +} 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 new file mode 100644 index 00000000000..12189b2c7bc --- /dev/null +++ b/build/media_source/plg_system_schemaorg/js/schemaorg-contact.es6.js @@ -0,0 +1,166 @@ +/** + * schemaorg-contact.js + * Minimal: populate placeholders from injected initialContact by baseName. + */ +((Joomla, document) => { + "use strict"; + + class SchemaOrgContactHandler { + constructor(options) { + this.options = Object.assign( + { + fieldMappings: { + name: "name", + email: "email_to", + url: "webpage", + streetAddress: ["address", "street"], + addressLocality: ["suburb", "state", "address"], + postalCode: "postcode", + addressRegion: "state", + addressCountry: "country", + telephone: "telephone", + mobile: "mobile", + fax: "fax", + misc: "misc", + position: "position", + }, + }, + options + ); + + // nested fields that must go under [address] + this.nestedFields = { + streetAddress: "address", + postalCode: "address", + addressLocality: "address", + addressRegion: "address", + addressCountry: "address", + }; + + // read injected contact from Joomla options or global + const opt = + (Joomla && + Joomla.getOptions && + Joomla.getOptions("plg_system_schemaorg")) || + window.plg_system_schemaorg || + {}; + this.initialContact = opt.initialContact || null; + + this._initOnce = false; + this.init(); + } + + init() { + if (this._initOnce) return; + this._initOnce = true; + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", () => this.bindEvents()); + } else { + this.bindEvents(); + } + } + + bindEvents() { + // Scope to the current form + const form = document.querySelector("form"); + if (!form) return; + + // Contact title inputs in the form + const contactNameFields = form.querySelectorAll( + "input.js-input-title[name*='[contact]']" + ); + + contactNameFields.forEach((field) => { + if (field.value && field.value.trim() && this.initialContact) { + this.populatePlaceholders(field, this.initialContact); + } + }); + } + + populatePlaceholders(contactField, contactData) { + if (!contactField || !contactData) return; + + // Normalize simple contact object and trim strings + const contact = Object.assign({}, contactData); + Object.keys(contact).forEach((k) => { + if (typeof contact[k] === "string") contact[k] = contact[k].trim(); + }); + + // find the role container (use nearby grouping) + const roleContainer = contactField.closest( + ".subform-repeatable-group, fieldset, form" + ); + if (!roleContainer) return; + + // Parse baseName from contact field name + const contactName = contactField.name || ""; + const baseMatch = contactName.match(/^(.*)\[contact\]$/); + if (!baseMatch) { + console.debug("schemaorg: contact baseName not found for", contactName); + return; + } + const baseName = baseMatch[1]; // e.g. jform[schema][Book][illustrator] + + // For each mapping, compute target name and set placeholder + Object.entries(this.options.fieldMappings).forEach( + ([schemaField, contactKey]) => { + let value = ""; + + if (Array.isArray(contactKey)) { + for (const k of contactKey) { + if (contact[k]) { + value = contact[k]; + break; + } + } + } else { + value = contact[contactKey] || ""; + } + + if (!value) return; + + const parentKey = this.nestedFields[schemaField] || null; + const targetName = parentKey + ? `${baseName}[${parentKey}][${schemaField}]` + : `${baseName}[${schemaField}]`; + + // find the input within the same roleContainer + const selector = `input[name='${targetName}'], textarea[name='${targetName}'], select[name='${targetName}']`; + const targetField = + roleContainer.querySelector(selector) || + document.querySelector(selector); + + if (targetField) { + targetField.placeholder = value + " — Inherited from contact"; + targetField.classList.add("has-contact-placeholder"); + } else { + // debug if not found + console.debug( + "schemaorg: could not find target field for", + targetName + ); + } + } + ); + + // emit event + document.dispatchEvent( + new CustomEvent("schemaorg:contact:loaded", { + detail: { + contactId: contact.id, + contactData: contact, + container: roleContainer, + }, + }) + ); + } + } + + // Initialize once + if (typeof Joomla !== "undefined") { + if (!Joomla.SchemaOrgContactHandler) { + Joomla.SchemaOrgContactHandler = new SchemaOrgContactHandler(); + } + } +})(window.Joomla, document); diff --git a/plugins/system/schemaorg/src/Extension/Schemaorg.php b/plugins/system/schemaorg/src/Extension/Schemaorg.php index 1fab0e01108..f9f4c883503 100644 --- a/plugins/system/schemaorg/src/Extension/Schemaorg.php +++ b/plugins/system/schemaorg/src/Extension/Schemaorg.php @@ -74,6 +74,13 @@ final class Schemaorg extends CMSPlugin implements SubscriberInterface, Dispatch ]; /** +     * Temporarily holds schema data between onContentPrepareData and onContentPrepareForm events. +     * +     * @var  ?array +     * @since __DEPLOY_VERSION__ +     */ + private ?array $preparedSchemaData = null; + /** * Returns an array of events this subscriber will listen to. * * @return array @@ -138,6 +145,8 @@ public function onContentPrepareData(Model\PrepareDataEvent $event) $schema = new Registry($results['schema']); $data->schema[$schemaType] = $schema->toArray(); + // Store the loaded data for use in onContentPrepareForm + $this->preparedSchemaData = $data->schema; } $dispatcher = $this->getDispatcher(); @@ -210,6 +219,95 @@ public function onContentPrepareForm(Model\PrepareFormEvent $event) $this->injectContactField($form, $type, $role); } } + + // After injecting contact fields, load the JavaScript + if ($app->isClient('administrator') && $this->isSupported($context)) { + $contactId = 0; + if ($this->preparedSchemaData) { + + foreach (self::ROLE_CONTACT_MAP as $type => $roles) { + + if (isset($this->preparedSchemaData[$type])) { + foreach ($roles as $role) { + if (!empty($this->preparedSchemaData[$type][$role]['contact'])) { + $contactId = (int) $this->preparedSchemaData[$type][$role]['contact']; + break 2; + } + } + } + } + } + + $this->loadContactFieldAssets($contactId); + } + } + + /** +  * Load JavaScript and CSS assets for contact field functionality +     * and pass pre-loaded contact data if it exists. +     * +     * @param   int  $contactId  The ID of a pre-selected contact, or 0 if none. +     * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + private function loadContactFieldAssets(int $contactId = 0): void + { + + $app = $this->getApplication(); + $doc = $app->getDocument(); + + if (!($doc instanceof \Joomla\CMS\Document\HtmlDocument)) { + return; + } + + $initialContactData = null; + if ($contactId > 0) { + + /** @var \Joomla\CMS\Extension\MVCComponent $component */ + $component = $app->bootComponent('com_contact'); + $mvcFactory = $component->getMVCFactory(); + + /** @var ContactModel $contactModel */ + $contactModel = $mvcFactory->createModel('Contact', 'Administrator', ['ignore_request' => true]); + $contact = $contactModel->getItem($contactId); + if ($contact) { + $initialContactData = [ + 'id' => (int) ($contact->id ?? 0), + 'name' => $contact->name ?? '', + 'email_to' => $contact->email_to ?? '', + 'address' => $contact->address ?? '', + 'street' => $contact->street ?? '', + 'suburb' => $contact->suburb ?? '', + 'state' => $contact->state ?? '', + 'postcode' => $contact->postcode ?? '', + 'country' => $contact->country ?? '', + 'telephone' => $contact->telephone ?? '', + 'webpage' => $contact->webpage ?? '', + ]; + } + } + $wa = $doc->getWebAssetManager(); + + // Register the asset if not already registered + if (!$wa->assetExists('script', 'plg_system_schemaorg.contact')) { + $wa->registerScript( + 'plg_system_schemaorg.contact', + 'plg_system_schemaorg/schemaorg-contact.js', + ['version' => 'auto', 'relative' => true], + ['defer' => true], + ['core'] + ); + } + + // // Use the assets + $wa->useScript('plg_system_schemaorg.contact'); + + // Add inline configuration + $doc->addScriptOptions('plg_system_schemaorg', [ + 'initialContact' => $initialContactData, + ]); } /** @@ -420,6 +518,7 @@ private function fillNodeFromContact(array &$node, $contact): void $node['address'] = $addr; } + /** * Saves form field data in the database * From 01ae119d5610c8b33881e945473a278132ae2557 Mon Sep 17 00:00:00 2001 From: shahzan01 Date: Fri, 12 Sep 2025 10:30:31 +0530 Subject: [PATCH 5/9] feat : added default contact and permission check for contact --- .../language/en-GB/plg_system_schemaorg.ini | 45 +++++++-------- .../js/schemaorg-contact.es6.js | 25 +++++++-- plugins/system/schemaorg/schemaorg.xml | 13 ++++- .../schemaorg/src/Extension/Schemaorg.php | 55 +++++++++++++++++-- 4 files changed, 104 insertions(+), 34 deletions(-) diff --git a/administrator/language/en-GB/plg_system_schemaorg.ini b/administrator/language/en-GB/plg_system_schemaorg.ini index 189a8c2a5f2..3ca8b6c7507 100644 --- a/administrator/language/en-GB/plg_system_schemaorg.ini +++ b/administrator/language/en-GB/plg_system_schemaorg.ini @@ -1,22 +1,23 @@ -; Joomla! Project -; (C) 2023 Open Source Matters, Inc. -; License GNU General Public License version 2 or later; see LICENSE.txt -; Note : All ini files need to be saved as UTF-8 - -PLG_SYSTEM_SCHEMAORG="System - Schema.org" -PLG_SYSTEM_SCHEMAORG_BASETYPE_DESCRIPTION="Choose whether your website represents an organization or a single person." -PLG_SYSTEM_SCHEMAORG_BASETYPE_LABEL="Base Type" -PLG_SYSTEM_SCHEMAORG_BASETYPE_OPTION_ORGANIZATION="Organization" -PLG_SYSTEM_SCHEMAORG_BASETYPE_OPTION_PERSON="Person" -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_CONFIGURATED="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_CONFIGURATED_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." -PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_EXTEND_JED_DESC="Need more Schema types? Extend with Schema Plugins from Joomla! Extension Directory." -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_SOCIALMEDIA_LABEL="Social Media Accounts" -PLG_SYSTEM_SCHEMAORG_SOCIALMEDIA_URL_LABEL="URL" -PLG_SYSTEM_SCHEMAORG_USER_LABEL="Select User" -PLG_SYSTEM_SCHEMAORG_XML_DESCRIPTION="Adds custom form field in article view and then injects that data in JSON+LD format in the head tag of that particular article." +; Joomla! Project +; (C) 2023 Open Source Matters, Inc. +; License GNU General Public License version 2 or later; see LICENSE.txt +; Note : All ini files need to be saved as UTF-8 + +PLG_SYSTEM_SCHEMAORG="System - Schema.org" +PLG_SYSTEM_SCHEMAORG_BASETYPE_DESCRIPTION="Choose whether your website represents an organization or a single person." +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_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_CONFIGURATED="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_CONFIGURATED_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." +PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_EXTEND_JED_DESC="Need more Schema types? Extend with Schema Plugins from Joomla! Extension Directory." +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_SOCIALMEDIA_LABEL="Social Media Accounts" +PLG_SYSTEM_SCHEMAORG_SOCIALMEDIA_URL_LABEL="URL" +PLG_SYSTEM_SCHEMAORG_USER_LABEL="Select User" +PLG_SYSTEM_SCHEMAORG_XML_DESCRIPTION="Adds custom form field in article view and then injects that data in JSON+LD format in the head tag of that particular article." 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 12189b2c7bc..ca321415325 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 @@ -70,12 +70,21 @@ const contactNameFields = form.querySelectorAll( "input.js-input-title[name*='[contact]']" ); - + let isPopulated = false; contactNameFields.forEach((field) => { if (field.value && field.value.trim() && this.initialContact) { this.populatePlaceholders(field, this.initialContact); + isPopulated = true; } }); + if (!isPopulated) { + contactNameFields.forEach((field) => { + if (this.initialContact) { + this.populatePlaceholders(field, this.initialContact); + isPopulated = true; + } + }); + } } populatePlaceholders(contactField, contactData) { @@ -83,8 +92,12 @@ // Normalize simple contact object and trim strings const contact = Object.assign({}, contactData); + let isDefaultContact = false; Object.keys(contact).forEach((k) => { if (typeof contact[k] === "string") contact[k] = contact[k].trim(); + if (k === "isDefaultContact") { + isDefaultContact = Boolean(contact[k]); + } }); // find the role container (use nearby grouping) @@ -119,7 +132,6 @@ } if (!value) return; - const parentKey = this.nestedFields[schemaField] || null; const targetName = parentKey ? `${baseName}[${parentKey}][${schemaField}]` @@ -130,9 +142,14 @@ const targetField = roleContainer.querySelector(selector) || document.querySelector(selector); - + let newValue = value; + if (isDefaultContact) { + newValue += ` — Inherited from default contact "${contact.name}"`; + } else { + newValue += ` — Inherited from contact "${contact.name}"`; + } if (targetField) { - targetField.placeholder = value + " — Inherited from contact"; + targetField.placeholder = newValue; targetField.classList.add("has-contact-placeholder"); } else { // debug if not found diff --git a/plugins/system/schemaorg/schemaorg.xml b/plugins/system/schemaorg/schemaorg.xml index 326ef254756..26db5645641 100644 --- a/plugins/system/schemaorg/schemaorg.xml +++ b/plugins/system/schemaorg/schemaorg.xml @@ -20,7 +20,8 @@ -
+
- + params->get('defaultContact', 0); + $isDefaultContact = false; + if ($contactId <= 0 && $defaultContactId > 0) { + $contactId = $defaultContactId; + $isDefaultContact = true; + } $initialContactData = null; if ($contactId > 0) { @@ -285,6 +290,7 @@ private function loadContactFieldAssets(int $contactId = 0): void 'country' => $contact->country ?? '', 'telephone' => $contact->telephone ?? '', 'webpage' => $contact->webpage ?? '', + 'isDefaultContact' => $isDefaultContact, ]; } } @@ -332,15 +338,38 @@ private function injectContactField(\Joomla\CMS\Form\Form $form, string $type, s $roleField = $nodes[0]; + // Get current user and permission checks for com_contact + $user = $this->getApplication()->getIdentity(); + $canCreate = $user->authorise('core.create', 'com_contact'); + $canEdit = $user->authorise('core.edit', 'com_contact'); + $canView = $user->authorise('core.view', 'com_contact'); + $contact = new \SimpleXMLElement(''); $contact->addAttribute('name', 'contact'); $contact->addAttribute('type', 'modal_contact'); $contact->addAttribute('label', 'COM_CONTACT_SELECT_CONTACT_LABEL'); $contact->addAttribute('hiddenLabel', 'true'); - $contact->addAttribute('select', 'true'); - $contact->addAttribute('new', 'true'); - $contact->addAttribute('edit', 'true'); - $contact->addAttribute('clear', 'true'); + + // Only show select if user can view contacts + if ($canView) { + $contact->addAttribute('select', 'true'); + } + + // Only allow creating a contact if user has create permission + if ($canCreate) { + $contact->addAttribute('new', 'true'); + } + + // Edit button shown only to users with edit permission + if ($canEdit) { + $contact->addAttribute('edit', 'true'); + } + + // Clear should be allowed if user can view (so they can clear their selection) + if ($canView) { + $contact->addAttribute('clear', 'true'); + } + $contact->addAttribute('addfieldprefix', 'Joomla\Component\Contact\Administrator\Field'); // Prepend into the role’s inner
so it’s the first control @@ -364,12 +393,14 @@ private function enrichGraphContacts(array &$graph): void foreach ($graph as &$entry) { if (!is_array($entry) || empty($entry['@type'])) { + continue; } $type = $entry['@type']; if (!isset(self::ROLE_CONTACT_MAP[$type])) { + continue; } @@ -382,18 +413,30 @@ private function enrichGraphContacts(array &$graph): void $roleNodes = []; $roleNodes = [&$entry[$role]]; + // Enrich each role node when it has a contact id + $filledNodes = 0; foreach ($roleNodes as &$roleNode) { if (!isset($roleNode['contact']) || (int) $roleNode['contact'] <= 0) { continue; } $contact = $this->getContactById((int) $roleNode['contact']); - if ($contact) { $this->fillNodeFromContact($roleNode, $contact); + $filledNodes++; unset($roleNode['contact']); } } + + if ($filledNodes == 0) { + $defaultContactId = (int) $this->params->get('defaultContact', 0); + if ($defaultContactId > 0) { + $contact = $this->getContactById($defaultContactId); + if ($contact) { + $this->fillNodeFromContact($roleNode, $contact); + } + } + } } } } From b631d1b6c71387314d01e25e0f7976917dfeadcd Mon Sep 17 00:00:00 2001 From: shahzan01 Date: Fri, 12 Sep 2025 10:46:22 +0530 Subject: [PATCH 6/9] chore : run the php-cs-fixer on the changed files --- .../schemaorg/src/Extension/Schemaorg.php | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/plugins/system/schemaorg/src/Extension/Schemaorg.php b/plugins/system/schemaorg/src/Extension/Schemaorg.php index c012c1916f7..cb8a774eb35 100644 --- a/plugins/system/schemaorg/src/Extension/Schemaorg.php +++ b/plugins/system/schemaorg/src/Extension/Schemaorg.php @@ -59,13 +59,13 @@ final class Schemaorg extends CMSPlugin implements SubscriberInterface, Dispatch */ private const ROLE_CONTACT_MAP = [ 'Article' => [ - 'author' + 'author', ], 'BlogPosting' => [ - 'author' + 'author', ], 'Book' => [ - 'illustrator' + 'illustrator', ], 'Event' => [ 'organizer', @@ -264,7 +264,7 @@ private function loadContactFieldAssets(int $contactId = 0): void $defaultContactId = (int) $this->params->get('defaultContact', 0); $isDefaultContact = false; if ($contactId <= 0 && $defaultContactId > 0) { - $contactId = $defaultContactId; + $contactId = $defaultContactId; $isDefaultContact = true; } $initialContactData = null; @@ -279,17 +279,17 @@ private function loadContactFieldAssets(int $contactId = 0): void $contact = $contactModel->getItem($contactId); if ($contact) { $initialContactData = [ - 'id' => (int) ($contact->id ?? 0), - 'name' => $contact->name ?? '', - 'email_to' => $contact->email_to ?? '', - 'address' => $contact->address ?? '', - 'street' => $contact->street ?? '', - 'suburb' => $contact->suburb ?? '', - 'state' => $contact->state ?? '', - 'postcode' => $contact->postcode ?? '', - 'country' => $contact->country ?? '', - 'telephone' => $contact->telephone ?? '', - 'webpage' => $contact->webpage ?? '', + 'id' => (int) ($contact->id ?? 0), + 'name' => $contact->name ?? '', + 'email_to' => $contact->email_to ?? '', + 'address' => $contact->address ?? '', + 'street' => $contact->street ?? '', + 'suburb' => $contact->suburb ?? '', + 'state' => $contact->state ?? '', + 'postcode' => $contact->postcode ?? '', + 'country' => $contact->country ?? '', + 'telephone' => $contact->telephone ?? '', + 'webpage' => $contact->webpage ?? '', 'isDefaultContact' => $isDefaultContact, ]; } @@ -302,7 +302,7 @@ private function loadContactFieldAssets(int $contactId = 0): void 'plg_system_schemaorg.contact', 'plg_system_schemaorg/schemaorg-contact.js', ['version' => 'auto', 'relative' => true], - ['defer' => true], + ['defer' => true], ['core'] ); } @@ -339,14 +339,14 @@ private function injectContactField(\Joomla\CMS\Form\Form $form, string $type, s $roleField = $nodes[0]; // Get current user and permission checks for com_contact - $user = $this->getApplication()->getIdentity(); + $user = $this->getApplication()->getIdentity(); $canCreate = $user->authorise('core.create', 'com_contact'); $canEdit = $user->authorise('core.edit', 'com_contact'); $canView = $user->authorise('core.view', 'com_contact'); $contact = new \SimpleXMLElement(''); - $contact->addAttribute('name', 'contact'); - $contact->addAttribute('type', 'modal_contact'); + $contact->addAttribute('name', 'contact'); + $contact->addAttribute('type', 'modal_contact'); $contact->addAttribute('label', 'COM_CONTACT_SELECT_CONTACT_LABEL'); $contact->addAttribute('hiddenLabel', 'true'); @@ -392,7 +392,7 @@ private function enrichGraphContacts(array &$graph): void foreach ($graph as &$entry) { - if (!is_array($entry) || empty($entry['@type'])) { + if (!\is_array($entry) || empty($entry['@type'])) { continue; } @@ -505,7 +505,7 @@ private function fillNodeFromContact(array &$node, $contact): void // Build a PostalAddress object as "address" - if (isset($node['address']) && is_array($node['address'])) { + if (isset($node['address']) && \is_array($node['address'])) { $addr = $node['address']; } else { $addr = []; From 8c27ad02f68629c5cee46d5950ce5101768e414a Mon Sep 17 00:00:00 2001 From: shahzan01 Date: Mon, 15 Sep 2025 13:08:08 +0530 Subject: [PATCH 7/9] fix : typo in schema.org plugin language file --- administrator/language/en-GB/plg_system_schemaorg.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/administrator/language/en-GB/plg_system_schemaorg.ini b/administrator/language/en-GB/plg_system_schemaorg.ini index 3ca8b6c7507..6b78d4e3a79 100644 --- a/administrator/language/en-GB/plg_system_schemaorg.ini +++ b/administrator/language/en-GB/plg_system_schemaorg.ini @@ -10,8 +10,8 @@ PLG_SYSTEM_SCHEMAORG_BASETYPE_OPTION_ORGANIZATION="Organization" PLG_SYSTEM_SCHEMAORG_BASETYPE_OPTION_PERSON="Person" PLG_SYSTEM_SCHEMAORG_CONTACT_LABEL="Select 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_CONFIGURATED="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_CONFIGURATED_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." +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." PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_EXTEND_JED_DESC="Need more Schema types? Extend with Schema Plugins from Joomla! Extension Directory." PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_LABEL="Schema" PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_TYPE_LABEL="Schema Type" From daf38525e855f894536076120667bb41027125fa Mon Sep 17 00:00:00 2001 From: shahzan01 Date: Mon, 15 Sep 2025 13:18:46 +0530 Subject: [PATCH 8/9] fix : phpcs errors --- plugins/system/schemaorg/src/Extension/Schemaorg.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/system/schemaorg/src/Extension/Schemaorg.php b/plugins/system/schemaorg/src/Extension/Schemaorg.php index 8b98f0096f5..fb599dbff02 100644 --- a/plugins/system/schemaorg/src/Extension/Schemaorg.php +++ b/plugins/system/schemaorg/src/Extension/Schemaorg.php @@ -226,9 +226,7 @@ public function onContentPrepareForm(Model\PrepareFormEvent $event) if ($app->isClient('administrator') && $this->isSupported($context)) { $contactId = 0; if ($this->preparedSchemaData) { - foreach (self::ROLE_CONTACT_MAP as $type => $roles) { - if (isset($this->preparedSchemaData[$type])) { foreach ($roles as $role) { if (!empty($this->preparedSchemaData[$type][$role]['contact'])) { @@ -395,14 +393,12 @@ private function enrichGraphContacts(array &$graph): void foreach ($graph as &$entry) { if (!\is_array($entry) || empty($entry['@type'])) { - continue; } $type = $entry['@type']; if (!isset(self::ROLE_CONTACT_MAP[$type])) { - continue; } From 1945d7af0cf48abba4fb0177f2fdec4f9c1134e7 Mon Sep 17 00:00:00 2001 From: shahzan01 Date: Sat, 4 Oct 2025 09:24:52 +0530 Subject: [PATCH 9/9] fix : some minor fixes --- .../language/en-GB/plg_system_schemaorg.ini | 2 ++ .../plg_system_schemaorg/joomla.asset.json | 13 +++++++------ .../js/schemaorg-contact.es6.js | 18 +++++++++++++++--- plugins/system/schemaorg/schemaorg.xml | 5 +++-- .../schemaorg/src/Extension/Schemaorg.php | 6 +++++- 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/administrator/language/en-GB/plg_system_schemaorg.ini b/administrator/language/en-GB/plg_system_schemaorg.ini index 6b78d4e3a79..063a4649fa3 100644 --- a/administrator/language/en-GB/plg_system_schemaorg.ini +++ b/administrator/language/en-GB/plg_system_schemaorg.ini @@ -16,6 +16,8 @@ PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_EXTEND_JED_DESC="Need more Schema type 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_INHERIT_CONTACT="Inherited from contact" +PLG_SYSTEM_SCHEMAORG_INHERIT_DEFAULT_CONTACT="Inherited from default contact" PLG_SYSTEM_SCHEMAORG_NAME_LABEL="Name" PLG_SYSTEM_SCHEMAORG_SOCIALMEDIA_LABEL="Social Media Accounts" PLG_SYSTEM_SCHEMAORG_SOCIALMEDIA_URL_LABEL="URL" diff --git a/build/media_source/plg_system_schemaorg/joomla.asset.json b/build/media_source/plg_system_schemaorg/joomla.asset.json index 8b2c6833726..8b3d56d01a3 100644 --- a/build/media_source/plg_system_schemaorg/joomla.asset.json +++ b/build/media_source/plg_system_schemaorg/joomla.asset.json @@ -1,19 +1,20 @@ { "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json", "name": "plg_system_schemaorg", - "version": "1.0.0", - "description": "Schema.org System Plugin Assets", + "version": "__DEPLOY_VERSION__", + "description": "Joomla CMS", "license": "GPL-2.0-or-later", "assets": [ { "name": "plg_system_schemaorg.contact", "type": "script", "uri": "plg_system_schemaorg/schemaorg-contact.js", - "dependencies": ["core"], + "dependencies": [ + "core" + ], "attributes": { - "defer": true - }, - "version": "1.0.0" + "type": "module" + } } ] } 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..521fe914444 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 @@ -1,6 +1,10 @@ +/** + * @copyright (C) 2025 Open Source Matters, Inc. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ /** * schemaorg-contact.js - * Minimal: populate placeholders from injected initialContact by baseName. + * Populate placeholders from injected initialContact by baseName. */ ((Joomla, document) => { "use strict"; @@ -143,10 +147,18 @@ roleContainer.querySelector(selector) || document.querySelector(selector); let newValue = value; + const defaultContactText = Joomla.Text._( + "PLG_SYSTEM_SCHEMAORG_INHERIT_DEFAULT_CONTACT" + ); + + const contactText = Joomla.Text._( + "PLG_SYSTEM_SCHEMAORG_INHERIT_CONTACT" + ); + if (isDefaultContact) { - newValue += ` — Inherited from default contact "${contact.name}"`; + newValue += ` — ${defaultContactText} "${contact.name}"`; } else { - newValue += ` — Inherited from contact "${contact.name}"`; + newValue += ` — ${contactText} "${contact.name}"`; } if (targetField) { targetField.placeholder = newValue; diff --git a/plugins/system/schemaorg/schemaorg.xml b/plugins/system/schemaorg/schemaorg.xml index 26db5645641..b81bd4e2e9e 100644 --- a/plugins/system/schemaorg/schemaorg.xml +++ b/plugins/system/schemaorg/schemaorg.xml @@ -20,8 +20,7 @@ -
+
+ + useScript('plg_system_schemaorg.contact'); // Add inline configuration