Commit realizado el 12:13:52 08-04-2024

This commit is contained in:
Pagina Web Monito
2024-04-08 12:13:55 -04:00
commit 0c33094de9
7815 changed files with 1365694 additions and 0 deletions

View File

@@ -0,0 +1 @@
.recipe-instructions-data{margin-bottom:15px}.recipe-instructions-data .inner-wrapper{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:15px}.recipe-instructions-data .inner-wrapper img{margin-left:15px;max-width:200px}.rank-math-review-notes{margin-top:20px;margin-bottom:20px;float:left;width:100%}.rank-math-review-notes h4{margin-top:0;margin-bottom:20px}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(()=>{"use strict";const e=lodash,t=wp.i18n,a=wp.hooks,n=wp.data,m=wp.components;(0,a.addFilter)("rank_math_schema_list","rank-math-pro",(function(a){if((0,e.isEmpty)(rankMath.activeTemplates))return a;var l=wp.element.createElement("div",{className:"rank-math-schema-active-templates"},wp.element.createElement("h4",{className:"rank-math-schema-section-title"},(0,t.__)("Global Templates in Use","rank-math-pro")),(0,e.map)(rankMath.activeTemplates,(function(a,l){return wp.element.createElement("div",{key:l,id:"rank-math-schema-item",className:"rank-math-schema-item row"},wp.element.createElement("strong",{className:"rank-math-schema-name"},(0,e.get)(a,"metadata.title",a["@type"])),wp.element.createElement("span",{className:"rank-math-schema-item-actions"},wp.element.createElement(m.Button,{isLink:!0,className:"button rank-math-delete-schema",onClick:function(){return(0,n.dispatch)("rank-math-pro").deleteActiveTemplate(l)}},wp.element.createElement("i",{className:"rm-icon rm-icon-trash"}),wp.element.createElement("span",null,(0,t.__)("Delete","rank-math-pro")))))})));return wp.element.createElement(React.Fragment,null,a,l)}))})();

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,446 @@
<?php
/**
* The Schema Module
*
* @since 2.0.0
* @package RankMath
* @subpackage RankMath\Schema
* @author Rank Math <support@rankmath.com>
*/
namespace RankMathPro\Schema;
use RankMath\Helper;
use RankMath\Admin\Admin_Helper;
use RankMath\Schema\DB;
use RankMath\Traits\Hooker;
use RankMath\Rest\Sanitize;
use MyThemeShop\Helpers\Str;
use MyThemeShop\Helpers\Param;
use WP_Screen;
defined( 'ABSPATH' ) || exit;
/**
* Admin class.
*/
class Admin {
use Hooker;
/**
* The Constructor.
*/
public function __construct() {
$this->action( 'admin_enqueue_scripts', 'overwrite_wplink', 100 );
$this->action( 'rank_math/admin/before_editor_scripts', 'admin_scripts' );
$this->action( 'rank_math/admin/editor_scripts', 'deregister_scripts', 99 );
$this->action( 'save_post', 'save', 10, 2 );
$this->action( 'edit_form_after_title', 'render_div' );
$this->filter( 'rank_math/filter_metadata', 'filter_metadata', 10, 2 );
$this->filter( 'rank_math/settings/snippet/types', 'add_pro_schema_types' );
$this->filter( 'rank_math/schema/filter_data', 'update_schema_data' );
new Taxonomy();
}
/**
* Update schema data.
*
* @param array $schemas Schema data.
*/
public function update_schema_data( $schemas ) {
if ( empty( $schemas ) ) {
return $schemas;
}
foreach ( $schemas as $schema_key => $schema ) {
if ( empty( $schema['review'] ) ) {
continue;
}
if (
! empty( $schema['review']['positiveNotes'] ) &&
! empty( $schema['review']['positiveNotes']['itemListElement'] ) &&
is_string( $schema['review']['positiveNotes']['itemListElement'] )
) {
$notes = explode( PHP_EOL, $schema['review']['positiveNotes']['itemListElement'] );
$schemas[ $schema_key ]['review']['positiveNotes']['itemListElement'] = [];
foreach ( $notes as $key => $note ) {
$schemas[ $schema_key ]['review']['positiveNotes']['itemListElement'][] = [
'@type' => 'ListItem',
'position' => $key + 1,
'name' => $note,
];
}
}
if (
! empty( $schema['review']['negativeNotes'] ) &&
! empty( $schema['review']['negativeNotes']['itemListElement'] ) &&
is_string( $schema['review']['negativeNotes']['itemListElement'] )
) {
$notes = explode( PHP_EOL, $schema['review']['negativeNotes']['itemListElement'] );
$schemas[ $schema_key ]['review']['negativeNotes']['itemListElement'] = [];
foreach ( $notes as $key => $note ) {
$schemas[ $schema_key ]['review']['negativeNotes']['itemListElement'][] = [
'@type' => 'ListItem',
'position' => $key + 1,
'name' => $note,
];
}
}
}
return $schemas;
}
/**
* Add Pro schema types in Schema settings choices array.
*
* @param array $types Schema types.
*/
public function add_pro_schema_types( $types ) {
$types = array_merge(
$types,
[
'dataset' => esc_html__( 'DataSet', 'rank-math-pro' ),
'FactCheck' => esc_html__( 'Fact Check', 'rank-math-pro' ),
'movie' => esc_html__( 'Movie', 'rank-math-pro' ),
]
);
unset( $types['off'] );
ksort( $types, SORT_NATURAL | SORT_FLAG_CASE );
return [ 'off' => esc_html__( 'None (Click here to set one)', 'rank-math-pro' ) ] + $types;
}
/**
* Overwrite wplink script file.
* Rank Math adds new options in the link popup when editing a post.
*/
public function overwrite_wplink() {
if ( ! Admin_Helper::is_post_edit() || Admin_Helper::is_posts_page() ) {
return;
}
wp_deregister_script( 'rank-math-formats' );
wp_register_script(
'rank-math-formats',
RANK_MATH_PRO_URL . 'assets/admin/js/gutenberg-formats.js',
[],
rank_math_pro()->version,
true
);
wp_deregister_script( 'wplink' );
wp_register_script( 'wplink', RANK_MATH_PRO_URL . 'assets/admin/js/wplink.js', [ 'jquery', 'wpdialogs' ], rank_math_pro()->version, true );
wp_localize_script(
'wplink',
'wpLinkL10n',
[
'title' => esc_html__( 'Insert/edit link', 'rank-math-pro' ),
'update' => esc_html__( 'Update', 'rank-math-pro' ),
'save' => esc_html__( 'Add Link', 'rank-math-pro' ),
'noTitle' => esc_html__( '(no title)', 'rank-math-pro' ),
'noMatchesFound' => esc_html__( 'No matches found.', 'rank-math-pro' ),
'linkSelected' => esc_html__( 'Link selected.', 'rank-math-pro' ),
'linkInserted' => esc_html__( 'Link inserted.', 'rank-math-pro' ),
'relCheckbox' => '<code>rel="nofollow"</code>',
'sponsoredCheckbox' => '<code>rel="sponsored"</code>',
'aboutCheckbox' => '<code>about</code>',
'mentionsCheckbox' => '<code>mentions</code>',
'schemaMarkupLabel' => esc_html__( 'Use in Schema Markup', 'rank-math-pro' ),
'linkTitle' => esc_html__( 'Link Title', 'rank-math-pro' ),
]
);
}
/**
* Enqueue Styles and Scripts required for the schema functionality on Gutenberg & Classic editor.
*
* @return void
*/
public function admin_scripts() {
if ( ! $this->can_enqueue_scripts() ) {
return;
}
$this->localize_data();
wp_enqueue_style( 'rank-math-schema-pro', RANK_MATH_PRO_URL . 'includes/modules/schema/assets/css/schema.css', [ 'rank-math-schema' ], rank_math_pro()->version );
wp_enqueue_script(
'rank-math-pro-schema-filters',
RANK_MATH_PRO_URL . 'includes/modules/schema/assets/js/schemaFilters.js',
[
'wp-plugins',
'wp-components',
'wp-hooks',
'wp-api-fetch',
'lodash',
],
rank_math_pro()->version,
true
);
$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : false;
if ( $screen instanceof WP_Screen && 'rank_math_schema' === $screen->post_type ) {
Helper::add_json( 'isTemplateScreen', true );
wp_enqueue_script(
'rank-math-pro-schema',
rank_math()->plugin_url() . 'includes/modules/schema/assets/js/schema-template.js',
[
'clipboard',
'wp-autop',
'wp-components',
'wp-editor',
'wp-edit-post',
'wp-element',
'wp-i18n',
'wp-plugins',
'rank-math-analyzer',
],
rank_math_pro()->version,
true
);
return;
}
wp_enqueue_script( 'rank-math-schema-pro', RANK_MATH_PRO_URL . 'includes/modules/schema/assets/js/schema.js', [ 'rank-math-schema' ], rank_math_pro()->version, true );
}
/**
* Deregister some scripts.
*/
public function deregister_scripts() {
$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : false;
if ( ! $screen instanceof WP_Screen || 'post' !== $screen->base || Helper::is_elementor_editor() || 'rank_math_schema' !== $screen->post_type ) {
return;
}
wp_deregister_script( 'rank-math-editor' );
wp_deregister_script( 'rank-math-schema' );
if ( wp_script_is( 'rank-math-pro-editor', 'registered' ) ) {
wp_deregister_script( 'rank-math-pro-editor' );
}
}
/**
* Render app div
*/
public function render_div() {
$screen = get_current_screen();
if ( 'rank_math_schema' !== $screen->post_type ) {
return;
}
Helper::add_json( 'postType', 'rank_math_schema' );
wp_nonce_field( 'rank_math_schema_template', 'security' );
?>
<div id="rank-math-schema-template"></div>
<textarea name="rank_math_schema" rows="8" cols="80" class="rank-math-schema"></textarea>
<input type="text" name="rank_math_schema_meta_id" class="rank-math-schema-meta-id" value="">
<?php
}
/**
* Save post data.
*
* @param int $post_id Post id.
* @param object $post Post object.
*/
public function save( $post_id, $post ) {
if (
! isset( $_POST['security'] ) ||
! wp_verify_nonce( $_POST['security'], 'rank_math_schema_template' ) ||
! isset( $_POST['rank_math_schema'] )
) {
return $post_id;
}
$post_type = get_post_type_object( $post->post_type );
if ( ! current_user_can( $post_type->cap->edit_post, $post_id ) ) {
return $post_id;
}
$sanitizer = Sanitize::get();
$schema = stripslashes_deep( $_POST['rank_math_schema'] );
$schema = json_decode( $schema, true );
$schema = $sanitizer->sanitize( 'rank_math_schema', $schema );
$meta_key = 'rank_math_schema_' . $schema['@type'];
update_post_meta( $post_id, $meta_key, $schema );
// Publish Schema Template post.
if ( 'rank_math_schema' === $post->post_type && 'publish' !== $post->post_status ) {
wp_update_post(
[
'ID' => $post_id,
'post_status' => 'publish',
]
);
}
}
/**
* Add excluded template conditions in the Schema template and remove it from the metadata.
*
* @param array $meta Meta data to update.
* @param WP_REST_Request $request Full details about the request.
*
* @return array Processed metadata.
*/
public function filter_metadata( $meta, $request ) {
foreach ( $meta as $meta_key => $meta_value ) {
if ( ! Str::starts_with( 'rank_math_exclude_template_', $meta_key ) ) {
continue;
}
$template_id = absint( \str_replace( 'rank_math_exclude_template_', '', $meta_key ) );
$schema_data = DB::get_schemas( $template_id );
$meta_id = key( $schema_data );
$meta_key = 'rank_math_schema_' . $schema_data[ $meta_id ]['@type'];
$schema_data[ $meta_id ]['metadata']['displayConditions'][] = [
'condition' => 'exclude',
'category' => 'singular',
'type' => $request->get_param( 'objectType' ),
'value' => $request->get_param( 'objectID' ),
];
$db_id = absint( str_replace( 'schema-', '', $meta_id ) );
update_metadata_by_mid( 'post', $db_id, $schema_data[ $meta_id ], $meta_key );
unset( $meta[ "rank_math_exclude_template_{$template_id}" ] );
}
return $meta;
}
/**
* [get_schema_templates description]
*
* @return array
*/
protected function get_schema_templates() {
$posts = get_posts(
[
'post_type' => 'rank_math_schema',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
]
);
if ( empty( $posts ) ) {
return [];
}
$templates = [];
foreach ( $posts as $post ) {
$data = DB::get_template_type( $post->ID );
$data['title'] = $post->post_title;
$data['id'] = $post->ID;
$templates[] = $data;
}
return $templates;
}
/**
* Whether to enqueue schema scripts on the page.
*
* @return bool
*/
private function can_enqueue_scripts() {
if ( ! Helper::has_cap( 'onpage_snippet' ) ) {
return false;
}
if ( ! Helper::is_divi_frontend_editor() && ! is_admin() ) {
return false;
}
global $pagenow;
if ( 'edit-tags.php' === $pagenow ) {
return false;
}
if ( Admin_Helper::is_term_edit() ) {
$taxonomy = Param::request( 'taxonomy' );
return true !== apply_filters(
'rank_math/snippet/remove_taxonomy_data',
Helper::get_settings( 'titles.remove_' . $taxonomy . '_snippet_data' ),
$taxonomy
);
}
return ( Admin_Helper::is_post_edit() || Helper::is_divi_frontend_editor() ) && ! Admin_Helper::is_posts_page();
}
/**
* Add active templates to the schemas json
*
* @return array
*/
private function get_active_templates() {
$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : false;
if ( $screen instanceof WP_Screen && 'rank_math_schema' === $screen->post_type ) {
return [];
}
$templates = Display_Conditions::get_schema_templates();
if ( empty( $templates ) ) {
return [];
}
$schemas = [];
foreach ( $templates as $template ) {
$template['schema']['isTemplate'] = true;
$schemas[ $template['id'] ] = $template['schema'];
}
return $schemas;
}
/**
* Localized data.
*/
private function localize_data() {
$post = get_post();
Helper::add_json( 'postStatus', get_post_field( 'post_status', $post ) );
Helper::add_json( 'postLink', get_permalink( $post ) );
Helper::add_json( 'schemaTemplates', $this->get_schema_templates() );
Helper::add_json( 'activeTemplates', $this->get_active_templates() );
Helper::add_json( 'accessiblePostTypes', Helper::get_accessible_post_types() );
Helper::add_json( 'accessibleTaxonomies', Helper::get_accessible_taxonomies() );
Helper::add_json( 'postTaxonomies', $this->get_post_taxonomies() );
}
/**
* Get Post taxonomies.
*/
private function get_post_taxonomies() {
$post_types = Helper::get_accessible_post_types();
$data = [];
foreach ( $post_types as $post_type ) {
$taxonomies = Helper::get_object_taxonomies( $post_type );
if ( empty( $taxonomies ) ) {
continue;
}
unset( $taxonomies['off'] );
$data[ $post_type ] = [ 'all' => esc_html__( 'All Taxonomies', 'rank-math-pro' ) ] + $taxonomies;
}
return $data;
}
}

View File

