PluginProbe ʕ •ᴥ•ʔ
Custom Twitter Feeds – A Tweets Widget or X Feed Widget / 2.7.0
Custom Twitter Feeds – A Tweets Widget or X Feed Widget v2.7.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 1 month ago Builder 1 month ago Integrations 1 month ago SmashTwitter 1 month ago UsageTracking 1 month ago V2 1 month ago blocks 1 month ago CTF_Display_Elements.php 1 month ago CTF_Feed.php 1 month ago CTF_Feed_Locator.php 1 month ago CTF_GDPR_Integrations.php 1 month ago CTF_Parse.php 1 month ago CTF_Settings.php 1 month ago CtfAdmin.php 1 month ago CtfCache.php 1 month ago CtfFeed.php 1 month ago CtfOauthConnect.php 1 month ago SB_Twitter_Cron_Updater.php 1 month ago admin-hooks.php 1 month ago ctf-functions.php 1 month ago notices.php 1 month ago widget.php 1 month ago
CtfFeed.php
2371 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 .= ' ' . $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_html = '';
1705
1706 $flags_att = '';
1707 $flags = array();
1708 if ( CTF_GDPR_Integrations::doing_gdpr( $feed_options ) ) {
1709 $flags[] = 'gdpr';
1710 }
1711 if ( ! is_admin() && CTF_Feed_Locator::should_do_ajax_locating( $this->feedID(), get_the_ID() ) ) {
1712 $flags[] = 'locator';
1713 }
1714 if ( ! empty( $flags ) ) {
1715 $flags_att = ' data-ctf-flags="' . implode( ',', $flags ) . '"';
1716 }
1717
1718 $post_id_att = ' data-postid="' . esc_attr( get_the_ID() ) . '"';
1719 $feed_id_att = ' data-feed-id="' . $this->feedID() . '"';
1720
1721 $ctf_feed_html .= '<!-- Custom Twitter Feeds by Smash Balloon -->';
1722 $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 .'">';
1723 $tweet_set = $this->tweet_set;
1724
1725 // dynamically include header
1726 if ( $feed_options['showheader'] ) {
1727 $ctf_feed_html .= $this->getFeedHeaderHtml( $tweet_set, $this->feed_options );
1728 }
1729
1730 $ctf_feed_html .= '<div class="ctf-tweets">';
1731
1732 return $ctf_feed_html;
1733 }
1734
1735 /**
1736 * creates opening html for the feed
1737 *
1738 * @return string opening html that creates the feed
1739 */
1740 public function getFeedClosingHtml()
1741 {
1742 $feed_options = $this->feed_options;
1743 $ctf_feed_html = '';
1744
1745 $ctf_feed_html .= '</div>'; // closing div for ctf-tweets
1746
1747 if ( $feed_options['showbutton'] ) {
1748 $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>';
1749 }
1750
1751 if ( $feed_options['creditctf'] ) {
1752 $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>';
1753 }
1754
1755 $ctf_feed_html .= '</div>'; // closing div tag for #ctf
1756 if ( $feed_options['ajax_theme'] ) {
1757 $ctf_feed_html .= '<script type="text/javascript" src="' . CTF_JS_URL . '"></script>';
1758 }
1759
1760 return $ctf_feed_html;
1761 }
1762
1763 /**
1764 * creates html for header of the feed
1765 *
1766 * @param $tweet_set string trimmed tweets to be added to the feed
1767 * @param $feed_options options for the feed
1768 * @return string html that creates the header of the feed
1769 */
1770 protected function getFeedHeaderHtml( $tweet_set, $feed_options )
1771 {
1772 $ctf_header_html = '';
1773 $ctf_no_bio = ( $feed_options['showbio'] && !empty($tweet_set[0]['user']['description']) ) ? '' : ' ctf-no-bio';
1774
1775 // temporary workaround for cached http images
1776 $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'];
1777
1778
1779 if ( $feed_options['type'] === 'usertimeline' ) {
1780 ### TEMPLATE HEADER
1781 $ctf_header_html .= '<div class="ctf-header' . $ctf_no_bio . '" style="' . $feed_options['headerbgcolor'] . '">';
1782 $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">';
1783 $ctf_header_html .= '<div class="ctf-header-text">';
1784 $ctf_header_html .= '<p class="ctf-header-user" style="' . $feed_options['headertextcolor'] . '">';
1785 $ctf_header_html .= '<span class="ctf-header-name">';
1786
1787 if ( $feed_options['headertext'] != '' ) {
1788 $ctf_header_html .= esc_html( $feed_options['headertext'] );
1789 } else {
1790 $ctf_header_html .= esc_html( $tweet_set[0]['user']['name'] );
1791 }
1792
1793 $ctf_header_html .= '</span>';
1794
1795 if ( $tweet_set[0]['user']['verified'] == 1 ) {
1796 $ctf_header_html .= '<span class="ctf-verified">' . ctf_get_fa_el( 'fa-check-circle' ) . '</span>';
1797 }
1798
1799 $ctf_header_html .= '<span class="ctf-header-follow">' . ctf_get_fa_el( 'fa-twitter' ) . __( 'Follow', 'custom-twitter-feeds' ) . '</span>';
1800 $ctf_header_html .= '</p>';
1801
1802 if ( $feed_options['showbio'] && !empty($tweet_set[0]['user']['description']) ) {
1803 $ctf_header_html .= '<p class="ctf-header-bio" style="' . $feed_options['headertextcolor'] . '">' . $tweet_set[0]['user']['description'] . '</p>';
1804 }
1805
1806 $ctf_header_html .= '</div>';
1807 $ctf_header_html .= '<div class="ctf-header-img">';
1808 $ctf_header_html .= '<div class="ctf-header-img-hover">' . ctf_get_fa_el( 'fa-twitter' ) . '</div>';
1809 if ( CTF_GDPR_Integrations::doing_gdpr( $feed_options ) ) {
1810 $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>';
1811 } else {
1812 $ctf_header_html .= '<img src="' . $tweet_set[0]['user']['profile_image_url_https'] . '" alt="' . $tweet_set[0]['user']['name'] . '" width="48" height="48">';
1813 }
1814 $ctf_header_html .= '</div>';
1815 $ctf_header_html .= '</a>';
1816 $ctf_header_html .= '</div>';
1817 } else {
1818 ### TEMPLATE HEADER GENERIC
1819 if ( $feed_options['type'] === 'search' ) {
1820 $default_header_text = $feed_options['headertext'] != '' ? esc_html($feed_options['headertext']) : $feed_options['feed_term'];
1821 $url_part = 'hashtag/' . str_replace("#", "", $feed_options['feed_term']);
1822 } else {
1823 $default_header_text = 'Twitter';
1824 $url_part = $feed_options['screenname']; //Need to get screenname here
1825 }
1826
1827 $default_header_text = str_replace( ' -filter:retweets', '', $default_header_text );
1828
1829 $ctf_header_html .= '<div class="ctf-header ctf-header-type-generic" style="' . $feed_options['headerbgcolor'] . '">';
1830 $ctf_header_html .= '<a href="https://twitter.com/' . $url_part . '" target="_blank" rel="noopener noreferrer" class="ctf-header-link">';
1831 $ctf_header_html .= '<div class="ctf-header-text">';
1832 $ctf_header_html .= '<p class="ctf-header-no-bio" style="' . $feed_options['headertextcolor'] . '">' . $default_header_text . '</p>';
1833 $ctf_header_html .= '</div>';
1834 $ctf_header_html .= '<div class="ctf-header-img">';
1835 $ctf_header_html .= '<div class="ctf-header-generic-icon">';
1836 $ctf_header_html .= ctf_get_fa_el( 'fa-twitter' );
1837 $ctf_header_html .= '</div>';
1838 $ctf_header_html .= '</div>';
1839 $ctf_header_html .= '</a>';
1840 $ctf_header_html .= '</div>';
1841 }
1842
1843 return $ctf_header_html;
1844 }
1845
1846 /**
1847 * outputs the html for a set of tweets to be used in the feed
1848 *
1849 * @param int $is_pagination 1 or 0, used to differentiate between the first set and subsequent tweet sets
1850 *
1851 * @return string $tweet_html
1852 */
1853 public function getTweetSetHtml( $is_pagination = 0 ){
1854 $feed_id = $this->feedID();
1855 $tweet_set = isset( $this->tweet_set['statuses'] ) ? $this->tweet_set['statuses'] : $this->tweet_set;
1856 $options = ctf_get_database_settings();
1857 $len = min( $this->feed_options['num'] + $is_pagination, count( $tweet_set ) );
1858 $i = $is_pagination; // starts at index "1" to offset duplicate tweet
1859 $feed_options = $this->feed_options;
1860 $tweet_html = $this->feed_html;
1861 $feed_id = $this->is_legacy ? $this->unique_legacy_id : $this->feed_id;
1862 $ctf_data_needed = $this->num_tweets_needed;
1863 $ctf_feed_classes = CTF_Parse::get_feed_classes($feed_options, $this->check_for_duplicates, $feed_id);
1864 $ctf_enable_intents = ((bool)$options['disableintents'] === false) && ctf_show('actions', $feed_options) ? ' data-ctfintents="1" ' : '';
1865 $ctf_main_atts = CTF_Display_Elements::get_feed_container_data_attributes( $feed_options, $feed_id, $this->feedID() ) . $ctf_enable_intents;
1866
1867
1868 if (!$is_pagination) {
1869 if ( empty( $this->was_error_or_empty( $this->tweet_set ) ) ) {
1870 $this->error_report->process_error( 'no_tweets_found_cache' );
1871 }
1872 ob_start();
1873 include ctf_get_feed_template_part('feed', $feed_options);
1874 $tweet_html .= ob_get_contents();
1875 ob_get_clean();
1876 }
1877
1878 return $tweet_html;
1879 }
1880
1881 public function getItemSetHtml($is_pagination = 0) {
1882 $options = get_option('ctf_options');
1883 $tweet_set = isset($this->tweet_set['statuses']) ? $this->tweet_set['statuses'] : $this->tweet_set;
1884 $tweet_count = CTF_Parse::get_tweet_count($tweet_set);
1885 $len = min($this->feed_options['num'] + $is_pagination, $tweet_count);
1886 if ( CTF_DOING_SMASH_TWITTER ) {
1887 $i = 0; // starts at index "1" to offset duplicate tweet
1888 $was_pagination = $is_pagination;
1889 $is_pagination = 0;
1890 $tweet_html = '';
1891 if ($was_pagination && (!isset($tweet_set[0]['id_str']))) {
1892 $tweet_html = $this->getOutOfTweetsHtml($this->feed_options);
1893 }
1894 } else {
1895 $i = $is_pagination; // starts at index "1" to offset duplicate tweet
1896 $tweet_html = '';
1897 if ($is_pagination && (!isset($tweet_set[1]['id_str']))) {
1898 $tweet_html = $this->getOutOfTweetsHtml($this->feed_options);
1899 }
1900 }
1901
1902 ob_start();
1903
1904 $this->tweet_loop($tweet_set, $this->feed_options, $is_pagination);
1905 $tweet_html .= ob_get_contents();
1906 ob_get_clean();
1907
1908 return $tweet_html;
1909 }
1910 /**
1911 * displays a message if there is an error in the feed
1912 *
1913 * @return string error html
1914 */
1915 public function getErrorHtml()
1916 {
1917 $error_html = '';
1918 $error_html .= '<div id="ctf" class="ctf" data-ctfshortcode="' . $this->getShortCodeJSON() . '">';
1919 $error_html .= '<div class="ctf-error">';
1920 $error_html .= '<div class="ctf-error-user">';
1921
1922 $error_html .= '</div>';
1923
1924 if ( current_user_can( 'manage_options' ) ) {
1925 $error_html .= '<div class="ctf-error-admin">';
1926 $error_html .= '<p><b>This message is only visible to admins:</b><br />';
1927 $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 />';
1928 if ($this->missing_credentials) {
1929 $error_html .= 'There is a problem with your access token, access token secret, consumer token, or consumer secret<br />';
1930 }
1931 $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>';
1932
1933 $error_html .= '</div>';
1934 } else {
1935 $error_html .= '<p>' . __( 'Twitter feed is not available at the moment.', 'custom-twitter-feeds' ) . '</p>';
1936 }
1937 $error_html .= '</div>'; // end .ctf-error
1938 $error_html .= '</div>'; // end #ctf
1939
1940 return $error_html;
1941 }
1942
1943
1944 public function tweet_loop( $tweet_set, $feed_options, $is_pagination ) {
1945 #$tweet_set = isset( $this->tweet_set['statuses'] ) ? $this->tweet_set['statuses'] : $this->tweet_set;
1946 $len = min( $this->feed_options['num'] + $is_pagination, count( (array)$tweet_set ) );
1947 $i = $is_pagination; // starts at index "1" to offset duplicate tweet
1948 $t = (count((array)$tweet_set) > 1 ? $t = 1 : 0); // Set index based on tweets returned
1949 $tweet_html = '';
1950 if ( $is_pagination && ( ! isset ( $tweet_set[1]['id_str'] ) ) ) {
1951 $tweet_html .= $this->getOutOfTweetsHtml( $this->feed_options );
1952 }
1953 if ($is_pagination > - 1 && (isset($tweet_set[$t]['id_str']))) {
1954
1955 while ( $i < $len ) {
1956 $post = $tweet_set[$i];
1957 if (isset($post['retweeted_status'])) {
1958 $retweeter = array(
1959 'name' => $post['user']['name'],
1960 'screen_name' => $post['user']['screen_name']
1961 );
1962 $post = $post['retweeted_status'];
1963 // temporary workaround for cached http images
1964 $post['user']['profile_image_url_https'] = isset($post['user']['profile_image_url_https']) ? $post['user']['profile_image_url_https'] : $post['user']['profile_image_url'];
1965 }
1966 else {
1967 unset($retweeter);
1968 }
1969 // check for quoted
1970 if (isset($post['quoted_status'])) {
1971 $quoted = $post['quoted_status'];
1972 }
1973 else {
1974 unset($quoted);
1975 }
1976 include ctf_get_feed_template_part('item', $feed_options);
1977 $i++;
1978 }
1979 }
1980 }
1981
1982 /**
1983 * Get Global Twitter Feed CSS
1984 *
1985 * @since 2.0
1986 * @return array
1987 */
1988 public function get_feed_style(){
1989 $feed_style = '';
1990 $feed_html_id = ($this->is_legacy ? $this->unique_legacy_id : $this->feed_id);
1991
1992 $feed_ctn = '.ctf-feed-' . $feed_html_id;
1993
1994 $css_array = [
1995 //Load More Button Style
1996 [
1997 'selector' => $feed_ctn . ' .ctf-more',
1998 'properties' => [
1999 'background-color' => [
2000 'value' => $this->feed_options['buttoncolor'],
2001 'important' => true
2002 ],
2003 'color' => [
2004 'value' => $this->feed_options['buttontextcolor'],
2005 'important' => true
2006 ]
2007 ]
2008 ],
2009 [
2010 'selector' => $feed_ctn . ' .ctf-more:hover',
2011 'properties' => [
2012 'background-color' => [
2013 'value' => $this->feed_options['buttonhovercolor'],
2014 'important' => true
2015 ]
2016 ]
2017 ],
2018 //Author Text Style
2019 [
2020 'selector' => $feed_ctn . ' .ctf-author-name',
2021 'properties' => [
2022 'color' => [
2023 'value' => $this->feed_options['authortextcolor'],
2024 'important' => true
2025 ],
2026 'font-size' => [
2027 'value' => $this->feed_options['authortextsize'],
2028 'important' => true
2029 ]
2030 ]
2031 ],
2032 //Tweet Text Style
2033 [
2034 'selector' => $feed_ctn . ' .ctf-tweet-text, ' .$feed_ctn . ' .ctf-quoted-tweet-text' ,
2035 'properties' => [
2036 'color' => [
2037 'value' => $this->feed_options['textcolor'],
2038 'important' => true
2039 ],
2040 'font-size' => [
2041 'value' => $this->feed_options['tweettextsize'],
2042 'important' => true
2043 ],
2044 'font-weight' => [
2045 'value' => $this->feed_options['tweettextweight'],
2046 'important' => true
2047 ]
2048 ]
2049 ],
2050 //Date Style
2051 [
2052 'selector' => $feed_ctn . ' .ctf-tweet-meta a',
2053 'properties' => [
2054 'color' => [
2055 'value' => $this->feed_options['datetextcolor'],
2056 'important' => true
2057 ],
2058 'font-size' => [
2059 'value' => $this->feed_options['datetextsize'],
2060 'important' => true
2061 ],
2062 'font-weight' => [
2063 'value' => $this->feed_options['datetextweight'],
2064 'important' => true
2065 ]
2066 ]
2067 ],
2068 //Icon Style
2069 [
2070 'selector' => $feed_ctn . ' .ctf-tweet-actions a',
2071 'properties' => [
2072 'color' => [
2073 'value' => $this->feed_options['iconcolor'],
2074 'important' => true
2075 ],
2076 'font-size' => [
2077 'value' => $this->feed_options['iconsize'],
2078 'important' => true
2079 ]
2080 ]
2081 ],
2082 //Quoted Tweet
2083 [
2084 'selector' => $feed_ctn . ' .ctf-quoted-tweet',
2085 'properties' => [
2086 'font-size' => [
2087 'value' => $this->feed_options['quotedauthorsize'],
2088 'important' => true
2089 ],
2090 'font-weight' => [
2091 'value' => $this->feed_options['quotedauthorweight'],
2092 'important' => true
2093 ],
2094 'color' => [
2095 'value' => $this->feed_options['textcolor'],
2096 'important' => true
2097 ]
2098 ]
2099 ],
2100 //Twitter Link Style
2101 [
2102 'selector' => $feed_ctn . ' .ctf-twitterlink',
2103 'properties' => [
2104 'font-size' => [
2105 'value' => floor( .8 * (int)$this->feed_options['iconsize'] ),
2106 'important' => true
2107 ],
2108 'color' => [
2109 'value' => $this->feed_options['textcolor'],
2110 'important' => true
2111 ]
2112 ]
2113 ],
2114 //Twitter Cards
2115 [
2116 'selector' => $feed_ctn . ' .ctf-tc-summary-info *',
2117 'properties' => [
2118 'font-size' => [
2119 'value' => floor( .8 * (int)$this->feed_options['cardstextsize'] ),
2120 'important' => true
2121 ],
2122 'color' => [
2123 'value' => $this->feed_options['cardstextcolor'],
2124 'important' => true
2125 ]
2126 ]
2127 ],
2128 //Text Header
2129 [
2130 'selector' => $feed_ctn . ' .ctf-header-type-text',
2131 'properties' => [
2132 'color' => [
2133 'value' => $this->feed_options['customheadertextcolor'],
2134 'important' => true
2135 ]
2136 ]
2137 ]
2138 ];
2139
2140 //Feed Container
2141 if( isset($this->feed_options['height']) && $this->feed_options['height'] != 0){
2142 array_push($css_array, [
2143 'selector' => $feed_ctn . '.ctf-fixed-height',
2144 'properties' => [
2145 'height' => [
2146 'value' => $this->feed_options['height'],
2147 'important' => true
2148 ],
2149 ]
2150 ]);
2151 }
2152 //Link Text Color
2153 if( !CTF_Feed_Builder::check_if_on( $this->feed_options['disablelinks'] ) ){
2154 array_push($css_array,[
2155 'selector' => $feed_ctn . ' .ctf-tweet-text a',
2156 'properties' => [
2157 'color' => [
2158 'value' => $this->feed_options['linktextcolor'],
2159 'important' => true
2160 ]
2161 ]
2162 ]
2163 );
2164 }
2165 //Feed Post item style / Boxed & Regular
2166 $post_item_css = [];
2167 if($this->feed_options['tweetpoststyle'] === 'boxed'){
2168 $post_item_css = [
2169 'selector' => $feed_ctn . '.ctf-boxed-style .ctf-item',
2170 'properties' => [
2171 'background-color' => [
2172 'value' => $this->feed_options['tweetbgcolor'],
2173 'important' => true
2174 ],
2175 'border-radius' => [
2176 'value' => $this->feed_options['tweetcorners']
2177 ]
2178 ]
2179 ];
2180 }else if($this->feed_options['tweetpoststyle'] === 'regular' && CTF_Feed_Builder::check_if_on( $this->feed_options['tweetsepline'] ) ){
2181 $post_item_css = [
2182 'selector' => $feed_ctn . '.ctf-regular-style .ctf-item, '. $feed_ctn . ' .ctf-header',
2183 'properties' => [
2184 'border-bottom' => [
2185 'size' => $this->feed_options['tweetsepsize'],
2186 'color' => $this->feed_options['tweetsepcolor'],
2187 'important' => true
2188 ]
2189 ]
2190 ];
2191 }
2192 array_push($css_array, $post_item_css);
2193
2194 //Color Pallete
2195 if( isset($this->feed_options['colorpalette']) && $this->feed_options['colorpalette'] == 'custom'){
2196
2197 //Custom Background Color
2198 array_push($css_array, [
2199 'selector' => $feed_ctn . '.ctf_palette_custom_' . $feed_html_id . ' .ctf-item, '. $feed_ctn . '.ctf_palette_custom_' . $feed_html_id . ' .ctf-header',
2200 'properties' => [
2201 'background' => [
2202 'value' => $this->feed_options['custombgcolor'],
2203 'important' => true
2204 ],
2205 ]
2206 ]);
2207 //Custom Accent Color
2208 array_push($css_array, [
2209 'selector' => $feed_ctn . '.ctf_palette_custom_' . $feed_html_id . ' .ctf-corner-logo',
2210 'properties' => [
2211 'color' => [
2212 'value' => $this->feed_options['customaccentcolor'],
2213 'important' => true
2214 ],
2215 ]
2216 ]);
2217 //Custom Text 1 Color
2218 array_push($css_array, [
2219 'selector' => $feed_ctn . '.ctf_palette_custom_' . $feed_html_id . ' .ctf-author-name, .ctf_palette_custom_' . $feed_html_id . ' .ctf-tweet-text',
2220 'properties' => [
2221 'color' => [
2222 'value' => $this->feed_options['customtextcolor1'],
2223 'important' => true
2224 ],
2225 ]
2226 ]);
2227
2228 //Custom Text 2 Color
2229 array_push($css_array, [
2230 'selector' => $feed_ctn . '.ctf_palette_custom_' . $feed_html_id . ' .ctf-author-screenname',
2231 'properties' => [
2232 'color' => [
2233 'value' => $this->feed_options['customtextcolor2'],
2234 'important' => true
2235 ],
2236 ]
2237 ]);
2238
2239 //Custom Link Color
2240 array_push($css_array, [
2241 'selector' => $feed_ctn . '.ctf_palette_custom_' . $feed_html_id . ' .ctf-tweet-text a',
2242 'properties' => [
2243 'color' => [
2244 'value' => $this->feed_options['customlinkcolor'],
2245 'important' => true
2246 ],
2247 ]
2248 ]);
2249 }
2250
2251 //Legacy Feeds
2252 if( $this->is_legacy == true ){
2253 array_push($css_array,
2254 [
2255 'selector' => $feed_ctn . ' .ctf-item',
2256 'properties' => [
2257 'background-color' => [
2258 'value' => $this->feed_options['tweetbgcolor'],
2259 'important' => true
2260 ]
2261 ]
2262 ],
2263 [
2264 'selector' => $feed_ctn . ' .ctf-corner-logo ',
2265 'properties' => [
2266 'font-size' => [
2267 'value' => $this->feed_options['logosize'],
2268 'important' => true
2269 ],
2270 'color' => [
2271 'value' => $this->feed_options['logocolor'],
2272 'important' => true
2273 ]
2274 ]
2275 ],
2276 [
2277 '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',
2278 'properties' => [
2279 'font-size' => [
2280 'value' => $this->feed_options['authortextsize'],
2281 'important' => true
2282 ],
2283 'font-weight' => [
2284 'value' => $this->feed_options['authortextweight']
2285 ],
2286 'color' => [
2287 'value' => $this->feed_options['textcolor'],
2288 ]
2289 ]
2290 ],
2291 [
2292 'selector' => $feed_ctn . ' .ctf-header-user, ' . $feed_ctn . ' .ctf-header-bio, ' . $feed_ctn . ' .ctf-header-no-bio' ,
2293 'properties' => [
2294 'color' => [
2295 'value' => $this->feed_options['headertextcolor'],
2296 'important' => true
2297 ]
2298 ]
2299 ],
2300 [
2301 'selector' => $feed_ctn . ' .ctf-header' ,
2302 'properties' => [
2303 'background-color' => [
2304 'value' => $this->feed_options['headerbgcolor'],
2305 'important' => true
2306 ]
2307 ]
2308 ],
2309 [
2310 'selector' => $feed_ctn,
2311 'properties' => [
2312 'background-color' => [
2313 'value' => $this->feed_options['bgcolor'],
2314 'important' => true
2315 ],
2316 'height' => [
2317 'value' => $this->feed_options['height'],
2318 'unit' => $this->feed_options['height_unit'],
2319 'important' => true
2320 ],
2321 'width' => [
2322 'value' => $this->feed_options['width'],
2323 'unit' => $this->feed_options['width_unit'],
2324 'important' => true
2325 ]
2326 ]
2327 ]
2328
2329
2330 );
2331
2332 }
2333
2334 $feed_style .= '<style type="text/css" data-ctf-style="' . $feed_html_id . '">';
2335 $feed_style .= CTF_Parse::parse_css_style( $css_array );
2336 $feed_style .= '</style>';
2337 echo $feed_style;
2338 }
2339
2340 /**
2341 * @return mixed
2342 * @since 2.0
2343 */
2344 public static function get_legacy_feed_settings() {
2345 return json_decode( get_option( 'ctf_legacy_feed_settings', '{}' ), true );
2346 }
2347
2348 public function get_legacy_feed_unique_id() {
2349 return $this->unique_legacy_id;
2350 }
2351
2352 public function should_show_footer( $tweet_set ) {
2353 return $this->was_error_or_empty( $tweet_set );
2354 }
2355
2356 public function was_error_or_empty( $tweet_set ) {
2357 if ( empty( $tweet_set ) ) {
2358 return false;
2359 }
2360 if ( ! empty( $tweet_set ) && isset( $tweet_set[0] ) && is_string( $tweet_set[0] ) && $tweet_set[0] === 'error' ) {
2361 return false;
2362 }
2363 $error = $this->error_report->get_critical_error();
2364 if ( ! empty( $error ) && empty( $tweet_set ) ) {
2365 return false;
2366 }
2367
2368 return true;
2369 }
2370 }
2371