PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 2.5.7
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v2.5.7
3.4.1 3.4.0 3.3.9 3.3.8 3.3.7 3.3.6 3.3.5 3.3.4 3.3.3 3.3.2 3.3.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.3.0 2.3.1 2.3.2 2.3.3 All 194 releases
convertkit / includes / class-convertkit-resource-forms.php

class-convertkit-resource-forms.php in Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages 2.5.7, at includes/class-convertkit-resource-forms.php

410 lines 11.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ConvertKit Forms Resource class.
4 *
5 * @package ConvertKit
6 * @author ConvertKit
7 */
8
9 /**
10 * Reads ConvertKit Forms from the options table, and refreshes
11 * ConvertKit Forms data stored locally from the API.
12 *
13 * @since 1.9.6
14 */
15 class ConvertKit_Resource_Forms extends ConvertKit_Resource_V4 {
16
17 /**
18 * Holds the Settings Key that stores site wide ConvertKit settings
19 *
20 * @var string
21 */
22 public $settings_name = 'convertkit_forms';
23
24 /**
25 * The type of resource
26 *
27 * @var string
28 */
29 public $type = 'forms';
30
31 /**
32 * Constructor.
33 *
34 * @since 1.9.8.4
35 *
36 * @param bool|string $context Context.
37 */
38 public function __construct( $context = false ) {
39
40 // Initialize the API if the Access Token has been defined in the Plugin Settings.
41 $settings = new ConvertKit_Settings();
42 if ( $settings->has_access_and_refresh_token() ) {
43 $this->api = new ConvertKit_API_V4(
44 CONVERTKIT_OAUTH_CLIENT_ID,
45 CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI,
46 $settings->get_access_token(),
47 $settings->get_refresh_token(),
48 $settings->debug_enabled(),
49 $context
50 );
51 }
52
53 // Call parent initialization function.
54 parent::init();
55
56 }
57
58 /**
59 * Returns all non-inline forms based on the sort order.
60 *
61 * @since 2.2.4
62 *
63 * @return bool|array
64 */
65 public function get_non_inline() {
66
67 // If the ConvertKit WordPress Libraries are < 1.3.6 (e.g. loaded by an outdated
68 // addon), or a WordPress site updates this Plugin before other ConvertKit Plugins,
69 // get_by() won't be available and will cause an E_ERROR, crashing the site.
70 // @see https://wordpress.org/support/topic/error-1795/.
71 if ( ! method_exists( $this, 'get_by' ) ) {
72 return false;
73 }
74
75 return $this->get_by( 'format', array( 'modal', 'slide in', 'sticky bar' ) );
76
77 }
78
79
80 /**
81 * Returns whether any non-inline forms exist in the options table.
82 *
83 * @since 2.2.4
84 *
85 * @return bool
86 */
87 public function non_inline_exist() {
88
89 if ( ! $this->get_non_inline() ) {
90 return false;
91 }
92
93 return true;
94
95 }
96
97 /**
98 * Determines if the given Form ID is a legacy Form or Landing Page.
99 *
100 * @since 2.5.0
101 *
102 * @param int $id Form or Landing Page ID.
103 */
104 public function is_legacy( $id ) {
105
106 // Get Form.
107 $form = $this->get_by_id( (int) $id );
108
109 // Return false if no Form exists.
110 if ( ! $form ) {
111 return false;
112 }
113
114 // If the `format` key exists, this is not a legacy Form.
115 if ( array_key_exists( 'format', $form ) ) {
116 return false;
117 }
118
119 return true;
120
121 }
122
123 /**
124 * Returns a <select> field populated with all forms, based on the given parameters.
125 *
126 * @since 2.3.9
127 *
128 * @param string $name Name.
129 * @param string $id ID.
130 * @param bool|array $css_classes <select> CSS class(es).
131 * @param string $selected_option <option> value to mark as selected.
132 * @param bool|array $prepend_options <option> elements to prepend before resources.
133 * @param bool|array $attributes <select> attributes.
134 * @param bool|string|array $description Description.
135 * @return string HTML Select Field
136 */
137 public function get_select_field_all( $name, $id, $css_classes, $selected_option, $prepend_options = false, $attributes = false, $description = false ) {
138
139 return $this->get_select_field(
140 $this->get(),
141 $name,
142 $id,
143 $css_classes,
144 $selected_option,
145 $prepend_options,
146 $attributes,
147 $description
148 );
149
150 }
151
152 /**
153 * Returns a <select> field populated with all non-inline forms, based on the given parameters.
154 *
155 * @since 2.3.9
156 *
157 * @param string $name Name.
158 * @param string $id ID.
159 * @param bool|array $css_classes <select> CSS class(es).
160 * @param string $selected_option <option> value to mark as selected.
161 * @param bool|array $prepend_options <option> elements to prepend before resources.
162 * @param bool|array $attributes <select> attributes.
163 * @param bool|string|array $description Description.
164 * @return string HTML Select Field
165 */
166 public function get_select_field_non_inline( $name, $id, $css_classes, $selected_option, $prepend_options = false, $attributes = false, $description = false ) {
167
168 return $this->get_select_field(
169 $this->get_non_inline(),
170 $name,
171 $id,
172 $css_classes,
173 $selected_option,
174 $prepend_options,
175 $attributes,
176 $description
177 );
178
179 }
180
181 /**
182 * Returns a <select> field populated with the resources, based on the given parameters.
183 *
184 * @since 2.3.9
185 *
186 * @param array $forms Forms.
187 * @param string $name Name.
188 * @param string $id ID.
189 * @param bool|array $css_classes <select> CSS class(es).
190 * @param string $selected_option <option> value to mark as selected.
191 * @param bool|array $prepend_options <option> elements to prepend before resources.
192 * @param bool|array $attributes <select> attributes.
193 * @param bool|string|array $description Description.
194 * @return string HTML Select Field
195 */
196 private function get_select_field( $forms, $name, $id, $css_classes, $selected_option, $prepend_options = false, $attributes = false, $description = false ) {
197
198 $html = sprintf(
199 '<select name="%s" id="%s" class="%s"',
200 esc_attr( $name ),
201 esc_attr( $id ),
202 esc_attr( ( is_array( $css_classes ) ? implode( ' ', $css_classes ) : '' ) )
203 );
204
205 // Append any attributes.
206 if ( $attributes ) {
207 foreach ( $attributes as $key => $value ) {
208 $html .= sprintf(
209 ' %s="%s"',
210 esc_attr( $key ),
211 esc_attr( $value )
212 );
213 }
214 }
215
216 // Close select tag.
217 $html .= '>';
218
219 // If any prepended options exist, add them now.
220 if ( $prepend_options ) {
221 foreach ( $prepend_options as $value => $label ) {
222 $html .= sprintf(
223 '<option value="%s" data-preserve-on-refresh="1"%s>%s</option>',
224 esc_attr( $value ),
225 selected( $selected_option, $value, false ),
226 esc_attr( $label )
227 );
228 }
229 }
230
231 // Iterate through resources, if they exist, building <option> elements.
232 if ( $forms ) {
233 foreach ( $forms as $form ) {
234 // Legacy forms don't include a `format` key, so define them as inline.
235 $html .= sprintf(
236 '<option value="%s"%s>%s [%s]</option>',
237 esc_attr( $form['id'] ),
238 selected( $selected_option, $form['id'], false ),
239 esc_attr( $form['name'] ),
240 ( ! empty( $form['format'] ) ? esc_attr( $form['format'] ) : 'inline' )
241 );
242 }
243 }
244
245 // Close select.
246 $html .= '</select>';
247
248 // If no description is provided, return the select field now.
249 if ( ! $description ) {
250 return $html;
251 }
252
253 // Append description before returning field.
254 if ( ! is_array( $description ) ) {
255 return $html . '<p class="description">' . $description . '</p>';
256 }
257
258 // Return description lines in a paragraph, using breaklines for each description entry in the array.
259 return $html . '<p class="description">' . implode( '<br />', $description ) . '</p>';
260
261 }
262
263 /**
264 * Returns the HTML/JS markup for the given Form ID.
265 *
266 * Legacy Forms will return HTML.
267 * Current Forms will return a <script> embed string.
268 *
269 * @since 1.9.6
270 *
271 * @param int $id Form ID.
272 * @return WP_Error|string
273 */
274 public function get_html( $id ) {
275
276 // Cast ID to integer.
277 $id = absint( $id );
278
279 // Bail if the resources are a WP_Error.
280 if ( is_wp_error( $this->resources ) ) {
281 return $this->resources;
282 }
283
284 // Bail if the resource doesn't exist.
285 if ( ! isset( $this->resources[ $id ] ) ) {
286 return new WP_Error(
287 'convertkit_resource_forms_get_html',
288 sprintf(
289 /* translators: ConvertKit Form ID */
290 __( 'ConvertKit Form ID %s does not exist on ConvertKit.', 'convertkit' ),
291 $id
292 )
293 );
294 }
295
296 // If no uid is present in the Form API data, this is a legacy form that's served by directly fetching the HTML
297 // from forms.convertkit.com.
298 if ( ! isset( $this->resources[ $id ]['uid'] ) ) {
299 // Initialize Settings.
300 $settings = new ConvertKit_Settings();
301
302 // Bail if no Access Token is specified in the Plugin Settings.
303 if ( ! $settings->has_access_token() ) {
304 return new WP_Error(
305 'convertkit_resource_forms_get_html',
306 __( 'ConvertKit Legacy Form could not be fetched as no Access Token specified in Plugin Settings', 'convertkit' )
307 );
308 }
309
310 // Initialize the API.
311 $api = new ConvertKit_API_V4(
312 CONVERTKIT_OAUTH_CLIENT_ID,
313 CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI,
314 $settings->get_access_token(),
315 $settings->get_refresh_token(),
316 $settings->debug_enabled(),
317 'output_form'
318 );
319
320 // Return Legacy Form HTML.
321 // We now call get_html() with the `embed_url` property, instead of get_form_html() with the `id` property,
322 // because `embed_url` includes the API Key.
323 return $api->get_html( $this->resources[ $id ]['embed_url'] );
324 }
325
326 // If the form's format is not an inline form, add the inline script before the closing </body> tag.
327 // This prevents a modal form's overlay being constrained by the WordPress Theme's styles,
328 // and accidentally embedding the same non-inline form twice, which would result in e.g. the same modal form
329 // displaying twice.
330 if ( $this->resources[ $id ]['format'] !== 'inline' ) {
331 add_filter(
332 'convertkit_output_scripts_footer',
333 function ( $scripts ) use ( $id ) {
334
335 $scripts[] = array(
336 'async' => true,
337 'data-uid' => $this->resources[ $id ]['uid'],
338 'src' => $this->resources[ $id ]['embed_js'],
339 );
340
341 return $scripts;
342
343 }
344 );
345
346 // Sanity check we're not in the WordPress Admin interface.
347 // Some third party REST API Plugins seem to load frontend Posts, which would result in a wp_die() as
348 // the output Plugin class (rightly) isn't initialized in the backend.
349 if ( is_admin() ) {
350 return '';
351 }
352
353 // Don't output the global non-inline form, if defined, because
354 // a non-inline form was specified at either Post/Page default level, Post/Page level
355 // or Post Category level.
356 // This prevents multiple non-inline forms loading.
357 remove_action( 'wp_footer', array( WP_ConvertKit()->get_class( 'output' ), 'output_global_non_inline_form' ), 1 );
358
359 // Don't return a script for output, as it'll be output in the site's footer.
360 return '';
361 }
362
363 // If here, return Form <script> embed now, as we want the inline form to display at this specific point of the content.
364
365 // Define script key-value pairs.
366 $script = array(
367 'async' => true,
368 'data-uid' => $this->resources[ $id ]['uid'],
369 'src' => $this->resources[ $id ]['embed_js'],
370 );
371
372 /**
373 * Filter the form <script> key/value pairs immediately before the script is output.
374 *
375 * @since 2.4.5
376 *
377 * @param array $script Form script key/value pairs to output as <script> tag.
378 */
379 $script = apply_filters( 'convertkit_resource_forms_output_script', $script );
380
381 // Build script output.
382 $output = '<script';
383 foreach ( $script as $attribute => $value ) {
384 // If the value is true, just output the attribute.
385 if ( $value === true ) {
386 $output .= ' ' . esc_attr( $attribute );
387 continue;
388 }
389
390 // Sanitize attribute and value.
391 $attribute = esc_attr( $attribute );
392 $value = ( $attribute === 'src' ? esc_url( $value ) : esc_attr( $value ) );
393
394 // Output the attribute and value.
395 $output .= ' ' . $attribute;
396
397 // Output the value, if it's not a blank string.
398 if ( strlen( $value ) > 0 ) {
399 $output .= '="' . $value . '"';
400 }
401 }
402 $output .= '></script>';
403
404 // Return script output.
405 return $output;
406
407 }
408
409 }
410