@@ -0,0 +1,223 @@
<?php
/**
* The Schema AJAX
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMathPro
* @author MyThemeShop <admin@mythemeshop.com>
*/
namespace RankMathPro\Schema;
use MyThemeShop\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Ajax class.
*/
class Ajax {
use \RankMath\Traits\Hooker;
use \RankMath\Traits\Ajax;
/**
* The Constructor.
*/
public function __construct() {
$this->ajax( 'fetch_from_url', 'fetch_from_url' );
$this->ajax( 'get_conditions_data', 'get_conditions_data' );
}
/**
* Fetch from url.
*/
public function fetch_from_url() {
$this->verify_nonce( 'rank-math-ajax-nonce' );
$this->has_cap_ajax( 'general' );
$url = Param::post( 'url', false, FILTER_VALIDATE_URL );
if ( ! $url || strtolower( substr( $url, 0, 4 ) ) !== 'http' ) {
$this->error( esc_html__( 'No url found.', 'rank-math-pro' ) );
}
$parser = new Parser();
$output = $parser->from_url( $url );
if ( is_wp_error( $output ) ) {
$this->error( $output->get_error_message() );
}
$this->success( [ 'json' => $output ] );
}
/**
* Get posts/terms/author data.
*/
public function get_conditions_data() {
$this->verify_nonce( 'rank-math-ajax-nonce' );
$this->has_cap_ajax( 'general' );
$method = 'singular' === Param::get( 'category', false ) ? 'get_singular' : 'get_terms';
$data = $this->{$method}(
Param::get( 'userInput', false ),
Param::get( 'type', false ),
Param::get( 'value', false ),
Param::get( 'postTaxonomy', false )
);
$this->success( [ 'data' => $data ] );
}
/**
* Get posts by searched string & post type.
*
* @param string $search Searched String.
* @param string $type Post Type.
* @param int $value Object ID.
* @param int $taxonomy Is taxonomy.
*/
private function get_singular( $search, $type, $value, $taxonomy ) {
if ( 'null' === $search && $value ) {
if ( $taxonomy && taxonomy_exists( $taxonomy ) ) {
$data = [
'value' => $value,
'title' => get_term( $value )->name,
];
} else {
$data = [
'value' => $value,
'title' => get_the_title( $value ),
];
}
return $data;
}
if ( $taxonomy && 'all' !== $taxonomy ) {
$terms = get_terms(
[
'taxonomy' => $taxonomy,
'fields' => 'id=>name',
'search' => $search,
'hide_empty' => false,
]
);
if ( empty( $terms ) ) {
return [];
}
foreach ( $terms as $id => $name ) {
$data[] = [
'value' => $id,
'title' => $name,
];
}
return $data;
}
$posts = get_posts(
[
'post_type' => $type,
's' => $search,
'numberposts' => -1,
]
);
if ( empty( $posts ) ) {
return [];
}
$data = [];
foreach ( $posts as $post ) {
$data[] = [
'value' => $post->ID,
'title' => $post->post_title,
];
}
return $data;
}
/**
* Get terms by searched string and taxonomy.
*
* @param string $search Searched String.
* @param string $type Object type.
* @param int $value Term ID.
* @param string $taxonomy Taxonomy name.
*/
private function get_terms( $search, $type, $value, $taxonomy ) {
$data = [];
if ( 'author' === $type ) {
return $this->get_authors( $search, $value );
}
if ( 'null' === $search && $value ) {
$term = get_term_by( 'id', absint( $value ), $type );
return [
'value' => $value,
'title' => ! empty( $term ) ? $term->name : '',
];
}
$terms = get_terms(
[
'taxonomy' => $type,
'search' => $search,
'hide_empty' => false,
]
);
if ( ! empty( $terms ) ) {
foreach ( $terms as $term ) {
$data[] = [
'value' => $term->term_id,
'title' => $term->name,
];
}
}
return $data;
}
/**
* Get terms by searched string and taxonomy.
*
* @param string $search Searched String.
* @param int $value Term ID.
*/
private function get_authors( $search, $value ) {
if ( 'null' === $search && $value ) {
$author = get_user_by( 'id', $value );
return [
'value' => $value,
'title' => ! empty( $author ) ? $author->display_name : '',
];
}
$data = [];
$authors = get_users(
[
'search' => '*' . $search . '*',
'search_columns' => [ 'display_name', 'user_nicename', 'user_login', 'user_email' ],
]
);
if ( ! empty( $authors ) ) {
foreach ( $authors as $author ) {
$data[] = [
'value' => $author->ID,
'title' => $author->data->display_name,
];
}
}
return $data;
}
}

View File

@@ -0,0 +1,292 @@
<?php
/**
* Outputs specific schema code from Schema Template
*
* @since 2.0.7
* @package RankMath
* @subpackage RankMathPro
* @author MyThemeShop <admin@mythemeshop.com>
*/
namespace RankMathPro\Schema;
use RankMath\Helper;
use RankMath\Schema\DB;
use RankMath\Traits\Hooker;
use MyThemeShop\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Display Conditions class.
*/
class Display_Conditions {
use Hooker;
/**
* Display conditions data.
*
* @var array
*/
private static $conditions = [];
/**
* Insert Schema data.
*
* @var array
*/
private static $insert_schemas = [];
/**
* Get Schema data from Schema Templates post type.
*
* @param array $data Array of json-ld data.
* @param JsonLD $jsonld Instance of jsonld.
*
* @return array
*/
public static function get_schema_templates( $data = [], $jsonld = [] ) {
global $wpdb;
$templates = $wpdb->get_col( "SELECT ID FROM {$wpdb->prefix}posts WHERE post_type='rank_math_schema' AND post_status='publish'" );
if ( empty( $templates ) ) {
return;
}
$newdata = [];
foreach ( $templates as $template ) {
self::$conditions = [
'general' => '',
'singular' => '',
'archive' => '',
];
$schema = DB::get_schemas( $template );
self::prepare_inserted_schemas( current( $schema ) );
if ( ! self::can_add( current( $schema ) ) ) {
continue;
}
if ( is_admin() || Helper::is_divi_frontend_editor() ) {
$newdata[] = [
'id' => $template,
'schema' => current( $schema ),
];
continue;
}
DB::unpublish_jobposting_post( $jsonld, $schema );
$schema = $jsonld->replace_variables( $schema );
$schema = $jsonld->filter( $schema, $jsonld, $data );
$newdata[] = $schema;
}
return $newdata;
}
/**
* Whether schema can be added to current page
*
* @param array $schema Schema Data.
*
* @return boolean
*/
private static function can_add( $schema ) {
if ( empty( $schema ) || empty( $schema['metadata']['displayConditions'] ) ) {
return false;
}
foreach ( $schema['metadata']['displayConditions'] as $condition ) {
$operator = $condition['condition'];
if ( 'insert' === $operator ) {
// We handle the insert condition in the prepare_inserted_schemas() method.
continue;
}
$category = $condition['category'];
$taxonomy = ! empty( $condition['postTaxonomy'] ) ? $condition['postTaxonomy'] : '';
$type = $condition['type'];
$value = $condition['value'];
$method = "can_add_{$category}";
// Skip if already confirmed.
if ( 'include' === $operator && self::$conditions[ $category ] ) {
continue;
}
self::$conditions[ $category ] = self::$method( $operator, $type, $value, $taxonomy );
}
// Add Schema if the only condition is "Include / Entire Site".
if ( ! empty( self::$conditions['general'] ) && 1 === count( $schema['metadata']['displayConditions'] ) ) {
return true;
}
if ( ( is_singular() || is_admin() ) && isset( self::$conditions['singular'] ) ) {
return self::$conditions['singular'];
}
if ( ( is_archive() || is_search() ) && isset( self::$conditions['archive'] ) ) {
return self::$conditions['archive'];
}
return ! empty( self::$conditions['general'] );
}
/**
* Prepare inserted schemas: check if they can be added to current page, and if so, add them to the $insert_schemas static array.
*
* @param array $schema Schema Data.
*/
private static function prepare_inserted_schemas( $schema ) {
if ( empty( $schema ) || empty( $schema['metadata']['displayConditions'] ) ) {
return;
}
foreach ( $schema['metadata']['displayConditions'] as $condition ) {
$operator = $condition['condition'];
if ( 'insert' !== $operator ) {
continue;
}
if ( empty( $schema['metadata']['title'] ) ) {
continue;
}
$in_schema = $condition['category'];
if ( 'custom' === $in_schema ) {
if ( empty( $condition['value'] ) ) {
continue;
}
$in_schema = $condition['value'];
}
if ( 'ProfilePage' === $in_schema && ! is_singular() ) {
continue;
}
if ( 'ProfilePage' === $in_schema && ! empty( $condition['authorID'] ) ) {
$author_ids = wp_parse_id_list( $condition['authorID'] );
global $post;
if ( ! in_array( (int) $post->post_author, $author_ids, true ) ) {
continue;
}
}
$with_key = $schema['metadata']['title'];
self::$insert_schemas[ $in_schema ][] = [
'key' => $with_key,
'schema' => $schema,
];
}
}
/**
* Get inserted schemas.
*
* @return array
*/
public static function get_insertable_schemas() {
return self::$insert_schemas;
}
/**
* Whether schema can be added to current page
*
* @param string $operator Comparision Operator.
*
* @return boolean
*/
private static function can_add_general( $operator ) {
return 'include' === $operator;
}
/**
* Whether schema can be added on archive page
*
* @param string $operator Comparision Operator.
* @param string $type Post/Taxonoy type.
* @param string $value Post/Term ID.
*
* @return boolean
*/
private static function can_add_archive( $operator, $type, $value ) {
if ( 'search' === $type ) {
return 'include' === $operator && is_search();
}
if ( ! is_archive() ) {
return false;
}
if ( 'all' === $type ) {
return 'include' === $operator;
}
if ( 'author' === $type ) {
return is_author() && 'include' === $operator && is_author( $value );
}
if ( 'category' === $type ) {
return ! is_category() ? self::$conditions['archive'] : 'include' === $operator && is_category( $value );
}
if ( 'post_tag' === $type ) {
return ! is_tag() ? self::$conditions['archive'] : 'include' === $operator && is_tag( $value );
}
return 'include' === $operator && is_tax( $type, $value );
}
/**
* Whether schema can be added on single page
*
* @param string $operator Comparision Operator.
* @param string $type Post/Taxonoy type.
* @param string $value Post/Term ID.
* @param string $taxonomy Post Taxonomy.
*
* @return boolean
*/
private static function can_add_singular( $operator, $type, $value, $taxonomy ) {
$post = is_admin() || is_singular() ? get_post( get_the_ID() ) : [];
if ( empty( $post ) ) {
return false;
}
if ( 'all' === $type ) {
return 'include' === $operator;
}
if ( $type !== $post->post_type ) {
return false;
}
if ( ! $value ) {
return 'include' === $operator;
}
if ( $taxonomy && 'exclude' === $operator ) {
return ! has_term( $value, $taxonomy );
}
if ( $taxonomy ) {
return 'include' === $operator && has_term( $value, $taxonomy );
}
if ( absint( $post->ID ) === absint( $value ) ) {
return 'include' === $operator;
}
return 'exclude' === $operator;
}
}

View File

