Skip to content

Commit 8cb7864

Browse files
committed
feat : add og tag injection into html
1 parent 085ff65 commit 8cb7864

File tree

6 files changed

+183
-375
lines changed

6 files changed

+183
-375
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,6 @@ cypress.config.mjs
107107

108108
# WebAuthn FIDO metadata cache
109109
/plugins/system/webauthn/fido.jwt
110+
cccsocialmedia
111+
administrator/language/en-GB/en-GB.plg_system_cccsocialmedia.ini
112+
administrator/language/en-GB/en-GB.plg_system_cccsocialmedia.sys.ini

plugins/system/opengraph/language/en-GB/plg_system_opengraph.ini

Lines changed: 19 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -35,43 +35,10 @@ PLG_SYSTEM_OPENGRAPH_ENABLE_CATEGORY_OVERRIDE_DESC="Allow categories to have cus
3535
PLG_SYSTEM_OPENGRAPH_FALLBACK_TO_SITE_LOGO="Use Site Logo as Fallback"
3636
PLG_SYSTEM_OPENGRAPH_FALLBACK_TO_SITE_LOGO_DESC="When no OG image is specified, use the site's logo as fallback image. If disabled, no image tag will be generated."
3737

38-
; Custom Fields Labels (for reference)
39-
PLG_SYSTEM_OPENGRAPH_FIELD_OG_TITLE="Open Graph Title"
40-
PLG_SYSTEM_OPENGRAPH_FIELD_OG_TITLE_DESC="Custom title for Open Graph sharing. Leave empty to use article title."
41-
42-
PLG_SYSTEM_OPENGRAPH_FIELD_OG_DESCRIPTION="Open Graph Description"
43-
PLG_SYSTEM_OPENGRAPH_FIELD_OG_DESCRIPTION_DESC="Custom description for Open Graph sharing. Leave empty to use article meta description or intro text."
44-
45-
PLG_SYSTEM_OPENGRAPH_FIELD_OG_IMAGE="Open Graph Image"
46-
PLG_SYSTEM_OPENGRAPH_FIELD_OG_IMAGE_DESC="Custom image for Open Graph sharing. Leave empty to use article intro image or site logo."
47-
48-
; Error Messages
49-
PLG_SYSTEM_OPENGRAPH_ERROR_INVALID_CATEGORY="Invalid category specified for OG metadata"
50-
PLG_SYSTEM_OPENGRAPH_ERROR_SAVE_FAILED="Failed to save OG metadata"
51-
PLG_SYSTEM_OPENGRAPH_ERROR_DELETE_FAILED="Failed to delete OG metadata"
52-
PLG_SYSTEM_OPENGRAPH_ERROR_FIELD_TOO_LONG="Field value exceeds maximum length"
53-
54-
; Success Messages
55-
PLG_SYSTEM_OPENGRAPH_SUCCESS_SAVED="OG metadata saved successfully"
56-
PLG_SYSTEM_OPENGRAPH_SUCCESS_DELETED="OG metadata deleted successfully"
57-
58-
; Information Messages
59-
PLG_SYSTEM_OPENGRAPH_INFO_NO_ARTICLE="No article context available for OG tag generation"
60-
PLG_SYSTEM_OPENGRAPH_INFO_USING_FALLBACK="Using fallback values for OG tag generation"
61-
PLG_SYSTEM_OPENGRAPH_INFO_HIERARCHY_APPLIED="OG metadata hierarchy applied: %s level used"
62-
63-
; Priority Levels
64-
PLG_SYSTEM_OPENGRAPH_PRIORITY_ARTICLE="Article"
65-
PLG_SYSTEM_OPENGRAPH_PRIORITY_CATEGORY="Category"
66-
PLG_SYSTEM_OPENGRAPH_PRIORITY_GLOBAL="Global"
67-
PLG_SYSTEM_OPENGRAPH_PRIORITY_AUTO="Auto-generated"
68-
69-
; Form Fieldsets
70-
PLG_SYSTEM_OPENGRAPH_FIELDSET_ARTICLE="OpenGraph Settings"
38+
;fieldsets
39+
PLG_SYSTEM_OPENGRAPH_FIELDSET_ARTICLE="OpenGraph"
7140
PLG_SYSTEM_OPENGRAPH_FIELDSET_ARTICLE_DESC="Configure OpenGraph metadata for social media sharing. These settings override global defaults."
7241

73-
PLG_SYSTEM_OPENGRAPH_FIELDSET_CATEGORY="OpenGraph Category Settings"
74-
PLG_SYSTEM_OPENGRAPH_FIELDSET_CATEGORY_DESC="Configure OpenGraph metadata for this category. These settings will be used for articles in this category when no article-specific settings are defined."
7542

