Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
66.67% covered (warning)
66.67%
24 / 36
78.57% covered (warning)
78.57%
11 / 14
CRAP
0.00% covered (danger)
0.00%
0 / 1
Jetpack_Forms
66.67% covered (warning)
66.67%
24 / 36
78.57% covered (warning)
78.57%
11 / 14
48.15
0.00% covered (danger)
0.00%
0 / 1
 load_contact_form
84.62% covered (warning)
84.62%
11 / 13
0.00% covered (danger)
0.00%
0 / 1
6.13
 plugin_url
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 assets_url
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 is_feedback_dashboard_enabled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 is_legacy_menu_item_retired
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 is_mailpoet_enabled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 is_hostinger_reach_enabled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 is_integrations_enabled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 is_conditional_logic_enabled
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 is_webhooks_enabled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 should_honor_content_destinations
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
30
 show_dashboard_integrations
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 show_block_integrations
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 show_integration_icons
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Package description here
4 *
5 * @package automattic/jetpack-forms
6 */
7
8namespace Automattic\Jetpack\Forms;
9
10use Automattic\Jetpack\Current_Plan;
11use Automattic\Jetpack\Forms\ContactForm\Feedback_Source;
12use Automattic\Jetpack\Forms\ContactForm\Util;
13use Automattic\Jetpack\Forms\Dashboard\Dashboard;
14/**
15 * Understands the Jetpack Forms package.
16 */
17class Jetpack_Forms {
18
19    const PACKAGE_VERSION = '8.3.8';
20
21    /**
22     * Plan feature slug gating field conditional logic.
23     */
24    const CONDITIONAL_LOGIC_FEATURE = 'form-conditional-logic';
25
26    /**
27     * Load the contact form module.
28     */
29    public static function load_contact_form() {
30        Util::init();
31
32        if ( self::is_feedback_dashboard_enabled() ) {
33            $dashboard = new Dashboard();
34            $dashboard->init();
35        }
36
37        if ( is_admin() && apply_filters_deprecated( 'tmp_grunion_allow_editor_view', array( true ), '0.30.5', '', 'This functionality will be removed in an upcoming version.' ) ) {
38            add_action( 'current_screen', '\Automattic\Jetpack\Forms\ContactForm\Editor_View::add_hooks' );
39        }
40
41        add_action( 'init', '\Automattic\Jetpack\Forms\ContactForm\Util::register_pattern' );
42
43        // Add hook to delete file attachments when a feedback post is deleted
44        add_action( 'before_delete_post', array( '\Automattic\Jetpack\Forms\ContactForm\Contact_Form', 'delete_feedback_files' ) );
45
46        // Invalidate the source post IDs cache when a feedback post is permanently deleted.
47        add_action( 'deleted_post', array( '\Automattic\Jetpack\Forms\ContactForm\Feedback', 'invalidate_source_ids_cache_on_delete' ), 10, 2 );
48
49        // Enforces the availability of block support controls in the UI for classic themes.
50        add_filter( 'wp_theme_json_data_default', array( '\Automattic\Jetpack\Forms\ContactForm\Contact_Form', 'add_theme_json_data_for_classic_themes' ) );
51
52        // Initialize abilities registration for WordPress Abilities API (WP 6.9+)
53        \Automattic\Jetpack\Forms\Abilities\Forms_Abilities::init();
54
55        if ( defined( 'WP_CLI' ) && \WP_CLI ) {
56            \WP_CLI::add_command( 'jetpack-forms', CLI::class );
57        }
58    }
59
60    /**
61     * Get the plugin URL.
62     */
63    public static function plugin_url() {
64        return plugin_dir_url( __FILE__ );
65    }
66
67    /**
68     * Get the assets URL.
69     */
70    public static function assets_url() {
71        return plugin_dir_url( __DIR__ ) . 'assets';
72    }
73
74    /**
75     * Returns true if the feedback dashboard is enabled.
76     *
77     * @return boolean
78     */
79    public static function is_feedback_dashboard_enabled() {
80        /**
81         * Enable the Jetpack Forms dashboard.
82         *
83         * Returning false hides the Forms admin menu entry and skips the dashboard
84         * entirely. Unrelated to which dashboard renders — there is only one.
85         *
86         * @module contact-form
87         * @since 0.3.0
88         *
89         * @param bool $enabled Should the Jetpack Forms dashboard be enabled? Default true.
90         */
91        return apply_filters( 'jetpack_forms_dashboard_enable', true );
92    }
93
94    /**
95     * Returns true if the legacy menu item is retired.
96     *
97     * @return boolean
98     */
99    public static function is_legacy_menu_item_retired() {
100        return apply_filters( 'jetpack_forms_retire_legacy_menu_item', true );
101    }
102
103    /**
104     * Returns true if MailPoet integration is enabled.
105     *
106     * @return boolean
107     */
108    public static function is_mailpoet_enabled() {
109        /**
110         * Enable MailPoet integration.
111         *
112         * @param bool false Whether MailPoet integration be enabled. Default is false.
113         */
114        return apply_filters( 'jetpack_forms_mailpoet_enable', true );
115    }
116
117    /**
118     * Returns true if Hostinger Reach integration is enabled.
119     *
120     * @return boolean
121     */
122    public static function is_hostinger_reach_enabled() {
123        /**
124         * Enable Hostinger Reach integration.
125         *
126         * @param bool false Whether Hostinger Reach integration be enabled. Default is false.
127         */
128        return apply_filters( 'jetpack_forms_hostinger_reach_enable', false );
129    }
130
131    /**
132     * Returns true if the Integrations UI should be enabled.
133     *
134     * @return boolean
135     */
136    public static function is_integrations_enabled() {
137        /**
138         * Whether to enable the Integrations UI.
139         *
140         * @param bool true Whether to enable the Integrations UI. Default true.
141         */
142        return apply_filters( 'jetpack_forms_is_integrations_enabled', true );
143    }
144
145    /**
146     * Returns true if the site's plan includes field conditional logic.
147     *
148     * One switch for the whole feature: the editor panel, the front-end show/hide, and the
149     * submission-time enforcement in validation and storage. Gating them together means a
150     * form can never hide a field from the visitor while still requiring it on submit.
151     *
152     * Losing the plan on a form that already has conditions is safe: the conditions are
153     * simply ignored, so every field renders, validates and stores as an ordinary field.
154     *
155     * @return boolean
156     */
157    public static function is_conditional_logic_enabled() {
158        // Fail closed on WordPress.com until its WPCOM_Features copy knows the slug, or supports()
159        // falls back to the Jetpack free plan, which includes it. Drop once that copy ships.
160        $supported = ( ! function_exists( 'wpcom_feature_exists' ) || wpcom_feature_exists( self::CONDITIONAL_LOGIC_FEATURE ) )
161            && Current_Plan::supports( self::CONDITIONAL_LOGIC_FEATURE );
162
163        /**
164         * Whether field conditional logic is available on this site.
165         *
166         * @since 8.3.0
167         *
168         * @param bool $supported Whether the site's plan includes conditional logic.
169         */
170        return (bool) apply_filters( 'jetpack_forms_conditional_logic_enabled', $supported );
171    }
172
173    /**
174     * Returns true if webhooks are enabled.
175     *
176     * @return boolean
177     */
178    public static function is_webhooks_enabled() {
179        /**
180         * Whether to enable webhooks for Jetpack Forms.
181         *
182         * @param bool true Whether webhooks should be enabled. Default true.
183         */
184        return apply_filters( 'jetpack_forms_webhooks_enabled', true );
185    }
186
187    /**
188     * Whether author-configured outbound destinations from a form source should be honored.
189     *
190     * Destinations declared in the form content (webhooks, the legacy postToUrl attribute and
191     * the Salesforce integration) carry submission data to an outbound URL, so they are only
192     * honored when whoever placed the form had an administrator-level capability:
193     *
194     * - For post/page forms (`single`, numeric source id) the source post's author must have
195     *   the `manage_options` capability. Editor/Author/Contributor-authored forms are dropped.
196     * - For block templates, block template parts and widgets the source id is not a numeric
197     *   post, so there is no author to check. Editing any of those surfaces already requires
198     *   the `edit_theme_options` capability — administrator-tier, strictly above the
199     *   capabilities an Editor/Author/Contributor holds — so their destinations are trusted.
200     *
201     * The source type is established server-side (from the signed JWT, or by re-rendering the
202     * real template/template part on the legacy path) and is not forgeable by the submitter.
203     *
204     * Returns false for any other unresolved source (non-numeric id of an unknown type, or a
205     * numeric id with no admin-capable author).
206     *
207     * @param int|string $source_id   The form source id: a post id for post/page forms, or a
208     *                                non-numeric value for widget or block-template sources.
209     * @param string     $source_type The form source type: single, widget, block_template or
210     *                                block_template_part. Defaults to 'single'.
211     * @return boolean
212     */
213    public static function should_honor_content_destinations( $source_id, $source_type = 'single' ) {
214        // Block templates, template parts and widgets can only be authored by users with the
215        // administrator-tier `edit_theme_options` capability, so their destinations are trusted
216        // even though the source id is not a numeric post.
217        if ( in_array( $source_type, Feedback_Source::ADMIN_TIER_SOURCE_TYPES, true ) ) {
218            return true;
219        }
220
221        if ( ! is_numeric( $source_id ) ) {
222            return false;
223        }
224
225        $source_id = (int) $source_id;
226        if ( $source_id <= 0 ) {
227            return false;
228        }
229
230        $author_id = (int) get_post_field( 'post_author', $source_id );
231
232        return $author_id > 0 && user_can( $author_id, 'manage_options' );
233    }
234
235    /**
236     * Returns true if the Integrations UI should be shown in the Forms dashboard.
237     *
238     * @since 6.22.0
239     *
240     * @return boolean
241     */
242    public static function show_dashboard_integrations() {
243        /**
244         * Whether to show Integrations UI in the Forms dashboard.
245         *
246         * @since 6.22.0
247         *
248         * @param bool true Whether to show the Integrations UI in the dashboard. Default true.
249         */
250        return apply_filters( 'jetpack_forms_show_dashboard_integrations', true );
251    }
252
253    /**
254     * Returns true if the Integrations UI should be shown in the Form block editor.
255     *
256     * @since 6.22.0
257     *
258     * @return boolean
259     */
260    public static function show_block_integrations() {
261        /**
262         * Whether to show Integrations UI in the Form block editor.
263         *
264         * @since 6.22.0
265         *
266         * @param bool true Whether to show the Integrations UI in the editor. Default true.
267         */
268        return apply_filters( 'jetpack_forms_show_block_integrations', true );
269    }
270
271    /**
272     * Returns true if integration icons should be shown (editor sidebar and integrations modal).
273     *
274     * @since 6.22.0
275     *
276     * @return boolean
277     */
278    public static function show_integration_icons() {
279        /**
280         * Whether to show integration icons in the UI.
281         *
282         * If set to false, the ActiveIntegrations component (editor sidebar) will be hidden
283         * and integration icons in the integrations modal will not be rendered.
284         *
285         * @since 6.22.0
286         *
287         * @param bool true Whether to show integration icons. Default true.
288         */
289        return apply_filters( 'jetpack_forms_show_integration_icons', true );
290    }
291}