@@ -0,0 +1,661 @@
<?php
/**
* Outputs specific schema code from Schema Template
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMathPro
* @author MyThemeShop <admin@mythemeshop.com>
*/
namespace RankMathPro\Schema;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Schema\DB;
use MyThemeShop\Helpers\Str;
use MyThemeShop\Helpers\HTML;
defined( 'ABSPATH' ) || exit;
/**
* Schema Frontend class.
*/
class Frontend {
use Hooker;
/**
* The Constructor.
*/
public function __construct() {
$this->filter( 'rank_math/json_ld', 'add_about_mention_attributes', 11 );
$this->filter( 'rank_math/json_ld', 'add_template_schema', 8, 2 );
$this->filter( 'rank_math/json_ld', 'add_schema_from_shortcode', 8, 2 );
$this->filter( 'rank_math/json_ld', 'convert_schema_to_item_list', 99, 2 );
$this->filter( 'rank_math/json_ld', 'validate_schema_data', 999 );
$this->filter( 'rank_math/json_ld', 'add_subjectof_property', 99 );
$this->filter( 'rank_math/json_ld', 'insert_template_schema', 20, 2 );
$this->action( 'rank_math/schema/preview/validate', 'validate_preview_data' );
$this->filter( 'rank_math/snippet/rich_snippet_itemlist_entity', 'filter_item_list_schema' );
$this->filter( 'rank_math/schema/valid_types', 'valid_types' );
$this->filter( 'rank_math/snippet/rich_snippet_product_entity', 'add_manufacturer_property' );
$this->filter( 'rank_math/snippet/rich_snippet_product_entity', 'remove_empty_offers' );
$this->filter( 'rank_math/snippet/rich_snippet_videoobject_entity', 'convert_familyfriendly_property' );
$this->filter( 'rank_math/snippet/rich_snippet_podcastepisode_entity', 'convert_familyfriendly_property' );
$this->filter( 'rank_math/snippet/rich_snippet_entity', 'schema_entity' );
new Display_Conditions();
new Snippet_Pro_Shortcode();
if ( $this->do_filter( 'link/remove_schema_attribute', false ) ) {
$this->filter( 'the_content', 'remove_schema_attribute', 11 );
}
// Schema Preview.
$this->filter( 'query_vars', 'add_query_vars' );
$this->filter( 'init', 'add_endpoint' );
$this->action( 'template_redirect', 'schema_preview_template' );
}
/**
* Add the 'photos' query variable so WordPress won't mangle it.
*
* @param array $vars Array of vars.
*/
public function add_query_vars( $vars ) {
$vars[] = 'schema-preview';
return $vars;
}
/**
* Add endpoint
*/
public function add_endpoint() {
add_rewrite_endpoint( 'schema-preview', EP_PERMALINK | EP_PAGES | EP_ROOT );
}
/**
* Schema preview template
*/
public function schema_preview_template() {
global $wp_query;
// if this is not a request for schema preview or a singular or home object then bail.
if (
! isset( $wp_query->query_vars['schema-preview'] ) ||
( ! is_singular() && ! is_home() && ! is_category() && ! is_tag() && ! is_tax() )
) {
return;
}
header( 'Content-Type: application/json' );
do_action( 'rank_math/json_ld/preview' );
exit;
}
/**
* Add nofollow and target attributes to link.
*
* @param string $content Post content.
* @return string
*/
public function remove_schema_attribute( $content ) {
preg_match_all( '/<(a\s[^>]+)>/', $content, $matches );
if ( empty( $matches ) || empty( $matches[0] ) ) {
return $content;
}
foreach ( $matches[0] as $link ) {
$attrs = HTML::extract_attributes( $link );
if ( ! isset( $attrs['data-schema-attribute'] ) ) {
continue;
}
unset( $attrs['data-schema-attribute'] );
$content = str_replace( $link, '<a' . HTML::attributes_to_string( $attrs ) . '>', $content );
}
return $content;
}
/**
* Filter functiont to extend valid schema types to use in Rank Math generated schema object.
*
* @param array $types Valid Schema types.
*
* @return array
*/
public function valid_types( $types ) {
return array_merge( $types, [ 'movie', 'dataset', 'claimreview' ] );
}
/**
* Validate Code Validation Schema data before displaying it in Preview window.
*
* @param array $schemas Array of json-ld data.
* @return array
*
* @since 2.6.1
*/
public function validate_preview_data( $schemas ) {
foreach ( $schemas as $schema_key => $schema ) {
if ( empty( $schema['subjectOf'] ) ) {
continue;
}
foreach ( $schema['subjectOf'] as $key => $property ) {
if ( empty( $schemas[ $key ] ) ) {
continue;
}
$schema['subjectOf'][ $key ] = $schemas[ $key ];
unset( $schemas[ $key ] );
}
$schema['subjectOf'] = array_values( $schema['subjectOf'] );
$schemas[ $schema_key ] = $schema;
}
return $schemas;
}
/**
* Add FAQ/HowTo schema in subjectOf property of primary schema.
*
* @param array $schemas Array of json-ld data.
* @return array
*
* @since 1.0.62
*/
public function add_subjectof_property( $schemas ) {
if ( empty( $schemas ) ) {
return $schemas;
}
foreach ( $schemas as $id => $schema ) {
if ( ! Str::starts_with( 'schema-', $id ) && 'richSnippet' !== $id ) {
continue;
}
$this->add_prop_subjectof( $schema, $schemas );
if ( ! empty( $schema['subjectOf'] ) ) {
$schemas[ $id ] = $schema;
break;
}
}
return $schemas;
}
/**
* Add subjectOf property in current schema entity.
*
* @param array $entity Schema Entity.
* @param array $schemas Array of json-ld data.
*
* @since 1.0.62
*/
private function add_prop_subjectof( &$entity, &$schemas ) {
if (
! isset( $entity['@type'] ) ||
empty( $entity['isPrimary'] ) ||
! empty( $entity['isCustom'] ) ||
in_array( $entity['@type'], [ 'FAQPage', 'HowTo' ], true )
) {
return;
}
global $wp_query;
$subject_of = [];
foreach ( $schemas as $key => $schema ) {
if ( ! isset( $schema['@type'] ) || ! in_array( $schema['@type'], [ 'FAQPage', 'HowTo' ], true ) ) {
continue;
}
if ( isset( $schema['isPrimary'] ) ) {
unset( $schema['isPrimary'] );
}
if ( isset( $schema['isCustom'] ) ) {
unset( $schema['isCustom'] );
}
if ( isset( $wp_query->query_vars['schema-preview'] ) ) {
$subject_of[ $key ] = $schema;
continue;
}
$subject_of[] = $schema;
unset( $schemas[ $key ] );
}
$entity['subjectOf'] = $subject_of;
}
/**
* Get Default Schema Data.
*
* @param array $data Array of json-ld data.
* @param JsonLD $jsonld Instance of jsonld.
*
* @return array
*/
public function convert_schema_to_item_list( $data, $jsonld ) {
$schemas = array_filter(
$data,
function( $schema ) {
if ( isset( $schema['@type'] ) && in_array( $schema['@type'], [ 'Course', 'Movie', 'Recipe', 'Restaurant' ], true ) ) {
return true;
}
return false;
}
);
if ( 2 > count( $schemas ) ) {
return $data;
}
$data['itemList'] = [
'@type' => 'ItemList',
'itemListElement' => [],
];
$count = 1;
foreach ( $schemas as $id => $schema ) {
unset( $data[ $id ] );
$schema['url'] = $jsonld->parts['url'] . '#' . $id;
if ( isset( $schema['isPrimary'] ) ) {
unset( $schema['isPrimary'] );
}
$data['itemList']['itemListElement'][] = [
'@type' => 'ListItem',
'position' => $count,
'item' => $schema,
];
$count++;
}
return $data;
}
/**
* Add Schema data from Schema Templates.
*
* @param array $data Array of json-ld data.
* @param JsonLD $jsonld Instance of jsonld.
*
* @return array
*/
public function add_template_schema( $data, $jsonld ) {
$schemas = Display_Conditions::get_schema_templates( $data, $jsonld );
if ( empty( $schemas ) ) {
return $data;
}
foreach ( $schemas as $schema ) {
$data = array_merge( $data, $schema );
}
return $data;
}
/**
* Insert the appropriate Schema data from Schema Templates.
*
* @param array $data Array of json-ld data.
* @param JsonLD $jsonld Instance of jsonld.
*
* @return array
*/
public function insert_template_schema( $data, $jsonld ) {
$schema_array = Display_Conditions::get_insertable_schemas();
if ( empty( $schema_array ) ) {
return $data;
}
foreach ( $schema_array as $insert_in => $schemas ) {
// If the $insert_in is not a @type present in the data, then skip it.
$insert_key = false;
foreach ( $data as $key => $schema ) {
if ( $key === $insert_in ) {
$insert_key = $key;
break;
}
if ( ! isset( $schema['@type'] ) ) {
continue;
}
if ( $schema['@type'] === $insert_in ) {
$insert_key = $key;
break;
}
}
if ( ! $insert_key ) {
continue;
}
// Now insert the schema(s).
foreach ( $schemas as $schema ) {
$schema_key = $schema['key'];
$schema_data = $schema['schema'];
unset( $schema_data['isPrimary'], $schema_data['isCustom'], $schema_data['isTemplate'], $schema_data['metadata'] );
$schema_data = $jsonld->replace_variables( $schema_data );
foreach ( $schema_data as $key => $value ) {
if ( ! isset( $data[ $insert_key ][ $key ] ) ) {
$data[ $insert_key ][ $key ] = $value;
}
}
}
}
return $data;
}
/**
* Add About & Mention attributes to Webpage schema.
*
* @param array $data Array of json-ld data.
* @return array
*/
public function add_about_mention_attributes( $data ) {
if ( ! is_singular() || empty( $data['WebPage'] ) ) {
return $data;
}
global $post;
if ( ! $post->post_content ) {
return $data;
}
preg_match_all( '|<a[^>]+>([^<]+)</a>|', $post->post_content, $matches );
if ( empty( $matches ) || empty( $matches[0] ) ) {
return $data;
}
foreach ( $matches[0] as $link ) {
$attrs = HTML::extract_attributes( $link );
if ( empty( $attrs['data-schema-attribute'] ) ) {
continue;
}
$attributes = explode( ' ', $attrs['data-schema-attribute'] );
if ( in_array( 'about', $attributes, true ) ) {
$data['WebPage']['about'][] = [
'@type' => 'Thing',
'name' => wp_strip_all_tags( $link ),
'sameAs' => $attrs['href'],
];
}
if ( in_array( 'mentions', $attributes, true ) ) {
$data['WebPage']['mentions'][] = [
'@type' => 'Thing',
'name' => wp_strip_all_tags( $link ),
'sameAs' => $attrs['href'],
];
}
}
return $data;
}
/**
* Filter to change the itemList schema data.
*
* @param array $schema Snippet Data.
* @return array
*/
public function filter_item_list_schema( $schema ) {
if ( ! is_archive() ) {
return $schema;
}
$elements = [];
$count = 1;
while ( have_posts() ) {
the_post();
$elements[] = [
'@type' => 'ListItem',
'position' => $count,
'url' => get_the_permalink(),
];
$count++;
}
wp_reset_postdata();
$schema['itemListElement'] = $elements;
return $schema;
}
/**
* Validate Schema Data.
*
* @param array $schemas Array of json-ld data.
*
* @return array
*/
public function validate_schema_data( $schemas ) {
if ( empty( $schemas ) ) {
return $schemas;
}
$validate_types = [ 'Dataset', 'LocalBusiness' ];
foreach ( $schemas as $id => $schema ) {
$type = isset( $schema['@type'] ) ? $schema['@type'] : '';
if ( ! Str::starts_with( 'schema-', $id ) || ! in_array( $type, $validate_types, true ) ) {
continue;
}
$hash = [
'isPartOf' => true,
'publisher' => 'LocalBusiness' === $type,
'inLanguage' => 'LocalBusiness' === $type,
];
foreach ( $hash as $property => $value ) {
if ( ! $value || ! isset( $schema[ $property ] ) ) {
continue;
}
if ( 'Dataset' === $type && 'isPartOf' === $property && ! empty( $schema[ $property ]['@type'] ) ) {
continue;
}
unset( $schemas[ $id ][ $property ] );
}
if ( 'Dataset' === $type && ! empty( $schema['publisher'] ) ) {
$schemas[ $id ]['creator'] = $schema['publisher'];
unset( $schemas[ $id ]['publisher'] );
}
}
return $schemas;
}
/**
* Get Schema data from Schema Templates post type.
*
* @param array $data Array of json-ld data.
* @param JsonLD $jsonld Instance of jsonld.
*
* @return array
*/
public function add_schema_from_shortcode( $data, $jsonld ) {
if ( ! is_singular() || ! $this->do_filter( 'rank_math/schema/add_shortcode_schema', true ) ) {
return $data;
}
global $post;
$blocks = parse_blocks( $post->post_content );
if ( ! empty( $blocks ) ) {
foreach ( $blocks as $block ) {
if ( 'rank-math/rich-snippet' !== $block['blockName'] ) {
continue;
}
$id = isset( $block['attrs']['id'] ) ? $block['attrs']['id'] : '';
$post_id = isset( $block['attrs']['post_id'] ) ? $block['attrs']['post_id'] : '';
if ( ! $id && ! $post_id ) {
continue;
}
$data = array_merge( $data, $this->get_schema_data_by_id( $id, $post_id, $jsonld, $data ) );
}
}
$regex = '/\[rank_math_rich_snippet (.*)\]/m';
preg_match_all( $regex, $post->post_content, $matches, PREG_SET_ORDER, 0 );
if ( ! empty( $matches ) ) {
foreach ( $matches as $key => $match ) {
parse_str( str_replace( ' ', '&', $match[1] ), $output );
$post_id = isset( $output['post_id'] ) ? str_replace( [ '"', "'" ], '', $output['post_id'] ) : '';
$id = isset( $output['id'] ) ? str_replace( [ '"', "'" ], '', $output['id'] ) : '';
$data = array_merge( $data, $this->get_schema_data_by_id( $id, $post_id, $jsonld, $data ) );
}
}
return $data;
}
/**
* Add Manufacturer property to Product schema.
*
* @param array $schema Product schema data.
* @return array
*/
public function add_manufacturer_property( $schema ) {
if ( empty( $schema['manufacturer'] ) ) {
return $schema;
}
$type = Helper::get_settings( 'titles.knowledgegraph_type' );
$type = 'company' === $type ? 'organization' : 'person';
$schema['manufacturer'] = [ '@id' => home_url( "/#{$type}" ) ];
return $schema;
}
/**
* Remove empty offers data from the Product schema.
*
* @param array $schema Product schema data.
* @return array
*/
public function remove_empty_offers( $schema ) {
if (
empty( $schema['offers'] ) ||
empty( $schema['review'] ) ||
(
empty( $schema['review']['positiveNotes'] ) &&
empty( $schema['review']['negativeNotes'] )
)
) {
return $schema;
}
if ( ! empty( $schema['offers']['price'] ) ) {
return $schema;
}
unset( $schema['offers'] );
return $schema;
}
/**
* Backward compatibility code to move the positiveNotes & negativeNotes properties in review.
*
* @param array $schema Schema data.
* @return array
*
* @since 3.0.19
*/
public function schema_entity( $schema ) {
if ( empty( $schema['review'] ) ) {
return $schema;
}
if ( ! empty( $schema['positiveNotes'] ) ) {
$schema['review']['positiveNotes'] = $schema['positiveNotes'];
unset( $schema['positiveNotes'] );
}
if ( ! empty( $schema['negativeNotes'] ) ) {
$schema['review']['negativeNotes'] = $schema['negativeNotes'];
unset( $schema['negativeNotes'] );
}
return $schema;
}
/**
* Convert isFamilyFriendly property used in Video schema to boolean.
*
* @param array $schema Video schema data.
* @return array
*
* @since 2.13.0
*/
public function convert_familyfriendly_property( $schema ) {
if ( empty( $schema['isFamilyFriendly'] ) ) {
return $schema;
}
$schema['isFamilyFriendly'] = 'True';
return $schema;
}
/**
* Get Schema data by ID.
*
* @param string $id Schema shortcode ID.
* @param int $post_id Post ID.
* @param JsonLD $jsonld Instance of jsonld.
* @param array $data Array of json-ld data.
*
* @return array
*/
private function get_schema_data_by_id( $id, $post_id, $jsonld, $data ) {
$schemas = $id ? DB::get_schema_by_shortcode_id( trim( $id ) ) : DB::get_schemas( trim( $post_id ) );
$current_post_id = get_the_ID();
if (
empty( $schemas ) ||
(
isset( $schemas['post_id'] ) && $current_post_id === (int) $schemas['post_id']
) ||
$post_id === $current_post_id
) {
return [];
}
$post_id = isset( $schemas['post_id'] ) ? $schemas['post_id'] : $post_id;
$schemas = isset( $schemas['schema'] ) ? [ $schemas['schema'] ] : $schemas;
$schemas = $jsonld->replace_variables( $schemas, get_post( $post_id ) );
$schemas = $jsonld->filter( $schemas, $jsonld, $data );
if ( isset( $schemas[0]['isPrimary'] ) ) {
unset( $schemas[0]['isPrimary'] );
}
return $schemas;
}
}

View File

