Unbounce Landing Pages - Version 0.1.7

Version Description

  • Documentation changes
Download this release

Release Info

Developer unbouncewordpress
Plugin Icon Unbounce Landing Pages
Version 0.1.7
Comparing to
See all releases

Version 0.1.7

Files changed (7) hide show
  1. UBConfig.php +179 -0
  2. UBHTTP.php +231 -0
  3. UBIcon.php +9 -0
  4. UBLogger.php +118 -0
  5. UBUtil.php +14 -0
  6. Unbounce-Page.php +153 -0
  7. readme.txt +73 -0
UBConfig.php ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class UBConfig {
4
+
5
+ const UB_PLUGIN_NAME = 'ub-wordpress';
6
+ const UB_ROUTES_CACHE_KEY = 'ub-route-cache';
7
+ const UB_REMOTE_DEBUG_KEY = 'ub-remote-debug';
8
+ const UB_CACHE_TIMEOUT_ENV_KEY = 'UB_WP_ROUTES_CACHE_EXP';
9
+ const UB_USER_AGENT = 'Unbounce WP Plugin 0.1.7';
10
+ const UB_VERSION = '0.1.7';
11
+
12
+ public static function get_page_server_domain() {
13
+ $domain = getenv('UB_PAGE_SERVER_DOMAIN');
14
+ return $domain ? $domain : 'wp.unbounce.com';
15
+ }
16
+
17
+ public static function get_remote_log_url() {
18
+ $url = getenv('UB_REMOTE_LOG_URL');
19
+ if ($url == null) {
20
+ return 'https://events-gateway.unbounce.com/events/wordpress_logs';
21
+ }
22
+ return $url;
23
+ }
24
+
25
+ public static function debug_loggging_enabled() {
26
+ return WP_DEBUG || WP_DEBUG_LOG || UBConfig::remote_debug_logging_enabled();
27
+ }
28
+
29
+ public static function remote_debug_logging_enabled() {
30
+ return get_option(UBConfig::UB_REMOTE_DEBUG_KEY, 0) == 1;
31
+ }
32
+
33
+ public static function fetch_proxyable_url_set($domain, $etag) {
34
+ if(!$domain) {
35
+ UBLogger::warning('Domain not provided, not fetching wp-routes.json');
36
+ return array('FAILURE', null, null, null);
37
+ }
38
+
39
+ $url = 'https://' . UBConfig::get_page_server_domain() . '/wp-routes.json';
40
+ $curl = curl_init();
41
+ $curl_options = array(
42
+ CURLOPT_URL => $url,
43
+ CURLOPT_CUSTOMREQUEST => "GET",
44
+ CURLOPT_HEADER => true,
45
+ CURLOPT_USERAGENT => UBConfig::UB_USER_AGENT,
46
+ CURLOPT_HTTPHEADER => array('Host: ' . $domain, 'If-None-Match: ' . $etag),
47
+ CURLOPT_RETURNTRANSFER => true,
48
+ CURLOPT_FOLLOWLOCATION => false,
49
+ CURLOPT_TIMEOUT => 5
50
+ );
51
+
52
+ UBLogger::debug("Retrieving routes from '$url', etag: '$etag', host: '$domain'");
53
+
54
+ curl_setopt_array($curl, $curl_options);
55
+ $data = curl_exec($curl);
56
+
57
+ $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
58
+ $curl_error = null;
59
+
60
+ // when having an CURL error, http_code is 0
61
+ if ($http_code == 0) {
62
+ $curl_error = curl_error($curl);
63
+ }
64
+
65
+ curl_close($curl);
66
+
67
+ list($headers, $body) = array_pad(explode("\r\n\r\n", $data, 2), 2, null);
68
+
69
+ $matches = array();
70
+ $does_match = preg_match('/ETag: (\S+)/is', $headers, $matches);
71
+ if ($does_match) {
72
+ $etag = $matches[1];
73
+ }
74
+
75
+ $matches = array();
76
+ $does_match = preg_match('/Cache-Control: max-age=(\S+)/is', $headers, $matches);
77
+ if ($does_match) {
78
+ $max_age = $matches[1];
79
+ }
80
+
81
+ if ($http_code == 200) {
82
+ $json_body = json_decode($body);
83
+
84
+ if (is_null($json_body)) {
85
+ $json_error = json_last_error();
86
+ UBLogger::warning("An error occurred while processing routes, JSON error: '$json_error'");
87
+ return array('FAILURE', null, null, null);
88
+ }
89
+ else {
90
+ UBLogger::debug("Retrieved new routes, HTTP code: '$http_code'");
91
+ return array('NEW', $etag, $max_age, $json_body);
92
+ }
93
+ }
94
+ if ($http_code == 304) {
95
+ UBLogger::debug("Routes have not changed, HTTP code: '$http_code'");
96
+ return array('SAME', $etag, $max_age, null);
97
+ }
98
+ if ($http_code == 404) {
99
+ UBLogger::debug("No routes to retrieve, HTTP code: '$http_code'");
100
+ return array('NONE', null, null, null);
101
+ }
102
+ else {
103
+ UBLogger::warning("An error occurred while retrieving routes; HTTP code: '$http_code'; Error: " . $curl_error);
104
+ return array('FAILURE', null, null, null);
105
+ }
106
+ }
107
+
108
+ public static function _read_unbounce_domain_info($cache_getter,
109
+ $cache_setter,
110
+ $fetch_proxyable_url_set,
111
+ $domain,
112
+ $expire_now=false) {
113
+
114
+ $proxyable_url_set = null;
115
+
116
+ $cache_max_time_default = 10;
117
+
118
+ $domains_info = $cache_getter(UBConfig::UB_ROUTES_CACHE_KEY);
119
+ $domain_info = UBUtil::array_fetch($domains_info, $domain, array());
120
+
121
+ $proxyable_url_set = UBUtil::array_fetch($domain_info, 'proxyable_url_set');
122
+ $proxyable_url_set_fetched_at = UBUtil::array_fetch($domain_info, 'proxyable_url_set_fetched_at');
123
+ $proxyable_url_set_cache_timeout = UBUtil::array_fetch($domain_info, 'proxyable_url_set_cache_timeout');
124
+ $proxyable_url_set_etag = UBUtil::array_fetch($domain_info, 'proxyable_url_set_etag');
125
+
126
+ $cache_max_time = is_null($proxyable_url_set_cache_timeout) ? $cache_max_time_default : $proxyable_url_set_cache_timeout;
127
+
128
+ $current_time = time();
129
+
130
+ if ($expire_now ||
131
+ is_null($proxyable_url_set) ||
132
+ ($current_time - $proxyable_url_set_fetched_at > $cache_max_time)) {
133
+
134
+ $result_array = call_user_func($fetch_proxyable_url_set, $domain, $proxyable_url_set_etag);
135
+
136
+ list($routes_status, $etag, $max_age, $proxyable_url_set_new) = $result_array;
137
+
138
+ if ($routes_status == 'NEW') {
139
+ $domain_info['proxyable_url_set'] = $proxyable_url_set_new;
140
+ $domain_info['proxyable_url_set_etag'] = $etag;
141
+ $domain_info['proxyable_url_set_cache_timeout'] = $max_age;
142
+ }
143
+ elseif ($routes_status == 'SAME') {
144
+ // Just extend the cache
145
+ $domain_info['proxyable_url_set_cache_timeout'] = $max_age;
146
+ }
147
+ elseif ($routes_status == 'NONE') {
148
+ $domain_info['proxyable_url_set'] = array();
149
+ $domain_info['proxyable_url_set_etag'] = null;
150
+ }
151
+ elseif ($routes_status == 'FAILURE') {
152
+ UBLogger::warning('Route fetching failed');
153
+ }
154
+ else {
155
+ UBLogger::warning("Unknown response from route fetcher: '$routes_status'");
156
+ }
157
+
158
+ $domain_info['proxyable_url_set_fetched_at'] = $current_time;
159
+ $domains_info[$domain] = $domain_info;
160
+ $cache_setter(UBConfig::UB_ROUTES_CACHE_KEY, $domains_info);
161
+ }
162
+
163
+
164
+ return UBUtil::array_select_by_key($domain_info,
165
+ array('proxyable_url_set',
166
+ 'proxyable_url_set_fetched_at'));
167
+ }
168
+
169
+ public static function read_unbounce_domain_info($domain, $expire_now) {
170
+ return UBConfig::_read_unbounce_domain_info(
171
+ 'get_option',
172
+ 'update_option',
173
+ 'UBConfig::fetch_proxyable_url_set',
174
+ $domain,
175
+ $expire_now);
176
+ }
177
+
178
+ }
179
+ ?>
UBHTTP.php ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class UBHTTP {
4
+ private static $powered_by_header_regex = '/^X-Powered-By: (.+)$/i';
5
+ private static $form_confirmation_url_regex = '/(.+)\/[a-z]+-form_confirmation\.html/';
6
+ private static $forward_headers = '/^(Content-Type:|Location:|ETag:|Last-Modified:|Link:|Content-Location:|Set-Cookie:|X-Server-Instance:|X-Unbounce-PageId:|X-Unbounce-Variant:|X-Unbounce-VisitorID:)/i';
7
+
8
+
9
+ public static function is_private_ip_address($ip_address) {
10
+ return !filter_var($ip_address,
11
+ FILTER_VALIDATE_IP,
12
+ FILTER_FLAG_NO_PRIV_RANGE + FILTER_FLAG_NO_RES_RANGE);
13
+ }
14
+
15
+ public static function cookie_string_from_array($cookies) {
16
+ $join_cookie_values = function ($k, $v) { return $k . '=' . $v; };
17
+ $cookie_strings = array_map($join_cookie_values,
18
+ array_keys($cookies),
19
+ $cookies);
20
+ return join('; ', $cookie_strings);
21
+ }
22
+
23
+ private static function fetch_header_value_function($regex) {
24
+ return function ($header_string) use ($regex) {
25
+ $matches = array();
26
+ preg_match($regex,
27
+ $header_string,
28
+ $matches);
29
+ return $matches[1];
30
+ };
31
+ }
32
+
33
+ public static function rewrite_x_powered_by_header($header_string, $existing_headers) {
34
+ $fetch_powered_by_value = UBHTTP::fetch_header_value_function(UBHTTP::$powered_by_header_regex);
35
+
36
+ $existing_powered_by = preg_grep(UBHTTP::$powered_by_header_regex,
37
+ $existing_headers);
38
+
39
+ $existing_powered_by = array_map($fetch_powered_by_value,
40
+ $existing_powered_by);
41
+
42
+ return 'X-Powered-By: ' .
43
+ join($existing_powered_by, ', ') . ', ' .
44
+ $fetch_powered_by_value($header_string);
45
+ }
46
+
47
+ public static function get_proxied_for_header($out_headers,
48
+ $request_headers,
49
+ $current_ip) {
50
+ $forwarded_for = UBUtil::array_fetch($request_headers, 'X-Forwarded-For');
51
+
52
+ if($forwarded_for !== null && UBHTTP::is_private_ip_address($current_ip)) {
53
+ $proxied_for = $forwarded_for;
54
+ } else {
55
+ $proxied_for = $current_ip;
56
+ }
57
+
58
+ $out_headers[] = 'X-Proxied-For: ' . $proxied_for;
59
+ return $out_headers;
60
+ }
61
+
62
+ public static function stream_headers_function($existing_headers) {
63
+ return function ($curl, $header_string) use ($existing_headers) {
64
+ $http_status_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
65
+
66
+ http_response_code($http_status_code);
67
+
68
+ if(preg_match(UBHTTP::$powered_by_header_regex, $header_string) == 1) {
69
+ $result = UBHTTP::rewrite_x_powered_by_header($header_string, $existing_headers);
70
+ header($result);
71
+
72
+ } elseif (preg_match(UBHTTP::$forward_headers, $header_string)) {
73
+ // false means don't replace the exsisting header
74
+ header($header_string, false);
75
+ }
76
+
77
+ // We must show curl that we've processed every byte of the input header
78
+ return strlen($header_string);
79
+ };
80
+ }
81
+
82
+ public static function stream_response_function() {
83
+ return function ($curl, $string) {
84
+ // Stream the body to the client
85
+ echo $string;
86
+
87
+ // We must show curl that we've processed every byte of the input string
88
+ return strlen($string);
89
+ };
90
+ }
91
+
92
+ public static function determine_protocol($server_global, $wp_is_ssl) {
93
+ $forwarded_proto = UBUtil::array_fetch($server_global, 'HTTP_X_FORWARDED_PROTO');
94
+ $request_scheme = UBUtil::array_fetch($server_global, 'REQUEST_SCHEME');
95
+ $script_uri = UBUtil::array_fetch($server_global, 'SCRIPT_URI');
96
+ $script_uri_scheme = parse_url($script_uri, PHP_URL_SCHEME);
97
+ $https = UBUtil::array_fetch($server_global, 'HTTPS', 'off');
98
+
99
+ // X-Forwarded-Proto should be respected first, as it is what the end
100
+ // user will see (if Wordpress is behind a load balancer).
101
+ if(UBHTTP::is_valid_protocol($forwarded_proto)) {
102
+ return $forwarded_proto . '://';
103
+ }
104
+ // Next use REQUEST_SCHEME, if it is available. This is the recommended way
105
+ // to get the protocol, but it is not available on all hosts.
106
+ elseif(UBHTTP::is_valid_protocol($request_scheme)) {
107
+ return $request_scheme . '://';
108
+ }
109
+ // Next try to pull it out of the SCRIPT_URI. This is also not always available.
110
+ elseif(UBHTTP::is_valid_protocol($script_uri_scheme)) {
111
+ return $script_uri_scheme . '://';
112
+ }
113
+ // Wordpress' is_ssl() may return the correct boolean for http/https if
114
+ // the site was setup properly.
115
+ elseif($wp_is_ssl || !is_null($https) && $https !== 'off') {
116
+ return 'https://';
117
+ }
118
+ // We default to http as most HTTPS sites will also have HTTP available.
119
+ else {
120
+ return 'http://';
121
+ }
122
+ }
123
+
124
+ private static function is_valid_protocol($protocol) {
125
+ return $protocol === 'http' || $protocol === 'https';
126
+ }
127
+
128
+ public static function stream_request($method,
129
+ $target_url,
130
+ $cookie_string,
131
+ $headers0,
132
+ $post_body = null,
133
+ $user_agent) {
134
+
135
+ $existing_headers = headers_list();
136
+ $request_headers = getallheaders();
137
+ $remote_ip = $_SERVER['REMOTE_ADDR'];
138
+
139
+ $headers = UBHTTP::get_proxied_for_header($headers0,
140
+ $request_headers,
141
+ $remote_ip);
142
+
143
+ UBLogger::debug_var('target_url', $target_url);
144
+
145
+ $stream_headers = UBHTTP::stream_headers_function($existing_headers);
146
+ $stream_body = UBHTTP::stream_response_function();
147
+ $curl = curl_init();
148
+ // http://php.net/manual/en/function.curl-setopt.php
149
+ $curl_options = array(
150
+ CURLOPT_URL => $target_url,
151
+ CURLOPT_POST => $method == "POST",
152
+ CURLOPT_CUSTOMREQUEST => $method,
153
+ CURLOPT_USERAGENT => $user_agent,
154
+ CURLOPT_COOKIE => $cookie_string,
155
+ CURLOPT_HTTPHEADER => $headers,
156
+ CURLOPT_HEADERFUNCTION => $stream_headers,
157
+ CURLOPT_WRITEFUNCTION => $stream_body,
158
+ CURLOPT_FOLLOWLOCATION => false,
159
+ CURLOPT_TIMEOUT => 5
160
+ );
161
+
162
+ if ($method == "POST" && $post_body != null) {
163
+ $curl_options[CURLOPT_POSTFIELDS] = http_build_query($post_body);
164
+ }
165
+
166
+ curl_setopt_array($curl, $curl_options);
167
+ $resp = curl_exec($curl);
168
+ if(!$resp){
169
+ $message = 'Error proxying to "' . $target_url . ", " . $original_target_url
170
+ . '": "' . curl_error($curl) . '" - Code: ' . curl_errno($curl);
171
+ UBLogger::warning($message);
172
+ http_response_code(500);
173
+ }
174
+ curl_close($curl);
175
+ }
176
+
177
+ public static function is_extract_url_proxyable($proxyable_url_set,
178
+ $extract_regex,
179
+ $match_position,
180
+ $url) {
181
+ $matches = array();
182
+ $does_match = preg_match($extract_regex,
183
+ $url,
184
+ $matches);
185
+
186
+ return $does_match && in_array($matches[1], $proxyable_url_set);
187
+ }
188
+
189
+ public static function is_confirmation_dialog($proxyable_url_set, $url_without_protocol) {
190
+ return UBHTTP::is_extract_url_proxyable($proxyable_url_set,
191
+ UBHTTP::$form_confirmation_url_regex,
192
+ 1,
193
+ $url_without_protocol);
194
+ }
195
+
196
+ public static function is_tracking_link($proxyable_url_set, $url_without_protocol) {
197
+ return UBHTTP::is_extract_url_proxyable($proxyable_url_set,
198
+ "/^(.+)?\/(clkn|clkg)\/?/",
199
+ 1,
200
+ $url_without_protocol);
201
+ }
202
+
203
+ public static function get_url_purpose($proxyable_url_set, $http_method, $url) {
204
+ $host = parse_url($url, PHP_URL_HOST);
205
+ $path = parse_url($url, PHP_URL_PATH);
206
+ $url_without_protocol = $host . $path;
207
+
208
+ if ($http_method == "POST" &&
209
+ preg_match("/^\/(fsn|fsg|fs)\/?$/", $path)) {
210
+
211
+ return "SubmitLead";
212
+
213
+ } elseif ($http_method == "GET" &&
214
+ UBHTTP::is_tracking_link($proxyable_url_set, $url_without_protocol)) {
215
+
216
+ return "TrackClick";
217
+
218
+ } elseif ($http_method == "GET" &&
219
+ (in_array($url_without_protocol, $proxyable_url_set) ||
220
+ UBHTTP::is_confirmation_dialog($proxyable_url_set, $url_without_protocol))) {
221
+
222
+ return "ViewLandingPage";
223
+
224
+ } else {
225
+ return null;
226
+ }
227
+ }
228
+
229
+ }
230
+
231
+ ?>
UBIcon.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class UBIcon {
4
+ public static function base64_encoded_svg() {
5
+ return 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmlld0JveD0iMCAwIDI1Mi43ODY2NyAyNTIuNzg2NjciCiAgIGhlaWdodD0iMjUyLjc4NjY3IgogICB3aWR0aD0iMjUyLjc4NjY3IgogICB4bWw6c3BhY2U9InByZXNlcnZlIgogICB2ZXJzaW9uPSIxLjEiCiAgIGlkPSJzdmcyIj48bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGE4Ij48cmRmOlJERj48Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+PGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+PGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPjwvY2M6V29yaz48L3JkZjpSREY+PC9tZXRhZGF0YT48ZGVmcwogICAgIGlkPSJkZWZzNiIgLz48ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMzMzMzMzMywwLDAsLTEuMzMzMzMzMywwLDI1Mi43ODY2NykiCiAgICAgaWQ9ImcxMCI+PGcKICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMC4xKSIKICAgICAgIGlkPSJnMTIiPjxwYXRoCiAgICAgICAgIGlkPSJwYXRoMTQiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiCiAgICAgICAgIGQ9Ik0gOTQ3Ljk1MywxODk1LjkgQyA0MjQuMzkxLDE4OTUuOSAwLDE0NzEuNDkgMCw5NDcuOTUzIDAsNDI0LjQxNCA0MjQuMzkxLDAgOTQ3Ljk1MywwIGMgNTIzLjU2NywwIDk0Ny45NTcsNDI0LjQxNCA5NDcuOTU3LDk0Ny45NTMgMCw1MjMuNTM3IC00MjQuMzksOTQ3Ljk0NyAtOTQ3Ljk1Nyw5NDcuOTQ3IHogTSA2ODUuODU1LDI4MS4yMjcgYyAxMC40ODUsNjcuNDg4IDIwLjQ4MSwxMjkuNTA3IDI5LjgyNSwxODYuNzQyIC0yMDguNzc0LDEwNC42NDQgLTM0MS4wODIsMzE1LjMxNiAtMzA3LjM0LDU1OC43OTEgNDYuMDU4LDMzMC42NyAzMDAuNjY0LDUwMC4yNSA2MjAuODYsNDcxLjQgMjQuMjgsMzQuMzcgNTAuOTMsNjcuMzUgODEuMjYsOTkuMjYgNTQuMDIsNjAuMzkgMTM0LjM1LDYyLjI5IDk4LjIyLC05LjI4IC03Mi44MiwtMTM3LjggLTEwMS42LC0yNDEuODQgLTE2NC4xNSwtNDA4LjkyIC02Mi4zNDIsLTE3Ny43IC0xNTguNzA2LC00MzguNTEzIC0yODYuOTg3LC04OTYuNDYyIC05LjI3NywtNDEuOTM0IC03NS4wMDQsLTM1LjI1IC03MS42ODgsLTEuNTMxIHogTSAxNDg4LjA1LDg4OC40ODQgQyAxNDQ2LjQyLDU3Mi43NSAxMTUxLjMsMzkzLjU3IDg1Ny45NDUsNDI0LjUwOCBjIDIxLjI5Myw3MS45ODggMzEuMzc5LDEwMi42OTEgNTYuMDU5LDE2MC43MTkgMTguNjIxLDMzLjQ4OCA4OC4zMzYsNDcuMTc1IDE0Mi40NjYsNzAuMTgzIDEwOS45NSwzOS41MTYgMTk0LjM5LDEzNy42NiAyMTAuMzUsMjYxLjUxMiAxMS4yMyw4Ny44MDggLTE0LjQyLDE3MS45NDggLTY0LjcsMjM2Ljk3OCAtMzUuMTYsNDQuNjIgLTY4LjMsNzEuNjYgLTU2Ljk4LDExMy41NSAxNi42NSw1Ni41NCAyOS40Miw5OC41MSA2MC40OCwxNjkuNTggMTkyLjc1LC0xMDMuNTMgMzEyLjkxLC0zMTguNTcgMjgyLjQzLC01NDguNTQ2IiAvPjxwYXRoCiAgICAgICAgIGlkPSJwYXRoMTYiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiCiAgICAgICAgIGQ9Im0gNjI5LjgwMSw5OTguNDY1IGMgLTEwLjg3NSwtODQuNDY5IDEyLjEyOSwtMTY1LjA4MiA1OC4yMzQsLTIyOC42NzYgMzAuNzMxLC00MS4wNDcgNTQuMjcsLTY0Ljk4IDY1Ljc5NywtODMuODEyIDM3Ljk4OCwyMDUuNzA3IDY1LjQwMiwzMTIuMTE3IDEwMS45MzgsNDMxLjUwMyAxNi4zNzUsNDkuODcgNDMuNTA3LDExOS44MiA2My4xNDgsMTY3LjQ1IC0yMy40MjYsLTcuODQgLTU2LjY1NiwtMTYuNTYgLTgzLjc5NywtMjcuMTggLTEwNy40OTIsLTQwLjMxIC0xODkuNjY4LC0xMzcuNDQgLTIwNS4zMiwtMjU5LjI4NSIgLz48L2c+PC9nPjwvc3ZnPg==';
6
+ }
7
+ }
8
+
9
+ ?>
UBLogger.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once dirname(__FILE__) . '/UBConfig.php';
4
+
5
+ class UBLogger {
6
+
7
+ // should be called when the plugin is loaded
8
+ public static function setup_logger() {
9
+ if(!isset($GLOBALS['wp_log_plugins'])) {
10
+ $GLOBALS['wp_log_plugins'] = array();
11
+ }
12
+ $GLOBALS['wp_log_plugins'][UBConfig::UB_PLUGIN_NAME] = array();
13
+ $GLOBALS['wp_log_plugins'][UBConfig::UB_PLUGIN_NAME . '-vars'] = array();
14
+ }
15
+
16
+ public static function upload_logs_to_unbounce($url) {
17
+ if(UBConfig::remote_debug_logging_enabled()) {
18
+ $datetime = new DateTime('NOW', new DateTimeZone('UTC'));
19
+ $data = array(
20
+ 'type' => 'WordpressLogV1.0',
21
+ 'messages' => $GLOBALS['wp_log'][UBConfig::UB_PLUGIN_NAME],
22
+ 'vars' => $GLOBALS['wp_log'][UBConfig::UB_PLUGIN_NAME . '-vars'],
23
+ 'id' => uniqid(),
24
+ 'time_sent' => $datetime->format('Y-m-d\TH:i:s.000\Z'),
25
+ 'source' => UBConfig::UB_USER_AGENT . ' ' . gethostname()
26
+ );
27
+ $data_string = json_encode($data, JSON_UNESCAPED_SLASHES);
28
+
29
+ $curl = curl_init();
30
+ $curl_options = array(
31
+ CURLOPT_URL => $url,
32
+ CURLOPT_CUSTOMREQUEST => 'POST',
33
+ CURLOPT_USERAGENT => UBConfig::UB_USER_AGENT,
34
+ CURLOPT_FOLLOWLOCATION => false,
35
+ CURLOPT_HTTPHEADER => array(
36
+ 'Content-Type: application/json',
37
+ 'Content-Length: ' . strlen($data_string)
38
+ ),
39
+ CURLOPT_POSTFIELDS => $data_string,
40
+ CURLOPT_TIMEOUT => 2
41
+ );
42
+ curl_setopt_array($curl, $curl_options);
43
+ $success = curl_exec($curl);
44
+ $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
45
+
46
+ if(!$success) {
47
+ $message = 'Unable to send log messages to ' . $url . ': "'
48
+ . curl_error($curl) . '" - HTTP status: ' . curl_errno($curl);
49
+ UBLogger::warning($message);
50
+ } elseif($http_code >= 200 && $http_code < 300) {
51
+ $message = 'Successfully sent log messsages to ' . $url
52
+ . ' - HTTP status: ' . $http_code;
53
+ UBLogger::debug($message);
54
+ } else {
55
+ $message = 'Unable to send log messages to ' . $url
56
+ . ' - HTTP status: ' . $http_code;
57
+ UBLogger::warning($message);
58
+ }
59
+
60
+ curl_close($curl);
61
+ }
62
+ }
63
+
64
+ public static function format_log_entry($level, $msg) {
65
+ $msg = is_string($msg) ? $msg : print_r($msg, true);
66
+ return '[' . UBConfig::UB_PLUGIN_NAME . '] [' . $level . '] ' . $msg;
67
+ }
68
+
69
+ private static function log_wp_log($log_entry) {
70
+ $GLOBALS['wp_log'][UBConfig::UB_PLUGIN_NAME][] = $log_entry;
71
+ }
72
+
73
+ private static function log_wp_log_var($var, $val) {
74
+ $GLOBALS['wp_log'][UBConfig::UB_PLUGIN_NAME . '-vars'][$var] = $val;
75
+ }
76
+
77
+ private static function log_error_log($log_entry) {
78
+ error_log($log_entry);
79
+ }
80
+
81
+ public static function log($level, $msg) {
82
+ if(UBConfig::debug_loggging_enabled()) {
83
+ $log_entry = UBLogger::format_log_entry($level, $msg);
84
+ UBLogger::log_wp_log($log_entry);
85
+ UBLogger::log_error_log($log_entry);
86
+ }
87
+ }
88
+
89
+ public static function log_var($level, $var, $val) {
90
+ if(UBConfig::debug_loggging_enabled()) {
91
+ UBLogger::log($level, '$' . $var . ': ' . $val);
92
+ UBLogger::log_wp_log_var($var, $val);
93
+ }
94
+ }
95
+
96
+ public static function info($msg) {
97
+ UBLogger::log('INFO', $msg);
98
+ }
99
+
100
+ public static function warning($msg) {
101
+ UBLogger::log('WARNING', $msg);
102
+ }
103
+
104
+ public static function debug($msg) {
105
+ UBLogger::log('DEBUG', $msg);
106
+ }
107
+
108
+ public static function debug_var($var, $val) {
109
+ UBLogger::log_var('DEBUG', $var, $val);
110
+ }
111
+
112
+ public static function config($msg) {
113
+ UBLogger::log('CONFIG', $msg);
114
+ }
115
+
116
+ }
117
+
118
+ ?>
UBUtil.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class UBUtil {
4
+
5
+ public static function array_select_by_key($input, $keep) {
6
+ return array_intersect_key($input, array_flip($keep));
7
+ }
8
+
9
+ public static function array_fetch($array, $index, $default = null) {
10
+ return isset($array[$index]) ? $array[$index] : $default;
11
+ }
12
+
13
+ }
14
+ ?>
Unbounce-Page.php ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Unbounce
4
+ Plugin URI: http://unbounce.com
5
+ Description: Publish Unbounce Landing Pages to your Wordpress Domain.
6
+ Version: 0.1.7
7
+ Author: Unbounce
8
+ Author URI: http://unbounce.com
9
+ License: GPLv2
10
+ */
11
+
12
+ require_once dirname(__FILE__) . '/UBUtil.php';
13
+ require_once dirname(__FILE__) . '/UBConfig.php';
14
+ require_once dirname(__FILE__) . '/UBLogger.php';
15
+ require_once dirname(__FILE__) . '/UBHTTP.php';
16
+ require_once dirname(__FILE__). '/UBIcon.php';
17
+
18
+ register_activation_hook(__FILE__, function() {
19
+ add_option(UBConfig::UB_ROUTES_CACHE_KEY, array());
20
+ add_option(UBConfig::UB_REMOTE_DEBUG_KEY, 0);
21
+ });
22
+
23
+ register_deactivation_hook(__FILE__, function() {
24
+ delete_option(UBConfig::UB_ROUTES_CACHE_KEY);
25
+ delete_option(UBConfig::UB_REMOTE_DEBUG_KEY);
26
+ });
27
+
28
+ add_action('init', function() {
29
+ UBLogger::setup_logger();
30
+
31
+ $start = microtime(true);
32
+
33
+ $ps_domain = UBConfig::get_page_server_domain();
34
+ $http_method = UBUtil::array_fetch($_SERVER, 'REQUEST_METHOD');
35
+ $referer = UBUtil::array_fetch($_SERVER, 'HTTP_REFERER');
36
+ $user_agent = UBUtil::array_fetch($_SERVER, 'HTTP_USER_AGENT');
37
+ $protocol = UBHTTP::determine_protocol($_SERVER, is_ssl());
38
+ $domain = UBUtil::array_fetch($_SERVER, 'HTTP_HOST');
39
+ $current_path = UBUtil::array_fetch($_SERVER, 'REQUEST_URI');
40
+
41
+ $raw_url = $protocol . $ps_domain . $current_path;
42
+ $current_url = trim($protocol . $domain . $current_path, '/');
43
+
44
+ $domain_info = UBConfig::read_unbounce_domain_info($domain, false);
45
+ $proxyable_url_set = UBUtil::array_fetch($domain_info, 'proxyable_url_set', array());
46
+
47
+ UBLogger::debug_var('ps_domain', $ps_domain);
48
+ UBLogger::debug_var('http_method', $http_method);
49
+ UBLogger::debug_var('referer', $referer);
50
+ UBLogger::debug_var('user_agent', $user_agent);
51
+ UBLogger::debug_var('protocol', $protocol);
52
+ UBLogger::debug_var('domain', $domain);
53
+ UBLogger::debug_var('current_path', $current_path);
54
+ UBLogger::debug_var('raw_url', $raw_url);
55
+ UBLogger::debug_var('current_url ', $current_url );
56
+
57
+ ////////////////////
58
+
59
+ if ($proxyable_url_set == null) {
60
+ UBLogger::warning("wp-routes.json not found for domain " . $domain);
61
+ }
62
+ else {
63
+ $url_purpose = UBHTTP::get_url_purpose($proxyable_url_set,
64
+ $http_method,
65
+ $current_url);
66
+ if ($url_purpose == null) {
67
+ UBLogger::debug("ignoring request to URL " . $current_url);
68
+ }
69
+ else {
70
+ UBLogger::debug("perform ''" . $url_purpose . "'' on received URL " . $current_url);
71
+
72
+ $cookies_to_forward = UBUtil::array_select_by_key($_COOKIE,
73
+ array('ubvs', 'ubpv', 'ubvt'));
74
+
75
+ $cookie_string = UBHTTP::cookie_string_from_array($cookies_to_forward);
76
+
77
+ $req_headers = $referer == null ? array('Host: ' . $domain) : array('Referer: ' . $referer, 'Host: ' . $domain);
78
+
79
+ // Make sure we don't get cached by Wordpress hosts like WPEngine
80
+ header('Cache-Control: max-age=0; private');
81
+
82
+ UBHTTP::stream_request($http_method,
83
+ $raw_url,
84
+ $cookie_string,
85
+ $req_headers,
86
+ $_POST,
87
+ $user_agent);
88
+
89
+ $end = microtime(true);
90
+ $time_taken = ($end - $start) * 1000;
91
+
92
+ UBLogger::debug_var('time_taken', $time_taken);
93
+ UBLogger::debug("proxying for $current_url done successfuly -- took $time_taken ms");
94
+
95
+ exit(0);
96
+ }
97
+ }
98
+ });
99
+
100
+ function render_unbounce_pages($domain_info) {
101
+ echo '<h1>Unbounce Pages</h1>';
102
+
103
+ $proxyable_url_set = UBUtil::array_fetch($domain_info, 'proxyable_url_set');
104
+ if(empty($proxyable_url_set)) {
105
+ echo '<p class="warning">No URLs have been registered from Unbounce</p>';
106
+
107
+ } else {
108
+ $proxyable_url_set_fetched_at = UBUtil::array_fetch($domain_info, 'proxyable_url_set_fetched_at');
109
+
110
+ $list_items = array_map(function($url) { return '<li><a href="//'. $url .'">' . $url . '</a></li>'; },
111
+ $proxyable_url_set);
112
+
113
+ echo '<div class="unbounce-page-list">';
114
+ echo '<ul>' . join($list_items, "\n") . '</ul>';
115
+ echo '<p>Last refresh date: <span id="last-cache-fetch" style="font-weight: bold;">' . date('r', $proxyable_url_set_fetched_at) . '</span></p>';
116
+ echo '</div>';
117
+
118
+ }
119
+
120
+ $flush_pages_url = admin_url('admin-post.php?action=flush_unbounce_pages');
121
+ echo "<p><a href='$flush_pages_url'>Refresh Cache</a></p>";
122
+ echo '<p><a href="https://app.unbounce.com">Go to Unbounce</a></p>';
123
+ }
124
+
125
+ add_action('admin_menu', function() {
126
+ $print_admin_panel = function() {
127
+ $domain = UBUtil::array_fetch($_SERVER, 'HTTP_HOST');
128
+ $domain_info = UBConfig::read_unbounce_domain_info($domain, false);
129
+ render_unbounce_pages($domain_info);
130
+ };
131
+
132
+ add_menu_page('Unbounce Pages',
133
+ 'Unbounce Pages',
134
+ 'manage_options',
135
+ 'unbounce-pages',
136
+ $print_admin_panel,
137
+ UBIcon::base64_encoded_svg());
138
+ });
139
+
140
+ add_action('admin_post_flush_unbounce_pages', function() {
141
+ $domain = UBUtil::array_fetch($_SERVER, 'HTTP_HOST');
142
+ // Expire cache and redirect
143
+ $_domain_info = UBConfig::read_unbounce_domain_info($domain, true);
144
+ status_header(301);
145
+ $location = admin_url('admin.php?page=unbounce-pages');
146
+ header("Location: $location");
147
+ });
148
+
149
+ add_action('shutdown', function() {
150
+ UBLogger::upload_logs_to_unbounce(UBConfig::get_remote_log_url());
151
+ });
152
+
153
+ ?>
readme.txt ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Plugin Name ===
2
+ Contributors: unbouncewordpress
3
+ Tags: unbounce
4
+ Requires at least: 4.1.5
5
+ Tested up to: 4.2.2
6
+ Stable tag: 0.1.7
7
+ License: GPLv2 or later
8
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
+
10
+ Publish your Unbounce pages to WordPress!
11
+
12
+ == Description ==
13
+
14
+ Publish your [Unbounce](http://unbounce.com/ "The Mobile Responsive Landing Page Builder for Marketers") pages to WordPress!
15
+
16
+ This Unbounce Plug-In is in Beta Testing, if you are interested trying it out
17
+ please contact our support team at support@unbounce.com
18
+
19
+ == Installation ==
20
+
21
+ 1. Create a Wordpress domain in [Unbounce](http://unbounce.com/ "The Mobile Responsive Landing Page Builder for Marketers")
22
+ 1. Install this plugin through the WordPress store
23
+ 1. Activate this plugin after installation completes
24
+
25
+ OR
26
+
27
+ 1. Create a Wordpress domain in [Unbounce](http://unbounce.com/ "The Mobile Responsive Landing Page Builder for Marketers")
28
+ 1. Upload the zip file via the 'Plugins' menu in WordPress
29
+ 1. Activate this plugin after installation completes
30
+
31
+ == Frequently Asked Questions ==
32
+
33
+ = How do I join the beta test for this plugin? =
34
+
35
+ If you are interested trying out the plugin, please contact our support team at support@unbounce.com.
36
+
37
+ = Do I need an Unbounce account? =
38
+
39
+ Yes. You need to sign up for Unbounce in order to publish pages. To publish Unbounce pages to your
40
+ Unbounce site, you will need to add a Wordpress domain in Unbounce. For example, if you Wordpress
41
+ site is available at www.example.com, you will need to add www.example.com and publish pages in
42
+ Unbounce to that domain for them to be visible on your Wordpress site.
43
+
44
+ = Do I need to log in to Unbounce? =
45
+
46
+ No, the plugin will work without any authentication.
47
+
48
+ = Does this plugin fetch any data from Unbounce? =
49
+
50
+ Yes, this plugin will pull information from Unbounce's servers regarding which pages you have
51
+ published from Unbounce to your Wordpress site. Any pages that you have published to your Wordpress
52
+ site in Unbounce will be fetched from Unbounce's servers and displayed on your Wordpress site.
53
+ If you have a page published in Unbounce and are using the same URL for a Wordpress Page, the
54
+ Unbounce page will be displayed, not the Wordpress page.
55
+
56
+ = Does this plugin send any data to Unbounce? =
57
+
58
+ No, not by default. This plugin as an optional "debug" mode which will send diagnostic information to
59
+ Unbounce when switched on. This feature is disabled when you install the plugin. An Unbounce Customer
60
+ Success Coach may request that you turn the debug feature on if you are experiencing issues with the plugin
61
+ to help track down the issue.
62
+
63
+ == Screenshots ==
64
+
65
+ == Changelog ==
66
+
67
+ = 0.1.7 =
68
+ * Documentation changes
69
+
70
+ = 0.1.1 =
71
+ * Initial release
72
+
73
+ == Upgrade Notice ==