Skip to content

Commit cadce74

Browse files
Merge pull request #398 from jonasdekeukelaere/og-images
Add og:image to meta entity
2 parents 5daa82c + 30bb2a9 commit cadce74

File tree

14 files changed

+284
-20
lines changed

14 files changed

+284
-20
lines changed

src/Backend/Core/Engine/Meta.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
use Common\Uri as CommonUri;
77
use Backend\Core\Engine\Model as BackendModel;
88
use Backend\Core\Language\Language as BackendLanguage;
9+
use ForkCMS\Utility\Thumbnails;
10+
use SpoonFormCheckbox;
911

1012
/**
1113
* This class represents a META-object
@@ -255,6 +257,11 @@ public function getCanonicalUrlOverwrite(): bool
255257
return (bool) $this->data['data']['canonical_url_overwrite'];
256258
}
257259

260+
public function getOgImage(): ?string
261+
{
262+
return $this->data['og_image'] ?? null;
263+
}
264+
258265
/**
259266
* If the fields are disabled we don't have any values in the post.
260267
* When an error occurs in the other fields of the form the meta-fields would be cleared
@@ -367,6 +374,12 @@ protected function loadForm(): void
367374
$this->form->addTextarea('meta_custom', $this->data['custom'] ?? null);
368375
}
369376

377+
// Og:image
378+
$this->form->addImage('og_image');
379+
if ($this->data['og_image'] ?? null) {
380+
$this->form->addCheckbox('og_image_delete');
381+
}
382+
370383
$this->form->addHidden('meta_id', $this->id);
371384
$this->form->addHidden('base_field_name', $this->baseFieldName);
372385
$this->form->addHidden('custom', $this->custom);
@@ -420,6 +433,8 @@ public function save(bool $update = false): int
420433
{
421434
$this->validate();
422435

436+
$this->data['og_image'] = $this->handleOgImage();
437+
423438
//serialize data for save
424439
if (!empty($this->data['data'])) {
425440
$this->data['data'] = serialize($this->data['data']);
@@ -564,4 +579,37 @@ public function getMetaEntity(): MetaEntity
564579

565580
return MetaEntity::fromBackendMeta($this);
566581
}
582+
583+
private function handleOgImage(): ?string
584+
{
585+
$imagePath = FRONTEND_FILES_PATH . '/Pages/images';
586+
/** @var Thumbnails $thumbnails */
587+
$thumbnails = BackendModel::getContainer()->get(Thumbnails::class);
588+
589+
if ($this->form->existsField('og_image_delete')) {
590+
/** @var SpoonFormCheckbox $deleteField */
591+
$deleteField = $this->form->getField('og_image_delete');
592+
if ($deleteField->isChecked()) {
593+
$thumbnails->delete($imagePath, $this->data['og_image']);
594+
$this->data['og_image'] = null;
595+
}
596+
}
597+
598+
/** @var FormImage $imageField */
599+
$imageField = $this->form->getField('og_image');
600+
if (!$imageField->isFilled()) {
601+
return $this->data['og_image'] ?? null;
602+
}
603+
604+
$thumbnails->delete($imagePath, $this->data['og_image']);
605+
606+
$extension = $imageField->getExtension();
607+
$filename = $this->data['title'] . '_og_image_' . time() . '.' . $extension;
608+
609+
$imageFullPath = $imagePath . '/source/' . $filename;
610+
$imageField->moveFile($imageFullPath);
611+
$thumbnails->generate($imagePath, $imageFullPath);
612+
613+
return $filename;
614+
}
567615
}

src/Backend/Core/Installer/Data/locale.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13537,6 +13537,16 @@
1353713537
<translation language="nl"><![CDATA[inhoud bewerekn]]></translation>
1353813538
<translation language="en"><![CDATA[edit content]]></translation>
1353913539
</item>
13540+
<item type="label" name="OgImage">
13541+
<translation language="nl"><![CDATA[Og:image]]></translation>
13542+
<translation language="fr"><![CDATA[Og:image]]></translation>
13543+
<translation language="en"><![CDATA[Og:image]]></translation>
13544+
</item>
13545+
<item type="message" name="HelpOgImage">
13546+
<translation language="nl"><![CDATA[Voeg een afbeelding toe dom als og:image-tag te gebruiken.]]></translation>
13547+
<translation language="fr"><![CDATA[Ajoutez une image à utiliser pour la balise og:image.]]></translation>
13548+
<translation language="en"><![CDATA[Add an image to use for the og:image tag.]]></translation>
13549+
</item>
1354013550
</Core>
1354113551
</Backend>
1354213552
</locale>