@@ -0,0 +1,115 @@
<?php
/**
* Add Media RSS feed.
*
* @since 1.0
* @package RankMath
* @subpackage RankMath\Schema
* @author Rank Math <support@rankmath.com>
*/
namespace RankMathPro\Schema;
use RankMath\Helper;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Media_RSS class.
*/
class Media_RSS {
use Hooker;
/**
* The Constructor.
*/
public function __construct() {
if ( Helper::get_settings( 'general.disable_media_rss' ) ) {
return;
}
$this->action( 'rss2_ns', 'add_namespace' );
$this->action( 'rss2_item', 'add_video_data', 10, 1 );
}
/**
* Add namespace to RSS feed.
*
* @copyright Copyright (C) 2008-2019, Yoast BV
* The following code is a derivative work of the code from the Yoast(https://github.com/Yoast/wordpress-seo/), which is licensed under GPL v3.
*/
public function add_namespace() {
if ( apply_filters( 'rank_math/rss/add_media_namespace', true ) ) {
echo ' xmlns:media="http://search.yahoo.com/mrss/" ';
}
}
/**
* Add Video Data in RSS feed.
*
* @see https://www.rssboard.org/media-rss
* @see https://support.google.com/news/publisher-center/answer/9545420?hl=en
*/
public function add_video_data() {
global $post;
$video_schema = get_post_meta( $post->ID, 'rank_math_schema_VideoObject', true );
if ( empty( $video_schema ) ) {
return;
}
$url = ! empty( $video_schema['contentUrl'] ) ? $video_schema['contentUrl'] : ( ! empty( $video_schema['embedUrl'] ) ? $video_schema['embedUrl'] : '' );
if ( ! $url ) {
return;
}
$attrs = ! empty( $video_schema['width'] ) ? ' width="' . esc_attr( $video_schema['width'] ) . '"' : '';
$attrs .= ! empty( $video_schema['height'] ) ? ' height="' . esc_attr( $video_schema['height'] ) . '"' : '';
$duration = ! empty( $video_schema['duration'] ) ? Helper::duration_to_seconds( $video_schema['duration'] ) : '';
$name = ! empty( $video_schema['name'] ) ? Helper::replace_vars( $video_schema['name'], $post ) : '';
$description = ! empty( $video_schema['description'] ) ? Helper::replace_vars( $video_schema['description'], $post ) : '';
$thumbnail = ! empty( $video_schema['thumbnailUrl'] ) ? Helper::replace_vars( $video_schema['thumbnailUrl'], $post ) : '';
$tags = ! empty( $video_schema['metadata']['tags'] ) ? Helper::replace_vars( $video_schema['metadata']['tags'] ) : '';
$categories = ! empty( $video_schema['metadata']['category'] ) ? Helper::replace_vars( $video_schema['metadata']['category'] ) : '';
$rating = ! empty( $video_schema['isFamilyFriendly'] ) ? 'nonadult' : 'adult';
$this->newline( '<media:content url="' . esc_url( $url ) . '" medium="video"' . $attrs . '>' );
$this->newline( '<media:player url="' . esc_url( $url ) . '" />', 3 );
if ( $name ) {
$this->newline( '<media:title type="plain">' . esc_html( $name ) . '</media:title>', 3 );
}
if ( $description ) {
$this->newline( '<media:description type="html"><![CDATA[' . wp_kses_post( $description ) . ']]></media:description>', 3 );
}
if ( $thumbnail ) {
$this->newline( '<media:thumbnail url="' . esc_url( $thumbnail ) . '" />', 3 );
}
if ( $tags ) {
$this->newline( '<media:keywords>' . esc_html( $tags ) . '</media:keywords>', 3 );
}
if ( $categories ) {
$this->newline( '<media:category>' . esc_html( $categories ) . '</media:category>', 3 );
}
if ( $rating ) {
$this->newline( '<media:rating scheme="urn:simple">' . esc_html( $rating ) . '</media:rating>', 3 );
}
$this->newline( '</media:content>', 2 );
}
/**
* Write a newline with indent count.
*
* @param string $content Content to write.
* @param integer $indent Count of indent.
*/
private function newline( $content, $indent = 0 ) {
echo str_repeat( "\t", $indent ) . $content . "\n";
}
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* The Schema Parser
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMathPro
* @author MyThemeShop <admin@mythemeshop.com>
*/
namespace RankMathPro\Schema;
use WP_Error;
use DOMXpath;
use DOMDocument;
defined( 'ABSPATH' ) || exit;
/**
* Parser class.
*/
class Parser {
/**
* Get json from url.
*
* @param string $url Url to fetch html from.
*/
public function from_url( $url ) {
$response = wp_remote_get(
$url,
[
'timeout' => 30,
'sslverify' => false,
]
);
if ( is_wp_error( $response ) ) {
return $response;
}
$response = wp_remote_retrieve_body( $response );
if ( empty( $response ) ) {
return new WP_Error( 'body_not_found', esc_html__( 'No html body found.', 'rank-math-pro' ) );
}
return $this->from_html( $response );
}
/**
* Get json from html.
*
* @param string $html HTML to parse.
*/
public function from_html( $html ) {
libxml_use_internal_errors( 1 );
// DOM.
$dom = new DOMDocument();
$dom->loadHTML( $html );
// XPath.
$xpath = new DOMXpath( $dom );
$scripts = $xpath->query( '//script[@type="application/ld+json"]' );
$json = [];
foreach ( $scripts as $script ) {
$json[] = json_decode( trim( $script->nodeValue ) ); // phpcs:ignore
}
return $json;
}
}

View File

@@ -0,0 +1,137 @@
<?php
/**
* The Schema Template Post Type
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMathPro
* @author MyThemeShop <admin@mythemeshop.com>
*/
namespace RankMathPro\Schema;
use RankMath\Helper;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Post_Type class.
*/
class Post_Type {
use Hooker;
/**
* The Constructor.
*/
public function __construct() {
$this->action( 'init', 'register' );
$this->action( 'admin_menu', 'add_menu', 11 );
$this->action( 'parent_file', 'parent_file' );
$this->action( 'submenu_file', 'submenu_file' );
}
/**
* Register template post type.
*/
public function register() {
$labels = [
'name' => _x( 'Schemas', 'Post Type General Name', 'rank-math-pro' ),
'singular_name' => _x( 'Schema', 'Post Type Singular Name', 'rank-math-pro' ),
'menu_name' => __( 'Schemas', 'rank-math-pro' ),
'name_admin_bar' => __( 'Schema', 'rank-math-pro' ),
'all_items' => __( 'All Schemas', 'rank-math-pro' ),
'add_new_item' => __( 'Add New Schema', 'rank-math-pro' ),
'new_item' => __( 'New Schema', 'rank-math-pro' ),
'edit_item' => __( 'Edit Schema', 'rank-math-pro' ),
'update_item' => __( 'Update Schema', 'rank-math-pro' ),
'view_item' => __( 'View Schema', 'rank-math-pro' ),
'view_items' => __( 'View Schemas', 'rank-math-pro' ),
'search_items' => __( 'Search schemas', 'rank-math-pro' ),
];
$capability = 'rank_math_onpage_snippet';
$args = [
'label' => __( 'Schema', 'rank-math-pro' ),
'description' => __( 'Rank Math Schema Templates', 'rank-math-pro' ),
'labels' => $labels,
'supports' => [ 'title' ],
'hierarchical' => false,
'public' => false,
'show_ui' => true,
'show_in_menu' => false,
'menu_position' => 5,
'show_in_admin_bar' => false,
'show_in_nav_menus' => false,
'can_export' => true,
'has_archive' => false,
'exclude_from_search' => true,
'publicly_queryable' => false,
'rewrite' => false,
'capability_type' => 'page',
'capabilities' => [
'edit_post' => $capability,
'read_post' => $capability,
'delete_post' => $capability,
'edit_posts' => $capability,
'edit_others_posts' => $capability,
'publish_posts' => $capability,
'read_private_posts' => $capability,
'create_posts' => $capability,
],
'show_in_rest' => true,
];
register_post_type( 'rank_math_schema', $args );
}
/**
* Add post type as submenu.
*/
public function add_menu() {
if ( ! Helper::has_cap( 'onpage_snippet' ) ) {
return;
}
add_submenu_page(
'rank-math',
esc_html__( 'Schema Templates', 'rank-math-pro' ),
esc_html__( 'Schema Templates', 'rank-math-pro' ),
'edit_posts',
'edit.php?post_type=rank_math_schema'
);
}
/**
* Fix parent active menu
*
* @param string $file Filename.
* @return string
*/
public function parent_file( $file ) {
$screen = get_current_screen();
if ( in_array( $screen->base, [ 'post', 'edit' ], true ) && 'rank_math_schema' === $screen->post_type ) {
$file = 'rank-math';
}
return $file;
}
/**
* Fix submenu active menu
*
* @param string $file Filename.
* @return string
*/
public function submenu_file( $file ) {
$screen = get_current_screen();
if ( in_array( $screen->base, [ 'post', 'edit' ], true ) && 'rank_math_schema' === $screen->post_type ) {
$file = 'edit.php?post_type=rank_math_schema';
}
return $file;
}
}

View File

@@ -0,0 +1,165 @@
<?php
/**
* The REST API.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMathPro
* @author MyThemeShop <admin@mythemeshop.com>
*/
namespace RankMathPro\Schema;
use WP_Error;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Controller;
use RankMath\Helper;
use RankMath\Schema\DB;
use RankMath\Traits\Meta;
use RankMath\Rest\Sanitize;
defined( 'ABSPATH' ) || exit;
/**
* Rest class.
*/
class Rest extends WP_REST_Controller {
use Meta;
/**
* Constructor.
*/
public function __construct() {
$this->namespace = \RankMath\Rest\Rest_Helper::BASE;
}
/**
* Registers the routes for the objects of the controller.
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/saveTemplate',
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => [ $this, 'save_template' ],
'args' => [
'schema' => [
'required' => true,
'description' => esc_html__( 'Schema to add.', 'rank-math-pro' ),
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_param_empty' ],
],
],
'permission_callback' => [ $this, 'get_permissions_check' ],
]
);
register_rest_route(
$this->namespace,
'/getVideoData',
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_video_data' ],
'args' => $this->get_video_args(),
'permission_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'can_manage_options' ],
]
);
}
/**
* Get Video details.
*
* @param WP_REST_Request $request Full details about the request.
* @return bool Whether the API key matches or not.
*/
public function get_video_data( WP_REST_Request $request ) {
$object_id = $request->get_param( 'objectID' );
$url = $request->get_param( 'url' );
$post_type = get_post_type( $object_id );
if ( false === filter_var( $url, FILTER_VALIDATE_URL ) || ! Helper::get_settings( "titles.pt_{$post_type}_autodetect_video", 'on' ) ) {
return [];
}
global $wp_embed;
return ( new \RankMathPro\Schema\Video\Parser( get_post( $object_id ) ) )->get_metadata( $wp_embed->autoembed( $url ) );
}
/**
* Update metadata.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function save_template( WP_REST_Request $request ) {
$sanitizer = Sanitize::get();
$schema = $request->get_param( 'schema' );
$post_id = $request->get_param( 'postId' );
foreach ( $schema as $id => $value ) {
$schema[ $id ] = $sanitizer->sanitize( $id, $value );
}
if ( $post_id ) {
DB::delete_schema_data( $post_id );
}
$meta_key = 'rank_math_schema_' . $schema['@type'];
$template_id = wp_insert_post(
[
'ID' => $post_id,
'post_status' => 'publish',
'post_type' => 'rank_math_schema',
'post_title' => $schema['metadata']['title'],
]
);
update_post_meta( $template_id, $meta_key, $schema );
return [
'id' => $template_id,
'link' => get_edit_post_link( $template_id ),
];
}
/**
* Checks whether a given request has permission to read post.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
*/
public static function get_permissions_check( $request ) { // phpcs:ignore
if ( current_user_can( 'edit_posts' ) ) {
return true;
}
return new WP_Error(
'rest_cannot_edit',
__( 'Sorry, you are not allowed to save template.', 'rank-math-pro' ),
[ 'status' => rest_authorization_required_code() ]
);
}
/**
* Get video arguments.
*
* @return array
*/
private function get_video_args() {
return [
'objectID' => [
'type' => 'integer',
'required' => true,
'description' => esc_html__( 'Object unique id', 'rank-math-pro' ),
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_param_empty' ],
],
'url' => [
'required' => true,
'description' => esc_html__( 'Video URL.', 'rank-math-pro' ),
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_param_empty' ],
],
];
}
}

View File

@@ -0,0 +1,288 @@
<?php
/**
* The Schema Module
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMathPro
* @author MyThemeShop <admin@mythemeshop.com>
*/
namespace RankMathPro\Schema;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use MyThemeShop\Helpers\Str;
defined( 'ABSPATH' ) || exit;
/**
* Schema class.
*/
class Schema {
use Hooker;
/**
* The Constructor.
*/
public function __construct() {
$this->includes();
$this->hooks();
}
/**
* Include required files.
*/
public function includes() {
new Admin();
new Ajax();
new Post_Type();
new \RankMath\Schema\Schema();
new Frontend();
new Video();
}
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'enqueue_block_editor_assets', 'editor_assets', 9 );
$this->filter( 'rank_math/schema/block/howto-block', 'add_graph', 11, 2 );
$this->filter( 'rank_math/schema/block/howto/content', 'block_content', 11, 3 );
}
/**
* Enqueue Styles and Scripts required for blocks at backend.
*/
public function editor_assets() {
wp_enqueue_script(
'rank-math-howto-block',
RANK_MATH_PRO_URL . 'assets/admin/js/blocks.js',
[],
rank_math_pro()->version,
true
);
if ( Helper::is_module_active( 'local-seo' ) ) {
Helper::add_json( 'previewImage', RANK_MATH_PRO_URL . 'includes/modules/local-seo/assets/img/map-placeholder.jpg' );
Helper::add_json( 'mapStyle', Helper::get_settings( 'titles.map_style', 'roadmap' ) );
Helper::add_json( 'limitLocations', Helper::get_settings( 'titles.limit_results', 10 ) );
}
}
/**
* Display additional content in the HowTo Block.
*
* @param string $output Schema data.
* @param array $data Output data.
* @param array $attributes Schema attributes.
*/
public function block_content( $output, $data, $attributes ) {
$data[] = $this->build_estimated_cost( $attributes );
$data[] = $this->build_supplies( $attributes );
$data[] = $this->build_tools( $attributes );
$data[] = $this->build_materials( $attributes );
return join( "\n", $data );
}
/**
* FAQ rich snippet.
*
* @param array $data Array of JSON-LD data.
* @param array $block JsonLD Instance.
*
* @return array
*/
public function add_graph( $data, $block ) {
$attrs = $block['attrs'];
$this->add_estimated_cost( $data['howto'], $attrs );
$this->add_supplies( $data['howto'], $attrs );
$this->add_tools( $data['howto'], $attrs );
$this->add_materials( $data['howto'], $attrs );
return $data;
}
/**
* [build_estimated_cost description]
*
* @param [type] $attrs [description].
*
* @return [type] [description]
*/
private function build_estimated_cost( $attrs ) {
if ( empty( $attrs['estimatedCost'] ) ) {
return;
}
$currency = ! empty( $attrs['estimatedCostCurrency'] ) ? $attrs['estimatedCostCurrency'] : 'USD';
return sprintf(
'<p class="rank-math-howto-estimatedCost"><strong>%2$s</strong> <span>%1$s</span></p>',
$attrs['estimatedCost'] . ' ' . $currency,
__( 'Estimated Cost:', 'rank-math-pro' )
);
}
/**
* [build_estimated_cost description]
*
* @param [type] $attrs [description].
*
* @return [type] [description]
*/
private function build_supplies( $attrs ) {
if ( empty( $attrs['supply'] ) ) {
return;
}
$supplies = Str::to_arr_no_empty( $attrs['supply'] );
if ( empty( $supplies ) ) {
return;
}
return sprintf(
'<p class="rank-math-howto-supply"><strong>%2$s</strong> <ul><li>%1$s</li></ul></p>',
implode( '</li><li>', $supplies ),
__( 'Supply:', 'rank-math-pro' )
);
}
/**
* [build_estimated_cost description]
*
* @param [type] $attrs [description].
*
* @return [type] [description]
*/
private function build_tools( $attrs ) {
if ( empty( $attrs['tools'] ) ) {
return;
}
$tools = Str::to_arr_no_empty( $attrs['tools'] );
if ( empty( $tools ) ) {
return;
}
return sprintf(
'<p class="rank-math-howto-tools"><strong>%2$s</strong> <ul><li>%1$s</li></ul></p>',
implode( '</li><li>', $tools ),
__( 'Tools:', 'rank-math-pro' )
);
}
/**
* [build_estimated_cost description]
*
* @param [type] $attrs [description].
*
* @return [type] [description]
*/
private function build_materials( $attrs ) {
if ( empty( $attrs['material'] ) ) {
return;
}
$tools = Str::to_arr_no_empty( $attrs['tools'] );
if ( empty( $tools ) ) {
return;
}
return sprintf(
'<p class="rank-math-howto-tools"><strong>%2$s</strong> <span>%1$s</span></p>',
$attrs['material'],
__( 'Materials:', 'rank-math-pro' )
);
}
/**
* Add Duration.
*
* @param [type] $data [description].
* @param [type] $attrs [description].
*/
private function add_estimated_cost( &$data, $attrs ) {
if ( empty( $attrs['estimatedCost'] ) ) {
return;
}
$data['estimatedCost'] = [
'@type' => 'MonetaryAmount',
'currency' => ! empty( $attrs['estimatedCostCurrency'] ) ? $attrs['estimatedCostCurrency'] : 'USD',
'value' => $attrs['estimatedCost'],
];
}
/**
* Add Duration.
*
* @param [type] $data [description].
* @param [type] $attrs [description].
*/
private function add_supplies( &$data, $attrs ) {
if ( empty( $attrs['supply'] ) ) {
return;
}
$supplies = Str::to_arr_no_empty( $attrs['supply'] );
if ( empty( $supplies ) ) {
return;
}
$supply = [];
foreach ( $supplies as $value ) {
$supply[] = [
'@type' => 'HowToSupply',
'name' => $value,
];
}
$data['supply'] = $supply;
}
/**
* Add Duration.
*
* @param [type] $data [description].
* @param [type] $attrs [description].
*/
private function add_tools( &$data, $attrs ) {
if ( empty( $attrs['tools'] ) ) {
return;
}
$tools = Str::to_arr_no_empty( $attrs['tools'] );
if ( empty( $tools ) ) {
return;
}
$tool = [];
foreach ( $tools as $value ) {
$tool[] = [
'@type' => 'HowToTool',
'name' => $value,
];
}
$data['tool'] = $tool;
}
/**
* Add Duration.
*
* @param [type] $data [description].
* @param [type] $attrs [description].
*/
private function add_materials( &$data, $attrs ) {
if ( empty( $attrs['material'] ) ) {
return;
}
$data['material'] = $attrs['material'];
}
}

View File

