PluginProbe ʕ •ᴥ•ʔ
Smash Balloon Social Post Feed – Simple Social Feeds for WordPress / 4.0.5
Smash Balloon Social Post Feed – Simple Social Feeds for WordPress v4.0.5
4.8.1 trunk 1.0 1.1 1.12.1 1.2.3 1.2.4 1.2.5 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.5 1.5.1 1.5.2 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.4.1 1.6.5 1.6.5.1 1.6.6 1.6.6.1 1.6.6.2 1.6.6.3 1.6.7 1.6.7.1 1.6.8 1.6.8.1 1.6.8.2 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.8.2 1.8.2.1 1.8.2.2 1.8.2.3 1.9.0 1.9.1 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.8.1 1.9.9 1.9.9.1 1.9.9.2 1.9.9.3 2.0 2.0.1 2.1 2.1.1 2.1.2 2.1.3 2.10 2.11 2.11.1 2.12 2.12.1 2.12.2 2.12.3 2.12.4 2.13 2.14 2.14.1 2.15 2.15.1 2.16 2.16.1 2.17 2.17.1 2.18 2.18.1 2.18.2 2.18.3 2.19 2.19.1 2.19.2 2.19.3 2.2 2.2.1 2.3 2.3.1 2.3.10 2.3.2 2.3.3 2.3.4 2.3.6 2.3.7 2.3.8 2.3.9 2.4 2.4.1 2.4.1.1 2.4.1.2 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.5 2.5.1 2.5.2 2.6 2.6.1 2.6.2 2.6.3 2.6.4 2.7 2.7.1 2.7.2 2.8 2.9 2.9.1 4.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.1 4.1.1 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.3.0 4.3.1 4.3.2 4.3.3 4.3.4 4.7.5 4.7.6 4.7.7
custom-facebook-feed / inc / Builder / CFF_Source.php
custom-facebook-feed / inc / Builder Last commit date
Controls 4 years ago Tabs 4 years ago CFF_Builder_Customizer.php 4 years ago CFF_Db.php 4 years ago CFF_Feed_Builder.php 4 years ago CFF_Feed_Saver.php 4 years ago CFF_Feed_Saver_Manager.php 4 years ago CFF_Post_Set.php 4 years ago CFF_Source.php 4 years ago CFF_Theme_CSS.php 4 years ago CFF_Tooltip_Wizard.php 4 years ago
CFF_Source.php
1000 lines
1 <?php
2 /**
3 * Custom Facebook Feed Source
4 *
5 * @since 4.0
6 */
7
8 namespace CustomFacebookFeed\Builder;
9
10 class CFF_Source {
11
12 const BATCH_SIZE = 15;
13
14 /**
15 * AJAX hooks for various feed data related functionality
16 *
17 * @since 4.0
18 */
19 public static function hooks() {
20 add_action( 'wp_ajax_cff_source_builder_update', array( 'CustomFacebookFeed\Builder\CFF_Source', 'builder_update' ) );
21 add_action( 'wp_ajax_cff_source_builder_update_multiple', array( 'CustomFacebookFeed\Builder\CFF_Source', 'builder_update_multiple' ) );
22 add_action( 'wp_ajax_cff_source_get_page', array( 'CustomFacebookFeed\Builder\CFF_Source', 'get_page' ) );
23 add_action( 'wp_ajax_cff_source_get_featured_post_preview', array( 'CustomFacebookFeed\Builder\CFF_Source', 'get_featured_post_preview' ) );
24 add_action( 'wp_ajax_cff_source_get_playlist_post_preview', array( 'CustomFacebookFeed\Builder\CFF_Source', 'get_playlist_post_preview' ) );
25 add_action( 'admin_init', array( 'CustomFacebookFeed\Builder\CFF_Source', 'batch_process_legacy_source_queue' ) );
26 }
27
28 /**
29 * Used in an AJAX call to update sources based on selections or
30 * input from a user. Makes an API request to add additiona info
31 * about the connected source.
32 *
33 * @since 4.0
34 */
35 public static function builder_update() {
36 check_ajax_referer( 'cff-admin' , 'nonce');
37
38 $cap = current_user_can( 'manage_custom_facebook_feed_options' ) ? 'manage_custom_facebook_feed_options' : 'manage_options';
39 $cap = apply_filters( 'cff_settings_pages_capability', $cap );
40 if ( ! current_user_can( $cap ) ) {
41 wp_send_json_error(); // This auto-dies.
42 }
43
44
45 $source_data = array(
46 'access_token' => sanitize_text_field( $_POST['access_token'] ),
47 'id' => sanitize_text_field( $_POST['id'] ),
48 'type' => sanitize_text_field( $_POST['type'] ),
49 'privilege' => isset( $_POST['privilege'] ) ? sanitize_text_field( $_POST['privilege'] ) : '',
50 );
51
52 if ( ! empty( $_POST['name'] ) ) {
53 $source_data['name'] = sanitize_text_field( $_POST['name'] );
54 }
55
56 $return = CFF_Source::process_connecting_source_data( $source_data );
57
58 echo $return;
59
60 wp_die();
61 }
62
63
64 /**
65 * Add our update a source from raw API data.
66 *
67 * @param $source_data
68 *
69 * @return string
70 */
71 public static function process_connecting_source_data( $source_data ) {
72 $header_details = \CustomFacebookFeed\CFF_Utils::fetch_header_data( $source_data['id'], $source_data['type'] === 'group', $source_data['access_token'], 0, false, '' );
73
74 if ( ! isset( $header_details->name ) ) {
75 $message = __( 'There was a problem connecting this account. Please make sure your access token and ID are correct.');
76 $details = '';
77 if ( isset( $header_details->cached_error ) ) {
78 $details = $header_details->cached_error->message;
79 $details = '<span class="sb-caption">API Response: ' . esc_html( $details ) . '</span>';
80 } elseif ( isset( $header_details->error ) ) {
81 $details = $header_details->error->message;
82 $details = '<span class="sb-caption">API Response: ' . esc_html( $details ) . '</span>';
83 }
84
85 $return_html = '<div class="cff-groups-connect-actions sb-alerts-wrap"><div class="sb-alert">
86 <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
87 <path d="M8.99935 0.666504C4.39935 0.666504 0.666016 4.39984 0.666016 8.99984C0.666016 13.5998 4.39935 17.3332 8.99935 17.3332C13.5993 17.3332 17.3327 13.5998 17.3327 8.99984C17.3327 4.39984 13.5993 0.666504 8.99935 0.666504ZM9.83268 13.1665H8.16602V11.4998H9.83268V13.1665ZM9.83268 9.83317H8.16602V4.83317H9.83268V9.83317Z" fill="#995C00"/>
88 </svg>
89 <span><strong>' . esc_html( $message ) . '</strong></span><br>
90 ' . $details . '
91 </div></div>';
92
93 $return = array(
94 'success' => false,
95 'message' => $return_html
96 );
97 return \CustomFacebookFeed\CFF_Utils::cff_json_encode( $return );
98 }
99
100 if ( isset( $header_details->shortcode_options ) ) {
101 unset( $header_details->shortcode_options );
102 }
103
104 if ( isset( $header_details->name ) ) {
105 $source_data['name'] = $header_details->name;
106 }
107 $source_data['info'] = $header_details;
108
109 // don't update or insert the access token if there is an API error
110 if ( ! isset( $header_details->error ) && ! isset( $header_details->cached_error ) ) {
111 $source_data['error'] = '';
112 CFF_Source::update_or_insert( $source_data );
113 }
114
115 return \CustomFacebookFeed\CFF_Utils::cff_json_encode( CFF_Feed_Builder::get_source_list() );
116 }
117
118 /**
119 * Used in an AJAX call to update Multiple sources based on selections or
120 * input from a user. Makes an API request to add additiona info
121 * about the connected source.
122 *
123 * @since 4.0
124 */
125 public static function builder_update_multiple() {
126
127 if(check_ajax_referer( 'cff_admin_nonce' , 'nonce', false) || check_ajax_referer( 'cff-admin' , 'nonce', false) ){
128 $cap = current_user_can( 'manage_custom_facebook_feed_options' ) ? 'manage_custom_facebook_feed_options' : 'manage_options';
129 $cap = apply_filters( 'cff_settings_pages_capability', $cap );
130 if ( ! current_user_can( $cap ) ) {
131 wp_send_json_error(); // This auto-dies.
132 }
133
134 if(isset($_POST['sourcesList']) && !empty($_POST['sourcesList']) && is_array($_POST['sourcesList'])){
135 foreach ($_POST['sourcesList'] as $single_source):
136 $source_data = array(
137 'access_token' => sanitize_text_field( $single_source['access_token'] ),
138 'id' => sanitize_text_field( $single_source['account_id'] ),
139 'name' => isset($single_source['name']) ? sanitize_text_field($single_source['name']) : '',
140 'type' => sanitize_text_field( $_POST['type'] ),
141 'privilege' => isset( $single_source['privilege'] ) ? sanitize_text_field( $single_source['privilege'] ) : '',
142 );
143 $header_details = \CustomFacebookFeed\CFF_Utils::fetch_header_data( $source_data['id'], $source_data['type'] === 'group', $source_data['access_token'], 0, false, '' );
144 if ( isset( $header_details->shortcode_options ) ) {
145 unset( $header_details->shortcode_options );
146 }
147 if ( isset( $header_details->name ) ) {
148 $source_data['name'] = $header_details->name;
149 }
150 $source_data['info'] = $header_details;
151 // don't update or insert the access token if there is an API error
152 if ( ! isset( $header_details->error ) ) {
153 $source_data['error'] = '';
154 CFF_Source::update_or_insert( $source_data );
155 }
156 endforeach;
157 }
158 echo \CustomFacebookFeed\CFF_Utils::cff_json_encode( CFF_Feed_Builder::get_source_list() );
159 }
160
161 wp_die();
162 }
163
164 /**
165 * Get a list of sources with a limit and offset like a page
166 *
167 * @since 4.0
168 */
169 public static function get_page() {
170 check_ajax_referer( 'cff-admin' , 'nonce');
171
172 $cap = current_user_can( 'manage_custom_facebook_feed_options' ) ? 'manage_custom_facebook_feed_options' : 'manage_options';
173 $cap = apply_filters( 'cff_settings_pages_capability', $cap );
174 if ( ! current_user_can( $cap ) ) {
175 wp_send_json_error(); // This auto-dies.
176 }
177
178
179 $args = array( 'page' => $_POST['page'] );
180 $source_data = CFF_Db::source_query( $args );
181
182 echo \CustomFacebookFeed\CFF_Utils::cff_json_encode( $source_data );
183
184 wp_die();
185 }
186
187 /**
188 * Using the URL and source ID, info about a single post is returned
189 *
190 * @since 4.0
191 */
192 public static function get_featured_post_preview() {
193 check_ajax_referer( 'cff-admin' , 'nonce');
194
195 $cap = current_user_can( 'manage_custom_facebook_feed_options' ) ? 'manage_custom_facebook_feed_options' : 'manage_options';
196 $cap = apply_filters( 'cff_settings_pages_capability', $cap );
197 if ( ! current_user_can( $cap ) ) {
198 wp_send_json_error(); // This auto-dies.
199 }
200
201
202 $query_args = array(
203 'id' => sanitize_text_field( $_POST['source_id'] )
204 );
205 $results = CFF_Db::source_query( $query_args );
206
207 if ( ! isset( $results[0] ) ) {
208 echo '{"error":{"message":"No valid ID found"}}';
209 wp_die();
210
211 }
212 $access_token = $results[0]['access_token'];
213
214 $url_or_post_id = $_POST['url_or_id'];
215
216 $id = CFF_Source::extract_id( $url_or_post_id, 'album' );
217
218
219 if ( isset( $id ) ) {
220 $data = CFF_Source::fetch_featured( $id, sanitize_text_field( $_POST['source_id'] ), $access_token );
221 echo $data;
222
223 } else {
224 echo '{"error":{"message":"No valid ID found"}}';
225 }
226
227 wp_die();
228 }
229
230 /**
231 * Using the URL or ID, info about a single playlist is returned
232 *
233 * @since 4.0
234 */
235 public static function get_playlist_post_preview() {
236 check_ajax_referer( 'cff-admin' , 'nonce');
237
238 $cap = current_user_can( 'manage_custom_facebook_feed_options' ) ? 'manage_custom_facebook_feed_options' : 'manage_options';
239 $cap = apply_filters( 'cff_settings_pages_capability', $cap );
240 if ( ! current_user_can( $cap ) ) {
241 wp_send_json_error(); // This auto-dies.
242 }
243
244
245 $query_args = array(
246 'id' => sanitize_text_field( $_POST['source_id'] )
247 );
248 $results = CFF_Db::source_query( $query_args );
249
250 if ( ! isset( $results[0] ) ) {
251 echo '{"error":{"message":"No valid ID found"}}';
252 wp_die();
253 }
254 $access_token = $results[0]['access_token'];
255
256 $url_or_post_id = $_POST['url_or_id'];
257
258 $id = CFF_Source::extract_id( $url_or_post_id, 'playlist' );
259
260 if ( ! empty( $id ) ) {
261 $data = CFF_Source::fetch_playlist( $id, $access_token );
262 echo $data;
263
264 } else {
265 echo '{"error":{"message":"Not a valid playlist for this account"}}';
266 }
267
268 wp_die();
269 }
270
271 /**
272 * Makes an API request to the featured post endpoint
273 *
274 * @param $post_id $url
275 * @param string $source_id
276 * @param string $access_token
277 *
278 * @return bool|string
279 *
280 * @since 4.0
281 */
282 public static function fetch_featured( $post_id, $source_id, $access_token ) {
283 // need a connected business account for this to work
284 if ( empty( $access_token ) ) {
285 return false;
286 }
287
288 $full_id = $source_id . '_' . $post_id;
289 if ( function_exists( 'cff_featured_post_id' ) ) {
290 $featured_post_url = cff_featured_post_id( $full_id, $access_token);
291 } else {
292 $featured_post_url = 'https://graph.facebook.com/v4.0/'.$full_id.'?fields=id,from{picture,id,name,link},message,message_tags,story,story_tags,picture,full_picture,status_type,created_time,backdated_time,attachments{title,description,media_type,unshimmed_url,target{id},multi_share_end_card,media{source,image},subattachments},shares,comments.summary(true){message,created_time},likes.summary(true).limit(0),call_to_action,privacy&access_token=' . $access_token;
293 }
294 if ( function_exists( 'cff_featured_event_id' ) ) {
295 $featured_event_url = cff_featured_event_id( $full_id, $access_token);
296 } else {
297 $featured_event_url = 'https://graph.facebook.com/v4.0/'.$full_id.'?fields=id,name,attending_count,ticket_uri,cover,start_time,end_time,timezone,place,description,interested_count&access_token='.$access_token;
298 }
299
300 $response = wp_remote_get( $featured_post_url );
301 $return = '{}';
302 if ( ! \CustomFacebookFeed\CFF_Utils::cff_is_wp_error( $response ) ) {
303 if ( ! \CustomFacebookFeed\CFF_Utils::cff_is_fb_error( $response['body'] ) ) {
304 return $response['body'];
305 } else {
306 $return = $response['body'];
307 }
308 }
309
310 $response = wp_remote_get( $featured_event_url );
311 if ( ! \CustomFacebookFeed\CFF_Utils::cff_is_wp_error( $response ) ) {
312 if ( ! \CustomFacebookFeed\CFF_Utils::cff_is_fb_error( $response['body'] ) ) {
313 return $response['body'];
314 }
315 } else {
316 return '{"error":{"message":"HTTP request error"}}';
317 }
318
319 return $return;
320 }
321
322 /**
323 * Makes an API request to the playlist endpoint
324 *
325 * @param $playlist_id $url
326 * @param string $access_token
327 *
328 * @return bool|string
329 *
330 * @since 4.0
331 */
332 public static function fetch_playlist( $playlist_id, $access_token ) {
333 // need a connected business account for this to work
334 if ( empty( $access_token ) ) {
335 return false;
336 }
337
338 $url = 'https://graph.facebook.com/v3.2/'.$playlist_id.'/videos/?access_token='.$access_token.'&fields=published,source,updated_time,created_time,title,description,embed_html,format{picture}&locale=en_US&limit=5';
339
340 $response = wp_remote_get( $url );
341 $return = '{}';
342 if ( ! \CustomFacebookFeed\CFF_Utils::cff_is_wp_error( $response ) ) {
343 if ( ! \CustomFacebookFeed\CFF_Utils::cff_is_fb_error( $response['body'] ) ) {
344 return json_encode(
345 array_merge(
346 json_decode($response['body'], true),
347 [
348 'playlistID' => $playlist_id
349 ]
350 ), true
351 );
352 } else {
353 $return = $response['body'];
354 }
355 }
356
357 return $return;
358 }
359
360 /**
361 * Connection URLs are based on the website connecting accounts so that is
362 * configured here and returned
363 *
364 * @return array
365 *
366 * @since 4.0
367 */
368 public static function get_connection_urls($is_settings = false) {
369 $urls = array();
370 $admin_url_state = ($is_settings) ? admin_url( 'admin.php?page=cff-settings' ) : admin_url( 'admin.php?page=cff-feed-builder' );
371 //If the admin_url isn't returned correctly then use a fallback
372 if ( $admin_url_state == '/wp-admin/admin.php?page=cff-feed-builder'
373 || $admin_url_state == '/wp-admin/admin.php?page=cff-feed-builder&tab=configuration' ) {
374 $admin_url_state = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
375 }
376 #$urls['page'] = 'https://api.smashballoon.com/v2/facebook-login.php?state=' . $admin_url_state;
377 #$urls['group'] = 'https://api.smashballoon.com/v2/facebook-group-login.php?state=' . $admin_url_state;
378
379 $sb_admin_email = get_option('admin_email');
380 $urls['page'] = 'https://connect.smashballoon.com/auth/fb/?wordpress_user=' . $sb_admin_email . '&state=';
381 $urls['group'] = 'https://connect.smashballoon.com/auth/fb/?wordpress_user=' . $sb_admin_email . '&state=';
382 $urls['stateURL'] = $admin_url_state;
383
384 return $urls;
385 }
386
387 /**
388 * Used as a listener for the account connection process. If
389 * data is returned from the account connection processed it's used
390 * to generate the list of possible sources to chose from.
391 *
392 * @return array|bool
393 *
394 * @since 4.0
395 */
396 public static function maybe_source_connection_data() {
397 if ( isset( $_GET['cff_access_token'] )
398 && isset( $_GET['cff_final_response'] )
399 && $_GET['cff_final_response'] == 'true' ) {
400
401 // clear access token errors since the user is reconnecting accounts
402 $reporter = \CustomFacebookFeed\CFF_Utils::cff_is_pro_version() ? cff_main_pro()->cff_error_reporter : cff_main()->cff_error_reporter;
403 $reporter->remove_error( 'accesstoken' );
404
405 $access_token = sanitize_text_field( $_GET['cff_access_token'] );
406 if ( isset( $_GET['cff_group'] ) ) {
407 $return = CFF_Source::retrieve_available_groups( $access_token );
408 } else {
409 $return = CFF_Source::retrieve_available_pages( $access_token );
410 }
411
412 if ( $return ) {
413 return $return;
414
415 } else {
416 return array( 'error' => __( 'Unable to connect to Facebook to retrieve account information.', 'custom-facebook-feed' ) );
417 }
418
419 }
420
421 return false;
422 }
423
424 /**
425 * Uses the Facebook API to retrieve a list of pages for the
426 * access token
427 *
428 * @param string $access_token
429 *
430 * @return array|bool
431 *
432 * @since 4.0
433 */
434 public static function retrieve_available_pages( $access_token ) {
435
436 //Get User Info
437 $user_url = 'https://graph.facebook.com/me?fields=name,id,picture&access_token=' . $access_token;
438 $user_id_data = \CustomFacebookFeed\CFF_Utils::cff_fetchUrl( $user_url );
439 $user_id_data_arr = json_decode( $user_id_data );
440
441 $url = 'https://graph.facebook.com/me/accounts?fields=access_token,name,id&limit=500&access_token=' . $access_token;
442 $pages_data = \CustomFacebookFeed\CFF_Utils::cff_fetchUrl( $url );
443 $pages_data_arr = json_decode( $pages_data, true );
444
445 if ( isset( $pages_data_arr['data'] ) ) {
446 $return = array(
447 'user' => $user_id_data_arr,
448 'pages' => $pages_data_arr['data'],
449 );
450
451 return $return;
452 } else if ( isset( $pages_data_arr['error'] ) ) {
453 return $pages_data_arr;
454 } else {
455 return [
456 'error' => [
457 'code' => 'HTTP Request',
458 'message' => __( 'Your server could not complete a remote request to Facebook\'s API. Your host may be blocking access or there may be a problem with your server.', 'custom-facebook-feed' )
459 ]
460 ];
461 }
462
463 return false;
464 }
465
466 /**
467 * Uses the Facebook API to retrieve a list of groups for the
468 * access token split into "admin" and "member" groupings
469 *
470 * @param string $access_token
471 *
472 * @return array|bool
473 *
474 * @since 4.0
475 */
476 public static function retrieve_available_groups( $access_token ) {
477 //Extend the user token by making a call to /me/accounts. User must be an admin of a page for this to work as won't work if the response is empty.
478 $url = 'https://graph.facebook.com/me/accounts?limit=500&access_token=' . $access_token;
479
480 $accounts_data = \CustomFacebookFeed\CFF_Utils::cff_fetchUrl( $url );
481 if ( empty( $accounts_data ) ) {
482 return [
483 'error' => [
484 'code' => 'HTTP Request',
485 'message' => __( 'Your server could not complete a remote request to Facebook\'s API. Your host may be blocking access or there may be a problem with your server.', 'custom-facebook-feed' )
486 ]
487 ];
488 }
489 $accounts_data_arr = json_decode( $accounts_data );
490 $cff_token_expiration = 'never';
491 if ( empty( $accounts_data_arr->data ) ) {
492 $cff_token_expiration = '60 days';
493 }
494
495 if ( ! empty( $accounts_data_arr->error ) ) {
496 return $accounts_data_arr;
497 }
498
499 //Get User Info
500 $user_url = 'https://graph.facebook.com/me?fields=name,id,picture&access_token=' . $access_token;
501 $user_id_data = \CustomFacebookFeed\CFF_Utils::cff_fetchUrl( $user_url );
502
503 if ( ! empty( $user_id_data ) ) {
504 $user_id_data_arr = json_decode( $user_id_data );
505
506 $user_id = $user_id_data_arr->id;
507
508 $admin_ids = [];
509 //Get groups they're admin of
510 $groups_admin_url = 'https://graph.facebook.com/' . $user_id . '/groups?admin_only=true&fields=name,id,picture&access_token=' . $access_token;
511 $groups_admin_data = \CustomFacebookFeed\CFF_Utils::cff_fetchUrl( $groups_admin_url );
512 $groups_admin_data_arr = json_decode( $groups_admin_data, true );
513 $admin_groups = array();
514 if ( isset( $groups_admin_data_arr['data'] ) ) {
515 foreach ( $groups_admin_data_arr['data'] as $single_group ) {
516 $single_group['expiration'] = $cff_token_expiration;
517 $single_group['access_token'] = $access_token;
518 $admin_groups[] = $single_group;
519 $admin_ids[] = $single_group['id'];
520 }
521 }
522
523 //Get member groups
524 $groups_url = 'https://graph.facebook.com/' . $user_id . '/groups?admin_only=false&fields=name,id,picture&access_token=' . $access_token;
525 $groups_data = \CustomFacebookFeed\CFF_Utils::cff_fetchUrl( $groups_url );
526 $groups_data_arr = json_decode( $groups_data, true );
527 $member_groups = array();
528 if ( isset( $groups_data_arr['data'] ) ) {
529 foreach ( $groups_data_arr['data'] as $single_group ) {
530 if ( ! in_array( $single_group['id'], $admin_ids, true ) ) {
531 $single_group['expiration'] = $cff_token_expiration;
532 $single_group['access_token'] = $access_token;
533 $member_groups[] = $single_group;
534 }
535
536 }
537 }
538 $return = array(
539 'user' => $user_id_data_arr,
540 'admin' => $admin_groups,
541 'member' => $member_groups
542 );
543
544 return $return;
545 } else if ( isset( $accounts_data_arr['error'] ) ) {
546 return $accounts_data;
547 } else {
548 return [
549 'error' => [
550 'code' => 'HTTP Request',
551 'message' => __( 'Your server could not complete a remote request to Facebook\'s API. Your host may be blocking access or there may be a problem with your server.', 'custom-facebook-feed' )
552 ]
553 ];
554 }
555
556 return false;
557 }
558
559 /**
560 * Used to update or insert connected accounts (sources)
561 *
562 * @param array $source_data
563 *
564 * @return bool
565 *
566 * @since 4.0
567 */
568 public static function update_or_insert( $source_data ) {
569 if ( ! isset( $source_data['id'] ) ) {
570 return false;
571 }
572
573 if ( isset( $source_data['info'] ) ) {
574 // data from an API request related to the source is saved as a JSON string
575 if ( is_object( $source_data['info'] ) || is_array( $source_data['info'] ) ) {
576 $source_data['info'] = \CustomFacebookFeed\CFF_Utils::cff_json_encode( $source_data['info'] );
577 }
578 }
579
580 if ( CFF_Source::exists_in_database( $source_data ) ) {
581 $source_data['last_updated'] = date( 'Y-m-d H:i:s' );
582 CFF_Source::update( $source_data );
583 } else {
584 if ( ! isset( $source_data['access_token'] ) ) {
585 return false;
586 }
587 CFF_Source::insert( $source_data );
588 }
589 }
590
591 /**
592 * Whether or not the source exists in the database
593 *
594 * @param array $args
595 *
596 * @return bool
597 *
598 * @since 4.0
599 */
600 public static function exists_in_database( $args ) {
601 $results = CFF_Db::source_query( $args );
602
603 return isset( $results[0] );
604 }
605
606 /**
607 * Add a new source as a row in the cff_sources table
608 *
609 * @param array $source_data
610 *
611 * @return false|int
612 *
613 * @since 4.0
614 */
615 public static function insert( $source_data ) {
616 $source_data['username'] = $source_data['name'];
617 $data = $source_data;
618
619 return CFF_Db::source_insert( $data );
620 }
621
622 /**
623 * Update info in rows that match the source data
624 *
625 * @param array $source_data
626 *
627 * @return false|int
628 *
629 * @since 4.0
630 */
631 public static function update( $source_data, $where_privilige = true ) {
632 $where = array( 'id' => $source_data['id'] );
633 unset( $source_data['id'] );
634
635 if ( $where_privilige && isset( $source_data['privilege'] ) ) {
636 $where['privilege'] = $source_data['privilege'];
637 }
638
639 // usernames are more common in the other plugins so
640 // that is the name of the column that is used as the
641 // page or group "name" data
642 if ( isset( $source_data['name'] ) ) {
643 $source_data['username'] = $source_data['name'];
644 }
645 $data = $source_data;
646
647 return CFF_Db::source_update( $data, $where );
648 }
649
650 /**
651 * Attempts to find the album or playlist ID from
652 * a Facebook URL
653 *
654 * @param string $url_or_post_id
655 * @param string $type
656 *
657 * @return bool|mixed|string
658 *
659 * @since 4.0
660 */
661 public static function extract_id( $url_or_post_id, $type ) {
662 $id = false;
663
664 if ( $type === 'album' ) {
665 if ( strpos( $url_or_post_id, '/' ) === false ) {
666 $id = sanitize_text_field( $url_or_post_id );
667 } elseif( strpos( $url_or_post_id, '&set=a.' ) !== false ) {
668 $things = explode( '&set=a.', $url_or_post_id );
669
670 $id = $things[1];
671 } else {
672 $regex = '/(?:https?:\/\/)?(?:www\.)?facebook\.com\/(?:(?:\w\.)*#!\/)?(?:pages\/)?(?:[\w\-\.]*\/)*([\w\-\.]*)/';
673 if ( preg_match( $regex, $url_or_post_id, $matches ) ) {
674
675 if ( isset( $matches[0] ) ) {
676 $id = end( $matches );
677 }
678 }
679 }
680 } elseif ( $type === 'playlist') {
681 if ( strpos( $url_or_post_id, '/' ) === false ) {
682 $id = sanitize_text_field( $url_or_post_id );
683 } else { //https://www.facebook.com/watch/539051002877739/1979731855647067/?more=less // https://www.facebook.com/videos/vl.1234567890/
684 $regex = "~(?:vl\.\d+/)?(\d+)~i";
685 if ( stripos( $url_or_post_id, 'videos' ) !== false && preg_match( $regex, $url_or_post_id, $matches ) ) {
686 if ( isset( $matches[0] ) ) {
687 $id_pieces = end( $matches );
688
689 if ( strpos( $id_pieces, '.' ) !== false ) {
690 $id = explode( '.', $id_pieces )[1];
691 } else {
692 $id = $matches[0];
693 error_log(json_encode($matches));
694 }
695 }
696
697 } else {
698 if ( strpos( $url_or_post_id, '?' ) !== false ) {
699 $url_or_post_id = explode( '?', $url_or_post_id )[0];
700 }
701
702 $parts = explode( '/', $url_or_post_id );
703
704
705 $id = $parts[ count( $parts ) - 1 ];
706
707 if ( empty( $id ) ) {
708 $id = $parts[ count( $parts ) - 2 ];
709 }
710
711 $id = (int) filter_var( $id, FILTER_SANITIZE_NUMBER_INT );
712 }
713
714 }
715 }
716
717 return $id;
718 }
719
720 /**
721 * Creates a queue of connected accounts that need to be added to
722 * the sources table
723 *
724 * @since 4.0.3
725 */
726 public static function set_legacy_source_queue() {
727 $cff_statuses_option = get_option( 'cff_statuses', array() );
728 $connected_accounts = (array)json_decode(stripcslashes(get_option( 'cff_connected_accounts' )), true);
729
730 $cff_statuses_option['legacy_source_queue'] = array_chunk( array_keys( $connected_accounts ), CFF_Source::BATCH_SIZE );
731
732 update_option( 'cff_statuses', $cff_statuses_option );
733 }
734
735 /**
736 * Whether or not there are still sources in the queue and
737 * this isn't disabled
738 *
739 * @return bool
740 *
741 * @since 4.0.3
742 */
743 public static function should_do_source_updates() {
744 $cff_statuses_option = get_option( 'cff_statuses', array() );
745
746 $should_do_source_updates = isset( $cff_statuses_option['legacy_source_queue'] ) ? ! empty( $cff_statuses_option['legacy_source_queue'] ) : false;
747
748 return apply_filters( 'should_do_source_updates', $should_do_source_updates );
749 }
750
751 /**
752 * Processes one set of connected accounts
753 *
754 * @since 4.0.3
755 */
756 public static function batch_process_legacy_source_queue() {
757 if ( ! CFF_Source::should_do_source_updates() ) {
758 return;
759 }
760
761 $cff_statuses_option = get_option( 'cff_statuses', array() );
762 $batch = array_shift( $cff_statuses_option['legacy_source_queue'] );
763 update_option( 'cff_statuses', $cff_statuses_option ); // updated early just in case there is a fatal error
764
765 if ( empty( $batch ) ) {
766 return;
767 }
768 $connected_accounts = (array)json_decode(stripcslashes(get_option( 'cff_connected_accounts' )), true);
769 foreach ( $batch as $account_key ) {
770 $connected_account = isset( $connected_accounts[ $account_key ] ) ? $connected_accounts[ $account_key ] : false;
771
772 if ( $connected_account ) {
773 CFF_Source::update_single_source( $connected_account );
774 }
775 }
776
777 }
778
779 /**
780 * Transfer data from a connected account to the sources table
781 * after it's been validated with an API call
782 *
783 * @param array $connected_account
784 *
785 * @since 4.0.3
786 */
787 public static function update_single_source( $connected_account ) {
788 $cff_page_slugs = get_option( 'cff_page_slugs', array() );
789 $access_token = str_replace("02Sb981f26534g75h091287a46p5l63","", $connected_account['accesstoken'] );
790 $id = str_replace( ' ', '', $connected_account['id'] );
791 $header_details = \CustomFacebookFeed\CFF_Utils::fetch_header_data( $id, $connected_account['pagetype'] === 'group', $access_token, 0, false, '' );
792
793 $source_data = array(
794 'access_token' => $connected_account['accesstoken'],
795 'id' => $connected_account['id'],
796 'type' => $connected_account['pagetype'],
797 'name' => $connected_account['name'],
798 'privilege' => '', // see if events token?
799 );
800
801 if ( ! is_numeric( $id ) ) {
802 if ( ! isset( $cff_page_slugs[ $id ] ) ) {
803 $cff_page_slugs[ $id ] = $header_details->id;
804 update_option( 'cff_page_slugs', $cff_page_slugs );
805 }
806 $source_data['id'] = $header_details->id;
807 }
808
809 if ( isset( $header_details->shortcode_options ) ) {
810 unset( $header_details->shortcode_options );
811 }
812
813 if ( isset( $header_details->name ) ) {
814 $source_data['name'] = $header_details->name;
815 }
816 $source_data['info'] = $header_details;
817 $source_data['error'] = '';
818
819 if ( isset( $header_details->error ) || isset( $header_details->cached_error ) ) {
820 $source_data['error'] = isset( $header_details->error ) ? \CustomFacebookFeed\CFF_Utils::cff_json_encode( $header_details->error ) : \CustomFacebookFeed\CFF_Utils::cff_json_encode( $header_details->cached_error );
821 }
822
823 CFF_Source::update_or_insert( $source_data );
824
825 $source_data['record_id'] = 0;
826 $source_data['account_id'] = $connected_account['id'];
827 $source_data['account_type'] = $connected_account['pagetype'];
828 $source_data['username'] = $source_data['name'];
829
830 return $source_data;
831 }
832
833 /**
834 * Creates a source from the access token and
835 * source ID saved in 3.x settings
836 *
837 * @since 4.0.3
838 */
839 public static function update_source_from_legacy_settings() {
840 $db_access_token_option = get_option( 'cff_access_token' );
841 $db_page_access_token = get_option( 'cff_page_access_token' );
842 $db_page_id_option = get_option( 'cff_page_id' );
843 $db_page_type = get_option( 'cff_page_type' );
844 $cff_page_slugs = get_option( 'cff_page_slugs', array() );
845
846 if ( (! empty( $db_access_token_option ) || ! empty( $db_page_access_token ))
847 && ! empty( $db_page_id_option ) ) {
848 $db_access_tokens = explode(',', str_replace( ' ', '', $db_access_token_option ) );
849 $db_page_ids = explode(',', str_replace( ' ', '', $db_page_id_option ) );
850
851 $i = 0;
852 foreach ( $db_access_tokens as $db_access_token ){
853 if ( strpos( $db_access_token, ':' ) !== false ) {
854 $id_at_arr = explode( ':', $db_access_token );
855 $db_page_id = $id_at_arr[0];
856 $db_access_token = $id_at_arr[1];
857 } else {
858 $db_page_id = $db_page_ids[ $i ];
859 }
860 $source_data = array(
861 'access_token' => ! empty( $db_page_access_token ) ? $db_page_access_token : $db_access_token,
862 'id' => $db_page_id,
863 'type' => $db_page_type === 'group' ? 'group' : 'page',
864 'name' => $db_page_id,
865 'privilege' => '', // see if events token?
866 );
867
868 $header_details = \CustomFacebookFeed\CFF_Utils::fetch_header_data( $source_data['id'], $source_data['type'] === 'group', $source_data['access_token'], 0, false, '' );
869
870 if ( isset( $header_details->shortcode_options ) ) {
871 unset( $header_details->shortcode_options );
872 }
873
874 if ( isset( $header_details->name ) ) {
875 $source_data['name'] = $header_details->name;
876 }
877
878 if ( ! is_numeric( $source_data['id'] ) && isset( $header_details->id ) ) {
879 if ( ! isset( $cff_page_slugs[ $source_data['id'] ] ) ) {
880 $cff_page_slugs[ $source_data['id'] ] = $header_details->id;
881 update_option( 'cff_page_slugs', $cff_page_slugs );
882 }
883 $source_data['id'] = $header_details->id;
884 }
885
886 $source_data['info'] = $header_details;
887
888 // don't update or insert the access token if there is an API error
889 if ( ! isset( $header_details->error ) && ! isset( $header_details->cached_error ) ) {
890 \CustomFacebookFeed\Builder\CFF_Source::update_or_insert( $source_data );
891 } else {
892 if ( ! empty( $db_page_access_token ) && ! empty( $db_access_token ) ) {
893 $source_data = array(
894 'access_token' => $db_access_token,
895 'id' => $db_page_id,
896 'type' => $db_page_type === 'group' ? 'group' : 'page',
897 'name' => $db_page_id,
898 'privilege' => '', // see if events token?
899 );
900
901 $header_details = \CustomFacebookFeed\CFF_Utils::fetch_header_data( $source_data['id'], $source_data['type'] === 'group', $source_data['access_token'], 0, false, '' );
902
903 if ( isset( $header_details->shortcode_options ) ) {
904 unset( $header_details->shortcode_options );
905 }
906
907 if ( isset( $header_details->name ) ) {
908 $source_data['name'] = $header_details->name;
909 }
910 $source_data['info'] = $header_details;
911
912 if ( ! isset( $header_details->error ) && ! isset( $header_details->cached_error ) ) {
913 \CustomFacebookFeed\Builder\CFF_Source::update_or_insert( $source_data );
914 }
915 }
916 }
917 $i++;
918 }
919
920 }
921 }
922
923 /**
924 * If the plugin is still updating legacy sources this function
925 * can be used to udpate a single source if needed before
926 * the update is done.
927 *
928 * @param string $slug_or_id
929 *
930 * @return array|bool
931 */
932 public static function maybe_one_off_connected_account_update( $slug_or_id ) {
933 if ( ! CFF_Source::should_do_source_updates() ) {
934 return false;
935 }
936
937 $connected_accounts = (array)json_decode(stripcslashes(get_option( 'cff_connected_accounts' )), true);
938 $connected_account = isset( $connected_accounts[ $slug_or_id ] ) ? $connected_accounts[ $slug_or_id ] : false;
939
940 if ( $connected_account ) {
941 return CFF_Source::update_single_source( $connected_account );
942 }
943
944 return false;
945 }
946
947 /**
948 * Get the Facebook ID using an alphanumeric page "slug" if
949 * it has been created in the DB
950 *
951 * @param string $slug
952 *
953 * @return bool|string
954 *
955 * @since 4.0.3
956 */
957 public static function get_id_from_slug( $slug ) {
958 $cff_page_slugs = get_option( 'cff_page_slugs', array() );
959 if ( isset( $cff_page_slugs[ $slug ] ) ) {
960 return $cff_page_slugs[ $slug ];
961 }
962 return false;
963 }
964
965 /**
966 * Clears the "error" column in the cff_sources table for a specific
967 * account
968 *
969 * @param string $account_id
970 *
971 * @return bool
972 *
973 * @since 4.0.3
974 */
975 public static function clear_error( $account_id ) {
976 $source_data = array(
977 'id' => $account_id,
978 'error' => ''
979 );
980 return \CustomFacebookFeed\Builder\CFF_Source::update_or_insert( $source_data );
981 }
982
983 /**
984 * Adds an error to the error table by account ID
985 *
986 * @param string $account_id
987 * @param string|object|array $error
988 *
989 * @return bool
990 *
991 * @since 4.0.3
992 */
993 public static function add_error( $account_id, $error ) {
994 $source_data = array(
995 'id' => $account_id,
996 'error' => is_string( $error ) ? $error : \CustomFacebookFeed\CFF_Utils::cff_json_encode( $error )
997 );
998 return \CustomFacebookFeed\Builder\CFF_Source::update_or_insert( $source_data );
999 }
1000 }