src/Backend/Core/Layout/Templates/FormLayout.html.twig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,20 @@
233233
</div>
234234
</div>
235235
</div>
236+
{# og:image #}
237+
<div class="col-md-12">
238+
<div class="panel panel-default">
239+
<div class="panel-heading"><p class="tab-pane-title">{{ 'lbl.OgImage'|trans|ucfirst }}</p></div>
240+
<div class="panel-body">
241+
{% if form.parent.vars.data.meta.ogImage %}
242+
<img class="img-responsive img-thumbnail" src="/src/Frontend/Files/Pages/images/source/{{ form.parent.vars.data.meta.ogImage }}">
243+
{% endif %}
244+
{{ form_row(form.deleteOgImage, {'row_attr': {class: form.parent.vars.data.meta.ogImage ? '' : 'hidden'}}) }}
245+
{{ form_row(form.ogImage) }}
246+
</div>
247+
</div>
248+
</div>
249+
{# og:image end #}
236250
<input type="hidden" id="{{ customId }}" value="{{ custom_meta_tags ? '1' : '0' }}">
237251
<input type="hidden" id="{{ classId }}" value="{{ generate_url_callback_class }}">
238252
<input type="hidden" id="{{ methodId }}" value="{{ generate_url_callback_method }}">

src/Backend/Form/Type/MetaType.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
use SpoonFilter;
1010
use Symfony\Component\Form\AbstractType;
1111
use Symfony\Component\Form\CallbackTransformer;
12+
use Symfony\Component\Form\Event\PostSubmitEvent;
1213
use Symfony\Component\Form\Exception\InvalidArgumentException;
1314
use Symfony\Component\Form\Exception\LogicException;
1415
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
1516
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
1617
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
18+
use Symfony\Component\Form\Extension\Core\Type\FileType;
1719
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
1820
use Symfony\Component\Form\Extension\Core\Type\TextType;
1921
use Symfony\Component\Form\FormBuilderInterface;
@@ -24,6 +26,7 @@
2426
use Symfony\Component\Form\FormView;
2527
use Symfony\Component\OptionsResolver\OptionsResolver;
2628
use Symfony\Component\Translation\TranslatorInterface;
29+
use Symfony\Component\Validator\Constraints\File;
2730

2831
class MetaType extends AbstractType
2932
{
@@ -96,6 +99,32 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
9699
)
97100
->add('SEOIndex', ChoiceType::class, $this->getSEOIndexChoiceTypeOptions())
98101
->add('SEOFollow', ChoiceType::class, $this->getSEOFollowChoiceTypeOptions())
102+
->add(
103+
'ogImage',
104+
FileType::class,
105+
[
106+
'label' => 'lbl.OgImage',
107+
'required' => false,
108+
'attr' => ['accept' => 'image/jpeg, image/gif, image/png'],
109+
'constraints' => [
110+
new File(
111+
[
112+
'maxSize' => '5M',
113+
'mimeTypes' => ['image/jpeg', 'image/gif', 'image/png'],
114+
'mimeTypesMessage' => 'err.JPGGIFAndPNGOnly',
115+
]
116+
),
117+
],
118+
]
119+
)
120+
->add(
121+
'deleteOgImage',
122+
CheckboxType::class,
123+
[
124+
'label' => 'lbl.Delete',
125+
'required' => false,
126+
]
127+
)
99128
->addModelTransformer(
100129
new CallbackTransformer($this->getMetaTransformFunction(), $this->getMetaReverseTransformFunction())
101130
)
@@ -275,6 +304,8 @@ private function getMetaReverseTransformFunction(): callable
275304
SEOFollow::fromString((string) $metaData['SEOFollow']),
276305
SEOIndex::fromString((string) $metaData['SEOIndex']),
277306
[],
307+
$metaData['ogImage'],
308+
$metaData['deleteOgImage'],
278309
$metaId
279310
);
280311
}
@@ -292,7 +323,10 @@ private function getMetaReverseTransformFunction(): callable
292323
$metaData['canonicalUrlOverwrite'],
293324
array_key_exists('custom', $metaData) ? $metaData['custom'] : null,
294325
SEOFollow::fromString((string) $metaData['SEOFollow']),
295-
SEOIndex::fromString((string) $metaData['SEOIndex'])
326+
SEOIndex::fromString((string) $metaData['SEOIndex']),
327+
[],
328+
$metaData['ogImage'],
329+
$metaData['deleteOgImage']
296330
);
297331

