-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[4.1] [RFC] Use schema.org for metadata #25117
Changes from 7 commits
05548fb
8205436
1c59e87
5a2395c
6da6fd3
1c491f5
a3f15bb
3133be5
7d4f7c9
3cb789f
f0fc72f
6c21fe4
e463aac
e5d5c9d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ | |
|
||
defined('_JEXEC') or die; | ||
|
||
use Joomla\CMS\Application\CMSApplicationInterface; | ||
use Joomla\CMS\Categories\Categories; | ||
use Joomla\CMS\Factory; | ||
use Joomla\CMS\Helper\TagsHelper; | ||
|
@@ -20,7 +21,12 @@ | |
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; | ||
use Joomla\CMS\Plugin\PluginHelper; | ||
use Joomla\CMS\Router\Route; | ||
use Joomla\CMS\Uri\Uri; | ||
use Joomla\CMS\User\User; | ||
use Joomla\Component\Contact\Site\Helper\Route as ContactHelperRoute; | ||
use Spatie\SchemaOrg\Person; | ||
use Spatie\SchemaOrg\PostalAddress; | ||
use Spatie\SchemaOrg\Schema; | ||
|
||
/** | ||
* HTML Contact View class for the Contact component | ||
|
@@ -107,12 +113,13 @@ class HtmlView extends BaseHtmlView | |
* | ||
* @param string $tpl The name of the template file to parse; automatically searches through the template paths. | ||
* | ||
* @return mixed A string if successful, otherwise an Error object. | ||
* @return void | ||
* @throws \Exception | ||
*/ | ||
public function display($tpl = null) | ||
{ | ||
$app = Factory::getApplication(); | ||
$user = Factory::getUser(); | ||
$user = $app->getIdentity(); | ||
$state = $this->get('State'); | ||
$item = $this->get('Item'); | ||
$this->form = $this->get('Form'); | ||
|
@@ -181,7 +188,7 @@ public function display($tpl = null) | |
$app->enqueueMessage(Text::_('JERROR_ALERTNOAUTHOR'), 'error'); | ||
$app->setHeader('status', 403, true); | ||
|
||
return false; | ||
return; | ||
} | ||
|
||
$options['category_id'] = $item->catid; | ||
|
@@ -347,7 +354,7 @@ public function display($tpl = null) | |
$item->text = $item->misc; | ||
} | ||
|
||
$app->triggerEvent('onContentPrepare', array ('com_contact.contact', &$item, &$this->params, $offset)); | ||
$app->triggerEvent('onContentPrepare', array('com_contact.contact', &$item, &$this->params, $offset)); | ||
|
||
// Store the events for later | ||
$item->event = new \stdClass; | ||
|
@@ -370,7 +377,7 @@ public function display($tpl = null) | |
if ($item->params->get('show_user_custom_fields') && $item->user_id && $contactUser = Factory::getUser($item->user_id)) | ||
{ | ||
$contactUser->text = ''; | ||
$app->triggerEvent('onContentPrepare', array ('com_users.user', &$contactUser, &$item->params, 0)); | ||
$app->triggerEvent('onContentPrepare', array('com_users.user', &$contactUser, &$item->params, 0)); | ||
|
||
if (!isset($contactUser->jcfields)) | ||
{ | ||
|
@@ -421,8 +428,9 @@ public function display($tpl = null) | |
} | ||
|
||
$this->_prepareDocument(); | ||
$this->addJsonSchema(); | ||
|
||
return parent::display($tpl); | ||
parent::display($tpl); | ||
} | ||
|
||
/** | ||
|
@@ -535,4 +543,62 @@ protected function _prepareDocument() | |
} | ||
} | ||
} | ||
|
||
/** | ||
* Prepares the document. | ||
* | ||
* @return void | ||
*/ | ||
private function addJsonSchema() | ||
{ | ||
// Note we don't display tags here as the keywords property isn't valid for a person | ||
$schema = Schema::person() | ||
->if($this->item->params->get('show_name'), function (Person $schema) { | ||
$schema->name($this->item->name); | ||
}) | ||
->if($this->item->image && $this->item->params->get('show_image'), function (Person $schema) { | ||
$schema->image(Uri::root() . $this->item->image); | ||
}) | ||
->if($this->item->params->get('show_position'), function (Person $schema) { | ||
$schema->jobTitle($this->item->con_position); | ||
}) | ||
->if($this->item->params->get('address_check') > 0, function (Person $schema) { | ||
$schema->address( | ||
Schema::postalAddress() | ||
->if($this->item->address && $this->params->get('show_street_address'), function (PostalAddress $schema) { | ||
$schema->streetAddress($this->item->address); | ||
}) | ||
->if($this->item->suburb && $this->params->get('show_suburb'), function (PostalAddress $schema) { | ||
$schema->addressLocality($this->item->suburb); | ||
}) | ||
->if($this->item->state && $this->params->get('show_state'), function (PostalAddress $schema) { | ||
$schema->addressRegion($this->item->state); | ||
}) | ||
->if($this->item->postcode && $this->params->get('show_postcode'), function (PostalAddress $schema) { | ||
$schema->postalCode($this->item->postcode); | ||
}) | ||
->if($this->item->country && $this->params->get('show_country'), function (PostalAddress $schema) { | ||
$schema->addressCountry($this->item->country); | ||
}) | ||
); | ||
}) | ||
// TODO: Should we expose the raw email like this? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we do in the vcard download |
||
->if($this->item->params->get('show_email') === '1', function (Person $schema) { | ||
$schema->email($this->item->email_raw); | ||
}) | ||
->if($this->item->telephone && $this->params->get('show_telephone'), function (Person $schema) { | ||
$schema->telephone($this->item->telephone); | ||
}) | ||
->if($this->item->fax && $this->params->get('show_fax'), function (Person $schema) { | ||
$schema->faxNumber($this->item->fax); | ||
}) | ||
->if($this->item->mobile && $this->params->get('show_mobile'), function (Person $schema) { | ||
$schema->telephone($this->item->mobile); | ||
}) | ||
->if($this->item->webpage && $this->params->get('show_webpage'), function (Person $schema) { | ||
$schema->url($this->item->webpage); | ||
}); | ||
|
||
$this->document->addScriptDeclaration(json_encode($schema, JDEBUG ? JSON_PRETTY_PRINT : 0), 'application/ld+json'); | ||
wilsonge marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,9 +11,11 @@ | |
|
||
defined('_JEXEC') or die; | ||
|
||
use Joomla\CMS\Application\CMSApplicationInterface; | ||
use Joomla\CMS\Categories\Categories; | ||
use Joomla\CMS\Factory; | ||
use Joomla\CMS\Helper\TagsHelper; | ||
use Joomla\CMS\HTML\HTMLHelper; | ||
use Joomla\CMS\Language\Associations; | ||
use Joomla\CMS\Language\Text; | ||
use Joomla\CMS\Layout\FileLayout; | ||
|
@@ -23,6 +25,9 @@ | |
use Joomla\CMS\Router\Route; | ||
use Joomla\CMS\Uri\Uri; | ||
use Joomla\Component\Content\Site\Helper\AssociationHelper; | ||
use Spatie\SchemaOrg\Article; | ||
use Spatie\SchemaOrg\Person; | ||
use Spatie\SchemaOrg\Schema; | ||
|
||
/** | ||
* HTML Article View class for the Content component | ||
|
@@ -80,13 +85,16 @@ class HtmlView extends BaseHtmlView | |
* | ||
* @param string $tpl The name of the template file to parse; automatically searches through the template paths. | ||
* | ||
* @return mixed A string if successful, otherwise an Error object. | ||
* @return void | ||
* @throws \Exception | ||
*/ | ||
public function display($tpl = null) | ||
{ | ||
if ($this->getLayout() == 'pagebreak') | ||
{ | ||
return parent::display($tpl); | ||
parent::display($tpl); | ||
|
||
return; | ||
} | ||
|
||
$app = Factory::getApplication(); | ||
|
@@ -255,6 +263,7 @@ public function display($tpl = null) | |
$this->pageclass_sfx = htmlspecialchars($this->item->params->get('pageclass_sfx')); | ||
|
||
$this->_prepareDocument(); | ||
$this->addJsonSchema($app); | ||
|
||
parent::display($tpl); | ||
} | ||
|
@@ -387,4 +396,61 @@ protected function _prepareDocument() | |
$this->document->setMetaData('robots', 'noindex, nofollow'); | ||
} | ||
} | ||
|
||
/** | ||
* Prepares the document. | ||
* | ||
* @param CMSApplicationInterface $app The application object | ||
* | ||
This comment was marked as abuse.
Sorry, something went wrong. |
||
* @return void | ||
*/ | ||
private function addJsonSchema($app) | ||
{ | ||
$images = json_decode($this->item->images); | ||
$articleLanguage = ($this->item->language === '*') ? $app->get('language') : $this->item->language; | ||
$authorised = $app->getIdentity()->getAuthorisedViewLevels(); | ||
$keywords = []; | ||
|
||
foreach ($this->item->tags->itemTags as $tag) | ||
{ | ||
if (in_array($tag->access, $authorised)) { | ||
$keywords[] = $this->escape($tag->title); | ||
} | ||
} | ||
|
||
// TODO: This requires a publisher to pass google structured data checker | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I saw that - but I'm not sure the best way of achieving this as its mandated for the image to be above 700px width - which clearly may not be the case in an article :/ |
||
$schema = Schema::article() | ||
->articleBody($this->item->text) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicating the entire article text into JSON? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yup. that's apparently how it should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you sure about that @wilsonge ? I am looking at some pages from the site of another cms that dont There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If true, I stand by my deleted comment - this is probably unsuitable for content. How does one insert this into article and tie it up to specific pieces of content? With Microdata it's simple by using editor button that inserts the tags around selected content. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That looks counter-productive to me. Would not want to bloat up the page like this. How about the other question? Microdata is not just for automatically generated content. It can be used inside actual content, e.g. inside articles. |
||
->if($this->item->params->get('show_title'), function (Article $schema) { | ||
$schema->headline($this->escape($this->item->title)); | ||
}) | ||
->inLanguage($articleLanguage) | ||
->dateCreated(HTMLHelper::_('date', $this->item->created, "Y-m-d")) | ||
->dateModified(HTMLHelper::_('date', $this->item->modified, "Y-m-d")) | ||
->datePublished(HTMLHelper::_('date', $this->item->publish_up, "Y-m-d")) | ||
->if($this->item->params->get('show_author') === '1' && !empty($this->item->author), function (Article $schema) { | ||
$schema->author( | ||
Schema::Person() | ||
->name($this->item->created_by_alias ?: $this->item->author) | ||
->if($this->item->params->get('link_author'), function(Person $schema) { | ||
$schema->url($this->item->contact_link); | ||
}) | ||
); | ||
}); | ||
|
||
if (!empty($keywords)) | ||
{ | ||
$schema->keywords($keywords); | ||
} | ||
|
||
if (!empty($images->image_fulltext)) | ||
{ | ||
$schema->image( | ||
Schema::imageObject() | ||
->url($images->image_fulltext) | ||
); | ||
} | ||
|
||
$this->document->addScriptDeclaration(json_encode($schema, JDEBUG ? JSON_PRETTY_PRINT : 0), 'application/ld+json'); | ||
} | ||
} |
This comment was marked as abuse.
Sorry, something went wrong.