PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 2.2.0
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v2.2.0
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-output.php

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

472 lines 12.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ConvertKit Output class.
4 *
5 * @package ConvertKit
6 * @author ConvertKit
7 */
8
9 /**
10 * Outputs Forms and Landing Pages on the frontend web site, based on
11 * the Post and Plugin's configuration.
12 *
13 * @since 1.9.6
14 */
15 class ConvertKit_Output {
16
17 /**
18 * Holds the ConvertKit Subscriber ID.
19 *
20 * @since 2.0.6
21 *
22 * @var int|string
23 */
24 private $subscriber_id = 0;
25
26 /**
27 * Holds the ConvertKit Plugin Settings class
28 *
29 * @since 1.9.6
30 *
31 * @var bool|ConvertKit_Settings
32 */
33 private $settings = false;
34
35 /**
36 * Holds the ConvertKit Post Settings class
37 *
38 * @since 1.9.6
39 *
40 * @var bool|ConvertKit_Post
41 */
42 private $post_settings = false;
43
44 /**
45 * Holds the available ConvertKit Forms
46 *
47 * @since 1.9.6
48 *
49 * @var bool|ConvertKit_Resource_Forms
50 */
51 private $forms = false;
52
53 /**
54 * Holds the available ConvertKit Landing Pages
55 *
56 * @since 1.9.6
57 *
58 * @var bool|ConvertKit_Resource_Landing_Pages
59 */
60 private $landing_pages = false;
61
62 /**
63 * Constructor. Registers actions and filters to output ConvertKit Forms and Landing Pages
64 * on the frontend web site.
65 *
66 * @since 1.9.6
67 */
68 public function __construct() {
69
70 add_action( 'init', array( $this, 'get_subscriber_id_from_request' ), 1 );
71 add_action( 'template_redirect', array( $this, 'output_form' ) );
72 add_action( 'template_redirect', array( $this, 'page_takeover' ) );
73 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
74 add_filter( 'the_content', array( $this, 'append_form_to_content' ) );
75 add_action( 'wp_footer', array( $this, 'output_scripts_footer' ) );
76
77 }
78
79 /**
80 * Runs the `convertkit_output_output_form` action for singular Post Types that don't use the_content()
81 * or apply_filters( 'the_content' ) to output a ConvertKit Form.
82 *
83 * @since 1.9.6
84 */
85 public function output_form() {
86
87 /**
88 * Outputs a ConvertKit Form on singular Post Types that don't use the_content()
89 * or apply_filters( 'the_content' ).
90 *
91 * @since 1.9.6
92 *
93 * @return string Post Content with Form Appended, if applicable
94 */
95 do_action( 'convertkit_output_output_form' );
96
97 }
98
99 /**
100 * Outputs a ConvertKit Landing Page if configured, replacing all output for the singular Post Type.
101 *
102 * @since 1.9.6
103 */
104 public function page_takeover() {
105
106 $queried_object = get_queried_object();
107
108 // Bail if the queried object cannot be inspected.
109 if ( ! isset( $queried_object->post_type ) ) {
110 return;
111 }
112
113 // Get Post ID.
114 $post_id = $queried_object->ID;
115
116 // Bail if the queried object isn't a supported Post Type for Landing Pages.
117 if ( $queried_object->post_type !== 'page' ) {
118 return;
119 }
120
121 // Get ConvertKit Post's Settings, if they have not yet been loaded.
122 if ( ! $this->post_settings ) {
123 $this->post_settings = new ConvertKit_Post( $post_id );
124 }
125
126 // Get Landing Page ID.
127 $landing_page_id = $this->post_settings->get_landing_page();
128
129 /**
130 * Define the ConvertKit Landing Page ID to display for the given Post ID,
131 * overriding the Post settings.
132 *
133 * Return false to not display any ConvertKit Landing Page.
134 *
135 * @since 1.9.6
136 *
137 * @param int $landing_page_id Landing Page ID
138 * @param int $post_id Post ID
139 */
140 $landing_page_id = apply_filters( 'convertkit_output_page_takeover_landing_page_id', $landing_page_id, $post_id );
141
142 // Bail if no Landing Page is configured to be output.
143 if ( empty( $landing_page_id ) ) {
144 return;
145 }
146
147 // Get available ConvertKit Landing Pages, if they have not yet been loaded.
148 if ( ! $this->landing_pages ) {
149 $this->landing_pages = new ConvertKit_Resource_Landing_Pages( 'output_landing_page' );
150 }
151
152 // Get Landing Page.
153 $landing_page = $this->landing_pages->get_html( $this->post_settings->get_landing_page() );
154
155 // Bail if an error occured.
156 if ( is_wp_error( $landing_page ) ) {
157 return;
158 }
159
160 // Output Landing Page.
161 // Output is supplied from ConvertKit's API, which is already sanitized.
162 echo $landing_page; // phpcs:ignore WordPress.Security.EscapeOutput
163 exit;
164
165 }
166
167 /**
168 * Appends a form to the singular Page, Post or Custom Post Type's Content.
169 *
170 * @param string $content Post Content.
171 * @return string Post Content with Form Appended, if applicable
172 */
173 public function append_form_to_content( $content ) {
174
175 // Bail if not a singular Post Type.
176 if ( ! is_singular() ) {
177 return $content;
178 }
179
180 // Get Post ID and ConvertKit Form ID for the Post.
181 $post_id = get_the_ID();
182 $form_id = $this->get_post_form_id( $post_id );
183
184 /**
185 * Define the ConvertKit Form ID to display for the given Post ID,
186 * overriding the Post, Category or Plugin settings.
187 *
188 * Return false to not display any ConvertKit Form.
189 *
190 * @since 1.9.6
191 *
192 * @param bool|int $form_id Form ID
193 * @param int $post_id Post ID
194 */
195 $form_id = apply_filters( 'convertkit_output_append_form_to_content_form_id', $form_id, $post_id );
196
197 // Return the Post Content, unedited, if the Form ID is false or zero.
198 if ( ! $form_id ) {
199 return $content;
200 }
201
202 // Get available ConvertKit Forms, if they have not yet been loaded.
203 if ( ! $this->forms ) {
204 $this->forms = new ConvertKit_Resource_Forms( 'output_form' );
205 }
206
207 // Get Form HTML.
208 $form = $this->forms->get_html( $form_id );
209
210 // If an error occured, it could be because the specified Form ID for the Post either:
211 // - belongs to another ConvertKit account (i.e. API credentials were changed in the Plugin, but this Post's specified Form was not changed), or
212 // - the form was deleted from the ConvertKit account.
213 // Attempt to fallback to the default form for this Post Type.
214 if ( is_wp_error( $form ) ) {
215 if ( $this->settings->debug_enabled() ) {
216 $content .= '<!-- ConvertKit append_form_to_content(): ' . $form->get_error_message() . ' Attempting fallback to Default Form. -->';
217 }
218
219 // Get Default Form ID for this Post's Type.
220 $form_id = $this->settings->get_default_form( get_post_type( $post_id ) );
221
222 // If no Default Form is specified, just return the Post Content, unedited.
223 if ( ! $form_id ) {
224 if ( $this->settings->debug_enabled() ) {
225 $content .= '<!-- ConvertKit append_form_to_content(): No Default Form exists as a fallback. -->';
226 }
227
228 return $content;
229 }
230
231 // Get Form HTML.
232 $form = $this->forms->get_html( $form_id );
233
234 // If an error occured again, the default form doesn't exist in this ConvertKit account.
235 // Just return the Post Content, unedited.
236 if ( is_wp_error( $form ) ) {
237 if ( $this->settings->debug_enabled() ) {
238 $content .= '<!-- ConvertKit append_form_to_content(): Default Form: ' . $form->get_error_message() . ' -->';
239 }
240
241 return $content;
242 }
243 }
244
245 // If here, we have a ConvertKit Form.
246 // Append form to Post's Content.
247 $content = $content .= $form;
248
249 /**
250 * Filter the Post's Content, which includes a ConvertKit Form, immediately before it is output.
251 *
252 * @since 1.9.6
253 *
254 * @param string $content Post Content
255 * @param string $form ConvertKit Form HTML
256 * @param int $post_id Post ID
257 * @param int $form_id ConvertKit Form ID
258 */
259 $content = apply_filters( 'convertkit_frontend_append_form', $content, $form, $post_id, $form_id );
260
261 return $content;
262
263 }
264
265 /**
266 * Returns the Post, Category or Plugin ConvertKit Form ID for the given Post.
267 *
268 * If the Post specifies a form to use, returns that Form ID.
269 * If the Post uses the 'Default' setting, and an assigned Category has a Form ID, uses the Category's Form ID.
270 * Otherwise falls back to the Plugin's Default Form ID (if any).
271 *
272 * @since 1.9.6
273 *
274 * @param int $post_id Post ID.
275 * @return bool|string|int false|'default'|Form ID
276 */
277 private function get_post_form_id( $post_id ) {
278
279 // Get Settings, if they have not yet been loaded.
280 if ( ! $this->settings ) {
281 $this->settings = new ConvertKit_Settings();
282 }
283
284 // Get ConvertKit Post's Settings, if they have not yet been loaded.
285 if ( ! $this->post_settings ) {
286 $this->post_settings = new ConvertKit_Post( $post_id );
287 }
288
289 // If the Post specifies a Form to use, return its ID now.
290 if ( $this->post_settings->has_form() ) {
291 return $this->post_settings->get_form();
292 }
293
294 // If the Post specifies that no Form should be used, return false.
295 if ( $this->post_settings->uses_no_form() ) {
296 return false;
297 }
298
299 // Sanity check that the Post uses the Default Form setting, which should be the case
300 // because the above conditions were not met.
301 if ( ! $this->post_settings->uses_default_form() ) {
302 return false;
303 }
304
305 // Get Post's Categories.
306 $categories = wp_get_post_categories(
307 $post_id,
308 array(
309 'fields' => 'ids',
310 )
311 );
312
313 // If no Categories exist, use the Default Form.
314 if ( ! is_array( $categories ) || ! count( $categories ) ) {
315 // Get Post Type.
316 return $this->settings->get_default_form( get_post_type( $post_id ) );
317 }
318
319 /**
320 * Iterate through Categories in reverse order.
321 * This honors the behaviour < 1.9.6, which states that if multiple Categories each have a Form.
322 * assigned, the last Category with a Form in the wp_get_post_categories() call will be used.
323 */
324 $categories = array_reverse( $categories );
325 foreach ( $categories as $term_id ) {
326 // Load Term Settings.
327 $term_settings = new ConvertKit_Term( $term_id );
328
329 // If a Form ID exists, return it now.
330 if ( $term_settings->has_form() ) {
331 return $term_settings->get_form();
332 }
333 }
334
335 // If here, use the Plugin's Default Form.
336 return $this->settings->get_default_form( get_post_type( $post_id ) );
337
338 }
339
340 /**
341 * Enqueue scripts.
342 *
343 * @since 1.9.6
344 */
345 public function enqueue_scripts() {
346
347 // Get Post.
348 $post = get_post();
349
350 // Bail if no Post could be fetched.
351 if ( ! $post ) {
352 return;
353 }
354
355 // Get ConvertKit Settings and Post's Settings.
356 $settings = new ConvertKit_Settings();
357 $convertkit_post = new ConvertKit_Post( $post->ID );
358
359 // Register scripts that we might use.
360 wp_register_script(
361 'convertkit-js',
362 CONVERTKIT_PLUGIN_URL . 'resources/frontend/js/convertkit.js',
363 array( 'jquery' ),
364 CONVERTKIT_PLUGIN_VERSION,
365 true
366 );
367 wp_localize_script(
368 'convertkit-js',
369 'convertkit',
370 array(
371 'ajaxurl' => admin_url( 'admin-ajax.php' ),
372 'debug' => $settings->debug_enabled(),
373 'nonce' => wp_create_nonce( 'convertkit' ),
374 'subscriber_id' => $this->subscriber_id,
375 'tag' => ( ( is_singular() && $convertkit_post->has_tag() ) ? $convertkit_post->get_tag() : false ),
376 'post_id' => $post->ID,
377 )
378 );
379
380 // Bail if the no scripts setting is enabled.
381 if ( $settings->scripts_disabled() ) {
382 return;
383 }
384
385 // Enqueue.
386 wp_enqueue_script( 'convertkit-js' );
387
388 }
389
390 /**
391 * Gets the subscriber ID from the request (either the cookie or the URL).
392 *
393 * @since 1.9.6
394 */
395 public function get_subscriber_id_from_request() {
396
397 // Use ConvertKit_Subscriber class to fetch and validate the subscriber ID.
398 $subscriber = new ConvertKit_Subscriber();
399 $subscriber_id = $subscriber->get_subscriber_id();
400
401 // If an error occured, the subscriber ID in the request/cookie is not a valid subscriber.
402 if ( is_wp_error( $subscriber_id ) ) {
403 return;
404 }
405
406 $this->subscriber_id = $subscriber_id;
407
408 }
409
410 /**
411 * Outputs any JS <script> tags registered with the convertkit_output_scripts_footer
412 * filter
413 *
414 * @since 2.1.4
415 */
416 public function output_scripts_footer() {
417
418 // Define array of scripts.
419 $scripts = array();
420
421 /**
422 * Define an array of scripts to output in the footer of the WordPress site.
423 *
424 * @since 2.1.4
425 *
426 * @param array $scripts Scripts.
427 */
428 $scripts = apply_filters( 'convertkit_output_scripts_footer', $scripts );
429
430 // Bail if no scripts exist.
431 if ( ! count( $scripts ) ) {
432 return;
433 }
434
435 // Define array to store <script> outputs.
436 $output_scripts = array();
437
438 // Iterate through scripts, building the <script> tag for each.
439 foreach ( $scripts as $script ) {
440 $output = '<script';
441
442 foreach ( $script as $attribute => $value ) {
443 // If the value is true, just output the attribute.
444 if ( $value === true ) {
445 $output .= ' ' . esc_attr( $attribute );
446 continue;
447 }
448
449 // Output the attribute and value.
450 $output .= ' ' . esc_attr( $attribute ) . '="' . esc_attr( $value ) . '"';
451 }
452 $output .= '></script>';
453
454 // Add to array.
455 $output_scripts[] = $output;
456 }
457
458 // Remove duplicate scripts.
459 // This prevents the same non-inline form displaying twice. For example, if a modal form is specified both
460 // in the Page's settings and the Form block, the user would see the same modal form displayed twice
461 // because the script would be output twice.
462 $output_scripts = array_unique( $output_scripts );
463
464 // Output scripts.
465 foreach ( $output_scripts as $output_script ) {
466 echo $output_script . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
467 }
468
469 }
470
471 }
472