Skip to content

Commit

Permalink
Merge pull request #751 from Kit/fix-domdocument-blank-form-error
Browse files Browse the repository at this point in the history
Fix `DOMDocument` Fatal Error when non-inline Form specified
  • Loading branch information
n7studios authored Dec 6, 2024
2 parents b75d55d + 1be57d0 commit d7beb62
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 0 deletions.
25 changes: 25 additions & 0 deletions includes/class-convertkit-output.php
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,24 @@ public function append_form_to_content( $content ) {
}
}

// If the Form HTML is empty, it's a modal form that has been set to load in the footer of the site.
// We don't need to append anything to the content.
if ( empty( $form ) ) {
if ( $this->settings->debug_enabled() ) {
$content .= '<!-- Kit append_form_to_content(): Form is non-inline, appended to footer. -->';
}

return $content;
}

// If here, we have a ConvertKit Form.
// Append form to Post's Content, based on the position setting.
$form_position = $this->settings->get_default_form_position( get_post_type( $post_id ) );

if ( $this->settings->debug_enabled() ) {
$content .= '<!-- Kit append_form_to_content(): Form Position: ' . esc_html( $form_position ) . ' -->';
}

switch ( $form_position ) {
case 'before_after_content':
$content = $form . $content . $form;
Expand Down Expand Up @@ -391,6 +406,11 @@ public function append_form_to_content( $content ) {
*/
private function inject_form_after_element( $content, $tag, $index, $form ) {

// If the form is empty, don't inject anything.
if ( empty( $form ) ) {
return $content;
}

// Define the meta tag.
$meta_tag = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">';

Expand Down Expand Up @@ -459,6 +479,11 @@ private function inject_form_after_element( $content, $tag, $index, $form ) {
*/
private function inject_form_after_element_fallback( $content, $tag, $index, $form ) {

// If the form is empty, don't inject anything.
if ( empty( $form ) ) {
return $content;
}

// Calculate tag length.
$tag_length = ( strlen( $tag ) + 3 );

Expand Down
43 changes: 43 additions & 0 deletions tests/acceptance/forms/post-types/CPTFormCest.php
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,49 @@ public function testAddNewCPTUsingDefaultFormAfterParagraphElement(AcceptanceTes
$I->dontSeeInSource('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">');
}

/**
* Test that specifying a non-inline Form specified in the Plugin Settings does not
* result in a fatal error when creating and viewing a new WordPress CPT, and its position is set
* to after the 3rd paragraph.
*
* @since 2.6.8
*
* @param AcceptanceTester $I Tester.
*/
public function testAddNewCPTUsingDefaultNonInlineFormAfterParagraphElement(AcceptanceTester $I)
{
// Setup ConvertKit plugin with Default Form for CPTs set to be output after the 3rd paragraph of content.
$I->setupConvertKitPlugin(
$I,
[
'article_form' => $_ENV['CONVERTKIT_API_FORM_FORMAT_MODAL_ID'],
'article_form_position' => 'after_element',
'article_form_position_element' => 'p',
'article_form_position_element_index' => 3,
]
);
$I->setupConvertKitPluginResources($I);

// Setup CPT with placeholder content.
$pageID = $I->addGutenbergPageToDatabase($I, 'article', 'Kit: CPT: Non-Inline Form: Default: After 3rd Paragraph Element');

// View the Page on the frontend site.
$I->amOnPage('?p=' . $pageID);

// Check that no PHP warnings or notices were output.
$I->checkNoWarningsAndNoticesOnScreen($I);

// Confirm that one ConvertKit Form is output in the DOM.
// This confirms that there is only one script on the page for this form, which renders the form.
$I->seeNumberOfElementsInDOM('form[data-sv-form="' . $_ENV['CONVERTKIT_API_FORM_FORMAT_MODAL_ID'] . '"]', 1);

// Confirm character encoding is not broken due to using DOMDocument.
$I->seeInSource('Adhaésionés altéram improbis mi pariendarum sit stulti triarium');

// Confirm no meta tag exists within the content.
$I->dontSeeInSource('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">');
}

/**
* Test that the Default Form specified in the Plugin Settings works when
* creating and viewing a new WordPress CPT, and its position is set
Expand Down
43 changes: 43 additions & 0 deletions tests/acceptance/forms/post-types/PageFormCest.php
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,49 @@ public function testAddNewPageUsingDefaultFormAfterParagraphElement(AcceptanceTe
$I->dontSeeInSource('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">');
}

/**
* Test that specifying a non-inline Form specified in the Plugin Settings does not
* result in a fatal error when creating and viewing a new WordPress Page, and its position is set
* to after the 3rd paragraph.
*
* @since 2.6.8
*
* @param AcceptanceTester $I Tester.
*/
public function testAddNewPageUsingDefaultNonInlineFormAfterParagraphElement(AcceptanceTester $I)
{
// Setup ConvertKit plugin with Default Form for Pages set to be output after the 3rd paragraph of content.
$I->setupConvertKitPlugin(
$I,
[
'page_form' => $_ENV['CONVERTKIT_API_FORM_FORMAT_MODAL_ID'],
'page_form_position' => 'after_element',
'page_form_position_element' => 'p',
'page_form_position_element_index' => 3,
]
);
$I->setupConvertKitPluginResources($I);

// Setup Page with placeholder content.
$pageID = $I->addGutenbergPageToDatabase($I, 'page', 'Kit: Page: Non-Inline Form: Default: After 3rd Paragraph Element');

// View the Page on the frontend site.
$I->amOnPage('?p=' . $pageID);

// Check that no PHP warnings or notices were output.
$I->checkNoWarningsAndNoticesOnScreen($I);

// Confirm that one ConvertKit Form is output in the DOM.
// This confirms that there is only one script on the page for this form, which renders the form.
$I->seeNumberOfElementsInDOM('form[data-sv-form="' . $_ENV['CONVERTKIT_API_FORM_FORMAT_MODAL_ID'] . '"]', 1);

// Confirm character encoding is not broken due to using DOMDocument.
$I->seeInSource('Adhaésionés altéram improbis mi pariendarum sit stulti triarium');

// Confirm no meta tag exists within the content.
$I->dontSeeInSource('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">');
}

/**
* Test that the Default Form specified in the Plugin Settings works when
* creating and viewing a new WordPress Page, and its position is set
Expand Down
43 changes: 43 additions & 0 deletions tests/acceptance/forms/post-types/PostFormCest.php
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,49 @@ public function testAddNewPostUsingDefaultFormAfterParagraphElement(AcceptanceTe
$I->dontSeeInSource('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">');
}

/**
* Test that specifying a non-inline Form specified in the Plugin Settings does not
* result in a fatal error when creating and viewing a new WordPress Post, and its position is set
* to after the 3rd paragraph.
*
* @since 2.6.8
*
* @param AcceptanceTester $I Tester.
*/
public function testAddNewPostUsingDefaultNonInlineFormAfterParagraphElement(AcceptanceTester $I)
{
// Setup ConvertKit plugin with Default Form for Posts set to be output after the 3rd paragraph of content.
$I->setupConvertKitPlugin(
$I,
[
'post_form' => $_ENV['CONVERTKIT_API_FORM_FORMAT_MODAL_ID'],
'post_form_position' => 'after_element',
'post_form_position_element' => 'p',
'post_form_position_element_index' => 3,
]
);
$I->setupConvertKitPluginResources($I);

// Setup Post with placeholder content.
$pageID = $I->addGutenbergPageToDatabase($I, 'post', 'Kit: Post: Non-Inline Form: Default: After 3rd Paragraph Element');

// View the Page on the frontend site.
$I->amOnPage('?p=' . $pageID);

// Check that no PHP warnings or notices were output.
$I->checkNoWarningsAndNoticesOnScreen($I);

// Confirm that one ConvertKit Form is output in the DOM.
// This confirms that there is only one script on the page for this form, which renders the form.
$I->seeNumberOfElementsInDOM('form[data-sv-form="' . $_ENV['CONVERTKIT_API_FORM_FORMAT_MODAL_ID'] . '"]', 1);

// Confirm character encoding is not broken due to using DOMDocument.
$I->seeInSource('Adhaésionés altéram improbis mi pariendarum sit stulti triarium');

// Confirm no meta tag exists within the content.
$I->dontSeeInSource('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">');
}

/**
* Test that the Default Form specified in the Plugin Settings works when
* creating and viewing a new WordPress Post, and its position is set
Expand Down

0 comments on commit d7beb62

Please sign in to comment.