7643
; Common Field Labels
7744
PLG_SYSTEM_OPENGRAPH_OG_TITLE_LABEL="OpenGraph Title"
@@ -87,6 +54,7 @@ PLG_SYSTEM_OPENGRAPH_OG_IMAGE_DESC="Image for social media sharing. Recommended
8754

8855
PLG_SYSTEM_OPENGRAPH_OG_IMAGE_ALT_LABEL="OpenGraph Image Alt Text"
8956
PLG_SYSTEM_OPENGRAPH_OG_IMAGE_ALT_DESC="Alternative text for the OpenGraph image for accessibility."
57+
PLG_SYSTEM_OPENGRAPH_OG_IMAGE_ALT_HINT="Enter a brief description of the image for accessibility"
9058

9159
PLG_SYSTEM_OPENGRAPH_OG_TYPE_LABEL="OpenGraph Type"
9260
PLG_SYSTEM_OPENGRAPH_OG_TYPE_DESC="Content type for social media platforms."
@@ -110,67 +78,25 @@ PLG_SYSTEM_OPENGRAPH_TYPE_PROFILE="Profile"
11078
PLG_SYSTEM_OPENGRAPH_TYPE_PRODUCT="Product"
11179
PLG_SYSTEM_OPENGRAPH_TYPE_EVENT="Event"
11280

113-
; Article Specific
114-
PLG_SYSTEM_OPENGRAPH_ARTICLE_SECTION_LABEL="Article Section"
115-
PLG_SYSTEM_OPENGRAPH_ARTICLE_SECTION_DESC="Section or category tag for the article."
116-
PLG_SYSTEM_OPENGRAPH_ARTICLE_SECTION_HINT="e.g., Technology, Sports, News"
81+
;advanced settings
82+
PLG_SYSTEM_OPENGRAPH_SHOW_ADVANCED_LABEL="Show Advanced Settings"
83+
PLG_SYSTEM_OPENGRAPH_SHOW_ADVANCED_DESC="Show advanced settings for OpenGraph metadata."
11784

118-
PLG_SYSTEM_OPENGRAPH_PRIORITY_NOTE_LABEL="Priority Information"
119-
PLG_SYSTEM_OPENGRAPH_PRIORITY_NOTE_DESC="These article settings take priority over category and global settings. Leave fields empty to inherit from higher levels."
85+
PLG_SYSTEM_OPENGRAPH_TWITTER_CARD_LABEL="Twitter Card Type"
86+
PLG_SYSTEM_OPENGRAPH_TWITTER_CARD_DESC="Select the type of Twitter card to use for this content."
12087

121-
; Category Specific
122-
PLG_SYSTEM_OPENGRAPH_CATEGORY_TITLE_DESC="Custom title for this category's social media sharing."
123-
PLG_SYSTEM_OPENGRAPH_CATEGORY_TITLE_HINT="Enter a title that represents this category"
88+
PLG_SYSTEM_OPENGRAPH_TWITTER_TITLE_LABEL="Twitter Title"
89+
PLG_SYSTEM_OPENGRAPH_TWITTER_TITLE_DESC="Custom title for Twitter sharing. Recommended length: 70 characters."
90+
PLG_SYSTEM_OPENGRAPH_TWITTER_TITLE_HINT="Enter a compelling title for Twitter sharing"
12491

125-
PLG_SYSTEM_OPENGRAPH_CATEGORY_DESCRIPTION_DESC="Description for articles in this category when no article-specific description is set."
126-
PLG_SYSTEM_OPENGRAPH_CATEGORY_DESCRIPTION_HINT="Describe what this category contains"
92+
PLG_SYSTEM_OPENGRAPH_TWITTER_DESC_LABEL="Twitter Description"
93+
PLG_SYSTEM_OPENGRAPH_TWITTER_DESC_DESC="Custom description for Twitter sharing. Recommended length: 120-160 characters."
94+
PLG_SYSTEM_OPENGRAPH_TWITTER_DESC_HINT="Enter a brief, engaging description"
12795

