Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.30% covered (success)
96.30%
52 / 54
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ContentId
96.23% covered (success)
96.23%
51 / 53
66.67% covered (warning)
66.67%
2 / 3
16
0.00% covered (danger)
0.00%
0 / 1
 init
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
3
 element
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
6
 save
89.47% covered (success)
89.47%
17 / 19
0.00% covered (danger)
0.00%
0 / 1
7.06
1<?php
2
3declare( strict_types = 1 );
4
5/**
6 * BeyondWords Component: Content ID
7 *
8 * @package BeyondWords\Editor\Components
9 * @author  Stuart McAlpine <stu@beyondwords.io>
10 * @since   6.3.0
11 * @since   7.0.0 Refactored to BeyondWords namespace with snake_case methods.
12 */
13
14namespace BeyondWords\Editor\Components;
15
16/**
17 * ContentId
18 *
19 * @since 6.3.0
20 * @since 7.0.0 Refactored to BeyondWords namespace with snake_case methods.
21 */
22defined( 'ABSPATH' ) || exit;
23
24class ContentId {
25
26    /**
27     * Init.
28     *
29     * @since 6.3.0
30     * @since 7.0.0 Refactored to BeyondWords namespace with snake_case methods.
31     */
32    public static function init() {
33        add_action(
34            'wp_loaded',
35            function (): void {
36                $post_types = \BeyondWords\Settings\Utils::get_compatible_post_types();
37
38                if ( is_array( $post_types ) ) {
39                    foreach ( $post_types as $post_type ) {
40                        add_action( "save_post_{$post_type}", [ self::class, 'save'], 10 );
41                    }
42                }
43            }
44        );
45    }
46
47    /**
48     * HTML output for this component.
49     *
50     * @since 6.3.0
51     * @since 7.0.0 Refactored to BeyondWords namespace with snake_case methods.
52     *
53     * @param \WP_Post $post The post object.
54     */
55    public static function element( $post ) {
56        $content_id       = \BeyondWords\Post\Meta::get_content_id( $post->ID ) ?: '';
57        $project_id       = \BeyondWords\Post\Meta::get_project_id( $post->ID ) ?: get_option( 'beyondwords_project_id', '' );
58        $post_type        = get_post_type( $post );
59        $post_type_object = $post_type ? get_post_type_object( $post_type ) : null;
60        $rest_base        = ( $post_type_object && ! empty( $post_type_object->rest_base ) ) ? $post_type_object->rest_base : $post_type;
61
62        wp_nonce_field( 'beyondwords_content_id', 'beyondwords_content_id_nonce' );
63        ?>
64        <div id="beyondwords-metabox-content-id" style="margin: 8px 0 13px;">
65            <p class="post-attributes-label-wrapper">
66                <label for="beyondwords_content_id" class="post-attributes-label">
67                    <?php esc_html_e( 'Content ID', 'speechkit' ); ?>
68                </label>
69            </p>
70            <div style="display: flex; gap: 4px; align-items: center;">
71                <input
72                    type="text"
73                    id="beyondwords_content_id"
74                    name="beyondwords_content_id"
75                    value="<?php echo esc_attr( $content_id ); ?>"
76                    style="flex: 1;"
77                />
78                <button
79                    type="button"
80                    id="beyondwords__content-id--fetch"
81                    class="button"
82                    data-project-id="<?php echo esc_attr( $project_id ); ?>"
83                    data-rest-base="<?php echo esc_attr( $rest_base ); ?>"
84                >
85                    <?php esc_html_e( 'Fetch', 'speechkit' ); ?>
86                </button>
87            </div>
88        </div>
89        <?php
90    }
91
92    /**
93     * Save the meta when the post is saved.
94     *
95     * @since 6.3.0
96     * @since 7.0.0 Refactored to BeyondWords namespace with snake_case methods.
97     *
98     * @param int $post_id The ID of the post being saved.
99     */
100    public static function save( $post_id ) {
101        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
102            return $post_id;
103        }
104
105        if (
106            ! isset( $_POST['beyondwords_content_id_nonce'] ) ||
107            ! wp_verify_nonce(
108                sanitize_key( $_POST['beyondwords_content_id_nonce'] ),
109                'beyondwords_content_id'
110            )
111        ) {
112            return $post_id;
113        }
114
115        if ( ! current_user_can( 'edit_post', $post_id ) ) {
116            return $post_id;
117        }
118
119        if ( isset( $_POST['beyondwords_content_id'] ) ) {
120            // Content IDs are interpolated into API URL paths, so they need a stricter
121            // charset than sanitize_text_field() — see Meta::sanitize_content_id().
122            update_post_meta(
123                $post_id,
124                'beyondwords_content_id',
125                \BeyondWords\Post\Meta::sanitize_content_id(
126                    sanitize_text_field( wp_unslash( $_POST['beyondwords_content_id'] ) )
127                )
128            );
129        }
130
131        return $post_id;
132    }
133}