298332
return $this->meta[$metaId];

src/Backend/Modules/Pages/Actions/Edit.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,7 @@ protected function parse(): void
644644

645645
// parse some variables
646646
$this->template->assign('item', $this->record);
647+
$this->template->assign('og_image', $this->meta->getOgImage());
647648
$this->template->assign('isGod', $this->isGod);
648649
$this->template->assign('templates', $this->templates);
649650
$this->template->assign('positions', $this->positions);

src/Backend/Modules/Pages/Installer/Data/install.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ CREATE TABLE IF NOT EXISTS `pages` (
2020
`allow_children` tinyint(1) NOT NULL DEFAULT '1',
2121
`allow_edit` tinyint(1) NOT NULL DEFAULT '1',
2222
`allow_delete` tinyint(1) NOT NULL DEFAULT '1',
23+
`og_image`` VARCHAR(255) DEFAULT NULL`,
2324
`sequence` int(11) NOT NULL,
2425
PRIMARY KEY (`revision_id`),
2526
KEY `idx_id_status_hidden_language` (`id`,`status`,`hidden`,`language`)

src/Common/Doctrine/Entity/Meta.php

Lines changed: 111 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
namespace Common\Doctrine\Entity;
44

55
use Backend\Core\Engine\Meta as BackendMeta;
6+
use Backend\Core\Engine\Model as BackendModel;
67
use Common\Doctrine\ValueObject\SEOFollow;
78
use Common\Doctrine\ValueObject\SEOIndex;
89
use Doctrine\ORM\Mapping as ORM;
10+
use ForkCMS\Utility\Thumbnails;
11+
use Symfony\Component\HttpFoundation\File\UploadedFile;
912

1013
/**
1114
* @ORM\Table(name="meta", indexes={@ORM\Index(name="idx_url", columns={"url"})})
@@ -114,6 +117,27 @@ class Meta
114117
*/
115118
private $seoIndex;
116119

120+
/**
121+
* @var string|null
122+
*
123+
* @ORM\Column(type="string", length=255, name="og_image", nullable=true)
124+
*/
125+
private $ogImage;
126+
127+
/**
128+
* @var string|null
129+
*/
130+
private $oldOgImage;
131+
132+
/**
133+
* @var UploadedFile|null
134+
*/
135+
private $uploadedOgImage;
136+
/**
137+
* @var bool
138+
*/
139+
private $deleteOgImage = false;
140+
117141
public function __construct(
118142
string $keywords,
119143
bool $keywordsOverwrite,
@@ -129,6 +153,8 @@ public function __construct(
129153
SEOFollow $seoFollow = null,
130154
SEOIndex $seoIndex = null,
131155
array $unserialisedData = [],
156+
?UploadedFile $uploadedOgImage = null,
157+
bool $deleteOgImage = false,
132158
int $id = null
133159
) {
134160
$this->keywords = $keywords;
@@ -143,6 +169,8 @@ public function __construct(
143169
$this->unserialisedData = $unserialisedData;
144170
$this->seoFollow = $seoFollow;
145171
$this->seoIndex = $seoIndex;
172+
$this->uploadedOgImage = $uploadedOgImage;
173+
$this->deleteOgImage = $deleteOgImage;
146174
$this->id = $id;
147175

148176
if ($canonicalUrlOverwrite) {
@@ -168,7 +196,9 @@ public function update(
168196
string $custom = null,
169197
SEOFollow $seoFollow = null,
170198
SEOIndex $seoIndex = null,
171-
array $unserialisedData = []
199+
array $unserialisedData = [],
200+
?UploadedFile $uploadedOgImage = null,
201+
bool $deleteOgImage = false,
172202
) {
173203
$this->keywords = $keywords;
174204
$this->keywordsOverwrite = $keywordsOverwrite;
@@ -182,6 +212,12 @@ public function update(
182212
$this->unserialisedData = $unserialisedData;
183213
$this->seoFollow = $seoFollow;
184214
$this->seoIndex = $seoIndex;
215+
$this->uploadedOgImage = $uploadedOgImage;
216+
$this->deleteOgImage = $deleteOgImage;
217+
if ($deleteOgImage) {
218+
$this->oldOgImage = $this->ogImage;
219+
$this->ogImage = null;
220+
}
185221

186222
if ($canonicalUrlOverwrite) {
187223
$this->unserialisedData['canonical_url'] = $canonicalUrl;
@@ -242,7 +278,7 @@ public static function fromBackendMeta(BackendMeta $meta): self
242278
array_key_exists('SEOFollow', $metaData) ? SEOFollow::fromString((string) $metaData['SEOFollow']) : null,
243279
array_key_exists('SEOIndex', $metaData) ? SEOIndex::fromString((string) $metaData['SEOIndex']) : null,
244280
$metaData['data'] ?? [],
245-
$meta->getId()
281+
id: $meta->getId()
246282
);
247283
}
248284

@@ -269,8 +305,7 @@ public static function updateWithFormData(array $metaData): self
269305
$metaData['custom'] ?? null,
270306
SEOFollow::fromString((string) $metaData['SEOFollow']),
271307
SEOIndex::fromString((string) $metaData['SEOIndex']),
272-
[],
273-
(int) $metaData['id']
308+
id: (int) $metaData['id']
274309
);
275310
}
276311

@@ -374,4 +409,76 @@ public function getSEOFollow(): ?SEOFollow
374409

375410
return $this->seoFollow;
376411
}
412+
413+
public function getOgImage(): ?string
414+
{
415+
return $this->ogImage;
416+
}
417+
418+
public function getUploadedOgImage(): ?UploadedFile
419+
{
420+
return $this->uploadedOgImage;
421+
}
422+
423+
public function isDeleteOgImage(): bool
424+
{
425+
return $this->deleteOgImage;
426+
}
427+
428+
/**
429+
* @ORM\PrePersist()
430+
* @ORM\PreUpdate()
431+
*/
432+
public function prepareOgImage(): void
433+
{
434+
$this->oldOgImage = $this->ogImage;
435+
436+
if ($this->uploadedOgImage instanceof UploadedFile) {
437+
$extension = $this->uploadedOgImage->getClientOriginalExtension();
438+
$filename = $this->getTitle() . '_og_image_' . time() . '.' . $extension;
439+
440+
$this->ogImage = $filename;
441+
}
442+
}
443+
444+
/**
445+
* @ORM\PostPersist()
446+
* @ORM\PostUpdate()
447+
*/
448+
public function uploadOgImage(): void
449+
{
450+
$imagePath = FRONTEND_FILES_PATH . '/Pages/images';
451+
/** @var Thumbnails $thumbnails */
452+
$thumbnails = BackendModel::getContainer()->get(Thumbnails::class);
453+
454+
if ($this->deleteOgImage) {
455+
$thumbnails->delete($imagePath, $this->oldOgImage);
456+
}
457+
458+
if (!$this->uploadedOgImage instanceof UploadedFile) {
459+
return;
460+
}
461+
462+
$thumbnails->delete($imagePath, $this->oldOgImage);
463+
464+
$filename = $this->ogImage;
465+
466+
$imageFullPath = $imagePath . '/source/' . $filename;
467+
468+
$this->uploadedOgImage->move($imagePath . '/source', $filename);
469+
$thumbnails->generate($imagePath, $imageFullPath);
470+
}
471+
472+
/**
473+
* @ORM\PostRemove()
474+
*/
475+
public function removeOgImage(): void
476+
{
477+
$imagePath = FRONTEND_FILES_PATH . '/Pages/images';
478+
/** @var Thumbnails $thumbnails */
479+
$thumbnails = BackendModel::getContainer()->get(Thumbnails::class);
480+
481+
$thumbnails->delete($imagePath, $this->oldOgImage);
482+
}
483+
377484
}

src/Frontend/Core/Engine/Base/Block.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,9 @@ protected function setMeta(Meta $meta): void
547547
true
548548
);
549549
}
550+
if ($meta->getOgImage()) {
551+
$this->header->addOpenGraphImage(FRONTEND_FILES_URL . '/Pages/images/source/' . $meta->getOgImage(), true);
552+
}
550553
}
551554

552555
/**

0 commit comments

Comments
 (0)