Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 1 addition & 12 deletions src/ConvertKit_API.php
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,6 @@ public function refresh_token(string $refreshToken, string $redirectURI)
* @param string $url URL of HTML page.
*
* @throws \InvalidArgumentException If the URL is not a valid URL format.
* @throws \Exception If parsing the legacy form or landing page failed.
*
* @return false|string
*/
Expand Down Expand Up @@ -328,21 +327,11 @@ public function get_resource(string $url)
$this->convert_relative_to_absolute_urls($html->getElementsByTagName('script'), 'src', $url_scheme_host_only);
$this->convert_relative_to_absolute_urls($html->getElementsByTagName('form'), 'action', $url_scheme_host_only);

// Save HTML.
$resource = $html->saveHTML();

// If the result is false, return a blank string.
if (!$resource) {
throw new \Exception(sprintf('Could not parse %s', $url));
}

// Remove some HTML tags that DOMDocument adds, returning the output.
// We do this instead of using LIBXML_HTML_NOIMPLIED in loadHTML(), because Legacy Forms
// are not always contained in a single root / outer element, which is required for
// LIBXML_HTML_NOIMPLIED to correctly work.
$resource = $this->strip_html_head_body_tags($resource);

return $resource;
return $this->get_body_html($html);
}

/**
Expand Down
64 changes: 48 additions & 16 deletions src/ConvertKit_API_Traits.php
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,21 @@ public function add_subscriber_to_form(int $form_id, int $subscriber_id, string
);
}

/**
* Adds a subscriber to a legacy form by subscriber ID
*
* @param integer $form_id Legacy Form ID.
* @param integer $subscriber_id Subscriber ID.
*
* @since 2.0.0
*
* @return false|mixed
*/
public function add_subscriber_to_legacy_form(int $form_id, int $subscriber_id)
{
return $this->post(sprintf('landing_pages/%s/subscribers/%s', $form_id, $subscriber_id));
}

/**
* List subscribers for a form
*
Expand Down Expand Up @@ -1914,8 +1929,13 @@ public function get_segments(
*/
public function convert_relative_to_absolute_urls(\DOMNodeList $elements, string $attribute, string $url) // phpcs:ignore Squiz.Commenting.FunctionComment.IncorrectTypeHint, Generic.Files.LineLength.TooLong
{
// Anchor hrefs.
// Store DOMNodeList in array, as iteration stops if a node is modified.
$nodes = [];
foreach ($elements as $element) {
$nodes[] = $element;
}

foreach ($nodes as $element) {
// Skip if the attribute's value is empty.
if (empty($element->getAttribute($attribute))) {
continue;
Expand All @@ -1931,31 +1951,43 @@ public function convert_relative_to_absolute_urls(\DOMNodeList $elements, string
continue;
}

// Remove element if it's rocket-loader.min.js. Including it prevents landing page redirects from working.
if (strpos($element->getAttribute($attribute), 'rocket-loader.min.js') !== false) {
if ($element->parentNode instanceof \DOMNode) {
$element->parentNode->removeChild($element);
}
continue;
}

// If here, the attribute's value is a relative URL, missing the http(s) and domain.
// Prepend the URL to the attribute's value.
$element->setAttribute($attribute, $url . $element->getAttribute($attribute));
}
}//end foreach
}

/**
* Strips <html>, <head> and <body> opening and closing tags from the given markup,
* as well as the Content-Type meta tag we might have added in get_html().
* Returns the HTML within the DOMDocument's <body> tag as a string.
*
* @param \DOMDocument $dom DOM Document.
*
* @param string $markup HTML Markup.
* @since 2.1.0
*
* @return string HTML Markup
* @return string
*/
public function strip_html_head_body_tags(string $markup)
public function get_body_html(\DOMDocument $dom)
{
$markup = str_replace('<html>', '', $markup);
$markup = str_replace('</html>', '', $markup);
$markup = str_replace('<head>', '', $markup);
$markup = str_replace('</head>', '', $markup);
$markup = str_replace('<body>', '', $markup);
$markup = str_replace('</body>', '', $markup);
$markup = str_replace('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">', '', $markup);

return $markup;
$body = $dom->getElementsByTagName('body')->item(0);

if (! $body instanceof \DOMElement) {
return '';
}

$html = '';
foreach ($body->childNodes as $child) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
$html .= $dom->saveHTML($child);
}

