https?):\/\/www\.documentcloud\.org\/documents\/(?P[0-9]+-[\p{L}\p{N}%-]+)'; /** * Constructor. */ function __construct() { // Check for conflicts with other DocumentCloud plugins. // Not needed on WordPress VIP since no other DocumentCloud plugins exist. if ( ! defined( 'WPCOM_IS_VIP_ENV' ) || ! WPCOM_IS_VIP_ENV ) { add_action( 'admin_init', array( $this, 'check_dc_plugin_conflict' ) ); } // Register the oEmbed provider add_action( 'init', array( $this, 'register_dc_oembed_provider' ) ); // Set the textdomain for the plugin so it is translation compatible add_action( 'plugins_loaded', array( $this, 'load_plugin_textdomain' ) ); // Only called when `[documentcloud]` shortcode is used add_shortcode( 'documentcloud', array( $this, 'process_dc_shortcode' ) ); // Called just before oEmbed endpoint is hit add_filter( 'oembed_fetch_url', array( $this, 'prepare_oembed_fetch' ), 10, 3 ); // Setup the settings page add_action( 'admin_menu', array( $this, 'add_options_page' ) ); add_action( 'admin_init', array( $this, 'settings_init' ) ); } /** * Load plugin textdomain. */ function load_plugin_textdomain() { load_plugin_textdomain( 'documentcloud' ); } /** * Check for conflicts with the Navis DocumentCloud plugin. */ function check_dc_plugin_conflict() { if ( is_plugin_active( 'navis-documentcloud/navis-documentcloud.php' ) ) { add_action( 'admin_notices', array( $this, 'dc_conflict_admin_notice' ) ); } } /** * Create an admin notice when conflicts exist with Navis DocumentCloud. */ function dc_conflict_admin_notice() { ?>

Warning! You have two conflicting DocumentCloud plugins activated. Please deactivate Navis DocumentCloud, which has been replaced by DocumentCloud.', 'documentcloud' ) ); ?>