128-
PLG_SYSTEM_OPENGRAPH_CATEGORY_IMAGE_DESC="Default image for articles in this category."
129-
PLG_SYSTEM_OPENGRAPH_CATEGORY_TYPE_DESC="Default content type for articles in this category."
130-
PLG_SYSTEM_OPENGRAPH_CATEGORY_URL_DESC="Custom URL for this category page."
131-
PLG_SYSTEM_OPENGRAPH_CATEGORY_URL_HINT="Leave empty to use the category's URL"
132-
PLG_SYSTEM_OPENGRAPH_CATEGORY_ENABLE_DESC="Enable OpenGraph tags for this category and its articles."
96+
PLG_SYSTEM_OPENGRAPH_TWITTER_IMAGE_LABEL="Twitter Image"
97+
PLG_SYSTEM_OPENGRAPH_TWITTER_IMAGE_DESC="Image for Twitter sharing. Recommended size: 1200x630 pixels."
13398

134-
PLG_SYSTEM_OPENGRAPH_INHERIT_PARENT_LABEL="Inherit from Parent"
135-
PLG_SYSTEM_OPENGRAPH_INHERIT_PARENT_DESC="Inherit OpenGraph settings from parent category when available."
99+
PLG_SYSTEM_OPENGRAPH_FB_APP_ID_LABEL="Facebook App ID"
100+
PLG_SYSTEM_OPENGRAPH_FB_APP_ID_DESC="Enter your Facebook App ID to enable Facebook Open Graph debugging."
101+
PLG_SYSTEM_OPENGRAPH_FB_APP_ID_HINT="Enter your Facebook App ID to enable Facebook Open Graph debugging."
136102

137-
PLG_SYSTEM_OPENGRAPH_DEFAULT_ARTICLES_LABEL="Default for Articles"
138-
PLG_SYSTEM_OPENGRAPH_DEFAULT_ARTICLES_DESC="Use these settings as defaults for articles in this category."
139-
140-
PLG_SYSTEM_OPENGRAPH_CATEGORY_SPECIFIC_LABEL="Category-Specific Options"
141-
142-
PLG_SYSTEM_OPENGRAPH_SHOW_CATEGORY_LABEL="Show Category in Articles"
143-
PLG_SYSTEM_OPENGRAPH_SHOW_CATEGORY_DESC="Include category name in article OpenGraph metadata."
144-
145-
PLG_SYSTEM_OPENGRAPH_USE_KEYWORDS_LABEL="Use Category Keywords"
146-
PLG_SYSTEM_OPENGRAPH_USE_KEYWORDS_DESC="Include category keywords in OpenGraph metadata."
147-
148-
PLG_SYSTEM_OPENGRAPH_INHERITANCE_NOTE_LABEL="Inheritance Information"
149-
PLG_SYSTEM_OPENGRAPH_INHERITANCE_NOTE_DESC="Category settings are inherited by articles unless overridden at the article level. Global settings serve as the final fallback."
150-
151-
; Character Counters
152-
PLG_SYSTEM_OPENGRAPH_TITLE_COUNTER_DESC="Character counter for title optimization"
153-
PLG_SYSTEM_OPENGRAPH_DESCRIPTION_COUNTER_DESC="Character counter for description optimization"
154-
155-
; Note Fields
156-
PLG_SYSTEM_OPENGRAPH_CATEGORY_NOTE_LABEL="Category Settings Note"
157-
PLG_SYSTEM_OPENGRAPH_CATEGORY_NOTE_DESC="These settings apply to this category and can be inherited by articles within it."
158-
159-
; Additional Missing Constants
160-
PLG_SYSTEM_OPENGRAPH_CATEGORY_SETTINGS="Category OpenGraph Settings"
161-
PLG_SYSTEM_OPENGRAPH_GLOBAL_SETTINGS="Global OpenGraph Settings"
162-
PLG_SYSTEM_OPENGRAPH_ARTICLE_SETTINGS="Article OpenGraph Settings"
163-
164-
; Default values text
165-
PLG_SYSTEM_OPENGRAPH_DEFAULT_TITLE="Use site title"
166-
PLG_SYSTEM_OPENGRAPH_DEFAULT_DESCRIPTION="Use site description"
167-
PLG_SYSTEM_OPENGRAPH_DEFAULT_IMAGE="Use site logo"
168-
169-
; Status messages for category fields
170-
PLG_SYSTEM_OPENGRAPH_CATEGORY_ENABLED="OpenGraph enabled for this category"
171-
PLG_SYSTEM_OPENGRAPH_CATEGORY_DISABLED="OpenGraph disabled for this category"
172-
PLG_SYSTEM_OPENGRAPH_CATEGORY_INHERIT="Inherit from global settings"
173-
174-
; Help text for complex fields
175-
PLG_SYSTEM_OPENGRAPH_TYPE_HELP="Select the content type that best describes this category. This affects how social media platforms display shared links."
176-
PLG_SYSTEM_OPENGRAPH_IMAGE_HELP="Upload an image that represents this category. Recommended dimensions: 1200x630 pixels for optimal display on social media."

