Better WordPress reCAPTCHA (with no CAPTCHA reCAPTCHA) - Version 2.0.0

Version Description

  • New Features
    • Add support for reCAPTCHA version 2
    • Add support for multiple reCAPTCHA instances per page (reCAPTCHA version 2 only)
    • Add an HTTPS setting for reCAPTCHA version 1
  • Enhancements
    • Add support for Contact Form version 4.x
    • Add support for custom login/register paths
    • Add reCAPTCHA before the submit field in comment form for WordPress 4.2 or higher
    • Use a lower priority when filter the comment_form_defaults filter hook so reCAPTCHA can still be added to themes that filter it as well
  • Other Changes
    • Change minimum PHP version required to 5.3.2
    • Show the captcha to all users (including admins) by default
    • Contact Form 7:
      • The shortcode [bwp-recaptcha] has been deprecated, use [recaptcha recaptcha-xxx] instead.
      • bwp-recaptcha will continue to work for Contact Form 7 prior to version 4.1 (last supported is 4.0.3). bwprecaptcha and bwp_recaptcha will still work with version 4.1+, so you won't have to manually update any form if you're using them.
    • Add a Croatian translation
    • Layerthemes.com has become an official sponsor for BWP Plugins!
  • Bugs fixed
    • Fix Akismet integration not working properly
    • Don't output comment form related fields in other forms, which leads to extraneous markups in Contact Form 7 forms
    • Create session only when needed and on demand
    • Fix an issue where saving sub blog's API keys overwrites network's API keys in a multisite installation
  • API
    • BWP_RECAPTCHA::load_captcha_library() has been removed, the PHP reCAPTCHA library is now autoloaded whenever needed (for reCAPTCHA version 1).

View the full changelog

=

Download this release

Release Info

Developer OddOneOut
Plugin Icon wp plugin Better WordPress reCAPTCHA (with no CAPTCHA reCAPTCHA)
Version 2.0.0
Comparing to
See all releases

Code changes from version 1.1.2 to 2.0.0

Files changed (72) hide show
  1. README.md +7 -0
  2. bwp-recaptcha-ms.php +1 -2
  3. bwp-recaptcha.php +40 -4
  4. bwp-recaptcha.pot +268 -258
  5. composer.json +33 -0
  6. composer.lock +100 -0
  7. includes/addons/contact-form-7/captcha-shortcode.php +352 -0
  8. includes/addons/contact-form-7/v1.php +33 -0
  9. includes/addons/contact-form-7/v2.php +59 -0
  10. includes/addons/index.php +2 -0
  11. includes/bwp-option-page/bwp-option-page.php +0 -3
  12. includes/bwp-option-page/images/ad_250x250.png +0 -0
  13. includes/class-bwp-recaptcha-cf7.php +0 -317
  14. includes/class-bwp-recaptcha.php +677 -684
  15. includes/index.php +2 -0
  16. includes/provider/abstract-provider.php +139 -0
  17. includes/provider/index.php +2 -0
  18. includes/provider/recaptcha/index.php +2 -0
  19. includes/{recaptcha → provider/recaptcha}/recaptchalib.php +67 -84
  20. includes/provider/recaptcha/response.php +10 -0
  21. includes/provider/v1-languages.php +13 -0
  22. includes/provider/v1.php +182 -0
  23. includes/provider/v2-languages.php +60 -0
  24. includes/provider/v2.php +165 -0
  25. js/bwp-recaptcha.js +17 -0
  26. languages/bwp-recaptcha-hr.mo +0 -0
  27. languages/bwp-recaptcha-hr.po +585 -0
  28. readme.txt +77 -85
  29. screenshot-1.png +0 -0
  30. screenshot-2.png +0 -0
  31. screenshot-3.png +0 -0
  32. screenshot-4.png +0 -0
  33. screenshot-5.png +0 -0
  34. vendor/autoload.php +7 -0
  35. vendor/composer/ClassLoader.php +413 -0
  36. vendor/composer/autoload_classmap.php +20 -0
  37. vendor/composer/autoload_files.php +9 -0
  38. vendor/composer/autoload_namespaces.php +9 -0
  39. vendor/composer/autoload_psr4.php +10 -0
  40. vendor/composer/autoload_real.php +50 -0
  41. vendor/composer/installed.json +86 -0
  42. vendor/google/recaptcha/CONTRIBUTING.md +24 -0
  43. vendor/google/recaptcha/LICENSE +29 -0
  44. vendor/google/recaptcha/README.md +66 -0
  45. vendor/google/recaptcha/composer.json +28 -0
  46. vendor/google/recaptcha/examples/example-captcha.php +128 -0
  47. vendor/google/recaptcha/phpunit.xml.dist +16 -0
  48. vendor/google/recaptcha/src/ReCaptcha/ReCaptcha.php +97 -0
  49. vendor/google/recaptcha/src/ReCaptcha/RequestMethod.php +42 -0
  50. vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Post.php +70 -0
  51. vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Socket.php +104 -0
  52. vendor/google/recaptcha/src/ReCaptcha/RequestMethod/SocketPost.php +120 -0
  53. vendor/google/recaptcha/src/ReCaptcha/RequestParameters.php +103 -0
  54. vendor/google/recaptcha/src/ReCaptcha/Response.php +102 -0
  55. vendor/google/recaptcha/tests/ReCaptcha/ReCaptchaTest.php +75 -0
  56. vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/PostTest.php +118 -0
  57. vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/SocketPostTest.php +90 -0
  58. vendor/google/recaptcha/tests/ReCaptcha/RequestParametersTest.php +61 -0
  59. vendor/google/recaptcha/tests/ReCaptcha/ResponseTest.php +68 -0
  60. vendor/kminh/bwp-framework/composer.json +25 -0
  61. {includes/bwp-option-page → vendor/kminh/bwp-framework}/css/bwp-option-page.css +4 -4
  62. vendor/kminh/bwp-framework/images/ad_lt_250x250.png +0 -0
  63. {includes/bwp-option-page → vendor/kminh/bwp-framework}/images/icon-paypal.gif +0 -0
  64. {includes/bwp-option-page → vendor/kminh/bwp-framework}/images/icon-rss.png +0 -0
  65. {includes/bwp-option-page → vendor/kminh/bwp-framework}/images/icon-twitter.png +0 -0
  66. {includes/bwp-option-page → vendor/kminh/bwp-framework}/js/paypal.js +0 -0
  67. includes/bwp-option-page/includes/class-bwp-option-page.php → vendor/kminh/bwp-framework/src/bwp-option-page/includes/class-bwp-option-page-v2.php +725 -510
  68. {includes → vendor/kminh/bwp-framework/src}/bwp-option-page/includes/index.php +0 -0
  69. {includes → vendor/kminh/bwp-framework/src}/bwp-option-page/index.php +0 -0
  70. includes/class-bwp-framework-improved.php → vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php +870 -727
  71. vendor/kminh/bwp-framework/src/class-bwp-version.php +34 -0
  72. vendor/kminh/bwp-framework/src/index.php +2 -0
README.md ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ # Better WordPress reCAPTCHA
2
+
3
+ This WordPress plugin supports Akismet and Contact Form 7.
4
+
5
+ See http://betterwp.net/wordpress-plugins/bwp-recaptcha/ for documentation.
6
+
7
+ Report issues: https://github.com/OddOneOut/bwp-recaptcha/issues
bwp-recaptcha-ms.php CHANGED
@@ -1,3 +1,2 @@
1
  <?php
2
- include_once(dirname(__FILE__). '/bwp-recaptcha/bwp-recaptcha.php');
3
- ?>
1
  <?php
2
+ include_once __DIR__ . '/bwp-recaptcha/bwp-recaptcha.php';
 
bwp-recaptcha.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Better WordPress reCAPTCHA
4
  Plugin URI: http://betterwp.net/wordpress-plugins/bwp-recaptcha/
5
  Description: This plugin utilizes reCAPTCHA (with support for Akismet) to help your blog stay clear of spams. This plugin, however, has a different approach from the current WP-reCAPTCHA plugin and allows you to customize how the captcha looks using CSS.
6
- Version: 1.1.2
7
  Text Domain: bwp-recaptcha
8
  Domain Path: /languages/
9
  Author: Khang Minh
@@ -15,6 +15,42 @@ License: GPLv3
15
  if (class_exists('BWP_RECAPTCHA') || !defined('ABSPATH'))
16
  return;
17
 
18
- // Init the plugin
19
- require_once dirname(__FILE__) . '/includes/class-bwp-recaptcha.php';
20
- $bwp_capt = new BWP_RECAPTCHA();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  Plugin Name: Better WordPress reCAPTCHA
4
  Plugin URI: http://betterwp.net/wordpress-plugins/bwp-recaptcha/
5
  Description: This plugin utilizes reCAPTCHA (with support for Akismet) to help your blog stay clear of spams. This plugin, however, has a different approach from the current WP-reCAPTCHA plugin and allows you to customize how the captcha looks using CSS.
6
+ Version: 2.0.0
7
  Text Domain: bwp-recaptcha
8
  Domain Path: /languages/
9
  Author: Khang Minh
15
  if (class_exists('BWP_RECAPTCHA') || !defined('ABSPATH'))
16
  return;
17
 
18
+ $bwp_capt_meta = array(
19
+ 'title' => 'Better WordPress reCAPTCHA',
20
+ 'version' => '2.0.0',
21
+ 'domain' => 'bwp-recaptcha'
22
+ );
23
+
24
+ // show a friendly message when PHP version is lower than required version
25
+ // @todo remove this when WordPress drops support for PHP version < 5.3.2
26
+ if (version_compare(PHP_VERSION, '5.3.2', '<'))
27
+ {
28
+ function bwp_capt_warn_php_version()
29
+ {
30
+ global $bwp_capt_meta;
31
+
32
+ require_once __DIR__ . '/vendor/kminh/bwp-framework/src/class-bwp-version.php';
33
+
34
+ BWP_VERSION::warn_required_versions(
35
+ $bwp_capt_meta['title'],
36
+ $bwp_capt_meta['domain']
37
+ );
38
+ }
39
+
40
+ add_action('admin_notices', 'bwp_capt_warn_php_version');
41
+ add_action('network_admin_notices', 'bwp_capt_warn_php_version');
42
+
43
+ return;
44
+ }
45
+
46
+ // dependencies
47
+ require_once __DIR__ . '/vendor/autoload.php';
48
+
49
+ // @since 2.0.0 we hook to 'init' action with a priority of 9 to make sure the
50
+ // plugin loads before Contact Form 7 loads
51
+ add_filter('bwp_capt_init_priority', function() {
52
+ return 9;
53
+ });
54
+
55
+ // init the plugin
56
+ $bwp_capt = new BWP_RECAPTCHA($bwp_capt_meta);
bwp-recaptcha.pot CHANGED
@@ -1,7 +1,8 @@
 
1
  msgid ""
2
  msgstr ""
3
  "Project-Id-Version: BWP reCAPTCHA\n"
4
- "POT-Creation-Date: 2014-07-04 22:37+0700\n"
5
  "PO-Revision-Date: 2014-07-04 22:37+0700\n"
6
  "Last-Translator: Khang Minh <contact@betterwp.net>\n"
7
  "Language-Team: BWP <contact@betterwp.net>\n"
@@ -9,201 +10,59 @@ msgstr ""
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
- "X-Generator: Poedit 1.6.5\n"
13
  "X-Poedit-Basepath: .\n"
14
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
15
  "X-Poedit-SourceCharset: UTF-8\n"
16
- "X-Poedit-KeywordsList: __;_e;_;gettext;gettext_noop\n"
17
  "X-Poedit-SearchPath-0: .\n"
18
 
19
- #: includes/bwp-option-page/includes/class-bwp-option-page.php:80
20
- msgid "Plugin Configurations"
21
- msgstr ""
22
-
23
- #: includes/bwp-option-page/includes/class-bwp-option-page.php:503
24
- msgid "Save Changes"
25
- msgstr ""
26
-
27
- #: includes/class-bwp-framework-improved.php:211
28
- #, php-format
29
- msgid ""
30
- "%s requires WordPress <strong>%s</strong> or higher and PHP <strong>%s</"
31
- "strong> or higher. The plugin will not protected function until you update "
32
- "your software. Please deactivate this plugin."
33
- msgstr ""
34
-
35
- #: includes/class-bwp-framework-improved.php:228
36
- msgid "Development Log"
37
- msgstr ""
38
-
39
- #: includes/class-bwp-framework-improved.php:228
40
- msgid "Frequently Asked Questions"
41
- msgstr ""
42
-
43
- #: includes/class-bwp-framework-improved.php:228
44
- msgid "FAQ"
45
- msgstr ""
46
-
47
- #: includes/class-bwp-framework-improved.php:228
48
- msgid "Got a problem? Send me a feedback!"
49
- msgstr ""
50
-
51
- #: includes/class-bwp-framework-improved.php:228
52
- msgid "Contact"
53
- msgstr ""
54
-
55
- #: includes/class-bwp-framework-improved.php:235
56
- msgid ""
57
- "You can buy me some special coffees if you appreciate my work, thank you!"
58
- msgstr ""
59
-
60
- #: includes/class-bwp-framework-improved.php:249
61
- #, php-format
62
- msgid "Donate to %s"
63
- msgstr ""
64
-
65
- #: includes/class-bwp-framework-improved.php:251
66
- msgid "One cup $5.00"
67
- msgstr ""
68
-
69
- #: includes/class-bwp-framework-improved.php:252
70
- msgid "Two cups $10.00"
71
- msgstr ""
72
-
73
- #: includes/class-bwp-framework-improved.php:253
74
- msgid "Five cups! $25.00"
75
- msgstr ""
76
-
77
- #: includes/class-bwp-framework-improved.php:254
78
- msgid "One LL-cup!!! $50.00"
79
- msgstr ""
80
-
81
- #: includes/class-bwp-framework-improved.php:255
82
- msgid "... or any amount!"
83
- msgstr ""
84
-
85
- #: includes/class-bwp-framework-improved.php:270
86
- msgid "Latest updates from BetterWP.net!"
87
- msgstr ""
88
-
89
- #: includes/class-bwp-framework-improved.php:271
90
- msgid "Follow me on Twitter!"
91
  msgstr ""
92
 
93
- #: includes/class-bwp-framework-improved.php:281
94
- msgid "This Plugin is Proudly Sponsored By"
95
  msgstr ""
96
 
97
- #: includes/class-bwp-framework-improved.php:300
98
- #, php-format
99
- msgid "You are using version %s!"
100
- msgstr ""
101
-
102
- #: includes/class-bwp-framework-improved.php:541
103
- msgid "Settings"
104
  msgstr ""
105
 
106
- #: includes/class-bwp-recaptcha-cf7.php:103
107
  msgid "This reCAPTCHA tag is provided by the BWP reCAPTCHA WordPress plugin."
108
  msgstr ""
109
 
110
- #: includes/class-bwp-recaptcha-cf7.php:106
111
  #, php-format
112
  msgid ""
113
  "Please refer to <a target=\"_blank\" href=\"%s\">BWP reCAPTCHA's "
114
- "documentation </a> for a quick guide on how to customize the look and feel "
115
- "of this tag."
116
- msgstr ""
117
-
118
- #: includes/class-bwp-recaptcha-cf7.php:115
119
- msgid "Name"
120
  msgstr ""
121
 
122
- #: includes/class-bwp-recaptcha-cf7.php:122
123
- msgid "Copy this code and paste it into the form left."
124
- msgstr ""
125
-
126
- #: includes/class-bwp-recaptcha.php:101
127
  msgid ""
128
  "<strong>ERROR:</strong> Incorrect or empty reCAPTCHA response, please try "
129
  "again."
130
  msgstr ""
131
 
132
- #: includes/class-bwp-recaptcha.php:103
133
  #, php-format
134
  msgid ""
135
  "Error: Incorrect or empty reCAPTCHA response, please click the back button "
136
  "on your browser's toolbar or click on %s to go back."
137
  msgstr ""
138
 
139
- #: includes/class-bwp-recaptcha.php:127 includes/class-bwp-recaptcha.php:450
140
  msgid "General Options"
141
  msgstr ""
142
 
143
- #: includes/class-bwp-recaptcha.php:130 includes/class-bwp-recaptcha.php:459
144
  msgid "Theme Options"
145
  msgstr ""
146
 
147
- #: includes/class-bwp-recaptcha.php:167
148
- msgid "Get another challenge"
149
- msgstr ""
150
-
151
- #: includes/class-bwp-recaptcha.php:168
152
- msgid "Get audio reCAPTCHA"
153
- msgstr ""
154
-
155
- #: includes/class-bwp-recaptcha.php:169
156
- msgid "Get image reCAPTCHA"
157
- msgstr ""
158
-
159
- #: includes/class-bwp-recaptcha.php:170
160
- msgid "About reCAPTCHA"
161
- msgstr ""
162
-
163
- #: includes/class-bwp-recaptcha.php:174
164
- msgid "Enter the two words in the box:"
165
- msgstr ""
166
-
167
- #: includes/class-bwp-recaptcha.php:175
168
- msgid "Enter the numbers you hear:"
169
- msgstr ""
170
-
171
- #: includes/class-bwp-recaptcha.php:236
172
- msgid "English"
173
- msgstr ""
174
-
175
- #: includes/class-bwp-recaptcha.php:237
176
- msgid "Dutch"
177
- msgstr ""
178
-
179
- #: includes/class-bwp-recaptcha.php:238
180
- msgid "French"
181
- msgstr ""
182
-
183
- #: includes/class-bwp-recaptcha.php:239
184
- msgid "German"
185
- msgstr ""
186
-
187
- #: includes/class-bwp-recaptcha.php:240
188
- msgid "Italian"
189
- msgstr ""
190
-
191
- #: includes/class-bwp-recaptcha.php:241
192
- msgid "Portuguese"
193
- msgstr ""
194
-
195
- #: includes/class-bwp-recaptcha.php:242
196
- msgid "Russian"
197
- msgstr ""
198
-
199
- #: includes/class-bwp-recaptcha.php:243
200
- msgid "Spanish"
201
- msgstr ""
202
-
203
- #: includes/class-bwp-recaptcha.php:244
204
- msgid "Turkish"
205
- msgstr ""
206
-
207
  #: includes/class-bwp-recaptcha.php:248
208
  msgid "Read Profile"
209
  msgstr ""
@@ -212,246 +71,270 @@ msgstr ""
212
  msgid "Manage Options"
213
  msgstr ""
214
 
215
- #: includes/class-bwp-recaptcha.php:439
216
  msgid "Better WordPress reCAPTCHA"
217
  msgstr ""
218
 
219
- #: includes/class-bwp-recaptcha.php:449
220
  msgid "BWP reCAPTCHA General Options"
221
  msgstr ""
222
 
223
- #: includes/class-bwp-recaptcha.php:458
224
  msgid "BWP reCAPTCHA Theme Options"
225
  msgstr ""
226
 
227
- #: includes/class-bwp-recaptcha.php:496
228
- msgid "You do not have sufficient permissions to access this page."
229
- msgstr ""
230
-
231
- #: includes/class-bwp-recaptcha.php:531
232
  msgid "reCAPTCHA API Keys"
233
  msgstr ""
234
 
235
- #: includes/class-bwp-recaptcha.php:532
236
  msgid "Use main site's keys"
237
  msgstr ""
238
 
239
- #: includes/class-bwp-recaptcha.php:533
240
- msgid "Public Key"
241
  msgstr ""
242
 
243
- #: includes/class-bwp-recaptcha.php:534
244
- msgid "Private Key"
245
  msgstr ""
246
 
247
- #: includes/class-bwp-recaptcha.php:535
248
  msgid "Plugin Functionality"
249
  msgstr ""
250
 
251
- #: includes/class-bwp-recaptcha.php:536
 
 
 
 
 
 
 
 
252
  msgid "Enable this plugin for"
253
  msgstr ""
254
 
255
- #: includes/class-bwp-recaptcha.php:537
256
  msgid "Hide captcha for"
257
  msgstr ""
258
 
259
- #: includes/class-bwp-recaptcha.php:538
260
  msgid "reCAPTCHA for comment form"
261
  msgstr ""
262
 
263
- #: includes/class-bwp-recaptcha.php:539
264
  msgid "Captcha position"
265
  msgstr ""
266
 
267
- #: includes/class-bwp-recaptcha.php:540
268
  msgid "If invalid captcha response"
269
  msgstr ""
270
 
271
- #: includes/class-bwp-recaptcha.php:541 includes/class-bwp-recaptcha.php:542
 
 
 
 
272
  msgid "Invalid captcha error message"
273
  msgstr ""
274
 
275
- #: includes/class-bwp-recaptcha.php:543
276
  msgid "Akismet Integration for comment form"
277
  msgstr ""
278
 
279
- #: includes/class-bwp-recaptcha.php:544
280
  msgid "Integrate with Akismet?"
281
  msgstr ""
282
 
283
- #: includes/class-bwp-recaptcha.php:545
284
  msgid "If correct captcha response"
285
  msgstr ""
286
 
287
- #: includes/class-bwp-recaptcha.php:546
288
  msgid "Contact Form 7 Integration"
289
  msgstr ""
290
 
291
- #: includes/class-bwp-recaptcha.php:547
292
- msgid "Captcha shortcode tag"
293
  msgstr ""
294
 
295
- #: includes/class-bwp-recaptcha.php:570
296
  #, php-format
297
  msgid ""
298
- "For this plugin to work, you will need a pair of API keys (public and "
299
- "private), which is available for free <a href=\"%s\" target=\"_blank\">here</"
300
- "a>. Once you have created those two keys for this domain, simply paste them "
301
- "below.</em>"
302
  msgstr ""
303
 
304
- #: includes/class-bwp-recaptcha.php:576
305
  msgid "Control how this plugin works."
306
  msgstr ""
307
 
308
- #: includes/class-bwp-recaptcha.php:577
309
  msgid "Settings that are applied to comment forms only."
310
  msgstr ""
311
 
312
- #: includes/class-bwp-recaptcha.php:579
313
- msgid "Integrate with Akismet for better end-user experience."
314
  msgstr ""
315
 
316
- #: includes/class-bwp-recaptcha.php:580
 
 
 
 
 
 
 
317
  msgid ""
318
  "Add reCAPTCHA to Contact Form 7. This only works if you have Contact Form 7 "
319
  "activated."
320
  msgstr ""
321
 
322
- #: includes/class-bwp-recaptcha.php:597
323
  msgid "After comment field"
324
  msgstr ""
325
 
326
- #: includes/class-bwp-recaptcha.php:598
327
  msgid "After form fields (name, email, website)"
328
  msgstr ""
329
 
330
- #: includes/class-bwp-recaptcha.php:601
331
  msgid "Redirect commenter back to the comment form with error message"
332
  msgstr ""
333
 
334
- #: includes/class-bwp-recaptcha.php:602
335
  msgid "Show an error page just like WordPress does"
336
  msgstr ""
337
 
338
- #: includes/class-bwp-recaptcha.php:605
339
  msgid "Approve comment immediately"
340
  msgstr ""
341
 
342
- #: includes/class-bwp-recaptcha.php:606
343
  msgid "Hold comment in moderation queue"
344
  msgstr ""
345
 
346
- #: includes/class-bwp-recaptcha.php:609
347
- msgid "Use \"bwp-recaptcha\" shortcode tag"
348
- msgstr ""
349
-
350
- #: includes/class-bwp-recaptcha.php:610
351
- msgid "Use \"recaptcha\" shortcode tag"
352
- msgstr ""
353
-
354
- #: includes/class-bwp-recaptcha.php:615
355
  msgid "Comment form."
356
  msgstr ""
357
 
358
- #: includes/class-bwp-recaptcha.php:618
359
  msgid "Registration form (user/site registration)."
360
  msgstr ""
361
 
362
- #: includes/class-bwp-recaptcha.php:621
363
  msgid "Login form."
364
  msgstr ""
365
 
366
- #: includes/class-bwp-recaptcha.php:624
367
  msgid "registered users <em>(even without any capabilities)</em>."
368
  msgstr ""
369
 
370
- #: includes/class-bwp-recaptcha.php:627
371
  msgid "users who can"
372
  msgstr ""
373
 
374
- #: includes/class-bwp-recaptcha.php:630
375
  msgid "visitors who have at least"
376
  msgstr ""
377
 
378
- #: includes/class-bwp-recaptcha.php:633
379
  msgid ""
380
  "A captcha is only shown when Akismet identifies a comment as spam. Highly "
381
  "recommended if you do not want to force your visitors to enter a captcha "
382
  "every time."
383
  msgstr ""
384
 
385
- #: includes/class-bwp-recaptcha.php:638
386
  msgid "uncheck to use different key pairs for this site."
387
  msgstr ""
388
 
389
- #: includes/class-bwp-recaptcha.php:644
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  msgid "A public key used to request captchas from reCAPTCHA server."
391
  msgstr ""
392
 
393
- #: includes/class-bwp-recaptcha.php:649
394
  msgid "A private (secret) key used to authenticate user's response."
395
  msgstr ""
396
 
397
- #: includes/class-bwp-recaptcha.php:662
398
  msgid "approved comment(s)."
399
  msgstr ""
400
 
401
- #: includes/class-bwp-recaptcha.php:670
402
  msgid ""
403
  "It is best to put comments identified as spam in moderation queue so you are "
404
  "able to review and instruct Akismet to correctly handle similar comments in "
405
  "the future.</em>"
406
  msgstr ""
407
 
408
- #: includes/class-bwp-recaptcha.php:731
409
  msgid "reCAPTCHA theme"
410
  msgstr ""
411
 
412
- #: includes/class-bwp-recaptcha.php:732
413
  msgid "Use default CSS"
414
  msgstr ""
415
 
416
- #: includes/class-bwp-recaptcha.php:733
417
  msgid "Language for built-in themes"
418
  msgstr ""
419
 
420
- #: includes/class-bwp-recaptcha.php:734
421
  msgid "Tabindex for captcha input field"
422
  msgstr ""
423
 
424
- #: includes/class-bwp-recaptcha.php:735
425
  msgid "Preview your reCAPTCHA"
426
  msgstr ""
427
 
428
- #: includes/class-bwp-recaptcha.php:745
429
  msgid ""
430
  "<em>Below you will see how your reCAPTCHA will look. Note that this might "
431
  "differ on your actual pages.<br /></em>"
432
  msgstr ""
433
 
434
- #: includes/class-bwp-recaptcha.php:750
435
  msgid "Default Theme (Red)"
436
  msgstr ""
437
 
438
- #: includes/class-bwp-recaptcha.php:751
439
  msgid "White Theme"
440
  msgstr ""
441
 
442
- #: includes/class-bwp-recaptcha.php:752
443
  msgid "Black Theme"
444
  msgstr ""
445
 
446
- #: includes/class-bwp-recaptcha.php:753
447
  msgid "Clean Theme"
448
  msgstr ""
449
 
450
- #: includes/class-bwp-recaptcha.php:754
451
  msgid "Custom Theme (use CSS)"
452
  msgstr ""
453
 
454
- #: includes/class-bwp-recaptcha.php:760
455
  #, php-format
456
  msgid ""
457
  "This is for Custom Theme only. Disable this and add your own CSS to style "
@@ -459,74 +342,201 @@ msgid ""
459
  "\">here</a>."
460
  msgstr ""
461
 
462
- #: includes/class-bwp-recaptcha.php:766
463
- msgid "This is only useful when you do not use any minify or cache plugin."
464
- msgstr ""
465
-
466
- #: includes/class-bwp-recaptcha.php:772
467
  msgid ""
468
  "This should be 4 if you place the captcha before the textarea, and 5 if you "
469
  "put it after. Set to 0 to disable."
470
  msgstr ""
471
 
472
- #: includes/class-bwp-recaptcha.php:780
473
  #, php-format
474
  msgid ""
475
  "If you would like to add custom translations, please read <a href=\"%s\" "
476
  "target=\"_blank\">this dedicated tip</a>."
477
  msgstr ""
478
 
479
- #: includes/class-bwp-recaptcha.php:853
480
- msgid "All options have been saved."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
481
  msgstr ""
482
 
483
- #: includes/class-bwp-recaptcha.php:861
 
 
 
 
484
  msgid "Warning"
485
  msgstr ""
486
 
487
- #: includes/class-bwp-recaptcha.php:862
488
  #, php-format
489
  msgid ""
490
  "API key(s) missing. Please get an API key from <a href=\"%1$s\">%1$s</a> "
491
  "(free!)"
492
  msgstr ""
493
 
494
- #: includes/class-bwp-recaptcha.php:873
495
  msgid "Notice"
496
  msgstr ""
497
 
498
- #: includes/class-bwp-recaptcha.php:874
499
  msgid ""
500
  "You are enabling Akismet integration but Akismet is not currently active. "
501
  "Please activate Akismet for the integration to work."
502
  msgstr ""
503
 
504
- #: includes/class-bwp-recaptcha.php:1040
505
  msgid "Your comment was identified as spam, please complete the CAPTCHA below:"
506
  msgstr ""
507
 
508
- #: includes/class-bwp-recaptcha.php:1110
 
 
 
 
 
 
 
 
 
 
 
 
 
509
  #, php-format
510
  msgid "To use reCAPTCHA you must get an API key from <a href=\"%1$s\">%1$s</a>"
511
  msgstr ""
512
 
513
- #: includes/class-bwp-recaptcha.php:1211 includes/class-bwp-recaptcha.php:1278
514
- msgid "ERROR"
515
  msgstr ""
516
 
517
- #: includes/class-bwp-recaptcha.php:1212 includes/class-bwp-recaptcha.php:1279
518
- msgid "Unknown captcha error."
519
  msgstr ""
520
 
521
- #: includes/class-bwp-recaptcha.php:1361
522
- msgid "this link"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
523
  msgstr ""
524
 
525
- #: includes/class-bwp-recaptcha.php:1367
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
526
  msgid ""
527
- "There is some problem with your reCAPTCHA API keys, please double check them."
528
  msgstr ""
529
 
530
- #: includes/class-bwp-recaptcha.php:1372
531
- msgid "Unknown error. Please contact an administrator for more info."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
532
  msgstr ""
1
+ #, fuzzy
2
  msgid ""
3
  msgstr ""
4
  "Project-Id-Version: BWP reCAPTCHA\n"
5
+ "POT-Creation-Date: 2015-08-16 15:36+0700\n"
6
  "PO-Revision-Date: 2014-07-04 22:37+0700\n"
7
  "Last-Translator: Khang Minh <contact@betterwp.net>\n"
8
  "Language-Team: BWP <contact@betterwp.net>\n"
10
  "MIME-Version: 1.0\n"
11
  "Content-Type: text/plain; charset=UTF-8\n"
12
  "Content-Transfer-Encoding: 8bit\n"
13
+ "X-Generator: Poedit 1.8.2\n"
14
  "X-Poedit-Basepath: .\n"
15
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
16
  "X-Poedit-SourceCharset: UTF-8\n"
17
+ "X-Poedit-KeywordsList: __;_e;_;gettext;gettext_noop;_x\n"
18
  "X-Poedit-SearchPath-0: .\n"
19
 
20
+ #: includes/addons/contact-form-7/captcha-shortcode.php:150
21
+ #: includes/addons/contact-form-7/captcha-shortcode.php:187
22
+ msgid "Name"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  msgstr ""
24
 
25
+ #: includes/addons/contact-form-7/captcha-shortcode.php:161
26
+ msgid "Insert Tag"
27
  msgstr ""
28
 
29
+ #: includes/addons/contact-form-7/captcha-shortcode.php:196
30
+ msgid "Copy this code and paste it into the form left."
 
 
 
 
 
31
  msgstr ""
32
 
33
+ #: includes/addons/contact-form-7/captcha-shortcode.php:211
34
  msgid "This reCAPTCHA tag is provided by the BWP reCAPTCHA WordPress plugin."
35
  msgstr ""
36
 
37
+ #: includes/addons/contact-form-7/captcha-shortcode.php:216
38
  #, php-format
39
  msgid ""
40
  "Please refer to <a target=\"_blank\" href=\"%s\">BWP reCAPTCHA's "
41
+ "documentation</a> for a quick guide on how to customize the look and feel of "
42
+ "this tag."
 
 
 
 
43
  msgstr ""
44
 
45
+ #: includes/class-bwp-recaptcha.php:112
 
 
 
 
46
  msgid ""
47
  "<strong>ERROR:</strong> Incorrect or empty reCAPTCHA response, please try "
48
  "again."
49
  msgstr ""
50
 
51
+ #: includes/class-bwp-recaptcha.php:114
52
  #, php-format
53
  msgid ""
54
  "Error: Incorrect or empty reCAPTCHA response, please click the back button "
55
  "on your browser's toolbar or click on %s to go back."
56
  msgstr ""
57
 
58
+ #: includes/class-bwp-recaptcha.php:145 includes/class-bwp-recaptcha.php:510
59
  msgid "General Options"
60
  msgstr ""
61
 
62
+ #: includes/class-bwp-recaptcha.php:148 includes/class-bwp-recaptcha.php:519
63
  msgid "Theme Options"
64
  msgstr ""
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  #: includes/class-bwp-recaptcha.php:248
67
  msgid "Read Profile"
68
  msgstr ""
71
  msgid "Manage Options"
72
  msgstr ""
73
 
74
+ #: includes/class-bwp-recaptcha.php:499
75
  msgid "Better WordPress reCAPTCHA"
76
  msgstr ""
77
 
78
+ #: includes/class-bwp-recaptcha.php:509
79
  msgid "BWP reCAPTCHA General Options"
80
  msgstr ""
81
 
82
+ #: includes/class-bwp-recaptcha.php:518
83
  msgid "BWP reCAPTCHA Theme Options"
84
  msgstr ""
85
 
86
+ #: includes/class-bwp-recaptcha.php:583
 
 
 
 
87
  msgid "reCAPTCHA API Keys"
88
  msgstr ""
89
 
90
+ #: includes/class-bwp-recaptcha.php:584
91
  msgid "Use main site's keys"
92
  msgstr ""
93
 
94
+ #: includes/class-bwp-recaptcha.php:585
95
+ msgid "Site Key"
96
  msgstr ""
97
 
98
+ #: includes/class-bwp-recaptcha.php:586
99
+ msgid "Secret Key"
100
  msgstr ""
101
 
102
+ #: includes/class-bwp-recaptcha.php:587
103
  msgid "Plugin Functionality"
104
  msgstr ""
105
 
106
+ #: includes/class-bwp-recaptcha.php:588
107
+ msgid "Use reCAPTCHA version 1"
108
+ msgstr ""
109
+
110
+ #: includes/class-bwp-recaptcha.php:589
111
+ msgid "Force https"
112
+ msgstr ""
113
+
114
+ #: includes/class-bwp-recaptcha.php:590
115
  msgid "Enable this plugin for"
116
  msgstr ""
117
 
118
+ #: includes/class-bwp-recaptcha.php:591
119
  msgid "Hide captcha for"
120
  msgstr ""
121
 
122
+ #: includes/class-bwp-recaptcha.php:592
123
  msgid "reCAPTCHA for comment form"
124
  msgstr ""
125
 
126
+ #: includes/class-bwp-recaptcha.php:593
127
  msgid "Captcha position"
128
  msgstr ""
129
 
130
+ #: includes/class-bwp-recaptcha.php:594
131
  msgid "If invalid captcha response"
132
  msgstr ""
133
 
134
+ #: includes/class-bwp-recaptcha.php:595
135
+ msgid "Auto fill comment field"
136
+ msgstr ""
137
+
138
+ #: includes/class-bwp-recaptcha.php:596 includes/class-bwp-recaptcha.php:597
139
  msgid "Invalid captcha error message"
140
  msgstr ""
141
 
142
+ #: includes/class-bwp-recaptcha.php:598
143
  msgid "Akismet Integration for comment form"
144
  msgstr ""
145
 
146
+ #: includes/class-bwp-recaptcha.php:599
147
  msgid "Integrate with Akismet?"
148
  msgstr ""
149
 
150
+ #: includes/class-bwp-recaptcha.php:600
151
  msgid "If correct captcha response"
152
  msgstr ""
153
 
154
+ #: includes/class-bwp-recaptcha.php:601
155
  msgid "Contact Form 7 Integration"
156
  msgstr ""
157
 
158
+ #: includes/class-bwp-recaptcha.php:602
159
+ msgid "Integrate with Contact Form 7?"
160
  msgstr ""
161
 
162
+ #: includes/class-bwp-recaptcha.php:628
163
  #, php-format
164
  msgid ""
165
+ "For this plugin to work, you will need a pair of API keys, which is "
166
+ "available for free <a href=\"%s\" target=\"_blank\">here</a>. Once you have "
167
+ "created those two keys for the current domain, simply paste them below.</em>"
 
168
  msgstr ""
169
 
170
+ #: includes/class-bwp-recaptcha.php:633
171
  msgid "Control how this plugin works."
172
  msgstr ""
173
 
174
+ #: includes/class-bwp-recaptcha.php:634
175
  msgid "Settings that are applied to comment forms only."
176
  msgstr ""
177
 
178
+ #: includes/class-bwp-recaptcha.php:636
179
+ msgid "Integrate the comment form with Akismet for better end-user experience."
180
  msgstr ""
181
 
182
+ #: includes/class-bwp-recaptcha.php:637 includes/class-bwp-recaptcha.php:704
183
+ #, php-format
184
+ msgid ""
185
+ "This feature requires an active <a target=\"_blank\" href=\"%s\">PHP "
186
+ "session</a>."
187
+ msgstr ""
188
+
189
+ #: includes/class-bwp-recaptcha.php:639
190
  msgid ""
191
  "Add reCAPTCHA to Contact Form 7. This only works if you have Contact Form 7 "
192
  "activated."
193
  msgstr ""
194
 
195
+ #: includes/class-bwp-recaptcha.php:655
196
  msgid "After comment field"
197
  msgstr ""
198
 
199
+ #: includes/class-bwp-recaptcha.php:656
200
  msgid "After form fields (name, email, website)"
201
  msgstr ""
202
 
203
+ #: includes/class-bwp-recaptcha.php:659
204
  msgid "Redirect commenter back to the comment form with error message"
205
  msgstr ""
206
 
207
+ #: includes/class-bwp-recaptcha.php:660
208
  msgid "Show an error page just like WordPress does"
209
  msgstr ""
210
 
211
+ #: includes/class-bwp-recaptcha.php:663
212
  msgid "Approve comment immediately"
213
  msgstr ""
214
 
215
+ #: includes/class-bwp-recaptcha.php:664
216
  msgid "Hold comment in moderation queue"
217
  msgstr ""
218
 
219
+ #: includes/class-bwp-recaptcha.php:669
 
 
 
 
 
 
 
 
220
  msgid "Comment form."
221
  msgstr ""
222
 
223
+ #: includes/class-bwp-recaptcha.php:672
224
  msgid "Registration form (user/site registration)."
225
  msgstr ""
226
 
227
+ #: includes/class-bwp-recaptcha.php:675
228
  msgid "Login form."
229
  msgstr ""
230
 
231
+ #: includes/class-bwp-recaptcha.php:678
232
  msgid "registered users <em>(even without any capabilities)</em>."
233
  msgstr ""
234
 
235
+ #: includes/class-bwp-recaptcha.php:681
236
  msgid "users who can"
237
  msgstr ""
238
 
239
+ #: includes/class-bwp-recaptcha.php:684
240
  msgid "visitors who have at least"
241
  msgstr ""
242
 
243
+ #: includes/class-bwp-recaptcha.php:687
244
  msgid ""
245
  "A captcha is only shown when Akismet identifies a comment as spam. Highly "
246
  "recommended if you do not want to force your visitors to enter a captcha "
247
  "every time."
248
  msgstr ""
249
 
250
+ #: includes/class-bwp-recaptcha.php:692
251
  msgid "uncheck to use different key pairs for this site."
252
  msgstr ""
253
 
254
+ #: includes/class-bwp-recaptcha.php:695
255
+ msgid "check this if you prefer the oldschool recaptcha."
256
+ msgstr ""
257
+
258
+ #: includes/class-bwp-recaptcha.php:698
259
+ msgid "check this to make requests to reCAPTCHA server always secured."
260
+ msgstr ""
261
+
262
+ #: includes/class-bwp-recaptcha.php:701
263
+ msgid "After redirected, auto fill the comment field with previous comment."
264
+ msgstr ""
265
+
266
+ #: includes/class-bwp-recaptcha.php:709
267
+ msgid ""
268
+ "With this you can use the <code>recaptcha</code> shortcode tag in your "
269
+ "Contact Form 7 forms."
270
+ msgstr ""
271
+
272
+ #: includes/class-bwp-recaptcha.php:715
273
  msgid "A public key used to request captchas from reCAPTCHA server."
274
  msgstr ""
275
 
276
+ #: includes/class-bwp-recaptcha.php:720
277
  msgid "A private (secret) key used to authenticate user's response."
278
  msgstr ""
279
 
280
+ #: includes/class-bwp-recaptcha.php:733
281
  msgid "approved comment(s)."
282
  msgstr ""
283
 
284
+ #: includes/class-bwp-recaptcha.php:741
285
  msgid ""
286
  "It is best to put comments identified as spam in moderation queue so you are "
287
  "able to review and instruct Akismet to correctly handle similar comments in "
288
  "the future.</em>"
289
  msgstr ""
290
 
291
+ #: includes/class-bwp-recaptcha.php:804 includes/class-bwp-recaptcha.php:863
292
  msgid "reCAPTCHA theme"
293
  msgstr ""
294
 
295
+ #: includes/class-bwp-recaptcha.php:805
296
  msgid "Use default CSS"
297
  msgstr ""
298
 
299
+ #: includes/class-bwp-recaptcha.php:806
300
  msgid "Language for built-in themes"
301
  msgstr ""
302
 
303
+ #: includes/class-bwp-recaptcha.php:807 includes/class-bwp-recaptcha.php:866
304
  msgid "Tabindex for captcha input field"
305
  msgstr ""
306
 
307
+ #: includes/class-bwp-recaptcha.php:808 includes/class-bwp-recaptcha.php:867
308
  msgid "Preview your reCAPTCHA"
309
  msgstr ""
310
 
311
+ #: includes/class-bwp-recaptcha.php:818 includes/class-bwp-recaptcha.php:877
312
  msgid ""
313
  "<em>Below you will see how your reCAPTCHA will look. Note that this might "
314
  "differ on your actual pages.<br /></em>"
315
  msgstr ""
316
 
317
+ #: includes/class-bwp-recaptcha.php:823
318
  msgid "Default Theme (Red)"
319
  msgstr ""
320
 
321
+ #: includes/class-bwp-recaptcha.php:824
322
  msgid "White Theme"
323
  msgstr ""
324
 
325
+ #: includes/class-bwp-recaptcha.php:825
326
  msgid "Black Theme"
327
  msgstr ""
328
 
329
+ #: includes/class-bwp-recaptcha.php:826
330
  msgid "Clean Theme"
331
  msgstr ""
332
 
333
+ #: includes/class-bwp-recaptcha.php:827
334
  msgid "Custom Theme (use CSS)"
335
  msgstr ""
336
 
337
+ #: includes/class-bwp-recaptcha.php:833
338
  #, php-format
339
  msgid ""
340
  "This is for Custom Theme only. Disable this and add your own CSS to style "
342
  "\">here</a>."
343
  msgstr ""
344
 
345
+ #: includes/class-bwp-recaptcha.php:842 includes/class-bwp-recaptcha.php:901
 
 
 
 
346
  msgid ""
347
  "This should be 4 if you place the captcha before the textarea, and 5 if you "
348
  "put it after. Set to 0 to disable."
349
  msgstr ""
350
 
351
+ #: includes/class-bwp-recaptcha.php:850
352
  #, php-format
353
  msgid ""
354
  "If you would like to add custom translations, please read <a href=\"%s\" "
355
  "target=\"_blank\">this dedicated tip</a>."
356
  msgstr ""
357
 
358
+ #: includes/class-bwp-recaptcha.php:864
359
+ msgid "reCAPTCHA size"
360
+ msgstr ""
361
+
362
+ #: includes/class-bwp-recaptcha.php:865
363
+ msgid "Language"
364
+ msgstr ""
365
+
366
+ #: includes/class-bwp-recaptcha.php:882
367
+ msgid "Light"
368
+ msgstr ""
369
+
370
+ #: includes/class-bwp-recaptcha.php:883
371
+ msgid "Dark"
372
+ msgstr ""
373
+
374
+ #: includes/class-bwp-recaptcha.php:886
375
+ msgid "Normal"
376
+ msgstr ""
377
+
378
+ #: includes/class-bwp-recaptcha.php:887
379
+ msgid "Compact"
380
  msgstr ""
381
 
382
+ #: includes/class-bwp-recaptcha.php:890
383
+ msgid "Auto-detected"
384
+ msgstr ""
385
+
386
+ #: includes/class-bwp-recaptcha.php:941
387
  msgid "Warning"
388
  msgstr ""
389
 
390
+ #: includes/class-bwp-recaptcha.php:942
391
  #, php-format
392
  msgid ""
393
  "API key(s) missing. Please get an API key from <a href=\"%1$s\">%1$s</a> "
394
  "(free!)"
395
  msgstr ""
396
 
397
+ #: includes/class-bwp-recaptcha.php:953
398
  msgid "Notice"
399
  msgstr ""
400
 
401
+ #: includes/class-bwp-recaptcha.php:954
402
  msgid ""
403
  "You are enabling Akismet integration but Akismet is not currently active. "
404
  "Please activate Akismet for the integration to work."
405
  msgstr ""
406
 
407
+ #: includes/class-bwp-recaptcha.php:1085
408
  msgid "Your comment was identified as spam, please complete the CAPTCHA below:"
409
  msgstr ""
410
 
411
+ #: includes/class-bwp-recaptcha.php:1263
412
+ msgid "this link"
413
+ msgstr ""
414
+
415
+ #: includes/provider/abstract-provider.php:91
416
+ msgid ""
417
+ "There is some problem with your reCAPTCHA API keys, please double check them."
418
+ msgstr ""
419
+
420
+ #: includes/provider/abstract-provider.php:94
421
+ msgid "Unknown error. Please contact an administrator for more info."
422
+ msgstr ""
423
+
424
+ #: includes/provider/v1.php:90
425
  #, php-format
426
  msgid "To use reCAPTCHA you must get an API key from <a href=\"%1$s\">%1$s</a>"
427
  msgstr ""
428
 
429
+ #: includes/provider/v1.php:156
430
+ msgid "Get another challenge"
431
  msgstr ""
432
 
433
+ #: includes/provider/v1.php:157
434
+ msgid "Get audio reCAPTCHA"
435
  msgstr ""
436
 
437
+ #: includes/provider/v1.php:158
438
+ msgid "Get image reCAPTCHA"
439
+ msgstr ""
440
+
441
+ #: includes/provider/v1.php:159
442
+ msgid "About reCAPTCHA"
443
+ msgstr ""
444
+
445
+ #: includes/provider/v1.php:163
446
+ msgid "Type what you see"
447
+ msgstr ""
448
+
449
+ #: includes/provider/v1.php:164
450
+ msgid "Type what you hear"
451
+ msgstr ""
452
+
453
+ #: vendor/kminh/bwp-framework/src/bwp-option-page/includes/class-bwp-option-page-v2.php:94
454
+ msgid "Plugin Configurations"
455
+ msgstr ""
456
+
457
+ #: vendor/kminh/bwp-framework/src/bwp-option-page/includes/class-bwp-option-page-v2.php:625
458
+ msgid "Save Changes"
459
  msgstr ""
460
 
461
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:285
462
+ msgid "Development Log"
463
+ msgstr ""
464
+
465
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:285
466
+ msgid "Frequently Asked Questions"
467
+ msgstr ""
468
+
469
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:285
470
+ msgid "FAQ"
471
+ msgstr ""
472
+
473
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:285
474
+ msgid "Got a problem? Send me a feedback!"
475
+ msgstr ""
476
+
477
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:285
478
+ msgid "Contact"
479
+ msgstr ""
480
+
481
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:292
482
  msgid ""
483
+ "You can buy me some special coffees if you appreciate my work, thank you!"
484
  msgstr ""
485
 
486
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:306
487
+ #, php-format
488
+ msgid "Donate to %s"
489
+ msgstr ""
490
+
491
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:308
492
+ msgid "One cup $5.00"
493
+ msgstr ""
494
+
495
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:309
496
+ msgid "Two cups $10.00"
497
+ msgstr ""
498
+
499
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:310
500
+ msgid "Five cups! $25.00"
501
+ msgstr ""
502
+
503
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:311
504
+ msgid "One LL-cup!!! $50.00"
505
+ msgstr ""
506
+
507
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:312
508
+ msgid "... or any amount!"
509
+ msgstr ""
510
+
511
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:327
512
+ msgid "Latest updates from BetterWP.net!"
513
+ msgstr ""
514
+
515
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:328
516
+ msgid "Follow me on Twitter!"
517
+ msgstr ""
518
+
519
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:338
520
+ msgid "This Plugin is Proudly Sponsored By"
521
+ msgstr ""
522
+
523
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:358
524
+ #, php-format
525
+ msgid "You are using version %s!"
526
+ msgstr ""
527
+
528
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:646
529
+ msgid "Settings"
530
+ msgstr ""
531
+
532
+ #: vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php:679
533
+ msgid "All options have been saved."
534
+ msgstr ""
535
+
536
+ #: vendor/kminh/bwp-framework/src/class-bwp-version.php:25
537
+ #, php-format
538
+ msgid ""
539
+ "%s requires WordPress <strong>%s</strong> or higher and PHP <strong>%s</"
540
+ "strong> or higher. The plugin will not function until you update your "
541
+ "software. Please deactivate this plugin."
542
  msgstr ""
composer.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "kdm/bwp-recaptcha",
3
+ "description": "A WordPress plugin that utilizes the popular anti-spam library, reCAPTCHA, to help your blog stay clear of spams.",
4
+ "homepage": "http://betterwp.net",
5
+ "license": "GPLv3",
6
+ "repositories": [
7
+ {
8
+ "type": "git",
9
+ "url": "https://github.com/kminh/bwp-framework"
10
+ }
11
+ ],
12
+ "authors": [
13
+ {
14
+ "name": "Khang Minh",
15
+ "email": "contact@betterwp.net"
16
+ }
17
+ ],
18
+ "require": {
19
+ "php": "^5.3.2",
20
+ "kminh/bwp-framework": "dev-master",
21
+ "google/recaptcha": "^1.1"
22
+ },
23
+ "autoload": {
24
+ "classmap": [
25
+ "includes/"
26
+ ]
27
+ },
28
+ "extra": {
29
+ "branch-alias": {
30
+ "dev-master": "2.0.x-dev"
31
+ }
32
+ }
33
+ }
composer.lock ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_readme": [
3
+ "This file locks the dependencies of your project to a known state",
4
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5
+ "This file is @generated automatically"
6
+ ],
7
+ "hash": "7d7cc68d17224c2b892ccaa1a8aad12a",
8
+ "packages": [
9
+ {
10
+ "name": "google/recaptcha",
11
+ "version": "1.1.1",
12
+ "source": {
13
+ "type": "git",
14
+ "url": "https://github.com/google/recaptcha.git",
15
+ "reference": "090585935d95ebdf2d16dd071b10c9179a94da47"
16
+ },
17
+ "dist": {
18
+ "type": "zip",
19
+ "url": "https://api.github.com/repos/google/recaptcha/zipball/090585935d95ebdf2d16dd071b10c9179a94da47",
20
+ "reference": "090585935d95ebdf2d16dd071b10c9179a94da47",
21
+ "shasum": ""
22
+ },
23
+ "require": {
24
+ "php": ">=5.3.2"
25
+ },
26
+ "require-dev": {
27
+ "phpunit/phpunit": "4.5.*"
28
+ },
29
+ "type": "library",
30
+ "extra": {
31
+ "branch-alias": {
32
+ "dev-master": "1.1.x-dev"
33
+ }
34
+ },
35
+ "autoload": {
36
+ "psr-4": {
37
+ "ReCaptcha\\": "src/ReCaptcha"
38
+ }
39
+ },
40
+ "notification-url": "https://packagist.org/downloads/",
41
+ "license": [
42
+ "BSD-3-Clause"
43
+ ],
44
+ "description": "Client library for reCAPTCHA, a free service that protect websites from spam and abuse.",
45
+ "homepage": "http://www.google.com/recaptcha/",
46
+ "keywords": [
47
+ "Abuse",
48
+ "captcha",
49
+ "recaptcha",
50
+ "spam"
51
+ ],
52
+ "time": "2015-03-16 13:45:08"
53
+ },
54
+ {
55
+ "name": "kminh/bwp-framework",
56
+ "version": "dev-master",
57
+ "source": {
58
+ "type": "git",
59
+ "url": "https://github.com/kminh/bwp-framework",
60
+ "reference": "e5a66731a92ed897188b55b94756694f0e9710b7"
61
+ },
62
+ "require": {
63
+ "php": "~5.1"
64
+ },
65
+ "type": "library",
66
+ "extra": {
67
+ "branch-alias": {
68
+ "dev-master": "1.0.x-dev"
69
+ }
70
+ },
71
+ "autoload": {
72
+ "classmap": [
73
+ "src/"
74
+ ]
75
+ },
76
+ "license": [
77
+ "GPLv3"
78
+ ],
79
+ "authors": [
80
+ {
81
+ "name": "Khang Minh",
82
+ "email": "kminhfoss@gmail.com"
83
+ }
84
+ ],
85
+ "description": "Base codes for BWP WordPress Plugins",
86
+ "homepage": "http://betterwp.net",
87
+ "time": "2015-08-16 08:27:08"
88
+ }
89
+ ],
90
+ "packages-dev": [],
91
+ "aliases": [],
92
+ "minimum-stability": "stable",
93
+ "stability-flags": {
94
+ "kminh/bwp-framework": 20
95
+ },
96
+ "prefer-stable": false,
97
+ "prefer-lowest": false,
98
+ "platform": [],
99
+ "platform-dev": []
100
+ }
includes/addons/contact-form-7/captcha-shortcode.php ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 Khang Minh <betterwp.net>
4
+ * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER
5
+ */
6
+
7
+ /**
8
+ * This class provides base integration between Contact Form 7 and BWP reCAPTCHA
9
+ * @since 1.1.0
10
+ */
11
+ class BWP_Recaptcha_CF7_Shortcode
12
+ {
13
+ /**
14
+ * The main plugin
15
+ *
16
+ * @access private
17
+ */
18
+ private static $_plugin;
19
+
20
+ /**
21
+ * Hold BWP_Recaptcha_Provider instance
22
+ *
23
+ * @access private
24
+ */
25
+ private static $_captchaProvider;
26
+
27
+ /**
28
+ * Hold BWP reCAPTCHA options
29
+ *
30
+ * @access private
31
+ */
32
+ private static $_options;
33
+
34
+ /**
35
+ * Text domain
36
+ *
37
+ * @access private
38
+ */
39
+ private static $_domain;
40
+
41
+ /**
42
+ * Private constructor
43
+ *
44
+ * @access private
45
+ */
46
+ private function __construct() {}
47
+
48
+ /**
49
+ * Init the integration
50
+ *
51
+ * @access public
52
+ */
53
+ public static function init(BWP_RECAPTCHA $plugin)
54
+ {
55
+ // make use of BWP reCAPTCHA's options and domain
56
+ self::$_plugin = $plugin;
57
+ self::$_captchaProvider = $plugin->get_captcha_provider();
58
+ self::$_options = $plugin->options;
59
+ self::$_domain = $plugin->plugin_dkey;
60
+
61
+ // register our main hooks to CF7
62
+ self::_registerHooks();
63
+ }
64
+
65
+ /**
66
+ * Adds recaptcha to Contact Form 7
67
+ *
68
+ * Register necessary hooks so that admin can add recaptcha to forms and
69
+ * validate captcha properly
70
+ *
71
+ * @return void
72
+ * @access private
73
+ */
74
+ private static function _registerHooks()
75
+ {
76
+ // admin hooks
77
+ if (is_admin()) {
78
+ add_action('admin_init', array(__CLASS__, 'registerCf7Tag'), 45);
79
+ }
80
+
81
+ // front-end hooks
82
+ add_action('wpcf7_init', array(__CLASS__, 'registerCf7Shortcode'));
83
+
84
+ // validation for all types of shortcodes, `bwp*` shortcodes are kept
85
+ // for BC only, and should not be used anymore
86
+ add_filter('wpcf7_validate_bwp-recaptcha', array(__CLASS__, 'validateCaptcha'), 10, 2);
87
+ add_filter('wpcf7_validate_bwp_recaptcha', array(__CLASS__, 'validateCaptcha'), 10, 2);
88
+ add_filter('wpcf7_validate_bwprecaptcha', array(__CLASS__, 'validateCaptcha'), 10, 2);
89
+ add_filter('wpcf7_validate_recaptcha', array(__CLASS__, 'validateCaptcha'), 10, 2);
90
+
91
+ // need to refresh captcha when the form is submitted via ajax
92
+ add_filter('wpcf7_ajax_json_echo', array(__CLASS__, 'refreshCaptcha'));
93
+
94
+ static::registerMoreHooks();
95
+ }
96
+
97
+ protected static function registerMoreHooks()
98
+ {
99
+ // to be overriden
100
+ }
101
+
102
+ /**
103
+ * Add BWP reCAPTCHA tag to CF7's tag selection pane
104
+ *
105
+ * @return void
106
+ * @access public
107
+ */
108
+ public static function registerCf7Tag()
109
+ {
110
+ $tagTitle = 'BWP reCAPTCHA';
111
+
112
+ // support for version prior to 4.2
113
+ if (version_compare(WPCF7_VERSION, '4.2', '<')) {
114
+ if (!function_exists('wpcf7_add_tag_generator')) {
115
+ return false;
116
+ }
117
+
118
+ wpcf7_add_tag_generator(
119
+ 'recaptcha',
120
+ $tagTitle,
121
+ 'wpcf7-tg-pane-recaptcha',
122
+ array(__CLASS__, 'renderCf7RecaptchaTagPane41')
123
+ );
124
+ } else {
125
+ $tagGenerator = WPCF7_TagGenerator::get_instance();
126
+ $tagGenerator->add('recaptcha', $tagTitle, array(__CLASS__, 'renderCf7RecaptchaTagPane'));
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Render BWP reCAPTCHA tag pane for `recaptcha` shortcode
132
+ *
133
+ * This is used with Contact Form 7 version 4.2+
134
+ *
135
+ * @param WPCF7_ContactForm $contactForm
136
+ * @param array $args
137
+ * @access public
138
+ */
139
+ public static function renderCf7RecaptchaTagPane($contactForm, $args = '')
140
+ {
141
+ $args = wp_parse_args($args, array());
142
+ ?>
143
+ <div class="control-box">
144
+ <fieldset>
145
+ <legend><?php echo self::_getTagDescription(); ?></legend>
146
+
147
+ <table class="form-table">
148
+ <tbody>
149
+ <tr>
150
+ <th scope="row"><label for="<?php echo esc_attr( $args['content'] . '-name' ); ?>"><?php echo esc_html( __( 'Name', 'contact-form-7' ) ); ?></label></th>
151
+ <td><input type="text" name="name" class="tg-name oneline" id="<?php echo esc_attr( $args['content'] . '-name' ); ?>" /></td>
152
+ </tr>
153
+ </tbody>
154
+ </table>
155
+ </fieldset>
156
+ </div>
157
+
158
+ <div class="insert-box">
159
+ <input type="text" name="recaptcha" class="tag code" readonly="readonly" onfocus="this.select()" />
160
+ <div class="submitbox">
161
+ <input type="button" class="button button-primary insert-tag" value="<?php echo esc_attr( __( 'Insert Tag', 'contact-form-7' ) ); ?>" />
162
+ </div>
163
+ </div>
164
+ <?php
165
+ }
166
+
167
+ /**
168
+ * Render BWP reCAPTCHA tag pane for `recaptcha` shortcode
169
+ *
170
+ * This is used with Contact Form 7 prior to version 4.2
171
+ *
172
+ * @param WPCF7_ContactForm $contactForm
173
+ * @access public
174
+ */
175
+ public static function renderCf7RecaptchaTagPane41($contactForm)
176
+ {
177
+ ?>
178
+ <div id="wpcf7-tg-pane-recaptcha" class="hidden">
179
+ <form action="">
180
+ <table>
181
+ <tr>
182
+ <td colspan="2"><?php echo self::_getTagDescription(); ?></td>
183
+ </tr>
184
+
185
+ <tr>
186
+ <td>
187
+ <?php echo esc_html(__('Name', 'contact-form-7')); ?>
188
+ <br />
189
+ <input type="text" name="name" class="tg-name oneline" />
190
+ </td>
191
+ <td></td>
192
+ </tr>
193
+ </table>
194
+
195
+ <div class="tg-tag">
196
+ <?php echo esc_html(__( "Copy this code and paste it into the form left.", 'contact-form-7')); ?>
197
+ <br />
198
+ <input type="text" name="recaptcha" class="tag" readonly="readonly" onfocus="this.select()" />
199
+ </div>
200
+ </form>
201
+ </div>
202
+ <?php
203
+ }
204
+
205
+ private static function _getTagDescription()
206
+ {
207
+ $pluginUrl = self::$_plugin->plugin_url;
208
+
209
+ $description = array(
210
+ '<strong style="color: #e6255b">',
211
+ esc_html(__('This reCAPTCHA tag is provided by the BWP reCAPTCHA WordPress plugin.', self::$_domain)),
212
+ '</strong>',
213
+ '<br />',
214
+ sprintf('<a href="%1$s">%1$s</a>', $pluginUrl),
215
+ '<br />',
216
+ sprintf(__('Please refer to <a target="_blank" href="%s">'
217
+ . 'BWP reCAPTCHA\'s documentation</a> for '
218
+ . 'a quick guide on how to customize the look and feel '
219
+ . 'of this tag.', self::$_domain), $pluginUrl . '/#customization')
220
+ );
221
+
222
+ return implode("\n", $description);
223
+ }
224
+
225
+ /**
226
+ * Register the BWP reCAPTCHA shortcode to CF7
227
+ *
228
+ * @return void
229
+ * @access public
230
+ */
231
+ public static function registerCf7Shortcode()
232
+ {
233
+ if (!function_exists('wpcf7_add_shortcode')) {
234
+ return false;
235
+ }
236
+
237
+ // @since 2.0.0 add support for two aliases:
238
+ // 1. `bwp_recaptcha`
239
+ // 2. `bwprecaptcha`
240
+ // This is to keep BC only and is deprecated
241
+ wpcf7_add_shortcode(array(
242
+ 'recaptcha',
243
+ 'bwp-recaptcha', // this will be converted to bwp_recaptcha in CF7 4.1+
244
+ 'bwprecaptcha',
245
+ ), array(__CLASS__, 'renderCf7Shortcode'), true);
246
+ }
247
+
248
+ /**
249
+ * Render the actual CF7 reCAPTCHA shortcode
250
+ *
251
+ * @access public
252
+ * @param array $tag
253
+ * @uses WPCF7_Shortcode class
254
+ */
255
+ public static function renderCf7Shortcode($tag)
256
+ {
257
+ $rc = self::$_plugin;
258
+
259
+ // some CF7-specific codes
260
+ $tag = new WPCF7_Shortcode($tag);
261
+ $name = $tag->name;
262
+
263
+ // if current user can bypass the captcha, no need to render anything
264
+ if ($rc->user_can_bypass()) {
265
+ return '';
266
+ }
267
+
268
+ if (empty($name)) {
269
+ return '';
270
+ }
271
+
272
+ // get validation error, if any
273
+ $error = function_exists('wpcf7_get_validation_error')
274
+ ? wpcf7_get_validation_error($name) : '';
275
+
276
+ ob_start();
277
+
278
+ do_action('bwp_recaptcha_add_markups', '', 'cf7-' . $name);
279
+ $rcOutput = ob_get_contents();
280
+
281
+ ob_end_clean();
282
+
283
+ // add a dummy input so that CF7's JS script can later display the
284
+ // error message (for ajax submit only)
285
+ $cf7Input = sprintf(
286
+ '<span class="wpcf7-form-control-wrap %1$s"><input type="hidden" '
287
+ . 'name="%1$s-dummy" /></span>',
288
+ esc_attr($tag->name)
289
+ );
290
+
291
+ return $rcOutput . $cf7Input . $error;
292
+ }
293
+
294
+ /**
295
+ * Validate captcha returned by the Contact Form
296
+ *
297
+ * @access public
298
+ * @uses WPCF7_Shortcode class
299
+ *
300
+ * @param WPCF7_Validation $result @since CF7 4.1
301
+ * @param array $tag
302
+ *
303
+ * @return WPCF7_Validation
304
+ */
305
+ public static function validateCaptcha($result, $tag)
306
+ {
307
+ $rc = self::$_plugin;
308
+ $provider = self::$_captchaProvider;
309
+
310
+ // some CF7-specific codes
311
+ $tag = new WPCF7_Shortcode($tag);
312
+ $type = $tag->type;
313
+ $name = $tag->name;
314
+
315
+ // if current user can bypass the captcha, no need to validate anything
316
+ if ($rc->user_can_bypass()) {
317
+ return $result;
318
+ }
319
+
320
+ // invalid captcha
321
+ if ($errors = $provider->verify()) {
322
+ $errorMessage = $provider->getErrorMessage(current($errors));
323
+
324
+ // invalid captcha response, show an error message
325
+ if (version_compare(WPCF7_VERSION, '4.1', '>=')) {
326
+ $result->invalidate($tag, $errorMessage);
327
+ } else {
328
+ // CF7 prior to 4.1 uses below codes
329
+ $result['valid'] = false;
330
+ $result['reason'][$name] = $errorMessage;
331
+ }
332
+ }
333
+
334
+ return $result;
335
+ }
336
+
337
+ /**
338
+ * Prepare the onSubmit hook array for child classes
339
+ *
340
+ * @access public
341
+ * @param array $items
342
+ * @return array
343
+ */
344
+ public static function refreshCaptcha($items)
345
+ {
346
+ if (!isset($items['onSubmit']) || !is_array($items['onSubmit'])) {
347
+ $items['onSubmit'] = array();
348
+ }
349
+
350
+ return $items;
351
+ }
352
+ }
includes/addons/contact-form-7/v1.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright (c) 2015 Khang Minh <contact@betterwp.net>
5
+ * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER
6
+ */
7
+
8
+ /**
9
+ * Shortcode for recaptcha v1
10
+ *
11
+ * @author Khang Minh <contact@betterwp.net>
12
+ */
13
+ class BWP_Recaptcha_CF7_V1 extends BWP_Recaptcha_CF7_Shortcode
14
+ {
15
+ protected static function registerMoreHooks()
16
+ {
17
+ add_filter('wpcf7_ajax_json_echo', array(__CLASS__, 'refreshCaptcha'));
18
+ }
19
+
20
+ /**
21
+ * Refresh the captcha when needed
22
+ *
23
+ * @access public
24
+ * @param array $items
25
+ * @return array
26
+ */
27
+ public static function refreshCaptcha($items)
28
+ {
29
+ $items['onSubmit'][] = 'if (typeof Recaptcha !== "undefined") { Recaptcha.reload(); }';
30
+
31
+ return $items;
32
+ }
33
+ }
includes/addons/contact-form-7/v2.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright (c) 2015 Khang Minh <contact@betterwp.net>
5
+ * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER
6
+ */
7
+
8
+ /**
9
+ * Shortcode for recaptcha v2
10
+ *
11
+ * @author Khang Minh <contact@betterwp.net>
12
+ */
13
+ class BWP_Recaptcha_CF7_V2 extends BWP_Recaptcha_CF7_Shortcode
14
+ {
15
+ protected static function registerMoreHooks()
16
+ {
17
+ add_filter('wpcf7_ajax_json_echo', array(__CLASS__, 'refreshCaptcha'));
18
+ }
19
+
20
+ /**
21
+ * Refresh the captcha when needed
22
+ *
23
+ * @access public
24
+ * @param array $items
25
+ * @return array
26
+ */
27
+ public static function refreshCaptcha($items)
28
+ {
29
+ if (!function_exists('wpcf7_scan_shortcode')) {
30
+ return $items;
31
+ }
32
+
33
+ if (!$fields = wpcf7_scan_shortcode(array('type' => array(
34
+ 'recaptcha',
35
+ 'bwprecaptcha',
36
+ 'bwp-recaptcha',
37
+ 'bwp_recaptcha'
38
+ )))) {
39
+ return $items;
40
+ };
41
+
42
+ $codes = array();
43
+ foreach ($fields as $field) {
44
+ $name = $field['name'];
45
+ $options = $field['options'];
46
+
47
+ if (empty($name) || empty($_POST['bwp-recaptcha-widget-id'])) {
48
+ continue;
49
+ }
50
+
51
+ // right now we can only support one captcha instance per form
52
+ $codes[] = 'if (grecaptcha) { grecaptcha.reset(' . trim($_POST['bwp-recaptcha-widget-id']) . '); }';
53
+ }
54
+
55
+ $items['onSubmit'][] = implode('', $codes);
56
+
57
+ return $items;
58
+ }
59
+ }
includes/addons/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ //white page
includes/bwp-option-page/bwp-option-page.php DELETED
@@ -1,3 +0,0 @@
1
- <?php
2
- if (!is_admin()) return;
3
- require_once(dirname(__FILE__) . '/includes/class-bwp-option-page.php');
 
 
 
includes/bwp-option-page/images/ad_250x250.png DELETED
Binary file
includes/class-bwp-recaptcha-cf7.php DELETED
@@ -1,317 +0,0 @@
1
- <?php
2
- /**
3
- * Copyright (c) 2014 Khang Minh <betterwp.net>
4
- * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER
5
- */
6
-
7
- /**
8
- * This class provides integration between Contact Form 7 and BWP reCAPTCHA
9
- * @since 1.1.0
10
- */
11
- class BWP_RECAPTCHA_CF7
12
- {
13
- /**
14
- * Hold BWP reCAPTCHA instance
15
- *
16
- * @access private
17
- */
18
- private static $_bwpRcInstance;
19
-
20
- /**
21
- * Hold BWP reCAPTCHA options
22
- *
23
- * @access private
24
- */
25
- private static $_options;
26
-
27
- /**
28
- * Text domain
29
- *
30
- * @access private
31
- */
32
- private static $_domain;
33
-
34
- /**
35
- * Private constructor
36
- *
37
- * @access private
38
- */
39
- private function __construct() {}
40
-
41
- /**
42
- * Init the integration
43
- *
44
- * @access public
45
- */
46
- public static function init($bwpRcInstance)
47
- {
48
- // make use of BWP reCAPTCHA's options and domain
49
- self::$_bwpRcInstance = $bwpRcInstance;
50
- self::$_options = $bwpRcInstance->options;
51
- self::$_domain = $bwpRcInstance->plugin_dkey;
52
-
53
- // register our main hooks to CF7
54
- self::_registerHooks();
55
- }
56
-
57
- /**
58
- * Adds recaptcha to Contact Form 7
59
- *
60
- * Register necessary hooks so that admin can add recaptcha to forms and
61
- * validate captcha properly
62
- *
63
- * @return void
64
- * @access private
65
- */
66
- private static function _registerHooks()
67
- {
68
- // admin hooks
69
- add_action('admin_init', array(__CLASS__, 'registerCf7Tag'), 45);
70
-
71
- // front-end hooks
72
- add_action('wpcf7_init', array(__CLASS__, 'registerCf7Shortcode'));
73
-
74
- if (self::$_options['select_cf7_tag'] == 'bwp-recaptcha') {
75
- add_filter('wpcf7_validate_bwp-recaptcha', array(__CLASS__, 'validateCaptcha'), 10, 2);
76
- } else {
77
- add_filter('wpcf7_validate_recaptcha', array(__CLASS__, 'validateCaptcha'), 10, 2);
78
- }
79
-
80
- add_filter('wpcf7_ajax_json_echo', array(__CLASS__, 'refreshCaptcha'));
81
-
82
- // other hooks
83
- //self::_enqueueMedia();
84
- }
85
-
86
- private static function _enqueueMedia()
87
- {
88
- wp_enqueue_script('recaptcha-ajax', 'http://www.google.com/recaptcha/api/js/recaptcha_ajax.js');
89
- }
90
-
91
- private static function _renderCf7TagPane($for)
92
- {
93
- $id = 'wpcf7-tg-pane-' . $for;
94
- ?>
95
- <div id="<?php echo $id; ?>" class="hidden">
96
-
97
- <form action="">
98
-
99
- <table>
100
- <tr>
101
- <td colspan="2">
102
- <strong style="color: #e6255b"><?php echo esc_html(
103
- __('This reCAPTCHA tag is provided by the BWP reCAPTCHA WordPress plugin.', self::$_domain)
104
- ); ?></strong><br />
105
- <a href="<?php echo self::$_bwpRcInstance->plugin_url; ?>"><?php echo self::$_bwpRcInstance->plugin_url; ?></a><br />
106
- <?php printf(__('Please refer to <a target="_blank" href="%s">'
107
- . 'BWP reCAPTCHA\'s documentation </a> for '
108
- . 'a quick guide on how to customize the look and feel '
109
- . 'of this tag.', self::$_domain),
110
- 'http://betterwp.net/wordpress-plugins/bwp-recaptcha/#customization'); ?>
111
- </td>
112
- </tr>
113
-
114
- <tr>
115
- <td><?php echo esc_html(__('Name', 'contact-form-7')); ?><br />
116
- <input type="text" name="name" class="tg-name oneline" /></td>
117
- <td></td>
118
- </tr>
119
- </table>
120
-
121
- <div class="tg-tag">
122
- <?php echo esc_html(__( "Copy this code and paste it into the form left.", 'contact-form-7')); ?><br />
123
- <input type="text" name="<?php echo $for; ?>" class="tag" readonly="readonly" onfocus="this.select()" />
124
- </div>
125
-
126
- </form>
127
-
128
- </div>
129
- <?php
130
- }
131
-
132
- /**
133
- * Add BWP reCAPTCHA tag to CF7's tag selection pane
134
- *
135
- * @return void
136
- * @access public
137
- */
138
- public static function registerCf7Tag()
139
- {
140
- if (!function_exists('wpcf7_add_tag_generator')) {
141
- return false;
142
- }
143
-
144
- if (self::$_options['select_cf7_tag'] == 'bwp-recaptcha') {
145
- wpcf7_add_tag_generator(
146
- 'bwp-recaptcha',
147
- 'BWP reCAPTCHA', // this string needs no translation
148
- 'wpcf7-tg-pane-bwp-recaptcha',
149
- array(__CLASS__, 'renderCf7BWPRecaptchaTagPane')
150
- );
151
- } else {
152
- wpcf7_add_tag_generator(
153
- 'recaptcha',
154
- 'BWP reCAPTCHA', // this string needs no translation
155
- 'wpcf7-tg-pane-recaptcha',
156
- array(__CLASS__, 'renderCf7RecaptchaTagPane')
157
- );
158
- }
159
- }
160
-
161
- /**
162
- * Render BWP reCAPTCHA tag pane for `bwp-recaptcha` shortcode
163
- *
164
- * @return void
165
- * @access public
166
- */
167
- public static function renderCf7BWPRecaptchaTagPane(&$contactForm)
168
- {
169
- self::_renderCf7TagPane('bwp-recaptcha');
170
- }
171
-
172
- /**
173
- * Render BWP reCAPTCHA tag pane for `recaptcha` shortcode
174
- *
175
- * @return void
176
- * @access public
177
- */
178
- public static function renderCf7RecaptchaTagPane(&$contactForm)
179
- {
180
- self::_renderCf7TagPane('recaptcha');
181
- }
182
-
183
- /**
184
- * Register the BWP reCAPTCHA shortcode to CF7
185
- *
186
- * @return void
187
- * @access public
188
- */
189
- public static function registerCf7Shortcode()
190
- {
191
- if (!function_exists('wpcf7_add_shortcode')) {
192
- return false;
193
- }
194
-
195
- if (self::$_options['select_cf7_tag'] == 'bwp-recaptcha') {
196
- wpcf7_add_shortcode('bwp-recaptcha', array(__CLASS__, 'renderCf7Shortcode'), true);
197
- } else {
198
- wpcf7_add_shortcode('recaptcha', array(__CLASS__, 'renderCf7Shortcode'), true);
199
- }
200
- }
201
-
202
- /**
203
- * Render the actual CF7 reCAPTCHA shortcode
204
- *
205
- * @access public
206
- * @uses WPCF7_Shortcode class
207
- */
208
- public static function renderCf7Shortcode($tag)
209
- {
210
- $rc = self::$_bwpRcInstance;
211
-
212
- // some CF7-specific codes
213
- $tag = new WPCF7_Shortcode($tag);
214
- $name = $tag->name;
215
-
216
- // if current user can bypass the captcha, no need to render anything
217
- if ($rc->user_can_bypass()) {
218
- return '';
219
- }
220
-
221
- // get validation error, if any
222
- $error = function_exists('wpcf7_get_validation_error')
223
- ? wpcf7_get_validation_error($name) : '';
224
-
225
- ob_start();
226
-
227
- do_action('bwp_recaptcha_add_markups');
228
- $rcOutput = ob_get_contents();
229
-
230
- ob_end_clean();
231
-
232
- // we use ajax to populate recaptcha
233
- /*$rcOutput = ''
234
- . "\n" . '<script type="text/javascript">'
235
- . "\n" . 'jQuery(document).ready(function() {'
236
- . "\n\t" . 'Recaptcha.create("' . $rc->options['input_pubkey'] . '", "' . $tag->name . '", {'
237
- . "\n\t\t" . 'theme: "' . $rc->options['select_theme'] . '",'
238
- . "\n\t\t" . 'lang: "' . $rc->options['select_lang'] . '"'
239
- . "\n\t" . '});'
240
- . "\n" . '});'
241
- . "\n" . '</script>';
242
- $rcOutput .= '<div id="' . esc_attr($tag->name) . '"></div>';*/
243
-
244
- // add a dummy input so that CF7's JS script can later display the error message (for ajax submit only)
245
- $cf7Input = sprintf(
246
- '<span class="wpcf7-form-control-wrap %1$s"><input type="hidden" name="%1$s-dummy" /></span>',
247
- $tag->name
248
- );
249
-
250
- return $rcOutput . $cf7Input . $error;
251
- }
252
-
253
- /**
254
- * Validate captcha returned by the Contact Form
255
- *
256
- * @access public
257
- * @uses WPCF7_Shortcode class
258
- * @uses reCAPTCHA PHP library
259
- */
260
- public static function validateCaptcha($result, $tag)
261
- {
262
- $rc = self::$_bwpRcInstance;
263
-
264
- // some CF7-specific codes
265
- $tag = new WPCF7_Shortcode($tag);
266
- $type = $tag->type;
267
- $name = $tag->name;
268
-
269
- // if current user can bypass the captcha, no need to validate anything
270
- if ($rc->user_can_bypass()) {
271
- return $result;
272
- }
273
-
274
- // if the captcha challenge and response are not found, return error
275
- if (!isset($_POST['recaptcha_challenge_field'])
276
- || !isset($_POST['recaptcha_response_field'])
277
- ) {
278
- $result['valid'] = false;
279
- $result['reason'][$name] = $rc->options['input_error'];
280
- }
281
-
282
- // load the recaptcha PHP library just in case
283
- $rc->load_captcha_library();
284
-
285
- $response = recaptcha_check_answer(
286
- $rc->options['input_prikey'],
287
- $_SERVER['REMOTE_ADDR'],
288
- $_POST['recaptcha_challenge_field'],
289
- $_POST['recaptcha_response_field']
290
- );
291
-
292
- if (!$response->is_valid) {
293
- // invalid captcha response, show an error message
294
- $result['valid'] = false;
295
- $result['reason'][$name] = $rc->options['input_error'];
296
- }
297
-
298
- return $result;
299
- }
300
-
301
- /**
302
- * Refresh the captcha when needed
303
- *
304
- * @access public
305
- * @return array
306
- */
307
- public static function refreshCaptcha($items)
308
- {
309
- if (!isset($items['onSubmit']) || !is_array($items['onSubmit'])) {
310
- $items['onSubmit'] = array();
311
- }
312
-
313
- $items['onSubmit'][] = 'if (typeof Recaptcha != "undefined") { Recaptcha.reload(); }';
314
-
315
- return $items;
316
- }
317
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class-bwp-recaptcha.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2014 Khang Minh <betterwp.net>
4
  *
5
  * This program is free software: you can redistribute it and/or modify
6
  * it under the terms of the GNU General Public License as published by
@@ -25,9 +25,10 @@ function bwp_capt_comment_form($args = array(), $post_id = null)
25
  {
26
  global $bwp_capt;
27
 
28
- remove_action('comment_form_after_fields', array($bwp_capt, 'add_recaptcha'));
29
- remove_action('comment_form_logged_in_after', array($bwp_capt, 'add_recaptcha'));
30
- remove_filter('comment_form_defaults', array($bwp_capt, 'add_recaptcha_after_comment_field'));
 
31
 
32
  ob_start();
33
 
@@ -37,90 +38,107 @@ function bwp_capt_comment_form($args = array(), $post_id = null)
37
  ob_end_clean();
38
 
39
  if (isset($args['comment_notes_after']))
40
- $args['comment_notes_after'] .= $recaptcha_html;
41
  else
42
  $args['comment_notes_after'] = $recaptcha_html;
43
 
44
  comment_form($args, $post_id);
45
  }
46
 
47
- if (!class_exists('BWP_FRAMEWORK_IMPROVED'))
48
- require_once('class-bwp-framework-improved.php');
49
-
50
- class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
51
  {
52
  /**
53
  * reCAPTCHA built-in languages
54
  */
55
- var $lang;
 
 
 
 
 
56
 
57
  /**
58
  * User capabilities to bypass captcha
59
  */
60
- var $caps;
61
 
62
  /**
63
  * Is registering via wp-login.php
64
  */
65
- var $is_reg = false;
66
 
67
  /**
68
  * Captcha error message when registering via wp-login.php
69
  */
70
- var $reg_errors = false;
71
 
72
  /**
73
  * Is signing up (multi-site only)
74
  */
75
- var $is_signup = false;
76
 
77
  /**
78
  * Is logging in via wp-login.php
79
  */
80
- var $is_login = false;
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
  /**
83
- * Constructor
84
  */
85
- public function __construct($version = '1.1.2')
86
  {
87
- // Plugin's title
88
- $this->plugin_title = 'Better WordPress reCAPTCHA';
89
- // Plugin's version
90
- $this->set_version($version);
91
- // Plugin's language domain
92
- $this->domain = 'bwp-recaptcha';
93
  // Basic version checking
94
  if (!$this->check_required_versions())
95
  return;
96
 
97
  // Default options
98
  $options = array(
99
- 'input_pubkey' => '',
100
- 'input_prikey' => '',
101
- 'input_error' => __('<strong>ERROR:</strong> Incorrect or '
102
  . 'empty reCAPTCHA response, please try again.', $this->domain),
103
- 'input_back' => __('Error: Incorrect or empty reCAPTCHA response, '
104
  . 'please click the back button on your browser\'s toolbar or '
105
  . 'click on %s to go back.', $this->domain),
106
- 'input_approved' => 1,
107
- 'input_tab' => 0,
108
- 'enable_comment' => 'yes',
109
- 'enable_registration' => 'yes',
110
- 'enable_login' => '',
111
- 'enable_akismet' => '',
112
- 'enable_css' => 'yes',
113
- 'use_global_keys' => 'yes',
114
- 'select_lang' => 'en',
115
- 'select_theme' => 'red',
116
- 'select_cap' => 'manage_options',
117
- 'select_cf7_tag' => 'bwp-recaptcha',
118
- 'select_response' => 'redirect',
119
- 'select_position' => 'after_comment_field',
120
- 'select_akismet_react' => 'hold',
121
- 'hide_registered' => 'yes',
122
- 'hide_cap' => '',
123
- 'hide_approved' => 'yes'
 
 
 
 
 
 
 
124
  );
125
 
126
  $this->add_option_key('BWP_CAPT_OPTION_GENERAL', 'bwp_capt_general',
@@ -135,114 +153,96 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
135
  'http://betterwp.net/wordpress-plugins/bwp-recaptcha/', false);
136
  }
137
 
138
- private function _load_template_functions()
 
 
 
 
 
139
  {
140
- if (!function_exists('bwp_capt_custom_theme_widget')) :
141
-
142
- /**
143
- * Output custom reCAPTCHA theme
144
- *
145
- * By defining this function in your theme/plugin, you can override this
146
- * and thus changing the html codes to suit your needs.
147
- *
148
- * @return void
149
- */
150
- function bwp_capt_custom_theme_widget()
151
  {
152
- global $bwp_capt;
153
- ?>
154
- <script type="text/javascript">
155
- var RecaptchaOptions = {
156
- theme : 'custom',
157
- custom_theme_widget: 'recaptcha_widget',
158
- tabindex: <?php echo (int) $bwp_capt->options['input_tab']; echo "\n"; ?>
159
- };
160
- </script>
161
- <div id="recaptcha_widget" style="display: none;">
162
- <p class="recaptcha_only_if_incorrect_sol">
163
- <?php echo $bwp_capt->options['input_error']; ?>
164
- </p>
165
- <div id="recaptcha_image"></div>
166
- <div class="recaptcha_control">
167
- <a href="javascript:Recaptcha.reload()" title="<?php _e('Get another challenge', $bwp_capt->domain); ?>"><img src="<?php echo BWP_CAPT_IMAGES . '/icon_refresh.png'; ?>" alt="<?php _e('Get another challenge', $bwp_capt->domain); ?>" /></a>
168
- <span class="recaptcha_only_if_image"><a href="javascript:Recaptcha.switch_type('audio')" title="<?php _e('Get audio reCAPTCHA', $bwp_capt->domain); ?>"><img src="<?php echo BWP_CAPT_IMAGES . '/icon_sound.png'; ?>" alt="<?php _e('Get audio reCAPTCHA', $bwp_capt->domain); ?>" /></a></span>
169
- <span class="recaptcha_only_if_audio"><a href="javascript:Recaptcha.switch_type('image')" title="<?php _e('Get image reCAPTCHA', $bwp_capt->domain); ?>"><img src="<?php echo BWP_CAPT_IMAGES . '/icon_image.png'; ?>" alt="<?php _e('Get image reCAPTCHA', $bwp_capt->domain); ?>" /></a></span>
170
- <span><a href="javascript:Recaptcha.showhelp()" title="<?php _e('About reCAPTCHA', $bwp_capt->domain); ?>"><img src="<?php echo BWP_CAPT_IMAGES . '/icon_help.png'; ?>" alt="<?php _e('About reCAPTCHA', $bwp_capt->domain); ?>" /></a></span>
171
- </div>
172
-
173
- <div class="recaptcha_text">
174
- <span class="recaptcha_only_if_image"><label for="recaptcha_response_field"><em><small><?php _e('Enter the two words in the box:', $bwp_capt->domain); ?></small></em></label></span>
175
- <span class="recaptcha_only_if_audio"><label for="recaptcha_response_field"><em><small><?php _e('Enter the numbers you hear:', $bwp_capt->domain); ?></small></em></label></span>
176
- <input type="text" id="recaptcha_response_field" tabindex="<?php echo (int) $bwp_capt->options['input_tab']; ?>" class="input" name="recaptcha_response_field" />
177
- </div>
178
- </div>
179
- <?php
180
  }
181
 
182
- endif;
 
 
 
 
 
 
 
 
 
183
  }
184
 
185
  private function _set_session_data($key, $value)
186
  {
187
- // use $_SESSION, if $_SESSION isn't available there's no alternative
188
- // for now
 
189
  if (!isset($_SESSION))
190
- {
191
  return;
192
- }
193
 
194
  $_SESSION[$key] = trim($value);
195
  }
196
 
 
 
 
 
 
 
 
 
 
197
  private function _unset_session_data($key)
198
  {
199
  if (isset($_SESSION[$key]))
200
- {
201
  unset($_SESSION[$key]);
202
- }
203
  }
204
 
205
  /**
206
- * Checks if captcha is required based on akismet integration
207
  *
208
  * @since 1.1.1
209
  * @return bool
210
  */
211
- private function _is_captcha_required()
212
  {
213
- if (!defined('AKISMET_VERSION') || 'yes' != $this->options['enable_akismet'])
214
- return true;
215
-
216
- if ($this->_is_comment_spam())
217
  return true;
218
 
219
  return false;
220
  }
221
 
222
- private function _is_comment_spam()
 
 
 
 
 
223
  {
224
- if (isset($_SESSION['bwp_capt_comment_is_spam'])
225
- && 'yes' == $_SESSION['bwp_capt_comment_is_spam']
226
- ) {
227
  return true;
228
- }
229
 
230
  return false;
231
  }
232
 
233
  protected function pre_init_properties()
234
  {
235
- $this->lang = array(
236
- __('English', $this->domain) => 'en',
237
- __('Dutch', $this->domain) => 'nl',
238
- __('French', $this->domain) => 'fr',
239
- __('German', $this->domain) => 'de',
240
- __('Italian', $this->domain) => 'it',
241
- __('Portuguese', $this->domain) => 'pt',
242
- __('Russian', $this->domain) => 'ru',
243
- __('Spanish', $this->domain) => 'es',
244
- __('Turkish', $this->domain) => 'tr'
245
- );
246
 
247
  $this->caps = apply_filters('bwp_capt_bypass_caps', array(
248
  __('Read Profile', $this->domain) => 'read',
@@ -251,128 +251,187 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
251
 
252
  // @since 1.1.0 init public and private keys based on multi-site setting
253
  $this->init_captcha_keys();
 
254
 
255
- if (strpos($_SERVER['REQUEST_URI'], 'wp-login.php') !== false
256
- && !empty($_REQUEST['action']) && 'register' == $_REQUEST['action']
257
- ) {
258
- // whether user is requesting regular user registration page
259
- $this->is_reg = true;
 
 
 
 
 
 
 
 
 
 
 
260
  }
261
 
262
- if (strpos($_SERVER['REQUEST_URI'], 'wp-signup.php') !== false)
263
  {
264
- // whether user is requesting wp-signup page (multi-site page for
265
- // user/site registration)
266
- $this->is_signup = true;
 
 
 
 
 
 
 
 
 
 
 
267
  }
 
268
 
269
- if (strpos($_SERVER['REQUEST_URI'], 'wp-login.php') !== false
270
- && empty($_REQUEST['action'])
271
- ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  // whether user is requesting the wp-login page
273
  $this->is_login = true;
274
  }
 
 
 
 
 
 
275
  }
276
 
277
- protected function pre_init_hooks()
 
 
 
278
  {
279
- if (!is_admin() && !isset($_SESSION))
280
  {
281
- // start a session to store Akismet and comment data between
282
- // requests, only on front end and when applicable
283
- if (headers_sent() && (!defined('WP_DEBUG') || !WP_DEBUG))
284
- return;
285
-
286
- session_start();
 
 
287
  }
288
  }
289
 
290
- protected function init_hooks()
291
  {
292
- // load custom template function at this stage to make it pluggable
293
- $this->_load_template_functions();
294
 
295
- if (defined('WPCF7_VERSION'))
 
 
 
 
296
  {
297
- // add support for Contact Form 7 (CF7) automatically if CF7 is
298
- // installed and activated
299
- include_once dirname(__FILE__) . '/class-bwp-recaptcha-cf7.php';
300
- BWP_RECAPTCHA_CF7::init($this);
301
  }
302
-
303
- if (!empty($this->options['input_pubkey']) && !empty($this->options['input_prikey']))
304
  {
305
- // this action needs to be added when a captcha is manually needed
306
- add_action('bwp_recaptcha_add_markups', array($this, 'add_recaptcha'));
307
-
308
- if ('yes' == $this->options['enable_comment'])
309
  {
310
- // add captcha to comment form
311
- if (!$this->_is_captcha_required())
312
- {
313
- // if user chooses to integrate with akismet, only show
314
- // recaptcha when comment is marked as spam
315
- add_action('akismet_spam_caught', array($this, 'add_recaptcha_after_akismet'));
316
- }
317
- else if (!$this->user_can_bypass())
318
- {
319
- if ($this->options['select_position'] == 'after_fields')
320
- {
321
- // show captcha after website field
322
- add_action('comment_form_after_fields', array($this, 'add_recaptcha'));
323
- add_action('comment_form_logged_in_after', array($this, 'add_recaptcha'));
324
- }
325
- elseif ($this->options['select_position'] == 'after_comment_field')
326
- {
327
- // show captcha after comment field (default @since 1.1.1)
328
- add_filter('comment_form_defaults', array($this, 'add_recaptcha_after_comment_field'));
329
- }
330
-
331
- // fill the comment textarea
332
- add_filter('comment_form_field_comment', array($this, 'fill_comment_content'));
333
-
334
- // check entered captcha for comment form
335
- add_action('pre_comment_on_post', array($this, 'check_recaptcha'));
336
- }
337
  }
338
-
339
- if ('yes' == $this->options['enable_registration'] && $this->is_reg)
340
  {
341
- // normal user registration page
342
- add_action('register_form', array($this, 'add_recaptcha'));
343
- add_filter('registration_errors', array($this, 'check_reg_recaptcha'));
 
 
 
 
 
 
 
 
 
 
344
  }
345
 
346
- if ('yes' == $this->options['enable_registration'] && $this->is_signup)
347
- {
348
- // wpms user/site registration page
349
- add_action('signup_extra_fields', array($this, 'add_recaptcha'));
350
- add_action('signup_blogform', array($this, 'add_blog_reg_recaptcha'));
351
- add_filter('wpmu_validate_user_signup', array($this, 'check_user_reg_recaptcha'));
352
- add_filter('wpmu_validate_blog_signup', array($this, 'check_blog_reg_recaptcha'));
353
  }
354
 
355
- if ('yes' == $this->options['enable_login'] && $this->is_login)
356
- {
357
- // @since 1.1.0 add captcha to login form
358
- add_action('login_form', array($this, 'add_recaptcha'));
359
-
360
- // the priority of 15 is to ensure that we run the filter before
361
- // WordPress authenticates the user.
362
- add_filter('authenticate', array($this, 'authenticate_with_recaptcha'), 15);
363
- }
364
  }
365
  }
366
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
  protected function init_captcha_keys()
368
  {
 
 
369
  if (self::is_multisite())
370
  {
371
- if ('yes' == $this->options['use_global_keys'])
 
372
  {
373
- $site_options = get_site_option(BWP_CAPT_OPTION_GENERAL);
374
- $this->options['input_pubkey'] = $site_options['input_pubkey'];
375
- $this->options['input_prikey'] = $site_options['input_prikey'];
 
 
 
 
376
  }
377
  }
378
  }
@@ -397,22 +456,22 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
397
  // load default CSS for custom theme
398
  wp_enqueue_style('bwp-capt', $bwp_capt_css);
399
  }
 
400
 
401
- if (('yes' == $this->options['enable_registration'] && $this->is_reg)
402
- || ('yes' == $this->options['enable_login'] && $this->is_login)
403
- ) {
404
- add_action('login_head', array($this, 'print_inline_styles_for_login'), 11); // make sure this is late enough
405
- }
406
  }
407
  }
408
 
409
- public function load_captcha_library()
 
 
 
410
  {
411
- if (!function_exists('recaptcha_get_html')
412
- || !function_exists('recaptcha_check_answer')
413
- ) {
414
- require_once(dirname(__FILE__) . '/recaptcha/recaptchalib.php');
415
- }
416
  }
417
 
418
  public function print_inline_styles_for_login()
@@ -423,7 +482,7 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
423
  #login {
424
  width: <?php echo $login_width; ?>px;
425
  }
426
- #recaptcha_widget_div {
427
  margin-bottom: 15px;
428
  zoom: 1;
429
  }
@@ -441,7 +500,7 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
441
  'BWP reCAPT',
442
  BWP_CAPT_CAPABILITY,
443
  BWP_CAPT_OPTION_GENERAL,
444
- array($this, 'build_option_pages'),
445
  BWP_CAPT_IMAGES . '/icon_menu.png'
446
  );
447
 
@@ -451,7 +510,7 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
451
  __('General Options', $this->domain),
452
  BWP_CAPT_CAPABILITY,
453
  BWP_CAPT_OPTION_GENERAL,
454
- array($this, 'build_option_pages')
455
  );
456
 
457
  add_submenu_page(
@@ -460,16 +519,17 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
460
  __('Theme Options', $this->domain),
461
  BWP_CAPT_CAPABILITY,
462
  BWP_CAPT_OPTION_THEME,
463
- array($this, 'build_option_pages')
464
  );
465
  }
466
 
467
  public function modify_option_page()
468
  {
469
  global $blog_id;
 
 
470
  ?>
471
  <script type="text/javascript">
472
- <?php if (self::is_multisite() && 1 < $blog_id) { ?>
473
  var rc_readonly = <?php echo 'yes' == $this->options['use_global_keys'] ? 'true' : 'false'; ?>;
474
  jQuery('input[name="input_pubkey"], input[name="input_prikey"]').prop('readOnly', rc_readonly);
475
  jQuery('input[name="use_global_keys"]').on('click', function() {
@@ -479,35 +539,23 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
479
  jQuery('input[name="input_pubkey"], input[name="input_prikey"]').prop('readOnly', false);
480
  }
481
  });
482
- <?php } else { ?>
483
- jQuery('input[name="use_global_keys"]').parents('li.bwp-clear').hide();
484
- <?php } ?>
485
  </script>
486
  <?php
 
487
  }
488
 
489
- /**
490
- * Build the option pages
491
- *
492
- * Utilizes BWP Option Page Builder (@see BWP_OPTION_PAGE)
493
- */
494
- public function build_option_pages()
495
  {
496
- if (!current_user_can(BWP_CAPT_CAPABILITY))
497
- wp_die(__('You do not have sufficient permissions to access this page.'));
498
-
499
- $page = $_GET['page'];
500
- $bwp_option_page = new BWP_OPTION_PAGE($page, $this->site_options, $this->domain);
501
-
502
- $options = array();
503
 
504
  if (!empty($page))
505
  {
506
  if ($page == BWP_CAPT_OPTION_GENERAL)
507
  {
508
- $bwp_option_page->set_current_tab(1);
509
 
510
- // Option Structures - Form
511
  $form = array(
512
  'items' => array(
513
  'heading',
@@ -515,69 +563,79 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
515
  'input',
516
  'input',
517
  'heading',
 
 
518
  'section',
519
  'section',
520
  'heading',
521
  'select',
522
  'select',
 
523
  'input',
524
  'input',
525
  'heading',
526
  'checkbox',
527
  'select',
528
  'heading',
529
- 'select'
530
  ),
531
  'item_labels' => array(
532
  __('reCAPTCHA API Keys', $this->domain),
533
  __('Use main site\'s keys', $this->domain),
534
- __('Public Key', $this->domain),
535
- __('Private Key', $this->domain),
536
  __('Plugin Functionality', $this->domain),
 
 
537
  __('Enable this plugin for', $this->domain),
538
  __('Hide captcha for', $this->domain),
539
  __('reCAPTCHA for comment form', $this->domain),
540
  __('Captcha position', $this->domain),
541
  __('If invalid captcha response', $this->domain),
 
542
  __('Invalid captcha error message', $this->domain),
543
  __('Invalid captcha error message', $this->domain),
544
  __('Akismet Integration for comment form', $this->domain),
545
  __('Integrate with Akismet?', $this->domain),
546
  __('If correct captcha response', $this->domain),
547
  __('Contact Form 7 Integration', $this->domain),
548
- __('Captcha shortcode tag', $this->domain)
549
  ),
550
  'item_names' => array(
551
  'h1',
552
- 'cb7',
553
  'input_pubkey',
554
  'input_prikey',
555
  'heading_func',
 
 
556
  'sec1',
557
  'sec2',
558
- 'h2',
559
  'select_position',
560
  'select_response',
 
561
  'input_error',
562
  'input_back',
563
  'h3',
564
  'cb6',
565
  'select_akismet_react',
566
  'heading_cf7',
567
- 'select_cf7_tag'
568
  ),
569
  'heading' => array(
570
  'h1' => '<em>' . sprintf(
571
  __('For this plugin to work, you will need '
572
- . 'a pair of API keys (public and private), '
573
- . 'which is available for free <a href="%s" target="_blank">here</a>. '
574
- . 'Once you have created those two keys for this domain, '
575
  . 'simply paste them below.</em>', $this->domain),
576
  'https://www.google.com/recaptcha/admin/create'),
577
  'heading_func' => '<em>' . __('Control how this plugin works.', $this->domain) . '</em>',
578
- 'h2' => '<em>' . __('Settings that are applied to '
579
  . 'comment forms only.', $this->domain) . '</em>',
580
- 'h3' => '<em>' . __('Integrate with Akismet for better end-user experience.', $this->domain) . '</em>',
 
 
581
  'heading_cf7' => '<em>' . __('Add reCAPTCHA to Contact Form 7. '
582
  . 'This only works if you have Contact Form 7 activated.', $this->domain) . '</em>'
583
  ),
@@ -592,7 +650,6 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
592
  array('checkbox', 'name' => 'cb5')
593
  ),
594
  'select' => array(
595
- 'select_lang' => $this->lang,
596
  'select_cap' => $this->caps,
597
  'select_position' => array(
598
  __('After comment field', $this->domain) => 'after_comment_field',
@@ -605,10 +662,6 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
605
  'select_akismet_react' => array(
606
  __('Approve comment immediately', $this->domain) => '1',
607
  __('Hold comment in moderation queue', $this->domain) => 'hold'
608
- ),
609
- 'select_cf7_tag' => array(
610
- __('Use "bwp-recaptcha" shortcode tag', $this->domain) => 'bwp-recaptcha',
611
- __('Use "recaptcha" shortcode tag', $this->domain) => 'recaptcha'
612
  )
613
  ),
614
  'checkbox' => array(
@@ -635,8 +688,25 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
635
  . 'Highly recommended if you do not want to '
636
  . 'force your visitors to enter a captcha every time.', $this->domain) => 'enable_akismet'
637
  ),
638
- 'cb7' => array(
639
  __('uncheck to use different key pairs for this site.', $this->domain) => 'use_global_keys'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
640
  )
641
  ),
642
  'input' => array(
@@ -661,27 +731,39 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
661
  'input_approved' => array(
662
  'size' => 3,
663
  'label' => __('approved comment(s).', $this->domain)
664
- ),
665
  ),
666
  'container' => array(
667
- 'cb8' => ''
668
  ),
669
  'post' => array(
670
- 'select_akismet_react' => '<br /><span style="display:inline-block;margin-top:5px;">'
671
  . __('It is best to put comments identified as spam in moderation queue '
672
  . 'so you are able to review and instruct '
673
  . 'Akismet to correctly handle similar comments in the future.</em>', $this->domain)
674
- . '</span>'
675
  ),
676
  'inline_fields' => array(
677
  'cb4' => array('select_cap' => 'select'),
678
  'cb5' => array('input_approved' => 'input')
 
 
 
 
 
 
 
 
 
 
 
679
  )
680
  );
681
 
682
- // Get the default options
683
- $options = $bwp_option_page->get_options(array(
684
  'use_global_keys',
 
 
685
  'input_pubkey',
686
  'input_prikey',
687
  'input_error',
@@ -693,34 +775,24 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
693
  'enable_registration',
694
  'enable_login',
695
  'enable_comment',
 
696
  'input_back',
697
  'select_position',
698
- 'select_cf7_tag',
699
  'select_response',
700
  'enable_akismet',
701
- 'select_akismet_react'
702
- ), $this->options);
703
-
704
- // Get option from the database
705
- $options = $bwp_option_page->get_db_options($page, $options);
706
-
707
- $option_formats = array(
708
- 'input_approved' => 'int',
709
- 'input_error' => 'html',
710
- 'input_back' => 'html'
711
  );
712
 
713
- $option_super_admin = array();
714
-
715
  // show appropriate fields based on multi-site setting
716
  add_action('bwp_option_action_before_submit_button', array($this, 'modify_option_page'));
717
  }
718
  else if ($page == BWP_CAPT_OPTION_THEME)
719
  {
720
- $bwp_option_page->set_current_tab(2);
721
 
722
- // Option Structures - Form
723
- $form = array(
724
  'items' => array(
725
  'select',
726
  'checkbox',
@@ -760,11 +832,8 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
760
  'cb1' => array(
761
  sprintf(__('This is for Custom Theme only. '
762
  . 'Disable this and add your own CSS to style the Custom Theme. '
763
- . 'More info <a href="%s#customization" target="_blank">here</a>.', $this->domain),
764
  BWP_CAPT_PLUGIN_URL) => 'enable_css'
765
- ),
766
- 'cb2' => array(
767
- __('This is only useful when you do not use any minify or cache plugin.', $this->domain) => 'enable_selective'
768
  )
769
  ),
770
  'input' => array(
@@ -782,78 +851,88 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
782
  . 'please read <a href="%s" target="_blank">this dedicated tip</a>.', $this->domain),
783
  'http://betterwp.net/wordpress-tips/how-to-add-custom-translations-to-bwp-recaptcha/')
784
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
785
  );
786
 
787
- // Get the default options
788
- $options = $bwp_option_page->get_options(array(
789
- 'select_lang',
790
- 'select_theme',
791
- 'input_tab',
792
- 'enable_css',
793
- ), $this->options);
794
-
795
- // Get option from the database
796
- $options = $bwp_option_page->get_db_options($page, $options);
797
-
798
- $option_formats = array(
 
 
799
  'input_tab' => 'int'
800
  );
801
 
802
- $option_super_admin = array();
803
-
804
  // preview reCAPTCHA
805
  add_action('bwp_option_action_before_submit_button', array($this, 'add_recaptcha'));
806
  }
807
  }
808
 
809
- // Get option from user input
810
- if (isset($_POST['submit_' . $bwp_option_page->get_form_name()])
811
- && isset($options) && is_array($options))
812
- {
813
- // basic security check
814
- check_admin_referer($page);
815
-
816
- foreach ($options as $key => &$option)
817
- {
818
- if (isset($_POST[$key]))
819
- {
820
- $bwp_option_page->format_field($key, $option_formats);
821
- $option = trim(stripslashes($_POST[$key]));
822
- }
823
- else
824
- {
825
- if (!isset($_POST[$key]))
826
- {
827
- // for checkboxes that are not checked
828
- $option = '';
829
- }
830
- else if (isset($option_formats[$key])
831
- && 'int' == $option_formats[$key]
832
- && ('' === $_POST[$key] || 0 > $_POST[$key])
833
- ) {
834
- // expect integer but received empty string or negative integer
835
- $option = $this->options_default[$key];
836
- }
837
- }
838
- }
839
-
840
- // update per-blog options
841
- update_option($page, $options);
842
-
843
- global $blog_id;
844
- if (!$this->is_normal_admin() && $blog_id == 1)
845
- {
846
- // Update site options if is super admin and is on main site
847
- update_site_option($page, $options);
848
- }
849
-
850
- // refresh the options property to include updated options
851
- $this->options = array_merge($this->options, $options);
852
-
853
- // Update options successfully
854
- $this->add_notice(__('All options have been saved.', $this->domain));
855
- }
856
 
 
 
857
  if (empty($this->options['input_pubkey'])
858
  || empty($this->options['input_prikey'])
859
  ) {
@@ -877,11 +956,7 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
877
  );
878
  }
879
 
880
- // Assign the form and option array
881
- $bwp_option_page->init($form, $options, $this->form_tabs);
882
-
883
- // Build the option page
884
- $bwp_option_page->generate_html_form();
885
  }
886
 
887
  /**
@@ -892,7 +967,7 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
892
  global $wp_rewrite;
893
 
894
  if (!is_singular() || !get_option('page_comments'))
895
- return;
896
 
897
  $page = get_query_var('cpage');
898
  if (empty($page))
@@ -931,6 +1006,12 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
931
  return true;
932
  }
933
 
 
 
 
 
 
 
934
  if ('yes' == $this->options['hide_approved'])
935
  {
936
  $commenter = wp_get_current_commenter();
@@ -961,385 +1042,203 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
961
 
962
  // has more approved comments than required?
963
  if ($approved_count >= $this->options['input_approved'])
 
 
964
  return true;
 
965
  }
966
 
967
  return false;
968
  }
969
 
970
  /**
971
- * Make text safe to edit inside textarea
972
  *
973
- * This function will be removed once requirement is moved to WP 3.1.
 
 
 
 
 
 
974
  *
975
- * @since 1.1.1
976
- * @return string
977
  */
978
- private function _esc_textarea($text)
979
  {
980
- return htmlspecialchars($text, ENT_QUOTES, get_option('blog_charset'));
 
981
  }
982
 
983
- public function fill_comment_content($comment_field)
 
 
 
 
 
984
  {
985
- if ('back' == $this->options['select_response'])
986
- {
987
- // no need to refill the comment contents if no redirection is involved
988
- return $comment_field;
989
- }
990
-
991
- if (!empty($_SESSION['bwp_capt_comment']))
992
  {
993
- // put the comment content back if possible
994
- $comment_text = stripslashes($_SESSION['bwp_capt_comment']);
995
- $comment_field = preg_replace('#(<textarea\s[^>]*>)(.*?)(</textarea>)#uis',
996
- '$1' . $this->_esc_textarea($comment_text) . '$3',
997
- $comment_field
998
- );
999
-
1000
- $this->_unset_session_data('bwp_capt_comment');
1001
- }
1002
-
1003
- return $comment_field;
1004
- }
1005
-
1006
- /**
1007
- * Output the reCAPTCHA HTML, use theme if specified
1008
- *
1009
- * @param $errors @since 1.1.0
1010
- * @return void
1011
- */
1012
- public function add_recaptcha($errors = false)
1013
- {
1014
- $this->load_captcha_library();
1015
-
1016
- if (!defined('BWP_CAPT_ADDED'))
1017
- {
1018
- // make sure we add only one recaptcha instance
1019
- define('BWP_CAPT_ADDED', true);
1020
-
1021
- // captcha error can comes from $_GET variable or passed via
1022
- // hooks' parameters.
1023
- $captcha_error = '';
1024
- $extra_class = '';
1025
-
1026
- if (!empty($_GET['cerror']) && 'incorrect-captcha-sol' == $_GET['cerror'])
1027
- {
1028
- $captcha_error = $_GET['cerror'];
1029
- }
1030
- else if (is_wp_error($errors))
1031
- {
1032
- // right now only registration errors are passed this way
1033
- $captcha_error = $errors->get_error_message('reg-recaptcha-error');
1034
- $extra_class = ' error';
1035
- }
1036
-
1037
- if ($this->_is_comment_spam())
1038
- {
1039
  ?>
1040
  <p class="bwp-capt-spam-identified">
1041
  <?php _e('Your comment was identified as spam, '
1042
  . 'please complete the CAPTCHA below:', $this->domain); ?>
1043
  </p>
1044
  <?php
1045
- }
1046
-
1047
- do_action('bwp_capt_before_add_captcha');
1048
 
1049
- ?>
1050
- <style type="text/css">
1051
- /* this is to prevent the iframe from showing up in Chrome */
1052
- iframe[src="about:blank"] {
1053
- display: none;
1054
- }
1055
- </style>
1056
- <?php
1057
- if ($this->options['select_theme'] != 'custom')
1058
- {
1059
 
1060
- if (!empty($captcha_error))
1061
- {
1062
- ?>
1063
- <p class="recaptcha_only_if_incorrect_sol<?php echo $extra_class; ?>">
1064
- <?php echo $this->options['input_error']; ?>
1065
- </p>
1066
- <?php
1067
- }
1068
- ?>
1069
- <script type="text/javascript">
1070
- var RecaptchaOptions = (typeof CustomRecaptchaOptions === 'undefined') ? {
1071
- theme: '<?php echo $this->options['select_theme']; ?>',
1072
- lang: '<?php echo $this->options['select_lang']; ?>',
1073
- <?php
1074
- if (!empty($this->options['input_tab'])) {
1075
- ?>
1076
- tabindex: <?php echo (int) $this->options['input_tab']; echo "\n"; ?>
1077
- <?php
1078
- }
1079
- ?>
1080
- } : CustomRecaptchaOptions;
1081
- </script>
1082
- <?php
1083
- }
1084
- else
1085
- {
1086
- bwp_capt_custom_theme_widget();
1087
- }
1088
-
1089
- if ('redirect' == $this->options['select_response'] && !is_admin())
1090
- {
1091
  ?>
1092
- <input type="hidden" name="error_redirect_to"
1093
- value="<?php esc_attr_e($this->get_current_comment_page_link()); ?>" />
1094
  <?php
1095
- }
1096
-
1097
- $use_ssl = is_ssl() ? true : false;
1098
-
1099
- if (!empty($this->options['input_pubkey']))
1100
- {
1101
- echo recaptcha_get_html(
1102
- $this->options['input_pubkey'],
1103
- $captcha_error,
1104
- $use_ssl,
1105
- $this->options['select_lang']
1106
- );
1107
- }
1108
- else if (current_user_can('manage_options'))
1109
- {
1110
- // if user is an admin show the actual error
1111
- printf(__('To use reCAPTCHA you must get an API key from '
1112
- . '<a href="%1$s">%1$s</a>', $this->domain),
1113
- 'https://www.google.com/recaptcha/admin/create');
1114
- }
1115
- else
1116
- echo '';
1117
  }
1118
  }
1119
 
1120
  /**
1121
  * Adds captcha to below comment field
1122
  *
 
 
 
 
1123
  * @since 1.1.1
1124
  * @return string
1125
  */
1126
  public function add_recaptcha_after_comment_field($form_defaults)
1127
  {
1128
- ob_start();
1129
-
1130
- do_action('bwp_recaptcha_add_markups');
1131
- $recaptcha_html = ob_get_contents();
1132
-
1133
- ob_end_clean();
1134
 
1135
  $form_defaults['comment_notes_after'] = !isset($form_defaults['comment_notes_after'])
1136
- ? $recaptcha_html : $form_defaults['comment_notes_after'] . $recaptcha_html;
1137
 
1138
  return $form_defaults;
1139
  }
1140
 
1141
  /**
1142
- * Adds a captcha to blog registration page
1143
  *
1144
- * @since 1.1.0
1145
- * @return void
 
 
1146
  */
1147
- public function add_blog_reg_recaptcha($errors)
1148
  {
1149
- // if user is not logged in, they can choose between signup for account
1150
- // or sign up for blog after account creation.
1151
- if (!is_user_logged_in())
1152
- {
1153
- // if user chooses to signup for blog also, we don't show recaptcha
1154
- // again because they have already provided the captcha once.
1155
- }
1156
- elseif (!$this->user_can_bypass())
1157
- {
1158
- // user is logged in and wants to add a new blog, show captcha if
1159
- // user can not bypass
1160
- $this->add_recaptcha($errors);
1161
- }
1162
  }
1163
 
1164
  /**
1165
- * Authenticates the user using captcha when logging in
1166
  *
1167
- * @filter authenticate, @see ::wp-signon in package WordPress/pluggable.php
1168
- * @since 1.1.0
1169
- * @return WP_User
 
1170
  */
1171
- public function authenticate_with_recaptcha($user)
1172
  {
1173
- if (empty($_POST['log']) && empty($_POST['pwd']))
1174
- {
1175
- return $user;
1176
- }
1177
-
1178
- // if the $user object itself is a WP_Error object, we simply append
1179
- // errors to it, otherwise we create a new one.
1180
- $errors = is_wp_error($user) ? $user : new WP_Error();
1181
 
1182
- if (!isset($_POST['recaptcha_challenge_field'])
1183
- || !isset($_POST["recaptcha_response_field"])
1184
  ) {
1185
- // captcha response is empty, show error message
1186
- $errors->add('login-recaptcha-error', $this->options['input_error']);
1187
- }
1188
- else
1189
- {
1190
- $this->load_captcha_library();
1191
-
1192
- if (function_exists('recaptcha_check_answer'))
1193
- {
1194
- // check catpcha response error using recaptcha's PHP library
1195
- $response = recaptcha_check_answer(
1196
- $this->options['input_prikey'],
1197
- $_SERVER['REMOTE_ADDR'],
1198
- $_POST['recaptcha_challenge_field'],
1199
- $_POST['recaptcha_response_field']
1200
- );
1201
-
1202
- if (!$response->is_valid)
1203
- {
1204
- // incorrect captcha response show error message
1205
- if ($response->error == 'incorrect-captcha-sol')
1206
- {
1207
- $errors->add('login-recaptcha-error', $this->options['input_error']);
1208
- }
1209
- else
1210
- {
1211
- $errors->add('login-recaptcha-error', '<strong>'
1212
- . __('ERROR', $this->domain) . '</strong>: '
1213
- . __('Unknown captcha error.', $this->domain));
1214
- }
1215
- }
1216
- }
1217
- }
1218
-
1219
- $errorCodes = $errors->get_error_codes();
1220
- if (in_array('login-recaptcha-error', $errorCodes))
1221
- {
1222
- // invalid recaptcha detected, exit the login process and
1223
- $user = is_wp_error($user) ? $user : $errors;
1224
-
1225
- // do not allow WordPress to try authenticating the user, either
1226
- // using cookie or username/password pair
1227
- remove_filter('authenticate', 'wp_authenticate_username_password', 20, 3);
1228
- remove_filter('authenticate', 'wp_authenticate_cookie', 30, 3);
1229
  }
1230
 
1231
- return $user;
1232
  }
1233
 
1234
  /**
1235
- * Check captcha response on registration page
 
1236
  *
1237
- * This function should be used on both user registration page (single or
1238
- * multisite) and blog registration page (multisite).
1239
  *
1240
- * @since 1.1.0
1241
- * @return WP_Error
1242
  */
1243
- public function check_reg_recaptcha($errors)
1244
  {
1245
- $this->load_captcha_library();
1246
-
1247
- if (is_array($errors) && isset($errors['errors']))
1248
- {
1249
- // if $errors is an array, we're probably checking recaptcha for Multi-Site WP
1250
- $temp = $errors;
1251
- $errors = $errors['errors'];
1252
- }
1253
-
1254
- if (!isset($_POST['recaptcha_challenge_field'])
1255
- || !isset($_POST["recaptcha_response_field"])
1256
- ) {
1257
- $errors->add('reg-recaptcha-error', $this->options['input_error']);
1258
- $stop = true;
1259
- }
1260
 
1261
- if (empty($stop) && function_exists('recaptcha_check_answer'))
1262
- {
1263
- $response = recaptcha_check_answer(
1264
- $this->options['input_prikey'],
1265
- $_SERVER['REMOTE_ADDR'],
1266
- $_POST['recaptcha_challenge_field'],
1267
- $_POST['recaptcha_response_field']
1268
- );
1269
 
1270
- if (!$response->is_valid)
1271
- {
1272
- if ($response->error == 'incorrect-captcha-sol')
1273
- {
1274
- $errors->add('reg-recaptcha-error', $this->options['input_error']);
1275
- }
1276
- else
1277
- {
1278
- $errors->add('reg-recaptcha-error', '<strong>'
1279
- . __('ERROR', $this->domain) . '</strong>: '
1280
- . __('Unknown captcha error.', $this->domain));
1281
- }
1282
- }
1283
- }
1284
 
1285
- if (isset($temp))
1286
- {
1287
- $temp['errors'] = $errors;
1288
- $errors = $temp;
1289
- }
1290
 
1291
- return $errors;
 
1292
  }
1293
 
1294
- public function check_user_reg_recaptcha($errors)
 
 
 
 
 
 
 
 
1295
  {
1296
- if (isset($_POST['stage']) && 'validate-blog-signup' == $_POST['stage'])
1297
- {
1298
- // user is registering a new blog, we don't need to check anything
1299
- // because captcha is not required at this stage
1300
- return $errors;
1301
- }
1302
- else
1303
- {
1304
- return $this->check_reg_recaptcha($errors);
1305
- }
1306
  }
1307
 
1308
- public function check_blog_reg_recaptcha($errors)
1309
  {
1310
- if (!is_user_logged_in())
1311
- {
1312
- return $errors;
1313
- }
1314
- elseif (!$this->user_can_bypass())
1315
  {
1316
- // check captcha response if needed
1317
- return $this->check_reg_recaptcha($errors);
 
 
 
 
 
 
1318
  }
1319
 
1320
- return $errors;
1321
  }
1322
 
1323
  /**
1324
  * Check captcha response for comment forms
1325
  *
1326
- * @return void
1327
  */
1328
- public function check_recaptcha($comment_post_ID)
1329
  {
1330
- $this->load_captcha_library();
1331
-
1332
- $response = recaptcha_check_answer(
1333
- $this->options['input_prikey'],
1334
- $_SERVER['REMOTE_ADDR'],
1335
- $_POST['recaptcha_challenge_field'],
1336
- $_POST['recaptcha_response_field']
1337
- );
1338
-
1339
- if (!$response->is_valid)
1340
  {
1341
- if (isset($_POST['comment']))
1342
- $this->_set_session_data('bwp_capt_comment', $_POST['comment']);
 
 
 
 
 
 
 
 
1343
 
1344
  if ('redirect' == $this->options['select_response'])
1345
  {
@@ -1348,93 +1247,187 @@ class BWP_RECAPTCHA extends BWP_FRAMEWORK_IMPROVED
1348
  $location = !empty($_POST['error_redirect_to'])
1349
  ? $_POST['error_redirect_to']
1350
  : get_permalink($comment_post_ID) . '#respond';
1351
- $location = add_query_arg('cerror', $response->error, $location);
 
1352
 
1353
  wp_safe_redirect($location);
 
1354
  exit;
1355
  }
1356
  else if ('back' == $this->options['select_response'])
1357
  {
1358
- if ('incorrect-captcha-sol' == $response->error)
1359
  {
1360
  wp_die(sprintf($this->options['input_back'],
1361
  ' <a href="javascript:history.go(-1);">'
1362
  . __('this link', $this->domain)
1363
  . '</a>'));
1364
  }
1365
- else if (current_user_can('manage_options'))
1366
- {
1367
- // show actual error only to admin
1368
- wp_die(__('There is some problem with your reCAPTCHA API keys, '
1369
- . 'please double check them.', $this->domain));
1370
- }
1371
  else
1372
  {
1373
- wp_die(__('Unknown error. Please contact an administrator '
1374
- . 'for more info.', $this->domain));
1375
  }
1376
  }
 
 
1377
  }
1378
- else
 
1379
  {
1380
- if ($this->_is_comment_spam())
 
1381
  {
1382
- // spam comments are handled by recaptcha so we do not increase
1383
- // Akismet spam counter
1384
  add_filter('akismet_spam_count_incr', create_function('', 'return 0;'), 11);
1385
 
 
1386
  // workaround for remove_filter function
1387
  add_filter('pre_comment_approved', array($this, 'akismet_comment_status'), 10);
1388
  add_filter('pre_comment_approved', array($this, 'akismet_comment_status'), 11);
1389
  }
1390
 
1391
- // reset Akistmet-related data, next comment should be checked
1392
- // again from the beginning
1393
- $this->_unset_session_data('bwp_capt_comment');
1394
- $this->_unset_session_data('bwp_capt_comment_is_spam');
1395
  }
1396
  }
1397
 
1398
- public function akismet_comment_status()
1399
  {
1400
- $bwp_capt_cs = $this->options['select_akismet_react'];
1401
- $bwp_capt_cs = 'hold' == $bwp_capt_cs ? '0' : $bwp_capt_cs;
1402
 
1403
- if (defined('BWP_CAPT_AKISMET_COMMENT_STATUS')
1404
- && BWP_CAPT_AKISMET_COMMENT_STATUS == 'spam'
1405
- ) {
1406
- // @since 1.1.1 put comment into spam queue is no longer an option
1407
- // but can still be forced
1408
- return 'spam';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1409
  }
1410
 
1411
- return $bwp_capt_cs;
1412
  }
1413
 
1414
  /**
1415
- * Adds recaptcha to comment form if akismet marks a comment as spam
1416
  *
1417
- * @return void
 
 
 
 
 
 
 
 
 
 
1418
  */
1419
- public function add_recaptcha_after_akismet()
1420
  {
1421
- $comment_post_ID = isset($_POST['comment_post_ID'])
1422
- ? (int) $_POST['comment_post_ID']
1423
- : 0;
1424
 
1425
- $this->_set_session_data('bwp_capt_comment_is_spam', 'yes');
 
 
 
 
 
 
 
 
 
 
 
 
1426
 
1427
- if (isset($_POST['comment']))
1428
- $this->_set_session_data('bwp_capt_comment', $_POST['comment']);
 
 
 
 
 
 
 
 
 
 
 
1429
 
1430
- $location_hash = $this->options['select_position'] == 'after_comment_field'
1431
- ? 'comment' : 'respond';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1432
 
1433
- $location = !empty($_POST['error_redirect_to'])
1434
- ? $_POST['error_redirect_to']
1435
- : get_permalink($comment_post_ID) . '#' . $location_hash;
 
 
 
 
 
 
 
 
 
 
 
 
1436
 
1437
- wp_safe_redirect($location);
1438
- exit;
1439
  }
1440
  }
1
  <?php
2
  /**
3
+ * Copyright (c) 2015 Khang Minh <betterwp.net>
4
  *
5
  * This program is free software: you can redistribute it and/or modify
6
  * it under the terms of the GNU General Public License as published by
25
  {
26
  global $bwp_capt;
27
 
28
+ remove_action('comment_form_after_fields', array($bwp_capt, 'add_comment_recaptcha'));
29
+ remove_action('comment_form_logged_in_after', array($bwp_capt, 'add_comment_recaptcha'));
30
+ remove_filter('comment_form_defaults', array($bwp_capt, 'add_recaptcha_after_comment_field'), 11);
31
+ remove_filter('comment_form_submit_field', array($bwp_capt, 'add_recaptcha_before_comment_submit_field'));
32
 
33
  ob_start();
34
 
38
  ob_end_clean();
39
 
40
  if (isset($args['comment_notes_after']))
41
+ $args['comment_notes_after'] .= "\n" . $recaptcha_html;
42
  else
43
  $args['comment_notes_after'] = $recaptcha_html;
44
 
45
  comment_form($args, $post_id);
46
  }
47
 
48
+ class BWP_RECAPTCHA extends BWP_FRAMEWORK_V2
 
 
 
49
  {
50
  /**
51
  * reCAPTCHA built-in languages
52
  */
53
+ public $lang;
54
+
55
+ /**
56
+ * @since 2.0.0 languages for recaptcha v2
57
+ */
58
+ public $v2_lang;
59
 
60
  /**
61
  * User capabilities to bypass captcha
62
  */
63
+ public $caps;
64
 
65
  /**
66
  * Is registering via wp-login.php
67
  */
68
+ public $is_reg = false;
69
 
70
  /**
71
  * Captcha error message when registering via wp-login.php
72
  */
73
+ public $reg_errors = false;
74
 
75
  /**
76
  * Is signing up (multi-site only)
77
  */
78
+ public $is_signup = false;
79
 
80
  /**
81
  * Is logging in via wp-login.php
82
  */
83
+ public $is_login = false;
84
+
85
+ /**
86
+ * User has enough approved comments, no captcha needed
87
+ */
88
+ public $user_is_approved = false;
89
+
90
+ /**
91
+ * The recaptcha provider, which takes care of rendering and verifying
92
+ *
93
+ * @var BWP_Recaptcha_Provider
94
+ */
95
+ protected $provider;
96
 
97
  /**
98
+ * {@inheritDoc}
99
  */
100
+ public function __construct(array $meta)
101
  {
102
+ parent::__construct($meta);
103
+
 
 
 
 
104
  // Basic version checking
105
  if (!$this->check_required_versions())
106
  return;
107
 
108
  // Default options
109
  $options = array(
110
+ 'input_pubkey' => '',
111
+ 'input_prikey' => '',
112
+ 'input_error' => __('<strong>ERROR:</strong> Incorrect or '
113
  . 'empty reCAPTCHA response, please try again.', $this->domain),
114
+ 'input_back' => __('Error: Incorrect or empty reCAPTCHA response, '
115
  . 'please click the back button on your browser\'s toolbar or '
116
  . 'click on %s to go back.', $this->domain),
117
+ 'input_approved' => 1,
118
+ 'input_tab' => 0,
119
+ 'enable_comment' => 'yes',
120
+ 'enable_registration' => '',
121
+ 'enable_login' => '',
122
+ 'enable_akismet' => '',
123
+ 'enable_cf7' => 'yes', // @since 2.0.0
124
+ 'enable_auto_fill_comment' => '',
125
+ 'enable_css' => 'yes',
126
+ 'enable_v1_https' => '', // @since 2.0.0, force recaptcha v1 to use https
127
+ 'use_recaptcha_v1' => '', // @since 2.0.0 whether to use recaptcha v1
128
+ 'use_global_keys' => 'yes',
129
+ 'select_lang' => 'en',
130
+ 'select_theme' => 'red',
131
+ 'select_cap' => 'manage_options',
132
+ 'select_response' => 'redirect',
133
+ 'select_position' => 'after_comment_field',
134
+ 'select_v2_lang' => '', // @since 2.0.0, default to empty (auto detected)
135
+ 'select_v2_theme' => 'light', // @since 2.0.0 'light' or 'dark'
136
+ 'select_v2_size' => 'normal', // @since 2.0.0
137
+ 'select_v2_jsapi_position' => 'on_demand', // @since 2.0.0 load on all pages or only when needed
138
+ 'select_akismet_react' => 'hold',
139
+ 'hide_registered' => '',
140
+ 'hide_cap' => '',
141
+ 'hide_approved' => ''
142
  );
143
 
144
  $this->add_option_key('BWP_CAPT_OPTION_GENERAL', 'bwp_capt_general',
153
  'http://betterwp.net/wordpress-plugins/bwp-recaptcha/', false);
154
  }
155
 
156
+ /**
157
+ * Init a PHP session
158
+ *
159
+ * @since 2.0.0
160
+ */
161
+ private function _init_session()
162
  {
163
+ if (('redirect' == $this->options['select_response']
164
+ && 'yes' == $this->options['enable_auto_fill_comment']
165
+ || $this->_is_akismet_integration_enabled())
166
+ ) {
167
+ // should init session
168
+ }
169
+ else
 
 
 
 
170
  {
171
+ // session not needed
172
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  }
174
 
175
+ // do not init session in admin or when session is already active
176
+ if (!is_admin() && !isset($_SESSION))
177
+ {
178
+ // do not init a session if headers are already sent, but we will
179
+ // still start the session in debug mode
180
+ if (headers_sent() && (!defined('WP_DEBUG') || !WP_DEBUG))
181
+ return;
182
+
183
+ session_start();
184
+ }
185
  }
186
 
187
  private function _set_session_data($key, $value)
188
  {
189
+ // init session on demand
190
+ $this->_init_session();
191
+
192
  if (!isset($_SESSION))
 
193
  return;
 
194
 
195
  $_SESSION[$key] = trim($value);
196
  }
197
 
198
+ private function _get_session_data($key)
199
+ {
200
+ // init session on demand
201
+ $this->_init_session();
202
+
203
+ if (isset($_SESSION[$key]))
204
+ return $_SESSION[$key];
205
+ }
206
+
207
  private function _unset_session_data($key)
208
  {
209
  if (isset($_SESSION[$key]))
 
210
  unset($_SESSION[$key]);
 
211
  }
212
 
213
  /**
214
+ * Whether akismet integration is enabled
215
  *
216
  * @since 1.1.1
217
  * @return bool
218
  */
219
+ private function _is_akismet_integration_enabled()
220
  {
221
+ if (defined('AKISMET_VERSION') && 'yes' == $this->options['enable_akismet'])
 
 
 
222
  return true;
223
 
224
  return false;
225
  }
226
 
227
+ /**
228
+ * Whether the system has marked a previous comment as spam
229
+ *
230
+ * @return bool
231
+ */
232
+ private function _is_previous_comment_spam()
233
  {
234
+ $is_spam = $this->_get_session_data('bwp_capt_previous_comment_is_spam');
235
+
236
+ if ($is_spam && 'yes' == $is_spam)
237
  return true;
 
238
 
239
  return false;
240
  }
241
 
242
  protected function pre_init_properties()
243
  {
244
+ $this->lang = include_once __DIR__ . '/provider/v1-languages.php';
245
+ $this->v2_lang = include_once __DIR__ . '/provider/v2-languages.php';
 
 
 
 
 
 
 
 
 
246
 
247
  $this->caps = apply_filters('bwp_capt_bypass_caps', array(
248
  __('Read Profile', $this->domain) => 'read',
251
 
252
  // @since 1.1.0 init public and private keys based on multi-site setting
253
  $this->init_captcha_keys();
254
+ }
255
 
256
+ protected function load_libraries()
257
+ {
258
+ $this->provider = BWP_Recaptcha_Provider::create($this);
259
+ }
260
+
261
+ protected function init_hooks()
262
+ {
263
+ // determine the current page to behave correctly
264
+ $this->determine_current_page();
265
+
266
+ // init addons
267
+ $this->init_addons();
268
+
269
+ // user can bypass captcha, nothing else to do
270
+ if ($this->user_can_bypass()) {
271
+ return;
272
  }
273
 
274
+ if (!empty($this->options['input_pubkey']) && !empty($this->options['input_prikey']))
275
  {
276
+ // this action needs to be added when a captcha is manually needed
277
+ add_action('bwp_recaptcha_add_markups', array($this, 'add_recaptcha'));
278
+
279
+ if ('yes' == $this->options['enable_comment'])
280
+ $this->init_comment_form_captcha();
281
+
282
+ if ('yes' == $this->options['enable_login'] && $this->is_login)
283
+ $this->init_login_form_captcha();
284
+
285
+ if ('yes' == $this->options['enable_registration'] && $this->is_reg)
286
+ $this->init_registration_form_captcha();
287
+
288
+ if ('yes' == $this->options['enable_registration'] && $this->is_signup)
289
+ $this->init_multisite_registration_form_captcha();
290
  }
291
+ }
292
 
293
+ /**
294
+ * Copied from wp-includes/general-template.php:wp_registration_url
295
+ * because we still have to support 3.0
296
+ */
297
+ private function _wp_registration_url()
298
+ {
299
+ return apply_filters('register_url', site_url('wp-login.php?action=register', 'login'));
300
+ }
301
+
302
+ protected function determine_current_page()
303
+ {
304
+ $login_path = str_replace(home_url(), '', wp_login_url());
305
+ $register_path = str_replace(home_url(), '', $this->_wp_registration_url());
306
+
307
+ if (strpos($_SERVER['REQUEST_URI'], $register_path) === 0)
308
+ {
309
+ // whether user is requesting regular user registration page
310
+ $this->is_reg = true;
311
+ }
312
+ elseif (strpos($_SERVER['REQUEST_URI'], $login_path) === 0)
313
+ {
314
  // whether user is requesting the wp-login page
315
  $this->is_login = true;
316
  }
317
+ elseif (strpos($_SERVER['REQUEST_URI'], 'wp-signup.php') !== false)
318
+ {
319
+ // whether user is requesting wp-signup page (multi-site page for
320
+ // user/site registration)
321
+ $this->is_signup = true;
322
+ }
323
  }
324
 
325
+ /**
326
+ * Init cf7 addon if applicable
327
+ */
328
+ protected function init_cf7_addon()
329
  {
330
+ if (defined('WPCF7_VERSION') && 'yes' == $this->options['enable_cf7'])
331
  {
332
+ // add support for Contact Form 7 (CF7) automatically if CF7 is
333
+ // installed and activated
334
+ // @since 2.0.0 this should use appropriate class for current
335
+ // version of recaptcha
336
+ if ('yes' == $this->options['use_recaptcha_v1'])
337
+ BWP_Recaptcha_CF7_V1::init($this);
338
+ else
339
+ BWP_Recaptcha_CF7_V2::init($this);
340
  }
341
  }
342
 
343
+ protected function init_addons()
344
  {
345
+ $this->init_cf7_addon();
346
+ }
347
 
348
+ protected function init_comment_form_captcha()
349
+ {
350
+ // if user chooses to integrate with akismet, and previous comment is
351
+ // not marked as spam
352
+ if ($this->_is_akismet_integration_enabled() && !$this->_is_previous_comment_spam())
353
  {
354
+ // only add a recaptcha once akismet has identified a comment as spam
355
+ add_action('akismet_spam_caught', array($this, 'add_recaptcha_after_akismet'));
 
 
356
  }
357
+ else
 
358
  {
359
+ if ($this->options['select_position'] == 'after_fields')
 
 
 
360
  {
361
+ // show captcha after website field
362
+ add_action('comment_form_after_fields', array($this, 'add_comment_recaptcha'));
363
+ add_action('comment_form_logged_in_after', array($this, 'add_comment_recaptcha'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  }
365
+ elseif ($this->options['select_position'] == 'after_comment_field')
 
366
  {
367
+ /**
368
+ * show captcha after comment field (default @since 1.1.1)
369
+ *
370
+ * @since 2.0.0 and @since WordPress 4.2.0
371
+ * there's a new filter to add recaptcha that doesn't
372
+ * rely on the fragile `comment_notes_after`, we will
373
+ * use that if possible
374
+ */
375
+ if (version_compare($this->get_current_wp_version(), '4.2', '>='))
376
+ add_filter('comment_form_submit_field', array($this, 'add_recaptcha_before_comment_submit_field'));
377
+ else
378
+ // otherwise use the `comment_notes_after` arg
379
+ add_filter('comment_form_defaults', array($this, 'add_recaptcha_after_comment_field'), 11);
380
  }
381
 
382
+ // fill the comment textarea with previously submitted comment
383
+ if ('redirect' == $this->options['select_response']
384
+ && 'yes' == $this->options['enable_auto_fill_comment']
385
+ ) {
386
+ add_filter('comment_form_field_comment', array($this, 'fill_comment_field_with_previous_comment'));
 
 
387
  }
388
 
389
+ // check entered captcha for comment form
390
+ add_action('pre_comment_on_post', array($this, 'check_comment_recaptcha'));
 
 
 
 
 
 
 
391
  }
392
  }
393
 
394
+ protected function init_login_form_captcha()
395
+ {
396
+ // @since 1.1.0 add captcha to login form
397
+ add_action('login_form', array($this, 'add_recaptcha'));
398
+
399
+ // the priority of 15 is to ensure that we run the filter before
400
+ // WordPress authenticates the user.
401
+ add_filter('authenticate', array($this, 'check_login_recaptcha'), 15);
402
+ }
403
+
404
+ protected function init_registration_form_captcha()
405
+ {
406
+ // normal user registration page
407
+ add_action('register_form', array($this, 'add_recaptcha'));
408
+ add_filter('registration_errors', array($this, 'check_reg_recaptcha'));
409
+ }
410
+
411
+ protected function init_multisite_registration_form_captcha()
412
+ {
413
+ add_action('signup_extra_fields', array($this, 'add_multisite_user_reg_recaptcha'));
414
+ add_action('signup_blogform', array($this, 'add_multisite_blog_reg_recaptcha'));
415
+ add_filter('wpmu_validate_user_signup', array($this, 'check_multisite_user_reg_recaptcha'));
416
+ add_filter('wpmu_validate_blog_signup', array($this, 'check_multisite_blog_reg_recaptcha'));
417
+ }
418
+
419
  protected function init_captcha_keys()
420
  {
421
+ global $blog_id;
422
+
423
  if (self::is_multisite())
424
  {
425
+ // use api keys from main blog unless we're already on the main blog
426
+ if ($blog_id > 1 && 'yes' == $this->options['use_global_keys'])
427
  {
428
+ switch_to_blog(1);
429
+
430
+ $options = get_option(BWP_CAPT_OPTION_GENERAL);
431
+ $this->options['input_pubkey'] = $options['input_pubkey'];
432
+ $this->options['input_prikey'] = $options['input_prikey'];
433
+
434
+ restore_current_blog();
435
  }
436
  }
437
  }
456
  // load default CSS for custom theme
457
  wp_enqueue_style('bwp-capt', $bwp_capt_css);
458
  }
459
+ }
460
 
461
+ // additional css to make the captcha fit into the login/register form
462
+ if (('yes' == $this->options['enable_registration'] && $this->is_reg)
463
+ || ('yes' == $this->options['enable_login'] && $this->is_login)
464
+ ) {
465
+ add_action('login_head', array($this, 'print_inline_styles_for_login'), 11); // make sure this is late enough
466
  }
467
  }
468
 
469
+ /**
470
+ * @return BWP_Recaptcha_Provider
471
+ */
472
+ public function get_captcha_provider()
473
  {
474
+ return $this->provider;
 
 
 
 
475
  }
476
 
477
  public function print_inline_styles_for_login()
482
  #login {
483
  width: <?php echo $login_width; ?>px;
484
  }
485
+ #recaptcha_widget_div, .g-recaptcha {
486
  margin-bottom: 15px;
487
  zoom: 1;
488
  }
500
  'BWP reCAPT',
501
  BWP_CAPT_CAPABILITY,
502
  BWP_CAPT_OPTION_GENERAL,
503
+ array($this, 'show_option_page'),
504
  BWP_CAPT_IMAGES . '/icon_menu.png'
505
  );
506
 
510
  __('General Options', $this->domain),
511
  BWP_CAPT_CAPABILITY,
512
  BWP_CAPT_OPTION_GENERAL,
513
+ array($this, 'show_option_page')
514
  );
515
 
516
  add_submenu_page(
519
  __('Theme Options', $this->domain),
520
  BWP_CAPT_CAPABILITY,
521
  BWP_CAPT_OPTION_THEME,
522
+ array($this, 'show_option_page')
523
  );
524
  }
525
 
526
  public function modify_option_page()
527
  {
528
  global $blog_id;
529
+
530
+ if (self::is_multisite() && 1 < $blog_id) :
531
  ?>
532
  <script type="text/javascript">
 
533
  var rc_readonly = <?php echo 'yes' == $this->options['use_global_keys'] ? 'true' : 'false'; ?>;
534
  jQuery('input[name="input_pubkey"], input[name="input_prikey"]').prop('readOnly', rc_readonly);
535
  jQuery('input[name="use_global_keys"]').on('click', function() {
539
  jQuery('input[name="input_pubkey"], input[name="input_prikey"]').prop('readOnly', false);
540
  }
541
  });
 
 
 
542
  </script>
543
  <?php
544
+ endif;
545
  }
546
 
547
+ protected function build_option_page()
 
 
 
 
 
548
  {
549
+ $page = $this->get_current_admin_page();
550
+ $option_page = $this->curren_option_page;
551
+ $form_options = array();
 
 
 
 
552
 
553
  if (!empty($page))
554
  {
555
  if ($page == BWP_CAPT_OPTION_GENERAL)
556
  {
557
+ $option_page->set_current_tab(1);
558
 
 
559
  $form = array(
560
  'items' => array(
561
  'heading',
563
  'input',
564
  'input',
565
  'heading',
566
+ 'checkbox',
567
+ 'checkbox',
568
  'section',
569
  'section',
570
  'heading',
571
  'select',
572
  'select',
573
+ 'checkbox',
574
  'input',
575
  'input',
576
  'heading',
577
  'checkbox',
578
  'select',
579
  'heading',
580
+ 'checkbox'
581
  ),
582
  'item_labels' => array(
583
  __('reCAPTCHA API Keys', $this->domain),
584
  __('Use main site\'s keys', $this->domain),
585
+ __('Site Key', $this->domain),
586
+ __('Secret Key', $this->domain),
587
  __('Plugin Functionality', $this->domain),
588
+ __('Use reCAPTCHA version 1', $this->domain),
589
+ __('Force https', $this->domain),
590
  __('Enable this plugin for', $this->domain),
591
  __('Hide captcha for', $this->domain),
592
  __('reCAPTCHA for comment form', $this->domain),
593
  __('Captcha position', $this->domain),
594
  __('If invalid captcha response', $this->domain),
595
+ __('Auto fill comment field', $this->domain),
596
  __('Invalid captcha error message', $this->domain),
597
  __('Invalid captcha error message', $this->domain),
598
  __('Akismet Integration for comment form', $this->domain),
599
  __('Integrate with Akismet?', $this->domain),
600
  __('If correct captcha response', $this->domain),
601
  __('Contact Form 7 Integration', $this->domain),
602
+ __('Integrate with Contact Form 7?', $this->domain)
603
  ),
604
  'item_names' => array(
605
  'h1',
606
+ 'use_global_keys',
607
  'input_pubkey',
608
  'input_prikey',
609
  'heading_func',
610
+ 'use_recaptcha_v1',
611
+ 'enable_v1_https',
612
  'sec1',
613
  'sec2',
614
+ 'heading_comment',
615
  'select_position',
616
  'select_response',
617
+ 'enable_auto_fill_comment',
618
  'input_error',
619
  'input_back',
620
  'h3',
621
  'cb6',
622
  'select_akismet_react',
623
  'heading_cf7',
624
+ 'enable_cf7'
625
  ),
626
  'heading' => array(
627
  'h1' => '<em>' . sprintf(
628
  __('For this plugin to work, you will need '
629
+ . 'a pair of API keys, which is available for free <a href="%s" target="_blank">here</a>. '
630
+ . 'Once you have created those two keys for the current domain, '
 
631
  . 'simply paste them below.</em>', $this->domain),
632
  'https://www.google.com/recaptcha/admin/create'),
633
  'heading_func' => '<em>' . __('Control how this plugin works.', $this->domain) . '</em>',
634
+ 'heading_comment' => '<em>' . __('Settings that are applied to '
635
  . 'comment forms only.', $this->domain) . '</em>',
636
+ 'h3' => '<em>' . __('Integrate the comment form with Akismet for better end-user experience.', $this->domain) . ' '
637
+ . sprintf(__('This feature requires an active <a target="_blank" href="%s">PHP session</a>.', $this->domain), 'http://php.net/manual/en/intro.session.php')
638
+ . '</em>',
639
  'heading_cf7' => '<em>' . __('Add reCAPTCHA to Contact Form 7. '
640
  . 'This only works if you have Contact Form 7 activated.', $this->domain) . '</em>'
641
  ),
650
  array('checkbox', 'name' => 'cb5')
651
  ),
652
  'select' => array(
 
653
  'select_cap' => $this->caps,
654
  'select_position' => array(
655
  __('After comment field', $this->domain) => 'after_comment_field',
662
  'select_akismet_react' => array(
663
  __('Approve comment immediately', $this->domain) => '1',
664
  __('Hold comment in moderation queue', $this->domain) => 'hold'
 
 
 
 
665
  )
666
  ),
667
  'checkbox' => array(
688
  . 'Highly recommended if you do not want to '
689
  . 'force your visitors to enter a captcha every time.', $this->domain) => 'enable_akismet'
690
  ),
691
+ 'use_global_keys' => array(
692
  __('uncheck to use different key pairs for this site.', $this->domain) => 'use_global_keys'
693
+ ),
694
+ 'use_recaptcha_v1' => array(
695
+ __('check this if you prefer the oldschool recaptcha.', $this->domain) => 'use_recaptcha_v1'
696
+ ),
697
+ 'enable_v1_https' => array(
698
+ __('check this to make requests to reCAPTCHA server always secured.', $this->domain) => 'enable_v1_https'
699
+ ),
700
+ 'enable_auto_fill_comment' => array(
701
+ __('After redirected, auto fill the comment field with previous comment.', $this->domain)
702
+ . ' '
703
+ . sprintf(
704
+ __('This feature requires an active <a target="_blank" href="%s">PHP session</a>.', $this->domain),
705
+ 'http://php.net/manual/en/intro.session.php'
706
+ ) => 'enable_auto_fill_comment'
707
+ ),
708
+ 'enable_cf7' => array(
709
+ __('With this you can use the <code>recaptcha</code> shortcode tag in your Contact Form 7 forms.', $this->domain) => 'enable_cf7'
710
  )
711
  ),
712
  'input' => array(
731
  'input_approved' => array(
732
  'size' => 3,
733
  'label' => __('approved comment(s).', $this->domain)
734
+ )
735
  ),
736
  'container' => array(
737
+ 'cb8' => ''
738
  ),
739
  'post' => array(
740
+ 'select_akismet_react' => '<br />'
741
  . __('It is best to put comments identified as spam in moderation queue '
742
  . 'so you are able to review and instruct '
743
  . 'Akismet to correctly handle similar comments in the future.</em>', $this->domain)
 
744
  ),
745
  'inline_fields' => array(
746
  'cb4' => array('select_cap' => 'select'),
747
  'cb5' => array('input_approved' => 'input')
748
+ ),
749
+ 'env' => array(
750
+ 'use_global_keys' => 'multisite'
751
+ ),
752
+ 'blog' => array(
753
+ 'use_global_keys' => 'sub'
754
+ ),
755
+ 'formats' => array(
756
+ 'input_approved' => 'int',
757
+ 'input_error' => 'html',
758
+ 'input_back' => 'html'
759
  )
760
  );
761
 
762
+ // options that should be handled by this form
763
+ $form_options = array(
764
  'use_global_keys',
765
+ 'use_recaptcha_v1',
766
+ 'enable_v1_https',
767
  'input_pubkey',
768
  'input_prikey',
769
  'input_error',
775
  'enable_registration',
776
  'enable_login',
777
  'enable_comment',
778
+ 'enable_auto_fill_comment',
779
  'input_back',
780
  'select_position',
 
781
  'select_response',
782
  'enable_akismet',
783
+ 'select_akismet_react',
784
+ 'enable_cf7'
 
 
 
 
 
 
 
 
785
  );
786
 
 
 
787
  // show appropriate fields based on multi-site setting
788
  add_action('bwp_option_action_before_submit_button', array($this, 'modify_option_page'));
789
  }
790
  else if ($page == BWP_CAPT_OPTION_THEME)
791
  {
792
+ $option_page->set_current_tab(2);
793
 
794
+ // @since 2.0.0 differnet settings for different recaptcha
795
+ $form = $this->options['use_recaptcha_v1'] == 'yes' ? array(
796
  'items' => array(
797
  'select',
798
  'checkbox',
832
  'cb1' => array(
833
  sprintf(__('This is for Custom Theme only. '
834
  . 'Disable this and add your own CSS to style the Custom Theme. '
835
+ . 'More info <a href="%s#recaptcha-version-1" target="_blank">here</a>.', $this->domain),
836
  BWP_CAPT_PLUGIN_URL) => 'enable_css'
 
 
 
837
  )
838
  ),
839
  'input' => array(
851
  . 'please read <a href="%s" target="_blank">this dedicated tip</a>.', $this->domain),
852
  'http://betterwp.net/wordpress-tips/how-to-add-custom-translations-to-bwp-recaptcha/')
853
  )
854
+ ) : array(
855
+ 'items' => array(
856
+ 'select',
857
+ 'select',
858
+ 'select',
859
+ 'input',
860
+ 'heading'
861
+ ),
862
+ 'item_labels' => array(
863
+ __('reCAPTCHA theme', $this->domain),
864
+ __('reCAPTCHA size', $this->domain),
865
+ __('Language', $this->domain),
866
+ __('Tabindex for captcha input field', $this->domain),
867
+ __('Preview your reCAPTCHA', $this->domain)
868
+ ),
869
+ 'item_names' => array(
870
+ 'select_v2_theme',
871
+ 'select_v2_size',
872
+ 'select_v2_lang',
873
+ 'input_tab',
874
+ 'h1'
875
+ ),
876
+ 'heading' => array(
877
+ 'h1' => __('<em>Below you will see how your reCAPTCHA will look. '
878
+ . 'Note that this might differ on your actual pages.<br /></em>', $this->domain)
879
+ ),
880
+ 'select' => array(
881
+ 'select_v2_theme' => array(
882
+ _x('Light', 'recaptcha v2 light theme', $this->domain) => 'light',
883
+ _x('Dark', 'recaptcha v2 dark theme', $this->domain) => 'dark'
884
+ ),
885
+ 'select_v2_size' => array(
886
+ _x('Normal', 'recaptcha v2 normal size', $this->domain) => 'normal',
887
+ _x('Compact', 'recaptcha v2 compact size', $this->domain) => 'compact'
888
+ ),
889
+ 'select_v2_lang' => array_merge(array(
890
+ _x('Auto-detected', 'recaptcha v2 language', $this->domain) => ''
891
+ ), $this->v2_lang),
892
+ /* 'select_v2_jsapi_position' => array( */
893
+ /* __('When needed', $this->domain) => 'on_demand', */
894
+ /* __('Globally', $this->domain) => 'globally', */
895
+ /* __('Manually', $this->domain) => 'manually' */
896
+ /* ) */
897
+ ),
898
+ 'input' => array(
899
+ 'input_tab' => array(
900
+ 'size' => 3,
901
+ 'label' => '<br />' . __('This should be 4 if you '
902
+ . 'place the captcha before the textarea, '
903
+ . 'and 5 if you put it after. Set to 0 to disable.', $this->domain)
904
+ )
905
+ )
906
  );
907
 
908
+ $form_options = $this->options['use_recaptcha_v1'] == 'yes'
909
+ ? array(
910
+ 'select_lang',
911
+ 'select_theme',
912
+ 'input_tab',
913
+ 'enable_css'
914
+ ) : array(
915
+ 'select_v2_theme',
916
+ 'select_v2_size',
917
+ 'select_v2_lang',
918
+ 'input_tab'
919
+ );
920
+
921
+ $form['formats'] = array(
922
  'input_tab' => 'int'
923
  );
924
 
 
 
925
  // preview reCAPTCHA
926
  add_action('bwp_option_action_before_submit_button', array($this, 'add_recaptcha'));
927
  }
928
  }
929
 
930
+ // assign the form and option array
931
+ $option_page->init($form, $form_options);
932
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
933
 
934
+ public function show_option_page()
935
+ {
936
  if (empty($this->options['input_pubkey'])
937
  || empty($this->options['input_prikey'])
938
  ) {
956
  );
957
  }
958
 
959
+ $this->curren_option_page->generate_html_form();
 
 
 
 
960
  }
961
 
962
  /**
967
  global $wp_rewrite;
968
 
969
  if (!is_singular() || !get_option('page_comments'))
970
+ return '';
971
 
972
  $page = get_query_var('cpage');
973
  if (empty($page))
1006
  return true;
1007
  }
1008
 
1009
+ if ($this->user_is_approved)
1010
+ {
1011
+ // save one db query
1012
+ return true;
1013
+ }
1014
+
1015
  if ('yes' == $this->options['hide_approved'])
1016
  {
1017
  $commenter = wp_get_current_commenter();
1042
 
1043
  // has more approved comments than required?
1044
  if ($approved_count >= $this->options['input_approved'])
1045
+ {
1046
+ $this->user_is_approved = true;
1047
  return true;
1048
+ }
1049
  }
1050
 
1051
  return false;
1052
  }
1053
 
1054
  /**
1055
+ * Output the reCAPTCHA HTML, use theme if specified
1056
  *
1057
+ * This function is used in almost every situation where a captcha is
1058
+ * needed, namely:
1059
+ * 1. comment form
1060
+ * 2. login/register form (standard WordPress)
1061
+ * 3. user/blog registration form (multisite)
1062
+ * - show captcha after email address when registering for a new user
1063
+ * account @see wp-signup.php::show_user_form
1064
  *
1065
+ * @param $errors @since 1.1.0
1066
+ * @param $formId @since 2.0.0
1067
  */
1068
+ public function add_recaptcha($errors = '', $formId = null)
1069
  {
1070
+ $errors = !is_wp_error($errors) ? new WP_Error() : $errors;
1071
+ $this->provider->renderCaptcha($errors, $formId);
1072
  }
1073
 
1074
+ /**
1075
+ * Add captcha to the comment form
1076
+ *
1077
+ * @since 2.0.0
1078
+ */
1079
+ public function add_comment_recaptcha()
1080
  {
1081
+ if ($this->_is_previous_comment_spam())
 
 
 
 
 
 
1082
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1083
  ?>
1084
  <p class="bwp-capt-spam-identified">
1085
  <?php _e('Your comment was identified as spam, '
1086
  . 'please complete the CAPTCHA below:', $this->domain); ?>
1087
  </p>
1088
  <?php
1089
+ }
 
 
1090
 
1091
+ $this->add_recaptcha();
 
 
 
 
 
 
 
 
 
1092
 
1093
+ // with this we can redirect to the previous comment url, with support
1094
+ // for previous comment page
1095
+ if ('redirect' == $this->options['select_response'])
1096
+ {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1097
  ?>
1098
+ <input type="hidden" name="error_redirect_to"
1099
+ value="<?php esc_attr_e($this->get_current_comment_page_link()); ?>" />
1100
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1101
  }
1102
  }
1103
 
1104
  /**
1105
  * Adds captcha to below comment field
1106
  *
1107
+ * This is fragile because themes can define their own
1108
+ * `comment_notes_after` arg which override this one. In such case one must
1109
+ * use `bwp_capt_comment_form()` instead of `comment_form()`
1110
+ *
1111
  * @since 1.1.1
1112
  * @return string
1113
  */
1114
  public function add_recaptcha_after_comment_field($form_defaults)
1115
  {
1116
+ $recaptcha_html = $this->get_comment_recaptcha_html();
 
 
 
 
 
1117
 
1118
  $form_defaults['comment_notes_after'] = !isset($form_defaults['comment_notes_after'])
1119
+ ? $recaptcha_html : $form_defaults['comment_notes_after'] . "\n" . $recaptcha_html;
1120
 
1121
  return $form_defaults;
1122
  }
1123
 
1124
  /**
1125
+ * Adds captcha to just before the submit field
1126
  *
1127
+ * This makes use of the `comment_form_submit_field` filter
1128
+ *
1129
+ * @since 2.0.0
1130
+ * @return string
1131
  */
1132
+ public function add_recaptcha_before_comment_submit_field($submit_field)
1133
  {
1134
+ $recaptcha_html = $this->get_comment_recaptcha_html();
1135
+
1136
+ return $recaptcha_html . "\n" . $submit_field;
 
 
 
 
 
 
 
 
 
 
1137
  }
1138
 
1139
  /**
1140
+ * This overrides Akismet's filter on the 'pre_comment_approved' hook
1141
  *
1142
+ * This allows us to control a comment's status even if it is marked as
1143
+ * spam by Akismet.
1144
+ *
1145
+ * @see Akismet::last_comment_status
1146
  */
1147
+ public function akismet_comment_status()
1148
  {
1149
+ $bwp_capt_cs = $this->options['select_akismet_react'];
1150
+ $bwp_capt_cs = 'hold' == $bwp_capt_cs ? '0' : $bwp_capt_cs;
 
 
 
 
 
 
1151
 
1152
+ if (defined('BWP_CAPT_AKISMET_COMMENT_STATUS')
1153
+ && BWP_CAPT_AKISMET_COMMENT_STATUS == 'spam'
1154
  ) {
1155
+ // @since 1.1.1 put comment into spam queue is no longer an option
1156
+ // but can still be forced
1157
+ return 'spam';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1158
  }
1159
 
1160
+ return $bwp_capt_cs;
1161
  }
1162
 
1163
  /**
1164
+ * Marks that we need a recaptcha because akismet has told us that
1165
+ * previous comment is considered spam
1166
  *
1167
+ * This should redirect the commenter back to the comment form
 
1168
  *
1169
+ * @return void
 
1170
  */
1171
+ public function add_recaptcha_after_akismet()
1172
  {
1173
+ $comment_post_ID = isset($_POST['comment_post_ID'])
1174
+ ? (int) $_POST['comment_post_ID']
1175
+ : 0;
 
 
 
 
 
 
 
 
 
 
 
 
1176
 
1177
+ $this->_set_session_data('bwp_capt_previous_comment_is_spam', 'yes');
1178
+ $this->_set_session_data('bwp_capt_previous_comment', isset($_POST['comment']) ? $_POST['comment'] : '');
 
 
 
 
 
 
1179
 
1180
+ $location_hash = $this->options['select_position'] == 'after_comment_field'
1181
+ ? 'comment' : 'respond';
 
 
 
 
 
 
 
 
 
 
 
 
1182
 
1183
+ $location = !empty($_POST['error_redirect_to'])
1184
+ ? $_POST['error_redirect_to']
1185
+ : get_permalink($comment_post_ID) . '#' . $location_hash;
 
 
1186
 
1187
+ wp_safe_redirect($location);
1188
+ exit;
1189
  }
1190
 
1191
+ /**
1192
+ * Make text safe to edit inside textarea
1193
+ *
1194
+ * This function will be removed once requirement is moved to WP 3.1.
1195
+ *
1196
+ * @since 1.1.1
1197
+ * @return string
1198
+ */
1199
+ private function _esc_textarea($text)
1200
  {
1201
+ return htmlspecialchars($text, ENT_QUOTES, get_option('blog_charset'));
 
 
 
 
 
 
 
 
 
1202
  }
1203
 
1204
+ public function fill_comment_field_with_previous_comment($comment_field)
1205
  {
1206
+ $previous_comment = $this->_get_session_data('bwp_capt_previous_comment');
1207
+
1208
+ if (!empty($previous_comment))
 
 
1209
  {
1210
+ // put the comment content back if possible
1211
+ $comment_text = stripslashes($previous_comment);
1212
+ $comment_field = preg_replace('#(<textarea\s[^>]*>)(.*?)(</textarea>)#uis',
1213
+ '$1' . $this->_esc_textarea($comment_text) . '$3',
1214
+ $comment_field
1215
+ );
1216
+
1217
+ $this->_unset_session_data('bwp_capt_previous_comment');
1218
  }
1219
 
1220
+ return $comment_field;
1221
  }
1222
 
1223
  /**
1224
  * Check captcha response for comment forms
1225
  *
1226
+ * @param int $comment_post_ID
1227
  */
1228
+ public function check_comment_recaptcha($comment_post_ID)
1229
  {
1230
+ if ($errors = $this->provider->verify())
 
 
 
 
 
 
 
 
 
1231
  {
1232
+ $error = current($errors);
1233
+ $errorCode = current(array_keys($errors));
1234
+
1235
+ // save the previous comment in session so we can use it to fill
1236
+ // the comment field later on, but only do this when needed
1237
+ if ('redirect' == $this->options['select_response']
1238
+ && 'yes' == $this->options['enable_auto_fill_comment']
1239
+ ) {
1240
+ $this->_set_session_data('bwp_capt_previous_comment', isset($_POST['comment']) ? $_POST['comment'] : '');
1241
+ }
1242
 
1243
  if ('redirect' == $this->options['select_response'])
1244
  {
1247
  $location = !empty($_POST['error_redirect_to'])
1248
  ? $_POST['error_redirect_to']
1249
  : get_permalink($comment_post_ID) . '#respond';
1250
+
1251
+ $location = add_query_arg('cerror', $errorCode, $location);
1252
 
1253
  wp_safe_redirect($location);
1254
+
1255
  exit;
1256
  }
1257
  else if ('back' == $this->options['select_response'])
1258
  {
1259
+ if ('invalid-response' == $error)
1260
  {
1261
  wp_die(sprintf($this->options['input_back'],
1262
  ' <a href="javascript:history.go(-1);">'
1263
  . __('this link', $this->domain)
1264
  . '</a>'));
1265
  }
 
 
 
 
 
 
1266
  else
1267
  {
1268
+ wp_die($this->provider->getErrorMessage($error));
 
1269
  }
1270
  }
1271
+
1272
+ return;
1273
  }
1274
+
1275
+ if ($this->_is_akismet_integration_enabled())
1276
  {
1277
+ // recaptcha is valid, and previous comment is considered spam
1278
+ if ($this->_is_previous_comment_spam())
1279
  {
1280
+ // do not increase Akismet spam counter
 
1281
  add_filter('akismet_spam_count_incr', create_function('', 'return 0;'), 11);
1282
 
1283
+ // use the correct status for the marked-as-spam comment, use
1284
  // workaround for remove_filter function
1285
  add_filter('pre_comment_approved', array($this, 'akismet_comment_status'), 10);
1286
  add_filter('pre_comment_approved', array($this, 'akismet_comment_status'), 11);
1287
  }
1288
 
1289
+ // reset Akismet-related data, next comment should be checked again
1290
+ // from the beginning
1291
+ $this->_unset_session_data('bwp_capt_previous_comment');
1292
+ $this->_unset_session_data('bwp_capt_previous_comment_is_spam');
1293
  }
1294
  }
1295
 
1296
+ protected function get_comment_recaptcha_html()
1297
  {
1298
+ ob_start();
 
1299
 
1300
+ $this->add_comment_recaptcha();
1301
+ $recaptcha_html = ob_get_contents();
1302
+
1303
+ ob_end_clean();
1304
+
1305
+ return $recaptcha_html;
1306
+ }
1307
+
1308
+ /**
1309
+ * Check captcha response for login form
1310
+ *
1311
+ * @filter authenticate, @see ::wp-signon in package WordPress/pluggable.php
1312
+ * @since 1.1.0
1313
+ * @return WP_User if captcha is ok
1314
+ * WP_Error if captcha is NOT ok
1315
+ */
1316
+ public function check_login_recaptcha($user)
1317
+ {
1318
+ if (empty($_POST['log']) && empty($_POST['pwd']))
1319
+ return $user;
1320
+
1321
+ // if the $user object itself is a WP_Error object, we simply append
1322
+ // errors to it, otherwise we create a new one.
1323
+ $errors = is_wp_error($user) ? $user : new WP_Error();
1324
+
1325
+ if ($captchaErrors = $this->provider->verify())
1326
+ {
1327
+ $errors->add('recaptcha-error', $this->provider->getErrorMessage(current($captchaErrors)));
1328
+
1329
+ // invalid recaptcha detected, the returned $user object should be
1330
+ // a WP_Error object
1331
+ $user = is_wp_error($user) ? $user : $errors;
1332
+
1333
+ // do not allow WordPress to try authenticating the user, either
1334
+ // using cookie or username/password pair
1335
+ remove_filter('authenticate', 'wp_authenticate_username_password', 20, 3);
1336
+ remove_filter('authenticate', 'wp_authenticate_cookie', 30, 3);
1337
  }
1338
 
1339
+ return $user;
1340
  }
1341
 
1342
  /**
1343
+ * Check captcha response on registration page
1344
  *
1345
+ * This function is used in two scenarios:
1346
+ * 1. When a user registers for a new accont on a standard WordPress installation
1347
+ * 2. When a user registers for a new account OR registers for a blog on a
1348
+ * multisite WordPress installation
1349
+ *
1350
+ * Either way we should always receive a WP_Error instance to inject our
1351
+ * errors into.
1352
+ *
1353
+ * @since 1.1.0
1354
+ * @param WP_Error $errors
1355
+ * @return WP_Error
1356
  */
1357
+ public function check_reg_recaptcha(WP_Error $errors)
1358
  {
1359
+ if ($captchaErrors = $this->provider->verify())
1360
+ $errors->add('recaptcha-error', $this->provider->getErrorMessage(current($captchaErrors)));
 
1361
 
1362
+ return $errors;
1363
+ }
1364
+
1365
+ /**
1366
+ * Adds a captcha to multisite user registration page
1367
+ *
1368
+ * @since 2.0.0
1369
+ * @param WP_Error $errors
1370
+ */
1371
+ public function add_multisite_user_reg_recaptcha(WP_Error $errors)
1372
+ {
1373
+ $this->add_recaptcha($errors);
1374
+ }
1375
 
1376
+ /**
1377
+ * Adds a captcha to multisite blog registration page
1378
+ *
1379
+ * @since 1.1.0
1380
+ * @param WP_Error $errors
1381
+ */
1382
+ public function add_multisite_blog_reg_recaptcha(WP_Error $errors)
1383
+ {
1384
+ // only show a captcha when user is already registered and is
1385
+ // registering a new blog
1386
+ if (is_user_logged_in())
1387
+ $this->add_recaptcha($errors);
1388
+ }
1389
 
1390
+ /**
1391
+ * Check captcha when registering for a new user account on a multisite
1392
+ * installation
1393
+ *
1394
+ * This should validate captcha when the user form is submitted, current
1395
+ * stage is 'validate-user-signup' @see wp-signup.php::signup_user
1396
+ *
1397
+ * @param array $result use $result['errors'] to get a WP_Error instance
1398
+ * @return array
1399
+ */
1400
+ public function check_multisite_user_reg_recaptcha(array $result)
1401
+ {
1402
+ if (isset($_POST['stage']) && 'validate-blog-signup' == $_POST['stage'])
1403
+ {
1404
+ // user is registering a new blog, we don't need to check anything
1405
+ // because captcha is not required at this stage
1406
+ return $result;
1407
+ }
1408
+ else
1409
+ {
1410
+ $result['errors'] = $this->check_reg_recaptcha($result['errors']);
1411
+ return $result;
1412
+ }
1413
+ }
1414
 
1415
+ /**
1416
+ * Check captcha when registering for a new blog on a multisite
1417
+ * installation
1418
+ *
1419
+ * This should only validate the captcha if the user is already registered
1420
+ * and is registering a new blog, current stag is 'validate-blog-signup'
1421
+ * @see wp-signup.php::signup_blog
1422
+ *
1423
+ * @param array $result use $result['errors'] to get a WP_Error instance
1424
+ * @return array
1425
+ */
1426
+ public function check_multisite_blog_reg_recaptcha(array $result)
1427
+ {
1428
+ if (is_user_logged_in())
1429
+ $result['errors'] = $this->check_reg_recaptcha($result['errors']);
1430
 
1431
+ return $result;
 
1432
  }
1433
  }
includes/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ //white page
includes/provider/abstract-provider.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright (c) 2015 Khang Minh <contact@betterwp.net>
5
+ * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER
6
+ */
7
+
8
+ /**
9
+ * @author Khang Minh <contact@betterwp.net>
10
+ * @since 2.0.0
11
+ * @package BWP reCAPTCHA
12
+ */
13
+ abstract class BWP_Recaptcha_Provider
14
+ {
15
+ protected $options;
16
+
17
+ protected $domain;
18
+
19
+ public function __construct(array $options, $domain)
20
+ {
21
+ $this->options = $options;
22
+ $this->domain = $domain;
23
+ }
24
+
25
+ public static function create(BWP_RECAPTCHA $plugin)
26
+ {
27
+ $options = $plugin->options;
28
+ $domain = $plugin->domain;
29
+
30
+ $providerOptions = array(
31
+ 'site_key' => $options['input_pubkey'],
32
+ 'secret_key' => $options['input_prikey'],
33
+ 'theme' => $options['select_theme'],
34
+ 'language' => $options['select_lang'],
35
+ 'tabindex' => $options['input_tab'],
36
+ 'invalid_response_message' => $options['input_error'],
37
+ );
38
+
39
+ if ('yes' == $options['use_recaptcha_v1']) {
40
+ $providerOptions = array_merge($providerOptions, array(
41
+ 'use_ssl' => $options['enable_v1_https']
42
+ ));
43
+
44
+ return new BWP_Recaptcha_Provider_V1($providerOptions, $domain);
45
+ } else {
46
+ $providerOptions = array_merge($providerOptions, array(
47
+ 'language' => $options['select_v2_lang'],
48
+ 'theme' => $options['select_v2_theme'],
49
+ 'size' => $options['select_v2_size'],
50
+ 'position' => $options['select_v2_jsapi_position']
51
+ ));
52
+
53
+ return new BWP_Recaptcha_Provider_V2($providerOptions, $domain);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Render the recaptcha
59
+ *
60
+ * @param WP_ERROR $errors
61
+ * @param string $formId id of the form this recaptcha belongs to, this
62
+ * should basically be a unique identifier
63
+ */
64
+ abstract public function renderCaptcha(WP_Error $errors = null, $formId = null);
65
+
66
+ /**
67
+ * Verify a captcha response
68
+ *
69
+ * @param string $userResponse if null check from $_POST
70
+ * @return array of errors, an empty array means there are no error
71
+ * keys are actual error codes, values are
72
+ * processed error codes
73
+ */
74
+ abstract public function verify($userResponse = null);
75
+
76
+ public function getOption($key)
77
+ {
78
+ return isset($this->options[$key]) ? $this->options[$key] : '';
79
+ }
80
+
81
+ public function getDomain()
82
+ {
83
+ return $this->domain;
84
+ }
85
+
86
+ public function getErrorMessage($error)
87
+ {
88
+ if ('invalid-response' == $error) {
89
+ return $this->options['invalid_response_message'];
90
+ } elseif ('invalid-keys' == $error && current_user_can('manage_options')) {
91
+ return __('There is some problem with your reCAPTCHA API keys, '
92
+ . 'please double check them.', $this->domain);
93
+ } else {
94
+ return __('Unknown error. Please contact an administrator '
95
+ . 'for more info.', $this->domain);
96
+ }
97
+ }
98
+
99
+ public function getErrorMessageFromCode($errorCode)
100
+ {
101
+ $error = $this->processError($errorCode);
102
+ return $this->getErrorMessage($error);
103
+ }
104
+
105
+ protected function getIpAddress()
106
+ {
107
+ return !empty($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null;
108
+ }
109
+
110
+ protected function processError($errorCode)
111
+ {
112
+ $errorMaps = array(
113
+ // v2 errors
114
+ 'missing-input-secret' => 'invalid-keys',
115
+ 'invalid-input-secret' => 'invalid-keys',
116
+ 'missing-input-response' => 'invalid-response',
117
+ 'invalid-input-response' => 'invalid-response',
118
+ // v1 errors
119
+ 'incorrect-captcha-sol' => 'invalid-response'
120
+ );
121
+
122
+ if (isset($errorMaps[$errorCode])) {
123
+ return $errorMaps[$errorCode];
124
+ }
125
+
126
+ return 'unknown';
127
+ }
128
+
129
+ protected function processErrors(array $errorCodes)
130
+ {
131
+ $processedErrorCodes = array();
132
+
133
+ foreach ($errorCodes as $code) {
134
+ $processedErrorCodes[$code] = $this->processError($code);
135
+ }
136
+
137
+ return $processedErrorCodes;
138
+ }
139
+ }
includes/provider/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ //white page
includes/provider/recaptcha/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ //white page
includes/{recaptcha → provider/recaptcha}/recaptchalib.php RENAMED
@@ -45,13 +45,13 @@ define("RECAPTCHA_VERIFY_SERVER", "www.google.com");
45
  * @return string - encoded request
46
  */
47
  function _recaptcha_qsencode ($data) {
48
- $req = "";
49
- foreach ( $data as $key => $value )
50
- $req .= $key . '=' . urlencode( stripslashes($value) ) . '&';
51
 
52
- // Cut the last '&'
53
- $req=substr($req,0,strlen($req)-1);
54
- return $req;
55
  }
56
 
57
 
@@ -66,29 +66,29 @@ function _recaptcha_qsencode ($data) {
66
  */
67
  function _recaptcha_http_post($host, $path, $data, $port = 80) {
68
 
69
- $req = _recaptcha_qsencode ($data);
70
 
71
- $http_request = "POST $path HTTP/1.0\r\n";
72
- $http_request .= "Host: $host\r\n";
73
- $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
74
- $http_request .= "Content-Length: " . strlen($req) . "\r\n";
75
- $http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
76
- $http_request .= "\r\n";
77
- $http_request .= $req;
78
 
79
- $response = '';
80
- if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
81
- die ('Could not open socket');
82
- }
83
 
84
- fwrite($fs, $http_request);
85
 
86
- while ( !feof($fs) )
87
- $response .= fgets($fs, 1160); // One TCP-IP packet
88
- fclose($fs);
89
- $response = explode("\r\n\r\n", $response, 2);
90
 
91
- return $response;
92
  }
93
 
94
 
@@ -110,42 +110,28 @@ function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false, $lang = '
110
  }
111
 
112
  if ($use_ssl) {
113
- $server = RECAPTCHA_API_SECURE_SERVER;
114
- } else {
115
- $server = RECAPTCHA_API_SERVER;
116
- }
117
-
118
- $errorpart = "";
119
- if ($error) {
120
- $errorpart = "&amp;error=" . $error;
121
- }
122
  // BWP recaptcha update note, @since 1.1.0
123
  // added a hl query var to correctly localize the recaptcha text for
124
  // pre-defined themes
125
- //return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>
126
- return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '&amp;hl=' . $lang . '"></script>
127
 
128
  <noscript>
129
- <iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '&amp;hl=' . $lang . '" height="300" width="500"></iframe><br/>
130
- <textarea style="display:none" name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
131
- <input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
132
  </noscript>';
133
  }
134
 
135
-
136
-
137
-
138
- /**
139
- * A ReCaptchaResponse is returned from recaptcha_check_answer()
140
- */
141
- if (!class_exists('ReCaptchaResponse')) :
142
- class ReCaptchaResponse {
143
- var $is_valid;
144
- var $error;
145
- }
146
- endif;
147
-
148
-
149
  /**
150
  * Calls an HTTP POST function to verify if the user's guess was correct
151
  * @param string $privkey
@@ -167,34 +153,34 @@ function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $ex
167
 
168
 
169
 
170
- //discard spam submissions
171
- if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
172
- $recaptcha_response = new ReCaptchaResponse();
173
- $recaptcha_response->is_valid = false;
174
- $recaptcha_response->error = 'incorrect-captcha-sol';
175
- return $recaptcha_response;
176
- }
177
-
178
- $response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify",
179
- array (
180
- 'privatekey' => $privkey,
181
- 'remoteip' => $remoteip,
182
- 'challenge' => $challenge,
183
- 'response' => $response
184
- ) + $extra_params
185
- );
186
-
187
- $answers = explode ("\n", $response [1]);
188
- $recaptcha_response = new ReCaptchaResponse();
189
-
190
- if (trim ($answers [0]) == 'true') {
191
- $recaptcha_response->is_valid = true;
192
- }
193
- else {
194
- $recaptcha_response->is_valid = false;
195
- $recaptcha_response->error = $answers [1];
196
- }
197
- return $recaptcha_response;
198
 
199
  }
200
 
@@ -236,7 +222,7 @@ function _recaptcha_mailhide_urlbase64 ($x) {
236
  function recaptcha_mailhide_url($pubkey, $privkey, $email) {
237
  if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
238
  die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
239
- "you can do so at <a href='http://www.google.com/recaptcha/mailhide/apikey'>http://www.google.com/recaptcha/mailhide/apikey</a>");
240
  }
241
 
242
 
@@ -278,6 +264,3 @@ function recaptcha_mailhide_html($pubkey, $privkey, $email) {
278
  "' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities ($emailparts [1]);
279
 
280
  }
281
-
282
-
283
- ?>
45
  * @return string - encoded request
46
  */
47
  function _recaptcha_qsencode ($data) {
48
+ $req = "";
49
+ foreach ( $data as $key => $value )
50
+ $req .= $key . '=' . urlencode( stripslashes($value) ) . '&';
51
 
52
+ // Cut the last '&'
53
+ $req=substr($req,0,strlen($req)-1);
54
+ return $req;
55
  }
56
 
57
 
66
  */
67
  function _recaptcha_http_post($host, $path, $data, $port = 80) {
68
 
69
+ $req = _recaptcha_qsencode ($data);
70
 
71
+ $http_request = "POST $path HTTP/1.0\r\n";
72
+ $http_request .= "Host: $host\r\n";
73
+ $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
74
+ $http_request .= "Content-Length: " . strlen($req) . "\r\n";
75
+ $http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
76
+ $http_request .= "\r\n";
77
+ $http_request .= $req;
78
 
79
+ $response = '';
80
+ if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
81
+ die ('Could not open socket');
82
+ }
83
 
84
+ fwrite($fs, $http_request);
85
 
86
+ while ( !feof($fs) )
87
+ $response .= fgets($fs, 1160); // One TCP-IP packet
88
+ fclose($fs);
89
+ $response = explode("\r\n\r\n", $response, 2);
90
 
91
+ return $response;
92
  }
93
 
94
 
110
  }
111
 
112
  if ($use_ssl) {
113
+ $server = RECAPTCHA_API_SECURE_SERVER;
114
+ } else {
115
+ $server = RECAPTCHA_API_SERVER;
116
+ }
117
+
118
+ $errorpart = "";
119
+ if ($error) {
120
+ $errorpart = "&amp;error=" . $error;
121
+ }
122
  // BWP recaptcha update note, @since 1.1.0
123
  // added a hl query var to correctly localize the recaptcha text for
124
  // pre-defined themes
125
+ //return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>
126
+ return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '&amp;hl=' . $lang . '"></script>
127
 
128
  <noscript>
129
+ <iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '&amp;hl=' . $lang . '" height="300" width="500"></iframe><br/>
130
+ <textarea style="display:none" name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
131
+ <input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
132
  </noscript>';
133
  }
134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  /**
136
  * Calls an HTTP POST function to verify if the user's guess was correct
137
  * @param string $privkey
153
 
154
 
155
 
156
+ //discard spam submissions
157
+ if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
158
+ $recaptcha_response = new ReCaptchaResponse();
159
+ $recaptcha_response->is_valid = false;
160
+ $recaptcha_response->error = 'incorrect-captcha-sol';
161
+ return $recaptcha_response;
162
+ }
163
+
164
+ $response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify",
165
+ array (
166
+ 'privatekey' => $privkey,
167
+ 'remoteip' => $remoteip,
168
+ 'challenge' => $challenge,
169
+ 'response' => $response
170
+ ) + $extra_params
171
+ );
172
+
173
+ $answers = explode ("\n", $response [1]);
174
+ $recaptcha_response = new ReCaptchaResponse();
175
+
176
+ if (trim ($answers [0]) == 'true') {
177
+ $recaptcha_response->is_valid = true;
178
+ }
179
+ else {
180
+ $recaptcha_response->is_valid = false;
181
+ $recaptcha_response->error = $answers [1];
182
+ }
183
+ return $recaptcha_response;
184
 
185
  }
186
 
222
  function recaptcha_mailhide_url($pubkey, $privkey, $email) {
223
  if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
224
  die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
225
+ "you can do so at <a href='http://www.google.com/recaptcha/mailhide/apikey'>http://www.google.com/recaptcha/mailhide/apikey</a>");
226
  }
227
 
228
 
264
  "' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities ($emailparts [1]);
265
 
266
  }
 
 
 
includes/provider/recaptcha/response.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A ReCaptchaResponse is returned from recaptcha_check_answer()
5
+ */
6
+ class ReCaptchaResponse
7
+ {
8
+ var $is_valid;
9
+ var $error;
10
+ }
includes/provider/v1-languages.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ return array(
4
+ 'English' => 'en',
5
+ 'Dutch' => 'nl',
6
+ 'French' => 'fr',
7
+ 'German' => 'de',
8
+ 'Italian' => 'it',
9
+ 'Portuguese' => 'pt',
10
+ 'Russian' => 'ru',
11
+ 'Spanish' => 'es',
12
+ 'Turkish' => 'tr'
13
+ );
includes/provider/v1.php ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright (c) 2015 Khang Minh <contact@betterwp.net>
5
+ * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER
6
+ */
7
+
8
+ /**
9
+ * This is the provider used for recaptcha v1
10
+ *
11
+ * @author Khang Minh <contact@betterwp.net>
12
+ * @since 2.0.0
13
+ * @package BWP reCAPTCHA
14
+ */
15
+ class BWP_Recaptcha_Provider_V1 extends BWP_Recaptcha_Provider
16
+ {
17
+ /**
18
+ * {@inheritDoc}
19
+ */
20
+ public function renderCaptcha(WP_Error $errors = null, $formId = null)
21
+ {
22
+ $this->loadCaptchaLibrary();
23
+
24
+ if (!defined('BWP_CAPT_ADDED')) {
25
+ // make sure we add only one recaptcha instance
26
+ define('BWP_CAPT_ADDED', true);
27
+
28
+ // captcha error can comes from $_GET variable or passed via
29
+ // hooks' parameters.
30
+ $captchaError = '';
31
+ $captchaErrorCode = null;
32
+
33
+ if (!empty($_GET['cerror'])) {
34
+ $captchaError = $this->getErrorMessageFromCode($_GET['cerror']);
35
+ $captchaErrorCode = $_GET['cerror'];
36
+ } elseif (isset($errors) && is_wp_error($errors)) {
37
+ $captchaError = $errors->get_error_message('recaptcha-error');
38
+ }
39
+
40
+ do_action('bwp_capt_before_add_captcha');
41
+ ?>
42
+ <style type="text/css">
43
+ /* this is to prevent the iframe from showing up in Chrome */
44
+ iframe[src="about:blank"] {
45
+ display: none;
46
+ }
47
+ </style>
48
+ <?php
49
+ if ($this->options['theme'] != 'custom') {
50
+ if (!empty($captchaError)) {
51
+ ?>
52
+ <p class="recaptcha_only_if_incorrect_sol error">
53
+ <?php echo $captchaError; ?>
54
+ </p>
55
+ <?php
56
+ }
57
+ ?>
58
+ <script type="text/javascript">
59
+ // @tododoc
60
+ var RecaptchaOptions = RecaptchaOptions || {
61
+ theme: '<?php echo $this->options['theme']; ?>',
62
+ lang: '<?php echo $this->options['language']; ?>',
63
+ <?php
64
+ if (!empty($this->options['tabindex'])) {
65
+ ?>
66
+ tabindex: <?php echo (int) $this->options['tabindex']; echo "\n"; ?>
67
+ <?php
68
+ };
69
+ ?>
70
+ };
71
+ </script>
72
+ <?php
73
+ } else {
74
+ $this->loadTemplateFunctions();
75
+ bwp_capt_custom_theme_widget();
76
+ }
77
+
78
+ $isSecured = is_ssl() ? true : false;
79
+ $isSecured = $this->options['use_ssl'] ? true : $isSecured;
80
+
81
+ if (!empty($this->options['secret_key'])) {
82
+ echo recaptcha_get_html(
83
+ $this->options['site_key'],
84
+ $captchaErrorCode,
85
+ $isSecured,
86
+ $this->options['language']
87
+ );
88
+ } else if (current_user_can('manage_options')) {
89
+ // if user is an admin show the actual error
90
+ printf(__('To use reCAPTCHA you must get an API key from '
91
+ . '<a href="%1$s">%1$s</a>', $this->domain),
92
+ 'https://www.google.com/recaptcha/admin/create');
93
+ }
94
+ }
95
+ }
96
+
97
+ /**
98
+ * {@inheritDoc}
99
+ */
100
+ public function verify($userResponse = null)
101
+ {
102
+ $this->loadCaptchaLibrary();
103
+
104
+ $challengeField = !empty($_POST['recaptcha_challenge_field'])
105
+ ? $_POST['recaptcha_challenge_field']
106
+ : null;
107
+
108
+ $userResponse = $userResponse ?: (!empty($_POST['recaptcha_response_field'])
109
+ ? $_POST['recaptcha_response_field']
110
+ : null);
111
+
112
+ $response = recaptcha_check_answer(
113
+ $this->options['secret_key'],
114
+ $this->getIpAddress(),
115
+ $challengeField,
116
+ $userResponse
117
+ );
118
+
119
+ if (!$response->is_valid) {
120
+ return $this->processErrors(array($response->error));
121
+ }
122
+ }
123
+
124
+ protected function loadTemplateFunctions()
125
+ {
126
+ if (!function_exists('bwp_capt_custom_theme_widget')) :
127
+
128
+ /**
129
+ * Output custom reCAPTCHA theme
130
+ *
131
+ * By defining this function in your theme/plugin, you can override this
132
+ * and thus changing the html codes to suit your needs.
133
+ *
134
+ * @return void
135
+ */
136
+ function bwp_capt_custom_theme_widget()
137
+ {
138
+ global $bwp_capt;
139
+
140
+ $provider = $bwp_capt->get_captcha_provider();
141
+ ?>
142
+ <script type="text/javascript">
143
+ var RecaptchaOptions = {
144
+ theme : 'custom',
145
+ custom_theme_widget: 'recaptcha_widget',
146
+ tabindex: <?php echo (int) $provider->getOption('tabindex'); echo "\n"; ?>
147
+ };
148
+ </script>
149
+
150
+ <div id="recaptcha_widget" style="display: none;">
151
+ <p class="recaptcha_only_if_incorrect_sol">
152
+ <?php echo $provider->getOption('invalid_response_message'); ?>
153
+ </p>
154
+ <div id="recaptcha_image"></div>
155
+ <div class="recaptcha_control">
156
+ <a href="javascript:Recaptcha.reload()" title="<?php _e('Get another challenge', $provider->getDomain()); ?>"><img src="<?php echo BWP_CAPT_IMAGES . '/icon_refresh.png'; ?>" alt="<?php _e('Get another challenge', $provider->getDomain()); ?>" /></a>
157
+ <span class="recaptcha_only_if_image"><a href="javascript:Recaptcha.switch_type('audio')" title="<?php _e('Get audio reCAPTCHA', $provider->getDomain()); ?>"><img src="<?php echo BWP_CAPT_IMAGES . '/icon_sound.png'; ?>" alt="<?php _e('Get audio reCAPTCHA', $provider->getDomain()); ?>" /></a></span>
158
+ <span class="recaptcha_only_if_audio"><a href="javascript:Recaptcha.switch_type('image')" title="<?php _e('Get image reCAPTCHA', $provider->getDomain()); ?>"><img src="<?php echo BWP_CAPT_IMAGES . '/icon_image.png'; ?>" alt="<?php _e('Get image reCAPTCHA', $provider->getDomain()); ?>" /></a></span>
159
+ <span><a href="javascript:Recaptcha.showhelp()" title="<?php _e('About reCAPTCHA', $provider->getDomain()); ?>"><img src="<?php echo BWP_CAPT_IMAGES . '/icon_help.png'; ?>" alt="<?php _e('About reCAPTCHA', $provider->getDomain()); ?>" /></a></span>
160
+ </div>
161
+
162
+ <div class="recaptcha_text">
163
+ <span class="recaptcha_only_if_image"><label for="recaptcha_response_field"><em><small><?php _e('Type what you see', $provider->getDomain()); ?>:</small></em></label></span>
164
+ <span class="recaptcha_only_if_audio"><label for="recaptcha_response_field"><em><small><?php _e('Type what you hear', $provider->getDomain()); ?>:</small></em></label></span>
165
+ <input type="text" id="recaptcha_response_field" tabindex="<?php echo (int) $provider->getOption('tabindex'); ?>" class="input" name="recaptcha_response_field" />
166
+ </div>
167
+ </div>
168
+ <?php
169
+ }
170
+
171
+ endif;
172
+ }
173
+
174
+ protected function loadCaptchaLibrary()
175
+ {
176
+ if (!function_exists('recaptcha_get_html')
177
+ || !function_exists('recaptcha_check_answer')
178
+ ) {
179
+ require_once __DIR__ . '/recaptcha/recaptchalib.php';
180
+ }
181
+ }
182
+ }
includes/provider/v2-languages.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ return array(
4
+ 'Arabic' => 'ar',
5
+ 'Bengali' => 'bn',
6
+ 'Bulgarian' => 'bg',
7
+ 'Catalan' => 'ca',
8
+ 'Chinese (Simplified)' => 'zh-CN',
9
+ 'Chinese (Traditional)' => 'zh-TW',
10
+ 'Croatian' => 'hr',
11
+ 'Czech' => 'cs',
12
+ 'Danish' => 'da',
13
+ 'Dutch' => 'nl',
14
+ 'English (UK)' => 'en-GB',
15
+ 'English (US)' => 'en',
16
+ 'Estonian' => 'et',
17
+ 'Filipino' => 'fil',
18
+ 'Finnish' => 'fi',
19
+ 'French' => 'fr',
20
+ 'French (Canadian)' => 'fr-CA',
21
+ 'German' => 'de',
22
+ 'Gujarati' => 'gu',
23
+ 'German (Austria)' => 'de-at',
24
+ 'german (switzerland)' => 'de-CH',
25
+ 'Greek' => 'el',
26
+ 'Hebrew' => 'iw',
27
+ 'Hindi' => 'hi',
28
+ 'Hungarain' => 'hu',
29
+ 'Indonesian' => 'id',
30
+ 'Italian' => 'it',
31
+ 'Japanese' => 'ja',
32
+ 'Kannada' => 'kn',
33
+ 'Korean' => 'ko',
34
+ 'Latvian' => 'lv',
35
+ 'Lithuanian' => 'lt',
36
+ 'Malay' => 'ms',
37
+ 'Malayalam' => 'ml',
38
+ 'Marathi' => 'mr',
39
+ 'Norwegian' => 'no',
40
+ 'Persian' => 'fa',
41
+ 'Polish' => 'pl',
42
+ 'Portuguese' => 'pt',
43
+ 'Portuguese (Brazil)' => 'pt-BR',
44
+ 'Portuguese (Portugal)' => 'pt-PT',
45
+ 'Romanian' => 'ro',
46
+ 'Russian' => 'ru',
47
+ 'Serbian' => 'sr',
48
+ 'Slovak' => 'sk',
49
+ 'Slovenian' => 'sl',
50
+ 'Spanish' => 'es',
51
+ 'Spanish (Latin America)' => 'es-419',
52
+ 'Swedish' => 'sv',
53
+ 'Tamil' => 'ta',
54
+ 'Telugu' => 'te',
55
+ 'Thai' => 'th',
56
+ 'Turkish' => 'tr',
57
+ 'Ukrainian' => 'uk',
58
+ 'Urdu' => 'ur',
59
+ 'Vietnamese' => 'vi'
60
+ );
includes/provider/v2.php ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright (c) 2015 Khang Minh <contact@betterwp.net>
5
+ * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER
6
+ */
7
+
8
+ /**
9
+ * This is the provider used for recaptcha v2
10
+ *
11
+ * @author Khang Minh <contact@betterwp.net>
12
+ * @since 2.0.0
13
+ * @package BWP reCAPTCHA
14
+ */
15
+ class BWP_Recaptcha_Provider_V2 extends BWP_Recaptcha_Provider
16
+ {
17
+ // this must always be a secured URL
18
+ // @see https://developers.google.com/recaptcha/docs/display
19
+ protected $jsSrc = 'https://www.google.com/recaptcha/api.js';
20
+
21
+ /**
22
+ * A list of instances created
23
+ *
24
+ * This array should contain ids of form that a recaptcha instance belongs
25
+ * to, e.g. 'cf7-form1', the key of the array will then be used to
26
+ * construct the widget id to be used with `grecaptcha.render()` and
27
+ * `grecaptcha.reset()`. @see
28
+ * https://developers.google.com/recaptcha/docs/display#example
29
+ *
30
+ * @var array
31
+ */
32
+ protected $instances = array();
33
+
34
+ public function __construct(array $options, $domain)
35
+ {
36
+ parent::__construct($options, $domain);
37
+
38
+ $this->_registerHooks();
39
+ }
40
+
41
+ /**
42
+ * {@inheritDoc}
43
+ */
44
+ public function renderCaptcha(WP_Error $errors = null, $formId = null)
45
+ {
46
+ $output = array();
47
+ $formId = $this->_getUniqueFormId($formId);
48
+
49
+ $this->instances[] = $formId;
50
+
51
+ if (!empty($_GET['cerror'])) {
52
+ $captchaError = $this->getErrorMessageFromCode($_GET['cerror']);
53
+ } elseif (isset($errors) && is_wp_error($errors)) {
54
+ $captchaError = $errors->get_error_message('recaptcha-error');
55
+ }
56
+
57
+ if (!empty($captchaError)) {
58
+ $output[] = '<p class="bwp-recaptcha-error error">' . $captchaError . '</p>';
59
+ }
60
+
61
+ $output[] = implode('', array(
62
+ '<input type="hidden" name="bwp-recaptcha-widget-id" value="' . esc_attr($this->_getWidgetId($formId)) . '" />',
63
+ '<div id="' . $this->_getWidgetHtmlId($formId) . '" class="g-recaptcha" ',
64
+ /* 'data-sitekey="' . esc_attr($this->options['site_key']) . '" ', */
65
+ /* 'data-theme="' . esc_attr($this->options['theme']) . '" ', */
66
+ /* 'data-size="' . esc_attr($this->options['size']) . '" ', */
67
+ /* 'data-tabindex="' . esc_attr($this->options['tabindex']) . '"', */
68
+ '>',
69
+ '</div>'
70
+ ));
71
+
72
+ do_action('bwp_capt_before_add_captcha');
73
+
74
+ echo implode("\n", $output);
75
+ }
76
+
77
+ /**
78
+ * {@inheritDoc}
79
+ */
80
+ public function verify($userResponse = null)
81
+ {
82
+ $userResponse = $userResponse ?: (!empty($_POST['g-recaptcha-response'])
83
+ ? $_POST['g-recaptcha-response']
84
+ : null);
85
+
86
+ $recaptcha = new ReCaptcha\ReCaptcha($this->options['secret_key']);
87
+ $response = $recaptcha->verify($userResponse, $this->getIpAddress());
88
+
89
+ if ($response->isSuccess()) {
90
+ return array();
91
+ } else {
92
+ return $this->processErrors($response->getErrorCodes());
93
+ }
94
+ }
95
+
96
+ public function printRecaptchaJS()
97
+ {
98
+ $args = array(
99
+ 'onload' => 'bwpRecaptchaCallback',
100
+ 'render' => 'explicit'
101
+ );
102
+
103
+ if (!empty($this->options['language'])) {
104
+ $args['hl'] = urlencode($this->options['language']);
105
+ }
106
+
107
+ $src = add_query_arg($args, $this->jsSrc);
108
+ ?>
109
+ <script type="text/javascript">
110
+ <?php foreach ($this->instances as $key => $formId) : ?>
111
+ var bwpRecaptchaWidget<?php echo $key + 1; ?>;
112
+ <?php endforeach; ?>
113
+ var bwpRecaptchaCallback = function() {
114
+ // render all collected recaptcha instances
115
+ <?php foreach ($this->instances as $key => $formId) : ?>
116
+ bwpRecaptchaWidget<?php echo $key + 1; ?> = grecaptcha.render('<?php echo $this->_getWidgetHtmlId($formId); ?>', {
117
+ sitekey: '<?php echo esc_js($this->options['site_key']); ?>',
118
+ theme: '<?php echo esc_js($this->options['theme']); ?>',
119
+ size: '<?php echo esc_js($this->options['size']); ?>',
120
+ tabindex: '<?php echo esc_js($this->options['tabindex']); ?>'
121
+ });
122
+ <?php endforeach; ?>
123
+ };
124
+ </script>
125
+
126
+ <script src="<?php echo esc_url($src) ?>" async defer></script>
127
+ <?php
128
+ }
129
+
130
+ private function _getWidgetId($formId)
131
+ {
132
+ return 'bwpRecaptchaWidget' . (array_search($formId, $this->instances, true) + 1);
133
+ }
134
+
135
+ private function _registerHooks()
136
+ {
137
+ $priority = 99999;
138
+
139
+ // regular pages
140
+ add_action('wp_footer', array($this, 'printRecaptchaJS'), $priority);
141
+
142
+ // login/register page
143
+ add_action('login_footer', array($this, 'printRecaptchaJS'), $priority);
144
+
145
+ // admin theme preview page
146
+ add_action('admin_footer-bwp-recapt_page_bwp_capt_theme', array($this, 'printRecaptchaJS'), $priority);
147
+ }
148
+
149
+ private function _getUniqueFormId($formId)
150
+ {
151
+ $formId = $formId ?: 'form';
152
+
153
+ if (!in_array($formId, $this->instances)) {
154
+ return $formId;
155
+ }
156
+
157
+ // non-unique form id, append the total number of instances plus one
158
+ return $formId . '-' . (count($this->instances) + 1);
159
+ }
160
+
161
+ private function _getWidgetHtmlId($formId)
162
+ {
163
+ return 'bwp-recaptcha-' . md5($formId);
164
+ }
165
+ }
js/bwp-recaptcha.js CHANGED
@@ -13,9 +13,26 @@ jQuery(function($) {
13
  }
14
  }
15
 
 
 
 
 
 
 
 
 
 
 
16
  toggle_comment_form_message();
 
 
17
 
18
  $('#select_response').on('change', function() {
19
  toggle_comment_form_message();
 
 
 
 
 
20
  });
21
  });
13
  }
14
  }
15
 
16
+ function toggle_auto_fill_switch() {
17
+ var selected = $('#select_response').val();
18
+ $('#enable_auto_fill_comment').parents('li.bwp-clear').toggle(selected === 'redirect');
19
+ }
20
+
21
+ function toggle_enable_v1_https() {
22
+ var checked = $('#use_recaptcha_v1').is(':checked');
23
+ $('#enable_v1_https').parents('li.bwp-clear').toggle(checked);
24
+ }
25
+
26
  toggle_comment_form_message();
27
+ toggle_auto_fill_switch();
28
+ toggle_enable_v1_https();
29
 
30
  $('#select_response').on('change', function() {
31
  toggle_comment_form_message();
32
+ toggle_auto_fill_switch();
33
+ });
34
+
35
+ $('#use_recaptcha_v1').on('change', function() {
36
+ toggle_enable_v1_https();
37
  });
38
  });
languages/bwp-recaptcha-hr.mo ADDED
Binary file
languages/bwp-recaptcha-hr.po ADDED
@@ -0,0 +1,585 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: BWP reCAPTCHA\n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: 2014-01-08 17:11+0700\n"
6
+ "PO-Revision-Date: 2015-08-16 15:32+0700\n"
7
+ "Last-Translator: Gospodin Bajrudin <gbajro@gmail.com>\n"
8
+ "Language-Team: Gospodin Bajrudin <gbajro@gmail.com>\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Poedit-KeywordsList: _;gettext;gettext_noop;__;_e\n"
13
+ "X-Poedit-Basepath: .\n"
14
+ "X-Poedit-SourceCharset: UTF-8\n"
15
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
16
+ "Language: hr\n"
17
+ "X-Generator: Poedit 1.8.2\n"
18
+ "X-Poedit-SearchPath-0: .\n"
19
+
20
+ #: includes/class-bwp-framework.php:178
21
+ #, php-format
22
+ msgid ""
23
+ "%s requires WordPress <strong>%s</strong> or higher and PHP <strong>%s</"
24
+ "strong> or higher. The plugin will not function until you update your "
25
+ "software. Please deactivate this plugin."
26
+ msgstr ""
27
+ "%s zahtjeva WordPress <strong>%s</strong> ili noviji i PHP <strong>%s</"
28
+ "strong> ili noviji. Ovaj dodatak nece raditi dok ne azurirate svoj softver. "
29
+ "Molimo deaktivirajte ovaj dodatak."
30
+
31
+ #: includes/class-bwp-framework.php:190
32
+ msgid "Development Log"
33
+ msgstr "Razvojni zapis"
34
+
35
+ #: includes/class-bwp-framework.php:190
36
+ msgid "Frequently Asked Questions"
37
+ msgstr "Često postavljana pitanja"
38
+
39
+ #: includes/class-bwp-framework.php:190
40
+ msgid "FAQ"
41
+ msgstr "FAQ"
42
+
43
+ #: includes/class-bwp-framework.php:190
44
+ msgid "Got a problem? Send me a feedback!"
45
+ msgstr "Imate problem? Pošaljite mi poruku!"
46
+
47
+ #: includes/class-bwp-framework.php:190
48
+ msgid "Contact"
49
+ msgstr "Kontakt"
50
+
51
+ #: includes/class-bwp-framework.php:197
52
+ msgid ""
53
+ "You can buy me some special coffees if you appreciate my work, thank you!"
54
+ msgstr "Možete mi kupiti specijalnu kavu ako cijenite moj posao, hvala Vam!"
55
+
56
+ #: includes/class-bwp-framework.php:211
57
+ msgid "Donate to "
58
+ msgstr "Donirati "
59
+
60
+ #: includes/class-bwp-framework.php:213
61
+ msgid "One cup $5.00"
62
+ msgstr "Jedna šalica $5.00"
63
+
64
+ #: includes/class-bwp-framework.php:214
65
+ msgid "Two cups $10.00"
66
+ msgstr "Dvije šalice $10.00"
67
+
68
+ #: includes/class-bwp-framework.php:215
69
+ msgid "Five cups! $25.00"
70
+ msgstr "Pet šalica! $25.00"
71
+
72
+ #: includes/class-bwp-framework.php:216
73
+ msgid "One LL-cup!!! $50.00"
74
+ msgstr "Jedna LL-šalica!!! $50.00"
75
+
76
+ #: includes/class-bwp-framework.php:217
77
+ msgid "... or any amount!"
78
+ msgstr "... ili bilo koja svota!"
79
+
80
+ #: includes/class-bwp-framework.php:232
81
+ msgid "Latest updates from BetterWP.net!"
82
+ msgstr "Zadnje nadogradnje od BetterWP.net!"
83
+
84
+ #: includes/class-bwp-framework.php:233
85
+ msgid "Follow me on Twitter!"
86
+ msgstr "Slijedi me na Twitteru"
87
+
88
+ #: includes/class-bwp-framework.php:243
89
+ msgid "This Plugin is Proudly Sponsored By"
90
+ msgstr "Ovaj dodatak je ponosno sponzoriran od"
91
+
92
+ #: includes/class-bwp-framework.php:260
93
+ #, php-format
94
+ msgid "You are using version %s!"
95
+ msgstr "Koristite inačicu %s!"
96
+
97
+ #: includes/class-bwp-framework.php:396
98
+ msgid "Settings"
99
+ msgstr "Postavke"
100
+
101
+ #: includes/class-bwp-recaptcha.php:44
102
+ msgid "Get another challenge"
103
+ msgstr "Ponovno generiraj kombinaciju"
104
+
105
+ #: includes/class-bwp-recaptcha.php:45
106
+ msgid "Get audio reCAPTCHA"
107
+ msgstr "Generiraj zvučni reCAPTCHA"
108
+
109
+ #: includes/class-bwp-recaptcha.php:46
110
+ msgid "Get video reCAPTCHA"
111
+ msgstr "Generiraj slikovni reCAPTCHA"
112
+
113
+ #: includes/class-bwp-recaptcha.php:47
114
+ msgid "About reCAPTCHA"
115
+ msgstr "O reCAPTCHA"
116
+
117
+ #: includes/class-bwp-recaptcha.php:51
118
+ msgid "Enter the two words in the box:"
119
+ msgstr "Unesite dvije riječi u polje:"
120
+
121
+ #: includes/class-bwp-recaptcha.php:52
122
+ msgid "Enter the numbers you hear:"
123
+ msgstr "Unesite brojeve koje ste čuli:"
124
+
125
+ #: includes/class-bwp-recaptcha.php:132
126
+ msgid ""
127
+ "<strong>ERROR:</strong> Incorrect or empty reCAPTCHA response, please try "
128
+ "again."
129
+ msgstr ""
130
+ "<strong>POGREŠKA:</strong> Netočan ili prazan reCAPTCHA odgovor, pokušajte "
131
+ "ponovno."
132
+
133
+ #: includes/class-bwp-recaptcha.php:133
134
+ #, php-format
135
+ msgid ""
136
+ "Error: Incorrect or empty reCAPTCHA response, please click the back button "
137
+ "on your browser's toolbar or click on %s to go back."
138
+ msgstr ""
139
+ "Pogreška: Netočan ili prazan reCAPTCHA odgovor, molimo kliknite tipku natrag "
140
+ "na Vašem pregledniku ili kliknite na %s za vratiti se."
141
+
142
+ #: includes/class-bwp-recaptcha.php:155 includes/class-bwp-recaptcha.php:313
143
+ msgid "General Options"
144
+ msgstr "Globalne Opcije"
145
+
146
+ #: includes/class-bwp-recaptcha.php:156 includes/class-bwp-recaptcha.php:314
147
+ msgid "Theme Options"
148
+ msgstr "Opcije teme"
149
+
150
+ #: includes/class-bwp-recaptcha.php:159
151
+ msgid "English"
152
+ msgstr "Engleski"
153
+
154
+ #: includes/class-bwp-recaptcha.php:160
155
+ msgid "Dutch"
156
+ msgstr "Nizozemski"
157
+
158
+ #: includes/class-bwp-recaptcha.php:161
159
+ msgid "French"
160
+ msgstr "Francuski"
161
+
162
+ #: includes/class-bwp-recaptcha.php:162
163
+ msgid "German"
164
+ msgstr "Njemački"
165
+
166
+ #: includes/class-bwp-recaptcha.php:163
167
+ msgid "Portuguese"
168
+ msgstr "Portugalski"
169
+
170
+ #: includes/class-bwp-recaptcha.php:164
171
+ msgid "Russian"
172
+ msgstr "Ruski"
173
+
174
+ #: includes/class-bwp-recaptcha.php:165
175
+ msgid "Spanish"
176
+ msgstr "Španjolski"
177
+
178
+ #: includes/class-bwp-recaptcha.php:166
179
+ msgid "Turkish"
180
+ msgstr "Turski"
181
+
182
+ #: includes/class-bwp-recaptcha.php:170
183
+ msgid "Read Profile"
184
+ msgstr "Provjeri profil"
185
+
186
+ #: includes/class-bwp-recaptcha.php:171
187
+ msgid "Manage Options"
188
+ msgstr "Upravljanje opcijama"
189
+
190
+ #: includes/class-bwp-recaptcha.php:311
191
+ msgid "Better WordPress reCAPTCHA"
192
+ msgstr "Better WordPress reCAPTCHA"
193
+
194
+ #: includes/class-bwp-recaptcha.php:313
195
+ msgid "BWP reCAPTCHA General Options"
196
+ msgstr "BWP reCAPTCHA Globalne Opcije"
197
+
198
+ #: includes/class-bwp-recaptcha.php:314
199
+ msgid "BWP reCAPTCHA Theme Options"
200
+ msgstr "BWP reCAPTCHA Opcije Teme"
201
+
202
+ #: includes/class-bwp-recaptcha.php:347
203
+ msgid "You do not have sufficient permissions to access this page."
204
+ msgstr "Nemate dovoljna prava za posjetiti ovu stranicu"
205
+
206
+ #: includes/class-bwp-recaptcha.php:366
207
+ msgid "What is reCAPTCHA?"
208
+ msgstr "Što je reCAPTCHA"
209
+
210
+ #: includes/class-bwp-recaptcha.php:367
211
+ msgid "This plugin will be"
212
+ msgstr "Ovaj dodatak će biti"
213
+
214
+ #: includes/class-bwp-recaptcha.php:368
215
+ msgid "Use main site's keys"
216
+ msgstr "Koristite ključeve glavne stranice"
217
+
218
+ #: includes/class-bwp-recaptcha.php:369
219
+ msgid "Public Key"
220
+ msgstr "Javni ključ"
221
+
222
+ #: includes/class-bwp-recaptcha.php:370
223
+ msgid "Private Key"
224
+ msgstr "Privatni ključ"
225
+
226
+ #: includes/class-bwp-recaptcha.php:371
227
+ msgid "Visibility Options (applied to comment forms)"
228
+ msgstr "Opcije prikaza (za komentare)"
229
+
230
+ #: includes/class-bwp-recaptcha.php:372
231
+ msgid "Hide the CAPTCHA for"
232
+ msgstr "Sakrij CAPTCHU za"
233
+
234
+ #: includes/class-bwp-recaptcha.php:373
235
+ msgid "If wrong or empty response"
236
+ msgstr "Ako je pokrešan ili prazan odgovor"
237
+
238
+ #: includes/class-bwp-recaptcha.php:374 includes/class-bwp-recaptcha.php:375
239
+ msgid "Show the error message"
240
+ msgstr "Prikaži poruku o pogrešci"
241
+
242
+ #: includes/class-bwp-recaptcha.php:376
243
+ msgid "Akismet Integration (applied to comment forms)"
244
+ msgstr "Akismet Integracija (za komentare)"
245
+
246
+ #: includes/class-bwp-recaptcha.php:377
247
+ msgid "Integrate with Akismet?"
248
+ msgstr "Integrati s Akismetom?"
249
+
250
+ #: includes/class-bwp-recaptcha.php:378
251
+ msgid "If correct CAPTCHA response"
252
+ msgstr "Za točan CAPTCHA odgovor"
253
+
254
+ #: includes/class-bwp-recaptcha.php:382
255
+ msgid ""
256
+ "reCAPTCHA is a free CAPTCHA service that helps to digitize books, newspapers "
257
+ "and old time radio shows. You can read more about reCAPTCHA <a href=\"http://"
258
+ "www.google.com/recaptcha/learnmore\" target=\"_blank\">here</a>."
259
+ msgstr ""
260
+ "reCAPTCHA je besplatan CAPTCHA servis koji pomaže digitalizaciji knjiga, "
261
+ "članaka i starih radio emisija. Više o reCAPTCHA možete saznati <a href="
262
+ "\"http://www.google.com/recaptcha/learnmore\" target=\"_blank\">ovdje</a>."
263
+
264
+ #: includes/class-bwp-recaptcha.php:383
265
+ msgid ""
266
+ "<em>This section allows you to determine when to show reCAPTCHA and how this "
267
+ "plugin reacts to errors.</em>"
268
+ msgstr ""
269
+ "<em>Ovaj dio omogućava pregled opcija o prikazu reCAPTCHE i kako će se ovaj "
270
+ "dodatak ponašati u slučaju pogrešaka.</em>"
271
+
272
+ #: includes/class-bwp-recaptcha.php:384
273
+ msgid ""
274
+ "<em>Integrate with Akismet for better end-user experience. reCAPTCHA is "
275
+ "optional and <strong>NO</strong> spam comment will be added to the spam/"
276
+ "moderation queue, except likely legitimate comments. This makes the task of "
277
+ "identifying sincere comments much easier. This integration is currently in "
278
+ "beta stage.</em>"
279
+ msgstr ""
280
+ "<em>Integrati s Akismet dodatkom za bolje korisničko iskustvo. reCAPTCHA je "
281
+ "neobavezna i <strong>NIJEDAN</strong> spam komentar neće se dodati u "
282
+ "direktorij za spam/moderaciju, osim komentara koji su najvjerojatnije "
283
+ "ispravni. To olakšava posao prepoznavanja ispravnih komentara. Ova "
284
+ "integracija je trenutno u beta fazi.</em>"
285
+
286
+ #: includes/class-bwp-recaptcha.php:400
287
+ msgid "Redirect commenter back to the comment form"
288
+ msgstr "Preusmjeri korisnika natrag formu za komentare"
289
+
290
+ #: includes/class-bwp-recaptcha.php:401
291
+ msgid "Show an error page just like WordPress does"
292
+ msgstr "Prikaži stranicu o pogrešci kao što to radi WordPress"
293
+
294
+ #: includes/class-bwp-recaptcha.php:404
295
+ msgid "Approve comment immediately"
296
+ msgstr "Odmah odobri komentar"
297
+
298
+ #: includes/class-bwp-recaptcha.php:405
299
+ msgid "Hold comment in moderation queue"
300
+ msgstr "Zadrži komentar u moderaciji"
301
+
302
+ #: includes/class-bwp-recaptcha.php:406
303
+ msgid "Put comment in spam queue"
304
+ msgstr "Stavi komentar u spam direktorij"
305
+
306
+ #: includes/class-bwp-recaptcha.php:410
307
+ msgid "enabled for comment forms."
308
+ msgstr "omogućeno kod komentara"
309
+
310
+ #: includes/class-bwp-recaptcha.php:411
311
+ msgid "enabled for registration form (user/site registration)."
312
+ msgstr "omogućeno kod registracijske forme (za korisnike i stranice) "
313
+
314
+ #: includes/class-bwp-recaptcha.php:412
315
+ msgid "enabled for login form."
316
+ msgstr "omogućeno kod forme za prijavu."
317
+
318
+ #: includes/class-bwp-recaptcha.php:413
319
+ msgid "registered users <em>(even without any capabilities)</em>."
320
+ msgstr "registrirani korisnici <em>(čak i bez ikakvih mogućnosti)</em>."
321
+
322
+ #: includes/class-bwp-recaptcha.php:414
323
+ msgid "users who can"
324
+ msgstr "korisnici koji mogu"
325
+
326
+ #: includes/class-bwp-recaptcha.php:415
327
+ msgid "visitors who have at least"
328
+ msgstr "posjetitelji koji imaju najmanje"
329
+
330
+ #: includes/class-bwp-recaptcha.php:416
331
+ msgid ""
332
+ "reCAPTCHA will only show when Akismet identifies a comment as spam. Highly "
333
+ "recommended if you do not want to force your visitors to type the captcha "
334
+ "every time."
335
+ msgstr ""
336
+ "reCAPTCHA će se prikazati samo ako Akismet identificira komentar kao spam. "
337
+ "Preporučeno ukoliko se želi smanjiti broj prikazivanja reCAPTCHE "
338
+ "posjetiteljima."
339
+
340
+ #: includes/class-bwp-recaptcha.php:417
341
+ msgid "uncheck to use different key pairs for this site."
342
+ msgstr "odznači ako želiš za koristiti druge ključeve za svoju stranicu "
343
+
344
+ #: includes/class-bwp-recaptcha.php:420
345
+ msgid "A public key used to request captchas from reCAPTCHA server."
346
+ msgstr "Javni ključ koristi se za dohvat CAPTCHE sa reCAPTCHA poslužitelja."
347
+
348
+ #: includes/class-bwp-recaptcha.php:421
349
+ msgid "A private (secret) key used to authenticate user's response."
350
+ msgstr ""
351
+ "Privatni ključ (tajni) koji se koristi za provjeru (autentikaciju) "
352
+ "korisnikova odgovora."
353
+
354
+ #: includes/class-bwp-recaptcha.php:422
355
+ msgid ""
356
+ "when redirect commenter back to the comment form (or when used in other "
357
+ "forms such as contact forms)."
358
+ msgstr ""
359
+ "kod vraćanja korisnika na formular za komentar (ili kod korištenja u drugim "
360
+ "formama, npr. kontakt formulara)."
361
+
362
+ #: includes/class-bwp-recaptcha.php:423
363
+ msgid "when show the normal error page with no redirection."
364
+ msgstr "kod prikaza stranice s greškom kod koje nema preusmjeravanja"
365
+
366
+ #: includes/class-bwp-recaptcha.php:424
367
+ msgid "approved comment(s)."
368
+ msgstr "Odobren(i) komentar(i)."
369
+
370
+ #: includes/class-bwp-recaptcha.php:427
371
+ msgid ""
372
+ "<em><strong>Note:</strong> For this plugin to work, you will need a pair of "
373
+ "API keys (public and private), which is available for free <a href=\"https://"
374
+ "www.google.com/recaptcha/admin/create\" target=\"_blank\">here</a>. Once you "
375
+ "have created those two keys for this domain, simply paste them below.</em>"
376
+ msgstr ""
377
+ "<em><strong>Pažnja:</strong> Kako bi ovaj dodatak mogao raditi, potrebno je "
378
+ "koristiti API ključeve (javni i privatni), koji su besplatno dostupni <a "
379
+ "href=\"https://www.google.com/recaptcha/admin/create\" target=\"_blank"
380
+ "\">ovdje</a>. Nakon dobivanja ključeva za Vašu domenu, unesite ih ispod.</em>"
381
+
382
+ #: includes/class-bwp-recaptcha.php:428
383
+ msgid ""
384
+ "<em><strong>Note:</strong> Now you may wonder, why put the comment in the "
385
+ "spam queue? The benefit is Akismet will be able to mark the comment as False "
386
+ "Positive, and thus will not possibly block that comment in the future. "
387
+ "However, it is best to just put the comment in moderation queue as next time "
388
+ "Akismet will put such comment in moderation queue immediately without the "
389
+ "need of a CAPTCHA.</em>"
390
+ msgstr ""
391
+ "<em><strong>Pažnja:</strong> Zašto staviti komentar u spam direktorij? "
392
+ "Akismet će provjeriti i biti u mogućnosti označiti komentar kao legitiman, "
393
+ "te u budućnosti ne blokirati takav komentar. U principu, najbolje je staviti "
394
+ "komentar u moderaciju, te će svaki slijedeći puta Akismet postaviti komentar "
395
+ "direktno u moderaciju, bez potrebe za unošenjem CAPTCHA koda.</em>"
396
+
397
+ #: includes/class-bwp-recaptcha.php:457
398
+ msgid "Choose a theme"
399
+ msgstr "Izaberi temu"
400
+
401
+ #: includes/class-bwp-recaptcha.php:458
402
+ msgid "Use CSS provided by this plugin?"
403
+ msgstr "Koristi CSS koji je došao s ovim pluginom?"
404
+
405
+ #: includes/class-bwp-recaptcha.php:459
406
+ msgid "Load CSS, JS selectively?"
407
+ msgstr "Učitaj CSS, JS opcionalno?"
408
+
409
+ #: includes/class-bwp-recaptcha.php:460
410
+ msgid "Choose a language for built-in themes"
411
+ msgstr "Odaberi jezik za ugrađene teme"
412
+
413
+ #: includes/class-bwp-recaptcha.php:461
414
+ msgid "Tabindex for captcha input field"
415
+ msgstr "Tab kod polja za unos"
416
+
417
+ #: includes/class-bwp-recaptcha.php:462
418
+ msgid "Preview your reCAPTCHA"
419
+ msgstr "Pregledaj reCAPTCHU"
420
+
421
+ #: includes/class-bwp-recaptcha.php:466
422
+ msgid ""
423
+ "<em>Below you will see how your reCAPTCHA will look. Note that this might "
424
+ "differ on your actual pages.<br /></em>"
425
+ msgstr ""
426
+ "<em>Ispod je prikaz izgleda reCAPTCHE. Može se razlikovati na pravoj web "
427
+ "stranici.<br /></em>"
428
+
429
+ #: includes/class-bwp-recaptcha.php:470
430
+ msgid "Default Theme (Red)"
431
+ msgstr "Zadana Tema (Crvena)"
432
+
433
+ #: includes/class-bwp-recaptcha.php:471
434
+ msgid "White Theme"
435
+ msgstr "Bijela Tema"
436
+
437
+ #: includes/class-bwp-recaptcha.php:472
438
+ msgid "Black Theme"
439
+ msgstr "Crna Tema"
440
+
441
+ #: includes/class-bwp-recaptcha.php:473
442
+ msgid "Clean Theme"
443
+ msgstr "Clean (čista) Tema"
444
+
445
+ #: includes/class-bwp-recaptcha.php:474
446
+ msgid "Custom Theme (use CSS)"
447
+ msgstr "Vlastita tema (koristi CSS)"
448
+
449
+ #: includes/class-bwp-recaptcha.php:479
450
+ msgid ""
451
+ "This stylesheet is used to style the custom theme as well as the "
452
+ "registration page. You can disable this or add appropriate filters to use "
453
+ "your own."
454
+ msgstr ""
455
+ "Ovaj stil se koristi za prikaz ručno napravljene teme kao i registracijske "
456
+ "stranice. Može se onemogućiti ili urediti na željeni način."
457
+
458
+ #: includes/class-bwp-recaptcha.php:480
459
+ msgid "This is only useful when you do not use any minify or cache plugin."
460
+ msgstr ""
461
+ "Korisno kad se ne koristi dodaci koji uključuju spremnik (minify ili cache "
462
+ "dodatak)."
463
+
464
+ #: includes/class-bwp-recaptcha.php:483
465
+ msgid ""
466
+ "Basically, this should be 4 if you place the captcha before the textarea, "
467
+ "and 5 if you put it after. Set to 0 to disable."
468
+ msgstr ""
469
+ "Ovo bi trebalo biti 4 ako će se captcha prikazivati prije unosa teksta, a 5 "
470
+ "ako će se prikazivati poslije. Postaviti 0 da se onemogući."
471
+
472
+ #: includes/class-bwp-recaptcha.php:486
473
+ #, php-format
474
+ msgid ""
475
+ "<em><strong>Note:</strong> The four built-in captcha themes will look OK in "
476
+ "most WordPress themes; However, some times it is better to control how "
477
+ "reCAPTCHA looks using CSS. Please read <a href=\"%s#customization\" target="
478
+ "\"_blank\">this guide</a> if you would like to do so.</em>"
479
+ msgstr ""
480
+ "<em><strong>Pažnja:</strong> Četiri ugrađene teme će izgledati dobro u "
481
+ "većini WordPress tema. Ponekad je bolje koristiti CSS za kontroliranje "
482
+ "reCAPTCHA izgleda. Pročitajte <a href=\"%s#customization\" target=\"_blank"
483
+ "\">ove upute</a> ako želite promijeniti izgled.</em>"
484
+
485
+ #: includes/class-bwp-recaptcha.php:487
486
+ #, php-format
487
+ msgid ""
488
+ "<em><strong>Note:</strong> Above you can select some built-in languages. If "
489
+ "you would like to add your own language, please read <a href="
490
+ "\"%s#customization\" target=\"_blank\">this guide</a>.</em>"
491
+ msgstr ""
492
+ "<em><strong>Pažnja:</strong> Ovdje se mogu odabrati jezici za korištenje . "
493
+ "Ukoliko želite dodati svoj, pročitajte <a href=\"%s#customization\" target="
494
+ "\"_blank\">ove upute</a>.</em>"
495
+
496
+ #: includes/class-bwp-recaptcha.php:540
497
+ msgid "All options have been saved."
498
+ msgstr "Sve opcije su spremljene."
499
+
500
+ #: includes/class-bwp-recaptcha.php:546
501
+ msgid "Warning"
502
+ msgstr "Upozorenje"
503
+
504
+ #: includes/class-bwp-recaptcha.php:546
505
+ msgid ""
506
+ "API key(s) missing. Please get an API key from <a href='https://www.google."
507
+ "com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</"
508
+ "a> (free!)"
509
+ msgstr ""
510
+ "Nedostaje/u API ključ(evi). Mogu se zatražiti na <a href='https://www."
511
+ "google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/"
512
+ "create</a> (besplatno!)"
513
+
514
+ #: includes/class-bwp-recaptcha.php:548
515
+ msgid "Notice"
516
+ msgstr "Obavijest"
517
+
518
+ #: includes/class-bwp-recaptcha.php:548
519
+ msgid ""
520
+ "You are enabling Akismet integration but Akismet is not currently active. "
521
+ "Please activate Akismet for the integration to work."
522
+ msgstr ""
523
+ "Omogućili ste Akismet integraciju ali Akismet trenutno nije aktivan. "
524
+ "Aktivirajte Akismet kako bi integracija proradila."
525
+
526
+ #: includes/class-bwp-recaptcha.php:671
527
+ msgid "Your comment was identified as spam, please complete the CAPTCHA below:"
528
+ msgstr "Vaš komentar je prepoznat kao spam, molimo popunite CAPTCHU:"
529
+
530
+ #: includes/class-bwp-recaptcha.php:714
531
+ msgid ""
532
+ "To use reCAPTCHA you must get an API key from <a href='https://www.google."
533
+ "com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>"
534
+ msgstr ""
535
+ "Za korištenje reCAPTCHA potrebno je preuzeti API ključ sa <a href='https://"
536
+ "www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/"
537
+ "admin/create</a>"
538
+
539
+ #: includes/class-bwp-recaptcha.php:763 includes/class-bwp-recaptcha.php:808
540
+ msgid "<strong>ERROR</strong>: Unknown captcha error."
541
+ msgstr "<strong>POGREŠKA</strong>: Nepoznata captcha pogreška"
542
+
543
+ #: includes/class-bwp-recaptcha.php:878
544
+ msgid "this link"
545
+ msgstr "ovu poveznicu"
546
+
547
+ #: includes/class-bwp-recaptcha.php:880
548
+ msgid ""
549
+ "There is some problem with your reCAPTCHA API keys, please double check them."
550
+ msgstr "Postoji problem s reCAPTCHA API ključevima, provjerite ih još jednom."
551
+
552
+ #: includes/class-bwp-recaptcha.php:882
553
+ msgid "Unknown error. Please contact the administrator for more info."
554
+ msgstr "Nepoznata greška. Kontaktirajte administratora za više informacija."
555
+
556
+ #: includes/class-bwp-recaptcha-cf7.php:107
557
+ msgid "This reCAPTCHA tag is provided by the BWP reCAPTCHA WordPress plugin."
558
+ msgstr ""
559
+ "Ovaj reCAPTCHA tag je dodjeljen od strane BWP reCAPTCHA WordPress dodatka."
560
+
561
+ #: includes/class-bwp-recaptcha-cf7.php:110
562
+ msgid ""
563
+ "Please refer to <a target=\"_blank\" href=\"http://betterwp.net/wordpress-"
564
+ "plugins/bwp-recaptcha/#customization\">BWP reCAPTCHA's documentation </a> "
565
+ "for a quick guide on how to customize the look and feel of this tag."
566
+ msgstr ""
567
+ "Pogledaj na <a target=\"_blank\" href=\"http://betterwp.net/wordpress-"
568
+ "plugins/bwp-recaptcha/#customization\">BWP reCAPTCHA dokumentaciju </a> za "
569
+ "kratke upute kako promijeniti izgled ovog taga."
570
+
571
+ #: includes/class-bwp-recaptcha-cf7.php:116
572
+ msgid "Name"
573
+ msgstr "Ime"
574
+
575
+ #: includes/class-bwp-recaptcha-cf7.php:123
576
+ msgid "Copy this code and paste it into the form left."
577
+ msgstr "Kopiraj ovaj dio koda i zalijepi lijevo u polje forme"
578
+
579
+ #: includes/bwp-option-page/includes/class-bwp-option-page.php:80
580
+ msgid "Plugin Configurations"
581
+ msgstr "Postavke dodatka"
582
+
583
+ #: includes/bwp-option-page/includes/class-bwp-option-page.php:398
584
+ msgid "Save Changes"
585
+ msgstr "Spremi promjene"
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === Better WordPress reCAPTCHA (support Akismet and Contact Form 7) ===
2
  Contributors: OddOneOut
3
- Donate link: http://betterwp.net/wordpress-plugins/bwp-recaptcha/
4
  Tags: recaptcha, captcha, comment captcha, login captcha, user registration captcha, blog registration captcha, contact form, contact form 7, akismet, akismet integration, akismet captcha, anti-spam, antispam
5
  Requires at least: 3.0
6
- Tested up to: 3.9
7
- Stable tag: 1.1.2
8
  License: GPLv3 or later
9
 
10
  This plugin utilizes Google reCAPTCHA to help your blog stay clear of spams. You can use this plugin with Akismet and Contact Form 7.
@@ -19,36 +19,43 @@ Akismet and Contact Form 7 are supported out of the box.
19
 
20
  [How-to: Add BWP reCAPTCHA to Contact Form 7](http://betterwp.net/wordpress-tips/how-to-add-bwp-recaptcha-to-contact-form-7/).
21
 
22
- [How-to: Add custom translations to reCAPTCHA](http://betterwp.net/wordpress-tips/how-to-add-custom-translations-to-bwp-recaptcha/).
23
 
24
  [Official Documentation](http://betterwp.net/wordpress-plugins/bwp-recaptcha/).
25
 
26
  **Some Features**
27
 
28
- * You can add captcha to comment form, user registration form, site registration form and login form
29
- * You can add captcha to form generated by Contact Form 7 plugin: use `recaptcha` or `bwp-recaptcha` shortcode tag
30
- * Hide reCAPTCHA for qualified visitors
31
- * Registered Users (even with no capabilities needed)
32
- * Authorized Users (users who have some capabilities, you can extend the default list)
33
- * Visitors who have at least a required number of approved comments
34
- * Comment Form:
35
- * You can position captcha before or after the comment field (new in 1.1.1)
36
- * Control how the plugin reacts when captcha response is invalid
37
- * Set error message when captcha response is invalid
38
- * Theme Features:
39
- * Choose between 4 default themes or create your own (sample CSS and images provided)
40
- * Use built-in languages or [add custom translations](http://betterwp.net/wordpress-tips/how-to-add-custom-translations-to-bwp-recaptcha/).
41
- * Integrate with Akismet for better end-users experience, i.e. "only force a CAPTCHA when a comment looks like spam".
42
- * WordPress Multi-site compatible: you can set different key pair for each site or use a single key pair for all sites
43
- * And more...
 
 
 
 
 
 
 
 
44
 
45
  Please don't forget to rate this plugin [5 shining stars](http://wordpress.org/support/view/plugin-reviews/bwp-recaptcha?filter=5) if you like it, thanks!
46
 
47
  **Get in touch**
48
 
49
- * Support is provided via [BetterWP.net Community](http://betterwp.net/community/).
50
- * Follow and contribute to development via [Github](http://betterwp.net/redirect-to?https://github.com/OddOneOut/Better-WordPress-reCAPTCHA).
51
- * You can also follow me on [Twitter](http://twitter.com/0dd0ne0ut).
52
  * Check out [latest WordPress Tips and Ideas](http://feeds.feedburner.com/BetterWPnet) from BetterWP.net.
53
 
54
  **Languages**
@@ -58,83 +65,68 @@ Please don't forget to rate this plugin [5 shining stars](http://wordpress.org/s
58
  * Hungarian (hu_HU). Thanks to [Attila Porvay](http://helloftranslations.net)
59
  * French (fr_FR). Thansk to [Christophe GUILLOUX](http://christophe.guilloux.info) and **Raoul Pierre**!
60
  * German (de_DE). Thanks to [Andreas Reitberger](http://wdbase.de/?p=585)
 
61
 
62
  Please [help translate](http://betterwp.net/wordpress-tips/create-pot-file-using-poedit/) this plugin!
63
 
64
  == Installation ==
65
 
66
- 1. Upload the `bwp-recaptcha` folder to the `/wp-content/plugins/` directory
67
- 2. Activate the plugin through the Plugins menu in WordPress. After activation, you should see a menu of this plugin on your left. If you can not locate it, click on Settings under the plugin's name.
68
- 3. Follow steps described in [plugin usage documentation](http://betterwp.net/wordpress-plugins/bwp-recaptcha/#usage) to properly add reCAPTCHA to your desired forms.
69
- 4. Configure the plugin, and add your API keys. You must have API keys for the current domain for this plugin to work.
70
- 5. Say goodbye to spam!
71
-
72
  [View instructions with images](http://betterwp.net/wordpress-plugins/bwp-recaptcha/installation/).
73
 
74
  == Frequently Asked Questions ==
75
 
76
- [Check plugin news and ask questions](http://betterwp.net/topic/bwp-recaptcha/).
77
 
78
  == Screenshots ==
79
 
80
- 1. reCAPTCHA added to Comment Form (default reCAPTCHA theme, Twenty Fourteen theme).
81
- 2. reCAPTCHA added to Contact Form 7 (custom reCAPTCHA theme, Twenty Fourteen theme).
82
- 3. reCAPTCHA added to WordPress Login Form (custom reCAPTCHA theme).
83
- 4. reCAPTCHA added to Blog Registration Form (multi-site enabled, 'clean' reCAPTCHA theme, Twenty Fourteen theme).
 
84
 
85
  == Changelog ==
86
 
87
- = 1.1.2 =
88
- * Fixed an issue where captcha is not displayed but still checked when added to a Contact Form 7 form.
89
-
90
- = 1.1.1 =
91
- * You can now choose to add captcha below comment text area without using a theme function. More info [here](http://betterwp.net/wordpress-plugins/bwp-recaptcha/#usage)
92
- * Added `recaptcha` shortcode tag back to Contact Form 7. Users can now choose between `recaptcha` and `bwp-recaptcha`
93
- * Added support for other plugins that include a slightly different version of reCAPTCHA library to avoid conflicts
94
- * Added Italian reCAPTCHA language (`it`)
95
- * Removed selective CSS, JS setting in Theme Options
96
- * Removed "Put comment in spam queue" option for Akismet integration. If you still want to use this option add this to your `wp-config.php`: `define('BWP_CAPT_AKISMET_COMMENT_STATUS', 'spam');`
97
- * Improved user registration and site registration form on a multi-site installation
98
- * Fixed an issue where a hidden iframe is adding margin to bottom of page in Google Chrome and Safari. This is merely a workaround solution so hopefully Google will fix this issue in reCAPTCHA
99
- * Fixed an issue where captcha is only checked after username and password is correct on login form
100
- * Fixed an issue where a bot can bypass recaptcha on user registration form
101
- * Fixed an issue where some PHP warnings are shown. Note that this fix might cause Akismet integration to fail, so users are advised to test this update first if Akismet integration is enabled
102
- * Updated German translation, thanks to Andreas Reitberger!
103
- * Updated French translation, thanks to Raoul Pierr!
104
- * WordPress 3.9 compatible
105
- * Other fixes and enhancements
106
-
107
- = 1.1.0 =
108
- * Marked as WordPress 3.8 compatible.
109
- * Added official support for Contact Form 7, users no longer have to install third-party plugins to integrate BWP reCAPTCHA and Contact Form 7. More info [here](http://betterwp.net/wordpress-tips/how-to-add-bwp-recaptcha-to-contact-form-7/).
110
- * Added an option to enable reCAPTCHA for login form (`wp-login.php`). This option is disabled by default.
111
- * Added better support for Multi-site installation. Admin can choose to use main site's key pair or different key pair for a specific site.
112
- * Added a German translation. Thanks to Andreas Reitberger!
113
- * Changed the default tabindex for recaptcha input field to 0 (disable).
114
- * Fixed localization issue (captcha was not translated correctly.)
115
- * Other fixes and improvements.
116
-
117
- **Note to translators:** several new strings are added so please update your translations.
118
-
119
- = 1.0.2 =
120
- * Marked as WordPress 3.7 compatible.
121
- * Added a Hungarian translation. Thanks to Attila Porvay!
122
- * Added a French translation. Thanks to Christophe GUILLOUX!
123
- * Updated BWP Framework to fix a possible bug that caues BWP setting pages to go blank.
124
- * Removed the `frameborder` attribute within the noscript tag of the PHP reCAPTCHA library for W3C compliance, thanks to Jools!
125
- * **Good news**: ManageWP.com has become the official sponsor for BWP reCAPTCHA - [Read more](http://betterwp.net/319-better-wordpress-plugins-updates-2013/).
126
-
127
- = 1.0.1 =
128
- * Added a template function that allows you to display reCAPTCHA below the textarea in a comment form. Check the installation tab out if you would like to know how to use the new template function. Thanks to Joo Bruni!
129
- * Made the public key and private key site-wide options. If you use BWP reCAPTCHA on a multi-site installation, you will only need to input this once.
130
- * Added Spanish - Espanol translation, thanks to Ivan Leomuro!
131
- * Marked this plugin as compatible with WordPress 3.2.x.
132
- * Other minor bugfixes and improvements.
133
-
134
- = 1.0.0 =
135
- * Initial Release.
136
 
137
  == Upgrade Notice ==
138
 
139
- = 1.0.0 =
140
- * Enjoy the plugin!
1
  === Better WordPress reCAPTCHA (support Akismet and Contact Form 7) ===
2
  Contributors: OddOneOut
3
+ Donate link: http://betterwp.net/wordpress-plugins/bwp-recaptcha/#contributions
4
  Tags: recaptcha, captcha, comment captcha, login captcha, user registration captcha, blog registration captcha, contact form, contact form 7, akismet, akismet integration, akismet captcha, anti-spam, antispam
5
  Requires at least: 3.0
6
+ Tested up to: 4.3
7
+ Stable tag: 2.0.0
8
  License: GPLv3 or later
9
 
10
  This plugin utilizes Google reCAPTCHA to help your blog stay clear of spams. You can use this plugin with Akismet and Contact Form 7.
19
 
20
  [How-to: Add BWP reCAPTCHA to Contact Form 7](http://betterwp.net/wordpress-tips/how-to-add-bwp-recaptcha-to-contact-form-7/).
21
 
22
+ [How-to: Add custom translations to reCAPTCHA (version 1 only)](http://betterwp.net/wordpress-tips/how-to-add-custom-translations-to-bwp-recaptcha/).
23
 
24
  [Official Documentation](http://betterwp.net/wordpress-plugins/bwp-recaptcha/).
25
 
26
  **Some Features**
27
 
28
+ - You can add captcha to comment form, user registration form, site
29
+ registration form and login form
30
+ - You can add captcha to form generated by Contact Form 7 plugin
31
+ - Hide captcha for qualified visitors
32
+ - Comment Form:
33
+ - You can position captcha before or after the comment field
34
+ - Control how the plugin reacts when captcha response is invalid
35
+ - Set error message when captcha response is invalid
36
+ - Theme Features:
37
+ - reCAPTCHA version 2:
38
+ - Choose between 2 default themes
39
+ - Normal or compact size
40
+ - More than 50 languages
41
+ - reCAPTCHA version 1:
42
+ - Choose between 4 default themes or create your own (sample CSS and images
43
+ provided)
44
+ - Use built-in languages or add custom translations
45
+ - Integrate with Akismet for better end-users experience, i.e. "only force a
46
+ CAPTCHA when a comment looks like spam".
47
+ - WordPress Multi-site compatible: you can set different key pair for each
48
+ site or use a single key pair for all sites.
49
+ - And more...
50
+
51
+ **Support this plugin**
52
 
53
  Please don't forget to rate this plugin [5 shining stars](http://wordpress.org/support/view/plugin-reviews/bwp-recaptcha?filter=5) if you like it, thanks!
54
 
55
  **Get in touch**
56
 
57
+ * Found a bug? Have a feature request? [Let me know](http://betterwp.net/wordpress-plugins/bwp-recaptcha/#report-issues)!
58
+ * Follow me on [Twitter](http://twitter.com/0dd0ne0ut).
 
59
  * Check out [latest WordPress Tips and Ideas](http://feeds.feedburner.com/BetterWPnet) from BetterWP.net.
60
 
61
  **Languages**
65
  * Hungarian (hu_HU). Thanks to [Attila Porvay](http://helloftranslations.net)
66
  * French (fr_FR). Thansk to [Christophe GUILLOUX](http://christophe.guilloux.info) and **Raoul Pierre**!
67
  * German (de_DE). Thanks to [Andreas Reitberger](http://wdbase.de/?p=585)
68
+ * Croatian (hr). Thanks to Ivan!
69
 
70
  Please [help translate](http://betterwp.net/wordpress-tips/create-pot-file-using-poedit/) this plugin!
71
 
72
  == Installation ==
73
 
 
 
 
 
 
 
74
  [View instructions with images](http://betterwp.net/wordpress-plugins/bwp-recaptcha/installation/).
75
 
76
  == Frequently Asked Questions ==
77
 
78
+ [View current FAQs](http://betterwp.net/wordpress-plugins/bwp-recaptcha/faq/).
79
 
80
  == Screenshots ==
81
 
82
+ 1. reCAPTCHA added to Comment Form.
83
+ 2. reCAPTCHA added to WordPress Login Form.
84
+ 3. reCAPTCHA added to Blog Registration Form (multi-site enabled).
85
+ 4. reCAPTCHA added to Contact Form 7.
86
+ 5. reCAPTCHA version 1 added to Comment Form.
87
 
88
  == Changelog ==
89
 
90
+ = 2.0.0 =
91
+
92
+ - **New Features**
93
+ - Add support for reCAPTCHA version 2
94
+ - Add support for multiple reCAPTCHA instances per page (reCAPTCHA
95
+ version 2 only)
96
+ - Add an HTTPS setting for reCAPTCHA version 1
97
+ - **Enhancements**
98
+ - Add support for Contact Form version 4.x
99
+ - Add support for custom login/register paths
100
+ - Add reCAPTCHA before the submit field in comment form for WordPress 4.2
101
+ or higher
102
+ - Use a lower priority when filter the `comment_form_defaults` filter
103
+ hook so reCAPTCHA can still be added to themes that filter it as well
104
+ - **Other Changes**
105
+ - Change minimum PHP version required to 5.3.2
106
+ - Show the captcha to all users (including admins) by default
107
+ - Contact Form 7:
108
+ - The shortcode `[bwp-recaptcha]` has been deprecated, use
109
+ `[recaptcha recaptcha-xxx]` instead.
110
+ - `bwp-recaptcha` will continue to work for Contact Form 7 prior to
111
+ version 4.1 (last supported is 4.0.3). `bwprecaptcha` and
112
+ `bwp_recaptcha` will still work with version 4.1+, so you won't
113
+ have to manually update any form if you're using them.
114
+ - Add a Croatian translation
115
+ - Layerthemes.com has become an official sponsor for BWP Plugins!
116
+ - **Bugs fixed**
117
+ - Fix Akismet integration not working properly
118
+ - Don't output comment form related fields in other forms, which leads to
119
+ extraneous markups in Contact Form 7 forms
120
+ - Create session only when needed and on demand
121
+ - Fix an issue where saving sub blog's API keys overwrites network's API
122
+ keys in a multisite installation
123
+ - **API**
124
+ - `BWP_RECAPTCHA::load_captcha_library()` has been removed, the PHP
125
+ reCAPTCHA library is now autoloaded whenever needed (for reCAPTCHA
126
+ version 1).
127
+
128
+ [View the full changelog](http://betterwp.net/wordpress-plugins/bwp-recaptcha/changelog/)
 
 
 
 
 
 
 
 
 
 
129
 
130
  == Upgrade Notice ==
131
 
132
+ Nothing here yet.
 
screenshot-1.png CHANGED
Binary file
screenshot-2.png CHANGED
Binary file
screenshot-3.png CHANGED
Binary file
screenshot-4.png CHANGED
Binary file
screenshot-5.png ADDED
Binary file
vendor/autoload.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload.php @generated by Composer
4
+
5
+ require_once __DIR__ . '/composer' . '/autoload_real.php';
6
+
7
+ return ComposerAutoloaderInit6c5bcb69668d113ca6adc94f79a95d73::getLoader();
vendor/composer/ClassLoader.php ADDED
@@ -0,0 +1,413 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Composer.
5
+ *
6
+ * (c) Nils Adermann <naderman@naderman.de>
7
+ * Jordi Boggiano <j.boggiano@seld.be>
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ namespace Composer\Autoload;
14
+
15
+ /**
16
+ * ClassLoader implements a PSR-0 class loader
17
+ *
18
+ * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
19
+ *
20
+ * $loader = new \Composer\Autoload\ClassLoader();
21
+ *
22
+ * // register classes with namespaces
23
+ * $loader->add('Symfony\Component', __DIR__.'/component');
24
+ * $loader->add('Symfony', __DIR__.'/framework');
25
+ *
26
+ * // activate the autoloader
27
+ * $loader->register();
28
+ *
29
+ * // to enable searching the include path (eg. for PEAR packages)
30
+ * $loader->setUseIncludePath(true);
31
+ *
32
+ * In this example, if you try to use a class in the Symfony\Component
33
+ * namespace or one of its children (Symfony\Component\Console for instance),
34
+ * the autoloader will first look for the class under the component/
35
+ * directory, and it will then fallback to the framework/ directory if not
36
+ * found before giving up.
37
+ *
38
+ * This class is loosely based on the Symfony UniversalClassLoader.
39
+ *
40
+ * @author Fabien Potencier <fabien@symfony.com>
41
+ * @author Jordi Boggiano <j.boggiano@seld.be>
42
+ */
43
+ class ClassLoader
44
+ {
45
+ // PSR-4
46
+ private $prefixLengthsPsr4 = array();
47
+ private $prefixDirsPsr4 = array();
48
+ private $fallbackDirsPsr4 = array();
49
+
50
+ // PSR-0
51
+ private $prefixesPsr0 = array();
52
+ private $fallbackDirsPsr0 = array();
53
+
54
+ private $useIncludePath = false;
55
+ private $classMap = array();
56
+
57
+ private $classMapAuthoritative = false;
58
+
59
+ public function getPrefixes()
60
+ {
61
+ if (!empty($this->prefixesPsr0)) {
62
+ return call_user_func_array('array_merge', $this->prefixesPsr0);
63
+ }
64
+
65
+ return array();
66
+ }
67
+
68
+ public function getPrefixesPsr4()
69
+ {
70
+ return $this->prefixDirsPsr4;
71
+ }
72
+
73
+ public function getFallbackDirs()
74
+ {
75
+ return $this->fallbackDirsPsr0;
76
+ }
77
+
78
+ public function getFallbackDirsPsr4()
79
+ {
80
+ return $this->fallbackDirsPsr4;
81
+ }
82
+
83
+ public function getClassMap()
84
+ {
85
+ return $this->classMap;
86
+ }
87
+
88
+ /**
89
+ * @param array $classMap Class to filename map
90
+ */
91
+ public function addClassMap(array $classMap)
92
+ {
93
+ if ($this->classMap) {
94
+ $this->classMap = array_merge($this->classMap, $classMap);
95
+ } else {
96
+ $this->classMap = $classMap;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Registers a set of PSR-0 directories for a given prefix, either
102
+ * appending or prepending to the ones previously set for this prefix.
103
+ *
104
+ * @param string $prefix The prefix
105
+ * @param array|string $paths The PSR-0 root directories
106
+ * @param bool $prepend Whether to prepend the directories
107
+ */
108
+ public function add($prefix, $paths, $prepend = false)
109
+ {
110
+ if (!$prefix) {
111
+ if ($prepend) {
112
+ $this->fallbackDirsPsr0 = array_merge(
113
+ (array) $paths,
114
+ $this->fallbackDirsPsr0
115
+ );
116
+ } else {
117
+ $this->fallbackDirsPsr0 = array_merge(
118
+ $this->fallbackDirsPsr0,
119
+ (array) $paths
120
+ );
121
+ }
122
+
123
+ return;
124
+ }
125
+
126
+ $first = $prefix[0];
127
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
128
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
129
+
130
+ return;
131
+ }
132
+ if ($prepend) {
133
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
134
+ (array) $paths,
135
+ $this->prefixesPsr0[$first][$prefix]
136
+ );
137
+ } else {
138
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
139
+ $this->prefixesPsr0[$first][$prefix],
140
+ (array) $paths
141
+ );
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Registers a set of PSR-4 directories for a given namespace, either
147
+ * appending or prepending to the ones previously set for this namespace.
148
+ *
149
+ * @param string $prefix The prefix/namespace, with trailing '\\'
150
+ * @param array|string $paths The PSR-0 base directories
151
+ * @param bool $prepend Whether to prepend the directories
152
+ *
153
+ * @throws \InvalidArgumentException
154
+ */
155
+ public function addPsr4($prefix, $paths, $prepend = false)
156
+ {
157
+ if (!$prefix) {
158
+ // Register directories for the root namespace.
159
+ if ($prepend) {
160
+ $this->fallbackDirsPsr4 = array_merge(
161
+ (array) $paths,
162
+ $this->fallbackDirsPsr4
163
+ );
164
+ } else {
165
+ $this->fallbackDirsPsr4 = array_merge(
166
+ $this->fallbackDirsPsr4,
167
+ (array) $paths
168
+ );
169
+ }
170
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
171
+ // Register directories for a new namespace.
172
+ $length = strlen($prefix);
173
+ if ('\\' !== $prefix[$length - 1]) {
174
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
175
+ }
176
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
177
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
178
+ } elseif ($prepend) {
179
+ // Prepend directories for an already registered namespace.
180
+ $this->prefixDirsPsr4[$prefix] = array_merge(
181
+ (array) $paths,
182
+ $this->prefixDirsPsr4[$prefix]
183
+ );
184
+ } else {
185
+ // Append directories for an already registered namespace.
186
+ $this->prefixDirsPsr4[$prefix] = array_merge(
187
+ $this->prefixDirsPsr4[$prefix],
188
+ (array) $paths
189
+ );
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Registers a set of PSR-0 directories for a given prefix,
195
+ * replacing any others previously set for this prefix.
196
+ *
197
+ * @param string $prefix The prefix
198
+ * @param array|string $paths The PSR-0 base directories
199
+ */
200
+ public function set($prefix, $paths)
201
+ {
202
+ if (!$prefix) {
203
+ $this->fallbackDirsPsr0 = (array) $paths;
204
+ } else {
205
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Registers a set of PSR-4 directories for a given namespace,
211
+ * replacing any others previously set for this namespace.
212
+ *
213
+ * @param string $prefix The prefix/namespace, with trailing '\\'
214
+ * @param array|string $paths The PSR-4 base directories
215
+ *
216
+ * @throws \InvalidArgumentException
217
+ */
218
+ public function setPsr4($prefix, $paths)
219
+ {
220
+ if (!$prefix) {
221
+ $this->fallbackDirsPsr4 = (array) $paths;
222
+ } else {
223
+ $length = strlen($prefix);
224
+ if ('\\' !== $prefix[$length - 1]) {
225
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
226
+ }
227
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
228
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Turns on searching the include path for class files.
234
+ *
235
+ * @param bool $useIncludePath
236
+ */
237
+ public function setUseIncludePath($useIncludePath)
238
+ {
239
+ $this->useIncludePath = $useIncludePath;
240
+ }
241
+
242
+ /**
243
+ * Can be used to check if the autoloader uses the include path to check
244
+ * for classes.
245
+ *
246
+ * @return bool
247
+ */
248
+ public function getUseIncludePath()
249
+ {
250
+ return $this->useIncludePath;
251
+ }
252
+
253
+ /**
254
+ * Turns off searching the prefix and fallback directories for classes
255
+ * that have not been registered with the class map.
256
+ *
257
+ * @param bool $classMapAuthoritative
258
+ */
259
+ public function setClassMapAuthoritative($classMapAuthoritative)
260
+ {
261
+ $this->classMapAuthoritative = $classMapAuthoritative;
262
+ }
263
+
264
+ /**
265
+ * Should class lookup fail if not found in the current class map?
266
+ *
267
+ * @return bool
268
+ */
269
+ public function isClassMapAuthoritative()
270
+ {
271
+ return $this->classMapAuthoritative;
272
+ }
273
+
274
+ /**
275
+ * Registers this instance as an autoloader.
276
+ *
277
+ * @param bool $prepend Whether to prepend the autoloader or not
278
+ */
279
+ public function register($prepend = false)
280
+ {
281
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
282
+ }
283
+
284
+ /**
285
+ * Unregisters this instance as an autoloader.
286
+ */
287
+ public function unregister()
288
+ {
289
+ spl_autoload_unregister(array($this, 'loadClass'));
290
+ }
291
+
292
+ /**
293
+ * Loads the given class or interface.
294
+ *
295
+ * @param string $class The name of the class
296
+ * @return bool|null True if loaded, null otherwise
297
+ */
298
+ public function loadClass($class)
299
+ {
300
+ if ($file = $this->findFile($class)) {
301
+ includeFile($file);
302
+
303
+ return true;
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Finds the path to the file where the class is defined.
309
+ *
310
+ * @param string $class The name of the class
311
+ *
312
+ * @return string|false The path if found, false otherwise
313
+ */
314
+ public function findFile($class)
315
+ {
316
+ // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
317
+ if ('\\' == $class[0]) {
318
+ $class = substr($class, 1);
319
+ }
320
+
321
+ // class map lookup
322
+ if (isset($this->classMap[$class])) {
323
+ return $this->classMap[$class];
324
+ }
325
+ if ($this->classMapAuthoritative) {
326
+ return false;
327
+ }
328
+
329
+ $file = $this->findFileWithExtension($class, '.php');
330
+
331
+ // Search for Hack files if we are running on HHVM
332
+ if ($file === null && defined('HHVM_VERSION')) {
333
+ $file = $this->findFileWithExtension($class, '.hh');
334
+ }
335
+
336
+ if ($file === null) {
337
+ // Remember that this class does not exist.
338
+ return $this->classMap[$class] = false;
339
+ }
340
+
341
+ return $file;
342
+ }
343
+
344
+ private function findFileWithExtension($class, $ext)
345
+ {
346
+ // PSR-4 lookup
347
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
348
+
349
+ $first = $class[0];
350
+ if (isset($this->prefixLengthsPsr4[$first])) {
351
+ foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
352
+ if (0 === strpos($class, $prefix)) {
353
+ foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
354
+ if (is_file($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
355
+ return $file;
356
+ }
357
+ }
358
+ }
359
+ }
360
+ }
361
+
362
+ // PSR-4 fallback dirs
363
+ foreach ($this->fallbackDirsPsr4 as $dir) {
364
+ if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
365
+ return $file;
366
+ }
367
+ }
368
+
369
+ // PSR-0 lookup
370
+ if (false !== $pos = strrpos($class, '\\')) {
371
+ // namespaced class name
372
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
373
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
374
+ } else {
375
+ // PEAR-like class name
376
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
377
+ }
378
+
379
+ if (isset($this->prefixesPsr0[$first])) {
380
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
381
+ if (0 === strpos($class, $prefix)) {
382
+ foreach ($dirs as $dir) {
383
+ if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
384
+ return $file;
385
+ }
386
+ }
387
+ }
388
+ }
389
+ }
390
+
391
+ // PSR-0 fallback dirs
392
+ foreach ($this->fallbackDirsPsr0 as $dir) {
393
+ if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
394
+ return $file;
395
+ }
396
+ }
397
+
398
+ // PSR-0 include paths.
399
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
400
+ return $file;
401
+ }
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Scope isolated include.
407
+ *
408
+ * Prevents access to $this/self from included files.
409
+ */
410
+ function includeFile($file)
411
+ {
412
+ include $file;
413
+ }
vendor/composer/autoload_classmap.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_classmap.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'BWP_FRAMEWORK_V2' => $vendorDir . '/kminh/bwp-framework/src/class-bwp-framework-v2.php',
10
+ 'BWP_OPTION_PAGE_V2' => $vendorDir . '/kminh/bwp-framework/src/bwp-option-page/includes/class-bwp-option-page-v2.php',
11
+ 'BWP_RECAPTCHA' => $baseDir . '/includes/class-bwp-recaptcha.php',
12
+ 'BWP_Recaptcha_CF7_Shortcode' => $baseDir . '/includes/addons/contact-form-7/captcha-shortcode.php',
13
+ 'BWP_Recaptcha_CF7_V1' => $baseDir . '/includes/addons/contact-form-7/v1.php',
14
+ 'BWP_Recaptcha_CF7_V2' => $baseDir . '/includes/addons/contact-form-7/v2.php',
15
+ 'BWP_Recaptcha_Provider' => $baseDir . '/includes/provider/abstract-provider.php',
16
+ 'BWP_Recaptcha_Provider_V1' => $baseDir . '/includes/provider/v1.php',
17
+ 'BWP_Recaptcha_Provider_V2' => $baseDir . '/includes/provider/v2.php',
18
+ 'BWP_VERSION' => $vendorDir . '/kminh/bwp-framework/src/class-bwp-version.php',
19
+ 'ReCaptchaResponse' => $baseDir . '/includes/provider/recaptcha/response.php',
20
+ );
vendor/composer/autoload_files.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_files.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ );
vendor/composer/autoload_namespaces.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_namespaces.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ );
vendor/composer/autoload_psr4.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_psr4.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'ReCaptcha\\' => array($vendorDir . '/google/recaptcha/src/ReCaptcha'),
10
+ );
vendor/composer/autoload_real.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_real.php @generated by Composer
4
+
5
+ class ComposerAutoloaderInit6c5bcb69668d113ca6adc94f79a95d73
6
+ {
7
+ private static $loader;
8
+
9
+ public static function loadClassLoader($class)
10
+ {
11
+ if ('Composer\Autoload\ClassLoader' === $class) {
12
+ require __DIR__ . '/ClassLoader.php';
13
+ }
14
+ }
15
+
16
+ public static function getLoader()
17
+ {
18
+ if (null !== self::$loader) {
19
+ return self::$loader;
20
+ }
21
+
22
+ spl_autoload_register(array('ComposerAutoloaderInit6c5bcb69668d113ca6adc94f79a95d73', 'loadClassLoader'), true, true);
23
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit6c5bcb69668d113ca6adc94f79a95d73', 'loadClassLoader'));
25
+
26
+ $map = require __DIR__ . '/autoload_namespaces.php';
27
+ foreach ($map as $namespace => $path) {
28
+ $loader->set($namespace, $path);
29
+ }
30
+
31
+ $map = require __DIR__ . '/autoload_psr4.php';
32
+ foreach ($map as $namespace => $path) {
33
+ $loader->setPsr4($namespace, $path);
34
+ }
35
+
36
+ $classMap = require __DIR__ . '/autoload_classmap.php';
37
+ if ($classMap) {
38
+ $loader->addClassMap($classMap);
39
+ }
40
+
41
+ $loader->register(true);
42
+
43
+ return $loader;
44
+ }
45
+ }
46
+
47
+ function composerRequire6c5bcb69668d113ca6adc94f79a95d73($file)
48
+ {
49
+ require $file;
50
+ }
vendor/composer/installed.json ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "name": "google/recaptcha",
4
+ "version": "1.1.1",
5
+ "version_normalized": "1.1.1.0",
6
+ "source": {
7
+ "type": "git",
8
+ "url": "https://github.com/google/recaptcha.git",
9
+ "reference": "090585935d95ebdf2d16dd071b10c9179a94da47"
10
+ },
11
+ "dist": {
12
+ "type": "zip",
13
+ "url": "https://api.github.com/repos/google/recaptcha/zipball/090585935d95ebdf2d16dd071b10c9179a94da47",
14
+ "reference": "090585935d95ebdf2d16dd071b10c9179a94da47",
15
+ "shasum": ""
16
+ },
17
+ "require": {
18
+ "php": ">=5.3.2"
19
+ },
20
+ "require-dev": {
21
+ "phpunit/phpunit": "4.5.*"
22
+ },
23
+ "time": "2015-03-16 13:45:08",
24
+ "type": "library",
25
+ "extra": {
26
+ "branch-alias": {
27
+ "dev-master": "1.1.x-dev"
28
+ }
29
+ },
30
+ "installation-source": "dist",
31
+ "autoload": {
32
+ "psr-4": {
33
+ "ReCaptcha\\": "src/ReCaptcha"
34
+ }
35
+ },
36
+ "notification-url": "https://packagist.org/downloads/",
37
+ "license": [
38
+ "BSD-3-Clause"
39
+ ],
40
+ "description": "Client library for reCAPTCHA, a free service that protect websites from spam and abuse.",
41
+ "homepage": "http://www.google.com/recaptcha/",
42
+ "keywords": [
43
+ "Abuse",
44
+ "captcha",
45
+ "recaptcha",
46
+ "spam"
47
+ ]
48
+ },
49
+ {
50
+ "name": "kminh/bwp-framework",
51
+ "version": "dev-master",
52
+ "version_normalized": "9999999-dev",
53
+ "source": {
54
+ "type": "git",
55
+ "url": "https://github.com/kminh/bwp-framework",
56
+ "reference": "e5a66731a92ed897188b55b94756694f0e9710b7"
57
+ },
58
+ "require": {
59
+ "php": "~5.1"
60
+ },
61
+ "time": "2015-08-16 08:27:08",
62
+ "type": "library",
63
+ "extra": {
64
+ "branch-alias": {
65
+ "dev-master": "1.0.x-dev"
66
+ }
67
+ },
68
+ "installation-source": "source",
69
+ "autoload": {
70
+ "classmap": [
71
+ "src/"
72
+ ]
73
+ },
74
+ "license": [
75
+ "GPLv3"
76
+ ],
77
+ "authors": [
78
+ {
79
+ "name": "Khang Minh",
80
+ "email": "kminhfoss@gmail.com"
81
+ }
82
+ ],
83
+ "description": "Base codes for BWP WordPress Plugins",
84
+ "homepage": "http://betterwp.net"
85
+ }
86
+ ]
vendor/google/recaptcha/CONTRIBUTING.md ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Want to contribute? Great! First, read this page (including the small print at the end).
2
+
3
+ ### Before you contribute
4
+ Before we can use your code, you must sign the
5
+ [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1)
6
+ (CLA), which you can do online. The CLA is necessary mainly because you own the
7
+ copyright to your changes, even after your contribution becomes part of our
8
+ codebase, so we need your permission to use and distribute your code. We also
9
+ need to be sure of various other things—for instance that you'll tell us if you
10
+ know that your code infringes on other people's patents. You don't have to sign
11
+ the CLA until after you've submitted your code for review and a member has
12
+ approved it, but you must do it before we can put your code into our codebase.
13
+ Before you start working on a larger contribution, you should get in touch with
14
+ us first through the issue tracker with your idea so that we can help out and
15
+ possibly guide you. Coordinating up front makes it much easier to avoid
16
+ frustration later on.
17
+
18
+ ### Code reviews
19
+ All submissions, including submissions by project members, require review. We
20
+ use Github pull requests for this purpose.
21
+
22
+ ### The small print
23
+ Contributions made by corporations are covered by a different agreement than
24
+ the one above, the Software Grant and Corporate Contributor License Agreement.
vendor/google/recaptcha/LICENSE ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright 2014, Google Inc.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are
6
+ met:
7
+
8
+ * Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+ * Redistributions in binary form must reproduce the above
11
+ copyright notice, this list of conditions and the following disclaimer
12
+ in the documentation and/or other materials provided with the
13
+ distribution.
14
+ * Neither the name of Google Inc. nor the names of its
15
+ contributors may be used to endorse or promote products derived from
16
+ this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
vendor/google/recaptcha/README.md ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # reCAPTCHA PHP client library
2
+
3
+ [![Build Status](https://travis-ci.org/google/recaptcha.svg)](https://travis-ci.org/google/recaptcha)
4
+ [![Latest Stable Version](https://poser.pugx.org/google/recaptcha/v/stable.svg)](https://packagist.org/packages/google/recaptcha)
5
+ [![Total Downloads](https://poser.pugx.org/google/recaptcha/downloads.svg)](https://packagist.org/packages/google/recaptcha)
6
+
7
+ * Project page: http://www.google.com/recaptcha/
8
+ * Repository: https://github.com/google/recaptcha
9
+ * Version: 1.1.0
10
+ * License: BSD, see [LICENSE](LICENSE)
11
+
12
+ ## Description
13
+
14
+ reCAPTCHA is a free CAPTCHA service that protect websites from spam and abuse.
15
+ This is Google authored code that provides plugins for third-party integration
16
+ with reCAPTCHA.
17
+
18
+ ## Installation
19
+
20
+ Use [Composer](https://getcomposer.org/) to install the library. Either use
21
+ `composer require google/recaptcha "~1.1"` or add the following to your
22
+ `composer.json`:
23
+ ```json
24
+ "require": {
25
+ "google/recaptcha": "~1.1"
26
+ }
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ First, register keys for your site at https://www.google.com/recaptcha/admin
32
+
33
+ When your app receives a form submission containing the `g-recaptcha-response`
34
+ field, you can verify it using:
35
+ ```php
36
+ <?php
37
+ $recaptcha = new \ReCaptcha\ReCaptcha($secret);
38
+ $resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp);
39
+ if ($resp->isSuccess()) {
40
+ // verified!
41
+ } else {
42
+ $errors = $resp->getErrorCodes();
43
+ }
44
+ ```
45
+
46
+ You can see an end-to-end working example in [examples/example-captcha.php](examples/example-captcha.php)
47
+
48
+ ## Upgrading
49
+
50
+ ### From 1.0.0
51
+
52
+ The previous version of this client is still available on the `1.0.0` tag
53
+ [in this repo](https://github.com/google/recaptcha/tree/1.0.0) but it is purely
54
+ for reference and will not receive any updates.
55
+
56
+ The major changes in 1.1.0 are:
57
+ * installation now via Composer;
58
+ * class loading also via Composer;
59
+ * classes now namespaced;
60
+ * old method call was `$rc->verifyResponse($remoteIp, $response)`, new call is `$rc->verify($response, $remoteIp)`
61
+
62
+ ## Contributing
63
+
64
+ We accept contributions via GitHub Pull Requests, but all contributors need to
65
+ be covered by the standard Google Contributor License Agreement. You can find
66
+ instructions for this in [CONTRIBUTING](CONTRIBUTING.md)
vendor/google/recaptcha/composer.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "google/recaptcha",
3
+ "description": "Client library for reCAPTCHA, a free service that protect websites from spam and abuse.",
4
+ "type": "library",
5
+ "keywords": ["recaptcha", "captcha", "spam", "abuse"],
6
+ "homepage": "http://www.google.com/recaptcha/",
7
+ "license": "BSD-3-Clause",
8
+ "support": {
9
+ "forum": "https://groups.google.com/forum/#!forum/recaptcha",
10
+ "source": "https://github.com/google/recaptcha"
11
+ },
12
+ "require": {
13
+ "php": ">=5.3.2"
14
+ },
15
+ "require-dev": {
16
+ "phpunit/phpunit": "4.5.*"
17
+ },
18
+ "autoload": {
19
+ "psr-4": {
20
+ "ReCaptcha\\": "src/ReCaptcha"
21
+ }
22
+ },
23
+ "extra": {
24
+ "branch-alias": {
25
+ "dev-master": "1.1.x-dev"
26
+ }
27
+ }
28
+ }
vendor/google/recaptcha/examples/example-captcha.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Working sample code to accompany the library. The instructions here assume
4
+ * you've just cloned the repo. If you've installed via composer, you will want
5
+ * to adjust the path to the autoloader.
6
+ *
7
+ * 1. Run the server. For example, under Linux you can probably use:
8
+ * /usr/bin/php -S "localhost:8000" "examples/example-captcha.php"
9
+ * 2. Point your browser at http://localhost:8000
10
+ * 3. Follow the instructions
11
+ *
12
+ * @copyright Copyright (c) 2015, Google Inc.
13
+ * @link http://www.google.com/recaptcha
14
+ *
15
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
16
+ * of this software and associated documentation files (the "Software"), to deal
17
+ * in the Software without restriction, including without limitation the rights
18
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
+ * copies of the Software, and to permit persons to whom the Software is
20
+ * furnished to do so, subject to the following conditions:
21
+ *
22
+ * The above copyright notice and this permission notice shall be included in
23
+ * all copies or substantial portions of the Software.
24
+ *
25
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31
+ * THE SOFTWARE.
32
+ */
33
+ // Initiate the autoloader.
34
+ require_once __DIR__ . '/../vendor/autoload.php';
35
+
36
+ // Register API keys at https://www.google.com/recaptcha/admin
37
+ $siteKey = '';
38
+ $secret = '';
39
+
40
+ // reCAPTCHA supported 40+ languages listed here: https://developers.google.com/recaptcha/docs/language
41
+ $lang = 'en';
42
+ ?>
43
+ <html>
44
+ <head>
45
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
46
+ <title>reCAPTCHA Example</title>
47
+ <link rel="shortcut icon" href="//www.gstatic.com/recaptcha/admin/favicon.ico" type="image/x-icon"/>
48
+ <style type="text/css">
49
+ body {
50
+ margin: 1em 5em 0 5em;
51
+ font-family: sans-serif;
52
+ }
53
+ fieldset {
54
+ display: inline;
55
+ padding: 1em;
56
+ }
57
+ </style>
58
+ </head>
59
+ <body>
60
+ <h1>reCAPTCHA Example</h1>
61
+ <?php if ($siteKey === '' || $secret === ''): ?>
62
+ <h2>Add your keys</h2>
63
+ <p>If you do not have keys already then visit <tt>
64
+ <a href = "https://www.google.com/recaptcha/admin">
65
+ https://www.google.com/recaptcha/admin</a></tt> to generate them.
66
+ Edit this file and set the respective keys in <tt>$siteKey</tt> and
67
+ <tt>$secret</tt>. Reload the page after this.</p>
68
+ <?php
69
+ elseif (isset($_POST['g-recaptcha-response'])):
70
+ // The POST data here is unfiltered because this is an example.
71
+ // In production, *always* sanitise and validate your input'
72
+ ?>
73
+ <h2><tt>POST</tt> data</h2>
74
+ <tt><pre><?php var_export($_POST); ?></pre></tt>
75
+ <?php
76
+ // If the form submission includes the "g-captcha-response" field
77
+ // Create an instance of the service using your secret
78
+ $recaptcha = new \ReCaptcha\ReCaptcha($secret);
79
+
80
+ // If file_get_contents() is locked down on your PHP installation to disallow
81
+ // its use with URLs, then you can use the alternative request method instead.
82
+ // This makes use of fsockopen() instead.
83
+ // $recaptcha = new \ReCaptcha\ReCaptcha($secret, new \ReCaptcha\RequestMethod\SocketPost());
84
+
85
+ // Make the call to verify the response and also pass the user's IP address
86
+ $resp = $recaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
87
+
88
+ if ($resp->isSuccess()):
89
+ // If the response is a success, that's it!
90
+ ?>
91
+ <h2>Success!</h2>
92
+ <p>That's it. Everything is working. Go integrate this into your real project.</p>
93
+ <p><a href="/">Try again</a></p>
94
+ <?php
95
+ else:
96
+ // If it's not successfull, then one or more error codes will be returned.
97
+ ?>
98
+ <h2>Something went wrong</h2>
99
+ <p>The following error was returned: <?php
100
+ foreach ($resp->getErrorCodes() as $code) {
101
+ echo '<tt>' . $code . '</tt> ';
102
+ }
103
+ ?></p>
104
+ <p>Check the error code reference at <tt><a href="https://developers.google.com/recaptcha/docs/verify#error-code-reference">https://developers.google.com/recaptcha/docs/verify#error-code-reference</a></tt>.
105
+ <p><strong>Note:</strong> Error code <tt>missing-input-response</tt> may mean the user just didn't complete the reCAPTCHA.</p>
106
+ <p><a href="/">Try again</a></p>
107
+ <?php
108
+ endif;
109
+ else:
110
+ // Add the g-recaptcha tag to the form you want to include the reCAPTCHA element
111
+ ?>
112
+ <p>Complete the reCAPTCHA then submit the form.</p>
113
+ <form action="/" method="post">
114
+ <fieldset>
115
+ <legend>An example form</legend>
116
+ <p>Example input A: <input type="text" name="ex-a" value="foo"></p>
117
+ <p>Example input B: <input type="text" name="ex-b" value="bar"></p>
118
+
119
+ <div class="g-recaptcha" data-sitekey="<?php echo $siteKey; ?>"></div>
120
+ <script type="text/javascript"
121
+ src="https://www.google.com/recaptcha/api.js?hl=<?php echo $lang; ?>">
122
+ </script>
123
+ <p><input type="submit" value="Submit" /></p>
124
+ </fieldset>
125
+ </form>
126
+ <?php endif; ?>
127
+ </body>
128
+ </html>
vendor/google/recaptcha/phpunit.xml.dist ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
+ xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.4/phpunit.xsd"
4
+ colors="true"
5
+ verbose="true">
6
+ <testsuites>
7
+ <testsuite name="reCAPTCHA Test Suite">
8
+ <directory>tests/ReCaptcha/</directory>
9
+ </testsuite>
10
+ </testsuites>
11
+ <filter>
12
+ <whitelist>
13
+ <directory suffix=".php">src/ReCaptcha/</directory>
14
+ </whitelist>
15
+ </filter>
16
+ </phpunit>
vendor/google/recaptcha/src/ReCaptcha/ReCaptcha.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a PHP library that handles calling reCAPTCHA.
4
+ *
5
+ * @copyright Copyright (c) 2015, Google Inc.
6
+ * @link http://www.google.com/recaptcha
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ namespace ReCaptcha;
28
+
29
+ /**
30
+ * reCAPTCHA client.
31
+ */
32
+ class ReCaptcha
33
+ {
34
+ /**
35
+ * Version of this client library.
36
+ * @const string
37
+ */
38
+ const VERSION = 'php_1.1.0';
39
+
40
+ /**
41
+ * Shared secret for the site.
42
+ * @var type string
43
+ */
44
+ private $secret;
45
+
46
+ /**
47
+ * Method used to communicate with service. Defaults to POST request.
48
+ * @var RequestMethod
49
+ */
50
+ private $requestMethod;
51
+
52
+ /**
53
+ * Create a configured instance to use the reCAPTCHA service.
54
+ *
55
+ * @param string $secret shared secret between site and reCAPTCHA server.
56
+ * @param RequestMethod $requestMethod method used to send the request. Defaults to POST.
57
+ */
58
+ public function __construct($secret, RequestMethod $requestMethod = null)
59
+ {
60
+ if (empty($secret)) {
61
+ throw new \RuntimeException('No secret provided');
62
+ }
63
+
64
+ if (!is_string($secret)) {
65
+ throw new \RuntimeException('The provided secret must be a string');
66
+ }
67
+
68
+ $this->secret = $secret;
69
+
70
+ if (!is_null($requestMethod)) {
71
+ $this->requestMethod = $requestMethod;
72
+ } else {
73
+ $this->requestMethod = new RequestMethod\Post();
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Calls the reCAPTCHA siteverify API to verify whether the user passes
79
+ * CAPTCHA test.
80
+ *
81
+ * @param string $response The value of 'g-recaptcha-response' in the submitted form.
82
+ * @param string $remoteIp The end user's IP address.
83
+ * @return Response Response from the service.
84
+ */
85
+ public function verify($response, $remoteIp = null)
86
+ {
87
+ // Discard empty solution submissions
88
+ if (empty($response)) {
89
+ $recaptchaResponse = new Response(false, array('missing-input-response'));
90
+ return $recaptchaResponse;
91
+ }
92
+
93
+ $params = new RequestParameters($this->secret, $response, $remoteIp, self::VERSION);
94
+ $rawResponse = $this->requestMethod->submit($params);
95
+ return Response::fromJson($rawResponse);
96
+ }
97
+ }
vendor/google/recaptcha/src/ReCaptcha/RequestMethod.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a PHP library that handles calling reCAPTCHA.
4
+ *
5
+ * @copyright Copyright (c) 2015, Google Inc.
6
+ * @link http://www.google.com/recaptcha
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ namespace ReCaptcha;
28
+
29
+ /**
30
+ * Method used to send the request to the service.
31
+ */
32
+ interface RequestMethod
33
+ {
34
+
35
+ /**
36
+ * Submit the request with the specified parameters.
37
+ *
38
+ * @param RequestParameters $params Request parameters
39
+ * @return string Body of the reCAPTCHA response
40
+ */
41
+ public function submit(RequestParameters $params);
42
+ }
vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Post.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a PHP library that handles calling reCAPTCHA.
4
+ *
5
+ * @copyright Copyright (c) 2015, Google Inc.
6
+ * @link http://www.google.com/recaptcha
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ namespace ReCaptcha\RequestMethod;
28
+
29
+ use ReCaptcha\RequestMethod;
30
+ use ReCaptcha\RequestParameters;
31
+
32
+ /**
33
+ * Sends POST requests to the reCAPTCHA service.
34
+ */
35
+ class Post implements RequestMethod
36
+ {
37
+ /**
38
+ * URL to which requests are POSTed.
39
+ * @const string
40
+ */
41
+ const SITE_VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify';
42
+
43
+ /**
44
+ * Submit the POST request with the specified parameters.
45
+ *
46
+ * @param RequestParameters $params Request parameters
47
+ * @return string Body of the reCAPTCHA response
48
+ */
49
+ public function submit(RequestParameters $params)
50
+ {
51
+ /**
52
+ * PHP 5.6.0 changed the way you specify the peer name for SSL context options.
53
+ * Using "CN_name" will still work, but it will raise deprecated errors.
54
+ */
55
+ $peer_key = version_compare(PHP_VERSION, '5.6.0', '<') ? 'CN_name' : 'peer_name';
56
+ $options = array(
57
+ 'http' => array(
58
+ 'header' => "Content-type: application/x-www-form-urlencoded\r\n",
59
+ 'method' => 'POST',
60
+ 'content' => $params->toQueryString(),
61
+ // Force the peer to validate (not needed in 5.6.0+, but still works
62
+ 'verify_peer' => true,
63
+ // Force the peer validation to use www.google.com
64
+ $peer_key => 'www.google.com',
65
+ ),
66
+ );
67
+ $context = stream_context_create($options);
68
+ return file_get_contents(self::SITE_VERIFY_URL, false, $context);
69
+ }
70
+ }
vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Socket.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a PHP library that handles calling reCAPTCHA.
4
+ *
5
+ * @copyright Copyright (c) 2015, Google Inc.
6
+ * @link http://www.google.com/recaptcha
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ namespace ReCaptcha\RequestMethod;
28
+
29
+ /**
30
+ * Convenience wrapper around native socket and file functions to allow for
31
+ * mocking.
32
+ */
33
+ class Socket
34
+ {
35
+ private $handle = null;
36
+
37
+ /**
38
+ * fsockopen
39
+ *
40
+ * @see http://php.net/fsockopen
41
+ * @param string $hostname
42
+ * @param int $port
43
+ * @param int $errno
44
+ * @param string $errstr
45
+ * @param float $timeout
46
+ * @return resource
47
+ */
48
+ public function fsockopen($hostname, $port = -1, &$errno = 0, &$errstr = '', $timeout = null)
49
+ {
50
+ $this->handle = fsockopen($hostname, $port, $errno, $errstr, (is_null($timeout) ? ini_get("default_socket_timeout") : $timeout));
51
+
52
+ if ($this->handle != false && $errno === 0 && $errstr === '') {
53
+ return $this->handle;
54
+ } else {
55
+ return false;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * fwrite
61
+ *
62
+ * @see http://php.net/fwrite
63
+ * @param string $string
64
+ * @param int $length
65
+ * @return int | bool
66
+ */
67
+ public function fwrite($string, $length = null)
68
+ {
69
+ return fwrite($this->handle, $string, (is_null($length) ? strlen($string) : $length));
70
+ }
71
+
72
+ /**
73
+ * fgets
74
+ *
75
+ * @see http://php.net/fgets
76
+ * @param int $length
77
+ */
78
+ public function fgets($length = null)
79
+ {
80
+ return fgets($this->handle, $length);
81
+ }
82
+
83
+ /**
84
+ * feof
85
+ *
86
+ * @see http://php.net/feof
87
+ * @return bool
88
+ */
89
+ public function feof()
90
+ {
91
+ return feof($this->handle);
92
+ }
93
+
94
+ /**
95
+ * fclose
96
+ *
97
+ * @see http://php.net/fclose
98
+ * @return bool
99
+ */
100
+ public function fclose()
101
+ {
102
+ return fclose($this->handle);
103
+ }
104
+ }
vendor/google/recaptcha/src/ReCaptcha/RequestMethod/SocketPost.php ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a PHP library that handles calling reCAPTCHA.
4
+ *
5
+ * @copyright Copyright (c) 2015, Google Inc.
6
+ * @link http://www.google.com/recaptcha
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ namespace ReCaptcha\RequestMethod;
28
+
29
+ use ReCaptcha\RequestMethod;
30
+ use ReCaptcha\RequestParameters;
31
+
32
+ /**
33
+ * Sends a POST request to the reCAPTCHA service, but makes use of fsockopen()
34
+ * instead of get_file_contents(). This is to account for people who may be on
35
+ * servers where allow_furl_open is disabled.
36
+ */
37
+ class SocketPost implements RequestMethod
38
+ {
39
+ /**
40
+ * reCAPTCHA service host.
41
+ * @const string
42
+ */
43
+ const RECAPTCHA_HOST = 'www.google.com';
44
+
45
+ /**
46
+ * @const string reCAPTCHA service path
47
+ */
48
+ const SITE_VERIFY_PATH = '/recaptcha/api/siteverify';
49
+
50
+ /**
51
+ * @const string Bad request error
52
+ */
53
+ const BAD_REQUEST = '{"success": false, "error-codes": ["invalid-request"]}';
54
+
55
+ /**
56
+ * @const string Bad response error
57
+ */
58
+ const BAD_RESPONSE = '{"success": false, "error-codes": ["invalid-response"]}';
59
+
60
+ /**
61
+ * Socket to the reCAPTCHA service
62
+ * @var Socket
63
+ */
64
+ private $socket;
65
+
66
+ /**
67
+ * Constructor
68
+ *
69
+ * @param \ReCaptcha\RequestMethod\Socket $socket optional socket, injectable for testing
70
+ */
71
+ public function __construct(Socket $socket = null)
72
+ {
73
+ if (!is_null($socket)) {
74
+ $this->socket = $socket;
75
+ } else {
76
+ $this->socket = new Socket();
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Submit the POST request with the specified parameters.
82
+ *
83
+ * @param RequestParameters $params Request parameters
84
+ * @return string Body of the reCAPTCHA response
85
+ */
86
+ public function submit(RequestParameters $params)
87
+ {
88
+ $errno = 0;
89
+ $errstr = '';
90
+
91
+ if ($this->socket->fsockopen('ssl://' . self::RECAPTCHA_HOST, 443, $errno, $errstr, 30) !== false) {
92
+ $content = $params->toQueryString();
93
+
94
+ $request = "POST " . self::SITE_VERIFY_PATH . " HTTP/1.1\r\n";
95
+ $request .= "Host: " . self::RECAPTCHA_HOST . "\r\n";
96
+ $request .= "Content-Type: application/x-www-form-urlencoded\r\n";
97
+ $request .= "Content-length: " . strlen($content) . "\r\n";
98
+ $request .= "Connection: close\r\n\r\n";
99
+ $request .= $content . "\r\n\r\n";
100
+
101
+ $this->socket->fwrite($request);
102
+ $response = '';
103
+
104
+ while (!$this->socket->feof()) {
105
+ $response .= $this->socket->fgets(4096);
106
+ }
107
+
108
+ $this->socket->fclose();
109
+
110
+ if (0 === strpos($response, 'HTTP/1.1 200 OK')) {
111
+ $parts = preg_split("#\n\s*\n#Uis", $response);
112
+ return $parts[1];
113
+ }
114
+
115
+ return self::BAD_RESPONSE;
116
+ }
117
+
118
+ return self::BAD_REQUEST;
119
+ }
120
+ }
vendor/google/recaptcha/src/ReCaptcha/RequestParameters.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a PHP library that handles calling reCAPTCHA.
4
+ *
5
+ * @copyright Copyright (c) 2015, Google Inc.
6
+ * @link http://www.google.com/recaptcha
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ namespace ReCaptcha;
28
+
29
+ /**
30
+ * Stores and formats the parameters for the request to the reCAPTCHA service.
31
+ */
32
+ class RequestParameters
33
+ {
34
+ /**
35
+ * Site secret.
36
+ * @var string
37
+ */
38
+ private $secret;
39
+
40
+ /**
41
+ * Form response.
42
+ * @var string
43
+ */
44
+ private $response;
45
+
46
+ /**
47
+ * Remote user's IP address.
48
+ * @var string
49
+ */
50
+ private $remoteIp;
51
+
52
+ /**
53
+ * Client version.
54
+ * @var string
55
+ */
56
+ private $version;
57
+
58
+ /**
59
+ * Initialise parameters.
60
+ *
61
+ * @param string $secret Site secret.
62
+ * @param string $response Value from g-captcha-response form field.
63
+ * @param string $remoteIp User's IP address.
64
+ * @param string $version Version of this client library.
65
+ */
66
+ public function __construct($secret, $response, $remoteIp = null, $version = null)
67
+ {
68
+ $this->secret = $secret;
69
+ $this->response = $response;
70
+ $this->remoteIp = $remoteIp;
71
+ $this->version = $version;
72
+ }
73
+
74
+ /**
75
+ * Array representation.
76
+ *
77
+ * @return array Array formatted parameters.
78
+ */
79
+ public function toArray()
80
+ {
81
+ $params = array('secret' => $this->secret, 'response' => $this->response);
82
+
83
+ if (!is_null($this->remoteIp)) {
84
+ $params['remoteip'] = $this->remoteIp;
85
+ }
86
+
87
+ if (!is_null($this->version)) {
88
+ $params['version'] = $this->version;
89
+ }
90
+
91
+ return $params;
92
+ }
93
+
94
+ /**
95
+ * Query string representation for HTTP request.
96
+ *
97
+ * @return string Query string formatted parameters.
98
+ */
99
+ public function toQueryString()
100
+ {
101
+ return http_build_query($this->toArray());
102
+ }
103
+ }
vendor/google/recaptcha/src/ReCaptcha/Response.php ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a PHP library that handles calling reCAPTCHA.
4
+ *
5
+ * @copyright Copyright (c) 2015, Google Inc.
6
+ * @link http://www.google.com/recaptcha
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ namespace ReCaptcha;
28
+
29
+ /**
30
+ * The response returned from the service.
31
+ */
32
+ class Response
33
+ {
34
+ /**
35
+ * Succes or failure.
36
+ * @var boolean
37
+ */
38
+ private $success = false;
39
+
40
+ /**
41
+ * Error code strings.
42
+ * @var array
43
+ */
44
+ private $errorCodes = array();
45
+
46
+ /**
47
+ * Build the response from the expected JSON returned by the service.
48
+ *
49
+ * @param string $json
50
+ * @return \ReCaptcha\Response
51
+ */
52
+ public static function fromJson($json)
53
+ {
54
+ $responseData = json_decode($json, true);
55
+
56
+ if (!$responseData) {
57
+ return new Response(false, array('invalid-json'));
58
+ }
59
+
60
+ if (isset($responseData['success']) && $responseData['success'] == true) {
61
+ return new Response(true);
62
+ }
63
+
64
+ if (isset($responseData['error-codes']) && is_array($responseData['error-codes'])) {
65
+ return new Response(false, $responseData['error-codes']);
66
+ }
67
+
68
+ return new Response(false);
69
+ }
70
+
71
+ /**
72
+ * Constructor.
73
+ *
74
+ * @param boolean $success
75
+ * @param array $errorCodes
76
+ */
77
+ public function __construct($success, array $errorCodes = array())
78
+ {
79
+ $this->success = $success;
80
+ $this->errorCodes = $errorCodes;
81
+ }
82
+
83
+ /**
84
+ * Is success?
85
+ *
86
+ * @return boolean
87
+ */
88
+ public function isSuccess()
89
+ {
90
+ return $this->success;
91
+ }
92
+
93
+ /**
94
+ * Get error codes.
95
+ *
96
+ * @return array
97
+ */
98
+ public function getErrorCodes()
99
+ {
100
+ return $this->errorCodes;
101
+ }
102
+ }
vendor/google/recaptcha/tests/ReCaptcha/ReCaptchaTest.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a PHP library that handles calling reCAPTCHA.
4
+ *
5
+ * @copyright Copyright (c) 2015, Google Inc.
6
+ * @link http://www.google.com/recaptcha
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ namespace ReCaptcha;
28
+
29
+ class ReCaptchaTest extends \PHPUnit_Framework_TestCase
30
+ {
31
+
32
+ /**
33
+ * @expectedException \RuntimeException
34
+ * @dataProvider invalidSecretProvider
35
+ */
36
+ public function testExceptionThrownOnInvalidSecret($invalid)
37
+ {
38
+ $rc = new ReCaptcha($invalid);
39
+ }
40
+
41
+ public function invalidSecretProvider()
42
+ {
43
+ return array(
44
+ array(''),
45
+ array(null),
46
+ array(0),
47
+ array(new \stdClass()),
48
+ array(array()),
49
+ );
50
+ }
51
+
52
+ public function testVerifyReturnsErrorOnMissingResponse()
53
+ {
54
+ $rc = new ReCaptcha('secret');
55
+ $response = $rc->verify('');
56
+ $this->assertFalse($response->isSuccess());
57
+ $this->assertEquals(array('missing-input-response'), $response->getErrorCodes());
58
+ }
59
+
60
+ public function testVerifyReturnsResponse()
61
+ {
62
+ $method = $this->getMock('\\ReCaptcha\\RequestMethod', array('submit'));
63
+ $method->expects($this->once())
64
+ ->method('submit')
65
+ ->with($this->callback(function ($params) {
66
+
67
+ return true;
68
+ }))
69
+ ->will($this->returnValue('{"success": true}'));
70
+ ;
71
+ $rc = new ReCaptcha('secret', $method);
72
+ $response = $rc->verify('response');
73
+ $this->assertTrue($response->isSuccess());
74
+ }
75
+ }
vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/PostTest.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a PHP library that handles calling reCAPTCHA.
4
+ *
5
+ * @copyright Copyright (c) 2015, Google Inc.
6
+ * @link http://www.google.com/recaptcha
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ namespace ReCaptcha\RequestMethod;
28
+
29
+ use ReCaptcha\RequestParameters;
30
+
31
+ class PostTest extends \PHPUnit_Framework_TestCase
32
+ {
33
+ public static $assert = null;
34
+ protected $parameters = null;
35
+ protected $runcount = 0;
36
+
37
+ public function setUp()
38
+ {
39
+ $this->parameters = new RequestParameters("secret", "response", "remoteip", "version");
40
+ }
41
+
42
+ public function tearDown()
43
+ {
44
+ self::$assert = null;
45
+ }
46
+
47
+ public function testHTTPContextOptions()
48
+ {
49
+ $req = new Post();
50
+ self::$assert = array($this, "httpContextOptionsCallback");
51
+ $req->submit($this->parameters);
52
+ $this->assertEquals(1, $this->runcount, "The assertion was ran");
53
+ }
54
+
55
+ public function testSSLContextOptions()
56
+ {
57
+ $req = new Post();
58
+ self::$assert = array($this, "sslContextOptionsCallback");
59
+ $req->submit($this->parameters);
60
+ $this->assertEquals(1, $this->runcount, "The assertion was ran");
61
+ }
62
+
63
+ public function httpContextOptionsCallback(array $args)
64
+ {
65
+ $this->runcount++;
66
+ $this->assertCommonOptions($args);
67
+
68
+ $options = stream_context_get_options($args[2]);
69
+ $this->assertArrayHasKey('http', $options);
70
+
71
+ $this->assertArrayHasKey('method', $options['http']);
72
+ $this->assertEquals("POST", $options['http']['method']);
73
+
74
+ $this->assertArrayHasKey('content', $options['http']);
75
+ $this->assertEquals($this->parameters->toQueryString(), $options['http']['content']);
76
+
77
+ $this->assertArrayHasKey('header', $options['http']);
78
+ $headers = array(
79
+ "Content-type: application/x-www-form-urlencoded",
80
+ );
81
+ foreach ($headers as $header) {
82
+ $this->assertContains($header, $options['http']['header']);
83
+ }
84
+ }
85
+
86
+ public function sslContextOptionsCallback(array $args)
87
+ {
88
+ $this->runcount++;
89
+ $this->assertCommonOptions($args);
90
+
91
+ $options = stream_context_get_options($args[2]);
92
+ $this->assertArrayHasKey('http', $options);
93
+ $this->assertArrayHasKey('verify_peer', $options['http']);
94
+ $this->assertTrue($options['http']['verify_peer']);
95
+
96
+ $key = version_compare(PHP_VERSION, "5.6.0", "<") ? "CN_name" : "peer_name";
97
+
98
+ $this->assertArrayHasKey($key, $options['http']);
99
+ $this->assertEquals("www.google.com", $options['http'][$key]);
100
+ }
101
+
102
+ protected function assertCommonOptions(array $args)
103
+ {
104
+ $this->assertCount(3, $args);
105
+ $this->assertStringStartsWith("https://www.google.com/", $args[0]);
106
+ $this->assertFalse($args[1]);
107
+ $this->assertTrue(is_resource($args[2]), "The context options should be a resource");
108
+ }
109
+ }
110
+
111
+ function file_get_contents()
112
+ {
113
+ if (PostTest::$assert) {
114
+ return call_user_func(PostTest::$assert, func_get_args());
115
+ }
116
+ // Since we can't represent maxlen in userland...
117
+ return call_user_func_array('file_get_contents', func_get_args());
118
+ }
vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/SocketPostTest.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a PHP library that handles calling reCAPTCHA.
4
+ *
5
+ * @copyright Copyright (c) 2015, Google Inc.
6
+ * @link http://www.google.com/recaptcha
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ namespace ReCaptcha\RequestMethod;
28
+
29
+ use ReCaptcha\RequestParameters;
30
+
31
+ class SocketPostTest extends \PHPUnit_Framework_TestCase
32
+ {
33
+
34
+ public function testSubmitSuccess()
35
+ {
36
+ $socket = $this->getMock('\\ReCaptcha\\RequestMethod\\Socket', array('fsockopen', 'fwrite', 'fgets', 'feof', 'fclose'));
37
+ $socket->expects($this->once())
38
+ ->method('fsockopen')
39
+ ->willReturn(true);
40
+ $socket->expects($this->once())
41
+ ->method('fwrite');
42
+ $socket->expects($this->once())
43
+ ->method('fgets')
44
+ ->willReturn("HTTP/1.1 200 OK\n\nRESPONSEBODY");
45
+ $socket->expects($this->exactly(2))
46
+ ->method('feof')
47
+ ->will($this->onConsecutiveCalls(false, true));
48
+ $socket->expects($this->once())
49
+ ->method('fclose')
50
+ ->willReturn(true);
51
+
52
+ $ps = new SocketPost($socket);
53
+ $response = $ps->submit(new RequestParameters("secret", "response", "remoteip", "version"));
54
+ $this->assertEquals('RESPONSEBODY', $response);
55
+ }
56
+
57
+ public function testSubmitBadResponse()
58
+ {
59
+ $socket = $this->getMock('\\ReCaptcha\\RequestMethod\\Socket', array('fsockopen', 'fwrite', 'fgets', 'feof', 'fclose'));
60
+ $socket->expects($this->once())
61
+ ->method('fsockopen')
62
+ ->willReturn(true);
63
+ $socket->expects($this->once())
64
+ ->method('fwrite');
65
+ $socket->expects($this->once())
66
+ ->method('fgets')
67
+ ->willReturn("HTTP/1.1 500 NOPEn\\nBOBBINS");
68
+ $socket->expects($this->exactly(2))
69
+ ->method('feof')
70
+ ->will($this->onConsecutiveCalls(false, true));
71
+ $socket->expects($this->once())
72
+ ->method('fclose')
73
+ ->willReturn(true);
74
+
75
+ $ps = new SocketPost($socket);
76
+ $response = $ps->submit(new RequestParameters("secret", "response", "remoteip", "version"));
77
+ $this->assertEquals(SocketPost::BAD_RESPONSE, $response);
78
+ }
79
+
80
+ public function testSubmitBadRequest()
81
+ {
82
+ $socket = $this->getMock('\\ReCaptcha\\RequestMethod\\Socket', array('fsockopen'));
83
+ $socket->expects($this->once())
84
+ ->method('fsockopen')
85
+ ->willReturn(false);
86
+ $ps = new SocketPost($socket);
87
+ $response = $ps->submit(new RequestParameters("secret", "response", "remoteip", "version"));
88
+ $this->assertEquals(SocketPost::BAD_REQUEST, $response);
89
+ }
90
+ }
vendor/google/recaptcha/tests/ReCaptcha/RequestParametersTest.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a PHP library that handles calling reCAPTCHA.
4
+ *
5
+ * @copyright Copyright (c) 2015, Google Inc.
6
+ * @link http://www.google.com/recaptcha
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ namespace ReCaptcha;
28
+
29
+ class RequestParametersTest extends \PHPUnit_Framework_TestCase
30
+ {
31
+
32
+ public function provideValidData()
33
+ {
34
+ return array(
35
+ array('SECRET', 'RESPONSE', 'REMOTEIP', 'VERSION',
36
+ array('secret' => 'SECRET', 'response' => 'RESPONSE', 'remoteip' => 'REMOTEIP', 'version' => 'VERSION'),
37
+ 'secret=SECRET&response=RESPONSE&remoteip=REMOTEIP&version=VERSION'),
38
+ array('SECRET', 'RESPONSE', null, null,
39
+ array('secret' => 'SECRET', 'response' => 'RESPONSE'),
40
+ 'secret=SECRET&response=RESPONSE'),
41
+ );
42
+ }
43
+
44
+ /**
45
+ * @dataProvider provideValidData
46
+ */
47
+ public function testToArray($secret, $response, $remoteIp, $version, $expectedArray, $expectedQuery)
48
+ {
49
+ $params = new RequestParameters($secret, $response, $remoteIp, $version);
50
+ $this->assertEquals($params->toArray(), $expectedArray);
51
+ }
52
+
53
+ /**
54
+ * @dataProvider provideValidData
55
+ */
56
+ public function testToQueryString($secret, $response, $remoteIp, $version, $expectedArray, $expectedQuery)
57
+ {
58
+ $params = new RequestParameters($secret, $response, $remoteIp, $version);
59
+ $this->assertEquals($params->toQueryString(), $expectedQuery);
60
+ }
61
+ }
vendor/google/recaptcha/tests/ReCaptcha/ResponseTest.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a PHP library that handles calling reCAPTCHA.
4
+ *
5
+ * @copyright Copyright (c) 2015, Google Inc.
6
+ * @link http://www.google.com/recaptcha
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ namespace ReCaptcha;
28
+
29
+ class ResponseTest extends \PHPUnit_Framework_TestCase
30
+ {
31
+
32
+ /**
33
+ * @dataProvider provideJson
34
+ */
35
+ public function testFromJson($json, $success, $errorCodes)
36
+ {
37
+ $response = Response::fromJson($json);
38
+ $this->assertEquals($success, $response->isSuccess());
39
+ $this->assertEquals($errorCodes, $response->getErrorCodes());
40
+ }
41
+
42
+ public function provideJson()
43
+ {
44
+ return array(
45
+ array('{"success": true}', true, array()),
46
+ array('{"success": false, "error-codes": ["test"]}', false, array('test')),
47
+ array('{"success": true, "error-codes": ["test"]}', true, array()),
48
+ array('{"success": false}', false, array()),
49
+ array('BAD JSON', false, array('invalid-json')),
50
+ );
51
+ }
52
+
53
+ public function testIsSuccess()
54
+ {
55
+ $response = new Response(true);
56
+ $this->assertTrue($response->isSuccess());
57
+
58
+ $response = new Response(false);
59
+ $this->assertFalse($response->isSuccess());
60
+ }
61
+
62
+ public function testGetErrorCodes()
63
+ {
64
+ $errorCodes = array('test');
65
+ $response = new Response(true, $errorCodes);
66
+ $this->assertEquals($errorCodes, $response->getErrorCodes());
67
+ }
68
+ }
vendor/kminh/bwp-framework/composer.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "kminh/bwp-framework",
3
+ "description": "Base codes for BWP WordPress Plugins",
4
+ "homepage": "http://betterwp.net",
5
+ "license": "GPLv3",
6
+ "authors": [
7
+ {
8
+ "name": "Khang Minh",
9
+ "email": "contact@betterwp.net"
10
+ }
11
+ ],
12
+ "require": {
13
+ "php": "~5.1"
14
+ },
15
+ "autoload": {
16
+ "classmap": [
17
+ "src/"
18
+ ]
19
+ },
20
+ "extra": {
21
+ "branch-alias": {
22
+ "dev-master": "1.0.x-dev"
23
+ }
24
+ }
25
+ }
{includes/bwp-option-page → vendor/kminh/bwp-framework}/css/bwp-option-page.css RENAMED
@@ -48,7 +48,7 @@ h2 .nav-tab{padding:6px 15px 6px;}
48
  }
49
 
50
  .bwp-option-page p.submit {
51
- clear: both;
52
  padding-top: 1.5em;
53
  }
54
 
@@ -73,7 +73,7 @@ h2 .nav-tab{padding:6px 15px 6px;}
73
  display: block;
74
  float: left;
75
  width: 200px;
76
- margin: 3px 0 1em 0;
77
  }
78
 
79
  .type-checkbox {
@@ -85,7 +85,7 @@ p.bwp-option-page-inputs {
85
  padding: 0;
86
  }
87
 
88
- .bwp-option-page-inputs input {
89
  margin: 0 0 5px 0;
90
  }
91
 
@@ -94,7 +94,7 @@ p.bwp-option-page-inputs {
94
  }
95
 
96
  .bwp-option-page-inputs select {
97
- margin: 1px 0 0 0;
98
  }
99
 
100
  .bwp-option-page-inputs input[type="checkbox"] {
48
  }
49
 
50
  .bwp-option-page p.submit {
51
+ /* clear: both; */
52
  padding-top: 1.5em;
53
  }
54
 
73
  display: block;
74
  float: left;
75
  width: 200px;
76
+ margin: 5px 0 1em 0;
77
  }
78
 
79
  .type-checkbox {
85
  padding: 0;
86
  }
87
 
88
+ .bwp-option-page-inputs input[type="text"], .bwp-option-page-inputs select {
89
  margin: 0 0 5px 0;
90
  }
91
 
94
  }
95
 
96
  .bwp-option-page-inputs select {
97
+ /* margin: 1px 0 0 0; */
98
  }
99
 
100
  .bwp-option-page-inputs input[type="checkbox"] {
vendor/kminh/bwp-framework/images/ad_lt_250x250.png ADDED
Binary file
{includes/bwp-option-page → vendor/kminh/bwp-framework}/images/icon-paypal.gif RENAMED
File without changes
{includes/bwp-option-page → vendor/kminh/bwp-framework}/images/icon-rss.png RENAMED
File without changes
{includes/bwp-option-page → vendor/kminh/bwp-framework}/images/icon-twitter.png RENAMED
File without changes
{includes/bwp-option-page → vendor/kminh/bwp-framework}/js/paypal.js RENAMED
File without changes
includes/bwp-option-page/includes/class-bwp-option-page.php → vendor/kminh/bwp-framework/src/bwp-option-page/includes/class-bwp-option-page-v2.php RENAMED
@@ -1,510 +1,725 @@
1
- <?php
2
- /**
3
- * Copyright (c) 2014 Khang Minh <betterwp.net>
4
- * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER
5
- */
6
-
7
- class BWP_OPTION_PAGE {
8
-
9
- /**
10
- * The form
11
- */
12
- var $form;
13
-
14
- /**
15
- * The form name
16
- */
17
- var $form_name;
18
-
19
- /**
20
- * Tabs to build
21
- */
22
- var $form_tabs;
23
-
24
- /**
25
- * Current tab
26
- */
27
- var $current_tab;
28
-
29
- /**
30
- * This holds the form items, determining the position
31
- */
32
- var $form_items = array();
33
-
34
- /**
35
- * This holds the name for each items (an item can have more than one fields)
36
- */
37
- var $form_item_names = array();
38
-
39
- /**
40
- * This holds the form label
41
- */
42
- var $form_item_labels = array();
43
-
44
- /**
45
- * This holds the form option aka data
46
- */
47
- var $form_options = array(), $site_options = array();
48
-
49
- /**
50
- * Other things
51
- */
52
- var $domain;
53
-
54
- /**
55
- * Constructor
56
- */
57
- function __construct($form_name = 'bwp_option_page', $site_options = array(), $domain = '')
58
- {
59
- $this->form_name = $form_name;
60
- $this->site_options = $site_options;
61
- $this->domain = $domain;
62
- }
63
-
64
- /**
65
- * Init the class
66
- *
67
- * @param array $form The form array that contains everything we need to build the form
68
- * @param array $options The data array that contains all data fetched from db or by default
69
- * @param string $form_name The name of the form, change this if you have more than one forms on a page
70
- */
71
- function init($form = array(), $options = array(), $form_tabs = array())
72
- {
73
- $this->form_items = $form['items'];
74
- $this->form_item_names = $form['item_names'];
75
- $this->form_item_labels = $form['item_labels'];
76
- $this->form = $form;
77
- $this->form_options = $options;
78
- $this->form_tabs = $form_tabs;
79
- if (sizeof($this->form_tabs) == 0)
80
- $this->form_tabs = array(__('Plugin Configurations', 'bwp-option-page'));
81
- }
82
-
83
- function get_form_name()
84
- {
85
- return $this->form_name;
86
- }
87
-
88
- function set_current_tab($current_tab = 0)
89
- {
90
- $this->current_tab = $current_tab;
91
- }
92
-
93
- function get_options($options = array(), $options_default = array())
94
- {
95
- foreach ($options_default as $key => $option)
96
- {
97
- if (!in_array($key, $options))
98
- unset($options_default[$key]);
99
- }
100
- return $options_default;
101
- }
102
-
103
- function get_db_options($name = '', $options = array())
104
- {
105
- $db_options = get_option($name);
106
- if (!$db_options)
107
- update_option($name, $options);
108
- else if (array_keys($options) != array_keys($db_options))
109
- {
110
- foreach ($db_options as $key => $data)
111
- if (isset($options[$key]) && !in_array($key, $this->site_options))
112
- $options[$key] = $data;
113
- update_option($name, $options);
114
- }
115
- else
116
- {
117
- foreach ($db_options as $key => $data)
118
- if (!in_array($key, $this->site_options))
119
- $options[$key] = $data;
120
- }
121
-
122
- return $options;
123
- }
124
-
125
- function format_field($key, $option_formats)
126
- {
127
- if (!empty($option_formats[$key]))
128
- {
129
- if ('int' == $option_formats[$key])
130
- $_POST[$key] = (int) $_POST[$key];
131
- else if ('float' == $option_formats[$key])
132
- $_POST[$key] = (float) $_POST[$key];
133
- else if ('html' == $option_formats[$key])
134
- $_POST[$key] = wp_filter_post_kses($_POST[$key]);
135
- }
136
- else
137
- $_POST[$key] = strip_tags($_POST[$key]);
138
- }
139
-
140
- function kill_html_fields(&$form = array(), $ids)
141
- {
142
- $ids = (array) $ids;
143
- $in_keys = array('items', 'item_labels', 'item_names');
144
- foreach ($ids as $id)
145
- {
146
- foreach ($in_keys as $key)
147
- unset($form[$key][$id]);
148
- }
149
- }
150
-
151
- /**
152
- * Generate HTML field
153
- *
154
- * @params they explain themselves
155
- */
156
- function generate_html_field($type = '', $data = array(), $name = '', $in_section = false)
157
- {
158
- $pre_html_field = '';
159
- $post_html_field = '';
160
- $checked = 'checked="checked" ';
161
- $selected = 'selected="selected" ';
162
-
163
- $value = isset($this->form_options[$name])
164
- ? $this->form_options[$name]
165
- : '';
166
-
167
- $value = !empty($this->domain)
168
- && ('textarea' == $type || 'input' == $type)
169
- ? __($value, $this->domain)
170
- : $value;
171
-
172
- if (is_array($value))
173
- {
174
- foreach ($value as &$v)
175
- $v = is_array($v) ? array_map('esc_attr', $v) : esc_attr($v);
176
- }
177
- else
178
- {
179
- $value = 'textarea' == $type
180
- ? esc_html($value)
181
- : esc_attr($value);
182
- }
183
-
184
- $array_replace = array();
185
- $array_search = array('size', 'name', 'value', 'cols',
186
- 'rows', 'label', 'disabled', 'pre', 'post');
187
- $return_html = '';
188
-
189
- $br = isset($this->form['inline_fields'][$name])
190
- && is_array($this->form['inline_fields'][$name])
191
- ? ''
192
- : "<br />\n";
193
-
194
- $pre = !empty($data['pre']) ? $data['pre'] : '';
195
- $post = !empty($data['post']) ? $data['post'] : '';
196
-
197
- $param = empty($this->form['params'][$name])
198
- ? false : $this->form['params'][$name];
199
-
200
- switch ($type)
201
- {
202
- case 'heading':
203
- $html_field = '%s';
204
- break;
205
-
206
- case 'input':
207
- $html_field = (!$in_section) ? '%pre%<input%disabled% size="%size%" type="text" id="' . $name . '" name="' . $name . '" value="' . $value . '" /> <em>%label%</em>' : '<label for="' . $name . '">%pre%<input%disabled% size="%size%" type="text" id="' . $name . '" name="' . $name . '" value="' . $value . '" /> <em>%label%</em></label>';
208
- break;
209
-
210
- case 'select':
211
- case 'select_multi':
212
- $pre_html_field = 'select_multi' == $type
213
- ? '%pre%<select id="' . $name . '" name="' . $name . '[]" multiple>' . "\n"
214
- : '%pre%<select id="' . $name . '" name="' . $name . '">' . "\n";
215
- $html_field = '<option %selected%value="%value%" />%option%</option>';
216
- $post_html_field = '</select>%post%' . $br;
217
- break;
218
-
219
- case 'checkbox':
220
- $html_field = '<label for="%name%">' . '<input %checked%type="checkbox" id="%name%" name="%name%" value="yes" /> %label%</label>';
221
- break;
222
-
223
- case 'checkbox_multi':
224
- $html_field = '<label for="%name%-%value%">' . '<input %checked%type="checkbox" id="%name%-%value%" name="%name%[]" value="%value%" /> %label%</label>';
225
- break;
226
-
227
- case 'radio':
228
- $html_field = '<label>' . '<input %checked%type="radio" name="' . $name . '" value="%value%" /> %label%</label>'; break;
229
-
230
- case 'textarea':
231
- $html_field = '%pre%<textarea%disabled% id="' . $name . '" name="' . $name . '" cols="%cols%" rows="%rows%">' . $value . '</textarea>%post%';
232
- break;
233
- }
234
-
235
- if (!isset($data))
236
- return;
237
-
238
- if ($type == 'heading' && !is_array($data))
239
- {
240
- $return_html .= sprintf($html_field, $data) . $br;
241
- }
242
- else if ($type == 'radio'
243
- || $type == 'checkbox' || $type == 'checkbox_multi'
244
- || $type == 'select' || $type == 'select_multi'
245
- ) {
246
- foreach ($data as $key => $value)
247
- {
248
- if ($type == 'checkbox')
249
- {
250
- // handle checkbox a little bit differently
251
- if ($this->form_options[$value] == 'yes')
252
- {
253
- $return_html .= str_replace(
254
- array('%value%', '%name%', '%label%', '%checked%'),
255
- array($value, $value, $key, $checked),
256
- $html_field
257
- );
258
-
259
- $return_html .= apply_filters('bwp_option_after_' . $type . '_' . $name . '_checked', '', $value, $param);
260
- $return_html .= $br;
261
- }
262
- else
263
- {
264
- $return_html .= str_replace(
265
- array('%value%', '%name%', '%label%', '%checked%'),
266
- array($value, $value, $key, ''),
267
- $html_field
268
- );
269
-
270
- $return_html .= apply_filters('bwp_option_after_' . $type . '_' . $name, '', $value, $param);
271
- $return_html .= $br;
272
- }
273
- }
274
- else if ($type == 'checkbox_multi')
275
- {
276
- // handle a multi checkbox differently
277
- if (isset($this->form_options[$name])
278
- && is_array($this->form_options[$name])
279
- && (in_array($value, $this->form_options[$name])
280
- || array_key_exists($value, $this->form_options[$name]))
281
- ) {
282
- $return_html .= str_replace(
283
- array('%value%', '%name%', '%label%', '%checked%'),
284
- array($value, $name, $key, $checked),
285
- $html_field
286
- );
287
-
288
- $return_html .= apply_filters('bwp_option_after_' . $type . '_' . $name . '_checked', '', $value, $param);
289
- $return_html .= $br;
290
- }
291
- else
292
- {
293
- $return_html .= str_replace(
294
- array('%value%', '%name%', '%label%', '%checked%'),
295
- array($value, $name, $key, ''),
296
- $html_field
297
- );
298
-
299
- $return_html .= apply_filters('bwp_option_after_' . $type . '_' . $name, '', $value, $param);
300
- $return_html .= $br;
301
- }
302
- }
303
- else if (isset($this->form_options[$name])
304
- && ($this->form_options[$name] == $value
305
- || (is_array($this->form_options[$name])
306
- && (in_array($value, $this->form_options[$name])
307
- || array_key_exists($value, $this->form_options[$name]))))
308
- ) {
309
- $return_html .= str_replace(
310
- array('%value%', '%name%', '%label%', '%option%', '%checked%', '%selected%', '%pre%', '%post%'),
311
- array($value, $value, $key, $key, $checked, $selected, $pre, $post),
312
- $html_field
313
- ) . $br;
314
- }
315
- else
316
- $return_html .= str_replace(
317
- array('%value%', '%name%', '%label%', '%option%', '%checked%', '%selected%', '%pre%', '%post%'),
318
- array($value, $value, $key, $key, '', '', $pre, $post),
319
- $html_field
320
- ) . $br;
321
- }
322
- }
323
- else
324
- {
325
- foreach ($array_search as &$keyword)
326
- {
327
- $array_replace[$keyword] = '';
328
- if (!empty($data[$keyword]))
329
- {
330
- $array_replace[$keyword] = $data[$keyword];
331
- }
332
- $keyword = '%' . $keyword . '%';
333
- }
334
- $return_html = str_replace($array_search, $array_replace, $html_field) . $br;
335
- }
336
-
337
- // inline fields
338
- $inline_html = '';
339
- if (isset($this->form['inline_fields'][$name]) && is_array($this->form['inline_fields'][$name]))
340
- {
341
- foreach ($this->form['inline_fields'][$name] as $field => $field_type)
342
- {
343
- if (isset($this->form[$field_type][$field]))
344
- $inline_html = ' ' . $this->generate_html_field($field_type, $this->form[$field_type][$field], $field, $in_section);
345
- }
346
- }
347
-
348
- // Post
349
- $post = (!empty($this->form['post'][$name])) ? ' ' . $this->form['post'][$name] : $post;
350
-
351
- return str_replace('%pre%', $pre, $pre_html_field) . $return_html . str_replace('%post%', $post, $post_html_field) . $inline_html;
352
- }
353
-
354
- /**
355
- * Generate HTML fields
356
- *
357
- * @params they explain themselves
358
- */
359
- function generate_html_fields($type, $name)
360
- {
361
- $item_label = '';
362
- $return_html = '';
363
-
364
- $item_key = array_keys($this->form_item_names, $name);
365
-
366
- $input_class = ($type == 'heading') ? 'bwp-option-page-heading-desc' : 'bwp-option-page-inputs';
367
-
368
- // An inline item can hold any HTML markup
369
- // An example is to display some kinds of button right be low the label
370
- $inline = '';
371
- if (isset($this->form['inline']) && is_array($this->form['inline']) && array_key_exists($name, $this->form['inline']))
372
- {
373
- $inline = (empty($this->form['inline'][$name])) ? '' : $this->form['inline'][$name];
374
- }
375
- $inline .= "\n";
376
-
377
- switch ($type)
378
- {
379
- case 'section':
380
- if (!isset($this->form[$name]) || !is_array($this->form[$name]))
381
- return;
382
-
383
- $item_label = '<span class="bwp-opton-page-label">' . $this->form_item_labels[$item_key[0]] . $inline . '</span>';
384
-
385
- foreach ($this->form[$name] as $section_field)
386
- {
387
- $type = $section_field[0];
388
- $name = $section_field['name'];
389
-
390
- if (isset($this->form[$section_field[0]]))
391
- {
392
- $return_html .= $this->generate_html_field($section_field[0], $this->form[$type][$name], $name, true);
393
- }
394
- }
395
- break;
396
-
397
- default:
398
- if (!isset($this->form[$type][$name])
399
- || ($type != 'heading' && !is_array($this->form[$type][$name])))
400
- return;
401
-
402
- $item_label = $type != 'checkbox' && $type != 'checkbox_multi' && $type != 'radio'
403
- ? '<label class="bwp-opton-page-label" for="' . $name . '">'
404
- . $this->form_item_labels[$item_key[0]] . $inline
405
- . '</label>'
406
- : '<span class="bwp-opton-page-label type-' . $type . '">'
407
- . $this->form_item_labels[$item_key[0]] . $inline
408
- . '</span>';
409
- $item_label = $type == 'heading'
410
- ? '<h3>' . $this->form_item_labels[$item_key[0]] . '</h3>' . $inline
411
- : $item_label;
412
-
413
- if (isset($this->form[$type]))
414
- $return_html = $this->generate_html_field($type, $this->form[$type][$name], $name);
415
- break;
416
- }
417
-
418
- // A container can hold some result executed by customized script,
419
- // such as displaying something when user press the submit button
420
- $containers = '';
421
- if (isset($this->form['container'])
422
- && is_array($this->form['container'])
423
- && array_key_exists($name, $this->form['container'])
424
- ) {
425
- $container_array = (array) $this->form['container'][$name];
426
- foreach ($container_array as $container)
427
- $containers .= empty($container)
428
- ? '<div style="display: none;"><!-- --></div>'
429
- : '<div class="bwp-clear">' . $container . '</div>' . "\n";
430
- }
431
-
432
- $pure_return = trim(strip_tags($return_html));
433
- if (empty($pure_return) && $type == 'heading')
434
- return $item_label . $containers;
435
- else
436
- return $item_label . '<p class="' . $input_class . '">'
437
- . $return_html . '</p>'
438
- . $containers;
439
- }
440
-
441
- /**
442
- * Generate HTML form
443
- *
444
- * @see Constructor
445
- */
446
- function generate_html_form()
447
- {
448
- $return_str = '<div class="wrap" style="padding-bottom: 20px;">' . "\n";
449
- if (sizeof($this->form_tabs) >= 2)
450
- $return_str .= apply_filters('bwp-admin-form-icon', '<div class="icon32" id="icon-options-general"><br></div>' . "\n");
451
- else
452
- $return_str .= '<div class="icon32" id="icon-options-general"><br></div>';
453
-
454
- if (sizeof($this->form_tabs) >= 2)
455
- {
456
- $count = 0;
457
- $return_str .= '<h2 class="bwp-option-page-tabs">' . "\n";
458
- $return_str .= apply_filters('bwp-admin-plugin-version', '') . "\n";
459
- foreach ($this->form_tabs as $title => $link)
460
- {
461
- $count++;
462
- $active = ($count == $this->current_tab) ? ' nav-tab-active' : '';
463
- $return_str .= '<a class="nav-tab' . $active . '" href="' . $link . '">' . $title . '</a>' . "\n";
464
- }
465
- $return_str .= '</h2>' . "\n";
466
- }
467
- else if (!isset($this->form_tabs[0]))
468
- {
469
- $title = array_keys($this->form_tabs);
470
- $return_str .= '<h2>' . $title[0] . '</h2>' . "\n";
471
- }
472
- else
473
- $return_str .= '<h2>' . $this->form_tabs[0] . '</h2>' . "\n";
474
-
475
- $return_str .= apply_filters('bwp_option_before_form', '');
476
- echo $return_str;
477
- do_action('bwp_option_action_before_form');
478
- $return_str = '';
479
- $return_str .= '<form class="bwp-option-page" name="' . $this->form_name . '" method="post" action="">' . "\n";
480
- if (function_exists('wp_nonce_field'))
481
- {
482
- echo $return_str;
483
- wp_nonce_field($this->form_name);
484
- $return_str = '';
485
- }
486
- $return_str .= '<ul>' . "\n";
487
-
488
- // generate filled form
489
- if (isset($this->form_items) && is_array($this->form_items))
490
- foreach ($this->form_items as $key => $type)
491
- {
492
- if (!empty($this->form_item_names[$key]) && !empty($this->form_item_labels[$key]))
493
- {
494
- $return_str .= '<li class="bwp-clear">' . $this->generate_html_fields($type, $this->form_item_names[$key]) . '</li>' . "\n";
495
- }
496
- }
497
-
498
- $return_str .= '</ul>' . "\n";
499
- $return_str .= apply_filters('bwp_option_before_submit_button', '');
500
- echo $return_str;
501
- do_action('bwp_option_action_before_submit_button');
502
- $return_str = '';
503
- $return_str .= apply_filters('bwp_option_submit_button', '<p class="submit"><input type="submit" class="button-primary" name="submit_' . $this->form_name . '" value="' . __('Save Changes') . '" /></p>') . "\n";
504
- $return_str .= '</form>' . "\n";
505
- $return_str .= '</div>' . "\n";
506
-
507
- echo $return_str;
508
- }
509
-
510
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2015 Khang Minh <contact@betterwp.net>
4
+ * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER
5
+ */
6
+
7
+ class BWP_OPTION_PAGE_V2
8
+ {
9
+ /**
10
+ * The plugin that initializes this option page instance
11
+ *
12
+ * @var BWP_FRAMEWORK_V2
13
+ */
14
+ public $plugin;
15
+
16
+ /**
17
+ * The form
18
+ */
19
+ public $form;
20
+
21
+ /**
22
+ * The form name
23
+ */
24
+ public $form_name;
25
+
26
+ /**
27
+ * Tabs to build
28
+ */
29
+ public $form_tabs;
30
+
31
+ /**
32
+ * Current tab
33
+ */
34
+ public $current_tab;
35
+
36
+ /**
37
+ * This holds the form items, determining the position
38
+ */
39
+ public $form_items = array();
40
+
41
+ /**
42
+ * This holds the name for each items (an item can have more than one fields)
43
+ */
44
+ public $form_item_names = array();
45
+
46
+ /**
47
+ * This holds the form label
48
+ */
49
+ public $form_item_labels = array();
50
+
51
+ /**
52
+ * This holds the form option aka data
53
+ */
54
+ public $form_options = array();
55
+ public $site_options = array();
56
+
57
+ /**
58
+ * Text domain
59
+ */
60
+ public $domain;
61
+
62
+ /**
63
+ * Constructor
64
+ */
65
+ public function __construct($form_name = 'bwp_option_page', BWP_FRAMEWORK_V2 $plugin)
66
+ {
67
+ $this->form_name = $form_name;
68
+ $this->site_options = $plugin->site_options;
69
+ $this->domain = $plugin->domain;
70
+
71
+ $this->plugin = $plugin;
72
+ }
73
+
74
+ /**
75
+ * Init the class
76
+ *
77
+ * @param array $form form data to build the form for the current option page
78
+ * @param array $form_option_keys contains all option keys that should be handled by the current option page form
79
+ */
80
+ public function init($form = array(), $form_option_keys = array())
81
+ {
82
+ $this->form_items = $form['items'];
83
+ $this->form_item_names = $form['item_names'];
84
+ $this->form_item_labels = $form['item_labels'];
85
+ $this->form = $form;
86
+ $this->form_options = $this->plugin->get_options_by_keys($form_option_keys);
87
+ $this->form_tabs = $this->plugin->form_tabs;
88
+
89
+ $this->form['formats'] = isset($this->form['formats'])
90
+ ? $this->form['formats']
91
+ : array();
92
+
93
+ if (sizeof($this->form_tabs) == 0)
94
+ $this->form_tabs = array(__('Plugin Configurations', 'bwp-option-page'));
95
+ }
96
+
97
+ public function get_form_name()
98
+ {
99
+ return $this->form_name;
100
+ }
101
+
102
+ public function set_current_tab($current_tab = 0)
103
+ {
104
+ $this->current_tab = $current_tab;
105
+ }
106
+
107
+ public function get_options($options = array(), $options_default = array())
108
+ {
109
+ foreach ($options_default as $key => $option)
110
+ {
111
+ if (!in_array($key, $options))
112
+ unset($options_default[$key]);
113
+ }
114
+
115
+ return $options_default;
116
+ }
117
+
118
+ public function get_db_options($name = '', $options = array())
119
+ {
120
+ $db_options = get_option($name);
121
+
122
+ if (!$db_options)
123
+ {
124
+ update_option($name, $options);
125
+ }
126
+ else if (array_keys($options) != array_keys($db_options))
127
+ {
128
+ foreach ($db_options as $key => $data)
129
+ if (isset($options[$key]) && !in_array($key, $this->site_options))
130
+ $options[$key] = $data;
131
+
132
+ update_option($name, $options);
133
+ }
134
+ else
135
+ {
136
+ foreach ($db_options as $key => $data)
137
+ {
138
+ if (!in_array($key, $this->site_options))
139
+ $options[$key] = $data;
140
+ }
141
+ }
142
+
143
+ return $options;
144
+ }
145
+
146
+ public function format_field($key)
147
+ {
148
+ $option_formats = $this->form['formats'];
149
+
150
+ if (!empty($option_formats[$key]))
151
+ {
152
+ if ('int' == $option_formats[$key])
153
+ $_POST[$key] = (int) $_POST[$key];
154
+ else if ('float' == $option_formats[$key])
155
+ $_POST[$key] = (float) $_POST[$key];
156
+ else if ('html' == $option_formats[$key])
157
+ $_POST[$key] = wp_filter_post_kses($_POST[$key]);
158
+ }
159
+ else
160
+ $_POST[$key] = strip_tags($_POST[$key]);
161
+ }
162
+
163
+ public function kill_html_fields(&$form, $names)
164
+ {
165
+ $ids = array();
166
+ $names = (array) $names;
167
+
168
+ foreach ($form['item_names'] as $key => $name)
169
+ {
170
+ if (in_array($name, $names))
171
+ $ids[] = $key;
172
+ }
173
+
174
+ $in_keys = array(
175
+ 'items',
176
+ 'item_labels',
177
+ 'item_names'
178
+ );
179
+
180
+ foreach ($ids as $id)
181
+ {
182
+ foreach ($in_keys as $key)
183
+ unset($form[$key][$id]);
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Generate HTML field
189
+ */
190
+ public function generate_html_field($type = '', $data = array(), $name = '', $in_section = false)
191
+ {
192
+ $pre_html_field = '';
193
+ $post_html_field = '';
194
+
195
+ $checked = 'checked="checked" ';
196
+ $selected = 'selected="selected" ';
197
+
198
+ $value = isset($this->form_options[$name])
199
+ ? $this->form_options[$name]
200
+ : '';
201
+
202
+ $value = isset($data['value']) ? $data['value'] : $value;
203
+
204
+ $value = !empty($this->domain)
205
+ && ('textarea' == $type || 'input' == $type)
206
+ ? __($value, $this->domain)
207
+ : $value;
208
+
209
+ if (is_array($value))
210
+ {
211
+ foreach ($value as &$v)
212
+ $v = is_array($v) ? array_map('esc_attr', $v) : esc_attr($v);
213
+ }
214
+ else
215
+ {
216
+ $value = 'textarea' == $type
217
+ ? esc_html($value)
218
+ : esc_attr($value);
219
+ }
220
+
221
+ $array_replace = array();
222
+ $array_search = array(
223
+ 'size',
224
+ 'name',
225
+ 'value',
226
+ 'cols',
227
+ 'rows',
228
+ 'label',
229
+ 'disabled',
230
+ 'pre',
231
+ 'post'
232
+ );
233
+
234
+ $return_html = '';
235
+
236
+ $br = isset($this->form['inline_fields'][$name])
237
+ && is_array($this->form['inline_fields'][$name])
238
+ ? ''
239
+ : "<br />\n";
240
+
241
+ $pre = !empty($data['pre']) ? $data['pre'] : '';
242
+ $post = !empty($data['post']) ? $data['post'] : '';
243
+
244
+ $param = empty($this->form['params'][$name])
245
+ ? false : $this->form['params'][$name];
246
+
247
+ switch ($type)
248
+ {
249
+ case 'heading':
250
+ $html_field = '%s';
251
+ break;
252
+
253
+ case 'input':
254
+ $html_field = !$in_section
255
+ ? '%pre%<input%disabled% size="%size%" type="text" '
256
+ . 'id="' . $name . '" '
257
+ . 'name="' . $name . '" '
258
+ . 'value="' . $value . '" /> <em>%label%</em>'
259
+ : '<label for="' . $name . '">%pre%<input%disabled% size="%size%" type="text" '
260
+ . 'id="' . $name . '" '
261
+ . 'name="' . $name . '" '
262
+ . 'value="' . $value . '" /> <em>%label%</em></label>';
263
+ break;
264
+
265
+ case 'select':
266
+ case 'select_multi':
267
+ $pre_html_field = 'select_multi' == $type
268
+ ? '%pre%<select id="' . $name . '" name="' . $name . '[]" multiple>' . "\n"
269
+ : '%pre%<select id="' . $name . '" name="' . $name . '">' . "\n";
270
+
271
+ $html_field = '<option %selected%value="%value%">%option%</option>';
272
+
273
+ $post_html_field = '</select>%post%' . $br;
274
+ break;
275
+
276
+ case 'checkbox':
277
+ $html_field = '<label for="%name%">'
278
+ . '<input %checked%type="checkbox" id="%name%" name="%name%" value="yes" /> %label%</label>';
279
+ break;
280
+
281
+ case 'checkbox_multi':
282
+ $html_field = '<label for="%name%-%value%">'
283
+ . '<input %checked%type="checkbox" id="%name%-%value%" name="%name%[]" value="%value%" /> %label%</label>';
284
+ break;
285
+
286
+ case 'radio':
287
+ $html_field = '<label>' . '<input %checked%type="radio" '
288
+ . 'name="' . $name . '" value="%value%" /> %label%</label>';
289
+ break;
290
+
291
+ case 'textarea':
292
+ $html_field = '%pre%<textarea%disabled% '
293
+ . 'id="' . $name . '" '
294
+ . 'name="' . $name . '" cols="%cols%" rows="%rows%">'
295
+ . $value . '</textarea>%post%';
296
+ break;
297
+ }
298
+
299
+ if (!isset($data))
300
+ return;
301
+
302
+ if ($type == 'heading' && !is_array($data))
303
+ {
304
+ $return_html .= sprintf($html_field, $data) . $br;
305
+ }
306
+ else if ($type == 'radio'
307
+ || $type == 'checkbox' || $type == 'checkbox_multi'
308
+ || $type == 'select' || $type == 'select_multi'
309
+ ) {
310
+ foreach ($data as $key => $value)
311
+ {
312
+ if ($type == 'checkbox')
313
+ {
314
+ // handle checkbox a little bit differently
315
+ if ($this->form_options[$value] == 'yes')
316
+ {
317
+ $return_html .= str_replace(
318
+ array('%value%', '%name%', '%label%', '%checked%'),
319
+ array($value, $value, $key, $checked),
320
+ $html_field
321
+ );
322
+
323
+ $return_html .= apply_filters('bwp_option_after_' . $type . '_' . $name . '_checked', '', $value, $param);
324
+ $return_html .= $br;
325
+ }
326
+ else
327
+ {
328
+ $return_html .= str_replace(
329
+ array('%value%', '%name%', '%label%', '%checked%'),
330
+ array($value, $value, $key, ''),
331
+ $html_field
332
+ );
333
+
334
+ $return_html .= apply_filters('bwp_option_after_' . $type . '_' . $name, '', $value, $param);
335
+ $return_html .= $br;
336
+ }
337
+ }
338
+ else if ($type == 'checkbox_multi')
339
+ {
340
+ // handle a multi checkbox differently
341
+ if (isset($this->form_options[$name])
342
+ && is_array($this->form_options[$name])
343
+ && (in_array($value, $this->form_options[$name])
344
+ || array_key_exists($value, $this->form_options[$name]))
345
+ ) {
346
+ $return_html .= str_replace(
347
+ array('%value%', '%name%', '%label%', '%checked%'),
348
+ array($value, $name, $key, $checked),
349
+ $html_field
350
+ );
351
+
352
+ $return_html .= apply_filters('bwp_option_after_' . $type . '_' . $name . '_checked', '', $value, $param);
353
+ $return_html .= $br;
354
+ }
355
+ else
356
+ {
357
+ $return_html .= str_replace(
358
+ array('%value%', '%name%', '%label%', '%checked%'),
359
+ array($value, $name, $key, ''),
360
+ $html_field
361
+ );
362
+
363
+ $return_html .= apply_filters('bwp_option_after_' . $type . '_' . $name, '', $value, $param);
364
+ $return_html .= $br;
365
+ }
366
+ }
367
+ else if (isset($this->form_options[$name])
368
+ && ($this->form_options[$name] == $value
369
+ || (is_array($this->form_options[$name])
370
+ && (in_array($value, $this->form_options[$name])
371
+ || array_key_exists($value, $this->form_options[$name]))))
372
+ ) {
373
+ $item_br = $type == 'select' || $type == 'select_multi' ? "\n" : $br;
374
+
375
+ $return_html .= str_replace(
376
+ array('%value%', '%name%', '%label%', '%option%', '%checked%', '%selected%', '%pre%', '%post%'),
377
+ array($value, $value, $key, $key, $checked, $selected, $pre, $post),
378
+ $html_field
379
+ ) . $item_br;
380
+ }
381
+ else
382
+ {
383
+ $item_br = $type == 'select' || $type == 'select_multi' ? "\n" : $br;
384
+
385
+ $return_html .= str_replace(
386
+ array('%value%', '%name%', '%label%', '%option%', '%checked%', '%selected%', '%pre%', '%post%'),
387
+ array($value, $value, $key, $key, '', '', $pre, $post),
388
+ $html_field
389
+ ) . $item_br;
390
+ }
391
+ }
392
+ }
393
+ else
394
+ {
395
+ foreach ($array_search as &$keyword)
396
+ {
397
+ $array_replace[$keyword] = '';
398
+
399
+ if (!empty($data[$keyword]))
400
+ {
401
+ $array_replace[$keyword] = $data[$keyword];
402
+ }
403
+
404
+ $keyword = '%' . $keyword . '%';
405
+ }
406
+
407
+ $return_html = str_replace($array_search, $array_replace, $html_field) . $br;
408
+ }
409
+
410
+ // inline fields
411
+ $inline_html = '';
412
+ if (isset($this->form['inline_fields'][$name]) && is_array($this->form['inline_fields'][$name]))
413
+ {
414
+ foreach ($this->form['inline_fields'][$name] as $field => $field_type)
415
+ {
416
+ if (isset($this->form[$field_type][$field]))
417
+ $inline_html = ' ' . $this->generate_html_field($field_type, $this->form[$field_type][$field], $field, $in_section);
418
+ }
419
+ }
420
+
421
+ // html after field
422
+ $post = !empty($this->form['post'][$name])
423
+ ? ' ' . $this->form['post'][$name]
424
+ : $post;
425
+
426
+ return str_replace('%pre%', $pre, $pre_html_field) . $return_html . str_replace('%post%', $post, $post_html_field) . $inline_html;
427
+ }
428
+
429
+ /**
430
+ * Generate HTML fields
431
+ *
432
+ * @params they explain themselves
433
+ */
434
+ public function generate_html_fields($type, $name)
435
+ {
436
+ $item_label = '';
437
+ $return_html = '';
438
+
439
+ $item_key = array_keys($this->form_item_names, $name);
440
+
441
+ $input_class = $type == 'heading'
442
+ ? 'bwp-option-page-heading-desc'
443
+ : 'bwp-option-page-inputs';
444
+
445
+ // an inline item can hold any HTML markup, example is to display some
446
+ // kinds of button right be low the label
447
+ $inline = '';
448
+
449
+ if (isset($this->form['inline']) && is_array($this->form['inline'])
450
+ && array_key_exists($name, $this->form['inline'])
451
+ ) {
452
+ $inline = empty($this->form['inline'][$name]) ? '' : $this->form['inline'][$name];
453
+ }
454
+
455
+ $inline .= "\n";
456
+
457
+ switch ($type)
458
+ {
459
+ case 'section':
460
+ if (!isset($this->form[$name]) || !is_array($this->form[$name]))
461
+ return;
462
+
463
+ $item_label = '<span class="bwp-opton-page-label">'
464
+ . $this->form_item_labels[$item_key[0]]
465
+ . $inline
466
+ . '</span>';
467
+
468
+ foreach ($this->form[$name] as $section_field)
469
+ {
470
+ $type = $section_field[0];
471
+ $name = $section_field['name'];
472
+
473
+ if (isset($this->form[$section_field[0]]))
474
+ {
475
+ $return_html .= $this->generate_html_field($section_field[0], $this->form[$type][$name], $name, true);
476
+ }
477
+ }
478
+ break;
479
+
480
+ default:
481
+ if (!isset($this->form[$type][$name])
482
+ || ($type != 'heading' && !is_array($this->form[$type][$name])))
483
+ return;
484
+
485
+ $item_label = $type != 'checkbox' && $type != 'checkbox_multi' && $type != 'radio'
486
+ ? '<label class="bwp-opton-page-label" for="' . $name . '">'
487
+ . $this->form_item_labels[$item_key[0]] . $inline
488
+ . '</label>'
489
+ : '<span class="bwp-opton-page-label type-' . $type . '">'
490
+ . $this->form_item_labels[$item_key[0]] . $inline
491
+ . '</span>';
492
+
493
+ $item_label = $type == 'heading'
494
+ ? '<h3>' . $this->form_item_labels[$item_key[0]] . '</h3>' . $inline
495
+ : $item_label;
496
+
497
+ if (isset($this->form[$type]))
498
+ $return_html = $this->generate_html_field($type, $this->form[$type][$name], $name);
499
+ break;
500
+ }
501
+
502
+ // a container can hold some result executed by customized script,
503
+ // such as displaying something when user press the submit button
504
+ $containers = '';
505
+
506
+ if (isset($this->form['container'])
507
+ && is_array($this->form['container'])
508
+ && array_key_exists($name, $this->form['container'])
509
+ ) {
510
+ $container_array = (array) $this->form['container'][$name];
511
+
512
+ foreach ($container_array as $container)
513
+ {
514
+ $containers .= empty($container)
515
+ ? '<div style="display: none;"><!-- --></div>'
516
+ : '<div class="bwp-clear">' . $container . '</div>' . "\n";
517
+ }
518
+ }
519
+
520
+ $pure_return = trim(strip_tags($return_html));
521
+
522
+ if (empty($pure_return) && $type == 'heading')
523
+ {
524
+ return $item_label . $containers;
525
+ }
526
+ else
527
+ {
528
+ return $item_label . '<p class="' . $input_class . '">'
529
+ . $return_html . '</p>'
530
+ . $containers;
531
+ }
532
+ }
533
+
534
+ /**
535
+ * Generate HTML form
536
+ *
537
+ * @see Constructor
538
+ */
539
+ public function generate_html_form()
540
+ {
541
+ $return_str = '<div class="wrap" style="padding-bottom: 20px;">' . "\n";
542
+
543
+ if (sizeof($this->form_tabs) >= 2)
544
+ $return_str .= apply_filters('bwp-admin-form-icon', '<div class="icon32" id="icon-options-general"><br></div>' . "\n");
545
+ else
546
+ $return_str .= '<div class="icon32" id="icon-options-general"><br></div>';
547
+
548
+ if (sizeof($this->form_tabs) >= 2)
549
+ {
550
+ $count = 0;
551
+
552
+ $return_str .= '<h2 class="bwp-option-page-tabs">' . "\n";
553
+ $return_str .= apply_filters('bwp-admin-plugin-version', '') . "\n";
554
+
555
+ foreach ($this->form_tabs as $title => $link)
556
+ {
557
+ $count++;
558
+
559
+ $active = $count == $this->current_tab ? ' nav-tab-active' : '';
560
+ $return_str .= '<a class="nav-tab' . $active . '" href="' . $link . '">' . $title . '</a>' . "\n";
561
+ }
562
+
563
+ $return_str .= '</h2>' . "\n";
564
+ }
565
+ else if (!isset($this->form_tabs[0]))
566
+ {
567
+ $title = array_keys($this->form_tabs);
568
+ $return_str .= '<h2>' . $title[0] . '</h2>' . "\n";
569
+ }
570
+ else
571
+ $return_str .= '<h2>' . $this->form_tabs[0] . '</h2>' . "\n";
572
+
573
+ $return_str .= apply_filters('bwp_option_before_form', '');
574
+ echo $return_str;
575
+
576
+ do_action('bwp_option_action_before_form');
577
+
578
+ $return_str = '';
579
+ $return_str .= '<form class="bwp-option-page" name="' . $this->form_name . '" method="post" action="">' . "\n";
580
+
581
+ if (function_exists('wp_nonce_field'))
582
+ {
583
+ echo $return_str;
584
+
585
+ wp_nonce_field($this->form_name);
586
+
587
+ $return_str = '';
588
+ }
589
+
590
+ $return_str .= '<ul>' . "\n";
591
+
592
+ // generate filled form
593
+ if (isset($this->form_items) && is_array($this->form_items))
594
+ {
595
+ foreach ($this->form_items as $key => $type)
596
+ {
597
+ $name = !empty($this->form_item_names[$key])
598
+ ? $this->form_item_names[$key]
599
+ : '';
600
+
601
+ // this form item should not be shown
602
+ if ($this->is_form_item_hidden($name)) {
603
+ continue;
604
+ }
605
+
606
+ if (!empty($name) && !empty($this->form_item_labels[$key])
607
+ ) {
608
+ $return_str .= '<li class="bwp-clear">'
609
+ . $this->generate_html_fields($type, $name)
610
+ . '</li>'
611
+ . "\n";
612
+ }
613
+ }
614
+ }
615
+
616
+ $return_str .= '</ul>' . "\n";
617
+ $return_str .= apply_filters('bwp_option_before_submit_button', '');
618
+
619
+ echo $return_str;
620
+ do_action('bwp_option_action_before_submit_button');
621
+
622
+ $return_str = '';
623
+ $return_str .= apply_filters('bwp_option_submit_button',
624
+ '<p class="submit"><input type="submit" class="button-primary" name="submit_'
625
+ . $this->form_name . '" value="' . __('Save Changes') . '" /></p>') . "\n";
626
+
627
+ $return_str .= '</form>' . "\n";
628
+ $return_str .= '</div>' . "\n";
629
+
630
+ echo $return_str;
631
+ }
632
+
633
+ public function submit_html_form()
634
+ {
635
+ // basic security check
636
+ check_admin_referer($this->form_name);
637
+
638
+ $options = $this->form_options;
639
+ $option_formats = $this->form['formats'];
640
+
641
+ foreach ($options as $name => &$option)
642
+ {
643
+ // if this form item is hidden, it should not be handled here
644
+ if ($this->is_form_item_hidden($name)) {
645
+ continue;
646
+ }
647
+
648
+ if (isset($_POST[$name]))
649
+ {
650
+ // make sure options are in expected formats
651
+ $this->format_field($name);
652
+ $option = trim(stripslashes($_POST[$name]));
653
+ }
654
+
655
+ if (!isset($_POST[$name])
656
+ && !isset($this->form['input'][$name]['disabled'])
657
+ ) {
658
+ // checkbox, exclude disabled input
659
+ $option = '';
660
+ }
661
+ elseif (isset($option_formats[$name])
662
+ && 'int' == $option_formats[$name]
663
+ && ('' === $_POST[$name] || 0 > $_POST[$name])
664
+ ) {
665
+ // expect integer but received empty string or negative
666
+ // integer, revert to default value
667
+ $option = $this->plugin->options_default[$name];
668
+ }
669
+ }
670
+
671
+ // update per-blog options
672
+ update_option($this->form_name, $options);
673
+
674
+ // Update site options if is super admin and is on main blog
675
+ if (!BWP_FRAMEWORK_V2::is_normal_admin() && BWP_FRAMEWORK_V2::is_on_main_blog())
676
+ update_site_option($this->form_name, $options);
677
+
678
+ // refresh the options for the form as well as the plugin's options
679
+ $this->form_options = array_merge($this->form_options, $options);
680
+ $this->plugin->options = array_merge($this->plugin->options, $options);
681
+
682
+ return true;
683
+ }
684
+
685
+ protected function is_form_item_hidden($name)
686
+ {
687
+ if (isset($this->form['env'])
688
+ && !BWP_FRAMEWORK_V2::is_multisite()
689
+ && array_key_exists($name, $this->form['env'])
690
+ && $this->form['env'][$name] == 'multisite')
691
+ {
692
+ // hide multisite field if not in multisite environment
693
+ return true;
694
+ }
695
+
696
+ if (isset($this->form['blog'])
697
+ && BWP_FRAMEWORK_V2::is_multisite()
698
+ && array_key_exists($name, $this->form['blog'])
699
+ ) {
700
+ global $blog_id;
701
+
702
+ if ($this->form['blog'][$name] == 'main' && $blog_id > 1)
703
+ {
704
+ // this field should be on main blog only
705
+ return true;
706
+ }
707
+ elseif ($this->form['blog'][$name] == 'sub' && $blog_id == 1)
708
+ {
709
+ // this field should be on sub blogs only
710
+ return true;
711
+ }
712
+ }
713
+
714
+ if (isset($this->form['role'])
715
+ && BWP_FRAMEWORK_V2::is_normal_admin()
716
+ && array_key_exists($name, $this->form['role'])
717
+ && $this->form['role'][$name] == 'superadmin')
718
+ {
719
+ // hide superadmin-only fields if user is normal admin
720
+ return true;
721
+ }
722
+
723
+ return false;
724
+ }
725
+ }
{includes → vendor/kminh/bwp-framework/src}/bwp-option-page/includes/index.php RENAMED
File without changes
{includes → vendor/kminh/bwp-framework/src}/bwp-option-page/index.php RENAMED
File without changes
includes/class-bwp-framework-improved.php → vendor/kminh/bwp-framework/src/class-bwp-framework-v2.php RENAMED
@@ -1,727 +1,870 @@
1
- <?php
2
- /**
3
- * Copyright (c) 2014 Khang Minh <betterwp.net>
4
- * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER
5
- */
6
-
7
- class BWP_FRAMEWORK_IMPROVED {
8
-
9
- /**
10
- * Database related data
11
- */
12
- var $options = array();
13
-
14
- /**
15
- * Default data
16
- */
17
- var $options_default = array(), $site_options = array();
18
-
19
- /**
20
- * Hold db option keys
21
- */
22
- var $option_keys = array();
23
-
24
- /**
25
- * Hold extra option keys
26
- */
27
- var $extra_option_keys = array();
28
-
29
- /**
30
- * Hold old option pages
31
- */
32
- var $option_pages = array();
33
-
34
- /**
35
- * Key to identify plugin
36
- */
37
- var $plugin_key;
38
-
39
- /**
40
- * Constant Key to identify plugin
41
- */
42
- var $plugin_ckey;
43
-
44
- /**
45
- * Domain Key to identify plugin
46
- */
47
- var $plugin_dkey;
48
-
49
- /**
50
- * Title of the plugin
51
- */
52
- var $plugin_title;
53
-
54
- /**
55
- * Homepage of the plugin
56
- */
57
- var $plugin_url;
58
-
59
- /**
60
- * Urls to various parts of homepage or other places
61
- *
62
- * Expect to have a format of array('relative' => bool, 'url' => url)
63
- */
64
- var $urls = array();
65
-
66
- /**
67
- * Plugin file
68
- */
69
- var $plugin_file;
70
-
71
- /**
72
- * Plugin folder
73
- */
74
- var $plugin_folder;
75
-
76
- /**
77
- * Plugin WP url
78
- */
79
- var $plugin_wp_url;
80
-
81
- /**
82
- * Version of the plugin
83
- */
84
- var $plugin_ver = '';
85
-
86
- /**
87
- * Message shown to user (Warning, Notes, etc.)
88
- */
89
- var $notices = array(), $notice_shown = false;
90
-
91
- /**
92
- * Error shown to user
93
- */
94
- var $errors = array(), $error_shown = false;
95
-
96
- /**
97
- * Capabilities to manage this plugin
98
- */
99
- var $plugin_cap = 'manage_options';
100
-
101
- /**
102
- * Whether or not to create filter for media paths
103
- */
104
- var $need_media_filters;
105
-
106
- /**
107
- * Form tabs to build
108
- */
109
- var $form_tabs = array();
110
-
111
- /**
112
- * Other things
113
- */
114
- var $wp_ver = '3.0';
115
- var $php_ver = '5';
116
- var $domain = '';
117
-
118
- /**
119
- * Other special variables
120
- */
121
- protected $_menu_under_settings = false;
122
- protected $_simple_menu = false;
123
-
124
- /**
125
- * Build base properties
126
- */
127
- protected function build_properties($key, $dkey, $options, $plugin_title = '',
128
- $plugin_file = '', $plugin_url = '', $need_media_filters = true)
129
- {
130
- $this->plugin_key = strtolower($key);
131
- $this->plugin_ckey = strtoupper($key);
132
- $this->plugin_dkey = $dkey;
133
- $this->plugin_title = $plugin_title;
134
- $this->plugin_url = $plugin_url;
135
-
136
- $this->options_default = $options;
137
- $this->need_media_filters = (boolean) $need_media_filters;
138
-
139
- $this->plugin_file = $plugin_file;
140
- $this->plugin_folder = basename(dirname($plugin_file));
141
-
142
- $this->pre_init_actions();
143
- $this->init_actions();
144
-
145
- // Load locale
146
- load_plugin_textdomain($dkey, false, $this->plugin_folder . '/languages');
147
- }
148
-
149
- protected function add_option_key($key, $option, $title)
150
- {
151
- $this->option_keys[$key] = $option;
152
- $this->option_pages[$key] = $title;
153
- }
154
-
155
- protected function add_extra_option_key($key, $option, $title)
156
- {
157
- $this->extra_option_keys[$key] = $option;
158
- $this->option_pages[$key] = $title;
159
- }
160
-
161
- public function add_icon()
162
- {
163
- return '<div class="icon32" id="icon-bwp-plugin" '
164
- . 'style=\'background-image: url("'
165
- . constant($this->plugin_ckey . '_IMAGES')
166
- . '/icon_menu_32.png");\'><br></div>' . "\n";
167
- }
168
-
169
- protected function set_version($ver = '', $type = '')
170
- {
171
- switch ($type)
172
- {
173
- case '': $this->plugin_ver = $ver;
174
- break;
175
- case 'php': $this->php_ver = $ver;
176
- break;
177
- case 'wp': $this->wp_ver = $ver;
178
- break;
179
- }
180
- }
181
-
182
- protected function get_version($type = '')
183
- {
184
- switch ($type)
185
- {
186
- case '': return $this->plugin_ver;
187
- break;
188
- case 'php': return $this->php_ver;
189
- break;
190
- case 'wp': return $this->wp_ver;
191
- break;
192
- }
193
- }
194
-
195
- protected function check_required_versions()
196
- {
197
- if (version_compare(PHP_VERSION, $this->php_ver, '<')
198
- || version_compare(get_bloginfo('version'), $this->wp_ver, '<')
199
- ) {
200
- add_action('admin_notices', array($this, 'warn_required_versions'));
201
- add_action('network_admin_notices', array($this, 'warn_required_versions'));
202
- return false;
203
- }
204
- else
205
- return true;
206
- }
207
-
208
- public function warn_required_versions()
209
- {
210
- echo '<div class="error"><p>' . sprintf(
211
- __('%s requires WordPress <strong>%s</strong> or higher '
212
- . 'and PHP <strong>%s</strong> or higher. '
213
- . 'The plugin will not protected function until you update your software. '
214
- . 'Please deactivate this plugin.', $this->plugin_dkey),
215
- $this->plugin_title, $this->wp_ver, $this->php_ver)
216
- . '</p></div>';
217
- }
218
-
219
- public function show_donation()
220
- {
221
- $showable = apply_filters('bwp_donation_showable', true);
222
- $ad_showable = apply_filters('bwp_ad_showable', true);
223
- ?>
224
- <div id="bwp-info-place">
225
- <div id="bwp-donation" style="margin-bottom: 0px;">
226
- <a href="<?php echo $this->plugin_url; ?>"><?php echo $this->plugin_title; ?></a> <small>v<?php echo $this->plugin_ver; ?></small><br />
227
- <small>
228
- <a href="<?php echo str_replace('/wordpress-plugins/', '/topic/', $this->plugin_url); ?>"><?php _e('Development Log', $this->plugin_dkey); ?></a> &ndash; <a href="<?php echo $this->plugin_url . 'faq/'; ?>" title="<?php _e('Frequently Asked Questions', $this->plugin_dkey) ?>"><?php _e('FAQ', $this->plugin_dkey); ?></a> &ndash; <a href="http://betterwp.net/contact/" title="<?php _e('Got a problem? Send me a feedback!', $this->plugin_dkey) ?>"><?php _e('Contact', $this->plugin_dkey); ?></a>
229
- </small>
230
- <br />
231
- <?php
232
- if (true == $showable || ($this->is_multisite() && is_super_admin()))
233
- {
234
- ?>
235
- <small><?php _e('You can buy me some special coffees if you appreciate my work, thank you!', $this->plugin_dkey); ?></small>
236
- <form class="paypal-form" action="https://www.paypal.com/cgi-bin/webscr" method="post">
237
- <p>
238
- <input type="hidden" name="cmd" value="_xclick">
239
- <input type="hidden" name="business" value="NWBB8JUDW5VSY">
240
- <input type="hidden" name="lc" value="VN">
241
- <input type="hidden" name="button_subtype" value="services">
242
- <input type="hidden" name="no_note" value="0">
243
- <input type="hidden" name="cn" value="Would you like to say anything to me?">
244
- <input type="hidden" name="no_shipping" value="1">
245
- <input type="hidden" name="rm" value="1">
246
- <input type="hidden" name="return" value="http://betterwp.net">
247
- <input type="hidden" name="currency_code" value="USD">
248
- <input type="hidden" name="bn" value="PP-BuyNowBF:icon-paypal.gif:NonHosted">
249
- <input type="hidden" name="item_name" value="<?php printf(__('Donate to %s', $this->plugin_dkey), $this->plugin_title); ?>" />
250
- <select name="amount">
251
- <option value="5.00"><?php _e('One cup $5.00', $this->plugin_dkey); ?></option>
252
- <option value="10.00"><?php _e('Two cups $10.00', $this->plugin_dkey); ?></option>
253
- <option value="25.00"><?php _e('Five cups! $25.00', $this->plugin_dkey); ?></option>
254
- <option value="50.00"><?php _e('One LL-cup!!! $50.00', $this->plugin_dkey); ?></option>
255
- <option value="100.00"><?php _e('... or any amount!', $this->plugin_dkey); ?></option>
256
- </select>
257
- <span class="paypal-alternate-input" style="display: none;"><!-- --></span>
258
- <input class="paypal-submit" type="image" src="<?php echo $this->plugin_wp_url . 'includes/bwp-option-page/images/icon-paypal.gif'; ?>" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" />
259
- <img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
260
- </p>
261
- </form>
262
- <?php
263
- }
264
- ?>
265
- </div>
266
- <div class="bwp-separator">
267
- <div style="height: 10px; width: 5px; background-color: #cccccc; margin: 0 auto;"><!-- --></div>
268
- </div>
269
- <div id="bwp-contact">
270
- <a class="bwp-rss" href="http://feeds.feedburner.com/BetterWPnet"><?php _e('Latest updates from BetterWP.net!', $this->plugin_dkey); ?></a>
271
- <a class="bwp-twitter" href="http://twitter.com/0dd0ne0ut"><?php _e('Follow me on Twitter!', $this->plugin_dkey); ?></a>
272
- </div>
273
- <?php
274
- if (true == $ad_showable)
275
- {
276
- ?>
277
- <div class="bwp-separator">
278
- <div style="height: 10px; width: 5px; background-color: #cccccc; margin: 0 auto;"><!-- --></div>
279
- </div>
280
- <div id="bwp-ads">
281
- <p><strong><?php _e('This Plugin is Proudly Sponsored By', $this->plugin_dkey); ?></strong></p>
282
- <div style="width: 250px; margin: 0 auto;">
283
- <a href="http://managewp.com/?utm_source=<?php echo $this->plugin_key; ?>&amp;utm_medium=Banner&amp;utm_content=mwp250_2&amp;utm_campaign=Plugins">
284
- <img src="<?php echo $this->plugin_wp_url . 'includes/bwp-option-page/images/ad_250x250.png'; ?>" />
285
- </a>
286
- </div>
287
- </div>
288
- <?php
289
- }
290
- ?>
291
- </div>
292
- <?php
293
- }
294
-
295
- public function show_version()
296
- {
297
- if (empty($this->plugin_ver)) return '';
298
-
299
- return '<a class="nav-tab version" title="'
300
- . sprintf(esc_attr(__('You are using version %s!', $this->plugin_dkey)), $this->plugin_ver)
301
- . '">' . $this->plugin_ver . '</a>';
302
- }
303
-
304
- protected function pre_init_actions()
305
- {
306
- $this->pre_init_build_constants();
307
- $this->pre_init_build_options();
308
- $this->pre_init_properties();
309
- $this->load_libraries();
310
- $this->pre_init_hooks();
311
- $this->pre_init_update_plugin();
312
-
313
- // Support installation and uninstallation
314
- register_activation_hook($this->plugin_file, array($this, 'install'));
315
- register_deactivation_hook($this->plugin_file, array($this, 'uninstall'));
316
- }
317
-
318
- protected function init_actions()
319
- {
320
- add_action('init', array($this, 'build_wp_properties'));
321
- add_action('init', array($this, 'init'));
322
-
323
- // register backend hooks
324
- add_action('admin_menu', array($this, 'init_admin'), 1);
325
- }
326
-
327
- public function init()
328
- {
329
- do_action($this->plugin_key . '_pre_init');
330
-
331
- $this->init_update_plugin();
332
- $this->build_constants();
333
- $this->build_options();
334
- $this->init_properties();
335
- $this->init_hooks();
336
- $this->enqueue_media();
337
-
338
- do_action($this->plugin_key . '_loaded');
339
-
340
- // icon 32px
341
- if ($this->is_admin_page())
342
- {
343
- add_filter('bwp-admin-form-icon', array($this, 'add_icon'));
344
- add_filter('bwp-admin-plugin-version', array($this, 'show_version'));
345
- add_action('bwp_option_action_before_form', array($this, 'show_donation'), 12);
346
- }
347
- }
348
-
349
- protected function add_cap($cap)
350
- {
351
- $this->plugin_cap = $cap;
352
- }
353
-
354
- public function build_wp_properties()
355
- {
356
- // set the plugin WP url here so it can be filtered
357
- if (defined('BWP_USE_SYMLINKS'))
358
- // make use of symlinks on development environment
359
- $this->plugin_wp_url = trailingslashit(plugins_url($this->plugin_folder));
360
- else
361
- // this should allow other package to include BWP plugins while
362
- // retaining correct URLs pointing to assets
363
- $this->plugin_wp_url = trailingslashit(plugin_dir_url($this->plugin_file));
364
- }
365
-
366
- protected function pre_init_build_constants()
367
- {
368
- // url to plugin bwp website
369
- define($this->plugin_ckey . '_PLUGIN_URL', $this->plugin_url);
370
- // the capability needed to configure this plugin
371
- define($this->plugin_ckey . '_CAPABILITY', $this->plugin_cap);
372
-
373
- // define registered option keys, to be used when building option pages
374
- // and build options
375
- foreach ($this->option_keys as $key => $option)
376
- {
377
- define(strtoupper($key), $option);
378
- }
379
- foreach ($this->extra_option_keys as $key => $option)
380
- {
381
- define(strtoupper($key), $option);
382
- }
383
- }
384
-
385
- protected function build_constants()
386
- {
387
- // these constants are only available once plugin_wp_url is available
388
- if (true == $this->need_media_filters)
389
- {
390
- define($this->plugin_ckey . '_IMAGES',
391
- apply_filters($this->plugin_key . '_image_path',
392
- $this->plugin_wp_url . 'images'));
393
- define($this->plugin_ckey . '_CSS',
394
- apply_filters($this->plugin_key . '_css_path',
395
- $this->plugin_wp_url . 'css'));
396
- define($this->plugin_ckey . '_JS',
397
- apply_filters($this->plugin_key . '_js_path',
398
- $this->plugin_wp_url . 'js'));
399
- }
400
- else
401
- {
402
- define($this->plugin_ckey . '_IMAGES', $this->plugin_wp_url . 'images');
403
- define($this->plugin_ckey . '_CSS', $this->plugin_wp_url . 'css');
404
- define($this->plugin_ckey . '_JS', $this->plugin_wp_url . 'js');
405
- }
406
- }
407
-
408
- protected function pre_init_build_options()
409
- {
410
- $this->build_options();
411
- }
412
-
413
- protected function build_options()
414
- {
415
- // Get all options and merge them
416
- $options = $this->options_default;
417
- foreach ($this->option_keys as $option)
418
- {
419
- $db_option = get_option($option);
420
- if ($db_option && is_array($db_option))
421
- $options = array_merge($options, $db_option);
422
- unset($db_option);
423
- // Also check for global options if in Multi-site
424
- if ($this->is_multisite())
425
- {
426
- $db_option = get_site_option($option);
427
- if ($db_option && is_array($db_option))
428
- {
429
- $temp = array();
430
- foreach ($db_option as $k => $o)
431
- {
432
- if (in_array($k, $this->site_options))
433
- $temp[$k] = $o;
434
- }
435
- $options = array_merge($options, $temp);
436
- }
437
- }
438
- }
439
- $this->options = $options;
440
- }
441
-
442
- protected function pre_init_properties()
443
- {
444
- /* intentionally left blank */
445
- }
446
-
447
- protected function init_properties()
448
- {
449
- /* intentionally left blank */
450
- }
451
-
452
- protected function load_libraries()
453
- {
454
- /* intentionally left blank */
455
- }
456
-
457
- protected function update_plugin($when = '')
458
- {
459
- if (!is_admin())
460
- return;
461
-
462
- $current_version = $this->plugin_ver;
463
- $db_version = get_option($this->plugin_key . '_version');
464
-
465
- $action_hook = 'pre_init' == $when
466
- ? $this->plugin_key . '_upgrade'
467
- : $this->plugin_key . '_init_upgrade';
468
-
469
- if (!$db_version || version_compare($db_version, $current_version, '<'))
470
- {
471
- do_action($action_hook, $db_version, $current_version);
472
- // only mark as upgraded when this is init update
473
- if ('init' == $when)
474
- update_option($this->plugin_key . '_version', $current_version);
475
- }
476
- }
477
-
478
- protected function pre_init_update_plugin()
479
- {
480
- $this->update_plugin('pre_init');
481
- }
482
-
483
- protected function init_update_plugin()
484
- {
485
- $this->update_plugin('init');
486
- }
487
-
488
- protected function pre_init_hooks()
489
- {
490
- /* intentionally left blank */
491
- }
492
-
493
- protected function init_hooks()
494
- {
495
- /* intentionally left blank */
496
- }
497
-
498
- protected function enqueue_media()
499
- {
500
- /* intentionally left blank */
501
- }
502
-
503
- public function install()
504
- {
505
- /* intentionally left blank */
506
- }
507
-
508
- public function uninstall()
509
- {
510
- /* intentionally left blank */
511
- }
512
-
513
- protected function is_admin_page($page = '')
514
- {
515
- if (is_admin() && !empty($_GET['page'])
516
- && (in_array($_GET['page'], $this->option_keys)
517
- || in_array($_GET['page'], $this->extra_option_keys))
518
- && (empty($page)
519
- || (!empty($page) && $page == $_GET['page']))
520
- ) {
521
- return true;
522
- }
523
- }
524
-
525
- public function get_admin_page($page)
526
- {
527
- $option_script = !$this->_menu_under_settings && !$this->_simple_menu
528
- ? 'admin.php'
529
- : 'options-general.php';
530
-
531
- return add_query_arg(array('page' => $page), admin_url($option_script));
532
- }
533
-
534
- public function plugin_action_links($links, $file)
535
- {
536
- $option_keys = array_values($this->option_keys);
537
-
538
- if (false !== strpos(plugin_basename($this->plugin_file), $file))
539
- {
540
- $links[] = '<a href="' . $this->get_admin_page($option_keys[0]) . '">'
541
- . __('Settings') . '</a>';
542
- }
543
-
544
- return $links;
545
- }
546
-
547
- public function init_admin()
548
- {
549
- $this->_menu_under_settings = apply_filters('bwp_menus_under_settings', false);
550
-
551
- add_filter('plugin_action_links', array($this, 'plugin_action_links'), 10, 2);
552
-
553
- if ($this->is_admin_page())
554
- {
555
- // Build tabs
556
- $this->build_tabs();
557
-
558
- // Load option page builder
559
- if (!class_exists('BWP_OPTION_PAGE'))
560
- require_once dirname(__FILE__) . '/bwp-option-page/bwp-option-page.php';
561
-
562
- // Enqueue style sheets and scripts for the option page
563
- wp_enqueue_style(
564
- 'bwp-option-page',
565
- $this->plugin_wp_url . 'includes/bwp-option-page/css/bwp-option-page.css',
566
- self::is_multisite() ? array('wp-admin') : array(),
567
- '1.1.0'
568
- );
569
-
570
- wp_enqueue_script(
571
- 'bwp-paypal-js',
572
- $this->plugin_wp_url . 'includes/bwp-option-page/js/paypal.js',
573
- array('jquery')
574
- );
575
- }
576
-
577
- $this->build_menus();
578
- }
579
-
580
- /**
581
- * Build the Menus
582
- */
583
- protected function build_menus()
584
- {
585
- /* intentionally left blank */
586
- }
587
-
588
- protected function build_tabs()
589
- {
590
- $option_script = !$this->_menu_under_settings
591
- ? 'admin.php'
592
- : 'options-general.php';
593
-
594
- foreach ($this->option_pages as $key => $page)
595
- {
596
- $pagelink = !empty($this->option_keys[$key])
597
- ? $this->option_keys[$key]
598
- : $this->extra_option_keys[$key];
599
-
600
- $this->form_tabs[$page] = admin_url($option_script)
601
- . '?page=' . $pagelink;
602
- }
603
- }
604
-
605
- /**
606
- * Build the option pages
607
- *
608
- * Utilizes BWP Option Page Builder (@see BWP_OPTION_PAGE)
609
- */
610
- protected function build_option_pages()
611
- {
612
- /* intentionally left blank */
613
- }
614
-
615
- protected function add_notice($notice)
616
- {
617
- if (!in_array($notice, $this->notices))
618
- {
619
- $this->notices[] = $notice;
620
- add_action('bwp_option_action_before_form', array($this, 'show_notices'));
621
- }
622
- }
623
-
624
- public function show_notices()
625
- {
626
- if (false == $this->notice_shown)
627
- {
628
- foreach ($this->notices as $notice)
629
- {
630
- echo '<div class="updated fade"><p>' . $notice . '</p></div>';
631
- }
632
- $this->notice_shown = true;
633
- }
634
- }
635
-
636
- protected function add_error($error)
637
- {
638
- if (!in_array($error, $this->errors))
639
- {
640
- $this->errors[] = $error;
641
- add_action('bwp_option_action_before_form', array($this, 'show_errors'));
642
- }
643
- }
644
-
645
- public function show_errors()
646
- {
647
- if (false == $this->error_shown)
648
- {
649
- foreach ($this->errors as $error)
650
- {
651
- echo '<div class="error"><p>' . $error . '</p></div>';
652
- }
653
- $this->error_shown = true;
654
- }
655
- }
656
-
657
- public function add_url($key, $url, $relative = true)
658
- {
659
- $this->urls[$key] = array(
660
- 'relative' => $relative,
661
- 'url' => $url
662
- );
663
- }
664
-
665
- public function get_url($key)
666
- {
667
- if (isset($this->urls[$key]))
668
- {
669
- $url = $this->urls[$key];
670
- if ($url['relative'])
671
- return trailingslashit($this->plugin_url) . $url['url'];
672
-
673
- return $url['url'];
674
- }
675
-
676
- return '';
677
- }
678
-
679
- public static function is_multisite()
680
- {
681
- if (function_exists('is_multisite') && is_multisite())
682
- return true;
683
-
684
- if (defined('MULTISITE'))
685
- return MULTISITE;
686
-
687
- if (defined('SUBDOMAIN_INSTALL') || defined('VHOST') || defined('SUNRISE'))
688
- return true;
689
-
690
- return false;
691
- }
692
-
693
- public static function is_subdomain_install()
694
- {
695
- if (defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL)
696
- return true;
697
-
698
- return false;
699
- }
700
-
701
- protected static function is_normal_admin()
702
- {
703
- if (self::is_multisite() && !is_super_admin())
704
- return true;
705
- return false;
706
- }
707
-
708
- protected static function is_apache()
709
- {
710
- if (isset($_SERVER['SERVER_SOFTWARE'])
711
- && false !== stripos($_SERVER['SERVER_SOFTWARE'], 'apache')
712
- ) {
713
- return true;
714
- }
715
- return false;
716
- }
717
-
718
- protected static function is_nginx()
719
- {
720
- if (isset($_SERVER['SERVER_SOFTWARE'])
721
- && false !== stripos($_SERVER['SERVER_SOFTWARE'], 'nginx')
722
- ) {
723
- return true;
724
- }
725
- return false;
726
- }
727
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2015 Khang Minh <contact@betterwp.net>
4
+ * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER
5
+ */
6
+
7
+ class BWP_FRAMEWORK_V2
8
+ {
9
+ /**
10
+ * Database related data
11
+ */
12
+ public $options = array();
13
+
14
+ /**
15
+ * Default data
16
+ */
17
+ public $options_default = array();
18
+
19
+ /**
20
+ * Global options
21
+ */
22
+ public $site_options = array();
23
+
24
+ /**
25
+ * Hold db option keys
26
+ */
27
+ public $option_keys = array();
28
+
29
+ /**
30
+ * Hold extra option keys
31
+ */
32
+ public $extra_option_keys = array();
33
+
34
+ /**
35
+ * Hold option pages
36
+ */
37
+ public $option_pages = array();
38
+
39
+ /**
40
+ * The current option page instance
41
+ *
42
+ * @var BWP_OPTION_PAGE_V2
43
+ */
44
+ public $curren_option_page;
45
+
46
+ /**
47
+ * Key to identify plugin
48
+ */
49
+ public $plugin_key;
50
+
51
+ /**
52
+ * Constant Key to identify plugin
53
+ */
54
+ public $plugin_ckey;
55
+
56
+ /**
57
+ * Domain Key to identify plugin
58
+ */
59
+ public $plugin_dkey;
60
+
61
+ /**
62
+ * Title of the plugin
63
+ */
64
+ public $plugin_title;
65
+
66
+ /**
67
+ * Homepage of the plugin
68
+ */
69
+ public $plugin_url;
70
+
71
+ /**
72
+ * Urls to various parts of homepage or other places
73
+ *
74
+ * Expect to have a format of array('relative' => bool, 'url' => url)
75
+ */
76
+ public $urls = array();
77
+
78
+ /**
79
+ * Plugin file
80
+ */
81
+ public $plugin_file;
82
+
83
+ /**
84
+ * Plugin folder
85
+ */
86
+ public $plugin_folder;
87
+
88
+ /**
89
+ * Plugin WP url
90
+ */
91
+ public $plugin_wp_url;
92
+
93
+ /**
94
+ * Version of the plugin
95
+ */
96
+ public $plugin_ver = '';
97
+
98
+ /**
99
+ * Message shown to user (Warning, Notes, etc.)
100
+ */
101
+ public $notices = array();
102
+ public $notice_shown = false;
103
+
104
+ /**
105
+ * Error shown to user
106
+ */
107
+ public $errors = array();
108
+ public $error_shown = false;
109
+
110
+ /**
111
+ * Capabilities to manage this plugin
112
+ */
113
+ public $plugin_cap = 'manage_options';
114
+
115
+ /**
116
+ * Whether or not to create filter for media paths
117
+ */
118
+ public $need_media_filters;
119
+
120
+ /**
121
+ * Form tabs to build
122
+ */
123
+ public $form_tabs = array();
124
+
125
+ /**
126
+ * Version constraints
127
+ */
128
+ public $wp_ver;
129
+ public $php_ver;
130
+
131
+ /**
132
+ * Number of framework revisions
133
+ */
134
+ public $revision = 143;
135
+
136
+ /**
137
+ * Text domain
138
+ */
139
+ public $domain = '';
140
+
141
+ /**
142
+ * Other special variables
143
+ */
144
+ protected $_menu_under_settings = false;
145
+ protected $_simple_menu = false;
146
+
147
+ /**
148
+ * Construct a new plugin with appropriate meta
149
+ *
150
+ * @param array $meta
151
+ * @since rev 142
152
+ */
153
+ public function __construct(array $meta)
154
+ {
155
+ $required = array(
156
+ 'title', 'version', 'domain'
157
+ );
158
+
159
+ foreach ($required as $required_meta)
160
+ {
161
+ if (!array_key_exists($required_meta, $meta))
162
+ {
163
+ throw new \InvalidArgumentException(sprintf('Missing required meta (%s) to construct plugin', $required_meta));
164
+ }
165
+ }
166
+
167
+ $this->plugin_title = $meta['title'];
168
+
169
+ require_once __DIR__ . '/class-bwp-version.php';
170
+
171
+ $this->set_version(isset($meta['php_version']) ? $meta['php_version'] : BWP_VERSION::$php_ver, 'php');
172
+ $this->set_version(isset($meta['wp_version']) ? $meta['wp_version'] : BWP_VERSION::$wp_ver, 'wp');
173
+ $this->set_version($meta['version']);
174
+
175
+ $this->domain = $meta['domain'];
176
+ }
177
+
178
+ /**
179
+ * Build base properties
180
+ */
181
+ protected function build_properties($key, $dkey, $options, $plugin_title = '',
182
+ $plugin_file = '', $plugin_url = '', $need_media_filters = true)
183
+ {
184
+ $this->plugin_key = strtolower($key);
185
+ $this->plugin_ckey = strtoupper($key);
186
+ $this->plugin_dkey = $dkey;
187
+ $this->plugin_title = $plugin_title;
188
+ $this->plugin_url = $plugin_url;
189
+
190
+ $this->options_default = $options;
191
+ $this->need_media_filters = (boolean) $need_media_filters;
192
+
193
+ $this->plugin_file = $plugin_file;
194
+ $this->plugin_folder = basename(dirname($plugin_file));
195
+
196
+ $this->pre_init_actions();
197
+ $this->init_actions();
198
+
199
+ // Load locale
200
+ load_plugin_textdomain($dkey, false, $this->plugin_folder . '/languages');
201
+ }
202
+
203
+ protected function add_option_key($key, $option, $title)
204
+ {
205
+ $this->option_keys[$key] = $option;
206
+ $this->option_pages[$key] = $title;
207
+ }
208
+
209
+ protected function add_extra_option_key($key, $option, $title)
210
+ {
211
+ $this->extra_option_keys[$key] = $option;
212
+ $this->option_pages[$key] = $title;
213
+ }
214
+
215
+ public function add_icon()
216
+ {
217
+ return '<div class="icon32" id="icon-bwp-plugin" '
218
+ . 'style=\'background-image: url("'
219
+ . constant($this->plugin_ckey . '_IMAGES')
220
+ . '/icon_menu_32.png");\'><br></div>' . "\n";
221
+ }
222
+
223
+ protected function set_version($ver = '', $type = '')
224
+ {
225
+ switch ($type)
226
+ {
227
+ case '': $this->plugin_ver = $ver;
228
+ break;
229
+ case 'php': $this->php_ver = $ver;
230
+ break;
231
+ case 'wp': $this->wp_ver = $ver;
232
+ break;
233
+ }
234
+ }
235
+
236
+ protected function get_version($type = '')
237
+ {
238
+ switch ($type)
239
+ {
240
+ case '': return $this->plugin_ver;
241
+ break;
242
+ case 'php': return $this->php_ver;
243
+ break;
244
+ case 'wp': return $this->wp_ver;
245
+ break;
246
+ }
247
+ }
248
+
249
+ protected function get_current_wp_version()
250
+ {
251
+ return get_bloginfo('version');
252
+ }
253
+
254
+ protected function check_required_versions()
255
+ {
256
+ if (version_compare(PHP_VERSION, $this->php_ver, '<')
257
+ || version_compare(get_bloginfo('version'), $this->wp_ver, '<')
258
+ ) {
259
+ add_action('admin_notices', array($this, 'warn_required_versions'));
260
+ add_action('network_admin_notices', array($this, 'warn_required_versions'));
261
+ return false;
262
+ }
263
+ else
264
+ return true;
265
+ }
266
+
267
+ public function warn_required_versions()
268
+ {
269
+ BWP_VERSION::warn_required_versions($this->plugin_title, $this->plugin_dkey, $this->php_ver, $this->wp_ver);
270
+ }
271
+
272
+ public function show_donation()
273
+ {
274
+ $info_showable = apply_filters('bwp_info_showable', true);
275
+ $donation_showable = apply_filters('bwp_donation_showable', true);
276
+ $ad_showable = apply_filters('bwp_ad_showable', true);
277
+
278
+ if (true == $info_showable || (self::is_multisite() && is_super_admin()))
279
+ {
280
+ ?>
281
+ <div id="bwp-info-place">
282
+ <div id="bwp-donation" style="margin-bottom: 0px;">
283
+ <a href="<?php echo $this->plugin_url; ?>"><?php echo $this->plugin_title; ?></a> <small>v<?php echo $this->plugin_ver; ?></small><br />
284
+ <small>
285
+ <a href="<?php echo str_replace('/wordpress-plugins/', '/topic/', $this->plugin_url); ?>"><?php _e('Development Log', $this->plugin_dkey); ?></a> &ndash; <a href="<?php echo $this->plugin_url . 'faq/'; ?>" title="<?php _e('Frequently Asked Questions', $this->plugin_dkey) ?>"><?php _e('FAQ', $this->plugin_dkey); ?></a> &ndash; <a href="http://betterwp.net/contact/" title="<?php _e('Got a problem? Send me a feedback!', $this->plugin_dkey) ?>"><?php _e('Contact', $this->plugin_dkey); ?></a>
286
+ </small>
287
+ <br />
288
+ <?php
289
+ if (true == $donation_showable || (self::is_multisite() && is_super_admin()))
290
+ {
291
+ ?>
292
+ <small><?php _e('You can buy me some special coffees if you appreciate my work, thank you!', $this->plugin_dkey); ?></small>
293
+ <form class="paypal-form" action="https://www.paypal.com/cgi-bin/webscr" method="post">
294
+ <p>
295
+ <input type="hidden" name="cmd" value="_xclick">
296
+ <input type="hidden" name="business" value="NWBB8JUDW5VSY">
297
+ <input type="hidden" name="lc" value="VN">
298
+ <input type="hidden" name="button_subtype" value="services">
299
+ <input type="hidden" name="no_note" value="0">
300
+ <input type="hidden" name="cn" value="Would you like to say anything to me?">
301
+ <input type="hidden" name="no_shipping" value="1">
302
+ <input type="hidden" name="rm" value="1">
303
+ <input type="hidden" name="return" value="http://betterwp.net">
304
+ <input type="hidden" name="currency_code" value="USD">
305
+ <input type="hidden" name="bn" value="PP-BuyNowBF:icon-paypal.gif:NonHosted">
306
+ <input type="hidden" name="item_name" value="<?php printf(__('Donate to %s', $this->plugin_dkey), $this->plugin_title); ?>" />
307
+ <select name="amount">
308
+ <option value="5.00"><?php _e('One cup $5.00', $this->plugin_dkey); ?></option>
309
+ <option value="10.00"><?php _e('Two cups $10.00', $this->plugin_dkey); ?></option>
310
+ <option value="25.00"><?php _e('Five cups! $25.00', $this->plugin_dkey); ?></option>
311
+ <option value="50.00"><?php _e('One LL-cup!!! $50.00', $this->plugin_dkey); ?></option>
312
+ <option value="100.00"><?php _e('... or any amount!', $this->plugin_dkey); ?></option>
313
+ </select>
314
+ <span class="paypal-alternate-input" style="display: none;"><!-- --></span>
315
+ <input class="paypal-submit" type="image" src="<?php echo $this->plugin_wp_url . 'vendor/kminh/bwp-framework/images/icon-paypal.gif'; ?>" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" />
316
+ <img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
317
+ </p>
318
+ </form>
319
+ <?php
320
+ }
321
+ ?>
322
+ </div>
323
+ <div class="bwp-separator">
324
+ <div style="height: 10px; width: 5px; background-color: #cccccc; margin: 0 auto;"><!-- --></div>
325
+ </div>
326
+ <div id="bwp-contact">
327
+ <a class="bwp-rss" href="http://feeds.feedburner.com/BetterWPnet"><?php _e('Latest updates from BetterWP.net!', $this->plugin_dkey); ?></a>
328
+ <a class="bwp-twitter" href="http://twitter.com/0dd0ne0ut"><?php _e('Follow me on Twitter!', $this->plugin_dkey); ?></a>
329
+ </div>
330
+ <?php
331
+ if (true == $ad_showable)
332
+ {
333
+ ?>
334
+ <div class="bwp-separator">
335
+ <div style="height: 10px; width: 5px; background-color: #cccccc; margin: 0 auto;"><!-- --></div>
336
+ </div>
337
+ <div id="bwp-ads">
338
+ <p><strong><?php _e('This Plugin is Proudly Sponsored By', $this->plugin_dkey); ?></strong></p>
339
+ <div style="width: 250px; margin: 0 auto;">
340
+ <a href="http://bit.ly/bwp-layer-themes" target="_blank">
341
+ <img src="<?php echo $this->plugin_wp_url . 'vendor/kminh/bwp-framework/images/ad_lt_250x250.png'; ?>" />
342
+ </a>
343
+ </div>
344
+ </div>
345
+ <?php
346
+ }
347
+ ?>
348
+ </div>
349
+ <?php
350
+ }
351
+ }
352
+
353
+ public function show_version()
354
+ {
355
+ if (empty($this->plugin_ver)) return '';
356
+
357
+ return '<a class="nav-tab version" title="'
358
+ . sprintf(esc_attr(__('You are using version %s!', $this->plugin_dkey)), $this->plugin_ver)
359
+ . '">' . $this->plugin_ver . '</a>';
360
+ }
361
+
362
+ protected function pre_init_actions()
363
+ {
364
+ $this->pre_init_build_constants();
365
+ $this->pre_init_build_options();
366
+ $this->pre_init_properties();
367
+ $this->load_libraries();
368
+ $this->pre_init_hooks();
369
+ $this->pre_init_update_plugin();
370
+
371
+ // Support installation and uninstallation
372
+ register_activation_hook($this->plugin_file, array($this, 'install'));
373
+ register_deactivation_hook($this->plugin_file, array($this, 'uninstall'));
374
+ }
375
+
376
+ protected function init_actions()
377
+ {
378
+ // @since rev 140, sometimes we need to hook to the 'init' action with
379
+ // a specific priority
380
+ $init_priority = apply_filters($this->plugin_key . '_init_priority', 10);
381
+
382
+ add_action('init', array($this, 'build_wp_properties'), $init_priority);
383
+ add_action('init', array($this, 'init'), $init_priority);
384
+
385
+ // register backend hooks
386
+ add_action('admin_init', array($this, 'init_admin'), 1);
387
+ add_action('admin_menu', array($this, 'init_admin_menu'), 1);
388
+ }
389
+
390
+ public function init()
391
+ {
392
+ do_action($this->plugin_key . '_pre_init');
393
+
394
+ $this->init_update_plugin();
395
+ $this->build_constants();
396
+ $this->build_options();
397
+ $this->init_properties();
398
+ $this->init_hooks();
399
+ $this->enqueue_media();
400
+
401
+ do_action($this->plugin_key . '_loaded');
402
+
403
+ // icon 32px
404
+ if ($this->is_admin_page())
405
+ {
406
+ add_filter('bwp-admin-form-icon', array($this, 'add_icon'));
407
+ add_filter('bwp-admin-plugin-version', array($this, 'show_version'));
408
+ add_action('bwp_option_action_before_form', array($this, 'show_donation'), 12);
409
+ }
410
+ }
411
+
412
+ protected function add_cap($cap)
413
+ {
414
+ $this->plugin_cap = $cap;
415
+ }
416
+
417
+ public function build_wp_properties()
418
+ {
419
+ // set the plugin WP url here so it can be filtered
420
+ if (defined('BWP_USE_SYMLINKS'))
421
+ // make use of symlinks on development environment
422
+ $this->plugin_wp_url = trailingslashit(plugins_url($this->plugin_folder));
423
+ else
424
+ // this should allow other package to include BWP plugins while
425
+ // retaining correct URLs pointing to assets
426
+ $this->plugin_wp_url = trailingslashit(plugin_dir_url($this->plugin_file));
427
+ }
428
+
429
+ protected function pre_init_build_constants()
430
+ {
431
+ // url to plugin bwp website
432
+ define($this->plugin_ckey . '_PLUGIN_URL', $this->plugin_url);
433
+ // the capability needed to configure this plugin
434
+ define($this->plugin_ckey . '_CAPABILITY', $this->plugin_cap);
435
+
436
+ // define registered option keys, to be used when building option pages
437
+ // and build options
438
+ foreach ($this->option_keys as $key => $option)
439
+ {
440
+ define(strtoupper($key), $option);
441
+ }
442
+ foreach ($this->extra_option_keys as $key => $option)
443
+ {
444
+ define(strtoupper($key), $option);
445
+ }
446
+ }
447
+
448
+ protected function build_constants()
449
+ {
450
+ // these constants are only available once plugin_wp_url is available
451
+ if (true == $this->need_media_filters)
452
+ {
453
+ define($this->plugin_ckey . '_IMAGES',
454
+ apply_filters($this->plugin_key . '_image_path',
455
+ $this->plugin_wp_url . 'images'));
456
+ define($this->plugin_ckey . '_CSS',
457
+ apply_filters($this->plugin_key . '_css_path',
458
+ $this->plugin_wp_url . 'css'));
459
+ define($this->plugin_ckey . '_JS',
460
+ apply_filters($this->plugin_key . '_js_path',
461
+ $this->plugin_wp_url . 'js'));
462
+ }
463
+ else
464
+ {
465
+ define($this->plugin_ckey . '_IMAGES', $this->plugin_wp_url . 'images');
466
+ define($this->plugin_ckey . '_CSS', $this->plugin_wp_url . 'css');
467
+ define($this->plugin_ckey . '_JS', $this->plugin_wp_url . 'js');
468
+ }
469
+ }
470
+
471
+ protected function pre_init_build_options()
472
+ {
473
+ $this->build_options();
474
+ }
475
+
476
+ protected function build_options()
477
+ {
478
+ // Get all options and merge them
479
+ $options = $this->options_default;
480
+ foreach ($this->option_keys as $option)
481
+ {
482
+ $db_option = get_option($option);
483
+ $db_option = $db_option && is_array($db_option)
484
+ ? $db_option
485
+ : array();
486
+
487
+ // check for obsolete keys and remove them from db
488
+ if ($obsolete_keys = array_diff_key($db_option, $this->options_default))
489
+ {
490
+ foreach ($obsolete_keys as $obsolete_key) {
491
+ unset($db_option[$obsolete_key]);
492
+ }
493
+
494
+ update_option($option, $db_option);
495
+ }
496
+
497
+ $options = array_merge($options, $db_option);
498
+ unset($db_option);
499
+
500
+ // also check for global options if in Multi-site
501
+ if (self::is_multisite())
502
+ {
503
+ $db_option = get_site_option($option);
504
+ if ($db_option && is_array($db_option))
505
+ {
506
+ $temp = array();
507
+ foreach ($db_option as $k => $o)
508
+ {
509
+ if (in_array($k, $this->site_options))
510
+ $temp[$k] = $o;
511
+ }
512
+ $options = array_merge($options, $temp);
513
+ }
514
+ }
515
+ }
516
+ $this->options = $options;
517
+ }
518
+
519
+ /**
520
+ * Get current options by their keys
521
+ *
522
+ * @param array $option_keys
523
+ */
524
+ public function get_options_by_keys(array $option_keys)
525
+ {
526
+ $options = array();
527
+
528
+ foreach ($option_keys as $key) {
529
+ if (array_key_exists($key, $this->options)) {
530
+ $options[$key] = $this->options[$key];
531
+ }
532
+ }
533
+
534
+ return $options;
535
+ }
536
+
537
+ protected function pre_init_properties()
538
+ {
539
+ /* intentionally left blank */
540
+ }
541
+
542
+ protected function init_properties()
543
+ {
544
+ /* intentionally left blank */
545
+ }
546
+
547
+ protected function load_libraries()
548
+ {
549
+ /* intentionally left blank */
550
+ }
551
+
552
+ protected function update_plugin($when = '')
553
+ {
554
+ if (!is_admin())
555
+ return;
556
+
557
+ $current_version = $this->plugin_ver;
558
+ $db_version = get_option($this->plugin_key . '_version');
559
+
560
+ $action_hook = 'pre_init' == $when
561
+ ? $this->plugin_key . '_upgrade'
562
+ : $this->plugin_key . '_init_upgrade';
563
+
564
+ if (!$db_version || version_compare($db_version, $current_version, '<'))
565
+ {
566
+ do_action($action_hook, $db_version, $current_version);
567
+ // only mark as upgraded when this is init update
568
+ if ('init' == $when)
569
+ update_option($this->plugin_key . '_version', $current_version);
570
+ }
571
+ }
572
+
573
+ protected function pre_init_update_plugin()
574
+ {
575
+ $this->update_plugin('pre_init');
576
+ }
577
+
578
+ protected function init_update_plugin()
579
+ {
580
+ $this->update_plugin('init');
581
+ }
582
+
583
+ protected function pre_init_hooks()
584
+ {
585
+ /* intentionally left blank */
586
+ }
587
+
588
+ protected function init_hooks()
589
+ {
590
+ /* intentionally left blank */
591
+ }
592
+
593
+ protected function enqueue_media()
594
+ {
595
+ /* intentionally left blank */
596
+ }
597
+
598
+ public function install()
599
+ {
600
+ /* intentionally left blank */
601
+ }
602
+
603
+ public function uninstall()
604
+ {
605
+ /* intentionally left blank */
606
+ }
607
+
608
+ protected function is_admin_page($page = '')
609
+ {
610
+ if (is_admin() && !empty($_GET['page'])
611
+ && (in_array($_GET['page'], $this->option_keys)
612
+ || in_array($_GET['page'], $this->extra_option_keys))
613
+ && (empty($page)
614
+ || (!empty($page) && $page == $_GET['page']))
615
+ ) {
616
+ return true;
617
+ }
618
+ }
619
+
620
+ protected function get_current_admin_page()
621
+ {
622
+ if ($this->is_admin_page()) {
623
+ return wp_unslash($_GET['page']);
624
+ }
625
+
626
+ return '';
627
+ }
628
+
629
+ public function get_admin_page_url($page = '')
630
+ {
631
+ $page = $page ?: $this->get_current_admin_page();
632
+ $option_script = !$this->_menu_under_settings && !$this->_simple_menu
633
+ ? 'admin.php'
634
+ : 'options-general.php';
635
+
636
+ return add_query_arg(array('page' => $page), admin_url($option_script));
637
+ }
638
+
639
+ public function plugin_action_links($links, $file)
640
+ {
641
+ $option_keys = array_values($this->option_keys);
642
+
643
+ if (false !== strpos(plugin_basename($this->plugin_file), $file))
644
+ {
645
+ $links[] = '<a href="' . $this->get_admin_page_url($option_keys[0]) . '">'
646
+ . __('Settings') . '</a>';
647
+ }
648
+
649
+ return $links;
650
+ }
651
+
652
+ public function init_admin()
653
+ {
654
+ if ($this->is_admin_page())
655
+ {
656
+ $this->curren_option_page = new BWP_OPTION_PAGE_V2(
657
+ $this->get_current_admin_page(), $this
658
+ );
659
+
660
+ $this->build_option_page();
661
+
662
+ // submit the form on the current option page when needed
663
+ if (isset($_POST['submit_' . $this->curren_option_page->get_form_name()]))
664
+ {
665
+ $submitted = $this->curren_option_page->submit_html_form();
666
+
667
+ // form submitted successfully
668
+ if ($submitted)
669
+ {
670
+ // redirect to current page to invalidate POST data with
671
+ // proper messages
672
+ wp_safe_redirect(add_query_arg('flash', 'options-saved', $this->get_admin_page_url()));
673
+ exit;
674
+ }
675
+ }
676
+
677
+ // show flash messages if needed
678
+ if (!empty($_GET['flash']) && $_GET['flash'] == 'options-saved')
679
+ $this->add_notice(__('All options have been saved.', $this->domain));
680
+ }
681
+ }
682
+
683
+ public function init_admin_menu()
684
+ {
685
+ $this->_menu_under_settings = apply_filters('bwp_menus_under_settings', false);
686
+
687
+ add_filter('plugin_action_links', array($this, 'plugin_action_links'), 10, 2);
688
+
689
+ if ($this->is_admin_page())
690
+ {
691
+ // build tabs
692
+ $this->build_tabs();
693
+
694
+ // enqueue style sheets and scripts for the option page
695
+ wp_enqueue_style(
696
+ 'bwp-option-page',
697
+ $this->plugin_wp_url . 'vendor/kminh/bwp-framework/css/bwp-option-page.css',
698
+ self::is_multisite() || class_exists('JCP_UseGoogleLibraries') ? array('wp-admin') : array(),
699
+ '1.1.0'
700
+ );
701
+
702
+ wp_enqueue_script(
703
+ 'bwp-paypal-js',
704
+ $this->plugin_wp_url . 'vendor/kminh/bwp-framework/js/paypal.js',
705
+ array('jquery')
706
+ );
707
+ }
708
+
709
+ $this->build_menus();
710
+ }
711
+
712
+ /**
713
+ * Build the Menus
714
+ */
715
+ protected function build_menus()
716
+ {
717
+ /* intentionally left blank */
718
+ }
719
+
720
+ protected function build_tabs()
721
+ {
722
+ $option_script = !$this->_menu_under_settings
723
+ ? 'admin.php'
724
+ : 'options-general.php';
725
+
726
+ foreach ($this->option_pages as $key => $page)
727
+ {
728
+ $pagelink = !empty($this->option_keys[$key])
729
+ ? $this->option_keys[$key]
730
+ : $this->extra_option_keys[$key];
731
+
732
+ $this->form_tabs[$page] = admin_url($option_script)
733
+ . '?page=' . $pagelink;
734
+ }
735
+ }
736
+
737
+ /**
738
+ * Build the option pages
739
+ */
740
+ protected function build_option_page()
741
+ {
742
+ /* intentionally left blank */
743
+ }
744
+
745
+ public function show_option_page()
746
+ {
747
+ /* filled by plugin */
748
+ }
749
+
750
+ public function add_notice($notice)
751
+ {
752
+ if (!in_array($notice, $this->notices))
753
+ {
754
+ $this->notices[] = $notice;
755
+ add_action('bwp_option_action_before_form', array($this, 'show_notices'));
756
+ }
757
+ }
758
+
759
+ public function show_notices()
760
+ {
761
+ if (false == $this->notice_shown)
762
+ {
763
+ foreach ($this->notices as $notice)
764
+ {
765
+ echo '<div class="updated fade"><p>' . $notice . '</p></div>';
766
+ }
767
+ $this->notice_shown = true;
768
+ }
769
+ }
770
+
771
+ public function add_error($error)
772
+ {
773
+ if (!in_array($error, $this->errors))
774
+ {
775
+ $this->errors[] = $error;
776
+ add_action('bwp_option_action_before_form', array($this, 'show_errors'));
777
+ }
778
+ }
779
+
780
+ public function show_errors()
781
+ {
782
+ if (false == $this->error_shown)
783
+ {
784
+ foreach ($this->errors as $error)
785
+ {
786
+ echo '<div class="error"><p>' . $error . '</p></div>';
787
+ }
788
+ $this->error_shown = true;
789
+ }
790
+ }
791
+
792
+ public function add_url($key, $url, $relative = true)
793
+ {
794
+ $this->urls[$key] = array(
795
+ 'relative' => $relative,
796
+ 'url' => $url
797
+ );
798
+ }
799
+
800
+ public function get_url($key)
801
+ {
802
+ if (isset($this->urls[$key]))
803
+ {
804
+ $url = $this->urls[$key];
805
+ if ($url['relative'])
806
+ return trailingslashit($this->plugin_url) . $url['url'];
807
+
808
+ return $url['url'];
809
+ }
810
+
811
+ return '';
812
+ }
813
+
814
+ public static function is_multisite()
815
+ {
816
+ if (function_exists('is_multisite') && is_multisite())
817
+ return true;
818
+
819
+ if (defined('MULTISITE'))
820
+ return MULTISITE;
821
+
822
+ if (defined('SUBDOMAIN_INSTALL') || defined('VHOST') || defined('SUNRISE'))
823
+ return true;
824
+
825
+ return false;
826
+ }
827
+
828
+ public static function is_subdomain_install()
829
+ {
830
+ if (defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL)
831
+ return true;
832
+
833
+ return false;
834
+ }
835
+
836
+ public static function is_normal_admin()
837
+ {
838
+ if (self::is_multisite() && !is_super_admin())
839
+ return true;
840
+ return false;
841
+ }
842
+
843
+ public static function is_on_main_blog()
844
+ {
845
+ global $blog_id;
846
+
847
+ return self::is_multisite() && intval($blog_id) === 1;
848
+ }
849
+
850
+ protected static function is_apache()
851
+ {
852
+ if (isset($_SERVER['SERVER_SOFTWARE'])
853
+ && false !== stripos($_SERVER['SERVER_SOFTWARE'], 'apache')
854
+ ) {
855
+ return true;
856
+ }
857
+ return false;
858
+ }
859
+
860
+ protected static function is_nginx()
861
+ {
862
+ if (isset($_SERVER['SERVER_SOFTWARE'])
863
+ && false !== stripos($_SERVER['SERVER_SOFTWARE'], 'nginx')
864
+ ) {
865
+ return true;
866
+ }
867
+
868
+ return false;
869
+ }
870
+ }
vendor/kminh/bwp-framework/src/class-bwp-version.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!class_exists('BWP_VERSION')) :
4
+
5
+ /**
6
+ * Class BWP_VERSION
7
+ * @author Khang Minh <contact@betterwp.net>
8
+ */
9
+ class BWP_VERSION
10
+ {
11
+ /**
12
+ * Default version constraints
13
+ */
14
+ public static $php_ver = '5.3.2';
15
+ public static $wp_ver = '3.0';
16
+
17
+ private function __construct() {}
18
+
19
+ public static function warn_required_versions($title, $domain, $php_ver = null, $wp_ver = null)
20
+ {
21
+ $php_ver = $php_ver ?: self::$php_ver;
22
+ $wp_ver = $wp_ver ?: self::$wp_ver;
23
+
24
+ echo '<div class="error"><p>' . sprintf(
25
+ __('%s requires WordPress <strong>%s</strong> or higher '
26
+ . 'and PHP <strong>%s</strong> or higher. '
27
+ . 'The plugin will not function until you update your software. '
28
+ . 'Please deactivate this plugin.', $domain),
29
+ $title, $wp_ver, $php_ver)
30
+ . '</p></div>';
31
+ }
32
+ }
33
+
34
+ endif;
vendor/kminh/bwp-framework/src/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ //white page