1
|
|
|
<?php namespace XoopsModules\Smartobject; |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Containing the class to manage meta informations of the SmartObject framework |
5
|
|
|
* |
6
|
|
|
* @license GNU |
7
|
|
|
* @author marcan <[email protected]> |
8
|
|
|
* @link http://smartfactory.ca The SmartFactory |
9
|
|
|
* @package SmartObject |
10
|
|
|
* @subpackage SmartObjectCore |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
use XoopsModules\Smartobject; |
14
|
|
|
/** @var Smartobject\Helper $helper */ |
15
|
|
|
$helper = Smartobject\Helper::getInstance(); |
16
|
|
|
|
17
|
|
|
// defined('XOOPS_ROOT_PATH') || die('Restricted access'); |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Class MetaGen is a class providing some methods to dynamically and automatically customize Meta Tags information |
21
|
|
|
* @author The SmartFactory <www.smartfactory.ca> |
22
|
|
|
*/ |
23
|
|
|
class MetaGen |
24
|
|
|
{ |
25
|
|
|
public $_myts; |
26
|
|
|
|
27
|
|
|
public $_title; |
28
|
|
|
public $_original_title; |
29
|
|
|
public $_keywords; |
30
|
|
|
public $_meta_description; |
31
|
|
|
public $_categoryPath; |
32
|
|
|
public $_description; |
33
|
|
|
public $_minChar = 4; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* SmartMetaGen constructor. |
37
|
|
|
* @param $title |
38
|
|
|
* @param bool $keywords |
39
|
|
|
* @param bool $description |
40
|
|
|
* @param bool $categoryPath |
41
|
|
|
*/ |
42
|
|
|
public function __construct($title, $keywords = false, $description = false, $categoryPath = false) |
43
|
|
|
{ |
44
|
|
|
$this->_myts = \MyTextSanitizer::getInstance(); |
45
|
|
|
$this->setCategoryPath($categoryPath); |
46
|
|
|
$this->setTitle($title); |
47
|
|
|
$this->setDescription($description); |
48
|
|
|
|
49
|
|
|
if (!$keywords) { |
50
|
|
|
$keywords = $this->createMetaKeywords(); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/* $myts = \MyTextSanitizer::getInstance(); |
54
|
|
|
if (method_exists($myts, 'formatForML')) { |
55
|
|
|
$keywords = $myts->formatForML($keywords); |
56
|
|
|
$description = $myts->formatForML($description); |
57
|
|
|
} |
58
|
|
|
*/ |
59
|
|
|
$this->setKeywords($keywords); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Return true if the string is length > 0 |
64
|
|
|
* |
65
|
|
|
* @credit psylove |
66
|
|
|
* |
67
|
|
|
* @var string $string Chaine de caract�re |
68
|
|
|
* @return boolean |
69
|
|
|
*/ |
70
|
|
|
public function emptyString($var) |
71
|
|
|
{ |
72
|
|
|
return (strlen($var) > 0); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* Create a title for the short_url field of an article |
77
|
|
|
* |
78
|
|
|
* @credit psylove |
79
|
|
|
* |
80
|
|
|
* @var string $title title of the article |
81
|
|
|
* @param bool|string $withExt |
82
|
|
|
* @return string sort_url for the article |
83
|
|
|
*/ |
84
|
|
|
public function generateSeoTitle($title = '', $withExt = true) |
85
|
|
|
{ |
86
|
|
|
// Transformation de la chaine en minuscule |
87
|
|
|
// Codage de la chaine afin d'éviter les erreurs 500 en cas de caractères imprévus |
88
|
|
|
$title = rawurlencode(strtolower($title)); |
89
|
|
|
|
90
|
|
|
// Transformation des ponctuations |
91
|
|
|
$pattern = [ |
92
|
|
|
'/%09/', // Tab |
93
|
|
|
'/%20/', // Space |
94
|
|
|
'/%21/', // ! |
95
|
|
|
'/%22/', // " |
96
|
|
|
'/%23/', // # |
97
|
|
|
'/%25/', // % |
98
|
|
|
'/%26/', // & |
99
|
|
|
'/%27/', // ' |
100
|
|
|
'/%28/', // ( |
101
|
|
|
'/%29/', // ) |
102
|
|
|
'/%2C/', // , |
103
|
|
|
'/%2F/', // / |
104
|
|
|
'/%3A/', // : |
105
|
|
|
'/%3B/', // ; |
106
|
|
|
'/%3C/', // < |
107
|
|
|
'/%3D/', // = |
108
|
|
|
'/%3E/', // > |
109
|
|
|
'/%3F/', // ? |
110
|
|
|
'/%40/', // @ |
111
|
|
|
'/%5B/', // [ |
112
|
|
|
'/%5C/', // \ |
113
|
|
|
'/%5D/', // ] |
114
|
|
|
'/%5E/', // ^ |
115
|
|
|
'/%7B/', // { |
116
|
|
|
'/%7C/', // | |
117
|
|
|
'/%7D/', // } |
118
|
|
|
'/%7E/', // ~ |
119
|
|
|
"/\./" // . |
120
|
|
|
]; |
121
|
|
|
$rep_pat = [ |
122
|
|
|
'-', |
123
|
|
|
'-', |
124
|
|
|
'-', |
125
|
|
|
'-', |
126
|
|
|
'-', |
127
|
|
|
'-100', |
128
|
|
|
'-', |
129
|
|
|
'-', |
130
|
|
|
'-', |
131
|
|
|
'-', |
132
|
|
|
'-', |
133
|
|
|
'-', |
134
|
|
|
'-', |
135
|
|
|
'-', |
136
|
|
|
'-', |
137
|
|
|
'-', |
138
|
|
|
'-', |
139
|
|
|
'-', |
140
|
|
|
'-at-', |
141
|
|
|
'-', |
142
|
|
|
'-', |
143
|
|
|
'-', |
144
|
|
|
'-', |
145
|
|
|
'-', |
146
|
|
|
'-', |
147
|
|
|
'-', |
148
|
|
|
'-', |
149
|
|
|
'-' |
150
|
|
|
]; |
151
|
|
|
$title = preg_replace($pattern, $rep_pat, $title); |
152
|
|
|
|
153
|
|
|
// Transformation des caractères accentués |
154
|
|
|
$pattern = [ |
155
|
|
|
'/%B0/', // ° |
156
|
|
|
'/%E8/', // è |
157
|
|
|
'/%E9/', // é |
158
|
|
|
'/%EA/', // ê |
159
|
|
|
'/%EB/', // ë |
160
|
|
|
'/%E7/', // ç |
161
|
|
|
'/%E0/', // à |
162
|
|
|
'/%E2/', // â |
163
|
|
|
'/%E4/', // ä |
164
|
|
|
'/%EE/', // î |
165
|
|
|
'/%EF/', // ï |
166
|
|
|
'/%F9/', // ù |
167
|
|
|
'/%FC/', // ü |
168
|
|
|
'/%FB/', // û |
169
|
|
|
'/%F4/', // ô |
170
|
|
|
'/%F6/', // ö |
171
|
|
|
]; |
172
|
|
|
$rep_pat = ['-', 'e', 'e', 'e', 'e', 'c', 'a', 'a', 'a', 'i', 'i', 'u', 'u', 'u', 'o', 'o']; |
173
|
|
|
$title = preg_replace($pattern, $rep_pat, $title); |
174
|
|
|
|
175
|
|
|
$tableau = explode('-', $title); // Transforme la chaine de caract�res en tableau |
176
|
|
|
$tableau = array_filter($tableau, [$this, 'emptyString']); // Supprime les chaines vides du tableau |
177
|
|
|
$title = implode('-', $tableau); // Transforme un tableau en chaine de caract�res s�par� par un tiret |
178
|
|
|
|
179
|
|
|
if (count($title) > 0) { |
180
|
|
|
if ($withExt) { |
181
|
|
|
$title .= '.html'; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
return $title; |
185
|
|
|
} else { |
186
|
|
|
return ''; |
187
|
|
|
} |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* @param $document |
192
|
|
|
* @return mixed |
193
|
|
|
*/ |
194
|
|
|
public function html2text($document) |
195
|
|
|
{ |
196
|
|
|
return Smartobject\Utility::getHtml2text($document); |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* @param $title |
201
|
|
|
*/ |
202
|
|
|
public function setTitle($title) |
203
|
|
|
{ |
204
|
|
|
global $xoopsModule; |
205
|
|
|
/** @var Smartobject\Helper $helper */ |
206
|
|
|
$helper = Smartobject\Helper::getInstance(); |
207
|
|
|
|
208
|
|
|
$this->_title = $this->html2text($title); |
209
|
|
|
$this->_title = $this->purifyText($this->_title); |
210
|
|
|
$this->_original_title = $this->_title; |
211
|
|
|
|
212
|
|
|
$moduleName = $xoopsModule->getVar('name'); |
213
|
|
|
|
214
|
|
|
$titleTag = []; |
215
|
|
|
|
216
|
|
|
$show_mod_name_breadcrumb = null !==($helper->getConfig('show_mod_name_breadcrumb')) ? $helper->getConfig('show_mod_name_breadcrumb') : true; |
217
|
|
|
|
218
|
|
|
if ($moduleName && $show_mod_name_breadcrumb) { |
219
|
|
|
$titleTag['module'] = $moduleName; |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
if (isset($this->_title) && ('' !== $this->_title) && (strtoupper($this->_title) != strtoupper($moduleName))) { |
223
|
|
|
$titleTag['title'] = $this->_title; |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
if (isset($this->_categoryPath) && ('' !== $this->_categoryPath)) { |
227
|
|
|
$titleTag['category'] = $this->_categoryPath; |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
$ret = isset($titleTag['title']) ? $titleTag['title'] : ''; |
231
|
|
|
|
232
|
|
View Code Duplication |
if (isset($titleTag['category']) && '' !== $titleTag['category']) { |
|
|
|
|
233
|
|
|
if ('' !== $ret) { |
234
|
|
|
$ret .= ' - '; |
235
|
|
|
} |
236
|
|
|
$ret .= $titleTag['category']; |
237
|
|
|
} |
238
|
|
View Code Duplication |
if (isset($titleTag['module']) && '' !== $titleTag['module']) { |
|
|
|
|
239
|
|
|
if ('' !== $ret) { |
240
|
|
|
$ret .= ' - '; |
241
|
|
|
} |
242
|
|
|
$ret .= $titleTag['module']; |
243
|
|
|
} |
244
|
|
|
$this->_title = $ret; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
/** |
248
|
|
|
* @param $keywords |
249
|
|
|
*/ |
250
|
|
|
public function setKeywords($keywords) |
251
|
|
|
{ |
252
|
|
|
$this->_keywords = $keywords; |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* @param $categoryPath |
257
|
|
|
*/ |
258
|
|
|
public function setCategoryPath($categoryPath) |
259
|
|
|
{ |
260
|
|
|
$categoryPath = $this->html2text($categoryPath); |
261
|
|
|
$this->_categoryPath = $categoryPath; |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* @param $description |
266
|
|
|
*/ |
267
|
|
|
public function setDescription($description) |
268
|
|
|
{ |
269
|
|
|
if (!$description) { |
270
|
|
|
/** @var Smartobject\Helper $helper */ |
271
|
|
|
$helper = Smartobject\Helper::getInstance(); |
272
|
|
|
|
273
|
|
|
if (null !== ($helper->getConfig('module_meta_description'))) { |
274
|
|
|
$description = $helper->getConfig('module_meta_description'); |
275
|
|
|
} |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
$description = $this->html2text($description); |
279
|
|
|
$description = $this->purifyText($description); |
280
|
|
|
|
281
|
|
|
$description = preg_replace("/([^\r\n])\r\n([^\r\n])/", "\\1 \\2", $description); |
282
|
|
|
$description = preg_replace("/[\r\n]*\r\n[\r\n]*/", "\r\n\r\n", $description); |
283
|
|
|
$description = preg_replace('/[ ]* [ ]*/', ' ', $description); |
284
|
|
|
$description = stripslashes($description); |
285
|
|
|
|
286
|
|
|
$this->_description = $description; |
287
|
|
|
$this->_meta_description = $this->createMetaDescription(); |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
public function createTitleTag() |
291
|
|
|
{ |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* @param $text |
296
|
|
|
* @param bool $keyword |
297
|
|
|
* @return mixed|string |
298
|
|
|
*/ |
299
|
|
|
public function purifyText($text, $keyword = false) |
300
|
|
|
{ |
301
|
|
|
return Smartobject\Utility::purifyText($text, $keyword); |
302
|
|
|
} |
303
|
|
|
|
304
|
|
|
/** |
305
|
|
|
* @param int $maxWords |
306
|
|
|
* @return string |
307
|
|
|
*/ |
308
|
|
|
public function createMetaDescription($maxWords = 100) |
309
|
|
|
{ |
310
|
|
|
$words = []; |
|
|
|
|
311
|
|
|
$words = explode(' ', $this->_description); |
312
|
|
|
|
313
|
|
|
// Only keep $maxWords words |
314
|
|
|
$newWords = []; |
315
|
|
|
$i = 0; |
316
|
|
|
|
317
|
|
|
while ($i < $maxWords - 1 && $i < count($words)) { |
318
|
|
|
$newWords[] = $words[$i]; |
319
|
|
|
++$i; |
320
|
|
|
} |
321
|
|
|
$ret = implode(' ', $newWords); |
322
|
|
|
|
323
|
|
|
return $ret; |
324
|
|
|
} |
325
|
|
|
|
326
|
|
|
/** |
327
|
|
|
* @param $text |
328
|
|
|
* @param $minChar |
329
|
|
|
* @return array |
330
|
|
|
*/ |
331
|
|
|
public function findMetaKeywords($text, $minChar) |
332
|
|
|
{ |
333
|
|
|
$keywords = []; |
334
|
|
|
|
335
|
|
|
$text = $this->purifyText($text); |
336
|
|
|
$text = $this->html2text($text); |
337
|
|
|
|
338
|
|
|
$text = preg_replace("/([^\r\n])\r\n([^\r\n])/", "\\1 \\2", $text); |
339
|
|
|
$text = preg_replace("/[\r\n]*\r\n[\r\n]*/", "\r\n\r\n", $text); |
340
|
|
|
$text = preg_replace('/[ ]* [ ]*/', ' ', $text); |
341
|
|
|
$text = stripslashes($text); |
342
|
|
|
$text = |
|
|
|
|
343
|
|
|
|
344
|
|
|
$originalKeywords = preg_split('/[^a-zA-Z\'"-]+/', $text, -1, PREG_SPLIT_NO_EMPTY); |
345
|
|
|
|
346
|
|
|
foreach ($originalKeywords as $originalKeyword) { |
347
|
|
|
$secondRoundKeywords = explode("'", $originalKeyword); |
348
|
|
|
foreach ($secondRoundKeywords as $secondRoundKeyword) { |
349
|
|
|
if (strlen($secondRoundKeyword) >= $minChar) { |
350
|
|
|
if (!in_array($secondRoundKeyword, $keywords)) { |
351
|
|
|
$keywords[] = trim($secondRoundKeyword); |
352
|
|
|
} |
353
|
|
|
} |
354
|
|
|
} |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
return $keywords; |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
/** |
361
|
|
|
* @return string |
362
|
|
|
*/ |
363
|
|
|
public function createMetaKeywords() |
364
|
|
|
{ |
365
|
|
|
/** @var Smartobject\Helper $helper */ |
366
|
|
|
$helper = Smartobject\Helper::getInstance(); |
367
|
|
|
|
368
|
|
|
$keywords = $this->findMetaKeywords($this->_original_title . ' ' . $this->_description, $this->_minChar); |
369
|
|
|
if (null !== ($helper->getModule()) && null !== ($helper->getConfig('moduleMetaKeywords')) |
370
|
|
|
&& '' !== $helper->getConfig('moduleMetaKeywords')) { |
371
|
|
|
$moduleKeywords = explode(',', $helper->getConfig('moduleMetaKeywords')); |
372
|
|
|
$keywords = array_merge($keywords, $moduleKeywords); |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
/* Commenting this out as it may cause problem on XOOPS ML websites |
376
|
|
|
$return_keywords = array(); |
377
|
|
|
|
378
|
|
|
// Cleaning for duplicate keywords |
379
|
|
|
foreach ($keywords as $keyword) { |
380
|
|
|
if (!in_array($keyword, $keywords)) { |
381
|
|
|
$return_keywords[] = trim($keyword); |
382
|
|
|
} |
383
|
|
|
}*/ |
384
|
|
|
|
385
|
|
|
// Only take the first 90 keywords |
386
|
|
|
$newKeywords = []; |
387
|
|
|
$i = 0; |
388
|
|
|
while ($i < 90 - 1 && isset($keywords[$i])) { |
389
|
|
|
$newKeywords[] = $keywords[$i]; |
390
|
|
|
++$i; |
391
|
|
|
} |
392
|
|
|
$ret = implode(', ', $newKeywords); |
393
|
|
|
|
394
|
|
|
return $ret; |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
public function autoBuildMeta_keywords() |
398
|
|
|
{ |
399
|
|
|
} |
400
|
|
|
|
401
|
|
|
public function buildAutoMetaTags() |
402
|
|
|
{ |
403
|
|
|
global $xoopsModule; |
404
|
|
|
/** @var Smartobject\Helper $helper */ |
405
|
|
|
$helper = Smartobject\Helper::getInstance(); |
|
|
|
|
406
|
|
|
|
407
|
|
|
$this->_keywords = $this->createMetaKeywords(); |
408
|
|
|
$this->_meta_description = $this->createMetaDescription(); |
409
|
|
|
$this->_title = $this->createTitleTag(); |
|
|
|
|
410
|
|
|
} |
411
|
|
|
|
412
|
|
|
public function createMetaTags() |
413
|
|
|
{ |
414
|
|
|
global $xoopsTpl, $xoTheme; |
415
|
|
|
|
416
|
|
|
if (is_object($xoTheme)) { |
417
|
|
|
$xoTheme->addMeta('meta', 'keywords', $this->_keywords); |
418
|
|
|
$xoTheme->addMeta('meta', 'description', $this->_description); |
419
|
|
|
$xoTheme->addMeta('meta', 'title', $this->_title); |
420
|
|
|
} else { |
421
|
|
|
$xoopsTpl->assign('xoops_meta_keywords', $this->_keywords); |
422
|
|
|
$xoopsTpl->assign('xoops_meta_description', $this->_description); |
423
|
|
|
} |
424
|
|
|
$xoopsTpl->assign('xoops_pagetitle', $this->_title); |
425
|
|
|
} |
426
|
|
|
} |
427
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.