'defer', 'in_footer' => true, ) ); add_shortcode( '3task_review_box', array( __CLASS__, 'shortcode_box' ) ); add_shortcode( '3task_review_score', array( __CLASS__, 'shortcode_score' ) ); add_shortcode( '3task_review_summary', array( __CLASS__, 'shortcode_summary' ) ); self::bridge(); add_shortcode( '3task_review_toplist', array( __CLASS__, 'shortcode_toplist' ) ); add_shortcode( '3task_review_reviewers', array( __CLASS__, 'shortcode_reviewers' ) ); if ( function_exists( 'register_block_type' ) ) { register_block_type( THREERB_DIR . 'blocks/box', array( 'render_callback' => array( __CLASS__, 'render_block' ) ) ); register_block_type( THREERB_DIR . 'blocks/summary', array( 'render_callback' => array( __CLASS__, 'render_summary' ) ) ); register_block_type( THREERB_DIR . 'blocks/score', array( 'render_callback' => array( __CLASS__, 'render_score' ) ) ); register_block_type( THREERB_DIR . 'blocks/toplist', array( 'render_callback' => array( __CLASS__, 'render_toplist' ) ) ); register_block_type( THREERB_DIR . 'blocks/reviewers', array( 'render_callback' => array( __CLASS__, 'render_reviewers' ) ) ); } } /** * Shortcode [3task_review_box id="" kompakt display="" style=""]. * * @param array|string $atts Attribute. * @return string */ public static function shortcode_box( $atts ) { $atts = is_array( $atts ) ? $atts : array(); $kompakt = in_array( 'kompakt', $atts, true ) || in_array( 'compact', $atts, true ); $a = shortcode_atts( array( 'id' => '', 'display' => '', 'style' => '', ), $atts, '3task_review_box' ); $id = self::post_id( $a['id'] ); if ( ! $id ) { return ''; } return ThreeRB_Render::box( $id, array( 'variant' => $kompakt ? 'compact' : 'full', 'display' => sanitize_key( $a['display'] ), 'style' => sanitize_key( $a['style'] ), ) ); } /** * Shortcode [3task_review_score id=""]. * * @param array|string $atts Attribute. * @return string */ public static function shortcode_score( $atts ) { $a = shortcode_atts( array( 'id' => '' ), is_array( $atts ) ? $atts : array(), '3task_review_score' ); $id = self::post_id( $a['id'] ); return $id ? ThreeRB_Render::score( $id ) : ''; } /** * Shortcode [3task_review_summary id=""]. * * @param array|string $atts Attribute. * @return string */ public static function shortcode_summary( $atts ) { $a = shortcode_atts( array( 'id' => '' ), is_array( $atts ) ? $atts : array(), '3task_review_summary' ); $id = self::post_id( $a['id'] ); return $id ? ThreeRB_Render::summary( $id ) : ''; } /** * Brücke nach dem Umzug: alte WP-Review-Shortcodes zeigen unsere Box. Nur, solange WP Review aus ist. */ public static function bridge() { if ( ThreeRB_Migrate::wp_review_active() ) { return; } foreach ( array( 'wp-review', 'wp_review' ) as $name ) { if ( ! shortcode_exists( $name ) ) { add_shortcode( $name, array( __CLASS__, 'bridge_box' ) ); } } foreach ( array( 'wp-review-total', 'wp_review_total' ) as $name ) { if ( ! shortcode_exists( $name ) ) { add_shortcode( $name, array( __CLASS__, 'shortcode_score' ) ); } } foreach ( array( 'wp-review-visitor-rating', 'wp_review_visitor_rating' ) as $name ) { if ( ! shortcode_exists( $name ) ) { add_shortcode( $name, '__return_empty_string' ); } } } /** * [wp-review id=""] zeigt die volle Box. * * @param array|string $atts Attribute. * @return string */ public static function bridge_box( $atts ) { $a = shortcode_atts( array( 'id' => '' ), is_array( $atts ) ? $atts : array(), 'wp-review' ); $id = self::post_id( $a['id'] ); return $id ? ThreeRB_Render::box( $id ) : ''; } /** * Shortcode [3task_review_toplist count="5" type="post" category=""]. * * @param array|string $atts Attribute. * @return string */ public static function shortcode_toplist( $atts ) { $a = shortcode_atts( array( 'count' => '5', 'type' => 'post', 'category' => '', 'tag' => '', 'order' => 'desc', 'criterion' => '', 'display' => 'list', 'stars' => '', 'paged' => '', ), is_array( $atts ) ? $atts : array(), '3task_review_toplist' ); return ThreeRB_Render::toplist( array( 'count' => ctype_digit( (string) $a['count'] ) ? (int) $a['count'] : 5, 'postType' => sanitize_key( $a['type'] ), 'term' => ctype_digit( (string) $a['category'] ) ? (int) $a['category'] : 0, 'tag' => ctype_digit( (string) $a['tag'] ) ? (int) $a['tag'] : 0, 'order' => sanitize_key( $a['order'] ), 'criterion' => $a['criterion'], 'display' => sanitize_key( $a['display'] ), 'stars' => $a['stars'], 'paged' => $a['paged'], ) ); } /** * Shortcode [3task_review_reviewers count="5"]. * * @param array|string $atts Attribute. * @return string */ public static function shortcode_reviewers( $atts ) { $a = shortcode_atts( array( 'count' => '5' ), is_array( $atts ) ? $atts : array(), '3task_review_reviewers' ); return ThreeRB_Render::reviewers( array( 'count' => ctype_digit( (string) $a['count'] ) ? (int) $a['count'] : 5 ) ); } /** * Block threerb/summary. * * @param array $attrs Attribute. * @param string $content Inhalt. * @param WP_Block $block Block mit Kontext. * @return string */ public static function render_summary( $attrs, $content = '', $block = null ) { $id = self::block_post( $attrs, $block ); return $id ? ThreeRB_Render::summary( $id ) : ''; } /** * Block threerb/score (Query-Loop). * * @param array $attrs Attribute. * @param string $content Inhalt. * @param WP_Block $block Block mit Kontext. * @return string */ public static function render_score( $attrs, $content = '', $block = null ) { $id = self::block_post( $attrs, $block ); return $id ? ThreeRB_Render::score( $id ) : ''; } /** * Block threerb/toplist. * * @param array $attrs Attribute. * @return string */ public static function render_toplist( $attrs ) { return ThreeRB_Render::toplist( array( 'count' => isset( $attrs['count'] ) ? (int) $attrs['count'] : 5, 'postType' => isset( $attrs['postType'] ) ? sanitize_key( (string) $attrs['postType'] ) : 'post', 'term' => isset( $attrs['term'] ) ? absint( $attrs['term'] ) : 0, 'tag' => isset( $attrs['tag'] ) ? absint( $attrs['tag'] ) : 0, 'order' => isset( $attrs['order'] ) ? (string) $attrs['order'] : 'desc', 'criterion' => isset( $attrs['criterion'] ) ? (string) $attrs['criterion'] : '', 'display' => isset( $attrs['display'] ) ? (string) $attrs['display'] : 'list', 'stars' => ! empty( $attrs['stars'] ), 'paged' => ! empty( $attrs['paged'] ), ) ); } /** * Block threerb/reviewers. * * @param array $attrs Attribute. * @return string */ public static function render_reviewers( $attrs ) { return ThreeRB_Render::reviewers( array( 'count' => isset( $attrs['count'] ) ? (int) $attrs['count'] : 5 ) ); } /** * Beitrag eines Blocks: Attribut, dann Block-Kontext, dann aktueller Beitrag. * * @param array $attrs Attribute. * @param WP_Block $block Block. * @return int */ private static function block_post( $attrs, $block ) { $id = isset( $attrs['postId'] ) ? absint( $attrs['postId'] ) : 0; if ( ! $id && $block instanceof WP_Block && isset( $block->context['postId'] ) ) { $id = absint( $block->context['postId'] ); } return $id ? $id : (int) get_the_ID(); } /** * Block threerb/box. * * @param array $attrs Attribute laut block.json. * @param string $content Inhalt. * @param WP_Block $block Block mit Kontext. * @return string */ public static function render_block( $attrs, $content = '', $block = null ) { $id = isset( $attrs['postId'] ) ? absint( $attrs['postId'] ) : 0; if ( ! $id && $block instanceof WP_Block && isset( $block->context['postId'] ) ) { $id = absint( $block->context['postId'] ); } if ( ! $id ) { $id = (int) get_the_ID(); } if ( ! $id ) { return ''; } $variante = isset( $attrs['variant'] ) && in_array( $attrs['variant'], array( 'full', 'compact', 'summary', 'score' ), true ) ? $attrs['variant'] : 'compact'; if ( 'summary' === $variante ) { return ThreeRB_Render::summary( $id ); } if ( 'score' === $variante ) { return ThreeRB_Render::score( $id ); } return ThreeRB_Render::box( $id, array( 'variant' => $variante, 'display' => isset( $attrs['display'] ) ? sanitize_key( $attrs['display'] ) : '', 'style' => isset( $attrs['style'] ) ? sanitize_key( $attrs['style'] ) : '', ) ); } /** * Platzierung im Beitrag: oben Kurzurteil, unten volle Box (nicht doppelt). * * @param string $content Inhalt. * @return string */ public static function place( $content ) { if ( ! is_singular() || ! in_the_loop() || ! is_main_query() ) { return $content; } $id = (int) get_the_ID(); if ( (int) get_queried_object_id() !== $id ) { return $content; } $box = ThreeRB_Box::get( $id ); if ( ! ThreeRB_Box::has_rating( $box ) || ! ThreeRB_Render::visible( $id ) ) { return $content; } $oben = $box['place']['top'] ? ThreeRB_Render::summary( $id ) : ''; $unten = ( $box['place']['bottom'] && false === strpos( $content, 'data-trb-full' ) ) ? ThreeRB_Render::box( $id ) : ''; return $oben . $content . $unten; } /** * Beiträge, deren Review schon im Graph eines SEO-Plugins steht. * * @var array */ private static $graph = array(); /** * Merker für den Graph zurücksetzen (neue Seite, Prüfläufe). */ public static function reset_graph() { self::$graph = array(); } /** * JSON-LD im Kopf auf Einzelseiten, außer Rank Math oder Yoast haben den Knoten schon übernommen. * Beide schreiben ihr Schema an wp_head mit Priorität 1, wir kommen mit 30 danach. */ public static function head() { if ( ! is_singular() ) { return; } $id = (int) get_queried_object_id(); if ( ! empty( self::$graph[ $id ] ) ) { return; } $json = self::jsonld( $id ); if ( '' !== $json ) { echo $json . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JSON mit JSON_HEX_TAG, siehe ThreeRB_Schema::encode(). } } /** * Rank Math: Review in dessen Graph einhängen. * * @param array $data Entitäten von Rank Math. * @param mixed $jsonld Rank-Math-Objekt. * @return array */ public static function rank_math( $data, $jsonld = null ) { $knoten = self::graph_node(); if ( null === $knoten || ! is_array( $data ) ) { return $data; } $data['threerbReview'] = $knoten; return $data; } /** * Yoast SEO: Review als Baustein an den Graph anhängen. * * @param array $graph Graph-Bausteine. * @param mixed $context Yoast-Kontext. * @return array */ public static function yoast( $graph, $context = null ) { $knoten = self::graph_node(); if ( null === $knoten || ! is_array( $graph ) ) { return $graph; } $graph[] = $knoten; return $graph; } /** * Knoten der aktuellen Einzelseite für einen fremden Graph, oder null. * * @return array|null */ private static function graph_node() { if ( ! is_singular() ) { return null; } $id = (int) get_queried_object_id(); $knoten = self::node( $id ); if ( null === $knoten ) { return null; } unset( $knoten['@context'] ); $url = get_permalink( $id ); $knoten['@id'] = $url . '#threerb-item'; $knoten['mainEntityOfPage'] = array( '@id' => $url . '#webpage' ); self::$graph[ $id ] = true; return $knoten; } /** * Script-Element mit dem Schema eines Beitrags, oder leer. * * @param int $post_id Beitrag. * @return string */ public static function jsonld( $post_id ) { $knoten = self::node( $post_id ); if ( null === $knoten ) { return ''; } return ''; } /** * Schema-Knoten eines Beitrags nach dem Filter threerb_schema, oder null. * * @param int $post_id Beitrag. * @return array|null */ public static function node( $post_id ) { if ( ! ThreeRB_Render::is_public( $post_id ) ) { return null; } $box = ThreeRB_Box::get( $post_id ); if ( ! $box ) { return null; } $post = get_post( $post_id ); if ( 'organization' === ThreeRB_Settings::value( 'author' ) ) { $autor = array( 'type' => 'Organization', 'name' => get_bloginfo( 'name' ), 'url' => home_url( '/' ), ); } else { $nutzer = get_userdata( (int) $post->post_author ); $autor = $nutzer ? array( 'type' => 'Person', 'name' => $nutzer->display_name, 'url' => get_author_posts_url( $nutzer->ID ), ) : array( 'type' => 'Organization', 'name' => get_bloginfo( 'name' ), 'url' => home_url( '/' ), ); } $knoten = ThreeRB_Schema::build( $box, array( 'date' => get_the_date( 'Y-m-d', $post ), 'site_name' => get_bloginfo( 'name' ), 'author' => $autor, ) ); /** * Schema-Knoten vor der Ausgabe ändern oder mit null abschalten. * * @param array|null $knoten Knoten. * @param int $post_id Beitrag. */ $knoten = apply_filters( 'threerb_schema', $knoten, $post_id ); return is_array( $knoten ) ? $knoten : null; } /** * CSS früh laden, wenn der Beitrag eine Box hat (vermeidet Springen beim Laden). */ public static function early_assets() { if ( is_singular() && ThreeRB_Box::has_rating( ThreeRB_Box::get( (int) get_queried_object_id() ) ) ) { wp_enqueue_style( 'threerb-box' ); } } /** * Beitrags-ID aus Attribut oder aktueller Beitrag. * * @param mixed $wert Attribut. * @return int */ private static function post_id( $wert ) { $wert = trim( (string) $wert ); if ( '' === $wert ) { return (int) get_the_ID(); } return ctype_digit( $wert ) ? (int) $wert : 0; } }