plugins/system/opengraph/opengraph.xml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,15 @@
7171
label="PLG_SYSTEM_OPENGRAPH_GLOBAL_OG_TYPE"
7272
description="PLG_SYSTEM_OPENGRAPH_GLOBAL_OG_TYPE_DESC"
7373
>
74-
<option value="website">website</option>
75-
<option value="article">article</option>
76-
<option value="blog">blog</option>
77-
<option value="profile">profile</option>
78-
<option value="video">video</option>
79-
<option value="music">music</option>
80-
<option value="book">book</option>
81-
<option value="product">product</option>
82-
<option value="event">event</option>
74+
<option value="website">PLG_SYSTEM_OPENGRAPH_TYPE_WEBSITE</option>
75+
<option value="article">PLG_SYSTEM_OPENGRAPH_TYPE_ARTICLE</option>
76+
<option value="blog">PLG_SYSTEM_OPENGRAPH_TYPE_BLOG</option>
77+
<option value="profile">PLG_SYSTEM_OPENGRAPH_TYPE_PROFILE</option>
78+
<option value="video">PLG_SYSTEM_OPENGRAPH_TYPE_VIDEO</option>
79+
<option value="music">PLG_SYSTEM_OPENGRAPH_TYPE_MUSIC</option>
80+
<option value="book">PLG_SYSTEM_OPENGRAPH_TYPE_BOOK</option>
81+
<option value="product">PLG_SYSTEM_OPENGRAPH_TYPE_PRODUCT</option>
82+
<option value="event">PLG_SYSTEM_OPENGRAPH_TYPE_EVENT</option>
8383
</field>
8484
</fieldset>
8585

plugins/system/opengraph/src/Extension/opengraph.php

Lines changed: 84 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,22 @@
1515
use Joomla\CMS\Plugin\CMSPlugin;
1616
use Joomla\Event\SubscriberInterface;
1717
use Joomla\CMS\Form\Form;
18+
use Joomla\CMS\Document\HtmlDocument;
19+
use Joomla\CMS\Table\Table;
20+
use Joomla\Registry\Registry;
21+
use Joomla\CMS\Document\Document;
22+
use Joomla\CMS\Uri\Uri;
1823

19-
// phpcs:disable PSR1.Files.SideEffects
20-
\defined('_JEXEC') or die;
21-
// phpcs:enable PSR1.Files.SideEffects
2224

2325

24-
/**
25-
* OpenGraph Metadata plugin.
26-
*
27-
* @since __DEPLOY_VERSION__
28-
*/
26+
27+
\defined('_JEXEC') or die;
2928