@@ -0,0 +1,145 @@
<?php
/**
* Outputs specific schema code from Schema Template
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMathPro
* @author MyThemeShop <admin@mythemeshop.com>
*/
namespace RankMathPro\Schema;
use RankMath\Traits\Hooker;
use RankMath\Schema\Snippet_Shortcode;
defined( 'ABSPATH' ) || exit;
/**
* Schema Frontend class.
*/
class Snippet_Pro_Shortcode extends Snippet_Shortcode {
use Hooker;
/**
* The Constructor.
*/
public function __construct() {
$this->filter( 'rank_math/snippet/html', 'add_shortcode_view', 10, 4 );
$this->filter( 'rank_math/snippet/after_schema_content', 'show_review_notes' );
$this->filter( 'shortcode_atts_rank_math_rich_snippet', 'register_fields_attribute', 10, 4 );
$this->filter( 'rank_math/schema/shortcode/filter_attributes', 'filter_attributes', 10, 2 );
}
/**
* Filter schema fields.
*
* @param array $schema Schema data.
* @param array $atts The user defined shortcode attributes.
*
* @return array Filtered Schema fields.
*/
public function filter_attributes( $schema, $atts ) {
if ( empty( $atts['fields'] ) ) {
return $schema;
}
$fields = explode( ',', $atts['fields'] );
$fields[] = '@type';
return array_intersect_key( $schema, array_flip( $fields ) );
}
/**
* Filters shortcode attributes.
*
* If the third parameter of the shortcode_atts() function is present then this filter is available.
*
* @param array $out The output array of shortcode attributes.
* @param array $pairs The supported attributes and their defaults.
* @param array $atts The user defined shortcode attributes.
* @param string $shortcode The shortcode name.
*/
public function register_fields_attribute( $out, $pairs, $atts, $shortcode ) { // phpcs:ignore
return wp_parse_args( $atts, $out );
}
/**
* Filter to change the rank_math_rich_snippet shortcode content.
*
* @param string $html Shortcode content.
* @param string $schema Current Schema data.
* @param string $post Current Post Object.
* @param string $shortcode Shortcode class instance.
*
* @return string Shortcode Content.
*/
public function add_shortcode_view( $html, $schema, $post, $shortcode ) { // phpcs:ignore
wp_enqueue_style( 'rank-math-review-pro-snippet', RANK_MATH_PRO_URL . 'includes/modules/schema/assets/css/rank-math-snippet.css', null, rank_math_pro()->version );
$type = \strtolower( $schema['@type'] );
if ( ! in_array( $type, [ 'dataset', 'movie', 'claimreview', 'faqpage', 'howto', 'jobposting', 'product', 'recipe', 'podcastepisode' ], true ) ) {
return $html;
}
ob_start();
echo '<div id="rank-math-rich-snippet-wrapper">';
include "shortcode/$type.php";
$this->show_review_notes( $shortcode );
echo '</div>';
return ob_get_clean();
}
/**
* Display Pros & Cons.
*
* @since 3.0.18
*/
public function show_review_notes( $shortcode ) {
$labels = [
'pros' => __( 'Pros', 'rank-math-pro' ),
'cons' => __( 'Cons', 'rank-math-pro' ),
];
/**
* Filter: Allow changing the Pros & Cons labels.
*
* @param array $labels {
* @type string $pros Pros label.
* @type string $cons Cons label.
* }
*/
$labels = $this->do_filter( 'schema/review_notes_labels', $labels );
$positive_notes = ! empty( $shortcode->get_field_value( 'positiveNotes' ) ) ? $shortcode->get_field_value( 'positiveNotes' ) : $shortcode->get_field_value( 'review.positiveNotes' );
if ( ! empty( $positive_notes['itemListElement'] ) ) {
?>
<div class="rank-math-review-notes rank-math-review-pros">
<h4><?php echo esc_html( $labels['pros'] ); ?></h4>
<ul>
<?php foreach ( $positive_notes['itemListElement'] as $positive_note ) { ?>
<li><?php echo esc_html( $positive_note['name'] ); ?></li>
<?php } ?>
</ul>
</div>
<?php
}
$negative_notes = ! empty( $shortcode->get_field_value( 'negativeNotes' ) ) ? $shortcode->get_field_value( 'negativeNotes' ) : $shortcode->get_field_value( 'review.negativeNotes' );
if ( ! empty( $negative_notes['itemListElement'] ) ) {
?>
<div class="rank-math-review-notes rank-math-review-cons">
<h4><?php echo esc_html( $labels['cons'] ); ?></h4>
<ul>
<?php foreach ( $negative_notes['itemListElement'] as $negative_note ) { ?>
<li><?php echo esc_html( $negative_note['name'] ); ?></li>
<?php } ?>
</ul>
</div>
<?php
}
}
}

View File

@@ -0,0 +1,255 @@
<?php
/**
* The Schema Module
*
* @since 2.1.0
* @package RankMath
* @subpackage RankMath\Schema
* @author Rank Math <support@rankmath.com>
*/
namespace RankMathPro\Schema;
use RankMath\Helper;
use RankMath\Admin\Admin_Helper;
use RankMath\Schema\DB;
use RankMath\Rest\Sanitize;
use RankMath\Traits\Hooker;
use MyThemeShop\Helpers\Arr;
use MyThemeShop\Helpers\Str;
use MyThemeShop\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Taxonomy class.
*/
class Taxonomy extends Admin {
use Hooker;
/**
* The Constructor.
*/
public function __construct() {
$this->action( 'init', 'init', 9999 );
$this->action( 'rank_math/json_ld', 'add_schema', 11, 2 );
if (
! Helper::has_cap( 'onpage_snippet' ) ||
! Admin_Helper::is_term_edit() ||
! $this->can_add( Param::request( 'taxonomy' ) )
) {
return;
}
$this->action( 'rank_math/admin/editor_scripts', 'enqueue' );
}
/**
* Add schema-preview rewrite rule for taxonomies.
*/
public function init() {
$taxonomies = Helper::get_accessible_taxonomies();
foreach ( $taxonomies as $slug => $taxonomy ) {
if ( empty( $taxonomy->rewrite['slug'] ) || ! $this->can_add( $slug ) ) {
continue;
}
add_rewrite_rule(
$taxonomy->rewrite['slug'] . '/(.+?)/schema-preview/?$',
'index.php?' . $slug . '=$matches[1]&schema-preview=$matches[3]',
'top'
);
}
}
/**
* Enqueue Styles and Scripts required for metabox.
*/
public function enqueue() {
global $pagenow;
$cmb = cmb2_get_metabox( 'rank_math_metabox' );
if ( false === $cmb || 'edit-tags.php' === $pagenow ) {
return;
}
$schemas = $this->get_schema_data( $cmb->object_id() );
Helper::add_json( 'schemas', $schemas );
Helper::add_json( 'customSchemaImage', esc_url( rank_math()->plugin_url() . 'includes/modules/schema/assets/img/custom-schema-builder.jpg' ) );
Helper::add_json( 'postLink', get_term_link( (int) $cmb->object_id() ) );
Helper::add_json( 'activeTemplates', $this->get_active_templates() );
wp_enqueue_style( 'rank-math-schema', rank_math()->plugin_url() . 'includes/modules/schema/assets/css/schema.css', [ 'wp-components', 'rank-math-editor' ], rank_math()->version );
wp_enqueue_script( 'rank-math-schema', rank_math()->plugin_url() . 'includes/modules/schema/assets/js/schema-gutenberg.js', [ 'rank-math-editor', 'clipboard' ], rank_math()->version, true );
wp_enqueue_style( 'rank-math-schema-pro', RANK_MATH_PRO_URL . 'includes/modules/schema/assets/css/schema.css', null, rank_math_pro()->version );
wp_enqueue_script(
'rank-math-pro-schema-filters',
RANK_MATH_PRO_URL . 'includes/modules/schema/assets/js/schemaFilters.js',
[
'wp-plugins',
'wp-components',
'wp-hooks',
'wp-api-fetch',
'lodash',
],
rank_math_pro()->version,
true
);
wp_enqueue_script( 'rank-math-schema-pro', RANK_MATH_PRO_URL . 'includes/modules/schema/assets/js/schema.js', [ 'rank-math-editor' ], rank_math_pro()->version, true );
}
/**
* Get Default Schema Data.
*
* @param array $data Array of json-ld data.
* @param JsonLD $jsonld Instance of jsonld.
*
* @return array
*/
public function add_schema( $data, $jsonld ) {
if ( ! is_category() && ! is_tag() && ! is_tax() ) {
return $data;
}
$queried_object = get_queried_object();
if (
empty( $queried_object ) ||
is_wp_error( $queried_object ) ||
! $this->can_add( $queried_object->taxonomy )
) {
return $data;
}
$schemas = DB::get_schemas( $queried_object->term_id, 'termmeta' );
if ( empty( $schemas ) ) {
return $data;
}
if ( isset( $data['ItemList'] ) ) {
unset( $data['ItemList'] );
}
if ( isset( $data['ProductsPage'] ) ) {
unset( $data['ProductsPage'] );
}
if ( isset( $data['WebPage'] ) ) {
$data['WebPage']['@type'] = [
'WebPage',
'CollectionPage',
];
}
$schemas = $jsonld->replace_variables( $schemas );
$schemas = $jsonld->filter( $schemas, $jsonld, $data );
return array_merge( $data, $schemas );
}
/**
* Get Schema Data.
*
* @param int $term_id Term ID.
*
* @return array $schemas Schema Data.
*/
private function get_schema_data( $term_id ) {
$schemas = DB::get_schemas( $term_id, 'termmeta' );
if ( ! empty( $schemas ) || metadata_exists( 'term', $term_id, 'rank_math_rich_snippet' ) ) {
return $schemas;
}
return [];
}
/**
* Add active templates to the schemas json
*
* @return array
*/
public function get_active_templates() {
$templates = $this->get_schema_templates();
if ( empty( $templates ) ) {
return [];
}
$screen = get_current_screen();
$schemas = [];
foreach ( $templates as $template ) {
if ( empty( $template['schema']['metadata']['displayConditions'] ) ) {
continue;
}
$conditions = $template['schema']['metadata']['displayConditions'];
$can_add = false;
$data = [];
foreach ( $conditions as $condition ) {
$category = $condition['category'];
if ( 'archive' !== $category ) {
continue;
}
$operator = $condition['condition'];
if ( ! empty( $data[ $category ] ) && 'exclude' !== $operator ) {
continue;
}
$type = $condition['type'];
$value = $condition['value'];
if ( 'general' === $category ) {
$data[ $category ] = 'include' === $operator;
continue;
}
if ( $value && absint( Param::get( 'tag_ID' ) ) === $value ) {
$data[ $category ] = 'include' === $operator;
break;
}
if ( 'all' === $type ) {
$data[ $category ] = 'include' === $operator;
} elseif ( $type !== $screen->taxonomy ) {
$data[ $category ] = false;
} elseif ( ! $value ) {
$data[ $category ] = 'include' === $operator;
} elseif ( Param::get( 'tag_ID' ) !== $value ) {
$data[ $category ] = isset( $data[ $category ] ) ? $data[ $category ] : false;
} else {
$data[ $category ] = 'include' === $operator;
}
}
if ( isset( $data['archive'] ) ) {
$can_add = $data['archive'];
} else {
$can_add = ! empty( $data['general'] );
}
if ( $can_add ) {
$template['schema']['isTemplate'] = true;
$schemas[ $template['id'] ] = $template['schema'];
}
}
return $schemas;
}
/**
* Can add Schema data on current taxonomy
*
* @param string $taxonomy Taxonomy name.
*
* @return bool
*/
private function can_add( $taxonomy ) {
return Helper::get_settings( 'titles.tax_' . $taxonomy . '_add_meta_box' ) &&
true !== apply_filters(
'rank_math/snippet/remove_taxonomy_data',
Helper::get_settings( 'titles.remove_' . $taxonomy . '_snippet_data' ),
$taxonomy
);
}
}

View File

@@ -0,0 +1,155 @@
<?php
/**
* The Video Schema generator.
*
* @since 2.0.9
* @package RankMathPro
* @subpackage RankMathPro\Schema
* @author Rank Math <support@rankmath.com>
*/
namespace RankMathPro\Schema;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
/**
* Video_Schema_Generator class.
*/
class Video_Schema_Generator extends \WP_Background_Process {
/**
* Prefix.
*
* (default value: 'wp')
*
* @var string
* @access protected
*/
protected $prefix = 'rank_math';
/**
* Action.
*
* @var string
*/
protected $action = 'add_video_schema';
/**
* Main instance
*
* Ensure only one instance is loaded or can be loaded.
*
* @return Video_Schema_Generator
*/
public static function get() {
static $instance;
if ( is_null( $instance ) && ! ( $instance instanceof Video_Schema_Generator ) ) {
$instance = new Video_Schema_Generator();
}
return $instance;
}
/**
* Start creating batches.
*
* @param [type] $posts [description].
*/
public function start( $posts ) {
$chunks = array_chunk( $posts, 10 );
foreach ( $chunks as $chunk ) {
$this->push_to_queue( $chunk );
}
$this->save()->dispatch();
}
/**
* Complete.
*
* Override if applicable, but ensure that the below actions are
* performed, or, call parent::complete().
*/
protected function complete() {
delete_option( 'rank_math_video_posts' );
Helper::add_notification(
esc_html__( 'Rank Math: Added Video Schema to posts successfully.', 'rank-math-pro' ),
[
'type' => 'success',
'id' => 'rank_math_video_posts',
'classes' => 'rank-math-notice',
]
);
parent::complete();
}
/**
* Task to perform
*
* @param array $posts Posts to process.
*
* @return bool
*/
protected function task( $posts ) {
try {
foreach ( $posts as $post ) {
$this->convert( $post );
}
return false;
} catch ( Exception $error ) {
return true;
}
}
/**
* Convert post.
*
* @param int $post_id Post ID.
*/
public function convert( $post_id ) {
update_post_meta( $post_id, '_rank_math_video', 'true' );
( new Video\Parser( get_post( $post_id ) ) )->save();
}
/**
* Find posts.
*
* @return array
*/
public function find_posts() {
global $wpdb;
$posts = get_option( 'rank_math_video_posts' );
if ( false !== $posts ) {
return $posts;
}
// Schema Posts.
$post_types = array_filter(
Helper::get_accessible_post_types(),
function( $post_type ) {
return 'attachment' !== $post_type && Helper::get_settings( "titles.pt_{$post_type}_autodetect_video", 'on' );
}
);
$posts = get_posts(
[
'post_type' => array_keys( $post_types ),
'numberposts' => -1,
'fields' => 'ids',
'meta_query' => [
[
'key' => 'rank_math_schema_VideoObject',
'compare' => 'NOT EXISTS',
],
],
]
);
update_option( 'rank_math_video_posts', $posts, false );
return $posts;
}
}

View File

