styles[] = $current_style; } wp_send_json( $styles ); } add_action( 'wp_ajax_get_style_json', __NAMESPACE__ . '\get_style_json' ); /** * AJAX Method for getting metadata from other websites for citations. */ function get_website_meta() { if ( ! extension_loaded( 'dom' ) || ! extension_loaded( 'libxml' ) ) { wp_send_json_error( [], 501 ); exit; } check_ajax_referer( 'abt-ajax' ); if ( ! isset( $_POST['url'] ) ) { wp_send_json_error( [], 400 ); } $url = esc_url_raw( wp_unslash( $_POST['url'] ) ); $raw = wp_remote_retrieve_body( wp_safe_remote_get( $url ) ); $html = new \DOMDocument(); libxml_use_internal_errors( true ); $html->loadHTML( $raw ); $xpath = new \DOMXPath( $html ); $payload = [ 'article' => [], 'authors' => [], 'og' => [], 'sailthru' => [], ]; /** * Stray Meta "name" Tags. */ $authors = $xpath->query( '//meta[ @name="author" ]' ); foreach ( $authors as $node ) { $a = explode( ' ', sanitize_text_field( $node->getAttribute( 'content' ) ), 2 ); $a = [ 'given' => $a[0], 'family' => $a[1], ]; if ( ! is_int( array_search( $a, $payload['authors'], true ) ) ) { $payload['authors'][] = $a; } } $issued = $xpath->query( '//meta[ @name="pubdate" ]' )->item( 0 ); if ( $issued ) { $payload['issued'] = sanitize_text_field( $issued->getAttribute( 'content' ) ); } /** * Open Graph Tags. */ $opengraph = $xpath->query( '//meta[ starts-with( @property, "og:" ) ]' ); foreach ( $opengraph as $node ) { $expl = explode( ':', $node->getAttribute( 'property' ), 2 ); $key = sanitize_key( str_replace( ':', '_', $expl[1] ) ); $value = sanitize_text_field( $node->getAttribute( 'content' ) ); $payload['og'][ $key ] = $value; } /** * Article Tags. */ $article = $xpath->query( '//meta[ starts-with( @property, "article:" ) ]' ); foreach ( $article as $node ) { $expl = explode( ':', $node->getAttribute( 'property' ), 2 ); $key = sanitize_key( $expl[1] ); $value = sanitize_text_field( $node->getAttribute( 'content' ) ); $payload['article'][ $key ] = $value; } /** * Sailthru Tags. */ $sailthru = $xpath->query( '//meta[ starts-with( @name, "sailthru" ) ]' ); foreach ( $sailthru as $node ) { $expl = explode( '.', $node->getAttribute( 'name' ), 2 ); $key = sanitize_key( $expl[1] ); $value = sanitize_text_field( $node->getAttribute( 'content' ) ); if ( 'author' === $key ) { if ( strlen( $value ) > 50 ) { continue; } $a = explode( ' ', $value, 2 ); $a = [ 'given' => $a[0], 'family' => $a[1], ]; if ( ! is_int( array_search( $a, $payload['authors'], true ) ) ) { $payload['authors'][] = $a; } continue; } $payload['sailthru'][ $key ] = $value; } /** * Itemprop Tags. */ $issued = $xpath->query( '//*[ @itemprop="datePublished" ]' )->item( 0 ); if ( $issued ) { if ( $issued->hasAttribute( 'datetime' ) ) { $payload['issued'] = esc_attr( $issued->getAttribute( 'datetime' ) ); } elseif ( $issued->hasAttribute( 'content' ) ) { $payload['issued'] = esc_attr( $issued->getAttribute( 'content' ) ); } } $authors = $xpath->query( '//*[ @itemprop="author" ][ not( ancestor::*[ @itemtype="http://schema.org/Comment" ] ) ]' ); foreach ( $authors as $author ) { if ( $author->nodeName === 'meta' ) { continue; } $a = explode( ' ', sanitize_text_field( $author->textContent ), 2 ); $a = [ 'given' => $a[0], 'family' => $a[1], ]; if ( ! is_int( array_search( $a, $payload['authors'], true ) ) ) { $payload['authors'][] = $a; } } $title = $xpath->query( '//*[ @itemprop="headline" ]' )->item( 0 ); if ( $title ) { $payload['title'] = sanitize_text_field( $title->textContent ); } /** * ABT Tags. */ $abt = $xpath->query( '//meta[ starts-with( @property, "abt:" ) ]' ); foreach ( $abt as $node ) { $expl = explode( ':', $node->getAttribute( 'property' ), 2 ); $key = sanitize_key( $expl[1] ); $value = sanitize_text_field( $node->getAttribute( 'content' ) ); if ( 'author' === $key ) { $a = explode( '|', $value, 2 ); $a = [ 'given' => $a[0], 'family' => $a[1], ]; if ( ! is_int( array_search( $a, $payload['authors'], true ) ) ) { $payload['authors'][] = $a; } } } // Last ditch effort to get a title of the site. if ( ! $payload['title'] ) { $title = $xpath->query( '/html/head/title' )->item( 0 ); if ( $title ) { $payload['title'] = sanitize_text_field( $title->textContent ); } } wp_send_json( $payload ); } add_action( 'wp_ajax_get_website_meta', __NAMESPACE__ . '\get_website_meta' ); /** * Custom API to update _abt_state meta since current WordPress APIs are broken. */ function update_abt_state() { check_ajax_referer( 'abt-ajax' ); if ( ! isset( $_POST['state'], $_POST['post_id'] ) ) { wp_send_json_error( 'required fields not sent', 400 ); } $post_id = intval( $_POST['post_id'] ); $state = json_decode( wp_unslash( $_POST['state'] ) ); // phpcs:ignore if ( is_null( $state ) ) { wp_send_json_error( 'state is null', 400 ); } $updated = update_post_meta( $post_id, '_abt_state', wp_slash( wp_json_encode( $state ) ) ); wp_send_json_success( $state ); } add_action( 'wp_ajax_update_abt_state', __NAMESPACE__ . '\update_abt_state' );