3029
final class Opengraph extends CMSPlugin implements SubscriberInterface
3130
{
32-
/**
33-
* Returns an array of events this subscriber will listen to.
34-
*
35-
* @return array
36-
*
37-
* @since __DEPLOY_VERSION__
38-
*/
31+
protected $app;
32+
protected $autoloadLanguage = true;
33+
3934
public static function getSubscribedEvents(): array
4035
{
4136
return [
@@ -44,53 +39,43 @@ public static function getSubscribedEvents(): array
4439
];
4540
}
4641

47-
/**
48-
* Application object
49-
*
50-
* @var CMSApplication
51-
* @since __DEPLOY_VERSION__
52-
*/
53-
protected $app;
54-
55-
/**
56-
* Load the language file on instantiation.
57-
*
58-
* @var boolean
59-
* @since __DEPLOY_VERSION__
60-
*/
61-
protected $autoloadLanguage = true;
62-
63-
/**
64-
* Method to handle the onBeforeCompileHead event
65-
*
66-
* @param BeforeCompileHeadEvent $event The event object
67-
*
68-
* @return void
69-
*
70-
* @since __DEPLOY_VERSION__
71-
*/
72-
public function onBeforeCompileHead(BeforeCompileHeadEvent $event)
42+
public function onBeforeCompileHead(BeforeCompileHeadEvent $event): void
7343
{
7444
$app = $this->getApplication();
7545

76-
// Only run in frontend
7746
if (!$app->isClient('site')) {
7847
return;
7948
}
8049

81-
// Will add OpenGraph meta tags logic here in the future
82-
// This method will be called to generate OpenGraph tags
50+
$input = $app->input;
51+
$option = $input->get('option', '', 'cmd');
52+
$view = $input->get('view', '', 'cmd');
53+
$id = $input->getInt('id');
54+
55+
if ($option !== 'com_content' || $view !== 'article' || !$id) {
56+
return;
57+
}
58+
59+
$table = Table::getInstance('Content');
60+
if (!$table->load($id)) {
61+
return;
62+
}
63+
64+
$attribs = new Registry($table->attribs);
65+
66+
if ($attribs->get('og_enabled', '') === '0') {
67+
return;
68+
}
69+
70+
$document = $this->app->getDocument();
71+
72+
if (!$document instanceof HtmlDocument) {
73+
return;
74+
}
75+
76+
$this->injectOpenGraphData($document, $attribs);
8377
}
8478

85-
/**
86-
* Method to add OpenGraph fields to content forms
87-
*
88-
* @param PrepareFormEvent $event The event object.
89-
*
90-
* @return void
91-
*
92-
* @since __DEPLOY_VERSION__
93-
*/
9479
public function onContentPrepareForm(PrepareFormEvent $event): void
9580
{
9681
$app = $this->getApplication();
@@ -100,55 +85,61 @@ public function onContentPrepareForm(PrepareFormEvent $event): void
10085
}
10186

10287
$form = $event->getForm();
103-
$data = $event->getData();
104-
10588
$name = $form->getName();
10689

107-
108-
109-
// Check if it's the article form
11090
if ($name === 'com_content.article') {
111-
$xmlFile = __DIR__ . '/../Forms/Article/Article.xml';
112-
if (file_exists($xmlFile)) {
113-
$result = $form->loadFile($xmlFile, false);
114-
91+
$xml = __DIR__ . '/../forms/opengraph.xml';
92+
if (file_exists($xml)) {
93+
$form->loadFile($xml, false);
11594
}
11695
}
96+
}
11797

118-
// Check if it's the category form
119-
if (strpos($name, 'com_categories.category') === 0) {
120-
$extension = '';
121-
122-
// Extract extension from form name if it's concatenated
123-
if ($name === 'com_categories.categorycom_content') {
124-
$extension = 'com_content';
125-
} else {
126-
// Try to get extension from different sources
127-
if (is_object($data) && isset($data->extension)) {
128-
$extension = $data->extension;
129-
} elseif (is_array($data) && isset($data['extension'])) {
130-
$extension = $data['extension'];
131-
} else {
132-
$extension = $form->getValue('extension');
133-
}
134-
135-
// If still empty, try from request
136-
if (empty($extension)) {
137-
$input = $this->getApplication()->input;
138-
$extension = $input->get('extension', '', 'cmd');
139-
}
140-
}
98+
private function injectOpenGraphData(Document $document, Registry $params): void
99+
{
141100

142101

102+
$this->setMetaData($document, 'og:title', $params->get('og_title'), 'property');
103+
$this->setMetaData($document, 'og:description', $params->get('og_description'), 'property');
104+
$this->setMetaData($document, 'og:type', $params->get('og_type'), 'property');
143105

144-
// Load form only for content categories
145-
if ($extension === 'com_content') {
146-
$xmlFile = __DIR__ . '/../Forms/Category/Category.xml';
147-
if (file_exists($xmlFile)) {
148-
$result = $form->loadFile($xmlFile, false);
149106

150-
}
151-
}
107+
$this->setMetaData($document, 'twitter:card', $params->get('twitter_card'), 'name');
108+
$this->setMetaData($document, 'twitter:title', $params->get('twitter_title'), 'name');
109+
$this->setMetaData($document, 'twitter:description', $params->get('twitter_description'), 'name');
110+
111+
$this->setMetaData($document, 'fb:app_id', $params->get('fb_app_id'), 'property');
112+
113+
$this->setOpenGraphImage(
114+
$document,
115+
$params->get('og_image'),
116+
$params->get('og_image_alt'),
117+
Uri::base()
118+
);
119+
120+
121+
}
122+
123+
private function setMetaData(Document $document, string $name, ?string $value, string $attributeType): void
124+
{
125+
if (!empty($value)) {
126+
$document->setMetaData($name, $value, $attributeType);
152127
}
153128
}
154-
}
129+
130+
private function setOpenGraphImage(Document $document, ?string $image, ?string $alt = '', ?string $baseUrl = ''): void
131+
{
132+
if (empty($image)) {
133+
return;
134+
}
135+
136+
$url = rtrim((string) $baseUrl, '/') . '/' . ltrim($image, '/');
137+
138+
$this->setMetaData($document, 'og:image', $url, 'property');
139+
$this->setMetaData($document, 'og:image:alt', $alt, 'property');
140+
$this->setMetaData($document, 'twitter:image', $url, 'name');
141+
$this->setMetaData($document, 'twitter:image:alt', $alt, 'name');
142+
}
143+
144+
145+
}

0 commit comments

Comments
 (0)