Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
73.68% covered (warning)
73.68%
42 / 57
28.57% covered (danger)
28.57%
2 / 7
CRAP
n/a
0 / 0
wpcomsh_insert_shared_post_data
93.75% covered (success)
93.75%
30 / 32
0.00% covered (danger)
0.00%
0 / 1
8.02
wpcomsh_get_shared_post_arg
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
3
wpcomsh_get_embed_content
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
wpcomsh_get_image_content
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
wpcomsh_get_text_content
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
wpcomsh_filter_title
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
wpcomsh_filter_content
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Adds fallback behavior for non-Gutenframed sites to be able to use the 'Share Post' functionality from WPCOM Reader.
4 *
5 * @package share-post
6 */
7
8/**
9 * Saves shared post data.
10 *
11 * @param int      $target_post_id Post ID.
12 * @param ?WP_Post $post           Post object.
13 * @param bool     $update         Whether this is an update.
14 *
15 * @return int|void|WP_Error
16 */
17function wpcomsh_insert_shared_post_data( $target_post_id, $post = null, $update = false ) {
18
19    // There are cases when plugins trigger insert hooks without arguments, we just return in this case.
20    if ( null === $post ) {
21        return $target_post_id;
22    }
23
24    // This `$update` check avoids infinite loops of trying to update our updated post.
25    if ( $update ) {
26        return;
27    }
28
29    // Abort this function if we are not in a post sharing context.
30    $is_post_share = isset( $_GET['is_post_share'] ) && $_GET['is_post_share']; // phpcs:ignore WordPress.Security
31    if ( ! $is_post_share ) {
32        return;
33    }
34
35    $title   = wpcomsh_get_shared_post_arg( 'title' );
36    $image   = wpcomsh_get_shared_post_arg( 'image' );
37    $text    = wpcomsh_get_shared_post_arg( 'text' );
38    $url     = wpcomsh_get_shared_post_arg( 'url' );
39    $embed   = strtok( wpcomsh_get_shared_post_arg( 'embed' ), '?' );
40    $link    = sprintf(
41        '<a href="%1$s">%2$s</a>',
42        esc_url( $url ),
43        sanitize_text_field( $title )
44    );
45    $content = '';
46
47    if ( $embed ) {
48        $content .= wpcomsh_get_embed_content( $embed );
49    }
50
51    if ( $image ) {
52        $content .= wpcomsh_get_image_content( $image, $text, $link );
53    }
54
55    if ( $text ) {
56        $content .= wpcomsh_get_text_content( $text, $link );
57    }
58
59    $data = array(
60        'ID'           => $target_post_id,
61        'post_title'   => $title,
62        'post_content' => $content,
63    );
64
65    // Required to satisfy get_default_post_to_edit(), which has these filters after post creation.
66    add_filter( 'default_title', 'wpcomsh_filter_title', 10, 2 );
67    add_filter( 'default_content', 'wpcomsh_filter_content', 10, 2 );
68
69    return wp_update_post( wp_slash( $data ) );
70}
71add_action( 'wp_insert_post', 'wpcomsh_insert_shared_post_data', 10, 3 );
72
73/**
74 * Get an argument from the share link.
75 *
76 * @param string $key Query argument name.
77 * @return string Unslashed, unescaped value, or an empty string when absent.
78 */
79function wpcomsh_get_shared_post_arg( $key ) {
80    // phpcs:ignore WordPress.Security -- Values are escaped where they are used.
81    return isset( $_GET[ $key ] ) && is_string( $_GET[ $key ] ) ? wp_unslash( $_GET[ $key ] ) : '';
82}
83
84/**
85 * Generate the embed content for our sharing post.
86 *
87 * @param string $embed URL of our embed.
88 * @return string Generated content for the sharing post.
89 */
90function wpcomsh_get_embed_content( $embed ) {
91    $url = esc_url_raw( wp_check_invalid_utf8( $embed ) );
92    if ( '' === $url ) {
93        return '';
94    }
95
96    // Matches the core/embed block's save() output, so the editor validates it.
97    return get_comment_delimited_block_content(
98        'core/embed',
99        array( 'url' => $url ),
100        sprintf(
101            '<figure class="wp-block-embed"><div class="wp-block-embed__wrapper">%s</div></figure>',
102            "\n" . htmlspecialchars( $url, ENT_QUOTES, 'UTF-8', true ) . "\n"
103        )
104    );
105}
106
107/**
108 * Generate the image content for our sharing post.
109 *
110 * @param string $image URL of our image.
111 * @param string $text  Content of the shared post.
112 * @param string $link  Permalink to the shared post.
113 * @return string Generated content for the sharing post.
114 */
115function wpcomsh_get_image_content( $image, $text, $link ) {
116    return sprintf(
117        '<!-- wp:image --><figure class="wp-block-image"><img src="%1$s" alt=""/>%2$s</figure><!-- /wp:image -->',
118        esc_url( $image ),
119        empty( $text ) ? '<figcaption>' . $link . '</figcaption>' : null // $link is escaped on initialization
120    );
121}
122
123/**
124 * Generate the text content for our sharing post.
125 *
126 * @param string $text Content of the shared post.
127 * @param string $link Permalink to the shared post.
128 * @return string Generated content for the sharing post.
129 */
130function wpcomsh_get_text_content( $text, $link ) {
131    return sprintf(
132        '<!-- wp:quote --><blockquote class="wp-block-quote"><p>%1$s</p><cite>%2$s</cite></blockquote><!-- /wp:quote -->',
133        wp_kses_post( $text ),
134        $link // Escaped on initialization.
135    );
136}
137
138/**
139 * Update the target post's title.
140 *
141 * @param string  $post_title Post title determined by `get_default_post_to_edit()`.
142 * @param WP_Post $post       Post object of newly-inserted post.
143 * @return string Updated post title from source post.
144 */
145function wpcomsh_filter_title( $post_title, $post ) {
146    return $post->post_title;
147}
148
149/**
150 * Update the target post's content (`post_content`).
151 *
152 * @param string  $post_content Post content determined by `get_default_post_to_edit()`.
153 * @param WP_Post $post         Post object of newly-inserted post.
154 * @return string Updated post content from source post.
155 */
156function wpcomsh_filter_content( $post_content, $post ) {
157    return $post->post_content;
158}