PluginProbe ʕ •ᴥ•ʔ
Custom Twitter Feeds – A Tweets Widget or X Feed Widget / 2.8.0
Custom Twitter Feeds – A Tweets Widget or X Feed Widget v2.8.0
2.8.0 2.7.0 2.6.1 2.6.0 1.0 1.0.1 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.2 1.2.1 1.2.10 1.2.11 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3 1.4 1.4.1 1.5 1.5.1 1.6 1.6.1 1.7 1.8 1.8.1 1.8.2 1.8.3 1.8.4 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1 2.1.1 2.1.2 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.5.4 2.5.5 trunk
custom-twitter-feeds / custom-twitter-feed.php
custom-twitter-feeds Last commit date
admin 4 weeks ago assets 4 weeks ago css 4 weeks ago img 4 weeks ago inc 4 weeks ago js 4 weeks ago languages 4 weeks ago templates 4 weeks ago vendor 4 weeks ago views 4 weeks ago README.md 4 weeks ago README.txt 1 week ago changelog.txt 4 weeks ago custom-twitter-feed.php 4 weeks ago uninstall.php 4 weeks ago
custom-twitter-feed.php
1174 lines
1 <?php
2
3 use TwitterFeed\Builder\CTF_Feed_Builder;
4 /*
5 Plugin Name: Smash Balloon X (Twitter) Feed
6 Plugin URI: https://smashballoon.com/custom-twitter-feeds
7 Description: Customizable X Feeds, formerly known as Twitter feeds, for your website
8 Version: 2.8.0
9 Author: Smash Balloon
10 Author URI: https://smashballoon.com/
11 Text Domain: custom-twitter-feeds
12 */
13 /*
14 Copyright 2025 Smash Balloon LLC (email : hey@smashballoon.com)
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 */
27
28 if ( ! defined( 'CTF_URL' ) ) {
29 // Use smash Twitter if API V2 credentials are not defined.
30 $ctf_options = get_option('ctf_options', array());
31 define( 'CTF_DOING_SMASH_TWITTER', empty($ctf_options['consumer_key']) && empty($ctf_options['consumer_secret']));
32
33 define( 'CTF_URL', plugin_dir_path( __FILE__ ) );
34 define( 'CTF_VERSION', '2.8.0' );
35 define( 'CTF_TITLE', 'Custom Twitter Feeds' );
36 define( 'CTF_JS_URL', plugins_url( '/js/ctf-scripts.min.js?ver=' . CTF_VERSION , __FILE__ ) );
37 define( 'CTF_PRODUCT_NAME', 'Custom Twitter Feeds' );
38 }
39
40 if ( ! defined( 'CTF_SITE_ACCESS_TOKEN_KEY' ) ) {
41 define( 'CTF_SITE_ACCESS_TOKEN_KEY', 'site_access_token_free' );
42 }
43 if ( ! defined( 'SMASH_TWITTER_URL' ) ) {
44 define( 'SMASH_TWITTER_URL', 'https://ctf.smashballoon.com/api/' );
45 }
46 if ( ! defined( 'SMASH_TWITTER_TIMELINE_PATH' ) ) {
47 define( 'SMASH_TWITTER_TIMELINE_PATH', '1.1/timeline' );
48 }
49
50 if ( ! defined( 'SMASH_TWITTER_URL_EXTRA_GET_PARAMS' ) ) {
51 define( 'SMASH_TWITTER_URL_EXTRA_GET_PARAMS', '' );
52 }
53
54 if ( ! defined( 'OAUTH_PROCESSOR_URL' ) ) {
55 define( 'OAUTH_PROCESSOR_URL', 'https://connect.smashballoon.com/auth/tw/' );
56 }
57
58 if ( ! defined( 'CTF_PLUGIN_NAME' ) ) {
59 define( 'CTF_PLUGIN_NAME', 'Custom Twitter Feeds' );
60 }
61 if ( ! defined( 'CTF_SMASH_USAGE_TRACKING_API_URL' ) ) {
62 define( 'CTF_SMASH_USAGE_TRACKING_API_URL', 'https://usage.smashballoon.com/api' );
63 }
64
65 // Plugin Folder Path.
66 if ( ! defined( 'CTF_PLUGIN_DIR' ) ) {
67 define( 'CTF_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
68 }
69 // Plugin Folder URL.
70 if ( ! defined( 'CTF_PLUGIN_URL' ) ) {
71 define( 'CTF_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
72 }
73 // Db version.
74 if ( ! defined( 'CTF_DBVERSION' ) ) {
75 define( 'CTF_DBVERSION', '1.5' );
76 }
77 if ( ! defined( 'CTF_FEED_LOCATOR' ) ) {
78 define( 'CTF_FEED_LOCATOR', 'ctf_feed_locator' );
79 }
80
81 if ( ! defined( 'CTF_BUILDER_DIR' ) ) {
82 define( 'CTF_BUILDER_DIR', CTF_PLUGIN_DIR . 'admin/builder/' );
83 }
84 if ( ! defined( 'CTF_BUILDER_URL' ) ) {
85 define( 'CTF_BUILDER_URL', CTF_PLUGIN_URL . 'admin/builder/' );
86 }
87 if ( ! defined( 'CTF_UPLOADS_NAME' ) ) {
88 define( 'CTF_UPLOADS_NAME', 'sb-twitter-feed-images' );
89 }
90
91 if ( ! defined( 'CTF_PLUGIN_NAME' ) ) {
92 define( 'CTF_PLUGIN_NAME', 'Custom Twitter Feed Free' );
93 }
94 if ( ! defined( 'CTF_FEEDS_POSTS_TABLE' ) ) {
95 define( 'CTF_FEEDS_POSTS_TABLE', 'ctf_feeds_posts' );
96 }
97 if ( ! defined( 'CTF_POSTS_TABLE' ) ) {
98 define( 'CTF_POSTS_TABLE', 'ctf_posts' );
99 }
100 if ( ! defined( 'CTF_LICENSE_URL' ) ) {
101 define( 'CTF_LICENSE_URL', 'https://smashballoon.com/' );
102 }
103
104 if ( ! defined( 'CTF_PLUGIN_BASENAME' ) ) {
105 define( 'CTF_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
106 }
107
108 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
109
110 if ( version_compare( phpversion(), '7.4', '<' ) ) {
111 if( !function_exists( 'ctf_check_php_notice' ) ){
112 function ctf_check_php_notice(){ ?>
113 <div class="notice notice-error">
114 <div>
115 <p><strong><?php echo esc_html__('Important:','custom-twitter-feeds') ?> </strong><?php echo esc_html__('Your website is using an outdated version of PHP. The Custom Twitter Feeds plugin requires PHP version 7.4 or higher and so has been temporarily deactivated.','custom-twitter-feeds') ?></p>
116
117 <p>
118 <?php
119 echo esc_html__('To continue using the plugin','custom-twitter-feeds') . ', ';
120
121 echo __('you can either manually reinstall the previous version of the plugin ','custom-twitter-feeds' );
122
123 echo esc_html__('or contact your host to request that they upgrade your PHP version to 7.4 or higher.','custom-twitter-feeds');
124 ?>
125 </p>
126 </div>
127 </div>
128 <?php
129 }
130 }
131 add_action( 'admin_notices', 'ctf_check_php_notice' );
132 return; //Stop until PHP version is fixed
133 }
134
135 require_once( CTF_URL . '/inc/widget.php' );
136
137 require_once( CTF_URL . '/inc/admin-hooks.php' );
138
139 function ctf_plugin_init() {
140 require_once trailingslashit( CTF_PLUGIN_DIR ) . 'inc/blocks/class-ctf-blocks.php';
141
142 $ctf_blocks = new CTF_Blocks();
143
144 if ( $ctf_blocks->allow_load() ) {
145 $ctf_blocks->load();
146 }
147
148 require trailingslashit( CTF_PLUGIN_DIR ) . 'vendor/autoload.php';
149 include_once trailingslashit( CTF_PLUGIN_DIR ) . '/inc/ctf-functions.php';
150
151 // Initialize modern feed block after autoloader is available (CTF_Modern_Feed_Block extends vendor SB_Feed_Block).
152 require_once trailingslashit( CTF_PLUGIN_DIR ) . 'inc/blocks/CTF_Modern_Feed_Block.php';
153 $modern_block = new \TwitterFeed\Admin\Blocks\CTF_Modern_Feed_Block();
154 $modern_block->register_hooks();
155
156 // Initialize the deactivation feedback survey.
157 if ( class_exists( '\Smashballoon\TwitterFeed\Vendor\Smashballoon\Framework\Packages\Feedback\FeedbackManager' ) ) {
158 \Smashballoon\TwitterFeed\Vendor\Smashballoon\Framework\Packages\Feedback\FeedbackManager::init(
159 [
160 'plugin_slug' => 'custom-twitter-feeds',
161 'plugin_name' => 'Smash Balloon Custom Twitter Feeds',
162 'plugin_version' => CTF_VERSION,
163 'plugin_file' => CTF_PLUGIN_DIR . 'custom-twitter-feed.php',
164 'support_url' => 'https://smashballoon.com/support/?utm_campaign=twitter-free&utm_source=plugin&utm_medium=support',
165 'enable_help_widget' => true,
166 'help_url' => 'https://smashballoon.com/docs/twitter/',
167 ]
168 );
169 }
170
171 if ( is_admin() ) {
172 if ( version_compare( PHP_VERSION, '5.3.0' ) >= 0
173 && version_compare( get_bloginfo('version'), '4.6' , '>' ) ) {
174 $ctf_notifications = new TwitterFeed\Admin\CTF_Notifications();
175 $ctf_notifications->init();
176
177 $ctf_new_user = new TwitterFeed\Admin\CTF_New_User();
178 $ctf_new_user->init();
179
180 $ctf_global_settings = new TwitterFeed\Admin\CTF_Global_Settings();
181 $ctf_admin_notices = new TwitterFeed\Admin\CTF_Admin_Notices();
182 $ctf_tooltip_wizard = new TwitterFeed\Builder\CTF_Tooltip_Wizard();
183 $ctf_support = new TwitterFeed\Admin\CTF_Support();
184 $ctf_admin_notices = new TwitterFeed\Admin\CTF_Admin_Notices();
185 $ctf_about_us = new TwitterFeed\Admin\CTF_About_Us();
186
187
188 require_once trailingslashit( CTF_PLUGIN_DIR ) . 'inc/Admin/addon-functions.php';
189 }
190 }
191 require_once trailingslashit( CTF_PLUGIN_DIR ) . 'inc/Admin/CTF_Upgrader.php';
192 $ctf_upgrader = new TwitterFeed\Admin\CTF_Upgrader();
193 $ctf_upgrader->hooks();
194
195
196 $cron_update_manager = new \TwitterFeed\SmashTwitter\CronUpdaterManager();
197 $cron_update_manager->hooks();
198
199 $error_reporter = new \TwitterFeed\SmashTwitter\Services\ErrorReporterService();
200 $error_reporter->init_hooks();
201
202 $GLOBALS['ctf_smash_usage_tracking'] = new \TwitterFeed\UsageTracking\SmashUsageTracking();
203
204 // Initialize Elementor integration.
205 \TwitterFeed\Integrations\Elementor\CTF_Elementor_Base::register();
206
207 // Initialize recommended blocks in Gutenberg sidebar.
208 $recommended_blocks = new \Smashballoon\TwitterFeed\Vendor\Smashballoon\Framework\Packages\Blocks\RecommendedBlocks();
209 $recommended_blocks->setup();
210 }
211 add_action( 'plugins_loaded', 'ctf_plugin_init' );
212
213 include_once trailingslashit( CTF_PLUGIN_DIR ) . '/inc/Builder/CTF_Feed_Builder.php';
214
215
216 function ctf_update_settings() {
217 $existing_deprecated_options = get_option( 'ctf_configure' );
218 $existing_options = get_option( 'ctf_options' );
219
220 update_option( 'ctf_version', CTF_VERSION );
221
222 if ( ! empty( $existing_deprecated_options ) && empty( $existing_options ) ) {
223 $merged_options = $existing_deprecated_options;
224 $merged_options = array_merge( $merged_options, get_option( 'ctf_customize', array() ) );
225 $merged_options = array_merge( $merged_options, get_option( 'ctf_style', array() ) );
226
227 update_option( 'ctf_options', $merged_options );
228 }
229 }
230
231 function ctf_check_for_db_updates() {
232
233 $db_ver = get_option( 'ctf_db_version', 0 );
234
235 if ( (float) $db_ver < 1.0 ) {
236 global $wp_roles;
237 $wp_roles->add_cap( 'administrator', 'manage_twitter_feed_options' );
238
239 $ctf_statuses_option = get_option( 'ctf_statuses', array() );
240
241 if ( ! isset( $ctf_statuses_option['first_install'] ) ) {
242
243 $options_set = get_option( 'ctf_options', false );
244
245 if ( $options_set ) {
246 $ctf_statuses_option['first_install'] = 'from_update';
247 } else {
248 $ctf_statuses_option['first_install'] = time();
249 }
250
251 $ctf_rating_notice_option = get_option( 'ctf_rating_notice', false );
252
253 if ( $ctf_rating_notice_option === 'dismissed' ) {
254 $ctf_statuses_option['rating_notice_dismissed'] = time();
255 }
256
257 $ctf_rating_notice_waiting = get_transient( 'custom_twitter_feeds_rating_notice_waiting' );
258
259 if ( $ctf_rating_notice_waiting === false
260 && $ctf_rating_notice_option === false ) {
261 $time = 2 * WEEK_IN_SECONDS;
262 set_transient( 'custom_twitter_feeds_rating_notice_waiting', 'waiting', $time );
263 update_option( 'ctf_rating_notice', 'pending', false );
264 }
265
266 update_option( 'ctf_statuses', $ctf_statuses_option, false );
267
268 }
269
270 update_option( 'ctf_db_version', CTF_DBVERSION );
271 }
272
273 if ( version_compare( $db_ver, '1.0.1', '<' ) ) {
274 TwitterFeed\CTF_Feed_Locator::create_table();
275 update_option( 'ctf_db_version', CTF_DBVERSION );
276 }
277
278 // For v2.0
279 if ( version_compare( $db_ver, '1.4', '<' ) ) {
280 update_option( 'ctf_db_version', CTF_DBVERSION );
281 \TwitterFeed\Builder\CTF_Db::create_tables();
282 $ctf_statuses_option = get_option( 'ctf_statuses', array() );
283 $ctf_options = get_option( 'ctf_options', array() );
284
285 if ( ! isset( $ctf_statuses_option['first_install'] ) ) {
286
287 $options_set = get_option( 'ctf_options', false );
288
289 if ( $options_set ) {
290 $ctf_statuses_option['first_install'] = 'from_update';
291 } else {
292 $ctf_statuses_option['first_install'] = time();
293 }
294
295 $ctf_rating_notice_option = get_option( 'ctf_rating_notice', false );
296
297 if ( $ctf_rating_notice_option === 'dismissed' ) {
298 $ctf_statuses_option['rating_notice_dismissed'] = time();
299 }
300
301 $ctf_rating_notice_waiting = get_transient( 'custom_twitter_feeds_rating_notice_waiting' );
302
303 if ( $ctf_rating_notice_waiting === false
304 && $ctf_rating_notice_option === false ) {
305 $time = 2 * WEEK_IN_SECONDS;
306 set_transient( 'custom_twitter_feeds_rating_notice_waiting', 'waiting', $time );
307 update_option( 'ctf_rating_notice', 'pending', false );
308 }
309 }
310
311 //Legacy feeds
312 $options_support_legacy = false;
313
314 if ( isset( $ctf_options['access_token'] ) && ! empty( $ctf_options['access_token'] ) ) {
315 $options_support_legacy = true;
316 $base_settings = \TwitterFeed\CTF_Settings::legacy_shortcode_atts( array(), $ctf_options );
317 update_option( 'ctf_legacy_feed_settings', ctf_json_encode( $base_settings ), false );
318 }
319 // how many legacy feeds?
320 $args = array(
321 'html_location' => array( 'header', 'footer', 'sidebar', 'content', 'unknown' ),
322 'group_by' => 'shortcode_atts',
323 'page' => 1,
324 );
325
326 $feeds_data = \TwitterFeed\CTF_Feed_Locator::legacy_twitter_feed_locator_query( $args );
327 $num_legacy = count( $feeds_data );
328 $ctf_statuses_option['support_legacy_shortcode'] = $options_support_legacy;
329 if ( $num_legacy > 0 ) {
330 if ( $num_legacy > 1 ) {
331 $ctf_statuses_option['legacy_onboarding'] = array(
332 'active' => true,
333 'type' => 'multiple',
334 );
335 $ctf_statuses_option['support_legacy_shortcode'] = true;
336 } else {
337 $ctf_statuses_option['legacy_onboarding'] = array(
338 'active' => true,
339 'type' => 'single',
340 );
341
342 $shortcode_atts = ! empty( $feeds_data[0] ) && $feeds_data[0]['shortcode_atts'] != '[""]' ? json_decode( $feeds_data[0]['shortcode_atts'], true ) : array();
343 $shortcode_atts = is_array( $shortcode_atts ) ? $shortcode_atts : array();
344
345 $ctf_statuses_option['support_legacy_shortcode'] = $shortcode_atts;
346
347 $shortcode_atts['from_update'] = true;
348
349 $db = ctf_get_database_settings();
350 $base_settings = \TwitterFeed\CTF_Settings::legacy_shortcode_atts( $shortcode_atts, $db );
351
352 $feed_saver = new \TwitterFeed\Builder\CTF_Feed_Saver( false );
353 $feed_saver->set_data( $base_settings );
354
355 $feed_name = 'My Feed';
356 $feed_saver->set_feed_name( $feed_name );
357
358 $new_feed_id = $feed_saver->update_or_insert();
359
360 $args = array(
361 'new_feed_id' => $new_feed_id,
362 'legacy_feed_id' => $feeds_data[0]['feed_id'],
363 );
364
365 \TwitterFeed\CTF_Feed_Locator::update_legacy_to_builder( $args );
366 }
367 } elseif ( $num_legacy === 0 && $options_support_legacy ) {
368 $ctf_statuses_option['support_legacy_shortcode'] = true;
369 }
370
371 update_option( 'ctf_statuses', $ctf_statuses_option, false );
372 update_option( 'ctf_db_version', CTF_DBVERSION );
373
374 if ( ! wp_next_scheduled( 'ctf_feed_update' ) ) {
375 wp_schedule_event( time() + 60, 'twicedaily', 'ctf_feed_update' );
376 }
377
378 global $wp_roles;
379 $wp_roles->add_cap( 'administrator', 'manage_twitter_feed_options' );
380
381 }
382
383 // For Smash Twitter
384 if ( version_compare( $db_ver, '1.5', '<' ) ) {
385 update_option( 'ctf_db_version', CTF_DBVERSION );
386 global $wpdb;
387 ctf_create_database_table();
388 $table_name = $wpdb->prefix . CTF_FEEDS_POSTS_TABLE;
389
390 $wpdb->query( "ALTER TABLE $table_name ADD COLUMN type VARCHAR(1000) DEFAULT '' NOT NULL" );
391 $wpdb->query( "ALTER TABLE $table_name ADD COLUMN term VARCHAR(1000) DEFAULT '' NOT NULL" );
392 $wpdb->query( "ALTER TABLE $table_name ADD INDEX type_term (term(140),type(51))" );
393
394 \TwitterFeed\SmashTwitter\CronUpdaterManager::schedule_cron_job();
395
396 $ctf_statuses_option = get_option( 'ctf_statuses', array() );
397 // to space out the API requests, we have the initial cron update scheduled a day + random number of hours.
398 $ctf_statuses_option['first_cron_update'] = mt_rand(0,23) * 3600 + time() + DAY_IN_SECONDS;
399 update_option( 'ctf_statuses', $ctf_statuses_option, false );
400
401 update_option( 'ctf_db_version', CTF_DBVERSION );
402
403 }
404
405 }
406 add_action( 'wp_loaded', 'ctf_check_for_db_updates' );
407
408
409 /**
410 * include the admin files only if in the admin area
411 */
412 if ( is_admin() ) {
413
414 $ctf_version = get_option( 'ctf_version', false );
415
416 if ( ! $ctf_version ) {
417 ctf_update_settings();
418 }
419 require_once( CTF_URL . '/inc/CtfAdmin.php' );
420 require_once( CTF_URL . '/inc/notices.php' );
421
422 $admin = new CtfAdmin;
423 }
424
425 /**
426 * Generates the Twitter feed wherever the shortcode is placed
427 *
428 * @param $atts array shortcode arguments
429 *
430 * @return string
431 */
432 function ctf_init( $atts, $preview_settings = false ) {
433 wp_enqueue_script( 'ctf_scripts' );
434 $twitter_feed = TwitterFeed\CtfFeed::init( $atts, null, 0, array(), 1, $preview_settings);
435 if ( isset( $twitter_feed->feed_options['feederror'] ) && ! empty( $twitter_feed->feed_options['feederror'] ) ) {
436 return "<span id='ctf-no-id'>" . sprintf( __( 'No feed found with the ID %1$s. Go to the %2$sAll Feeds page%3$s and select an ID from an existing feed.', 'custom-twitter-feeds' ), esc_html( $twitter_feed->feed_options['feed'] ), '<a href="' . esc_url( admin_url( 'admin.php?page=ctf-feed-builder' ) ) . '">', '</a>' ) . '</span><br /><br />';
437 } else {
438 // if there is an error, display the error html, otherwise the feed
439 if ( ! $twitter_feed->tweet_set || ($twitter_feed->missing_credentials && ! CTF_DOING_SMASH_TWITTER) || ! isset( $twitter_feed->tweet_set[0]['created_at'] ) ) {
440 if ( ! empty( $twitter_feed->tweet_set['errors'] ) ) {
441 $twitter_feed->maybeCacheTweets();
442 } else {
443 $twitter_feed->maybeCacheTweets(true);
444 }
445 $feed_html = '';
446 $feed_html .= $twitter_feed->getTweetSetHtml();
447
448 return $feed_html;
449 } else {
450 if ( ! $twitter_feed->feed_options['persistentcache'] ) {
451 $twitter_feed->maybeCacheTweets();
452 }
453 $feed_html = '';
454 $feed_html .= $twitter_feed->getTweetSetHtml();
455
456 return $feed_html;
457 }
458 }
459 }
460 add_shortcode( 'custom-twitter-feed', 'ctf_init' );
461 add_shortcode( 'custom-twitter-feeds', 'ctf_init' );
462
463 /**
464 * Called via ajax to get more posts after the "load more" button is clicked
465 */
466 function ctf_get_more_posts() {
467 $shortcode_data = json_decode( str_replace( '\"', '"', sanitize_text_field( $_POST['shortcode_data'] ) ), true ); // necessary to unescape quotes
468 $last_id_data = isset( $_POST['last_id_data'] ) ? sanitize_text_field( $_POST['last_id_data'] ) : '';
469 $num_needed = isset( $_POST['num_needed'] ) ? (int)$_POST['num_needed'] : 0;
470 $ids_to_remove = isset( $_POST['ids_to_remove'] ) ? $_POST['ids_to_remove'] : array();
471 $feed = isset( $_POST['v2feed'] ) ? sanitize_key( $_POST['v2feed'] ) : '';
472 if ( empty( $shortcode_data ) ) {
473 $shortcode_data = array();
474 }
475 $shortcode_data['feed'] = $feed;
476
477 $is_pagination = empty( $last_id_data ) ? 0 : 1;
478 $persistent_index = isset( $_POST['persistent_index'] ) ? sanitize_text_field( $_POST['persistent_index'] ) : '';
479
480 $twitter_feed = TwitterFeed\CtfFeed::init( $shortcode_data, $last_id_data, $num_needed, $ids_to_remove, $persistent_index );
481
482 if ( ! CTF_DOING_SMASH_TWITTER && ! $twitter_feed->feed_options['persistentcache'] ) {
483 $twitter_feed->maybeCacheTweets();
484 }
485
486 $atts = $shortcode_data;
487 $feed_id = isset( $_POST['feed_id'] ) ? sanitize_text_field( $_POST['feed_id'] ) : 'unknown';
488 $location = isset( $_POST['location'] ) && in_array( $_POST['location'], array( 'header', 'footer', 'sidebar', 'content' ), true ) ? sanitize_text_field( $_POST['location'] ) : 'unknown';
489 $post_id = isset( $_POST['post_id'] ) && $_POST['post_id'] !== 'unknown' ? (int)$_POST['post_id'] : 'unknown';
490 $feed_details = array(
491 'feed_id' => $feed_id,
492 'atts' => $atts,
493 'location' => array(
494 'post_id' => $post_id,
495 'html' => $location
496 )
497 );
498
499 ctf_do_background_tasks( $feed_details );
500
501 echo $twitter_feed->getItemSetHtml( $is_pagination );
502
503 die();
504 }
505 add_action( 'wp_ajax_nopriv_ctf_get_more_posts', 'ctf_get_more_posts' );
506 add_action( 'wp_ajax_ctf_get_more_posts', 'ctf_get_more_posts' );
507
508 function ctf_do_locator() {
509 if ( ! isset( $_POST['feed_id'] ) || strpos( $_POST['feed_id'], 'ctf' ) === false ) {
510 die( 'invalid feed ID');
511 }
512
513 $feed_id = sanitize_text_field( $_POST['feed_id'] );
514
515 $atts_raw = isset( $_POST['atts'] ) ? json_decode( stripslashes( $_POST['atts'] ), true ) : array();
516 if ( is_array( $atts_raw ) ) {
517 array_map( 'sanitize_text_field', $atts_raw );
518 } else {
519 $atts_raw = array();
520 }
521 $atts = $atts_raw; // now sanitized
522
523 $location = isset( $_POST['location'] ) && in_array( $_POST['location'], array( 'header', 'footer', 'sidebar', 'content' ), true ) ? sanitize_text_field( $_POST['location'] ) : 'unknown';
524 $post_id = isset( $_POST['post_id'] ) && $_POST['post_id'] !== 'unknown' ? (int)$_POST['post_id'] : 'unknown';
525 $feed_details = array(
526 'feed_id' => $feed_id,
527 'atts' => $atts,
528 'location' => array(
529 'post_id' => $post_id,
530 'html' => $location
531 )
532 );
533
534 ctf_do_background_tasks( $feed_details );
535
536 wp_die( 'locating success' );
537 }
538 add_action( 'wp_ajax_ctf_do_locator', 'ctf_do_locator' );
539 add_action( 'wp_ajax_nopriv_ctf_do_locator', 'ctf_do_locator' );
540
541 function ctf_do_background_tasks( $feed_details ) {
542 $locator = new TwitterFeed\CTF_Feed_Locator( $feed_details );
543 $locator->add_or_update_entry();
544 if ( $locator->should_clear_old_locations() ) {
545 $locator->delete_old_locations();
546 }
547 }
548
549 function ctf_plugin_action_links( $links ) {
550 $pro_link = '<a href="https://smashballoon.com/custom-twitter-feeds/demo/?utm_campaign=twitter-free&utm_source=plugins-page&utm_medium=upgrade-link" target="_blank" style="font-weight: bold; color: #1da867;">' . __( 'Try the Pro Demo', 'custom-twitter-feeds' ) . '</a>';
551 $settings_link = '<a href="'. esc_url( admin_url( 'admin.php?page=ctf-feed-builder' ) ) .'">' . __( 'Settings' ) . '</a>';
552 array_unshift( $links, $pro_link, $settings_link );
553
554 return $links;
555 }
556 add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), 'ctf_plugin_action_links' );
557
558 function ctf_json_encode( $thing ) {
559 if ( function_exists( 'wp_json_encode' ) ) {
560 return wp_json_encode( $thing );
561 } else {
562 return json_encode( $thing );
563 }
564 }
565
566 /**
567 * the html output is controlled by the user selecting which portions of tweets to show
568 *
569 * @param $part string part of the feed in the html
570 * @param $feed_options array options that contain what parts of the tweet to show
571 * @return bool whether or not to show the tweet
572 */
573 function ctf_show( $part, $feed_options ) {
574 if ( ctf_doing_customizer( $feed_options ) ) {
575 return true;
576 }
577
578 $tweet_excludes = isset( $feed_options['tweet_excludes'] ) ? $feed_options['tweet_excludes'] : '';
579 $tweet_includes = isset( $feed_options['tweet_includes'] ) ? $feed_options['tweet_includes'] : '';
580
581 // if part is in the array of excluded parts or not in the array of included parts, don't show
582 if ( ! empty( $tweet_excludes ) ) {
583 return ( in_array( $part, (array) $tweet_excludes ) === false );
584 } else {
585 return ( in_array( $part, (array) $tweet_includes ) === true );
586 }
587 }
588
589 /**
590 * this function returns the properly formatted date string based on user input
591 *
592 * @param $raw_date string the date from the Twitter api
593 * @param $feed_options array options for the feed that contain date formatting settings
594 * @param $utc_offset int offset in seconds for the time display based on timezone
595 * @return string formatted date
596 */
597 function ctf_get_formatted_date( $raw_date, $feed_options, $utc_offset ) {
598
599 $options = get_option( 'ctf_options' );
600 $timezone = isset( $options['timezone'] ) ? $options['timezone'] : 'default';
601 // use php \DateTimeZone class to handle the date formatting and offsets
602 $date_obj = new \DateTime($raw_date, new \DateTimeZone('UTC'));
603
604 if ( $timezone != 'default' ) {
605 $date_obj->setTimeZone( new \DateTimeZone( $timezone ) );
606 $utc_offset = $date_obj->getOffset();
607 }
608 $tz_offset_timestamp = $date_obj->getTimestamp() + $utc_offset;
609
610 // use the custom date format if set, otherwise use from the selected defaults
611 if ( ! empty( $feed_options['datecustom'] ) ) {
612 $date_str = date_i18n( $feed_options['datecustom'], $tz_offset_timestamp );
613 } else {
614
615 switch ( $feed_options['dateformat'] ) {
616 case '2':
617 $date_str = date_i18n( 'F j', $tz_offset_timestamp );
618 break;
619 case '3':
620 $date_str = date_i18n( 'F j, Y', $tz_offset_timestamp );
621 break;
622 case '4':
623 $date_str = date_i18n( 'm.d', $tz_offset_timestamp );
624 break;
625 case '5':
626 $date_str = date_i18n( 'm.d.y', $tz_offset_timestamp );
627 break;
628 case '6':
629 $date_str = date_i18n( 'D M jS, Y', $tz_offset_timestamp );
630 break;
631 case '7':
632 $date_str = date_i18n( 'l F jS, Y', $tz_offset_timestamp );
633 break;
634 case '8':
635 $date_str = date_i18n( 'l F jS, Y - g:i a', $tz_offset_timestamp );
636 break;
637 case '9':
638 $date_str = date_i18n( "l M jS, 'y", $tz_offset_timestamp );
639 break;
640 case '10':
641 $date_str = date_i18n( 'm.d.y', $tz_offset_timestamp );
642 break;
643 case '18':
644 $date_str = date_i18n( 'm.d.y - G:i', $tz_offset_timestamp );
645 break;
646 case '11':
647 $date_str = date_i18n( 'm/d/y', $tz_offset_timestamp );
648 break;
649 case '12':
650 $date_str = date_i18n( 'd.m.y', $tz_offset_timestamp );
651 break;
652 case '19':
653 $date_str = date_i18n( 'd.m.y - G:i', $tz_offset_timestamp );
654 break;
655 case '13':
656 $date_str = date_i18n( 'd/m/y', $tz_offset_timestamp );
657 break;
658 case '14':
659 $date_str = date_i18n( 'd-m-Y, G:i', $tz_offset_timestamp );
660 break;
661 case '15':
662 $date_str = date_i18n( 'jS F Y, G:i', $tz_offset_timestamp );
663 break;
664 case '16':
665 $date_str = date_i18n( 'd M Y, G:i', $tz_offset_timestamp );
666 break;
667 case '17':
668 $date_str = date_i18n( 'l jS F Y, G:i', $tz_offset_timestamp );
669 break;
670 case '20':
671 $date_str = date_i18n( 'Y-m-d', $tz_offset_timestamp );
672 break;
673 default:
674 // default format is similar to Twitter
675 $ctf_minute = ! empty( $options['mtime'] ) ? $options['mtime'] : 'm';
676 $ctf_hour = ! empty( $options['htime'] ) ? $options['htime'] : 'h';
677 $ctf_now_str = ! empty( $options['nowtime'] ) ? $options['nowtime'] : 'now';
678
679 $now = time() + $utc_offset;
680
681 $difference = $now - $tz_offset_timestamp;
682 if ( $difference < 60 ) {
683 $date_str = $ctf_now_str;
684 } elseif ( $difference < 60*60 ) {
685 $date_str = round( $difference/60 ) . $ctf_minute;
686 } elseif ( $difference < 60*60*24 ) {
687 $date_str = round( $difference/3600 ) . $ctf_hour;
688 } else {
689 $one_year_from_date = new \DateTime( $raw_date, new \DateTimeZone( "UTC" ) );
690 $one_year_from_date->modify('+1 year');
691 $one_year_from_date_timestamp = $one_year_from_date->getTimestamp();
692 if ( $now > $one_year_from_date_timestamp ) {
693 $date_str = date_i18n( 'j M Y', $tz_offset_timestamp );
694 } else {
695 $date_str = date_i18n( 'j M', $tz_offset_timestamp );
696 }
697 }
698
699 break;
700 }
701 }
702
703 return $date_str;
704 }
705
706 function ctf_maybe_shorten_text( $string, $feed_settings ) {
707 #if( !ctf_doing_customizer($feed_settings) ){
708 $limit = is_array( $feed_settings ) ? $feed_settings['textlength'] : $feed_settings;
709
710 if ( strlen( $string ) <= $limit
711 || $limit >= 280 ) {
712 return $string;
713 }
714
715 $parts = preg_split( '/([\s\n\r]+)/', $string, null, PREG_SPLIT_DELIM_CAPTURE );
716 $parts_count = count( $parts );
717
718 $length = 0;
719 $last_part = 0;
720 $first_parts = array();
721 $end_parts = array();
722 for ( ; $last_part < $parts_count; $last_part++ ) {
723 $length += strlen( $parts[ $last_part ] );
724 if ( $length < $limit ) {
725 $first_parts[] = $parts[ $last_part ];
726 } else {
727 $end_parts[] = $parts[ $last_part ];
728 }
729 }
730 $return = implode( ' ', $first_parts ) . '<button type="button" class="ctf_more" aria-expanded="false" aria-label="' . esc_attr__( 'Show full tweet text', 'custom-twitter-feeds' ) . '" style="background:none;border:0;padding:0;font:inherit;color:inherit;cursor:pointer;"><span aria-hidden="true">...</span></button><span class="ctf_remaining">';
731
732 $return .= implode( ' ', $end_parts ) . '</span>';
733
734 return $return;
735 #}
736 #return $string;
737 }
738 add_filter( 'ctf_tweet_text', 'ctf_maybe_shorten_text', 10, 2 );
739
740 function ctf_replace_urls( $string, $feed_settings, $post ) {
741
742 if ( $feed_settings['shorturls'] ) {
743 return $string;
744 }
745
746 if ( isset( $post['entities']['urls'][0] ) ) {
747 foreach ( $post['entities']['urls'] as $url ) {
748 if ( isset( $url['url'] ) ) {
749 // The tweet text is already esc_html()'d before this filter runs, so the
750 // replacement must be encoded the same way or it re-opens a raw channel
751 // into the escaped string (SMASH-1796).
752 $string = str_replace( $url['url'], esc_html( $url['expanded_url'] ), $string );
753 }
754 }
755 }
756
757 return $string;
758 }
759 add_filter( 'ctf_tweet_text', 'ctf_replace_urls', 9, 3 );
760 add_filter( 'ctf_quoted_tweet_text', 'ctf_replace_urls', 9, 3 );
761
762 function ctf_get_fa_el( $icon ) {
763 $options = get_option( 'ctf_options' );
764 $font_method = 'svg';
765
766 $elems = array(
767 'fa-arrows-alt' => array(
768 'icon' => '<span class="fa fa-arrows-alt"></span>',
769 'svg' => '<svg class="svg-inline--fa fa-arrows-alt fa-w-16" aria-hidden="true" focusable="false" data-fa-processed="" data-prefix="fa" data-icon="arrows-alt" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M352.201 425.775l-79.196 79.196c-9.373 9.373-24.568 9.373-33.941 0l-79.196-79.196c-15.119-15.119-4.411-40.971 16.971-40.97h51.162L228 284H127.196v51.162c0 21.382-25.851 32.09-40.971 16.971L7.029 272.937c-9.373-9.373-9.373-24.569 0-33.941L86.225 159.8c15.119-15.119 40.971-4.411 40.971 16.971V228H228V127.196h-51.23c-21.382 0-32.09-25.851-16.971-40.971l79.196-79.196c9.373-9.373 24.568-9.373 33.941 0l79.196 79.196c15.119 15.119 4.411 40.971-16.971 40.971h-51.162V228h100.804v-51.162c0-21.382 25.851-32.09 40.97-16.971l79.196 79.196c9.373 9.373 9.373 24.569 0 33.941L425.773 352.2c-15.119 15.119-40.971 4.411-40.97-16.971V284H284v100.804h51.23c21.382 0 32.09 25.851 16.971 40.971z"></path></svg>'
770 ),
771 'fa-check-circle' => array(
772 'icon' => '<span class="fa fa-check-circle"></span>',
773 'svg' => '<svg class="svg-inline--fa fa-check-circle fa-w-16" aria-hidden="true" focusable="false" data-fa-processed="" data-prefix="fa" data-icon="check-circle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"></path></svg>'
774 ),
775 'fa-reply' => array(
776 'icon' => '<span class="fa fa-reply"></span>',
777 'svg' => '<svg class="svg-inline--fa fa-w-16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><g><path fill="currentColor" d="M14.046 2.242l-4.148-.01h-.002c-4.374 0-7.8 3.427-7.8 7.802 0 4.098 3.186 7.206 7.465 7.37v3.828c0 .108.044.286.12.403.142.225.384.347.632.347.138 0 .277-.038.402-.118.264-.168 6.473-4.14 8.088-5.506 1.902-1.61 3.04-3.97 3.043-6.312v-.017c-.006-4.367-3.43-7.787-7.8-7.788zm3.787 12.972c-1.134.96-4.862 3.405-6.772 4.643V16.67c0-.414-.335-.75-.75-.75h-.396c-3.66 0-6.318-2.476-6.318-5.886 0-3.534 2.768-6.302 6.3-6.302l4.147.01h.002c3.532 0 6.3 2.766 6.302 6.296-.003 1.91-.942 3.844-2.514 5.176z"></path></g></svg>'
778 ),
779 'fa-retweet' => array(
780 'icon' => '<span class="fa fa-retweet"></span>',
781 'svg' => '<svg class="svg-inline--fa fa-w-16" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path fill="currentColor" d="M23.77 15.67c-.292-.293-.767-.293-1.06 0l-2.22 2.22V7.65c0-2.068-1.683-3.75-3.75-3.75h-5.85c-.414 0-.75.336-.75.75s.336.75.75.75h5.85c1.24 0 2.25 1.01 2.25 2.25v10.24l-2.22-2.22c-.293-.293-.768-.293-1.06 0s-.294.768 0 1.06l3.5 3.5c.145.147.337.22.53.22s.383-.072.53-.22l3.5-3.5c.294-.292.294-.767 0-1.06zm-10.66 3.28H7.26c-1.24 0-2.25-1.01-2.25-2.25V6.46l2.22 2.22c.148.147.34.22.532.22s.384-.073.53-.22c.293-.293.293-.768 0-1.06l-3.5-3.5c-.293-.294-.768-.294-1.06 0l-3.5 3.5c-.294.292-.294.767 0 1.06s.767.293 1.06 0l2.22-2.22V16.7c0 2.068 1.683 3.75 3.75 3.75h5.85c.414 0 .75-.336.75-.75s-.337-.75-.75-.75z"></path></svg>'
782 ),
783 'fa-x' => array(
784 'icon' => '<span class="fa fab fa-twitter"></span>',
785 'svg' => '<svg aria-hidden="true" focusable="false" width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M21.1161 6.27344H24.2289L17.4284 14.0459L25.4286 24.6225H19.1645L14.2583 18.2079L8.6444 24.6225H5.52976L12.8035 16.309L5.12891 6.27344H11.552L15.9868 12.1367L21.1161 6.27344ZM20.0236 22.7594H21.7484L10.6148 8.03871H8.7639L20.0236 22.7594Z" fill="black"/>
786 </svg>',
787 ),
788 'fa-heart' => array(
789 'icon' => '<span class="fa fa-heart"></span>',
790 'svg' => '<svg class="svg-inline--fa fa-w-16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><g><path fill="currentColor" d="M12 21.638h-.014C9.403 21.59 1.95 14.856 1.95 8.478c0-3.064 2.525-5.754 5.403-5.754 2.29 0 3.83 1.58 4.646 2.73.814-1.148 2.354-2.73 4.645-2.73 2.88 0 5.404 2.69 5.404 5.755 0 6.376-7.454 13.11-10.037 13.157H12zM7.354 4.225c-2.08 0-3.903 1.988-3.903 4.255 0 5.74 7.034 11.596 8.55 11.658 1.518-.062 8.55-5.917 8.55-11.658 0-2.267-1.823-4.255-3.903-4.255-2.528 0-3.94 2.936-3.952 2.965-.23.562-1.156.562-1.387 0-.014-.03-1.425-2.965-3.954-2.965z"></path></g></svg>'
791 ),
792 'fa-twitter' => array(
793 'icon' => '<span class="fa fab fa-twitter"></span>',
794 'svg' => '<svg class="svg-inline--fa fa-twitter fa-w-16" aria-hidden="true" focusable="false" data-fa-processed="" data-prefix="fab" data-icon="twitter" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg>'
795 ),
796 'fa-user' => array(
797 'icon' => '<span class="fa fa-user"></span>',
798 'svg' => '<svg class="svg-inline--fa fa-user fa-w-16" aria-hidden="true" focusable="false" data-fa-processed="" data-prefix="fa" data-icon="user" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M96 160C96 71.634 167.635 0 256 0s160 71.634 160 160-71.635 160-160 160S96 248.366 96 160zm304 192h-28.556c-71.006 42.713-159.912 42.695-230.888 0H112C50.144 352 0 402.144 0 464v24c0 13.255 10.745 24 24 24h464c13.255 0 24-10.745 24-24v-24c0-61.856-50.144-112-112-112z"></path></svg>'
799 ),
800 'ctf_playbtn' => array(
801 'icon' => '',
802 'svg' => '<svg style="color: rgba(255,255,255,1)" class="svg-inline--fa fa-play fa-w-14 ctf_playbtn" aria-hidden="true" focusable="false" data-fa-processed="" data-prefix="fa" data-icon="play" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z"></path></svg>'
803 ),
804 'fa-file-video-o' => array(
805 'icon' => '<span class="fa fa-file-video-o ctf-tweet-text-media" aria-hidden="true"></span>',
806 'svg' => '<svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="file-video" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" class="svg-inline--fa fa-file-video fa-w-12 fa-9x ctf-tweet-text-media"><path fill="currentColor" d="M369.941 97.941l-83.882-83.882A48 48 0 0 0 252.118 0H48C21.49 0 0 21.49 0 48v416c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48V131.882a48 48 0 0 0-14.059-33.941zM332.118 128H256V51.882L332.118 128zM48 464V48h160v104c0 13.255 10.745 24 24 24h104v288H48zm228.687-211.303L224 305.374V268c0-11.046-8.954-20-20-20H100c-11.046 0-20 8.954-20 20v104c0 11.046 8.954 20 20 20h104c11.046 0 20-8.954 20-20v-37.374l52.687 52.674C286.704 397.318 304 390.28 304 375.986V264.011c0-14.311-17.309-21.319-27.313-11.314z" class=""></path></svg>'
807 ),
808 'fa-picture-o' => array(
809 'icon' => '<span class="fa fa-picture-o ctf-tweet-text-media" aria-hidden="true"></span>',
810 'svg' => '<svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="image" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="svg-inline--fa fa-image fa-w-16 fa-9x ctf-tweet-text-media"><path fill="currentColor" d="M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm-6 336H54a6 6 0 0 1-6-6V118a6 6 0 0 1 6-6h404a6 6 0 0 1 6 6v276a6 6 0 0 1-6 6zM128 152c-22.091 0-40 17.909-40 40s17.909 40 40 40 40-17.909 40-40-17.909-40-40-40zM96 352h320v-80l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L192 304l-39.515-39.515c-4.686-4.686-12.284-4.686-16.971 0L96 304v48z" class=""></path></svg>'
811 ),
812 );
813
814 if ( $font_method !== 'fontfile' ){
815 return $elems[ $icon ]['svg'];
816 }
817
818 return $elems[ $icon ]['icon'];
819 }
820
821 /**
822 * manually clears the cached tweets in case of error or user preference
823 *
824 * @return mixed bool whether or not it was successful
825 */
826 function ctf_clear_cache() {
827
828 //Delete all transients
829 global $wpdb;
830 $table_name = $wpdb->prefix . "options";
831 $result = $wpdb->query("
832 DELETE
833 FROM $table_name
834 WHERE `option_name` LIKE ('%\_transient\_ctf\_%')
835 ");
836 $wpdb->query("
837 DELETE
838 FROM $table_name
839 WHERE `option_name` LIKE ('%\_transient\_timeout\_ctf\_%')
840 ");
841
842 ctf_clear_page_caches();
843
844 }
845 add_action( 'ctf_cron_job', 'ctf_clear_cache' );
846
847 function ctf_clear_cache_admin() {
848 check_ajax_referer('ctf-admin' , 'ctf_nonce');
849 if ( ! ctf_current_user_can( 'manage_twitter_feed_options' ) ) {
850 wp_send_json_error();
851 }
852
853 //Delete all transients
854 global $wpdb;
855 $table_name = $wpdb->prefix . "options";
856 $result = $wpdb->query("
857 DELETE
858 FROM $table_name
859 WHERE `option_name` LIKE ('%\_transient\_ctf\_%')
860 ");
861 $wpdb->query("
862 DELETE
863 FROM $table_name
864 WHERE `option_name` LIKE ('%\_transient\_timeout\_ctf\_%')
865 ");
866
867 ctf_clear_page_caches();
868
869 wp_send_json_success();
870 }
871 add_action( 'wp_ajax_ctf_clear_cache_admin', 'ctf_clear_cache_admin' );
872
873 function ctf_activate() {
874 // set usage tracking to false if fresh install. Skip when the Pro plugin is active: it shares
875 // this option and defaults tracking on, so seeding a disabled record here would silently turn it off.
876 $usage_tracking = get_option( 'ctf_usage_tracking', false );
877
878 global $wp_roles;
879 $wp_roles->add_cap( 'administrator', 'manage_twitter_feed_options' );
880
881 $ctf_network_active = is_multisite() ? (array) get_site_option( 'active_sitewide_plugins', array() ) : array();
882 $ctf_pro_active = in_array( 'custom-twitter-feeds-pro/custom-twitter-feed.php', (array) get_option( 'active_plugins', array() ), true )
883 || isset( $ctf_network_active['custom-twitter-feeds-pro/custom-twitter-feed.php'] );
884
885 if ( ! is_array( $usage_tracking ) && ! $ctf_pro_active ) {
886 $usage_tracking = array(
887 'enabled' => false,
888 'last_send' => 0
889 );
890
891 update_option( 'ctf_usage_tracking', $usage_tracking, false );
892 }
893 global $wp_roles;
894 $wp_roles->add_cap( 'administrator', 'manage_twitter_feed_options' );
895 }
896 register_activation_hook( __FILE__, 'ctf_activate' );
897
898 /**
899 * clear the cache and unschedule an cron jobs when deactivated
900 */
901 function ctf_deactivate() {
902 ctf_clear_cache();
903
904 wp_clear_scheduled_hook( 'ctf_cron_job' );
905 wp_clear_scheduled_hook( \TwitterFeed\UsageTracking\Config::CRON_HOOK );
906 }
907 register_deactivation_hook( __FILE__, 'ctf_deactivate' );
908
909 /**
910 * Loads the javascript for the plugin front-end. Also localizes the admin-ajax file location for use in ajax calls
911 */
912 function ctf_scripts_and_styles( $enqueue = false ) {
913 $options = get_option( 'ctf_options' );
914 $not_ajax_theme = (! isset( $options['ajax_theme'] ) || ! $options['ajax_theme']);
915 $font_method = 'svg';
916
917 $loacalize_args = array(
918 'ajax_url' => admin_url( 'admin-ajax.php' ),
919 'i18n' => array(
920 /* translators: %s: number of new tweets loaded into the feed (screen reader announcement) */
921 'newTweetsLoaded' => __( '%s new tweets loaded', 'custom-twitter-feeds' ),
922 'noMoreTweets' => __( "That's all! No more Tweets to load", 'custom-twitter-feeds' ),
923 ),
924 );
925
926 wp_enqueue_style( 'ctf_styles', plugins_url( '/css/ctf-styles.min.css', __FILE__ ), array(), CTF_VERSION );
927 wp_register_script( 'ctf_scripts', CTF_JS_URL, array( 'jquery' ), CTF_VERSION, true );
928
929 if ( $not_ajax_theme ) {
930 wp_localize_script( 'ctf_scripts', 'ctf', $loacalize_args );
931 } else {
932 wp_localize_script( 'jquery', 'ctf', $loacalize_args );
933 }
934
935 if ( $enqueue ) {
936 wp_enqueue_style( 'ctf_styles' );
937 wp_enqueue_script( 'ctf_scripts' );
938 }
939 }
940 add_action( 'wp_enqueue_scripts', 'ctf_scripts_and_styles' );
941
942 /**
943 * outputs the custom js from the "Customize" tab on the Settings page
944 */
945 function ctf_custom_js() {
946 $options = get_option( 'ctf_options' );
947 $ctf_custom_js = isset( $options[ 'custom_js' ] ) ? $options[ 'custom_js' ] : '';
948
949 if ( ! empty( $ctf_custom_js ) ) {
950 ?>
951 <!-- Custom Twitter Feeds JS -->
952 <script type="text/javascript">
953 <?php echo "window.ctf_custom_js = function($){" . stripslashes( $ctf_custom_js ) . "}\r\n"; ?>
954 </script>
955 <?php
956 }
957 }
958 add_action( 'wp_footer', 'ctf_custom_js' );
959
960 /**
961 * outputs the custom css from the "Customize" tab on the Settings page
962 */
963 function ctf_custom_css() {
964 $options = get_option( 'ctf_options' );
965 $ctf_custom_css = isset( $options[ 'custom_css' ] ) ? $options[ 'custom_css' ] : '';
966
967 if ( ! empty( $ctf_custom_css ) ) {
968 ?>
969 <!-- Custom Twitter Feeds CSS -->
970 <style type="text/css">
971 <?php echo stripslashes( $ctf_custom_css ) . "\r\n"; ?>
972 </style>
973 <?php
974 }
975 }
976 add_action( 'wp_head', 'ctf_custom_css' );
977
978 /**
979 * Some CSS and JS needed in the admin area as well
980 */
981 function ctf_admin_scripts_and_styles() {
982 // SMASH-1378: design-token mirror (provides --sb-focus-ring etc.) registered
983 // as a dependency of the admin stylesheets so the focus-ring custom property
984 // is available across all TW Free admin pages. Also registered in
985 // CTF_Feed_Builder::global_enqueue_ressources_scripts() for the builder/
986 // settings lifecycle; wp_register_style() is idempotent.
987 wp_register_style( 'ctf-tokens-local', CTF_PLUGIN_URL . 'assets/tokens/ctf-tokens-local.css', array(), CTF_VERSION );
988 wp_enqueue_style(
989 'feed-global-style',
990 CTF_PLUGIN_URL . 'admin/builder/assets/css/global.css',
991 array( 'ctf-tokens-local' ),
992 CTF_VERSION
993 );
994 wp_enqueue_style( 'ctf_admin_styles', plugins_url( '/css/ctf-admin-styles.css', __FILE__ ), array( 'ctf-tokens-local' ), CTF_VERSION );
995 wp_enqueue_style( 'sb-font-awesome', 'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css' );
996 wp_enqueue_script( 'ctf_admin_scripts', plugins_url( '/js/ctf-admin-scripts.js', __FILE__ ) , array( 'jquery' ), CTF_VERSION, false );
997 wp_localize_script( 'ctf_admin_scripts', 'ctf', array(
998 'ajax_url' => admin_url( 'admin-ajax.php' ),
999 'sb_nonce' => wp_create_nonce( 'ctf-smash-balloon' ),
1000 'nonce' => wp_create_nonce( 'ctf-admin' )
1001 )
1002 );
1003 $strings = array(
1004 'addon_activate' => esc_html__( 'Activate', 'custom-twitter-feeds' ),
1005 'addon_activated' => esc_html__( 'Activated', 'custom-twitter-feeds' ),
1006 'addon_active' => esc_html__( 'Active', 'custom-twitter-feeds' ),
1007 'addon_deactivate' => esc_html__( 'Deactivate', 'custom-twitter-feeds' ),
1008 'addon_inactive' => esc_html__( 'Inactive', 'custom-twitter-feeds' ),
1009 'addon_install' => esc_html__( 'Install Addon', 'custom-twitter-feeds' ),
1010 'addon_error' => esc_html__( 'Could not install addon. Please download from wpforms.com and install manually.', 'custom-twitter-feeds' ),
1011 'plugin_error' => esc_html__( 'Could not install a plugin. Please download from WordPress.org and install manually.', 'custom-twitter-feeds' ),
1012 'addon_search' => esc_html__( 'Searching Addons', 'custom-twitter-feeds' ),
1013 'ajax_url' => admin_url( 'admin-ajax.php' ),
1014 'cancel' => esc_html__( 'Cancel', 'custom-twitter-feeds' ),
1015 'close' => esc_html__( 'Close', 'custom-twitter-feeds' ),
1016 'nonce' => wp_create_nonce( 'ctf-admin' ),
1017 'almost_done' => esc_html__( 'Almost Done', 'custom-twitter-feeds' ),
1018 'oops' => esc_html__( 'Oops!', 'custom-twitter-feeds' ),
1019 'ok' => esc_html__( 'OK', 'custom-twitter-feeds' ),
1020 'plugin_install_activate_btn' => esc_html__( 'Install and Activate', 'custom-twitter-feeds' ),
1021 'plugin_install_activate_confirm' => esc_html__( 'needs to be installed and activated to import its forms. Would you like us to install and activate it for you?', 'custom-twitter-feeds' ),
1022 'plugin_activate_btn' => esc_html__( 'Activate', 'custom-twitter-feeds' ),
1023 'smashPlugins' => CTF_Feed_Builder::install_plugins_popup()
1024 );
1025 $strings = apply_filters( 'ctf_admin_strings', $strings );
1026
1027 wp_localize_script(
1028 'ctf_admin_scripts',
1029 'ctf_admin_strings',
1030 $strings
1031 );
1032 wp_enqueue_style( 'wp-color-picker' );
1033 wp_enqueue_script( 'wp-color-picker' );
1034 wp_enqueue_script(
1035 'jquery-matchheight',
1036 CTF_PLUGIN_URL . 'js/jquery.matchHeight-min.js',
1037 array( 'jquery' ),
1038 '0.7.0',
1039 false
1040 );
1041 }
1042 add_action( 'admin_enqueue_scripts', 'ctf_admin_scripts_and_styles' );
1043
1044
1045 function ctf_is_pro_version() {
1046 return defined( 'CTF_STORE_URL' );
1047 }
1048
1049
1050 function ctf_get_database_settings() {
1051 $options = get_option( 'ctf_options', array() );
1052 $options = set_global_default_settings( $options );
1053 return $options;
1054 }
1055
1056 function set_global_default_settings( $options ) {
1057 $defaults = array(
1058 'disableintents' => false,
1059 'creditctf' => false,
1060 'ajax_theme' => false,
1061 );
1062 foreach ( $defaults as $key => $value ) {
1063 if ( ! isset( $options[ $key ] ) ) {
1064 $options[ $key ] = $value;
1065 }
1066 }
1067 return $options;
1068 }
1069
1070 function ctf_clear_page_caches() {
1071 //Clear cache of major caching plugins
1072 if(isset($GLOBALS['wp_fastest_cache']) && method_exists($GLOBALS['wp_fastest_cache'], 'deleteCache')){
1073 $GLOBALS['wp_fastest_cache']->deleteCache();
1074 }
1075 //WP Super Cache
1076 if (function_exists('wp_cache_clear_cache')) {
1077 wp_cache_clear_cache();
1078 }
1079 //W3 Total Cache
1080 if (function_exists('w3tc_flush_all')) {
1081 w3tc_flush_all();
1082 }
1083 if (function_exists('sg_cachepress_purge_cache')) {
1084 sg_cachepress_purge_cache();
1085 }
1086
1087 // Litespeed Cache (older method)
1088 if ( method_exists( 'LiteSpeed_Cache_API', 'purge' ) ) {
1089 LiteSpeed_Cache_API::purge( 'esi.custom-twitter-feeds' );
1090 }
1091
1092 // Litespeed Cache (new method)
1093 if(has_action('litespeed_purge')) {
1094 do_action( 'litespeed_purge', 'esi.custom-twitter-feeds' );
1095 }
1096 }
1097
1098 /**
1099 * Add the custom interval of 30 minutes for cron caching
1100 *
1101 * @param array $schedules current list of cron intervals
1102 *
1103 * @return array
1104 *
1105 * @since 2.0
1106 */
1107 function ctf_cron_custom_interval( $schedules ) {
1108 $schedules['ctf30mins'] = array(
1109 'interval' => 30 * 60,
1110 'display' => __( 'Every 30 minutes' )
1111 );
1112 $schedules['ctfweekly'] = array(
1113 'interval' => 3600 * 24 * 7,
1114 'display' => __( 'Weekly' )
1115 );
1116
1117 return $schedules;
1118 }
1119
1120 add_filter( 'cron_schedules', 'ctf_cron_custom_interval' );
1121
1122 function ctf_create_database_table() {
1123 global $wpdb;
1124 global $wp_version;
1125
1126 $table_name = esc_sql( $wpdb->prefix . CTF_POSTS_TABLE );
1127 $feeds_posts_table_name = esc_sql( $wpdb->prefix . CTF_FEEDS_POSTS_TABLE );
1128 $charset_collate = '';
1129
1130 if ( version_compare( $wp_version, '3.5', '>' ) ) {
1131 $charset_collate = $wpdb->get_charset_collate();
1132 }
1133
1134 if ( $wpdb->get_var( "show tables like '$table_name'" ) != $table_name ) {
1135 $sql = "CREATE TABLE " . $table_name . " (
1136 id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
1137 twitter_id VARCHAR(1000) DEFAULT '' NOT NULL,
1138 created_on DATETIME,
1139 last_requested DATE,
1140 time_stamp DATETIME,
1141 json_data LONGTEXT DEFAULT '' NOT NULL,
1142 media_id VARCHAR(1000) DEFAULT '' NOT NULL,
1143 sizes VARCHAR(1000) DEFAULT '' NOT NULL,
1144 aspect_ratio DECIMAL (4,2) DEFAULT 0 NOT NULL,
1145 images_done TINYINT(1) DEFAULT 0 NOT NULL
1146 ) $charset_collate;";
1147 $wpdb->query( $sql );
1148 }
1149
1150 if ( $wpdb->get_var( "show tables like '$feeds_posts_table_name'" ) != $feeds_posts_table_name ) {
1151 $sql = "CREATE TABLE " . $feeds_posts_table_name . " (
1152 record_id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
1153 id INT(11) UNSIGNED NOT NULL,
1154 feed_id VARCHAR(1000) DEFAULT '' NOT NULL,
1155 INDEX feed_id (feed_id(100))
1156 ) $charset_collate;";
1157 $wpdb->query( $sql );
1158 }
1159
1160 return $wpdb->get_var( "show tables like '$table_name'" ) === $table_name;
1161 }
1162
1163 function ctf_text_domain() {
1164 load_plugin_textdomain( 'custom-twitter-feeds', false, basename( dirname(__FILE__) ) . '/languages' );
1165 }
1166
1167 add_action( 'init', 'ctf_text_domain' );
1168
1169 //BUILDER CODE
1170 function ctf_builder() {
1171 return \TwitterFeed\Builder\CTF_Feed_Builder::instance();
1172 }
1173 ctf_builder();
1174