$height, 'width' => $width, 'full_width' => $full_width, ); } /** * Get the attribute defaults for the shortcode. * * @return array */ function get_default_atts() { $default_sizes = $this->get_default_sizes(); return array( 'url' => null, 'container' => null, 'notes' => null, 'responsive_offset' => null, 'page' => null, 'note' => null, 'zoom' => null, 'search' => null, 'responsive' => null, 'sidebar' => null, 'text' => null, 'pdf' => null, // The following defaults match the existing plugin, except // `height/width` are prefixed `max*` per the oEmbed spec. // You can still use `height/width` for backwards // compatibility, but they'll be mapped to `max*`. // Precedence (lower number == higher priority): // 1. `width` on shortcode // 2. `maxwidth` on shortcode // 3. Settings > DocumentCloud > "Default embed width" // 4. `wp_embed_defaults()['width']` 'maxheight' => $default_sizes['height'], 'maxwidth' => $default_sizes['width'], 'format' => 'normal', ); } /** * Prepare the oEmbed fetch URL. * * @param string $provider * @param string $url * @param array $args * @return string */ function prepare_oembed_fetch( $provider, $url, $args ) { // Merge actual args with default attributes so that defaults are always // sent to oEmbed endpoint $default_atts = $this->get_default_atts(); $atts = array_merge( $default_atts, $args ); // Some resources (like notes) have multiple possible // user-facing URLs. We recompose them into a single form. $url = $this->clean_dc_url( $url ); // Send these to the oEmbed endpoint itself $oembed_config_keys = array( 'maxheight', 'maxwidth' ); // Specifically *don't* include these on the embed config itself $excluded_embed_config_keys = array( 'url', 'format', 'height', 'width', 'maxheight', 'maxwidth', 'discover' ); // Clean and prepare arguments foreach ( $atts as $key => $value ) { if ( in_array( $key, $oembed_config_keys ) ) { $provider = add_query_arg( $key, $value, $provider ); } if ( ! in_array( $key, $excluded_embed_config_keys ) ) { // Without this check, `add_query_arg()` will treat values // that are actually ID selectors, like `container=#foo`, // as URL fragments and throw them at the end of the URL. if ( 0 === strpos( $value, '#' ) ) { $value = urlencode( $value ); } $url = add_query_arg( $key, $value, $url ); } } $provider = add_query_arg( 'url', urlencode( $url ), $provider ); return $provider; } /** * Create the DocumentCloud embed output from the shortcode. * * @param array $atts * @return string */ function process_dc_shortcode( $atts ) { $default_sizes = $this->get_default_sizes(); $default_atts = $this->get_default_atts(); // Smooshes together passed-in shortcode attrs with defaults // and filters to only those we accept. $filtered_atts = shortcode_atts( $default_atts, $atts ); // Either the `url` or `id` attributes are required, but `id` // is only supported for backwards compatibility. If it's used, // we force this to embed a document. I.e., `id` can't be used // for embedding notes, pages, or other non-document resources. if ( empty( $atts['url'] ) ) { if ( empty( $atts['id'] ) ) { return ''; } else { $url = $filtered_atts['url'] = 'https://' . WP_DocumentCloud::OEMBED_RESOURCE_DOMAIN . "/documents/{$atts['id']}.html"; } } // `height/width` beat `maxheight/maxwidth`; see full precedence list in `get_default_atts()`. if ( isset( $atts['height'] ) ) { $filtered_atts['maxheight'] = $atts['height']; } if ( isset( $atts['width'] ) ) { $filtered_atts['maxwidth'] = $atts['width']; } // `responsive` defaults true, but our responsive layout // ignores width declarations. If a user indicates a width and // hasn't otherwise specifically indicated `responsive='true'`, // it's safe to assume they expect us to respect the width, so // we disable the responsive flag. if ( ( isset( $atts['width'] ) || isset( $atts['maxwidth'] ) ) && 'true' !== $atts['responsive'] ) { $filtered_atts['responsive'] = 'false'; } // If the format is set to wide, it blows away all other width // settings. if ( 'wide' === $filtered_atts['format'] ) { $filtered_atts['maxwidth'] = $default_sizes['full_width']; } // For the benefit of some templates, notify template that // we're requesting an asset wider than the default size. global $post; $is_wide = intval( $filtered_atts['maxwidth'] ) > $default_sizes['width']; if ( apply_filters( 'documentcloud_caching_enabled', WP_DocumentCloud::CACHING_ENABLED ) ) { // This lets WordPress cache the result of the oEmbed call. // Thanks to http://bit.ly/1HykA0U for this pattern. global $wp_embed; $url = $filtered_atts['url'] = $this->clean_dc_url( $atts['url'] ); return $wp_embed->shortcode( $filtered_atts, $url ); } else { return wp_oembed_get( $atts['url'], $filtered_atts ); } } /** * Parse the DocumentCloud URL into its components. * * @param string $url * @return array */ function parse_dc_url( $url ) { $patterns = array( // Document '{' . WP_DocumentCloud::DOCUMENT_PATTERN . '\.html$}', // Pages and page variants '{' . WP_DocumentCloud::DOCUMENT_PATTERN . '.html#document\/p(?P[0-9]+)$}', '{' . WP_DocumentCloud::DOCUMENT_PATTERN . '\/pages\/(?P[0-9]+)\.(html|js)$}', // Notes and note variants '{' . WP_DocumentCloud::DOCUMENT_PATTERN . '\/annotations\/(?P[0-9]+)\.(html|js)$}', '{' . WP_DocumentCloud::DOCUMENT_PATTERN . '.html#document\/p([0-9]+)/a(?P[0-9]+)$}', '{' . WP_DocumentCloud::DOCUMENT_PATTERN . '.html#annotation\/a(?P[0-9]+)$}', ); $elements = array(); foreach ( $patterns as $pattern ) { $perfect_match = preg_match( $pattern, $url, $elements ); if ( $perfect_match ) { break; } } return $elements; } /** * Clean the DocumentCloud URL. * * @param string $url * @return string */ function clean_dc_url( $url ) { $elements = $this->parse_dc_url( $url ); if ( isset( $elements['document_slug'] ) ) { $url = "{$elements['protocol']}://" . WP_DocumentCloud::OEMBED_RESOURCE_DOMAIN . "/documents/{$elements['document_slug']}"; if ( isset( $elements['page_number'] ) ) { $url .= "/pages/{$elements['page_number']}"; } else if ( isset( $elements['note_id'] ) ) { $url .= "/annotations/{$elements['note_id']}"; } $url .= '.html'; } return $url; } /** * Add the DocumentCloud options page. */ function add_options_page() { if ( current_user_can( 'manage_options' ) ) { add_options_page( 'DocumentCloud', 'DocumentCloud', 'manage_options', 'documentcloud', array( $this, 'render_options_page' ) ); } } /** * Render the DocumentCloud options page. */ function render_options_page() { ?>

responsive="false" on an embed.', 'documentcloud' ) ) ?>

get_default_sizes(); echo ''; } /** * Render the default width field. */ function default_width_field() { $default_sizes = $this->get_default_sizes(); echo ''; } /** * Render the full width field. */ function full_width_field() { $default_sizes = $this->get_default_sizes(); echo ''; } } new WP_DocumentCloud;