You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
362 lines
8.2 KiB
PHTML
362 lines
8.2 KiB
PHTML
8 months ago
|
<?php
|
||
|
/**
|
||
|
* The AIO Schema Rich Snippets Import Class
|
||
|
*
|
||
|
* @since 0.9.0
|
||
|
* @package RankMath
|
||
|
* @subpackage RankMath\Admin\Importers
|
||
|
* @author Rank Math <support@rankmath.com>
|
||
|
*/
|
||
|
|
||
|
namespace RankMath\Admin\Importers;
|
||
|
|
||
|
use RankMath\Helper;
|
||
|
use RankMath\Admin\Admin_Helper;
|
||
|
use RankMath\Helpers\DB;
|
||
|
use RankMath\Helpers\Str;
|
||
|
|
||
|
defined( 'ABSPATH' ) || exit;
|
||
|
|
||
|
/**
|
||
|
* Import_AIO_Rich_Snippet class.
|
||
|
*/
|
||
|
class AIO_Rich_Snippet extends Plugin_Importer {
|
||
|
|
||
|
/**
|
||
|
* The plugin name.
|
||
|
*
|
||
|
* @var string
|
||
|
*/
|
||
|
protected $plugin_name = 'AIO Schema Rich Snippet';
|
||
|
|
||
|
/**
|
||
|
* Plugin options meta key.
|
||
|
*
|
||
|
* @var string
|
||
|
*/
|
||
|
protected $meta_key = '_bsf_post_type';
|
||
|
|
||
|
/**
|
||
|
* Option keys to import and clean.
|
||
|
*
|
||
|
* @var array
|
||
|
*/
|
||
|
protected $option_keys = [ 'bsf_', 'bsf_%' ];
|
||
|
|
||
|
/**
|
||
|
* Choices keys to import.
|
||
|
*
|
||
|
* @var array
|
||
|
*/
|
||
|
protected $choices = [ 'postmeta' ];
|
||
|
|
||
|
/**
|
||
|
* Import post meta of plugin.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
protected function postmeta() {
|
||
|
$this->set_pagination( $this->get_post_ids( true ) );
|
||
|
|
||
|
// Set Converter.
|
||
|
foreach ( $this->get_post_ids() as $snippet_post ) {
|
||
|
$type = $this->is_allowed_type( $snippet_post->meta_value );
|
||
|
$meta_keys = $this->get_metakeys( $type );
|
||
|
if ( false === $type || false === $meta_keys ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$this->set_postmeta( $snippet_post->post_id, $type, $meta_keys );
|
||
|
}
|
||
|
|
||
|
return $this->get_pagination_arg();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set snippet meta.
|
||
|
*
|
||
|
* @param int $post_id Post ID.
|
||
|
* @param string $type Type to get keys for.
|
||
|
* @param array $meta_keys Array of meta keys to save.
|
||
|
*/
|
||
|
private function set_postmeta( $post_id, $type, $meta_keys ) {
|
||
|
$data = [];
|
||
|
foreach ( $meta_keys as $snippet_key => $snippet_value ) {
|
||
|
$value = get_post_meta( $post_id, '_bsf_' . $snippet_key, true );
|
||
|
$this->validate_schema_data( $data, $value, $snippet_value );
|
||
|
}
|
||
|
|
||
|
if ( empty( $data ) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Convert post now.
|
||
|
$data['@type'] = $this->validate_type( $type );
|
||
|
$data['metadata'] = [
|
||
|
'title' => Helper::sanitize_schema_title( $data['@type'] ),
|
||
|
'type' => 'template',
|
||
|
'isPrimary' => 1,
|
||
|
'shortcode' => uniqid( 's-' ),
|
||
|
];
|
||
|
|
||
|
update_post_meta( $post_id, 'rank_math_schema_' . $data['@type'], $data );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Validate schema type.
|
||
|
*
|
||
|
* @param string $type Schema Type.
|
||
|
*/
|
||
|
private function validate_type( $type ) {
|
||
|
if ( 'software' === $type ) {
|
||
|
return 'SoftwareApplication';
|
||
|
}
|
||
|
|
||
|
if ( 'video' === $type ) {
|
||
|
return 'VideoObject';
|
||
|
}
|
||
|
|
||
|
return ucfirst( $type );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Validate schema data.
|
||
|
*
|
||
|
* @param array $data Schema entity data.
|
||
|
* @param string $value Entity value.
|
||
|
* @param string $key Entity key.
|
||
|
*/
|
||
|
private function validate_schema_data( &$data, $value, $key ) {
|
||
|
if ( ! Str::contains( '.', $key ) ) {
|
||
|
$data[ $key ] = $value;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$element = explode( '.', $key );
|
||
|
if ( 2 === count( $element ) ) {
|
||
|
$this->add_type( $data[ $element[0] ], $element[0] );
|
||
|
$data[ $element[0] ][ $element[1] ] = $value;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( count( $element ) > 2 ) {
|
||
|
$this->add_type( $data[ $element[0] ], $element[0] );
|
||
|
$this->add_type( $data[ $element[0] ][ $element[1] ], $element[1] );
|
||
|
$data[ $element[0] ][ $element[1] ][ $element[2] ] = $value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add property type.
|
||
|
*
|
||
|
* @param array $data Schema entity data.
|
||
|
* @param string $key Entity key.
|
||
|
*/
|
||
|
private function add_type( &$data, $key ) {
|
||
|
if ( 'location' === $key ) {
|
||
|
$data['@type'] = 'Place';
|
||
|
}
|
||
|
|
||
|
if ( 'address' === $key ) {
|
||
|
$data['@type'] = 'PostalAddress';
|
||
|
}
|
||
|
|
||
|
if ( 'offers' === $key ) {
|
||
|
$data['@type'] = 'Offer';
|
||
|
}
|
||
|
|
||
|
if ( 'brand' === $key ) {
|
||
|
$data['@type'] = 'Brand';
|
||
|
}
|
||
|
|
||
|
if ( 'review' === $key ) {
|
||
|
$data['@type'] = 'Review';
|
||
|
}
|
||
|
|
||
|
if ( 'reviewRating' === $key ) {
|
||
|
$data['@type'] = 'Rating';
|
||
|
}
|
||
|
|
||
|
if ( 'nutrition' === $key ) {
|
||
|
$data['@type'] = 'NutritionInformation';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the actions which can be performed for the plugin.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function get_choices() {
|
||
|
return [
|
||
|
'postmeta' => esc_html__( 'Import Schemas', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import all Schema data for Posts, Pages, and custom post types.', 'rank-math' ) ),
|
||
|
];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get all post IDs of all allowed post types only.
|
||
|
*
|
||
|
* @param bool $count If we need count only for pagination purposes.
|
||
|
* @return int|array
|
||
|
*/
|
||
|
protected function get_post_ids( $count = false ) {
|
||
|
$paged = $this->get_pagination_arg( 'page' );
|
||
|
$table = DB::query_builder( 'postmeta' )->where( 'meta_key', '_bsf_post_type' );
|
||
|
|
||
|
return $count ? absint( $table->selectCount( 'meta_id' )->getVar() ) :
|
||
|
$table->page( $paged - 1, $this->items_per_page )->get();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get snippet types.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
private function get_types() {
|
||
|
return [
|
||
|
'2' => 'event',
|
||
|
'5' => 'person',
|
||
|
'6' => 'product',
|
||
|
'7' => 'recipe',
|
||
|
'8' => 'software',
|
||
|
'9' => 'video',
|
||
|
'10' => 'article',
|
||
|
'11' => 'service',
|
||
|
];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Is snippet type allowed.
|
||
|
*
|
||
|
* @param string $type Type to check.
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
private function is_allowed_type( $type ) {
|
||
|
$types = $this->get_types();
|
||
|
return isset( $types[ $type ] ) ? $types[ $type ] : false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get meta keys hash to import.
|
||
|
*
|
||
|
* @param string $type Type to get keys for.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
private function get_metakeys( $type ) {
|
||
|
$hash = [
|
||
|
'event' => $this->get_event_fields(),
|
||
|
'product' => $this->get_product_fields(),
|
||
|
'recipe' => $this->get_recipe_fields(),
|
||
|
'software' => $this->get_software_fields(),
|
||
|
'video' => $this->get_video_fields(),
|
||
|
'article' => [
|
||
|
'article_name' => 'headline',
|
||
|
'article_desc' => 'description',
|
||
|
],
|
||
|
'person' => [
|
||
|
'people_fn' => 'name',
|
||
|
'people_nickname' => 'description',
|
||
|
'people_job_title' => 'jobTitle',
|
||
|
'people_street' => 'address.streetAddress',
|
||
|
'people_local' => 'address.addressLocality',
|
||
|
'people_region' => 'address.addressRegion',
|
||
|
'people_postal' => 'address.postalCode',
|
||
|
],
|
||
|
'service' => [
|
||
|
'service_type' => 'serviceType',
|
||
|
'service_desc' => 'description',
|
||
|
],
|
||
|
];
|
||
|
|
||
|
return isset( $hash[ $type ] ) ? $hash[ $type ] : false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get event fields.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
private function get_event_fields() {
|
||
|
return [
|
||
|
'event_title' => 'name',
|
||
|
'event_desc' => 'description',
|
||
|
'event_organization' => 'location.name',
|
||
|
'event_street' => 'location.address.streetAddress',
|
||
|
'event_local' => 'location.address.addressLocality',
|
||
|
'event_region' => 'location.address.addressRegion',
|
||
|
'event_postal_code' => 'location.address.postalCode',
|
||
|
'event_start_date' => 'startDate',
|
||
|
'event_end_date' => 'endDate',
|
||
|
'event_price' => 'offers.price',
|
||
|
'event_cur' => 'offers.priceCurrency',
|
||
|
'event_ticket_url' => 'offers.url',
|
||
|
];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get product fields.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
private function get_product_fields() {
|
||
|
return [
|
||
|
'product_brand' => 'brand.name',
|
||
|
'product_name' => 'name',
|
||
|
'product_price' => 'offers.price',
|
||
|
'product_cur' => 'offers.priceCurrency',
|
||
|
'product_status' => 'offers.availability',
|
||
|
];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get recipe fields.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
private function get_recipe_fields() {
|
||
|
return [
|
||
|
'recipes_name' => 'name',
|
||
|
'recipes_desc' => 'description',
|
||
|
'recipes_preptime' => 'prepTime',
|
||
|
'recipes_cooktime' => 'cookTime',
|
||
|
'recipes_totaltime' => 'totalTime',
|
||
|
'recipes_ingredient' => 'recipeIngredient',
|
||
|
'recipes_nutrition' => 'nutrition.calories',
|
||
|
];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get software fields.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
private function get_software_fields() {
|
||
|
return [
|
||
|
'software_rating' => 'review.reviewRating.ratingValue',
|
||
|
'software_price' => 'offers.price',
|
||
|
'software_cur' => 'offers.priceCurrency',
|
||
|
'software_name' => 'name',
|
||
|
'software_os' => 'operatingSystem',
|
||
|
'software_cat' => 'applicationCategory',
|
||
|
];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get video fields.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
private function get_video_fields() {
|
||
|
return [
|
||
|
'video_title' => 'name',
|
||
|
'video_desc' => 'description',
|
||
|
'video_thumb' => 'thumbnailUrl',
|
||
|
'video_url' => 'contentUrl',
|
||
|
'video_emb_url' => 'embedUrl',
|
||
|
'video_duration' => 'duration',
|
||
|
];
|
||
|
}
|
||
|
}
|