PDF rausgenommen
This commit is contained in:
@ -0,0 +1,8 @@
|
||||
.yst_colorpicker {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
label.checkbox {
|
||||
display: block;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
jQuery(document).ready(function($){
|
||||
$('.yst_colorpicker').wpColorPicker();
|
||||
});
|
@ -0,0 +1,36 @@
|
||||
/* global wpseoMediaL10n */
|
||||
/* global ajaxurl */
|
||||
/* global wp */
|
||||
/* jshint -W097 */
|
||||
/* jshint -W003 */
|
||||
/* jshint unused:false */
|
||||
|
||||
// Taken and adapted from http://www.webmaster-source.com/2013/02/06/using-the-wordpress-3-5-media-uploader-in-your-plugin-or-theme/
|
||||
jQuery(document).ready(
|
||||
function($) {
|
||||
'use strict';
|
||||
if( typeof wp.media === 'undefined' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('.wpseo_image_upload_button').each(function(index, element) {
|
||||
var wpseo_target_id = $(element).attr('id').replace(/_button$/, '');
|
||||
var wpseo_custom_uploader = wp.media.frames.file_frame = wp.media({
|
||||
title: wpseoMediaL10n.choose_image,
|
||||
button: { text: wpseoMediaL10n.choose_image },
|
||||
multiple: false
|
||||
});
|
||||
|
||||
wpseo_custom_uploader.on( 'select', function() {
|
||||
var attachment = wpseo_custom_uploader.state().get( 'selection' ).first().toJSON();
|
||||
$( '#' + wpseo_target_id ).val( attachment.url );
|
||||
}
|
||||
);
|
||||
|
||||
$(element).click( function( e ) {
|
||||
e.preventDefault();
|
||||
wpseo_custom_uploader.open();
|
||||
} );
|
||||
} );
|
||||
}
|
||||
);
|
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/**
|
||||
* @package YoastSEO_AMP_Glue\Admin
|
||||
* @author Joost de Valk
|
||||
* @copyright 2016 Yoast BV
|
||||
* @license GPL-2.0+
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'YoastSEO_AMP_Backend', false ) ) {
|
||||
/**
|
||||
* This class improves upon the AMP output by the default WordPress AMP plugin using Yoast SEO metadata.
|
||||
*/
|
||||
class YoastSEO_AMP_Backend {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $options;
|
||||
|
||||
/**
|
||||
* YoastSEO_AMP_Backend constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->options = YoastSEO_AMP_Options::get();
|
||||
|
||||
// Add subitem to menu
|
||||
add_filter( 'wpseo_submenu_pages', array( $this, 'add_submenu_page' ) );
|
||||
|
||||
// Register AMP admin page as a Yoast SEO admin page
|
||||
add_filter( 'wpseo_admin_pages', array( $this, 'add_admin_pages' ) );
|
||||
|
||||
add_filter( 'wpseo_amp_supported_post_types', array( $this, 'remove_page_post_type' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out page post-type if not enabled in the AMP plugin.
|
||||
*
|
||||
* @param array $post_types Post types enabled for AMP support.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function remove_page_post_type( $post_types ) {
|
||||
if ( ! post_type_supports( 'page', AMP_QUERY_VAR ) ) {
|
||||
unset( $post_types[ 'page' ] );
|
||||
}
|
||||
|
||||
return $post_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add submenu item
|
||||
*
|
||||
* @param array $sub_menu_pages
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_submenu_page( $sub_menu_pages ) {
|
||||
|
||||
$sub_menu_pages[] = array(
|
||||
'wpseo_dashboard',
|
||||
__( 'AMP', 'wordpress-seo' ),
|
||||
__( 'AMP', 'wordpress-seo' ),
|
||||
'manage_options',
|
||||
'wpseo_amp',
|
||||
array( $this, 'display' ),
|
||||
array( array( $this, 'enqueue_admin_page' ) ),
|
||||
);
|
||||
|
||||
return $sub_menu_pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the admin page
|
||||
*/
|
||||
public function display() {
|
||||
require 'views/admin-page.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue admin page JS
|
||||
*/
|
||||
public function enqueue_admin_page() {
|
||||
wp_enqueue_style( 'yoast_amp_css', plugin_dir_url( __FILE__ ) . 'assets/amp-admin-page.css', array( 'wp-color-picker' ), false );
|
||||
|
||||
wp_enqueue_media(); // enqueue files needed for upload functionality
|
||||
wp_enqueue_script( 'wpseo-admin-media', plugin_dir_url( __FILE__ ) . 'assets/wp-seo-admin-media.js', array(
|
||||
'jquery',
|
||||
'jquery-ui-core',
|
||||
), false, true );
|
||||
wp_localize_script( 'wpseo-admin-media', 'wpseoMediaL10n', $this->localize_media_script() );
|
||||
|
||||
wp_enqueue_script( 'yoast_amp_js', plugin_dir_url( __FILE__ ) . 'assets/amp-admin-page.js', array(
|
||||
'jquery',
|
||||
'wp-color-picker'
|
||||
), false, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass some variables to js for upload module.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function localize_media_script() {
|
||||
return array(
|
||||
'choose_image' => __( 'Use Logo', 'wordpress-seo' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add admin page to admin_pages so the correct assets are loaded by WPSEO
|
||||
*
|
||||
* @param $admin_pages
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_admin_pages( $admin_pages ) {
|
||||
$admin_pages[] = 'wpseo_amp';
|
||||
|
||||
return $admin_pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a color picker
|
||||
*
|
||||
* @param string $var
|
||||
* @param string $label
|
||||
*
|
||||
* @SuppressWarnings("PMD.UnusedPrivateMethod") // As this is used in a view
|
||||
*/
|
||||
private function color_picker( $var, $label ) {
|
||||
echo '<label class="checkbox" for="', esc_attr( $var ), '">', esc_html( $label ), '</label>';
|
||||
echo '<input type="text" name="wpseo_amp[', esc_attr( $var ), ']"';
|
||||
if ( isset( $this->options[ $var ] ) ) {
|
||||
echo ' value="' . esc_attr( $this->options[ $var ] ) . '"';
|
||||
}
|
||||
echo ' class="yst_colorpicker" id="', esc_attr( $var ), '"/>';
|
||||
echo '<br/>';
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* @package YoastSEO_AMP_Glue\CSS_Builder
|
||||
* @author Jip Moors
|
||||
* @copyright 2016 Yoast BV
|
||||
* @license GPL-2.0+
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'YoastSEO_AMP_CSS_Builder', false ) ) {
|
||||
|
||||
class YoastSEO_AMP_CSS_Builder {
|
||||
|
||||
/** @var array Option to CSS lookup map */
|
||||
private $items = array();
|
||||
|
||||
/**
|
||||
* Add option to CSS map
|
||||
*
|
||||
* @param string $option_key Option key.
|
||||
* @param string $selector CSS Selector.
|
||||
* @param string $property CSS Property that will hold the value of the option.
|
||||
*/
|
||||
public function add_option( $option_key, $selector, $property ) {
|
||||
$this->items[ $option_key ] = array( 'selector' => $selector, 'property' => $property );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Output CSS
|
||||
*/
|
||||
public function build() {
|
||||
$options = YoastSEO_AMP_Options::get();
|
||||
|
||||
$output = "\n";
|
||||
$css = array();
|
||||
|
||||
$options = array_filter( $options );
|
||||
$apply = array_intersect_key( $this->items, $options );
|
||||
|
||||
if ( is_array( $apply ) ) {
|
||||
foreach ( $apply as $key => $placement ) {
|
||||
|
||||
if ( ! isset( $css[ $placement['selector'] ] ) ) {
|
||||
$css[ $placement['selector'] ] = array();
|
||||
}
|
||||
|
||||
$css[ $placement['selector'] ][ $placement['property'] ] = $options[ $key ];
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $css ) ) {
|
||||
foreach ( $css as $selector => $properties ) {
|
||||
|
||||
$inner = '';
|
||||
foreach ( $properties as $property => $value ) {
|
||||
$inner .= sprintf( "%s: %s;\n", $property, $value );
|
||||
}
|
||||
|
||||
$output .= sprintf( "%s {\n%s}\n", $selector, $inner );
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,396 @@
|
||||
<?php
|
||||
/**
|
||||
* @package YoastSEO_AMP_Glue\Frontend
|
||||
* @author Joost de Valk
|
||||
* @copyright 2016 Yoast BV
|
||||
* @license GPL-2.0+
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'YoastSEO_AMP_Frontend' ) ) {
|
||||
/**
|
||||
* This class improves upon the AMP output by the default WordPress AMP plugin using Yoast SEO metadata.
|
||||
*/
|
||||
class YoastSEO_AMP_Frontend {
|
||||
|
||||
/**
|
||||
* @var WPSEO_Frontend
|
||||
*/
|
||||
private $front;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $wpseo_options;
|
||||
|
||||
/**
|
||||
* YoastSEO_AMP_Frontend constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->set_options();
|
||||
|
||||
add_action( 'amp_init', array( $this, 'post_types' ) );
|
||||
|
||||
add_action( 'amp_post_template_css', array( $this, 'additional_css' ) );
|
||||
add_action( 'amp_post_template_head', array( $this, 'extra_head' ) );
|
||||
add_action( 'amp_post_template_footer', array( $this, 'extra_footer' ) );
|
||||
|
||||
add_filter( 'amp_post_template_data', array( $this, 'fix_amp_post_data' ) );
|
||||
add_filter( 'amp_post_template_metadata', array( $this, 'fix_amp_post_metadata' ), 10, 2 );
|
||||
add_filter( 'amp_post_template_analytics', array( $this, 'analytics' ) );
|
||||
|
||||
add_filter( 'amp_content_sanitizers', array( $this, 'add_sanitizer' ) );
|
||||
}
|
||||
|
||||
private function set_options() {
|
||||
$this->wpseo_options = WPSEO_Options::get_all();
|
||||
$this->options = YoastSEO_AMP_Options::get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add our own sanitizer to the array of sanitizers
|
||||
*
|
||||
* @param array $sanitizers
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_sanitizer( $sanitizers ) {
|
||||
require_once 'class-sanitizer.php';
|
||||
|
||||
$sanitizers['Yoast_AMP_Blacklist_Sanitizer'] = array();
|
||||
|
||||
return $sanitizers;
|
||||
}
|
||||
|
||||
/**
|
||||
* If analytics tracking has been set, output it now.
|
||||
*
|
||||
* @param array $analytics
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function analytics( $analytics ) {
|
||||
// If Monster Insights is outputting analytics, don't do anything.
|
||||
if ( ! empty( $analytics['monsterinsights-googleanalytics'] ) ) {
|
||||
// Clear analytics-extra options because Monster Insights is taking care of everything.
|
||||
$this->options['analytics-extra'] = '';
|
||||
|
||||
return $analytics;
|
||||
}
|
||||
|
||||
if ( ! empty( $this->options['analytics-extra'] ) ) {
|
||||
return $analytics;
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'Yoast_GA_Options' ) || Yoast_GA_Options::instance()->get_tracking_code() === null ) {
|
||||
return $analytics;
|
||||
}
|
||||
$UA = Yoast_GA_Options::instance()->get_tracking_code();
|
||||
|
||||
$analytics['yst-googleanalytics'] = array(
|
||||
'type' => 'googleanalytics',
|
||||
'attributes' => array(),
|
||||
'config_data' => array(
|
||||
'vars' => array(
|
||||
'account' => $UA
|
||||
),
|
||||
'triggers' => array(
|
||||
'trackPageview' => array(
|
||||
'on' => 'visible',
|
||||
'request' => 'pageview',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $analytics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make AMP work for all the post types we want it for
|
||||
*/
|
||||
public function post_types() {
|
||||
$post_types = get_post_types( array( 'public' => true ), 'objects' );
|
||||
if ( is_array( $post_types ) && $post_types !== array() ) {
|
||||
foreach ( $post_types as $post_type ) {
|
||||
|
||||
$post_type_name = $post_type->name;
|
||||
|
||||
if ( ! isset( $this->options[ 'post_types-' . $post_type_name . '-amp' ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If AMP page support is not present, don't allow enabling it here.
|
||||
if ( 'page' === $post_type_name && ! post_type_supports( 'page', AMP_QUERY_VAR ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $this->options[ 'post_types-' . $post_type_name . '-amp' ] === 'on' ) {
|
||||
add_post_type_support( $post_type_name, AMP_QUERY_VAR );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( 'post' === $post_type_name ) {
|
||||
add_action( 'wp', array( $this, 'disable_amp_for_posts' ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
remove_post_type_support( $post_type_name, AMP_QUERY_VAR );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables AMP for posts specifically, run later because of AMP plugin internals
|
||||
*/
|
||||
public function disable_amp_for_posts() {
|
||||
remove_post_type_support( 'post', AMP_QUERY_VAR );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the basic AMP post data
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fix_amp_post_data( $data ) {
|
||||
if ( ! $this->front ) {
|
||||
$this->front = WPSEO_Frontend::get_instance();
|
||||
}
|
||||
$data['canonical_url'] = $this->front->canonical( false );
|
||||
|
||||
if ( ! empty( $this->options['amp_site_icon'] ) ) {
|
||||
$data['site_icon_url'] = $this->options['amp_site_icon'];
|
||||
}
|
||||
|
||||
// If we are loading extra analytics, we need to load the module too.
|
||||
if ( ! empty( $this->options['analytics-extra'] ) ) {
|
||||
$data['amp_component_scripts']['amp-analytics'] = 'https://cdn.ampproject.org/v0/amp-analytics-0.1.js';
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the AMP metadata for a post
|
||||
*
|
||||
* @param array $metadata
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fix_amp_post_metadata( $metadata, $post ) {
|
||||
if ( ! $this->front ) {
|
||||
$this->front = WPSEO_Frontend::get_instance();
|
||||
}
|
||||
|
||||
$this->build_organization_object( $metadata );
|
||||
|
||||
$desc = $this->front->metadesc( false );
|
||||
if ( $desc ) {
|
||||
$metadata['description'] = $desc;
|
||||
}
|
||||
|
||||
$image = isset( $metadata['image'] ) ? $metadata['image'] : null;
|
||||
|
||||
$metadata['image'] = $this->get_image( $post, $image );
|
||||
$metadata['@type'] = $this->get_post_schema_type( $post );
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional CSS to the AMP output
|
||||
*/
|
||||
public function additional_css() {
|
||||
require 'views/additional-css.php';
|
||||
|
||||
$selectors = $this->get_class_selectors();
|
||||
|
||||
$css_builder = new YoastSEO_AMP_CSS_Builder();
|
||||
$css_builder->add_option( 'header-color', $selectors[ 'header-color' ], 'background' );
|
||||
$css_builder->add_option( 'headings-color', $selectors[ 'headings-color' ], 'color' );
|
||||
$css_builder->add_option( 'text-color', $selectors[ 'text-color' ], 'color' );
|
||||
|
||||
$css_builder->add_option( 'blockquote-bg-color', $selectors[ 'blockquote-bg-color' ], 'background-color' );
|
||||
$css_builder->add_option( 'blockquote-border-color', $selectors[ 'blockquote-border-color' ], 'border-color' );
|
||||
$css_builder->add_option( 'blockquote-text-color', $selectors[ 'blockquote-text-color' ], 'color' );
|
||||
|
||||
$css_builder->add_option( 'link-color', $selectors[ 'link-color' ], 'color' );
|
||||
$css_builder->add_option( 'link-color-hover', $selectors[ 'link-color-hover' ], 'color' );
|
||||
|
||||
$css_builder->add_option( 'meta-color', $selectors[ 'meta-color' ], 'color' );
|
||||
|
||||
echo $css_builder->build();
|
||||
|
||||
if ( ! empty( $this->options['extra-css'] ) ) {
|
||||
$safe_text = strip_tags( $this->options['extra-css'] );
|
||||
$safe_text = wp_check_invalid_utf8( $safe_text );
|
||||
$safe_text = _wp_specialchars( $safe_text, ENT_NOQUOTES );
|
||||
echo $safe_text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs extra code in the head, if set
|
||||
*/
|
||||
public function extra_head() {
|
||||
$options = WPSEO_Options::get_option( 'wpseo_social' );
|
||||
|
||||
if ( $options['twitter'] === true ) {
|
||||
WPSEO_Twitter::get_instance();
|
||||
}
|
||||
|
||||
if ( $options['opengraph'] === true ) {
|
||||
$GLOBALS['wpseo_og'] = new WPSEO_OpenGraph;
|
||||
}
|
||||
|
||||
do_action( 'wpseo_opengraph' );
|
||||
|
||||
echo strip_tags( $this->options['extra-head'], '<link><meta>' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs analytics code in the footer, if set
|
||||
*/
|
||||
public function extra_footer() {
|
||||
echo $this->options['analytics-extra'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the organization object if needed.
|
||||
*
|
||||
* @param array $metadata
|
||||
*/
|
||||
private function build_organization_object( &$metadata ) {
|
||||
// While it's using the blog name, it's actually outputting the company name.
|
||||
if ( ! empty( $this->wpseo_options['company_name'] ) ) {
|
||||
$metadata['publisher']['name'] = $this->wpseo_options['company_name'];
|
||||
}
|
||||
|
||||
// The logo needs to be 600px wide max, 60px high max.
|
||||
$logo = $this->get_image_object( $this->wpseo_options['company_logo'], array( 600, 60 ) );
|
||||
if ( is_array( $logo ) ) {
|
||||
$metadata['publisher']['logo'] = $logo;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an image object array from an image URL
|
||||
*
|
||||
* @param string $image_url Image URL to build URL for.
|
||||
* @param string|array $size Optional. Image size. Accepts any valid image size, or an array of width
|
||||
* and height values in pixels (in that order). Default 'full'.
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
private function get_image_object( $image_url, $size = 'full' ) {
|
||||
if ( empty( $image_url ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$image_id = attachment_url_to_postid( $image_url );
|
||||
$image_src = wp_get_attachment_image_src( $image_id, $size );
|
||||
|
||||
if ( is_array( $image_src ) ) {
|
||||
return array(
|
||||
'@type' => 'ImageObject',
|
||||
'url' => $image_src[0],
|
||||
'width' => $image_src[1],
|
||||
'height' => $image_src[2]
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Schema.org image for the post
|
||||
*
|
||||
* @param WP_Post $post Post to retrieve the data for.
|
||||
* @param array|null $image The currently set post image.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_image( $post, $image ) {
|
||||
$og_image = $this->get_image_object( WPSEO_Meta::get_value( 'opengraph-image', $post->ID ) );
|
||||
if ( is_array( $og_image ) ) {
|
||||
return $og_image;
|
||||
}
|
||||
|
||||
// Posts without an image fail validation in Google, leading to Search Console errors
|
||||
if ( ! is_array( $image ) && isset( $this->options['default_image'] ) ) {
|
||||
return $this->get_image_object( $this->options['default_image'] );
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Schema.org type for the post, based on the post type.
|
||||
*
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_post_schema_type( $post ) {
|
||||
$type = 'WebPage';
|
||||
if ( 'post' === $post->post_type ) {
|
||||
$type = 'Article';
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: 'yoastseo_amp_schema_type' - Allow changing the Schema.org type for the post
|
||||
*
|
||||
* @api string $type The Schema.org type for the $post
|
||||
*
|
||||
* @param WP_Post $post
|
||||
*/
|
||||
$type = apply_filters( 'yoastseo_amp_schema_type', $type, $post );
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets version dependent class names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_class_selectors() {
|
||||
$selectors = array(
|
||||
'header-color' => 'nav.amp-wp-title-bar',
|
||||
'headings-color' => '.amp-wp-title, h2, h3, h4',
|
||||
'text-color' => '.amp-wp-content',
|
||||
|
||||
'blockquote-bg-color' => '.amp-wp-content blockquote',
|
||||
'blockquote-border-color' => '.amp-wp-content blockquote',
|
||||
'blockquote-text-color' => '.amp-wp-content blockquote',
|
||||
|
||||
'link-color' => 'a, a:active, a:visited',
|
||||
'link-color-hover' => 'a:hover, a:focus',
|
||||
|
||||
'meta-color' => '.amp-wp-meta li, .amp-wp-meta li a',
|
||||
);
|
||||
|
||||
// CSS classnames have been changed in version 0.4.0.
|
||||
if ( version_compare( AMP__VERSION, '0.4.0', '>=' ) ) {
|
||||
$selectors_v4 = array(
|
||||
'header-color' => 'header.amp-wp-header, html',
|
||||
'text-color' => 'div.amp-wp-article',
|
||||
'blockquote-bg-color' => '.amp-wp-article-content blockquote',
|
||||
'blockquote-border-color' => '.amp-wp-article-content blockquote',
|
||||
'blockquote-text-color' => '.amp-wp-article-content blockquote',
|
||||
'meta-color' => '.amp-wp-meta, .amp-wp-meta a',
|
||||
);
|
||||
$selectors = array_merge( $selectors, $selectors_v4 );
|
||||
}
|
||||
|
||||
return $selectors;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,233 @@
|
||||
<?php
|
||||
/**
|
||||
* @package YoastSEO_AMP_Glue\Options
|
||||
* @author Jip Moors
|
||||
* @copyright 2016 Yoast BV
|
||||
* @license GPL-2.0+
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'YoastSEO_AMP_Options' ) ) {
|
||||
|
||||
class YoastSEO_AMP_Options {
|
||||
|
||||
/** @var string Name of the option in the database */
|
||||
private $option_name = 'wpseo_amp';
|
||||
|
||||
/** @var array Current options */
|
||||
private $options;
|
||||
|
||||
/** @var array Option defaults */
|
||||
private $defaults = array(
|
||||
'version' => 1,
|
||||
'amp_site_icon' => '',
|
||||
'default_image' => '',
|
||||
'header-color' => '',
|
||||
'headings-color' => '',
|
||||
'text-color' => '',
|
||||
'meta-color' => '',
|
||||
'link-color' => '',
|
||||
'link-color-hover' => '',
|
||||
'underline' => 'underline',
|
||||
'blockquote-text-color' => '',
|
||||
'blockquote-bg-color' => '',
|
||||
'blockquote-border-color' => '',
|
||||
'extra-css' => '',
|
||||
'extra-head' => '',
|
||||
'analytics-extra' => '',
|
||||
);
|
||||
|
||||
/** @var self Class instance */
|
||||
private static $instance;
|
||||
|
||||
private function __construct() {
|
||||
// Register settings
|
||||
add_action( 'admin_init', array( $this, 'register_settings' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the premium settings
|
||||
*/
|
||||
public function register_settings() {
|
||||
register_setting( 'wpseo_amp_settings', $this->option_name, array( $this, 'sanitize_options' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize options
|
||||
*
|
||||
* @param $options
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function sanitize_options( $options ) {
|
||||
$options['version'] = 1;
|
||||
|
||||
// Sanitize extra CSS field.
|
||||
$extra_css = strip_tags( $options['extra-css'] );
|
||||
$extra_css = wp_check_invalid_utf8( $extra_css );
|
||||
$extra_css = _wp_specialchars( $extra_css, ENT_NOQUOTES );
|
||||
$options['extra-css'] = $extra_css;
|
||||
|
||||
// Only allow meta and link tags in head.
|
||||
$options['extra-head'] = strip_tags( $options['extra-head'], '<link><meta>' );
|
||||
|
||||
$colors = array(
|
||||
'header-color',
|
||||
'headings-color',
|
||||
'text-color',
|
||||
'meta-color',
|
||||
'link-color',
|
||||
'blockquote-text-color',
|
||||
'blockquote-bg-color',
|
||||
'blockquote-border-color',
|
||||
);
|
||||
|
||||
foreach ( $colors as $color ) {
|
||||
$options[ $color ] = $this->sanitize_color( $options[ $color ], '' );
|
||||
}
|
||||
|
||||
// Only allow 'on' or 'off'
|
||||
foreach ( $options as $key => $value ) {
|
||||
if ( 'post_types-' === substr( $key, 0, 11 ) ) {
|
||||
$options[ $key ] = ( $value === 'on' ) ? 'on' : 'off';
|
||||
}
|
||||
}
|
||||
|
||||
$options['analytics-extra'] = $this->sanitize_analytics_code( $options['analytics-extra'] );
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize hexadecimal color
|
||||
*
|
||||
* @param string $color String to test for valid color.
|
||||
* @param string $default Value the string will get when no color is found.
|
||||
*
|
||||
* @return string Color or $default
|
||||
*/
|
||||
private function sanitize_color( $color, $default ) {
|
||||
if ( preg_match( '~^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{3})$~', $color, $matches ) ) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $source Raw input.
|
||||
*
|
||||
* @return string Sanitized code.
|
||||
*/
|
||||
private function sanitize_analytics_code( $source ) {
|
||||
|
||||
$source = trim( $source );
|
||||
|
||||
if ( empty( $source ) ) {
|
||||
return $source;
|
||||
}
|
||||
|
||||
$code = $source;
|
||||
|
||||
// Strip all tags, to verify JSON input.
|
||||
$json = strip_tags( $code );
|
||||
$parsed_json = json_decode( $json, true );
|
||||
|
||||
// Non-parsable JSON is always bad.
|
||||
if ( is_null( $parsed_json ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$allowed_tags = strip_tags( $code, '<amp-analytics>' );
|
||||
|
||||
// Strip JSON content so we can apply verified script tag.
|
||||
$tag = str_replace( $json, '', $allowed_tags );
|
||||
|
||||
// If the tag doesn't occur in the code, the code is invalid.
|
||||
if ( false === strpos( $allowed_tags, '<amp-analytics' ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$parts = explode( '><', $tag );
|
||||
$parts[0] .= '>';
|
||||
$parts[1] = '<' . $parts[1];
|
||||
|
||||
// Rebuild with script tag and json content.
|
||||
array_splice( $parts, 1, null, array(
|
||||
'<script type="application/json">',
|
||||
trim( $json ),
|
||||
'</script>'
|
||||
) );
|
||||
|
||||
return implode( "\n", $parts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get() {
|
||||
|
||||
$me = self::get_instance();
|
||||
$me->fetch_options();
|
||||
|
||||
return $me->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return YoastSEO_AMP_Options
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( ! isset( self::$instance ) ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect options
|
||||
*
|
||||
* @SuppressWarnings("PMD.UnusedPrivateMethod")
|
||||
*/
|
||||
private function fetch_options() {
|
||||
$saved_options = $this->options;
|
||||
if ( ! is_array( $this->options ) ) {
|
||||
$saved_options = get_option( 'wpseo_amp' );
|
||||
|
||||
// Apply defaults.
|
||||
$this->options = wp_parse_args( $saved_options, $this->defaults );
|
||||
}
|
||||
|
||||
// Make sure all post types are present.
|
||||
$this->update_post_type_settings();
|
||||
|
||||
// Save changes to database.
|
||||
if ( $this->options !== $saved_options ) {
|
||||
update_option( $this->option_name, $this->options );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get post types
|
||||
*/
|
||||
private function update_post_type_settings() {
|
||||
$post_type_names = array();
|
||||
|
||||
$post_types = get_post_types( array( 'public' => true ), 'objects' );
|
||||
|
||||
if ( is_array( $post_types ) && $post_types !== array() ) {
|
||||
foreach ( $post_types as $post_type ) {
|
||||
if ( ! isset( $this->options[ 'post_types-' . $post_type->name . '-amp' ] ) ) {
|
||||
$this->options[ 'post_types-' . $post_type->name . '-amp' ] = 'off';
|
||||
if ( 'post' === $post_type->name ) {
|
||||
$this->options[ 'post_types-' . $post_type->name . '-amp' ] = 'on';
|
||||
}
|
||||
}
|
||||
|
||||
$post_type_names[] = $post_type->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'AMP__DIR__' ) ) {
|
||||
header( 'Status: 403 Forbidden' );
|
||||
header( 'HTTP/1.1 403 Forbidden' );
|
||||
exit();
|
||||
}
|
||||
|
||||
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-base-sanitizer.php' );
|
||||
|
||||
/**
|
||||
* Strips blacklisted tags and attributes from content, on top of the ones the AMP plugin already removes.
|
||||
*
|
||||
* See following for blacklist:
|
||||
* https://github.com/ampproject/amphtml/blob/master/spec/amp-html-format.md#html-tags
|
||||
*/
|
||||
class Yoast_AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
||||
|
||||
/**
|
||||
* The actual sanitization function
|
||||
*/
|
||||
public function sanitize() {
|
||||
$body = $this->get_body_node();
|
||||
$this->strip_attributes_recursive( $body );
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes through the DOM and removes stuff that shouldn't be there.
|
||||
*
|
||||
* @param DOMNode $node
|
||||
*/
|
||||
private function strip_attributes_recursive( $node ) {
|
||||
if ( $node->nodeType !== XML_ELEMENT_NODE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $node->hasAttributes() ) {
|
||||
$node_name = $node->nodeName;
|
||||
$length = $node->attributes->length;
|
||||
for ( $i = $length - 1; $i >= 0; $i -- ) {
|
||||
$attribute = $node->attributes->item( $i );
|
||||
|
||||
switch ( $node_name ) {
|
||||
case 'a':
|
||||
$this->sanitize_a_attribute( $node, $attribute );
|
||||
break;
|
||||
case 'pre':
|
||||
$this->sanitize_pre_attribute( $node, $attribute );
|
||||
break;
|
||||
case 'table':
|
||||
$this->sanitize_table_attribute( $node, $attribute );
|
||||
break;
|
||||
case 'td':
|
||||
case 'th':
|
||||
$this->sanitize_cell_attribute( $node, $attribute );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $node->childNodes as $child_node ) {
|
||||
$this->strip_attributes_recursive( $child_node );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes through the DOM and strips forbidden tags
|
||||
*
|
||||
* @param DOMNode $node
|
||||
* @param array $tag_names
|
||||
*/
|
||||
private function strip_tags( $node, $tag_names ) {
|
||||
foreach ( $tag_names as $tag_name ) {
|
||||
$elements = $node->getElementsByTagName( $tag_name );
|
||||
$length = $elements->length;
|
||||
if ( 0 === $length ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( $i = $length - 1; $i >= 0; $i -- ) {
|
||||
$element = $elements->item( $i );
|
||||
$parent_node = $element->parentNode;
|
||||
$parent_node->removeChild( $element );
|
||||
|
||||
if ( 'body' !== $parent_node->nodeName && AMP_DOM_Utils::is_node_empty( $parent_node ) ) {
|
||||
$parent_node->parentNode->removeChild( $parent_node );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes anchor attributes
|
||||
*
|
||||
* @param DOMNode $node
|
||||
* @param object $attribute
|
||||
*/
|
||||
private function sanitize_a_attribute( $node, $attribute ) {
|
||||
$attribute_name = strtolower( $attribute->name );
|
||||
|
||||
if ( 'rel' === $attribute_name && 'nofollow' !== $attribute->value ) {
|
||||
$node->removeAttribute( $attribute_name );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes pre tag attributes
|
||||
*
|
||||
* @param DOMNode $node
|
||||
* @param object $attribute
|
||||
*/
|
||||
private function sanitize_pre_attribute( $node, $attribute ) {
|
||||
$attribute_name = strtolower( $attribute->name );
|
||||
|
||||
if ( 'line' === $attribute_name ) {
|
||||
$node->removeAttribute( $attribute_name );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes td / th tag attributes
|
||||
*
|
||||
* @param DOMNode $node
|
||||
* @param object $attribute
|
||||
*/
|
||||
private function sanitize_cell_attribute( $node, $attribute ) {
|
||||
$attribute_name = strtolower( $attribute->name );
|
||||
|
||||
if ( in_array( $attribute_name, array( 'width', 'height' ) ) ) {
|
||||
$node->removeAttribute( $attribute_name );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize table tag
|
||||
* attributes
|
||||
*
|
||||
* @param DOMNode $node
|
||||
* @param object $attribute
|
||||
*/
|
||||
private function sanitize_table_attribute( $node, $attribute ) {
|
||||
$attribute_name = strtolower( $attribute->name );
|
||||
|
||||
if ( in_array( $attribute_name, array( 'border', 'cellspacing', 'cellpadding', 'summary' ) ) ) {
|
||||
$node->removeAttribute( $attribute_name );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
td, th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
a, a:active, a:visited {
|
||||
text-decoration: <?php echo ( ( 'underline' === $this->options['underline'] ) ? 'underline' : 'none' ); ?>;
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'WPSEO_VERSION' ) ) {
|
||||
header( 'Status: 403 Forbidden' );
|
||||
header( 'HTTP/1.1 403 Forbidden' );
|
||||
exit();
|
||||
}
|
||||
|
||||
$yform = Yoast_Form::get_instance();
|
||||
$yform->admin_header( true, 'wpseo_amp', false, 'wpseo_amp_settings' );
|
||||
|
||||
?>
|
||||
|
||||
<h2 class="nav-tab-wrapper" id="wpseo-tabs">
|
||||
<a class="nav-tab" id="posttypes-tab" href="#top#posttypes"><?php echo esc_html( __( 'Post types', 'wordpress-seo' ) ); ?></a>
|
||||
<a class="nav-tab" id="design-tab" href="#top#design"><?php echo esc_html( __( 'Design', 'wordpress-seo' ) ); ?></a>
|
||||
<a class="nav-tab" id="analytics-tab" href="#top#analytics"><?php echo esc_html( __( 'Analytics', 'wordpress-seo' ) ); ?></a>
|
||||
</h2>
|
||||
|
||||
<div class="tabwrapper">
|
||||
|
||||
<div id="posttypes" class="wpseotab">
|
||||
<h2><?php echo esc_html( __( 'Post types that have AMP support', 'wordpress-seo' ) ); ?></h2>
|
||||
<p><?php echo esc_html( __( 'Generally you\'d want this to be your news post types.', 'wordpress-seo' ) ); ?><br/>
|
||||
<?php echo esc_html( __( 'Post is enabled by default, feel free to enable any of them.', 'wordpress-seo' ) ); ?></p>
|
||||
<?php
|
||||
|
||||
$post_types = apply_filters( 'wpseo_sitemaps_supported_post_types', get_post_types( array( 'public' => true ), 'objects' ) );
|
||||
|
||||
// Allow specific AMP post type overrides, especially needed for Page support.
|
||||
$post_types = apply_filters( 'wpseo_amp_supported_post_types', $post_types );
|
||||
|
||||
if ( is_array( $post_types ) && $post_types !== array() ) {
|
||||
foreach ( $post_types as $pt ) {
|
||||
$yform->toggle_switch(
|
||||
'post_types-' . $pt->name . '-amp',
|
||||
array(
|
||||
'on' => __( 'Enabled', 'wordpress-seo' ),
|
||||
'off' => __( 'Disabled', 'wordpress-seo' )
|
||||
),
|
||||
$pt->labels->name . ' (<code>' . $pt->name . '</code>)'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! post_type_supports( 'page', AMP_QUERY_VAR ) ):
|
||||
?>
|
||||
<br>
|
||||
<strong><?php echo esc_html( __( 'Please note:', 'wordpress-seo' ) ); ?></strong>
|
||||
<?php echo esc_html( __( 'Currently pages are not supported by the AMP plugin.', 'wordpress-seo' ) ); ?>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="design" class="wpseotab">
|
||||
<h3><?php echo esc_html( __( 'Images', 'wordpress-seo' ) ); ?></h3>
|
||||
|
||||
<?php
|
||||
$yform->media_input( 'amp_site_icon', __( 'AMP icon', 'wordpress-seo' ) ); ?>
|
||||
<p class="desc"><?php echo esc_html( __( 'Must be at least 32px × 32px', 'wordpress-seo' ) ); ?></p>
|
||||
<br/>
|
||||
|
||||
<?php
|
||||
$yform->media_input( 'default_image', __( 'Default image', 'wordpress-seo' ) ); ?>
|
||||
<p class="desc"><?php echo esc_html( __( 'Used when a post doesn\'t have an image associated with it.', 'wordpress-seo' ) ); ?>
|
||||
<br><?php echo esc_html( __( 'The image must be at least 696px wide.', 'wordpress-seo' ) ) ?></p>
|
||||
<br/>
|
||||
|
||||
<h3><?php echo esc_html( __( 'Content colors', 'wordpress-seo' ) ); ?></h3>
|
||||
|
||||
<?php
|
||||
$this->color_picker( 'header-color', __( 'AMP Header color', 'wordpress-seo' ) );
|
||||
$this->color_picker( 'headings-color', __( 'Title color', 'wordpress-seo' ) );
|
||||
$this->color_picker( 'text-color', __( 'Text color', 'wordpress-seo' ) );
|
||||
$this->color_picker( 'meta-color', __( 'Post meta info color', 'wordpress-seo' ) );
|
||||
?>
|
||||
<br/>
|
||||
|
||||
<h3><?php echo esc_html( __( 'Links', 'wordpress-seo' ) ); ?></h3>
|
||||
<?php
|
||||
$this->color_picker( 'link-color', __( 'Text color', 'wordpress-seo' ) );
|
||||
$this->color_picker( 'link-color-hover', __( 'Hover color', 'wordpress-seo' ) );
|
||||
?>
|
||||
|
||||
<?php $yform->light_switch( 'underline', __( 'Underline', 'wordpress-seo' ), array(
|
||||
__( 'Underline', 'wordpress-seo' ),
|
||||
__( 'No underline', 'wordpress-seo' )
|
||||
) ); ?>
|
||||
|
||||
<br/>
|
||||
|
||||
<h3><?php echo esc_html( __( 'Blockquotes', 'wordpress-seo' ) ); ?></h3>
|
||||
<?php
|
||||
$this->color_picker( 'blockquote-text-color', __( 'Text color', 'wordpress-seo' ) );
|
||||
$this->color_picker( 'blockquote-bg-color', __( 'Background color', 'wordpress-seo' ) );
|
||||
$this->color_picker( 'blockquote-border-color', __( 'Border color', 'wordpress-seo' ) );
|
||||
?>
|
||||
<br/>
|
||||
|
||||
<h3><?php echo esc_html( __( 'Extra CSS', 'wordpress-seo' ) ); ?></h3>
|
||||
<?php $yform->textarea( 'extra-css', __( 'Extra CSS', 'wordpress-seo' ), array(
|
||||
'rows' => 5,
|
||||
'cols' => 100
|
||||
) ); ?>
|
||||
|
||||
<br/>
|
||||
|
||||
<h3><?php printf( esc_html( __( 'Extra code in %s', 'wordpress-seo' ) ), '<code><head></code>' ); ?></h3>
|
||||
<p><?php echo sprintf( esc_html( __( 'Only %s and %s tags are allowed, other tags will be removed automatically.', 'wordpress-seo' ) ), '<code>meta</code>', '<code>link</code>' ) ?></p>
|
||||
<?php $yform->textarea( 'extra-head', __( 'Extra code', 'wordpress-seo' ), array(
|
||||
'rows' => 5,
|
||||
'cols' => 100
|
||||
) ); ?>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="analytics" class="wpseotab">
|
||||
<h2><?php echo esc_html( __( 'AMP Analytics', 'wordpress-seo' ) ); ?></h2>
|
||||
|
||||
<?php
|
||||
if ( class_exists( 'Yoast_GA_Options' ) ) {
|
||||
echo '<p>', esc_html( __( 'Because your Google Analytics plugin by Yoast is active, your AMP pages will also be tracked.', 'wordpress-seo' ) ), '<br>';
|
||||
$UA = Yoast_GA_Options::instance()->get_tracking_code();
|
||||
if ( $UA === null ) {
|
||||
echo esc_html( __( 'Make sure to connect your Google Analytics plugin properly.', 'wordpress-seo' ) );
|
||||
} else {
|
||||
echo sprintf( esc_html( __( 'Pageviews will be tracked using the following account: %s.', 'wordpress-seo' ) ), '<code>' . $UA . '</code>' );
|
||||
}
|
||||
|
||||
echo '</p>';
|
||||
|
||||
echo '<p>', esc_html( __( 'Optionally you can override the default AMP tracking code with your own by putting it below:', 'wordpress-seo' ) ), '</p>';
|
||||
$yform->textarea( 'analytics-extra', __( 'Analytics code', 'wordpress-seo' ), array(
|
||||
'rows' => 5,
|
||||
'cols' => 100
|
||||
) );
|
||||
} else {
|
||||
echo '<p>', esc_html( __( 'Optionally add a valid google analytics tracking code.', 'wordpress-seo' ) ), '</p>';
|
||||
$yform->textarea( 'analytics-extra', __( 'Analytics code', 'wordpress-seo' ), array(
|
||||
'rows' => 5,
|
||||
'cols' => 100
|
||||
) );
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
|
||||
$yform->admin_footer();
|
Reference in New Issue
Block a user