/
var
/
www
/
barefootlaw.org
/
wp-content
/
plugins
/
fb-instant-articles
/
Upload File
HOME
<?php /** * Plugin Name: Instant Articles for WP * Description: Add support for Instant Articles for Facebook to your WordPress site. * Author: Automattic, Dekode, Facebook * Author URI: https://vip.wordpress.com/plugins/instant-articles/ * Version: 4.2.1 * Text Domain: instant-articles * License: GPLv2 * License URI: http://www.gnu.org/licenses/gpl-2.0.html * * @package default */ /** * Prints error about incompatible version. Extracted as function issue: #390 * * @since 3.3.4 */ function show_version_incompatible_warning() { echo '<div class="error"><p>' . esc_html__( 'Instant Articles for WP requires PHP 5.4 to function properly. Please upgrade PHP or deactivate Instant Articles for WP.', 'instant-articles' ) . '</p></div>'; } if ( version_compare( PHP_VERSION, '5.4', '<' ) ) { add_action( 'admin_notices', 'show_version_incompatible_warning' ); return; } else { $autoloader = require __DIR__ . '/vendor/autoload.php'; $autoloader->add( 'Facebook\\', __DIR__ . '/vendor/facebook/facebook-instant-articles-sdk-php/src' ); $autoloader->add( 'Facebook\\', __DIR__ . '/vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src' ); defined( 'ABSPATH' ) || die( 'Shame on you' ); define( 'IA_PLUGIN_VERSION', '4.2.1' ); define( 'IA_PLUGIN_PATH_FULL', __FILE__ ); define( 'IA_PLUGIN_PATH', plugin_basename( __FILE__ ) ); define( 'IA_PLUGIN_FILE_BASENAME', pathinfo( __FILE__, PATHINFO_FILENAME ) ); define( 'IA_PLUGIN_TEXT_DOMAIN', 'instant-articles' ); define( 'IA_PLUGIN_FORCE_SUBMIT_KEY', 'instant_articles_force_submit' ); // Let users define their own feed slug. if ( ! defined( 'INSTANT_ARTICLES_SLUG' ) ) { define( 'INSTANT_ARTICLES_SLUG', 'instant-articles' ); } require_once( dirname( __FILE__ ) . '/embeds.php' ); require_once( dirname( __FILE__ ) . '/class-instant-articles-post.php' ); require_once( dirname( __FILE__ ) . '/wizard/class-instant-articles-wizard.php' ); require_once( dirname( __FILE__ ) . '/meta-box/class-instant-articles-meta-box.php' ); require_once( dirname( __FILE__ ) . '/class-instant-articles-amp-markup.php' ); require_once( dirname( __FILE__ ) . '/class-instant-articles-signer.php' ); /** * Plugin activation hook to add our rewrite rules. * * @since 0.1 */ function instant_articles_activate() { instant_articles_init(); flush_rewrite_rules(); } register_activation_hook( __FILE__, 'instant_articles_activate' ); /** * Show a message to set up the plugin when it is activated */ add_action( 'admin_notices', 'instant_articles_setup_admin_notice' ); add_action( 'network_admin_notices', 'instant_articles_setup_admin_notice' ); // also show message on multisite function instant_articles_setup_admin_notice() { global $pagenow; if ( $pagenow === 'plugins.php' && ! Instant_Articles_Option_FB_Page::get_option_decoded()[ "page_id" ] ) { $settings_url = Instant_Articles_Wizard::get_url(); echo '<div class="updated settings-error notice is-dismissible">'; echo '<p>Congrats, you\'ve installed the Instant Articles for WP plugin. Now <a href="' . esc_url_raw($settings_url) . '">set it up</a> to start publishing Instant Articles.'; echo '</div>'; } } /** * Plugin activation hook to remove our rewrite rules. * * @since 0.1 */ function instant_articles_deactivate() { flush_rewrite_rules(); } register_deactivation_hook( __FILE__, 'instant_articles_deactivate' ); /** * Load plugin textdomain. * * @since 0.1 */ function instant_articles_load_textdomain() { load_plugin_textdomain( 'instant-articles', false, plugin_dir_path( __FILE__ ) . '/languages' ); } add_action( 'plugins_loaded', 'instant_articles_load_textdomain' ); /** * Plugin hook to load compat layers. * * @since 2.0 */ function instant_articles_load_compat() { require_once( dirname( __FILE__ ) . '/compat.php' ); } add_action( 'plugins_loaded', 'instant_articles_load_compat' ); /** * Register our special feed. * * @since 0.1 */ function instant_articles_init() { add_feed( INSTANT_ARTICLES_SLUG, 'instant_articles_feed' ); } add_action( 'init', 'instant_articles_init' ); /** * Feed display callback. * * @since 0.1 */ function instant_articles_feed() { // Load the feed template. include( dirname( __FILE__ ) . '/feed-template.php' ); } /** * Whether currently processing an instant article. * * @param bool Set the status * @return bool */ function is_transforming_instant_article( $set_status = null ) { static $is_instant_article = false; if ( isset( $set_status ) ) { $is_instant_article = (bool) $set_status; } return $is_instant_article; } /** * Modify the main query for our feed. * * We want the posts in the modified order, to provide Facebook with content updates even for older posts. * Facebook will only import 100 posts at the time. * Facebook will only update posts modified within the last 24 hours * * @param WP_Query $query The WP_Query object. Passed by reference. */ function instant_articles_query( $query ) { if ( $query->is_main_query() && $query->is_feed( INSTANT_ARTICLES_SLUG ) ) { $query->set( 'orderby', 'modified' ); $query->set( 'posts_per_page', 10 ); $query->set( 'posts_per_rss', 10 ); /** * Filter the post types to include in the query. * * Default to `post` only, but allow other post types to be included by the theme/plugins. * * @since 2.12 * * @param array $post_types Array of post types */ $post_types = apply_filters( 'instant_articles_post_types', array( 'post' ) ); $query->set( 'post_type', $post_types ); /** * If the constant INSTANT_ARTICLES_LIMIT_POSTS is set to true, we will limit the feed * to only include posts which are modified within the last 24 hours. * Facebook will initially need 100 posts to pass the review, but will only update * already imported articles if they are modified within the last 24 hours. */ if ( defined( 'INSTANT_ARTICLES_LIMIT_POSTS' ) && INSTANT_ARTICLES_LIMIT_POSTS ) { $query->set( 'date_query', array( array( 'column' => 'post_modified', 'after' => '1 day ago', ), ) ); } } } add_action( 'pre_get_posts', 'instant_articles_query', 10, 1 ); /** * Filter the SQL query to not include posts with empty content -- FB will complain. * * @since 0.1 * @param string $where The original where part of the SQL statement. * @param WP_Query $query The WP_Query instance. * @return string The modified where part of the SQL statement. */ function instant_articles_query_where( $where, $query ) { // Don’t modify the SQL query with a potentially expensive WHERE clause if we’re OK with fewer posts than 100 and are OK with filtering in the loop. if ( defined( 'INSTANT_ARTICLES_LIMIT_POSTS' ) && INSTANT_ARTICLES_LIMIT_POSTS ) { return $where; } if ( $query->is_main_query() && $query->is_feed( INSTANT_ARTICLES_SLUG ) ) { global $wpdb; $where .= " AND {$wpdb->posts}.post_content NOT LIKE ''"; } return $where; } add_filter( 'posts_where' , 'instant_articles_query_where', 10, 2 ); /** * Register all scripts and styles for the admin UI. * * @since 0.4 */ function instant_articles_register_scripts() { wp_register_style( 'instant-articles-meta-box', plugins_url( '/css/instant-articles-meta-box.css', __FILE__ ), null, IA_PLUGIN_VERSION, false ); wp_register_style( 'instant-articles-settings', plugins_url( '/css/instant-articles-settings.css', __FILE__ ), null, IA_PLUGIN_VERSION, false ); wp_register_style( 'instant-articles-wizard', plugins_url( '/css/instant-articles-wizard.css', __FILE__ ), null, IA_PLUGIN_VERSION, false ); wp_register_style( 'instant-articles-index-column', plugins_url( '/css/instant-articles-index-column.css', __FILE__ ), null, IA_PLUGIN_VERSION, false ); wp_register_script( 'instant-articles-meta-box', plugins_url( '/js/instant-articles-meta-box.js', __FILE__ ), null, IA_PLUGIN_VERSION, false ); wp_register_script( 'instant-articles-option-ads', plugins_url( '/js/instant-articles-option-ads.js', __FILE__ ), null, IA_PLUGIN_VERSION, false ); wp_register_script( 'instant-articles-option-analytics', plugins_url( '/js/instant-articles-option-analytics.js', __FILE__ ), null, IA_PLUGIN_VERSION, false ); wp_register_script( 'instant-articles-option-publishing', plugins_url( '/js/instant-articles-option-publishing.js', __FILE__ ), null, IA_PLUGIN_VERSION, false ); wp_register_script( 'instant-articles-settings', plugins_url( '/js/instant-articles-settings.js', __FILE__ ), null, IA_PLUGIN_VERSION, false ); } add_action( 'init', 'instant_articles_register_scripts' ); /** * Enqueue all scripts and styles for the admin UI. * * @since 0.4 */ function instant_articles_enqueue_scripts() { wp_enqueue_style( 'instant-articles-meta-box' ); wp_enqueue_style( 'instant-articles-settings-wizard' ); wp_enqueue_style( 'instant-articles-settings' ); wp_enqueue_style( 'instant-articles-wizard' ); wp_enqueue_style( 'instant-articles-index-column' ); wp_enqueue_script( 'instant-articles-meta-box' ); wp_enqueue_script( 'instant-articles-option-ads' ); wp_enqueue_script( 'instant-articles-option-analytics' ); wp_enqueue_script( 'instant-articles-option-publishing' ); wp_enqueue_script( 'instant-articles-settings' ); wp_enqueue_script( 'instant-articles-wizard' ); } add_action( 'admin_enqueue_scripts', 'instant_articles_enqueue_scripts' ); /** * Automatically add meta tag for Instant Articles URL claiming * when page is set. * * @since 0.4 */ function inject_url_claiming_meta_tag() { $publishing_settings = Instant_Articles_Option_Publishing::get_option_decoded(); $fb_page_settings = Instant_Articles_Option_FB_Page::get_option_decoded(); if ( isset( $fb_page_settings[ 'page_id' ] ) ) { ?> <meta property="fb:pages" content="<?php echo esc_attr( $fb_page_settings[ 'page_id' ] ); ?>" /> <?php } } add_action( 'wp_head', 'inject_url_claiming_meta_tag' ); /** * Automatically add meta tag for Instant Articles Open Publish scraper * * @since 4.0 */ function inject_ia_markup_meta_tag() { $post = get_post(); // If there's no current post, return if ( ! $post ) { return; } // Transform the post to an Instant Article. $adapter = new Instant_Articles_Post( $post ); if ( $adapter->should_submit_post() ) { $url = $adapter->get_canonical_url(); $url = add_query_arg( 'ia_markup', '1', $url ); $fb_page_settings = Instant_Articles_Option_FB_Page::get_option_decoded(); $publishing_settings = Instant_Articles_Option_Publishing::get_option_decoded(); $dev_mode = isset( $publishing_settings['dev_mode'] ) ? ( $publishing_settings['dev_mode'] ? true : false ) : false; if ( $dev_mode ) { ?> <meta property="ia:markup_url_dev" content="<?php echo esc_attr( $url ); ?>" /> <?php } else { ?> <meta property="ia:markup_url" content="<?php echo esc_attr( $url ); ?>" /> <?php } } } add_action( 'wp_head', 'inject_ia_markup_meta_tag' ); // Injects the <link rel...> tag if the AMP Markup is enabled add_action( 'wp_head', array('Instant_Articles_AMP_Markup', 'inject_link_rel') ); // Initialize the Instant Articles meta box. Instant_Articles_Meta_Box::init(); function ia_markup_version( ) { $post = get_post(); if (isset( $_GET[ 'ia_markup' ] ) && $_GET[ 'ia_markup' ]) { // Transform the post to an Instant Article. $adapter = new Instant_Articles_Post( $post ); $article = $adapter->to_instant_article(); echo $article->render( null, true ); die(); } } add_action( 'wp', 'ia_markup_version' ); // Add hook for generating the AMP markup add_action( 'wp', array('Instant_Articles_AMP_Markup', 'markup_version') ); Instant_Articles_Wizard::init(); Instant_Articles_Signer::init(); function invalidate_post_transformation_info_cache( $post_id, $post ) { // These post metas are caches on the calculations made to decide if // a post is in good state to be converted to an Instant Article or not delete_post_meta( $post_id, '_has_warnings_after_transformation' ); delete_post_meta( $post_id, '_is_empty_after_transformation' ); } add_action( 'save_post', 'invalidate_post_transformation_info_cache', 10, 2 ); // We also need to invalidate the transformation caches when the option containing // the custom transformer rules is updated function invalidate_all_posts_transformation_info_cache( $option ) { if ( $option === Instant_Articles_Option_Publishing::OPTION_KEY ) { // These post metas are caches on the calculations made to decide if // a post is in good state to be converted to an Instant Article or not delete_post_meta_by_key( '_has_warnings_after_transformation' ); delete_post_meta_by_key( '_is_empty_after_transformation' ); } } add_action( 'updated_option', 'invalidate_all_posts_transformation_info_cache', 10, 1 ); function fbia_indicator_column_heading( $columns ) { $publishing_settings = Instant_Articles_Option_Publishing::get_option_decoded(); $display_warning_column = isset( $publishing_settings[ 'display_warning_column' ] ) ? $publishing_settings[ 'display_warning_column' ] : '0'; if( "1" === $display_warning_column ) { $columns[ 'FBIA' ] = "<span title='Facebook Instant Article Distribution Status' class='fbia-col-heading'>FB IA Status</span>"; } return $columns; } add_filter( 'manage_posts_columns', 'fbia_indicator_column_heading' ); function fbia_indication_column( $column_name, $post_ID ) { $publishing_settings = Instant_Articles_Option_Publishing::get_option_decoded(); $display_warning_column = isset( $publishing_settings[ 'display_warning_column' ] ) ? $publishing_settings[ 'display_warning_column' ] : '0'; if( "1" === $display_warning_column ) { $red_light = '<span title="Instant article is empty after transformation." class="instant-articles-col-status error"></span>'; $yellow_light = '<span title="Instant article has warnings after transformation." class="instant-articles-col-status warning"></span>'; $green_light = '<span title="Instant article transformed successfully." class="instant-articles-col-status ok"></span>'; if ( $column_name === "FBIA" ) { $post = get_post( $post_ID ); $instant_articles_post = new \Instant_Articles_Post( $post ); $is_empty = $instant_articles_post->is_empty_after_transformation(); if ( true === $is_empty ) { echo wp_kses_post( $red_light ); return; } $has_warnings = $instant_articles_post->has_warnings_after_transformation(); if ( true === $has_warnings ) { echo wp_kses_post( $yellow_light ); return; } echo wp_kses_post( $green_light ); return; } } } add_action( 'manage_posts_custom_column', 'fbia_indication_column', 10, 2 ); function invalidate_scrape_on_update( $post_ID, $post_after, $post_before ) { $adapter = new Instant_Articles_Post( $post_after ); if ( $adapter->should_submit_post() ) { $fb_app_settings = Instant_Articles_Option_FB_App::get_option_decoded(); if ( ( isset( $fb_app_settings[ 'page_access_token' ] ) && $fb_app_settings[ 'page_access_token' ] ) && ( isset( $fb_app_settings[ 'app_id' ] ) && $fb_app_settings[ 'app_id' ] ) && ( isset( $fb_app_settings[ 'app_secret' ] ) && $fb_app_settings[ 'app_secret' ] ) ) { // Fetches the right URL to invalidate $url = $adapter->get_canonical_url(); // oAuth info $app_id = $fb_app_settings[ 'app_id' ]; $app_secret = $fb_app_settings[ 'app_secret' ]; $access_token = $fb_app_settings[ 'page_access_token' ]; // Build Graph SDK instance $fb = new \Facebook\Facebook([ 'app_id' => $app_id, 'app_secret' => $app_secret, 'default_access_token' => $access_token ]); function admin_notice__scrape_invalidation_failed() { ?> <div class="notice notice-error is-dismissible"> <p> <?php _e( 'It was not possible to automatically invalidate the scrape for this article.', IA_PLUGIN_TEXT_DOMAIN ) ?> <?php _e( 'Please trigger a new scrape manually using the Facebook Share Debugger.', IA_PLUGIN_TEXT_DOMAIN ) ?> </p> </div> <?php } function admin_notice__scrape_invalidation_success() { ?> <div class="notice notice-success is-dismissible"> <p> <?php _e( 'Successfully refreshed the Instant Articles cache for this article.', IA_PLUGIN_TEXT_DOMAIN ) ?> </p> </div> <?php } // Make call $graph_api_call = '/'; $graph_api_call = add_query_arg( 'id', rawurlencode($url), $graph_api_call); $graph_api_call = add_query_arg( 'scrape', 'true', $graph_api_call); try { $fb->post( $graph_api_call, [], $access_token ); add_action( 'admin_notices', 'admin_notice__scrape_invalidation_success' ); } catch(Facebook\Exceptions\FacebookResponseException $e) { echo '<pre>'; print_r($e->getTraceAsString()); add_action( 'admin_notices', 'admin_notice__scrape_invalidation_failed' ); } catch(Facebook\Exceptions\FacebookSDKException $e) { add_action( 'admin_notices', 'admin_notice__scrape_invalidation_failed' ); } } } } add_action( 'post_updated', 'invalidate_scrape_on_update', 10, 3 ); function rescrape_article( $post_id, $post ) { $adapter = new Instant_Articles_Post( $post ); $old_slugs = get_post_meta( $post_id, '_wp_old_slug' ); if ( $adapter->should_submit_post() ) { $fb_app_settings = Instant_Articles_Option_FB_App::get_option_decoded(); if ( ( isset( $fb_app_settings[ 'page_access_token' ] ) && $fb_app_settings[ 'page_access_token' ] ) && ( isset( $fb_app_settings[ 'app_id' ] ) && $fb_app_settings[ 'app_id' ] ) && ( isset( $fb_app_settings[ 'app_secret' ] ) && $fb_app_settings[ 'app_secret' ] ) ) { // Defer to access_token if configured to ensure backwards compatibility return; } try { if ( extension_loaded('openssl') ) { $client = Facebook\HttpClients\HttpClientsFactory::createHttpClient( null ); $url_encoded = urlencode($adapter->get_canonical_url()); $client->send( Instant_Articles_Signer::sign_request_path( "https://graph.facebook.com/?id=$url_encoded&scrape=true" ), 'POST', '', array(), 60 ); foreach ( $old_slugs as $slug ) { $clone_post = clone $post; $clone_post->post_name = $slug; $clone_adapter = new Instant_Articles_Post( $clone_post ); $url_encoded = urlencode($clone_adapter->get_canonical_url()); $client->send( Instant_Articles_Signer::sign_request_path( "https://graph.facebook.com/?id=$url_encoded&scrape=true" ), 'POST', '', array(), 60 ); } } } catch ( Exception $e ) { error_log( 'Unable to submit article.'.$e->getTraceAsString() ); } } } add_action( 'save_post', 'rescrape_article', 999, 2 ); }