@@ -0,0 +1,222 @@
<?php
/**
* The Video Schema.
*
* @since 1.0
* @package RankMath
* @subpackage RankMath\Schema
* @author Rank Math <support@rankmath.com>
*/
namespace RankMathPro\Schema;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use MyThemeShop\Helpers\Conditional;
defined( 'ABSPATH' ) || exit;
/**
* Video class.
*/
class Video {
use Hooker;
/**
* The Constructor.
*/
public function __construct() {
Video_Schema_Generator::get();
if ( Conditional::is_rest() ) {
$this->filter( 'rank_math/tools/generate_video_schema', 'generate_video_schema' );
}
$this->action( 'rank_math/pre_update_metadata', 'detect_video_in_content', 10, 3 );
if ( is_admin() ) {
$this->action( 'cmb2_admin_init', 'add_video_settings' );
$this->action( 'rank_math/admin/settings/others', 'add_media_rss_field' );
$this->filter( 'rank_math/database/tools', 'generate_video_schema_tool' );
return;
}
$this->action( 'rank_math/opengraph/facebook', 'add_video_tags', 99 );
new Media_RSS();
}
/**
* Add auto-detect Video fields in Titles & Meta settings.
*/
public function add_video_settings() {
foreach ( Helper::get_accessible_post_types() as $post_type ) {
$this->action( "rank_math/admin/settings/post-type-{$post_type}", 'add_video_schema_fields', 10, 2 );
}
}
/**
* Add auto-generate video schema settings.
*
* @param object $cmb CMB2 instance.
* @param array $tab Current settings tab.
*/
public function add_video_schema_fields( $cmb, $tab ) {
if ( 'attachment' === $tab['post_type'] ) {
return;
}
$field_ids = wp_list_pluck( $cmb->prop( 'fields' ), 'id' );
$field_position = array_search( "pt_{$tab['post_type']}_default_article_type", array_keys( $field_ids ), true ) + 1;
$cmb->add_field(
[
'id' => 'pt_' . $tab['post_type'] . '_autodetect_video',
'type' => 'toggle',
'name' => esc_html__( 'Autodetect Video', 'rank-math-pro' ),
'desc' => esc_html__( 'Populate automatic Video Schema by auto-detecting any video in the content.', 'rank-math-pro' ),
'options' => [
'off' => esc_html__( 'Default', 'rank-math-pro' ),
'on' => esc_html__( 'Custom', 'rank-math-pro' ),
],
'default' => 'on',
],
++$field_position
);
$cmb->add_field(
[
'id' => 'pt_' . $tab['post_type'] . '_autogenerate_image',
'type' => 'toggle',
'name' => esc_html__( 'Autogenerate Image', 'rank-math-pro' ),
'desc' => esc_html__( 'Auto-generate image for the auto detected video.', 'rank-math-pro' ),
'options' => [
'off' => esc_html__( 'Default', 'rank-math-pro' ),
'on' => esc_html__( 'Custom', 'rank-math-pro' ),
],
'default' => 'off',
'dep' => [ [ 'pt_' . $tab['post_type'] . '_autodetect_video', 'on' ] ],
],
++$field_position
);
}
/**
* Add new settings.
*
* @param object $cmb CMB2 instance.
*/
public function add_media_rss_field( $cmb ) {
$field_ids = wp_list_pluck( $cmb->prop( 'fields' ), 'id' );
$field_position = array_search( 'rss_after_content', array_keys( $field_ids ), true ) + 1;
$cmb->add_field(
[
'id' => 'disable_media_rss',
'type' => 'toggle',
'name' => esc_html__( 'Remove Media Data from RSS feed', 'rank-math-pro' ),
'desc' => esc_html__( 'Remove Media Data from RSS feed', 'rank-math-pro' ),
'options' => [
'off' => esc_html__( 'Default', 'rank-math-pro' ),
'on' => esc_html__( 'Custom', 'rank-math-pro' ),
],
'default' => 'off',
],
++$field_position
);
}
/**
* Output the video tags.
*
* @link https://yandex.com/support/video/partners/open-graph.html#player
*
* @param OpenGraph $opengraph The current opengraph network object.
*/
public function add_video_tags( $opengraph ) {
if ( ! is_singular() ) {
return;
}
global $post;
$video_data = get_post_meta( $post->ID, 'rank_math_schema_VideoObject', true );
if ( empty( $video_data ) ) {
return;
}
$tags = [
'ya:ovs:adult' => ! empty( $video_data['isFamilyFriendly'] ) ? false : true,
'ya:ovs:upload_date' => ! empty( $video_data['uploadDate'] ) ? Helper::replace_vars( $video_data['uploadDate'], $post ) : '',
'ya:ovs:allow_embed' => ! empty( $video_data['embedUrl'] ) ? 'true' : 'false',
];
foreach ( $tags as $tag => $value ) {
$opengraph->tag( $tag, $value );
}
}
/**
* Automatically add Video Schema when post is updated.
*
* @param int $object_id Object ID.
* @param int $object_type Object type.
* @param string $content Updated post content.
*/
public function detect_video_in_content( $object_id, $object_type, $content = '' ) {
if ( 'post' !== $object_type ) {
return;
}
$post = get_post( $object_id );
if ( $content ) {
$post->post_content = $content;
}
( new Video\Parser( $post ) )->save();
}
/**
* Add database tools.
*
* @param array $tools Array of tools.
*
* @return array
*/
public function generate_video_schema_tool( $tools ) {
$posts = Video_Schema_Generator::get()->find_posts();
if ( empty( $posts ) ) {
return $tools;
}
$generate_video_schema = [
'generate_video_schema' => [
'title' => esc_html__( 'Generate Video Schema for Old Posts/Pages', 'rank-math-pro' ),
'description' => esc_html__( 'Add Video schema to posts which have YouTube or Vimeo Video in the content. Applies to only those Posts/Pages/CPTs in which Autodetect Video Option is On.', 'rank-math-pro' ),
'confirm_text' => esc_html__( 'Are you sure you want to add Video Schema to the posts/pages with the video in the content? This action is irreversible.', 'rank-math-pro' ),
'button_text' => esc_html__( 'Generate', 'rank-math-pro' ),
],
];
$index = array_search( 'recreate_tables', array_keys( $tools ), true );
$pos = false === $index ? count( $tools ) : $index + 1;
$tools = array_slice( $tools, 0, $pos, true ) + $generate_video_schema + array_slice( $tools, $pos, count( $tools ) - 1, true );
return $tools;
}
/**
* Detect Video in the content and add schema.
*
* @return string
*/
public function generate_video_schema() {
$posts = Video_Schema_Generator::get()->find_posts();
if ( empty( $posts ) ) {
return esc_html__( 'No posts found to convert.', 'rank-math-pro' );
}
Video_Schema_Generator::get()->start( $posts );
return esc_html__( 'Conversion started. A success message will be shown here once the process completes. You can close this page.', 'rank-math-pro' );
}
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* Shortcode - course
*
* @package RankMath
* @subpackage RankMath\Schema
*/
defined( 'ABSPATH' ) || exit;
$shortcode->get_description( $schema['claimReviewed'] );
$shortcode->get_image();
?>
<div class="rank-math-review-data">
<?php
$shortcode->get_field(
esc_html__( 'URL', 'rank-math-pro' ),
'url'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Author Name', 'rank-math-pro' ),
'itemReviewed.author.name'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Published Date', 'rank-math-pro' ),
'itemReviewed.datePublished'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Appearance Headline', 'rank-math-pro' ),
'itemReviewed.appearance.headline'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Appearance URL', 'rank-math-pro' ),
'itemReviewed.appearance.url'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Appearance Author', 'rank-math-pro' ),
'itemReviewed.appearance.author.name'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Appearance Published Date', 'rank-math-pro' ),
'itemReviewed.appearance.datePublished'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Alternate Name', 'rank-math-pro' ),
'reviewRating.alternateName'
);
?>
<?php $shortcode->show_ratings( 'reviewRating.ratingValue' ); ?>
</div>

View File

@@ -0,0 +1,120 @@
<?php
/**
* Shortcode - course
*
* @package RankMath
* @subpackage RankMath\Schema
*/
defined( 'ABSPATH' ) || exit;
$shortcode->get_title();
$shortcode->get_image();
?>
<div class="rank-math-review-data">
<?php $shortcode->get_description(); ?>
<?php
$shortcode->get_field(
esc_html__( 'URL', 'rank-math-pro' ),
'url'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Reference Web page ', 'rank-math-pro' ),
'sameAs'
);
?>
<?php
$identifier = $shortcode->get_field_value( 'identifier' );
if ( ! empty( $identifier ) ) {
$identifiers = explode( PHP_EOL, $identifier );
$shortcode->output_field(
esc_html__( 'Identifier', 'rank-math-pro' ),
'<ul><li>' . join( '</li><li>', $identifiers ) . '</li></ul>'
);
}
?>
<?php
$keyword = $shortcode->get_field_value( 'keywords' );
if ( ! empty( $keyword ) ) {
$keywords = explode( PHP_EOL, $keyword );
$shortcode->output_field(
esc_html__( 'Keywords', 'rank-math-pro' ),
'<ul><li>' . join( '</li><li>', $keywords ) . '</li></ul>'
);
}
?>
<?php
$shortcode->get_field(
esc_html__( 'License', 'rank-math-pro' ),
'license'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Catalog', 'rank-math-pro' ),
'includedInDataCatalog.name'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Temporal Coverage', 'rank-math-pro' ),
'temporalCoverage'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Special Coverage', 'rank-math-pro' ),
'spatialCoverage'
);
?>
<?php
$data_sets = $shortcode->get_field_value( 'hasPart' );
$labels = [
'name' => esc_html__( 'Name', 'rank-math-pro' ),
'description' => esc_html__( 'Description', 'rank-math-pro' ),
'license' => esc_html__( 'License', 'rank-math-pro' ),
];
if ( ! empty( $data_sets ) ) {
echo '<h3>' . esc_html__( 'Data Sets', 'rank-math-pro' ) . '</h3>';
foreach ( $data_sets as $data_set ) {
echo '<div>';
foreach ( $labels as $key => $label ) {
echo "<p><strong>{$label}</strong>: {$data_set[$key]}</p>"; // phpcs:ignore
}
echo '</div>';
}
}
?>
<?php
$distributions = $shortcode->get_field_value( 'distribution' );
$labels = [
'encodingFormat' => esc_html__( 'Format', 'rank-math-pro' ),
'contentUrl' => esc_html__( 'URL', 'rank-math-pro' ),
];
if ( ! empty( $distributions ) ) {
echo '<h3>' . esc_html__( 'Distribution', 'rank-math-pro' ) . '</h3>';
foreach ( $distributions as $distribution ) {
echo '<div>';
foreach ( $labels as $key => $label ) {
echo "<p><strong>{$label}</strong>: {$distribution[$key]}</p>"; // phpcs:ignore
}
echo '</div>';
}
}
?>
</div>

View File

@@ -0,0 +1,39 @@
<?php
/**
* Shortcode - FAQPage
*
* @package RankMath
* @subpackage RankMath\Schema
*/
use RankMath\Schema\Block_FAQ;
defined( 'ABSPATH' ) || exit;
if ( empty( $schema['mainEntity'] ) ) {
return;
}
$attributes = [
'questions' => [],
'listStyle' => '',
'titleWrapper' => 'h3',
'sizeSlug' => 'thumbnail',
'listCssClasses' => '',
'titleCssClasses' => '',
'contentCssClasses' => '',
'textAlign' => 'left',
];
foreach ( $schema['mainEntity'] as $index => $main_entity ) {
$attributes['questions'][] = [
'id' => 'faq-' . ( $index + 1 ),
'title' => $main_entity['name'],
'content' => $main_entity['acceptedAnswer']['text'],
'visible' => 1,
'imageID' => 0,
'imageUrl' => isset( $main_entity['image'] ) ? $main_entity['image'] : '',
];
}
echo Block_FAQ::markup( $attributes ); // phpcs:ignore

View File

@@ -0,0 +1,69 @@
<?php
/**
* Shortcode - HowTo
*
* @package RankMath
* @subpackage RankMath\Schema
*/
use RankMath\Schema\Block_HowTo;
use RankMath\Helpers\WordPress;
defined( 'ABSPATH' ) || exit;
$has_duration = false;
$days = 0;
$hours = 0;
$minutes = 0;
if ( isset( $schema['totalTime'] ) && WordPress::get_formatted_duration( $schema['totalTime'] ) ) {
$has_duration = true;
$duration = new \DateInterval( $schema['totalTime'] );
$days = $duration->d;
$hours = $duration->h;
$minutes = $duration->i;
}
$attributes = [
'days' => $days,
'hours' => $hours,
'minutes' => $minutes,
'hasDuration' => $has_duration,
'material' => isset( $schema['material'] ) ? $schema['material'] : '',
'imageUrl' => isset( $schema['image']['url'] ) ? $schema['image']['url'] : '',
'description' => isset( $schema['description'] ) ? $schema['description'] : '',
'estimatedCost' => isset( $schema['estimatedCost']['value'] ) ? $schema['estimatedCost']['value'] : '',
'estimatedCostCurrency' => isset( $schema['estimatedCost']['currency'] ) ? $schema['estimatedCost']['currency'] : '',
'steps' => [],
'supply' => '',
'tools' => '',
];
if ( ! empty( $schema['step'] ) ) {
foreach ( $schema['step'] as $step ) {
$attributes['steps'][] = [
'visible' => 1,
'title' => $step['name'],
'imageUrl' => $step['image']['url'],
'content' => $step['itemListElement']['text'],
];
}
}
if ( ! empty( $schema['supply'] ) ) {
foreach ( $schema['supply'] as $supply ) {
$attributes['supply'] .= $supply['name'] . PHP_EOL;
}
}
if ( ! empty( $schema['tool'] ) ) {
foreach ( $schema['tool'] as $tool ) {
$attributes['tools'] .= $tool['name'] . PHP_EOL;
}
}
// No steps.
if ( empty( $attributes['steps'] ) ) {
return;
}
echo Block_HowTo::markup( $attributes ); // phpcs:ignore

View File

@@ -0,0 +1,146 @@
<?php
/**
* Shortcode - Job Posting
*
* @package RankMath
* @subpackage RankMath\Schema
*/
defined( 'ABSPATH' ) || exit;
$shortcode->get_title();
$shortcode->get_image();
?>
<div class="rank-math-review-data">
<?php $shortcode->get_description(); ?>
<?php
$shortcode->get_field(
esc_html__( 'Salary', 'rank-math-pro' ),
'baseSalary.value.value'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Salary Currency', 'rank-math-pro' ),
'baseSalary.currency'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Payroll', 'rank-math-pro' ),
'baseSalary.value.unitText'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Date Posted', 'rank-math-pro' ),
'datePosted'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Posting Expiry Date', 'rank-math-pro' ),
'validThrough'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Unpublish when expired', 'rank-math-pro' ),
'unpublish'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Employment Type ', 'rank-math-pro' ),
'employmentType'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Hiring Organization ', 'rank-math-pro' ),
'hiringOrganization.name'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Organization URL', 'rank-math-pro' ),
'hiringOrganization.sameAs'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Organization Logo', 'rank-math-pro' ),
'hiringOrganization.logo'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Job Type', 'rank-math-pro' ),
'jobLocationType'
);
?>
<?php
$locations = $shortcode->get_field_value( 'applicantLocationRequirements' );
if ( ! empty( $locations ) ) {
$locations = array_map(
function( $location ) {
return ! empty( $location['name'] ) ? $location['name'] : '';
},
$locations
);
$shortcode->output_field(
esc_html__( 'Job Location', 'rank-math-pro' ),
'<ul><li>' . join( '</li><li>', $locations ) . '</li></ul>'
);
}
?>
<?php
$shortcode->get_field(
esc_html__( 'Location', 'rank-math-pro' ),
'jobLocation.address'
);
?>
<?php
$education = $shortcode->get_field_value( 'educationRequirements' );
if ( is_array( $education ) && ! empty( $education ) ) {
$education = array_map(
function( $credential ) {
return ! empty( $credential['credentialCategory'] ) ? ucwords( $credential['credentialCategory'] ) : '';
},
$education
);
$shortcode->output_field(
esc_html__( 'Education Required', 'rank-math-pro' ),
'<ul><li>' . join( '</li><li>', $education ) . '</li></ul>'
);
}
?>
<?php
$experience = $shortcode->get_field_value( 'experienceRequirements' );
if ( is_array( $experience ) && ! empty( $experience['monthsOfExperience'] ) ) {
$shortcode->output_field(
esc_html__( 'Experience Required', 'rank-math-pro' ),
$experience['monthsOfExperience'] . ' ' . esc_html__( 'Months', 'rank-math-pro' )
);
}
?>
</div>

View File

@@ -0,0 +1,33 @@
<?php
/**
* Shortcode - Movie
*
* @package RankMath
* @subpackage RankMath\Schema
*/
defined( 'ABSPATH' ) || exit;
$shortcode->get_title();
$shortcode->get_image();
?>
<div class="rank-math-review-data">
<?php
$shortcode->get_field(
esc_html__( 'Director', 'rank-math-pro' ),
'director'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Date Created', 'rank-math-pro' ),
'dateCreated',
true
);
?>
<?php $shortcode->show_ratings(); ?>
</div>

View File

@@ -0,0 +1,133 @@
<?php
/**
* Shortcode - PodcastEpisode
*
* @since 3.0.17
* @package RankMathPro
* @subpackage RankMathPro\Schema
*/
use RankMath\Helpers\WordPress;
defined( 'ABSPATH' ) || exit;
if ( empty( $schema['associatedMedia'] ) || empty( $schema['associatedMedia']['contentUrl'] ) ) {
return;
}
$post_title = get_the_title( $post->ID );
$episode_title = $schema['name'];
if ( $schema['name'] === $post_title && $post->ID === get_the_ID() ) {
$episode_title = '';
}
/**
* Filter: 'rank_math/schema/podcast_episode_title' - Allow changing the title of the podcast episode. Pass false to disable.
*
* @var string $post_title The title of the podcast episode.
*
* @param WP_Post $post The post object.
* @param array $schema The schema array.
*/
$episode_title = apply_filters( 'rank_math/schema/podcast_episode_title', $episode_title, $post, $schema );
$season = ! empty( $schema['partOfSeason'] ) ? $schema['partOfSeason'] : [];
$time_required = [];
if ( isset( $schema['timeRequired'] ) && WordPress::get_formatted_duration( $schema['timeRequired'] ) ) {
$duration = new \DateInterval( $schema['timeRequired'] );
$time_required[] = ! empty( $duration->h ) ? sprintf( esc_html__( '%d Hour', 'rank-math-pro' ), $duration->h ) : '';
$time_required[] = ! empty( $duration->i ) ? sprintf( esc_html__( '%d Min', 'rank-math-pro' ), $duration->i ) : '';
$time_required[] = ! empty( $duration->s ) ?sprintf( esc_html__( '%d Sec', 'rank-math-pro' ), $duration->s ) : '';
$time_required = array_filter( $time_required );
}
ob_start();
?>
<!-- wp:columns -->
<div class="wp-block-columns" style="gap: 2em;">
<!-- wp:column -->
<?php if ( ! empty( $schema['thumbnailUrl'] ) ) {
$image_id = attachment_url_to_postid( $schema['thumbnailUrl'] );
$img = '<img src="' . esc_url( $schema['thumbnailUrl'] ) . '" />';
if ( $image_id ) {
$img = wp_get_attachment_image( $image_id, 'medium', false, [ 'class' => 'wp-image-' . $image_id ] );
}
?>
<div class="wp-block-column" style="flex: 0 0 25%;">
<!-- wp:image -->
<figure class="wp-block-image size-medium is-resized">
<?php echo wp_kses_post( $img ); ?>
</figure>
<!-- /wp:image -->
</div>
<!-- /wp:column -->
<?php } ?>
<!-- wp:column -->
<div class="wp-block-column">
<!-- wp:paragraph -->
<p>
<?php if ( ! empty( $schema['datePublished'] ) ) { ?>
<span class="rank-math-podcast-date">
<?php echo esc_html( date( "j F", strtotime( $schema['datePublished'] ) ) ); ?>
</span> &#183;
<?php } ?>
<span>
<?php if ( ! empty( $season['seasonNumber'] ) ) { ?>
<?php echo esc_html__( 'Season', 'rank-math-pro' ); ?> <?php echo esc_html( $season['seasonNumber'] ); ?>
<?php if ( ! empty( $season['name'] ) ) { ?>
: <?php if ( ! empty( $season['url'] ) ) { ?>
<a href="<?php echo esc_url( $season['url'] ); ?>"><?php echo esc_html( $season['name'] ); ?></a>
<?php } else { ?>
<?php echo esc_html( $season['name'] ); ?>
<?php } ?>
<?php } ?> &#183;
<?php } ?>
<?php if ( ! empty( $schema['episodeNumber'] ) ) { ?>
<?php echo esc_html__( 'Episode', 'rank-math-pro' ); ?> <?php echo esc_html( $schema['episodeNumber'] ); ?>
<?php } ?>
</span>
</p>
<!-- /wp:paragraph -->
<?php if ( $episode_title ) { ?>
<!-- wp:heading -->
<h2>
<?php echo esc_html( $episode_title ); ?>
</h2>
<!-- /wp:heading -->
<?php } ?>
<!-- wp:paragraph -->
<p>
<?php if ( ! empty( $time_required ) ) { ?>
<span>
<?php echo implode( ', ', $time_required ); ?>
</span>
&#183;
<?php } ?>
<?php if ( ! empty( $schema['author'] ) ) { ?>
<?php echo esc_html__( 'By', 'rank-math-pro' ); ?> <?php echo esc_html( $schema['author']['name'] ); ?>
<?php } ?>
</p>
<!-- /wp:paragraph -->
</div>
<!-- /wp:column -->
</div>
<!-- /wp:columns -->
<!-- wp:audio -->
<figure class="wp-block-audio">
<audio controls src="<?php echo esc_url( $schema['associatedMedia']['contentUrl'] ); ?>"></audio>
</figure>
<!-- /wp:audio -->
<?php if ( ! empty( $schema['description'] ) ) { ?>
<!-- wp:paragraph -->
<p><?php echo esc_html( $schema['description'] ); ?></p>
<!-- /wp:paragraph -->
<?php } ?>
<?php
echo do_blocks( ob_get_clean() );

View File

@@ -0,0 +1,89 @@
<?php
/**
* Shortcode - Product
*
* @since 2.7.0
* @package RankMathPro
* @subpackage RankMathPro\Schema
*/
defined( 'ABSPATH' ) || exit;
$shortcode->get_title();
$shortcode->get_image();
$offers = $shortcode->get_field_value( 'offers' );
$positive_notes = $shortcode->get_field_value( 'review.positiveNotes' );
$negative_notes = $shortcode->get_field_value( 'review.negativeNotes' );
?>
<div class="rank-math-review-data">
<?php $shortcode->get_description(); ?>
<?php
$shortcode->get_field(
esc_html__( 'Product SKU', 'rank-math-pro' ),
'sku'
);
?>
<?php
$brand = $shortcode->get_field_value( 'brand' );
if ( ! empty( $brand['url'] ) && ! empty( $brand['name'] ) ) {
?>
<p>
<strong><?php echo esc_html__( 'Product Brand', 'rank-math-pro' ); ?>: </strong>
<a href="<?php echo esc_url( $brand['url'] ); ?>"><?php echo esc_html( $brand['name'] ); ?></a>
</p>
<?php
} else {
$shortcode->get_field(
esc_html__( 'Product Brand', 'rank-math-pro' ),
'brand.name'
);
}
?>
<?php
if (
! empty( $offers['price'] ) ||
(
empty( $positive_notes ) &&
empty( $negative_notes )
)
) {
?>
<?php
$shortcode->get_field(
esc_html__( 'Product Currency', 'rank-math-pro' ),
'offers.priceCurrency'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Product Price', 'rank-math-pro' ),
'offers.price'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Price Valid Until', 'rank-math-pro' ),
'offers.priceValidUntil'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Product In-Stock', 'rank-math-pro' ),
'offers.availability'
);
?>
<?php } ?>
<?php $shortcode->show_ratings(); ?>
</div>

View File

@@ -0,0 +1,186 @@
<?php
/**
* Shortcode - Recipe
*
* @package RankMathPro
* @subpackage RankMathPro\Schema
*/
defined( 'ABSPATH' ) || exit;
$shortcode->get_title();
$shortcode->get_image();
?>
<div class="rank-math-review-data">
<?php $shortcode->get_description(); ?>
<?php
$shortcode->get_field(
esc_html__( 'Type', 'rank-math-pro' ),
'recipeCategory'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Cuisine', 'rank-math-pro' ),
'recipeCuisine'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Keywords', 'rank-math-pro' ),
'keywords'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Recipe Yield', 'rank-math-pro' ),
'recipeYield'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Calories', 'rank-math-pro' ),
'nutrition.calories'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Preparation Time', 'rank-math-pro' ),
'prepTime'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Cooking Time', 'rank-math-pro' ),
'cookTime'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Total Time', 'rank-math-pro' ),
'totalTime'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Recipe Video Name', 'rank-math-pro' ),
'video.name'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Recipe Video Description', 'rank-math-pro' ),
'video.description'
);
?>
<?php
$shortcode->get_field(
esc_html__( 'Recipe Video Thumbnail', 'rank-math-pro' ),
'video.thumbnailUrl'
);
?>
<?php
$videoembed = $shortcode->get_field_value( 'video' );
if ( ! empty( $videoembed ) ) {
global $wp_embed;
if ( ! empty( $videoembed['embedUrl'] ) ) {
echo do_shortcode( $wp_embed->autoembed( $videoembed['embedUrl'] ) );
} elseif ( ! empty( $videoembed['contentUrl'] ) ) {
echo do_shortcode( $wp_embed->autoembed( $videoembed['contentUrl'] ) );
}
}
?>
<?php
$ingredient = $shortcode->get_field_value( 'recipeIngredient' );
$shortcode->output_field(
esc_html__( 'Recipe Ingredients', 'rank-math-pro' ),
'<ul><li>' . join( '</li><li>', $ingredient ) . '</li></ul>'
);
?>
<?php
$instructions = $shortcode->get_field_value( 'recipeInstructions' );
if ( is_string( $instructions ) ) {
$shortcode->get_field(
esc_html__( 'Recipe Instructions', 'rank-math-pro' ),
'recipeInstructions'
);
} else {
// HowTo Array.
if ( isset( $instructions[0]['@type'] ) && 'HowtoStep' === $instructions[0]['@type'] ) {
$instructions = wp_list_pluck( $instructions, 'text' );
$shortcode->output_field(
esc_html__( 'Recipe Instructions', 'rank-math-pro' ),
'<ul><li>' . join( '</li><li>', $instructions ) . '</li></ul>'
);
}
// Single HowToSection data.
if ( ! empty( $instructions['itemListElement'] ) ) {
$shortcode->output_field(
esc_html__( 'Recipe Instructions', 'rank-math-pro' ),
''
);
$shortcode->output_field(
$instructions['name'],
'<ul><li>' . join( '</li><li>', wp_list_pluck( $instructions['itemListElement'], 'text' ) ) . '</li></ul>'
);
}
// Multiple HowToSection data.
if ( isset( $instructions[0]['@type'] ) && 'HowToSection' === $instructions[0]['@type'] ) {
$shortcode->output_field(
esc_html__( 'Recipe Instructions', 'rank-math-pro' ),
''
);
foreach ( $instructions as $section ) {
if ( empty( $section['itemListElement'] ) ) {
continue;
}
$data = '';
foreach ( $section['itemListElement'] as $item ) {
$url = ! empty( $item['url'] ) ? $item['url'] : '';
$name = ! empty( $item['name'] ) ? $item['name'] : '';
$image = ! empty( $item['image'] ) ? $item['image']['url'] : '';
$text = ! empty( $item['text'] ) ? $item['text'] : '';
$data .= '<div class="inner-wrapper">';
$data .= '<div class="content-wrapper">';
$data .= '<h5><a href="' . esc_url( $url ) . '" target="_blank">' . esc_html__( $name ) . '</a></h5>';
$data .= '<p>' . esc_html( $text ) . '</p>';
$data .= '</div>';
$data .= '<img src="' . esc_url( $image ) . '" />';
$data .= '</div>';
}
echo '<div class="recipe-instructions-data">';
$shortcode->output_field(
$section['name'],
$data
);
echo '</div>';
}
}
}
?>
<?php $shortcode->show_ratings(); ?>
</div>

View File

@@ -0,0 +1,80 @@
<?php
/**
* The DailyMotion Video.
*
* @since 2.7.1
* @package RankMath
* @subpackage RankMath\Schema\Video
* @author Rank Math <support@rankmath.com>
*/
namespace RankMathPro\Schema\Video;
use MyThemeShop\Helpers\Str;
defined( 'ABSPATH' ) || exit;
/**
* DailyMotion class.
*/
class DailyMotion {
/**
* Match url.
*
* @param string $url Url to match.
* @return bool
*/
public static function match( $url ) {
if ( ! Str::contains( 'dailymotion.com', $url ) ) {
return false;
}
$id = strtok( basename( $url ), '_' );
if ( empty( $id ) ) {
return false;
}
return self::fetch_data( $id, $url );
}
/**
* Fetch data.
*
* @param string $video_id Video ID.
* @param string $url Video Source.
* @return array
*
* @link https://developer.dailymotion.com/api/#video-fields
*/
private static function fetch_data( $video_id, $url ) {
$data = [
'src' => $url,
'embed' => true,
];
$response = wp_remote_get( "https://api.dailymotion.com/video/{$video_id}?fields=title,description,duration,thumbnail_url,width,height,created_time" );
if (
is_wp_error( $response ) ||
! in_array( wp_remote_retrieve_response_code( $response ), [ 200, 204 ], true )
) {
return $data;
}
$content = wp_remote_retrieve_body( $response );
$content = json_decode( $content, true );
$data = [
'name' => ! empty( $content['title'] ) ? $content['title'] : '',
'description' => ! empty( $content['description'] ) ? $content['description'] : '',
'src' => $url,
'embed' => true,
'width' => $content['width'],
'height' => $content['height'],
'isFamilyFriendly' => true,
'duration' => 'PT' . $content['duration'] . 'S',
'thumbnail' => $content['thumbnail_url'],
'uploadDate' => gmdate( 'Y-m-d\TH:i:s', $content['created_time'] ),
];
return $data;
}
}

View File

@@ -0,0 +1,400 @@
<?php
/**
* The Video Parser
*
* @since 2.0.0
* @package RankMath
* @subpackage RankMath\Schema\Video
* @author Rank Math <support@rankmath.com>
*/
namespace RankMathPro\Schema\Video;
use RankMath\Helper;
use RankMath\Schema\DB;
use MyThemeShop\Helpers\Str;
defined( 'ABSPATH' ) || exit;
/**
* Parser class.
*/
class Parser {
/**
* Post.
*
* @var WP_Post
*/
private $post;
/**
* Stored Video URLs.
*
* @var array
*/
private $urls;
/**
* The Constructor.
*
* @param WP_Post $post Post to parse.
*/
public function __construct( $post ) {
$this->post = $post;
}
/**
* Save video object.
*/
public function save() {
if (
! ( $this->post instanceof \WP_Post ) ||
wp_is_post_revision( $this->post->ID ) ||
! Helper::get_settings( "titles.pt_{$this->post->post_type}_autodetect_video", 'on' )
) {
return;
}
$content = trim( $this->post->post_content . ' ' . $this->get_custom_fields_data() );
if ( empty( $content ) ) {
return;
}
$this->urls = $this->get_video_urls();
$content = apply_filters( 'the_content', $content );
$allowed_types = apply_filters( 'media_embedded_in_content_allowed_types', [ 'video', 'embed', 'iframe' ] );
$tags = implode( '|', $allowed_types );
$videos = [];
preg_match_all( '#<(?P<tag>' . $tags . ')[^<]*?(?:>[\s\S]*?<\/(?P=tag)>|\s*\/>)#', $content, $matches );
if ( ! empty( $matches ) && ! empty( $matches[0] ) ) {
foreach ( $matches[0] as $html ) {
$videos[] = $this->get_metadata( $html );
}
}
$videos = array_merge( $videos, $this->get_links_from_shortcode( $content ) );
$videos = array_filter(
$videos,
function( $video ) {
return ! empty( $video['src'] ) ? $video['src'] : false;
}
);
if ( empty( $videos ) ) {
return;
}
$schemas = $this->get_default_schema_data();
foreach ( $videos as $video ) {
$schemas[] = [
'@type' => 'VideoObject',
'metadata' => [
'title' => 'Video',
'type' => 'template',
'shortcode' => uniqid( 's-' ),
'isPrimary' => empty( DB::get_schemas( $this->post->ID ) ),
'reviewLocationShortcode' => '[rank_math_rich_snippet]',
'category' => '%categories%',
'tags' => '%tags%',
'isAutoGenerated' => true,
],
'name' => ! empty( $video['name'] ) ? $video['name'] : '%seo_title%',
'description' => ! empty( $video['description'] ) ? $video['description'] : '%seo_description%',
'uploadDate' => ! empty( $video['uploadDate'] ) ? $video['uploadDate'] : '%date(Y-m-dTH:i:sP)%',
'thumbnailUrl' => ! empty( $video['thumbnail'] ) ? $video['thumbnail'] : '%post_thumbnail%',
'embedUrl' => ! empty( $video['embed'] ) ? $video['src'] : '',
'contentUrl' => empty( $video['embed'] ) ? $video['src'] : '',
'duration' => ! empty( $video['duration'] ) ? $video['duration'] : '',
'width' => ! empty( $video['width'] ) ? $video['width'] : '',
'height' => ! empty( $video['height'] ) ? $video['height'] : '',
'isFamilyFriendly' => ! empty( $video['isFamilyFriendly'] ) ? (bool) $video['isFamilyFriendly'] : true,
];
}
foreach ( array_filter( $schemas ) as $schema ) {
add_post_meta( $this->post->ID, "rank_math_schema_{$schema['@type']}", $schema );
}
}
/**
* Get default schema data.
*/
private function get_default_schema_data() {
if ( ! empty( DB::get_schemas( $this->post->ID ) ) ) {
return [];
}
$default_type = Helper::get_default_schema_type( $this->post->ID, true );
if ( ! $default_type ) {
return [];
}
$is_article = in_array( $default_type, [ 'Article', 'NewsArticle', 'BlogPosting' ], true );
$schema_data = [];
if ( $is_article ) {
$schema_data = [
'headline' => Helper::get_settings( "titles.pt_{$this->post->post_type}_default_snippet_name" ),
'description' => Helper::get_settings( "titles.pt_{$this->post->post_type}_default_snippet_desc" ),
'datePublished' => '%date(Y-m-dTH:i:sP)%',
'dateModified' => '%modified(Y-m-dTH:i:sP)%',
'image' => [
'@type' => 'ImageObject',
'url' => '%post_thumbnail%',
],
'author' => [
'@type' => 'Person',
'name' => '%name%',
],
];
}
$schema_data['@type'] = $default_type;
$schema_data['metadata'] = [
'title' => Helper::sanitize_schema_title( $default_type ),
'type' => 'template',
'isPrimary' => true,
];
return [ $schema_data ];
}
/**
* Get Video source from the content.
*
* @param array $html Video Links.
*
* @return array
*/
public function get_metadata( $html ) {
preg_match_all( '@src=[\'"]([^"]+)[\'"]@', $html, $matches );
if ( empty( $matches ) || empty( $matches[1] ) ) {
return false;
}
return $this->get_video_metadata( $matches[1][0] );
}
/**
* Validate Video source.
*
* @param string $url Video Source.
* @return array
*/
private function get_video_metadata( $url ) {
$url = preg_replace( '/\?.*/', '', $url ); // Remove query string from URL.
if (
$url &&
(
is_array( $this->urls ) &&
(
in_array( $url, $this->urls, true ) ||
in_array( $url . '?feature=oembed', $this->urls, true )
)
)
) {
return false;
}
$this->urls[] = $url;
$networks = [
'Video\Youtube',
'Video\Vimeo',
'Video\DailyMotion',
'Video\TedVideos',
'Video\VideoPress',
'Video\WordPress',
];
$data = false;
foreach ( $networks as $network ) {
$data = \call_user_func( [ '\\RankMathPro\\Schema\\' . $network, 'match' ], $url );
if ( is_array( $data ) ) {
break;
}
}
// Save image locally.
if ( ! empty( $data['thumbnail'] ) ) {
$data['thumbnail'] = $this->save_video_thumbnail( $data );
}
return $data;
}
/**
* Get Video Links from YouTube Embed plugin.
*
* @param string $content Post Content.
* @return array
*
* Credit ridgerunner (https://stackoverflow.com/users/433790/ridgerunner)
*/
private function get_links_from_shortcode( $content ) {
preg_match_all(
'~
https?:// # Required scheme. Either http or https.
(?:[0-9A-Z-]+\.)? # Optional subdomain.
(?: # Group host alternatives.
youtu\.be/ # Either youtu.be,
| youtube # or youtube.com or
(?:-nocookie)? # youtube-nocookie.com
\.com # followed by
\S*? # Allow anything up to VIDEO_ID,
[^\w\s-] # but char before ID is non-ID char.
) # End host alternatives.
([\w-]{11}) # $1: VIDEO_ID is exactly 11 chars.
(?=[^\w-]|$) # Assert next char is non-ID or EOS.
(?! # Assert URL is not pre-linked.
[?=&+%\w.-]* # Allow URL (query) remainder.
(?: # Group pre-linked alternatives.
[\'"][^<>]*> # Either inside a start tag,
| </a> # or inside <a> element text contents.
) # End recognized pre-linked alts.
) # End negative lookahead assertion.
[?=&+%\w.-]* # Consume any URL (query) remainder.
~ix',
$content,
$matches
);
if ( empty( $matches ) || empty( $matches[1] ) ) {
return [];
}
$data = [];
foreach ( $matches[1] as $video_id ) {
$data[] = $this->get_video_metadata( "https://www.youtube.com/embed/{$video_id}" );
}
return $data;
}
/**
* Validate Video source.
*
* @param array $data Video data.
* @return array
*
* Credits to m1r0 @ https://gist.github.com/m1r0/f22d5237ee93bcccb0d9
*/
private function save_video_thumbnail( $data ) {
$url = $data['thumbnail'];
if ( ! Helper::get_settings( "titles.pt_{$this->post->post_type}_autogenerate_image", 'off' ) ) {
return false;
}
if ( ! class_exists( 'WP_Http' ) ) {
include_once( ABSPATH . WPINC . '/class-http.php' );
}
$url = explode( '?', $url )[0];
$http = new \WP_Http();
$response = $http->request( $url );
if ( 200 !== $response['response']['code'] ) {
return false;
}
$image_title = __( 'Video Thumbnail', 'rank-math-pro' );
if ( ! empty( $data['name'] ) ) {
$image_title = $data['name'];
} elseif ( ! empty( $this->post->post_title ) ) {
$image_title = $this->post->post_title;
}
$filename = substr( sanitize_title( $image_title, 'video-thumbnail' ), 0, 32 ) . '.jpg';
/**
* Filter the filename of the video thumbnail.
*
* @param string $filename The filename of the video thumbnail.
* @param array $data The video data.
* @param object $post The post object.
*/
$filename = apply_filters( 'rank_math/schema/video_thumbnail_filename', $filename, $data, $this->post );
$upload = wp_upload_bits( sanitize_file_name( $filename ), null, $response['body'] );
if ( ! empty( $upload['error'] ) ) {
return false;
}
$file_path = $upload['file'];
$file_name = basename( $file_path );
$file_type = wp_check_filetype( $file_name, null );
$wp_upload_dir = wp_upload_dir();
// Translators: Placeholder is the image title.
$attachment_title = sprintf( __( 'Video Thumbnail: %s', 'rank-math-pro' ), $image_title );
/**
* Filter the attachment title of the video thumbnail.
*
* @param string $attachment_title The attachment title of the video thumbnail.
* @param array $data The video data.
* @param object $post The post object.
*/
$attachment_title = apply_filters( 'rank_math/schema/video_thumbnail_attachment_title', $attachment_title, $data, $this->post );
$post_info = [
'guid' => $wp_upload_dir['url'] . '/' . $file_name,
'post_mime_type' => $file_type['type'],
'post_title' => $attachment_title,
'post_content' => '',
'post_status' => 'inherit',
];
$attach_id = wp_insert_attachment( $post_info, $file_path, $this->post->ID );
// Include image.php.
require_once( ABSPATH . 'wp-admin/includes/image.php' );
// Define attachment metadata.
$attach_data = wp_generate_attachment_metadata( $attach_id, $file_path );
// Assign metadata to attachment.
wp_update_attachment_metadata( $attach_id, $attach_data );
return wp_get_attachment_url( $attach_id );
}
/**
* Get Video URls stored in VideoObject schema.
*
* @return array
*/
private function get_video_urls() {
$schemas = DB::get_schemas( $this->post->ID );
if ( empty( $schemas ) ) {
return [];
}
$urls = [];
foreach ( $schemas as $schema ) {
if ( empty( $schema['@type'] ) || 'VideoObject' !== $schema['@type'] ) {
continue;
}
$urls[] = ! empty( $schema['embedUrl'] ) ? $schema['embedUrl'] : '';
$urls[] = ! empty( $schema['contentUrl'] ) ? $schema['contentUrl'] : '';
}
return array_filter( $urls );
}
/**
* Get Custom fields data.
*/
private function get_custom_fields_data() {
$custom_fields = Str::to_arr_no_empty( Helper::get_settings( 'sitemap.video_sitemap_custom_fields' ) );
if ( empty( $custom_fields ) ) {
return;
}
$content = '';
foreach ( $custom_fields as $custom_field ) {
$content = $content . ' ' . get_post_meta( $this->post->ID, $custom_field, true );
}
return trim( $content );
}
}

View File

@@ -0,0 +1,75 @@
<?php
/**
* The TedVideos
*
* @since 2.7.1
* @package RankMath
* @subpackage RankMath\Schema\Video
* @author Rank Math <support@rankmath.com>
*/
namespace RankMathPro\Schema\Video;
use RankMath\Helper;
use MyThemeShop\Helpers\Str;
defined( 'ABSPATH' ) || exit;
/**
* TedVideos class.
*/
class TedVideos {
/**
* Match url.
*
* @param string $url Url to match.
* @return bool
*/
public static function match( $url ) {
if ( ! Str::contains( 'ted.com', $url ) ) {
return false;
}
return self::fetch_data( $url );
}
/**
* Fetch data.
*
* @param string $url Video Source.
* @return array
*/
private static function fetch_data( $url ) {
$data = [
'src' => $url,
'embed' => true,
];
$response = wp_remote_get( str_replace( 'embed.', '', $url ) );
if (
is_wp_error( $response ) ||
! in_array( wp_remote_retrieve_response_code( $response ), [ 200, 204 ], true )
) {
return $data;
}
$content = wp_remote_retrieve_body( $response );
preg_match_all( "/<meta content='(.*?)' itemprop='(width|height|duration|uploadDate)'>/i", $content, $item_props, PREG_SET_ORDER );
foreach ( $item_props as $item_prop ) {
$data[ $item_prop[2] ] = $item_prop[1];
}
preg_match_all( '/<meta name="(title|description)" content="(.*?)" \/>/i', $content, $item_props, PREG_SET_ORDER );
foreach ( $item_props as $item_prop ) {
$key = 'title' === $item_prop[1] ? 'name' : $item_prop[1];
$data[ $key ] = $item_prop[2];
}
preg_match( '/<meta property="og:image" content="(.*?)" \/>/i', $content, $image );
$data['thumbnail'] = ! empty( $image ) && isset( $image[1] ) ? $image[1] : '';
return $data;
}
}

View File

@@ -0,0 +1,81 @@
<?php
/**
* The VideoPress.
*
* @since 2.7.1
* @package RankMath
* @subpackage RankMath\Schema\Video
* @author Rank Math <support@rankmath.com>
*/
namespace RankMathPro\Schema\Video;
use MyThemeShop\Helpers\Str;
defined( 'ABSPATH' ) || exit;
/**
* VideoPress class.
*/
class VideoPress {
/**
* Match url.
*
* @param string $url Url to match.
* @return bool
*/
public static function match( $url ) {
if ( ! Str::contains( 'video.wordpress.com', $url ) ) {
return false;
}
$video_id = str_replace( 'https://video.wordpress.com/embed/', '', $url );
if ( ! $video_id ) {
return false;
}
return self::fetch_data( $video_id, $url );
}
/**
* Fetch data.
*
* @param string $video_id Video ID.
* @param string $url Video Source.
* @return array
*
* @see https://developer.wordpress.com/docs/api/1/get/videos/%24guid/
*/
private static function fetch_data( $video_id, $url ) {
$data = [
'src' => $url,
'embed' => true,
];
$response = wp_remote_get( "https://public-api.wordpress.com/rest/v1.1/videos/{$video_id}" );
if (
is_wp_error( $response ) ||
! in_array( wp_remote_retrieve_response_code( $response ), [ 200, 204 ], true )
) {
return $data;
}
$content = wp_remote_retrieve_body( $response );
$content = json_decode( $content, true );
$data = [
'name' => ! empty( $content['title'] ) ? $content['title'] : '',
'description' => ! empty( $content['description'] ) ? $content['description'] : '',
'src' => $url,
'embed' => true,
'width' => isset( $content['width'] ) ? $content['width'] : '',
'height' => isset( $content['height'] ) ? $content['height'] : '',
'isFamilyFriendly' => true,
'duration' => isset( $content['duration'] ) ? 'PT' . $content['duration'] . 'S' : '',
'thumbnail' => isset( $content['poster'] ) ? $content['poster'] : '',
'uploadDate' => isset( $content['upload_date'] ) ? $content['upload_date'] : '',
];
return $data;
}
}

View File

@@ -0,0 +1,83 @@
<?php
/**
* The Vimeo
*
* @since 2.0.0
* @package RankMath
* @subpackage RankMath\Schema\Video
* @author Rank Math <support@rankmath.com>
*/
namespace RankMathPro\Schema\Video;
use RankMath\Helper;
use RankMath\Admin\Admin_Helper;
use MyThemeShop\Helpers\Str;
defined( 'ABSPATH' ) || exit;
/**
* Vimeo class.
*/
class Vimeo {
/**
* Match url.
*
* @param string $url Url to match.
* @return bool
*/
public static function match( $url ) {
if ( ! Str::contains( 'vimeo.com', $url ) ) {
return false;
}
preg_match( '#(https?://)?(www.)?(player.)?vimeo.com/([a-z]*/)*([0-9]{6,11})[?]?.*#', $url, $match );
if ( empty( $match[5] ) ) {
return false;
}
return self::fetch_data( $match[5], $url );
}
/**
* Fetch data.
*
* @param string $video_id Video ID.
* @param string $url Video Source.
* @return array
*/
private static function fetch_data( $video_id, $url ) {
$data = [
'src' => $url,
'embed' => true,
];
$response = wp_remote_get( "http://vimeo.com/api/v2/video/{$video_id}/json" );
if (
is_wp_error( $response ) ||
! in_array( wp_remote_retrieve_response_code( $response ), [ 200, 204 ], true )
) {
return $data;
}
$content = wp_remote_retrieve_body( $response );
$content = json_decode( $content, true );
$content = $content[0];
$data = [
'name' => ! empty( $content['title'] ) ? $content['title'] : '',
'description' => ! empty( $content['description'] ) ? $content['description'] : '',
'src' => $url,
'embed' => true,
'width' => $content['width'],
'height' => $content['height'],
'isFamilyFriendly' => true,
'duration' => 'PT' . $content['duration'] . 'S',
'thumbnail' => $content['thumbnail_large'],
'uploadDate' => $content['upload_date'],
];
return $data;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* The WordPress
*
* @since 2.0.0
* @package RankMath
* @subpackage RankMath\Schema\Video
* @author Rank Math <support@rankmath.com>
*/
namespace RankMathPro\Schema\Video;
use RankMath\Helper;
use RankMath\Admin\Admin_Helper;
defined( 'ABSPATH' ) || exit;
/**
* WordPress class.
*/
class WordPress {
/**
* Match url.
*
* @param string $url Url to match.
* @return bool
*/
public static function match( $url ) {
$type = wp_check_filetype( $url, wp_get_mime_types() );
if ( ! in_array( strtolower( $type['ext'] ), wp_get_video_extensions(), true ) ) {
return [];
}
return self::fetch_data( $url );
}
/**
* Fetch data.
*
* @param string $url Video Source.
* @return array
*/
private static function fetch_data( $url ) {
$data = [];
$attachment_id = attachment_url_to_postid( $url );
if ( $attachment_id ) {
$video_details = wp_get_attachment_metadata( $attachment_id );
$data = [
'width' => ! empty( $video_details['width'] ) ? $video_details['width'] : '',
'height' => ! empty( $video_details['height'] ) ? $video_details['height'] : '',
];
}
return array_merge(
[
'src' => $url,
'embed' => false,
],
$data
);
}
}

View File

@@ -0,0 +1,80 @@
<?php
/**
* The Youtube
*
* @since 2.0.0
* @package RankMath
* @subpackage RankMath\Schema\Video
* @author Rank Math <support@rankmath.com>
*/
namespace RankMathPro\Schema\Video;
use RankMath\Helper;
use RankMath\Admin\Admin_Helper;
defined( 'ABSPATH' ) || exit;
/**
* Youtube class.
*/
class Youtube {
/**
* Match url.
*
* @param string $url Url to match.
* @return bool
*/
public static function match( $url ) {
if ( ! preg_match( '#^https?://(?:www\.)?(?:youtube\.com/|youtu\.be/)#', $url ) ) {
return false;
}
preg_match( '%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $url, $match );
if ( empty( $match[1] ) ) {
return false;
}
return self::fetch_data( $match[1], $url );
}
/**
* Fetch data.
*
* @param string $video_id Video ID.
* @param string $url Video Source.
* @return array
*/
private static function fetch_data( $video_id, $url ) {
$data = [
'src' => $url,
'embed' => true,
];
$response = wp_remote_get( "https://www.youtube.com/watch?v={$video_id}" );
if (
is_wp_error( $response ) ||
! in_array( wp_remote_retrieve_response_code( $response ), [ 200, 204 ], true )
) {
return $data;
}
$content = wp_remote_retrieve_body( $response );
preg_match_all( '/<meta itemprop="(width|height|isFamilyFriendly|duration|uploadDate)" content="(.*?)">/i', $content, $item_props, PREG_SET_ORDER );
foreach ( $item_props as $item_prop ) {
$data[ $item_prop[1] ] = $item_prop[2];
}
preg_match_all( '/<meta name="(title|description)" content="(.*?)">/i', $content, $item_props, PREG_SET_ORDER );
foreach ( $item_props as $item_prop ) {
$key = 'title' === $item_prop[1] ? 'name' : $item_prop[1];
$data[ $key ] = $item_prop[2];
}
preg_match( '/<meta property="og:image" content="(.*?)">/i', $content, $image );
$data['thumbnail'] = ! empty( $image ) && isset( $image[1] ) ? $image[1] : '';
return $data;
}
}