return $html;
}

/**
Expand Down
132 changes: 132 additions & 0 deletions tests/ConvertKitMethodsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php

use PHPUnit\Framework\TestCase;
use Dotenv\Dotenv;
use ConvertKit_API\ConvertKit_API;

/**
* Test methods in ConvertKit_API_Traits that don't interact with the API,
* such as convert_relative_to_absolute_urls().
*/
class ConvertKitMethodsTest extends TestCase
{
/**
* Kit API Class
*
* @var object
*/
protected $api;

/**
* Initialize the API class before each test.
*
* @since 2.4.1
*
* @return void
*/
protected function setUp(): void
{
$this->api = new ConvertKit_API();
}

/**
* Test the convert_relative_to_absolute_urls() method.
*
* @since 2.4.1
*
* @return void
*/
public function testConvertRelativeToAbsoluteUrls()
{
// Setup HTML in DOMDocument.
$html = new \DOMDocument();
$html->loadHTML('<html>
<head>
<script type="text/javascript" src="rocket-loader.min.js"></script>
<link rel="stylesheet" href="//fonts.googleapis.com">
</head>
<body>
<a href="/test">Test</a>
<img src="/test.jpg" />
<script type="text/javascript" src="/test.js"></script>
<form action="/test">Test</form>
</body>
</html>');

// Define URL to prepend to relative URLs.
$url_scheme_host_only = 'https://example.com';

// Convert relative URLs to absolute URLs for elements we want to test.
$this->api->convert_relative_to_absolute_urls(
$html->getElementsByTagName('a'),
'href',
$url_scheme_host_only
);
$this->api->convert_relative_to_absolute_urls(
$html->getElementsByTagName('link'),
'href',
$url_scheme_host_only
);
$this->api->convert_relative_to_absolute_urls(
$html->getElementsByTagName('img'),
'src',
$url_scheme_host_only
);
$this->api->convert_relative_to_absolute_urls(
$html->getElementsByTagName('script'),
'src',
$url_scheme_host_only
);
$this->api->convert_relative_to_absolute_urls(
$html->getElementsByTagName('form'),
'action',
$url_scheme_host_only
);

// Fetch HTML string.
$output = $html->saveHTML();

// Assert string contains expected HTML elements that should not be modified.
$this->assertStringContainsString('<link rel="stylesheet" href="//fonts.googleapis.com">', $output);

// Assert string does not contain HTML elements that should be removed.
$this->assertStringNotContainsString(
'<script type="text/javascript" src="rocket-loader.min.js"></script>',
$output
);

// Assert string contains expected HTML elements that should be modified.
$this->assertStringContainsString(
'<a href="' . $url_scheme_host_only . '/test">Test</a>',
$output
);
$this->assertStringContainsString(
'<img src="' . $url_scheme_host_only . '/test.jpg">',
$output
);
$this->assertStringContainsString(
'<script type="text/javascript" src="' . $url_scheme_host_only . '/test.js"></script>',
$output
);
$this->assertStringContainsString(
'<form action="' . $url_scheme_host_only . '/test">Test</form>',
$output
);
}

/**
* Test that the get_body_html() method returns the expected HTML.
*
* @since 2.4.1
*/
public function testGetBodyHtml()
{
$content = '<h1>Vantar þinn ungling sjálfstraust í stærðfræði?</h1><p>This is a test</p>';
$html = new \DOMDocument();
$html->loadHTML('
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head>
<body>' . $content . '</body>
</html>');
$this->assertEquals($content, $this->api->get_body_html($html));
}
}
Loading