| 1 |
<?php |
| 2 |
|
| 3 |
if (!defined('ABSPATH')) { |
| 4 |
exit; // Called directly, nothing to do here. |
| 5 |
} |
| 6 |
|
| 7 |
// A save that was turned away comes back as a fresh page load, so what someone |
| 8 |
// typed only survives if it was put aside first. Fill the form from that when |
| 9 |
// there is one, otherwise from the saved test as before. The draft is tied to |
| 10 |
// the test it was typed against, so a rejected new test cannot reappear on a |
| 11 |
// different test's form and be saved over it. |
| 12 |
if (is_object($test)) { |
| 13 |
$convertpro_draft = convertpro_take_form_draft(isset($test->id) ? (int) $test->id : 0); |
| 14 |
|
| 15 |
if ($convertpro_draft) { |
| 16 |
$test->name = $convertpro_draft['name']; |
| 17 |
$test->test_type = $convertpro_draft['test_type']; |
| 18 |
$test->test_uri = $convertpro_draft['test_uri']; |
| 19 |
$test->conversion_type = $convertpro_draft['conversion_type']; |
| 20 |
$test->conversion_page_id = $convertpro_draft['conversion_page_id']; |
| 21 |
$test->conversion_url = $convertpro_draft['conversion_url']; |
| 22 |
|
| 23 |
if (!empty($convertpro_draft['variations'])) { |
| 24 |
$test->variations = array(); |
| 25 |
|
| 26 |
foreach ($convertpro_draft['variations'] as $convertpro_row) { |
| 27 |
$test->variations[] = (object) $convertpro_row; |
| 28 |
} |
| 29 |
} |
| 30 |
} |
| 31 |
} |
| 32 |
|
| 33 |
if ($scope == "edit") { |
| 34 |
$formUrl = admin_url('admin.php?page=convertpro-settings&scope=test&action=update&id=' . $test->id); |
| 35 |
} else { |
| 36 |
$formUrl = admin_url('admin.php?page=convertpro-settings&scope=test&action=store'); |
| 37 |
} |
| 38 |
?> |
| 39 |
<div class="meassage"> |
| 40 |
<?php |
| 41 |
// phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 42 |
$convertpro_message = isset($_GET['message']) ? sanitize_key(wp_unslash($_GET['message'])) : ''; |
| 43 |
|
| 44 |
$convertpro_notices = array( |
| 45 |
'save_success' => array('success', __('Saved.', 'convertpro')), |
| 46 |
'store_success' => array('success', __('Your test is ready. It starts running as soon as visitors arrive.', 'convertpro')), |
| 47 |
'error_name_missing' => array('error', __('Give the test a name so you can recognise it later.', 'convertpro')), |
| 48 |
'error_type_missing' => array('error', __('Pick whether you are testing whole pages or an element.', 'convertpro')), |
| 49 |
'conversion_page_missing' => array('error', __('Choose the page that counts as a conversion, so we know when a visitor succeeded.', 'convertpro')), |
| 50 |
'error_selector_missing' => array('error', __('Tell us what to watch for a click, such as a CSS class or part of the link address.', 'convertpro')), |
| 51 |
'error_uri_missing' => array('error', __('Add a test URL. This is the link you share, and it decides which version each visitor sees.', 'convertpro')), |
| 52 |
'error_test_page_invalid_chars' => array('error', __('The test URL cannot contain a slash. Use letters, numbers, dashes and underscores.', 'convertpro')), |
| 53 |
'error_uri_taken_by_content' => array('error', __('You already have a page or post at that address. Pick a different test URL, or the real page would start redirecting people.', 'convertpro')), |
| 54 |
'error_uri_taken_by_test' => array('error', __('Another test already uses that URL. Give this one its own address.', 'convertpro')), |
| 55 |
'error_need_two_variations' => array('error', __('A test needs at least two versions to compare.', 'convertpro')), |
| 56 |
'error_test_limit' => array('error', sprintf( |
| 57 |
/* translators: %d: number of tests the free plugin runs at once. */ |
| 58 |
_n( |
| 59 |
'EasyTest runs %d test at a time. Delete one you are done with to make room.', |
| 60 |
'EasyTest runs %d tests at a time. Delete one you are done with to make room.', |
| 61 |
convertpro_free_limit('tests'), |
| 62 |
'convertpro' |
| 63 |
), |
| 64 |
convertpro_free_limit('tests') |
| 65 |
)), |
| 66 |
'error_variation_limit' => array('error', sprintf( |
| 67 |
/* translators: %d: number of versions allowed per test. */ |
| 68 |
_n('A test compares %d version.', 'A test compares %d versions — A against B.', convertpro_free_limit('variations'), 'convertpro'), |
| 69 |
convertpro_free_limit('variations') |
| 70 |
)), |
| 71 |
'error_percentage_range' => array('error', __('Each share has to be between 1 and 100.', 'convertpro')), |
| 72 |
'error_percentage_total' => array('error', __('The shares have to add up to 100. Right now they do not.', 'convertpro')), |
| 73 |
'error_variation_page_missing' => array('error', __('Every version needs a page to send visitors to.', 'convertpro')), |
| 74 |
'error_variation_page_duplicate' => array('error', __('Two versions point at the same page, so there would be nothing to compare. Pick a different page for one of them.', 'convertpro')), |
| 75 |
'error_conversion_is_variation' => array('error', __('The conversion page is also one of the versions being tested, so everyone would convert the moment they arrive. Choose a different page.', 'convertpro')), |
| 76 |
'error_variation_class_missing' => array('error', __('Every version needs a CSS class. Copy it into your page builder on the element you want to test.', 'convertpro')), |
| 77 |
'error_variation_class_duplicate' => array('error', __('Two versions use the same CSS class. Each one needs its own.', 'convertpro')), |
| 78 |
'error_variation_class_invalid' => array('error', __('A CSS class can only use letters, numbers, dashes and underscores — something like hero-version-a. Symbols such as * or a comma would match the wrong part of your page.', 'convertpro')), |
| 79 |
'security_error' => array('error', __('That request could not be verified. Please try again.', 'convertpro')), |
| 80 |
'error_update_data_missing' => array('error', __('Something was missing from that request. Please try again.', 'convertpro')), |
| 81 |
'error_test_not_saved' => array('error', __('The test could not be saved. Nothing was lost — everything you filled in is still here, so try again.', 'convertpro')), |
| 82 |
); |
| 83 |
|
| 84 |
if (isset($convertpro_notices[$convertpro_message])) : |
| 85 |
list($convertpro_notice_type, $convertpro_notice_text) = $convertpro_notices[$convertpro_message]; |
| 86 |
?> |
| 87 |
<div class="notice notice-<?php echo esc_attr($convertpro_notice_type); ?> is-dismissible"> |
| 88 |
<p><?php echo esc_html($convertpro_notice_text); ?></p> |
| 89 |
</div> |
| 90 |
<?php endif; ?> |
| 91 |
|
| 92 |
<?php |
| 93 |
// A cache that answers before WordPress does will hand every visitor the same |
| 94 |
// version, and the test will look like it is running while measuring nothing. |
| 95 |
// We cannot reach those caches from here, so say what needs adding by hand. |
| 96 |
$convertpro_edge = convertpro_detect_edge_cache(); |
| 97 |
|
| 98 |
if ($convertpro_edge) : ?> |
| 99 |
<div class="notice notice-warning"> |
| 100 |
<p> |
| 101 |
<strong><?php |
| 102 |
/* translators: %s: name of the caching service, e.g. Cloudflare. */ |
| 103 |
printf(esc_html__('%s is in front of this site.', 'convertpro'), esc_html($convertpro_edge['name'])); |
| 104 |
?></strong> |
| 105 |
<?php echo esc_html($convertpro_edge['how']); ?> |
| 106 |
</p> |
| 107 |
</div> |
| 108 |
<?php endif; ?> |
| 109 |
|
| 110 |
</div> |
| 111 |
|
| 112 |
<script> |
| 113 |
function copyToClipboard(inputElement) { |
| 114 |
// Select the input field's text |
| 115 |
inputElement.select(); |
| 116 |
inputElement.setSelectionRange(0, 99999); // For mobile devices |
| 117 |
|
| 118 |
// Copy the text inside the input field |
| 119 |
document.execCommand("copy"); |
| 120 |
|
| 121 |
// Optional: Show a message to the user that the text has been copied |
| 122 |
|
| 123 |
} |
| 124 |
</script> |
| 125 |
|
| 126 |
|
| 127 |
<div class="convertpro-create-wrapper"> |
| 128 |
<div class="test-top-area"> |
| 129 |
<div class="back-test"> |
| 130 |
<a href="<?php echo esc_url(admin_url('admin.php?page=convertpro-settings')); ?>"><svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 131 |
<path d="M7.5 14.75L2.25 9.5M2.25 9.5L7.5 4.25M2.25 9.5L15.75 9.5" stroke="#080E13" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> |
| 132 |
</svg><?php echo esc_html__('Back to All Tests', 'convertpro') ?></a> |
| 133 |
</div> |
| 134 |
<div class="create-update-test"> |
| 135 |
<h4><?php echo esc_html($text); ?></h4> |
| 136 |
</div> |
| 137 |
</div> |
| 138 |
|
| 139 |
<form method="post" action="<?php echo esc_url($formUrl); ?>" id="convertpro-test-form"> |
| 140 |
<input name="nonce" type="hidden" value="<?php echo esc_attr(wp_create_nonce('convertpro-nonce')); ?>" /> |
| 141 |
<div class="test-top-wrap"> |
| 142 |
<div class="test-name-wrap"> |
| 143 |
<label for="test-name"><?php esc_html_e('Test name', 'convertpro'); ?></label> |
| 144 |
<p><?php echo esc_html__('Only you see this. Name it so you can tell it apart later.', 'convertpro') ?></p> |
| 145 |
<input id="test-name" class="text-name" name="test-name" type="text" value="<?php echo (isset($test->name) ? esc_attr($test->name) : ""); ?>" placeholder="<?php esc_attr_e('Add a name', 'convertpro'); ?>" required /> |
| 146 |
</div> |
| 147 |
|
| 148 |
<!-- /.test type select start--> |
| 149 |
<div class="test-type-wrapper"> |
| 150 |
<div class="test-type-title"> |
| 151 |
<h2><?php esc_html_e('Test type', 'convertpro'); ?>:</h2> |
| 152 |
</div> |
| 153 |
<div class="test-type-select"> |
| 154 |
<select name="convertpro-test-type" style="width: 100%;"> |
| 155 |
<?php if (!isset($test->test_type)) { ?> |
| 156 |
<option value="null" selected="selected"><?php esc_html_e('Please select test type ...', 'convertpro'); ?></option> |
| 157 |
<?php } ?> |
| 158 |
<option value="elements" <?php if (isset($test->test_type) && $test->test_type == "elements") { |
| 159 |
echo ('selected="selected"'); |
| 160 |
} ?>><?php esc_html_e('Elements', 'convertpro'); ?></option> |
| 161 |
<option value="pages" <?php if (isset($test->test_type) && $test->test_type == "pages") { |
| 162 |
echo ('selected="selected"'); |
| 163 |
} ?>><?php esc_html_e('Page', 'convertpro'); ?></option> |
| 164 |
</select> |
| 165 |
</div> |
| 166 |
</div> |
| 167 |
<!-- /.test type select end --> |
| 168 |
|
| 169 |
<!-- /.select page showing this content start --> |
| 170 |
<div class="convertpro-uri-wrapper"> |
| 171 |
<div class="convertpro-headline" style="margin-top: 14px;"> |
| 172 |
<label><?php esc_html_e('Test URL', 'convertpro'); ?></label> |
| 173 |
<p><?php echo esc_html__('Send people here and EasyTest passes them on to one of the versions below. Make up an address of your own — it cannot be a page you already have.', 'convertpro') ?></p> |
| 174 |
</div> |
| 175 |
<div class="url-identfier"> |
| 176 |
<span><?php echo esc_url(home_url('/')); ?></span> |
| 177 |
<input name="test-uri" type="text" placeholder="<?php esc_attr_e('summer-offer', 'convertpro'); ?>" pattern="^([A-Za-z0-9\-_\/]*)$" title="<?php esc_attr_e('Letters, numbers, dashes and underscores only', 'convertpro'); ?>" value="<?php echo isset($test->test_uri) ? esc_attr($test->test_uri) : ''; ?>" /> |
| 178 |
|
| 179 |
</div> |
| 180 |
<?php if (isset($test->test_uri) && '' !== $test->test_uri) : ?> |
| 181 |
<div class="convertpro-pageview"> |
| 182 |
<a class="pageview-btn" id="test-page-url" target="_blank" href="<?php echo esc_url(home_url() . '/' . $test->test_uri . '/'); ?>"><?php esc_html_e('View Page', 'convertpro'); ?></a> |
| 183 |
</div> |
| 184 |
|
| 185 |
<?php |
| 186 |
$convertpro_previews = array(); |
| 187 |
|
| 188 |
foreach ($test->variations as $convertpro_variation) { |
| 189 |
if (!empty($convertpro_variation->page_id) && get_post($convertpro_variation->page_id)) { |
| 190 |
$convertpro_previews[] = array( |
| 191 |
'name' => $convertpro_variation->name, |
| 192 |
'url' => get_permalink($convertpro_variation->page_id), |
| 193 |
); |
| 194 |
} |
| 195 |
} |
| 196 |
?> |
| 197 |
|
| 198 |
<?php if ($convertpro_previews) : ?> |
| 199 |
<p class="convertpro-preview-note"> |
| 200 |
<?php esc_html_e('Opening the test URL puts you on one version and keeps you there, the same as it would any visitor. To look at the others, open them directly:', 'convertpro'); ?> |
| 201 |
<?php foreach ($convertpro_previews as $convertpro_index => $convertpro_preview) : ?> |
| 202 |
<a href="<?php echo esc_url($convertpro_preview['url']); ?>" target="_blank"><?php echo esc_html($convertpro_preview['name']); ?></a><?php echo $convertpro_index < count($convertpro_previews) - 1 ? ', ' : ''; ?> |
| 203 |
<?php endforeach; ?> |
| 204 |
</p> |
| 205 |
<?php endif; ?> |
| 206 |
<?php endif; ?> |
| 207 |
</div> |
| 208 |
</div> |
| 209 |
|
| 210 |
<div class="convertpro-test-variations"> |
| 211 |
<div class="headline"> |
| 212 |
<div class="name"><?php esc_html_e('Version name', 'convertpro'); ?>:</div> |
| 213 |
<div class="post"><?php esc_html_e('Page', 'convertpro'); ?>:</div> |
| 214 |
<div class="percentage"><?php esc_html_e('Share', 'convertpro'); ?>:</div> |
| 215 |
<div class="convertpro-class-gen"><?php esc_html_e('CSS class', 'convertpro'); ?>:</div> |
| 216 |
<?php // Matches the row's actions column so every label sits over its own field. ?> |
| 217 |
<div class="actions" aria-hidden="true"></div> |
| 218 |
|
| 219 |
</div> |
| 220 |
<div id="variations-container"> |
| 221 |
<?php |
| 222 |
$i = 0; |
| 223 |
foreach ($test->variations as $variation) { |
| 224 |
|
| 225 |
?> |
| 226 |
<div class="convertpro-data-variation" data-variation-id="<?php echo esc_attr($variation->id); ?>"> |
| 227 |
<input type="hidden" name="test-variation[<?php echo esc_attr($i); ?>][id]" value="<?php echo esc_attr($variation->id); ?>"> |
| 228 |
<div class="name"> |
| 229 |
<input class="variation-name" name="test-variation[<?php echo esc_attr($i); ?>][name]" type="text" value="<?php echo esc_attr($variation->name); ?>" /> |
| 230 |
</div> |
| 231 |
<div class="post"> |
| 232 |
<select name="test-variation[<?php echo esc_attr($i); ?>][page-id]"> |
| 233 |
<option value="null" disabled selected><?php echo esc_attr('Select Page'); ?></option> |
| 234 |
<?php foreach ($pages as $page) { ?> |
| 235 |
<option value="<?php echo esc_attr($page->ID); ?>" <?php if (isset($variation->page_id) && $variation->page_id == $page->ID) { |
| 236 |
echo 'selected="selected"'; |
| 237 |
} ?>><?php echo esc_html(convertpro_page_option_label($page, $pages)); ?></option> |
| 238 |
|
| 239 |
<?php } ?> |
| 240 |
</select> |
| 241 |
</div> |
| 242 |
|
| 243 |
<div class="percentage"> |
| 244 |
<input name="test-variation[<?php echo esc_attr($i); ?>][percentage]" type="number" min="1" max="100" step="1" value="<?php echo esc_attr($variation->percentage); ?>" placeholder="<?php esc_attr_e('Share', 'convertpro'); ?>" required /> |
| 245 |
</div> |
| 246 |
<div class="convertpro-class-gen"> |
| 247 |
<input name="test-variation[<?php echo esc_attr($i); ?>][customclass]" type="text" value="<?php echo esc_attr($variation->class_name); ?>" placeholder="<?php esc_attr_e('CSS class', 'convertpro'); ?>" /> |
| 248 |
<div class="copy-button" onclick="copyToClipboard(this.previousElementSibling)">Copy</div> |
| 249 |
</div> |
| 250 |
|
| 251 |
<div class="actions"> |
| 252 |
<div class="button-delete">×</div> |
| 253 |
</div> |
| 254 |
</div> |
| 255 |
|
| 256 |
|
| 257 |
<?php $i++; |
| 258 |
} ?> |
| 259 |
|
| 260 |
</div> |
| 261 |
<?php do_action('convertpro-variation-btn') ?> |
| 262 |
|
| 263 |
<?php $convertpro_variation_cap = convertpro_free_limit('variations'); ?> |
| 264 |
<?php if ($convertpro_variation_cap) : ?> |
| 265 |
<p class="convertpro-variation-cap" style="display:none"> |
| 266 |
<?php |
| 267 |
printf( |
| 268 |
/* translators: %d: number of versions a test compares. */ |
| 269 |
esc_html(_n('A test compares %d version.', 'A test compares %d versions — A against B. Run a second test to try a third idea.', $convertpro_variation_cap, 'convertpro')), |
| 270 |
(int) $convertpro_variation_cap |
| 271 |
); |
| 272 |
?> |
| 273 |
</p> |
| 274 |
<?php endif; ?> |
| 275 |
|
| 276 |
<?php |
| 277 |
// Only the note for the current type starts visible; the script swaps |
| 278 |
// them when the type changes. |
| 279 |
$convertpro_current_type = isset($test->test_type) ? $test->test_type : ''; |
| 280 |
?> |
| 281 |
<p class="convertpro-variation-help convertpro-help-elements"<?php echo 'elements' === $convertpro_current_type ? '' : ' style="display:none"'; ?>> |
| 282 |
<?php esc_html_e('Copy each class and paste it into the CSS class field of the matching element in your page builder. Visitors see one version and the rest stay hidden.', 'convertpro'); ?> |
| 283 |
</p> |
| 284 |
<p class="convertpro-variation-help convertpro-help-pages"<?php echo 'pages' === $convertpro_current_type ? '' : ' style="display:none"'; ?>> |
| 285 |
<?php esc_html_e('The shares decide how traffic is divided and need to add up to 100. Once someone lands on a version, they keep seeing it.', 'convertpro'); ?> |
| 286 |
</p> |
| 287 |
</div> |
| 288 |
|
| 289 |
|
| 290 |
|
| 291 |
<?php $convertpro_goal = (isset($test->conversion_type) && 'click' === $test->conversion_type) ? 'click' : 'page'; ?> |
| 292 |
|
| 293 |
<div class="convertpro-goal-card"> |
| 294 |
<div class="test-conversion-page"> |
| 295 |
<h4><?php esc_html_e('What counts as a conversion', 'convertpro'); ?></h4> |
| 296 |
<p><?php esc_html_e('How we know a visitor did the thing you are testing for.', 'convertpro'); ?></p> |
| 297 |
</div> |
| 298 |
<select name="test-conversion-type" id="test-conversion-type" style="width: 100%;"> |
| 299 |
<option value="page" <?php selected($convertpro_goal, 'page'); ?>><?php esc_html_e('Reaching a page on this site', 'convertpro'); ?></option> |
| 300 |
<option value="click" <?php selected($convertpro_goal, 'click'); ?>><?php esc_html_e('Clicking a link or button', 'convertpro'); ?></option> |
| 301 |
</select> |
| 302 |
|
| 303 |
<div class="convertpro-conversion-page-wrapper convertpro-goal-field"> |
| 304 |
<label for="test-conversion-page"><?php esc_html_e('Which page', 'convertpro'); ?></label> |
| 305 |
<p class="convertpro-goal-hint"><?php esc_html_e('Reaching this page counts as a conversion.', 'convertpro'); ?></p> |
| 306 |
<select name="test-conversion-page" id="test-conversion-page" style="width: 100%;"> |
| 307 |
<option value="null" disabled selected><?php esc_html_e('Select a page', 'convertpro'); ?></option> |
| 308 |
<?php |
| 309 |
foreach ($pages as $page) { ?> |
| 310 |
<option value="<?php echo esc_attr($page->ID); ?>" <?php if (isset($test->conversion_page_id) && $test->conversion_page_id == $page->ID) { |
| 311 |
echo ('selected="selected"'); |
| 312 |
} ?>><?php echo esc_html(convertpro_page_option_label($page, $pages)); ?></option> |
| 313 |
<?php } ?> |
| 314 |
</select> |
| 315 |
</div> |
| 316 |
|
| 317 |
<div class="test-conversion-url-wrapper convertpro-goal-field"> |
| 318 |
<label for="test-conversion-selector"><?php esc_html_e('Which link or button', 'convertpro'); ?></label> |
| 319 |
<p class="convertpro-goal-hint"><?php esc_html_e('Its CSS class or id, or part of the address it points to. Use this when the next step is somewhere we cannot see, like a checkout on another site. Separate several with commas.', 'convertpro'); ?></p> |
| 320 |
<input type="text" name="test-conversion-selector" id="test-conversion-selector" |
| 321 |
value="<?php echo isset($test->conversion_url) ? esc_attr($test->conversion_url) : ''; ?>" |
| 322 |
placeholder="<?php esc_attr_e('.buy-now, #checkout-button, or checkout.example.com', 'convertpro'); ?>" /> |
| 323 |
</div> |
| 324 |
</div> |
| 325 |
<div class="submit-btn"> |
| 326 |
<input type="hidden" name="variation-count" value="<?php echo esc_attr($i); ?>" /> |
| 327 |
<input type="hidden" name="test-id" value="<?php echo (isset($test->id) ? esc_attr($test->id) : ''); ?>" /> |
| 328 |
<input class="test-button-save" type="submit" value="<?php esc_html_e('Save Test', 'convertpro'); ?>" /> |
| 329 |
|
| 330 |
</div> |
| 331 |
</form> |
| 332 |
|
| 333 |
</div> |