PluginProbe ʕ •ᴥ•ʔ
Custom Twitter Feeds – A Tweets Widget or X Feed Widget / 2.8.0
Custom Twitter Feeds – A Tweets Widget or X Feed Widget v2.8.0
2.8.0 2.7.0 2.6.1 2.6.0 1.0 1.0.1 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.2 1.2.1 1.2.10 1.2.11 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3 1.4 1.4.1 1.5 1.5.1 1.6 1.6.1 1.7 1.8 1.8.1 1.8.2 1.8.3 1.8.4 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1 2.1.1 2.1.2 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.5.4 2.5.5 trunk
custom-twitter-feeds / inc / CtfFeed.php
custom-twitter-feeds / inc Last commit date
Admin 4 weeks ago Builder 4 weeks ago Integrations 4 weeks ago SmashTwitter 4 weeks ago UsageTracking 4 weeks ago V2 4 weeks ago blocks 4 weeks ago CTF_Display_Elements.php 4 weeks ago CTF_Feed.php 4 weeks ago CTF_Feed_Locator.php 4 weeks ago CTF_GDPR_Integrations.php 4 weeks ago CTF_Parse.php 4 weeks ago CTF_Settings.php 4 weeks ago CtfAdmin.php 4 weeks ago CtfCache.php 4 weeks ago CtfFeed.php 4 weeks ago CtfOauthConnect.php 4 weeks ago SB_Twitter_Cron_Updater.php 4 weeks ago admin-hooks.php 4 weeks ago ctf-functions.php 4 weeks ago notices.php 4 weeks ago widget.php 4 weeks ago
CtfFeed.php
2372 lines
1 <?php
2 /**
3 * Class CtfFeed
4 *
5 * Creates the settings for the feed and outputs the html
6 */
7 namespace TwitterFeed;
8
9 use TwitterFeed\CTF_Parse;
10 use TwitterFeed\CtfCache;
11 use TwitterFeed\CTF_Feed;
12 use TwitterFeed\CTF_Settings;
13 use TwitterFeed\V2\CtfOauthConnect;
14 use TwitterFeed\CTF_Feed_Locator;
15 use TwitterFeed\CTF_GDPR_Integrations;
16 use TwitterFeed\Builder\CTF_Feed_Builder;
17 use TwitterFeed\SmashTwitter\ErrorReport;
18 use TwitterFeed\SmashTwitter\SettingsFilter;
19 use TwitterFeed\SmashTwitter\TweetFilterer;
20 use TwitterFeed\SmashTwitter\TweetSetModifier;
21
22 // Don't load directly
23 if ( ! defined( 'ABSPATH' ) ) {
24 die( '-1' );
25 }
26
27 class CtfFeed
28 {
29 /**
30 * @var array
31 */
32 public $errors = array();
33
34 /**
35 * @var array
36 */
37 protected $atts;
38
39 /**
40 * @var string
41 */
42 protected $last_id_data;
43
44 private $num_needed_input;
45
46 /**
47 * @var mixed|void
48 */
49 protected $db_options;
50
51 /**
52 * @var array
53 */
54 public $feed_options = array();
55
56 /**
57 * @var mixed|void
58 */
59 public $missing_credentials;
60
61 /**
62 * @var string
63 */
64 public $transient_name;
65
66 /**
67 * @var bool
68 */
69 protected $transient_data = false;
70
71 protected $raw_shortcode_atts;
72
73 /**
74 * @var int
75 */
76 private $num_tweets_needed;
77
78 private $check_for_duplicates = false;
79
80 /**
81 * @var array
82 */
83 public $tweet_set;
84
85 /**
86 * @var object
87 */
88 public $api_obj;
89
90 /**
91 * @var string
92 */
93 public $feed_html;
94
95 private $persistent_index;
96
97 /**
98 * @var string
99 */
100 public $feed_id;
101
102 /**
103 * @var CtfCache
104 */
105 public $cache;
106
107 /**
108 * @var boolean
109 */
110 public $is_legacy;
111
112 /**
113 * @var boolean
114 */
115 public $unique_legacy_id;
116
117 /**
118 * @var SettingsFilter
119 */
120 public $settings_filter;
121
122 /**
123 * @var ErrorReport
124 */
125 public $error_report;
126
127 /**
128 * retrieves and sets options that apply to the feed
129 *
130 * @param array $atts data from the shortcode
131 * @param string $last_id_data the last visible tweet on the feed, empty string if first set
132 * @param int $num_needed_input this number represents the number left to retrieve after the first set
133 */
134 public function __construct($atts, $last_id_data, $num_needed_input, $preview_settings = false) {
135 $this->settings_filter = new SettingsFilter();
136 $this->error_report = new ErrorReport();
137
138 //$this->atts = $atts;
139 $this->atts = CTF_Settings::filter_atts_for_legacy($atts);
140 $this->raw_shortcode_atts = CTF_Settings::filter_atts_for_legacy($atts);
141 if( isset($this->atts['feed']) ){
142 $atts['feed'] = $this->atts['feed'];
143 }
144
145 $this->last_id_data = $last_id_data;
146 $this->num_needed_input = $num_needed_input;
147 $this->db_options = get_option( 'ctf_options', array() );
148 $this->is_legacy = false;
149 if ( ! empty( $atts['feed'] ) && $atts['feed'] !== 'legacy' ) {
150 $this->feed_id = $this->atts['feed'];
151 $this->feed_options = CTF_Settings::get_settings_by_feed_id( $atts['feed'], $preview_settings );
152 if($this->feed_options == false){
153 $this->feed_options['feederror'] = true;
154 }else{
155 $this->feed_options['feed'] = $this->feed_id;
156 $this->atts = $this->feed_options;
157 add_action( 'wp_footer', [ $this, 'get_feed_style' ] );
158 }
159 }else{
160 $ctf_statuses = get_option( 'ctf_statuses', array() );
161 if ( ! empty( $ctf_statuses['support_legacy_shortcode'] ) ) {
162 if($preview_settings !== false && is_array($preview_settings)){
163 $this->feed_options = wp_parse_args( $this->atts, $preview_settings );
164 }else{
165 $legacy_settings_option = self::get_legacy_feed_settings();
166 if ( empty( $legacy_settings_option ) ) {
167 $this->feed_options = CTF_Settings::legacy_shortcode_atts( $this->atts, $this->db_options );
168 } else {
169 $this->feed_options = wp_parse_args( $this->atts, $legacy_settings_option );
170 }
171 }
172 $this->atts = wp_parse_args( $this->atts, \TwitterFeed\Builder\CTF_Feed_Saver::settings_defaults() );
173 $this->feed_options = wp_parse_args( $this->feed_options, $this->atts );
174 $this->feed_options['persistentcache'] = $this->atts['persistentcache'];
175
176 add_action( 'wp_footer', [ $this, 'get_feed_style' ] );
177 }
178 $this->unique_legacy_id = rand( 1, time() );
179 $this->is_legacy = true;
180
181 }
182 if ( ! empty( $this->feed_options ) ) {
183 $this->feed_options['customizer'] = isset($atts['customizer']) && $atts['customizer'] == true ? true : false;
184 }
185 if ( ! empty( $atts['feed'] ) ) {
186 $this->feed_options['feed'] = $atts['feed'];
187 }
188 $this->feed_options['selfreplies'] = false;
189 $this->feed_options['includereplies'] = false;
190 $this->feed_options['is_legacy'] = $this->is_legacy;
191 }
192
193 /**
194 * creates and returns all of the data needed to generate the output for the feed
195 *
196 * @param array $atts data from the shortcode
197 * @param string $last_id_data the last visible tweet on the feed, empty string if first set
198 * @param int $num_needed_input this number represents the number left to retrieve after the first set
199 * @return CtfFeed the complete object for the feed
200 */
201 public static function init( $atts, $last_id_data = '', $num_needed_input = 0, $ids_to_remove = array(), $persistent_index = 1, $preview_settings = false ){
202 if ( empty( $atts['feed'] ) ) {
203 $ctf_statuses = get_option( 'ctf_statuses', array() );
204 if ( empty( $ctf_statuses['support_legacy_shortcode'] ) ) {
205 if ( empty( $atts ) ) {
206 $atts = array();
207 }
208 $atts['feed'] = 1;
209 }
210 }
211
212 $feed = new CtfFeed( $atts, $last_id_data, $num_needed_input, $preview_settings );
213 $feed->setFeedOptions();
214
215 $feed->setCacheTypeOption();
216
217 if (CTF_DOING_SMASH_TWITTER || $feed->feed_options['persistentcache']) {
218 $feed->persistent_index = $persistent_index;
219 }
220 $feed->setTweetSet();
221 return $feed;
222 }
223
224 /**
225 * creates all of the feed options with shortcode settings having the highest priority
226 */
227 public function setFeedOptions(){
228 $this->feed_options['num'] = isset($this->feed_options['num']) && !empty($this->feed_options['num']) ? $this->feed_options['num'] : 1;
229 $this->setFeedTypeAndTermOptions();
230 $this->setAccessTokenAndSecretOptions();
231 $this->setConsumerKeyAndSecretOptions();
232 $db_only = array(
233 'request_method'
234 );
235 $this->setDatabaseOnlyOptions( $db_only );
236 $this->setCacheTimeOptions();
237 $this->setIncludeExcludeOptions();
238
239 if ( CTF_GDPR_Integrations::doing_gdpr( $this->feed_options ) ) {
240 CTF_GDPR_Integrations::init();
241 }
242 $this->feed_options['usertimeline_includeretweets'] = true;
243
244 if ( CTF_DOING_SMASH_TWITTER ) {
245 $this->settings_filter->set_settings( $this->feed_options );
246 if ( empty( $this->feed_options['feed_types_and_terms'] ) ) {
247 $this->feed_options['feed_types_and_terms'] = array();
248 }
249 $this->settings_filter->set_feed_type_and_terms( $this->feed_options['feed_types_and_terms'] );
250
251 $this->settings_filter->filter_feed_type_and_terms();
252
253 $this->feed_options = $this->settings_filter->get_settings();
254 $this->feed_options['feed_types_and_terms'] = $this->settings_filter->get_feed_type_and_terms();
255 }
256 }
257
258 /**
259 * uses the feed options to set the the tweets in the feed by using
260 * an existing set in a cache or by retrieving them from Twitter
261 */
262 protected function setTweetSet(){
263 $this->setTransientName();
264 if ( ! empty( $this->feed_options['feed'] ) ) {
265 $feed_id = $this->feed_options['feed'];
266 } else {
267 $feed_id = 'legacy';
268 }
269 if ( ! empty( $this->last_id_data ) ) {
270 $page = $this->last_id_data;
271 } else {
272 $page = '';
273 }
274 $this->cache = new CtfCache( $feed_id, $this->feed_options['cache_time'], $page );
275 if (! empty($this->raw_shortcode_atts['doingcronupdate'])) {
276 $this->maybeSetTweetsFromTwitter();
277 return;
278 }
279 $success = $this->maybeSetTweetsFromCache();
280
281 $is_persistent = $this->feed_options['persistentcache'] && ($this->feed_options['type'] == 'search' || $this->feed_options['type'] == 'hashtag');
282 if ( ! $success && ! $is_persistent) {
283 $this->maybeSetTweetsFromTwitter();
284 } elseif ( ! $success && $is_persistent ) {
285 $this->errors['error_message'] = 'No Tweets returned';
286 if (empty($this->api_obj)) {
287 $this->api_obj = new \stdClass();
288 }
289 $this
290 ->api_obj->api_error_no = '';
291 $this
292 ->api_obj->api_error_message = 'No Tweets returned';
293 $this->tweet_set = false;
294 }
295
296 $this->num_tweets_needed = $this->numTweetsNeeded();
297 }
298
299 /**
300 * the access token and secret must be set in order for the feed to work
301 * this function processes the user input and sets a flag if none are entered
302 */
303 private function setAccessTokenAndSecretOptions()
304 {
305 if ( CTF_DOING_SMASH_TWITTER ) {
306 $this->feed_options['access_token'] = 'missing';
307 $this->feed_options['access_token_secret'] = 'missing';
308
309 } else {
310 $this->feed_options['access_token'] = isset( $this->db_options['access_token'] ) && strlen( $this->db_options['access_token'] ) > 30 ? $this->db_options['access_token'] : 'missing';
311 $this->feed_options['access_token_secret'] = isset( $this->db_options['access_token_secret'] ) && strlen( $this->db_options['access_token_secret'] ) > 30 ? $this->db_options['access_token_secret'] : 'missing';
312
313 }
314
315 // verify that access token and secret have been entered
316 $this->setMissingCredentials();
317 }
318
319 /**
320 * generates the flag if there are missing access tokens
321 */
322 private function setMissingCredentials() {
323 if ( $this->feed_options['access_token'] == 'missing' || $this->feed_options['access_token_secret'] == 'missing' ) {
324 $this->missing_credentials = true;
325 } else {
326 $this->missing_credentials = false;
327 }
328 }
329
330 /**
331 * processes the consumer key and secret options
332 */
333 protected function setConsumerKeyAndSecretOptions(){
334 if (! empty( $this->db_options['consumer_key'] ) && ! empty($this->db_options['consumer_secret'] )) {
335 $this->feed_options['consumer_key'] = isset($this->db_options['consumer_key']) && strlen($this->db_options['consumer_key']) > 15 ? $this->db_options['consumer_key'] : '';
336 $this->feed_options['consumer_secret'] = isset($this->db_options['consumer_secret']) && strlen($this->db_options['consumer_secret']) > 30 ? $this->db_options['consumer_secret'] : '';
337 } else {
338 $this->feed_options['consumer_key'] = '';
339 $this->feed_options['consumer_secret'] = '';
340 }
341 }
342
343 /**
344 * determines what value to use and saves it for the appropriate key in the feed_options array
345 *
346 * @param $options mixed the key or array of keys to be set
347 * @param $options_page string options page this setting is set on
348 * @param string $default default value to use if there is no user input
349 */
350 public function setDatabaseOnlyOptions( $options, $default = '' )
351 {
352 if ( is_array( $options ) ) {
353 foreach ( $options as $option ) {
354 $this->feed_options[$option] = isset( $this->db_options[$option] ) && ! empty( $this->db_options[$option] ) ? $this->db_options[$option] : $default;
355 }
356 } else {
357 $this->feed_options[$options] = isset( $this->db_options[$options] ) && ! empty( $this->db_options[$options] ) ? $this->db_options[$options] : $default;
358 }
359 }
360
361 /**
362 * determines what value to use and saves it for the appropriate key in the feed_options array
363 *
364 * @param $options mixed the key or array of keys to be set
365 * @param $options_page string options page this setting is set on
366 * @param string $default default value to use if there is no user input
367 */
368 public function setStandardTextOptions( $options, $default = '' )
369 {
370 if ( is_array( $options ) ) {
371 foreach ( $options as $option ) {
372 $this->feed_options[$option] = isset( $this->atts[$option] ) ? esc_attr( __( $this->atts[$option], 'custom-twitter-feeds' ) ) : ( isset( $this->db_options[$option] ) ? esc_attr( $this->db_options[$option] ) : $default );
373 }
374 } else {
375 $this->feed_options[$options] = isset( $this->atts[$options] ) ? esc_attr( __( $this->atts[$options], 'custom-twitter-feeds' ) ) : ( isset( $this->db_options[$options] ) ? esc_attr( $this->db_options[$options] ) : $default );
376 }
377 }
378
379 /**
380 * creates the appropriate style attribute string for the text size setting
381 *
382 * @param $value mixed pixel size or other that the user has selected
383 * @return string string for the style attribute
384 */
385 public static function processTextSizeStyle( $value )
386 {
387 if ( $value == '' ) {
388 return '';
389 }
390 $processed_value = $value == 'inherit' ? '' : 'font-size: ' . $value . 'px;';
391
392 return $processed_value;
393 }
394
395 /**
396 * determines what value to use and saves it for the appropriate key in the feed_options array
397 *
398 * @param $options mixed the key or array of keys to be set
399 * @param string $default default value to use if there is no user input
400 */
401 public function setTextSizeOptions( $options, $default = '' )
402 {
403 if ( is_array( $options ) ) {
404 foreach ( $options as $option ) {
405 $this->feed_options[$option] = isset( $this->atts[$option] ) ? $this->processTextSizeStyle( esc_attr( $this->atts[$option] ) ) : ( isset( $this->db_options[$option] ) ? $this->processTextSizeStyle( esc_attr( $this->db_options[$option] ) ) : $default );
406 }
407 } else {
408 $this->feed_options[$options] = isset( $this->atts[$options] ) ? $this->processTextSizeStyle( esc_attr( $this->atts[$options] ) ) : ( isset( $this->db_options[$options] ) ? $this->processTextSizeStyle( esc_attr( $this->db_options[$options] ) ) : $default );
409 }
410 }
411
412 /**
413 * determines what value to use and saves it for the appropriate key in the feed_options array
414 *
415 * @param $options mixed the key or array of keys to be set
416 * @param $property string name of the property to be set
417 * @param string $default default value to use if there is no user input
418 */
419 public function setStandardStyleProperty( $options, $property, $default = '' )
420 {
421 if ( is_array( $options ) ) {
422 foreach ( $options as $option ) {
423 $this->feed_options[$option] = isset( $this->atts[$option] ) && $this->atts[$option] != 'inherit' ? $property . ': ' . esc_attr( $this->atts[$option] ) . ';' : ( isset( $this->db_options[$option] ) && $this->db_options[$option] != '#' && $this->db_options[$option] != '' && $this->db_options[$option] != 'inherit' ? $property . ': ' . esc_attr( $this->db_options[$option] ) . ';' : $default );
424 }
425 } else {
426 $this->feed_options[$options] = isset( $this->atts[$options] ) && $this->atts[$options] != 'inherit' ? $property . ': ' . esc_attr( $this->atts[$options] ) . ';' : ( isset( $this->db_options[$options] ) && $this->db_options[$options] != '#' && $this->db_options[$options] != '' && $this->db_options[$options] != 'inherit' ? $property . ': ' . esc_attr( $this->db_options[$options] ) . ';' : $default );
427 }
428 }
429
430 /**
431 * determines what value to use and saves it for the appropriate key in the feed_options array
432 *
433 * @param $options mixed the key or array of keys to be set
434 * @param bool|true $default default value to use if there is no user input
435 */
436 public function setStandardBoolOptions( $options, $default = true )
437 {
438 if ( is_array( $options ) ) {
439 foreach ( $options as $option ) {
440 $this->feed_options[$option] = isset( $this->atts[$option] ) ? ( $this->atts[$option] === 'true' ) : ( isset( $this->db_options[$option] ) ? (bool) $this->db_options[$option] : (bool) $default );
441 }
442 } else {
443 $this->feed_options[$options] = isset( $this->atts[$options] ) ? esc_attr( $this->atts[$options] ) : ( isset( $this->db_options[$options] ) ? esc_attr( $this->db_options[$options] ) : $default );
444 }
445 }
446
447 /**
448 * sets the width and height of the feed based on user input
449 */
450 public function setDimensionOptions(){
451 $this->feed_options['width'] = isset( $this->atts['width'] ) ? 'width: '. esc_attr( $this->atts['width'] ) .';' : ( ( isset( $this->db_options['width'] ) && $this->db_options['width'] != '' ) ? 'width: '. esc_attr( $this->db_options['width'] ) . ( isset( $this->db_options['width_unit'] ) ? esc_attr( $this->db_options['width_unit'] ) : '%' ) . ';' : '' );
452 $this->feed_options['height'] = isset( $this->atts['height'] ) ? 'height: '. esc_attr( $this->atts['height'] ) .';' : ( ( isset( $this->db_options['height'] ) && $this->db_options['height'] != '' ) ? 'height: '. esc_attr( $this->db_options['height'] ) . ( isset( $this->db_options['height_unit'] ) ? esc_attr( $this->db_options['height_unit'] ) : 'px' ) . ';' : '' );
453 }
454
455 /**
456 * sets the cache time based on user input
457 */
458 public function setCacheTimeOptions(){
459 if ( ! empty( $this->raw_shortcode_atts ) && ! empty( $this->raw_shortcode_atts['doingcronupdate'] ) ) {
460 $this->feed_options['cache_time'] = 60;
461 return;
462 }
463 $user_cache = isset($this->db_options['cache_time']) ? ((int)$this->db_options['cache_time'] * (int)$this->db_options['cache_time_unit']) : HOUR_IN_SECONDS;
464 $caching_type = ! empty( $this->db_options['ctf_caching_type'] ) ? $this->db_options['ctf_caching_type'] : 'page';
465 if ( empty( $this->raw_shortcode_atts['feed'] ) || $caching_type === 'page' ) {
466 $this->feed_options['cache_time'] = max($user_cache, 60);
467 } else {
468 $this->feed_options['cache_time'] = DAY_IN_SECONDS + HOUR_IN_SECONDS;
469 }
470 }
471
472
473 /**
474 * sets the number of tweets to retrieve
475 */
476 public function setTweetsToRetrieve(){
477 $min_tweets_to_retrieve = 10;
478
479 if ($this->num_needed_input < 1) {
480
481 if ($this->feed_options['num'] < 10) {
482 $count = max(round((int)$this->feed_options['num'] * (float)$this->feed_options['multiplier'] * 1.6) , $min_tweets_to_retrieve);
483 }
484 elseif ($this->feed_options['num'] < 30) {
485 $count = round((int)$this->feed_options['num'] * (float)$this->feed_options['multiplier'] * 1.2);
486 }
487 else {
488 $count = round((int)$this->feed_options['num'] * (float)$this->feed_options['multiplier']);
489 }
490 }
491 else {
492 $count = max($this->num_needed_input, 50);
493 $this->feed_options['num'] = $this->num_needed_input;
494 }
495
496 $this->feed_options['count'] = min($count, 200);
497
498 }
499
500 /**
501 * sets the feed type and associated parameter
502 */
503 public function setFeedTypeAndTermOptions(){
504 $this->feed_options['screenname'] = isset( $this->atts['screenname'] ) ? $this->atts['screenname'] : ( isset( $this->feed_options['usertimeline_text'] ) ? $this->feed_options['usertimeline_text'] : '' );
505
506 if ( isset( $this->atts['home'] ) && $this->atts['home'] == 'true' ) {
507 $this->feed_options['type'] = 'hometimeline';
508 }
509 if ( isset( $this->atts['screenname'] ) && !empty($this->atts['screenname'] )) {
510 $this->feed_options['type'] = 'usertimeline';
511 $this->feed_options['feed_term'] = isset( $this->atts['screenname'] ) ? ctf_validate_usertimeline_text( $this->atts['screenname'] ) : ( ( isset( $this->feed_options['usertimeline_text'] ) ) ? $this->feed_options['usertimeline_text'] : '' );
512 $this->feed_options['screenname'] = $this->feed_options['feed_term'];
513 }
514 if ( isset( $this->atts['hashtag'] ) && !empty($this->atts['hashtag'] )) {
515 $this->feed_options['type'] = 'hashtag';
516 $this->working_term = isset( $this->atts['hashtag'] ) ? $this->atts['hashtag'] : ( isset( $this->feed_options['hashtag'] ) ? $this->feed_options['hashtag'] : '' );
517 $this->feed_options['hashtag_text'] = $this->working_term;
518 $this->feed_options['feed_term'] = isset( $this->working_term ) ? ctf_validate_search_text( $this->working_term ) . ' -filter:retweets' : ( ( isset( $this->db_options['search_text'] ) ) ? $this->db_options['search_text'] . ' -filter:retweets' : '' );
519 $this->check_for_duplicates = true;
520 }
521
522 if ( empty($this->feed_options['type'])) {
523 $this->feed_options['type'] = isset( $this->atts['type'] ) ? $this->atts['type'] : 'usertimeline';
524 switch ( $this->feed_options['type'] ) {
525 case 'usertimeline':
526 $this->feed_options['feed_term'] = isset( $this->atts['usertimeline_text'] ) ? $this->atts['usertimeline_text'] : '';
527 break;
528 case 'hometimeline':
529 $this->feed_options['type'] = 'hometimeline';
530 break;
531 case 'hashtag':
532 $this->feed_options['feed_term'] = isset( $this->atts['search_text'] ) ? $this->atts['search_text'] . ' -filter:retweets' : '';
533 $this->check_for_duplicates = true;
534 break;
535 }
536 }
537 if($this->feed_options['type'] == 'usertimeline'){
538 $this->feed_options['feed_term'] = isset( $this->atts['screenname'] ) ? ctf_validate_usertimeline_text( $this->atts['screenname'] ) : ( ( isset( $this->feed_options['usertimeline_text'] ) ) ? $this->feed_options['usertimeline_text'] : '' );
539 $this->feed_options['usertimeline_text'] = $this->feed_options['feed_term'];
540 $this->feed_options['screenname'] = $this->feed_options['feed_term'];
541 }
542 $this->feed_options['includeretweets'] = true;
543
544 if($this->is_legacy && !empty($this->feed_options['type'])){
545 $this->feed_options['type'] = $this->feed_options['type'] == 'search' ? 'hashtag' : $this->feed_options['type'];
546 $this->set_legacy_terms_options();
547 }
548 }
549
550 public function set_legacy_terms_options(){
551 switch ($this->feed_options['type']) {
552 case 'usertimeline':
553 $this->feed_options['type'] = 'usertimeline';
554 $this->feed_options['feed_term'] = isset( $this->atts['screenname'] ) ? ctf_validate_usertimeline_text( $this->atts['screenname'] ) : ( ( isset( $this->feed_options['usertimeline_text'] ) ) ? $this->feed_options['usertimeline_text'] : '' );
555 $this->feed_options['screenname'] = $this->feed_options['feed_term'];
556 $this->feed_options['usertimeline_text'] = $this->feed_options['screenname'];
557 break;
558 case 'hometimeline':
559 $this->feed_options['type'] = 'hometimeline';
560 break;
561 case 'hashtag':
562 $this->feed_options['type'] = 'hashtag';
563 $this->working_term = isset( $this->atts['hashtag'] ) ? $this->atts['hashtag'] : ( isset( $this->feed_options['hashtag'] ) ? $this->feed_options['hashtag'] : '' );
564 $this->feed_options['hashtag_text'] = $this->working_term;
565 $this->feed_options['feed_term'] = isset( $this->working_term ) ? ctf_validate_search_text( $this->working_term ) . ' -filter:retweets' : ( ( isset( $this->db_options['search_text'] ) ) ? $this->db_options['search_text'] . ' -filter:retweets' : '' );
566 $this->check_for_duplicates = true;
567 $this->feed_options['persistentcache'] = true;
568 break;
569 }
570 }
571
572 /**
573 * sets the visible parts of each tweet for the feed
574 */
575 public function setIncludeExcludeOptions(){
576 $this->feed_options['tweet_includes'] = array();
577 $this->feed_options['tweet_excludes'] = array();
578 $this->feed_options['tweet_includes'] = isset($this->atts['include']) ? explode(',', str_replace(', ', ',', $this->atts['include'])) : array();
579 $legacy_atts_include = isset($this->raw_shortcode_atts['include']) ? explode(',', str_replace(', ', ',', $this->raw_shortcode_atts['include'])) : array();
580 $legacy_atts_exclude = isset($this->raw_shortcode_atts['exclude']) ? explode(',', str_replace(', ', ',', $this->raw_shortcode_atts['exclude'])) : array();
581 if ( ! empty( $legacy_atts_include ) ) {
582 if ( in_array( 'author', $legacy_atts_include, true ) ) {
583 $this->feed_options['tweet_includes'][] = 'author_text';
584 }
585 }
586 if ( ! empty( $legacy_atts_exclude ) ) {
587 if ( in_array( 'author', $legacy_atts_exclude, true ) ) {
588 $this->atts['exclude'] .= ',author_text';
589 }
590 }
591 if (empty($this->feed_options['tweet_includes'][0])) {
592 $this->feed_options['tweet_excludes'] = isset($this->atts['exclude']) ? explode(',', str_replace(', ', ',', $this->atts['exclude'])) : array();
593 }
594 if (empty($this->feed_options['tweet_excludes'][0]) && empty($this->feed_options['tweet_includes'][0])) {
595 $this->feed_options['tweet_includes'][] = isset($this->feed_options['include_retweeter']) && $this->feed_options['include_retweeter'] == false ? null : 'retweeter';
596 $this->feed_options['tweet_includes'][] = isset($this->feed_options['include_avatar']) && $this->feed_options['include_avatar'] == false ? null : 'avatar';
597 $this->feed_options['tweet_includes'][] = isset($this->feed_options['include_author']) && $this->feed_options['include_author'] == false ? null : 'author';
598 $this->feed_options['tweet_includes'][] = isset($this->feed_options['include_author_text']) && $this->feed_options['include_author_text'] == false ? null : 'author_text';
599
600 $this->feed_options['tweet_includes'][] = isset($this->feed_options['include_logo']) && $this->feed_options['include_logo'] == false ? null : 'logo';
601 $this->feed_options['tweet_includes'][] = isset($this->feed_options['include_text']) && $this->feed_options['include_text'] == false ? null : 'text';
602 $this->feed_options['tweet_includes'][] = isset($this->feed_options['include_date']) && $this->feed_options['include_date'] == false ? null : 'date';
603 $this->feed_options['tweet_includes'][] = isset($this->feed_options['include_actions']) && $this->feed_options['include_actions'] == false ? null : 'actions';
604 $this->feed_options['tweet_includes'][] = isset($this->feed_options['include_twitterlink']) && $this->feed_options['include_twitterlink'] == false ? null : 'twitterlink';
605 $this->feed_options['tweet_includes'][] = isset($this->feed_options['include_linkbox']) && $this->feed_options['include_linkbox'] == false ? null : 'linkbox';
606 $this->feed_options['tweet_includes'][] = isset($this->feed_options['include_replied_to']) && $this->feed_options['include_replied_to'] == false ? null : 'repliedto';
607 $this->feed_options['tweet_includes'][] = isset($this->feed_options['include_media']) && $this->feed_options['include_media'] == false ? null : 'media';
608 $this->feed_options['tweet_includes'][] = isset($this->feed_options['include_twittercards']) && $this->feed_options['include_twittercards'] == false ? null : 'twittercards';
609 }
610
611 }
612
613 /**
614 * sets the transient name for the caching system
615 */
616 public function setTransientName()
617 {
618 if ( CTF_DOING_SMASH_TWITTER ) {
619 if ( empty( $this->raw_shortcode_atts['is_legacy'] ) ) {
620 $this->transient_name = $this->feed_id;
621 return;
622 }
623
624 }
625 $this->transient_name = 'ctf____' . $this->last_id_data;
626
627 $last_id_data = substr($this->last_id_data, -5, 5);
628 if ( CTF_DOING_SMASH_TWITTER ) {
629 $last_id_data = '';
630 }
631 $num = isset($this->feed_options['num']) && !empty($this->feed_options['num']) ? $this->feed_options['num'] : 1;
632 $reply = $this->feed_options['includereplies'] === true ? 'r' : '';
633 $includewords = !empty($this->feed_options['includewords']) ? substr(str_replace(array(
634 ',',
635 ' '
636 ) , '', $this->feed_options['includewords']) , 0, 10) : '';
637 $excludewords = !empty($this->feed_options['excludewords']) ? substr(str_replace(array(
638 ',',
639 ' '
640 ) , '', $this->feed_options['excludewords']) , 0, 5) : '';
641 $noretweets = !$this->feed_options['includeretweets'] ? 'n' : '';
642 $remove_by_id_array = explode(',', str_replace(' ', '', $this->feed_options['remove_by_id']));
643 $remove_by_id_str = '';
644 $feedID = (!empty($this->atts['feedid'])) ? $this->atts['feedid'] . '_' : '';
645
646 if (!empty($remove_by_id_array)) {
647 foreach ($remove_by_id_array as $id) {
648 $remove_by_id_str .= substr($id, -3, 3);
649 }
650 }
651
652 switch ($this->feed_options['type']) {
653 case 'hometimeline':
654 $this->transient_name = 'ctf_' . $feedID . $last_id_data . 'home' . $num . $reply . $includewords . $remove_by_id_str . $excludewords . $noretweets;
655 break;
656 case 'usertimeline':
657 $screenname = isset($this->feed_options['screenname']) ? $this->feed_options['screenname'] : '';
658 $this->transient_name = substr('ctf__' . $feedID . $last_id_data . $screenname . $num . $reply . $includewords . $remove_by_id_str . $excludewords . $noretweets, 0, 45);
659 break;
660 case 'search':
661 $hashtag = isset($this->feed_options['feed_term']) ? $this->feed_options['feed_term'] : '';
662 $this->transient_name = substr('ctf_' . $feedID . $last_id_data . substr($hashtag, 0, 20) . $includewords . $num . $reply . $remove_by_id_str . $excludewords . $noretweets, 0, 45);
663 break;
664 case 'hashtag':
665 $hashtag = isset($this->feed_options['feed_term']) ? str_replace(' -filter:retweets', '', $this->feed_options['feed_term']) : '';
666 $this->transient_name = substr('ctf_' . $feedID . $last_id_data . substr($hashtag, 0, 20) . $includewords . $num . $reply . $remove_by_id_str . $excludewords . $noretweets, 0, 45);
667 break;
668 case 'mentionstimeline':
669 $this->transient_name = 'ctf_' . $feedID . $last_id_data . 'mentions' . $num . $includewords . $remove_by_id_str . $excludewords . $noretweets;
670 break;
671 case 'lists':
672 $list = isset($this->feed_options['feed_term']) ? $this->feed_options['feed_term'] : '';
673 $this->transient_name = substr('ctf_' . $feedID . $last_id_data . $list . $num . $reply . $includewords . $remove_by_id_str . $excludewords, 0, 45);
674 break;
675 default:
676 if (!empty($this->feed_options['feed_types_and_terms'])) {
677 $names = $this->feed_options['feed_types_and_terms'];
678 $working_name = '';
679 foreach ($names as $name) {
680 $working_name .= substr($name[1], 0, 3);
681 }
682 $this->transient_name = substr('ctf__' . $feedID . $last_id_data . $working_name . $num . $reply . $includewords . $remove_by_id_str . $excludewords . $noretweets, 0, 45);
683 break;
684 }
685
686 }
687 }
688
689 public function setCacheTypeOption() {
690 if (empty( $this->feed_options['persistentcache'] ) ) {
691 $this->feed_options['persistentcache'] = false;
692 return;
693 }
694 if ( $this->feed_options['persistentcache'] && ( $this->feed_options['type'] == 'search' || $this->feed_options['type'] == 'hashtag' ) ) {
695 $this->feed_options['persistentcache'] = true;
696 } else {
697 $this->feed_options['persistentcache'] = false;
698 }
699 }
700
701 /**
702 * checks the data available in the cache to make sure it seems to be valid
703 *
704 * @return bool|string false if the cache is valid, error otherwise
705 */
706 private function validateCache()
707 {
708 if ( isset( $this->transient_data[0] ) ) {
709 return false;
710 } else {
711 return 'invalid cache';
712 }
713 }
714
715 /**
716 * will use the cached data in the feed if data seems to be valid and user
717 * wants to use caching
718 *
719 * @return bool|mixed false if none is set, tweet set otherwise
720 */
721 public function maybeSetTweetsFromCache() {
722 if ( CTF_DOING_SMASH_TWITTER ) {
723 $feed_id = ! empty( $this->raw_shortcode_atts['feed'] ) ? $this->raw_shortcode_atts['feed'] : 1;
724 $cache_time = WEEK_IN_SECONDS;
725 if ( ! empty( $this->raw_shortcode_atts['is_legacy'] ) ) {
726 $cache_time = WEEK_IN_SECONDS;
727 }
728
729 $page = 0; // force to 0 for this type of use of the cache
730
731 if ( empty( $this->persistent_index ) || empty( $this->last_id_data ) ) {
732 $offset = false;
733 } else {
734 $offset = $this->persistent_index;
735 }
736
737 $repository = new \TwitterFeed\SmashTwitter\TweetRepository( $this->feed_options['feed_types_and_terms'], $this->transient_name, new \TwitterFeed\SmashTwitter\TweetAggregator(), new \TwitterFeed\CtfCache( $feed_id, $cache_time, $page ), new TweetSetModifier(), $this->error_report );
738 $found = $repository->paged_cache( $offset, $this->feed_options['num'] );
739
740 if ( ! $found ) {
741 $this->tweet_set = array();
742 } else {
743 $this->tweet_set = $repository->get_tweets();
744
745 $this->tweet_set = $this->filterTweetSet($this->tweet_set, false);
746 }
747
748 return $this->tweet_set;
749 }
750 if ($this->feed_options['persistentcache'] && ($this->feed_options['type'] == 'search' || $this->feed_options['type'] == 'hashtag')) {
751 $persistent_cache_tweets = $this->persistentCacheTweets();
752 if (is_array($persistent_cache_tweets)) {
753 $this->transient_data = array_slice($persistent_cache_tweets, ($this->persistent_index - $this->feed_options['num'] - 1) , $this->persistent_index);
754 }
755 else {
756 $this->transient_data = $persistent_cache_tweets;
757 }
758 }
759 else {
760 $this->transient_data = $this->cache->get_transient($this->transient_name);
761 if (!is_array($this->transient_data)) {
762 $this->transient_data = json_decode($this->transient_data, $assoc = true);
763 }
764
765 if ($this->feed_options['cache_time'] <= 0) {
766 return $this->tweet_set = false;
767 }
768 }
769 // validate the transient data
770 if ($this->transient_data) {
771
772 if ( is_array( $this->transient_data ) && ! empty( $this->transient_data[0] ) && $this->transient_data[0] === 'error' ) {
773 $this->tweet_set = array();
774 return true;
775 }
776
777 $this->errors['cache_status'] = $this->validateCache();
778 if ($this->errors['cache_status'] === false) {
779 return $this->tweet_set = $this->transient_data;
780 }
781 else {
782 return $this->tweet_set = false;
783 }
784 }
785 else {
786 $this->errors['cache_status'] = 'none found';
787 return $this->tweet_set = false;
788 }
789 }
790
791 private function persistentCacheTweets() {
792 // if cache exists get cached data
793 $includewords = !empty($this->feed_options['includewords']) ? substr(str_replace(array(
794 ',',
795 ' '
796 ) , '', $this->feed_options['includewords']) , 0, 10) : '';
797 $excludewords = !empty($this->feed_options['excludewords']) ? substr(str_replace(array(
798 ',',
799 ' '
800 ) , '', $this->feed_options['excludewords']) , 0, 5) : '';
801 $feedID = (!empty($this->atts['feedid'])) ? $this->atts['feedid'] . '_' : '';
802 $cache_name = substr('ctf_!_' . $feedID . $this->feed_options['feed_term'] . $includewords . $excludewords, 0, 45);
803 if ($this->feed_options['type'] === 'hashtag') {
804 $cache_name = str_replace(' -filter:retweets', '', $cache_name);
805 }
806 $cache_time_limit_reached = $this->cache->get_transient($cache_name) ? false : true;
807
808 $existing_cache = $this->cache->get_persistent( $cache_name );
809
810 if ($existing_cache && !is_array($existing_cache)) {
811 $existing_cache = json_decode($existing_cache, $assoc = true);
812 }
813
814 $this->persistent_index = (int)$this->persistent_index + (int)$this->feed_options['num'];
815
816 $this->feed_options['count'] = 200;
817
818 if (!empty($this->last_id_data) || (!$cache_time_limit_reached && $existing_cache !== false)) {
819 return $existing_cache;
820 }
821 elseif ($existing_cache) {
822 // use "since-id" to look for more in an api request
823 $since_id = $existing_cache[0]['id_str'];
824 $api_obj = $this->getTweetsSinceID($since_id, 'search', $this->feed_options['feed_term'], $this->feed_options['count']);
825 // add any new tweets to the cache
826 $tweet_set = json_decode($api_obj->json, $assoc = true);
827
828 $tweet_set = isset($tweet_set['statuses']) ? $tweet_set['statuses'] : array();
829
830 // add a transient to delay another api retrieval
831 $this->cache->set_transient($cache_name, true, $this->feed_options['cache_time']);
832
833 if (empty($tweet_set)) {
834 $existing_cache = $this->filterTweetSet($existing_cache, false);
835 $cache_set = json_encode($existing_cache);
836
837 $this->cache->set_persistent($cache_name, $cache_set );
838 return $existing_cache;
839 }
840 else {
841 $tweet_set = $this->reduceTweetSetData($tweet_set, false);
842 }
843
844 $tweet_set = $this->appendPersistentCacheTweets($existing_cache, $tweet_set);
845 $tweet_set = $this->filterTweetSet($tweet_set, false);
846
847 $cache_set = json_encode($tweet_set);
848
849 $this->cache->set_persistent($cache_name, $cache_set );
850
851 return $tweet_set;
852 // else if cached data doesn't exist
853
854 }
855 else {
856 // make a request for last 200 tweets
857 $api_obj = $this->apiConnect('search', $this->feed_options['feed_term']);
858 // cache them in a regular option
859 $this->tweet_set = json_decode($api_obj->json, $assoc = true);
860
861 // check for errors/tweets present
862 if (isset($this->tweet_set['errors'][0])) {
863 if (empty($this->api_obj)) {
864 $this->api_obj = new \stdClass();
865 }
866 $this
867 ->api_obj->api_error_no = $this->tweet_set['errors'][0]['code'];
868 $this
869 ->api_obj->api_error_message = $this->tweet_set['errors'][0]['message'];
870
871 $this->tweet_set = false;
872 }
873
874 $tweets = isset($this->tweet_set['statuses']) ? $this->tweet_set['statuses'] : $this->tweet_set;
875
876 if (empty($tweets)) {
877 $this->errors['error_message'] = 'No Tweets returned';
878 $this->tweet_set = false;
879 }
880 else {
881 $this->tweet_set = $this->reduceTweetSetData($tweets, false);
882 }
883
884 if ( empty( $this->tweet_set ) ) {
885 $this->tweet_set = array();
886 }
887
888 $tweet_set = json_encode($this->tweet_set);
889 // create a new persistent cache
890 $this->cache->set_persistent( $cache_name, $tweet_set );
891
892 // update list of persistent cache
893 $cache_list = get_option('ctf_cache_list', array());
894
895 $cache_list[] = $cache_name;
896
897 update_option('ctf_cache_list', $cache_list, false);
898
899 return $this->tweet_set;
900 }
901
902 // add the search parameter to another option that contains a list of all persistent caches available
903
904 }
905
906 /**
907 * a check to see if any of the filtering options for the feed are set
908 *
909 * @return bool whether or not a filter is used for this feed
910 */
911 private function hasTweetTextFilter() {
912 if (!empty($this->feed_options['includewords']) || !empty($this->feed_options['excludewords'])) {
913 return true;
914 }
915 elseif (!empty($this->feed_options['remove_by_id']) || !$this->feed_options['includeretweets']) {
916 return true;
917 }
918 else {
919 return false;
920 }
921 }
922
923 private function reduceTweetSetData( $tweet_set, $limit = true ) {
924 if ($this->hasTweetTextFilter() || !$this->feed_options['includereplies']) {
925 $tweet_set = $this->filterTweetSet($tweet_set, $limit);
926 }
927 if ( $this->check_for_duplicates ) {
928 $this->tweet_set = $this->removeDuplicates( $tweet_set, $limit );
929 }
930
931 if ( $this->feed_options['selfreplies'] ) {
932 $this->tweet_set = $this->filterTweetSet( $tweet_set, $limit );
933 }
934
935 $this->tweet_set = $tweet_set;
936 if (isset($tweet_set[0]['created_at'])) {
937 $this->tweet_set = CTF_Feed::reduceTweetSetData($tweet_set);
938 return $this->tweet_set;
939 }
940 else {
941 return false;
942 }
943 //$this->trimTweetData( false );
944 //return $this->tweet_set;
945 }
946
947 /**
948 * this takes the current set of tweets and processes them until there are
949 * enough filtered tweets to create the feed from
950 */
951 private function filterTweetSet( $tweet_set, $limit = true ){
952 $working_tweet_set = isset( $tweet_set['statuses'] ) ? $tweet_set['statuses'] : $tweet_set;
953 $usable_tweets = 0;
954 if ( $limit ) {
955 $tweets_needed = $this->feed_options['count'] + 1; // magic number here should be ADT
956 } else {
957 $tweets_needed = 200;
958 }
959 $this->feed_options['selfreplies'] = false;
960 $i = 0; // index of working_tweet_set
961 $still_setting_filtered_tweets = true;
962 while ( $still_setting_filtered_tweets ) { // stays true until the number to display is reached or out of tweets
963 if ( isset ( $working_tweet_set[$i] ) ) { // if there is another tweet available
964 $retweet_id = isset($working_tweet_set[$i]['retweeted_status']['id_str']) ? $working_tweet_set[$i]['retweeted_status']['id_str'] : '';
965 if (!empty($retweet_id) && !$this->feed_options['includeretweets']) {
966 unset($working_tweet_set[$i]);
967 }
968
969 if ( !$this->feed_options['selfreplies'] && isset( $working_tweet_set[$i]['in_reply_to_screen_name'] ) ) {
970 unset( $working_tweet_set[$i] );
971 }
972 if ( $this->feed_options['selfreplies'] && isset( $working_tweet_set[$i]['in_reply_to_screen_name'] ) && $working_tweet_set[$i]['in_reply_to_screen_name'] !== $working_tweet_set[$i]['user']['screen_name']) {
973 unset( $working_tweet_set[$i] );
974 } else {
975 $usable_tweets++;
976 }
977 } else {
978 $still_setting_filtered_tweets = false;
979 }
980
981 // if there are no more tweets needed
982 if ( $usable_tweets >= $tweets_needed ) {
983 $still_setting_filtered_tweets = false;
984 } else {
985 $i++;
986 }
987
988 }
989
990 if ( CTF_DOING_SMASH_TWITTER ) {
991 $filterer = new TweetFilterer();
992
993 $working_tweet_set = $filterer->maybe_filter_for_timeline( $working_tweet_set, $this );
994 }
995
996 if ( is_array( $working_tweet_set ) ) {
997 return array_values( $working_tweet_set );
998 } else {
999 return false;
1000 }
1001 }
1002
1003 private function appendPersistentCacheTweets( $existing_cache )
1004 {
1005 if ( is_array( $this->tweet_set ) ) {
1006 $tweet_set = array_merge( $this->tweet_set, $existing_cache );
1007 } else {
1008 $tweet_set = $existing_cache;
1009 }
1010
1011 $tweet_set = array_slice( $tweet_set, 0, 150 );
1012
1013 return $tweet_set;
1014 }
1015
1016
1017 private function removeDuplicates( $tweet_set, $limit = true )
1018 {
1019 $tweet_set = isset( $tweet_set['statuses'] ) ? $tweet_set['statuses'] : $tweet_set;
1020 $usable_tweets = 0;
1021 if ( $limit ) {
1022 $tweets_needed = $this->feed_options['count'] + 1; // magic number here should be ADT
1023 } else {
1024 $tweets_needed = 200;
1025 }
1026 $ids_of_tweets_to_remove = array();
1027
1028 $i = 0; // index of tweet_set
1029 $still_setting_filtered_tweets = true;
1030 while ( $still_setting_filtered_tweets ) { // stays true until the number to display is reached or out of tweets
1031 if ( isset( $tweet_set[$i]['retweeted_status']['id_str'] ) ) {
1032 unset( $tweet_set[$i] );
1033 } elseif ( isset( $tweet_set[$i] ) ) {
1034 $id = isset( $tweet_set[$i]['retweeted_status']['id_str'] ) ? $tweet_set[$i]['retweeted_status']['id_str'] : $tweet_set[$i]['id_str'];
1035 if ( in_array( $id, $ids_of_tweets_to_remove ) ) {
1036 unset( $tweet_set[$i] );
1037 } else {
1038 $usable_tweets++;
1039 $ids_of_tweets_to_remove[] = $id;
1040 }
1041 } else {
1042 $still_setting_filtered_tweets = false;
1043 }
1044
1045 // if there are no more tweets needed
1046 if ( $usable_tweets >= $tweets_needed ) {
1047 $still_setting_filtered_tweets = false;
1048 } else {
1049 $i++;
1050 }
1051
1052 }
1053
1054 if ( is_array( $tweet_set ) ) {
1055 return array_values( $tweet_set );
1056 } else {
1057 return false;
1058 }
1059 }
1060
1061 /**
1062 * will attempt to connect to the api to retrieve current tweets
1063 */
1064 public function maybeSetTweetsFromTwitter() {
1065 $this->setTweetsToRetrieve();
1066 if ( CTF_DOING_SMASH_TWITTER ) {
1067 $feed_id = ! empty( $this->raw_shortcode_atts['feed'] ) ? $this->raw_shortcode_atts['feed'] : 1;
1068 $cache_time = WEEK_IN_SECONDS;
1069 if ( ! empty( $this->raw_shortcode_atts['is_legacy'] ) ) {
1070 $cache_time = WEEK_IN_SECONDS;
1071 }
1072 $page = 0; // force to 0 for this type of use of the cache
1073
1074 if ( empty( $this->persistent_index ) || empty( $this->last_id_data ) ) {
1075 $offset = false;
1076 } else {
1077 $this->tweet_set = false;
1078 return;
1079 }
1080
1081 $repository = new \TwitterFeed\SmashTwitter\TweetRepository( $this->feed_options['feed_types_and_terms'], $this->transient_name, new \TwitterFeed\SmashTwitter\TweetAggregator(), new \TwitterFeed\CtfCache( $feed_id, $cache_time, $page ), new TweetSetModifier(), $this->error_report );
1082
1083 $doing_cron_update = ! empty( $this->raw_shortcode_atts['doingcronupdate'] );
1084
1085 $repository->get_set_cache( $doing_cron_update );
1086 $this->tweet_set = $repository->get_tweets();
1087
1088 if ( empty( $this->tweet_set ) ) {
1089 $this->error_report->process_error( 'no_tweets_found', true );
1090 }
1091
1092 $this->tweet_set = $this->filterTweetSet($this->tweet_set, false);
1093
1094 if ( empty( $this->tweet_set ) ) {
1095 $this->error_report->process_error( 'too_much_filtering', true );
1096 }
1097
1098 return;
1099 } else {
1100 $this->api_obj = $this->apiConnect($this->feed_options['type'], !empty($this->feed_options['feed_term']) ? $this->feed_options['feed_term'] : $this->feed_options['screenname']);
1101 $json_array = json_decode($this->api_obj->json, $assoc = true);
1102 $this->tweet_set = isset($json_array['data']) && is_array($json_array['data']) ? $json_array['data'] : $json_array;
1103 }
1104
1105 // check for errors/tweets present
1106 if ( $this->tweet_set['title'] === 'Too Many Requests' ) {
1107 $this->error_report->process_error( 'too_many_requests' );
1108 $this->tweet_set = array();
1109 }
1110
1111 if (isset($this->tweet_set['errors'][0])) {
1112 if (empty($this->api_obj)) {
1113 $this->api_obj = new \stdClass();
1114 }
1115 $this
1116 ->api_obj->api_error_no = $this->tweet_set['errors'][0]['code'];
1117 $this
1118 ->api_obj->api_error_message = $this->tweet_set['errors'][0]['message'];
1119 }
1120
1121 $tweets = isset($this->tweet_set['statuses']) ? $this->tweet_set['statuses'] : $this->tweet_set;
1122 if (empty($tweets)) {
1123 if ( empty( $this->tweet_set['errors'][0]['message'] ) ) {
1124 $this->errors['error_message'] = 'No Tweets returned';
1125 $this->tweet_set = array();
1126 }
1127
1128 } elseif ( !empty( $this->tweet_set['errors'][0]['message'] ) ) {
1129
1130 } else {
1131 $this->tweet_set = $this->reduceTweetSetData($tweets);
1132 }
1133 }
1134 /**
1135 * calculates how many tweets short the feed is so more can be retrieved via ajax
1136 *
1137 * @return int number of tweets needed
1138 */
1139 protected function numTweetsNeeded() {
1140 $tweet_count = 0;
1141 if ( isset( $this->tweet_set['statuses'] ) && is_array( $this->tweet_set['statuses'] ) ) {
1142 $tweet_count = count( $this->tweet_set['statuses'] );
1143 } elseif ( isset( $this->tweet_set ) && is_array( $this->tweet_set ) ) {
1144 $tweet_count = count( $this->tweet_set );
1145 }
1146
1147 return $this->feed_options['num'] - $tweet_count;
1148 }
1149
1150 /**
1151 * trims the unused data retrieved for more efficient caching
1152 */
1153 protected function trimTweetData( $limit = true )
1154 {
1155 $is_pagination = !empty( $this->last_id_data ) ? 1 : 0;
1156 $tweets = isset( $this->tweet_set['statuses'] ) ? $this->tweet_set['statuses'] : $this->tweet_set;
1157 if ( $limit ) {
1158 $len = min( $this->feed_options['num'] + $is_pagination, count( $tweets ) );
1159 } else {
1160 $len = count( $tweets );
1161 }
1162 $trimmed_tweets = array();
1163
1164 // for header
1165 if ( isset( $tweets[0] ) ) { // if this is the first set of tweets
1166 $trimmed_tweets[0]['user']['name']= $tweets[0]['user']['name'];
1167 //$trimmed_tweets[0]['user']['description']= $tweets[0]['user']['description'];
1168 //$trimmed_tweets[0]['user']['statuses_count']= $tweets[0]['user']['statuses_count'];
1169 //$trimmed_tweets[0]['user']['followers_count']= $tweets[0]['user']['followers_count'];
1170 }
1171
1172 for ( $i = 0; $i < $len; $i++ ) {
1173 $trimmed_tweets[$i]['user']['name'] = $tweets[$i]['user']['name'];
1174 $trimmed_tweets[$i]['user']['screen_name'] = $tweets[$i]['user']['screen_name'];
1175 $trimmed_tweets[$i]['user']['verified'] = $tweets[$i]['user']['verified'];
1176 $trimmed_tweets[$i]['user']['profile_image_url_https'] = $tweets[$i]['user']['profile_image_url_https'];
1177 $trimmed_tweets[$i]['user']['utc_offset']= $tweets[$i]['user']['utc_offset'];
1178 $trimmed_tweets[$i]['text'] = isset( $tweets[$i]['text'] ) ? $tweets[$i]['text'] : $tweets[$i]['full_text'];
1179 $trimmed_tweets[$i]['id_str']= $tweets[$i]['id_str'];
1180 $trimmed_tweets[$i]['created_at']= $tweets[$i]['created_at'];
1181 $trimmed_tweets[$i]['retweet_count']= $tweets[$i]['retweet_count'];
1182 $trimmed_tweets[$i]['favorite_count']= $tweets[$i]['favorite_count'];
1183
1184 if ( isset( $tweets[$i]['entities']['urls'][0] ) ) {
1185 foreach ( $tweets[$i]['entities']['urls'] as $url ) {
1186 $trimmed_tweets[$i]['entities']['urls'][] = array(
1187 'url' => $url['url'],
1188 'expanded_url' => $url['expanded_url'],
1189 'display_url' => $url['display_url'],
1190
1191 );
1192 }
1193 }
1194
1195 if ( isset( $tweets[$i]['retweeted_status'] ) ) {
1196 $trimmed_tweets[$i]['retweeted_status']['user']['name'] = $tweets[$i]['retweeted_status']['user']['name'];
1197 $trimmed_tweets[$i]['retweeted_status']['user']['screen_name'] = $tweets[$i]['retweeted_status']['user']['screen_name'];
1198 $trimmed_tweets[$i]['retweeted_status']['user']['verified'] = $tweets[$i]['retweeted_status']['user']['verified'];
1199 $trimmed_tweets[$i]['retweeted_status']['user']['profile_image_url_https'] = $tweets[$i]['retweeted_status']['user']['profile_image_url_https'];
1200 $trimmed_tweets[$i]['retweeted_status']['user']['utc_offset']= $tweets[$i]['retweeted_status']['user']['utc_offset'];
1201 $trimmed_tweets[$i]['retweeted_status']['text'] = isset( $tweets[$i]['retweeted_status']['text'] ) ? $tweets[$i]['retweeted_status']['text'] : $tweets[$i]['retweeted_status']['full_text'];
1202 $trimmed_tweets[$i]['retweeted_status']['id_str'] = $tweets[$i]['retweeted_status']['id_str'];
1203 $trimmed_tweets[$i]['retweeted_status']['created_at']= $tweets[$i]['retweeted_status']['created_at'];
1204 $trimmed_tweets[$i]['retweeted_status']['retweet_count']= $tweets[$i]['retweeted_status']['retweet_count'];
1205 $trimmed_tweets[$i]['retweeted_status']['favorite_count']= $tweets[$i]['retweeted_status']['favorite_count'];
1206 if ( isset( $tweets[$i]['retweeted_status']['entities']['urls'][0] ) ) {
1207 foreach ( $tweets[$i]['retweeted_status']['entities']['urls'] as $url ) {
1208 $trimmed_tweets[$i]['retweeted_status']['entities']['urls'][] = array(
1209 'url' => $url['url'],
1210 'expanded_url' => $url['expanded_url'],
1211 'display_url' => $url['display_url'],
1212
1213 );
1214 }
1215 }
1216 }
1217
1218 if ( isset( $tweets[$i]['retweeted_status']['quoted_status'] ) ) {
1219 $trimmed_tweets[$i]['retweeted_status']['quoted_status']['user']['name'] = $tweets[$i]['retweeted_status']['quoted_status']['user']['name'];
1220 $trimmed_tweets[$i]['retweeted_status']['quoted_status']['user']['screen_name'] = $tweets[$i]['retweeted_status']['quoted_status']['user']['screen_name'];
1221 $trimmed_tweets[$i]['retweeted_status']['quoted_status']['user']['verified'] = $tweets[$i]['retweeted_status']['quoted_status']['user']['verified'];
1222 $trimmed_tweets[$i]['retweeted_status']['quoted_status']['text'] = isset( $tweets[$i]['retweeted_status']['quoted_status']['text'] ) ? $tweets[$i]['retweeted_status']['quoted_status']['text'] : $tweets[$i]['retweeted_status']['quoted_status']['full_text'];
1223 $trimmed_tweets[$i]['retweeted_status']['quoted_status']['id_str'] = $tweets[$i]['retweeted_status']['quoted_status']['id_str'];
1224 if ( isset( $tweets[$i]['retweeted_status']['quoted_status']['entities']['urls'][0] ) ) {
1225 foreach ( $tweets[$i]['retweeted_status']['quoted_status']['entities']['urls'] as $url ) {
1226 $trimmed_tweets[$i]['retweeted_status']['quoted_status']['entities']['urls'][] = array(
1227 'url' => $url['url'],
1228 'expanded_url' => $url['expanded_url'],
1229 'display_url' => $url['display_url'],
1230 );
1231 }
1232 }
1233 }
1234
1235 if ( isset( $tweets[$i]['quoted_status'] ) ) {
1236 $trimmed_tweets[$i]['quoted_status']['user']['name'] = $tweets[$i]['quoted_status']['user']['name'];
1237 $trimmed_tweets[$i]['quoted_status']['user']['screen_name'] = $tweets[$i]['quoted_status']['user']['screen_name'];
1238 $trimmed_tweets[$i]['quoted_status']['user']['verified'] = $tweets[$i]['quoted_status']['user']['verified'];
1239 $trimmed_tweets[$i]['quoted_status']['text'] = isset( $tweets[$i]['quoted_status']['text'] ) ? $tweets[$i]['quoted_status']['text'] : $tweets[$i]['quoted_status']['full_text'];
1240 $trimmed_tweets[$i]['quoted_status']['id_str'] = $tweets[$i]['quoted_status']['id_str'];
1241 if ( isset( $tweets[$i]['quoted_status']['entities']['urls'][0] ) ) {
1242 foreach ( $tweets[$i]['quoted_status']['entities']['urls'] as $url ) {
1243 $trimmed_tweets[$i]['quoted_status']['entities']['urls'][] = array(
1244 'url' => $url['url'],
1245 'expanded_url' => $url['expanded_url'],
1246 'display_url' => $url['display_url'],
1247 );
1248 }
1249 }
1250 }
1251
1252 $trimmed_tweets[$i] = $this->filterTrimmedTweets( $trimmed_tweets[$i], $tweets[$i] );
1253 }
1254
1255 $this->tweet_set = $trimmed_tweets;
1256 }
1257
1258 protected function removeStringFromText( $string, $text) {
1259 return str_replace( $string, '', $text );
1260 }
1261
1262 /**
1263 * captures additional data for "Pro" features
1264 *
1265 * @param $trimmed array current set of trimmed tweets
1266 * @param $tweet array raw tweet data from api
1267 * @return array
1268 */
1269 protected function filterTrimmedTweets( $trimmed, $tweet )
1270 {
1271 if ( isset( $tweet['in_reply_to_screen_name'] ) ) {
1272 $trimmed['in_reply_to_screen_name'] = $tweet['in_reply_to_screen_name'];
1273 $trimmed['entities']['user_mentions'][0]['name'] = isset( $tweet['entities']['user_mentions'][0]['name'] ) ? $tweet['entities']['user_mentions'][0]['name'] : '';
1274 $trimmed['in_reply_to_status_id_str'] = $tweet['in_reply_to_status_id_str'];
1275 }
1276
1277 if ( isset( $tweet['extended_entities']['media'] ) ) {
1278 // if there is media, we need to remove the media url from the tweet text
1279 $text = isset( $tweet['full_text'] ) ? $tweet['full_text'] : $tweet['text'];
1280 if ( isset( $tweet['extended_entities']['media'][0]['url'] ) ) {
1281 $trimmed['text'] = $this->removeStringFromText( $tweet['extended_entities']['media'][0]['url'], $text );
1282 }
1283 $num_media = count( $tweet['extended_entities']['media'] );
1284 for ( $i = 0; $i < $num_media; $i++ ) {
1285 $trimmed['extended_entities']['media'][$i]['media_url_https'] = $tweet['extended_entities']['media'][$i]['media_url_https'];
1286 $trimmed['extended_entities']['media'][$i]['type'] = $tweet['extended_entities']['media'][$i]['type'];
1287 if ( isset( $tweet['extended_entities']['media'][$i]['sizes'] ) ) {
1288 $trimmed['extended_entities']['media'][$i]['sizes'] = $tweet['extended_entities']['media'][$i]['sizes'];
1289 }
1290 if ( $tweet['extended_entities']['media'][$i]['type'] == 'video' || $tweet['extended_entities']['media'][$i]['type'] == 'animated_gif' ) {
1291 foreach ( $tweet['extended_entities']['media'][$i]['video_info']['variants'] as $variant ) {
1292 if ( isset( $variant['content_type'] ) && $variant['content_type'] == 'video/mp4' ) {
1293 $trimmed['extended_entities']['media'][$i]['video_info']['variants'][$i]['url'] = $variant['url'];
1294 }
1295 }
1296 if ( ! isset( $trimmed['extended_entities']['media'][$i]['video_info']['variants'][$i]['url'] ) ) {
1297 $trimmed['extended_entities']['media'][$i]['video_info']['variants'][$i]['url'] = $tweet['extended_entities']['media'][$i]['video_info']['variants'][0]['url'];
1298 }
1299 }
1300 }
1301
1302 } elseif ( isset( $tweet['entities']['media'] ) ) {
1303 // if there is media, we need to remove the media url from the tweet text
1304 $text = isset( $tweet['full_text'] ) ? $tweet['full_text'] : $tweet['text'];
1305 if ( isset( $tweet['entities']['media'][0]['url'] ) ) {
1306 $trimmed['text'] = $this->removeStringFromText( $tweet['entities']['media'][0]['url'], $text );
1307 }
1308
1309 $num_media = count( $tweet['entities']['media'] );
1310 for ( $i = 0; $i < $num_media; $i++ ) {
1311 $trimmed['entities']['media'][$i]['media_url_https'] = $tweet['entities']['media'][$i]['media_url_https'];
1312 $trimmed['entities']['media'][$i]['type'] = $tweet['entities']['media'][$i]['type'];
1313 if ( isset( $tweet['entities']['media'][$i]['sizes'] ) ) {
1314 $trimmed['entities']['media'][$i]['sizes'] = $tweet['entities']['media'][$i]['sizes'];
1315 }
1316 if ( $tweet['entities']['media'][$i]['type'] == 'video' || $tweet['entities']['media'][$i]['type'] == 'animated_gif' ) {
1317 foreach ( $tweet['entities']['media'][$i]['video_info']['variants'] as $variant ) {
1318 if ( isset( $variant['content_type'] ) && $variant['content_type'] == 'video/mp4' ) {
1319 $trimmed['entities']['media'][$i]['video_info']['variants'][$i]['url'] = $variant['url'];
1320 }
1321 }
1322 if ( ! isset( $trimmed['entities']['media'][$i]['video_info']['variants'][$i]['url'] ) ) {
1323 $trimmed['entities']['media'][$i]['video_info']['variants'][$i]['url'] = $tweet['entities']['media'][$i]['video_info']['variants'][0]['url'];
1324 }
1325 }
1326 }
1327
1328 }
1329
1330 if ( isset( $tweet['retweeted_status']['extended_entities']['media'] ) ) {
1331 // if there is media, we need to remove the media url from the tweet text
1332 $retweeted_text = isset( $tweet['retweeted_status']['full_text'] ) ? $tweet['retweeted_status']['full_text'] : $tweet['retweeted_status']['text'];
1333 if ( isset( $tweet['retweeted_status']['extended_entities']['media'][0]['url'] ) ) {
1334 $trimmed['retweeted_status']['text'] = $this->removeStringFromText( $tweet['retweeted_status']['extended_entities']['media'][0]['url'], $retweeted_text );
1335 }
1336
1337 $num_media = count( $tweet['retweeted_status']['extended_entities']['media'] );
1338 for ( $i = 0; $i < $num_media; $i++ ) {
1339 $trimmed['retweeted_status']['extended_entities']['media'][$i]['media_url_https'] = $tweet['retweeted_status']['extended_entities']['media'][$i]['media_url_https'];
1340 $trimmed['retweeted_status']['extended_entities']['media'][$i]['type'] = $tweet['retweeted_status']['extended_entities']['media'][$i]['type'];
1341 if ( isset( $tweet['retweeted_status']['extended_entities']['media'][$i]['sizes'] ) ) {
1342 $trimmed['retweeted_status']['extended_entities']['media'][$i]['sizes'] = $tweet['retweeted_status']['extended_entities']['media'][$i]['sizes'];
1343 }
1344 if ( $tweet['retweeted_status']['extended_entities']['media'][$i]['type'] == 'video' || $tweet['retweeted_status']['extended_entities']['media'][$i]['type'] == 'animated_gif' ) {
1345 foreach ( $tweet['retweeted_status']['extended_entities']['media'][$i]['video_info']['variants'] as $variant ) {
1346 if ( isset( $variant['content_type'] ) && $variant['content_type'] == 'video/mp4' ) {
1347 $trimmed['retweeted_status']['extended_entities']['media'][$i]['video_info']['variants'][$i]['url'] = $variant['url'];
1348 }
1349 }
1350 if ( ! isset( $trimmed['retweeted_status']['extended_entities']['media'][$i]['video_info']['variants'][$i]['url'] ) ) {
1351 $trimmed['retweeted_status']['extended_entities']['media'][$i]['video_info']['variants'][$i]['url'] = $tweet['retweeted_status']['extended_entities']['media'][$i]['video_info']['variants'][0]['url'];
1352 }
1353 }
1354 }
1355
1356 } elseif ( isset( $tweet['retweeted_status']['entities']['media'] ) ) {
1357 // if there is media, we need to remove the media url from the tweet text
1358 $retweeted_text = isset( $tweet['retweeted_status']['full_text'] ) ? $tweet['retweeted_status']['full_text'] : $tweet['retweeted_status']['text'];
1359 if ( isset( $tweet['retweeted_status']['entities']['media'][0]['url'] ) ) {
1360 $trimmed['retweeted_status']['text'] = $this->removeStringFromText( $tweet['retweeted_status']['entities']['media'][0]['url'], $retweeted_text );
1361 }
1362
1363 $num_media = count( $tweet['retweeted_status']['entities']['media'] );
1364 for( $i = 0; $i < $num_media; $i++ ) {
1365 $trimmed['retweeted_status']['entities']['media'][$i]['media_url_https'] = $tweet['retweeted_status']['entities']['media'][$i]['media_url_https'];
1366 $trimmed['retweeted_status']['entities']['media'][$i]['type'] = $tweet['retweeted_status']['entities']['media'][$i]['type'];
1367 if ( isset( $tweet['retweeted_status']['entities']['media'][$i]['sizes'] ) ) {
1368 $trimmed['retweeted_status']['entities']['media'][$i]['sizes'] = $tweet['retweeted_status']['entities']['media'][$i]['sizes'];
1369 }
1370 if ( $tweet['retweeted_status']['entities']['media'][$i]['type'] == 'video' || $tweet['retweeted_status']['entities']['media'][$i]['type'] == 'animated_gif' ) {
1371 foreach ( $tweet['retweeted_status']['entities']['media'][$i]['video_info']['variants'] as $variant ) {
1372 if ( isset( $variant['content_type'] ) && $variant['content_type'] == 'video/mp4' ) {
1373 $trimmed['retweeted_status']['entities']['media'][$i]['video_info']['variants'][$i]['url'] = $variant['url'];
1374 }
1375 }
1376 if ( ! isset( $trimmed['retweeted_status']['entities']['media'][$i]['video_info']['variants'][$i]['url'] ) ) {
1377 $trimmed['retweeted_status']['entities']['media'][$i]['video_info']['variants'][$i]['url'] = $tweet['retweeted_status']['entities']['media'][$i]['video_info']['variants'][0]['url'];
1378 }
1379 }
1380 }
1381
1382 } elseif ( isset( $tweet['quoted_status']['extended_entities']['media'] ) ) {
1383 // if there is media, we need to remove the media url from the tweet text
1384 $quoted_text = isset( $tweet['quoted_status']['full_text'] ) ? $tweet['quoted_status']['full_text'] : $tweet['quoted_status']['text'];
1385 if ( isset( $tweet['quoted_status']['extended_entities']['media'][0]['url'] ) ) {
1386 $trimmed['quoted_status']['text'] = $this->removeStringFromText( $tweet['quoted_status']['extended_entities']['media'][0]['url'], $quoted_text );
1387 }
1388
1389 $num_media = count( $tweet['quoted_status']['extended_entities']['media'] );
1390 for( $i = 0; $i < $num_media; $i++ ) {
1391 $trimmed['quoted_status']['extended_entities']['media'][$i]['media_url_https'] = $tweet['quoted_status']['extended_entities']['media'][$i]['media_url_https'];
1392 $trimmed['quoted_status']['extended_entities']['media'][$i]['type'] = $tweet['quoted_status']['extended_entities']['media'][$i]['type'];
1393 if ( $tweet['quoted_status']['extended_entities']['media'][$i]['type'] == 'video' || $tweet['quoted_status']['extended_entities']['media'][$i]['type'] == 'animated_gif' ) {
1394 foreach ( $tweet['quoted_status']['extended_entities']['media'][$i]['video_info']['variants'] as $variant ) {
1395 if ( isset( $variant['content_type'] ) && $variant['content_type'] == 'video/mp4' ) {
1396 $trimmed['quoted_status']['extended_entities']['media'][$i]['video_info']['variants'][$i]['url'] = $variant['url'];
1397 }
1398 }
1399 if ( ! isset( $trimmed['quoted_status']['extended_entities']['media'][$i]['video_info']['variants'][$i]['url'] ) ) {
1400 $trimmed['quoted_status']['extended_entities']['media'][$i]['video_info']['variants'][$i]['url'] = $tweet['quoted_status']['extended_entities']['media'][$i]['video_info']['variants'][0]['url'];
1401 }
1402 }
1403 }
1404
1405 } elseif ( isset( $tweet['quoted_status']['entities']['media'] ) ) {
1406 // if there is media, we need to remove the media url from the tweet text
1407 $quoted_text = isset( $tweet['quoted_status']['full_text'] ) ? $tweet['quoted_status']['full_text'] : $tweet['quoted_status']['text'];
1408 if ( isset( $tweet['quoted_status']['entities']['media'][0]['url'] ) ) {
1409 $trimmed['quoted_status']['text'] = $this->removeStringFromText( $tweet['quoted_status']['entities']['media'][0]['url'], $quoted_text );
1410 }
1411
1412 $num_media = count( $tweet['quoted_status']['entities']['media'] );
1413 for( $i = 0; $i < $num_media; $i++ ) {
1414 $trimmed['quoted_status']['entities']['media'][$i]['media_url_https'] = $tweet['quoted_status']['entities']['media'][$i]['media_url_https'];
1415 $trimmed['quoted_status']['entities']['media'][$i]['type'] = $tweet['quoted_status']['entities']['media'][$i]['type'];
1416 if ( $tweet['quoted_status']['entities']['media'][$i]['type'] == 'video' || $tweet['quoted_status']['entities']['media'][$i]['type'] == 'animated_gif' ) {
1417 foreach ( $tweet['quoted_status']['entities']['media'][$i]['video_info']['variants'] as $variant ) {
1418 if ( isset( $variant['content_type'] ) && $variant['content_type'] == 'video/mp4' ) {
1419 $trimmed['quoted_status']['entities']['media'][$i]['video_info']['variants'][$i]['url'] = $variant['url'];
1420 }
1421 }
1422 if ( ! isset( $trimmed['quoted_status']['entities']['media'][$i]['video_info']['variants'][$i]['url'] ) ) {
1423 $trimmed['quoted_status']['entities']['media'][$i]['video_info']['variants'][$i]['url'] = $tweet['quoted_status']['entities']['media'][$i]['video_info']['variants'][0]['url'];
1424 }
1425 }
1426 }
1427
1428 }
1429
1430 if ( isset( $tweet['retweeted_status']['quoted_status']['extended_entities']['media'] ) ) {
1431 // if there is media, we need to remove the media url from the tweet text
1432 $retweeted_text = isset( $tweet['retweeted_status']['quoted_status']['full_text'] ) ? $tweet['retweeted_status']['quoted_status']['full_text'] : $tweet['retweeted_status']['quoted_status']['text'];
1433 if ( isset( $tweet['retweeted_status']['quoted_status']['extended_entities']['media'][0]['url'] ) ) {
1434 $trimmed['retweeted_status']['quoted_status']['text'] = $this->removeStringFromText( $tweet['retweeted_status']['quoted_status']['extended_entities']['media'][0]['url'], $retweeted_text );
1435 }
1436 $num_media = count( $tweet['retweeted_status']['quoted_status']['extended_entities']['media'] );
1437 for ( $i = 0; $i < $num_media; $i++ ) {
1438 $trimmed['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['media_url_https'] = $tweet['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['media_url_https'];
1439 $trimmed['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['type'] = $tweet['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['type'];
1440 if ( isset( $tweet['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['sizes'] ) ) {
1441 $trimmed['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['sizes'] = $tweet['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['sizes'];
1442 }
1443 if ( $tweet['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['type'] == 'video' || $tweet['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['type'] == 'animated_gif' ) {
1444 foreach ( $tweet['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['video_info']['variants'] as $variant ) {
1445 if ( isset( $variant['content_type'] ) && $variant['content_type'] == 'video/mp4' ) {
1446 $trimmed['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['video_info']['variants'][$i]['url'] = $variant['url'];
1447 }
1448 }
1449 if ( ! isset( $trimmed['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['video_info']['variants'][$i]['url'] ) ) {
1450 $trimmed['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['video_info']['variants'][$i]['url'] = $tweet['retweeted_status']['quoted_status']['extended_entities']['media'][$i]['video_info']['variants'][0]['url'];
1451 }
1452 }
1453 }
1454 } elseif ( isset( $tweet['retweeted_status']['quoted_status']['entities']['media'] ) ) {
1455 // if there is media, we need to remove the media url from the tweet text
1456 $retweeted_text = isset( $tweet['retweeted_status']['quoted_status']['full_text'] ) ? $tweet['retweeted_status']['quoted_status']['full_text'] : $tweet['retweeted_status']['quoted_status']['text'];
1457 if ( isset( $tweet['retweeted_status']['quoted_status']['entities']['media'][0]['url'] ) ) {
1458 $trimmed['retweeted_status']['quoted_status']['text'] = $this->removeStringFromText( $tweet['retweeted_status']['quoted_status']['entities']['media'][0]['url'], $retweeted_text );
1459 }
1460 $num_media = count( $tweet['retweeted_status']['quoted_status']['entities']['media'] );
1461 for( $i = 0; $i < $num_media; $i++ ) {
1462 $trimmed['retweeted_status']['quoted_status']['entities']['media'][$i]['media_url_https'] = $tweet['retweeted_status']['quoted_status']['entities']['media'][$i]['media_url_https'];
1463 $trimmed['retweeted_status']['quoted_status']['entities']['media'][$i]['type'] = $tweet['retweeted_status']['quoted_status']['entities']['media'][$i]['type'];
1464 if ( isset( $tweet['retweeted_status']['quoted_status']['entities']['media'][$i]['sizes'] ) ) {
1465 $trimmed['retweeted_status']['quoted_status']['entities']['media'][$i]['sizes'] = $tweet['retweeted_status']['quoted_status']['entities']['media'][$i]['sizes'];
1466 }
1467 if ( $tweet['retweeted_status']['quoted_status']['entities']['media'][$i]['type'] == 'video' || $tweet['retweeted_status']['quoted_status']['entities']['media'][$i]['type'] == 'animated_gif' ) {
1468 foreach ( $tweet['retweeted_status']['quoted_status']['entities']['media'][$i]['video_info']['variants'] as $variant ) {
1469 if ( isset( $variant['content_type'] ) && $variant['content_type'] == 'video/mp4' ) {
1470 $trimmed['retweeted_status']['quoted_status']['entities']['media'][$i]['video_info']['variants'][$i]['url'] = $variant['url'];
1471 }
1472 }
1473 if ( ! isset( $trimmed['retweeted_status']['quoted_status']['entities']['media'][$i]['video_info']['variants'][$i]['url'] ) ) {
1474 $trimmed['retweeted_status']['quoted_status']['entities']['media'][$i]['video_info']['variants'][$i]['url'] = $tweet['retweeted_status']['quoted_status']['entities']['media'][$i]['video_info']['variants'][0]['url'];
1475 }
1476 }
1477 }
1478 }
1479
1480 //remove the url from the text if it links to a quoted tweet that is already linked to
1481 if ( isset( $tweet['quoted_status'] ) ) {
1482 $maybe_remove_index = count( $tweet['entities']['urls'] ) - 1;
1483 if ( isset( $tweet['entities']['urls'][$maybe_remove_index]['url'] ) ) {
1484 $text = isset( $trimmed['full_text'] ) ? $trimmed['full_text'] : $trimmed['text'];
1485 $trimmed['text'] = $this->removeStringFromText( $tweet['entities']['urls'][$maybe_remove_index]['url'], $text );
1486 }
1487 }
1488
1489
1490 // used to generate twitter cards
1491 if ( isset( $tweet['entities']['urls'][0]['expanded_url'] ) ) {
1492 $trimmed['entities']['urls'][0]['expanded_url'] = $tweet['entities']['urls'][0]['expanded_url'];
1493 }
1494
1495 if ( isset( $tweet['retweeted_status']['entities']['urls'][0]['expanded_url'] ) ) {
1496 $trimmed['retweeted_status']['entities']['urls'][0]['expanded_url'] = $tweet['retweeted_status']['entities']['urls'][0]['expanded_url'];
1497 }
1498
1499 return $trimmed;
1500 }
1501
1502 /**
1503 * will create a transient with the tweet cache if one doesn't exist, the data seems valid, and caching is active
1504 */
1505 public function maybeCacheTweets( $error = false ) {
1506 if ( CTF_DOING_SMASH_TWITTER ) {
1507 if ( empty( $this->last_id_data ) ) {
1508 if ( $error ) {
1509 $cache = json_encode(array('error'));
1510 $this->cache->set_transient($this->transient_name, $cache, $this->feed_options['cache_time']);
1511 } else {
1512 if ((!$this->transient_data || $this->errors['cache_status']) && $this->feed_options['cache_time'] > 0) {
1513 $cache = json_encode($this->tweet_set);
1514 $this->cache->set_transient($this->transient_name, $cache, $this->feed_options['cache_time']);
1515 }
1516 }
1517 }
1518 return;
1519 }
1520 if ( $error ) {
1521 $cache = json_encode(array('error'));
1522 } else {
1523 $cache = json_encode($this->tweet_set);
1524 }
1525 $this->cache->set_transient($this->transient_name, $cache, $this->feed_options['cache_time']);
1526 }
1527
1528 /**
1529 * returns a JSON string to be used in the data attribute that contains the shortcode data
1530 */
1531 public function getShortCodeJSON() {
1532 $json = json_encode($this->raw_shortcode_atts);
1533 return $json !== false ? htmlentities($json) : '';
1534 }
1535
1536 /**
1537 * uses the endpoint to determing what get fields need to be set
1538 *
1539 * @param $end_point api endpoint needed
1540 * @param $feed_term term associated with the endpoint, user name or search term
1541 * @return array the get fields for the request
1542 */
1543 public function setGetFieldsArray( $end_point, $feed_term ){
1544 $get_fields = array();
1545
1546 $get_fields['tweet_mode'] = 'extended';
1547
1548 if ( $end_point === 'usertimeline' ) {
1549 if ( ! empty ( $feed_term ) ) {
1550 $get_fields['screen_name'] = $feed_term;
1551 }
1552 if ( !$this->feed_options['selfreplies'] ) {
1553 $get_fields['exclude_replies'] = 'true';
1554 }
1555 }
1556 if ( $end_point === 'hometimeline' ) {
1557 $get_fields['exclude_replies'] = 'true';
1558 if ( !$this->feed_options['selfreplies'] ) {
1559 $get_fields['exclude_replies'] = 'true';
1560 }
1561 }
1562 if ( $end_point === 'search' ) {
1563 $get_fields['q'] = $feed_term;
1564 }
1565 if ($end_point === 'userslookup') {
1566 if (!empty($feed_term)) {
1567 $get_fields['screen_name'] = $feed_term;
1568 }
1569 }
1570 return $get_fields;
1571 }
1572
1573 /**
1574 * attempts to connect and retrieve tweets from the Twitter api
1575 *
1576 * @return mixed|string object containing the response
1577 */
1578 public function apiConnect( $end_point, $feed_term )
1579 {
1580 // Only can be set in the options page
1581 $request_settings = array(
1582 'consumer_key' => $this->feed_options['consumer_key'],
1583 'consumer_secret' => $this->feed_options['consumer_secret'],
1584 'access_token' => $this->feed_options['access_token'],
1585 'access_token_secret' => $this->feed_options['access_token_secret'],
1586 );
1587
1588 // For pagination, an extra post needs to be retrieved since the last post is
1589 // included in the next set
1590 $count = $this->feed_options['count'];
1591
1592 $get_fields = $this->setGetFieldsArray( $end_point, $feed_term );
1593
1594 if ( ! empty( $this->last_id_data ) ) {
1595 $count++;
1596 $max_id = $this->last_id_data;
1597 }
1598 $get_fields['count'] = $count;
1599
1600 // max_id parameter should only be included for the second set of posts
1601 if ( isset( $max_id ) ) {
1602 $get_fields['max_id'] = $max_id;
1603 }
1604 // actual connection
1605 $twitter_connect = new CtfOauthConnect( $request_settings, $end_point );
1606 $twitter_connect->setUrlBase();
1607 $twitter_connect->setGetFields( $get_fields );
1608 $twitter_connect->setRequestMethod( $this->feed_options['request_method'] );
1609
1610 return $twitter_connect->performRequest();
1611 }
1612
1613 private function getTweetsSinceID( $since_id, $end_point = 'search', $feed_term = '', $count = 0)
1614 {
1615 // Only can be set in the options page
1616 $request_settings = array(
1617 'consumer_key' => $this->feed_options['consumer_key'],
1618 'consumer_secret' => $this->feed_options['consumer_secret'],
1619 'access_token' => $this->feed_options['access_token'],
1620 'access_token_secret' => $this->feed_options['access_token_secret'],
1621 );
1622
1623 $get_fields = $this->setGetFieldsArray( $end_point, $feed_term );
1624
1625 $get_fields['since_id'] = $since_id;
1626
1627 $get_fields['count'] = $count;
1628
1629 // actual connection
1630 $twitter_connect = new CtfOauthConnect( $request_settings, $end_point );
1631 $twitter_connect->setUrlBase();
1632 $twitter_connect->setGetFields( $get_fields );
1633 $twitter_connect->setRequestMethod( $this->feed_options['request_method'] );
1634
1635 return $twitter_connect->performRequest();
1636 }
1637
1638 public function feedID() {
1639 if ($this->feed_options['persistentcache']) {
1640 $includewords = !empty($this->feed_options['includewords']) ? substr(str_replace(array(
1641 ',',
1642 ' '
1643 ) , '', $this->feed_options['includewords']) , 0, 10) : '';
1644 $excludewords = !empty($this->feed_options['excludewords']) ? substr(str_replace(array(
1645 ',',
1646 ' '
1647 ) , '', $this->feed_options['excludewords']) , 0, 5) : '';
1648 $feed_id = (!empty($this->atts['feedid'])) ? substr('ctf_!_' . $this->atts['feedid'] . $includewords . $excludewords, 0, 45) : substr('ctf_!_' . $this->feed_options['feed_term'] . $includewords . $excludewords, 0, 45);
1649 if ($this->feed_options['type'] === 'hashtag') {
1650 $feed_id = str_replace(' -filter:retweets', '', $feed_id);
1651 }
1652 }
1653 else {
1654 $feed_id = $this->transient_name;
1655 }
1656
1657 return $feed_id;
1658 }
1659
1660 /**
1661 * If the feed runs out of tweets to display for some reason,
1662 * this function creates a graceful failure message
1663 *
1664 * @param $feed_options
1665 * @return string html for "out of tweets" message
1666 */
1667 protected function getOutOfTweetsHtml( $feed_options )
1668 {
1669 $html = '';
1670
1671 $html .= '<div class="ctf-out-of-tweets">';
1672 $html .= '<p>' . __( "That's all! No more Tweets to load", 'custom-twitter-feeds' ) . '</p>';
1673 $html .= '<p>';
1674 $html .= '<a class="twitter-share-button" href="https://twitter.com/share" target="_blank" rel="noopener noreferrer" data-size="large" data-url="'.get_home_url().'">Share</a>';
1675 if ( !empty( $feed_options['screenname'] ) ) {
1676 $html .= '<a class="twitter-follow-button" href="https://twitter.com/' . $feed_options['screenname'] . '" target="_blank" rel="noopener noreferrer" data-show-count="false" data-size="large" data-dnt="true">Follow</a>';
1677 }
1678 $html .= '</p>';
1679 $html .= '</div>';
1680
1681 return $html;
1682 }
1683
1684 /**
1685 * creates opening html for the feed
1686 *
1687 * @return string opening html that creates the feed
1688 */
1689 public function getFeedOpeningHtml(){
1690 $feed_options = $this->feed_options;
1691 $options = ctf_get_database_settings();
1692
1693 $ctf_data_disablelinks = ($feed_options['disablelinks'] == 'true') ? ' data-ctfdisablelinks="true"' : '';
1694 $ctf_data_linktextcolor = $feed_options['linktextcolor'] != '' ? ' data-ctflinktextcolor="'.$feed_options['linktextcolor'].'"' : '';
1695 $ctf_enable_intents = ($options['disableintents'] === false || $options['disableintents'] === 0) && ctf_show('actions', $feed_options) ? ' data-ctfintents="1"' : '';
1696
1697 $ctf_data_needed = $this->num_tweets_needed;
1698 $ctf_feed_type = ! empty ( $feed_options['type'] ) ? esc_attr( $feed_options['type'] ) : 'multiple';
1699 $ctf_feed_classes = 'ctf ctf-type-' . $ctf_feed_type;
1700 $ctf_feed_classes .= ' ' . \ctf_sanitize_css_class_list( $feed_options['class'] ) . ' ctf-styles';
1701 $ctf_feed_classes .= $feed_options['width_mobile_no_fixed'] ? ' ctf-width-resp' : '';
1702 if ( $this->check_for_duplicates ) { $ctf_feed_classes .= ' ctf-no-duplicates'; }
1703 $ctf_feed_classes = apply_filters( 'ctf_feed_classes', $ctf_feed_classes ); //add_filter( 'ctf_feed_classes', function( $ctf_feed_classes ) { return $ctf_feed_classes . ' new-class'; }, 10, 1 );
1704 $ctf_feed_classes = esc_attr( $ctf_feed_classes );
1705 $ctf_feed_html = '';
1706
1707 $flags_att = '';
1708 $flags = array();
1709 if ( CTF_GDPR_Integrations::doing_gdpr( $feed_options ) ) {
1710 $flags[] = 'gdpr';
1711 }
1712 if ( ! is_admin() && CTF_Feed_Locator::should_do_ajax_locating( $this->feedID(), get_the_ID() ) ) {
1713 $flags[] = 'locator';
1714 }
1715 if ( ! empty( $flags ) ) {
1716 $flags_att = ' data-ctf-flags="' . implode( ',', $flags ) . '"';
1717 }
1718
1719 $post_id_att = ' data-postid="' . esc_attr( get_the_ID() ) . '"';
1720 $feed_id_att = ' data-feed-id="' . $this->feedID() . '"';
1721
1722 $ctf_feed_html .= '<!-- Custom Twitter Feeds by Smash Balloon -->';
1723 $ctf_feed_html .= '<div id="ctf" class="' . $ctf_feed_classes . '" style="' . $feed_options['width'] . $feed_options['height'] . $feed_options['bgcolor'] . '" data-ctfshortcode="' . $this->getShortCodeJSON() . '"' .$ctf_data_disablelinks . $ctf_data_linktextcolor . $ctf_enable_intents . $flags_att . $post_id_att . $feed_id_att .' data-ctfneeded="'. $ctf_data_needed .'">';
1724 $tweet_set = $this->tweet_set;
1725
1726 // dynamically include header
1727 if ( $feed_options['showheader'] ) {
1728 $ctf_feed_html .= $this->getFeedHeaderHtml( $tweet_set, $this->feed_options );
1729 }
1730
1731 $ctf_feed_html .= '<div class="ctf-tweets">';
1732
1733 return $ctf_feed_html;
1734 }
1735
1736 /**
1737 * creates opening html for the feed
1738 *
1739 * @return string opening html that creates the feed
1740 */
1741 public function getFeedClosingHtml()
1742 {
1743 $feed_options = $this->feed_options;
1744 $ctf_feed_html = '';
1745
1746 $ctf_feed_html .= '</div>'; // closing div for ctf-tweets
1747
1748 if ( $feed_options['showbutton'] ) {
1749 $ctf_feed_html .= '<a href="javascript:void(0);" id="ctf-more" class="ctf-more" style="' . $feed_options['buttoncolor'] . $feed_options['buttontextcolor'] . '"><span>' . $feed_options['buttontext'] . '</span></a>';
1750 }
1751
1752 if ( $feed_options['creditctf'] ) {
1753 $ctf_feed_html .= '<div class="ctf-credit-link"><a href="https://smashballoon.com/custom-twitter-feeds/?utm_campaign=twitter-free&utm_source=frontend&utm_medium=credit" target="_blank" rel="noopener noreferrer">' . ctf_get_fa_el( 'fa-twitter' ) . 'Custom Twitter Feeds Plugin</a></div>';
1754 }
1755
1756 $ctf_feed_html .= '</div>'; // closing div tag for #ctf
1757 if ( $feed_options['ajax_theme'] ) {
1758 $ctf_feed_html .= '<script type="text/javascript" src="' . CTF_JS_URL . '"></script>';
1759 }
1760
1761 return $ctf_feed_html;
1762 }
1763
1764 /**
1765 * creates html for header of the feed
1766 *
1767 * @param $tweet_set string trimmed tweets to be added to the feed
1768 * @param $feed_options options for the feed
1769 * @return string html that creates the header of the feed
1770 */
1771 protected function getFeedHeaderHtml( $tweet_set, $feed_options )
1772 {
1773 $ctf_header_html = '';
1774 $ctf_no_bio = ( $feed_options['showbio'] && !empty($tweet_set[0]['user']['description']) ) ? '' : ' ctf-no-bio';
1775
1776 // temporary workaround for cached http images
1777 $tweet_set[0]['user']['profile_image_url_https'] = isset( $tweet_set[0]['user']['profile_image_url_https'] ) ? $tweet_set[0]['user']['profile_image_url_https'] : $tweet_set[0]['user']['profile_image_url'];
1778
1779
1780 if ( $feed_options['type'] === 'usertimeline' ) {
1781 ### TEMPLATE HEADER
1782 $ctf_header_html .= '<div class="ctf-header' . $ctf_no_bio . '" style="' . $feed_options['headerbgcolor'] . '">';
1783 $ctf_header_html .= '<a href="https://twitter.com/' . $tweet_set[0]['user']['screen_name'] . '" target="_blank" rel="noopener noreferrer" title="@' . $tweet_set[0]['user']['screen_name'] . '" class="ctf-header-link">';
1784 $ctf_header_html .= '<div class="ctf-header-text">';
1785 $ctf_header_html .= '<p class="ctf-header-user" style="' . $feed_options['headertextcolor'] . '">';
1786 $ctf_header_html .= '<span class="ctf-header-name">';
1787
1788 if ( $feed_options['headertext'] != '' ) {
1789 $ctf_header_html .= esc_html( $feed_options['headertext'] );
1790 } else {
1791 $ctf_header_html .= esc_html( $tweet_set[0]['user']['name'] );
1792 }
1793
1794 $ctf_header_html .= '</span>';
1795
1796 if ( $tweet_set[0]['user']['verified'] == 1 ) {
1797 $ctf_header_html .= '<span class="ctf-verified">' . ctf_get_fa_el( 'fa-check-circle' ) . '</span>';
1798 }
1799
1800 $ctf_header_html .= '<span class="ctf-header-follow">' . ctf_get_fa_el( 'fa-twitter' ) . __( 'Follow', 'custom-twitter-feeds' ) . '</span>';
1801 $ctf_header_html .= '</p>';
1802
1803 if ( $feed_options['showbio'] && !empty($tweet_set[0]['user']['description']) ) {
1804 $ctf_header_html .= '<p class="ctf-header-bio" style="' . $feed_options['headertextcolor'] . '">' . $tweet_set[0]['user']['description'] . '</p>';
1805 }
1806
1807 $ctf_header_html .= '</div>';
1808 $ctf_header_html .= '<div class="ctf-header-img">';
1809 $ctf_header_html .= '<div class="ctf-header-img-hover">' . ctf_get_fa_el( 'fa-twitter' ) . '</div>';
1810 if ( CTF_GDPR_Integrations::doing_gdpr( $feed_options ) ) {
1811 $ctf_header_html .= '<span data-avatar="' . esc_url( $tweet_set[0]['user']['profile_image_url_https'] ) . '" data-alt="' . $tweet_set[0]['user']['name'] . '" style="display: none;">Avatar</span>';
1812 } else {
1813 $ctf_header_html .= '<img src="' . esc_url( $tweet_set[0]['user']['profile_image_url_https'] ) . '" alt="' . esc_attr( $tweet_set[0]['user']['name'] ) . '" width="48" height="48">';
1814 }
1815 $ctf_header_html .= '</div>';
1816 $ctf_header_html .= '</a>';
1817 $ctf_header_html .= '</div>';
1818 } else {
1819 ### TEMPLATE HEADER GENERIC
1820 if ( $feed_options['type'] === 'search' ) {
1821 $default_header_text = $feed_options['headertext'] != '' ? esc_html($feed_options['headertext']) : $feed_options['feed_term'];
1822 $url_part = 'hashtag/' . str_replace("#", "", $feed_options['feed_term']);
1823 } else {
1824 $default_header_text = 'Twitter';
1825 $url_part = $feed_options['screenname']; //Need to get screenname here
1826 }
1827
1828 $default_header_text = str_replace( ' -filter:retweets', '', $default_header_text );
1829
1830 $ctf_header_html .= '<div class="ctf-header ctf-header-type-generic" style="' . $feed_options['headerbgcolor'] . '">';
1831 $ctf_header_html .= '<a href="https://twitter.com/' . $url_part . '" target="_blank" rel="noopener noreferrer" class="ctf-header-link">';
1832 $ctf_header_html .= '<div class="ctf-header-text">';
1833 $ctf_header_html .= '<p class="ctf-header-no-bio" style="' . $feed_options['headertextcolor'] . '">' . $default_header_text . '</p>';
1834 $ctf_header_html .= '</div>';
1835 $ctf_header_html .= '<div class="ctf-header-img">';
1836 $ctf_header_html .= '<div class="ctf-header-generic-icon">';
1837 $ctf_header_html .= ctf_get_fa_el( 'fa-twitter' );
1838 $ctf_header_html .= '</div>';
1839 $ctf_header_html .= '</div>';
1840 $ctf_header_html .= '</a>';
1841 $ctf_header_html .= '</div>';
1842 }
1843
1844 return $ctf_header_html;
1845 }
1846
1847 /**
1848 * outputs the html for a set of tweets to be used in the feed
1849 *
1850 * @param int $is_pagination 1 or 0, used to differentiate between the first set and subsequent tweet sets
1851 *
1852 * @return string $tweet_html
1853 */
1854 public function getTweetSetHtml( $is_pagination = 0 ){
1855 $feed_id = $this->feedID();
1856 $tweet_set = isset( $this->tweet_set['statuses'] ) ? $this->tweet_set['statuses'] : $this->tweet_set;
1857 $options = ctf_get_database_settings();
1858 $len = min( $this->feed_options['num'] + $is_pagination, count( $tweet_set ) );
1859 $i = $is_pagination; // starts at index "1" to offset duplicate tweet
1860 $feed_options = $this->feed_options;
1861 $tweet_html = $this->feed_html;
1862 $feed_id = $this->is_legacy ? $this->unique_legacy_id : $this->feed_id;
1863 $ctf_data_needed = $this->num_tweets_needed;
1864 $ctf_feed_classes = CTF_Parse::get_feed_classes($feed_options, $this->check_for_duplicates, $feed_id);
1865 $ctf_enable_intents = ((bool)$options['disableintents'] === false) && ctf_show('actions', $feed_options) ? ' data-ctfintents="1" ' : '';
1866 $ctf_main_atts = CTF_Display_Elements::get_feed_container_data_attributes( $feed_options, $feed_id, $this->feedID() ) . $ctf_enable_intents;
1867
1868
1869 if (!$is_pagination) {
1870 if ( empty( $this->was_error_or_empty( $this->tweet_set ) ) ) {
1871 $this->error_report->process_error( 'no_tweets_found_cache' );
1872 }
1873 ob_start();
1874 include ctf_get_feed_template_part('feed', $feed_options);
1875 $tweet_html .= ob_get_contents();
1876 ob_get_clean();
1877 }
1878
1879 return $tweet_html;
1880 }
1881
1882 public function getItemSetHtml($is_pagination = 0) {
1883 $options = get_option('ctf_options');
1884 $tweet_set = isset($this->tweet_set['statuses']) ? $this->tweet_set['statuses'] : $this->tweet_set;
1885 $tweet_count = CTF_Parse::get_tweet_count($tweet_set);
1886 $len = min($this->feed_options['num'] + $is_pagination, $tweet_count);
1887 if ( CTF_DOING_SMASH_TWITTER ) {
1888 $i = 0; // starts at index "1" to offset duplicate tweet
1889 $was_pagination = $is_pagination;
1890 $is_pagination = 0;
1891 $tweet_html = '';
1892 if ($was_pagination && (!isset($tweet_set[0]['id_str']))) {
1893 $tweet_html = $this->getOutOfTweetsHtml($this->feed_options);
1894 }
1895 } else {
1896 $i = $is_pagination; // starts at index "1" to offset duplicate tweet
1897 $tweet_html = '';
1898 if ($is_pagination && (!isset($tweet_set[1]['id_str']))) {
1899 $tweet_html = $this->getOutOfTweetsHtml($this->feed_options);
1900 }
1901 }
1902
1903 ob_start();
1904
1905 $this->tweet_loop($tweet_set, $this->feed_options, $is_pagination);
1906 $tweet_html .= ob_get_contents();
1907 ob_get_clean();
1908
1909 return $tweet_html;
1910 }
1911 /**
1912 * displays a message if there is an error in the feed
1913 *
1914 * @return string error html
1915 */
1916 public function getErrorHtml()
1917 {
1918 $error_html = '';
1919 $error_html .= '<div id="ctf" class="ctf" data-ctfshortcode="' . $this->getShortCodeJSON() . '">';
1920 $error_html .= '<div class="ctf-error">';
1921 $error_html .= '<div class="ctf-error-user">';
1922
1923 $error_html .= '</div>';
1924
1925 if ( current_user_can( 'manage_options' ) ) {
1926 $error_html .= '<div class="ctf-error-admin">';
1927 $error_html .= '<p><b>This message is only visible to admins:</b><br />';
1928 $error_html .= 'Due to changes with Twitter\'s API the plugin will not update feeds. Smash Balloon is working on a solution for our free users to see updated tweets in feeds again.<br>Follow the link below for more information and updates.<br />';
1929 if ($this->missing_credentials) {
1930 $error_html .= 'There is a problem with your access token, access token secret, consumer token, or consumer secret<br />';
1931 }
1932 $error_html .= '<a href="https://smashballoon.com/doc/smash-balloon-twitter-changes-free-version/?utm_source=feed-error&utm_medium=error-notice&utm_campaign=twitter-free&utm_content=CustomTwitterFeedChanges" target="_blank" rel="noopener noreferrer">Custom Twitter Feed Changes</a></p>';
1933
1934 $error_html .= '</div>';
1935 } else {
1936 $error_html .= '<p>' . __( 'Twitter feed is not available at the moment.', 'custom-twitter-feeds' ) . '</p>';
1937 }
1938 $error_html .= '</div>'; // end .ctf-error
1939 $error_html .= '</div>'; // end #ctf
1940
1941 return $error_html;
1942 }
1943
1944
1945 public function tweet_loop( $tweet_set, $feed_options, $is_pagination ) {
1946 #$tweet_set = isset( $this->tweet_set['statuses'] ) ? $this->tweet_set['statuses'] : $this->tweet_set;
1947 $len = min( $this->feed_options['num'] + $is_pagination, count( (array)$tweet_set ) );
1948 $i = $is_pagination; // starts at index "1" to offset duplicate tweet
1949 $t = (count((array)$tweet_set) > 1 ? $t = 1 : 0); // Set index based on tweets returned
1950 $tweet_html = '';
1951 if ( $is_pagination && ( ! isset ( $tweet_set[1]['id_str'] ) ) ) {
1952 $tweet_html .= $this->getOutOfTweetsHtml( $this->feed_options );
1953 }
1954 if ($is_pagination > - 1 && (isset($tweet_set[$t]['id_str']))) {
1955
1956 while ( $i < $len ) {
1957 $post = $tweet_set[$i];
1958 if (isset($post['retweeted_status'])) {
1959 $retweeter = array(
1960 'name' => $post['user']['name'],
1961 'screen_name' => $post['user']['screen_name']
1962 );
1963 $post = $post['retweeted_status'];
1964 // temporary workaround for cached http images
1965 $post['user']['profile_image_url_https'] = isset($post['user']['profile_image_url_https']) ? $post['user']['profile_image_url_https'] : $post['user']['profile_image_url'];
1966 }
1967 else {
1968 unset($retweeter);
1969 }
1970 // check for quoted
1971 if (isset($post['quoted_status'])) {
1972 $quoted = $post['quoted_status'];
1973 }
1974 else {
1975 unset($quoted);
1976 }
1977 include ctf_get_feed_template_part('item', $feed_options);
1978 $i++;
1979 }
1980 }
1981 }
1982
1983 /**
1984 * Get Global Twitter Feed CSS
1985 *
1986 * @since 2.0
1987 * @return array
1988 */
1989 public function get_feed_style(){
1990 $feed_style = '';
1991 $feed_html_id = ($this->is_legacy ? $this->unique_legacy_id : $this->feed_id);
1992
1993 $feed_ctn = '.ctf-feed-' . $feed_html_id;
1994
1995 $css_array = [
1996 //Load More Button Style
1997 [
1998 'selector' => $feed_ctn . ' .ctf-more',
1999 'properties' => [
2000 'background-color' => [
2001 'value' => $this->feed_options['buttoncolor'],
2002 'important' => true
2003 ],
2004 'color' => [
2005 'value' => $this->feed_options['buttontextcolor'],
2006 'important' => true
2007 ]
2008 ]
2009 ],
2010 [
2011 'selector' => $feed_ctn . ' .ctf-more:hover',
2012 'properties' => [
2013 'background-color' => [
2014 'value' => $this->feed_options['buttonhovercolor'],
2015 'important' => true
2016 ]
2017 ]
2018 ],
2019 //Author Text Style
2020 [
2021 'selector' => $feed_ctn . ' .ctf-author-name',
2022 'properties' => [
2023 'color' => [
2024 'value' => $this->feed_options['authortextcolor'],
2025 'important' => true
2026 ],
2027 'font-size' => [
2028 'value' => $this->feed_options['authortextsize'],
2029 'important' => true
2030 ]
2031 ]
2032 ],
2033 //Tweet Text Style
2034 [
2035 'selector' => $feed_ctn . ' .ctf-tweet-text, ' .$feed_ctn . ' .ctf-quoted-tweet-text' ,
2036 'properties' => [
2037 'color' => [
2038 'value' => $this->feed_options['textcolor'],
2039 'important' => true
2040 ],
2041 'font-size' => [
2042 'value' => $this->feed_options['tweettextsize'],
2043 'important' => true
2044 ],
2045 'font-weight' => [
2046 'value' => $this->feed_options['tweettextweight'],
2047 'important' => true
2048 ]
2049 ]
2050 ],
2051 //Date Style
2052 [
2053 'selector' => $feed_ctn . ' .ctf-tweet-meta a',
2054 'properties' => [
2055 'color' => [
2056 'value' => $this->feed_options['datetextcolor'],
2057 'important' => true
2058 ],
2059 'font-size' => [
2060 'value' => $this->feed_options['datetextsize'],
2061 'important' => true
2062 ],
2063 'font-weight' => [
2064 'value' => $this->feed_options['datetextweight'],
2065 'important' => true
2066 ]
2067 ]
2068 ],
2069 //Icon Style
2070 [
2071 'selector' => $feed_ctn . ' .ctf-tweet-actions a',
2072 'properties' => [
2073 'color' => [
2074 'value' => $this->feed_options['iconcolor'],
2075 'important' => true
2076 ],
2077 'font-size' => [
2078 'value' => $this->feed_options['iconsize'],
2079 'important' => true
2080 ]
2081 ]
2082 ],
2083 //Quoted Tweet
2084 [
2085 'selector' => $feed_ctn . ' .ctf-quoted-tweet',
2086 'properties' => [
2087 'font-size' => [
2088 'value' => $this->feed_options['quotedauthorsize'],
2089 'important' => true
2090 ],
2091 'font-weight' => [
2092 'value' => $this->feed_options['quotedauthorweight'],
2093 'important' => true
2094 ],
2095 'color' => [
2096 'value' => $this->feed_options['textcolor'],
2097 'important' => true
2098 ]
2099 ]
2100 ],
2101 //Twitter Link Style
2102 [
2103 'selector' => $feed_ctn . ' .ctf-twitterlink',
2104 'properties' => [
2105 'font-size' => [
2106 'value' => floor( .8 * (int)$this->feed_options['iconsize'] ),
2107 'important' => true
2108 ],
2109 'color' => [
2110 'value' => $this->feed_options['textcolor'],
2111 'important' => true
2112 ]
2113 ]
2114 ],
2115 //Twitter Cards
2116 [
2117 'selector' => $feed_ctn . ' .ctf-tc-summary-info *',
2118 'properties' => [
2119 'font-size' => [
2120 'value' => floor( .8 * (int)$this->feed_options['cardstextsize'] ),
2121 'important' => true
2122 ],
2123 'color' => [
2124 'value' => $this->feed_options['cardstextcolor'],
2125 'important' => true
2126 ]
2127 ]
2128 ],
2129 //Text Header
2130 [
2131 'selector' => $feed_ctn . ' .ctf-header-type-text',
2132 'properties' => [
2133 'color' => [
2134 'value' => $this->feed_options['customheadertextcolor'],
2135 'important' => true
2136 ]
2137 ]
2138 ]
2139 ];
2140
2141 //Feed Container
2142 if( isset($this->feed_options['height']) && $this->feed_options['height'] != 0){
2143 array_push($css_array, [
2144 'selector' => $feed_ctn . '.ctf-fixed-height',
2145 'properties' => [
2146 'height' => [
2147 'value' => $this->feed_options['height'],
2148 'important' => true
2149 ],
2150 ]
2151 ]);
2152 }
2153 //Link Text Color
2154 if( !CTF_Feed_Builder::check_if_on( $this->feed_options['disablelinks'] ) ){
2155 array_push($css_array,[
2156 'selector' => $feed_ctn . ' .ctf-tweet-text a',
2157 'properties' => [
2158 'color' => [
2159 'value' => $this->feed_options['linktextcolor'],
2160 'important' => true
2161 ]
2162 ]
2163 ]
2164 );
2165 }
2166 //Feed Post item style / Boxed & Regular
2167 $post_item_css = [];
2168 if($this->feed_options['tweetpoststyle'] === 'boxed'){
2169 $post_item_css = [
2170 'selector' => $feed_ctn . '.ctf-boxed-style .ctf-item',
2171 'properties' => [
2172 'background-color' => [
2173 'value' => $this->feed_options['tweetbgcolor'],
2174 'important' => true
2175 ],
2176 'border-radius' => [
2177 'value' => $this->feed_options['tweetcorners']
2178 ]
2179 ]
2180 ];
2181 }else if($this->feed_options['tweetpoststyle'] === 'regular' && CTF_Feed_Builder::check_if_on( $this->feed_options['tweetsepline'] ) ){
2182 $post_item_css = [
2183 'selector' => $feed_ctn . '.ctf-regular-style .ctf-item, '. $feed_ctn . ' .ctf-header',
2184 'properties' => [
2185 'border-bottom' => [
2186 'size' => $this->feed_options['tweetsepsize'],
2187 'color' => $this->feed_options['tweetsepcolor'],
2188 'important' => true
2189 ]
2190 ]
2191 ];
2192 }
2193 array_push($css_array, $post_item_css);
2194
2195 //Color Pallete
2196 if( isset($this->feed_options['colorpalette']) && $this->feed_options['colorpalette'] == 'custom'){
2197
2198 //Custom Background Color
2199 array_push($css_array, [
2200 'selector' => $feed_ctn . '.ctf_palette_custom_' . $feed_html_id . ' .ctf-item, '. $feed_ctn . '.ctf_palette_custom_' . $feed_html_id . ' .ctf-header',
2201 'properties' => [
2202 'background' => [
2203 'value' => $this->feed_options['custombgcolor'],
2204 'important' => true
2205 ],
2206 ]
2207 ]);
2208 //Custom Accent Color
2209 array_push($css_array, [
2210 'selector' => $feed_ctn . '.ctf_palette_custom_' . $feed_html_id . ' .ctf-corner-logo',
2211 'properties' => [
2212 'color' => [
2213 'value' => $this->feed_options['customaccentcolor'],
2214 'important' => true
2215 ],
2216 ]
2217 ]);
2218 //Custom Text 1 Color
2219 array_push($css_array, [
2220 'selector' => $feed_ctn . '.ctf_palette_custom_' . $feed_html_id . ' .ctf-author-name, .ctf_palette_custom_' . $feed_html_id . ' .ctf-tweet-text',
2221 'properties' => [
2222 'color' => [
2223 'value' => $this->feed_options['customtextcolor1'],
2224 'important' => true
2225 ],
2226 ]
2227 ]);
2228
2229 //Custom Text 2 Color
2230 array_push($css_array, [
2231 'selector' => $feed_ctn . '.ctf_palette_custom_' . $feed_html_id . ' .ctf-author-screenname',
2232 'properties' => [
2233 'color' => [
2234 'value' => $this->feed_options['customtextcolor2'],
2235 'important' => true
2236 ],
2237 ]
2238 ]);
2239
2240 //Custom Link Color
2241 array_push($css_array, [
2242 'selector' => $feed_ctn . '.ctf_palette_custom_' . $feed_html_id . ' .ctf-tweet-text a',
2243 'properties' => [
2244 'color' => [
2245 'value' => $this->feed_options['customlinkcolor'],
2246 'important' => true
2247 ],
2248 ]
2249 ]);
2250 }
2251
2252 //Legacy Feeds
2253 if( $this->is_legacy == true ){
2254 array_push($css_array,
2255 [
2256 'selector' => $feed_ctn . ' .ctf-item',
2257 'properties' => [
2258 'background-color' => [
2259 'value' => $this->feed_options['tweetbgcolor'],
2260 'important' => true
2261 ]
2262 ]
2263 ],
2264 [
2265 'selector' => $feed_ctn . ' .ctf-corner-logo ',
2266 'properties' => [
2267 'font-size' => [
2268 'value' => $this->feed_options['logosize'],
2269 'important' => true
2270 ],
2271 'color' => [
2272 'value' => $this->feed_options['logocolor'],
2273 'important' => true
2274 ]
2275 ]
2276 ],
2277 [
2278 'selector' => $feed_ctn . ' .ctf-retweet-text, '. $feed_ctn . ' .ctf-author-box-link, '. $feed_ctn . ' .ctf-author-avatar, '. $feed_ctn . ' .ctf-author-name, '.$feed_ctn . ' .ctf-author-screenname',
2279 'properties' => [
2280 'font-size' => [
2281 'value' => $this->feed_options['authortextsize'],
2282 'important' => true
2283 ],
2284 'font-weight' => [
2285 'value' => $this->feed_options['authortextweight']
2286 ],
2287 'color' => [
2288 'value' => $this->feed_options['textcolor'],
2289 ]
2290 ]
2291 ],
2292 [
2293 'selector' => $feed_ctn . ' .ctf-header-user, ' . $feed_ctn . ' .ctf-header-bio, ' . $feed_ctn . ' .ctf-header-no-bio' ,
2294 'properties' => [
2295 'color' => [
2296 'value' => $this->feed_options['headertextcolor'],
2297 'important' => true
2298 ]
2299 ]
2300 ],
2301 [
2302 'selector' => $feed_ctn . ' .ctf-header' ,
2303 'properties' => [
2304 'background-color' => [
2305 'value' => $this->feed_options['headerbgcolor'],
2306 'important' => true
2307 ]
2308 ]
2309 ],
2310 [
2311 'selector' => $feed_ctn,
2312 'properties' => [
2313 'background-color' => [
2314 'value' => $this->feed_options['bgcolor'],
2315 'important' => true
2316 ],
2317 'height' => [
2318 'value' => $this->feed_options['height'],
2319 'unit' => $this->feed_options['height_unit'],
2320 'important' => true
2321 ],
2322 'width' => [
2323 'value' => $this->feed_options['width'],
2324 'unit' => $this->feed_options['width_unit'],
2325 'important' => true
2326 ]
2327 ]
2328 ]
2329
2330
2331 );
2332
2333 }
2334
2335 $feed_style .= '<style type="text/css" data-ctf-style="' . $feed_html_id . '">';
2336 $feed_style .= CTF_Parse::parse_css_style( $css_array );
2337 $feed_style .= '</style>';
2338 echo $feed_style;
2339 }
2340
2341 /**
2342 * @return mixed
2343 * @since 2.0
2344 */
2345 public static function get_legacy_feed_settings() {
2346 return json_decode( get_option( 'ctf_legacy_feed_settings', '{}' ), true );
2347 }
2348
2349 public function get_legacy_feed_unique_id() {
2350 return $this->unique_legacy_id;
2351 }
2352
2353 public function should_show_footer( $tweet_set ) {
2354 return $this->was_error_or_empty( $tweet_set );
2355 }
2356
2357 public function was_error_or_empty( $tweet_set ) {
2358 if ( empty( $tweet_set ) ) {
2359 return false;
2360 }
2361 if ( ! empty( $tweet_set ) && isset( $tweet_set[0] ) && is_string( $tweet_set[0] ) && $tweet_set[0] === 'error' ) {
2362 return false;
2363 }
2364 $error = $this->error_report->get_critical_error();
2365 if ( ! empty( $error ) && empty( $tweet_set ) ) {
2366 return false;
2367 }
2368
2369 return true;
2370 }
2371 }
2372