PluginProbe
Tag Groups is the Advanced Way to Display Your Taxonomy Terms / trunk
Tag Groups is the Advanced Way to Display Your Taxonomy Terms vtrunk
2.2.2 2.2.1 2.2.0 trunk 1.40.0 1.40.2 1.41.0 1.42.1 1.43.0 1.43.1 1.43.10 1.43.10.1 1.43.2 1.43.3 1.43.4 1.43.5 1.43.6 1.43.7 1.43.9 1.44.0 1.44.1 1.44.3 1.44.3.1 2.0.0 2.0.1 All 36 releases
tag-groups / include / admin / class.feed.php

class.feed.php in Tag Groups is the Advanced Way to Display Your Taxonomy Terms trunk, at include/admin/class.feed.php

356 lines 10.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * @package Tag Groups
5 * @author Christoph Amthor
6 * @copyright 2018 Christoph Amthor (@ Chatty Mango, chattymango.com)
7 * @license GPL-3.0+
8 */
9
10 /**
11 * Inspiration from: https://bavotasan.com/2010/display-rss-feed-with-php/
12 */
13
14 if (! class_exists('TagGroups_Feed')) {
15 // phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace, Squiz.Classes.ValidClassName.NotCamelCaps -- Legacy class structure
16 class TagGroups_Feed
17 {
18 private $dom_doc;
19 private $url;
20 private $posts_url;
21 private $feed = array();
22 private $cache;
23 private $debug = false;
24 private $limit = 5;
25 private $amount = 5;
26 public $expired = false;
27
28
29 /**
30 * instantiation of DOMDocument and ChattyMango_Cache
31 *
32 * @param void
33 * @return void
34 */
35 public function __construct()
36 {
37
38 // experimental solution for "DOMDocument::load(): I/O warning : failed to load external entity" server errors
39 if (defined('PHP_VERSION_ID') && PHP_VERSION_ID < 80000 && function_exists('libxml_disable_entity_loader')) {
40 libxml_disable_entity_loader(false);
41 }
42
43 $this->dom_doc = new DOMDocument();
44 if (class_exists('TagGroups_Object_Cache')) {
45 $this->cache = new TagGroups_Object_Cache();
46 $this->cache
47 ->type(TagGroups_Object_Cache::WP_TRANSIENTS) // Don't use here user settings
48 ->lifetime(60 * 60 * 6);
49 }
50 }
51
52
53 /**
54 * Turns debugging on.
55 *
56 * @param void
57 * @return object $this
58 */
59 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- Legacy method naming
60 public function set_debug($debug = true)
61 {
62
63 $this->debug = $debug;
64 return $this;
65 }
66
67
68 /**
69 * Sets length of description
70 *
71 * @param int $limit
72 * @return object $this
73 */
74 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- Legacy method naming
75 public function set_limit($length)
76 {
77
78 $this->limit = $length;
79 return $this;
80 }
81
82
83 /**
84 * Sets max number of items
85 *
86 * @param int $amount
87 * @return object $this
88 */
89 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- Legacy method naming
90 public function set_amount($amount)
91 {
92
93 $this->amount = $amount;
94 return $this;
95 }
96
97
98 /**
99 * sets the URL where we can find the feed
100 *
101 * @param string $url
102 * @return object $this
103 */
104 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- Legacy method naming
105 public function set_url($url)
106 {
107
108 $this->url = $url;
109 if (isset($this->cache)) {
110 $this->cache->key(md5($url));
111 }
112
113 return $this;
114 }
115
116
117 /**
118 * sets the URL where we can find the posts
119 *
120 * @param string $posts_url
121 * @return object $this
122 */
123 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- Legacy method naming
124 public function set_posts_url($posts_url)
125 {
126
127 $this->posts_url = $posts_url;
128 return $this;
129 }
130
131
132 /**
133 * Shortcode to return the HTML, cached or live
134 *
135 * @return string
136 */
137 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- Legacy method naming
138 public function get_html()
139 {
140
141 $html = $this->cache_get();
142 if (empty($html)) {
143 $html = $this->load()->parse()->render(true);
144 }
145
146 return $html;
147 }
148
149 /**
150 * tries to read the rendered feed content from the cache, returns false if not possible
151 *
152 * @param void
153 * @return bool|string
154 */
155 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- Legacy method naming
156 private function cache_get()
157 {
158
159 if (isset($this->cache)) {
160 $data = $this->cache->get();
161 $this->expired = $this->cache->expired;
162 if ($data && $this->debug) {
163 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging
164 error_log('[Tag Groups] Feed items found in cache');
165 }
166
167 return $data;
168 } else {
169 return false;
170 }
171 }
172
173
174 /**
175 * saves rendered content to the cache
176 *
177 * @param string $data
178 * @return bool success?
179 */
180 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- Legacy method naming
181 private function cache_set($data)
182 {
183
184 if (isset($this->cache)) {
185 return $this->cache->set($data);
186 } else {
187 return false;
188 }
189 }
190
191
192 /**
193 * purges data (of this feed) from the cache
194 *
195 * @param void
196 * @return object $this
197 */
198 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- Legacy method naming
199 public function cache_purge()
200 {
201
202 if (isset($this->cache)) {
203 return $this->cache->purge();
204 } else {
205 return false;
206 }
207 }
208
209
210
211 /**
212 * loads the content from the feed
213 *
214 * @param string $url
215 * @return object $this
216 */
217 private function load()
218 {
219
220 $options = array(
221 'http' => array(
222 'user_agent' => 'PHP libxml agent',
223 'method' => 'GET',
224 'timeout' => '5'
225 )
226 );
227 $context = stream_context_create($options);
228 libxml_set_streams_context($context);
229 $this->dom_doc->load($this->url);
230 $xml = $this->dom_doc->saveXML();
231 // hack to make <media:content url="..." medium="image" /> available as new tag
232 $xml = preg_replace('#<media:content\s+url="([^"]+)"\s+medium="image"\s*\/>#', '<mediacontent>$1</mediacontent>', $xml);
233 $this->dom_doc->loadXML($xml);
234 return $this;
235 }
236
237
238 /**
239 * parses the feed data to retrieve items and relevant fields
240 *
241 * @param void
242 * @return object $this
243 */
244 public function parse()
245 {
246
247 foreach ($this->dom_doc->getElementsByTagName('item') as $node) {
248 $item = array (
249 'title' => $node->getElementsByTagName('title')->item(0)->nodeValue,
250 'desc' => $node->getElementsByTagName('description')->item(0)->nodeValue,
251 'link' => $node->getElementsByTagName('link')->item(0)->nodeValue,
252 'date' => $node->getElementsByTagName('pubDate')->item(0)->nodeValue,
253 'image_src' => $node->getElementsByTagName('mediacontent')->item(0)->nodeValue
254 );
255 // multiple categories and tags
256 $cats = $node->getElementsByTagName('category');
257 $item['categories'] = array();
258
259 for ($i = 0; $i < $cats->length; $i++) {
260 $item['categories'][] = $cats->item($i)->nodeValue;
261 }
262
263 array_push($this->feed, $item);
264 }
265
266 return $this;
267 }
268
269
270 /**
271 * Renders the feed to HTML
272 *
273 * @param int $limit maximum number of feed items
274 * @param bool $return true: return output as string, false: echo output
275 * @return string
276 */
277 private function render($return = true)
278 {
279
280 $html = '';
281 $date_format = get_option('date_format');
282 $view = new TagGroups_View('partials/admin_feed_item');
283
284 for ($x = 0; $x < $this->amount; $x++) {
285 if (isset($this->feed[$x])) {
286 $title = str_replace(' & ', ' &amp; ', $this->feed[$x]['title']);
287 $link = $this->feed[$x]['link'];
288 $description = $this->truncate_string_at_word($this->feed[$x]['desc'], $this->limit);
289 $date = gmdate($date_format, strtotime($this->feed[$x]['date']));
290 $view->set(array(
291 'date' => $date,
292 'link' => esc_url($link),
293 'title' => sanitize_text_field($title),
294 'description' => sanitize_text_field($description),
295 'image_src' => esc_url($this->feed[$x]['image_src']),
296 ));
297 $html .= $view->return_html();
298 // <p><small><b>' . sanitize_text_field( implode( ', ', $this->feed[$x]['categories'] ) ) . '</b></small></p>
299 }
300 }
301
302 $posts_url_campagin = $this->posts_url . ( strpos($this->posts_url, '?') ? '&pk_campaign=rss' : '?pk_campaign=rss' );
303 if (! empty($html)) {
304 $view = new TagGroups_View('partials/admin_feed_footer');
305 $view->set('link', esc_url($posts_url_campagin));
306 $html .= $view->return_html();
307 $this->cache_set($html);
308 } else {
309 /*
310 * Fallback: Ask user to go directly to the posts.
311 */
312 $view = new TagGroups_View('partials/admin_feed_fallback');
313 $view->set(array(
314 'posts_url_campaign' => esc_url($posts_url_campagin),
315 'posts_url' => $this->posts_url
316 ));
317 $html = $view->return_html();
318 TagGroups_Error::log('[Tag Groups] Feed is empty: ' . $this->url);
319 }
320
321 if ($return) {
322 return $html;
323 } else {
324 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- HTML already escaped in view
325 echo $html;
326 }
327 }
328
329
330 /**
331 *
332 *
333 * modified from https://wp-mix.com/php-truncate-text-word/
334 */
335 // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- Legacy method naming
336 private function truncate_string_at_word($string, $limit, $break = ". ", $pad = " ...")
337 {
338
339 if (mb_strlen($string) <= $limit) {
340 return $string;
341 }
342
343 if (false !== ($max = mb_strpos($string, $break, $limit))) {
344 if ($max < mb_strlen($string) - 1) {
345 $string = mb_substr($string, 0, $max) . $pad;
346 }
347 }
348
349 return $string;
350 }
351 }
352 // phpcs:ignore PSR12.Classes.ClosingBrace.StatementAfter -- Legacy code style
353
354
355 }
356