Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
67.65% covered (warning)
67.65%
23 / 34
78.57% covered (warning)
78.57%
11 / 14
CRAP
0.00% covered (danger)
0.00%
0 / 1
Jetpack_Forms
67.65% covered (warning)
67.65%
23 / 34
78.57% covered (warning)
78.57%
11 / 14
40.91
0.00% covered (danger)
0.00%
0 / 1
 load_contact_form
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
4.01
 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.2.2';
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
56    /**
57     * Get the plugin URL.
58     */
59    public static function plugin_url() {
60        return plugin_dir_url( __FILE__ );
61    }
62
63    /**
64     * Get the assets URL.
65     */
66    public static function assets_url() {
67        return plugin_dir_url( __DIR__ ) . 'assets';
68    }
69
70    /**
71     * Returns true if the feedback dashboard is enabled.
72     *
73     * @return boolean
74     */
75    public static function is_feedback_dashboard_enabled() {
76        /**
77         * Enable the Jetpack Forms dashboard.
78         *
79         * Returning false hides the Forms admin menu entry and skips the dashboard
80         * entirely. Unrelated to which dashboard renders — there is only one.
81         *
82         * @module contact-form
83         * @since 0.3.0
84         *
85         * @param bool $enabled Should the Jetpack Forms dashboard be enabled? Default true.
86         */
87        return apply_filters( 'jetpack_forms_dashboard_enable', true );
88    }
89
90    /**
91     * Returns true if the legacy menu item is retired.
92     *
93     * @return boolean
94     */
95    public static function is_legacy_menu_item_retired() {
96        return apply_filters( 'jetpack_forms_retire_legacy_menu_item', true );
97    }
98
99    /**
100     * Returns true if MailPoet integration is enabled.
101     *
102     * @return boolean
103     */
104    public static function is_mailpoet_enabled() {
105        /**
106         * Enable MailPoet integration.
107         *
108         * @param bool false Whether MailPoet integration be enabled. Default is false.
109         */
110        return apply_filters( 'jetpack_forms_mailpoet_enable', true );
111    }
112
113    /**
114     * Returns true if Hostinger Reach integration is enabled.
115     *
116     * @return boolean
117     */
118    public static function is_hostinger_reach_enabled() {
119        /**
120         * Enable Hostinger Reach integration.
121         *
122         * @param bool false Whether Hostinger Reach integration be enabled. Default is false.
123         */
124        return apply_filters( 'jetpack_forms_hostinger_reach_enable', false );
125    }
126
127    /**
128     * Returns true if the Integrations UI should be enabled.
129     *
130     * @return boolean
131     */
132    public static function is_integrations_enabled() {
133        /**
134         * Whether to enable the Integrations UI.
135         *
136         * @param bool true Whether to enable the Integrations UI. Default true.
137         */
138        return apply_filters( 'jetpack_forms_is_integrations_enabled', true );
139    }
140
141    /**
142     * Returns true if the site's plan includes field conditional logic.
143     *
144     * One switch for the whole feature: the editor panel, the front-end show/hide, and the
145     * submission-time enforcement in validation and storage. Gating them together means a
146     * form can never hide a field from the visitor while still requiring it on submit.
147     *
148     * Losing the plan on a form that already has conditions is safe: the conditions are
149     * simply ignored, so every field renders, validates and stores as an ordinary field.
150     *
151     * @return boolean
152     */
153    public static function is_conditional_logic_enabled() {
154        // Fail closed on WordPress.com until its WPCOM_Features copy knows the slug, or supports()
155        // falls back to the Jetpack free plan, which includes it. Drop once that copy ships.
156        $supported = ( ! function_exists( 'wpcom_feature_exists' ) || wpcom_feature_exists( self::CONDITIONAL_LOGIC_FEATURE ) )
157            && Current_Plan::supports( self::CONDITIONAL_LOGIC_FEATURE );
158
159        /**
160         * Whether field conditional logic is available on this site.
161         *
162         * @since $$next-version$$
163         *
164         * @param bool $supported Whether the site's plan includes conditional logic.
165         */
166        return (bool) apply_filters( 'jetpack_forms_conditional_logic_enabled', $supported );
167    }
168
169    /**
170     * Returns true if webhooks are enabled.
171     *
172     * @return boolean
173     */
174    public static function is_webhooks_enabled() {
175        /**
176         * Whether to enable webhooks for Jetpack Forms.
177         *
178         * @param bool true Whether webhooks should be enabled. Default true.
179         */
180        return apply_filters( 'jetpack_forms_webhooks_enabled', true );
181    }
182
183    /**
184     * Whether author-configured outbound destinations from a form source should be honored.
185     *
186     * Destinations declared in the form content (webhooks, the legacy postToUrl attribute and
187     * the Salesforce integration) carry submission data to an outbound URL, so they are only
188     * honored when whoever placed the form had an administrator-level capability:
189     *
190     * - For post/page forms (`single`, numeric source id) the source post's author must have
191     *   the `manage_options` capability. Editor/Author/Contributor-authored forms are dropped.
192     * - For block templates, block template parts and widgets the source id is not a numeric
193     *   post, so there is no author to check. Editing any of those surfaces already requires
194     *   the `edit_theme_options` capability — administrator-tier, strictly above the
195     *   capabilities an Editor/Author/Contributor holds — so their destinations are trusted.
196     *
197     * The source type is established server-side (from the signed JWT, or by re-rendering the
198     * real template/template part on the legacy path) and is not forgeable by the submitter.
199     *
200     * Returns false for any other unresolved source (non-numeric id of an unknown type, or a
201     * numeric id with no admin-capable author).
202     *
203     * @param int|string $source_id   The form source id: a post id for post/page forms, or a
204     *                                non-numeric value for widget or block-template sources.
205     * @param string     $source_type The form source type: single, widget, block_template or
206     *                                block_template_part. Defaults to 'single'.
207     * @return boolean
208     */
209    public static function should_honor_content_destinations( $source_id, $source_type = 'single' ) {
210        // Block templates, template parts and widgets can only be authored by users with the
211        // administrator-tier `edit_theme_options` capability, so their destinations are trusted
212        // even though the source id is not a numeric post.
213        if ( in_array( $source_type, Feedback_Source::ADMIN_TIER_SOURCE_TYPES, true ) ) {
214            return true;
215        }
216
217        if ( ! is_numeric( $source_id ) ) {
218            return false;
219        }
220
221        $source_id = (int) $source_id;
222        if ( $source_id <= 0 ) {
223            return false;
224        }
225
226        $author_id = (int) get_post_field( 'post_author', $source_id );
227
228        return $author_id > 0 && user_can( $author_id, 'manage_options' );
229    }
230
231    /**
232     * Returns true if the Integrations UI should be shown in the Forms dashboard.
233     *
234     * @since 6.22.0
235     *
236     * @return boolean
237     */
238    public static function show_dashboard_integrations() {
239        /**
240         * Whether to show Integrations UI in the Forms dashboard.
241         *
242         * @since 6.22.0
243         *
244         * @param bool true Whether to show the Integrations UI in the dashboard. Default true.
245         */
246        return apply_filters( 'jetpack_forms_show_dashboard_integrations', true );
247    }
248
249    /**
250     * Returns true if the Integrations UI should be shown in the Form block editor.
251     *
252     * @since 6.22.0
253     *
254     * @return boolean
255     */
256    public static function show_block_integrations() {
257        /**
258         * Whether to show Integrations UI in the Form block editor.
259         *
260         * @since 6.22.0
261         *
262         * @param bool true Whether to show the Integrations UI in the editor. Default true.
263         */
264        return apply_filters( 'jetpack_forms_show_block_integrations', true );
265    }
266
267    /**
268     * Returns true if integration icons should be shown (editor sidebar and integrations modal).
269     *
270     * @since 6.22.0
271     *
272     * @return boolean
273     */
274    public static function show_integration_icons() {
275        /**
276         * Whether to show integration icons in the UI.
277         *
278         * If set to false, the ActiveIntegrations component (editor sidebar) will be hidden
279         * and integration icons in the integrations modal will not be rendered.
280         *
281         * @since 6.22.0
282         *
283         * @param bool true Whether to show integration icons. Default true.
284         */
285        return apply_filters( 'jetpack_forms_show_integration_icons', true );
286    }
287}