Version Description
- Fix for users who were complaining about their scroll bars missing if they did not select a privacy policy page.
Download this release
Release Info
Developer | fclaussen |
Plugin | GDPR |
Version | 1.4.7 |
Comparing to | |
See all releases |
Version 1.4.7
- LICENSE.txt +339 -0
- README.txt +377 -0
- admin/class-gdpr-admin.php +894 -0
- admin/class-gdpr-requests-admin.php +359 -0
- admin/class-gdpr-telemetry.php +517 -0
- admin/index.php +1 -0
- admin/partials/index.php +1 -0
- admin/partials/requests.php +323 -0
- admin/partials/settings.php +324 -0
- admin/partials/templates/index.php +1 -0
- admin/partials/templates/tmpl-consents.php +28 -0
- admin/partials/templates/tmpl-cookies.php +71 -0
- admin/partials/templates/tmpl-tools.php +49 -0
- admin/partials/tools.php +135 -0
- assets/css/gdpr-admin.css +1 -0
- assets/css/gdpr-public.css +1 -0
- assets/js/gdpr-admin.js +1 -0
- assets/js/gdpr-public.js +1 -0
- gdpr.php +78 -0
- includes/class-gdpr-activator.php +44 -0
- includes/class-gdpr-audit-log.php +170 -0
- includes/class-gdpr-deactivator.php +38 -0
- includes/class-gdpr-email.php +229 -0
- includes/class-gdpr-help.php +188 -0
- includes/class-gdpr-requests.php +265 -0
- includes/class-gdpr.php +659 -0
- includes/helper-functions.php +120 -0
- includes/index.php +1 -0
- index.php +1 -0
- languages/gdpr.pot +1243 -0
- public/class-gdpr-public.php +359 -0
- public/class-gdpr-requests-public.php +392 -0
- public/index.php +1 -0
- public/partials/complaint-form.php +13 -0
- public/partials/confirmation-screens.php +80 -0
- public/partials/delete-form.php +24 -0
- public/partials/export-data-form.php +11 -0
- public/partials/index.php +1 -0
- public/partials/privacy-bar.php +27 -0
- public/partials/privacy-preferences-modal.php +142 -0
- public/partials/reconsent-modal.php +34 -0
- public/partials/rectify-form.php +12 -0
- templates/email/complaint-request.php +26 -0
- templates/email/complaint-resolved.php +5 -0
- templates/email/data-breach-notification.php +34 -0
- templates/email/data-breach-request.php +41 -0
- templates/email/delete-request.php +21 -0
- templates/email/delete-resolved.php +14 -0
- templates/email/export-data-request.php +19 -0
- templates/email/index.php +1 -0
- templates/email/new-request.php +11 -0
- templates/email/rectify-request.php +26 -0
- templates/email/rectify-resolved.php +5 -0
- uninstall.php +31 -0
LICENSE.txt
ADDED
@@ -0,0 +1,339 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
GNU GENERAL PUBLIC LICENSE
|
2 |
+
Version 2, June 1991
|
3 |
+
|
4 |
+
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
5 |
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
6 |
+
Everyone is permitted to copy and distribute verbatim copies
|
7 |
+
of this license document, but changing it is not allowed.
|
8 |
+
|
9 |
+
Preamble
|
10 |
+
|
11 |
+
The licenses for most software are designed to take away your
|
12 |
+
freedom to share and change it. By contrast, the GNU General Public
|
13 |
+
License is intended to guarantee your freedom to share and change free
|
14 |
+
software--to make sure the software is free for all its users. This
|
15 |
+
General Public License applies to most of the Free Software
|
16 |
+
Foundation's software and to any other program whose authors commit to
|
17 |
+
using it. (Some other Free Software Foundation software is covered by
|
18 |
+
the GNU Lesser General Public License instead.) You can apply it to
|
19 |
+
your programs, too.
|
20 |
+
|
21 |
+
When we speak of free software, we are referring to freedom, not
|
22 |
+
price. Our General Public Licenses are designed to make sure that you
|
23 |
+
have the freedom to distribute copies of free software (and charge for
|
24 |
+
this service if you wish), that you receive source code or can get it
|
25 |
+
if you want it, that you can change the software or use pieces of it
|
26 |
+
in new free programs; and that you know you can do these things.
|
27 |
+
|
28 |
+
To protect your rights, we need to make restrictions that forbid
|
29 |
+
anyone to deny you these rights or to ask you to surrender the rights.
|
30 |
+
These restrictions translate to certain responsibilities for you if you
|
31 |
+
distribute copies of the software, or if you modify it.
|
32 |
+
|
33 |
+
For example, if you distribute copies of such a program, whether
|
34 |
+
gratis or for a fee, you must give the recipients all the rights that
|
35 |
+
you have. You must make sure that they, too, receive or can get the
|
36 |
+
source code. And you must show them these terms so they know their
|
37 |
+
rights.
|
38 |
+
|
39 |
+
We protect your rights with two steps: (1) copyright the software, and
|
40 |
+
(2) offer you this license which gives you legal permission to copy,
|
41 |
+
distribute and/or modify the software.
|
42 |
+
|
43 |
+
Also, for each author's protection and ours, we want to make certain
|
44 |
+
that everyone understands that there is no warranty for this free
|
45 |
+
software. If the software is modified by someone else and passed on, we
|
46 |
+
want its recipients to know that what they have is not the original, so
|
47 |
+
that any problems introduced by others will not reflect on the original
|
48 |
+
authors' reputations.
|
49 |
+
|
50 |
+
Finally, any free program is threatened constantly by software
|
51 |
+
patents. We wish to avoid the danger that redistributors of a free
|
52 |
+
program will individually obtain patent licenses, in effect making the
|
53 |
+
program proprietary. To prevent this, we have made it clear that any
|
54 |
+
patent must be licensed for everyone's free use or not licensed at all.
|
55 |
+
|
56 |
+
The precise terms and conditions for copying, distribution and
|
57 |
+
modification follow.
|
58 |
+
|
59 |
+
GNU GENERAL PUBLIC LICENSE
|
60 |
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
61 |
+
|
62 |
+
0. This License applies to any program or other work which contains
|
63 |
+
a notice placed by the copyright holder saying it may be distributed
|
64 |
+
under the terms of this General Public License. The "Program", below,
|
65 |
+
refers to any such program or work, and a "work based on the Program"
|
66 |
+
means either the Program or any derivative work under copyright law:
|
67 |
+
that is to say, a work containing the Program or a portion of it,
|
68 |
+
either verbatim or with modifications and/or translated into another
|
69 |
+
language. (Hereinafter, translation is included without limitation in
|
70 |
+
the term "modification".) Each licensee is addressed as "you".
|
71 |
+
|
72 |
+
Activities other than copying, distribution and modification are not
|
73 |
+
covered by this License; they are outside its scope. The act of
|
74 |
+
running the Program is not restricted, and the output from the Program
|
75 |
+
is covered only if its contents constitute a work based on the
|
76 |
+
Program (independent of having been made by running the Program).
|
77 |
+
Whether that is true depends on what the Program does.
|
78 |
+
|
79 |
+
1. You may copy and distribute verbatim copies of the Program's
|
80 |
+
source code as you receive it, in any medium, provided that you
|
81 |
+
conspicuously and appropriately publish on each copy an appropriate
|
82 |
+
copyright notice and disclaimer of warranty; keep intact all the
|
83 |
+
notices that refer to this License and to the absence of any warranty;
|
84 |
+
and give any other recipients of the Program a copy of this License
|
85 |
+
along with the Program.
|
86 |
+
|
87 |
+
You may charge a fee for the physical act of transferring a copy, and
|
88 |
+
you may at your option offer warranty protection in exchange for a fee.
|
89 |
+
|
90 |
+
2. You may modify your copy or copies of the Program or any portion
|
91 |
+
of it, thus forming a work based on the Program, and copy and
|
92 |
+
distribute such modifications or work under the terms of Section 1
|
93 |
+
above, provided that you also meet all of these conditions:
|
94 |
+
|
95 |
+
a) You must cause the modified files to carry prominent notices
|
96 |
+
stating that you changed the files and the date of any change.
|
97 |
+
|
98 |
+
b) You must cause any work that you distribute or publish, that in
|
99 |
+
whole or in part contains or is derived from the Program or any
|
100 |
+
part thereof, to be licensed as a whole at no charge to all third
|
101 |
+
parties under the terms of this License.
|
102 |
+
|
103 |
+
c) If the modified program normally reads commands interactively
|
104 |
+
when run, you must cause it, when started running for such
|
105 |
+
interactive use in the most ordinary way, to print or display an
|
106 |
+
announcement including an appropriate copyright notice and a
|
107 |
+
notice that there is no warranty (or else, saying that you provide
|
108 |
+
a warranty) and that users may redistribute the program under
|
109 |
+
these conditions, and telling the user how to view a copy of this
|
110 |
+
License. (Exception: if the Program itself is interactive but
|
111 |
+
does not normally print such an announcement, your work based on
|
112 |
+
the Program is not required to print an announcement.)
|
113 |
+
|
114 |
+
These requirements apply to the modified work as a whole. If
|
115 |
+
identifiable sections of that work are not derived from the Program,
|
116 |
+
and can be reasonably considered independent and separate works in
|
117 |
+
themselves, then this License, and its terms, do not apply to those
|
118 |
+
sections when you distribute them as separate works. But when you
|
119 |
+
distribute the same sections as part of a whole which is a work based
|
120 |
+
on the Program, the distribution of the whole must be on the terms of
|
121 |
+
this License, whose permissions for other licensees extend to the
|
122 |
+
entire whole, and thus to each and every part regardless of who wrote it.
|
123 |
+
|
124 |
+
Thus, it is not the intent of this section to claim rights or contest
|
125 |
+
your rights to work written entirely by you; rather, the intent is to
|
126 |
+
exercise the right to control the distribution of derivative or
|
127 |
+
collective works based on the Program.
|
128 |
+
|
129 |
+
In addition, mere aggregation of another work not based on the Program
|
130 |
+
with the Program (or with a work based on the Program) on a volume of
|
131 |
+
a storage or distribution medium does not bring the other work under
|
132 |
+
the scope of this License.
|
133 |
+
|
134 |
+
3. You may copy and distribute the Program (or a work based on it,
|
135 |
+
under Section 2) in object code or executable form under the terms of
|
136 |
+
Sections 1 and 2 above provided that you also do one of the following:
|
137 |
+
|
138 |
+
a) Accompany it with the complete corresponding machine-readable
|
139 |
+
source code, which must be distributed under the terms of Sections
|
140 |
+
1 and 2 above on a medium customarily used for software interchange; or,
|
141 |
+
|
142 |
+
b) Accompany it with a written offer, valid for at least three
|
143 |
+
years, to give any third party, for a charge no more than your
|
144 |
+
cost of physically performing source distribution, a complete
|
145 |
+
machine-readable copy of the corresponding source code, to be
|
146 |
+
distributed under the terms of Sections 1 and 2 above on a medium
|
147 |
+
customarily used for software interchange; or,
|
148 |
+
|
149 |
+
c) Accompany it with the information you received as to the offer
|
150 |
+
to distribute corresponding source code. (This alternative is
|
151 |
+
allowed only for noncommercial distribution and only if you
|
152 |
+
received the program in object code or executable form with such
|
153 |
+
an offer, in accord with Subsection b above.)
|
154 |
+
|
155 |
+
The source code for a work means the preferred form of the work for
|
156 |
+
making modifications to it. For an executable work, complete source
|
157 |
+
code means all the source code for all modules it contains, plus any
|
158 |
+
associated interface definition files, plus the scripts used to
|
159 |
+
control compilation and installation of the executable. However, as a
|
160 |
+
special exception, the source code distributed need not include
|
161 |
+
anything that is normally distributed (in either source or binary
|
162 |
+
form) with the major components (compiler, kernel, and so on) of the
|
163 |
+
operating system on which the executable runs, unless that component
|
164 |
+
itself accompanies the executable.
|
165 |
+
|
166 |
+
If distribution of executable or object code is made by offering
|
167 |
+
access to copy from a designated place, then offering equivalent
|
168 |
+
access to copy the source code from the same place counts as
|
169 |
+
distribution of the source code, even though third parties are not
|
170 |
+
compelled to copy the source along with the object code.
|
171 |
+
|
172 |
+
4. You may not copy, modify, sublicense, or distribute the Program
|
173 |
+
except as expressly provided under this License. Any attempt
|
174 |
+
otherwise to copy, modify, sublicense or distribute the Program is
|
175 |
+
void, and will automatically terminate your rights under this License.
|
176 |
+
However, parties who have received copies, or rights, from you under
|
177 |
+
this License will not have their licenses terminated so long as such
|
178 |
+
parties remain in full compliance.
|
179 |
+
|
180 |
+
5. You are not required to accept this License, since you have not
|
181 |
+
signed it. However, nothing else grants you permission to modify or
|
182 |
+
distribute the Program or its derivative works. These actions are
|
183 |
+
prohibited by law if you do not accept this License. Therefore, by
|
184 |
+
modifying or distributing the Program (or any work based on the
|
185 |
+
Program), you indicate your acceptance of this License to do so, and
|
186 |
+
all its terms and conditions for copying, distributing or modifying
|
187 |
+
the Program or works based on it.
|
188 |
+
|
189 |
+
6. Each time you redistribute the Program (or any work based on the
|
190 |
+
Program), the recipient automatically receives a license from the
|
191 |
+
original licensor to copy, distribute or modify the Program subject to
|
192 |
+
these terms and conditions. You may not impose any further
|
193 |
+
restrictions on the recipients' exercise of the rights granted herein.
|
194 |
+
You are not responsible for enforcing compliance by third parties to
|
195 |
+
this License.
|
196 |
+
|
197 |
+
7. If, as a consequence of a court judgment or allegation of patent
|
198 |
+
infringement or for any other reason (not limited to patent issues),
|
199 |
+
conditions are imposed on you (whether by court order, agreement or
|
200 |
+
otherwise) that contradict the conditions of this License, they do not
|
201 |
+
excuse you from the conditions of this License. If you cannot
|
202 |
+
distribute so as to satisfy simultaneously your obligations under this
|
203 |
+
License and any other pertinent obligations, then as a consequence you
|
204 |
+
may not distribute the Program at all. For example, if a patent
|
205 |
+
license would not permit royalty-free redistribution of the Program by
|
206 |
+
all those who receive copies directly or indirectly through you, then
|
207 |
+
the only way you could satisfy both it and this License would be to
|
208 |
+
refrain entirely from distribution of the Program.
|
209 |
+
|
210 |
+
If any portion of this section is held invalid or unenforceable under
|
211 |
+
any particular circumstance, the balance of the section is intended to
|
212 |
+
apply and the section as a whole is intended to apply in other
|
213 |
+
circumstances.
|
214 |
+
|
215 |
+
It is not the purpose of this section to induce you to infringe any
|
216 |
+
patents or other property right claims or to contest validity of any
|
217 |
+
such claims; this section has the sole purpose of protecting the
|
218 |
+
integrity of the free software distribution system, which is
|
219 |
+
implemented by public license practices. Many people have made
|
220 |
+
generous contributions to the wide range of software distributed
|
221 |
+
through that system in reliance on consistent application of that
|
222 |
+
system; it is up to the author/donor to decide if he or she is willing
|
223 |
+
to distribute software through any other system and a licensee cannot
|
224 |
+
impose that choice.
|
225 |
+
|
226 |
+
This section is intended to make thoroughly clear what is believed to
|
227 |
+
be a consequence of the rest of this License.
|
228 |
+
|
229 |
+
8. If the distribution and/or use of the Program is restricted in
|
230 |
+
certain countries either by patents or by copyrighted interfaces, the
|
231 |
+
original copyright holder who places the Program under this License
|
232 |
+
may add an explicit geographical distribution limitation excluding
|
233 |
+
those countries, so that distribution is permitted only in or among
|
234 |
+
countries not thus excluded. In such case, this License incorporates
|
235 |
+
the limitation as if written in the body of this License.
|
236 |
+
|
237 |
+
9. The Free Software Foundation may publish revised and/or new versions
|
238 |
+
of the General Public License from time to time. Such new versions will
|
239 |
+
be similar in spirit to the present version, but may differ in detail to
|
240 |
+
address new problems or concerns.
|
241 |
+
|
242 |
+
Each version is given a distinguishing version number. If the Program
|
243 |
+
specifies a version number of this License which applies to it and "any
|
244 |
+
later version", you have the option of following the terms and conditions
|
245 |
+
either of that version or of any later version published by the Free
|
246 |
+
Software Foundation. If the Program does not specify a version number of
|
247 |
+
this License, you may choose any version ever published by the Free Software
|
248 |
+
Foundation.
|
249 |
+
|
250 |
+
10. If you wish to incorporate parts of the Program into other free
|
251 |
+
programs whose distribution conditions are different, write to the author
|
252 |
+
to ask for permission. For software which is copyrighted by the Free
|
253 |
+
Software Foundation, write to the Free Software Foundation; we sometimes
|
254 |
+
make exceptions for this. Our decision will be guided by the two goals
|
255 |
+
of preserving the free status of all derivatives of our free software and
|
256 |
+
of promoting the sharing and reuse of software generally.
|
257 |
+
|
258 |
+
NO WARRANTY
|
259 |
+
|
260 |
+
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
261 |
+
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
262 |
+
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
263 |
+
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
264 |
+
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
265 |
+
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
266 |
+
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
267 |
+
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
268 |
+
REPAIR OR CORRECTION.
|
269 |
+
|
270 |
+
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
271 |
+
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
272 |
+
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
273 |
+
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
274 |
+
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
275 |
+
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
276 |
+
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
277 |
+
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
278 |
+
POSSIBILITY OF SUCH DAMAGES.
|
279 |
+
|
280 |
+
END OF TERMS AND CONDITIONS
|
281 |
+
|
282 |
+
How to Apply These Terms to Your New Programs
|
283 |
+
|
284 |
+
If you develop a new program, and you want it to be of the greatest
|
285 |
+
possible use to the public, the best way to achieve this is to make it
|
286 |
+
free software which everyone can redistribute and change under these terms.
|
287 |
+
|
288 |
+
To do so, attach the following notices to the program. It is safest
|
289 |
+
to attach them to the start of each source file to most effectively
|
290 |
+
convey the exclusion of warranty; and each file should have at least
|
291 |
+
the "copyright" line and a pointer to where the full notice is found.
|
292 |
+
|
293 |
+
<one line to give the program's name and a brief idea of what it does.>
|
294 |
+
Copyright (C) <year> <name of author>
|
295 |
+
|
296 |
+
This program is free software; you can redistribute it and/or modify
|
297 |
+
it under the terms of the GNU General Public License as published by
|
298 |
+
the Free Software Foundation; either version 2 of the License, or
|
299 |
+
(at your option) any later version.
|
300 |
+
|
301 |
+
This program is distributed in the hope that it will be useful,
|
302 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
303 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
304 |
+
GNU General Public License for more details.
|
305 |
+
|
306 |
+
You should have received a copy of the GNU General Public License along
|
307 |
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
308 |
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
309 |
+
|
310 |
+
Also add information on how to contact you by electronic and paper mail.
|
311 |
+
|
312 |
+
If the program is interactive, make it output a short notice like this
|
313 |
+
when it starts in an interactive mode:
|
314 |
+
|
315 |
+
Gnomovision version 69, Copyright (C) year name of author
|
316 |
+
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
317 |
+
This is free software, and you are welcome to redistribute it
|
318 |
+
under certain conditions; type `show c' for details.
|
319 |
+
|
320 |
+
The hypothetical commands `show w' and `show c' should show the appropriate
|
321 |
+
parts of the General Public License. Of course, the commands you use may
|
322 |
+
be called something other than `show w' and `show c'; they could even be
|
323 |
+
mouse-clicks or menu items--whatever suits your program.
|
324 |
+
|
325 |
+
You should also get your employer (if you work as a programmer) or your
|
326 |
+
school, if any, to sign a "copyright disclaimer" for the program, if
|
327 |
+
necessary. Here is a sample; alter the names:
|
328 |
+
|
329 |
+
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
330 |
+
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
331 |
+
|
332 |
+
<signature of Ty Coon>, 1 April 1989
|
333 |
+
Ty Coon, President of Vice
|
334 |
+
|
335 |
+
This General Public License does not permit incorporating your program into
|
336 |
+
proprietary programs. If your program is a subroutine library, you may
|
337 |
+
consider it more useful to permit linking proprietary applications with the
|
338 |
+
library. If this is what you want to do, use the GNU Lesser General
|
339 |
+
Public License instead of this License.
|
README.txt
ADDED
@@ -0,0 +1,377 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== GDPR ===
|
2 |
+
Contributors: fclaussen, matthewfarlymn, trewknowledge
|
3 |
+
Donate link: http://gdpr-wp.com/donate/
|
4 |
+
Tags: gdpr, compliance, privacy, law, general data protection regulation
|
5 |
+
Requires at least: 4.7
|
6 |
+
Requires PHP: 5.6
|
7 |
+
Tested up to: 4.9
|
8 |
+
Stable tag: 1.4.7
|
9 |
+
License: GPLv2 or later
|
10 |
+
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
11 |
+
|
12 |
+
This plugin is meant to assist with the GDPR obligations of a Data processor and Controller.
|
13 |
+
|
14 |
+
== Description ==
|
15 |
+
|
16 |
+
This plugin is meant to assist a Controller, Data Processor, and Data Protection Officer (DPO) with efforts to meet the obligations and rights enacted under the GDPR.
|
17 |
+
|
18 |
+
== Documentation ==
|
19 |
+
[http://gdpr-wp.com/knowledge-base/](http://gdpr-wp.com/knowledge-base/)
|
20 |
+
|
21 |
+
== Collaboration ==
|
22 |
+
|
23 |
+
You can send your pull request at [https://github.com/trewknowledge/gdpr](https://github.com/trewknowledge/gdpr)
|
24 |
+
|
25 |
+
== Shortcodes & helper functions ==
|
26 |
+
[http://gdpr-wp.com/knowledge-base/functions-shortcodes/](http://gdpr-wp.com/knowledge-base/functions-shortcodes/)
|
27 |
+
|
28 |
+
== Features ==
|
29 |
+
|
30 |
+
* Consent management
|
31 |
+
* Privacy Preference management for Cookies with front-end preference UI & banner notifications
|
32 |
+
* Privacy Policy page configurations with version control and re-consent management
|
33 |
+
* Rights to erasure & deletion of website data with a double opt-in confirmation email
|
34 |
+
* Re-assignment of user data on erasure requests & pseudonymization of user website data
|
35 |
+
* Data Processor settings and publishing of contact information
|
36 |
+
* Right to access data by admin dashboard with email look up and export
|
37 |
+
* Right to access data by Data Subject with front-end requests button & double opt-in confirmation email
|
38 |
+
* Right to portability & export of data by Admin or Data Subject in XML or JSON formats
|
39 |
+
* Encrypted audit logs for the lifetime of Data Subject compliance activity
|
40 |
+
* Data Subject Secret Token for two-factor decryption and recovery of data
|
41 |
+
* Data breach notification logs and batch email notifications to Data Subjects
|
42 |
+
* Telemetry Tracker for visualizing plugins and website data
|
43 |
+
|
44 |
+
== Settings ==
|
45 |
+
|
46 |
+
**General**
|
47 |
+
|
48 |
+
From the Settings options in the dashboard, you can select the Privacy Policy page for tracking and logging consent.
|
49 |
+
|
50 |
+
On login, the user must consent to the Privacy Policy outlined on the site. If the user does not consent, the user will not be registered or logged in.
|
51 |
+
|
52 |
+
If the site owner updates the Privacy Policy page content, the change will be logged and flagged to the admin that they must notify users on next login to seek re-consent. Additionally, the warning message can be dismissed in the event of a minor correction or mistake.
|
53 |
+
|
54 |
+
Additionally, under General Settings the Admin can set the outgoing email limitation which would set the batch notification email limit per hour in the event of a Breach Notification.
|
55 |
+
|
56 |
+
**Cookie Preference Management**
|
57 |
+
|
58 |
+
Similar to consent management, users can opt in or out of cookies that are being used on the site. There are 3 formats of cookies that can be created which include:
|
59 |
+
|
60 |
+
* **Always Active:** Cookies that are always active or are required for the site to function.
|
61 |
+
* **Toggled:** Cookies that can be activated or blocked based on the user preference
|
62 |
+
* **Opt-Out Link:** Cookies that require configuration from a third-party source in order to opt-out
|
63 |
+
|
64 |
+
Depending on the user preference setting, you can use the `is_allowed_cookie( $cookie )` function to save and set the cookies. The cookie with the user approved cookies can be found at another cookie named `gdpr_approved_cookies`. There's also a helper function called `is_allowed_cookie( $cookie )` that you can use to prevent setting up a cookie.
|
65 |
+
|
66 |
+
**Consent Management**
|
67 |
+
|
68 |
+
Consents can be registered on the settings page. They can be optional or not. By default, this plugin comes with a Privacy Policy consent that users need to agree with on registration.
|
69 |
+
|
70 |
+
For optional consents, there's a wrapper function `have_consent( $consent_id )` to help you display or hide something on the site depending if the user gave consent or not.
|
71 |
+
|
72 |
+
Consents are logged to the user record for auditing or for access purposes.
|
73 |
+
|
74 |
+
|
75 |
+
== Requests Table & Rights of Data Subject ==
|
76 |
+
|
77 |
+
**Right to Erasure Requests**
|
78 |
+
|
79 |
+
1. The Data Subject is able to submit a request to be erased from the site using a shortcode.
|
80 |
+
1. When a request is made, the Data Subject will receive an email confirmation to confirm the deletion request.
|
81 |
+
|
82 |
+
1. After email confirmation, the user request is added to the requests table for review by the Administrator. The Administrator can also add a user manually with an email look up and review.
|
83 |
+
1. If the Data Subject has content published on the site for any post types or comments, they will be added to this table. If they do not have any content, they will receive a confirmation of erasure request and be provided a 6 digit Token for safekeeping after erasure in case of recover data needs.
|
84 |
+
1. The requests table allows the Administrator to reassign any content to another user or delete it.
|
85 |
+
1. In the event of comments, the Data Subject’s content would be made anonymous.
|
86 |
+
|
87 |
+
1. Admin can also manually add users to the erasure requests table with a manual email search
|
88 |
+
|
89 |
+
**Right to Access Data Request & User Data Portability**
|
90 |
+
|
91 |
+
1. The Data Subject can place a request to download their data with the shortcode.
|
92 |
+
1. After requesting their data, the user will receive a double opt-in confirmation email then the plugin will generate an XML or JSON file, which will be emailed to them for download with an expiration time of 48 hours.
|
93 |
+
|
94 |
+
**Right to Rectify & Complaint Requests**
|
95 |
+
|
96 |
+
1. The Data Subject can place a request to rectify data or file a complaint with the shortcode.
|
97 |
+
1. After making their request, the user will receive a double opt-in confirmation email and then add them to the table for admin to handle the request.
|
98 |
+
|
99 |
+
|
100 |
+
== Tools ==
|
101 |
+
|
102 |
+
**Access Data**
|
103 |
+
|
104 |
+
The Access Data tool allows the Admin to look up a user email and view the data of a particular user. The Admin can download and export the data in a JSON or XML format and provide to the Data Subject if manually requested.
|
105 |
+
|
106 |
+
NOTE: This method should not be used without the Data Subject confirming their identity.
|
107 |
+
|
108 |
+
**Audit Log**
|
109 |
+
|
110 |
+
Everything the Data Subject does from registration, providing consent to the privacy policy, terms of service and other requests are logged and encrypted in a database. Data breach notifications are also logged to all Data Subjects upon confirmation by Controller.
|
111 |
+
|
112 |
+
1. Using the Data Subject's email, you can look up and retrieve the user information and display it.
|
113 |
+
1. If the Data Subject has been removed from the site, this encrypted log is deleted from the database and saved as an encrypted file inside the plugin folder.
|
114 |
+
|
115 |
+
If in the future, the Data Subject makes a complaint or there is a need to recover the data, the user can provide their email address and the 6 digit token they received from the deletion confirmation email to decrypt and retrieve the file.
|
116 |
+
|
117 |
+
**Data Breach & Notifications**
|
118 |
+
|
119 |
+
In case of a data breach, the Admin can generate a Data Breach Notification to users by logging the information and confirm the breach through a double opt-in confirmation email. The following information would be recorded in the audit log:
|
120 |
+
|
121 |
+
1. Nature of the personal data breach
|
122 |
+
1. Name and contact details of the data protection officer
|
123 |
+
1. Likely consequences of the personal data breach
|
124 |
+
1. Measures were taken or proposed to be taken
|
125 |
+
|
126 |
+
Once the confirmation of the breach has been confirmed via email, the website will begin a batch email notification process to all users every hour until all users receive the notification.
|
127 |
+
|
128 |
+
== Telemetry Tracker ==
|
129 |
+
|
130 |
+
The Telemetry Tracker feature will display all data that is being sent outside of your server to another destination. It will indicate the plugin or theme responsible, file and line where the data is being sent.
|
131 |
+
|
132 |
+
WordPress Core and some plugins gather data from your install and send this data to an outside server.
|
133 |
+
|
134 |
+
WordPress Plugin Repository does not allow plugins to do that, but premium plugins are able to do this because they are not bound by the Plugin repository rules. If you did not explicitly opt-in for this feature you should make a complaint.
|
135 |
+
|
136 |
+
|
137 |
+
== Installation ==
|
138 |
+
|
139 |
+
1. Upload the plugin to the `/wp-content/plugins/` directory
|
140 |
+
1. Activate the plugin through the 'Plugins' menu in WordPress
|
141 |
+
1. Fill out all sections of the settings page.
|
142 |
+
|
143 |
+
|
144 |
+
== Important! ==
|
145 |
+
|
146 |
+
Activating this plugin does not guarantee that an organization is successfully meeting its responsibilities and obligations of GDPR. Individual organizations should assess their unique responsibilities and ensure extra measures are taken to meet any obligations required by law and based on a data protection impact assessment (DPIA).
|
147 |
+
|
148 |
+
|
149 |
+
== Frequently Asked Questions ==
|
150 |
+
|
151 |
+
= What is GDPR? =
|
152 |
+
|
153 |
+
This Regulation lays down rules relating to the protection of natural persons with regard to the processing of personal data and rules relating to the free movement of personal data.
|
154 |
+
|
155 |
+
This Regulation protects fundamental rights and freedoms of natural persons and in particular their right to the protection of personal data.
|
156 |
+
|
157 |
+
The free movement of personal data within the Union shall be neither restricted nor prohibited for reasons connected with the protection of natural persons with regard to the processing of personal data.
|
158 |
+
|
159 |
+
= How do Businesses benefit from GDPR? =
|
160 |
+
|
161 |
+
* Build stronger customer relationships and trust
|
162 |
+
* Improve the brand image of the organization and its brand reputation
|
163 |
+
* Improve the governance and responsibility of data
|
164 |
+
* Enhance the security and commitment to the privacy of the brand
|
165 |
+
* Create value-added competitive advantages
|
166 |
+
|
167 |
+
= When is the GDPR coming into effect? =
|
168 |
+
|
169 |
+
It will be enforced on May 25th, 2018.
|
170 |
+
|
171 |
+
= Who does the GDPR affect? =
|
172 |
+
|
173 |
+
The GDPR applies to all EU organisations – whether commercial business, charity or public authority – that collect, store or process EU residents’ personal data, even if they’re not EU citizens.
|
174 |
+
|
175 |
+
The GDPR applies to all organisations located within the EU, whether you are a commercial business, charity or public authority, institution and collect, store or process EU citizen data. It also applies to any organisation located outside of the EU if they also collect store or process EU citizen data.
|
176 |
+
|
177 |
+
= What is considered personal data? =
|
178 |
+
|
179 |
+
The GDPR defines personal data as any information or type of data that can directly or indirectly identify a natural person’s identity. This can include information such as Name, Address, Email, Photos, System Data, IP addresses, Location data, Phone numbers, and Cookies.
|
180 |
+
|
181 |
+
For other special categories of personal data, there are more strict regulations for categories such as Race, Religion, Political Views, Sexual Orientation, Health Information, Biometric and Genetic data.
|
182 |
+
|
183 |
+
= What are the penalties for non-compliance? =
|
184 |
+
|
185 |
+
Organizations can be fined up to 4% of annual global turnover for breaching GDPR or €20 Million. This is the maximum fine that can be imposed for the most serious infringements.
|
186 |
+
|
187 |
+
There is a tiered approach to the fines whereby a company can be fined 2% for not having their records in order (Article 28), not notifying the supervising authority and Data Subject about a security breach or for investigating and assessing the breach.
|
188 |
+
|
189 |
+
= Am I compliant just by activating this plugin? =
|
190 |
+
|
191 |
+
No, this plugin is meant to assist a Controller, Data Processor, and Data Protection Officer (DPO) with efforts to meet the obligations and rights enacted under the GDPR.
|
192 |
+
|
193 |
+
Activating this plugin does not guarantee that an organisation is successfully meeting its responsibilities and obligations of GDPR. Organisations should assess their unique responsibilities and ensure extra measures are taken to meet any obligations required by law and based on a data protection impact assessment (DPIA).
|
194 |
+
|
195 |
+
== Screenshots ==
|
196 |
+
|
197 |
+
1. Cookie settings page.
|
198 |
+
2. Cookie notification bar.
|
199 |
+
3. Cookie management modal.
|
200 |
+
4. Registration with consent checkboxes.
|
201 |
+
5. Consent management modal.
|
202 |
+
6. Privacy Policy page updated. Asking for re-consent.
|
203 |
+
7. User deletion review table.
|
204 |
+
8. Telemetry Tracker.
|
205 |
+
9. Audit Log sample.
|
206 |
+
|
207 |
+
== Changelog ==
|
208 |
+
|
209 |
+
= 1.4.7 =
|
210 |
+
* Fix for users who were complaining about their scroll bars missing if they did not select a privacy policy page.
|
211 |
+
|
212 |
+
= 1.4.6 =
|
213 |
+
* Change re-consent logic so it doesn't influence SEO with repeated content.
|
214 |
+
|
215 |
+
= 1.4.5 =
|
216 |
+
* Minor style adjustments
|
217 |
+
* Body scroll is disabled when modal is active
|
218 |
+
* Adjusting privacy bar to sit behind re-consent modal
|
219 |
+
|
220 |
+
= 1.4.4 =
|
221 |
+
* Fix all_cookies field being displayed as text field instead of hidden.
|
222 |
+
|
223 |
+
= 1.4.3 =
|
224 |
+
* Found one more instance of Telemetry Scanner, changed to Telemetry Tracker.
|
225 |
+
* Delete cookies when users change their preferences and disable some cookies.
|
226 |
+
* Changed cookies used field to textarea for easier reading when lots of cookies are set.
|
227 |
+
* Added a text to the settings page explaining that even if cookies are registered, if the user does not input some text for the privacy banner, it won't show up.
|
228 |
+
* Adding filters for the admin notification email. [https://gdpr-wp.com/knowledge-base/actions-filters/](https://gdpr-wp.com/knowledge-base/actions-filters/)
|
229 |
+
* Adding filters for the request forms button label. [https://gdpr-wp.com/knowledge-base/actions-filters/](https://gdpr-wp.com/knowledge-base/actions-filters/)
|
230 |
+
|
231 |
+
= 1.4.2 =
|
232 |
+
* Fix privacy bar reapearing. Cookie was not set to expire in a year.
|
233 |
+
|
234 |
+
= 1.4.1 =
|
235 |
+
* Allow links in the consent description in the wp profile page.
|
236 |
+
* Force tabs to be an array when empty to fix the notices and fatal error in the front end.
|
237 |
+
* Hide cookies sidebar in the privacy centre window if no cookies were registered.
|
238 |
+
* Adding a filter so the privacy bar button text can be changed.
|
239 |
+
* Changing Telemetry Scanner to Telemetry Tracker for consistency across the plugin.
|
240 |
+
* Translating missing strings.
|
241 |
+
* Adding options to add or remove consent checkboxes to woocommerce registration form and checkout registration form.
|
242 |
+
|
243 |
+
= 1.4.0 =
|
244 |
+
* Adding the option to disable the plugin CSS. Be careful when using this option. Make sure you know what you are doing.
|
245 |
+
* Adding the option to enable or disable the telemetry feature.
|
246 |
+
* Adding the option to add reCaptcha to the request forms.
|
247 |
+
* Adding comments to the personal data export.
|
248 |
+
* Moved privacy bar content field and privacy excerpt field to the general settings tab.
|
249 |
+
* Removed automatic privacy policy link from the privacy bar.
|
250 |
+
* We now accept links in the privacy bar content to get around the last change.
|
251 |
+
* Changed Telemetry cleanup schedule to hourly.
|
252 |
+
* Forcing the privacy bar to stay on the left to avoid CSS incompatibilities.
|
253 |
+
* Renaming the tab classes in the admin panel to again avoid incompatibilities.
|
254 |
+
* Fix privacy preference centre only showing up when cookies were registered.
|
255 |
+
|
256 |
+
= 1.3.5 =
|
257 |
+
* Fix undefined variable warning.
|
258 |
+
* Fix WooCommerce and possibly other plugins nonce manipulation for logged out users. For real this time.
|
259 |
+
* Fix XML export fatal error when meta key starts with a number.
|
260 |
+
|
261 |
+
= 1.3.4 =
|
262 |
+
* Prefixed all nonce actions.
|
263 |
+
* Fixed cookies being checked by default when they should have been unchecked.
|
264 |
+
* Possible fix for strange characters causing XML export to throw an error.
|
265 |
+
* Fix for WooCommerce nonce manipulation for logged out users that was preventing visitors from updating their privacy preferences.
|
266 |
+
|
267 |
+
= 1.3.3 =
|
268 |
+
* Fix translation error everybody has been complaining about.
|
269 |
+
|
270 |
+
= 1.3.2 =
|
271 |
+
* Fix issue with the is_allowed_cookie JS function.
|
272 |
+
|
273 |
+
= 1.3.1 =
|
274 |
+
* Fix consent syncing when difference comes from database and not the cookie.
|
275 |
+
* Might allow people to use external services like iubenda.
|
276 |
+
|
277 |
+
= 1.3.0 =
|
278 |
+
* Added BuddyPress registration form integration.
|
279 |
+
* Added WooCommerce registration and checkout registration form integration.
|
280 |
+
* Added admin notifications when a user makes a request that requires interaction.
|
281 |
+
|
282 |
+
= 1.2.2 =
|
283 |
+
* Adding a couple missing translation strings.
|
284 |
+
* Wrapping the telemetry post type page in an `if` so people can unregister it if they want to.
|
285 |
+
|
286 |
+
= 1.2.1 =
|
287 |
+
* After one user reported that their scroll bar disappeared I decided to remove the code that do that when the reconsent modal shows up. This has no impact on anything, but it might fix this user problem.
|
288 |
+
|
289 |
+
= 1.2.0 =
|
290 |
+
* Fix has_consent and is_allowed_cookie JavaScript functions not being available globally.
|
291 |
+
* Add a function to get the consent checkbox without echoing them.
|
292 |
+
* Change how the user deletion request works. We removed the email attachment to avoid being considered spam. The user can now download it immediatelly by clicking on their email link.
|
293 |
+
* Adding an option for user deletions always be added to the request review table. That will allow you to remove your users from third-party services before removing them from your site.
|
294 |
+
|
295 |
+
= 1.1.6 =
|
296 |
+
* Fix weird javascript issue that was preventing users from using the "Close my account" feature.
|
297 |
+
|
298 |
+
= 1.1.5 =
|
299 |
+
* The gdpr_request_form PHP function was returning instead of echoing. That is now fixed.
|
300 |
+
* Fix issue when syncing consent cookie and database values.
|
301 |
+
* Fix issue that prevented the privacy bar from disappearing after saving privacy preferences.
|
302 |
+
|
303 |
+
= 1.1.4 =
|
304 |
+
* Possible fix for cached sites.
|
305 |
+
* Added has_consent and is_allowed_cookie functions to javascript.
|
306 |
+
* Changed how the privacy bar and re-consent modal show up based on javascript.
|
307 |
+
* Better sync of consent and cookies with a cookie.
|
308 |
+
|
309 |
+
= 1.1.3 =
|
310 |
+
* Changed Complaint and Rectification form submit button wording.
|
311 |
+
* Added a loading indicator on the reconsent window. Slow servers will not give the impression that this featured is not working anymore.
|
312 |
+
* Fixed user notification not showing after confirming deletion email.
|
313 |
+
* Fixed consent "required" toggle not displaying the correct state.
|
314 |
+
* Added a second confirmation after disagreeing to reconsent.
|
315 |
+
|
316 |
+
|
317 |
+
= 1.1.2 =
|
318 |
+
* Fixed reconsent modal not closing after agreeing to the new policy.
|
319 |
+
|
320 |
+
= 1.1.1 =
|
321 |
+
* Forgot to unload jQuery-UI.
|
322 |
+
|
323 |
+
= 1.1.0 =
|
324 |
+
* Merge the two preferences windows into one.
|
325 |
+
* [gdpr_preferences] shortcode doesn't need the 'type' attribute to work anymore.
|
326 |
+
* Removed jQuery UI from the front end and replaced with our own notification window to keep a consistent color scheme, avoid unnecessary requests and avoid style issues from theme to theme.
|
327 |
+
* Allow logged out users to keep track of consents too. ( Those are not logged to the audit log for obvious reasons. )
|
328 |
+
* Added a refresh after preferences change so users can display forms or count the user visit and so on depending on the new user consent.
|
329 |
+
|
330 |
+
= 1.0.6 =
|
331 |
+
* Allowing users to add target on their privacy policy links on the consent description.
|
332 |
+
|
333 |
+
= 1.0.5 =
|
334 |
+
* Allow users to use links on their consent descriptions so they can link to their privacy policy or other pages.
|
335 |
+
|
336 |
+
= 1.0.4 =
|
337 |
+
* Added a link to the privacy policy page on the cookie bar and on the cookie preferences window.
|
338 |
+
* Added a new option for a text just before the privacy policy link on the cookie bar.
|
339 |
+
* Checking if the user actually registered cookies before showing the cookie bar.
|
340 |
+
|
341 |
+
= 1.0.3 =
|
342 |
+
* Added a shortcode for re-opening the cookie or consent management windows.
|
343 |
+
|
344 |
+
= 1.0.2 =
|
345 |
+
* Added new filters for access data so extensions can add more information.
|
346 |
+
* Rebuilt the translation pot file and added translation comments.
|
347 |
+
|
348 |
+
= 1.0.1 =
|
349 |
+
* Fix issue on cookie preferences not saving and displaying php errors.
|
350 |
+
|
351 |
+
= 1.0.0 =
|
352 |
+
* Added cookie management screen
|
353 |
+
* Added consent management screen
|
354 |
+
* Added Telemetry tracker
|
355 |
+
* Complete code rewrite
|
356 |
+
* Added more types of request
|
357 |
+
* Added Help documentation
|
358 |
+
* Added new shortcodes
|
359 |
+
* Changed to Settings API
|
360 |
+
|
361 |
+
= 0.1.1 =
|
362 |
+
* Set the admin email as the default processor information on activation
|
363 |
+
* Settings updated notice is now dismissible
|
364 |
+
|
365 |
+
= 0.1.0 =
|
366 |
+
* Beta version released to the public
|
367 |
+
|
368 |
+
== Upgrade Notice ==
|
369 |
+
|
370 |
+
= 1.0.0 =
|
371 |
+
This is a major rewrite of the plugin. Things will look different and work differently.
|
372 |
+
We tried to keep most things the same so the impact would be minimal.
|
373 |
+
This plugin is no longer in BETA.
|
374 |
+
Update with care
|
375 |
+
|
376 |
+
= 0.1.0 =
|
377 |
+
This plugin is in beta. Use it at your own discretion.
|
admin/class-gdpr-admin.php
ADDED
@@ -0,0 +1,894 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* The admin-specific functionality of the plugin.
|
5 |
+
*
|
6 |
+
* @link https://trewknowledge.com
|
7 |
+
* @since 1.0.0
|
8 |
+
*
|
9 |
+
* @package GDPR
|
10 |
+
* @subpackage admin
|
11 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
12 |
+
*/
|
13 |
+
|
14 |
+
/**
|
15 |
+
* The admin-specific functionality of the plugin.
|
16 |
+
*
|
17 |
+
* Defines the plugin name and version.
|
18 |
+
* Enqueue the admin-specific stylesheet and JavaScript.
|
19 |
+
*
|
20 |
+
* @package GDPR
|
21 |
+
* @subpackage admin
|
22 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
23 |
+
*/
|
24 |
+
class GDPR_Admin {
|
25 |
+
|
26 |
+
/**
|
27 |
+
* The ID of this plugin.
|
28 |
+
*
|
29 |
+
* @since 1.0.0
|
30 |
+
* @access private
|
31 |
+
* @var string $plugin_name The ID of this plugin.
|
32 |
+
*/
|
33 |
+
private $plugin_name;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* The version of this plugin.
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
* @access private
|
40 |
+
* @var string $version The current version of this plugin.
|
41 |
+
*/
|
42 |
+
private $version;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Allowed HTML for wp_kses.
|
46 |
+
* @since 1.0.5
|
47 |
+
* @access private
|
48 |
+
* @var array $allowed_html The allowed HTML for wp_kses.
|
49 |
+
*/
|
50 |
+
private $allowed_html;
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Initialize the class and set its properties.
|
54 |
+
*
|
55 |
+
* @since 1.0.0
|
56 |
+
* @param string $plugin_name The name of this plugin.
|
57 |
+
* @param string $version The version of this plugin.
|
58 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
59 |
+
*/
|
60 |
+
public function __construct( $plugin_name, $version ) {
|
61 |
+
$this->plugin_name = $plugin_name;
|
62 |
+
$this->version = $version;
|
63 |
+
$this->allowed_html = array(
|
64 |
+
'a' => array(
|
65 |
+
'href' => true,
|
66 |
+
'title' => true,
|
67 |
+
'target' => true,
|
68 |
+
),
|
69 |
+
);
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Register the stylesheets for the admin area.
|
74 |
+
*
|
75 |
+
* @since 1.0.0
|
76 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
77 |
+
*/
|
78 |
+
public function enqueue_styles() {
|
79 |
+
add_thickbox();
|
80 |
+
wp_enqueue_style( $this->plugin_name, plugin_dir_url( dirname( __FILE__ ) ) . 'assets/css/gdpr-admin.css', array(), $this->version, 'all' );
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Register the JavaScript for the admin area.
|
85 |
+
*
|
86 |
+
* @since 1.0.0
|
87 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
88 |
+
*/
|
89 |
+
public function enqueue_scripts() {
|
90 |
+
wp_enqueue_script( $this->plugin_name, plugin_dir_url( dirname( __FILE__ ) ) . 'assets/js/gdpr-admin.js', array( 'jquery', 'wp-util', 'jquery-ui-sortable' ), $this->version, false );
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Adds a menu page for the plugin with all it's sub pages.
|
95 |
+
*
|
96 |
+
* @since 1.0.0
|
97 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
98 |
+
*/
|
99 |
+
public function add_menu() {
|
100 |
+
$page_title = esc_html__( 'GDPR', 'gdpr' );
|
101 |
+
$capability = 'manage_options';
|
102 |
+
$parent_slug = 'gdpr-requests';
|
103 |
+
$function = array( $this, 'requests_page_template' );
|
104 |
+
$icon_url = 'dashicons-id';
|
105 |
+
|
106 |
+
$requests = get_option( 'gdpr_requests', array() );
|
107 |
+
$confirmed_requests = array_filter( $requests, function( $item ) {
|
108 |
+
return $item['confirmed'] == true;
|
109 |
+
} );
|
110 |
+
|
111 |
+
$menu_title = esc_html__( 'GDPR', 'gdpr' );
|
112 |
+
if ( count( $confirmed_requests ) ) {
|
113 |
+
$menu_title = sprintf( esc_html( 'GDPR %s' ), '<span class="awaiting-mod">' . count( $confirmed_requests ) . '</span>' );
|
114 |
+
}
|
115 |
+
|
116 |
+
add_menu_page( $page_title, $menu_title, $capability, $parent_slug, $function, $icon_url );
|
117 |
+
|
118 |
+
$menu_title = esc_html__( 'Requests', 'gdpr' );
|
119 |
+
$menu_slug = 'gdpr-requests';
|
120 |
+
$function = array( $this, 'requests_page_template' );
|
121 |
+
|
122 |
+
$requests_hook = add_submenu_page( $parent_slug, $menu_title, $menu_title, $capability, $menu_slug, $function );
|
123 |
+
|
124 |
+
$menu_title = esc_html__( 'Tools', 'gdpr' );
|
125 |
+
$menu_slug = 'gdpr-tools';
|
126 |
+
$function = array( $this, 'tools_page_template' );
|
127 |
+
|
128 |
+
$tools_hook = add_submenu_page( $parent_slug, $menu_title, $menu_title, $capability, $menu_slug, $function );
|
129 |
+
|
130 |
+
$menu_title = esc_html__( 'Settings', 'gdpr' );
|
131 |
+
$menu_slug = 'gdpr-settings';
|
132 |
+
$function = array( $this, 'settings_page_template' );
|
133 |
+
|
134 |
+
$settings_hook = add_submenu_page( $parent_slug, $menu_title, $menu_title, $capability, $menu_slug, $function );
|
135 |
+
|
136 |
+
|
137 |
+
$menu_slug = 'edit.php?post_type=telemetry';
|
138 |
+
|
139 |
+
$cpt = 'telemetry';
|
140 |
+
$cpt_obj = get_post_type_object( $cpt );
|
141 |
+
|
142 |
+
if ( $cpt_obj ) {
|
143 |
+
add_submenu_page( $parent_slug, $cpt_obj->labels->name, $cpt_obj->labels->menu_name, $capability, $menu_slug );
|
144 |
+
}
|
145 |
+
|
146 |
+
|
147 |
+
add_action( "load-{$requests_hook}", array( 'GDPR_Help', 'add_requests_help' ) );
|
148 |
+
add_action( "load-{$tools_hook}", array( 'GDPR_Help', 'add_tools_help' ) );
|
149 |
+
add_action( "load-{$settings_hook}", array( 'GDPR_Help', 'add_settings_help' ) );
|
150 |
+
add_action( "load-edit.php", array( 'GDPR_Help', 'add_telemetry_help' ) );
|
151 |
+
}
|
152 |
+
|
153 |
+
/**
|
154 |
+
* Sanitizing user input on the cookie tabs.
|
155 |
+
* @since 1.0.0
|
156 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
157 |
+
* @param array $tabs The cookie tabs.
|
158 |
+
* @return array The sanitized options.
|
159 |
+
*/
|
160 |
+
public function sanitize_cookie_tabs( $tabs ) {
|
161 |
+
|
162 |
+
$output = array();
|
163 |
+
if ( ! is_array( $tabs ) ) {
|
164 |
+
return array();
|
165 |
+
}
|
166 |
+
|
167 |
+
foreach ( $tabs as $key => $props ) {
|
168 |
+
if ( '' === $props['name'] || '' === $props['how_we_use'] ) {
|
169 |
+
unset( $tabs[ $key ] );
|
170 |
+
continue;
|
171 |
+
}
|
172 |
+
$output[ $key ] = array(
|
173 |
+
'name' => sanitize_text_field( wp_unslash( $props['name'] ) ),
|
174 |
+
'always_active' => isset( $props['always_active'] ) ? boolval( $props['always_active'] ) : 0,
|
175 |
+
'how_we_use' => wp_kses_post( $props['how_we_use'] ),
|
176 |
+
'cookies_used' => sanitize_text_field( wp_unslash( $props['cookies_used'] ) ),
|
177 |
+
);
|
178 |
+
|
179 |
+
if ( isset( $props['hosts'] ) ) {
|
180 |
+
foreach ( $props['hosts'] as $host_key => $host ) {
|
181 |
+
if ( empty( $host['name'] ) || empty( $host['cookies_used'] ) || empty( $host['cookies_used'] ) ) {
|
182 |
+
unset( $props['hosts'][ $host_key ] );
|
183 |
+
continue;
|
184 |
+
}
|
185 |
+
$output[ $key ]['hosts'][ $host_key ] = array(
|
186 |
+
'name' => sanitize_text_field( wp_unslash( $host['name'] ) ),
|
187 |
+
'cookies_used' => sanitize_text_field( wp_unslash( $host['cookies_used'] ) ),
|
188 |
+
'optout' => esc_url_raw( $host['optout'] ),
|
189 |
+
);
|
190 |
+
}
|
191 |
+
}
|
192 |
+
}
|
193 |
+
return $output;
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* Register settings.
|
198 |
+
* @since 1.0.0
|
199 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
200 |
+
*/
|
201 |
+
public function register_settings() {
|
202 |
+
$settings = array(
|
203 |
+
'gdpr_privacy_policy_page' => 'intval',
|
204 |
+
'gdpr_cookie_banner_content' => array( $this, 'sanitize_with_links' ),
|
205 |
+
'gdpr_cookie_privacy_excerpt' => 'sanitize_textarea_field',
|
206 |
+
'gdpr_cookie_popup_content' => array( $this, 'sanitize_cookie_tabs' ),
|
207 |
+
'gdpr_email_limit' => 'intval',
|
208 |
+
'gdpr_consent_types' => array( $this, 'sanitize_consents' ),
|
209 |
+
'gdpr_deletion_needs_review' => 'boolval',
|
210 |
+
'gdpr_disable_css' => 'boolval',
|
211 |
+
'gdpr_enable_telemetry_tracker' => 'boolval',
|
212 |
+
'gdpr_use_recaptcha' => 'boolval',
|
213 |
+
'gdpr_recaptcha_site_key' => 'sanitize_text_field',
|
214 |
+
'gdpr_recaptcha_secret_key' => 'sanitize_text_field',
|
215 |
+
'gdpr_add_consent_checkboxes_registration' => 'boolval',
|
216 |
+
'gdpr_add_consent_checkboxes_checkout' => 'boolval',
|
217 |
+
);
|
218 |
+
foreach ( $settings as $option_name => $sanitize_callback ) {
|
219 |
+
register_setting( 'gdpr', $option_name, array( 'sanitize_callback' => $sanitize_callback ) );
|
220 |
+
}
|
221 |
+
}
|
222 |
+
|
223 |
+
/**
|
224 |
+
* Sanitize content but allow links.
|
225 |
+
* @param string $string The string that will be sanitized.
|
226 |
+
* @return string Sanitized string.
|
227 |
+
* @since 1.4.0
|
228 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
229 |
+
*/
|
230 |
+
public function sanitize_with_links( $string ) {
|
231 |
+
return wp_kses( $string, $this->allowed_html );
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Sanitize the consents option when saving.
|
236 |
+
* @since 1.0.0
|
237 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
238 |
+
* @param array $consents The consents that were registered.
|
239 |
+
* @return array The sanitized consents array.
|
240 |
+
*/
|
241 |
+
public function sanitize_consents( $consents ) {
|
242 |
+
$output = array();
|
243 |
+
if ( ! is_array( $consents ) ) {
|
244 |
+
return $consents;
|
245 |
+
}
|
246 |
+
|
247 |
+
foreach ( $consents as $key => $props ) {
|
248 |
+
if ( '' === $props['name'] || '' === $props['description'] ) {
|
249 |
+
unset( $consents[ $key ] );
|
250 |
+
continue;
|
251 |
+
}
|
252 |
+
$output[ $key ] = array(
|
253 |
+
'name' => sanitize_text_field( wp_unslash( $props['name'] ) ),
|
254 |
+
'required' => isset( $props['required'] ) ? boolval( $props['required'] ) : 0,
|
255 |
+
'description' => wp_kses( wp_unslash( $props['description'] ), $this->allowed_html ),
|
256 |
+
'registration' => wp_kses( wp_unslash( $props['registration'] ), $this->allowed_html ),
|
257 |
+
);
|
258 |
+
}
|
259 |
+
return $output;
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Settings Page Template
|
264 |
+
*
|
265 |
+
* @since 1.0.0
|
266 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
267 |
+
*/
|
268 |
+
public function settings_page_template() {
|
269 |
+
$privacy_policy_page = get_option( 'gdpr_privacy_policy_page', 0 );
|
270 |
+
$tabs = array(
|
271 |
+
'general' => esc_html__( 'General', 'gdpr' ),
|
272 |
+
'cookies' => esc_html__( 'Cookies', 'gdpr' ),
|
273 |
+
'consents' => esc_html__( 'Consents', 'gdpr' ),
|
274 |
+
);
|
275 |
+
|
276 |
+
$tabs = apply_filters( 'gdpr_settings_pages', $tabs );
|
277 |
+
|
278 |
+
include_once plugin_dir_path( __FILE__ ) . 'partials/templates/tmpl-cookies.php';
|
279 |
+
include_once plugin_dir_path( __FILE__ ) . 'partials/templates/tmpl-consents.php';
|
280 |
+
|
281 |
+
include plugin_dir_path( __FILE__ ) . 'partials/settings.php';
|
282 |
+
}
|
283 |
+
|
284 |
+
/**
|
285 |
+
* Requests Page Template.
|
286 |
+
*
|
287 |
+
* @since 1.0.0
|
288 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
289 |
+
*/
|
290 |
+
public function requests_page_template() {
|
291 |
+
$requests = ( array ) get_option( 'gdpr_requests', array() );
|
292 |
+
|
293 |
+
if ( ! empty( $requests ) ) {
|
294 |
+
foreach ( $requests as $index => $request ) {
|
295 |
+
if ( ! $request['confirmed'] ) {
|
296 |
+
continue;
|
297 |
+
}
|
298 |
+
${$request['type']}[ $index ] = $request;
|
299 |
+
}
|
300 |
+
}
|
301 |
+
|
302 |
+
$tabs = array(
|
303 |
+
'rectify' => array(
|
304 |
+
'name' => __( 'Rectify Data', 'gdpr' ),
|
305 |
+
'count' => isset( $rectify ) ? count( $rectify ) : 0,
|
306 |
+
),
|
307 |
+
'complaint' => array(
|
308 |
+
'name' => __( 'Complaint', 'gdpr' ),
|
309 |
+
'count' => isset( $complaint ) ? count( $complaint ) : 0,
|
310 |
+
),
|
311 |
+
'delete' => array(
|
312 |
+
'name' => __( 'Erasure', 'gdpr' ),
|
313 |
+
'count' => isset( $delete ) ? count( $delete ) : 0,
|
314 |
+
),
|
315 |
+
);
|
316 |
+
|
317 |
+
include plugin_dir_path( __FILE__ ) . 'partials/requests.php';
|
318 |
+
}
|
319 |
+
|
320 |
+
/**
|
321 |
+
* Tools Page Template.
|
322 |
+
*
|
323 |
+
* @since 1.0.0
|
324 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
325 |
+
*/
|
326 |
+
public function tools_page_template() {
|
327 |
+
|
328 |
+
$tabs = array(
|
329 |
+
'access' => esc_html__( 'Access Data', 'gdpr' ),
|
330 |
+
'data-breach' => esc_html__( 'Data Breach', 'gdpr' ),
|
331 |
+
'audit-log' => esc_html__( 'Audit Log', 'gdpr' ),
|
332 |
+
);
|
333 |
+
|
334 |
+
include plugin_dir_path( __FILE__ ) . 'partials/tools.php';
|
335 |
+
}
|
336 |
+
|
337 |
+
/**
|
338 |
+
* The data markup on the access data page.
|
339 |
+
* @since 1.0.0
|
340 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
341 |
+
*/
|
342 |
+
public function access_data() {
|
343 |
+
if ( ! isset( $_POST['nonce'], $_POST['email'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'gdpr-access-data' ) ) {
|
344 |
+
wp_send_json_error();
|
345 |
+
}
|
346 |
+
|
347 |
+
$email = sanitize_email( $_POST['email'] );
|
348 |
+
$user = get_user_by( 'email', $email );
|
349 |
+
|
350 |
+
if ( ! $user instanceof WP_User ) {
|
351 |
+
wp_send_json_error();
|
352 |
+
}
|
353 |
+
|
354 |
+
$usermeta = GDPR::get_user_meta( $user->ID );
|
355 |
+
$comments = get_comments( array(
|
356 |
+
'author_email' => $user->user_email,
|
357 |
+
'include_unapproved' => true,
|
358 |
+
) );
|
359 |
+
$user_consents = get_user_meta( $user->ID, 'gdpr_consents' );
|
360 |
+
|
361 |
+
ob_start();
|
362 |
+
echo '<h2>' . $user->display_name . '<span>( ' . $email . ' )</span></h2>';
|
363 |
+
echo '<table class="widefat">
|
364 |
+
<tr>
|
365 |
+
<td class="row-title">Username</td>
|
366 |
+
<td>' . esc_html( $user->user_login ) . '</td>
|
367 |
+
</tr>
|
368 |
+
<tr>
|
369 |
+
<td class="row-title">First Name</td>
|
370 |
+
<td>' . esc_html( $user->first_name ) . '</td>
|
371 |
+
</tr>
|
372 |
+
<tr>
|
373 |
+
<td class="row-title">Last Name</td>
|
374 |
+
<td>' . esc_html( $user->last_name ) . '</td>
|
375 |
+
</tr>
|
376 |
+
<tr>
|
377 |
+
<td class="row-title">Email</td>
|
378 |
+
<td>' . esc_html( $user->user_email ) . '</td>
|
379 |
+
</tr>
|
380 |
+
<tr>
|
381 |
+
<td class="row-title">Nickname</td>
|
382 |
+
<td>' . esc_html( $user->nickname ) . '</td>
|
383 |
+
</tr>
|
384 |
+
<tr>
|
385 |
+
<td class="row-title">Bio</td>
|
386 |
+
<td>' . esc_html( $user->description ) . '</td>
|
387 |
+
</tr>
|
388 |
+
<tr>
|
389 |
+
<td class="row-title">URL</td>
|
390 |
+
<td>' . esc_url( $user->user_url ) . '</td>
|
391 |
+
</tr>
|
392 |
+
<tr>
|
393 |
+
<td class="row-title">Registered</td>
|
394 |
+
<td>' . esc_html( $user->user_registered ) . '</td>
|
395 |
+
</tr>
|
396 |
+
<tr>
|
397 |
+
<td class="row-title">Roles</td>
|
398 |
+
<td>' . esc_html( implode( ', ', $user->roles ) ) . '</td>
|
399 |
+
</tr>
|
400 |
+
</table>';
|
401 |
+
|
402 |
+
if ( ! empty( $user_consents ) ) {
|
403 |
+
echo '<h2>' . esc_html__( 'Consent Given', 'gdpr' ) . '</h2>';
|
404 |
+
echo '<table class="widefat">
|
405 |
+
<thead>
|
406 |
+
<tr>
|
407 |
+
<th>' . esc_html__( 'Consent ID', 'gdpr' ) . '</th>
|
408 |
+
</tr>
|
409 |
+
</thead>';
|
410 |
+
foreach ( $user_consents as $v ) {
|
411 |
+
echo '<tr>';
|
412 |
+
echo '<td class="row-title">' . esc_html( $v ) . '</td>';
|
413 |
+
echo '</tr>';
|
414 |
+
}
|
415 |
+
echo '</table>';
|
416 |
+
}
|
417 |
+
|
418 |
+
if ( ! empty( $comments ) ) {
|
419 |
+
echo '<h2>' . esc_html__( 'Comments', 'gdpr' ) . '</h2>';
|
420 |
+
foreach ( $comments as $v ) {
|
421 |
+
echo '<table class="widefat">
|
422 |
+
<thead>
|
423 |
+
<tr>
|
424 |
+
<th class="row-title">' . esc_html__( 'Comment Field', 'gdpr' ) . '</th>
|
425 |
+
<th class="row-title">' . esc_html__( 'Comment Data', 'gdpr' ) . '</th>
|
426 |
+
</tr>
|
427 |
+
</thead>
|
428 |
+
<tr>
|
429 |
+
<td class="row-title">comment_author</td>
|
430 |
+
<td>' . esc_html( $v->comment_author ) . '</td>
|
431 |
+
</tr>
|
432 |
+
<tr>
|
433 |
+
<td class="row-title">comment_author_email</td>
|
434 |
+
<td>' . esc_html( $v->comment_author_email ) . '</td>
|
435 |
+
</tr>
|
436 |
+
<tr>
|
437 |
+
<td class="row-title">comment_author_url</td>
|
438 |
+
<td>' . esc_html( $v->comment_author_url ) . '</td>
|
439 |
+
</tr>
|
440 |
+
<tr>
|
441 |
+
<td class="row-title">comment_author_IP</td>
|
442 |
+
<td>' . esc_html( $v->comment_author_IP ) . '</td>
|
443 |
+
</tr>
|
444 |
+
<tr>
|
445 |
+
<td class="row-title">comment_date</td>
|
446 |
+
<td>' . esc_html( $v->comment_date ) . '</td>
|
447 |
+
</tr>
|
448 |
+
<tr>
|
449 |
+
<td class="row-title">comment_agent</td>
|
450 |
+
<td>' . esc_html( $v->comment_agent ) . '</td>
|
451 |
+
</tr>
|
452 |
+
<tr>
|
453 |
+
<td class="row-title">comment_content</td>
|
454 |
+
<td>' . esc_html( $v->comment_content ) . '</td>
|
455 |
+
</tr>
|
456 |
+
</table><br>';
|
457 |
+
}
|
458 |
+
}
|
459 |
+
|
460 |
+
if ( ! empty( $usermeta ) ) {
|
461 |
+
echo '<h2>' . esc_html__( 'Metadata', 'gdpr' ) . '</h2>';
|
462 |
+
echo '<table class="widefat">
|
463 |
+
<thead>
|
464 |
+
<tr>
|
465 |
+
<th>' . esc_html__( 'Name', 'gdpr' ) . '</th>
|
466 |
+
<th>' . esc_html__( 'Value', 'gdpr' ) . '</th>
|
467 |
+
</tr>
|
468 |
+
</thead>';
|
469 |
+
foreach ( $usermeta as $k => $v ) {
|
470 |
+
echo '<tr>';
|
471 |
+
echo '<td class="row-title">' . esc_html( $k ) . '</td>';
|
472 |
+
echo '<td>';
|
473 |
+
foreach ( $v as $value ) {
|
474 |
+
if ( is_serialized( $value ) ) {
|
475 |
+
|
476 |
+
echo '<pre>' . print_r( maybe_unserialize( $value ), true ) . '</pre><br />';
|
477 |
+
} else {
|
478 |
+
echo print_r( $value, true ) . '<br />';
|
479 |
+
}
|
480 |
+
}
|
481 |
+
echo '</td>';
|
482 |
+
echo '</tr>';
|
483 |
+
}
|
484 |
+
echo '</table>';
|
485 |
+
|
486 |
+
}
|
487 |
+
|
488 |
+
do_action( 'admin_access_data_extra_tables', $email );
|
489 |
+
|
490 |
+
$result = ob_get_clean();
|
491 |
+
wp_send_json_success( array( 'user_email' => $email, 'result' => $result ) );
|
492 |
+
|
493 |
+
}
|
494 |
+
|
495 |
+
/**
|
496 |
+
* The audit-log for the audit log email lookup.
|
497 |
+
* @since 1.0.0
|
498 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
499 |
+
*/
|
500 |
+
public function audit_log() {
|
501 |
+
if ( ! isset( $_POST['nonce'], $_POST['email'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'gdpr-audit-log' ) ) {
|
502 |
+
wp_send_json_error();
|
503 |
+
}
|
504 |
+
|
505 |
+
$email = sanitize_email( $_POST['email'] );
|
506 |
+
$token = null;
|
507 |
+
|
508 |
+
if ( isset( $_POST['token'] ) ) {
|
509 |
+
$token = sanitize_text_field( wp_unslash( $_POST['token'] ) );
|
510 |
+
}
|
511 |
+
|
512 |
+
$log = GDPR_Audit_log::get_log( $email, $token );
|
513 |
+
|
514 |
+
if ( ! $log ) {
|
515 |
+
wp_send_json_error( esc_html__( 'No logs found for this email.', 'gdpr' ) );
|
516 |
+
}
|
517 |
+
|
518 |
+
wp_send_json_success( $log );
|
519 |
+
}
|
520 |
+
|
521 |
+
/**
|
522 |
+
* Admin notice when the user haven't picked a privacy policy page.
|
523 |
+
* @since 1.0.0
|
524 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
525 |
+
*/
|
526 |
+
public function privacy_policy_page_missing() {
|
527 |
+
$privacy_page = get_option( 'gdpr_privacy_policy_page', '' );
|
528 |
+
if ( ! empty( $privacy_page ) ) {
|
529 |
+
return;
|
530 |
+
}
|
531 |
+
?>
|
532 |
+
<div class="notice notice-error is-dismissible">
|
533 |
+
<p>
|
534 |
+
<strong><?php echo esc_html__( '[GDPR] You must select a Privacy Policy Page.', 'gdpr' ); ?></strong>
|
535 |
+
</p>
|
536 |
+
<p>
|
537 |
+
<a href="<?php echo esc_url( admin_url( 'admin.php?page=gdpr-settings' ) ) ?>" class="button button-primary"><?php esc_html_e( 'Select your Privacy Policy page', 'gdpr' ); ?></a>
|
538 |
+
</p>
|
539 |
+
</div>
|
540 |
+
<?php
|
541 |
+
}
|
542 |
+
|
543 |
+
/**
|
544 |
+
* Admin notice when the privacy policy has been updated.
|
545 |
+
* @since 1.0.0
|
546 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
547 |
+
*/
|
548 |
+
public function privacy_policy_updated_notice() {
|
549 |
+
$updated = get_option( 'gdpr_privacy_policy_updated' );
|
550 |
+
if ( ! $updated ) {
|
551 |
+
return;
|
552 |
+
}
|
553 |
+
?>
|
554 |
+
<div class="notice notice-error privacy-page-updated-notice is-dismissible">
|
555 |
+
<p>
|
556 |
+
<strong><?php echo esc_html__( 'Your Privacy Policy have been updated. In case this was not a small typo fix, you must ask users for explicit consent again.', 'gdpr' ); ?></strong>
|
557 |
+
</p>
|
558 |
+
<form action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post">
|
559 |
+
<?php wp_nonce_field( 'gdpr-seek_consent', 'privacy-policy-updated-nonce' ); ?>
|
560 |
+
<input type="hidden" name="action" value="seek_consent">
|
561 |
+
<p>
|
562 |
+
<?php submit_button( esc_html__( 'Ask for consent', 'gdpr' ), 'primary', 'submit', false ); ?>
|
563 |
+
</p>
|
564 |
+
</form>
|
565 |
+
<form action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post" class="frm-ignore-privacy-update">
|
566 |
+
<?php wp_nonce_field( 'gdpr-ignore_update', 'privacy-policy-ignore-update-nonce' ); ?>
|
567 |
+
<input type="hidden" name="action" value="ignore_privacy_policy_update">
|
568 |
+
<p>
|
569 |
+
<?php submit_button( esc_html__( 'Ignore', 'gdpr' ), 'secondary', 'submit', false ); ?>
|
570 |
+
</p>
|
571 |
+
</form>
|
572 |
+
</div>
|
573 |
+
<?php
|
574 |
+
}
|
575 |
+
|
576 |
+
/**
|
577 |
+
* Sends a confirmation email to the admin email address before continuing with the data breach notification.
|
578 |
+
* @since 1.0.0
|
579 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
580 |
+
*/
|
581 |
+
public function send_data_breach_confirmation_email() {
|
582 |
+
if ( ! isset( $_POST['gdpr_data_breach_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST[ 'gdpr_data_breach_nonce' ] ), 'gdpr-data-breach' ) ) {
|
583 |
+
wp_die( esc_html__( 'We could not verify the the security token. Please try again.', 'gdpr' ) );
|
584 |
+
}
|
585 |
+
|
586 |
+
if (
|
587 |
+
! isset(
|
588 |
+
$_POST['gdpr-data-breach-email-content'],
|
589 |
+
$_POST['gdpr-data-breach-nature'],
|
590 |
+
$_POST['gdpr-name-contact-details-protection-officer'],
|
591 |
+
$_POST['gdpr-likely-consequences'],
|
592 |
+
$_POST['gdpr-measures-taken']
|
593 |
+
)
|
594 |
+
) {
|
595 |
+
wp_die( esc_html__( 'One or more required fields are missing. Please try again.', 'gdpr' ) );
|
596 |
+
}
|
597 |
+
|
598 |
+
$email = get_bloginfo( 'admin_email' );
|
599 |
+
$user = wp_get_current_user();
|
600 |
+
$content = sanitize_textarea_field( wp_unslash( $_POST['gdpr-data-breach-email-content'] ) );
|
601 |
+
$nature = sanitize_textarea_field( wp_unslash( $_POST['gdpr-data-breach-nature'] ) );
|
602 |
+
$office_contact = sanitize_textarea_field( wp_unslash( $_POST['gdpr-name-contact-details-protection-officer'] ) );
|
603 |
+
$consequences = sanitize_textarea_field( wp_unslash( $_POST['gdpr-likely-consequences'] ) );
|
604 |
+
$measures = sanitize_textarea_field( wp_unslash( $_POST['gdpr-measures-taken'] ) );
|
605 |
+
|
606 |
+
$key = wp_generate_password( 20, false );
|
607 |
+
update_option( 'gdpr_data_breach_initiated', array(
|
608 |
+
'key' => $key,
|
609 |
+
'content' => $content,
|
610 |
+
'nature' => $nature,
|
611 |
+
'office_contact' => $office_contact,
|
612 |
+
'consequences' => $consequences,
|
613 |
+
'measures' => $measures
|
614 |
+
) );
|
615 |
+
|
616 |
+
$confirm_url = add_query_arg(
|
617 |
+
array(
|
618 |
+
'type' => 'data-breach-confirmed',
|
619 |
+
'key' => $key
|
620 |
+
),
|
621 |
+
get_home_url() . wp_get_referer() . '#data-breach'
|
622 |
+
);
|
623 |
+
|
624 |
+
GDPR_Email::send(
|
625 |
+
$email,
|
626 |
+
'data-breach-request',
|
627 |
+
array(
|
628 |
+
'requester' => $user->user_email,
|
629 |
+
'nature'=> $nature,
|
630 |
+
'office_contact' => $office_contact,
|
631 |
+
'consequences' => $consequences,
|
632 |
+
'measures' => $measures,
|
633 |
+
'confirm_url' => $confirm_url,
|
634 |
+
)
|
635 |
+
);
|
636 |
+
|
637 |
+
if ( $time = wp_next_scheduled( 'clean_gdpr_data_breach_request' ) ) {
|
638 |
+
wp_unschedule_event( $time, 'clean_gdpr_data_breach_request' );
|
639 |
+
}
|
640 |
+
wp_schedule_single_event( time() + 2 * DAY_IN_SECONDS, 'clean_gdpr_data_breach_request' );
|
641 |
+
|
642 |
+
add_settings_error( 'gdpr', 'resolved', esc_html__( 'Data breach notification has been initialized. An email confirmation has been sent to the website controller.', 'gdpr' ), 'updated' );
|
643 |
+
set_transient( 'settings_errors', get_settings_errors(), 30 );
|
644 |
+
wp_safe_redirect(
|
645 |
+
esc_url_raw(
|
646 |
+
add_query_arg(
|
647 |
+
array(
|
648 |
+
'settings-updated' => true
|
649 |
+
),
|
650 |
+
wp_get_referer() . '#data-breach'
|
651 |
+
)
|
652 |
+
)
|
653 |
+
);
|
654 |
+
exit;
|
655 |
+
}
|
656 |
+
|
657 |
+
/**
|
658 |
+
* CRON Job runs this after a couple days to cancel the data breach request.
|
659 |
+
* @since 1.0.0
|
660 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
661 |
+
*/
|
662 |
+
public function clean_data_breach_request() {
|
663 |
+
delete_option( 'gdpr_data_breach_initiated' );
|
664 |
+
}
|
665 |
+
|
666 |
+
/**
|
667 |
+
* CRON job runs this to clean up the telemetry post type every 12 hours.
|
668 |
+
* @since 1.0.0
|
669 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
670 |
+
*/
|
671 |
+
public function telemetry_cleanup() {
|
672 |
+
$args = array(
|
673 |
+
'post_type' => 'telemetry',
|
674 |
+
'posts_per_page' => -1,
|
675 |
+
'fields' => 'ids',
|
676 |
+
);
|
677 |
+
|
678 |
+
$telemetry_posts = get_posts( $args );
|
679 |
+
|
680 |
+
foreach ( $telemetry_posts as $post ) {
|
681 |
+
wp_delete_post( $post, true );
|
682 |
+
}
|
683 |
+
}
|
684 |
+
|
685 |
+
/**
|
686 |
+
* Sanitizes the consents during wordpress registration.
|
687 |
+
* @since 1.0.0
|
688 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
689 |
+
* @param WP_Error $errors The error object.
|
690 |
+
* @param string $sanitized_user_login The user login.
|
691 |
+
* @param string $user_email The user email.
|
692 |
+
* @return WP_Error WP_Error object with added errors or not.
|
693 |
+
*/
|
694 |
+
public function registration_errors( $errors, $sanitized_user_login, $user_email ) {
|
695 |
+
$consent_types = get_option( 'gdpr_consent_types', array() );
|
696 |
+
if ( empty( $consent_types ) ) {
|
697 |
+
return $errors;
|
698 |
+
}
|
699 |
+
|
700 |
+
foreach ( $consent_types as $key => $consent ) {
|
701 |
+
if ( $consent['required'] ) {
|
702 |
+
if ( ! isset( $_POST['user_consents'][ $key ] ) ) {
|
703 |
+
$errors->add( 'missing_required_consents', sprintf(
|
704 |
+
'<strong>%s</strong>: %s %s.',
|
705 |
+
__( 'ERROR', 'gdpr' ),
|
706 |
+
$consent['name'],
|
707 |
+
__( 'is a required consent', 'gdpr' )
|
708 |
+
) );
|
709 |
+
}
|
710 |
+
}
|
711 |
+
}
|
712 |
+
return $errors;
|
713 |
+
}
|
714 |
+
|
715 |
+
/**
|
716 |
+
* Remove the Privacy Policy consent from all users. On next login they will need to consent again.
|
717 |
+
* @since 1.0.0
|
718 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
719 |
+
*/
|
720 |
+
public function seek_consent() {
|
721 |
+
if ( ! isset( $_POST['privacy-policy-updated-nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['privacy-policy-updated-nonce'] ), 'gdpr-seek_consent' ) ) {
|
722 |
+
wp_die( esc_html__( 'We could not verify the the security token. Please try again.', 'gdpr' ) );
|
723 |
+
}
|
724 |
+
|
725 |
+
delete_option( 'gdpr_privacy_policy_updated' );
|
726 |
+
|
727 |
+
$users = get_users( array(
|
728 |
+
'fields' => 'all_with_meta'
|
729 |
+
) );
|
730 |
+
|
731 |
+
foreach ( $users as $user ) {
|
732 |
+
$usermeta = get_user_meta( $user->ID, 'gdpr_consents' );
|
733 |
+
if ( in_array( 'privacy-policy', $usermeta ) ) {
|
734 |
+
GDPR_Audit_Log::log( $user->ID, esc_html__( 'Privacy Policy has been updated. Removing the Privacy Policy consent and requesting new consent.', 'gdpr' ) );
|
735 |
+
delete_user_meta( $user->ID, 'gdpr_consents', 'privacy-policy' );
|
736 |
+
}
|
737 |
+
}
|
738 |
+
|
739 |
+
add_settings_error( 'gdpr', 'resolved', esc_html__( 'Users will have to consent to the updated privacy policy on login.', 'gdpr' ), 'updated' );
|
740 |
+
set_transient( 'settings_errors', get_settings_errors(), 30 );
|
741 |
+
wp_safe_redirect(
|
742 |
+
esc_url_raw(
|
743 |
+
add_query_arg(
|
744 |
+
array(
|
745 |
+
'settings-updated' => true
|
746 |
+
),
|
747 |
+
wp_get_referer()
|
748 |
+
)
|
749 |
+
)
|
750 |
+
);
|
751 |
+
exit;
|
752 |
+
}
|
753 |
+
|
754 |
+
/**
|
755 |
+
* Check if the privacy policy page content has been updated or not.
|
756 |
+
* @since 1.0.0
|
757 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
758 |
+
* @param int $ID The page ID.
|
759 |
+
* @param WP_Post $post The post object.
|
760 |
+
*/
|
761 |
+
public function privacy_policy_updated( $ID, $post ) {
|
762 |
+
$privacy_page = (int) get_option( 'gdpr_privacy_policy_page', 0 );
|
763 |
+
$ID = (int) $ID;
|
764 |
+
if ( $ID === $privacy_page ) {
|
765 |
+
$revisions = wp_get_post_revisions( $ID );
|
766 |
+
$revisions = array_filter( $revisions, function( $rev ) {
|
767 |
+
return strpos( $rev->post_name, 'autosave' ) === false;
|
768 |
+
});
|
769 |
+
|
770 |
+
reset( $revisions );
|
771 |
+
if ( current( $revisions )->post_content !== $post->post_content ) {
|
772 |
+
update_option( 'gdpr_privacy_policy_updated', 1 );
|
773 |
+
}
|
774 |
+
}
|
775 |
+
}
|
776 |
+
|
777 |
+
/**
|
778 |
+
* Ignore the privacy policy update. The update was probably just a typo fix.
|
779 |
+
* @since 1.0.0
|
780 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
781 |
+
*/
|
782 |
+
public function ignore_privacy_policy_update() {
|
783 |
+
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'gdpr-ignore_update' ) ) {
|
784 |
+
wp_send_json_error( esc_html__( 'We could not verify the the security token. Please try again.', 'gdpr' ) );
|
785 |
+
}
|
786 |
+
|
787 |
+
delete_option( 'gdpr_privacy_policy_updated' );
|
788 |
+
wp_send_json_success();
|
789 |
+
}
|
790 |
+
|
791 |
+
/**
|
792 |
+
* Add consent checkboxes to the user profile on wp dashboard.
|
793 |
+
* @since 1.0.0
|
794 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
795 |
+
* @param WP_User $user The user object.
|
796 |
+
*/
|
797 |
+
public function edit_user_profile( $user ) {
|
798 |
+
$consent_types = get_option( 'gdpr_consent_types', array() );
|
799 |
+
$user_consents = get_user_meta( $user->ID, 'gdpr_consents' );
|
800 |
+
if ( empty( $consent_types ) ) {
|
801 |
+
return;
|
802 |
+
}
|
803 |
+
?>
|
804 |
+
<h3><?php _e( 'Consent Management', 'gdpr' ); ?></h3>
|
805 |
+
|
806 |
+
<table class="form-table">
|
807 |
+
<?php foreach ( $consent_types as $consent_key => $consent ): ?>
|
808 |
+
<tr>
|
809 |
+
<th>
|
810 |
+
<label><?php echo esc_html( $consent['name'] ); ?></label>
|
811 |
+
</th>
|
812 |
+
<td>
|
813 |
+
<?php if ( $consent['required'] ): ?>
|
814 |
+
<input type="checkbox" name="user_consents[]" value="<?php echo esc_attr( $consent_key ); ?>" disabled checked>
|
815 |
+
<input type="hidden" name="user_consents[]" value="<?php echo esc_attr( $consent_key ); ?>">
|
816 |
+
<?php else: ?>
|
817 |
+
<input type="checkbox" name="user_consents[]" value="<?php echo esc_attr( $consent_key ); ?>" <?php echo ! empty( $user_consents ) ? checked( in_array( $consent_key, $user_consents, true ), 1, false ) : ''; ?>>
|
818 |
+
<?php endif ?>
|
819 |
+
<span class="description"><?php echo wp_kses( $consent['description'], $this->allowed_html ); ?></span>
|
820 |
+
</td>
|
821 |
+
</tr>
|
822 |
+
<?php endforeach ?>
|
823 |
+
</table>
|
824 |
+
|
825 |
+
<?php
|
826 |
+
}
|
827 |
+
|
828 |
+
/**
|
829 |
+
* Save the user consent preferences when he update his profile on wp dashboard.
|
830 |
+
* @since 1.0.0
|
831 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
832 |
+
* @param int $user_id The user ID.
|
833 |
+
*/
|
834 |
+
public function user_profile_update( $user_id ) {
|
835 |
+
if ( ! isset( $_POST['user_consents'] ) ) {
|
836 |
+
return;
|
837 |
+
}
|
838 |
+
|
839 |
+
$consents = array_map( 'sanitize_text_field', (array) $_POST['user_consents'] );
|
840 |
+
|
841 |
+
GDPR_Audit_Log::log( $user_id, esc_html__( 'Profile Updated. These are the user consents after the save:', 'gdpr' ) );
|
842 |
+
|
843 |
+
delete_user_meta( $user_id, 'gdpr_consents' );
|
844 |
+
|
845 |
+
foreach ( (array) $consents as $consent ) {
|
846 |
+
$consent = sanitize_text_field( wp_unslash( $consent ) );
|
847 |
+
add_user_meta( $user_id, 'gdpr_consents', $consent );
|
848 |
+
GDPR_Audit_Log::log( $user_id, $consent );
|
849 |
+
}
|
850 |
+
|
851 |
+
setcookie( "gdpr[consent_types]", json_encode( $consents ), time() + YEAR_IN_SECONDS, "/" );
|
852 |
+
}
|
853 |
+
|
854 |
+
/**
|
855 |
+
* Add the consent checkboxes to the checkout page.
|
856 |
+
* @since 1.3.0
|
857 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
858 |
+
* @param int $fields The checkout fields.
|
859 |
+
*/
|
860 |
+
public function woocommerce_consent_checkboxes( $fields ) {
|
861 |
+
$consent_types = get_option( 'gdpr_consent_types', array() );
|
862 |
+
|
863 |
+
foreach ( $consent_types as $key => $consent ) {
|
864 |
+
$required = ( isset( $consent['required'] ) && $consent['required'] ) ? 'required' : '';
|
865 |
+
|
866 |
+
$fields['account']['user_consents_' . esc_attr( $key ) ] = array(
|
867 |
+
'type' => 'checkbox',
|
868 |
+
'label' => wp_kses( $consent['registration'], $this->allowed_html ),
|
869 |
+
'required' => $required,
|
870 |
+
);
|
871 |
+
}
|
872 |
+
return $fields;
|
873 |
+
}
|
874 |
+
|
875 |
+
/**
|
876 |
+
* Save the user consent when registering from the checkout page.
|
877 |
+
* @since 1.3.0
|
878 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
879 |
+
* @param int $customer_id The user ID.
|
880 |
+
* @param array $data All data submitted during checkout.
|
881 |
+
*/
|
882 |
+
public function woocommerce_checkout_save_consent( $customer_id, $data ) {
|
883 |
+
$data = array_filter( $data );
|
884 |
+
$consent_arr = array_filter( array_keys( $data ), function( $item ) {
|
885 |
+
return false !== strpos( $item, 'user_consents_' );
|
886 |
+
} );
|
887 |
+
|
888 |
+
foreach ( $consent_arr as $key => $value ) {
|
889 |
+
$consent = str_replace( 'user_consents_', '', $value );
|
890 |
+
add_user_meta( $customer_id, 'gdpr_consents', $consent );
|
891 |
+
}
|
892 |
+
}
|
893 |
+
|
894 |
+
}
|
admin/class-gdpr-requests-admin.php
ADDED
@@ -0,0 +1,359 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* The admin facing requests functionality of the plugin.
|
5 |
+
*
|
6 |
+
* @link https://trewknowledge.com
|
7 |
+
* @since 1.0.0
|
8 |
+
*
|
9 |
+
* @package GDPR
|
10 |
+
* @subpackage admin
|
11 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
12 |
+
*/
|
13 |
+
|
14 |
+
/**
|
15 |
+
* The admin facing requests functionality of the plugin.
|
16 |
+
*
|
17 |
+
* @package GDPR
|
18 |
+
* @subpackage admin
|
19 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
20 |
+
*/
|
21 |
+
class GDPR_Requests_Admin extends GDPR_Requests {
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Add the user to the deletion requests list.
|
25 |
+
* @since 1.0.0
|
26 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
27 |
+
*/
|
28 |
+
public function add_to_deletion_requests() {
|
29 |
+
if ( ! isset( $_POST['gdpr_deletion_requests_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['gdpr_deletion_requests_nonce'] ), 'gdpr-add-to-deletion-requests' ) ) {
|
30 |
+
wp_die( esc_html__( 'We could not verify the user email or the security token. Please try again.', 'gdpr' ) );
|
31 |
+
}
|
32 |
+
|
33 |
+
$email = sanitize_email( $_POST['user_email'] );
|
34 |
+
$user = get_user_by( 'email', $email );
|
35 |
+
|
36 |
+
if ( ! $user instanceof WP_User ) {
|
37 |
+
add_settings_error( 'gdpr-requests', 'invalid-user', esc_html__( 'User not found.', 'gdpr' ), 'error' );
|
38 |
+
set_transient( 'settings_errors', get_settings_errors(), 30 );
|
39 |
+
wp_safe_redirect(
|
40 |
+
esc_url_raw(
|
41 |
+
add_query_arg(
|
42 |
+
array(
|
43 |
+
'settings-updated' => true
|
44 |
+
),
|
45 |
+
wp_get_referer() . '#delete'
|
46 |
+
)
|
47 |
+
)
|
48 |
+
);
|
49 |
+
exit;
|
50 |
+
} else {
|
51 |
+
if ( in_array( 'administrator', $user->roles ) ) {
|
52 |
+
$admins_query = new WP_User_Query( array(
|
53 |
+
'role' => 'Administrator'
|
54 |
+
) );
|
55 |
+
if ( 1 === $admins_query->get_total() ) {
|
56 |
+
/* translators: User email */
|
57 |
+
add_settings_error( 'gdpr-requests', 'invalid-request', sprintf( esc_html__( 'User %s is the only admin of the site. It cannot be deleted.', 'gdpr' ), $email ), 'error' );
|
58 |
+
set_transient( 'settings_errors', get_settings_errors(), 30 );
|
59 |
+
wp_safe_redirect(
|
60 |
+
esc_url_raw(
|
61 |
+
add_query_arg(
|
62 |
+
array(
|
63 |
+
'settings-updated' => true
|
64 |
+
),
|
65 |
+
wp_get_referer() . '#delete'
|
66 |
+
)
|
67 |
+
)
|
68 |
+
);
|
69 |
+
exit;
|
70 |
+
}
|
71 |
+
}
|
72 |
+
}
|
73 |
+
|
74 |
+
$requests = ( array ) get_option( 'gdpr_requests', array() );
|
75 |
+
|
76 |
+
if ( empty( $requests ) ) {
|
77 |
+
parent::add_to_requests( $email, 'delete', null, true );
|
78 |
+
GDPR_Audit_Log::log( $user->ID, esc_html__( 'User added to the deletion requests list by admin.', 'gdpr' ) );
|
79 |
+
/* translators: User email */
|
80 |
+
add_settings_error( 'gdpr-requests', 'new-request', sprintf( esc_html__( 'User %s was added to the deletion table.', 'gdpr' ), $email ), 'updated' );
|
81 |
+
set_transient( 'settings_errors', get_settings_errors(), 30 );
|
82 |
+
wp_safe_redirect(
|
83 |
+
esc_url_raw(
|
84 |
+
add_query_arg(
|
85 |
+
array(
|
86 |
+
'settings-updated' => true
|
87 |
+
),
|
88 |
+
wp_get_referer() . '#delete'
|
89 |
+
)
|
90 |
+
)
|
91 |
+
);
|
92 |
+
exit;
|
93 |
+
}
|
94 |
+
|
95 |
+
$deletion_requests = array_filter( $requests, function( $arr ) {
|
96 |
+
return 'delete' === $arr['type'];
|
97 |
+
});
|
98 |
+
$user_has_already_requested = array_search( $email, array_column( $deletion_requests, 'email' ) );
|
99 |
+
|
100 |
+
if ( false !== $user_has_already_requested ) {
|
101 |
+
add_settings_error( 'gdpr-requests', 'invalid-user', esc_html__( 'User already placed a deletion request.', 'gdpr' ), 'error' );
|
102 |
+
set_transient( 'settings_errors', get_settings_errors(), 30 );
|
103 |
+
wp_safe_redirect(
|
104 |
+
esc_url_raw(
|
105 |
+
add_query_arg(
|
106 |
+
array(
|
107 |
+
'settings-updated' => true
|
108 |
+
),
|
109 |
+
wp_get_referer() . '#delete'
|
110 |
+
)
|
111 |
+
)
|
112 |
+
);
|
113 |
+
exit;
|
114 |
+
}
|
115 |
+
|
116 |
+
parent::add_to_requests( $email, 'delete', null, true );
|
117 |
+
GDPR_Audit_Log::log( $user->ID, esc_html__( 'User added to the deletion requests list by admin.', 'gdpr' ) );
|
118 |
+
/* translators: User email */
|
119 |
+
add_settings_error( 'gdpr-requests', 'new-request', sprintf( esc_html__( 'User %s was added to the deletion table.', 'gdpr' ), $email ), 'updated' );
|
120 |
+
set_transient( 'settings_errors', get_settings_errors(), 30 );
|
121 |
+
wp_safe_redirect(
|
122 |
+
esc_url_raw(
|
123 |
+
add_query_arg(
|
124 |
+
array(
|
125 |
+
'settings-updated' => true
|
126 |
+
),
|
127 |
+
wp_get_referer() . '#delete'
|
128 |
+
)
|
129 |
+
)
|
130 |
+
);
|
131 |
+
exit;
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Cancels a request.
|
136 |
+
* @since 1.0.0
|
137 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
138 |
+
*/
|
139 |
+
public function cancel_request() {
|
140 |
+
if ( ! isset( $_POST['type'] ) ) {
|
141 |
+
wp_die( esc_html__( 'We could not verify the type of request you want to cancel.', 'gdpr' ) );
|
142 |
+
}
|
143 |
+
|
144 |
+
$type = sanitize_text_field( trim( strtolower( $_POST['type'] ) ) );
|
145 |
+
$allowed_types = parent::get_allowed_types();
|
146 |
+
|
147 |
+
if ( ! in_array( $type, $allowed_types ) ) {
|
148 |
+
/* translators: The type of request */
|
149 |
+
wp_die( sprintf( esc_html__( 'Type of request \'%s\' is not an allowed type.', 'gdpr' ), $type ) );
|
150 |
+
}
|
151 |
+
|
152 |
+
$nonce_field = 'gdpr_cancel_' . $type . '_nonce';
|
153 |
+
|
154 |
+
if ( ! isset( $_POST[ $nonce_field ], $_POST['user_email'], $_POST['index'] ) || ! wp_verify_nonce( sanitize_key( $_POST[ $nonce_field ] ), 'gdpr-request-nonce' ) ) {
|
155 |
+
wp_die( esc_html__( 'We could not verify the user email or the security token. Please try again.', 'gdpr' ) );
|
156 |
+
}
|
157 |
+
|
158 |
+
$email = sanitize_email( $_POST['user_email'] );
|
159 |
+
$index = sanitize_text_field( wp_unslash( $_POST['index'] ) );
|
160 |
+
|
161 |
+
parent::remove_from_requests( $index );
|
162 |
+
$user = get_user_by( 'email', $email );
|
163 |
+
/* translators: The type of request i.e 'delete' */
|
164 |
+
GDPR_Audit_Log::log( $user->ID, sprintf( esc_html__( 'User was removed from the %s request list by admin.', 'gdpr' ), $type ) );
|
165 |
+
|
166 |
+
/* translators: User email */
|
167 |
+
add_settings_error( 'gdpr-requests', 'remove-request', sprintf( esc_html__( 'User %s was removed from this request table.', 'gdpr' ), $email ), 'updated' );
|
168 |
+
set_transient( 'settings_errors', get_settings_errors(), 30 );
|
169 |
+
wp_safe_redirect(
|
170 |
+
esc_url_raw(
|
171 |
+
add_query_arg(
|
172 |
+
array(
|
173 |
+
'settings-updated' => true
|
174 |
+
),
|
175 |
+
wp_get_referer() . '#' . $type
|
176 |
+
)
|
177 |
+
)
|
178 |
+
);
|
179 |
+
exit;
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Marks a request as resolved and notifies the user.
|
184 |
+
* @since 1.0.0
|
185 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
186 |
+
*/
|
187 |
+
public function mark_resolved() {
|
188 |
+
if ( ! isset( $_POST['type'] ) ) {
|
189 |
+
wp_die( esc_html__( 'We could not verify the type of request you want to cancel.', 'gdpr' ) );
|
190 |
+
}
|
191 |
+
|
192 |
+
$type = sanitize_text_field( trim( strtolower( $_POST['type'] ) ) );
|
193 |
+
$allowed_types = parent::get_allowed_types();
|
194 |
+
|
195 |
+
if ( ! in_array( $type, $allowed_types ) ) {
|
196 |
+
/* translators: The type of request i.e. 'delete' */
|
197 |
+
wp_die( sprintf( esc_html__( 'Type of request \'%s\' is not an allowed type.', 'gdpr' ), $type ) );
|
198 |
+
}
|
199 |
+
|
200 |
+
$nonce_field = 'gdpr_' . $type . '_mark_resolved_nonce';
|
201 |
+
|
202 |
+
if ( ! isset( $_POST[ $nonce_field ], $_POST['user_email'], $_POST['index'] ) || ! wp_verify_nonce( sanitize_key( $_POST[ $nonce_field ] ), 'gdpr-mark-as-resolved' ) ) {
|
203 |
+
wp_die( esc_html__( 'We could not verify the user email or the security token. Please try again.', 'gdpr' ) );
|
204 |
+
}
|
205 |
+
|
206 |
+
$email = sanitize_email( $_POST['user_email'] );
|
207 |
+
$index = sanitize_text_field( $_POST['index'] );
|
208 |
+
|
209 |
+
|
210 |
+
parent::remove_from_requests( $index );
|
211 |
+
|
212 |
+
GDPR_Email::send( $email, $type . '-resolved' );
|
213 |
+
|
214 |
+
$user = get_user_by( 'email', $email );
|
215 |
+
/* translators: User email */
|
216 |
+
GDPR_Audit_Log::log( $user->ID, sprintf( esc_html__( 'User %s request was marked as resolved by admin.', 'gdpr' ), $user->user_email ) );
|
217 |
+
|
218 |
+
add_settings_error( 'gdpr-requests', 'resolved', sprintf( esc_html__( 'Request was resolved. User %s has been notified.', 'gdpr' ), $email ), 'updated' );
|
219 |
+
set_transient( 'settings_errors', get_settings_errors(), 30 );
|
220 |
+
wp_safe_redirect(
|
221 |
+
esc_url_raw(
|
222 |
+
add_query_arg(
|
223 |
+
array(
|
224 |
+
'settings-updated' => true
|
225 |
+
),
|
226 |
+
wp_get_referer() . '#' . $type
|
227 |
+
)
|
228 |
+
)
|
229 |
+
);
|
230 |
+
exit;
|
231 |
+
}
|
232 |
+
|
233 |
+
/**
|
234 |
+
* Deletes a user from the admin interface.
|
235 |
+
* @since 1.0.0
|
236 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
237 |
+
*/
|
238 |
+
public function delete_user() {
|
239 |
+
if ( ! isset( $_POST['gdpr_delete_user'], $_POST['user_email'], $_POST['index'] ) || ! wp_verify_nonce( $_POST['gdpr_delete_user'], 'gdpr-request-delete-user' ) ) {
|
240 |
+
wp_die( esc_html__( 'We could not verify the user email or the security token. Please try again.', 'gdpr' ) );
|
241 |
+
}
|
242 |
+
|
243 |
+
$email = sanitize_email( $_POST['user_email'] );
|
244 |
+
$user = get_user_by( 'email', $email );
|
245 |
+
$index = sanitize_text_field( $_POST['index'] );
|
246 |
+
parent::remove_from_requests( $index );
|
247 |
+
|
248 |
+
$token = GDPR::generate_pin();
|
249 |
+
GDPR_Email::send( $user->user_email, 'delete-resolved', array( 'token' => $token ) );
|
250 |
+
|
251 |
+
GDPR_Audit_Log::log( $user->ID, esc_html__( 'User was removed from the site.', 'gdpr') );
|
252 |
+
GDPR_Audit_Log::export_log( $user->ID, $token );
|
253 |
+
wp_delete_user( $user->ID );
|
254 |
+
|
255 |
+
/* translators: User email */
|
256 |
+
add_settings_error( 'gdpr-requests', 'new-request', sprintf( esc_html__( 'User %s was deleted from the site.', 'gdpr' ), $email ), 'updated' );
|
257 |
+
set_transient( 'settings_errors', get_settings_errors(), 30 );
|
258 |
+
wp_safe_redirect(
|
259 |
+
esc_url_raw(
|
260 |
+
add_query_arg(
|
261 |
+
array(
|
262 |
+
'settings-updated' => true
|
263 |
+
),
|
264 |
+
wp_get_referer() . '#delete'
|
265 |
+
)
|
266 |
+
)
|
267 |
+
);
|
268 |
+
exit;
|
269 |
+
}
|
270 |
+
|
271 |
+
/**
|
272 |
+
* Anonymize comments from a user.
|
273 |
+
* @since 1.0.0
|
274 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
275 |
+
*/
|
276 |
+
public function anonymize_comments() {
|
277 |
+
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'gdpr-anonymize-comments-action' ) ) {
|
278 |
+
wp_send_json_error( esc_html__( 'We could not verify the security token. Please try again.', 'gdpr' ) );
|
279 |
+
}
|
280 |
+
|
281 |
+
$email = sanitize_email( $_POST['user_email'] );
|
282 |
+
$comment_count = ( int ) $_POST['comment_count'];
|
283 |
+
|
284 |
+
$user = get_user_by( 'email', $email );
|
285 |
+
if ( ! $user instanceof WP_User ) {
|
286 |
+
wp_send_json_error( esc_html__( 'User not found.', 'gdpr' ) );
|
287 |
+
}
|
288 |
+
|
289 |
+
$comments = get_comments( array(
|
290 |
+
'author_email' => $user->user_email,
|
291 |
+
'include_unapproved' => true,
|
292 |
+
'number' => $comment_count,
|
293 |
+
) );
|
294 |
+
|
295 |
+
foreach ( $comments as $comment ) {
|
296 |
+
$new_comment = array();
|
297 |
+
$new_comment['comment_ID'] = $comment->comment_ID;
|
298 |
+
$new_comment['comment_author_IP'] = '0.0.0.0';
|
299 |
+
$new_comment['comment_author_email'] = '';
|
300 |
+
$new_comment['comment_author_url'] = '';
|
301 |
+
$new_comment['comment_agent'] = '';
|
302 |
+
$new_comment['comment_author'] = esc_html__( 'Guest', 'gdpr' );
|
303 |
+
$new_comment['user_id'] = 0;
|
304 |
+
wp_update_comment( $new_comment );
|
305 |
+
}
|
306 |
+
GDPR_Audit_Log::log( $user->ID, esc_html__( 'User comments were anonymized.', 'gdpr' ) );
|
307 |
+
wp_send_json_success();
|
308 |
+
}
|
309 |
+
|
310 |
+
/**
|
311 |
+
* Reassign content to a different user.
|
312 |
+
* @since 1.0.0
|
313 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
314 |
+
*/
|
315 |
+
public function reassign_content() {
|
316 |
+
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'gdpr-reassign-content-action' ) ) {
|
317 |
+
wp_send_json_error( esc_html__( 'We could not verify the security token. Please try again.', 'gdpr' ) );
|
318 |
+
}
|
319 |
+
|
320 |
+
if ( ! isset( $_POST['user_email'], $_POST['reassign_to'], $_POST['post_type'], $_POST['post_count'] ) ) {
|
321 |
+
wp_send_json_error( esc_html__( 'Essential data missing. Please try again.', 'gdpr' ) );
|
322 |
+
}
|
323 |
+
|
324 |
+
$email = sanitize_email( $_POST['user_email'] );
|
325 |
+
$reassign_to = ( int ) $_POST['reassign_to'];
|
326 |
+
$post_type = sanitize_text_field( wp_unslash( $_POST['post_type'] ) );
|
327 |
+
$post_count = ( int ) $_POST['post_count'];
|
328 |
+
|
329 |
+
$user = get_user_by( 'email', $email );
|
330 |
+
if ( ! $user instanceof WP_User ) {
|
331 |
+
wp_send_json_error( esc_html__( 'User not found.', 'gdpr' ) );
|
332 |
+
}
|
333 |
+
|
334 |
+
$args = array(
|
335 |
+
'author' => $user->ID,
|
336 |
+
'post_type' => $post_type,
|
337 |
+
'posts_per_page' => $post_count,
|
338 |
+
);
|
339 |
+
|
340 |
+
$posts = get_posts( $args );
|
341 |
+
|
342 |
+
if ( ! empty( $posts ) ) {
|
343 |
+
foreach ( $posts as $post ) {
|
344 |
+
wp_update_post( array(
|
345 |
+
'ID' => $post->ID,
|
346 |
+
'post_author' => $reassign_to,
|
347 |
+
) );
|
348 |
+
}
|
349 |
+
|
350 |
+
$reassign_to_user = get_user_by( 'ID', $reassign_to );
|
351 |
+
/* translators: 1: The post type, 2: The user the posts were reassigned to */
|
352 |
+
GDPR_Audit_Log::log( $user->ID, sprintf( esc_html__( 'User %s were reassigned to %s.', 'gdpr' ), $post_type, $reassign_to_user->display_name ) );
|
353 |
+
wp_send_json_success();
|
354 |
+
}
|
355 |
+
|
356 |
+
wp_send_json_error( esc_html__( 'Something went wrong. Please try again.', 'gdpr' ) );
|
357 |
+
}
|
358 |
+
|
359 |
+
}
|
admin/class-gdpr-telemetry.php
ADDED
@@ -0,0 +1,517 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* The telemetry post type registration file.
|
4 |
+
*
|
5 |
+
* @link https://trewknowledge.com
|
6 |
+
* @since 1.0.0
|
7 |
+
*
|
8 |
+
* @package GDPR
|
9 |
+
* @subpackage admin
|
10 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* The telemetry post type registration file.
|
15 |
+
*
|
16 |
+
* Defines the custom post type and edit the look and feel of the page.
|
17 |
+
*
|
18 |
+
* @package GDPR
|
19 |
+
* @subpackage admin
|
20 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
21 |
+
*/
|
22 |
+
class GDPR_Telemetry {
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Registers the telemetry post type.
|
26 |
+
* @since 1.0.0
|
27 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
28 |
+
*/
|
29 |
+
public function register_post_type() {
|
30 |
+
$telemetry_enabled = get_option( 'gdpr_enable_telemetry_tracker', false );
|
31 |
+
if ( ! $telemetry_enabled ) {
|
32 |
+
wp_clear_scheduled_hook( 'telemetry_cleanup' );
|
33 |
+
return;
|
34 |
+
}
|
35 |
+
|
36 |
+
if ( ! wp_next_scheduled( 'telemetry_cleanup' ) ) {
|
37 |
+
wp_schedule_event(
|
38 |
+
time(),
|
39 |
+
'hourly',
|
40 |
+
'telemetry_cleanup'
|
41 |
+
);
|
42 |
+
}
|
43 |
+
|
44 |
+
register_post_type(
|
45 |
+
'telemetry',
|
46 |
+
array(
|
47 |
+
'label' => esc_html__( 'Telemetry', 'gdpr' ),
|
48 |
+
'labels' => array(
|
49 |
+
'not_found' => esc_html__( 'No items found. Future connections will be shown at this place.', 'gdpr' ),
|
50 |
+
'not_found_in_trash' => esc_html__( 'No items found in trash.', 'gdpr' ),
|
51 |
+
'search_items' => esc_html__( 'Search in destination', 'gdpr' ),
|
52 |
+
),
|
53 |
+
'public' => false,
|
54 |
+
'show_ui' => true,
|
55 |
+
'show_in_menu' => false,
|
56 |
+
'show_in_nav_menus' => false,
|
57 |
+
'query_var' => true, // try setting to false
|
58 |
+
'hierarchical' => false,
|
59 |
+
'capability_type' => 'post',
|
60 |
+
'publicly_queryable' => false,
|
61 |
+
'exclude_from_search' => true
|
62 |
+
)
|
63 |
+
);
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Log the call request.
|
68 |
+
* @param object $response The call response.
|
69 |
+
* @param [type] $type Context under which the hook is fired.
|
70 |
+
* @param [type] $class HTTP transport used.
|
71 |
+
* @param [type] $args HTTP request arguments.
|
72 |
+
* @param [type] $url The request URL.
|
73 |
+
* @since 1.0.0
|
74 |
+
*/
|
75 |
+
public function log_request( $response, $type, $class, $args, $url ) {
|
76 |
+
$telemetry_enabled = get_option( 'gdpr_enable_telemetry_tracker', false );
|
77 |
+
if ( ! $telemetry_enabled ) {
|
78 |
+
return;
|
79 |
+
}
|
80 |
+
/* Only response type */
|
81 |
+
if ( 'response' !== $type ) {
|
82 |
+
return false;
|
83 |
+
}
|
84 |
+
|
85 |
+
/* Empty url */
|
86 |
+
if ( empty( $url ) ) {
|
87 |
+
return false;
|
88 |
+
}
|
89 |
+
|
90 |
+
/* Validate host */
|
91 |
+
$host = parse_url( $url, PHP_URL_HOST );
|
92 |
+
|
93 |
+
if ( ! $host ) {
|
94 |
+
return false;
|
95 |
+
}
|
96 |
+
|
97 |
+
/* Backtrace data */
|
98 |
+
$backtrace = self::_debug_backtrace();
|
99 |
+
|
100 |
+
/* No reference file found */
|
101 |
+
if ( empty( $backtrace['file'] ) ) {
|
102 |
+
return false;
|
103 |
+
}
|
104 |
+
|
105 |
+
/* Show your face, file */
|
106 |
+
$meta = self::_face_detect( $backtrace['file'] );
|
107 |
+
|
108 |
+
/* Extract backtrace data */
|
109 |
+
$file = str_replace( ABSPATH, '', $backtrace['file'] );
|
110 |
+
$line = ( int ) $backtrace['line'];
|
111 |
+
|
112 |
+
/* Response code */
|
113 |
+
$code = ( is_wp_error( $response ) ? -1 : wp_remote_retrieve_response_code( $response ) );
|
114 |
+
|
115 |
+
$postdata = self::_get_postdata( $args );
|
116 |
+
|
117 |
+
if ( ! $postdata ) {
|
118 |
+
return false;
|
119 |
+
}
|
120 |
+
|
121 |
+
/* Insert CPT */
|
122 |
+
$this->insert_post( array(
|
123 |
+
'url' => esc_url_raw($url),
|
124 |
+
'code' => $code,
|
125 |
+
'host' => $host,
|
126 |
+
'file' => $file,
|
127 |
+
'line' => $line,
|
128 |
+
'meta' => $meta,
|
129 |
+
'postdata' => $postdata,
|
130 |
+
) );
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Insert the telemetry post.
|
135 |
+
* @since 1.0.0
|
136 |
+
* @access private
|
137 |
+
* @param array $meta Meta values.
|
138 |
+
* @return int The post ID.
|
139 |
+
*/
|
140 |
+
private function insert_post( $meta ) {
|
141 |
+
/* Empty? */
|
142 |
+
if ( empty( $meta ) ) {
|
143 |
+
return;
|
144 |
+
}
|
145 |
+
|
146 |
+
/* Create post */
|
147 |
+
$post_id = wp_insert_post(
|
148 |
+
array(
|
149 |
+
'post_status' => 'publish',
|
150 |
+
'post_type' => 'telemetry'
|
151 |
+
)
|
152 |
+
);
|
153 |
+
|
154 |
+
/* Add meta values */
|
155 |
+
foreach( (array) $meta as $key => $value ) {
|
156 |
+
add_post_meta( $post_id, '_gdpr_telemetry_' .$key, $value, true );
|
157 |
+
}
|
158 |
+
|
159 |
+
return $post_id;
|
160 |
+
}
|
161 |
+
|
162 |
+
/**
|
163 |
+
* Add a Delete All button on top of the table.
|
164 |
+
* @param string $post_type The post type.
|
165 |
+
* @static
|
166 |
+
* @since 1.0.0
|
167 |
+
*/
|
168 |
+
public static function actions_above_table( $post_type ) {
|
169 |
+
if ( 'telemetry' !== $post_type ) {
|
170 |
+
return;
|
171 |
+
}
|
172 |
+
|
173 |
+
$url = wp_nonce_url(
|
174 |
+
add_query_arg(
|
175 |
+
array(
|
176 |
+
'action' => 'delete_all',
|
177 |
+
'post_type' => 'telemetry',
|
178 |
+
'post_status' => 'publish'
|
179 |
+
),
|
180 |
+
admin_url('edit.php')
|
181 |
+
),
|
182 |
+
'bulk-posts'
|
183 |
+
);
|
184 |
+
?>
|
185 |
+
<a href="<?php echo esc_url( $url ); ?>" class="button"><?php echo esc_html__('Delete all', 'gdpr'); ?></a>
|
186 |
+
<?php
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Adding custom columns.
|
191 |
+
* @since 1.0.0
|
192 |
+
* @param array $columns The columns array.
|
193 |
+
* @return array The new columns.
|
194 |
+
*/
|
195 |
+
public function manage_columns( $columns ) {
|
196 |
+
return array(
|
197 |
+
'url' => esc_html__( 'Destination', 'gdpr' ),
|
198 |
+
'file' => esc_html__( 'File', 'gdpr' ),
|
199 |
+
'code' => esc_html__( 'Code', 'gdpr' ),
|
200 |
+
'created' => esc_html__( 'Time', 'gdpr' ),
|
201 |
+
'postdata' => esc_html__( 'Data', 'gdpr')
|
202 |
+
);
|
203 |
+
}
|
204 |
+
|
205 |
+
/**
|
206 |
+
* Custom columns hook.
|
207 |
+
* @since 1.0.0
|
208 |
+
* @static
|
209 |
+
* @param string $column The column ID.
|
210 |
+
* @param int $post_id The post ID.
|
211 |
+
*/
|
212 |
+
public static function custom_column( $column, $post_id ) {
|
213 |
+
/* Column types */
|
214 |
+
$types = array(
|
215 |
+
'url' => array( __CLASS__, '_html_url' ),
|
216 |
+
'file' => array( __CLASS__, '_html_file' ),
|
217 |
+
'code' => array( __CLASS__, '_html_code' ),
|
218 |
+
'created' => array( __CLASS__, '_html_created' ),
|
219 |
+
'postdata' => array( __CLASS__, '_html_postdata' )
|
220 |
+
);
|
221 |
+
|
222 |
+
/* If type exists */
|
223 |
+
if ( ! empty( $types[ $column ] ) ) {
|
224 |
+
/* Callback */
|
225 |
+
$callback = $types[ $column ];
|
226 |
+
|
227 |
+
/* Execute */
|
228 |
+
if ( is_callable( $callback ) ) {
|
229 |
+
call_user_func( $callback, $post_id );
|
230 |
+
}
|
231 |
+
}
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* The URL column callback.
|
236 |
+
* @since 1.0.0
|
237 |
+
* @static
|
238 |
+
* @access private
|
239 |
+
* @param int $post_id The post ID.
|
240 |
+
*/
|
241 |
+
private static function _html_url( $post_id ) {
|
242 |
+
/* Init data */
|
243 |
+
$url = self::_get_post_meta( $post_id, 'url' );
|
244 |
+
$host = self::_get_post_meta( $post_id, 'host' );
|
245 |
+
|
246 |
+
/* Print output */
|
247 |
+
echo sprintf(
|
248 |
+
'<div>%s</div>',
|
249 |
+
str_replace( $host, '<code>' .$host. '</code>', esc_url( $url ) )
|
250 |
+
);
|
251 |
+
}
|
252 |
+
|
253 |
+
/**
|
254 |
+
* The file column callback.
|
255 |
+
* @since 1.0.0
|
256 |
+
* @access private
|
257 |
+
* @static
|
258 |
+
* @param int $post_id The post ID.
|
259 |
+
*/
|
260 |
+
private static function _html_file( $post_id ) {
|
261 |
+
$file = self::_get_post_meta( $post_id, 'file' );
|
262 |
+
$line = self::_get_post_meta( $post_id, 'line' );
|
263 |
+
$meta = self::_get_post_meta( $post_id, 'meta' );
|
264 |
+
|
265 |
+
/* Print output */
|
266 |
+
echo sprintf(
|
267 |
+
'<div>%s: %s<br /><code>/%s:%d</code></div>',
|
268 |
+
$meta['type'],
|
269 |
+
$meta['name'],
|
270 |
+
$file,
|
271 |
+
$line
|
272 |
+
);
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* The response code column callback.
|
277 |
+
* @since 1.0.0
|
278 |
+
* @access private
|
279 |
+
* @static
|
280 |
+
* @param int $post_id The post ID.
|
281 |
+
*/
|
282 |
+
private static function _html_code( $post_id ) {
|
283 |
+
echo self::_get_post_meta( $post_id, 'code' );
|
284 |
+
}
|
285 |
+
|
286 |
+
/**
|
287 |
+
* The created column callback.
|
288 |
+
* @since 1.0.0
|
289 |
+
* @access private
|
290 |
+
* @static
|
291 |
+
* @param int $post_id The post ID.
|
292 |
+
*/
|
293 |
+
private static function _html_created( $post_id ) {
|
294 |
+
/* translators: Amount of time */
|
295 |
+
echo sprintf(
|
296 |
+
esc_html__( '%s ago' ),
|
297 |
+
human_time_diff( get_post_time( 'G', true, $post_id ) )
|
298 |
+
);
|
299 |
+
}
|
300 |
+
|
301 |
+
/**
|
302 |
+
* The post data column callback.
|
303 |
+
* @since 1.0.0
|
304 |
+
* @access private
|
305 |
+
* @static
|
306 |
+
* @param int $post_id The post ID.
|
307 |
+
*/
|
308 |
+
private static function _html_postdata( $post_id ) {
|
309 |
+
/* Item post data */
|
310 |
+
$postdata = self::_get_post_meta( $post_id, 'postdata' );
|
311 |
+
|
312 |
+
/* Empty data? */
|
313 |
+
if ( empty( $postdata ) ) {
|
314 |
+
return;
|
315 |
+
}
|
316 |
+
|
317 |
+
/* Parse POST data */
|
318 |
+
if ( ! is_array( $postdata ) ) {
|
319 |
+
wp_parse_str( $postdata, $postdata );
|
320 |
+
}
|
321 |
+
|
322 |
+
/* Empty array? */
|
323 |
+
if ( empty( $postdata ) ) {
|
324 |
+
return;
|
325 |
+
}
|
326 |
+
|
327 |
+
/* Thickbox content start */
|
328 |
+
echo sprintf(
|
329 |
+
'<div id="gdpr-telemetry-thickbox-%d" class="gdpr-hidden"><pre>',
|
330 |
+
$post_id
|
331 |
+
);
|
332 |
+
|
333 |
+
/* POST data */
|
334 |
+
print_r( $postdata );
|
335 |
+
|
336 |
+
/* Thickbox content end */
|
337 |
+
echo '</pre></div>';
|
338 |
+
|
339 |
+
/* Thickbox button */
|
340 |
+
echo sprintf(
|
341 |
+
'<a href="#TB_inline?width=400&height=300&inlineId=gdpr-telemetry-thickbox-%d" class="button thickbox">%s</a>',
|
342 |
+
$post_id,
|
343 |
+
esc_html__( 'Show', 'gdpr' )
|
344 |
+
);
|
345 |
+
}
|
346 |
+
|
347 |
+
/**
|
348 |
+
* Get the post meta we care about.
|
349 |
+
* @since 1.0.0
|
350 |
+
* @access private
|
351 |
+
* @static
|
352 |
+
* @param int $post_id The post ID.
|
353 |
+
* @param string $key The key that matters to us.
|
354 |
+
* @return mixed The post meta.
|
355 |
+
*/
|
356 |
+
private static function _get_post_meta( $post_id, $key ) {
|
357 |
+
if ( $value = get_post_meta( $post_id, '_gdpr_telemetry_' .$key, true ) ) {
|
358 |
+
return $value;
|
359 |
+
}
|
360 |
+
|
361 |
+
return get_post_meta( $post_id, $key, true );
|
362 |
+
}
|
363 |
+
|
364 |
+
/**
|
365 |
+
* The debug backtrace of the call. This gives us the file and line of origin of the call.
|
366 |
+
* @since 1.0.0
|
367 |
+
* @access private
|
368 |
+
* @static
|
369 |
+
* @return array Extra information about the call like File and Line.
|
370 |
+
*/
|
371 |
+
private static function _debug_backtrace() {
|
372 |
+
/* Reverse items */
|
373 |
+
$trace = array_reverse( debug_backtrace() );
|
374 |
+
|
375 |
+
/* Loop items */
|
376 |
+
foreach( $trace as $index => $item ) {
|
377 |
+
if ( ! empty( $item['function'] ) && strpos( $item['function'], 'wp_remote_' ) !== false ) {
|
378 |
+
/* Use prev item */
|
379 |
+
if ( empty( $item['file'] ) ) {
|
380 |
+
$item = $trace[-- $index];
|
381 |
+
}
|
382 |
+
|
383 |
+
/* Get file and line */
|
384 |
+
if ( ! empty( $item['file'] ) && ! empty( $item['line'] ) ) {
|
385 |
+
return $item;
|
386 |
+
}
|
387 |
+
}
|
388 |
+
}
|
389 |
+
}
|
390 |
+
|
391 |
+
/**
|
392 |
+
* Is the call coming from a theme or plugin?
|
393 |
+
* @since 1.0.0
|
394 |
+
* @access private
|
395 |
+
* @static
|
396 |
+
* @param string $path Path to the file.
|
397 |
+
* @return array The name of the plugin or theme that made the call.
|
398 |
+
*/
|
399 |
+
private static function _face_detect( $path ) {
|
400 |
+
/* Default */
|
401 |
+
$meta = array(
|
402 |
+
'type' => 'WordPress',
|
403 |
+
'name' => 'Core'
|
404 |
+
);
|
405 |
+
|
406 |
+
/* Empty path */
|
407 |
+
if ( empty( $path ) ) {
|
408 |
+
return $meta;
|
409 |
+
}
|
410 |
+
|
411 |
+
/* Search for plugin */
|
412 |
+
if ( $data = self::_localize_plugin( $path ) ) {
|
413 |
+
return array(
|
414 |
+
'type' => 'Plugin',
|
415 |
+
'name' => $data['Name'],
|
416 |
+
);
|
417 |
+
|
418 |
+
/* Search for theme */
|
419 |
+
} else if ( $data = self::_localize_theme( $path ) ) {
|
420 |
+
return array(
|
421 |
+
'type' => 'Theme',
|
422 |
+
'name' => $data->get( 'Name' ),
|
423 |
+
);
|
424 |
+
}
|
425 |
+
|
426 |
+
return $meta;
|
427 |
+
}
|
428 |
+
|
429 |
+
/**
|
430 |
+
* Figures out if the file that made the call belongs to a plugin.
|
431 |
+
* @since 1.0.0
|
432 |
+
* @access private
|
433 |
+
* @static
|
434 |
+
* @param string $path The path to the file that made the call.
|
435 |
+
* @return string The plugin name.
|
436 |
+
*/
|
437 |
+
private static function _localize_plugin( $path ) {
|
438 |
+
/* Check path */
|
439 |
+
if ( false === strpos( $path, WP_PLUGIN_DIR ) ) {
|
440 |
+
return false;
|
441 |
+
}
|
442 |
+
|
443 |
+
/* Reduce path */
|
444 |
+
$path = ltrim( str_replace( WP_PLUGIN_DIR, '', $path ), DIRECTORY_SEPARATOR );
|
445 |
+
|
446 |
+
/* Get plugin folder */
|
447 |
+
$folder = substr( $path, 0, strpos( $path, DIRECTORY_SEPARATOR ) ) . DIRECTORY_SEPARATOR;
|
448 |
+
|
449 |
+
/* Frontend */
|
450 |
+
if ( ! function_exists( 'get_plugins' ) ) {
|
451 |
+
require_once( ABSPATH. 'wp-admin/includes/plugin.php' );
|
452 |
+
}
|
453 |
+
|
454 |
+
/* All active plugins */
|
455 |
+
$plugins = get_plugins();
|
456 |
+
|
457 |
+
/* Loop plugins */
|
458 |
+
foreach( $plugins as $path => $plugin ) {
|
459 |
+
if ( 0 === strpos( $path, $folder ) ) {
|
460 |
+
return $plugin;
|
461 |
+
}
|
462 |
+
}
|
463 |
+
}
|
464 |
+
|
465 |
+
/**
|
466 |
+
* Figures out if the file that made the call belongs to a theme.
|
467 |
+
* @since 1.0.0
|
468 |
+
* @access private
|
469 |
+
* @static
|
470 |
+
* @param string $path The path to the file that made the call.
|
471 |
+
* @return string The theme name.
|
472 |
+
*/
|
473 |
+
private static function _localize_theme( $path ) {
|
474 |
+
/* Check path */
|
475 |
+
if ( false === strpos( $path, get_theme_root() ) ) {
|
476 |
+
return false;
|
477 |
+
}
|
478 |
+
|
479 |
+
/* Reduce path */
|
480 |
+
$path = ltrim( str_replace( get_theme_root(), '', $path ), DIRECTORY_SEPARATOR );
|
481 |
+
|
482 |
+
/* Get theme folder */
|
483 |
+
$folder = substr( $path, 0, strpos( $path, DIRECTORY_SEPARATOR ) );
|
484 |
+
|
485 |
+
/* Get theme */
|
486 |
+
$theme = wp_get_theme( $folder );
|
487 |
+
|
488 |
+
/* Check & return theme */
|
489 |
+
if ( $theme->exists() ) {
|
490 |
+
return $theme;
|
491 |
+
}
|
492 |
+
|
493 |
+
return false;
|
494 |
+
}
|
495 |
+
|
496 |
+
/**
|
497 |
+
* The data that was transmitted.
|
498 |
+
* @since 1.0.0
|
499 |
+
* @access private
|
500 |
+
* @static
|
501 |
+
* @param array $args The http call arguments.
|
502 |
+
* @return mixed The request body.
|
503 |
+
*/
|
504 |
+
private static function _get_postdata( $args ) {
|
505 |
+
/* No POST data? */
|
506 |
+
if ( empty( $args['method'] ) OR 'POST' !== $args['method'] ) {
|
507 |
+
return NULL;
|
508 |
+
}
|
509 |
+
|
510 |
+
/* No body data? */
|
511 |
+
if ( empty( $args['body'] ) ) {
|
512 |
+
return NULL;
|
513 |
+
}
|
514 |
+
|
515 |
+
return $args['body'];
|
516 |
+
}
|
517 |
+
}
|
admin/index.php
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php // Silence is golden
|
admin/partials/index.php
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php // Silence is golden
|
admin/partials/requests.php
ADDED
@@ -0,0 +1,323 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Provide a admin area view for the plugin
|
5 |
+
*
|
6 |
+
* This file is used to markup the admin-facing aspects of the plugin.
|
7 |
+
*
|
8 |
+
* @link https://trewknowledge.com
|
9 |
+
* @since 1.0.0
|
10 |
+
*
|
11 |
+
* @package GDPR
|
12 |
+
* @subpackage admin/partials
|
13 |
+
*/
|
14 |
+
|
15 |
+
?>
|
16 |
+
|
17 |
+
<div class="wrap gdpr">
|
18 |
+
<h1><?php esc_html_e( 'Requests', 'gdpr' ); ?></h1>
|
19 |
+
<?php settings_errors(); ?>
|
20 |
+
<div class="nav-tab-wrapper">
|
21 |
+
<?php foreach ( $tabs as $key => $value ) : ?>
|
22 |
+
<a href="<?php echo '#' . $key; ?>" class="nav-tab">
|
23 |
+
<?php echo esc_html( $value['name'] ); ?>
|
24 |
+
<?php if ( $value['count'] ): ?>
|
25 |
+
<span class="gdpr-pending-requests-badge"><?php echo esc_html( $value['count'] ); ?></span>
|
26 |
+
<?php endif ?>
|
27 |
+
</a>
|
28 |
+
<?php endforeach; ?>
|
29 |
+
</div>
|
30 |
+
|
31 |
+
<div class="gdpr-tab hidden" data-id="rectify">
|
32 |
+
<h2><?php esc_html_e( 'Rectify Data', 'gdpr' ) ?></h2>
|
33 |
+
<table class="widefat gdpr-request-table">
|
34 |
+
<thead>
|
35 |
+
<tr>
|
36 |
+
<th><?php esc_html_e( 'Email', 'gdpr' ); ?></th>
|
37 |
+
<th class="text-center"><?php esc_html_e( 'Date of Request', 'gdpr' ); ?></th>
|
38 |
+
<th class="text-center"><?php esc_html_e( 'Information', 'gdpr' ); ?></th>
|
39 |
+
<th class="text-center"><?php esc_html_e( 'Actions', 'gdpr' ); ?></th>
|
40 |
+
</tr>
|
41 |
+
</thead>
|
42 |
+
<tbody>
|
43 |
+
<?php if ( isset( $rectify ) && ! empty( $rectify ) ): ?>
|
44 |
+
<?php foreach ( $rectify as $i => $request ): ?>
|
45 |
+
<tr>
|
46 |
+
<td class="row-title"><?php echo esc_html( $request['email'] ); ?></td>
|
47 |
+
<td class="text-center"><?php echo esc_html( $request['date'] ); ?></td>
|
48 |
+
<td class="text-center"><?php echo wp_kses( wpautop( wp_unslash( $request['data'] ) ), array( 'p' => true, 'br' => true ) ); ?></td>
|
49 |
+
<td class="text-center">
|
50 |
+
<form class="frm-process-rectification" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post">
|
51 |
+
<?php wp_nonce_field( 'gdpr-request-nonce', 'gdpr_cancel_rectify_nonce' ); ?>
|
52 |
+
<input type="hidden" name="action" value="gdpr_cancel_request">
|
53 |
+
<input type="hidden" name="type" value="rectify">
|
54 |
+
<input type="hidden" name="index" value="<?php echo esc_attr( $i ); ?>">
|
55 |
+
<input type="hidden" name="user_email" value="<?php echo esc_attr( $request['email'] ) ?>">
|
56 |
+
<?php submit_button( esc_html__( 'Cancel Request', 'gdpr' ), 'delete', '', false ) ?>
|
57 |
+
</form>
|
58 |
+
<form class="frm-process-rectification" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post">
|
59 |
+
<?php wp_nonce_field( 'gdpr-mark-as-resolved', 'gdpr_rectify_mark_resolved_nonce' ); ?>
|
60 |
+
<input type="hidden" name="action" value="gdpr_mark_resolved">
|
61 |
+
<input type="hidden" name="type" value="rectify">
|
62 |
+
<input type="hidden" name="index" value="<?php echo esc_attr( $i ); ?>">
|
63 |
+
<input type="hidden" name="user_email" value="<?php echo esc_attr( $request['email'] ) ?>">
|
64 |
+
<?php submit_button( esc_html__( 'Mark as Resolved', 'gdpr' ), 'primary', '', false ) ?>
|
65 |
+
</form>
|
66 |
+
</td>
|
67 |
+
</tr>
|
68 |
+
<?php endforeach ?>
|
69 |
+
<?php else: ?>
|
70 |
+
<tr>
|
71 |
+
<td colspan="4" class="text-center">
|
72 |
+
<?php esc_html_e( 'No pending requests', 'gdpr' ); ?>
|
73 |
+
</td>
|
74 |
+
</tr>
|
75 |
+
<?php endif ?>
|
76 |
+
</tbody>
|
77 |
+
<tfoot>
|
78 |
+
<tr>
|
79 |
+
<th><?php esc_html_e( 'Email', 'gdpr' ); ?></th>
|
80 |
+
<th class="text-center"><?php esc_html_e( 'Date of Request', 'gdpr' ); ?></th>
|
81 |
+
<th class="text-center"><?php esc_html_e( 'Information', 'gdpr' ); ?></th>
|
82 |
+
<th class="text-center"><?php esc_html_e( 'Actions', 'gdpr' ); ?></th>
|
83 |
+
</tr>
|
84 |
+
</tfoot>
|
85 |
+
</table>
|
86 |
+
</div>
|
87 |
+
|
88 |
+
<div class="gdpr-tab hidden" data-id="complaint">
|
89 |
+
<h2><?php esc_html_e( 'Complaints', 'gdpr' ) ?></h2>
|
90 |
+
<table class="widefat gdpr-request-table">
|
91 |
+
<thead>
|
92 |
+
<tr>
|
93 |
+
<th><?php esc_html_e( 'Email', 'gdpr' ); ?></th>
|
94 |
+
<th class="text-center"><?php esc_html_e( 'Date of Complaint', 'gdpr' ); ?></th>
|
95 |
+
<th class="text-center"><?php esc_html_e( 'Information', 'gdpr' ); ?></th>
|
96 |
+
<th class="text-center"><?php esc_html_e( 'Actions', 'gdpr' ); ?></th>
|
97 |
+
</tr>
|
98 |
+
</thead>
|
99 |
+
<tbody>
|
100 |
+
<?php if ( isset( $complaint ) && ! empty( $complaint ) ): ?>
|
101 |
+
<?php foreach ( $complaint as $i => $request ): ?>
|
102 |
+
<tr>
|
103 |
+
<td class="row-title"><?php echo esc_html( $request['email'] ); ?></td>
|
104 |
+
<td class="text-center"><?php echo esc_html( $request['date'] ); ?></td>
|
105 |
+
<td class="text-center"><?php echo esc_html( wp_unslash( $request['data'] ) ); ?></td>
|
106 |
+
<td class="text-center">
|
107 |
+
<form class="frm-process-complaint" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post">
|
108 |
+
<?php wp_nonce_field( 'gdpr-request-nonce', 'gdpr_cancel_complaint_nonce' ); ?>
|
109 |
+
<input type="hidden" name="action" value="gdpr_cancel_request">
|
110 |
+
<input type="hidden" name="type" value="complaint">
|
111 |
+
<input type="hidden" name="index" value="<?php echo esc_attr( $i ); ?>">
|
112 |
+
<input type="hidden" name="user_email" value="<?php echo esc_attr( $request['email'] ) ?>">
|
113 |
+
<?php submit_button( esc_html__( 'Cancel Request', 'gdpr' ), 'delete', '', false ) ?>
|
114 |
+
</form>
|
115 |
+
<form class="frm-process-complaint" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post">
|
116 |
+
<?php wp_nonce_field( 'gdpr-mark-as-resolved', 'gdpr_complaint_mark_resolved_nonce' ); ?>
|
117 |
+
<input type="hidden" name="action" value="gdpr_mark_resolved">
|
118 |
+
<input type="hidden" name="type" value="complaint">
|
119 |
+
<input type="hidden" name="index" value="<?php echo esc_attr( $i ); ?>">
|
120 |
+
<input type="hidden" name="user_email" value="<?php echo esc_attr( $request['email'] ) ?>">
|
121 |
+
<?php submit_button( esc_html__( 'Mark as Resolved', 'gdpr' ), 'primary', '', false ) ?>
|
122 |
+
</form>
|
123 |
+
</td>
|
124 |
+
</tr>
|
125 |
+
<?php endforeach ?>
|
126 |
+
<?php else: ?>
|
127 |
+
<tr>
|
128 |
+
<td colspan="4" class="text-center">
|
129 |
+
<?php esc_html_e( 'No pending requests', 'gdpr' ); ?>
|
130 |
+
</td>
|
131 |
+
</tr>
|
132 |
+
<?php endif ?>
|
133 |
+
</tbody>
|
134 |
+
<tfoot>
|
135 |
+
<tr>
|
136 |
+
<th><?php esc_html_e( 'Email', 'gdpr' ); ?></th>
|
137 |
+
<th class="text-center"><?php esc_html_e( 'Date of Complaint', 'gdpr' ); ?></th>
|
138 |
+
<th class="text-center"><?php esc_html_e( 'Information', 'gdpr' ); ?></th>
|
139 |
+
<th class="text-center"><?php esc_html_e( 'Actions', 'gdpr' ); ?></th>
|
140 |
+
</tr>
|
141 |
+
</tfoot>
|
142 |
+
</table>
|
143 |
+
</div>
|
144 |
+
|
145 |
+
<div class="gdpr-tab hidden" data-id="delete">
|
146 |
+
<h2><?php esc_html_e( 'Right to erasure', 'gdpr' ) ?></h2>
|
147 |
+
<div class="postbox not-full">
|
148 |
+
<form class="gdpr-manual-email-lookup" method="post" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>">
|
149 |
+
<div class="inside">
|
150 |
+
<input type="hidden" name="action" value="gdpr_add_to_deletion_requests">
|
151 |
+
<?php wp_nonce_field( 'gdpr-add-to-deletion-requests', 'gdpr_deletion_requests_nonce' ); ?>
|
152 |
+
<h4>
|
153 |
+
<label for="gdpr-request-email-lookup"><?php esc_html_e( 'Manually add a user', 'gdpr' ); ?></label>
|
154 |
+
</h4>
|
155 |
+
<input type="email" name="user_email" class="gdpr-request-email-lookup regular-text" placeholder="<?php esc_attr_e( 'email@domain.com', 'gdpr' ); ?>" required>
|
156 |
+
<?php submit_button( esc_html__( 'Submit', 'gdpr' ), 'primary', '', false ); ?>
|
157 |
+
</div>
|
158 |
+
</form>
|
159 |
+
</div>
|
160 |
+
<table class="widefat gdpr-request-table">
|
161 |
+
<thead>
|
162 |
+
<tr>
|
163 |
+
<th><?php esc_html_e( 'Email', 'gdpr' ); ?></th>
|
164 |
+
<th class="text-center"><?php esc_html_e( 'Date of Request', 'gdpr' ); ?></th>
|
165 |
+
<th class="text-center"><?php esc_html_e( 'Review', 'gdpr' ); ?></th>
|
166 |
+
<th class="text-center"><?php esc_html_e( 'Actions', 'gdpr' ); ?></th>
|
167 |
+
</tr>
|
168 |
+
</thead>
|
169 |
+
<tbody>
|
170 |
+
<?php if ( isset( $delete ) && ! empty( $delete ) ): ?>
|
171 |
+
<?php $index = 0; ?>
|
172 |
+
<?php foreach ( $delete as $i => $request ): ?>
|
173 |
+
<?php $user = get_user_by( 'email', $request['email'] ) ?>
|
174 |
+
<tr class="<?php echo ( $index % 2 == 0 ? '' : 'alternate' ); ?>">
|
175 |
+
<td class="row-title"><?php echo esc_html( $request['email'] ); ?></td>
|
176 |
+
<td class="text-center"><?php echo esc_html( $request['date'] ); ?></td>
|
177 |
+
<td class="text-center">
|
178 |
+
<?php
|
179 |
+
if ( GDPR_Requests::user_has_content( $user ) ) {
|
180 |
+
echo '<button class="button gdpr-review" data-index="' . esc_attr( $index ) . '">' . esc_html__( 'Review', 'gdpr' ) . '</button>';
|
181 |
+
} else {
|
182 |
+
esc_html_e( 'No content to review', 'gdpr' );
|
183 |
+
}
|
184 |
+
?>
|
185 |
+
<?php if ( GDPR_Requests::user_has_content( $user ) ): ?>
|
186 |
+
<?php else: ?>
|
187 |
+
<?php ?>
|
188 |
+
<?php endif; ?>
|
189 |
+
</td>
|
190 |
+
<td class="text-center">
|
191 |
+
<form class="frm-process-user-deletion" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post">
|
192 |
+
<?php wp_nonce_field( 'gdpr-request-nonce', 'gdpr_cancel_delete_nonce' ); ?>
|
193 |
+
<input type="hidden" name="action" value="gdpr_cancel_request">
|
194 |
+
<input type="hidden" name="type" value="delete">
|
195 |
+
<input type="hidden" name="user_email" value="<?php echo esc_attr( $request['email'] ) ?>">
|
196 |
+
<input type="hidden" name="index" value="<?php echo esc_attr( $i ); ?>">
|
197 |
+
<?php submit_button( esc_html__( 'Cancel Request', 'gdpr' ), 'delete', '', false ) ?>
|
198 |
+
</form>
|
199 |
+
<form class="frm-process-user-deletion" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post">
|
200 |
+
<?php wp_nonce_field( 'gdpr-request-delete-user', 'gdpr_delete_user' ); ?>
|
201 |
+
<input type="hidden" name="action" value="gdpr_delete_user">
|
202 |
+
<input type="hidden" name="user_email" value="<?php echo esc_attr( $request['email'] ) ?>">
|
203 |
+
<input type="hidden" name="index" value="<?php echo esc_attr( $i ); ?>">
|
204 |
+
<?php submit_button( esc_html__( 'Delete User', 'gdpr' ), 'primary', '', false ) ?>
|
205 |
+
</form>
|
206 |
+
</td>
|
207 |
+
</tr>
|
208 |
+
<?php if ( GDPR_Requests::user_has_content( $user ) ): ?>
|
209 |
+
<tr class="review" data-index="<?php echo esc_attr( $index ); ?>">
|
210 |
+
<td colspan="4">
|
211 |
+
<div class="hidden">
|
212 |
+
<table class="widefat">
|
213 |
+
<thead>
|
214 |
+
<tr>
|
215 |
+
<th><?php esc_html_e( 'Content Type', 'gdpr' ); ?></th>
|
216 |
+
<th class="text-center"><?php _e( 'Count', 'gdpr' ); ?></th>
|
217 |
+
<th class="text-center"><?php _e( 'Review', 'gdpr' ); ?></th>
|
218 |
+
<th class="text-center"><?php _e( 'Reassign', 'gdpr' ); ?></th>
|
219 |
+
<th class="text-center"><?php _e( 'Action', 'gdpr' ); ?></th>
|
220 |
+
</tr>
|
221 |
+
</thead>
|
222 |
+
<tbody>
|
223 |
+
<?php $post_types = get_post_types( array( 'public' => true ), 'objects' ); ?>
|
224 |
+
<?php foreach ( $post_types as $pt ): ?>
|
225 |
+
<?php
|
226 |
+
$uid = get_user_by( 'email', $request['email'] );
|
227 |
+
if ( $uid && $uid instanceof WP_User ) {
|
228 |
+
$uid = $uid->ID;
|
229 |
+
}
|
230 |
+
$count = count_user_posts( $uid, $pt->name );
|
231 |
+
if ( '0' === $count) {
|
232 |
+
continue;
|
233 |
+
}
|
234 |
+
?>
|
235 |
+
<tr>
|
236 |
+
<td class="row-title"><?php echo esc_attr( $pt->label ) ?></td>
|
237 |
+
<td class="text-center"><?php echo esc_attr( $count ) ?></td>
|
238 |
+
<td class="text-center">
|
239 |
+
<a href="<?php echo admin_url('edit.php?post_type=' . $pt->name . '&author=' . $uid); ?>" target="_blank" class="button"><?php echo esc_html( $pt->labels->view_items ); ?></a>
|
240 |
+
</td>
|
241 |
+
<td class="text-center">
|
242 |
+
<select name="reassign" class="gdpr-reassign">
|
243 |
+
<option value="0"></option>
|
244 |
+
<?php $admins = get_users( array( 'role' => 'administrator' ) ); ?>
|
245 |
+
<?php foreach ( $admins as $admin ): ?>
|
246 |
+
<option value="<?php echo esc_attr( $admin->ID ) ?>"><?php echo esc_html( $admin->display_name ) ?></option>
|
247 |
+
<?php endforeach; ?>
|
248 |
+
</select>
|
249 |
+
</td>
|
250 |
+
<td class="text-center">
|
251 |
+
<form method="post" class="gdpr-reassign-content">
|
252 |
+
<?php wp_nonce_field( 'gdpr-reassign-content-action', 'gdpr_reassign_content_nonce' ) ?>
|
253 |
+
<input type="hidden" name="user_email" value="<?php echo esc_attr( $request['email'] ) ?>">
|
254 |
+
<input type="hidden" name="reassign_to" value="">
|
255 |
+
<input type="hidden" name="post_type" value="<?php echo esc_attr( $pt->name ); ?>">
|
256 |
+
<input type="hidden" name="post_count" value="<?php echo esc_attr( $count ); ?>">
|
257 |
+
<?php submit_button( esc_html__( 'Reassign', 'gdpr' ), 'primary', '', false, array( 'disabled' => true ) ); ?>
|
258 |
+
<span class="spinner"></span>
|
259 |
+
<p class="hidden"><strong><?php esc_html_e( 'Resolved', 'gdpr' ); ?></strong></p>
|
260 |
+
</form>
|
261 |
+
<span class="spinner"></span>
|
262 |
+
</td>
|
263 |
+
</tr>
|
264 |
+
<?php endforeach; ?>
|
265 |
+
<?php
|
266 |
+
$comment_count = get_comments( array(
|
267 |
+
'author_email' => $request['email'],
|
268 |
+
'include_unapproved' => true,
|
269 |
+
'count' => true,
|
270 |
+
) );
|
271 |
+
|
272 |
+
if ( $comment_count ) {
|
273 |
+
?>
|
274 |
+
<tr>
|
275 |
+
<td class="row-title"><?php esc_html_e( 'Comments', 'gdpr' ); ?></td>
|
276 |
+
<td class="text-center"><?php echo esc_html( $comment_count ); ?></td>
|
277 |
+
<td class="text-center"><a href="<?php echo admin_url( 'edit-comments.php?comment_status=all&s=' . urlencode( $request['email'] ) ); ?>" target="_blank" class="button"><?php _e( 'View Comments', 'gdpr' ); ?></a></td>
|
278 |
+
<td></td>
|
279 |
+
<td class="text-center">
|
280 |
+
<form method="post" class="gdpr-anonymize-comments">
|
281 |
+
<?php wp_nonce_field( 'gdpr-anonymize-comments-action', 'gdpr_anonymize_comments_nonce' ) ?>
|
282 |
+
<input type="hidden" name="user_email" value="<?php echo esc_attr( $request['email'] ) ?>">
|
283 |
+
<input type="hidden" name="comment_count" value="<?php echo esc_attr( $comment_count ) ?>">
|
284 |
+
<?php submit_button( esc_html__( 'Anonymize', 'gdpr' ), 'primary', '', false ) ?>
|
285 |
+
<span class="spinner"></span>
|
286 |
+
<p class="hidden"><strong><?php esc_html_e( 'Resolved', 'gdpr' ); ?></strong></p>
|
287 |
+
</form>
|
288 |
+
</td>
|
289 |
+
</tr>
|
290 |
+
<?php
|
291 |
+
}
|
292 |
+
?>
|
293 |
+
</tbody>
|
294 |
+
<tr>
|
295 |
+
</tr>
|
296 |
+
</table>
|
297 |
+
</div>
|
298 |
+
</td>
|
299 |
+
</tr>
|
300 |
+
<?php endif ?>
|
301 |
+
<?php $index++; ?>
|
302 |
+
<?php endforeach; ?>
|
303 |
+
<?php else: ?>
|
304 |
+
<tr>
|
305 |
+
<td colspan="4" class="text-center">
|
306 |
+
<?php esc_html_e( 'No pending requests', 'gdpr' ); ?>
|
307 |
+
</td>
|
308 |
+
</tr>
|
309 |
+
<?php endif ?>
|
310 |
+
</tbody>
|
311 |
+
<tfoot>
|
312 |
+
<tr>
|
313 |
+
<th><?php esc_html_e( 'Email', 'gdpr' ); ?></th>
|
314 |
+
<th class="text-center"><?php esc_html_e( 'Date of Request', 'gdpr' ); ?></th>
|
315 |
+
<th class="text-center"><?php esc_html_e( 'Review', 'gdpr' ); ?></th>
|
316 |
+
<th class="text-center"><?php esc_html_e( 'Actions', 'gdpr' ); ?></th>
|
317 |
+
</tr>
|
318 |
+
</tfoot>
|
319 |
+
</table>
|
320 |
+
</div>
|
321 |
+
|
322 |
+
<!-- #poststuff -->
|
323 |
+
</div>
|
admin/partials/settings.php
ADDED
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="wrap gdpr">
|
2 |
+
<h1><?php esc_html_e( 'Settings', 'gdpr' ); ?></h1>
|
3 |
+
<div class="nav-tab-wrapper">
|
4 |
+
<?php foreach ( $tabs as $tab => $value ) : ?>
|
5 |
+
<a href="<?php echo '#' . $tab; ?>" class="nav-tab">
|
6 |
+
<?php echo esc_html( $value ); ?>
|
7 |
+
</a>
|
8 |
+
<?php endforeach; ?>
|
9 |
+
</div>
|
10 |
+
|
11 |
+
<?php settings_errors(); ?>
|
12 |
+
|
13 |
+
<form action="options.php" method="post" class="gdpr-settings-form">
|
14 |
+
|
15 |
+
<?php settings_fields( 'gdpr' ); ?>
|
16 |
+
|
17 |
+
<div class="gdpr-tab hidden" data-id="general">
|
18 |
+
<h2><?php esc_html_e( 'General', 'gdpr' ) ?></h2>
|
19 |
+
<table class="form-table" data-id="general">
|
20 |
+
<tbody>
|
21 |
+
<tr>
|
22 |
+
<th scope="row">
|
23 |
+
<label for="gdpr_privacy_policy_page"><?php esc_html_e( 'Privacy Policy Page', 'gdpr' ) ?></label>
|
24 |
+
</th>
|
25 |
+
<td>
|
26 |
+
<?php
|
27 |
+
$pages = get_pages();
|
28 |
+
?>
|
29 |
+
<select name="gdpr_privacy_policy_page" id="gdpr_privacy_policy_page">
|
30 |
+
<option value=""><?php esc_html_e( '-- Select --', 'gdpr' ) ?></option>
|
31 |
+
<?php foreach ( $pages as $page ): ?>
|
32 |
+
<option value="<?php echo esc_attr( $page->ID ) ?>" <?php selected( $privacy_policy_page, $page->ID ); ?>><?php echo esc_html( $page->post_title ); ?></option>
|
33 |
+
<?php endforeach ?>
|
34 |
+
</select>
|
35 |
+
</td>
|
36 |
+
</tr>
|
37 |
+
<tr>
|
38 |
+
<th scope="row">
|
39 |
+
<label for="gdpr_email_limit"><?php esc_html_e( 'Outgoing email limitation', 'gdpr' ) ?></label>
|
40 |
+
</th>
|
41 |
+
<td>
|
42 |
+
<?php $limit = get_option( 'gdpr_email_limit', 100 ); ?>
|
43 |
+
<input type="number" name="gdpr_email_limit" id="gdpr_email_limit" value="<?php echo esc_attr( $limit ); ?>">
|
44 |
+
</td>
|
45 |
+
</tr>
|
46 |
+
<tr>
|
47 |
+
<th scope="row">
|
48 |
+
<label for="gdpr_deletion_needs_review"><?php esc_html_e( 'User deletion', 'gdpr' ) ?></label>
|
49 |
+
</th>
|
50 |
+
<td>
|
51 |
+
<?php $needs_review = get_option( 'gdpr_deletion_needs_review', true ); ?>
|
52 |
+
<input type="checkbox" name="<?php echo esc_attr( 'gdpr_deletion_needs_review' ); ?>" id="gdpr_deletion_needs_review" value="1" <?php checked( $needs_review, true ); ?>><span class="description"><label for="gdpr_deletion_needs_review"><?php esc_html_e( 'Send all deletion requests to the review table.', 'gdpr' ); ?></label></label>
|
53 |
+
</td>
|
54 |
+
</tr>
|
55 |
+
<tr>
|
56 |
+
<th scope="row">
|
57 |
+
<label for="gdpr_disable_css"><?php esc_html_e( 'Disable CSS', 'gdpr' ) ?></label>
|
58 |
+
</th>
|
59 |
+
<td>
|
60 |
+
<?php $disable_css = get_option( 'gdpr_disable_css', false ); ?>
|
61 |
+
<input type="checkbox" name="<?php echo esc_attr( 'gdpr_disable_css' ); ?>" id="gdpr_disable_css" value="1" <?php checked( $disable_css, true ); ?>><label for="gdpr_disable_css"><span class="description"><?php esc_html_e( 'Make sure you know what you are doing before checking this.', 'gdpr' ); ?></span></label>
|
62 |
+
</td>
|
63 |
+
</tr>
|
64 |
+
<tr>
|
65 |
+
<th scope="row">
|
66 |
+
<label for="gdpr_enable_telemetry_tracker"><?php esc_html_e( 'Enable the Telemetry Tracker', 'gdpr' ) ?></label>
|
67 |
+
</th>
|
68 |
+
<td>
|
69 |
+
<?php $enable_telemetry = get_option( 'gdpr_enable_telemetry_tracker', false ); ?>
|
70 |
+
<input type="checkbox" name="<?php echo esc_attr( 'gdpr_enable_telemetry_tracker' ); ?>" id="gdpr_enable_telemetry_tracker" value="1" <?php checked( $enable_telemetry, true ); ?>><label for="gdpr_enable_telemetry_tracker"><span class="description"><?php esc_html_e( 'Toggles the Telemetry Tracker On/Off. (experimental)', 'gdpr' ); ?></span></label>
|
71 |
+
</td>
|
72 |
+
</tr>
|
73 |
+
</tbody>
|
74 |
+
</table>
|
75 |
+
<h2 class="title"><?php esc_html_e( 'Privacy Center', 'gdpr' ); ?></h2>
|
76 |
+
<p>
|
77 |
+
<?php esc_html_e( 'This section handles the privacy bar and some of the privacy preferences window.', 'gdpr' ) ?><br>
|
78 |
+
<strong><?php esc_html_e( 'Important:', 'gdpr' ); ?></strong> <?php esc_html_e( 'If the privacy banner text is not filled out, the privacy banner will not show up. Even if you registered your cookies.', 'gdpr' ) ?></p>
|
79 |
+
<table class="form-table" data-id="general">
|
80 |
+
<tbody>
|
81 |
+
<tr>
|
82 |
+
<th scope="row">
|
83 |
+
<label for="gdpr_cookie_banner_content"><?php esc_html_e( 'Privacy Banner Text', 'gdpr' ) ?></label>
|
84 |
+
</th>
|
85 |
+
<td>
|
86 |
+
<?php $privacy_bar_content = get_option( 'gdpr_cookie_banner_content', '' ); ?>
|
87 |
+
<textarea name="gdpr_cookie_banner_content" id="gdpr_cookie_banner_content" cols="80" rows="6"><?php echo esc_html( $privacy_bar_content ); ?></textarea>
|
88 |
+
</td>
|
89 |
+
</tr>
|
90 |
+
<tr>
|
91 |
+
<th scope="row">
|
92 |
+
<label for="gdpr_cookie_privacy_excerpt"><?php esc_html_e( 'Privacy Excerpt', 'gdpr' ) ?></label>
|
93 |
+
</th>
|
94 |
+
<td>
|
95 |
+
<?php $privacy_excerpt = get_option( 'gdpr_cookie_privacy_excerpt', '' ); ?>
|
96 |
+
<textarea name="gdpr_cookie_privacy_excerpt" id="gdpr_cookie_privacy_excerpt" cols="80" rows="6"><?php echo esc_html( $privacy_excerpt ); ?></textarea>
|
97 |
+
<p class="description"><?php esc_html_e( 'This will appear in the consent section of the privacy preference window.', 'gdpr' ); ?></p>
|
98 |
+
</td>
|
99 |
+
</tr>
|
100 |
+
</tbody>
|
101 |
+
</table>
|
102 |
+
<h2 class="title"><?php esc_html_e( 'Request Forms reCAPTCHA', 'gdpr' ); ?></h2>
|
103 |
+
<p><?php esc_html_e( 'To prevent spam attacks, you have the option to enable reCAPTCHA. Configure below your keys to make it work with our request forms.', 'gdpr' ); ?></p>
|
104 |
+
<p>
|
105 |
+
<?php echo sprintf(
|
106 |
+
/* translators: External link with instructions on how to proceed. */
|
107 |
+
esc_html__( 'You can find the necessary information %s.', 'gdpr' ),
|
108 |
+
'<a href="https://www.google.com/recaptcha/admin" target="_blank">' . esc_html__( 'here', 'gdpr' ) . '</a>'
|
109 |
+
) ?></p>
|
110 |
+
<table class="form-table" data-id="general">
|
111 |
+
<tbody>
|
112 |
+
<tr>
|
113 |
+
<th scope="row">
|
114 |
+
<label for="gdpr_use_recaptcha"><?php esc_html_e( 'Enable reCAPTCHA', 'gdpr' ) ?></label>
|
115 |
+
</th>
|
116 |
+
<td>
|
117 |
+
<?php $use_recaptcha = get_option( 'gdpr_use_recaptcha', false ); ?>
|
118 |
+
<input type="checkbox" name="<?php echo esc_attr( 'gdpr_use_recaptcha' ); ?>" id="gdpr_use_recaptcha" value="1" <?php checked( $use_recaptcha, true ); ?>>
|
119 |
+
</td>
|
120 |
+
</tr>
|
121 |
+
<tr>
|
122 |
+
<th scope="row">
|
123 |
+
<label for="gdpr_recaptcha_site_key"><?php esc_html_e( 'Site Key', 'gdpr' ) ?></label>
|
124 |
+
</th>
|
125 |
+
<td>
|
126 |
+
<?php $site_key = get_option( 'gdpr_recaptcha_site_key', '' ); ?>
|
127 |
+
<input type="text" name="gdpr_recaptcha_site_key" value="<?php echo esc_attr( $site_key ); ?>" placeholder="">
|
128 |
+
</td>
|
129 |
+
</tr>
|
130 |
+
<tr>
|
131 |
+
<th scope="row">
|
132 |
+
<label for="gdpr_recaptcha_secret_key"><?php esc_html_e( 'Secret Key', 'gdpr' ) ?></label>
|
133 |
+
</th>
|
134 |
+
<td>
|
135 |
+
<?php $secret_key = get_option( 'gdpr_recaptcha_secret_key', '' ); ?>
|
136 |
+
<input type="password" name="gdpr_recaptcha_secret_key" value="<?php echo esc_attr( $secret_key ); ?>" placeholder="">
|
137 |
+
</td>
|
138 |
+
</tr>
|
139 |
+
</tbody>
|
140 |
+
</table>
|
141 |
+
<?php if ( class_exists( 'WooCommerce' ) ): ?>
|
142 |
+
<h2 class="title"><?php esc_html_e( 'WooCommerce', 'gdpr' ); ?></h2>
|
143 |
+
<table class="form-table" data-id="general">
|
144 |
+
<tbody>
|
145 |
+
<tr>
|
146 |
+
<th scope="row">
|
147 |
+
<label for="gdpr_add_consent_checkboxes_registration"><?php esc_html_e( 'Add consent checkboxes to the registration page', 'gdpr' ) ?></label>
|
148 |
+
</th>
|
149 |
+
<td>
|
150 |
+
<?php $add_checkboxes_to_registration = get_option( 'gdpr_add_consent_checkboxes_registration', false ); ?>
|
151 |
+
<input type="checkbox" name="<?php echo esc_attr( 'gdpr_add_consent_checkboxes_registration' ); ?>" id="gdpr_add_consent_checkboxes_registration" value="1" <?php checked( $add_checkboxes_to_registration, true ); ?>>
|
152 |
+
</td>
|
153 |
+
</tr>
|
154 |
+
<tr>
|
155 |
+
<th scope="row">
|
156 |
+
<label for="gdpr_add_consent_checkboxes_checkout"><?php esc_html_e( 'Add consent checkboxes to the checkout registration form', 'gdpr' ) ?></label>
|
157 |
+
</th>
|
158 |
+
<td>
|
159 |
+
<?php $add_checkboxes_to_checkout = get_option( 'gdpr_add_consent_checkboxes_checkout', false ); ?>
|
160 |
+
<input type="checkbox" name="<?php echo esc_attr( 'gdpr_add_consent_checkboxes_checkout' ); ?>" id="gdpr_add_consent_checkboxes_checkout" value="1" <?php checked( $add_checkboxes_to_checkout, true ); ?>>
|
161 |
+
</td>
|
162 |
+
</tr>
|
163 |
+
</tbody>
|
164 |
+
</table>
|
165 |
+
<?php endif ?>
|
166 |
+
</div>
|
167 |
+
<div class="gdpr-tab hidden" data-id="cookies">
|
168 |
+
<h2><?php esc_html_e( 'Cookies', 'gdpr' ) ?></h2>
|
169 |
+
<input type="text" id="cookie-tabs" class="regular-text" placeholder="<?php esc_attr_e( 'Category name', 'gdpr' ); ?>">
|
170 |
+
<button class="button button-primary add-tab"><?php esc_html_e( 'Add tab', 'gdpr' ); ?></button>
|
171 |
+
<div id="tabs">
|
172 |
+
<?php $cookie_tabs = get_option( 'gdpr_cookie_popup_content', array() ); ?>
|
173 |
+
<?php if ( ! empty( $cookie_tabs ) ) : ?>
|
174 |
+
<?php foreach ( $cookie_tabs as $tab_key => $tab ) : ?>
|
175 |
+
<div class="postbox" id="cookie-tab-content-<?php echo esc_attr( $tab_key ); ?>">
|
176 |
+
<h2 class="hndle"><?php echo esc_html( $tab['name'] ); ?><button class="notice-dismiss" type="button"><span class="screen-reader-text"><?php esc_html_e( 'Remove this tab.', 'gdpr' ); ?></span></button></h2>
|
177 |
+
<input type="hidden" name="<?php echo esc_attr( 'gdpr_cookie_popup_content' ); ?>[<?php echo esc_attr( $tab_key ); ?>][name]" value="<?php echo esc_attr( $tab['name'] ); ?>" />
|
178 |
+
<div class="inside">
|
179 |
+
<table class="form-table">
|
180 |
+
<tr>
|
181 |
+
<th><label for="always-active-<?php echo esc_attr( $tab_key ); ?>"><?php esc_html_e( 'Always active', 'gdpr' ); ?></label></th>
|
182 |
+
<td>
|
183 |
+
<label class="gdpr-switch">
|
184 |
+
<input type="checkbox" name="<?php echo esc_attr( 'gdpr_cookie_popup_content' ); ?>[<?php echo esc_attr( $tab_key ); ?>][always_active]" <?php checked( esc_attr( $tab['always_active'] ), 1 ); ?> id="always-active-<?php echo esc_attr( $tab_key ); ?>">
|
185 |
+
<span class="gdpr-slider round"></span>
|
186 |
+
</label>
|
187 |
+
</td>
|
188 |
+
</tr>
|
189 |
+
<tr>
|
190 |
+
<th><label for="tab-how-we-use-<?php echo esc_attr( $tab_key ); ?>"><?php esc_html_e( 'How we use', 'gdpr' ); ?></label></th>
|
191 |
+
<td><textarea name="<?php echo esc_attr( 'gdpr_cookie_popup_content' ); ?>[<?php echo esc_attr( $tab_key ); ?>][how_we_use]" id="tab-how-we-use-<?php echo esc_attr( $tab_key ); ?>" cols="53" rows="3" required><?php echo esc_html( $tab['how_we_use'] ); ?></textarea></td>
|
192 |
+
</tr>
|
193 |
+
<tr>
|
194 |
+
<th><label for="cookies-used-<?php echo esc_attr( $tab_key ); ?>"><?php esc_html_e( 'Cookies used by the site', 'gdpr' ); ?></label></th>
|
195 |
+
<td>
|
196 |
+
<textarea cols="53" rows="3" name="<?php echo esc_attr( 'gdpr_cookie_popup_content' ); ?>[<?php echo esc_attr( $tab_key ); ?>][cookies_used]" id="cookies-used-<?php echo esc_attr( $tab_key ); ?>" required><?php echo esc_attr( $tab['cookies_used'] ); ?></textarea>
|
197 |
+
<br>
|
198 |
+
<span class="description"><?php esc_html_e( 'Comma separated list.', 'gdpr' ); ?></span>
|
199 |
+
</td>
|
200 |
+
</tr>
|
201 |
+
<tr>
|
202 |
+
<th><label for="hosts-<?php echo esc_attr( $tab_key ); ?>"><?php esc_html_e( 'Third party domains', 'gdpr' ); ?></label></th>
|
203 |
+
<td>
|
204 |
+
<input type="text" id="hosts-<?php echo esc_attr( $tab_key ); ?>" class="regular-text" placeholder="domain.com" />
|
205 |
+
<button class="button button-primary add-host" data-tabid="<?php echo esc_attr( $tab_key ); ?>"><?php esc_html_e( 'Add', 'gdpr' ); ?></button>
|
206 |
+
<br>
|
207 |
+
<span class="description"><?php esc_html_e( 'Cookies that are set by a third party, like facebook.com.', 'gdpr' ); ?></span>
|
208 |
+
</td>
|
209 |
+
</tr>
|
210 |
+
</table>
|
211 |
+
<div class="tab-hosts" data-tabid="<?php echo esc_attr( $tab_key ); ?>">
|
212 |
+
<?php if ( isset( $tab['hosts'] ) && $tab['hosts'] ) : ?>
|
213 |
+
<?php foreach ( $tab['hosts'] as $host_key => $host ) : ?>
|
214 |
+
<div class="postbox">
|
215 |
+
<h2 class="hndle"><?php echo esc_attr( $host_key ); ?><button class="notice-dismiss" type="button"><span class="screen-reader-text"><?php esc_html_e( 'Remove this domain.', 'gdpr' ); ?></span></button></h2>
|
216 |
+
<input type="hidden" name="<?php echo esc_attr( 'gdpr_cookie_popup_content' ); ?>[<?php echo esc_attr( $tab_key ); ?>][hosts][<?php echo esc_attr( $host_key ); ?>][name]" value="<?php echo esc_attr( $host_key ); ?>" />
|
217 |
+
<div class="inside">
|
218 |
+
<table class="form-table">
|
219 |
+
<tr>
|
220 |
+
<th><label for="hosts-cookies-used-<?php echo esc_attr( $host_key ); ?>"><?php esc_html_e( 'Cookies used', 'gdpr' ); ?></label></th>
|
221 |
+
<td>
|
222 |
+
<textarea cols="53" rows="3" name="<?php echo esc_attr( 'gdpr_cookie_popup_content' ); ?>[<?php echo esc_attr( $tab_key ); ?>][hosts][<?php echo esc_attr( $host_key ); ?>][cookies_used]" id="hosts-cookies-used-<?php echo esc_attr( $host_key ); ?>" required><?php echo esc_attr( $host['cookies_used'] ); ?></textarea>
|
223 |
+
<br>
|
224 |
+
<span class="description"><?php esc_html_e( 'Comma separated list.', 'gdpr' ); ?></span>
|
225 |
+
</td>
|
226 |
+
</tr>
|
227 |
+
<tr>
|
228 |
+
<th><label for="hosts-cookies-optout-<?php echo esc_attr( $host_key ); ?>"><?php esc_html_e( 'How to Opt Out', 'gdpr' ); ?></label></th>
|
229 |
+
<td>
|
230 |
+
<input type="text" name="<?php echo esc_attr( 'gdpr_cookie_popup_content' ); ?>[<?php echo esc_attr( $tab_key ); ?>][hosts][<?php echo esc_attr( $host_key ); ?>][optout]" value="<?php echo esc_attr( $host['optout'] ); ?>" id="hosts-cookies-optout-<?php echo esc_attr( $host_key ); ?>" class="regular-text" required />
|
231 |
+
<br>
|
232 |
+
<span class="description"><?php esc_html_e( 'Url with instructions on how to opt out.', 'gdpr' ); ?></span>
|
233 |
+
</td>
|
234 |
+
</tr>
|
235 |
+
</table>
|
236 |
+
</div>
|
237 |
+
</div>
|
238 |
+
<?php endforeach; ?>
|
239 |
+
<?php endif; ?>
|
240 |
+
</div>
|
241 |
+
</div><!-- .inside -->
|
242 |
+
</div><!-- .postbox -->
|
243 |
+
<?php endforeach ?>
|
244 |
+
<?php endif ?>
|
245 |
+
</div>
|
246 |
+
</div>
|
247 |
+
<div class="gdpr-tab hidden" data-id="consents">
|
248 |
+
<h2><?php esc_html_e( 'Consents', 'gdpr' ) ?></h2>
|
249 |
+
<input type="text" id="type-of-consent" class="regular-text" placeholder="<?php esc_attr_e( 'Type of consent', 'gdpr' ); ?>">
|
250 |
+
<button class="button button-primary add-consent"><?php esc_html_e( 'Add consent', 'gdpr' ); ?></button>
|
251 |
+
<div id="consent-tabs">
|
252 |
+
<?php
|
253 |
+
$default_consent_types = array(
|
254 |
+
'privacy-policy' => array(
|
255 |
+
'name' => 'Privacy Policy',
|
256 |
+
'required' => 'on',
|
257 |
+
'description' => sprintf( __( 'You read and agreed to our %s.', 'gdpr' ), '<a href="" target="_blank">' . esc_html( 'Privacy Policy', 'gdpr' ) . '</a>' ),
|
258 |
+
'registration' => sprintf( __( 'You read and agreed to our %s.', 'gdpr' ), '<a href="" target="_blank">' . esc_html( 'Privacy Policy', 'gdpr' ) . '</a>' ),
|
259 |
+
)
|
260 |
+
);
|
261 |
+
$consent_types = get_option( 'gdpr_consent_types', $default_consent_types ); ?>
|
262 |
+
<?php if ( ! empty( $consent_types ) ) : ?>
|
263 |
+
<?php foreach ( $consent_types as $consent_key => $consent ) : ?>
|
264 |
+
<div class="postbox" id="consent-type-content-<?php echo esc_attr( $consent_key ); ?>">
|
265 |
+
<h2 class="hndle"><?php echo esc_html( $consent['name'] ); ?> <span>(id: <?php echo esc_html( $consent_key ); ?>)</span><?php echo ( 'privacy-policy' === $consent_key ) ? '' : '<button class="notice-dismiss" type="button"><span class="screen-reader-text">' . esc_html__( 'Unregister this consent.', 'gdpr' ) . '</span></button>'; ?></h2>
|
266 |
+
<input type="hidden" name="<?php echo esc_attr( 'gdpr_consent_types' ); ?>[<?php echo esc_attr( $consent_key ); ?>][name]" value="<?php echo esc_attr( $consent['name'] ); ?>" />
|
267 |
+
<div class="inside">
|
268 |
+
<table class="form-table">
|
269 |
+
<tr>
|
270 |
+
<th><label for="required-<?php echo esc_attr( $consent_key ); ?>"><?php esc_html_e( 'Required', 'gdpr' ); ?></label></th>
|
271 |
+
<td>
|
272 |
+
<?php if ( 'privacy-policy' === $consent_key ): ?>
|
273 |
+
<span><?php esc_html_e( 'Required', 'gdpr' ) ?></span>
|
274 |
+
<input type="hidden" name="<?php echo esc_attr( 'gdpr_consent_types' ); ?>[<?php echo esc_attr( $consent_key ); ?>][required]" id="required-<?php echo esc_attr( $consent_key ); ?>" value="1">
|
275 |
+
<?php else: ?>
|
276 |
+
<label class="gdpr-switch">
|
277 |
+
<input type="checkbox" name="<?php echo esc_attr( 'gdpr_consent_types' ); ?>[<?php echo esc_attr( $consent_key ); ?>][required]" <?php checked( esc_attr( $consent['required'] ), 1 ); ?> id="required-<?php echo esc_attr( $consent_key ); ?>">
|
278 |
+
<span class="gdpr-slider round"></span>
|
279 |
+
</label>
|
280 |
+
<?php endif; ?>
|
281 |
+
</td>
|
282 |
+
</tr>
|
283 |
+
<tr>
|
284 |
+
<th><label for="consent-description-<?php echo esc_attr( $consent_key ); ?>"><?php esc_html_e( 'Consent description', 'gdpr' ); ?></label></th>
|
285 |
+
<td><textarea name="<?php echo esc_attr( 'gdpr_consent_types' ); ?>[<?php echo esc_attr( $consent_key ); ?>][description]" id="consent-description-<?php echo esc_attr( $consent_key ); ?>" cols="53" rows="3" required><?php echo esc_html( $consent['description'] ); ?></textarea></td>
|
286 |
+
</tr>
|
287 |
+
<tr>
|
288 |
+
<th><label for="consent-registration-<?php echo esc_attr( $consent_key ); ?>"><?php esc_html_e( 'Registration message', 'gdpr' ); ?></label></th>
|
289 |
+
<td><textarea name="<?php echo esc_attr( 'gdpr_consent_types' ); ?>[<?php echo esc_attr( $consent_key ); ?>][registration]" id="consent-registration-<?php echo esc_attr( $consent_key ); ?>" cols="53" rows="3" required><?php echo esc_html( $consent['registration'] ); ?></textarea></td>
|
290 |
+
</tr>
|
291 |
+
</table>
|
292 |
+
</div><!-- .inside -->
|
293 |
+
</div><!-- .postbox -->
|
294 |
+
<?php endforeach ?>
|
295 |
+
<?php endif ?>
|
296 |
+
</div>
|
297 |
+
</div>
|
298 |
+
<div class="gdpr-tab hidden" data-id="export-chanel">
|
299 |
+
<h2><?php esc_html_e( 'Data Export Chanel', 'gdpr' ) ?></h2>
|
300 |
+
<table class="form-table" data-id="general">
|
301 |
+
<tbody>
|
302 |
+
<tr>
|
303 |
+
<th scope="row">
|
304 |
+
<label for="data-export-chanel"><?php esc_html_e( 'Data Export Chanel', 'gdpr' ) ?></label>
|
305 |
+
</th>
|
306 |
+
<td>
|
307 |
+
<?php
|
308 |
+
$export_data = get_option('gdpr_export_data');
|
309 |
+
?>
|
310 |
+
<input name="<?php echo esc_attr( 'gdpr_export_data' ); ?>" type="radio" value="export-data" <?php if ($export_data == 'export-data') { ?> checked <?php } ?> ><?php esc_html_e( 'Data Export with email attachment', 'gdpr' ) ?> <br>
|
311 |
+
<input name="<?php echo esc_attr( 'gdpr_export_data' ); ?>" type="radio" value="file-export-data" <?php if ($export_data == 'file-export-data') { ?> checked <?php } ?>><?php esc_html_e( 'Data Export with download link', 'gdpr' ) ?> <br>
|
312 |
+
</td>
|
313 |
+
</tr>
|
314 |
+
</tbody>
|
315 |
+
</table>
|
316 |
+
</div>
|
317 |
+
<?php
|
318 |
+
do_action( 'gdpr_extra_settings' );
|
319 |
+
submit_button();
|
320 |
+
?>
|
321 |
+
</form>
|
322 |
+
|
323 |
+
<!-- #poststuff -->
|
324 |
+
</div>
|
admin/partials/templates/index.php
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php // Silence is golden
|
admin/partials/templates/tmpl-consents.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script type="text/html" id="tmpl-consents">
|
2 |
+
<div class="postbox" id="consent-type-content-{{data.key}}">
|
3 |
+
<h2 class="hndle">{{data.name}} <span>(id: {{data.key}})</span><button class="notice-dismiss" type="button"><span class="screen-reader-text"><?php esc_html_e( 'Unregister this consent.', 'gdpr' ); ?></span></button></h2>
|
4 |
+
<input type="hidden" name="{{data.option_name}}[{{data.key}}][name]" value="{{data.name}}" />
|
5 |
+
<input type="hidden" name="{{data.option_name}}[{{data.key}}][id]" value="{{data.id}}" />
|
6 |
+
<div class="inside">
|
7 |
+
<table class="form-table">
|
8 |
+
<tr>
|
9 |
+
<th><label for="required-{{data.key}}"><?php esc_html_e( 'Required', 'gdpr' ); ?></label></th>
|
10 |
+
<td>
|
11 |
+
<label class="gdpr-switch">
|
12 |
+
<input type="checkbox" name="{{data.option_name}}[{{data.key}}][required]" id="required-{{data.key}}">
|
13 |
+
<span class="gdpr-slider round"></span>
|
14 |
+
</label>
|
15 |
+
</td>
|
16 |
+
</tr>
|
17 |
+
<tr>
|
18 |
+
<th><label for="consent-description-{{data.key}}"><?php esc_html_e( 'Consent description', 'gdpr' ); ?></label></th>
|
19 |
+
<td><textarea name="{{data.option_name}}[{{data.key}}][description]" id="consent-description-{{data.key}}" cols="53" rows="3" required></textarea></td>
|
20 |
+
</tr>
|
21 |
+
<tr>
|
22 |
+
<th><label for="consent-registration-{{data.key}}"><?php esc_html_e( 'Registration message', 'gdpr' ); ?></label></th>
|
23 |
+
<td><textarea name="{{data.option_name}}[{{data.key}}][registration]" id="consent-registration-{{data.key}}" cols="53" rows="3" required></textarea></td>
|
24 |
+
</tr>
|
25 |
+
</table>
|
26 |
+
</div><!-- .inside -->
|
27 |
+
</div><!-- .postbox -->
|
28 |
+
</script>
|
admin/partials/templates/tmpl-cookies.php
ADDED
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script type="text/html" id="tmpl-cookie-tabs">
|
2 |
+
<div class="postbox" id="cookie-tab-content-{{data.key}}">
|
3 |
+
<h2 class="hndle">{{data.name}}<button class="notice-dismiss" type="button"><span class="screen-reader-text"><?php esc_html_e( 'Remove this tab.', 'gdpr' ); ?></span></button></h2>
|
4 |
+
<input type="hidden" name="{{data.option_name}}[{{data.key}}][name]" value="{{data.name}}" />
|
5 |
+
<div class="inside">
|
6 |
+
<table class="form-table">
|
7 |
+
<tr>
|
8 |
+
<th><label for="always-active-{{data.key}}"><?php esc_html_e( 'Always active', 'gdpr' ); ?></label></th>
|
9 |
+
<td>
|
10 |
+
<label class="gdpr-switch">
|
11 |
+
<input type="checkbox" name="{{data.option_name}}[{{data.key}}][always_active]" id="always-active-{{data.key}}">
|
12 |
+
<span class="gdpr-slider round"></span>
|
13 |
+
</label>
|
14 |
+
</td>
|
15 |
+
</tr>
|
16 |
+
<tr>
|
17 |
+
<th><label for="tab-how-we-use-{{data.key}}"><?php esc_html_e( 'How we use', 'gdpr' ); ?></label></th>
|
18 |
+
<td><textarea name="{{data.option_name}}[{{data.key}}][how_we_use]" id="tab-how-we-use-{{data.key}}" cols="53" rows="3" required></textarea></td>
|
19 |
+
</tr>
|
20 |
+
<tr>
|
21 |
+
<th><label for="cookies-used-{{data.key}}"><?php esc_html_e( 'Cookies used by the site', 'gdpr' ); ?></label></th>
|
22 |
+
<td>
|
23 |
+
<textarea cols="53" rows="3" name="{{data.option_name}}[{{data.key}}][cookies_used]" id="cookies-used-{{data.key}}" required></textarea>
|
24 |
+
<br>
|
25 |
+
<span class="description"><?php esc_html_e( 'Comma separated list.', 'gdpr' ); ?></span>
|
26 |
+
</td>
|
27 |
+
</tr>
|
28 |
+
<tr>
|
29 |
+
<th><label for="hosts-{{data.key}}"><?php esc_html_e( 'Third Party Domains', 'gdpr' ); ?></label></th>
|
30 |
+
<td>
|
31 |
+
<input type="text" id="hosts-{{data.key}}" class="regular-text" placeholder="domain.com" />
|
32 |
+
<button class="button button-primary add-host" data-tabid="{{data.key}}"><?php esc_html_e( 'Add', 'gdpr' ); ?></button>
|
33 |
+
<br>
|
34 |
+
<span class="description"><?php esc_html_e( 'Cookies that are set by a third party, like facebook.com', 'gdpr' ); ?></span>
|
35 |
+
</td>
|
36 |
+
</tr>
|
37 |
+
</table>
|
38 |
+
<div class="tab-hosts" data-tabid="{{data.key}}">
|
39 |
+
|
40 |
+
</div>
|
41 |
+
</div><!-- .inside -->
|
42 |
+
</div><!-- .postbox -->
|
43 |
+
</script>
|
44 |
+
|
45 |
+
|
46 |
+
<script type="text/html" id="tmpl-cookie-tabs-hosts">
|
47 |
+
<div class="postbox">
|
48 |
+
<h2 class="hndle">{{data.host_key}}<button class="notice-dismiss" type="button"><span class="screen-reader-text"><?php esc_html_e( 'Remove this domain.', 'gdpr' ); ?></span></button></h2>
|
49 |
+
<input type="hidden" name="{{data.option_name}}[{{data.tab_key}}][hosts][{{data.host_key}}][name]" value="{{data.host_key}}" />
|
50 |
+
<div class="inside">
|
51 |
+
<table class="form-table">
|
52 |
+
<tr>
|
53 |
+
<th><label for="hosts-cookies-used-{{data.host_key}}"><?php esc_html_e( 'Cookies used', 'gdpr' ); ?></label></th>
|
54 |
+
<td>
|
55 |
+
<textarea cols="53" rows="3" name="{{data.option_name}}[{{data.tab_key}}][hosts][{{data.host_key}}][cookies_used]" id="hosts-cookies-used-{{data.host_key}}" required></textarea>
|
56 |
+
<br>
|
57 |
+
<span class="description"><?php esc_html_e( 'Comma separated list.', 'gdpr' ); ?></span>
|
58 |
+
</td>
|
59 |
+
</tr>
|
60 |
+
<tr>
|
61 |
+
<th><label for="hosts-cookies-optout-{{data.host_key}}"><?php esc_html_e( 'How to Opt Out', 'gdpr' ); ?></label></th>
|
62 |
+
<td>
|
63 |
+
<input type="text" name="{{data.option_name}}[{{data.tab_key}}][hosts][{{data.host_key}}][optout]" id="hosts-cookies-optout-{{data.host_key}}" class="regular-text" required />
|
64 |
+
<br>
|
65 |
+
<span class="description"><?php esc_html_e( 'Url with instructions on how to opt out.', 'gdpr' ); ?></span>
|
66 |
+
</td>
|
67 |
+
</tr>
|
68 |
+
</table>
|
69 |
+
</div>
|
70 |
+
</div>
|
71 |
+
</script>
|
admin/partials/templates/tmpl-tools.php
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script type="text/html" id="tmpl-audit-log-result-success">
|
2 |
+
<div class="gdpr-audit-log-result">
|
3 |
+
<h2><?php echo _e( 'Result', 'gdpr' ); ?></h2>
|
4 |
+
<div class="postbox">
|
5 |
+
<div class="inside">
|
6 |
+
<textarea readonly class="gdpr-audit-log-result large-text" rows="20">{{{data.result}}}</textarea>
|
7 |
+
</div>
|
8 |
+
</div>
|
9 |
+
</div>
|
10 |
+
</script>
|
11 |
+
|
12 |
+
<script type="text/html" id="tmpl-audit-log-result-error">
|
13 |
+
<div class="gdpr-audit-log-result">
|
14 |
+
<h2><?php echo _e( 'Error', 'gdpr' ); ?></h2>
|
15 |
+
<div class="notice notice-error">
|
16 |
+
<p><?php esc_html_e( 'We could not find a any logs for that email and token combination.', 'gdpr' ); ?></p>
|
17 |
+
</div>
|
18 |
+
</div>
|
19 |
+
</script>
|
20 |
+
|
21 |
+
<script type="text/html" id="tmpl-access-data-result-success">
|
22 |
+
<div class="gdpr-access-data-result">
|
23 |
+
<h2><?php echo _e( 'Result', 'gdpr' ); ?></h2>
|
24 |
+
<p>
|
25 |
+
<form method="post" class="frm-export-data">
|
26 |
+
<?php wp_nonce_field( 'gdpr-export-data', 'gdpr_export_data_nonce' ); ?>
|
27 |
+
<input type="hidden" name="user_email" value="{{data.user_email}}">
|
28 |
+
<?php submit_button( 'XML', 'primary', 'download-data-xml', false ) ?>
|
29 |
+
<?php submit_button( 'JSON', 'primary', 'download-data-json', false ) ?>
|
30 |
+
</form>
|
31 |
+
</p>
|
32 |
+
<div class="postbox">
|
33 |
+
<div class="inside">
|
34 |
+
<div class="result">
|
35 |
+
{{{data.result}}}
|
36 |
+
</div>
|
37 |
+
</div>
|
38 |
+
</div>
|
39 |
+
</div>
|
40 |
+
</script>
|
41 |
+
|
42 |
+
<script type="text/html" id="tmpl-access-data-result-error">
|
43 |
+
<div class="gdpr-access-data-result">
|
44 |
+
<h2><?php echo _e( 'Error', 'gdpr' ); ?></h2>
|
45 |
+
<div class="notice notice-error">
|
46 |
+
<p><?php esc_html_e( 'We could not find a user with that email.', 'gdpr' ); ?></p>
|
47 |
+
</div>
|
48 |
+
</div>
|
49 |
+
</script>
|
admin/partials/tools.php
ADDED
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Provide a admin area view for the plugin
|
5 |
+
*
|
6 |
+
* This file is used to markup the admin-facing aspects of the plugin.
|
7 |
+
*
|
8 |
+
* @link https://trewknowledge.com
|
9 |
+
* @since 1.0.0
|
10 |
+
*
|
11 |
+
* @package GDPR
|
12 |
+
* @subpackage admin/partials
|
13 |
+
*/
|
14 |
+
|
15 |
+
include_once plugin_dir_path( __FILE__ ) . 'templates/tmpl-tools.php';
|
16 |
+
|
17 |
+
if ( isset( $_GET['type'], $_GET['key'] ) ) {
|
18 |
+
|
19 |
+
if ( 'data-breach-confirmed' === $_GET['type'] ) {
|
20 |
+
$key = sanitize_text_field( wp_unslash( $_GET['key'] ) );
|
21 |
+
|
22 |
+
$data_breach = get_option( 'gdpr_data_breach_initiated', array( 'key' => '' ) );
|
23 |
+
if ( ! empty( $data_breach ) ) {
|
24 |
+
if ( $key === $data_breach['key'] ) {
|
25 |
+
GDPR_Email::prepare_data_breach_emails( $key );
|
26 |
+
delete_option( 'gdpr_data_breach_initiated' );
|
27 |
+
|
28 |
+
if ( $time = wp_next_scheduled( 'clean_gdpr_data_breach_request' ) ) {
|
29 |
+
wp_unschedule_event( $time, 'clean_gdpr_data_breach_request' );
|
30 |
+
}
|
31 |
+
|
32 |
+
add_settings_error( 'gdpr', 'resolved', esc_html__( 'Data Breach confirmed. Preparing bulk emails.', 'gdpr' ), 'updated' );
|
33 |
+
}
|
34 |
+
|
35 |
+
}
|
36 |
+
|
37 |
+
|
38 |
+
}
|
39 |
+
}
|
40 |
+
|
41 |
+
?>
|
42 |
+
|
43 |
+
<div class="wrap gdpr">
|
44 |
+
<h1><?php esc_html_e( 'Tools', 'gdpr' ); ?></h1>
|
45 |
+
<?php settings_errors(); ?>
|
46 |
+
<div class="nav-tab-wrapper">
|
47 |
+
<?php foreach ( $tabs as $key => $value ) : ?>
|
48 |
+
<a href="<?php echo '#' . $key; ?>" class="nav-tab">
|
49 |
+
<?php echo esc_html( $value ); ?>
|
50 |
+
</a>
|
51 |
+
<?php endforeach; ?>
|
52 |
+
</div>
|
53 |
+
|
54 |
+
<div class="gdpr-tab hidden" data-id="access">
|
55 |
+
<h2><?php esc_html_e( 'Access Data', 'gdpr' ) ?></h2>
|
56 |
+
<div class="postbox not-full">
|
57 |
+
<form class="gdpr-access-data-lookup" method="post">
|
58 |
+
<div class="inside">
|
59 |
+
<?php wp_nonce_field( 'gdpr-access-data', 'gdpr_access_data_nonce' ); ?>
|
60 |
+
<h4>
|
61 |
+
<label for="gdpr-request-email-lookup"><?php esc_html_e( 'Search by email', 'gdpr' ); ?></label>
|
62 |
+
</h4>
|
63 |
+
<input type="email" name="user_email" class="regular-text" placeholder="<?php esc_attr_e( 'email@domain.com', 'gdpr' ); ?>" required>
|
64 |
+
<?php submit_button( esc_html__( 'Search', 'gdpr' ), 'primary', '', false ); ?>
|
65 |
+
<span class="spinner"></span>
|
66 |
+
</div>
|
67 |
+
</form>
|
68 |
+
</div>
|
69 |
+
</div>
|
70 |
+
|
71 |
+
<div class="gdpr-tab hidden" data-id="data-breach">
|
72 |
+
<h2><?php esc_html_e( 'Data Breach', 'gdpr' ) ?></h2>
|
73 |
+
<form class="gdpr-data-breach-form" method="post" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>">
|
74 |
+
<?php wp_nonce_field( 'gdpr-data-breach', 'gdpr_data_breach_nonce' ); ?>
|
75 |
+
<input type="hidden" name="action" value="gdpr_data_breach">
|
76 |
+
<table class="form-table">
|
77 |
+
<tr>
|
78 |
+
<th><?php esc_html_e( 'Email content', 'gdpr' ) ?></th>
|
79 |
+
<td>
|
80 |
+
<textarea name="gdpr-data-breach-email-content" class="large-text" rows="5"></textarea>
|
81 |
+
<span class="description"><?php esc_html_e( 'The content that the end user will see before the below information.', 'gdpr' ) ?></span>
|
82 |
+
</td>
|
83 |
+
</tr>
|
84 |
+
<tr>
|
85 |
+
<th><?php esc_html_e( 'Nature of the personal data breach', 'gdpr' ) ?></th>
|
86 |
+
<td>
|
87 |
+
<textarea name="gdpr-data-breach-nature" class="large-text" rows="5" required></textarea>
|
88 |
+
<span class="description"><?php esc_html_e( 'Describe the nature of the personal data breach including where possible, the categories and approximate number of data subjects concerned and the categories and approximate number of personal data records concerned.', 'gdpr' ) ?></span>
|
89 |
+
</td>
|
90 |
+
</tr>
|
91 |
+
<tr>
|
92 |
+
<th><?php esc_html_e( 'Name and contact details of the data protection officer', 'gdpr' ) ?></th>
|
93 |
+
<td>
|
94 |
+
<textarea name="gdpr-name-contact-details-protection-officer" class="large-text" rows="5" required></textarea>
|
95 |
+
<span class="description"><?php esc_html_e( 'Communicate the name and contact details of the data protection officer or other contact point where more information can be obtained.', 'gdpr' ) ?></span>
|
96 |
+
</td>
|
97 |
+
</tr>
|
98 |
+
<tr>
|
99 |
+
<th><?php esc_html_e( 'Likely consequences of the personal data breach', 'gdpr' ) ?></th>
|
100 |
+
<td>
|
101 |
+
<textarea name="gdpr-likely-consequences" class="large-text" rows="5" required></textarea>
|
102 |
+
</td>
|
103 |
+
</tr>
|
104 |
+
<tr>
|
105 |
+
<th><?php esc_html_e( 'Measures taken or proposed to be taken', 'gdpr' ) ?></th>
|
106 |
+
<td>
|
107 |
+
<textarea name="gdpr-measures-taken" class="large-text" rows="5" required></textarea>
|
108 |
+
<span class="description"><?php esc_html_e( 'Describe the measures taken or proposed to be taken by the controller to address the personal data breach, including, where appropriate, measures to mitigate its possible adverse effects.', 'gdpr' ) ?></span>
|
109 |
+
</td>
|
110 |
+
</tr>
|
111 |
+
</table>
|
112 |
+
<?php submit_button( esc_html__( 'Send confirmation email', 'gdpr' ), 'primary', '', false ); ?>
|
113 |
+
</form>
|
114 |
+
</div>
|
115 |
+
|
116 |
+
<div class="gdpr-tab hidden" data-id="audit-log">
|
117 |
+
<h2><?php esc_html_e( 'Audit Log', 'gdpr' ) ?></h2>
|
118 |
+
<div class="postbox not-full">
|
119 |
+
<form class="gdpr-audit-log-lookup" method="post">
|
120 |
+
<div class="inside">
|
121 |
+
<?php wp_nonce_field( 'gdpr-audit-log', 'gdpr_audit_log_nonce' ); ?>
|
122 |
+
<h4>
|
123 |
+
<label for="gdpr-request-email-lookup"><?php esc_html_e( 'Search by email', 'gdpr' ); ?></label>
|
124 |
+
</h4>
|
125 |
+
<input type="email" name="user_email" class="regular-text" placeholder="<?php esc_attr_e( 'email@domain.com', 'gdpr' ); ?>" required>
|
126 |
+
<input type="text" name="token" placeholder="<?php esc_attr_e( '6 digit token (optional)', 'gdpr' ); ?>">
|
127 |
+
<?php submit_button( esc_html__( 'Search', 'gdpr' ), 'primary', '', false ); ?>
|
128 |
+
<span class="spinner"></span>
|
129 |
+
</div>
|
130 |
+
</form>
|
131 |
+
</div>
|
132 |
+
</div>
|
133 |
+
|
134 |
+
<!-- #poststuff -->
|
135 |
+
</div>
|
assets/css/gdpr-admin.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
.gdpr-settings-form #tabs,.gdpr-settings-form #consent-tabs{margin-top:20px}.gdpr-settings-form #tabs .hndle,.gdpr-settings-form #consent-tabs .hndle{font-size:16px;padding:8px 12px;margin:0;line-height:1.4}.gdpr-settings-form #tabs .hndle span,.gdpr-settings-form #consent-tabs .hndle span{font-size:12px}.privacy-page-updated-notice form{display:inline-block}.privacy-page-updated-notice form .button-secondary{vertical-align:baseline}.privacy-page-updated-notice form .button-primary:active{vertical-align:baseline}.gdpr-pending-requests-badge{display:inline-block;vertical-align:text-bottom;margin:1px 0 0 2px;padding:0 5px;min-width:7px;height:17px;border-radius:11px;background-color:#ca4a1f;color:#fff;font-size:9px;line-height:17px;text-align:center}.gdpr-request-table .spinner,.gdpr-manual-email-lookup .spinner{float:none;display:none}.gdpr-manual-email-lookup .inside{margin-bottom:0}.gdpr-request-table td{vertical-align:middle}.gdpr-request-table form{display:inline-block}.gdpr-request-table .text-center{text-align:center}.gdpr-request-table tr.review>td{padding-top:0;padding-bottom:0}.gdpr-request-table tr.review table{margin-bottom:10px}.gdpr-switch{position:relative;display:inline-block;width:45px;height:24px}.gdpr-switch input{display:none}.gdpr-switch .gdpr-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;-webkit-transition:.4s;-o-transition:.4s;transition:.4s}.gdpr-switch .gdpr-slider:before{position:absolute;content:"";height:16px;width:16px;left:4px;bottom:4px;background-color:white;-webkit-transition:.4s;-o-transition:.4s;transition:.4s}.gdpr-switch .gdpr-slider.round{border-radius:34px}.gdpr-switch .gdpr-slider.round:before{border-radius:50%}.gdpr-switch input:checked+.gdpr-slider{background-color:#00b9eb}.gdpr-switch input:checked+.gdpr-slider:before{-webkit-transform:translateX(21px);-ms-transform:translateX(21px);transform:translateX(21px)}.gdpr-switch input:focus+.gdpr-slider{-webkit-box-shadow:0 0 1px #00b9eb;box-shadow:0 0 1px #00b9eb}#TB_ajaxContent pre{white-space:pre-wrap;word-wrap:break-word}.gdpr-hidden{display:none}.post-type-telemetry .page-title-action{display:none}.post-type-telemetry .row-actions{display:none}.post-type-telemetry .search-box{display:none}.post-type-telemetry .actions #filter-by-date,.post-type-telemetry .actions #post-query-submit,.post-type-telemetry .actions.bulkactions{display:none}.gdpr .not-full{display:inline-block}.gdpr .spinner{display:none;visibility:visible}.gdpr .gdpr-access-data-result h2 span{font-size:16px}#tabs .postbox .inside{margin:0 !important;padding:0 20px 20px 20px}#tabs .postbox .inside .form-table{margin-top:0}#tabs .postbox .inside .tab-hosts .postbox{margin-bottom:0}#tabs .postbox .inside .tab-hosts .postbox .inside{padding-bottom:0;background-color:#f9f9f9}@media screen and (max-width: 1024px){.tab-hosts .postbox{margin-top:15px}.tab-hosts .postbox .inside{padding:10px 20px 20px 20px !important}.form-table td{padding-right:0}.form-table td .button{margin-top:5px;margin-bottom:10px}.type-telemetry *{word-wrap:break-word !important}}@media screen and (max-width: 640px){.postbox{width:100%}.postbox .notice-dismiss{padding:8px}.inside .regular-text{width:100%}.inside .button{margin-top:5px}}
|
assets/css/gdpr-public.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
.gdpr-noscroll{overflow:hidden;position:fixed;width:100%}.gdpr-hidden{display:none}.gdpr-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);z-index:99999999;display:none}.gdpr *{font-family:Helvetica, Arial, sans-serif !important;text-transform:none !important;letter-spacing:0 !important;color:#455561;background:none;-webkit-box-shadow:none;box-shadow:none;text-shadow:none;outline:none;border:none;margin:0;padding:0}.gdpr button,.gdpr input[type="submit"]{color:#000;font-weight:normal;font-size:14px;margin:0;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1);line-height:1.5;display:block;min-width:auto;max-width:auto}.gdpr button:before,.gdpr button:after,.gdpr input[type="submit"]:before,.gdpr input[type="submit"]:after{display:inline-block;margin:0;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1);top:auto;right:auto;bottom:auto;left:auto;background:none}.gdpr button:hover,.gdpr button:active,.gdpr button:focus,.gdpr input[type="submit"]:hover,.gdpr input[type="submit"]:active,.gdpr input[type="submit"]:focus{margin:0;border:none;-webkit-box-shadow:none;box-shadow:none}.gdpr img{width:100% !important}.gdpr.gdpr-privacy-bar{position:fixed;bottom:0;left:0;background:rgba(0,0,0,0.9);width:100%;color:#fff;z-index:9999999}.gdpr.gdpr-privacy-bar .gdpr-wrapper{padding:20px 40px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-sizing:border-box;box-sizing:border-box}@media screen and (max-width: 1024px){.gdpr.gdpr-privacy-bar .gdpr-wrapper{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center}}.gdpr.gdpr-privacy-bar .gdpr-wrapper:after{content:"";display:table;clear:both}.gdpr.gdpr-privacy-bar .gdpr-wrapper p{margin:0;font-size:14px;font-weight:normal}.gdpr.gdpr-privacy-bar .gdpr-wrapper .gdpr-content{-webkit-box-flex:1;-ms-flex:1;flex:1;padding-right:200px}.gdpr.gdpr-privacy-bar .gdpr-wrapper .gdpr-content p{color:#ffffff}.gdpr.gdpr-privacy-bar .gdpr-wrapper .gdpr-content a{color:#fff;text-decoration:underline}@media screen and (max-width: 1024px){.gdpr.gdpr-privacy-bar .gdpr-wrapper .gdpr-content{padding-right:0;padding-bottom:20px}}.gdpr.gdpr-privacy-bar .gdpr-wrapper .gdpr-right{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}@media screen and (max-width: 640px){.gdpr.gdpr-privacy-bar .gdpr-wrapper .gdpr-right{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}}.gdpr.gdpr-privacy-bar .gdpr-wrapper .gdpr-right button:first-of-type{margin-left:10px}@media screen and (max-width: 640px){.gdpr.gdpr-privacy-bar .gdpr-wrapper .gdpr-right button:first-of-type{margin:0 0 10px 7px}.gdpr.gdpr-privacy-bar .gdpr-wrapper .gdpr-right button:first-of-type:before{left:-7px}}.gdpr.gdpr-privacy-bar .gdpr-wrapper .gdpr-right button:last-of-type{margin-right:0;margin-left:20px}@media screen and (max-width: 640px){.gdpr.gdpr-privacy-bar .gdpr-wrapper .gdpr-right button:last-of-type{margin:0}}.gdpr.gdpr-privacy-bar .gdpr-preferences{font-weight:normal;font-size:14px;text-decoration:underline;position:relative;margin-left:9px;color:#fff;float:left}.gdpr.gdpr-privacy-bar .gdpr-preferences:before{content:'\276F';font-size:1.1em;font-weight:normal;padding-right:5px;color:#fff;position:absolute;left:-7px;top:10px}.gdpr.gdpr-privacy-bar .gdpr-preferences:hover,.gdpr.gdpr-privacy-bar .gdpr-preferences:active,.gdpr.gdpr-privacy-bar .gdpr-preferences:focus,.gdpr.gdpr-privacy-bar .gdpr-preferences:focus-within,.gdpr.gdpr-privacy-bar .gdpr-preferences:visited{background:none}.gdpr.gdpr-privacy-bar button{margin:0 5px;padding:9px 10px}@media screen and (max-width: 640px){.gdpr.gdpr-privacy-bar button{margin:0}}.gdpr.gdpr-privacy-bar .gdpr-agreement{position:relative;font-size:13px;font-weight:normal;padding:12px 36px 12px 76px;height:auto;line-height:1.4285714;white-space:normal;margin:0;border-width:1px;border-style:solid;border-radius:3px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#0085ba;border-color:#0073aa #006799 #006799;-webkit-box-shadow:0 1px 0 #006799;box-shadow:0 1px 0 #006799;color:#fff;text-decoration:none;text-shadow:0 -1px 1px #006799, 1px 0 1px #006799, 0 1px 1px #006799, -1px 0 1px #006799}.gdpr.gdpr-privacy-bar .gdpr-agreement:hover{background:#008ec2;border-color:#006799}.gdpr.gdpr-privacy-bar .gdpr-agreement:hover:before{font-size:26px;background:#fafafa;color:#00b9eb}.gdpr.gdpr-privacy-bar .gdpr-agreement:active,.gdpr.gdpr-privacy-bar .gdpr-agreement:focus{background:#0073aa;border-color:#006799;-webkit-box-shadow:inset 0 2px 0 #006799;box-shadow:inset 0 2px 0 #006799;vertical-align:top}.gdpr.gdpr-privacy-bar .gdpr-agreement:active:before,.gdpr.gdpr-privacy-bar .gdpr-agreement:focus:before{-webkit-box-shadow:inset 0 2px 0 #ccc;box-shadow:inset 0 2px 0 #ccc;vertical-align:top}.gdpr.gdpr-privacy-bar .gdpr-agreement:before{content:'\2713';top:-1px;bottom:-1px;left:-1px;position:absolute;width:42.5px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:all 0.2s;-o-transition:all 0.2s;transition:all 0.2s;-webkit-transform:translateZ(0);transform:translateZ(0);text-shadow:none;text-decoration:none;font-size:13px;line-height:26px;cursor:pointer;border-width:1px;border-style:solid;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-top-left-radius:3px;border-bottom-left-radius:3px;white-space:nowrap;-webkit-box-sizing:border-box;box-sizing:border-box;color:#555;border-color:#ccc;background:#f7f7f7;-webkit-box-shadow:0 1px 0 #ccc;box-shadow:0 1px 0 #ccc;vertical-align:top;border-right:none}.gdpr.gdpr-privacy-preferences .gdpr-wrapper,.gdpr.gdpr-general-confirmation .gdpr-wrapper{position:fixed;top:50%;left:50%;-webkit-transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);transform:translate(-50%, -50%);z-index:999999999;width:100%;max-width:768px;height:100%;max-height:500px;overflow:hidden;display:none;border-radius:2.5px;padding:15px;-webkit-box-sizing:border-box;box-sizing:border-box}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form,.gdpr.gdpr-general-confirmation .gdpr-wrapper form{height:100%;position:relative}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>header,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>header{display:-webkit-box;display:-ms-flexbox;display:flex;height:75px}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>header .logo,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>header .logo{max-width:30%}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>header .logo a,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>header .logo a{padding:0;margin:0}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>header .logo a img,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>header .logo a img{display:block}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>header .gdpr-box-title,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>header .gdpr-box-title{background:#23282d;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;position:relative}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>header .gdpr-box-title h3,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>header .gdpr-box-title h3{margin:0 !important;padding:0 !important;text-align:center !important;color:#fff !important;font-weight:600 !important;font-size:22px !important}@media screen and (max-width: 640px){.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>header .gdpr-box-title h3,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>header .gdpr-box-title h3{font-size:18px !important}}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>header .gdpr-box-title .gdpr-close,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>header .gdpr-box-title .gdpr-close{color:#fff;position:absolute;top:0;right:0;cursor:pointer;-webkit-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;padding:15px 15px;line-height:0}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>header .gdpr-box-title .gdpr-close:hover:before,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>header .gdpr-box-title .gdpr-close:hover:before{-webkit-transform:scale(1.5);-ms-transform:scale(1.5);transform:scale(1.5)}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>header .gdpr-box-title .gdpr-close:before,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>header .gdpr-box-title .gdpr-close:before{content:'\00D7';line-height:12.5px;font-size:25px;display:inline-block;-webkit-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-backface-visibility:hidden;backface-visibility:hidden}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>footer,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>footer{position:absolute;padding:0 20px 20px 20px;bottom:0;left:160px;right:0;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}@media screen and (max-width: 640px){.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>footer,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>footer{left:0;bottom:5px}}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>footer input[type="submit"],.gdpr.gdpr-general-confirmation .gdpr-wrapper form>footer input[type="submit"]{font-size:13px;font-weight:normal;line-height:26px;height:28px;margin:0;padding:0 10px 1px;border-width:1px;border-style:solid;border-radius:3px;white-space:nowrap;-webkit-box-sizing:border-box;box-sizing:border-box;background:#0085ba;border-color:#0073aa #006799 #006799;-webkit-box-shadow:0 1px 0 #006799;box-shadow:0 1px 0 #006799;color:#fff;text-decoration:none;text-shadow:0 -1px 1px #006799, 1px 0 1px #006799, 0 1px 1px #006799, -1px 0 1px #006799}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>footer input[type="submit"]:hover,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>footer input[type="submit"]:hover{background:#008ec2;border-color:#006799}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>footer input[type="submit"]:active,.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>footer input[type="submit"].focus,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>footer input[type="submit"]:active,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>footer input[type="submit"].focus{background:#0073aa;border-color:#006799;-webkit-box-shadow:inset 0 2px 0 #006799;box-shadow:inset 0 2px 0 #006799;vertical-align:top}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>footer span,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>footer span{font-size:13px;line-height:20px;color:#555d66;font-style:italic}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>footer span a,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>footer span a{color:#0073aa;-webkit-transition-property:border,background,color;-o-transition-property:border,background,color;transition-property:border,background,color;-webkit-transition-duration:.05s;-o-transition-duration:.05s;transition-duration:.05s;-webkit-transition-timing-function:ease-in-out;-o-transition-timing-function:ease-in-out;transition-timing-function:ease-in-out;text-decoration:underline}.gdpr.gdpr-privacy-preferences .gdpr-wrapper form>footer span a:hover,.gdpr.gdpr-general-confirmation .gdpr-wrapper form>footer span a:hover{color:#00a0d2}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-mobile-menu,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-mobile-menu{display:none}@media screen and (max-width: 640px){.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-mobile-menu,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-mobile-menu{display:block}}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-mobile-menu button,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-mobile-menu button{width:100%;background-color:#191e23;color:#fff;font-size:14px;text-align:left;padding:15px;border-radius:0;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;line-height:0}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-mobile-menu button:hover,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-mobile-menu button:hover{color:#00b9eb}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-mobile-menu button:hover:after,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-mobile-menu button:hover:after{border-top-color:#00b9eb}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-mobile-menu button:after,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-mobile-menu button:after{content:'';width:0;height:0;border-left:7.5px solid transparent;border-right:7.5px solid transparent;border-top:7.5px solid #fff;-webkit-transition:all 0.2s;-o-transition:all 0.2s;transition:all 0.2s;right:15px;top:12px;position:absolute}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-mobile-menu button.gdpr-active:after,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-mobile-menu button.gdpr-active:after{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content{display:-webkit-box;display:-ms-flexbox;display:flex;height:calc( 100% - 75px);background:#f1f1f1}@media screen and (max-width: 640px){.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content{position:relative;height:calc( 100% - 119px)}}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs{border:none !important;min-width:160px;max-width:160px;padding:0;margin:0;overflow-y:auto;background-color:#23282d;position:relative}@media screen and (max-width: 640px){.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs{position:absolute;height:100%;width:100%;max-width:100%;display:none;z-index:1}}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li{list-style:none}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li button,.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li a,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li button,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li a{display:block;width:100%;background:#23282d;color:#fff;font-size:14px;text-align:left;padding:8px;border-radius:0;position:relative}@media screen and (max-width: 640px){.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li button,.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li a,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li button,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li a{padding:15px;line-height:1}}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li button:hover,.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li a:hover,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li button:hover,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li a:hover{background-color:#191e23;color:#00b9eb}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li button.gdpr-active,.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li a.gdpr-active,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li button.gdpr-active,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li a.gdpr-active{background-color:#0073aa}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li button.gdpr-active:hover,.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li a.gdpr-active:hover,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li button.gdpr-active:hover,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li a.gdpr-active:hover{color:#fff}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li button.gdpr-active:after,.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li a.gdpr-active:after,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li button.gdpr-active:after,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li a.gdpr-active:after{right:0;border:8px solid transparent;content:'';height:0;width:0;position:absolute;pointer-events:none;border-right-color:#f1f1f1;top:50%;margin-top:-8px}@media screen and (max-width: 640px){.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li button.gdpr-active:after,.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li a.gdpr-active:after,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li button.gdpr-active:after,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li a.gdpr-active:after{display:none}}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li .gdpr-subtabs,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li .gdpr-subtabs{position:relative;padding:8px 0;top:auto;left:auto;right:auto;bottom:auto;border:0;margin:0 0 0 0;-webkit-box-shadow:none;box-shadow:none;background-color:#32373c}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li .gdpr-subtabs li button,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li .gdpr-subtabs li button{background-color:transparent;font-size:13px;line-height:18px;padding:5px 8px}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li .gdpr-subtabs li button.gdpr-active,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li .gdpr-subtabs li button.gdpr-active{font-weight:600}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tabs li .gdpr-subtabs li button.gdpr-active:after,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tabs li .gdpr-subtabs li button.gdpr-active:after{border:none;content:''}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content{width:100%;margin-bottom:68px;overflow-y:auto}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div{display:none;padding:20px 20px 0 20px;overflow-y:auto;font-size:13px;height:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div header,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div header h4,.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div header label,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div header h4,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div header label{margin:0}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div header h4,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div header h4{font-weight:600 !important;padding-right:10px}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info{height:100%;overflow-y:auto;-webkit-box-flex:1;-ms-flex:1;flex:1;margin-top:20px;position:relative}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info>p,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info>p{margin-bottom:16px}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info strong,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info strong{border-bottom:1px solid rgba(0,0,0,0.4);display:block}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used{font-family:Helvetica, Arial, sans-serif;border:1px solid #e5e5e5;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.04);box-shadow:0 1px 1px rgba(0,0,0,0.04);margin-bottom:10px;background-color:#fff;font-size:13px}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used:first-of-type,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used:first-of-type{padding-top:0}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookie-title,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookie-title{padding:10px;border-bottom:1px solid #e1e1e1;color:#32373c;position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookie-title p,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookie-title p{margin:0;font-weight:600 !important}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookie-title .gdpr-always-active,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookie-title .gdpr-always-active{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;padding:0 10px;min-height:24px;text-align:center;border-radius:50px;line-height:16px;background-color:#00b9eb;color:#fff;font-style:normal}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookie-title a,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookie-title a{color:#0073aa}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookie-title a:hover,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookie-title a:hover{color:#00a0d2}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookies,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookies{color:#555;background-color:#f9f9f9;padding:10px}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookies span,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content>div .gdpr-info .gdpr-cookies-used .gdpr-cookies span{font-style:italic}.gdpr.gdpr-privacy-preferences .gdpr-wrapper .gdpr-content .gdpr-tab-content .gdpr-active,.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content .gdpr-tab-content .gdpr-active{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.gdpr.gdpr-general-confirmation .gdpr-wrapper{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;max-width:400px;min-height:250px}.gdpr.gdpr-general-confirmation .gdpr-wrapper>header{display:-webkit-box;display:-ms-flexbox;display:flex;height:75px}.gdpr.gdpr-general-confirmation .gdpr-wrapper>header .logo{max-width:30%}.gdpr.gdpr-general-confirmation .gdpr-wrapper>header .logo a{padding:0;margin:0}.gdpr.gdpr-general-confirmation .gdpr-wrapper>header .logo a img{display:block}.gdpr.gdpr-general-confirmation .gdpr-wrapper>header .gdpr-box-title{background:#23282d;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;position:relative}.gdpr.gdpr-general-confirmation .gdpr-wrapper>header .gdpr-box-title h3{margin:0 !important;padding:0 !important;text-align:center !important;color:#fff !important;font-weight:600 !important;font-size:22px !important}@media screen and (max-width: 640px){.gdpr.gdpr-general-confirmation .gdpr-wrapper>header .gdpr-box-title h3{font-size:18px !important}}.gdpr.gdpr-general-confirmation .gdpr-wrapper>header .gdpr-box-title .gdpr-close{color:#fff;position:absolute;top:0;right:0;cursor:pointer;-webkit-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;padding:15px 15px;line-height:0}.gdpr.gdpr-general-confirmation .gdpr-wrapper>header .gdpr-box-title .gdpr-close:hover:before{-webkit-transform:scale(1.5);-ms-transform:scale(1.5);transform:scale(1.5)}.gdpr.gdpr-general-confirmation .gdpr-wrapper>header .gdpr-box-title .gdpr-close:before{content:'\00D7';line-height:12.5px;font-size:25px;display:inline-block;-webkit-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-backface-visibility:hidden;backface-visibility:hidden}.gdpr.gdpr-general-confirmation .gdpr-wrapper>footer{background:#f1f1f1;padding:20px}.gdpr.gdpr-general-confirmation .gdpr-wrapper>footer button{font-size:13px;font-weight:normal;line-height:26px;height:28px;margin:0;padding:0 10px 1px;border-width:1px;border-style:solid;border-radius:3px;white-space:nowrap;-webkit-box-sizing:border-box;box-sizing:border-box;background:#0085ba;border-color:#0073aa #006799 #006799;-webkit-box-shadow:0 1px 0 #006799;box-shadow:0 1px 0 #006799;color:#fff;text-decoration:none;text-shadow:0 -1px 1px #006799, 1px 0 1px #006799, 0 1px 1px #006799, -1px 0 1px #006799;display:inline}.gdpr.gdpr-general-confirmation .gdpr-wrapper>footer button:hover{background:#008ec2;border-color:#006799}.gdpr.gdpr-general-confirmation .gdpr-wrapper>footer button:active,.gdpr.gdpr-general-confirmation .gdpr-wrapper>footer button.focus{background:#0073aa;border-color:#006799;-webkit-box-shadow:inset 0 2px 0 #006799;box-shadow:inset 0 2px 0 #006799;vertical-align:top}.gdpr.gdpr-general-confirmation .gdpr-wrapper>footer button.gdpr-cancel{color:#555;border-color:#ccc;background:#f7f7f7;-webkit-box-shadow:0 1px 0 #ccc;box-shadow:0 1px 0 #ccc;text-shadow:none}.gdpr.gdpr-general-confirmation .gdpr-wrapper>footer button.gdpr-cancel:hover{background:#fafafa;border-color:#999;color:#23282d;-webkit-box-shadow:0 1px 0 #ccc;box-shadow:0 1px 0 #ccc}.gdpr.gdpr-general-confirmation .gdpr-wrapper>footer button.gdpr-cancel:active,.gdpr.gdpr-general-confirmation .gdpr-wrapper>footer button.gdpr-cancel:focus{background:#eee;border-color:#999;-webkit-box-shadow:inset 0 2px 5px -3px rgba(0,0,0,0.5);box-shadow:inset 0 2px 5px -3px rgba(0,0,0,0.5);-webkit-transform:translateY(1px);-ms-transform:translateY(1px);transform:translateY(1px);color:#23282d}.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content{padding:20px 20px 0 20px;height:auto}.gdpr.gdpr-general-confirmation .gdpr-wrapper .gdpr-content p{margin:0}.gdpr-switch{position:relative;display:inline-block;min-width:45px;height:24px;margin-bottom:0}.gdpr-switch input{display:none}.gdpr-switch .gdpr-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;-webkit-transition:.4s;-o-transition:.4s;transition:.4s}.gdpr-switch .gdpr-slider:before{position:absolute;content:"";height:16px;width:16px;left:4px;bottom:4px;background-color:white;-webkit-transition:.4s;-o-transition:.4s;transition:.4s}.gdpr-switch .gdpr-slider.round{border-radius:34px}.gdpr-switch .gdpr-slider.round:before{border-radius:50%}.gdpr-switch input:checked+.gdpr-slider{background-color:#00b9eb}.gdpr-switch input:checked+.gdpr-slider:before{-webkit-transform:translateX(21px);-ms-transform:translateX(21px);transform:translateX(21px)}.gdpr-switch input:focus+.gdpr-slider{-webkit-box-shadow:0 0 1px #00b9eb;box-shadow:0 0 1px #00b9eb}.gdpr-reconsent-modal{width:100%;height:100%;position:fixed;top:0;left:0;background:#fff;z-index:9999999}.gdpr-reconsent-modal .gdpr-reconsent-modal-content{width:90%;margin:0 auto;position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%, -50%);-ms-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}@media screen and (min-width: 640px){.gdpr-reconsent-modal .gdpr-reconsent-modal-content{width:50%}}.gdpr-reconsent-modal .gdpr-reconsent-modal-content .gdpr-privacy-viewer{height:50vh;width:100%;border:1px solid #cecece;padding:20px;overflow:auto}.gdpr-reconsent-modal .gdpr-reconsent-modal-content textarea{resize:none}.gdpr-reconsent-modal .gdpr-reconsent-modal-content .gdpr-consent-buttons{text-align:center;margin:15px 0}.gdpr-reconsent-modal .gdpr-reconsent-modal-content .gdpr-consent-buttons a{padding:10px 20px;display:inline-block;margin:0 10px;color:#fff;border-radius:5px}.gdpr-reconsent-modal .gdpr-reconsent-modal-content .gdpr-consent-buttons a.gdpr-agree{background:#28a745}.gdpr-reconsent-modal .gdpr-reconsent-modal-content .gdpr-consent-buttons a.gdpr-disagree{color:#455561;padding:0}.gdpr-reconsent-modal .gdpr-reconsent-modal-content .gdpr-consent-loading{display:none;text-align:center;margin:15px 0}.gdpr-reconsent-modal .gdpr-reconsent-modal-content .gdpr-consent-loading .gdpr-loading{padding:10px 20px;display:inline-block;margin:0 10px}
|
assets/js/gdpr-admin.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
!function(t){"use strict";t(function(){function a(t){t=(t=t.replace(/^\s+|\s+$/g,"")).toLowerCase();for(var a="àáäâèéëêìíïîòóöôùúüûñç·/_,:;",e=0,n=a.length;e<n;e++)t=t.replace(new RegExp(a.charAt(e),"g"),"aaaaeeeeiiiioooouuuunc------".charAt(e));return t=t.replace(/[^a-z0-9 -]/g,"").replace(/\s+/g,"-").replace(/-+/g,"-")}t(document).on("click",".gdpr-settings-form .notice-dismiss",function(){t(this).parent().parent().remove()}),t(".add-tab").click(function(e){e.preventDefault();var n=t("#cookie-tabs");if(""!==n.val()){var i=a(n.val()),s=n.val(),d=wp.template("cookie-tabs");t("#tabs").append(d({key:i,name:s,option_name:"gdpr_cookie_popup_content"})),n.val("")}}),t(".add-consent").click(function(e){e.preventDefault();var n=t("#type-of-consent");if(""!==n.val()){var i=a(n.val()),s=n.val(),d=wp.template("consents");t("#consent-tabs").append(d({key:i,name:s,option_name:"gdpr_consent_types"})),n.val("")}}),t("#consent-tabs, #tabs").sortable(),t(document).on("click",".add-host",function(a){a.preventDefault();var e=t(this).siblings("input");if(""!==e.val()){var n=t(this).data("tabid"),i=e.val().toLowerCase().replace(" ","-"),s=wp.template("cookie-tabs-hosts");t('.tab-hosts[data-tabid="'+n+'"]').append(s({host_key:i,tab_key:n,option_name:"gdpr_cookie_popup_content"})),e.val("")}}),t(document).on("click","#tabs .notice-dismiss",function(a){a.preventDefault(),t(this).closest(".postbox").remove()}),t(document).on("click",".gdpr-request-table .gdpr-review",function(a){a.preventDefault();var e=t(this).data("index");t("tr[data-index="+e+"] div").slideToggle()}),t(document).on("click",".gdpr .nav-tab-wrapper a",function(a){var e=t(this).attr("href");if(e=e.replace("#",""),t(this).addClass("nav-tab-active"),t(this).siblings().removeClass("nav-tab-active"),t(".gdpr .gdpr-tab").addClass("hidden"),t(".gdpr .gdpr-tab[data-id="+e+"]").removeClass("hidden"),-1!==location.search.indexOf("page=gdpr-settings")){var n=t('.gdpr form input[name="_wp_http_referer"]'),i=n.val().split("#")[0];n.val(i+"#"+e)}});var e=window.location.hash;if(e){if(t('.gdpr .nav-tab-wrapper a[href="'+e+'"]').addClass("nav-tab-active"),t('.gdpr .gdpr-tab[data-id="'+e.replace("#","")+'"]').removeClass("hidden"),-1!==location.search.indexOf("page=gdpr-settings")){var n=t('.gdpr form input[name="_wp_http_referer"]'),i=n.val().split("#")[0];n.val(i+e)}}else t(".gdpr .nav-tab-wrapper a:eq(0)").addClass("nav-tab-active"),t(".gdpr .gdpr-tab:eq(0)").removeClass("hidden");t(document).on("change",".gdpr-reassign",function(){0!=t(this).val()?(t(this).closest("tr").find("td:last .button-primary").attr("disabled",!1),t(this).closest("tr").find('td:last input[name="reassign_to"]').val(t(this).val())):(t(this).closest("tr").find("td:last .button-primary").attr("disabled",!0),t(this).closest("tr").find('td:last input[name="reassign_to"]').val(""))}),t(document).on("submit",".gdpr-reassign-content",function(a){a.preventDefault();var e=t(this).find('input[name="user_email"]').val(),n=t(this).find('input[name="reassign_to"]').val(),i=t(this).find('input[name="post_type"]').val(),s=t(this).find('input[name="post_count"]').val(),d=t(this).find('input[name="gdpr_reassign_content_nonce"]').val(),o=t(this).find(".button-primary"),r=t(this).find(".spinner"),p=t(this).find("p.hidden");n&&(o.addClass("hidden"),r.addClass("is-active"),r.css("display","block"),t.post(ajaxurl,{action:"gdpr_reassign_content",user_email:e,reassign_to:n,post_type:i,post_count:s,nonce:d},function(t){r.removeClass("is-active"),r.hide(),p.removeClass("hidden"),t.success||p.text(t.data)}))}),t(document).on("submit",".gdpr-anonymize-comments",function(a){a.preventDefault();var e=t(this).find('input[name="user_email"]').val(),n=t(this).find('input[name="comment_count"]').val(),i=t(this).find('input[name="gdpr_anonymize_comments_nonce"]').val(),s=t(this).find(".button-primary"),d=t(this).find(".spinner"),o=t(this).find("p.hidden");s.addClass("hidden"),d.addClass("is-active"),d.css("display","block"),t.post(ajaxurl,{action:"gdpr_anonymize_comments",user_email:e,comment_count:n,nonce:i},function(t){d.removeClass("is-active"),d.hide(),o.removeClass("hidden"),t.success||o.text(t.data)})}),t(document).on("submit",".gdpr-access-data-lookup",function(a){a.preventDefault();var e=t(this).find('input[name="user_email"]'),n=e.val(),i=t(this).find('input[name="gdpr_access_data_nonce"]').val(),s=t(this).find(".button-primary"),d=t(this).find(".spinner"),o=t(".gdpr-access-data-result");s.addClass("hidden"),d.show(),o.remove(),e.val(""),t.post(ajaxurl,{action:"gdpr_access_data",nonce:i,email:n},function(a){if(s.removeClass("hidden"),d.hide(),a.success){var e=wp.template("access-data-result-success");t('.gdpr div[data-id="access"]').append(e({result:a.data.result,user_email:a.data.user_email}))}else{e=wp.template("access-data-result-error");t('.gdpr div[data-id="access"]').append(e())}})}),t(document).on("submit",".gdpr-audit-log-lookup",function(a){a.preventDefault();var e=t(this).find('input[name="user_email"]'),n=e.val(),i=t(this).find('input[name="token"]'),s=i.val(),d=t(this).find('input[name="gdpr_audit_log_nonce"]').val(),o=t(this).find(".button-primary"),r=t(this).find(".spinner"),p=t(".gdpr-audit-log-result");o.addClass("hidden"),r.show(),p.remove(),e.val(""),i.val(""),t.post(ajaxurl,{action:"gdpr_audit_log",nonce:d,email:n,token:s},function(a){if(o.removeClass("hidden"),r.hide(),a.success){var e=wp.template("audit-log-result-success");t('.gdpr div[data-id="audit-log"]').append(e({result:a.data}))}else{e=wp.template("audit-log-result-error");t('.gdpr div[data-id="audit-log"]').append(e())}})}),t(document).on("click",'.frm-export-data input[type="submit"]',function(a){a.preventDefault();var e=t(this).parents("form"),n=t(this).val(),i=e.find("#gdpr_export_data_nonce").val(),s=e.find('input[name="user_email"]').val(),d=n.toLowerCase();t.post(ajaxurl,{action:"gdpr_generate_data_export",nonce:i,type:n,email:s},function(a){a.success&&t("<a />",{href:"data:text/plain;charset=utf-8,"+encodeURIComponent(a.data),download:s+"."+d,text:"click"}).hide().appendTo("body")[0].click()})}),t(document).on("submit",".frm-ignore-privacy-update",function(a){a.preventDefault();var e=t(this).find('input[name="action"]').val(),n=t(this).find("#privacy-policy-ignore-update-nonce").val();t(".privacy-page-updated-notice .notice-dismiss").click(),t.post(ajaxurl,{action:e,nonce:n})})})}(jQuery);
|
assets/js/gdpr-public.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
!function(e){"use strict";var r=location.search,d=location.protocol+"//"+location.host+location.pathname;-1!==r.indexOf("notify=1")&&window.history.replaceState({},document.title,d),window.has_consent=function(e){if(Cookies.get("gdpr[consent_types]")&&JSON.parse(Cookies.get("gdpr[consent_types]")).indexOf(e)>-1)return!0;return!1},window.is_allowed_cookie=function(e){if(Cookies.get("gdpr[allowed_cookies]")&&JSON.parse(Cookies.get("gdpr[allowed_cookies]")).indexOf(e)>-1)return!0;return!1},e(function(){Cookies.get("gdpr[privacy_bar]")||e(".gdpr.gdpr-privacy-bar").delay(1e3).slideDown(600),!has_consent("privacy-policy")&&GDPR.is_user_logged_in&&0!=GDPR.privacy_page_id&&(e(".gdpr-reconsent-modal").show(),e("body").addClass("gdpr-noscroll"),e(".wpadminbar").hide()),e(document).on("click",".gdpr.gdpr-privacy-bar .gdpr-agreement",function(){e(".gdpr-privacy-preferences-frm").submit()}),e(document).on("submit",".gdpr-privacy-preferences-frm",function(){Cookies.set("gdpr[privacy_bar]",1,{expires:365})}),e(document).on("click",".gdpr-preferences",function(){e(this).data("type");e(".gdpr-overlay").fadeIn(),e("body").addClass("gdpr-noscroll"),e(".gdpr.gdpr-privacy-preferences .gdpr-wrapper").fadeIn()}),e(document).on("click",".gdpr.gdpr-privacy-preferences .gdpr-close, .gdpr-overlay",function(){e(".gdpr-overlay").fadeOut(),e("body").removeClass("gdpr-noscroll"),e(".gdpr.gdpr-privacy-preferences .gdpr-wrapper").fadeOut()}),e(document).on("click",".gdpr.gdpr-privacy-preferences .gdpr-tabs button",function(){var r="."+e(this).data("target");e(".gdpr.gdpr-privacy-preferences .gdpr-tab-content > div").removeClass("gdpr-active"),e(".gdpr.gdpr-privacy-preferences .gdpr-tab-content "+r).addClass("gdpr-active"),e(".gdpr.gdpr-privacy-preferences .gdpr-tabs").hasClass("gdpr-mobile-expanded")&&(e(".gdpr.gdpr-privacy-preferences .gdpr-mobile-menu button").removeClass("gdpr-active"),e(".gdpr.gdpr-privacy-preferences .gdpr-tabs").toggle()),e(".gdpr.gdpr-privacy-preferences .gdpr-tabs button").removeClass("gdpr-active"),e(".gdpr-subtabs li button").removeClass("gdpr-active"),e(this).hasClass("gdpr-tab-button")?(e(this).addClass("gdpr-active"),e(this).hasClass("gdpr-cookie-settings")&&e(".gdpr-subtabs").find("li button").first().addClass("gdpr-active")):(e(".gdpr-cookie-settings").addClass("gdpr-active"),e(this).addClass("gdpr-active"))}),e(document).on("click",".gdpr.gdpr-privacy-preferences .gdpr-mobile-menu button",function(r){e(this).toggleClass("gdpr-active"),e(".gdpr.gdpr-privacy-preferences .gdpr-tabs").toggle().addClass("gdpr-mobile-expanded")}),e(window).resize(function(){e(window).width()>640&&e(".gdpr.gdpr-privacy-preferences .gdpr-tabs").hasClass("gdpr-mobile-expanded")&&(e(".gdpr.gdpr-privacy-preferences .gdpr-mobile-menu button").removeClass("gdpr-active"),e(".gdpr.gdpr-privacy-preferences .gdpr-tabs").removeClass("gdpr-mobile-expanded").removeAttr("style"))}),e("form.gdpr-add-to-deletion-requests").on("submit",function(r){e(this).hasClass("confirmed")||(r.preventDefault(),e(".gdpr-overlay").fadeIn(),e("body").addClass("gdpr-noscroll"),e(".gdpr.gdpr-delete-confirmation .gdpr-wrapper").css({display:"flex"}).hide().fadeIn())}),e(document).on("click",".gdpr.gdpr-general-confirmation .gdpr-close, .gdpr-overlay, .gdpr-cancel",function(){e(".gdpr-overlay").fadeOut(),e(".gdpr-reconsent-modal").is(":visible")||e("body").removeClass("gdpr-noscroll"),e(".gdpr.gdpr-general-confirmation .gdpr-wrapper").fadeOut()}),e(document).on("click",".gdpr.gdpr-delete-confirmation button.gdpr-delete-account",function(){e("form.gdpr-add-to-deletion-requests").addClass("confirmed"),e('form.gdpr-add-to-deletion-requests.confirmed input[type="submit"]').click(),e(".gdpr-overlay").fadeOut(),e("body").removeClass("gdpr-noscroll"),e(".gdpr.gdpr-delete-confirmation .gdpr-wrapper").fadeOut()}),e(".gdpr-accept-confirmation").length>0&&(e(".gdpr-overlay").fadeIn(),e("body").addClass("gdpr-noscroll"),e(".gdpr.gdpr-accept-confirmation .gdpr-wrapper").css({display:"flex"}).hide().fadeIn(),e(document).on("click",".gdpr.gdpr-accept-confirmation button.gdpr-ok",function(){e(".gdpr-overlay").fadeOut(),e("body").removeClass("gdpr-noscroll"),e(".gdpr.gdpr-accept-confirmation .gdpr-wrapper").fadeOut()})),e(document).on("click",".gdpr-agree",function(r){r.preventDefault();e(this);e(".gdpr-consent-buttons").fadeOut(300,function(){e(".gdpr-consent-loading").fadeIn(300)});var d=0;setInterval(function(){e(".gdpr-ellipsis").html();d<3?(e(".gdpr-ellipsis").append("."),d++):(e(".gdpr-ellipsis").html(""),d=0)},600);e.post(GDPR.ajaxurl,{action:"agree_with_terms",nonce:e(this).data("nonce")},function(r){r.success&&(e(".gdpr-reconsent-modal").fadeOut(300,function(){e(this).remove(),e(".wpadminbar").show()}),e("body").removeClass("gdpr-noscroll"))})}),e(document).on("click",".gdpr-disagree",function(r){e(".gdpr-overlay").fadeIn(),e("body").addClass("gdpr-noscroll"),e(".gdpr.gdpr-disagree-confirmation .gdpr-wrapper").css({display:"flex"}).hide().fadeIn()}),e(document).on("click",".gdpr-disagree-confirm",function(r){r.preventDefault(),e(".gdpr-overlay").fadeOut(),e(".gdpr.gdpr-disagree-confirmation .gdpr-wrapper").fadeOut(),e(".gdpr-consent-buttons").fadeOut(300,function(){e(".gdpr-updating").html(GDPR.aborting),e(".gdpr-consent-loading").fadeIn(300)});var d=0;setInterval(function(){e(".gdpr-ellipsis").html();d<3?(e(".gdpr-ellipsis").append("."),d++):(e(".gdpr-ellipsis").html(""),d=0)},600);e.post(GDPR.ajaxurl,{action:"disagree_with_terms",nonce:e(this).data("nonce")},function(e){e.success&&location.reload()})})})}(jQuery),function(e){var r=!1;if("function"==typeof define&&define.amd&&(define(e),r=!0),"object"==typeof exports&&(module.exports=e(),r=!0),!r){var d=window.Cookies,n=window.Cookies=e();n.noConflict=function(){return window.Cookies=d,n}}}(function(){function e(){for(var e=0,r={};e<arguments.length;e++){var d=arguments[e];for(var n in d)r[n]=d[n]}return r}return function r(d){function n(r,o,t){var p;if("undefined"!=typeof document){if(arguments.length>1){if("number"==typeof(t=e({path:"/"},n.defaults,t)).expires){var a=new Date;a.setMilliseconds(a.getMilliseconds()+864e5*t.expires),t.expires=a}t.expires=t.expires?t.expires.toUTCString():"";try{p=JSON.stringify(o),/^[\{\[]/.test(p)&&(o=p)}catch(e){}o=d.write?d.write(o,r):encodeURIComponent(String(o)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),r=(r=(r=encodeURIComponent(String(r))).replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent)).replace(/[\(\)]/g,escape);var i="";for(var s in t)t[s]&&(i+="; "+s,!0!==t[s]&&(i+="="+t[s]));return document.cookie=r+"="+o+i}r||(p={});for(var c=document.cookie?document.cookie.split("; "):[],g=/(%[0-9A-Z]{2})+/g,l=0;l<c.length;l++){var f=c[l].split("="),u=f.slice(1).join("=");this.json||'"'!==u.charAt(0)||(u=u.slice(1,-1));try{var m=f[0].replace(g,decodeURIComponent);if(u=d.read?d.read(u,m):d(u,m)||u.replace(g,decodeURIComponent),this.json)try{u=JSON.parse(u)}catch(e){}if(r===m){p=u;break}r||(p[m]=u)}catch(e){}}return p}}return n.set=n,n.get=function(e){return n.call(n,e)},n.getJSON=function(){return n.apply({json:!0},[].slice.call(arguments))},n.defaults={},n.remove=function(r,d){n(r,"",e(d,{expires:-1}))},n.withConverter=r,n}(function(){})});
|
gdpr.php
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* The plugin bootstrap file
|
5 |
+
*
|
6 |
+
* This file is read by WordPress to generate the plugin information in the plugin
|
7 |
+
* admin area. This file also includes all of the dependencies used by the plugin,
|
8 |
+
* registers the activation and deactivation functions, and defines a function
|
9 |
+
* that starts the plugin.
|
10 |
+
*
|
11 |
+
* @link https://trewknowledge.com
|
12 |
+
* @since 1.0.0
|
13 |
+
* @package GDPR
|
14 |
+
*
|
15 |
+
* @wordpress-plugin
|
16 |
+
* Plugin Name: GDPR
|
17 |
+
* Plugin URI: https://trewknowledge.com
|
18 |
+
* Description: This plugin is meant to assist a Controller, Data Processor, and Data Protection Officer (DPO) with efforts to meet the obligations and rights enacted under the GDPR.
|
19 |
+
* Version: 1.4.7
|
20 |
+
* Author: Trew Knowledge
|
21 |
+
* Author URI: https://trewknowledge.com
|
22 |
+
* License: GPL-2.0+
|
23 |
+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
|
24 |
+
* Text Domain: gdpr
|
25 |
+
* Domain Path: /languages
|
26 |
+
*/
|
27 |
+
|
28 |
+
// If this file is called directly, abort.
|
29 |
+
if ( ! defined( 'WPINC' ) ) {
|
30 |
+
die;
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Currently plugin version.
|
35 |
+
* Start at version 1.0.0 and use SemVer - https://semver.org
|
36 |
+
* Rename this for your plugin and update it as you release new versions.
|
37 |
+
*/
|
38 |
+
define( 'GDPR_VERSION', '1.4.7' );
|
39 |
+
|
40 |
+
/**
|
41 |
+
* The code that runs during plugin activation.
|
42 |
+
* This action is documented in includes/class-gdpr-activator.php
|
43 |
+
*/
|
44 |
+
function activate_gdpr() {
|
45 |
+
require_once plugin_dir_path( __FILE__ ) . 'includes/class-gdpr-activator.php';
|
46 |
+
GDPR_Activator::activate();
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* The code that runs during plugin deactivation.
|
51 |
+
* This action is documented in includes/class-gdpr-deactivator.php
|
52 |
+
*/
|
53 |
+
function deactivate_gdpr() {
|
54 |
+
require_once plugin_dir_path( __FILE__ ) . 'includes/class-gdpr-deactivator.php';
|
55 |
+
GDPR_Deactivator::deactivate();
|
56 |
+
}
|
57 |
+
|
58 |
+
register_activation_hook( __FILE__, 'activate_gdpr' );
|
59 |
+
register_deactivation_hook( __FILE__, 'deactivate_gdpr' );
|
60 |
+
|
61 |
+
/**
|
62 |
+
* The core plugin class that is used to define internationalization,
|
63 |
+
* admin-specific hooks, and public-facing site hooks.
|
64 |
+
*/
|
65 |
+
require plugin_dir_path( __FILE__ ) . 'includes/class-gdpr.php';
|
66 |
+
require plugin_dir_path( __FILE__ ) . 'includes/helper-functions.php';
|
67 |
+
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Begins execution of the plugin.
|
71 |
+
*
|
72 |
+
* Since everything within the plugin is registered via hooks,
|
73 |
+
* then kicking off the plugin from this point in the file does
|
74 |
+
* not affect the page life cycle.
|
75 |
+
*
|
76 |
+
* @since 1.0.0
|
77 |
+
*/
|
78 |
+
new GDPR();
|
includes/class-gdpr-activator.php
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Fired during plugin activation
|
5 |
+
*
|
6 |
+
* @link https://trewknowledge.com
|
7 |
+
* @since 1.0.0
|
8 |
+
*
|
9 |
+
* @package GDPR
|
10 |
+
* @subpackage includes
|
11 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
12 |
+
*/
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Fired during plugin activation.
|
16 |
+
*
|
17 |
+
* This class defines all code necessary to run during the plugin's activation.
|
18 |
+
*
|
19 |
+
* @since 1.0.0
|
20 |
+
* @package GDPR
|
21 |
+
* @subpackage includes
|
22 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
23 |
+
*/
|
24 |
+
class GDPR_Activator {
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Runs when the user first activates the plugin.
|
28 |
+
* Sets a CRON jo to clean up the telemetry post type every 12 hours.
|
29 |
+
*
|
30 |
+
* @since 1.0.0
|
31 |
+
* @static
|
32 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
33 |
+
*/
|
34 |
+
public static function activate() {
|
35 |
+
add_option( 'gdpr_disable_css', false );
|
36 |
+
add_option( 'gdpr_enable_telemetry_tracker', false );
|
37 |
+
add_option( 'gdpr_use_recaptcha', false );
|
38 |
+
add_option( 'gdpr_recaptcha_site_key', '' );
|
39 |
+
add_option( 'gdpr_recaptcha_secret_key', '' );
|
40 |
+
add_option( 'gdpr_add_consent_checkboxes_registration', true );
|
41 |
+
add_option( 'gdpr_add_consent_checkboxes_checkout', true );
|
42 |
+
}
|
43 |
+
|
44 |
+
}
|
includes/class-gdpr-audit-log.php
ADDED
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* The file that defines the Audit Log component
|
5 |
+
*
|
6 |
+
* A class definition that includes attributes and functions used across both the
|
7 |
+
* public-facing side of the site and the admin area.
|
8 |
+
*
|
9 |
+
* @link http://trewknowledge.com
|
10 |
+
* @since 1.0.0
|
11 |
+
*
|
12 |
+
* @package GDPR
|
13 |
+
* @subpackage includes
|
14 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
15 |
+
*/
|
16 |
+
|
17 |
+
/**
|
18 |
+
* The Audit Log plugin class.
|
19 |
+
*
|
20 |
+
* This is used to help us save all interactions from the user regarding consents.
|
21 |
+
*
|
22 |
+
* @since 1.0.0
|
23 |
+
* @package GDPR
|
24 |
+
* @subpackage includes
|
25 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
26 |
+
*/
|
27 |
+
class GDPR_Audit_Log {
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Encrypts a string.
|
31 |
+
*
|
32 |
+
* @since 1.0.0
|
33 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
34 |
+
* @access private
|
35 |
+
* @static
|
36 |
+
* @param string $key The encryption key.
|
37 |
+
* @param string $data The data to be encrypted.
|
38 |
+
* @return string The encrypted string.
|
39 |
+
*/
|
40 |
+
private static function crypt( $key, $data ) {
|
41 |
+
$iv = openssl_random_pseudo_bytes( openssl_cipher_iv_length( 'aes-256-cbc' ) );
|
42 |
+
$encrypted = openssl_encrypt( $data, 'aes-256-cbc', $key, 0, $iv );
|
43 |
+
return base64_encode( $encrypted . '::' . $iv );
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Decrypts a string.
|
48 |
+
* @since 1.0.0
|
49 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
50 |
+
* @access private
|
51 |
+
* @static
|
52 |
+
* @param string $key The encryption key.
|
53 |
+
* @param string $data The data to be decrypted.
|
54 |
+
* @return string The decrypted string.
|
55 |
+
*/
|
56 |
+
private static function decrypt( $key, $data ) {
|
57 |
+
list( $encrypted_data, $iv ) = explode( '::', base64_decode( $data ), 2 );
|
58 |
+
return openssl_decrypt( $encrypted_data, 'aes-256-cbc', $key, 0, $iv );
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Logs something to our audit log.
|
63 |
+
* @since 1.0.0
|
64 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
65 |
+
* @static
|
66 |
+
* @param int $user_id The user ID.
|
67 |
+
* @param string $input The string to be logged.
|
68 |
+
*/
|
69 |
+
public static function log( $user_id, $input ) {
|
70 |
+
$user = get_user_by( 'ID', $user_id );
|
71 |
+
$date = '[' . date('Y/m/d H:i:s') . '] ';
|
72 |
+
$encrypted = self::crypt( $user->user_email, $date . $input);
|
73 |
+
add_user_meta( $user_id, 'gdpr_audit_log', $encrypted );
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Returns the existing logs for an email.
|
78 |
+
* @since 1.0.0
|
79 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
80 |
+
* @static
|
81 |
+
* @param string $email The data subject email.
|
82 |
+
* @param string $token A 6 digit token that is provided on user deletion.
|
83 |
+
* @return string The decrypted log.
|
84 |
+
*/
|
85 |
+
public static function get_log( $email, $token = null ) {
|
86 |
+
// Try getting an existing user
|
87 |
+
$user = get_user_by( 'email', $email );
|
88 |
+
if ( $user instanceof WP_User ) {
|
89 |
+
$user_log = get_user_meta( $user->ID, 'gdpr_audit_log', false );
|
90 |
+
ob_start();
|
91 |
+
foreach ( $user_log as $log ) {
|
92 |
+
echo self::decrypt( $email, $log ) . "\n";
|
93 |
+
}
|
94 |
+
$log = ob_get_clean();
|
95 |
+
} else {
|
96 |
+
$uploads_dir = wp_upload_dir();
|
97 |
+
$basedir = $uploads_dir['basedir'];
|
98 |
+
$path = $basedir . '/gdpr_logs/';
|
99 |
+
$email_masked = self::email_mask( $email . $token );
|
100 |
+
$filename = base64_encode( $email_masked );
|
101 |
+
$file_found = file_exists( $path . $filename );
|
102 |
+
if ( ! $file_found ) {
|
103 |
+
return false;
|
104 |
+
} else {
|
105 |
+
$log = file_get_contents( $path . $filename );
|
106 |
+
return self::decrypt( $email, $log );
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
return $log;
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Mask the email so it's not identifiable.
|
115 |
+
* @since 1.0.0
|
116 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
117 |
+
* @access private
|
118 |
+
* @static
|
119 |
+
* @param string $email The email to mask.
|
120 |
+
* @param string $character The character that will replace letters.
|
121 |
+
* @return string The masked email.
|
122 |
+
*/
|
123 |
+
private static function email_mask( $email, $character = '-' ){
|
124 |
+
$email_arr = explode( '@', $email, 2 );
|
125 |
+
|
126 |
+
$length = strlen( $email_arr[0] );
|
127 |
+
$suplement = ( 0 !== $length % 2) ? 1 : 0;
|
128 |
+
$length = floor( $length / 2 );
|
129 |
+
$username = substr( $email_arr[0], 0, $length ) . str_repeat( $character, $length + $suplement );
|
130 |
+
|
131 |
+
$length = strlen( $email_arr[1] );
|
132 |
+
$suplement = ( 0 !== $length % 2) ? 1 : 0;
|
133 |
+
$length = floor( $length / 2 );
|
134 |
+
$domain = str_repeat( $character, $length + $suplement ) . substr( $email_arr[1], -$length, $length );
|
135 |
+
|
136 |
+
return $username . '@' . $domain;
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Exports the user audit log to a file.
|
141 |
+
* @since 1.0.0
|
142 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
143 |
+
* @static
|
144 |
+
* @param int $user_id The user ID
|
145 |
+
* @param string $token The 6 digit token the user gets on deletion.
|
146 |
+
*/
|
147 |
+
public static function export_log( $user_id, $token ) {
|
148 |
+
$user = get_user_by( 'ID', $user_id );
|
149 |
+
if ( ! $user instanceof WP_User ) {
|
150 |
+
return;
|
151 |
+
}
|
152 |
+
|
153 |
+
$uploads_dir = wp_upload_dir();
|
154 |
+
$basedir = $uploads_dir['basedir'];
|
155 |
+
$path = $basedir . '/gdpr_logs/';
|
156 |
+
|
157 |
+
if ( wp_mkdir_p( $path ) ) {
|
158 |
+
if ( ! file_exists( $path . 'index.php' ) ) {
|
159 |
+
file_put_contents( $path . 'index.php', '' );
|
160 |
+
}
|
161 |
+
$log = self::get_log( $user->user_email );
|
162 |
+
$filename = self::email_mask( $user->user_email . $token );
|
163 |
+
$filename = base64_encode( $filename );
|
164 |
+
|
165 |
+
file_put_contents( $path . $filename, self::crypt( $user->user_email, $log ) );
|
166 |
+
}
|
167 |
+
|
168 |
+
}
|
169 |
+
|
170 |
+
}
|
includes/class-gdpr-deactivator.php
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Fired during plugin deactivation
|
5 |
+
*
|
6 |
+
* @link https://trewknowledge.com
|
7 |
+
* @since 1.0.0
|
8 |
+
*
|
9 |
+
* @package GDPR
|
10 |
+
* @subpackage includes
|
11 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
12 |
+
*/
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Fired during plugin deactivation.
|
16 |
+
*
|
17 |
+
* This class defines all code necessary to run during the plugin's deactivation.
|
18 |
+
*
|
19 |
+
* @since 1.0.0
|
20 |
+
* @package GDPR
|
21 |
+
* @subpackage includes
|
22 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
23 |
+
*/
|
24 |
+
class GDPR_Deactivator {
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Runs when the user deactivates the plugin.
|
28 |
+
* Clears the CRON job that deletes telemetry posts every 12 hours.
|
29 |
+
*
|
30 |
+
* @since 1.0.0
|
31 |
+
* @static
|
32 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
33 |
+
*/
|
34 |
+
public static function deactivate() {
|
35 |
+
wp_clear_scheduled_hook('telemetry_cleanup');
|
36 |
+
}
|
37 |
+
|
38 |
+
}
|
includes/class-gdpr-email.php
ADDED
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file handle emailing users.
|
4 |
+
*
|
5 |
+
* @link http://trewknowledge.com
|
6 |
+
* @since 1.0.0
|
7 |
+
*
|
8 |
+
* @package GDPR
|
9 |
+
* @subpackage includes
|
10 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Handles emailing users.
|
15 |
+
*
|
16 |
+
* @since 1.0.0
|
17 |
+
* @package GDPR
|
18 |
+
* @subpackage includes
|
19 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
20 |
+
*/
|
21 |
+
class GDPR_Email {
|
22 |
+
/**
|
23 |
+
* Locate template.
|
24 |
+
*
|
25 |
+
* Locate the called template.
|
26 |
+
* Search Order:
|
27 |
+
* 1. /themes/theme/gdpr/templates/email/$template_name
|
28 |
+
* 2. /plugins/gdpr/templates/$template_name.
|
29 |
+
*
|
30 |
+
* @since 1.0.0
|
31 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
32 |
+
* @access private
|
33 |
+
* @static
|
34 |
+
* @param string $template_name Template to load.
|
35 |
+
* @return string Path to the template file.
|
36 |
+
*/
|
37 |
+
private static function locate_template( $template_name ) {
|
38 |
+
// Set variable to search in gdpr folder of theme.
|
39 |
+
$theme_path = 'gdpr/email/';
|
40 |
+
|
41 |
+
// Set default plugin templates path.
|
42 |
+
$plugin_path = plugin_dir_path( dirname( __FILE__ ) ) . 'templates/email/'; // Path to the template folder
|
43 |
+
|
44 |
+
// Search template file in theme folder.
|
45 |
+
$template = locate_template( array(
|
46 |
+
$theme_path . $template_name
|
47 |
+
) );
|
48 |
+
|
49 |
+
// Get plugins template file.
|
50 |
+
if ( ! $template ) {
|
51 |
+
$template = $plugin_path . $template_name;
|
52 |
+
}
|
53 |
+
return $template;
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Get template.
|
58 |
+
*
|
59 |
+
* Search for the template and include the file.
|
60 |
+
*
|
61 |
+
* @since 1.0.0
|
62 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
63 |
+
* @access private
|
64 |
+
* @static
|
65 |
+
* @param string $template_name Template to load.
|
66 |
+
* @param array $args Arguments passed to the template file.
|
67 |
+
*/
|
68 |
+
private static function get_template( $template_name, $args = array() ) {
|
69 |
+
$template_file = self::locate_template( $template_name );
|
70 |
+
|
71 |
+
if ( ! file_exists( $template_file ) ) {
|
72 |
+
return;
|
73 |
+
}
|
74 |
+
include $template_file;
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Get the email content from the correct file.
|
79 |
+
* @since 1.0.0
|
80 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
81 |
+
* @static
|
82 |
+
* @param string $template_name Template to load.
|
83 |
+
* @param array $args Arguments passed to the template file.
|
84 |
+
* @return string Email contents.
|
85 |
+
*/
|
86 |
+
public static function get_email_content( $template_name, $args = array() ) {
|
87 |
+
ob_start();
|
88 |
+
self::get_template( $template_name, $args );
|
89 |
+
return ob_get_clean();
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Get a noreply email address.
|
94 |
+
* @since 1.0.0
|
95 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
96 |
+
* @access private
|
97 |
+
* @static
|
98 |
+
* @return string The noreply email address
|
99 |
+
*/
|
100 |
+
private static function get_do_not_reply_address() {
|
101 |
+
$sitename = strtolower( $_SERVER['SERVER_NAME'] );
|
102 |
+
if ( substr( $sitename, 0, 4 ) === 'www.' ) {
|
103 |
+
$sitename = substr( $sitename, 4 );
|
104 |
+
}
|
105 |
+
|
106 |
+
return apply_filters( 'gdpr_do_not_reply_address', 'noreply@' . $sitename );
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Create batches of users so we can throtle emails.
|
111 |
+
* Schedule CRON jobs every hour that sends the current batch of emails.
|
112 |
+
* @since 1.0.0
|
113 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
114 |
+
* @static
|
115 |
+
* @param string $key The confirmation key.
|
116 |
+
*/
|
117 |
+
public static function prepare_data_breach_emails( $key ) {
|
118 |
+
$data_breach = get_option( 'gdpr_data_breach_initiated', array( 'key' => '' ) );
|
119 |
+
if ( $key !== $data_breach['key'] ) {
|
120 |
+
return;
|
121 |
+
}
|
122 |
+
|
123 |
+
$limit = get_option( 'gdpr_email_limit', 100 );
|
124 |
+
|
125 |
+
$users = get_users( array(
|
126 |
+
'fields' => 'all_with_meta'
|
127 |
+
) );
|
128 |
+
|
129 |
+
$steps = ceil( count( $users ) / $limit );
|
130 |
+
|
131 |
+
foreach ( range( 0, $steps - 1 ) as $loop ) {
|
132 |
+
$offset = $limit * $loop;
|
133 |
+
$loop_emails = wp_list_pluck( $users, 'user_email' );
|
134 |
+
$loop_emails = array_slice( $loop_emails, $offset, $limit );
|
135 |
+
wp_schedule_single_event( time() + $loop * HOUR_IN_SECONDS, 'send_data_breach_emails', array( $loop_emails, $data_breach ) );
|
136 |
+
}
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* The CRON job set by the prepare_data_breach_emails calls this function.
|
141 |
+
* This sends one of the data breach batch emails.
|
142 |
+
* @since 1.0.0
|
143 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
144 |
+
* @param array $emails The batch recipients.
|
145 |
+
* @param string $data The contents of the email.
|
146 |
+
*/
|
147 |
+
public function send_data_breach_emails( $emails, $data ) {
|
148 |
+
$content = isset( $data['content'] ) ? sanitize_textarea_field( $data['content'] ) : '';
|
149 |
+
|
150 |
+
$nature = sanitize_textarea_field( wp_unslash( $data['nature'] ) );
|
151 |
+
$office_contact = sanitize_textarea_field( wp_unslash( $data['office_contact'] ) );
|
152 |
+
$consequences = sanitize_textarea_field( wp_unslash( $data['consequences'] ) );
|
153 |
+
$measures = sanitize_textarea_field( wp_unslash( $data['measures'] ) );
|
154 |
+
|
155 |
+
foreach ( (array) $emails as $email ) {
|
156 |
+
$user = get_user_by( 'email', $email );
|
157 |
+
if ( $user instanceof WP_User ) {
|
158 |
+
GDPR_Audit_Log::log( $user->ID, esc_html__( 'Data breach notification sent to user.', 'gdpr' ) );
|
159 |
+
/* translators: email content */
|
160 |
+
GDPR_Audit_Log::log( $user->ID, sprintf( esc_html__( 'Email content: %s', 'gdpr'), $content ) );
|
161 |
+
/* translators: nature of the data breach */
|
162 |
+
GDPR_Audit_Log::log( $user->ID, sprintf( esc_html__( 'Nature of data breach: %s', 'gdpr'), $nature ) );
|
163 |
+
/* translators: data protection officer contact information */
|
164 |
+
GDPR_Audit_Log::log( $user->ID, sprintf( esc_html__( 'Data protection officer contact: %s', 'gdpr'), $office_contact ) );
|
165 |
+
/* translators: likely consequences */
|
166 |
+
GDPR_Audit_Log::log( $user->ID, sprintf( esc_html__( 'Likely consequences of breach: %s', 'gdpr'), $consequences ) );
|
167 |
+
/* translators: measures taken */
|
168 |
+
GDPR_Audit_Log::log( $user->ID, sprintf( esc_html__( 'Measures taken or proposed to be taken: %s', 'gdpr'), $measures ) );
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
|
173 |
+
self::send( $emails, 'data-breach-notification', array(
|
174 |
+
'content' => $content,
|
175 |
+
'nature' => $nature,
|
176 |
+
'office_contact' => $office_contact,
|
177 |
+
'consequences' => $consequences,
|
178 |
+
'measures' => $measures,
|
179 |
+
) );
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Actually send an email.
|
184 |
+
* This check if the type is one of the possible types of email.
|
185 |
+
* Set the headers. Get the email content from the correct file.
|
186 |
+
* @since 1.0.0
|
187 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
188 |
+
* @static
|
189 |
+
* @param array $emails The recipient email addresses.
|
190 |
+
* @param string $type The email type.
|
191 |
+
* @param array $args The arguments to be used by the email template.
|
192 |
+
* @param array $attachments Attachments
|
193 |
+
* @return bool Whether the email contents were sent successfully.
|
194 |
+
*/
|
195 |
+
public static function send( $emails, $type, $args = array(), $attachments = array() ) {
|
196 |
+
$possible_types = apply_filters( 'gdpr_email_types', array(
|
197 |
+
'new-request' => apply_filters( 'gdpr_new_request_email_subject', esc_html__( 'GDPR Notification: There is a new request waiting to be reviewed.', 'gdpr' ) ),
|
198 |
+
'delete-request' => apply_filters( 'gdpr_delete_request_email_subject', esc_html__( 'Someone requested to close your account.', 'gdpr' ) ),
|
199 |
+
'delete-resolved' => apply_filters( 'gdpr_delete_resolved_email_subject', esc_html__( 'Your account has been closed.', 'gdpr' ) ),
|
200 |
+
'rectify-request' => apply_filters( 'gdpr_rectify_request_email_subject', esc_html__( 'Someone requested that we rectify data of your account.', 'gdpr' ) ),
|
201 |
+
'rectify-resolved' => apply_filters( 'gdpr_rectify_resolved_email_subject', esc_html__( 'Your request has been completed.', 'gdpr' ) ),
|
202 |
+
'complaint-request' => apply_filters( 'gdpr_complaint_request_email_subject', esc_html__( 'Someone made complaint on behalf of your account.', 'gdpr' ) ),
|
203 |
+
'complaint-resolved' => apply_filters( 'gdpr_complaint_resolved_email_subject', esc_html__( 'Your request has been completed.', 'gdpr' ) ),
|
204 |
+
'export-data-request' => apply_filters( 'gdpr_export_data_request_email_subject', esc_html__( 'Someone requested to download your data.', 'gdpr' ) ),
|
205 |
+
'export-data-resolved' => apply_filters( 'gdpr_export_data_resolved_email_subject', esc_html__( 'Your request has been completed.', 'gdpr' ) ),
|
206 |
+
'data-breach-request' => apply_filters( 'gdpr_data_breach_request_email_subject', esc_html__( 'Someone requested to send a data breach notification.', 'gdpr' ) ),
|
207 |
+
'data-breach-notification' => apply_filters( 'gdpr_data_breach_resolved_email_subject', esc_html__( 'Data Breach Notification.', 'gdpr' ) ),
|
208 |
+
) );
|
209 |
+
|
210 |
+
if ( ! in_array( $type, array_keys( $possible_types ), true ) ) {
|
211 |
+
return;
|
212 |
+
}
|
213 |
+
|
214 |
+
$no_reply = self::get_do_not_reply_address();
|
215 |
+
$headers = array( 'From: ' . get_bloginfo( 'name' ) . ' <' . $no_reply . '>' );
|
216 |
+
foreach ( (array) $emails as $email ) {
|
217 |
+
$headers[] = 'Bcc: ' . sanitize_email( $email );
|
218 |
+
}
|
219 |
+
|
220 |
+
$content = self::get_email_content( $type . '.php', $args );
|
221 |
+
|
222 |
+
return wp_mail( $no_reply,
|
223 |
+
$possible_types[ $type ],
|
224 |
+
html_entity_decode( $content, ENT_QUOTES, 'UTF-8' ),
|
225 |
+
$headers,
|
226 |
+
( ! empty( $attachments ) ) ? $attachments : array()
|
227 |
+
);
|
228 |
+
}
|
229 |
+
}
|
includes/class-gdpr-help.php
ADDED
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file is responsible for adding help sections to the plugin pages.
|
4 |
+
*
|
5 |
+
* @link http://trewknowledge.com
|
6 |
+
* @since 0.1.0
|
7 |
+
*
|
8 |
+
* @package GDPR
|
9 |
+
* @subpackage includes
|
10 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* A class that adds help tabs to the plugin pages.
|
15 |
+
*
|
16 |
+
* @since 1.0.0
|
17 |
+
* @package GDPR
|
18 |
+
* @subpackage includes
|
19 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
20 |
+
*/
|
21 |
+
class GDPR_Help {
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Add the requests page help tabs.
|
25 |
+
* @since 1.0.0
|
26 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
27 |
+
* @static
|
28 |
+
*/
|
29 |
+
public static function add_requests_help() {
|
30 |
+
$overview = '<h2>' . esc_html__( 'Overview', 'gdpr' ) . '</h2>' .
|
31 |
+
'<p>' . esc_html__( 'This page has multiple request tables. Users can request multiple things like getting deleted from the site or having their data rectified. All requests will come to these tables.', 'gdpr' ) . '</p>';
|
32 |
+
get_current_screen()->add_help_tab( array(
|
33 |
+
'id' => 'overview',
|
34 |
+
'title' => esc_html__( 'Overview', 'gdpr' ),
|
35 |
+
'content' => $overview,
|
36 |
+
) );
|
37 |
+
|
38 |
+
$rectify_help = '<h2>' . esc_html__( 'Rectify Data', 'gdpr' ) . '</h2>' .
|
39 |
+
'<p>' . esc_html__( 'Users may request to have their data rectified. They can place a request somewhere on your site and those requests will show up here.', 'gdpr' ) . '</p>' .
|
40 |
+
'<p>' . esc_html__( 'When you complete the request, mark it as resolved and the requester will get a notification email confirming that their request was resolved.', 'gdpr' ) . '</p>';
|
41 |
+
get_current_screen()->add_help_tab( array(
|
42 |
+
'id' => 'rectify-data',
|
43 |
+
'title' => esc_html__( 'Rectify Data', 'gdpr' ),
|
44 |
+
'content' => $rectify_help,
|
45 |
+
) );
|
46 |
+
|
47 |
+
$complaint_help = '<h2>' . esc_html__( 'Complaints', 'gdpr' ) . '</h2>' .
|
48 |
+
'<p>' . esc_html__( 'Users may complain about something that happened. They can place a complaint somewhere on your site and those complaints will show up here.', 'gdpr' ) . '</p>' .
|
49 |
+
'<p>' . esc_html__( 'When you resolve the problem, mark it as resolved and the requester will get a notification email confirming that his complaint was resolved.', 'gdpr' ) . '</p>';
|
50 |
+
get_current_screen()->add_help_tab( array(
|
51 |
+
'id' => 'complaint',
|
52 |
+
'title' => esc_html__( 'Complaints', 'gdpr' ),
|
53 |
+
'content' => $complaint_help,
|
54 |
+
) );
|
55 |
+
|
56 |
+
$erasure_help = '<h2>' . esc_html__( 'Erasure', 'gdpr' ) . '</h2>' .
|
57 |
+
'<p>' . esc_html__( 'Users may request to be deleted from the site. If they don\'t have any content published on the site (including comments) they will be removed from the site automatically. Otherwise, they will show up at this review table where you can reassign or delete their published content and anonymize his comments.', 'gdpr' ) . '</p>' .
|
58 |
+
'<p>' . esc_html__( 'When you are ready to delete the user, they will get a notification that their account has been closed. According to GDPR, you have 30 days to fulfill this request. On some occasions, you can ask to extend this time.', 'gdpr' ) . '</p>';
|
59 |
+
get_current_screen()->add_help_tab( array(
|
60 |
+
'id' => 'erasure',
|
61 |
+
'title' => esc_html__( 'Erasures', 'gdpr' ),
|
62 |
+
'content' => $erasure_help,
|
63 |
+
) );
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Add the tools page help tabs.
|
68 |
+
* @since 1.0.0
|
69 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
70 |
+
* @static
|
71 |
+
*/
|
72 |
+
public static function add_tools_help() {
|
73 |
+
$overview = '<h2>' . esc_html__( 'Overview', 'gdpr' ) . '</h2>' .
|
74 |
+
'<p>' . esc_html__( 'We added tools to make your life easier when you need to perform administrative tasks like notify all your users of a possible data breach.', 'gdpr' ) . '</p>';
|
75 |
+
get_current_screen()->add_help_tab( array(
|
76 |
+
'id' => 'overview',
|
77 |
+
'title' => esc_html__( 'Overview', 'gdpr' ),
|
78 |
+
'content' => $overview,
|
79 |
+
) );
|
80 |
+
|
81 |
+
$access_data_help = '<h2>' . esc_html__( 'Access Data', 'gdpr' ) . '</h2>' .
|
82 |
+
'<p>' . esc_html__( 'Use this page to look for all known data about a user. You can look it up using the user\'s email address and are able to download it in XML and JSON formats.', 'gdpr' ) . '</p>';
|
83 |
+
get_current_screen()->add_help_tab( array(
|
84 |
+
'id' => 'access-data',
|
85 |
+
'title' => esc_html__( 'Access Data', 'gdpr' ),
|
86 |
+
'content' => $access_data_help,
|
87 |
+
) );
|
88 |
+
|
89 |
+
$data_breach_help = '<h2>' . esc_html__( 'Data Breach Notification', 'gdpr' ) . '</h2>' .
|
90 |
+
'<p><strong>' . esc_html__( 'Use this carefully.', 'gdpr' ) . '</strong></p>' .
|
91 |
+
'<p>' . esc_html__( 'This will send a mass email to all your users with the information provided on these fields. This email is throttled based on the hourly limit set on the plugin settings page. ', 'gdpr' ) . '</p>' .
|
92 |
+
'<p><strong>' . esc_html__( 'Only use this tool if you believe your site has been compromised and that your user\'s personal data might have been leaked.', 'gdpr' ) . '</strong></p>';
|
93 |
+
get_current_screen()->add_help_tab( array(
|
94 |
+
'id' => 'data-breach',
|
95 |
+
'title' => esc_html__( 'Data Breach', 'gdpr' ),
|
96 |
+
'content' => $data_breach_help,
|
97 |
+
) );
|
98 |
+
|
99 |
+
$audit_log_help = '<h2>' . esc_html__( 'Audit Log', 'gdpr' ) . '</h2>' .
|
100 |
+
'<p><strong>' . esc_html__( 'We do not log any of the user\'s personal data.', 'gdpr' ) . '</strong></p>' .
|
101 |
+
'<p>' . esc_html__( 'All logs are encrypted before saving to the database. An encrypted log file is created whenever a user gets removed from the site.', 'gdpr' ) . '</p>' .
|
102 |
+
'<p>' . esc_html__( 'This tool will keep a record of some actions such as changing consent preferences, placing a request, data breach notifications received, etc…', 'gdpr' ) . '<br />' .
|
103 |
+
esc_html__( 'The only way to read the logs is to search for the user email. If the data subject is not a registered site user anymore, you need to ask for the 6 digit token that was provided during deletion. That will allow this tool to look for a log file with his information.', 'gdpr' ) . '</p>';
|
104 |
+
get_current_screen()->add_help_tab( array(
|
105 |
+
'id' => 'audit-log',
|
106 |
+
'title' => esc_html__( 'Audit Log', 'gdpr' ),
|
107 |
+
'content' => $audit_log_help,
|
108 |
+
) );
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Add the settings page help tabs.
|
113 |
+
* @since 1.0.0
|
114 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
115 |
+
* @static
|
116 |
+
*/
|
117 |
+
public static function add_settings_help() {
|
118 |
+
$general_settings_help = '<h2>' . esc_html__( 'General Settings', 'gdpr' ) . '</h2>' .
|
119 |
+
'<p>' . esc_html__( 'This plugin needs to know your privacy policy page to track updates to it and ask users to re-consent to your new terms.', 'gdpr' ) . '</p>' .
|
120 |
+
'<p>' . esc_html__( 'When sending a data breach notification to your users, we need to throttle the emails because of server limitations. This is an hourly limit. Check with your hosting provider before changing this value.', 'gdpr' ) . '</p>';
|
121 |
+
get_current_screen()->add_help_tab( array(
|
122 |
+
'id' => 'general',
|
123 |
+
'title' => esc_html__( 'General Settings', 'gdpr' ),
|
124 |
+
'content' => $general_settings_help,
|
125 |
+
) );
|
126 |
+
|
127 |
+
$cookies_settings_help = sprintf( '<h2>' . esc_html__( 'Cookie Management', 'gdpr' ) . '</h2>' .
|
128 |
+
'<p>' . esc_html__( 'Fill out every information you can about the cookies your site uses. Set the cookies that you set under Cookies Used and cookies used and set by third parties under the hosts section.', 'gdpr' ) . '</p>' .
|
129 |
+
/* translators: the function */
|
130 |
+
'<p>' . esc_html__( 'You must ask your developer to wrap the code that sets the cookies with our helper function %s.', 'gdpr' ) . '</p>' .
|
131 |
+
'<p>' . esc_html__( 'Some services like Google Analytics provide a way to opt out from their code with an extra parameter to their snippet.', 'gdpr' ) . '</p>' .
|
132 |
+
'<h3>' . esc_html__( 'External Links', 'gdpr' ) . '</h3>' .
|
133 |
+
'<ul>' .
|
134 |
+
'<li><a href="https://codex.wordpress.org/WordPress_Cookies" title="' . esc_attr__( 'WordPress cookies', 'gdpr' ) . '" target="_blank">'. esc_html__( 'WordPress cookies', 'gdpr' ) .'</a></li>' .
|
135 |
+
'</ul>',
|
136 |
+
'<code>is_allowed_cookie( $cookie_name )</code>'
|
137 |
+
);
|
138 |
+
get_current_screen()->add_help_tab( array(
|
139 |
+
'id' => 'cookies',
|
140 |
+
'title' => esc_html__( 'Cookie Management', 'gdpr' ),
|
141 |
+
'content' => $cookies_settings_help,
|
142 |
+
) );
|
143 |
+
|
144 |
+
$consent_settings_help = sprintf( '<h2>' . esc_html__( 'Consent Management ( Coming Soon )', 'gdpr' ) . '</h2>' .
|
145 |
+
'<p>' . esc_html__( 'All consents are disabled by default. On first registration, your users will need to consent to your privacy policy. Depending on your privacy policy you should register multiple types of consent on this page and allow them to be toggled on/off.', 'gdpr' ) . '</p>' .
|
146 |
+
/* translators: the function */
|
147 |
+
'<p>' . esc_html__( 'If you have an optional consent type, you must have a developer wrap the functionality in our helper function %s.', 'gdpr' ) . '</p>' .
|
148 |
+
'<p><strong>' . esc_html__( 'i.e.', 'gdpr' ) . '</strong><br />' . esc_html__( 'You registered email marketing as an optional consent but the user did not actively opt into it on their profile page. You should have your email capture form wrapped in our helper function to block registration or better yet, not even display the email capture form. Same goes for blocking adding the user to your mailing system on registration if consent is not given.', 'gdpr' ) . '</p>' .
|
149 |
+
'<h3>' . esc_html__( 'External Links', 'gdpr' ) . '</h3>' .
|
150 |
+
'<ul>' .
|
151 |
+
'<li><a href="https://gdpr-info.eu/art-7-gdpr/" title="' . esc_attr__( 'Article 7 - Conditions for consent', 'gdpr' ) . '" target="_blank">'. esc_html__( 'Article 7 - Conditions for consent', 'gdpr' ) .'</a></li>' .
|
152 |
+
'<li><a href="https://gdpr-info.eu/art-8-gdpr/" title="' . esc_attr__( "Article 8 - conditions applicable to child's consent in relation to information society services", 'gdpr' ) . '" target="_blank">'. esc_html__( "Article 8 - conditions applicable to child's consent in relation to information society services", 'gdpr' ) .'</a></li>' .
|
153 |
+
'<li><a href="https://gdpr-info.eu/recitals/no-42/" title="' . esc_attr__( 'Recital 42 - Burden of proof and requirements for consent', 'gdpr' ) . '" target="_blank">'. esc_html__( 'Recital 42 - Burden of proof and requirements for consent', 'gdpr' ) .'</a></li>' .
|
154 |
+
'<li><a href="https://gdpr-info.eu/recitals/no-43/" title="' . esc_attr__( 'Recital 43 - Freely Given consent', 'gdpr' ) . '" target="_blank">'. esc_html__( 'Recital 43 - Freely Given consent', 'gdpr' ) .'</a></li>' .
|
155 |
+
'</ul>',
|
156 |
+
'<code>have_consent( $consent_id )</code>'
|
157 |
+
);
|
158 |
+
|
159 |
+
get_current_screen()->add_help_tab( array(
|
160 |
+
'id' => 'consents',
|
161 |
+
'title' => esc_html__( 'Consent Management', 'gdpr' ),
|
162 |
+
'content' => $consent_settings_help,
|
163 |
+
) );
|
164 |
+
}
|
165 |
+
|
166 |
+
/**
|
167 |
+
* Add the telemetry page help tabs.
|
168 |
+
* @since 1.0.0
|
169 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
170 |
+
* @static
|
171 |
+
*/
|
172 |
+
public static function add_telemetry_help() {
|
173 |
+
if ( 'edit-telemetry' !== get_current_screen()->id ) {
|
174 |
+
return;
|
175 |
+
}
|
176 |
+
|
177 |
+
$telemetry_help = '<h2>' . esc_html__( 'Overview', 'gdpr' ) . '</h2>' .
|
178 |
+
'<p>' . esc_html__( 'This is all data that are being sent outside of your site. WordPress send some data to it\'s servers to be able to do automatic updates. You can reduce the amount of data being sent using filters.', 'gdpr' ) . '</p>' .
|
179 |
+
'<p>' . esc_html__( 'Some plugins also capture data and send it to their servers. Such practice is not allowed for plugins hosted on wordpress.org plugin repository. In case this is a Premium plugin, you should have been given the option to choose which type of data you want to send.', 'gdpr' ) . '</p>' .
|
180 |
+
'<p>' . esc_html__( 'Use this tool to identify plugins or themes sending potential personal data outside of your server and take action if necessary.', 'gdpr' ) . '</p>' .
|
181 |
+
'<p>' . esc_html__( 'All information on this page is automatically deleted every 12 hours so this doesn\'t grow too large and slow your site.' ) . '</p>';
|
182 |
+
get_current_screen()->add_help_tab( array(
|
183 |
+
'id' => 'overview',
|
184 |
+
'title' => esc_html__( 'Overview', 'gdpr' ),
|
185 |
+
'content' => $telemetry_help,
|
186 |
+
) );
|
187 |
+
}
|
188 |
+
}
|
includes/class-gdpr-requests.php
ADDED
@@ -0,0 +1,265 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* The requests functionality of the plugin.
|
5 |
+
*
|
6 |
+
* @link https://trewknowledge.com
|
7 |
+
* @since 1.0.0
|
8 |
+
*
|
9 |
+
* @package GDPR
|
10 |
+
* @subpackage includes
|
11 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
12 |
+
*/
|
13 |
+
|
14 |
+
/**
|
15 |
+
* The requests functionality of the plugin.
|
16 |
+
*
|
17 |
+
* @package GDPR
|
18 |
+
* @subpackage includes
|
19 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
20 |
+
*/
|
21 |
+
class GDPR_Requests {
|
22 |
+
|
23 |
+
/**
|
24 |
+
* The ID of this plugin.
|
25 |
+
*
|
26 |
+
* @since 1.0.0
|
27 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
28 |
+
* @access protected
|
29 |
+
* @static
|
30 |
+
* @var string $plugin_name The ID of this plugin.
|
31 |
+
*/
|
32 |
+
protected static $plugin_name;
|
33 |
+
|
34 |
+
/**
|
35 |
+
* The version of this plugin.
|
36 |
+
*
|
37 |
+
* @since 1.0.0
|
38 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
39 |
+
* @access protected
|
40 |
+
* @static
|
41 |
+
* @var string $version The current version of this plugin.
|
42 |
+
*/
|
43 |
+
protected static $version;
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Allowed types of requests.
|
47 |
+
*
|
48 |
+
* @since 1.0.0
|
49 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
50 |
+
* @access protected
|
51 |
+
* @static
|
52 |
+
* @var array
|
53 |
+
*/
|
54 |
+
protected static $allowed_types = array( 'export-data', 'rectify', 'complaint', 'delete' );
|
55 |
+
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Initialize the class and set its properties.
|
59 |
+
*
|
60 |
+
* @since 1.0.0
|
61 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
62 |
+
* @param string $plugin_name The name of this plugin.
|
63 |
+
* @param string $version The version of this plugin.
|
64 |
+
*/
|
65 |
+
public function __construct( $plugin_name, $version ) {
|
66 |
+
self::$plugin_name = $plugin_name;
|
67 |
+
self::$version = $version;
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Allowed types getter.
|
72 |
+
* @since 1.0.0
|
73 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
74 |
+
* @access protected
|
75 |
+
* @return array The allowed request types.
|
76 |
+
*/
|
77 |
+
protected function get_allowed_types() {
|
78 |
+
return self::$allowed_types;
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Checks if the user has any content published on the site. Including comments.
|
83 |
+
* @since 1.0.0
|
84 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
85 |
+
* @static
|
86 |
+
* @param WP_User/int $user The user object or the user ID.
|
87 |
+
* @return bool Whether the user has content or not.
|
88 |
+
*/
|
89 |
+
static function user_has_content( $user ) {
|
90 |
+
if ( ! $user instanceof WP_User ) {
|
91 |
+
if ( ! is_int( $user ) ) {
|
92 |
+
return;
|
93 |
+
}
|
94 |
+
$user = get_user_by( 'ID', $user );
|
95 |
+
}
|
96 |
+
|
97 |
+
$post_types = get_post_types( array( 'public' => true ) );
|
98 |
+
foreach ( $post_types as $pt ) {
|
99 |
+
$post_count = count_user_posts( $user->ID, $pt);
|
100 |
+
if ( $post_count > 0 ) {
|
101 |
+
return true;
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
$comments = get_comments( array(
|
106 |
+
'author_email' => $user->user_email,
|
107 |
+
'include_unapproved' => true,
|
108 |
+
'number' => 1,
|
109 |
+
'count' => true,
|
110 |
+
) );
|
111 |
+
|
112 |
+
if ( $comments ) {
|
113 |
+
return true;
|
114 |
+
}
|
115 |
+
|
116 |
+
$extra_checks = apply_filters( 'gdpr_user_has_content', false );
|
117 |
+
|
118 |
+
return $extra_checks;
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Removes the user from the requests list.
|
123 |
+
* @since 1.0.0
|
124 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
125 |
+
* @access protected
|
126 |
+
* @param string $index The request key.
|
127 |
+
* @return bool Whether the user was removed from the requests list.
|
128 |
+
*/
|
129 |
+
protected function remove_from_requests( $index ) {
|
130 |
+
$requests = ( array ) get_option( 'gdpr_requests', array() );
|
131 |
+
$index = sanitize_text_field( wp_unslash( $index ) );
|
132 |
+
|
133 |
+
if ( array_key_exists( $index, $requests ) ) {
|
134 |
+
unset( $requests[ $index ] );
|
135 |
+
update_option( 'gdpr_requests', $requests );
|
136 |
+
return true;
|
137 |
+
}
|
138 |
+
|
139 |
+
return false;
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Set the user request as confirmed.
|
144 |
+
* Unschedules the cron jobs that clean up the requests that haven't been confirmed.
|
145 |
+
* @since 1.0.0
|
146 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
147 |
+
* @access protected
|
148 |
+
* @param string $key The request key.
|
149 |
+
* @return bool Whether the request was confirmed or not.
|
150 |
+
*/
|
151 |
+
protected function confirm_request( $key ) {
|
152 |
+
$key = sanitize_text_field( wp_unslash( $key ) );
|
153 |
+
$requests = ( array ) get_option( 'gdpr_requests', array() );
|
154 |
+
|
155 |
+
if ( empty( $requests ) || ! isset( $requests[ $key ] ) ) {
|
156 |
+
return false;
|
157 |
+
}
|
158 |
+
|
159 |
+
$requests[ $key ]['confirmed'] = true;
|
160 |
+
$type = $requests[ $key ]['type'];
|
161 |
+
$email = $requests[ $key ]['email'];
|
162 |
+
|
163 |
+
$user = get_user_by( 'email', $email );
|
164 |
+
|
165 |
+
if ( $user instanceof WP_User ) {
|
166 |
+
$meta_key = self::$plugin_name . "_{$type}_key";
|
167 |
+
update_option( 'gdpr_requests', $requests );
|
168 |
+
delete_user_meta( $user->ID, $meta_key );
|
169 |
+
if ( $time = wp_next_scheduled( 'clean_gdpr_user_request_key', array( 'user_id' => $user->ID, 'meta_key' => $meta_key ) ) ) {
|
170 |
+
wp_unschedule_event( $time, 'clean_gdpr_user_request_key', array( 'user_id' => $user->ID, 'meta_key' => $meta_key ) );
|
171 |
+
}
|
172 |
+
}
|
173 |
+
|
174 |
+
return true;
|
175 |
+
}
|
176 |
+
|
177 |
+
/**
|
178 |
+
* The function the CRON job calls. It checks after a couple days if a request was confirmed or not.
|
179 |
+
* If it wasn't, the request gets removed.
|
180 |
+
* @since 1.0.0
|
181 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
182 |
+
* @param string $key The request key.
|
183 |
+
*/
|
184 |
+
function clean_requests( $key ) {
|
185 |
+
$key = sanitize_text_field( $key );
|
186 |
+
$requests = ( array ) get_option( 'gdpr_requests', array() );
|
187 |
+
|
188 |
+
if ( array_key_exists( $key, $requests ) ) {
|
189 |
+
if ( ! $requests[ $key ]['confirmed'] ) {
|
190 |
+
unset( $requests[ $key ] );
|
191 |
+
update_option( 'gdpr_requests', $requests );
|
192 |
+
}
|
193 |
+
}
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* Whenever a user places a request, the request key is saved as a user meta for comparison.
|
198 |
+
* @since 1.0.0
|
199 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
200 |
+
* @param int $user_id The user ID.
|
201 |
+
* @param string $meta_key The user meta key.
|
202 |
+
*/
|
203 |
+
function clean_user_request_key( $user_id, $meta_key ) {
|
204 |
+
$user_id = ( int ) $user_id;
|
205 |
+
$meta_key = sanitize_text_field( $meta_key );
|
206 |
+
|
207 |
+
$meta = get_user_meta( $user_id, $meta_key, true );
|
208 |
+
|
209 |
+
if ( $meta ) {
|
210 |
+
delete_user_meta( $user_id, $meta_key );
|
211 |
+
}
|
212 |
+
|
213 |
+
/* translators: Name of the usermeta */
|
214 |
+
GDPR_Audit_Log::log( $user_id, sprintf( esc_html__( 'User request expired. Removing %s user_meta.', 'gdpr' ), $meta_key ) );
|
215 |
+
}
|
216 |
+
|
217 |
+
/**
|
218 |
+
* Add a user to the request list. Set up the cleanup CRON job.
|
219 |
+
* @since 1.0.0
|
220 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
221 |
+
* @access protected
|
222 |
+
* @param string $email The requestant email.
|
223 |
+
* @param string $type The type of request.
|
224 |
+
* @param string $data Some types of request have an extra field. E.g. Complaint and Rectify data.
|
225 |
+
* @param string $confirmed If the request is confirmed or not.
|
226 |
+
*/
|
227 |
+
protected function add_to_requests( $email, $type, $data = null, $confirmed = false ) {
|
228 |
+
$requests = ( array ) get_option( 'gdpr_requests', array() );
|
229 |
+
|
230 |
+
$email = sanitize_email( $email );
|
231 |
+
$type = sanitize_text_field( wp_unslash( $type ) );
|
232 |
+
$data = sanitize_textarea_field( wp_unslash( $data ) );
|
233 |
+
|
234 |
+
if ( ! in_array( $type, self::$allowed_types ) ) {
|
235 |
+
return false;
|
236 |
+
}
|
237 |
+
|
238 |
+
$key = wp_generate_password( 20, false );
|
239 |
+
$requests[ $key ] = array(
|
240 |
+
'email' => $email,
|
241 |
+
'date' => date( "F j, Y" ),
|
242 |
+
'type' => $type,
|
243 |
+
'data' => $data,
|
244 |
+
'confirmed' => $confirmed
|
245 |
+
);
|
246 |
+
|
247 |
+
/**
|
248 |
+
* Remove user from the requests if it did not confirm in 2 days.
|
249 |
+
*/
|
250 |
+
$user = get_user_by( 'email', $email );
|
251 |
+
if ( $user instanceof WP_User ) {
|
252 |
+
$meta_key = self::$plugin_name . '_' . $type . '_key';
|
253 |
+
update_user_meta( $user->ID, $meta_key, $key );
|
254 |
+
if ( $time = wp_next_scheduled( 'clean_gdpr_user_request_key', array( 'user_id' => $user->ID, 'meta_key' => $meta_key ) ) ) {
|
255 |
+
wp_unschedule_event( $time, 'clean_gdpr_user_request_key', array( 'user_id' => $user->ID, 'meta_key' => $meta_key ) );
|
256 |
+
}
|
257 |
+
wp_schedule_single_event( time() + 2 * DAY_IN_SECONDS, 'clean_gdpr_user_request_key', array( 'user_id' => $user->ID, 'meta_key' => $meta_key ) );
|
258 |
+
}
|
259 |
+
|
260 |
+
update_option( 'gdpr_requests', $requests );
|
261 |
+
|
262 |
+
return $key;
|
263 |
+
}
|
264 |
+
|
265 |
+
}
|
includes/class-gdpr.php
ADDED
@@ -0,0 +1,659 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* The file that defines the core plugin class
|
5 |
+
*
|
6 |
+
* A class definition that includes attributes and functions used across both the
|
7 |
+
* public-facing side of the site and the admin area.
|
8 |
+
*
|
9 |
+
* @link https://trewknowledge.com
|
10 |
+
* @since 1.0.0
|
11 |
+
*
|
12 |
+
* @package GDPR
|
13 |
+
* @subpackage includes
|
14 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
15 |
+
*/
|
16 |
+
|
17 |
+
/**
|
18 |
+
* The core plugin class.
|
19 |
+
*
|
20 |
+
* This is used to define internationalization, admin-specific hooks, and
|
21 |
+
* public-facing site hooks.
|
22 |
+
*
|
23 |
+
* Also maintains the unique identifier of this plugin as well as the current
|
24 |
+
* version of the plugin.
|
25 |
+
*
|
26 |
+
* @since 1.0.0
|
27 |
+
* @package GDPR
|
28 |
+
* @subpackage includes
|
29 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
30 |
+
*/
|
31 |
+
class GDPR {
|
32 |
+
|
33 |
+
/**
|
34 |
+
* The unique identifier of this plugin.
|
35 |
+
*
|
36 |
+
* @since 1.0.0
|
37 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
38 |
+
* @access protected
|
39 |
+
* @var string $plugin_name The string used to uniquely identify this plugin.
|
40 |
+
*/
|
41 |
+
protected $plugin_name;
|
42 |
+
|
43 |
+
/**
|
44 |
+
* The current version of the plugin.
|
45 |
+
*
|
46 |
+
* @since 1.0.0
|
47 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
48 |
+
* @access protected
|
49 |
+
* @var string $version The current version of the plugin.
|
50 |
+
*/
|
51 |
+
protected $version;
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Define the core functionality of the plugin.
|
55 |
+
*
|
56 |
+
* Set the plugin name and the plugin version that can be used throughout the plugin.
|
57 |
+
* Load the dependencies, define the locale, and set the hooks for the admin area and
|
58 |
+
* the public-facing side of the site.
|
59 |
+
*
|
60 |
+
* @since 1.0.0
|
61 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
62 |
+
*/
|
63 |
+
public function __construct() {
|
64 |
+
if ( defined( 'GDPR_VERSION' ) ) {
|
65 |
+
$this->version = GDPR_VERSION;
|
66 |
+
} else {
|
67 |
+
$this->version = '1.0.0';
|
68 |
+
}
|
69 |
+
$this->plugin_name = 'gdpr';
|
70 |
+
|
71 |
+
$this->load_dependencies();
|
72 |
+
$this->define_common_hooks();
|
73 |
+
$this->define_admin_hooks();
|
74 |
+
$this->define_public_hooks();
|
75 |
+
|
76 |
+
if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) OR ( defined( 'DOING_CRON' ) && DOING_CRON ) OR ( defined( 'DOING_AJAX' ) && DOING_AJAX ) OR ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) ) {
|
77 |
+
return;
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Load the required dependencies for this plugin.
|
83 |
+
*
|
84 |
+
* @since 1.0.0
|
85 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
86 |
+
* @access private
|
87 |
+
*/
|
88 |
+
private function load_dependencies() {
|
89 |
+
/**
|
90 |
+
* The class responsible for adding help tabs.
|
91 |
+
*/
|
92 |
+
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-gdpr-help.php';
|
93 |
+
|
94 |
+
/**
|
95 |
+
* The class responsible logging user actions.
|
96 |
+
*/
|
97 |
+
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-gdpr-audit-log.php';
|
98 |
+
|
99 |
+
/**
|
100 |
+
* The class responsible for defining the telemetry post type.
|
101 |
+
*/
|
102 |
+
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-gdpr-telemetry.php';
|
103 |
+
|
104 |
+
/**
|
105 |
+
* The class responsible for defining the requests section of the plugin.
|
106 |
+
*/
|
107 |
+
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-gdpr-requests.php';
|
108 |
+
|
109 |
+
/**
|
110 |
+
* The class responsible for defining the admin facing requests section of the plugin.
|
111 |
+
*/
|
112 |
+
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-gdpr-requests-admin.php';
|
113 |
+
|
114 |
+
/**
|
115 |
+
* The class responsible for defining the admin facing requests section of the plugin.
|
116 |
+
*/
|
117 |
+
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-gdpr-requests-public.php';
|
118 |
+
|
119 |
+
/**
|
120 |
+
* The class responsible for locating the email templates and sending emails.
|
121 |
+
*/
|
122 |
+
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-gdpr-email.php';
|
123 |
+
|
124 |
+
/**
|
125 |
+
* The class responsible for defining all actions that occur in the admin area.
|
126 |
+
*/
|
127 |
+
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-gdpr-admin.php';
|
128 |
+
|
129 |
+
/**
|
130 |
+
* The class responsible for defining all actions that occur in the public-facing
|
131 |
+
* side of the site.
|
132 |
+
*/
|
133 |
+
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-gdpr-public.php';
|
134 |
+
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* Define the locale for this plugin for internationalization.
|
139 |
+
* @since 1.0.0
|
140 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
141 |
+
*/
|
142 |
+
public function set_locale() {
|
143 |
+
|
144 |
+
load_plugin_textdomain(
|
145 |
+
'gdpr',
|
146 |
+
false,
|
147 |
+
plugin_dir_url( dirname( __FILE__ ) ) . 'languages/'
|
148 |
+
);
|
149 |
+
|
150 |
+
}
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Register all of the common hooks.
|
154 |
+
* @since 1.0.0
|
155 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
156 |
+
* @access private
|
157 |
+
*/
|
158 |
+
private function define_common_hooks() {
|
159 |
+
add_action( 'wp_ajax_gdpr_generate_data_export', array( $this, 'export_data' ) );
|
160 |
+
}
|
161 |
+
|
162 |
+
/**
|
163 |
+
* Register all of the hooks related to the admin area functionality
|
164 |
+
* of the plugin.
|
165 |
+
*
|
166 |
+
* @since 1.0.0
|
167 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
168 |
+
* @access private
|
169 |
+
*/
|
170 |
+
private function define_admin_hooks() {
|
171 |
+
|
172 |
+
$plugin_admin = new GDPR_Admin( $this->get_plugin_name(), $this->get_version() );
|
173 |
+
$requests_admin = new GDPR_Requests_Admin( $this->get_plugin_name(), $this->get_version() );
|
174 |
+
$telemetry = new GDPR_Telemetry( $this->get_plugin_name(), $this->get_version() );
|
175 |
+
$requests = new GDPR_Requests( $this->get_plugin_name(), $this->get_version() );
|
176 |
+
$plugin_emails = new GDPR_Email();
|
177 |
+
$woo_add_to_registration = get_option( 'gdpr_add_consent_checkboxes_registration', false );
|
178 |
+
$woo_add_to_checkout = get_option( 'gdpr_add_consent_checkboxes_checkout', false );
|
179 |
+
|
180 |
+
add_filter( 'nonce_user_logged_out', array( $this, 'woo_nonce_fix' ), 100, 2 );
|
181 |
+
add_action( 'plugins_loaded', array( $this, 'set_locale' ) );
|
182 |
+
add_action( 'bp_account_details_fields', array( __CLASS__, 'consent_checkboxes' ) );
|
183 |
+
if ( $woo_add_to_registration ) {
|
184 |
+
add_action( 'woocommerce_register_form', array( __CLASS__, 'consent_checkboxes' ) );
|
185 |
+
}
|
186 |
+
if ( $woo_add_to_checkout ) {
|
187 |
+
add_action( 'woocommerce_checkout_update_user_meta', array( $plugin_admin, 'woocommerce_checkout_save_consent' ), 10, 2 );
|
188 |
+
add_filter( 'woocommerce_checkout_fields', array( $plugin_admin, 'woocommerce_consent_checkboxes' ) );
|
189 |
+
}
|
190 |
+
add_action( 'show_user_profile', array( $plugin_admin, 'edit_user_profile' ) );
|
191 |
+
add_action( 'personal_options_update', array( $plugin_admin, 'user_profile_update' ) );
|
192 |
+
add_action( 'admin_notices', array( $plugin_admin, 'privacy_policy_page_missing' ) );
|
193 |
+
add_action( 'admin_notices', array( $plugin_admin, 'privacy_policy_updated_notice' ) );
|
194 |
+
add_action( 'wp_ajax_ignore_privacy_policy_update', array( $plugin_admin, 'ignore_privacy_policy_update' ) );
|
195 |
+
add_action( 'admin_post_seek_consent', array( $plugin_admin, 'seek_consent' ) );
|
196 |
+
add_action( 'publish_page', array( $plugin_admin, 'privacy_policy_updated' ), 10, 2 );
|
197 |
+
add_action( 'admin_enqueue_scripts', array( $plugin_admin, 'enqueue_styles' ) );
|
198 |
+
add_action( 'admin_enqueue_scripts', array( $plugin_admin, 'enqueue_scripts' ) );
|
199 |
+
add_action( 'admin_menu', array( $plugin_admin, 'add_menu' ) );
|
200 |
+
add_action( 'admin_init', array( $plugin_admin, 'register_settings' ) );
|
201 |
+
add_action( 'register_form', array( __CLASS__, 'consent_checkboxes' ) );
|
202 |
+
add_action( 'registration_errors', array( $plugin_admin, 'registration_errors' ), 10, 3 );
|
203 |
+
add_action( 'user_register', array( __CLASS__, 'save_user_consent_on_registration' ) );
|
204 |
+
add_action( 'wp_ajax_gdpr_access_data', array( $plugin_admin, 'access_data' ) );
|
205 |
+
add_action( 'wp_ajax_gdpr_audit_log', array( $plugin_admin, 'audit_log' ) );
|
206 |
+
add_action( 'admin_post_gdpr_data_breach', array( $plugin_admin, 'send_data_breach_confirmation_email' ) );
|
207 |
+
add_action( 'clean_gdpr_data_breach_request', array( $plugin_admin, 'clean_data_breach_request' ), 10, 2 ); // CRON JOB
|
208 |
+
add_action( 'telemetry_cleanup', array( $plugin_admin, 'telemetry_cleanup' ) ); // CRON JOB
|
209 |
+
|
210 |
+
add_action( 'admin_post_gdpr_delete_user', array( $requests_admin, 'delete_user' ) );
|
211 |
+
add_action( 'admin_post_gdpr_cancel_request', array( $requests_admin, 'cancel_request' ) );
|
212 |
+
add_action( 'admin_post_gdpr_add_to_deletion_requests', array( $requests_admin, 'add_to_deletion_requests' ) );
|
213 |
+
add_action( 'admin_post_gdpr_mark_resolved', array( $requests_admin, 'mark_resolved' ) );
|
214 |
+
add_action( 'wp_ajax_gdpr_anonymize_comments', array( $requests_admin, 'anonymize_comments' ) );
|
215 |
+
add_action( 'wp_ajax_gdpr_reassign_content', array( $requests_admin, 'reassign_content' ) );
|
216 |
+
|
217 |
+
add_action( 'init', array( $telemetry, 'register_post_type' ) );
|
218 |
+
add_filter( 'http_api_debug', array( $telemetry, 'log_request' ), 10, 5 );
|
219 |
+
add_filter( 'manage_telemetry_posts_columns', array( $telemetry, 'manage_columns' ) );
|
220 |
+
add_filter( 'manage_telemetry_posts_custom_column', array( $telemetry, 'custom_column' ), 10, 2 );
|
221 |
+
add_filter( 'restrict_manage_posts', array( $telemetry, 'actions_above_table' ) );
|
222 |
+
add_filter( 'views_edit-telemetry', '__return_null' );
|
223 |
+
|
224 |
+
// CRON JOBS
|
225 |
+
add_action( 'clean_gdpr_requests', array( $requests, 'clean_requests' ) );
|
226 |
+
add_action( 'clean_gdpr_user_request_key', array( $requests, 'clean_user_request_key' ), 10, 2 );
|
227 |
+
|
228 |
+
add_action( 'send_data_breach_emails', array( $plugin_emails, 'send_data_breach_emails' ), 10, 2 );
|
229 |
+
}
|
230 |
+
|
231 |
+
/**
|
232 |
+
* Fixes nonce manipulation made by Woocommerce.
|
233 |
+
* @param int $user_id The user id.
|
234 |
+
* @param string $action The nonce Action.
|
235 |
+
* @return int The user id.
|
236 |
+
*/
|
237 |
+
function woo_nonce_fix( $user_id, $action ) {
|
238 |
+
if ( ( 0 !== $user_id ) && $action && ( false !== strpos( $action, 'gdpr-' ) ) ) {
|
239 |
+
$user_id = 0;
|
240 |
+
}
|
241 |
+
|
242 |
+
return $user_id;
|
243 |
+
}
|
244 |
+
|
245 |
+
/**
|
246 |
+
* Register all of the hooks related to the public-facing functionality
|
247 |
+
* of the plugin.
|
248 |
+
*
|
249 |
+
* @since 1.0.0
|
250 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
251 |
+
* @access private
|
252 |
+
*/
|
253 |
+
private function define_public_hooks() {
|
254 |
+
|
255 |
+
$plugin_public = new GDPR_Public( $this->get_plugin_name(), $this->get_version() );
|
256 |
+
$requests_public = new GDPR_Requests_Public( $this->get_plugin_name(), $this->get_version() );
|
257 |
+
|
258 |
+
add_action( 'wp_enqueue_scripts', array( $plugin_public, 'enqueue_styles' ) );
|
259 |
+
add_action( 'wp_enqueue_scripts', array( $plugin_public, 'enqueue_scripts' ) );
|
260 |
+
add_action( 'init', array( $plugin_public, 'set_plugin_cookies' ) );
|
261 |
+
add_action( 'wp_footer', array( $plugin_public, 'overlay' ) );
|
262 |
+
add_action( 'wp_footer', array( $plugin_public, 'privacy_bar' ) );
|
263 |
+
add_action( 'wp_footer', array( $plugin_public, 'is_consent_needed' ) );
|
264 |
+
add_action( 'wp_footer', array( $plugin_public, 'privacy_preferences_modal' ) );
|
265 |
+
add_action( 'wp_footer', array( $plugin_public, 'confirmation_screens' ) );
|
266 |
+
add_action( 'wp_ajax_disagree_with_terms', array( $plugin_public, 'logout' ) );
|
267 |
+
add_action( 'wp_ajax_agree_with_terms', array( $plugin_public, 'agree_with_terms' ) );
|
268 |
+
add_action( 'admin_post_gdpr_update_privacy_preferences', array( $plugin_public, 'update_privacy_preferences' ) );
|
269 |
+
add_action( 'admin_post_nopriv_gdpr_update_privacy_preferences', array( $plugin_public, 'update_privacy_preferences' ) );
|
270 |
+
|
271 |
+
add_action( 'wp', array( $requests_public, 'request_confirmed' ) );
|
272 |
+
add_action( 'admin_post_gdpr_send_request_email', array( $requests_public, 'send_request_email' ) );
|
273 |
+
add_action( 'admin_post_nopriv_gdpr_send_request_email', array( $requests_public, 'send_request_email' ) );
|
274 |
+
}
|
275 |
+
|
276 |
+
/**
|
277 |
+
* Checks in an array if a value is found using LIKE instead of =.
|
278 |
+
* @since 1.4.3
|
279 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
280 |
+
* @return Bool
|
281 |
+
*/
|
282 |
+
public static function similar_in_array( $needle, $haystack ) {
|
283 |
+
foreach ( $haystack as $value ) {
|
284 |
+
if( stripos( strtolower($value) , strtolower($needle) ) !== false ) {
|
285 |
+
return true;
|
286 |
+
}
|
287 |
+
}
|
288 |
+
|
289 |
+
return false;
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* Save the extra fields on a successful registration.
|
294 |
+
* @since 1.0.0
|
295 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
296 |
+
* @param int $user_id The user ID.
|
297 |
+
*/
|
298 |
+
public static function save_user_consent_on_registration( $user_id ) {
|
299 |
+
GDPR_Audit_Log::log( $user_id, esc_html__( 'User registered to the site.', 'gdpr' ) );
|
300 |
+
|
301 |
+
if ( isset( $_POST['user_consents'] ) ) {
|
302 |
+
|
303 |
+
$consents = array_map( 'sanitize_text_field', array_keys( $_POST['user_consents'] ) );
|
304 |
+
foreach ( $consents as $consent ) {
|
305 |
+
/* translators: Name of consent */
|
306 |
+
GDPR_Audit_Log::log( $user_id, sprintf( esc_html__( 'User gave explicit consent to %s', 'gdpr' ), $consent ) );
|
307 |
+
add_user_meta( $user_id, 'gdpr_consents', $consent );
|
308 |
+
}
|
309 |
+
setcookie( "gdpr[consent_types]", json_encode( $consents ), time() + YEAR_IN_SECONDS, "/" );
|
310 |
+
}
|
311 |
+
}
|
312 |
+
|
313 |
+
/**
|
314 |
+
* Returns the consent checkboxes to be used across the site.
|
315 |
+
* @since 1.2.0
|
316 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
317 |
+
*/
|
318 |
+
public static function get_consent_checkboxes() {
|
319 |
+
$consent_types = get_option( 'gdpr_consent_types', array() );
|
320 |
+
$sent_extras = ( isset( $_POST['user_consents'] ) ) ? $_POST['user_consents'] : array();
|
321 |
+
$allowed_html = array(
|
322 |
+
'a' => array(
|
323 |
+
'href' => true,
|
324 |
+
'title' => true,
|
325 |
+
'target' => true,
|
326 |
+
),
|
327 |
+
);
|
328 |
+
|
329 |
+
ob_start();
|
330 |
+
foreach ( $consent_types as $key => $consent ) {
|
331 |
+
$required = ( isset( $consent['required'] ) && $consent['required'] ) ? 'required' : '';
|
332 |
+
$checked = ( isset( $sent_extras[ $key ] ) ) ? checked( $sent_extras[ $key ], 1, false ) : '';
|
333 |
+
echo '<p>' .
|
334 |
+
'<input type="checkbox" name="user_consents[' . esc_attr( $key ) . ']" id="' . esc_attr( $key ) . '-consent" value="1" ' . $required . ' ' . $checked . '>' .
|
335 |
+
'<label for="' . esc_attr( $key ) . '-consent">' . wp_kses( $consent['registration'], $allowed_html ) . '</label>' .
|
336 |
+
'</p>';
|
337 |
+
}
|
338 |
+
|
339 |
+
return ob_get_clean();
|
340 |
+
}
|
341 |
+
|
342 |
+
/**
|
343 |
+
* Renders consent checkboxes to be used across the site.
|
344 |
+
* @since 1.1.4
|
345 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
346 |
+
*/
|
347 |
+
public static function consent_checkboxes() {
|
348 |
+
echo self::get_consent_checkboxes();
|
349 |
+
}
|
350 |
+
|
351 |
+
/**
|
352 |
+
* Get user meta for exporting.
|
353 |
+
* @since 1.0.0
|
354 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
355 |
+
* @static
|
356 |
+
* @param int $user_id The user ID.
|
357 |
+
* @return array The user meta minus not important metas.
|
358 |
+
*/
|
359 |
+
static function get_user_meta( $user_id ) {
|
360 |
+
$usermeta = get_user_meta( $user_id );
|
361 |
+
$remove_metadata = array(
|
362 |
+
'nickname',
|
363 |
+
'first_name',
|
364 |
+
'last_name',
|
365 |
+
'description',
|
366 |
+
'rich_editing',
|
367 |
+
'syntax_highlighting',
|
368 |
+
'comment_shortcuts',
|
369 |
+
'admin_color',
|
370 |
+
'use_ssl',
|
371 |
+
'show_admin_bar_front',
|
372 |
+
'wp_capabilities',
|
373 |
+
'wp_user_level',
|
374 |
+
'gdpr_consents',
|
375 |
+
'gdpr_audit_log',
|
376 |
+
'dismissed_wp_pointers',
|
377 |
+
'gdpr_delete_key',
|
378 |
+
'gdpr_rectify_key',
|
379 |
+
'gdpr_complaint_key',
|
380 |
+
'gdpr_export-data_key',
|
381 |
+
|
382 |
+
);
|
383 |
+
|
384 |
+
return array_diff_key( $usermeta, array_flip( $remove_metadata ) );
|
385 |
+
}
|
386 |
+
|
387 |
+
/**
|
388 |
+
* Generates the export in JSON or XML formats.
|
389 |
+
* @since 1.0.0
|
390 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
391 |
+
* @static
|
392 |
+
* @param string $email The user email.
|
393 |
+
* @param string $format Either XML or JSON.
|
394 |
+
* @return string Returns the file as string.
|
395 |
+
*/
|
396 |
+
static function generate_export( $email, $format ) {
|
397 |
+
|
398 |
+
$email = sanitize_email( $email );
|
399 |
+
$user = get_user_by( 'email', $email );
|
400 |
+
|
401 |
+
if ( ! $user instanceof WP_User ) {
|
402 |
+
return false;
|
403 |
+
}
|
404 |
+
|
405 |
+
$usermeta = self::get_user_meta( $user->ID );
|
406 |
+
$comments = get_comments( array(
|
407 |
+
'author_email' => $user->user_email,
|
408 |
+
'include_unapproved' => true,
|
409 |
+
) );
|
410 |
+
$user_consents = get_user_meta( $user->ID, 'gdpr_consents' );
|
411 |
+
$extra_content = apply_filters( 'gdpr_export_data_extra_tables', '', $email );
|
412 |
+
|
413 |
+
switch ( strtolower( $format ) ) {
|
414 |
+
case 'json':
|
415 |
+
$metadata = array();
|
416 |
+
|
417 |
+
foreach ( $usermeta as $k => $v ) {
|
418 |
+
$metadata[ $k ] = array();
|
419 |
+
foreach ( $v as $value ) {
|
420 |
+
if ( is_serialized( $value ) ) {
|
421 |
+
$metadata[ $k ][] = maybe_unserialize( $value );
|
422 |
+
} else {
|
423 |
+
$metadata[ $k ] = $value;
|
424 |
+
}
|
425 |
+
}
|
426 |
+
}
|
427 |
+
|
428 |
+
$comments_array = array();
|
429 |
+
if ( ! empty( $comments ) ) {
|
430 |
+
foreach ( $comments as $k => $v ) {
|
431 |
+
$comments_array[ $k ] = array(
|
432 |
+
'comment_author' => $v->comment_author,
|
433 |
+
'comment_author_email' => $v->comment_author_email,
|
434 |
+
'comment_author_url' => $v->comment_author_url,
|
435 |
+
'comment_author_IP' => $v->comment_author_IP,
|
436 |
+
'comment_date' => $v->comment_date,
|
437 |
+
'comment_agent' => $v->comment_agent,
|
438 |
+
'comment_content' => $v->comment_content,
|
439 |
+
);
|
440 |
+
}
|
441 |
+
}
|
442 |
+
|
443 |
+
$json = array(
|
444 |
+
'Personal Information' => array(
|
445 |
+
'Username' => $user->user_login,
|
446 |
+
'First name' => $user->first_name,
|
447 |
+
'Last name' => $user->last_name,
|
448 |
+
'Email' => $user->user_email,
|
449 |
+
'Nickname' => $user->nickname,
|
450 |
+
'Display name' => $user->display_name,
|
451 |
+
'Description' => $user->description,
|
452 |
+
'Website' => $user->user_url,
|
453 |
+
),
|
454 |
+
'Consents' => $user_consents,
|
455 |
+
'Metadata' => $metadata,
|
456 |
+
'Comments' => $comments_array,
|
457 |
+
);
|
458 |
+
|
459 |
+
if ( $extra_content ) {
|
460 |
+
$json[ $extra_content['name'] ] = $extra_content['content'];
|
461 |
+
}
|
462 |
+
return json_encode( $json );
|
463 |
+
break;
|
464 |
+
case 'md':
|
465 |
+
case 'markdown':
|
466 |
+
# code...
|
467 |
+
break;
|
468 |
+
|
469 |
+
default: // XML
|
470 |
+
$dom = new DomDocument( '1.0', 'ISO-8859-1' );
|
471 |
+
$personal_info = $dom->createElement( 'Personal_Information' );
|
472 |
+
$dom->appendChild( $personal_info );
|
473 |
+
$personal_info->appendChild( $dom->createElement( 'Username', $user->user_login ) );
|
474 |
+
$personal_info->appendChild( $dom->createElement( 'First_Name', $user->first_name ) );
|
475 |
+
$personal_info->appendChild( $dom->createElement( 'Last_Name', $user->last_name ) );
|
476 |
+
$personal_info->appendChild( $dom->createElement( 'Email', $user->user_email ) );
|
477 |
+
$personal_info->appendChild( $dom->createElement( 'Nickname', $user->nickname ) );
|
478 |
+
$personal_info->appendChild( $dom->createElement( 'Display_Name', $user->display_name ) );
|
479 |
+
$personal_info->appendChild( $dom->createElement( 'Description', $user->description ) );
|
480 |
+
$personal_info->appendChild( $dom->createElement( 'Website', $user->user_url ) );
|
481 |
+
|
482 |
+
if ( ! empty( $user_consents ) ) {
|
483 |
+
$consents = $dom->createElement( 'Consents' );
|
484 |
+
$dom->appendChild( $consents );
|
485 |
+
foreach ( $user_consents as $consent_item ) {
|
486 |
+
$consents->appendChild( $dom->createElement( 'consent', $consent_item ) );
|
487 |
+
}
|
488 |
+
}
|
489 |
+
|
490 |
+
if ( ! empty( $comments ) ) {
|
491 |
+
$comments_node = $dom->createElement( 'Comments' );
|
492 |
+
$dom->appendChild( $comments_node );
|
493 |
+
foreach ( $comments as $k => $v ) {
|
494 |
+
$single_comment = $dom->createElement( 'Comment' );
|
495 |
+
$comments_node->appendChild( $single_comment );
|
496 |
+
$single_comment->appendChild( $dom->createElement( 'comment_author', htmlspecialchars( $v->comment_author ) ) );
|
497 |
+
$single_comment->appendChild( $dom->createElement( 'comment_author_email', htmlspecialchars( $v->comment_author_email ) ) );
|
498 |
+
$single_comment->appendChild( $dom->createElement( 'comment_author_url', htmlspecialchars( $v->comment_author_url ) ) );
|
499 |
+
$single_comment->appendChild( $dom->createElement( 'comment_author_IP', htmlspecialchars( $v->comment_author_IP ) ) );
|
500 |
+
$single_comment->appendChild( $dom->createElement( 'comment_date', htmlspecialchars( $v->comment_date ) ) );
|
501 |
+
$single_comment->appendChild( $dom->createElement( 'comment_agent', htmlspecialchars( $v->comment_agent ) ) );
|
502 |
+
$single_comment->appendChild( $dom->createElement( 'comment_content', htmlspecialchars( $v->comment_content ) ) );
|
503 |
+
}
|
504 |
+
}
|
505 |
+
|
506 |
+
$meta_data = $dom->createElement( 'Metadata' );
|
507 |
+
$dom->appendChild( $meta_data );
|
508 |
+
|
509 |
+
foreach ( $usermeta as $k => $v ) {
|
510 |
+
$k = is_numeric( substr( $k, 0, 1 ) ) ? '_' . $k : $k;
|
511 |
+
$key = $dom->createElement( htmlspecialchars( $k ) );
|
512 |
+
$meta_data->appendChild( $key );
|
513 |
+
foreach ( $v as $value ) {
|
514 |
+
$key->appendChild( $dom->createElement( 'item', htmlspecialchars( $value ) ) );
|
515 |
+
}
|
516 |
+
}
|
517 |
+
|
518 |
+
if ( $extra_content ) {
|
519 |
+
$extra = $dom->createElement( $extra_content['name'] );
|
520 |
+
$dom->appendChild( $extra );
|
521 |
+
foreach ( $extra_content['content'] as $key => $obj ) {
|
522 |
+
$item = $extra->appendChild( $dom->createElement( 'item' ) );
|
523 |
+
foreach ( $obj as $k => $value ) {
|
524 |
+
$item->appendChild( $dom->createElement( $k, ( is_object( $value ) || is_array( $value ) ) ? serialize( (array) $value ) : $value ) );
|
525 |
+
}
|
526 |
+
}
|
527 |
+
}
|
528 |
+
|
529 |
+
$dom->preserveWhiteSpace = false;
|
530 |
+
$dom->formatOutput = true;
|
531 |
+
return $dom->saveXML();
|
532 |
+
break;
|
533 |
+
}
|
534 |
+
|
535 |
+
return false;
|
536 |
+
|
537 |
+
}
|
538 |
+
|
539 |
+
/**
|
540 |
+
* Export the generated export file.
|
541 |
+
* @since 1.0.0
|
542 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
543 |
+
*/
|
544 |
+
function export_data() {
|
545 |
+
if ( ! isset( $_POST['nonce'], $_POST['email'], $_POST['type'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'gdpr-export-data' ) ) {
|
546 |
+
wp_send_json_error();
|
547 |
+
}
|
548 |
+
|
549 |
+
$type = sanitize_text_field( wp_unslash( $_POST['type'] ) );
|
550 |
+
$email = sanitize_email( $_POST['email'] );
|
551 |
+
$user = get_user_by( 'email', $email );
|
552 |
+
|
553 |
+
if ( ! $user instanceof WP_User ) {
|
554 |
+
wp_send_json_error();
|
555 |
+
}
|
556 |
+
|
557 |
+
$export = self::generate_export( $email, $type );
|
558 |
+
if ( $export ) {
|
559 |
+
wp_send_json_success( $export );
|
560 |
+
}
|
561 |
+
|
562 |
+
wp_send_json_error();
|
563 |
+
}
|
564 |
+
|
565 |
+
/**
|
566 |
+
* Save a consent to the user meta.
|
567 |
+
* @since 1.1.4
|
568 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
569 |
+
* @param integer $user_id The user ID.
|
570 |
+
* @param string $consent The consent ID.
|
571 |
+
* @return void
|
572 |
+
*/
|
573 |
+
public static function save_consent( $user_id, $consent ) {
|
574 |
+
$registered_consent = get_option( 'gdpr_consent_types', array( 'privacy-policy' ) );
|
575 |
+
$consent_ids = array_keys( $registered_consent );
|
576 |
+
$user = get_user_by( 'ID', $user_id );
|
577 |
+
$consent = sanitize_text_field( wp_unslash( $consent ) );
|
578 |
+
|
579 |
+
if ( $user ) {
|
580 |
+
$user_consent = get_user_meta( $user_id, 'gdpr_consents' );
|
581 |
+
if ( in_array( $consent, $consent_ids ) && ! in_array( $consent, $user_consent ) ) {
|
582 |
+
add_user_meta( $user_id, 'gdpr_consents', $consent );
|
583 |
+
$user_consent[] = $consent;
|
584 |
+
setcookie( "gdpr[consent_types]", json_encode( $user_consent ), time() + YEAR_IN_SECONDS, "/" );
|
585 |
+
return true;
|
586 |
+
}
|
587 |
+
}
|
588 |
+
|
589 |
+
return false;
|
590 |
+
}
|
591 |
+
|
592 |
+
/**
|
593 |
+
* Remove a user consent.
|
594 |
+
* @since 1.1.4
|
595 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
596 |
+
* @param integer $user_id The user ID.
|
597 |
+
* @param string $consent The consent ID.
|
598 |
+
* @return void
|
599 |
+
*/
|
600 |
+
public static function remove_consent( $user_id, $consent ) {
|
601 |
+
$user = get_user_by( 'ID', $user_id );
|
602 |
+
|
603 |
+
if ( $user ) {
|
604 |
+
$user_consent = get_user_meta( $user_id, 'gdpr_consents' );
|
605 |
+
|
606 |
+
$consent = sanitize_text_field( wp_unslash( $consent ) );
|
607 |
+
$key = array_search( $consent, $user_consent );
|
608 |
+
if ( false !== $key ) {
|
609 |
+
delete_user_meta( $user_id, 'gdpr_consents', $consent );
|
610 |
+
unset( $user_consent[ $key ] );
|
611 |
+
setcookie( "gdpr[consent_types]", json_encode( $user_consent ), time() + YEAR_IN_SECONDS, "/" );
|
612 |
+
return true;
|
613 |
+
}
|
614 |
+
}
|
615 |
+
|
616 |
+
return false;
|
617 |
+
}
|
618 |
+
|
619 |
+
|
620 |
+
/**
|
621 |
+
* Generates a random 6 digit pin.
|
622 |
+
* This pin is necessary to use with the audit log files.
|
623 |
+
*
|
624 |
+
* @since 1.0.0
|
625 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
626 |
+
* @static
|
627 |
+
* @param integer $length Number of digits.
|
628 |
+
* @return string Returns the generated pin
|
629 |
+
*/
|
630 |
+
public static function generate_pin( $length = 6 ) {
|
631 |
+
$bytes = openssl_random_pseudo_bytes( $length / 2 );
|
632 |
+
return strtoupper( bin2hex( $bytes ) );
|
633 |
+
}
|
634 |
+
|
635 |
+
|
636 |
+
/**
|
637 |
+
* The name of the plugin used to uniquely identify it within the context of
|
638 |
+
* WordPress and to define internationalization functionality.
|
639 |
+
*
|
640 |
+
* @since 1.0.0
|
641 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
642 |
+
* @return string The name of the plugin.
|
643 |
+
*/
|
644 |
+
public function get_plugin_name() {
|
645 |
+
return $this->plugin_name;
|
646 |
+
}
|
647 |
+
|
648 |
+
/**
|
649 |
+
* Retrieve the version number of the plugin.
|
650 |
+
*
|
651 |
+
* @since 1.0.0
|
652 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
653 |
+
* @return string The version number of the plugin.
|
654 |
+
*/
|
655 |
+
public function get_version() {
|
656 |
+
return $this->version;
|
657 |
+
}
|
658 |
+
|
659 |
+
}
|
includes/helper-functions.php
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* The plugin helper functions
|
4 |
+
*
|
5 |
+
* @link https://trewknowledge.com
|
6 |
+
* @since 1.0.0
|
7 |
+
*
|
8 |
+
* @package GDPR
|
9 |
+
* @subpackage public
|
10 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Adds a button to re-open the cookie preferences modal.
|
15 |
+
* @since 1.0.0
|
16 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
17 |
+
* @param string $text The button text.
|
18 |
+
* @param string $type The type of preferences. Possible options are `cookies` or `consents`
|
19 |
+
*/
|
20 |
+
function gdpr_preferences( $text ) {
|
21 |
+
echo '<button type="button" class="gdpr-preferences">' . esc_html( $text ) . '</button>';
|
22 |
+
}
|
23 |
+
|
24 |
+
function gdpr_preferences_shortcode( $atts ) {
|
25 |
+
$atts = shortcode_atts( array(
|
26 |
+
'text' => esc_html__( 'Privacy Preferences', 'gdpr' ),
|
27 |
+
), $atts, 'gdpr_preferences' );
|
28 |
+
|
29 |
+
ob_start();
|
30 |
+
gdpr_preferences( $atts['text'] );
|
31 |
+
return ob_get_clean();
|
32 |
+
}
|
33 |
+
|
34 |
+
add_shortcode( 'gdpr_preferences', 'gdpr_preferences_shortcode' );
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Load the request forms.
|
38 |
+
* @since 1.0.0
|
39 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
40 |
+
* @param string $type The type of request.
|
41 |
+
*/
|
42 |
+
function gdpr_request_form( $type ) {
|
43 |
+
echo GDPR_Requests_Public::request_form( $type );
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Create the request form shortcode.
|
48 |
+
* @since 1.0.0
|
49 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
50 |
+
* @param string $atts Shortcode attributes.
|
51 |
+
*/
|
52 |
+
function gdpr_request_form_shortcode( $atts ) {
|
53 |
+
$atts = shortcode_atts( array(
|
54 |
+
'type' => '',
|
55 |
+
), $atts, 'gdpr_request_form' );
|
56 |
+
|
57 |
+
return GDPR_Requests_Public::request_form( $atts['type'] );
|
58 |
+
}
|
59 |
+
|
60 |
+
add_shortcode( 'gdpr_request_form', 'gdpr_request_form_shortcode' );
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Checks if a cookie is allowed
|
64 |
+
* @since 1.0.0
|
65 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
66 |
+
* @param string $cookie_name The cookie name.
|
67 |
+
* @return bool Whether the cookie is allowed or not.
|
68 |
+
*/
|
69 |
+
function is_allowed_cookie( $cookie_name ) {
|
70 |
+
if ( isset( $_COOKIE['gdpr']['allowed_cookies'] ) ) {
|
71 |
+
$allowed_cookies = json_decode( wp_unslash( $_COOKIE['gdpr']['allowed_cookies'] ), true );
|
72 |
+
$name = preg_quote( $cookie_name, '~' );
|
73 |
+
$result = preg_grep( '~' . $name . '~', $allowed_cookies );
|
74 |
+
if ( in_array( $cookie_name, $allowed_cookies ) || ! empty( $result ) ) {
|
75 |
+
return true;
|
76 |
+
}
|
77 |
+
}
|
78 |
+
|
79 |
+
return false;
|
80 |
+
}
|
81 |
+
|
82 |
+
function gdpr_deprecated_function( $function, $version, $replacement = null ) {
|
83 |
+
if ( defined( 'DOING_AJAX' ) ) {
|
84 |
+
do_action( 'deprecated_function_run', $function, $replacement, $version );
|
85 |
+
$log_string = "The {$function} function is deprecated since version {$version}.";
|
86 |
+
$log_string .= $replacement ? " Replace with {$replacement}." : '';
|
87 |
+
} else {
|
88 |
+
_deprecated_function( $function, $version, $replacement );
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Checks if a user gave consent.
|
94 |
+
* @since 1.0.0
|
95 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
96 |
+
* @param string $consent The consent id.
|
97 |
+
* @return bool Whether the user gave consent or not.
|
98 |
+
*/
|
99 |
+
function have_consent( $consent ) {
|
100 |
+
gdpr_deprecated_function( 'have_consent', '1.1.0', 'has_consent' );
|
101 |
+
return has_consent( $consent );
|
102 |
+
}
|
103 |
+
|
104 |
+
function has_consent( $consent ) {
|
105 |
+
|
106 |
+
if ( is_user_logged_in() ) {
|
107 |
+
$user = wp_get_current_user();
|
108 |
+
$consents = (array) get_user_meta( $user->ID, 'gdpr_consents' );
|
109 |
+
} else if ( isset( $_COOKIE['gdpr']['consent_types'] ) && ! empty( $_COOKIE['gdpr']['consent_types'] ) ) {
|
110 |
+
$consents = array_map( 'sanitize_text_field', (array) json_decode( wp_unslash( $_COOKIE['gdpr']['consent_types'] ) ) );
|
111 |
+
}
|
112 |
+
|
113 |
+
if ( isset( $consents ) && ! empty( $consents ) ) {
|
114 |
+
if ( in_array( $consent, $consents ) ) {
|
115 |
+
return true;
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
return false;
|
120 |
+
}
|
includes/index.php
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php // Silence is golden
|
index.php
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php // Silence is golden
|
languages/gdpr.pot
ADDED
@@ -0,0 +1,1243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright (C) 2018 gdpr
|
2 |
+
# This file is distributed under the same license as the gdpr package.
|
3 |
+
msgid ""
|
4 |
+
msgstr ""
|
5 |
+
"Project-Id-Version: gdpr\n"
|
6 |
+
"MIME-Version: 1.0\n"
|
7 |
+
"Content-Type: text/plain; charset=UTF-8\n"
|
8 |
+
"Content-Transfer-Encoding: 8bit\n"
|
9 |
+
"X-Poedit-Basepath: ..\n"
|
10 |
+
"X-Poedit-KeywordsList: __;_e;_ex:1,2c;_n:1,2;_n_noop:1,2;_nx:1,2,4c;_nx_noop:1,2,3c;_x:1,2c;esc_attr__;esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c\n"
|
11 |
+
"X-Poedit-SearchPath-0: .\n"
|
12 |
+
"X-Poedit-SearchPathExcluded-0: *.js\n"
|
13 |
+
"X-Poedit-SourceCharset: UTF-8\n"
|
14 |
+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
15 |
+
|
16 |
+
#: admin/class-gdpr-admin.php:100, admin/class-gdpr-admin.php:111
|
17 |
+
msgid "GDPR"
|
18 |
+
msgstr ""
|
19 |
+
|
20 |
+
#: admin/class-gdpr-admin.php:118, admin/partials/requests.php:18
|
21 |
+
msgid "Requests"
|
22 |
+
msgstr ""
|
23 |
+
|
24 |
+
#: admin/class-gdpr-admin.php:124, admin/partials/tools.php:44
|
25 |
+
msgid "Tools"
|
26 |
+
msgstr ""
|
27 |
+
|
28 |
+
#: admin/class-gdpr-admin.php:130, admin/partials/settings.php:2
|
29 |
+
msgid "Settings"
|
30 |
+
msgstr ""
|
31 |
+
|
32 |
+
#: admin/class-gdpr-admin.php:271, admin/partials/settings.php:18
|
33 |
+
msgid "General"
|
34 |
+
msgstr ""
|
35 |
+
|
36 |
+
#: admin/class-gdpr-admin.php:272, admin/partials/settings.php:168
|
37 |
+
msgid "Cookies"
|
38 |
+
msgstr ""
|
39 |
+
|
40 |
+
#: admin/class-gdpr-admin.php:273, admin/partials/settings.php:248
|
41 |
+
msgid "Consents"
|
42 |
+
msgstr ""
|
43 |
+
|
44 |
+
#: admin/class-gdpr-admin.php:304, includes/class-gdpr-help.php:38, includes/class-gdpr-help.php:43, admin/partials/requests.php:32
|
45 |
+
msgid "Rectify Data"
|
46 |
+
msgstr ""
|
47 |
+
|
48 |
+
#: admin/class-gdpr-admin.php:308
|
49 |
+
msgid "Complaint"
|
50 |
+
msgstr ""
|
51 |
+
|
52 |
+
#: admin/class-gdpr-admin.php:312, includes/class-gdpr-help.php:56
|
53 |
+
msgid "Erasure"
|
54 |
+
msgstr ""
|
55 |
+
|
56 |
+
#: admin/class-gdpr-admin.php:329, includes/class-gdpr-help.php:81, includes/class-gdpr-help.php:85, admin/partials/tools.php:55
|
57 |
+
msgid "Access Data"
|
58 |
+
msgstr ""
|
59 |
+
|
60 |
+
#: admin/class-gdpr-admin.php:330, includes/class-gdpr-help.php:95, admin/partials/tools.php:72
|
61 |
+
msgid "Data Breach"
|
62 |
+
msgstr ""
|
63 |
+
|
64 |
+
#: admin/class-gdpr-admin.php:331, includes/class-gdpr-help.php:99, includes/class-gdpr-help.php:106, admin/partials/tools.php:117
|
65 |
+
msgid "Audit Log"
|
66 |
+
msgstr ""
|
67 |
+
|
68 |
+
#: admin/class-gdpr-admin.php:403
|
69 |
+
msgid "Consent Given"
|
70 |
+
msgstr ""
|
71 |
+
|
72 |
+
#: admin/class-gdpr-admin.php:407
|
73 |
+
msgid "Consent ID"
|
74 |
+
msgstr ""
|
75 |
+
|
76 |
+
#: admin/class-gdpr-admin.php:419, admin/partials/requests.php:275
|
77 |
+
msgid "Comments"
|
78 |
+
msgstr ""
|
79 |
+
|
80 |
+
#: admin/class-gdpr-admin.php:424
|
81 |
+
msgid "Comment Field"
|
82 |
+
msgstr ""
|
83 |
+
|
84 |
+
#: admin/class-gdpr-admin.php:425
|
85 |
+
msgid "Comment Data"
|
86 |
+
msgstr ""
|
87 |
+
|
88 |
+
#: admin/class-gdpr-admin.php:461
|
89 |
+
msgid "Metadata"
|
90 |
+
msgstr ""
|
91 |
+
|
92 |
+
#: admin/class-gdpr-admin.php:465
|
93 |
+
msgid "Name"
|
94 |
+
msgstr ""
|
95 |
+
|
96 |
+
#: admin/class-gdpr-admin.php:466
|
97 |
+
msgid "Value"
|
98 |
+
msgstr ""
|
99 |
+
|
100 |
+
#: admin/class-gdpr-admin.php:515
|
101 |
+
msgid "No logs found for this email."
|
102 |
+
msgstr ""
|
103 |
+
|
104 |
+
#: admin/class-gdpr-admin.php:534
|
105 |
+
msgid "[GDPR] You must select a Privacy Policy Page."
|
106 |
+
msgstr ""
|
107 |
+
|
108 |
+
#: admin/class-gdpr-admin.php:537
|
109 |
+
msgid "Select your Privacy Policy page"
|
110 |
+
msgstr ""
|
111 |
+
|
112 |
+
#: admin/class-gdpr-admin.php:556
|
113 |
+
msgid "Your Privacy Policy have been updated. In case this was not a small typo fix, you must ask users for explicit consent again."
|
114 |
+
msgstr ""
|
115 |
+
|
116 |
+
#: admin/class-gdpr-admin.php:562
|
117 |
+
msgid "Ask for consent"
|
118 |
+
msgstr ""
|
119 |
+
|
120 |
+
#: admin/class-gdpr-admin.php:569
|
121 |
+
msgid "Ignore"
|
122 |
+
msgstr ""
|
123 |
+
|
124 |
+
#: admin/class-gdpr-admin.php:583, admin/class-gdpr-admin.php:722, admin/class-gdpr-admin.php:784, public/class-gdpr-public.php:189, public/class-gdpr-public.php:282, public/class-gdpr-public.php:296
|
125 |
+
msgid "We could not verify the the security token. Please try again."
|
126 |
+
msgstr ""
|
127 |
+
|
128 |
+
#: admin/class-gdpr-admin.php:595
|
129 |
+
msgid "One or more required fields are missing. Please try again."
|
130 |
+
msgstr ""
|
131 |
+
|
132 |
+
#: admin/class-gdpr-admin.php:642
|
133 |
+
msgid "Data breach notification has been initialized. An email confirmation has been sent to the website controller."
|
134 |
+
msgstr ""
|
135 |
+
|
136 |
+
#: admin/class-gdpr-admin.php:705
|
137 |
+
msgid "ERROR"
|
138 |
+
msgstr ""
|
139 |
+
|
140 |
+
#: admin/class-gdpr-admin.php:707
|
141 |
+
msgid "is a required consent"
|
142 |
+
msgstr ""
|
143 |
+
|
144 |
+
#: admin/class-gdpr-admin.php:734
|
145 |
+
msgid "Privacy Policy has been updated. Removing the Privacy Policy consent and requesting new consent."
|
146 |
+
msgstr ""
|
147 |
+
|
148 |
+
#: admin/class-gdpr-admin.php:739
|
149 |
+
msgid "Users will have to consent to the updated privacy policy on login."
|
150 |
+
msgstr ""
|
151 |
+
|
152 |
+
#: admin/class-gdpr-admin.php:804, includes/class-gdpr-help.php:161, public/partials/privacy-preferences-modal.php:31, public/partials/privacy-preferences-modal.php:48
|
153 |
+
msgid "Consent Management"
|
154 |
+
msgstr ""
|
155 |
+
|
156 |
+
#: admin/class-gdpr-admin.php:841
|
157 |
+
msgid "Profile Updated. These are the user consents after the save:"
|
158 |
+
msgstr ""
|
159 |
+
|
160 |
+
#: admin/class-gdpr-requests-admin.php:30, admin/class-gdpr-requests-admin.php:155, admin/class-gdpr-requests-admin.php:203, admin/class-gdpr-requests-admin.php:240
|
161 |
+
msgid "We could not verify the user email or the security token. Please try again."
|
162 |
+
msgstr ""
|
163 |
+
|
164 |
+
#: admin/class-gdpr-requests-admin.php:37, admin/class-gdpr-requests-admin.php:286, admin/class-gdpr-requests-admin.php:331, public/partials/confirmation-screens.php:48
|
165 |
+
msgid "User not found."
|
166 |
+
msgstr ""
|
167 |
+
|
168 |
+
#: admin/class-gdpr-requests-admin.php:57
|
169 |
+
msgid "User %s is the only admin of the site. It cannot be deleted."
|
170 |
+
msgstr ""
|
171 |
+
|
172 |
+
#: admin/class-gdpr-requests-admin.php:78, admin/class-gdpr-requests-admin.php:117
|
173 |
+
msgid "User added to the deletion requests list by admin."
|
174 |
+
msgstr ""
|
175 |
+
|
176 |
+
#: admin/class-gdpr-requests-admin.php:80, admin/class-gdpr-requests-admin.php:119
|
177 |
+
msgid "User %s was added to the deletion table."
|
178 |
+
msgstr ""
|
179 |
+
|
180 |
+
#: admin/class-gdpr-requests-admin.php:101
|
181 |
+
msgid "User already placed a deletion request."
|
182 |
+
msgstr ""
|
183 |
+
|
184 |
+
#: admin/class-gdpr-requests-admin.php:141, admin/class-gdpr-requests-admin.php:189
|
185 |
+
msgid "We could not verify the type of request you want to cancel."
|
186 |
+
msgstr ""
|
187 |
+
|
188 |
+
#. translators: The type of request
|
189 |
+
#: admin/class-gdpr-requests-admin.php:149, admin/class-gdpr-requests-admin.php:197
|
190 |
+
msgid "Type of request '%s' is not an allowed type."
|
191 |
+
msgstr ""
|
192 |
+
|
193 |
+
#. translators: The type of request i.e 'delete'
|
194 |
+
#: admin/class-gdpr-requests-admin.php:164
|
195 |
+
msgid "User was removed from the %s request list by admin."
|
196 |
+
msgstr ""
|
197 |
+
|
198 |
+
#: admin/class-gdpr-requests-admin.php:167
|
199 |
+
msgid "User %s was removed from this request table."
|
200 |
+
msgstr ""
|
201 |
+
|
202 |
+
#. translators: User email
|
203 |
+
#: admin/class-gdpr-requests-admin.php:216
|
204 |
+
msgid "User %s request was marked as resolved by admin."
|
205 |
+
msgstr ""
|
206 |
+
|
207 |
+
#: admin/class-gdpr-requests-admin.php:218
|
208 |
+
msgid "Request was resolved. User %s has been notified."
|
209 |
+
msgstr ""
|
210 |
+
|
211 |
+
#: admin/class-gdpr-requests-admin.php:251, public/class-gdpr-requests-public.php:44
|
212 |
+
msgid "User was removed from the site."
|
213 |
+
msgstr ""
|
214 |
+
|
215 |
+
#: admin/class-gdpr-requests-admin.php:256
|
216 |
+
msgid "User %s was deleted from the site."
|
217 |
+
msgstr ""
|
218 |
+
|
219 |
+
#: admin/class-gdpr-requests-admin.php:278, admin/class-gdpr-requests-admin.php:317, public/class-gdpr-requests-public.php:81
|
220 |
+
msgid "We could not verify the security token. Please try again."
|
221 |
+
msgstr ""
|
222 |
+
|
223 |
+
#: admin/class-gdpr-requests-admin.php:302
|
224 |
+
msgid "Guest"
|
225 |
+
msgstr ""
|
226 |
+
|
227 |
+
#: admin/class-gdpr-requests-admin.php:306
|
228 |
+
msgid "User comments were anonymized."
|
229 |
+
msgstr ""
|
230 |
+
|
231 |
+
#: admin/class-gdpr-requests-admin.php:321
|
232 |
+
msgid "Essential data missing. Please try again."
|
233 |
+
msgstr ""
|
234 |
+
|
235 |
+
#. translators: 1: The post type, 2: The user the posts were reassigned to
|
236 |
+
#: admin/class-gdpr-requests-admin.php:352
|
237 |
+
msgid "User %s were reassigned to %s."
|
238 |
+
msgstr ""
|
239 |
+
|
240 |
+
#: admin/class-gdpr-requests-admin.php:356
|
241 |
+
msgid "Something went wrong. Please try again."
|
242 |
+
msgstr ""
|
243 |
+
|
244 |
+
#: admin/class-gdpr-telemetry.php:47
|
245 |
+
msgid "Telemetry"
|
246 |
+
msgstr ""
|
247 |
+
|
248 |
+
#: admin/class-gdpr-telemetry.php:49
|
249 |
+
msgid "No items found. Future connections will be shown at this place."
|
250 |
+
msgstr ""
|
251 |
+
|
252 |
+
#: admin/class-gdpr-telemetry.php:50
|
253 |
+
msgid "No items found in trash."
|
254 |
+
msgstr ""
|
255 |
+
|
256 |
+
#: admin/class-gdpr-telemetry.php:51
|
257 |
+
msgid "Search in destination"
|
258 |
+
msgstr ""
|
259 |
+
|
260 |
+
#: admin/class-gdpr-telemetry.php:185
|
261 |
+
msgid "Delete all"
|
262 |
+
msgstr ""
|
263 |
+
|
264 |
+
#: admin/class-gdpr-telemetry.php:197
|
265 |
+
msgid "Destination"
|
266 |
+
msgstr ""
|
267 |
+
|
268 |
+
#: admin/class-gdpr-telemetry.php:198
|
269 |
+
msgid "File"
|
270 |
+
msgstr ""
|
271 |
+
|
272 |
+
#: admin/class-gdpr-telemetry.php:199
|
273 |
+
msgid "Code"
|
274 |
+
msgstr ""
|
275 |
+
|
276 |
+
#: admin/class-gdpr-telemetry.php:200
|
277 |
+
msgid "Time"
|
278 |
+
msgstr ""
|
279 |
+
|
280 |
+
#: admin/class-gdpr-telemetry.php:201
|
281 |
+
msgid "Data"
|
282 |
+
msgstr ""
|
283 |
+
|
284 |
+
#: admin/class-gdpr-telemetry.php:343
|
285 |
+
msgid "Show"
|
286 |
+
msgstr ""
|
287 |
+
|
288 |
+
#: includes/class-gdpr-email.php:158
|
289 |
+
msgid "Data breach notification sent to user."
|
290 |
+
msgstr ""
|
291 |
+
|
292 |
+
#. translators: email content
|
293 |
+
#: includes/class-gdpr-email.php:160
|
294 |
+
msgid "Email content: %s"
|
295 |
+
msgstr ""
|
296 |
+
|
297 |
+
#. translators: nature of the data breach
|
298 |
+
#: includes/class-gdpr-email.php:162
|
299 |
+
msgid "Nature of data breach: %s"
|
300 |
+
msgstr ""
|
301 |
+
|
302 |
+
#. translators: data protection officer contact information
|
303 |
+
#: includes/class-gdpr-email.php:164
|
304 |
+
msgid "Data protection officer contact: %s"
|
305 |
+
msgstr ""
|
306 |
+
|
307 |
+
#. translators: likely consequences
|
308 |
+
#: includes/class-gdpr-email.php:166
|
309 |
+
msgid "Likely consequences of breach: %s"
|
310 |
+
msgstr ""
|
311 |
+
|
312 |
+
#. translators: measures taken
|
313 |
+
#: includes/class-gdpr-email.php:168
|
314 |
+
msgid "Measures taken or proposed to be taken: %s"
|
315 |
+
msgstr ""
|
316 |
+
|
317 |
+
#: includes/class-gdpr-email.php:197
|
318 |
+
msgid "GDPR Notification: There is a new request waiting to be reviewed."
|
319 |
+
msgstr ""
|
320 |
+
|
321 |
+
#: includes/class-gdpr-email.php:198
|
322 |
+
msgid "Someone requested to close your account."
|
323 |
+
msgstr ""
|
324 |
+
|
325 |
+
#: includes/class-gdpr-email.php:199
|
326 |
+
msgid "Your account has been closed."
|
327 |
+
msgstr ""
|
328 |
+
|
329 |
+
#: includes/class-gdpr-email.php:200
|
330 |
+
msgid "Someone requested that we rectify data of your account."
|
331 |
+
msgstr ""
|
332 |
+
|
333 |
+
#: includes/class-gdpr-email.php:201, includes/class-gdpr-email.php:203, includes/class-gdpr-email.php:205
|
334 |
+
msgid "Your request has been completed."
|
335 |
+
msgstr ""
|
336 |
+
|
337 |
+
#: includes/class-gdpr-email.php:202
|
338 |
+
msgid "Someone made complaint on behalf of your account."
|
339 |
+
msgstr ""
|
340 |
+
|
341 |
+
#: includes/class-gdpr-email.php:204
|
342 |
+
msgid "Someone requested to download your data."
|
343 |
+
msgstr ""
|
344 |
+
|
345 |
+
#: includes/class-gdpr-email.php:206
|
346 |
+
msgid "Someone requested to send a data breach notification."
|
347 |
+
msgstr ""
|
348 |
+
|
349 |
+
#: includes/class-gdpr-email.php:207
|
350 |
+
msgid "Data Breach Notification."
|
351 |
+
msgstr ""
|
352 |
+
|
353 |
+
#: includes/class-gdpr-help.php:30, includes/class-gdpr-help.php:34, includes/class-gdpr-help.php:73, includes/class-gdpr-help.php:77, includes/class-gdpr-help.php:177, includes/class-gdpr-help.php:184
|
354 |
+
msgid "Overview"
|
355 |
+
msgstr ""
|
356 |
+
|
357 |
+
#: includes/class-gdpr-help.php:31
|
358 |
+
msgid "This page has multiple request tables. Users can request multiple things like getting deleted from the site or having their data rectified. All requests will come to these tables."
|
359 |
+
msgstr ""
|
360 |
+
|
361 |
+
#: includes/class-gdpr-help.php:39
|
362 |
+
msgid "Users may request to have their data rectified. They can place a request somewhere on your site and those requests will show up here."
|
363 |
+
msgstr ""
|
364 |
+
|
365 |
+
#: includes/class-gdpr-help.php:40
|
366 |
+
msgid "When you complete the request, mark it as resolved and the requester will get a notification email confirming that their request was resolved."
|
367 |
+
msgstr ""
|
368 |
+
|
369 |
+
#: includes/class-gdpr-help.php:47, includes/class-gdpr-help.php:52, admin/partials/requests.php:89
|
370 |
+
msgid "Complaints"
|
371 |
+
msgstr ""
|
372 |
+
|
373 |
+
#: includes/class-gdpr-help.php:48
|
374 |
+
msgid "Users may complain about something that happened. They can place a complaint somewhere on your site and those complaints will show up here."
|
375 |
+
msgstr ""
|
376 |
+
|
377 |
+
#: includes/class-gdpr-help.php:49
|
378 |
+
msgid "When you resolve the problem, mark it as resolved and the requester will get a notification email confirming that his complaint was resolved."
|
379 |
+
msgstr ""
|
380 |
+
|
381 |
+
#: includes/class-gdpr-help.php:57
|
382 |
+
msgid "Users may request to be deleted from the site. If they don't have any content published on the site (including comments) they will be removed from the site automatically. Otherwise, they will show up at this review table where you can reassign or delete their published content and anonymize his comments."
|
383 |
+
msgstr ""
|
384 |
+
|
385 |
+
#: includes/class-gdpr-help.php:58
|
386 |
+
msgid "When you are ready to delete the user, they will get a notification that their account has been closed. According to GDPR, you have 30 days to fulfill this request. On some occasions, you can ask to extend this time."
|
387 |
+
msgstr ""
|
388 |
+
|
389 |
+
#: includes/class-gdpr-help.php:61
|
390 |
+
msgid "Erasures"
|
391 |
+
msgstr ""
|
392 |
+
|
393 |
+
#: includes/class-gdpr-help.php:74
|
394 |
+
msgid "We added tools to make your life easier when you need to perform administrative tasks like notify all your users of a possible data breach."
|
395 |
+
msgstr ""
|
396 |
+
|
397 |
+
#: includes/class-gdpr-help.php:82
|
398 |
+
msgid "Use this page to look for all known data about a user. You can look it up using the user's email address and are able to download it in XML and JSON formats."
|
399 |
+
msgstr ""
|
400 |
+
|
401 |
+
#: includes/class-gdpr-help.php:89
|
402 |
+
msgid "Data Breach Notification"
|
403 |
+
msgstr ""
|
404 |
+
|
405 |
+
#: includes/class-gdpr-help.php:90
|
406 |
+
msgid "Use this carefully."
|
407 |
+
msgstr ""
|
408 |
+
|
409 |
+
#: includes/class-gdpr-help.php:91
|
410 |
+
msgid "This will send a mass email to all your users with the information provided on these fields. This email is throttled based on the hourly limit set on the plugin settings page. "
|
411 |
+
msgstr ""
|
412 |
+
|
413 |
+
#: includes/class-gdpr-help.php:92
|
414 |
+
msgid "Only use this tool if you believe your site has been compromised and that your user's personal data might have been leaked."
|
415 |
+
msgstr ""
|
416 |
+
|
417 |
+
#: includes/class-gdpr-help.php:100
|
418 |
+
msgid "We do not log any of the user's personal data."
|
419 |
+
msgstr ""
|
420 |
+
|
421 |
+
#: includes/class-gdpr-help.php:101
|
422 |
+
msgid "All logs are encrypted before saving to the database. An encrypted log file is created whenever a user gets removed from the site."
|
423 |
+
msgstr ""
|
424 |
+
|
425 |
+
#: includes/class-gdpr-help.php:102
|
426 |
+
msgid "This tool will keep a record of some actions such as changing consent preferences, placing a request, data breach notifications received, etc…"
|
427 |
+
msgstr ""
|
428 |
+
|
429 |
+
#: includes/class-gdpr-help.php:103
|
430 |
+
msgid "The only way to read the logs is to search for the user email. If the data subject is not a registered site user anymore, you need to ask for the 6 digit token that was provided during deletion. That will allow this tool to look for a log file with his information."
|
431 |
+
msgstr ""
|
432 |
+
|
433 |
+
#: includes/class-gdpr-help.php:118, includes/class-gdpr-help.php:123
|
434 |
+
msgid "General Settings"
|
435 |
+
msgstr ""
|
436 |
+
|
437 |
+
#: includes/class-gdpr-help.php:119
|
438 |
+
msgid "This plugin needs to know your privacy policy page to track updates to it and ask users to re-consent to your new terms."
|
439 |
+
msgstr ""
|
440 |
+
|
441 |
+
#: includes/class-gdpr-help.php:120
|
442 |
+
msgid "When sending a data breach notification to your users, we need to throttle the emails because of server limitations. This is an hourly limit. Check with your hosting provider before changing this value."
|
443 |
+
msgstr ""
|
444 |
+
|
445 |
+
#: includes/class-gdpr-help.php:127, includes/class-gdpr-help.php:140
|
446 |
+
msgid "Cookie Management"
|
447 |
+
msgstr ""
|
448 |
+
|
449 |
+
#: includes/class-gdpr-help.php:128
|
450 |
+
msgid "Fill out every information you can about the cookies your site uses. Set the cookies that you set under Cookies Used and cookies used and set by third parties under the hosts section."
|
451 |
+
msgstr ""
|
452 |
+
|
453 |
+
#: includes/class-gdpr-help.php:130
|
454 |
+
msgid "You must ask your developer to wrap the code that sets the cookies with our helper function %s."
|
455 |
+
msgstr ""
|
456 |
+
|
457 |
+
#: includes/class-gdpr-help.php:131
|
458 |
+
msgid "Some services like Google Analytics provide a way to opt out from their code with an extra parameter to their snippet."
|
459 |
+
msgstr ""
|
460 |
+
|
461 |
+
#: includes/class-gdpr-help.php:132, includes/class-gdpr-help.php:149
|
462 |
+
msgid "External Links"
|
463 |
+
msgstr ""
|
464 |
+
|
465 |
+
#: includes/class-gdpr-help.php:134, includes/class-gdpr-help.php:134
|
466 |
+
msgid "WordPress cookies"
|
467 |
+
msgstr ""
|
468 |
+
|
469 |
+
#: includes/class-gdpr-help.php:144
|
470 |
+
msgid "Consent Management ( Coming Soon )"
|
471 |
+
msgstr ""
|
472 |
+
|
473 |
+
#: includes/class-gdpr-help.php:145
|
474 |
+
msgid "All consents are disabled by default. On first registration, your users will need to consent to your privacy policy. Depending on your privacy policy you should register multiple types of consent on this page and allow them to be toggled on/off."
|
475 |
+
msgstr ""
|
476 |
+
|
477 |
+
#: includes/class-gdpr-help.php:147
|
478 |
+
msgid "If you have an optional consent type, you must have a developer wrap the functionality in our helper function %s."
|
479 |
+
msgstr ""
|
480 |
+
|
481 |
+
#: includes/class-gdpr-help.php:148
|
482 |
+
msgid "i.e."
|
483 |
+
msgstr ""
|
484 |
+
|
485 |
+
#: includes/class-gdpr-help.php:148
|
486 |
+
msgid "You registered email marketing as an optional consent but the user did not actively opt into it on their profile page. You should have your email capture form wrapped in our helper function to block registration or better yet, not even display the email capture form. Same goes for blocking adding the user to your mailing system on registration if consent is not given."
|
487 |
+
msgstr ""
|
488 |
+
|
489 |
+
#: includes/class-gdpr-help.php:151, includes/class-gdpr-help.php:151
|
490 |
+
msgid "Article 7 - Conditions for consent"
|
491 |
+
msgstr ""
|
492 |
+
|
493 |
+
#: includes/class-gdpr-help.php:152, includes/class-gdpr-help.php:152
|
494 |
+
msgid "Article 8 - conditions applicable to child's consent in relation to information society services"
|
495 |
+
msgstr ""
|
496 |
+
|
497 |
+
#: includes/class-gdpr-help.php:153, includes/class-gdpr-help.php:153
|
498 |
+
msgid "Recital 42 - Burden of proof and requirements for consent"
|
499 |
+
msgstr ""
|
500 |
+
|
501 |
+
#: includes/class-gdpr-help.php:154, includes/class-gdpr-help.php:154
|
502 |
+
msgid "Recital 43 - Freely Given consent"
|
503 |
+
msgstr ""
|
504 |
+
|
505 |
+
#: includes/class-gdpr-help.php:178
|
506 |
+
msgid "This is all data that are being sent outside of your site. WordPress send some data to it's servers to be able to do automatic updates. You can reduce the amount of data being sent using filters."
|
507 |
+
msgstr ""
|
508 |
+
|
509 |
+
#: includes/class-gdpr-help.php:179
|
510 |
+
msgid "Some plugins also capture data and send it to their servers. Such practice is not allowed for plugins hosted on wordpress.org plugin repository. In case this is a Premium plugin, you should have been given the option to choose which type of data you want to send."
|
511 |
+
msgstr ""
|
512 |
+
|
513 |
+
#: includes/class-gdpr-help.php:180
|
514 |
+
msgid "Use this tool to identify plugins or themes sending potential personal data outside of your server and take action if necessary."
|
515 |
+
msgstr ""
|
516 |
+
|
517 |
+
#: includes/class-gdpr-requests.php:214
|
518 |
+
msgid "User request expired. Removing %s user_meta."
|
519 |
+
msgstr ""
|
520 |
+
|
521 |
+
#: includes/class-gdpr.php:299
|
522 |
+
msgid "User registered to the site."
|
523 |
+
msgstr ""
|
524 |
+
|
525 |
+
#. translators: Name of consent
|
526 |
+
#: includes/class-gdpr.php:306
|
527 |
+
msgid "User gave explicit consent to %s"
|
528 |
+
msgstr ""
|
529 |
+
|
530 |
+
#: includes/helper-functions.php:26, public/partials/privacy-bar.php:23
|
531 |
+
msgid "Privacy Preferences"
|
532 |
+
msgstr ""
|
533 |
+
|
534 |
+
#: public/class-gdpr-public.php:124
|
535 |
+
msgid "Aborting"
|
536 |
+
msgstr ""
|
537 |
+
|
538 |
+
#: public/class-gdpr-public.php:138
|
539 |
+
msgid "I Agree"
|
540 |
+
msgstr ""
|
541 |
+
|
542 |
+
#: public/class-gdpr-public.php:193
|
543 |
+
msgid "You need to at least consent to our Privacy Policy."
|
544 |
+
msgstr ""
|
545 |
+
|
546 |
+
#: public/class-gdpr-public.php:230
|
547 |
+
msgid "User updated their privacy preferences. These are the new approved cookies and consent preferences:"
|
548 |
+
msgstr ""
|
549 |
+
|
550 |
+
#: public/class-gdpr-public.php:305
|
551 |
+
msgid "User consented to the Privacy Policies."
|
552 |
+
msgstr ""
|
553 |
+
|
554 |
+
#: public/class-gdpr-requests-public.php:77
|
555 |
+
msgid "Invalid type of request. Please try again."
|
556 |
+
msgstr ""
|
557 |
+
|
558 |
+
#: public/class-gdpr-requests-public.php:91, public/class-gdpr-requests-public.php:104
|
559 |
+
msgid "Please verify that you are not a robot."
|
560 |
+
msgstr ""
|
561 |
+
|
562 |
+
#: public/class-gdpr-requests-public.php:308
|
563 |
+
msgid "User confirmed a request to be deleted."
|
564 |
+
msgstr ""
|
565 |
+
|
566 |
+
#: public/class-gdpr-requests-public.php:310
|
567 |
+
msgid "Content was found for that user."
|
568 |
+
msgstr ""
|
569 |
+
|
570 |
+
#: public/class-gdpr-requests-public.php:312
|
571 |
+
msgid "User added to the erasure review table."
|
572 |
+
msgstr ""
|
573 |
+
|
574 |
+
#: public/class-gdpr-requests-public.php:346
|
575 |
+
msgid "User placed a request for rectification or a complaint."
|
576 |
+
msgstr ""
|
577 |
+
|
578 |
+
#. translators: File format. Can be XML or JSON
|
579 |
+
#: public/class-gdpr-requests-public.php:363
|
580 |
+
msgid "User downloaded all their data in %s format."
|
581 |
+
msgstr ""
|
582 |
+
|
583 |
+
#: admin/partials/requests.php:36, admin/partials/requests.php:79, admin/partials/requests.php:93, admin/partials/requests.php:136, admin/partials/requests.php:163, admin/partials/requests.php:313
|
584 |
+
msgid "Email"
|
585 |
+
msgstr ""
|
586 |
+
|
587 |
+
#: admin/partials/requests.php:37, admin/partials/requests.php:80, admin/partials/requests.php:164, admin/partials/requests.php:314
|
588 |
+
msgid "Date of Request"
|
589 |
+
msgstr ""
|
590 |
+
|
591 |
+
#: admin/partials/requests.php:38, admin/partials/requests.php:81, admin/partials/requests.php:95, admin/partials/requests.php:138
|
592 |
+
msgid "Information"
|
593 |
+
msgstr ""
|
594 |
+
|
595 |
+
#: admin/partials/requests.php:39, admin/partials/requests.php:82, admin/partials/requests.php:96, admin/partials/requests.php:139, admin/partials/requests.php:166, admin/partials/requests.php:316
|
596 |
+
msgid "Actions"
|
597 |
+
msgstr ""
|
598 |
+
|
599 |
+
#: admin/partials/requests.php:56, admin/partials/requests.php:113, admin/partials/requests.php:197
|
600 |
+
msgid "Cancel Request"
|
601 |
+
msgstr ""
|
602 |
+
|
603 |
+
#: admin/partials/requests.php:64, admin/partials/requests.php:121
|
604 |
+
msgid "Mark as Resolved"
|
605 |
+
msgstr ""
|
606 |
+
|
607 |
+
#: admin/partials/requests.php:72, admin/partials/requests.php:129, admin/partials/requests.php:306
|
608 |
+
msgid "No pending requests"
|
609 |
+
msgstr ""
|
610 |
+
|
611 |
+
#: admin/partials/requests.php:94, admin/partials/requests.php:137
|
612 |
+
msgid "Date of Complaint"
|
613 |
+
msgstr ""
|
614 |
+
|
615 |
+
#: admin/partials/requests.php:146
|
616 |
+
msgid "Right to erasure"
|
617 |
+
msgstr ""
|
618 |
+
|
619 |
+
#: admin/partials/requests.php:153
|
620 |
+
msgid "Manually add a user"
|
621 |
+
msgstr ""
|
622 |
+
|
623 |
+
#: admin/partials/requests.php:155, admin/partials/tools.php:63, admin/partials/tools.php:125
|
624 |
+
msgid "email@domain.com"
|
625 |
+
msgstr ""
|
626 |
+
|
627 |
+
#: admin/partials/requests.php:156, public/partials/complaint-form.php:11, public/partials/rectify-form.php:10
|
628 |
+
msgid "Submit"
|
629 |
+
msgstr ""
|
630 |
+
|
631 |
+
#: admin/partials/requests.php:165, admin/partials/requests.php:180, admin/partials/requests.php:217, admin/partials/requests.php:315
|
632 |
+
msgid "Review"
|
633 |
+
msgstr ""
|
634 |
+
|
635 |
+
#: admin/partials/requests.php:182
|
636 |
+
msgid "No content to review"
|
637 |
+
msgstr ""
|
638 |
+
|
639 |
+
#: admin/partials/requests.php:204
|
640 |
+
msgid "Delete User"
|
641 |
+
msgstr ""
|
642 |
+
|
643 |
+
#: admin/partials/requests.php:215
|
644 |
+
msgid "Content Type"
|
645 |
+
msgstr ""
|
646 |
+
|
647 |
+
#: admin/partials/requests.php:216
|
648 |
+
msgid "Count"
|
649 |
+
msgstr ""
|
650 |
+
|
651 |
+
#: admin/partials/requests.php:218, admin/partials/requests.php:257
|
652 |
+
msgid "Reassign"
|
653 |
+
msgstr ""
|
654 |
+
|
655 |
+
#: admin/partials/requests.php:219
|
656 |
+
msgid "Action"
|
657 |
+
msgstr ""
|
658 |
+
|
659 |
+
#: admin/partials/requests.php:259, admin/partials/requests.php:286
|
660 |
+
msgid "Resolved"
|
661 |
+
msgstr ""
|
662 |
+
|
663 |
+
#: admin/partials/requests.php:277
|
664 |
+
msgid "View Comments"
|
665 |
+
msgstr ""
|
666 |
+
|
667 |
+
#: admin/partials/requests.php:284
|
668 |
+
msgid "Anonymize"
|
669 |
+
msgstr ""
|
670 |
+
|
671 |
+
#: admin/partials/settings.php:23
|
672 |
+
msgid "Privacy Policy Page"
|
673 |
+
msgstr ""
|
674 |
+
|
675 |
+
#: admin/partials/settings.php:30
|
676 |
+
msgid "-- Select --"
|
677 |
+
msgstr ""
|
678 |
+
|
679 |
+
#: admin/partials/settings.php:39
|
680 |
+
msgid "Outgoing email limitation"
|
681 |
+
msgstr ""
|
682 |
+
|
683 |
+
#: admin/partials/settings.php:48
|
684 |
+
msgid "User deletion"
|
685 |
+
msgstr ""
|
686 |
+
|
687 |
+
#: admin/partials/settings.php:52
|
688 |
+
msgid "Send all deletion requests to the review table."
|
689 |
+
msgstr ""
|
690 |
+
|
691 |
+
#: admin/partials/settings.php:57
|
692 |
+
msgid "Disable CSS"
|
693 |
+
msgstr ""
|
694 |
+
|
695 |
+
#: admin/partials/settings.php:61
|
696 |
+
msgid "Make sure you know what you are doing before checking this."
|
697 |
+
msgstr ""
|
698 |
+
|
699 |
+
#: admin/partials/settings.php:66
|
700 |
+
msgid "Enable the Telemetry Tracker"
|
701 |
+
msgstr ""
|
702 |
+
|
703 |
+
#: admin/partials/settings.php:70
|
704 |
+
msgid "Toggles the Telemetry Tracker On/Off. (experimental)"
|
705 |
+
msgstr ""
|
706 |
+
|
707 |
+
#: admin/partials/settings.php:75
|
708 |
+
msgid "Privacy Center"
|
709 |
+
msgstr ""
|
710 |
+
|
711 |
+
#: admin/partials/settings.php:77
|
712 |
+
msgid "This section handles the privacy bar and some of the privacy preferences window."
|
713 |
+
msgstr ""
|
714 |
+
|
715 |
+
#: admin/partials/settings.php:78
|
716 |
+
msgid "Important:"
|
717 |
+
msgstr ""
|
718 |
+
|
719 |
+
#: admin/partials/settings.php:78
|
720 |
+
msgid "If the privacy banner text is not filled out, the privacy banner will not show up. Even if you registered your cookies."
|
721 |
+
msgstr ""
|
722 |
+
|
723 |
+
#: admin/partials/settings.php:83
|
724 |
+
msgid "Privacy Banner Text"
|
725 |
+
msgstr ""
|
726 |
+
|
727 |
+
#: admin/partials/settings.php:92
|
728 |
+
msgid "Privacy Excerpt"
|
729 |
+
msgstr ""
|
730 |
+
|
731 |
+
#: admin/partials/settings.php:97
|
732 |
+
msgid "This will appear in the consent section of the privacy preference window."
|
733 |
+
msgstr ""
|
734 |
+
|
735 |
+
#: admin/partials/settings.php:102
|
736 |
+
msgid "Request Forms reCAPTCHA"
|
737 |
+
msgstr ""
|
738 |
+
|
739 |
+
#: admin/partials/settings.php:103
|
740 |
+
msgid "To prevent spam attacks, you have the option to enable reCAPTCHA. Configure below your keys to make it work with our request forms."
|
741 |
+
msgstr ""
|
742 |
+
|
743 |
+
#: admin/partials/settings.php:107
|
744 |
+
msgid "You can find the necessary information %s."
|
745 |
+
msgstr ""
|
746 |
+
|
747 |
+
#: admin/partials/settings.php:108
|
748 |
+
msgid "here"
|
749 |
+
msgstr ""
|
750 |
+
|
751 |
+
#: admin/partials/settings.php:114
|
752 |
+
msgid "Enable reCAPTCHA"
|
753 |
+
msgstr ""
|
754 |
+
|
755 |
+
#: admin/partials/settings.php:123
|
756 |
+
msgid "Site Key"
|
757 |
+
msgstr ""
|
758 |
+
|
759 |
+
#: admin/partials/settings.php:132
|
760 |
+
msgid "Secret Key"
|
761 |
+
msgstr ""
|
762 |
+
|
763 |
+
#: admin/partials/settings.php:142
|
764 |
+
msgid "WooCommerce"
|
765 |
+
msgstr ""
|
766 |
+
|
767 |
+
#: admin/partials/settings.php:147
|
768 |
+
msgid "Add consent checkboxes to the registration page"
|
769 |
+
msgstr ""
|
770 |
+
|
771 |
+
#: admin/partials/settings.php:156
|
772 |
+
msgid "Add consent checkboxes to the checkout registration form"
|
773 |
+
msgstr ""
|
774 |
+
|
775 |
+
#: admin/partials/settings.php:169
|
776 |
+
msgid "Category name"
|
777 |
+
msgstr ""
|
778 |
+
|
779 |
+
#: admin/partials/settings.php:170
|
780 |
+
msgid "Add tab"
|
781 |
+
msgstr ""
|
782 |
+
|
783 |
+
#: admin/partials/settings.php:176, admin/partials/templates/tmpl-cookies.php:3
|
784 |
+
msgid "Remove this tab."
|
785 |
+
msgstr ""
|
786 |
+
|
787 |
+
#: admin/partials/settings.php:181, admin/partials/templates/tmpl-cookies.php:8
|
788 |
+
msgid "Always active"
|
789 |
+
msgstr ""
|
790 |
+
|
791 |
+
#: admin/partials/settings.php:190, admin/partials/templates/tmpl-cookies.php:17
|
792 |
+
msgid "How we use"
|
793 |
+
msgstr ""
|
794 |
+
|
795 |
+
#: admin/partials/settings.php:194, admin/partials/templates/tmpl-cookies.php:21
|
796 |
+
msgid "Cookies used by the site"
|
797 |
+
msgstr ""
|
798 |
+
|
799 |
+
#: admin/partials/settings.php:198, admin/partials/settings.php:224, admin/partials/templates/tmpl-cookies.php:25, admin/partials/templates/tmpl-cookies.php:57
|
800 |
+
msgid "Comma separated list."
|
801 |
+
msgstr ""
|
802 |
+
|
803 |
+
#: admin/partials/settings.php:202
|
804 |
+
msgid "Third party domains"
|
805 |
+
msgstr ""
|
806 |
+
|
807 |
+
#: admin/partials/settings.php:205, admin/partials/templates/tmpl-cookies.php:32
|
808 |
+
msgid "Add"
|
809 |
+
msgstr ""
|
810 |
+
|
811 |
+
#: admin/partials/settings.php:207
|
812 |
+
msgid "Cookies that are set by a third party, like facebook.com."
|
813 |
+
msgstr ""
|
814 |
+
|
815 |
+
#: admin/partials/settings.php:215, admin/partials/templates/tmpl-cookies.php:48
|
816 |
+
msgid "Remove this domain."
|
817 |
+
msgstr ""
|
818 |
+
|
819 |
+
#: admin/partials/settings.php:220, admin/partials/templates/tmpl-cookies.php:53
|
820 |
+
msgid "Cookies used"
|
821 |
+
msgstr ""
|
822 |
+
|
823 |
+
#: admin/partials/settings.php:228, admin/partials/templates/tmpl-cookies.php:61
|
824 |
+
msgid "How to Opt Out"
|
825 |
+
msgstr ""
|
826 |
+
|
827 |
+
#: admin/partials/settings.php:232, admin/partials/templates/tmpl-cookies.php:65
|
828 |
+
msgid "Url with instructions on how to opt out."
|
829 |
+
msgstr ""
|
830 |
+
|
831 |
+
#: admin/partials/settings.php:249
|
832 |
+
msgid "Type of consent"
|
833 |
+
msgstr ""
|
834 |
+
|
835 |
+
#: admin/partials/settings.php:250
|
836 |
+
msgid "Add consent"
|
837 |
+
msgstr ""
|
838 |
+
|
839 |
+
#: admin/partials/settings.php:257, admin/partials/settings.php:258
|
840 |
+
msgid "You read and agreed to our %s."
|
841 |
+
msgstr ""
|
842 |
+
|
843 |
+
#: admin/partials/settings.php:265, admin/partials/templates/tmpl-consents.php:3
|
844 |
+
msgid "Unregister this consent."
|
845 |
+
msgstr ""
|
846 |
+
|
847 |
+
#: admin/partials/settings.php:270, admin/partials/settings.php:273, public/partials/privacy-preferences-modal.php:57, admin/partials/templates/tmpl-consents.php:9
|
848 |
+
msgid "Required"
|
849 |
+
msgstr ""
|
850 |
+
|
851 |
+
#: admin/partials/settings.php:284, admin/partials/templates/tmpl-consents.php:18
|
852 |
+
msgid "Consent description"
|
853 |
+
msgstr ""
|
854 |
+
|
855 |
+
#: admin/partials/settings.php:288, admin/partials/templates/tmpl-consents.php:22
|
856 |
+
msgid "Registration message"
|
857 |
+
msgstr ""
|
858 |
+
|
859 |
+
#: admin/partials/settings.php:299, admin/partials/settings.php:304
|
860 |
+
msgid "Data Export Chanel"
|
861 |
+
msgstr ""
|
862 |
+
|
863 |
+
#: admin/partials/settings.php:310
|
864 |
+
msgid "Data Export with email attachment"
|
865 |
+
msgstr ""
|
866 |
+
|
867 |
+
#: admin/partials/settings.php:311
|
868 |
+
msgid "Data Export with download link"
|
869 |
+
msgstr ""
|
870 |
+
|
871 |
+
#: admin/partials/tools.php:32
|
872 |
+
msgid "Data Breach confirmed. Preparing bulk emails."
|
873 |
+
msgstr ""
|
874 |
+
|
875 |
+
#: admin/partials/tools.php:61, admin/partials/tools.php:123
|
876 |
+
msgid "Search by email"
|
877 |
+
msgstr ""
|
878 |
+
|
879 |
+
#: admin/partials/tools.php:64, admin/partials/tools.php:127
|
880 |
+
msgid "Search"
|
881 |
+
msgstr ""
|
882 |
+
|
883 |
+
#: admin/partials/tools.php:78
|
884 |
+
msgid "Email content"
|
885 |
+
msgstr ""
|
886 |
+
|
887 |
+
#: admin/partials/tools.php:81
|
888 |
+
msgid "The content that the end user will see before the below information."
|
889 |
+
msgstr ""
|
890 |
+
|
891 |
+
#: admin/partials/tools.php:85
|
892 |
+
msgid "Nature of the personal data breach"
|
893 |
+
msgstr ""
|
894 |
+
|
895 |
+
#: admin/partials/tools.php:88
|
896 |
+
msgid "Describe the nature of the personal data breach including where possible, the categories and approximate number of data subjects concerned and the categories and approximate number of personal data records concerned."
|
897 |
+
msgstr ""
|
898 |
+
|
899 |
+
#: admin/partials/tools.php:92
|
900 |
+
msgid "Name and contact details of the data protection officer"
|
901 |
+
msgstr ""
|
902 |
+
|
903 |
+
#: admin/partials/tools.php:95
|
904 |
+
msgid "Communicate the name and contact details of the data protection officer or other contact point where more information can be obtained."
|
905 |
+
msgstr ""
|
906 |
+
|
907 |
+
#: admin/partials/tools.php:99
|
908 |
+
msgid "Likely consequences of the personal data breach"
|
909 |
+
msgstr ""
|
910 |
+
|
911 |
+
#: admin/partials/tools.php:105
|
912 |
+
msgid "Measures taken or proposed to be taken"
|
913 |
+
msgstr ""
|
914 |
+
|
915 |
+
#: admin/partials/tools.php:108
|
916 |
+
msgid "Describe the measures taken or proposed to be taken by the controller to address the personal data breach, including, where appropriate, measures to mitigate its possible adverse effects."
|
917 |
+
msgstr ""
|
918 |
+
|
919 |
+
#: admin/partials/tools.php:112
|
920 |
+
msgid "Send confirmation email"
|
921 |
+
msgstr ""
|
922 |
+
|
923 |
+
#: admin/partials/tools.php:126
|
924 |
+
msgid "6 digit token (optional)"
|
925 |
+
msgstr ""
|
926 |
+
|
927 |
+
#: public/partials/confirmation-screens.php:18
|
928 |
+
msgid "Close your account?"
|
929 |
+
msgstr ""
|
930 |
+
|
931 |
+
#: public/partials/confirmation-screens.php:23
|
932 |
+
msgid "Your account will be closed and all data will be permanently deleted and cannot be recovered. Are you sure?"
|
933 |
+
msgstr ""
|
934 |
+
|
935 |
+
#: public/partials/confirmation-screens.php:27, public/partials/reconsent-modal.php:31
|
936 |
+
msgid "Cancel"
|
937 |
+
msgstr ""
|
938 |
+
|
939 |
+
#: public/partials/confirmation-screens.php:34
|
940 |
+
msgid "Error!"
|
941 |
+
msgstr ""
|
942 |
+
|
943 |
+
#: public/partials/confirmation-screens.php:36
|
944 |
+
msgid "Your account"
|
945 |
+
msgstr ""
|
946 |
+
|
947 |
+
#: public/partials/confirmation-screens.php:38
|
948 |
+
msgid "Your account has been closed. We are sorry to see you go."
|
949 |
+
msgstr ""
|
950 |
+
|
951 |
+
#: public/partials/confirmation-screens.php:40
|
952 |
+
msgid "Your request has been received and is being reviewed. You will receive an email when we are done."
|
953 |
+
msgstr ""
|
954 |
+
|
955 |
+
#: public/partials/confirmation-screens.php:44
|
956 |
+
msgid "Email confirmation"
|
957 |
+
msgstr ""
|
958 |
+
|
959 |
+
#: public/partials/confirmation-screens.php:45
|
960 |
+
msgid "We've sent you a confirmation email."
|
961 |
+
msgstr ""
|
962 |
+
|
963 |
+
#: public/partials/confirmation-screens.php:51
|
964 |
+
msgid "We can't delete this user."
|
965 |
+
msgstr ""
|
966 |
+
|
967 |
+
#: public/partials/confirmation-screens.php:54
|
968 |
+
msgid "Required information is missing from the form."
|
969 |
+
msgstr ""
|
970 |
+
|
971 |
+
#: public/partials/confirmation-screens.php:57
|
972 |
+
msgid "Request Received"
|
973 |
+
msgstr ""
|
974 |
+
|
975 |
+
#: public/partials/confirmation-screens.php:58
|
976 |
+
msgid "Your request has been received. We will be in touch soon."
|
977 |
+
msgstr ""
|
978 |
+
|
979 |
+
#: public/partials/confirmation-screens.php:61
|
980 |
+
msgid "There was a problem with your request. Please try again later."
|
981 |
+
msgstr ""
|
982 |
+
|
983 |
+
#: public/partials/delete-form.php:22
|
984 |
+
msgid "Close my account"
|
985 |
+
msgstr ""
|
986 |
+
|
987 |
+
#: public/partials/export-data-form.php:9
|
988 |
+
msgid "Download my data"
|
989 |
+
msgstr ""
|
990 |
+
|
991 |
+
#: public/partials/privacy-preferences-modal.php:22
|
992 |
+
msgid "Privacy Preference Center"
|
993 |
+
msgstr ""
|
994 |
+
|
995 |
+
#: public/partials/privacy-preferences-modal.php:27
|
996 |
+
msgid "Options"
|
997 |
+
msgstr ""
|
998 |
+
|
999 |
+
#: public/partials/privacy-preferences-modal.php:34
|
1000 |
+
msgid "Cookie Settings"
|
1001 |
+
msgstr ""
|
1002 |
+
|
1003 |
+
#: public/partials/privacy-preferences-modal.php:84
|
1004 |
+
msgid "Cookies Used"
|
1005 |
+
msgstr ""
|
1006 |
+
|
1007 |
+
#: public/partials/privacy-preferences-modal.php:101
|
1008 |
+
msgid "Always Active"
|
1009 |
+
msgstr ""
|
1010 |
+
|
1011 |
+
#: public/partials/privacy-preferences-modal.php:120
|
1012 |
+
msgid "Opt Out"
|
1013 |
+
msgstr ""
|
1014 |
+
|
1015 |
+
#: public/partials/privacy-preferences-modal.php:135
|
1016 |
+
msgid "Save Preferences"
|
1017 |
+
msgstr ""
|
1018 |
+
|
1019 |
+
#: public/partials/privacy-preferences-modal.php:137
|
1020 |
+
msgid "More Information"
|
1021 |
+
msgstr ""
|
1022 |
+
|
1023 |
+
#: public/partials/reconsent-modal.php:3
|
1024 |
+
msgid "Our Privacy Policy has been updated."
|
1025 |
+
msgstr ""
|
1026 |
+
|
1027 |
+
#: public/partials/reconsent-modal.php:4
|
1028 |
+
msgid "To continue using the site you need to read the revised version and agree to the terms."
|
1029 |
+
msgstr ""
|
1030 |
+
|
1031 |
+
#: public/partials/reconsent-modal.php:9
|
1032 |
+
msgid "Agree"
|
1033 |
+
msgstr ""
|
1034 |
+
|
1035 |
+
#: public/partials/reconsent-modal.php:10
|
1036 |
+
msgid "Disagree"
|
1037 |
+
msgstr ""
|
1038 |
+
|
1039 |
+
#: public/partials/reconsent-modal.php:13
|
1040 |
+
msgid "Updating"
|
1041 |
+
msgstr ""
|
1042 |
+
|
1043 |
+
#: public/partials/reconsent-modal.php:22
|
1044 |
+
msgid "Are you sure?"
|
1045 |
+
msgstr ""
|
1046 |
+
|
1047 |
+
#: public/partials/reconsent-modal.php:27
|
1048 |
+
msgid "By disagreeing you will no longer have access to our site and will be logged out."
|
1049 |
+
msgstr ""
|
1050 |
+
|
1051 |
+
#: public/partials/reconsent-modal.php:30
|
1052 |
+
msgid "Continue"
|
1053 |
+
msgstr ""
|
1054 |
+
|
1055 |
+
#: templates/email/complaint-request.php:4
|
1056 |
+
msgid ""
|
1057 |
+
"Someone placed a complaint on your behalf on our site.\n"
|
1058 |
+
"By clicking confirm a request will be made and we will do our best to fulfil it.\n"
|
1059 |
+
"\n"
|
1060 |
+
"--------------------------------------------------------\n"
|
1061 |
+
"Request\n"
|
1062 |
+
"--------------------------------------------------------\n"
|
1063 |
+
"%s\n"
|
1064 |
+
"\n"
|
1065 |
+
"\n"
|
1066 |
+
"\n"
|
1067 |
+
"\n"
|
1068 |
+
"To confirm this request, click here: %s\n"
|
1069 |
+
"\n"
|
1070 |
+
"\n"
|
1071 |
+
"\n"
|
1072 |
+
"---------------------------------------------------------------------------------\n"
|
1073 |
+
"If that wasn't you, reset your password: %s\n"
|
1074 |
+
""
|
1075 |
+
msgstr ""
|
1076 |
+
|
1077 |
+
#: templates/email/complaint-resolved.php:3
|
1078 |
+
msgid ""
|
1079 |
+
"We resolved your complaint request.\n"
|
1080 |
+
"If you have any problems or questions, don't hesitate to contact us."
|
1081 |
+
msgstr ""
|
1082 |
+
|
1083 |
+
#: templates/email/data-breach-notification.php:4
|
1084 |
+
msgid ""
|
1085 |
+
"%s\n"
|
1086 |
+
"\n"
|
1087 |
+
"--------------------------------------------------------\n"
|
1088 |
+
"Nature of the personal data breach:\n"
|
1089 |
+
"--------------------------------------------------------\n"
|
1090 |
+
"%s\n"
|
1091 |
+
"\n"
|
1092 |
+
"--------------------------------------------------------\n"
|
1093 |
+
"Name and contact details of the data protection officer:\n"
|
1094 |
+
"--------------------------------------------------------\n"
|
1095 |
+
"%s\n"
|
1096 |
+
"\n"
|
1097 |
+
"--------------------------------------------------------\n"
|
1098 |
+
"Likely consequences of the personal data breach:\n"
|
1099 |
+
"--------------------------------------------------------\n"
|
1100 |
+
"%s\n"
|
1101 |
+
"\n"
|
1102 |
+
"--------------------------------------------------------\n"
|
1103 |
+
"Measures taken or proposed to be taken:\n"
|
1104 |
+
"--------------------------------------------------------\n"
|
1105 |
+
"%s\n"
|
1106 |
+
""
|
1107 |
+
msgstr ""
|
1108 |
+
|
1109 |
+
#: templates/email/data-breach-request.php:4
|
1110 |
+
msgid ""
|
1111 |
+
"A request to send a mass email notification to all users regarding a data breach has been made by %s.\n"
|
1112 |
+
"\n"
|
1113 |
+
"--------------------------------------------------------\n"
|
1114 |
+
"Nature of the personal data breach:\n"
|
1115 |
+
"--------------------------------------------------------\n"
|
1116 |
+
"%s\n"
|
1117 |
+
"\n"
|
1118 |
+
"--------------------------------------------------------\n"
|
1119 |
+
"Name and contact details of the data protection officer:\n"
|
1120 |
+
"--------------------------------------------------------\n"
|
1121 |
+
"%s\n"
|
1122 |
+
"\n"
|
1123 |
+
"--------------------------------------------------------\n"
|
1124 |
+
"Likely consequences of the personal data breach:\n"
|
1125 |
+
"--------------------------------------------------------\n"
|
1126 |
+
"%s\n"
|
1127 |
+
"\n"
|
1128 |
+
"--------------------------------------------------------\n"
|
1129 |
+
"Measures taken or proposed to be taken:\n"
|
1130 |
+
"--------------------------------------------------------\n"
|
1131 |
+
"%s\n"
|
1132 |
+
"\n"
|
1133 |
+
"\n"
|
1134 |
+
"To confirm this request, click here: %s\n"
|
1135 |
+
"\n"
|
1136 |
+
"---------------------------------------------------------------------------------\n"
|
1137 |
+
"If that is not intended, have the person who requested it change their password.\n"
|
1138 |
+
"---------------------------------------------------------------------------------\n"
|
1139 |
+
""
|
1140 |
+
msgstr ""
|
1141 |
+
|
1142 |
+
#: templates/email/delete-request.php:4
|
1143 |
+
msgid ""
|
1144 |
+
"Someone placed a request for your information to be removed from our site.\n"
|
1145 |
+
"By clicking confirm your account will be removed from our site and all data we collected\n"
|
1146 |
+
"over time will be erased from our database. It will be impossible for us to retrieve that\n"
|
1147 |
+
"information in the future.\n"
|
1148 |
+
"\n"
|
1149 |
+
"\n"
|
1150 |
+
"\n"
|
1151 |
+
"To confirm this request, click here: %s\n"
|
1152 |
+
"\n"
|
1153 |
+
"\n"
|
1154 |
+
"\n"
|
1155 |
+
"---------------------------------------------------------------------------------\n"
|
1156 |
+
"If that wasn't you, reset your password: %s\n"
|
1157 |
+
""
|
1158 |
+
msgstr ""
|
1159 |
+
|
1160 |
+
#: templates/email/delete-resolved.php:5
|
1161 |
+
msgid ""
|
1162 |
+
"Your account has been closed.\n"
|
1163 |
+
"\n"
|
1164 |
+
"We no longer hold any information about you.\n"
|
1165 |
+
"If you ever need to make a complaint you can email us and we will try to help you.\n"
|
1166 |
+
"To be able to make a complaint you will be requested to provide your email address and the token below.\n"
|
1167 |
+
"\n"
|
1168 |
+
"%s"
|
1169 |
+
msgstr ""
|
1170 |
+
|
1171 |
+
#: templates/email/export-data-request.php:4
|
1172 |
+
msgid ""
|
1173 |
+
"Someone requested to download your data from our site.\n"
|
1174 |
+
"By clicking confirm we will redirect you back to our site where a download will begin.\n"
|
1175 |
+
"\n"
|
1176 |
+
"To download it in a XML format, click here: %s\n"
|
1177 |
+
"To download it in a JSON format, click here: %s\n"
|
1178 |
+
"\n"
|
1179 |
+
"\n"
|
1180 |
+
"\n"
|
1181 |
+
"---------------------------------------------------------------------------------\n"
|
1182 |
+
"If that wasn't you, reset your password: %s\n"
|
1183 |
+
""
|
1184 |
+
msgstr ""
|
1185 |
+
|
1186 |
+
#: templates/email/new-request.php:5
|
1187 |
+
msgid ""
|
1188 |
+
"There is a new %1$s request waiting for review.\n"
|
1189 |
+
"\n"
|
1190 |
+
"Review your requests: %2$s"
|
1191 |
+
msgstr ""
|
1192 |
+
|
1193 |
+
#: templates/email/rectify-request.php:4
|
1194 |
+
msgid ""
|
1195 |
+
"Someone placed a request for your information to be rectified on our site.\n"
|
1196 |
+
"By clicking confirm a request will be made and we will do our best to fulfil it.\n"
|
1197 |
+
"\n"
|
1198 |
+
"--------------------------------------------------------\n"
|
1199 |
+
"Request\n"
|
1200 |
+
"--------------------------------------------------------\n"
|
1201 |
+
"%s\n"
|
1202 |
+
"\n"
|
1203 |
+
"\n"
|
1204 |
+
"\n"
|
1205 |
+
"\n"
|
1206 |
+
"To confirm this request, click here: %s\n"
|
1207 |
+
"\n"
|
1208 |
+
"\n"
|
1209 |
+
"\n"
|
1210 |
+
"---------------------------------------------------------------------------------\n"
|
1211 |
+
"If that wasn't you, reset your password: %s\n"
|
1212 |
+
""
|
1213 |
+
msgstr ""
|
1214 |
+
|
1215 |
+
#: templates/email/rectify-resolved.php:3
|
1216 |
+
msgid ""
|
1217 |
+
"We resolved your rectification request.\n"
|
1218 |
+
"If you have any problems or questions, don't hesitate to contact us."
|
1219 |
+
msgstr ""
|
1220 |
+
|
1221 |
+
#: admin/partials/templates/tmpl-cookies.php:29
|
1222 |
+
msgid "Third Party Domains"
|
1223 |
+
msgstr ""
|
1224 |
+
|
1225 |
+
#: admin/partials/templates/tmpl-cookies.php:34
|
1226 |
+
msgid "Cookies that are set by a third party, like facebook.com"
|
1227 |
+
msgstr ""
|
1228 |
+
|
1229 |
+
#: admin/partials/templates/tmpl-tools.php:3, admin/partials/templates/tmpl-tools.php:23
|
1230 |
+
msgid "Result"
|
1231 |
+
msgstr ""
|
1232 |
+
|
1233 |
+
#: admin/partials/templates/tmpl-tools.php:14, admin/partials/templates/tmpl-tools.php:44
|
1234 |
+
msgid "Error"
|
1235 |
+
msgstr ""
|
1236 |
+
|
1237 |
+
#: admin/partials/templates/tmpl-tools.php:16
|
1238 |
+
msgid "We could not find a any logs for that email and token combination."
|
1239 |
+
msgstr ""
|
1240 |
+
|
1241 |
+
#: admin/partials/templates/tmpl-tools.php:46
|
1242 |
+
msgid "We could not find a user with that email."
|
1243 |
+
msgstr ""
|
public/class-gdpr-public.php
ADDED
@@ -0,0 +1,359 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* The public-facing functionality of the plugin.
|
5 |
+
*
|
6 |
+
* @link https://trewknowledge.com
|
7 |
+
* @since 1.0.0
|
8 |
+
*
|
9 |
+
* @package GDPR
|
10 |
+
* @subpackage public
|
11 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
12 |
+
*/
|
13 |
+
|
14 |
+
/**
|
15 |
+
* The public-facing functionality of the plugin.
|
16 |
+
*
|
17 |
+
* Defines the plugin name and version.
|
18 |
+
* Enqueue the admin-specific stylesheet and JavaScript.
|
19 |
+
*
|
20 |
+
* @package GDPR
|
21 |
+
* @subpackage public
|
22 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
23 |
+
*/
|
24 |
+
class GDPR_Public {
|
25 |
+
|
26 |
+
/**
|
27 |
+
* The ID of this plugin.
|
28 |
+
*
|
29 |
+
* @since 1.0.0
|
30 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
31 |
+
* @access private
|
32 |
+
* @var string $plugin_name The ID of this plugin.
|
33 |
+
*/
|
34 |
+
private $plugin_name;
|
35 |
+
|
36 |
+
/**
|
37 |
+
* The version of this plugin.
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
41 |
+
* @access private
|
42 |
+
* @var string $version The current version of this plugin.
|
43 |
+
*/
|
44 |
+
private $version;
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Allowed HTML for wp_kses.
|
48 |
+
* @since 1.1.0
|
49 |
+
* @access private
|
50 |
+
* @var array $allowed_html The allowed HTML for wp_kses.
|
51 |
+
*/
|
52 |
+
private $allowed_html;
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Initialize the class and set its properties.
|
56 |
+
*
|
57 |
+
* @since 1.0.0
|
58 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
59 |
+
* @param string $plugin_name The name of the plugin.
|
60 |
+
* @param string $version The version of this plugin.
|
61 |
+
*/
|
62 |
+
public function __construct( $plugin_name, $version ) {
|
63 |
+
$this->plugin_name = $plugin_name;
|
64 |
+
$this->version = $version;
|
65 |
+
$this->allowed_html = array(
|
66 |
+
'a' => array(
|
67 |
+
'href' => true,
|
68 |
+
'title' => true,
|
69 |
+
'target' => true,
|
70 |
+
),
|
71 |
+
);
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Checks if recaptcha is being used and add the code.
|
76 |
+
* Should be called from the request forms.
|
77 |
+
* @since 1.4.0
|
78 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
79 |
+
*/
|
80 |
+
public static function add_recaptcha() {
|
81 |
+
$use_recaptcha = get_option( 'gdpr_use_recaptcha', false );
|
82 |
+
if ( $use_recaptcha ) {
|
83 |
+
$site_key = get_option( 'gdpr_recaptcha_site_key', '' );
|
84 |
+
$secret_key = get_option( 'gdpr_recaptcha_secret_key', '' );
|
85 |
+
|
86 |
+
if ( $site_key && $secret_key ) {
|
87 |
+
echo '<div class="g-recaptcha" data-sitekey="' . $site_key . '"></div>';
|
88 |
+
}
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Register the stylesheets for the public-facing side of the site.
|
94 |
+
*
|
95 |
+
* @since 1.0.0
|
96 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
97 |
+
*/
|
98 |
+
public function enqueue_styles() {
|
99 |
+
$disable_css = get_option( 'gdpr_disable_css', false );
|
100 |
+
if ( ! $disable_css ) {
|
101 |
+
wp_enqueue_style( $this->plugin_name, plugin_dir_url( dirname( __FILE__ ) ) . 'assets/css/gdpr-public.css', array(), $this->version, 'all' );
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Register the JavaScript for the public-facing side of the site.
|
107 |
+
*
|
108 |
+
* @since 1.0.0
|
109 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
110 |
+
*/
|
111 |
+
public function enqueue_scripts() {
|
112 |
+
$use_recaptcha = get_option( 'gdpr_use_recaptcha', false );
|
113 |
+
if ( $use_recaptcha ) {
|
114 |
+
$site_key = get_option( 'gdpr_recaptcha_site_key', '' );
|
115 |
+
$secret_key = get_option( 'gdpr_recaptcha_secret_key', '' );
|
116 |
+
|
117 |
+
if ( $site_key && $secret_key ) {
|
118 |
+
wp_enqueue_script( $this->plugin_name . '-recaptcha', 'https://www.google.com/recaptcha/api.js' );
|
119 |
+
}
|
120 |
+
}
|
121 |
+
wp_enqueue_script( $this->plugin_name, plugin_dir_url( dirname( __FILE__ ) ) . 'assets/js/gdpr-public.js', array( 'jquery' ), $this->version, false );
|
122 |
+
wp_localize_script( $this->plugin_name, 'GDPR', array(
|
123 |
+
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
124 |
+
'aborting' => esc_html__( 'Aborting', 'gdpr' ),
|
125 |
+
'is_user_logged_in' => is_user_logged_in(),
|
126 |
+
'privacy_page_id' => get_option( 'gdpr_privacy_policy_page', 0 ),
|
127 |
+
) );
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Prints the privacy bar for the end user to save the consent and cookie settings.
|
132 |
+
* @since 1.0.0
|
133 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
134 |
+
*/
|
135 |
+
public function privacy_bar() {
|
136 |
+
$content = get_option( 'gdpr_cookie_banner_content', '' );
|
137 |
+
$tabs = get_option( 'gdpr_cookie_popup_content', array() );
|
138 |
+
$button_text = apply_filters( 'gdpr_privacy_bar_button_text', esc_html__( 'I Agree', 'gdpr' ) );
|
139 |
+
|
140 |
+
if ( empty( $content ) ) {
|
141 |
+
return;
|
142 |
+
}
|
143 |
+
|
144 |
+
include plugin_dir_path( __FILE__ ) . 'partials/privacy-bar.php';
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* The privacy preferences modal.
|
149 |
+
* @since 1.0.0
|
150 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
151 |
+
*/
|
152 |
+
public function privacy_preferences_modal() {
|
153 |
+
$cookie_privacy_excerpt = get_option( 'gdpr_cookie_privacy_excerpt', '' );
|
154 |
+
$consent_types = get_option( 'gdpr_consent_types', array() );
|
155 |
+
$privacy_policy_page = get_option( 'gdpr_privacy_policy_page', 0 );
|
156 |
+
$approved_cookies = isset( $_COOKIE['gdpr']['allowed_cookies'] ) ? json_decode( wp_unslash( $_COOKIE['gdpr']['allowed_cookies'] ) ) : array();
|
157 |
+
$user_consents = isset( $_COOKIE['gdpr']['consent_types'] ) ? json_decode( wp_unslash( $_COOKIE['gdpr']['consent_types'] ) ) : array();
|
158 |
+
$tabs = get_option( 'gdpr_cookie_popup_content', array() );
|
159 |
+
|
160 |
+
include plugin_dir_path( __FILE__ ) . 'partials/privacy-preferences-modal.php';
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* The black overlay for the plugin modals.
|
165 |
+
* @since 1.0.0
|
166 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
167 |
+
*/
|
168 |
+
public function overlay() {
|
169 |
+
echo '<div class="gdpr-overlay"></div>';
|
170 |
+
}
|
171 |
+
|
172 |
+
/**
|
173 |
+
* Prints the confirmation dialogs.
|
174 |
+
* @since 1.0.0
|
175 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
176 |
+
*/
|
177 |
+
public function confirmation_screens() {
|
178 |
+
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/partials/confirmation-screens.php';
|
179 |
+
}
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Update the user allowed cookies and types of consent.
|
183 |
+
* If the user is logged in, we also save consent to user meta.
|
184 |
+
* @since 1.1.0
|
185 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
186 |
+
*/
|
187 |
+
public function update_privacy_preferences() {
|
188 |
+
if ( ! isset( $_POST['update-privacy-preferences-nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['update-privacy-preferences-nonce'] ), 'gdpr-update_privacy_preferences' ) ) {
|
189 |
+
wp_die( esc_html__( 'We could not verify the the security token. Please try again.', 'gdpr' ) );
|
190 |
+
}
|
191 |
+
|
192 |
+
if ( ! isset( $_POST['user_consents'] ) ) {
|
193 |
+
wp_die( esc_html__( "You need to at least consent to our Privacy Policy.", 'gdpr' ) );
|
194 |
+
}
|
195 |
+
|
196 |
+
$consents = array_map( 'sanitize_text_field', (array) $_POST['user_consents'] );
|
197 |
+
$cookies = isset( $_POST['approved_cookies'] ) ? array_map( 'sanitize_text_field', (array) $_POST['approved_cookies'] ) : array();
|
198 |
+
$all_cookies = isset( $_POST['all_cookies'] ) ? array_map( 'sanitize_text_field', (array) json_decode( wp_unslash( $_POST['all_cookies'] ) ) ) : array();
|
199 |
+
|
200 |
+
$approved_cookies = array();
|
201 |
+
if ( ! empty( $cookies ) ) {
|
202 |
+
foreach ( $cookies as $cookieArr ) {
|
203 |
+
$cookieArr = json_decode( wp_unslash( $cookieArr ) );
|
204 |
+
foreach ( $cookieArr as $cookie ) {
|
205 |
+
$approved_cookies[] = $cookie;
|
206 |
+
}
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
$cookies_to_remove = array_diff( $all_cookies, $approved_cookies );
|
211 |
+
|
212 |
+
$cookies_as_json = json_encode( $approved_cookies );
|
213 |
+
$consents_as_json = json_encode( $consents );
|
214 |
+
|
215 |
+
setcookie( "gdpr[allowed_cookies]", $cookies_as_json, time() + YEAR_IN_SECONDS, "/" );
|
216 |
+
setcookie( "gdpr[consent_types]", $consents_as_json, time() + YEAR_IN_SECONDS, "/" );
|
217 |
+
|
218 |
+
foreach ( $cookies_to_remove as $cookie ) {
|
219 |
+
if ( GDPR::similar_in_array( $cookie, array_keys( $_COOKIE ) ) ) {
|
220 |
+
$domain = get_site_url();
|
221 |
+
$domain = wp_parse_url( $domain, PHP_URL_HOST );
|
222 |
+
unset( $_COOKIE[ $cookie ] );
|
223 |
+
setcookie( $cookie, NULL, -1, "/", $domain );
|
224 |
+
setcookie( $cookie, NULL, -1, "/", '.' . $domain );
|
225 |
+
}
|
226 |
+
}
|
227 |
+
|
228 |
+
if ( is_user_logged_in() ) {
|
229 |
+
$user = wp_get_current_user();
|
230 |
+
GDPR_Audit_Log::log( $user->ID, esc_html__( 'User updated their privacy preferences. These are the new approved cookies and consent preferences:', 'gdpr' ) );
|
231 |
+
if ( ! empty( $consents ) ) {
|
232 |
+
delete_user_meta( $user->ID, 'gdpr_consents' );
|
233 |
+
foreach ( $consents as $consent ) {
|
234 |
+
$consent = sanitize_text_field( wp_unslash( $consent ) );
|
235 |
+
add_user_meta( $user->ID, 'gdpr_consents', $consent );
|
236 |
+
GDPR_Audit_Log::log( $user->ID, 'Consent: ' . $consent );
|
237 |
+
}
|
238 |
+
}
|
239 |
+
|
240 |
+
if ( ! empty( $approved_cookies ) ) {
|
241 |
+
foreach ( $approved_cookies as $cookie ) {
|
242 |
+
GDPR_Audit_Log::log( $user->ID, 'Cookie: ' . $cookie );
|
243 |
+
}
|
244 |
+
}
|
245 |
+
|
246 |
+
}
|
247 |
+
|
248 |
+
wp_safe_redirect( esc_url_raw( wp_get_referer() ) );
|
249 |
+
exit;
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* Check if the user did not consent to the privacy policy
|
254 |
+
* @since 1.0.0
|
255 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
256 |
+
* @return bool Whether the user consented or not.
|
257 |
+
*/
|
258 |
+
public function is_consent_needed() {
|
259 |
+
$privacy_policy_page = get_option( 'gdpr_privacy_policy_page' );
|
260 |
+
if ( ! $privacy_policy_page || ! is_user_logged_in() ) {
|
261 |
+
return;
|
262 |
+
}
|
263 |
+
|
264 |
+
$page_obj = get_post( $privacy_policy_page );
|
265 |
+
$user = wp_get_current_user();
|
266 |
+
$user_consents = get_user_meta( $user->ID, 'gdpr_consents' );
|
267 |
+
|
268 |
+
if ( in_array( 'privacy-policy', $user_consents ) ) {
|
269 |
+
return;
|
270 |
+
}
|
271 |
+
|
272 |
+
include plugin_dir_path( __FILE__ ) . 'partials/reconsent-modal.php';
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Log the user out if they does not agree with the privacy policy terms when prompted.
|
277 |
+
* @since 1.0.0
|
278 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
279 |
+
*/
|
280 |
+
public function logout() {
|
281 |
+
if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'gdpr-user_disagree_with_terms' ) ) {
|
282 |
+
wp_send_json_error( esc_html__( 'We could not verify the the security token. Please try again.', 'gdpr' ) );
|
283 |
+
}
|
284 |
+
|
285 |
+
wp_logout();
|
286 |
+
wp_send_json_success();
|
287 |
+
}
|
288 |
+
|
289 |
+
/**
|
290 |
+
* The user agreed with the privacy policy terms when prompted.
|
291 |
+
* @since 1.0.0
|
292 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
293 |
+
*/
|
294 |
+
public function agree_with_terms() {
|
295 |
+
if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'gdpr-user_agree_with_terms' ) ) {
|
296 |
+
wp_send_json_error( esc_html__( 'We could not verify the the security token. Please try again.', 'gdpr' ) );
|
297 |
+
}
|
298 |
+
|
299 |
+
$user = wp_get_current_user();
|
300 |
+
$user_consents = get_user_meta( $user->ID, 'gdpr_consents' );
|
301 |
+
$user_consents[] = 'privacy-policy';
|
302 |
+
$user_consents = array_unique( $user_consents );
|
303 |
+
add_user_meta( $user->ID, 'gdpr_consents', 'privacy-policy' );
|
304 |
+
setcookie( "gdpr[consent_types]", json_encode( $user_consents ), time() + YEAR_IN_SECONDS, "/" );
|
305 |
+
GDPR_Audit_Log::log( $user->ID, esc_html__( 'User consented to the Privacy Policies.', 'gdpr' ) );
|
306 |
+
wp_send_json_success();
|
307 |
+
}
|
308 |
+
|
309 |
+
public function set_plugin_cookies() {
|
310 |
+
$user_id = get_current_user_id();
|
311 |
+
|
312 |
+
if ( ! isset( $_COOKIE['gdpr']['consent_types'] ) ) {
|
313 |
+
if ( ! $user_id ) {
|
314 |
+
setcookie( 'gdpr[consent_types]', '[]', time() + YEAR_IN_SECONDS, "/" );
|
315 |
+
} else {
|
316 |
+
$user_consents = get_user_meta( $user_id, 'gdpr_consents' );
|
317 |
+
setcookie( "gdpr[consent_types]", json_encode( $user_consents ), time() + YEAR_IN_SECONDS, "/" );
|
318 |
+
}
|
319 |
+
} else {
|
320 |
+
if ( $user_id ) {
|
321 |
+
$user_consents = (array) get_user_meta( $user_id, 'gdpr_consents' );
|
322 |
+
$cookie_consents = (array) json_decode( wp_unslash( $_COOKIE['gdpr']['consent_types'] ) );
|
323 |
+
|
324 |
+
$intersect = array_intersect( $user_consents, $cookie_consents );
|
325 |
+
$diff = array_merge( array_diff( $user_consents, $intersect ), array_diff( $cookie_consents, $intersect ) );
|
326 |
+
|
327 |
+
if ( ! empty( $diff ) ) {
|
328 |
+
setcookie( "gdpr[consent_types]", json_encode( $user_consents ), time() + YEAR_IN_SECONDS, "/" );
|
329 |
+
}
|
330 |
+
}
|
331 |
+
}
|
332 |
+
|
333 |
+
|
334 |
+
if ( ! isset( $_COOKIE['gdpr']['allowed_cookies'] ) ) {
|
335 |
+
$registered_cookies = get_option( 'gdpr_cookie_popup_content', array() );
|
336 |
+
$cookies = array();
|
337 |
+
if ( ! empty( $registered_cookies ) ) {
|
338 |
+
$required_cookies = array_filter( $registered_cookies, function( $item ) {
|
339 |
+
return $item['always_active'] == 1;
|
340 |
+
});
|
341 |
+
if ( ! empty( $required_cookies ) ) {
|
342 |
+
foreach ( $required_cookies as $category ) {
|
343 |
+
$cookies_used = explode( ',', $category['cookies_used'] );
|
344 |
+
foreach ( $cookies_used as $cookie ) {
|
345 |
+
$cookies[] = trim( $cookie );
|
346 |
+
}
|
347 |
+
}
|
348 |
+
}
|
349 |
+
}
|
350 |
+
|
351 |
+
if ( ! empty( $cookies ) ) {
|
352 |
+
setcookie( "gdpr[allowed_cookies]", json_encode( $cookies ), time() + YEAR_IN_SECONDS, "/" );
|
353 |
+
} else {
|
354 |
+
setcookie( "gdpr[allowed_cookies]", '[]', time() + YEAR_IN_SECONDS, "/" );
|
355 |
+
}
|
356 |
+
}
|
357 |
+
}
|
358 |
+
|
359 |
+
}
|
public/class-gdpr-requests-public.php
ADDED
@@ -0,0 +1,392 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* The public facing requests functionality of the plugin.
|
5 |
+
*
|
6 |
+
* @link https://trewknowledge.com
|
7 |
+
* @since 1.0.0
|
8 |
+
*
|
9 |
+
* @package GDPR
|
10 |
+
* @subpackage admin
|
11 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
12 |
+
*/
|
13 |
+
|
14 |
+
/**
|
15 |
+
* The public facing requests functionality of the plugin.
|
16 |
+
*
|
17 |
+
* @package GDPR
|
18 |
+
* @subpackage admin
|
19 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
20 |
+
*/
|
21 |
+
class GDPR_Requests_Public extends GDPR_Requests {
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Removes the user from the requests table, sends a notification email and
|
25 |
+
* delete the user from the site
|
26 |
+
* @since 1.0.0
|
27 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
28 |
+
* @param WP_User $user The user object.
|
29 |
+
* @param string $index The request key on the requests array.
|
30 |
+
* @return void
|
31 |
+
*/
|
32 |
+
public function delete_user( $user, $index ) {
|
33 |
+
if ( ! $user instanceof WP_User ) {
|
34 |
+
return false;
|
35 |
+
}
|
36 |
+
|
37 |
+
if ( ! function_exists( 'wp_delete_user' ) ) {
|
38 |
+
require_once( ABSPATH . 'wp-admin/includes/user.php' );
|
39 |
+
}
|
40 |
+
|
41 |
+
if ( parent::remove_from_requests( $index ) ) {
|
42 |
+
$token = GDPR::generate_pin();
|
43 |
+
GDPR_Email::send( $user->user_email, 'delete-resolved', array( 'token' => $token ) );
|
44 |
+
GDPR_Audit_Log::log( $user->ID, esc_html__( 'User was removed from the site.', 'gdpr' ) );
|
45 |
+
GDPR_Audit_Log::export_log( $user->ID, $token );
|
46 |
+
wp_delete_user( $user->ID );
|
47 |
+
wp_logout();
|
48 |
+
return true;
|
49 |
+
}
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Prints a request form.
|
54 |
+
* @since 1.0.0
|
55 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
56 |
+
* @static
|
57 |
+
* @param string $type The type of request to display the correct form.
|
58 |
+
* @return mixed Print the form html.
|
59 |
+
*/
|
60 |
+
public static function request_form( $type ) {
|
61 |
+
if ( ! in_array( $type, parent::$allowed_types ) ) {
|
62 |
+
return;
|
63 |
+
}
|
64 |
+
|
65 |
+
ob_start();
|
66 |
+
include plugin_dir_path( dirname( __FILE__ ) ) . 'public/partials/' . $type . '-form.php';
|
67 |
+
return ob_get_clean();
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Sends an email to the end user so it can confirm his request.
|
72 |
+
* @since 1.0.0
|
73 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
74 |
+
*/
|
75 |
+
public function send_request_email() {
|
76 |
+
if ( ! isset( $_POST['type'] ) || ! in_array( $_POST['type'], parent::$allowed_types ) ) {
|
77 |
+
wp_die( esc_html__( 'Invalid type of request. Please try again.', 'gdpr' ) );
|
78 |
+
}
|
79 |
+
|
80 |
+
if ( ! isset( $_POST['gdpr_request_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['gdpr_request_nonce'] ), 'gdpr-add-to-requests' ) ) {
|
81 |
+
wp_die( esc_html__( 'We could not verify the security token. Please try again.', 'gdpr' ) );
|
82 |
+
}
|
83 |
+
|
84 |
+
$use_recaptcha = get_option( 'gdpr_use_recaptcha', false );
|
85 |
+
if ( $use_recaptcha ) {
|
86 |
+
$site_key = get_option( 'gdpr_recaptcha_site_key', '' );
|
87 |
+
$secret_key = get_option( 'gdpr_recaptcha_secret_key', '' );
|
88 |
+
|
89 |
+
if ( $site_key && $secret_key ) {
|
90 |
+
if ( ! isset( $_POST['g-recaptcha-response'] ) || ! $_POST['g-recaptcha-response'] ) {
|
91 |
+
wp_die( esc_html__( 'Please verify that you are not a robot.', 'gdpr' ) );
|
92 |
+
}
|
93 |
+
|
94 |
+
$response = wp_remote_post( 'https://www.google.com/recaptcha/api/siteverify', array(
|
95 |
+
'body' => array(
|
96 |
+
'secret' => $secret_key,
|
97 |
+
'response' => $_POST['g-recaptcha-response'],
|
98 |
+
),
|
99 |
+
) );
|
100 |
+
|
101 |
+
$recaptcha_result = wp_remote_retrieve_body( $response );
|
102 |
+
$recaptcha_result = json_decode( $recaptcha_result );
|
103 |
+
if ( ! $recaptcha_result || ! $recaptcha_result->success ) {
|
104 |
+
wp_die( esc_html__( 'Please verify that you are not a robot.', 'gdpr' ) );
|
105 |
+
}
|
106 |
+
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
$type = sanitize_text_field( wp_unslash( $_POST['type'] ) );
|
111 |
+
$data = isset( $_POST['data'] ) ? sanitize_textarea_field( $_POST['data'] ) : '';
|
112 |
+
|
113 |
+
if ( is_user_logged_in() ) {
|
114 |
+
$user = wp_get_current_user();
|
115 |
+
} else {
|
116 |
+
$user = isset( $_POST['user_email'] ) ? get_user_by( 'email', sanitize_email( $_POST['user_email'] ) ) : null;
|
117 |
+
}
|
118 |
+
|
119 |
+
$email_args = array(
|
120 |
+
'forgot_password_url' => add_query_arg(
|
121 |
+
array(
|
122 |
+
'action' => 'rp',
|
123 |
+
'key' => get_password_reset_key( $user ),
|
124 |
+
'login' => $user->user_login,
|
125 |
+
),
|
126 |
+
wp_login_url()
|
127 |
+
),
|
128 |
+
);
|
129 |
+
|
130 |
+
switch ( $type ) {
|
131 |
+
case 'delete':
|
132 |
+
if ( ! $user instanceof WP_User ) {
|
133 |
+
wp_safe_redirect(
|
134 |
+
esc_url_raw(
|
135 |
+
add_query_arg(
|
136 |
+
array(
|
137 |
+
'notify' => 1,
|
138 |
+
'user-not-found' => 1,
|
139 |
+
),
|
140 |
+
wp_get_referer()
|
141 |
+
)
|
142 |
+
)
|
143 |
+
);
|
144 |
+
exit;
|
145 |
+
}
|
146 |
+
|
147 |
+
if ( in_array( 'administrator', $user->roles ) ) {
|
148 |
+
$admins_query = new WP_User_Query( array(
|
149 |
+
'role' => 'Administrator',
|
150 |
+
) );
|
151 |
+
if ( 1 === $admins_query->get_total() ) {
|
152 |
+
wp_safe_redirect(
|
153 |
+
esc_url_raw(
|
154 |
+
add_query_arg(
|
155 |
+
array(
|
156 |
+
'notify' => 1,
|
157 |
+
'cannot-delete' => 1,
|
158 |
+
),
|
159 |
+
wp_get_referer()
|
160 |
+
)
|
161 |
+
)
|
162 |
+
);
|
163 |
+
exit;
|
164 |
+
}
|
165 |
+
}
|
166 |
+
break;
|
167 |
+
|
168 |
+
case 'rectify':
|
169 |
+
case 'complaint':
|
170 |
+
if ( ! $data ) {
|
171 |
+
wp_safe_redirect(
|
172 |
+
esc_url_raw(
|
173 |
+
add_query_arg(
|
174 |
+
array(
|
175 |
+
'notify' => 1,
|
176 |
+
'required-information-missing' => 1,
|
177 |
+
),
|
178 |
+
wp_get_referer()
|
179 |
+
)
|
180 |
+
)
|
181 |
+
);
|
182 |
+
exit;
|
183 |
+
}
|
184 |
+
$email_args['data'] = $data;
|
185 |
+
break;
|
186 |
+
case 'export-data':
|
187 |
+
if ( ! $user instanceof WP_User ) {
|
188 |
+
wp_safe_redirect(
|
189 |
+
esc_url_raw(
|
190 |
+
add_query_arg(
|
191 |
+
array(
|
192 |
+
'notify' => 1,
|
193 |
+
'user-not-found' => 1,
|
194 |
+
),
|
195 |
+
wp_get_referer()
|
196 |
+
)
|
197 |
+
)
|
198 |
+
);
|
199 |
+
exit;
|
200 |
+
}
|
201 |
+
break;
|
202 |
+
}
|
203 |
+
|
204 |
+
$key = parent::add_to_requests( $user->user_email, $type, $data );
|
205 |
+
|
206 |
+
if ( 'export-data' !== $type ) {
|
207 |
+
$email_args['confirm_url'] = add_query_arg(
|
208 |
+
array(
|
209 |
+
'type' => $type,
|
210 |
+
'key' => $key,
|
211 |
+
'email' => $user->user_email,
|
212 |
+
),
|
213 |
+
home_url()
|
214 |
+
);
|
215 |
+
} else {
|
216 |
+
$email_args['confirm_url_xml'] = add_query_arg(
|
217 |
+
array(
|
218 |
+
'type' => $type,
|
219 |
+
'key' => $key,
|
220 |
+
'email' => $user->user_email,
|
221 |
+
'format' => 'xml',
|
222 |
+
),
|
223 |
+
home_url()
|
224 |
+
);
|
225 |
+
$email_args['confirm_url_json'] = add_query_arg(
|
226 |
+
array(
|
227 |
+
'type' => $type,
|
228 |
+
'key' => $key,
|
229 |
+
'email' => $user->user_email,
|
230 |
+
'format' => 'json',
|
231 |
+
),
|
232 |
+
home_url()
|
233 |
+
);
|
234 |
+
}
|
235 |
+
|
236 |
+
|
237 |
+
if ( GDPR_Email::send(
|
238 |
+
$user->user_email,
|
239 |
+
"{$type}-request",
|
240 |
+
$email_args
|
241 |
+
) ) {
|
242 |
+
wp_safe_redirect(
|
243 |
+
esc_url_raw(
|
244 |
+
add_query_arg(
|
245 |
+
array(
|
246 |
+
'notify' => 1,
|
247 |
+
'email-sent' => 1,
|
248 |
+
),
|
249 |
+
wp_get_referer()
|
250 |
+
)
|
251 |
+
)
|
252 |
+
);
|
253 |
+
exit;
|
254 |
+
} else {
|
255 |
+
wp_safe_redirect(
|
256 |
+
esc_url_raw(
|
257 |
+
add_query_arg(
|
258 |
+
array(
|
259 |
+
'notify' => 1,
|
260 |
+
'error' => 1,
|
261 |
+
),
|
262 |
+
wp_get_referer()
|
263 |
+
)
|
264 |
+
)
|
265 |
+
);
|
266 |
+
exit;
|
267 |
+
}
|
268 |
+
}
|
269 |
+
|
270 |
+
/**
|
271 |
+
* Runs when a user confirms a request email.
|
272 |
+
* This process the request, set the request to confirmed on the database.
|
273 |
+
* @since 1.0.0
|
274 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
275 |
+
*/
|
276 |
+
public function request_confirmed() {
|
277 |
+
if ( ! is_front_page() || ! isset( $_GET['type'], $_GET['key'], $_GET['email'] ) ) {
|
278 |
+
return;
|
279 |
+
}
|
280 |
+
|
281 |
+
$type = sanitize_text_field( wp_unslash( $_GET['type'] ) );
|
282 |
+
$key = sanitize_text_field( wp_unslash( $_GET['key'] ) );
|
283 |
+
$email = sanitize_email( $_GET['email'] );
|
284 |
+
$notification_email = sanitize_email( apply_filters( 'gdpr_admin_notification_email', get_option( 'admin_email' ) ) );
|
285 |
+
|
286 |
+
$user = get_user_by( 'email', $email );
|
287 |
+
if ( ! $user instanceof WP_User ) {
|
288 |
+
return;
|
289 |
+
}
|
290 |
+
|
291 |
+
$meta_key = get_user_meta( $user->ID, self::$plugin_name . "_{$type}_key", true );
|
292 |
+
if ( empty( $meta_key ) ) {
|
293 |
+
return;
|
294 |
+
}
|
295 |
+
|
296 |
+
if ( $key === $meta_key ) {
|
297 |
+
$notification_email_args = array(
|
298 |
+
'type' => $type,
|
299 |
+
'review_url' => add_query_arg( array( 'page' => 'gdpr-requests#' . $type ), admin_url() ),
|
300 |
+
);
|
301 |
+
switch ( $type ) {
|
302 |
+
case 'delete':
|
303 |
+
$found_posts = parent::user_has_content( $user );
|
304 |
+
$needs_review = get_option( 'gdpr_deletion_needs_review', true );
|
305 |
+
if ( $found_posts || $needs_review ) {
|
306 |
+
parent::confirm_request( $key );
|
307 |
+
GDPR_Email::send( $notification_email, 'new-request', $notification_email_args );
|
308 |
+
GDPR_Audit_Log::log( $user->ID, esc_html__( 'User confirmed a request to be deleted.', 'gdpr' ) );
|
309 |
+
if ( $found_posts ) {
|
310 |
+
GDPR_Audit_Log::log( $user->ID, esc_html__( 'Content was found for that user.', 'gdpr' ) );
|
311 |
+
}
|
312 |
+
GDPR_Audit_Log::log( $user->ID, esc_html__( 'User added to the erasure review table.', 'gdpr' ) );
|
313 |
+
wp_safe_redirect(
|
314 |
+
esc_url_raw(
|
315 |
+
add_query_arg(
|
316 |
+
array(
|
317 |
+
'user-deleted' => 0,
|
318 |
+
'notify' => 1,
|
319 |
+
),
|
320 |
+
home_url()
|
321 |
+
)
|
322 |
+
)
|
323 |
+
);
|
324 |
+
exit;
|
325 |
+
} else {
|
326 |
+
if ( $this->delete_user( $user, $key ) ) {
|
327 |
+
wp_safe_redirect(
|
328 |
+
esc_url_raw(
|
329 |
+
add_query_arg(
|
330 |
+
array(
|
331 |
+
'user-deleted' => 1,
|
332 |
+
'notify' => 1,
|
333 |
+
),
|
334 |
+
home_url()
|
335 |
+
)
|
336 |
+
)
|
337 |
+
);
|
338 |
+
exit;
|
339 |
+
}
|
340 |
+
}
|
341 |
+
break;
|
342 |
+
case 'rectify':
|
343 |
+
case 'complaint':
|
344 |
+
parent::confirm_request( $key );
|
345 |
+
GDPR_Email::send( $notification_email, 'new-request', $notification_email_args );
|
346 |
+
GDPR_Audit_Log::log( $user->ID, esc_html__( 'User placed a request for rectification or a complaint.', 'gdpr' ) );
|
347 |
+
wp_safe_redirect(
|
348 |
+
esc_url_raw(
|
349 |
+
add_query_arg(
|
350 |
+
array(
|
351 |
+
'request-confirmed' => 1,
|
352 |
+
'notify' => 1,
|
353 |
+
),
|
354 |
+
home_url()
|
355 |
+
)
|
356 |
+
)
|
357 |
+
);
|
358 |
+
exit;
|
359 |
+
break;
|
360 |
+
case 'export-data':
|
361 |
+
$format = isset( $_GET['format'] ) ? sanitize_text_field( wp_unslash( $_GET['format'] ) ) : 'xml';
|
362 |
+
/* translators: File format. Can be XML or JSON */
|
363 |
+
GDPR_Audit_Log::log( $user->ID, sprintf( esc_html__( 'User downloaded all their data in %s format.', 'gdpr' ), $format ) );
|
364 |
+
$this->file_export_data( $user->user_email, $format, $key );
|
365 |
+
break;
|
366 |
+
}
|
367 |
+
}
|
368 |
+
}
|
369 |
+
|
370 |
+
/**
|
371 |
+
* Downloads the user data export in the chosen format.
|
372 |
+
* @since 1.2.0
|
373 |
+
* @param string $email The recipient.
|
374 |
+
* @param string $format The export format. XML or JSON.
|
375 |
+
* @param string $key The request array key.
|
376 |
+
*/
|
377 |
+
private function file_export_data( $email, $format, $key ) {
|
378 |
+
$email = sanitize_email( $email );
|
379 |
+
$format = sanitize_text_field( wp_unslash( $format ) );
|
380 |
+
$key = sanitize_text_field( wp_unslash( $key ) );
|
381 |
+
|
382 |
+
$export = GDPR::generate_export( $email, $format );
|
383 |
+
if ( $export ) {
|
384 |
+
parent::remove_from_requests( $key );
|
385 |
+
header('Content-Type: application/octet-stream');
|
386 |
+
header('Content-Description: File Transfer');
|
387 |
+
header('Content-Disposition: attachment; filename=' . $email . '.' . $format);
|
388 |
+
echo $export;
|
389 |
+
}
|
390 |
+
die();
|
391 |
+
}
|
392 |
+
}
|
public/index.php
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php // Silence is golden
|
public/partials/complaint-form.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<form class="gdpr-add-to-complaint-requests" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post">
|
2 |
+
<?php wp_nonce_field( 'gdpr-add-to-requests', 'gdpr_request_nonce' ); ?>
|
3 |
+
<input type="hidden" name="action" value="gdpr_send_request_email">
|
4 |
+
<input type="hidden" name="type" value="complaint">
|
5 |
+
<?php if ( ! is_user_logged_in() ): ?>
|
6 |
+
<input type="email" name="user_email" placeholder="user@domain.com" required>
|
7 |
+
<?php endif ?>
|
8 |
+
<textarea name="data" rows="5" required></textarea>
|
9 |
+
|
10 |
+
<?php GDPR_Public::add_recaptcha(); ?>
|
11 |
+
<?php $submit_button_text = apply_filters( "gdpr_complaint_request_form_submit_text", esc_attr__( 'Submit', 'gdpr' ) ); ?>
|
12 |
+
<input type="submit" value="<?php echo esc_attr( $submit_button_text ); ?>">
|
13 |
+
</form>
|
public/partials/confirmation-screens.php
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* The confirmation dialogs.
|
4 |
+
*
|
5 |
+
* @link https://trewknowledge.com
|
6 |
+
* @since 1.0.0
|
7 |
+
*
|
8 |
+
* @package GDPR
|
9 |
+
* @subpackage public
|
10 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
11 |
+
*/
|
12 |
+
?>
|
13 |
+
|
14 |
+
<div class="gdpr gdpr-general-confirmation gdpr-delete-confirmation">
|
15 |
+
<div class="gdpr-wrapper">
|
16 |
+
<header>
|
17 |
+
<div class="gdpr-box-title">
|
18 |
+
<h3><?php esc_attr_e( 'Close your account?', 'gdpr' ); ?></h3>
|
19 |
+
<span class="gdpr-close"></span>
|
20 |
+
</div>
|
21 |
+
</header>
|
22 |
+
<div class="gdpr-content">
|
23 |
+
<p><?php esc_html_e( 'Your account will be closed and all data will be permanently deleted and cannot be recovered. Are you sure?', 'gdpr' ); ?></p>
|
24 |
+
</div>
|
25 |
+
<footer>
|
26 |
+
<button class="gdpr-delete-account">Continue</button>
|
27 |
+
<button class="gdpr-cancel"><?php esc_html_e( 'Cancel', 'gdpr' ); ?></button>
|
28 |
+
</footer>
|
29 |
+
</div>
|
30 |
+
</div>
|
31 |
+
|
32 |
+
<?php if ( isset( $_GET['notify'] ) && $_GET['notify'] ) : ?>
|
33 |
+
<?php
|
34 |
+
$title = __( 'Error!', 'gdpr' );
|
35 |
+
if ( isset( $_GET['user-deleted'] ) ) {
|
36 |
+
$title = __( 'Your account', 'gdpr' );
|
37 |
+
if ( $_GET['user-deleted'] ) {
|
38 |
+
$text = __( 'Your account has been closed. We are sorry to see you go.', 'gdpr' );
|
39 |
+
} else {
|
40 |
+
$text = __( 'Your request has been received and is being reviewed. You will receive an email when we are done.', 'gdpr' );
|
41 |
+
}
|
42 |
+
}
|
43 |
+
if ( isset( $_GET['email-sent'] ) && $_GET['email-sent'] ) {
|
44 |
+
$title = __( 'Email confirmation', 'gdpr' );
|
45 |
+
$text = __( 'We\'ve sent you a confirmation email.', 'gdpr' );
|
46 |
+
}
|
47 |
+
if ( isset( $_GET['user-not-found'] ) && $_GET['user-not-found'] ) {
|
48 |
+
$text = __( 'User not found.', 'gdpr' );
|
49 |
+
}
|
50 |
+
if ( isset( $_GET['cannot-delete'] ) && $_GET['cannot-delete'] ) {
|
51 |
+
$text = __( 'We can\'t delete this user.', 'gdpr' );
|
52 |
+
}
|
53 |
+
if ( isset( $_GET['required-information-missing'] ) && $_GET['required-information-missing'] ) {
|
54 |
+
$text = __( 'Required information is missing from the form.', 'gdpr' );
|
55 |
+
}
|
56 |
+
if ( isset( $_GET['request-confirmed'] ) && $_GET['request-confirmed'] ) {
|
57 |
+
$title = __( 'Request Received', 'gdpr' );
|
58 |
+
$text = __( 'Your request has been received. We will be in touch soon.', 'gdpr' );
|
59 |
+
}
|
60 |
+
if ( isset( $_GET['error'] ) && $_GET['error'] ) {
|
61 |
+
$text = __( 'There was a problem with your request. Please try again later.', 'gdpr' );
|
62 |
+
}
|
63 |
+
?>
|
64 |
+
<div class="gdpr gdpr-general-confirmation gdpr-accept-confirmation">
|
65 |
+
<div class="gdpr-wrapper">
|
66 |
+
<header>
|
67 |
+
<div class="gdpr-box-title">
|
68 |
+
<h3><?php echo esc_attr( $title ); ?></h3>
|
69 |
+
<span class="gdpr-close"></span>
|
70 |
+
</div>
|
71 |
+
</header>
|
72 |
+
<div class="gdpr-content">
|
73 |
+
<p><?php echo esc_html( $text ); ?></p>
|
74 |
+
</div>
|
75 |
+
<footer>
|
76 |
+
<button class="gdpr-ok">OK</button>
|
77 |
+
</footer>
|
78 |
+
</div>
|
79 |
+
</div>
|
80 |
+
<?php endif ?>
|
public/partials/delete-form.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* The add to deletion requests form markup.
|
4 |
+
*
|
5 |
+
* @link https://trewknowledge.com
|
6 |
+
* @since 1.0.0
|
7 |
+
*
|
8 |
+
* @package GDPR
|
9 |
+
* @subpackage public
|
10 |
+
* @author Fernando Claussen <fernandoclaussen@gmail.com>
|
11 |
+
*/
|
12 |
+
?>
|
13 |
+
|
14 |
+
<form class="gdpr-add-to-deletion-requests" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post">
|
15 |
+
<?php wp_nonce_field( 'gdpr-add-to-requests', 'gdpr_request_nonce' ); ?>
|
16 |
+
<input type="hidden" name="action" value="gdpr_send_request_email">
|
17 |
+
<input type="hidden" name="type" value="delete">
|
18 |
+
<?php if ( ! is_user_logged_in() ): ?>
|
19 |
+
<input type="email" name="user_email" placeholder="user@domain.com" required>
|
20 |
+
<?php endif ?>
|
21 |
+
<?php GDPR_Public::add_recaptcha(); ?>
|
22 |
+
<?php $submit_button_text = apply_filters( "gdpr_delete_request_form_submit_text", esc_attr__( 'Close my account', 'gdpr' ) ); ?>
|
23 |
+
<input type="submit" value="<?php echo esc_attr( $submit_button_text ); ?>">
|
24 |
+
</form>
|
public/partials/export-data-form.php
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<form class="gdpr-export-data-form" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post">
|
2 |
+
<?php wp_nonce_field( 'gdpr-add-to-requests', 'gdpr_request_nonce' ); ?>
|
3 |
+
<input type="hidden" name="action" value="gdpr_send_request_email">
|
4 |
+
<input type="hidden" name="type" value="export-data">
|
5 |
+
<?php if ( ! is_user_logged_in() ): ?>
|
6 |
+
<input type="email" name="user_email" placeholder="user@domain.com" required>
|
7 |
+
<?php endif ?>
|
8 |
+
<?php GDPR_Public::add_recaptcha(); ?>
|
9 |
+
<?php $submit_button_text = apply_filters( "gdpr_export_data_request_form_submit_text", esc_attr__( 'Download my data', 'gdpr' ) ); ?>
|
10 |
+
<input type="submit" value="<?php echo esc_attr( $submit_button_text ); ?>">
|
11 |
+
</form>
|
public/partials/index.php
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php // Silence is golden
|
public/partials/privacy-bar.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This file is used to markup the cookie bar.
|
5 |
+
*
|
6 |
+
*
|
7 |
+
* @link https://trewknowledge.com
|
8 |
+
* @since 1.0.0
|
9 |
+
*
|
10 |
+
* @package GDPR
|
11 |
+
* @subpackage public/partials
|
12 |
+
*/
|
13 |
+
?>
|
14 |
+
|
15 |
+
<div class="gdpr gdpr-privacy-bar" style="display:none;">
|
16 |
+
<div class="gdpr-wrapper">
|
17 |
+
<div class="gdpr-content">
|
18 |
+
<p>
|
19 |
+
<?php echo nl2br( wp_kses_post( $content ) ); ?>
|
20 |
+
</p>
|
21 |
+
</div>
|
22 |
+
<div class="gdpr-right">
|
23 |
+
<button class="gdpr-preferences" type="button"><?php esc_html_e( 'Privacy Preferences', 'gdpr' ); ?></button>
|
24 |
+
<button class="gdpr-agreement" type="button"><?php echo esc_html( $button_text ); ?></button>
|
25 |
+
</div>
|
26 |
+
</div>
|
27 |
+
</div>
|
public/partials/privacy-preferences-modal.php
ADDED
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This file is used to markup the cookie preferences window.
|
5 |
+
*
|
6 |
+
*
|
7 |
+
* @link https://trewknowledge.com
|
8 |
+
* @since 1.0.0
|
9 |
+
*
|
10 |
+
* @package GDPR
|
11 |
+
* @subpackage public/partials
|
12 |
+
*/
|
13 |
+
?>
|
14 |
+
|
15 |
+
<div class="gdpr gdpr-privacy-preferences">
|
16 |
+
<div class="gdpr-wrapper">
|
17 |
+
<form method="post" class="gdpr-privacy-preferences-frm" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>">
|
18 |
+
<input type="hidden" name="action" value="gdpr_update_privacy_preferences">
|
19 |
+
<?php wp_nonce_field( 'gdpr-update_privacy_preferences', 'update-privacy-preferences-nonce' ); ?>
|
20 |
+
<header>
|
21 |
+
<div class="gdpr-box-title">
|
22 |
+
<h3><?php esc_html_e( 'Privacy Preference Center', 'gdpr' ); ?></h3>
|
23 |
+
<span class="gdpr-close"></span>
|
24 |
+
</div>
|
25 |
+
</header>
|
26 |
+
<div class="gdpr-mobile-menu">
|
27 |
+
<button type="button"><?php esc_html_e( 'Options', 'gdpr' ); ?></button>
|
28 |
+
</div>
|
29 |
+
<div class="gdpr-content">
|
30 |
+
<ul class="gdpr-tabs">
|
31 |
+
<li><button type="button" class="gdpr-tab-button gdpr-active" data-target="gdpr-consent-management"><?php esc_html_e( 'Consent Management', 'gdpr' ); ?></button></li>
|
32 |
+
<?php reset( $tabs ); ?>
|
33 |
+
<?php if ( ! empty( $tabs ) ): ?>
|
34 |
+
<li><button type="button" class="gdpr-tab-button gdpr-cookie-settings" data-target="<?php echo esc_attr( key( $tabs ) ); ?>"><?php esc_html_e( 'Cookie Settings', 'gdpr' ); ?></button>
|
35 |
+
<ul class="gdpr-subtabs">
|
36 |
+
<?php
|
37 |
+
foreach ( $tabs as $key => $tab ) {
|
38 |
+
echo '<li><button type="button" data-target="' . esc_attr( $key ) . '" ' . '>' . esc_html( $tab['name'] ) . '</button></li>';
|
39 |
+
}
|
40 |
+
?>
|
41 |
+
</ul>
|
42 |
+
</li>
|
43 |
+
<?php endif ?>
|
44 |
+
</ul>
|
45 |
+
<div class="gdpr-tab-content">
|
46 |
+
<div class="gdpr-consent-management gdpr-active">
|
47 |
+
<header>
|
48 |
+
<h4><?php esc_html_e( 'Consent Management', 'gdpr' ); ?></h4>
|
49 |
+
</header>
|
50 |
+
<div class="gdpr-info">
|
51 |
+
<p><?php echo nl2br( esc_html( $cookie_privacy_excerpt ) ); ?></p>
|
52 |
+
<?php foreach ( $consent_types as $consent_key => $type ) : ?>
|
53 |
+
<div class="gdpr-cookies-used">
|
54 |
+
<div class="gdpr-cookie-title">
|
55 |
+
<p><?php echo esc_html( $type['name'] ); ?></p>
|
56 |
+
<?php if ( $type['required'] ) : ?>
|
57 |
+
<span class="gdpr-always-active"><?php esc_html_e( 'Required', 'gdpr' ); ?></span>
|
58 |
+
<input type="hidden" name="user_consents[]" value="<?php echo esc_attr( $consent_key ); ?>" checked style="display:none;">
|
59 |
+
<?php else : ?>
|
60 |
+
<label class="gdpr-switch">
|
61 |
+
<input type="checkbox" name="user_consents[]" value="<?php echo esc_attr( $consent_key ); ?>" <?php echo ! empty( $user_consents ) ? checked( in_array( $consent_key, $user_consents, true ), 1, false ) : ''; ?>>
|
62 |
+
<span class="gdpr-slider round"></span>
|
63 |
+
</label>
|
64 |
+
<?php endif; ?>
|
65 |
+
</div>
|
66 |
+
<div class="gdpr-cookies">
|
67 |
+
<span><?php echo wp_kses( $type['description'], $this->allowed_html ); ?></span>
|
68 |
+
</div>
|
69 |
+
</div>
|
70 |
+
<?php endforeach; ?>
|
71 |
+
</div>
|
72 |
+
</div>
|
73 |
+
<?php $all_cookies = array(); ?>
|
74 |
+
<?php foreach ( $tabs as $key => $tab ) : ?>
|
75 |
+
<div class="<?php echo esc_attr( $key ); ?>">
|
76 |
+
<header>
|
77 |
+
<h4><?php echo esc_html( $tab['name'] ); ?></h4>
|
78 |
+
</header><!-- /header -->
|
79 |
+
<div class="gdpr-info">
|
80 |
+
<p><?php echo nl2br( $tab['how_we_use'] ); ?></p>
|
81 |
+
<?php if ( isset( $tab['cookies_used'] ) && $tab['cookies_used'] ) : ?>
|
82 |
+
<div class="gdpr-cookies-used">
|
83 |
+
<div class="gdpr-cookie-title">
|
84 |
+
<p><?php esc_html_e( 'Cookies Used', 'gdpr' ); ?></p>
|
85 |
+
<?php
|
86 |
+
$site_cookies = array();
|
87 |
+
$enabled = false;
|
88 |
+
$cookies_used = explode( ',', $tab['cookies_used'] );
|
89 |
+
$approved_cookies = isset( $_COOKIE['gdpr']['allowed_cookies'] ) ? json_decode( wp_unslash( $_COOKIE['gdpr']['allowed_cookies'] ) ) : array();
|
90 |
+
foreach ( $cookies_used as $cookie ) {
|
91 |
+
$site_cookies[] = trim( $cookie );
|
92 |
+
$all_cookies[] = trim( $cookie );
|
93 |
+
if ( ! empty( $approved_cookies ) ) {
|
94 |
+
if ( in_array( trim( $cookie ), $approved_cookies ) ) {
|
95 |
+
$enabled = true;
|
96 |
+
}
|
97 |
+
}
|
98 |
+
}
|
99 |
+
?>
|
100 |
+
<?php if ( $tab['always_active'] ) : ?>
|
101 |
+
<span class="gdpr-always-active"><?php esc_html_e( 'Always Active', 'gdpr' ); ?></span>
|
102 |
+
<input type="hidden" name="approved_cookies[]" value="<?php echo esc_attr( json_encode( $site_cookies ) ) ?>" checked>
|
103 |
+
<?php else: ?>
|
104 |
+
<label class="gdpr-switch">
|
105 |
+
<input type="checkbox" name="approved_cookies[]" value="<?php echo esc_attr( json_encode( $site_cookies ) ) ?>" <?php checked( $enabled, true ); ?>>
|
106 |
+
<span class="gdpr-slider round"></span>
|
107 |
+
</label>
|
108 |
+
<?php endif; ?>
|
109 |
+
</div>
|
110 |
+
<div class="gdpr-cookies">
|
111 |
+
<span><?php echo esc_html( $tab['cookies_used'] ); ?></span>
|
112 |
+
</div>
|
113 |
+
</div>
|
114 |
+
<?php endif ?>
|
115 |
+
<?php if ( isset( $tab['hosts'] ) && ! empty( $tab['hosts'] ) ) : ?>
|
116 |
+
<?php foreach ( $tab['hosts'] as $host_key => $host ) : ?>
|
117 |
+
<div class="gdpr-cookies-used">
|
118 |
+
<div class="gdpr-cookie-title">
|
119 |
+
<p><?php echo esc_html( $host['name'] ); ?></p>
|
120 |
+
<a href="<?php echo esc_url( $host['optout'] ); ?>" target="_blank" class="gdpr-button"><?php esc_html_e( 'Opt Out', 'gdpr' ); ?></a>
|
121 |
+
</div>
|
122 |
+
<div class="gdpr-cookies">
|
123 |
+
<span><?php echo esc_html( $host['cookies_used'] ); ?></span>
|
124 |
+
</div>
|
125 |
+
</div>
|
126 |
+
<?php endforeach ?>
|
127 |
+
<?php endif ?>
|
128 |
+
</div>
|
129 |
+
</div>
|
130 |
+
<?php endforeach; ?>
|
131 |
+
</div>
|
132 |
+
<input type="hidden" name="all_cookies" value="<?php echo esc_attr( json_encode( $all_cookies ) ); ?>">
|
133 |
+
</div>
|
134 |
+
<footer>
|
135 |
+
<input type="submit" value="<?php esc_attr_e( 'Save Preferences', 'gdpr' ); ?>">
|
136 |
+
<?php if ( $privacy_policy_page ) : ?>
|
137 |
+
<span><a href="<?php echo esc_url( get_permalink( $privacy_policy_page ) ); ?>" target="_blank"><?php esc_html_e( 'More Information', 'gdpr' ); ?></a></span>
|
138 |
+
<?php endif ?>
|
139 |
+
</footer>
|
140 |
+
</form>
|
141 |
+
</div>
|
142 |
+
</div>
|
public/partials/reconsent-modal.php
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="gdpr-reconsent-modal" style="display:none;">
|
2 |
+
<div class="gdpr-reconsent-modal-content">
|
3 |
+
<h3><?php esc_html_e( 'Our Privacy Policy has been updated.', 'gdpr' ); ?></h3>
|
4 |
+
<h4><?php esc_html_e( 'To continue using the site you need to read the revised version and agree to the terms.', 'gdpr' ); ?></h4>
|
5 |
+
<div class="gdpr-privacy-viewer">
|
6 |
+
<?php echo apply_filters( 'the_content', $page_obj->post_content ); ?>
|
7 |
+
</div>
|
8 |
+
<div class="gdpr-consent-buttons">
|
9 |
+
<a href="#" class="gdpr-agree" data-nonce="<?php echo esc_attr( wp_create_nonce( 'gdpr-user_agree_with_terms' ) ); ?>"><?php esc_html_e( 'Agree', 'gdpr' ); ?></a>
|
10 |
+
<a href="#" class="gdpr-disagree"><?php esc_html_e( 'Disagree', 'gdpr' ); ?></a>
|
11 |
+
</div>
|
12 |
+
<div class="gdpr-consent-loading">
|
13 |
+
<p class="gdpr-loading"><span class="gdpr-updating"><?php esc_html_e( 'Updating', 'gdpr' ); ?></span><span class="gdpr-ellipsis"></span></p>
|
14 |
+
</div>
|
15 |
+
</div>
|
16 |
+
</div>
|
17 |
+
|
18 |
+
<div class="gdpr gdpr-general-confirmation gdpr-disagree-confirmation">
|
19 |
+
<div class="gdpr-wrapper">
|
20 |
+
<header>
|
21 |
+
<div class="gdpr-box-title">
|
22 |
+
<h3><?php esc_attr_e( 'Are you sure?', 'gdpr' ); ?></h3>
|
23 |
+
<span class="gdpr-close"></span>
|
24 |
+
</div>
|
25 |
+
</header>
|
26 |
+
<div class="gdpr-content">
|
27 |
+
<p><?php esc_html_e( 'By disagreeing you will no longer have access to our site and will be logged out.', 'gdpr' ); ?></p>
|
28 |
+
</div>
|
29 |
+
<footer>
|
30 |
+
<button class="gdpr-disagree-confirm" data-nonce="<?php echo esc_attr( wp_create_nonce( 'gdpr-user_disagree_with_terms' ) ); ?>"><?php esc_html_e( 'Continue', 'gdpr' ); ?></button>
|
31 |
+
<button class="gdpr-cancel"><?php esc_html_e( 'Cancel', 'gdpr' ); ?></button>
|
32 |
+
</footer>
|
33 |
+
</div>
|
34 |
+
</div>
|
public/partials/rectify-form.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<form class="gdpr-add-to-rectify-requests" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post">
|
2 |
+
<?php wp_nonce_field( 'gdpr-add-to-requests', 'gdpr_request_nonce' ); ?>
|
3 |
+
<input type="hidden" name="action" value="gdpr_send_request_email">
|
4 |
+
<input type="hidden" name="type" value="rectify">
|
5 |
+
<?php if ( ! is_user_logged_in() ): ?>
|
6 |
+
<input type="email" name="user_email" placeholder="user@domain.com" required>
|
7 |
+
<?php endif ?>
|
8 |
+
<textarea name="data" rows="5" required></textarea>
|
9 |
+
<?php GDPR_Public::add_recaptcha(); ?>
|
10 |
+
<?php $submit_button_text = apply_filters( "gdpr_rectify_request_form_submit_text", esc_attr__( 'Submit', 'gdpr' ) ); ?>
|
11 |
+
<input type="submit" value="<?php echo esc_attr( $submit_button_text ); ?>">
|
12 |
+
</form>
|
templates/email/complaint-request.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
echo sprintf(
|
3 |
+
/* translators: 1: The complaint content, 2: confirmation link, 3: reset password link */
|
4 |
+
esc_html__(
|
5 |
+
'Someone placed a complaint on your behalf on our site.
|
6 |
+
By clicking confirm a request will be made and we will do our best to fulfil it.
|
7 |
+
|
8 |
+
--------------------------------------------------------
|
9 |
+
Request
|
10 |
+
--------------------------------------------------------
|
11 |
+
%s
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
|
16 |
+
To confirm this request, click here: %s
|
17 |
+
|
18 |
+
|
19 |
+
|
20 |
+
---------------------------------------------------------------------------------
|
21 |
+
If that wasn\'t you, reset your password: %s
|
22 |
+
', 'gdpr' ),
|
23 |
+
esc_html( $args['data'] ),
|
24 |
+
esc_url_raw( $args['confirm_url'] ),
|
25 |
+
esc_url_raw( $args['forgot_password_url'] )
|
26 |
+
);
|
templates/email/complaint-resolved.php
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
echo esc_html__(
|
4 |
+
'We resolved your complaint request.
|
5 |
+
If you have any problems or questions, don\'t hesitate to contact us.', 'gdpr' );
|
templates/email/data-breach-notification.php
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
echo sprintf(
|
3 |
+
/* translators: 1: Email content, 2: Nature of data breach, 3: Contact details for data protection officer, 4: Likely consequences of breach, 5: Measures taken */
|
4 |
+
esc_html__(
|
5 |
+
'%s
|
6 |
+
|
7 |
+
--------------------------------------------------------
|
8 |
+
Nature of the personal data breach:
|
9 |
+
--------------------------------------------------------
|
10 |
+
%s
|
11 |
+
|
12 |
+
--------------------------------------------------------
|
13 |
+
Name and contact details of the data protection officer:
|
14 |
+
--------------------------------------------------------
|
15 |
+
%s
|
16 |
+
|
17 |
+
--------------------------------------------------------
|
18 |
+
Likely consequences of the personal data breach:
|
19 |
+
--------------------------------------------------------
|
20 |
+
%s
|
21 |
+
|
22 |
+
--------------------------------------------------------
|
23 |
+
Measures taken or proposed to be taken:
|
24 |
+
--------------------------------------------------------
|
25 |
+
%s
|
26 |
+
', 'gdpr' ),
|
27 |
+
esc_html( $args['content'] ),
|
28 |
+
esc_html( $args['nature'] ),
|
29 |
+
esc_html( $args['office_contact'] ),
|
30 |
+
esc_html( $args['consequences'] ),
|
31 |
+
esc_html( $args['measures'] ),
|
32 |
+
esc_url_raw( $args['confirm_url'] )
|
33 |
+
);
|
34 |
+
?>
|
templates/email/data-breach-request.php
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
echo sprintf(
|
3 |
+
/* translators: 1: User who requested the notification, 2: Nature of data breach, 3: Contact details for data protection officer, 4: Likely consequences of breach, 5: Measures taken, 6: Confirmation link */
|
4 |
+
esc_html__(
|
5 |
+
'A request to send a mass email notification to all users regarding a data breach has been made by %s.
|
6 |
+
|
7 |
+
--------------------------------------------------------
|
8 |
+
Nature of the personal data breach:
|
9 |
+
--------------------------------------------------------
|
10 |
+
%s
|
11 |
+
|
12 |
+
--------------------------------------------------------
|
13 |
+
Name and contact details of the data protection officer:
|
14 |
+
--------------------------------------------------------
|
15 |
+
%s
|
16 |
+
|
17 |
+
--------------------------------------------------------
|
18 |
+
Likely consequences of the personal data breach:
|
19 |
+
--------------------------------------------------------
|
20 |
+
%s
|
21 |
+
|
22 |
+
--------------------------------------------------------
|
23 |
+
Measures taken or proposed to be taken:
|
24 |
+
--------------------------------------------------------
|
25 |
+
%s
|
26 |
+
|
27 |
+
|
28 |
+
To confirm this request, click here: %s
|
29 |
+
|
30 |
+
---------------------------------------------------------------------------------
|
31 |
+
If that is not intended, have the person who requested it change their password.
|
32 |
+
---------------------------------------------------------------------------------
|
33 |
+
', 'gdpr' ),
|
34 |
+
esc_html( $args['requester'] ),
|
35 |
+
esc_html( $args['nature'] ),
|
36 |
+
esc_html( $args['office_contact'] ),
|
37 |
+
esc_html( $args['consequences'] ),
|
38 |
+
esc_html( $args['measures'] ),
|
39 |
+
esc_url_raw( $args['confirm_url'] )
|
40 |
+
);
|
41 |
+
?>
|
templates/email/delete-request.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
echo sprintf(
|
3 |
+
/* translators: 1: Confirmation link, 2: Reset password link */
|
4 |
+
esc_html__(
|
5 |
+
'Someone placed a request for your information to be removed from our site.
|
6 |
+
By clicking confirm your account will be removed from our site and all data we collected
|
7 |
+
over time will be erased from our database. It will be impossible for us to retrieve that
|
8 |
+
information in the future.
|
9 |
+
|
10 |
+
|
11 |
+
|
12 |
+
To confirm this request, click here: %s
|
13 |
+
|
14 |
+
|
15 |
+
|
16 |
+
---------------------------------------------------------------------------------
|
17 |
+
If that wasn\'t you, reset your password: %s
|
18 |
+
', 'gdpr' ),
|
19 |
+
esc_url_raw( $args['confirm_url'] ),
|
20 |
+
esc_url_raw( $args['forgot_password_url'] )
|
21 |
+
);
|
templates/email/delete-resolved.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
echo sprintf(
|
4 |
+
/* translators: 6-digit token for audit log */
|
5 |
+
esc_html__(
|
6 |
+
'Your account has been closed.
|
7 |
+
|
8 |
+
We no longer hold any information about you.
|
9 |
+
If you ever need to make a complaint you can email us and we will try to help you.
|
10 |
+
To be able to make a complaint you will be requested to provide your email address and the token below.
|
11 |
+
|
12 |
+
%s', 'gdpr' ),
|
13 |
+
$args['token']
|
14 |
+
);
|
templates/email/export-data-request.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
echo sprintf(
|
3 |
+
/* translators: 1: XML download link, 2: JSON download link, 3: reset password link */
|
4 |
+
esc_html__(
|
5 |
+
'Someone requested to download your data from our site.
|
6 |
+
By clicking confirm we will redirect you back to our site where a download will begin.
|
7 |
+
|
8 |
+
To download it in a XML format, click here: %s
|
9 |
+
To download it in a JSON format, click here: %s
|
10 |
+
|
11 |
+
|
12 |
+
|
13 |
+
---------------------------------------------------------------------------------
|
14 |
+
If that wasn\'t you, reset your password: %s
|
15 |
+
', 'gdpr' ),
|
16 |
+
esc_url_raw( $args['confirm_url_xml'] ),
|
17 |
+
esc_url_raw( $args['confirm_url_json'] ),
|
18 |
+
esc_url_raw( $args['forgot_password_url'] )
|
19 |
+
);
|
templates/email/index.php
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php // Silence is golden
|
templates/email/new-request.php
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
echo sprintf(
|
4 |
+
/* translators: 1: The type of request. 2: Link to where the request can be reviewed. */
|
5 |
+
esc_html__(
|
6 |
+
'There is a new %1$s request waiting for review.
|
7 |
+
|
8 |
+
Review your requests: %2$s', 'gdpr' ),
|
9 |
+
esc_html( $args['type'] ),
|
10 |
+
esc_url_raw( $args['review_url'] )
|
11 |
+
);
|
templates/email/rectify-request.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
echo sprintf(
|
3 |
+
/* translators: 1: The request content, 2: confirmation link, 3: reset password link */
|
4 |
+
esc_html__(
|
5 |
+
'Someone placed a request for your information to be rectified on our site.
|
6 |
+
By clicking confirm a request will be made and we will do our best to fulfil it.
|
7 |
+
|
8 |
+
--------------------------------------------------------
|
9 |
+
Request
|
10 |
+
--------------------------------------------------------
|
11 |
+
%s
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
|
16 |
+
To confirm this request, click here: %s
|
17 |
+
|
18 |
+
|
19 |
+
|
20 |
+
---------------------------------------------------------------------------------
|
21 |
+
If that wasn\'t you, reset your password: %s
|
22 |
+
', 'gdpr' ),
|
23 |
+
esc_html( $args['data'] ),
|
24 |
+
esc_url_raw( $args['confirm_url'] ),
|
25 |
+
esc_url_raw( $args['forgot_password_url'] )
|
26 |
+
);
|
templates/email/rectify-resolved.php
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
echo esc_html__(
|
4 |
+
'We resolved your rectification request.
|
5 |
+
If you have any problems or questions, don\'t hesitate to contact us.', 'gdpr' );
|
uninstall.php
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Fired when the plugin is uninstalled.
|
5 |
+
*
|
6 |
+
* When populating this file, consider the following flow
|
7 |
+
* of control:
|
8 |
+
*
|
9 |
+
* - This method should be static
|
10 |
+
* - Check if the $_REQUEST content actually is the plugin name
|
11 |
+
* - Run an admin referrer check to make sure it goes through authentication
|
12 |
+
* - Verify the output of $_GET makes sense
|
13 |
+
* - Repeat with other user roles. Best directly by using the links/query string parameters.
|
14 |
+
* - Repeat things for multisite. Once for a single site in the network, once sitewide.
|
15 |
+
*
|
16 |
+
* This file may be updated more in future version of the Boilerplate; however, this is the
|
17 |
+
* general skeleton and outline for how the file should work.
|
18 |
+
*
|
19 |
+
* For more information, see the following discussion:
|
20 |
+
* https://github.com/tommcfarlin/WordPress-Plugin-Boilerplate/pull/123#issuecomment-28541913
|
21 |
+
*
|
22 |
+
* @link https://trewknowledge.com
|
23 |
+
* @since 1.0.0
|
24 |
+
*
|
25 |
+
* @package GDPR
|
26 |
+
*/
|
27 |
+
|
28 |
+
// If uninstall not called from WordPress, then exit.
|
29 |
+
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
|
30 |
+
exit;
|
31 |
+
}
|