Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
72.29% covered (warning)
72.29%
60 / 83
66.67% covered (warning)
66.67%
8 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
Feedback_Source
72.29% covered (warning)
72.29%
60 / 83
66.67% covered (warning)
66.67%
8 / 12
122.73
0.00% covered (danger)
0.00%
0 / 1
 __construct
86.36% covered (warning)
86.36%
19 / 22
0.00% covered (danger)
0.00%
0 / 1
13.43
 from_submission
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
5
 get_source_title
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
56
 get_current
62.50% covered (warning)
62.50%
5 / 8
0.00% covered (danger)
0.00%
0 / 1
9.58
 from_serialized
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 get_permalink
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 get_edit_form_url
69.23% covered (warning)
69.23%
9 / 13
0.00% covered (danger)
0.00%
0 / 1
19.71
 get_relative_permalink
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 get_page_number
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_title
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_id
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 serialize
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Feedback Entry
4 *
5 * @package automattic/jetpack-forms
6 */
7
8namespace Automattic\Jetpack\Forms\ContactForm;
9
10/**
11 * Class Feedback_Source
12 *
13 * Represents where a feedback was created from, feedback entry with an ID, title, permalink, and page number.
14 */
15class Feedback_Source {
16
17    /**
18     * The ID of the post or page that the feedback was created on.
19     *
20     * @var string
21     */
22    private $id = '';
23
24    /**
25     * The title of the  post or page that the feedback was created on.
26     *
27     * @var string
28     */
29    private $title = '';
30
31    /**
32     * The permalink of the feedback entry.
33     *
34     * @var string
35     */
36    private $permalink = '';
37
38    /**
39     * The page number of the feedback post or page that the feedback was created on.
40     * This is used to determine the page number in a paginated view of page or post.
41     *
42     * @var int
43     */
44    private $page_number = 1;
45
46    /**
47     * The source type of the feedback entry.
48     * Possible values: single, widget, block_template, block_template_part
49     *
50     * @var string
51     */
52    private $source_type = 'single';
53
54    /**
55     * The request URL of the feedback entry.
56     *
57     * @var string
58     */
59    private $request_url = '';
60
61    /**
62     * Constructor for Feedback_Source.
63     *
64     * @param string|int $id          The Source ID = post ID, widget ID, block template ID, or 0 for homepage or non-post/page.
65     * @param string     $title       The title of the feedback entry.
66     * @param int        $page_number The page number of the feedback entry, default is 1.
67     * @param string     $source_type The source type of the feedback entry, default is 'single'.
68     * @param string     $request_url The request URL of the feedback entry.
69     */
70    public function __construct( $id = 0, $title = '', $page_number = 1, $source_type = 'single', $request_url = '' ) {
71
72        if ( is_numeric( $id ) ) {
73            $this->id = $id > 0 ? $id : 0;
74        } else {
75            $this->id = $id;
76        }
77
78        if ( is_numeric( $page_number ) ) {
79            $this->page_number = $page_number > 0 ? $page_number : 1;
80        } else {
81            $this->page_number = 1;
82        }
83
84        $this->title       = html_entity_decode( $title, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
85        $this->permalink   = empty( $request_url ) ? home_url() : $request_url;
86        $this->source_type = $source_type; // possible source types: single, widget, block_template, block_template_part
87        $this->request_url = $request_url;
88
89        if ( is_numeric( $id ) && ! empty( $id ) ) {
90            $entry_post = get_post( (int) $id );
91            if ( $entry_post && $entry_post->post_status === 'publish' ) {
92                $this->permalink = get_permalink( $entry_post );
93                $this->title     = html_entity_decode( get_the_title( $entry_post ), ENT_QUOTES | ENT_HTML5, 'UTF-8' );
94            } elseif ( $entry_post ) {
95                $this->permalink = '';
96
97                if ( $entry_post->post_status === 'trash' ) {
98                    /* translators: %s is the post title */
99                    $this->title = sprintf( __( '(trashed) %s', 'jetpack-forms' ), $this->title );
100                }
101            }
102            if ( empty( $entry_post ) ) {
103                /* translators: %s is the post title */
104                $this->title     = sprintf( __( '(deleted) %s', 'jetpack-forms' ), $this->title );
105                $this->permalink = '';
106            }
107        }
108    }
109
110    /**
111     * Creates a Feedback_Source instance from a submission.
112     *
113     * @param \WP_Post|null $current_post The current post object.
114     * @param int           $current_page_number The current page number, default is 1.
115     * @return Feedback_Source Returns an instance of Feedback_Source.
116     */
117    public static function from_submission( $current_post, int $current_page_number = 1 ) {
118        $id = isset( $current_post->ID ) ? (int) $current_post->ID : 0;
119
120        if ( ! $current_post instanceof \WP_Post || $id === 0 ) {
121            return new self( 0, '', $current_page_number );
122        }
123
124        $title = isset( $current_post->post_title ) ? html_entity_decode( $current_post->post_title, ENT_QUOTES | ENT_HTML5, 'UTF-8' ) : __( '(no title)', 'jetpack-forms' );
125
126        return new self( $id, $title, $current_page_number );
127    }
128
129    /**
130     * Get the title of the current page. That we can then use to display in the feedback entry.
131     *
132     * @return string The title of the current page. That we want to show to the user. To tell them where the feedback was left.
133     */
134    private static function get_source_title() {
135        if ( is_front_page() ) {
136            return get_bloginfo( 'name' );
137        }
138        if ( is_home() ) {
139            return get_the_title( get_option( 'page_for_posts', true ) );
140        }
141        if ( is_singular() ) {
142            return get_the_title();
143        }
144        if ( is_archive() ) {
145            return get_the_archive_title();
146        }
147        if ( is_search() ) {
148            /* translators: %s is the search term */
149            return sprintf( __( 'Search results for: %s', 'jetpack-forms' ), get_search_query() );
150        }
151        if ( is_404() ) {
152            return __( '404 Not Found', 'jetpack-forms' );
153        }
154        return get_bloginfo( 'name' );
155    }
156
157    /**
158     * Creates a Feedback_Source instance for a block template.
159     *
160     * @param array $attributes Form Shortcode attributes.
161     *
162     * @return Feedback_Source Returns an instance of Feedback_Source.
163     */
164    public static function get_current( $attributes ) {
165        global $wp, $page;
166        $current_url = home_url( add_query_arg( array(), $wp->request ) );
167        if ( isset( $attributes['widget'] ) && ! empty( $attributes['widget'] ) ) {
168            return new self( $attributes['widget'], self::get_source_title(), 1, 'widget', $current_url );
169        }
170
171        if ( isset( $attributes['block_template'] ) && ! empty( $attributes['block_template'] ) ) {
172            global $_wp_current_template_id;
173            return new self( $_wp_current_template_id, self::get_source_title(), $page, 'block_template', $current_url );
174        }
175
176        if ( isset( $attributes['block_template_part'] ) && ! empty( $attributes['block_template_part'] ) ) {
177            return new self( $attributes['block_template_part'], self::get_source_title(), $page, 'block_template_part', $current_url );
178        }
179
180        return new Feedback_Source( \get_the_ID(), \get_the_title(), $page, 'single', $current_url );
181    }
182
183    /**
184     * Creates a Feedback_Source instance from serialized data.
185     *
186     * @param array $data The serialized data.
187     * @return Feedback_Source Returns an instance of Feedback_Source.
188     */
189    public static function from_serialized( $data ) {
190        $id          = $data['source_id'] ?? 0;
191        $title       = $data['entry_title'] ?? '';
192        $page_number = $data['entry_page'] ?? 1;
193        $source_type = $data['source_type'] ?? 'single';
194        $request_url = $data['request_url'] ?? '';
195
196        return new self( $id, $title, $page_number, $source_type, $request_url );
197    }
198
199    /**
200     * Get the permalink of the feedback entry.
201     *
202     * @return string The permalink of the feedback entry.
203     */
204    public function get_permalink() {
205        if ( $this->page_number > 1 && ! empty( $this->permalink ) ) {
206            return add_query_arg( 'page', $this->page_number, $this->permalink );
207        }
208        return wp_validate_redirect( $this->permalink, home_url() );
209    }
210
211    /**
212     * Get the edit URL of the form or page where the feedback was submitted from.
213     *
214     * @return string The edit URL of the form or page.
215     */
216    public function get_edit_form_url() {
217
218        if ( current_user_can( 'edit_theme_options' ) ) {
219            if ( $this->source_type === 'block_template' && \wp_is_block_theme() ) {
220                return admin_url( 'site-editor.php?p=' . esc_attr( '/wp_template/' . addslashes( $this->id ) ) . '&canvas=edit' );
221            }
222
223            if ( $this->source_type === 'block_template_part' && \wp_is_block_theme() ) {
224                return admin_url( 'site-editor.php?p=' . esc_attr( '/wp_template_part/' . addslashes( $this->id ) ) . '&canvas=edit' );
225            }
226
227            if ( $this->source_type === 'widget' && current_theme_supports( 'widgets' ) ) {
228                return admin_url( 'widgets.php' );
229            }
230        }
231
232        if ( $this->id && is_numeric( $this->id ) && $this->id > 0 && current_user_can( 'edit_post', (int) $this->id ) ) {
233            $entry_post = get_post( (int) $this->id );
234            if ( $entry_post && $entry_post->post_status === 'trash' ) {
235                return ''; // No edit link is possible for trashed posts. They need to be restored first.
236            }
237            return \get_edit_post_link( (int) $this->id, 'url' );
238        }
239
240        return '';
241    }
242
243    /**
244     * Get the relative permalink of the feedback entry.
245     *
246     * @return string The relative permalink of the feedback entry.
247     */
248    public function get_relative_permalink() {
249        if ( ! empty( $this->permalink ) ) {
250            return wp_make_link_relative( $this->get_permalink() );
251        }
252        return '';
253    }
254
255    /**
256     * Get the page number of the feedback entry.
257     *
258     * @return int The page number of the feedback entry.
259     */
260    public function get_page_number() {
261        return $this->page_number;
262    }
263    /**
264     * Get the title of the feedback entry.
265     *
266     * @return string The title of the feedback entry.
267     */
268    public function get_title() {
269        return $this->title;
270    }
271    /**
272     * Get the post id of the feedback entry.
273     *
274     * @return int|string The ID of the feedback entry.
275     */
276    public function get_id() {
277        return $this->id;
278    }
279
280    /**
281     * Get the page number of the entry title.
282     *
283     * @return array
284     */
285    public function serialize() {
286        return array(
287            'entry_title' => $this->title,
288            'entry_page'  => $this->page_number,
289            'source_id'   => $this->id,
290            'source_type' => $this->source_type,
291            'request_url' => $this->request_url,
292        );
293    }
294}