WP Mail Logging - Version 1.8.5

Version Description

  • New: added privacy integration (erasure, export, policy content suggestion)
  • Fix: typo in readme
  • Fix: output of html comments in emails
  • Tweak: performance (duplicate queries of installation state)

=

Download this release

Release Info

Developer No3x
Plugin Icon 128x128 WP Mail Logging
Version 1.8.5
Comparing to
See all releases

Code changes from version 1.8.4 to 1.8.5

Files changed (31) hide show
  1. languages/wp-mail-logging-de_DE.mo +0 -0
  2. languages/wp-mail-logging-de_DE.po +5 -5
  3. languages/wp-mail-logging-zh_CN.mo +0 -0
  4. languages/wp-mail-logging-zh_CN.po +2 -2
  5. languages/wp-mail-logging.pot +100 -82
  6. lib/vendor/brandonwamboldt/wp-orm/README.md +281 -0
  7. lib/vendor/brandonwamboldt/wp-orm/src/BaseModel.php +18 -1
  8. lib/vendor/brandonwamboldt/wp-orm/src/DefaultQueryFactory.php +10 -0
  9. lib/vendor/brandonwamboldt/wp-orm/src/QueryFactory.php +8 -0
  10. readme.txt +13 -5
  11. {model → src/Model}/WPML_Mail.php +2 -3
  12. WPML_API_Example.php → src/WPML_API_Example.php +85 -85
  13. WPML_DI_Container.php → src/WPML_DI_Container.php +24 -24
  14. WPML_Email_Dispatcher.php → src/WPML_Email_Dispatcher.php +18 -18
  15. WPML_Email_Log_List.php → src/WPML_Email_Log_List.php +509 -510
  16. WPML_Email_Resender.php → src/WPML_Email_Resender.php +29 -29
  17. src/WPML_Hook_Remover.php +93 -0
  18. WPML_Init.php → src/WPML_Init.php +161 -158
  19. WPML_InstallIndicator.php → src/WPML_InstallIndicator.php +186 -171
  20. WPML_LifeCycle.php → src/WPML_LifeCycle.php +211 -211
  21. WPML_LogRotation.php → src/WPML_LogRotation.php +131 -131
  22. src/WPML_MailExtractor.php +96 -0
  23. src/WPML_MessageSanitizer.php +60 -0
  24. WPML_OptionsManager.php → src/WPML_OptionsManager.php +604 -604
  25. WPML_Plugin.php → src/WPML_Plugin.php +19 -57
  26. src/WPML_PrivacyController.php +157 -0
  27. WPML_Utils.php → src/WPML_Utils.php +118 -118
  28. {inc → src/inc}/class-wp-list-table.php +0 -0
  29. {inc → src/inc}/redux/WPML_Redux_Framework_config.php +359 -359
  30. {inc → src/inc}/redux/admin-init.php +2 -2
  31. wp-mail-logging.php +4 -5
languages/wp-mail-logging-de_DE.mo CHANGED
Binary file
languages/wp-mail-logging-de_DE.po CHANGED
@@ -4,15 +4,15 @@ msgid ""
4
  msgstr ""
5
  "Project-Id-Version: WP Mail Logging 1.8.0\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wp-mail-logging\n"
7
- "POT-Creation-Date: 2017-01-03 19:59+0100\n"
8
- "PO-Revision-Date: 2018-06-22 17:31+0200\n"
9
  "Last-Translator: \n"
10
  "Language-Team: \n"
11
  "Language: de_DE\n"
12
  "MIME-Version: 1.0\n"
13
  "Content-Type: text/plain; charset=UTF-8\n"
14
  "Content-Transfer-Encoding: 8bit\n"
15
- "X-Generator: Poedit 2.0.8\n"
16
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
17
 
18
  #: WPML_Email_Log_List.php:59
@@ -66,8 +66,8 @@ msgstr "Anhang %s ist nicht vorhanden"
66
  #: WPML_Email_Log_List.php:495
67
  msgid "Fallback to raw format because html is not convertible to json."
68
  msgstr ""
69
- "Darstellung in raw-Format, da eine html Nachricht nicht als json "
70
- "dargestellt werden kann."
71
 
72
  #: WPML_LifeCycle.php:205
73
  msgid "Settings"
4
  msgstr ""
5
  "Project-Id-Version: WP Mail Logging 1.8.0\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wp-mail-logging\n"
7
+ "POT-Creation-Date: 2017-02-12 02:34+0800\n"
8
+ "PO-Revision-Date: 2018-09-13 15:03+0200\n"
9
  "Last-Translator: \n"
10
  "Language-Team: \n"
11
  "Language: de_DE\n"
12
  "MIME-Version: 1.0\n"
13
  "Content-Type: text/plain; charset=UTF-8\n"
14
  "Content-Transfer-Encoding: 8bit\n"
15
+ "X-Generator: Poedit 2.1.1\n"
16
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
17
 
18
  #: WPML_Email_Log_List.php:59
66
  #: WPML_Email_Log_List.php:495
67
  msgid "Fallback to raw format because html is not convertible to json."
68
  msgstr ""
69
+ "Darstellung in raw-Format, da eine html Nachricht nicht als json dargestellt "
70
+ "werden kann."
71
 
72
  #: WPML_LifeCycle.php:205
73
  msgid "Settings"
languages/wp-mail-logging-zh_CN.mo CHANGED
Binary file
languages/wp-mail-logging-zh_CN.po CHANGED
@@ -8,9 +8,9 @@ msgstr ""
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
- "PO-Revision-Date: 2018-06-22 17:31+0200\n"
12
  "Language-Team: \n"
13
- "X-Generator: Poedit 2.0.8\n"
14
  "Plural-Forms: nplurals=1; plural=0;\n"
15
  "Language: zh_CN\n"
16
  "Last-Translator: \n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2018-09-13 14:54+0200\n"
12
  "Language-Team: \n"
13
+ "X-Generator: Poedit 2.1.1\n"
14
  "Plural-Forms: nplurals=1; plural=0;\n"
15
  "Language: zh_CN\n"
16
  "Last-Translator: \n"
languages/wp-mail-logging.pot CHANGED
@@ -2,9 +2,9 @@
2
  # This file is distributed under the GPLv3.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: WP Mail Logging 1.8.4\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wp-mail-logging\n"
7
- "POT-Creation-Date: 2018-06-22 15:35:01+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
@@ -14,295 +14,313 @@ msgstr ""
14
  "X-Generator: grunt-wp-i18n 0.5.4\n"
15
  "Language: en_GB\n"
16
 
17
- #: WPML_Email_Log_List.php:65
18
  msgid "No email found."
19
  msgstr ""
20
 
21
- #: WPML_Email_Log_List.php:77
22
  msgid "ID"
23
  msgstr ""
24
 
25
- #: WPML_Email_Log_List.php:78 inc/redux/WPML_Redux_Framework_config.php:191
 
26
  msgid "Time"
27
  msgstr ""
28
 
29
- #: WPML_Email_Log_List.php:79
30
  msgid "Receiver"
31
  msgstr ""
32
 
33
- #: WPML_Email_Log_List.php:80
34
  msgid "Subject"
35
  msgstr ""
36
 
37
- #: WPML_Email_Log_List.php:81 WPML_OptionsManager.php:497
38
  msgid "Message"
39
  msgstr ""
40
 
41
- #: WPML_Email_Log_List.php:82
42
  msgid "Headers"
43
  msgstr ""
44
 
45
- #: WPML_Email_Log_List.php:83
46
  msgid "Attachments"
47
  msgstr ""
48
 
49
- #: WPML_Email_Log_List.php:84
50
  msgid "Error"
51
  msgstr ""
52
 
53
- #: WPML_Email_Log_List.php:85
54
  msgid "Plugin Version"
55
  msgstr ""
56
 
57
- #: WPML_Email_Log_List.php:96
58
  msgid "Host"
59
  msgstr ""
60
 
61
- #: WPML_Email_Log_List.php:267 WPML_Email_Log_List.php:301
62
  msgid "Attachment %s is not present"
63
  msgstr ""
64
 
65
- #: WPML_Email_Log_List.php:495
66
  msgid "Fallback to raw format because html is not convertible to json."
67
  msgstr ""
68
 
69
- #: WPML_LifeCycle.php:205
70
  msgid "Settings"
71
  msgstr ""
72
 
73
- #: WPML_OptionsManager.php:321 WPML_OptionsManager.php:322
74
  msgid "WP Mail Log"
75
  msgstr ""
76
 
77
- #: WPML_OptionsManager.php:333 WPML_OptionsManager.php:334
78
- #: WPML_OptionsManager.php:345
79
  msgid "About"
80
  msgstr ""
81
 
82
- #: WPML_OptionsManager.php:422
83
  msgid "About Plugin"
84
  msgstr ""
85
 
86
- #: WPML_OptionsManager.php:431
87
  msgid "More information"
88
  msgstr ""
89
 
90
- #: WPML_OptionsManager.php:432
91
  msgid "Plugin Homepage/support"
92
  msgstr ""
93
 
94
- #: WPML_OptionsManager.php:433
95
  msgid "Plugin author's blog"
96
  msgstr ""
97
 
98
- #: WPML_OptionsManager.php:440
99
  msgid "Entries per page"
100
  msgstr ""
101
 
102
- #: WPML_OptionsManager.php:462
103
  msgid "You do not have sufficient permissions to access this page."
104
  msgstr ""
105
 
106
- #: WPML_OptionsManager.php:471
107
  msgid "Log"
108
  msgstr ""
109
 
110
- #: WPML_OptionsManager.php:515
111
  msgid "Close"
112
  msgstr ""
113
 
114
- #: WPML_OptionsManager.php:529
115
  msgid "Search"
116
  msgstr ""
117
 
118
- #: WPML_OptionsManager.php:554
119
  msgid "true"
120
  msgstr ""
121
 
122
- #: WPML_OptionsManager.php:556
123
  msgid "false"
124
  msgstr ""
125
 
126
- #: WPML_OptionsManager.php:559
127
  msgid "Administrator"
128
  msgstr ""
129
 
130
- #: WPML_OptionsManager.php:561
131
  msgid "Editor"
132
  msgstr ""
133
 
134
- #: WPML_OptionsManager.php:563
135
  msgid "Author"
136
  msgstr ""
137
 
138
- #: WPML_OptionsManager.php:565
139
  msgid "Contributor"
140
  msgstr ""
141
 
142
- #: WPML_OptionsManager.php:567
143
  msgid "Subscriber"
144
  msgstr ""
145
 
146
- #: WPML_OptionsManager.php:569
147
  msgid "Anyone"
148
  msgstr ""
149
 
150
- #: inc/class-wp-list-table.php:191
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  msgid "No items found."
152
  msgstr ""
153
 
154
- #: inc/class-wp-list-table.php:315
155
  msgid "Bulk Actions"
156
  msgstr ""
157
 
158
- #: inc/class-wp-list-table.php:325
159
  msgid "Apply"
160
  msgstr ""
161
 
162
- #: inc/class-wp-list-table.php:409
163
  msgid "Show all dates"
164
  msgstr ""
165
 
166
- #: inc/class-wp-list-table.php:422
167
  #. translators: 1: month name, 2: 4-digit year
168
  msgid "%1$s %2$d"
169
  msgstr ""
170
 
171
- #: inc/class-wp-list-table.php:438
172
  msgid "List View"
173
  msgstr ""
174
 
175
- #: inc/class-wp-list-table.php:439
176
  msgid "Excerpt View"
177
  msgstr ""
178
 
179
- #: inc/class-wp-list-table.php:465
180
  msgid "%s pending"
181
  msgstr ""
182
 
183
- #: inc/class-wp-list-table.php:533 inc/class-wp-list-table.php:948
184
  msgid "1 item"
185
  msgid_plural "%s items"
186
  msgstr[0] ""
187
  msgstr[1] ""
188
 
189
- #: inc/class-wp-list-table.php:551
190
  msgid "Go to the first page"
191
  msgstr ""
192
 
193
- #: inc/class-wp-list-table.php:558
194
  msgid "Go to the previous page"
195
  msgstr ""
196
 
197
- #: inc/class-wp-list-table.php:567
198
  msgid "Current page"
199
  msgstr ""
200
 
201
- #: inc/class-wp-list-table.php:577
202
  msgid "Go to the next page"
203
  msgstr ""
204
 
205
- #: inc/class-wp-list-table.php:584
206
  msgid "Go to the last page"
207
  msgstr ""
208
 
209
- #: inc/class-wp-list-table.php:720
210
  msgid "Select All"
211
  msgstr ""
212
 
213
- #: inc/redux/WPML_Redux_Framework_config.php:92
214
  msgid "General Settings"
215
  msgstr ""
216
 
217
- #: inc/redux/WPML_Redux_Framework_config.php:101
218
  msgid "Cleanup"
219
  msgstr ""
220
 
221
- #: inc/redux/WPML_Redux_Framework_config.php:102
222
  msgid "Delete all data on deactivation? (emails and settings)?"
223
  msgstr ""
224
 
225
- #: inc/redux/WPML_Redux_Framework_config.php:112
226
  msgid "Can See Submission data"
227
  msgstr ""
228
 
229
- #: inc/redux/WPML_Redux_Framework_config.php:113
230
  msgid "Select the minimum role."
231
  msgstr ""
232
 
233
- #: inc/redux/WPML_Redux_Framework_config.php:118
234
  msgid "WordPress Date Time Format"
235
  msgstr ""
236
 
237
- #: inc/redux/WPML_Redux_Framework_config.php:119
238
  msgid "Use format from WordPress settings (%s)"
239
  msgstr ""
240
 
241
- #: inc/redux/WPML_Redux_Framework_config.php:121
242
- #: inc/redux/WPML_Redux_Framework_config.php:146
243
- #: inc/redux/WPML_Redux_Framework_config.php:162
244
- #: inc/redux/WPML_Redux_Framework_config.php:184
245
  msgid "Enabled"
246
  msgstr ""
247
 
248
- #: inc/redux/WPML_Redux_Framework_config.php:122
249
- #: inc/redux/WPML_Redux_Framework_config.php:147
250
- #: inc/redux/WPML_Redux_Framework_config.php:163
251
- #: inc/redux/WPML_Redux_Framework_config.php:185
252
  msgid "Disabled"
253
  msgstr ""
254
 
255
- #: inc/redux/WPML_Redux_Framework_config.php:133
256
  msgid "Default Format for Message"
257
  msgstr ""
258
 
259
- #: inc/redux/WPML_Redux_Framework_config.php:134
260
  msgid "Select your preferred display format."
261
  msgstr ""
262
 
263
- #: inc/redux/WPML_Redux_Framework_config.php:139
264
  msgid "Display Host"
265
  msgstr ""
266
 
267
- #: inc/redux/WPML_Redux_Framework_config.php:140
268
  msgid "Display host column in list."
269
  msgstr ""
270
 
271
- #: inc/redux/WPML_Redux_Framework_config.php:152
272
  msgid "Log Rotation"
273
  msgstr ""
274
 
275
- #: inc/redux/WPML_Redux_Framework_config.php:153
276
  msgid "Save space by deleting logs regularly."
277
  msgstr ""
278
 
279
- #: inc/redux/WPML_Redux_Framework_config.php:159
280
  msgid "Cleanup by Amount"
281
  msgstr ""
282
 
283
- #: inc/redux/WPML_Redux_Framework_config.php:160
284
- #: inc/redux/WPML_Redux_Framework_config.php:182
285
  msgid "Setup a automated cleanup routine!"
286
  msgstr ""
287
 
288
- #: inc/redux/WPML_Redux_Framework_config.php:169
289
  msgid "Amount"
290
  msgstr ""
291
 
292
- #: inc/redux/WPML_Redux_Framework_config.php:170
293
- #: inc/redux/WPML_Redux_Framework_config.php:192
294
  msgid "When should mails are deleted?"
295
  msgstr ""
296
 
297
- #: inc/redux/WPML_Redux_Framework_config.php:171
298
  msgid "Cleanup when the stored mails exceed..."
299
  msgstr ""
300
 
301
- #: inc/redux/WPML_Redux_Framework_config.php:181
302
  msgid "Cleanup by Time"
303
  msgstr ""
304
 
305
- #: inc/redux/WPML_Redux_Framework_config.php:193
306
  msgid "Delete mails older than days..."
307
  msgstr ""
308
 
@@ -324,7 +342,7 @@ msgstr ""
324
  msgid "Logs each email sent by WordPress."
325
  msgstr ""
326
 
327
- #: inc/class-wp-list-table.php:573
328
  msgctxt "paging"
329
  msgid "%1$s of %2$s"
330
  msgstr ""
2
  # This file is distributed under the GPLv3.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: WP Mail Logging 1.8.5\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wp-mail-logging\n"
7
+ "POT-Creation-Date: 2018-09-13 13:01:17+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
14
  "X-Generator: grunt-wp-i18n 0.5.4\n"
15
  "Language: en_GB\n"
16
 
17
+ #: src/WPML_Email_Log_List.php:67
18
  msgid "No email found."
19
  msgstr ""
20
 
21
+ #: src/WPML_Email_Log_List.php:79
22
  msgid "ID"
23
  msgstr ""
24
 
25
+ #: src/WPML_Email_Log_List.php:80
26
+ #: src/inc/redux/WPML_Redux_Framework_config.php:191
27
  msgid "Time"
28
  msgstr ""
29
 
30
+ #: src/WPML_Email_Log_List.php:81
31
  msgid "Receiver"
32
  msgstr ""
33
 
34
+ #: src/WPML_Email_Log_List.php:82
35
  msgid "Subject"
36
  msgstr ""
37
 
38
+ #: src/WPML_Email_Log_List.php:83 src/WPML_OptionsManager.php:497
39
  msgid "Message"
40
  msgstr ""
41
 
42
+ #: src/WPML_Email_Log_List.php:84
43
  msgid "Headers"
44
  msgstr ""
45
 
46
+ #: src/WPML_Email_Log_List.php:85
47
  msgid "Attachments"
48
  msgstr ""
49
 
50
+ #: src/WPML_Email_Log_List.php:86
51
  msgid "Error"
52
  msgstr ""
53
 
54
+ #: src/WPML_Email_Log_List.php:87
55
  msgid "Plugin Version"
56
  msgstr ""
57
 
58
+ #: src/WPML_Email_Log_List.php:98
59
  msgid "Host"
60
  msgstr ""
61
 
62
+ #: src/WPML_Email_Log_List.php:266 src/WPML_Email_Log_List.php:300
63
  msgid "Attachment %s is not present"
64
  msgstr ""
65
 
66
+ #: src/WPML_Email_Log_List.php:494
67
  msgid "Fallback to raw format because html is not convertible to json."
68
  msgstr ""
69
 
70
+ #: src/WPML_LifeCycle.php:205
71
  msgid "Settings"
72
  msgstr ""
73
 
74
+ #: src/WPML_OptionsManager.php:321 src/WPML_OptionsManager.php:322
75
  msgid "WP Mail Log"
76
  msgstr ""
77
 
78
+ #: src/WPML_OptionsManager.php:333 src/WPML_OptionsManager.php:334
79
+ #: src/WPML_OptionsManager.php:345
80
  msgid "About"
81
  msgstr ""
82
 
83
+ #: src/WPML_OptionsManager.php:422
84
  msgid "About Plugin"
85
  msgstr ""
86
 
87
+ #: src/WPML_OptionsManager.php:431
88
  msgid "More information"
89
  msgstr ""
90
 
91
+ #: src/WPML_OptionsManager.php:432
92
  msgid "Plugin Homepage/support"
93
  msgstr ""
94
 
95
+ #: src/WPML_OptionsManager.php:433
96
  msgid "Plugin author's blog"
97
  msgstr ""
98
 
99
+ #: src/WPML_OptionsManager.php:440
100
  msgid "Entries per page"
101
  msgstr ""
102
 
103
+ #: src/WPML_OptionsManager.php:462
104
  msgid "You do not have sufficient permissions to access this page."
105
  msgstr ""
106
 
107
+ #: src/WPML_OptionsManager.php:471
108
  msgid "Log"
109
  msgstr ""
110
 
111
+ #: src/WPML_OptionsManager.php:515
112
  msgid "Close"
113
  msgstr ""
114
 
115
+ #: src/WPML_OptionsManager.php:529
116
  msgid "Search"
117
  msgstr ""
118
 
119
+ #: src/WPML_OptionsManager.php:554
120
  msgid "true"
121
  msgstr ""
122
 
123
+ #: src/WPML_OptionsManager.php:556
124
  msgid "false"
125
  msgstr ""
126
 
127
+ #: src/WPML_OptionsManager.php:559
128
  msgid "Administrator"
129
  msgstr ""
130
 
131
+ #: src/WPML_OptionsManager.php:561
132
  msgid "Editor"
133
  msgstr ""
134
 
135
+ #: src/WPML_OptionsManager.php:563
136
  msgid "Author"
137
  msgstr ""
138
 
139
+ #: src/WPML_OptionsManager.php:565
140
  msgid "Contributor"
141
  msgstr ""
142
 
143
+ #: src/WPML_OptionsManager.php:567
144
  msgid "Subscriber"
145
  msgstr ""
146
 
147
+ #: src/WPML_OptionsManager.php:569
148
  msgid "Anyone"
149
  msgstr ""
150
 
151
+ #: src/WPML_PrivacyController.php:43
152
+ msgid ""
153
+ "When you use this site several actions (e.g. commenting) trigger the "
154
+ "dispatch of emails. They contain information about you associated with your "
155
+ "email address. Which data are part of these emails depends on the action "
156
+ "performed. These emails are stored and accessible to the site management as "
157
+ "log."
158
+ msgstr ""
159
+
160
+ #: src/WPML_PrivacyController.php:101
161
+ msgid "Mails"
162
+ msgstr ""
163
+
164
+ #: src/WPML_PrivacyController.php:137
165
+ msgid "A mail with the id %d was unable to be removed at this time."
166
+ msgstr ""
167
+
168
+ #: src/inc/class-wp-list-table.php:191
169
  msgid "No items found."
170
  msgstr ""
171
 
172
+ #: src/inc/class-wp-list-table.php:315
173
  msgid "Bulk Actions"
174
  msgstr ""
175
 
176
+ #: src/inc/class-wp-list-table.php:325
177
  msgid "Apply"
178
  msgstr ""
179
 
180
+ #: src/inc/class-wp-list-table.php:409
181
  msgid "Show all dates"
182
  msgstr ""
183
 
184
+ #: src/inc/class-wp-list-table.php:422
185
  #. translators: 1: month name, 2: 4-digit year
186
  msgid "%1$s %2$d"
187
  msgstr ""
188
 
189
+ #: src/inc/class-wp-list-table.php:438
190
  msgid "List View"
191
  msgstr ""
192
 
193
+ #: src/inc/class-wp-list-table.php:439
194
  msgid "Excerpt View"
195
  msgstr ""
196
 
197
+ #: src/inc/class-wp-list-table.php:465
198
  msgid "%s pending"
199
  msgstr ""
200
 
201
+ #: src/inc/class-wp-list-table.php:533 src/inc/class-wp-list-table.php:948
202
  msgid "1 item"
203
  msgid_plural "%s items"
204
  msgstr[0] ""
205
  msgstr[1] ""
206
 
207
+ #: src/inc/class-wp-list-table.php:551
208
  msgid "Go to the first page"
209
  msgstr ""
210
 
211
+ #: src/inc/class-wp-list-table.php:558
212
  msgid "Go to the previous page"
213
  msgstr ""
214
 
215
+ #: src/inc/class-wp-list-table.php:567
216
  msgid "Current page"
217
  msgstr ""
218
 
219
+ #: src/inc/class-wp-list-table.php:577
220
  msgid "Go to the next page"
221
  msgstr ""
222
 
223
+ #: src/inc/class-wp-list-table.php:584
224
  msgid "Go to the last page"
225
  msgstr ""
226
 
227
+ #: src/inc/class-wp-list-table.php:720
228
  msgid "Select All"
229
  msgstr ""
230
 
231
+ #: src/inc/redux/WPML_Redux_Framework_config.php:92
232
  msgid "General Settings"
233
  msgstr ""
234
 
235
+ #: src/inc/redux/WPML_Redux_Framework_config.php:101
236
  msgid "Cleanup"
237
  msgstr ""
238
 
239
+ #: src/inc/redux/WPML_Redux_Framework_config.php:102
240
  msgid "Delete all data on deactivation? (emails and settings)?"
241
  msgstr ""
242
 
243
+ #: src/inc/redux/WPML_Redux_Framework_config.php:112
244
  msgid "Can See Submission data"
245
  msgstr ""
246
 
247
+ #: src/inc/redux/WPML_Redux_Framework_config.php:113
248
  msgid "Select the minimum role."
249
  msgstr ""
250
 
251
+ #: src/inc/redux/WPML_Redux_Framework_config.php:118
252
  msgid "WordPress Date Time Format"
253
  msgstr ""
254
 
255
+ #: src/inc/redux/WPML_Redux_Framework_config.php:119
256
  msgid "Use format from WordPress settings (%s)"
257
  msgstr ""
258
 
259
+ #: src/inc/redux/WPML_Redux_Framework_config.php:121
260
+ #: src/inc/redux/WPML_Redux_Framework_config.php:146
261
+ #: src/inc/redux/WPML_Redux_Framework_config.php:162
262
+ #: src/inc/redux/WPML_Redux_Framework_config.php:184
263
  msgid "Enabled"
264
  msgstr ""
265
 
266
+ #: src/inc/redux/WPML_Redux_Framework_config.php:122
267
+ #: src/inc/redux/WPML_Redux_Framework_config.php:147
268
+ #: src/inc/redux/WPML_Redux_Framework_config.php:163
269
+ #: src/inc/redux/WPML_Redux_Framework_config.php:185
270
  msgid "Disabled"
271
  msgstr ""
272
 
273
+ #: src/inc/redux/WPML_Redux_Framework_config.php:133
274
  msgid "Default Format for Message"
275
  msgstr ""
276
 
277
+ #: src/inc/redux/WPML_Redux_Framework_config.php:134
278
  msgid "Select your preferred display format."
279
  msgstr ""
280
 
281
+ #: src/inc/redux/WPML_Redux_Framework_config.php:139
282
  msgid "Display Host"
283
  msgstr ""
284
 
285
+ #: src/inc/redux/WPML_Redux_Framework_config.php:140
286
  msgid "Display host column in list."
287
  msgstr ""
288
 
289
+ #: src/inc/redux/WPML_Redux_Framework_config.php:152
290
  msgid "Log Rotation"
291
  msgstr ""
292
 
293
+ #: src/inc/redux/WPML_Redux_Framework_config.php:153
294
  msgid "Save space by deleting logs regularly."
295
  msgstr ""
296
 
297
+ #: src/inc/redux/WPML_Redux_Framework_config.php:159
298
  msgid "Cleanup by Amount"
299
  msgstr ""
300
 
301
+ #: src/inc/redux/WPML_Redux_Framework_config.php:160
302
+ #: src/inc/redux/WPML_Redux_Framework_config.php:182
303
  msgid "Setup a automated cleanup routine!"
304
  msgstr ""
305
 
306
+ #: src/inc/redux/WPML_Redux_Framework_config.php:169
307
  msgid "Amount"
308
  msgstr ""
309
 
310
+ #: src/inc/redux/WPML_Redux_Framework_config.php:170
311
+ #: src/inc/redux/WPML_Redux_Framework_config.php:192
312
  msgid "When should mails are deleted?"
313
  msgstr ""
314
 
315
+ #: src/inc/redux/WPML_Redux_Framework_config.php:171
316
  msgid "Cleanup when the stored mails exceed..."
317
  msgstr ""
318
 
319
+ #: src/inc/redux/WPML_Redux_Framework_config.php:181
320
  msgid "Cleanup by Time"
321
  msgstr ""
322
 
323
+ #: src/inc/redux/WPML_Redux_Framework_config.php:193
324
  msgid "Delete mails older than days..."
325
  msgstr ""
326
 
342
  msgid "Logs each email sent by WordPress."
343
  msgstr ""
344
 
345
+ #: src/inc/class-wp-list-table.php:573
346
  msgctxt "paging"
347
  msgid "%1$s of %2$s"
348
  msgstr ""
lib/vendor/brandonwamboldt/wp-orm/README.md ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ WordPress ORM
2
+ =============
3
+
4
+ WordPress ORM is a small library that adds a basic ORM into WordPress, which is easily extendable and includes models for core WordPress models such as posts, pages, comments and users. It's designed to allow you to easily add new models other than custom post types, and not have to write a lot of manual SQL.
5
+
6
+ Installation
7
+ ------------
8
+
9
+ While you can install and activate it like a normal plugin, I'd recommend putting it in the `/wp-content/mu-plugins` folder and adding a script called `wp-orm.php` to load the main plugin file (only top level `.php` files are loaded from `mu-plugins`).
10
+
11
+ `wp-orm.php`:
12
+
13
+ ```php
14
+ <?php require 'wp-orm/wp-orm.php';
15
+ ```
16
+
17
+ Examples
18
+ --------
19
+
20
+ #### Get 5 published pages, ordered by post title.
21
+
22
+ ```php
23
+ use WordPress\ORM\Model\Page;
24
+
25
+ $pages = Page::query()
26
+ ->limit(5)
27
+ ->where('post_status', 'publish')
28
+ ->sort_by('post_title')
29
+ ->order('ASC')
30
+ ->find();
31
+ ```
32
+
33
+ #### Find a user by their login
34
+
35
+ ```php
36
+ use WordPress\ORM\Model\User;
37
+
38
+ $user = User::find_one_by('user_login', 'brandon');
39
+
40
+ echo $user->get_user_login();
41
+
42
+ print_r($user->to_array());
43
+ ```
44
+
45
+ #### Example of a more complex query
46
+
47
+ ```php
48
+ use WordPress\ORM\Model\Post;
49
+
50
+ $posts = Post::query()
51
+ ->limit(15)
52
+ ->offset(0)
53
+ ->where_all(['post_status' => 'publish', 'post_type' => 'post'])
54
+ ->where_like('post_title', '%Hello world%')
55
+ ->sort_by('post_title')
56
+ ->order('ASC')
57
+ ->find();
58
+ ```
59
+
60
+ #### Updating a model
61
+
62
+ ```php
63
+ use WordPress\ORM\Model\Post;
64
+
65
+ $post = Post::find_one(1204);
66
+ $post->set_post_title('What an amazing post!');
67
+ $post->save();
68
+ ```
69
+
70
+ #### Meta data
71
+
72
+ Users, posts, pages and comments all support meta data.
73
+
74
+ ```php
75
+ $post = Post::find_one(1337);
76
+ $post->get_metadata('_edit_lock');
77
+ $post->update_metadata('_edit_lock', '');
78
+ $post->delete_metadata('_edit_lock');
79
+ ```
80
+
81
+ Meta data is saved immediately using WordPress meta data functions under the hood. Calling `save()` is not needed.
82
+
83
+ Custom Models
84
+ -------------
85
+
86
+ ```php
87
+ <?php
88
+
89
+ namespace WordPress\ORM;
90
+
91
+ class Venue extends BaseModel
92
+ {
93
+ protected $id;
94
+ protected $venue_title;
95
+ protected $description;
96
+ protected $now_playing;
97
+ protected $location;
98
+ protected $avg_rating;
99
+
100
+ public static function get_primary_key()
101
+ {
102
+ return 'id';
103
+ }
104
+
105
+ public static function get_table()
106
+ {
107
+ return 'wp_venues';
108
+ }
109
+
110
+ public static function get_searchable_fields()
111
+ {
112
+ return ['venue_title', 'description', 'now_playing'];
113
+ }
114
+ }
115
+ ```
116
+
117
+ You can now use this venue, persist it, and use the custom query DSL shown above to query it.
118
+
119
+ Model Methods
120
+ -------------
121
+
122
+ ##### Model::get_table()
123
+
124
+ This is a static method that you must define in your models, and should return the table to persist data to.
125
+
126
+ ##### Model::get_searchable_fields()
127
+
128
+ This is a static method that you must define in your models, and should return an array of properties to search when doing a search query.
129
+
130
+ ##### Model::get_primary_key()
131
+
132
+ Return's the property used as a primary key. Defaults to `id`.
133
+
134
+ ##### Model::create(array $properties)
135
+
136
+ Create a new model from an array of properties.
137
+
138
+ ##### Model::find_one_by(string $property, mixed $value)
139
+
140
+ Find a single model with the specified property value.
141
+
142
+ ##### Model::find_one(integer $id)
143
+
144
+ Find a single model who's primary key is equal to the given ID.
145
+
146
+ ##### Model::query()
147
+
148
+ Return a new `WordPress\ORM\Query` object.
149
+
150
+ ##### Model::all()
151
+
152
+ Return every single model in the database.
153
+
154
+ ##### $model->primary_key()
155
+
156
+ Return the model's primary key (the value, not the property name).
157
+
158
+ ##### $model->to_array()
159
+
160
+ Return all of the model's properties as an array.
161
+
162
+ ##### $model->flatten_props(array $props)
163
+
164
+ Call right before `save()`, should flatten any objects in the properties into strings so they can be persisted. Defaults to flattening `DateTime` objects into a timestamp and arrays into a serialized array.
165
+
166
+ ##### $model->save()
167
+
168
+ Save your model to the database. Creates a new row if the model doesn't have an ID, or updates an existing row if their is an ID.
169
+
170
+ ##### $model->delete()
171
+
172
+ Delete the model from the database. Returns `true` if it was successful or `false` if it was not.
173
+
174
+ ORM Queries
175
+ -----------
176
+
177
+ Below are the functions you have access to after you call the `Model::query()` function.
178
+
179
+ ##### $query->limit(integer $limit)
180
+
181
+ Limits the number of results returned using an SQL `LIMIT` clause.
182
+
183
+ ##### $query->offset(integer $offset)
184
+
185
+ Offset the results returned, used with pagination. Uses the SQL `OFFSET` clause.
186
+
187
+ ##### $query->sort_by(string $property)
188
+
189
+ Sort results by the specified property. Can also be a MySQL function such as `RAND()`.
190
+
191
+ ##### $query->order(string $order)
192
+
193
+ Order the results in the given order. Can be one of `ASC` or `DESC`.
194
+
195
+ ##### $query->search(string $search_term)
196
+
197
+ Limit results to items matching the given search term. Searches the properties returned by `Model::get_searchable_fields`.
198
+
199
+ ##### $query->where(string $property, string $value)
200
+
201
+ Add a parameter to the where clause. Equivalent to ` WHERE $property = '$value'`. `$value` is automatically escaped.
202
+
203
+ ##### $query->where_not(string $property, string $value)
204
+
205
+ Add a parameter to the where clause. Equivalent to ` WHERE $property != '$value'`. `$value` is automatically escaped.
206
+
207
+ ##### $query->where_like(string $property, string $value)
208
+
209
+ Add a parameter to the where clause. Equivalent to ` WHERE $property LIKE '$value'`. `$value` is automatically escaped.
210
+
211
+ ##### $query->where_not_like(string $property, string $value)
212
+
213
+ Add a parameter to the where clause. Equivalent to ` WHERE $property NOT LIKE '$value'`. `$value` is automatically escaped.
214
+
215
+ ##### $query->where_lt(string $property, string $value)
216
+
217
+ Add a parameter to the where clause. Equivalent to ` WHERE $property < '$value'`. `$value` is automatically escaped.
218
+
219
+ ##### $query->where_lte(string $property, string $value)
220
+
221
+ Add a parameter to the where clause. Equivalent to ` WHERE $property <= '$value'`. `$value` is automatically escaped.
222
+
223
+ ##### $query->where_gt(string $property, string $value)
224
+
225
+ Add a parameter to the where clause. Equivalent to ` WHERE $property > '$value'`. `$value` is automatically escaped.
226
+
227
+ ##### $query->where_gte(string $property, string $value)
228
+
229
+ Add a parameter to the where clause. Equivalent to ` WHERE $property >= '$value'`. `$value` is automatically escaped.
230
+
231
+ ##### $query->where_in(string $column, array $in)
232
+
233
+ Limit results to items where the given column is one of the given values. Equivalent to ` WHERE $property IN ('value1', 'value2')` where `value1` and `value2` are values in the array.
234
+
235
+ ##### $query->where_not_in(string $column, array $in)
236
+
237
+ Limit results to items where the given column is not one of the given values. Equivalent to ` WHERE $property NOT IN ('value1', 'value2')` where `value1` and `value2` are values in the array.
238
+
239
+ ##### $query->where_any(array $where)
240
+
241
+ Limit results to items that match any of the property/value pairs given in the array. Must match at least one.
242
+
243
+ ##### $query->where_all(array $where)
244
+
245
+ Limit results to items that match all of the property/value pairs given in the array.
246
+
247
+ Actions & Filters
248
+ -----------------
249
+
250
+ #### wporm_query($sql, $model_class)
251
+
252
+ Manipulate the raw SQL query created by the Query class.
253
+
254
+ ```php
255
+ add_filter('wporm_query', function($sql, $model_class) {
256
+ if ($model_class == 'WordPress\ORM\Model\Page') {
257
+ $sql = str_replace('wp_posts', 'wp2_posts', $sql);
258
+ }
259
+
260
+ return $sql;
261
+ }, 10, 2);
262
+ ```
263
+
264
+ #### wporm_count_query($sql, $model_class)
265
+
266
+ Manipulate the raw SQL query created by the Query class (the row count variation).
267
+
268
+ ```php
269
+ add_filter('wporm_count_query', function($sql, $model_class) {
270
+ if ($model_class == 'WordPress\ORM\Model\Page') {
271
+ $sql = str_replace('wp_posts', 'wp2_posts', $sql);
272
+ }
273
+
274
+ return $sql;
275
+ }, 10, 2);
276
+ ```
277
+
278
+ License
279
+ -------
280
+
281
+ This code is licensed under the MIT license.
lib/vendor/brandonwamboldt/wp-orm/src/BaseModel.php CHANGED
@@ -9,6 +9,12 @@ namespace No3x\WPML\ORM;
9
  */
10
  abstract class BaseModel implements ModelInterface
11
  {
 
 
 
 
 
 
12
  /**
13
  * Get the column used as the primary key, defaults to 'id'.
14
  *
@@ -211,13 +217,24 @@ abstract class BaseModel implements ModelInterface
211
  */
212
  public static function query()
213
  {
214
- $query = new Query(get_called_class());
215
  $query->set_searchable_fields(static::get_searchable_fields());
216
  $query->set_primary_key(static::get_primary_key());
217
 
218
  return $query;
219
  }
220
 
 
 
 
 
 
 
 
 
 
 
 
221
  /**
222
  * Return EVERY instance of this model from the database, with NO filtering.
223
  *
9
  */
10
  abstract class BaseModel implements ModelInterface
11
  {
12
+
13
+ /**
14
+ * @var QueryFactory
15
+ */
16
+ private static $queryFactory;
17
+
18
  /**
19
  * Get the column used as the primary key, defaults to 'id'.
20
  *
217
  */
218
  public static function query()
219
  {
220
+ $query = self::getQueryFactory()->buildQuery(get_called_class());
221
  $query->set_searchable_fields(static::get_searchable_fields());
222
  $query->set_primary_key(static::get_primary_key());
223
 
224
  return $query;
225
  }
226
 
227
+ public static function getQueryFactory() {
228
+ if (!isset(self::$queryFactory)) {
229
+ self::$queryFactory = new DefaultQueryFactory();
230
+ }
231
+ return self::$queryFactory;
232
+ }
233
+
234
+ public static function setQueryFactory(QueryFactory $queryFactory) {
235
+ self::$queryFactory = $queryFactory;
236
+ }
237
+
238
  /**
239
  * Return EVERY instance of this model from the database, with NO filtering.
240
  *
lib/vendor/brandonwamboldt/wp-orm/src/DefaultQueryFactory.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace No3x\WPML\ORM;
4
+
5
+
6
+ class DefaultQueryFactory implements QueryFactory {
7
+ public function buildQuery($modelClass) {
8
+ return new Query($modelClass);
9
+ }
10
+ }
lib/vendor/brandonwamboldt/wp-orm/src/QueryFactory.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace No3x\WPML\ORM;
4
+
5
+
6
+ interface QueryFactory {
7
+ public function buildQuery($modelClass);
8
+ }
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: mail, email, log, logging, debug, list, store, collect, view
5
  License: GPLv3
6
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
7
  Requires at least: 3.0
8
- Tested up to: 4.9.6
9
  Stable tag: 1.8.4
10
 
11
  Logs each email sent by WordPress.
@@ -41,7 +41,7 @@ I recommend the following plugins if you want to send mails via SMTP because the
41
  == Frequently Asked Questions ==
42
  = How do I know the mail was sent? =
43
  If there is no error logged chances are high the mail was sent. There are plugins that overwrite (do not customize) the default mailing mechanism of WordPress - they maybe do not inform about failure so it can't be logged by WP Mail Logging.
44
- = How do I know the wail was delivered? =
45
  The logged email has been sent by WordPress but please note this does NOT mean it has been delivered. With the given functionality of WordPress you can't determine if a mail was delivered successfully.
46
 
47
  == Screenshots ==
@@ -50,12 +50,20 @@ The logged email has been sent by WordPress but please note this does NOT mean i
50
  3. The Settings
51
 
52
  == Upgrade Notice ==
53
- = 1.8.4 =
54
- - Fix: transient bug
55
- - Fix: notice when attachments not set
 
 
56
 
57
  == Changelog ==
58
 
 
 
 
 
 
 
59
  = 1.8.4, June 22, 2018 =
60
  - Fix: transient bug
61
  - Fix: notice when attachments not set
5
  License: GPLv3
6
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
7
  Requires at least: 3.0
8
+ Tested up to: 4.9.8
9
  Stable tag: 1.8.4
10
 
11
  Logs each email sent by WordPress.
41
  == Frequently Asked Questions ==
42
  = How do I know the mail was sent? =
43
  If there is no error logged chances are high the mail was sent. There are plugins that overwrite (do not customize) the default mailing mechanism of WordPress - they maybe do not inform about failure so it can't be logged by WP Mail Logging.
44
+ = How do I know the mail was delivered? =
45
  The logged email has been sent by WordPress but please note this does NOT mean it has been delivered. With the given functionality of WordPress you can't determine if a mail was delivered successfully.
46
 
47
  == Screenshots ==
50
  3. The Settings
51
 
52
  == Upgrade Notice ==
53
+ = 1.8.5 =
54
+ - New: added privacy integration (erasure, export, policy content suggestion)
55
+ - Fix: typo in readme
56
+ - Fix: output of html comments in emails
57
+ - Tweak: performance (duplicate queries of installation state)
58
 
59
  == Changelog ==
60
 
61
+ = 1.8.5, September 13, 2018 =
62
+ - New: added privacy integration (erasure, export, policy content suggestion)
63
+ - Fix: typo in readme
64
+ - Fix: output of html comments in emails
65
+ - Tweak: performance (duplicate queries of installation state)
66
+
67
  = 1.8.4, June 22, 2018 =
68
  - Fix: transient bug
69
  - Fix: notice when attachments not set
{model → src/Model}/WPML_Mail.php RENAMED
@@ -66,9 +66,8 @@ class WPML_Mail extends BaseModel
66
  protected $plugin_version;
67
 
68
  /**
69
- * @var string
70
  */
71
-
72
  public function __construct(array $properties = array())
73
  {
74
  parent::__construct($properties);
@@ -104,4 +103,4 @@ class WPML_Mail extends BaseModel
104
  {
105
  return array('receiver', 'subject', 'headers', 'message', 'attachments', 'host');
106
  }
107
- }
66
  protected $plugin_version;
67
 
68
  /**
69
+ * @param array $properties
70
  */
 
71
  public function __construct(array $properties = array())
72
  {
73
  parent::__construct($properties);
103
  {
104
  return array('receiver', 'subject', 'headers', 'message', 'attachments', 'host');
105
  }
106
+ }
WPML_API_Example.php → src/WPML_API_Example.php RENAMED
@@ -1,85 +1,85 @@
1
- <?php
2
-
3
- namespace No3x\WPML;
4
-
5
- // Exit if accessed directly.
6
- if ( ! defined( 'ABSPATH' ) ) exit;
7
-
8
- /**
9
- * @author No3x
10
- * @since 1.0
11
- * The Plugin provides mechanisms to extend the displayed data.
12
- * This class is not an API class. It is just an example how to hook in.
13
- * If you consider writing a plugin please contact me for better hook support/documentation.
14
- */
15
- class WPML_API_Example {
16
-
17
- // require_once('WPML_API_Example.php');
18
- // $aAPI = new WPML_API_Example();
19
-
20
- public function addActionsAndFilters() {
21
- // In this example we are going to add a column 'test' in add_column.
22
- add_filter( WPML_Plugin::HOOK_LOGGING_COLUMNS, array( &$this, 'add_column' ) );
23
- add_filter( WPML_Plugin::HOOK_LOGGING_COLUMNS_RENDER, array( &$this, 'render_column' ), 10, 2 );
24
- // Change the supported formats of modal e.g. dashed:
25
- add_filter( WPML_Plugin::HOOK_LOGGING_SUPPORTED_FORMATS, array( &$this, 'add_supported_format') );
26
- // Change content of format dashed HOOK_LOGGING_FORMAT_CONTENT_{$your_format} e.g. dashed:
27
- add_filter( WPML_Plugin::HOOK_LOGGING_FORMAT_CONTENT . '_dashed', array( &$this, 'supported_format_dashed') );
28
- }
29
-
30
- /**
31
- * Is called when List Table is gathering columns.
32
- * @since 1.0
33
- * @param array $columns Array of columns.
34
- * @return array $columns Updated array of columns.
35
- */
36
- public function add_column( $columns ) {
37
- return $columns = array_merge( $columns,
38
- array( 'test' => 'test' )
39
- //,array('test2' => 'wp-mail-logging' ) // ...
40
- );
41
- }
42
-
43
- /**
44
- * Is called when the List Table could not find the column. So we can hook in and modify the column.
45
- * @since 1.0
46
- * @param array $item A singular item (one full row's worth of data).
47
- * @param array $column_name The name/slug of the column to be processed.
48
- * @return string Text or HTML to be placed inside the column <td>
49
- */
50
- public function render_column( $item, $column_name ) {
51
- switch ( $column_name ) {
52
- case 'test':
53
- return 'display relevant data. item contains all information you need about the row. You can process the data and add the result to this column. You can access it like this: $item[$column_name]';
54
- default:
55
- return '';
56
- }
57
- }
58
-
59
- /**
60
- * Is called when supported formats are collected. You can add a format here then you can provide a content function.
61
- * @since 1.6.0
62
- * @param array $formats supported formats
63
- * @return array supported formats + your additional formats
64
- * @see WPML_Plugin::HOOK_LOGGING_SUPPORTED_FORMATS
65
- */
66
- public function add_supported_format( $formats ) {
67
- $formats[] = 'dashed';
68
- return $formats;
69
- }
70
-
71
- /**
72
- * This function is called for each of your additional formats. Change the content of the modal here.
73
- * For example I add some dashes.
74
- * @since 1.6.0
75
- * @param $mail
76
- * @return string
77
- * @see WPML_Plugin::HOOK_LOGGING_FORMAT_CONTENT
78
- */
79
- public function supported_format_dashed( $mail ) {
80
- $dashedAppend = '';
81
- foreach( $mail as $property => $value )
82
- $dashedAppend .= str_replace(' ', '-', $value);
83
- return $dashedAppend;
84
- }
85
- }
1
+ <?php
2
+
3
+ namespace No3x\WPML;
4
+
5
+ // Exit if accessed directly.
6
+ if ( ! defined( 'ABSPATH' ) ) exit;
7
+
8
+ /**
9
+ * @author No3x
10
+ * @since 1.0
11
+ * The Plugin provides mechanisms to extend the displayed data.
12
+ * This class is not an API class. It is just an example how to hook in.
13
+ * If you consider writing a plugin please contact me for better hook support/documentation.
14
+ */
15
+ class WPML_API_Example {
16
+
17
+ // require_once('WPML_API_Example.php');
18
+ // $aAPI = new WPML_API_Example();
19
+
20
+ public function addActionsAndFilters() {
21
+ // In this example we are going to add a column 'test' in add_column.
22
+ add_filter( WPML_Plugin::HOOK_LOGGING_COLUMNS, array( &$this, 'add_column' ) );
23
+ add_filter( WPML_Plugin::HOOK_LOGGING_COLUMNS_RENDER, array( &$this, 'render_column' ), 10, 2 );
24
+ // Change the supported formats of modal e.g. dashed:
25
+ add_filter( WPML_Plugin::HOOK_LOGGING_SUPPORTED_FORMATS, array( &$this, 'add_supported_format') );
26
+ // Change content of format dashed HOOK_LOGGING_FORMAT_CONTENT_{$your_format} e.g. dashed:
27
+ add_filter( WPML_Plugin::HOOK_LOGGING_FORMAT_CONTENT . '_dashed', array( &$this, 'supported_format_dashed') );
28
+ }
29
+
30
+ /**
31
+ * Is called when List Table is gathering columns.
32
+ * @since 1.0
33
+ * @param array $columns Array of columns.
34
+ * @return array $columns Updated array of columns.
35
+ */
36
+ public function add_column( $columns ) {
37
+ return $columns = array_merge( $columns,
38
+ array( 'test' => 'test' )
39
+ //,array('test2' => 'wp-mail-logging' ) // ...
40
+ );
41
+ }
42
+
43
+ /**
44
+ * Is called when the List Table could not find the column. So we can hook in and modify the column.
45
+ * @since 1.0
46
+ * @param array $item A singular item (one full row's worth of data).
47
+ * @param array $column_name The name/slug of the column to be processed.
48
+ * @return string Text or HTML to be placed inside the column <td>
49
+ */
50
+ public function render_column( $item, $column_name ) {
51
+ switch ( $column_name ) {
52
+ case 'test':
53
+ return 'display relevant data. item contains all information you need about the row. You can process the data and add the result to this column. You can access it like this: $item[$column_name]';
54
+ default:
55
+ return '';
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Is called when supported formats are collected. You can add a format here then you can provide a content function.
61
+ * @since 1.6.0
62
+ * @param array $formats supported formats
63
+ * @return array supported formats + your additional formats
64
+ * @see WPML_Plugin::HOOK_LOGGING_SUPPORTED_FORMATS
65
+ */
66
+ public function add_supported_format( $formats ) {
67
+ $formats[] = 'dashed';
68
+ return $formats;
69
+ }
70
+
71
+ /**
72
+ * This function is called for each of your additional formats. Change the content of the modal here.
73
+ * For example I add some dashes.
74
+ * @since 1.6.0
75
+ * @param $mail
76
+ * @return string
77
+ * @see WPML_Plugin::HOOK_LOGGING_FORMAT_CONTENT
78
+ */
79
+ public function supported_format_dashed( $mail ) {
80
+ $dashedAppend = '';
81
+ foreach( $mail as $property => $value )
82
+ $dashedAppend .= str_replace(' ', '-', $value);
83
+ return $dashedAppend;
84
+ }
85
+ }
WPML_DI_Container.php → src/WPML_DI_Container.php RENAMED
@@ -1,24 +1,24 @@
1
- <?php
2
- /**
3
- * User: No3x
4
- * Date: 06.09.15
5
- * Time: 12:47
6
- */
7
-
8
- namespace No3x\WPML;
9
- use No3x\WPML\Pimple\Container;
10
-
11
- class WPML_DI_Container extends Container {
12
-
13
- public function addActionsAndFilters() {
14
- foreach ( $this->keys() as $key ) {
15
- $content = $this[ $key ];
16
- if ( is_object( $content ) ) {
17
- $reflection = new \ReflectionClass( $content );
18
- if ( $reflection->hasMethod( 'addActionsAndFilters' ) ) {
19
- $content->addActionsAndFilters();
20
- }
21
- }
22
- }
23
- }
24
- }
1
+ <?php
2
+ /**
3
+ * User: No3x
4
+ * Date: 06.09.15
5
+ * Time: 12:47
6
+ */
7
+
8
+ namespace No3x\WPML;
9
+ use No3x\WPML\Pimple\Container;
10
+
11
+ class WPML_DI_Container extends Container {
12
+
13
+ public function addActionsAndFilters() {
14
+ foreach ( $this->keys() as $key ) {
15
+ $content = $this[ $key ];
16
+ if ( is_object( $content ) ) {
17
+ $reflection = new \ReflectionClass( $content );
18
+ if ( $reflection->hasMethod( 'addActionsAndFilters' ) ) {
19
+ $content->addActionsAndFilters();
20
+ }
21
+ }
22
+ }
23
+ }
24
+ }
WPML_Email_Dispatcher.php → src/WPML_Email_Dispatcher.php RENAMED
@@ -1,18 +1,18 @@
1
- <?php
2
- /**
3
- * Created by IntelliJ IDEA.
4
- * User: czoeller
5
- * Date: 08.06.17
6
- * Time: 15:48
7
- */
8
-
9
- namespace No3x\WPML;
10
-
11
-
12
- class WPML_Email_Dispatcher {
13
-
14
- public function dispatch( $to, $subject, $message, $headers = '', $attachments = array() )
15
- {
16
- wp_mail( $to, $subject, $message, $headers, $attachments);
17
- }
18
- }
1
+ <?php
2
+ /**
3
+ * Created by IntelliJ IDEA.
4
+ * User: czoeller
5
+ * Date: 08.06.17
6
+ * Time: 15:48
7
+ */
8
+
9
+ namespace No3x\WPML;
10
+
11
+
12
+ class WPML_Email_Dispatcher {
13
+
14
+ public function dispatch( $to, $subject, $message, $headers = '', $attachments = array() )
15
+ {
16
+ wp_mail( $to, $subject, $message, $headers, $attachments);
17
+ }
18
+ }
WPML_Email_Log_List.php → src/WPML_Email_Log_List.php RENAMED
@@ -1,510 +1,509 @@
1
- <?php
2
-
3
- namespace No3x\WPML;
4
-
5
- use No3x\WPML\Model\WPML_Mail as Mail;
6
- use No3x\WPML\Model\WPML_Mail;
7
-
8
- // Exit if accessed directly.
9
- if ( ! defined( 'ABSPATH' ) ) exit;
10
-
11
- require_once( ABSPATH . 'wp-admin/includes/screen.php' );
12
- require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
13
-
14
- if ( ! class_exists( 'WP_List_Table' ) ) {
15
- require_once( plugin_dir_path( __FILE__ ) . 'inc/class-wp-list-table.php' );
16
- }
17
-
18
- /**
19
- * Renders the mails in a table list.
20
- * @author No3x
21
- * @since 1.0
22
- */
23
- class WPML_Email_Log_List extends \WP_List_Table {
24
-
25
- const NONCE_LIST_TABLE = 'wpml-list_table';
26
- private $supported_formats = array();
27
- /** @var WPML_Email_Resender $emailResender */
28
- private $emailResender;
29
-
30
- /**
31
- * Initializes the List Table
32
- * @since 1.0
33
- * @param array $supported_formats
34
- * @param WPML_Email_Resender $emailResender
35
- */
36
- function __construct( $supported_formats = array(), $emailResender ) {
37
- $this->supported_formats = $supported_formats;
38
- $this->emailResender = $emailResender;
39
- }
40
-
41
- function addActionsAndFilters() {
42
- add_action( 'admin_init', array( $this, 'init') );
43
- add_filter( WPML_Plugin::HOOK_LOGGING_SUPPORTED_FORMATS, function() {
44
- return $this->supported_formats;
45
- } );
46
- add_action( 'wp_ajax_wpml_email_get', __CLASS__ . '::ajax_wpml_email_get' );
47
- }
48
-
49
- function init() {
50
- global $status, $page, $hook_suffix;
51
-
52
- parent::__construct( array(
53
- 'singular' => 'email', // singular name of the listed records
54
- 'plural' => 'emails', // plural name of the listed records
55
- 'ajax' => false, // does this table support ajax?
56
- ) );
57
- }
58
-
59
- /**
60
- * Is displayed if no item is available to render
61
- * @since 1.0
62
- * @see WP_List_Table::no_items()
63
- */
64
- function no_items() {
65
- _e( 'No email found.', 'wp-mail-logging' );
66
- return;
67
- }
68
-
69
- /**
70
- * Defines the available columns.
71
- * @since 1.0
72
- * @see WP_List_Table::get_columns()
73
- */
74
- function get_columns() {
75
- $columns = array(
76
- 'cb' => '<input type="checkbox" />',
77
- 'mail_id' => __( 'ID', 'wp-mail-logging' ),
78
- 'timestamp' => __( 'Time', 'wp-mail-logging' ),
79
- 'receiver' => __( 'Receiver', 'wp-mail-logging' ),
80
- 'subject' => __( 'Subject', 'wp-mail-logging' ),
81
- 'message' => __( 'Message', 'wp-mail-logging' ),
82
- 'headers' => __( 'Headers', 'wp-mail-logging' ),
83
- 'attachments' => __( 'Attachments', 'wp-mail-logging' ),
84
- 'error' => __( 'Error', 'wp-mail-logging' ),
85
- 'plugin_version' => __( 'Plugin Version', 'wp-mail-logging' ),
86
- );
87
-
88
- /* @var $instance WPML_Plugin */
89
- $instance = WPML_Init::getInstance()->getService( 'plugin' );
90
-
91
- $switch = $instance->getSetting('display-host', false );
92
- if( true == $switch ) {
93
- $posAfterTimestamp = array_search('timestamp', array_keys($columns) ) + 1;
94
- $columns = array_merge(
95
- array_slice( $columns, 0, $posAfterTimestamp),
96
- [ 'host' => __( 'Host', 'wp-mail-logging' ) ],
97
- array_slice( $columns, $posAfterTimestamp )
98
- );
99
- }
100
-
101
- // Give a plugin the chance to edit the columns.
102
- $columns = apply_filters( WPML_Plugin::HOOK_LOGGING_COLUMNS, $columns );
103
-
104
- $reserved = array( '_title', 'comment', 'media', 'name', 'title', 'username', 'blogname' );
105
-
106
- // Show message for reserved column names.
107
- foreach ( $reserved as $reserved_key ) {
108
- if ( array_key_exists( $reserved_key, $columns ) ) {
109
- echo "You should avoid $reserved_key as keyname since it is treated by WordPress specially: Your table would still work, but you won't be able to show/hide the columns. You can prefix your columns!";
110
- break;
111
- }
112
- }
113
- return $columns;
114
- }
115
-
116
- /**
117
- * Define which columns are hidden
118
- * @since 1.0
119
- * @return array
120
- */
121
- function get_hidden_columns() {
122
- return array(
123
- 'plugin_version',
124
- 'mail_id',
125
- );
126
- }
127
-
128
- /**
129
- * Sanitize orderby parameter.
130
- * @s
131
- * @return string sanitized orderby parameter
132
- */
133
- private function sanitize_orderby() {
134
- return WPML_Utils::sanitize_expected_value( ( !empty( $_GET['orderby'] ) ) ? $_GET['orderby'] : null, $this->get_sortable_columns(), 'mail_id');
135
- }
136
-
137
- /**
138
- * Sanitize order parameter.
139
- * @return string sanitized order parameter
140
- */
141
- private function sanitize_order() {
142
- return WPML_Utils::sanitize_expected_value( ( !empty( $_GET['order'] ) ) ? $_GET['order'] : null, array('desc', 'asc'), 'desc');
143
- }
144
-
145
- /**
146
- * Prepares the items for rendering
147
- * @since 1.0
148
- * @param string|boolean $search string you want to search for. Default false.
149
- * @see WP_List_Table::prepare_items()
150
- */
151
- function prepare_items( $search = false ) {
152
- $orderby = $this->sanitize_orderby();
153
- $order = $this->sanitize_order();
154
-
155
- $columns = $this->get_columns();
156
- $hidden = $this->get_hidden_columns();
157
- $sortable = $this->get_sortable_columns();
158
- $this->_column_headers = array( $columns, $hidden, $sortable );
159
-
160
- $this->process_bulk_action();
161
-
162
- $per_page = $this->get_items_per_page( 'per_page', 25 );
163
- $current_page = $this->get_pagenum();
164
- $offset = ( $current_page - 1 ) * $per_page;
165
-
166
- $total_items = Mail::query()
167
- ->search( $search )
168
- ->find( true );
169
-
170
- $mails = Mail::query()
171
- ->search( $search )
172
- ->sort_by( $orderby )
173
- ->order( $order )
174
- ->limit( $per_page )
175
- ->offset( $offset )
176
- ->find();
177
-
178
- foreach ( $mails as $mail ) {
179
- /* @var $mail Mail */
180
- $this->items[] = $mail->to_array();
181
- }
182
-
183
- $this->set_pagination_args( array(
184
- 'total_items' => $total_items, // The total number of items.
185
- 'per_page' => $per_page, // Number of items per page.
186
- ) );
187
- }
188
-
189
- /**
190
- * Renders the cell.
191
- * Note: We can easily add filter for all columns if you want to / need to manipulate the content. (currently only additional column manipulation is supported)
192
- * @since 1.0
193
- * @param array $item The current item.
194
- * @param string $column_name The current column name.
195
- * @return string The cell content
196
- */
197
- function column_default( $item, $column_name ) {
198
- $column_content = '';
199
-
200
- // colmn_message is handled called directly by the list table by naming it colmn_$name. All other columns pass this function and might be named column_overridden_$column_name for further adaptation on output.
201
- if ( method_exists( $this, 'column_overridden_' . $column_name ) ) {
202
- $column_content = call_user_func( array( $this, 'column_overridden_' . $column_name ), $item );
203
- } elseif( array_key_exists( $column_name, $item ) ) {
204
- $column_content = $item[ $column_name ];
205
- } else {
206
- // If we don't know this column maybe a hook does - if no hook extracted data (string) out of the array we can avoid the output of 'Array()' (array).
207
- $column_content = ( is_array( $res = apply_filters( WPML_Plugin::HOOK_LOGGING_COLUMNS_RENDER, $item, $column_name ) ) ) ? '' : $res;
208
- }
209
-
210
- return $this->sanitize_text($column_content);
211
- }
212
-
213
- /**
214
- * Sanitize text to remove unsafe html.
215
- * @since 1.5.1
216
- * @param string $message unsafe text.
217
- * @return string safe text.
218
- */
219
- function sanitize_text( $message ) {
220
- $allowed_tags = wp_kses_allowed_html( 'post' );
221
- $allowed_tags['a']['data-message'] = true;
222
- $allowed_tags['style'][''] = true;
223
- return wp_kses( $message, $allowed_tags );
224
- }
225
-
226
- /**
227
- * Renders the message column.
228
- * @since 1.3
229
- * @param array $item The current item.
230
- * @return string
231
- */
232
- function column_message( $item ) {
233
- $content = $item['mail_id'];
234
- $message = '<a class="wp-mail-logging-view-message button button-secondary" href="#" data-mail-id="' . esc_attr( $content ) . '">View</a>';
235
- return $message;
236
- }
237
-
238
- /**
239
- * Renders the timestamp column.
240
- * @since 1.5.0
241
- * @param array $item The current item.
242
- * @return string
243
- */
244
- function column_overridden_timestamp( $item ) {
245
- return date_i18n( apply_filters( 'wpml_get_date_time_format', '' ), strtotime( $item['timestamp'] ) );
246
- }
247
-
248
- /**
249
- * Renders the attachment column in compbat mode for mails prior 1.6.0.
250
- * @since 1.6.0
251
- * @param array $item The current item.
252
- * @return string The attachment column.
253
- */
254
- function column_attachments_compat_152( $item ) {
255
- $attachment_append = '';
256
- $attachments = explode( ',\n', $item['attachments'] );
257
- $attachments = is_array( $attachments ) ? $attachments : array( $attachments );
258
- foreach ( $attachments as $attachment ) {
259
- // $attachment can be an empty string ''.
260
- if ( ! empty( $attachment ) ) {
261
- $filename = basename( $attachment );
262
- $attachment_path = WP_CONTENT_DIR . $attachment;
263
- $attachment_url = WP_CONTENT_URL . $attachment;
264
- if ( is_file( $attachment_path ) ) {
265
- $attachment_append .= '<a href="' . $attachment_url . '" title="' . $filename . '">' . WPML_Utils::generate_attachment_icon( $attachment_path ) . '</a> ';
266
- } else {
267
- $message = sprintf( __( 'Attachment %s is not present', 'wp-mail-logging' ), $filename );
268
- $attachment_append .= '<i class="fa fa-times" title="' . $message . '"></i>';
269
- }
270
- }
271
- }
272
- return $attachment_append;
273
- }
274
-
275
- /**
276
- * Renders the attachment column.
277
- * @since 1.3
278
- * @param array $item The current item.
279
- * @return string The attachment column.
280
- */
281
- function column_overridden_attachments( $item ) {
282
-
283
- if ( version_compare( trim( $item ['plugin_version'] ), '1.6.0', '<' ) ) {
284
- return $this->column_attachments_compat_152( $item );
285
- }
286
-
287
- $attachment_append = '';
288
- $attachments = explode( ',\n', $item['attachments'] );
289
- $attachments = is_array( $attachments ) ? $attachments : array( $attachments );
290
- foreach ( $attachments as $attachment ) {
291
- // $attachment can be an empty string ''.
292
- if ( ! empty( $attachment ) ) {
293
- $filename = basename( $attachment );
294
- $basename = '/uploads';
295
- $attachment_path = WP_CONTENT_DIR . $basename . $attachment;
296
- $attachment_url = WP_CONTENT_URL . $basename . $attachment;
297
-
298
- if ( is_file( $attachment_path ) ) {
299
- $attachment_append .= '<a href="' . $attachment_url . '" title="' . $filename . '">' . WPML_Utils::generate_attachment_icon( $attachment_path ) . '</a> ';
300
- } else {
301
- $message = sprintf( __( 'Attachment %s is not present', 'wp-mail-logging' ), $filename );
302
- $attachment_append .= '<i class="fa fa-times" title="' . $message . '"></i>';
303
- }
304
- }
305
- }
306
- return $attachment_append;
307
- }
308
-
309
- /**
310
- * Renders the error column.
311
- * @since 1.8.0
312
- * @param $item
313
- * @return string
314
- */
315
- function column_overridden_error($item ) {
316
- $error = $item['error'];
317
- if( empty($error)) return "";
318
- $errorMessage = is_array($error) ? join(',', $error) : $error;
319
- return "<i class='fa fa-exclamation-circle' title='{$errorMessage}' aria-hidden='true'></i>";
320
- }
321
-
322
- /**
323
- * Renders all components of the mail.
324
- * @since 1.3
325
- * @param array $item The current item.
326
- * @return string The mail as html
327
- */
328
- function render_mail( $item ) {
329
- $mailAppend = '';
330
- foreach ( $item as $key => $value ) {
331
- if ( array_key_exists( $key, $this->get_columns() ) && ! in_array( $key, $this->get_hidden_columns() ) ) {
332
- $display = $this->get_columns();
333
- $column_name = $key;
334
- $title = "<span class=\"title\">{$display[$key]}: </span>";
335
- $content = '';
336
- if ( 'message' !== $column_name && method_exists( $this, 'column_' . $column_name ) ) {
337
- if( 'error' === $column_name || 'attachments' === $column_name ) {
338
- // don't render with icons and stuff, just plain
339
- $content .= is_array($item[$column_name]) ? join("\n", $item[$column_name]) : $item[$column_name];
340
- } else {
341
- $content .= call_user_func( array( $this, 'column_' . $column_name ), $item );
342
- }
343
- } else {
344
- $content .= $this->column_default( $item, $column_name );
345
- }
346
- $mailAppend .= $title . htmlentities( $content );
347
- }
348
- }
349
-
350
- return $mailAppend;
351
- }
352
-
353
- /**
354
- * Renders all components of the mail.
355
- * @since 1.6.0
356
- * @param array $item The current item.
357
- * @return string The mail as html
358
- */
359
- function render_mail_html( $item ) {
360
- $mailAppend = '';
361
- foreach ( $item as $key => $value ) {
362
- if ( array_key_exists( $key, $this->get_columns() ) && ! in_array( $key, $this->get_hidden_columns() ) ) {
363
- $display = $this->get_columns();
364
- $column_name = $key;
365
- $mailAppend .= "<span class=\"title\">{$display[$key]}: </span>";
366
- if ( 'message' !== $column_name && method_exists( $this, 'column_' . $column_name ) ) {
367
- $mailAppend .= call_user_func( array( $this, 'column_' . $column_name ), $item );
368
- } else {
369
- $mailAppend .= $this->column_default( $item, $column_name );
370
- }
371
- }
372
- }
373
- return $mailAppend;
374
- }
375
- /**
376
- * Defines available bulk actions.
377
- * @since 1.0
378
- * @see WP_List_Table::get_bulk_actions()
379
- */
380
- function get_bulk_actions() {
381
- $actions = array(
382
- 'delete' => 'Delete',
383
- 'resend' => 'Resend'
384
- );
385
- return $actions;
386
- }
387
-
388
- /**
389
- * Processes bulk actions.
390
- * @since 1.0
391
- */
392
- function process_bulk_action() {
393
- if ( false === $this->current_action() ) {
394
- return;
395
- }
396
-
397
- if ( check_admin_referer( WPML_Email_Log_List::NONCE_LIST_TABLE, WPML_Email_Log_List::NONCE_LIST_TABLE . '_nonce' ) ) {
398
- $name = $this->_args['singular'];
399
-
400
- // Detect when a bulk action is being triggered.
401
- if ( 'delete' === $this->current_action() ) {
402
- foreach ( $_REQUEST[$name] as $item_id ) {
403
- $mail = Mail::find_one( $item_id );
404
- if ( false !== $mail ) {
405
- $mail->delete();
406
- }
407
- }
408
- } else if ( 'resend' == $this->current_action() ) {
409
- foreach ( $_REQUEST[$name] as $item_id ) {
410
- $mail = Mail::find_one( $item_id );
411
- if ( false !== $mail ) {
412
- $this->resend_email( $mail );
413
- }
414
- }
415
- }
416
- }
417
- }
418
-
419
- /**
420
- * Send logged email via wp_mail
421
- * @param WPML_Mail $mail the email object to resend
422
- * @since 1.8.0
423
- */
424
- function resend_email( $mail ) {
425
- $this->emailResender->resendMail( $mail );
426
- }
427
-
428
- /**
429
- * Render the cb column
430
- * @since 1.0
431
- * @param array $item The current item.
432
- * @return string the rendered cb cell content
433
- */
434
- function column_cb($item) {
435
- $name = $this->_args['singular'];
436
- return sprintf(
437
- '<input type="checkbox" name="%1$s[]" value="%2$s" />', $name, $item['mail_id']
438
- );
439
- }
440
-
441
- /**
442
- * Define the sortable columns
443
- * @since 1.0
444
- * @return array
445
- */
446
- function get_sortable_columns() {
447
- return array(
448
- // Description: column_name => array( 'display_name', true[asc] | false[desc] ).
449
- 'mail_id' => array( 'mail_id', false ),
450
- 'timestamp' => array( 'timestamp', true ),
451
- 'host' => array( 'host', true ),
452
- 'receiver' => array( 'receiver', true ),
453
- 'subject' => array( 'subject', true ),
454
- 'message' => array( 'message', true ),
455
- 'headers' => array( 'headers', true ),
456
- 'attachments' => array( 'attachments', true ),
457
- 'plugin_version'=> array( 'plugin_version', true ),
458
- );
459
- }
460
-
461
- /**
462
- * Ajax function to retrieve rendered mail in certain format.
463
- * @since 1.6.0
464
- */
465
- public static function ajax_wpml_email_get() {
466
- $formats = is_array( $additional = apply_filters( WPML_Plugin::HOOK_LOGGING_SUPPORTED_FORMATS, array() ) ) ? $additional : array();
467
-
468
- check_ajax_referer( 'wpml-modal-show', 'ajax_nonce', true );
469
-
470
- if( ! isset( $_POST['id'] ) )
471
- wp_die( "huh?" );
472
- $id = intval( $_POST['id'] );
473
-
474
- $format_requested = isset( $_POST['format'] ) ? $_POST['format'] : 'html';
475
- if ( ! in_array( $format_requested, $formats ) ) {
476
- echo "Unsupported Format. Using html as fallback.";
477
- $format_requested = WPML_Utils::sanitize_expected_value($format_requested, $formats, 'html');
478
- }
479
- $mail = Mail::find_one( $id );
480
- /* @var $instance WPML_Email_Log_List */
481
- $instance = WPML_Init::getInstance()->getService( 'emailLogList' );
482
- $mailAppend = '';
483
- switch( $format_requested ) {
484
- case 'html': {
485
- $mailAppend .= $instance->render_mail_html( $mail->to_array() );
486
- break;
487
- }
488
- case 'raw': {
489
- $mailAppend .= $instance->render_mail( $mail->to_array() );
490
- break;
491
- }
492
- case 'json': {
493
- if( stristr( str_replace(' ', '', $mail->get_headers()), "Content-Type:text/html")) {
494
- // Fallback to raw in case it is a html mail
495
- $mailAppend .= sprintf("<span class='info'>%s</span>", __("Fallback to raw format because html is not convertible to json.", 'wp-mail-logging' ) );
496
- $mailAppend .= $instance->render_mail( $mail->to_array() );
497
- } else {
498
- $mailAppend .= "<pre>" . json_encode( $mail->to_array(), JSON_PRETTY_PRINT ) . "</pre>";
499
- }
500
- break;
501
- }
502
- default:
503
- $mailAppend .= apply_filters( WPML_Plugin::HOOK_LOGGING_FORMAT_CONTENT . "_{$format_requested}", $mail->to_array() );
504
- break;
505
- }
506
-
507
- echo $instance->sanitize_text($mailAppend);
508
- wp_die(); // this is required to terminate immediately and return a proper response
509
- }
510
- }
1
+ <?php
2
+
3
+ namespace No3x\WPML;
4
+
5
+ use No3x\WPML\Model\WPML_Mail as Mail;
6
+
7
+ // Exit if accessed directly.
8
+ if ( ! defined( 'ABSPATH' ) ) exit;
9
+
10
+ require_once(ABSPATH . 'wp-admin/includes/screen.php');
11
+ require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
12
+
13
+ if ( ! class_exists( 'WP_List_Table' ) ) {
14
+ require_once( plugin_dir_path( __FILE__ ) . 'inc/class-wp-list-table.php' );
15
+ }
16
+
17
+ /**
18
+ * Renders the mails in a table list.
19
+ * @author No3x
20
+ * @since 1.0
21
+ */
22
+ class WPML_Email_Log_List extends \WP_List_Table {
23
+
24
+ const NONCE_LIST_TABLE = 'wpml-list_table';
25
+ private $supported_formats = array();
26
+ /** @var WPML_Email_Resender $emailResender */
27
+ private $emailResender;
28
+ /** @var WPML_MessageSanitizer $messageSanitizer */
29
+ private $messageSanitizer;
30
+
31
+ /**
32
+ * Initializes the List Table
33
+ * @since 1.0
34
+ * @param array $supported_formats
35
+ * @param WPML_Email_Resender $emailResender
36
+ */
37
+ function __construct( $supported_formats = array(), $emailResender ) {
38
+ $this->supported_formats = $supported_formats;
39
+ $this->emailResender = $emailResender;
40
+ $this->messageSanitizer = new WPML_MessageSanitizer();
41
+ }
42
+
43
+ function addActionsAndFilters() {
44
+ add_action( 'admin_init', array( $this, 'init') );
45
+ add_filter( WPML_Plugin::HOOK_LOGGING_SUPPORTED_FORMATS, function() {
46
+ return $this->supported_formats;
47
+ } );
48
+ add_action( 'wp_ajax_wpml_email_get', __CLASS__ . '::ajax_wpml_email_get' );
49
+ }
50
+
51
+ function init() {
52
+ global $status, $page, $hook_suffix;
53
+
54
+ parent::__construct( array(
55
+ 'singular' => 'email', // singular name of the listed records
56
+ 'plural' => 'emails', // plural name of the listed records
57
+ 'ajax' => false, // does this table support ajax?
58
+ ) );
59
+ }
60
+
61
+ /**
62
+ * Is displayed if no item is available to render
63
+ * @since 1.0
64
+ * @see WP_List_Table::no_items()
65
+ */
66
+ function no_items() {
67
+ _e( 'No email found.', 'wp-mail-logging' );
68
+ return;
69
+ }
70
+
71
+ /**
72
+ * Defines the available columns.
73
+ * @since 1.0
74
+ * @see WP_List_Table::get_columns()
75
+ */
76
+ function get_columns() {
77
+ $columns = array(
78
+ 'cb' => '<input type="checkbox" />',
79
+ 'mail_id' => __( 'ID', 'wp-mail-logging' ),
80
+ 'timestamp' => __( 'Time', 'wp-mail-logging' ),
81
+ 'receiver' => __( 'Receiver', 'wp-mail-logging' ),
82
+ 'subject' => __( 'Subject', 'wp-mail-logging' ),
83
+ 'message' => __( 'Message', 'wp-mail-logging' ),
84
+ 'headers' => __( 'Headers', 'wp-mail-logging' ),
85
+ 'attachments' => __( 'Attachments', 'wp-mail-logging' ),
86
+ 'error' => __( 'Error', 'wp-mail-logging' ),
87
+ 'plugin_version' => __( 'Plugin Version', 'wp-mail-logging' ),
88
+ );
89
+
90
+ /* @var $instance WPML_Plugin */
91
+ $instance = WPML_Init::getInstance()->getService( 'plugin' );
92
+
93
+ $switch = $instance->getSetting('display-host', false );
94
+ if( true == $switch ) {
95
+ $posAfterTimestamp = array_search('timestamp', array_keys($columns) ) + 1;
96
+ $columns = array_merge(
97
+ array_slice( $columns, 0, $posAfterTimestamp),
98
+ [ 'host' => __( 'Host', 'wp-mail-logging' ) ],
99
+ array_slice( $columns, $posAfterTimestamp )
100
+ );
101
+ }
102
+
103
+ // Give a plugin the chance to edit the columns.
104
+ $columns = apply_filters( WPML_Plugin::HOOK_LOGGING_COLUMNS, $columns );
105
+
106
+ $reserved = array( '_title', 'comment', 'media', 'name', 'title', 'username', 'blogname' );
107
+
108
+ // Show message for reserved column names.
109
+ foreach ( $reserved as $reserved_key ) {
110
+ if ( array_key_exists( $reserved_key, $columns ) ) {
111
+ echo "You should avoid $reserved_key as keyname since it is treated by WordPress specially: Your table would still work, but you won't be able to show/hide the columns. You can prefix your columns!";
112
+ break;
113
+ }
114
+ }
115
+ return $columns;
116
+ }
117
+
118
+ /**
119
+ * Define which columns are hidden
120
+ * @since 1.0
121
+ * @return array
122
+ */
123
+ function get_hidden_columns() {
124
+ return array(
125
+ 'plugin_version',
126
+ 'mail_id',
127
+ );
128
+ }
129
+
130
+ /**
131
+ * Sanitize orderby parameter.
132
+ * @s
133
+ * @return string sanitized orderby parameter
134
+ */
135
+ private function sanitize_orderby() {
136
+ return WPML_Utils::sanitize_expected_value( ( !empty( $_GET['orderby'] ) ) ? $_GET['orderby'] : null, $this->get_sortable_columns(), 'mail_id');
137
+ }
138
+
139
+ /**
140
+ * Sanitize order parameter.
141
+ * @return string sanitized order parameter
142
+ */
143
+ private function sanitize_order() {
144
+ return WPML_Utils::sanitize_expected_value( ( !empty( $_GET['order'] ) ) ? $_GET['order'] : null, array('desc', 'asc'), 'desc');
145
+ }
146
+
147
+ /**
148
+ * Prepares the items for rendering
149
+ * @since 1.0
150
+ * @param string|boolean $search string you want to search for. Default false.
151
+ * @see WP_List_Table::prepare_items()
152
+ */
153
+ function prepare_items( $search = false ) {
154
+ $orderby = $this->sanitize_orderby();
155
+ $order = $this->sanitize_order();
156
+
157
+ $columns = $this->get_columns();
158
+ $hidden = $this->get_hidden_columns();
159
+ $sortable = $this->get_sortable_columns();
160
+ $this->_column_headers = array( $columns, $hidden, $sortable );
161
+
162
+ $this->process_bulk_action();
163
+
164
+ $per_page = $this->get_items_per_page( 'per_page', 25 );
165
+ $current_page = $this->get_pagenum();
166
+ $offset = ( $current_page - 1 ) * $per_page;
167
+
168
+ $total_items = Mail::query()
169
+ ->search( $search )
170
+ ->find( true );
171
+
172
+ $mails = Mail::query()
173
+ ->search( $search )
174
+ ->sort_by( $orderby )
175
+ ->order( $order )
176
+ ->limit( $per_page )
177
+ ->offset( $offset )
178
+ ->find();
179
+
180
+ foreach ( $mails as $mail ) {
181
+ /* @var $mail Mail */
182
+ $this->items[] = $mail->to_array();
183
+ }
184
+
185
+ $this->set_pagination_args( array(
186
+ 'total_items' => $total_items, // The total number of items.
187
+ 'per_page' => $per_page, // Number of items per page.
188
+ ) );
189
+ }
190
+
191
+ /**
192
+ * Renders the cell.
193
+ * Note: We can easily add filter for all columns if you want to / need to manipulate the content. (currently only additional column manipulation is supported)
194
+ * @since 1.0
195
+ * @param array $item The current item.
196
+ * @param string $column_name The current column name.
197
+ * @return string The cell content
198
+ */
199
+ function column_default( $item, $column_name ) {
200
+ $column_content = '';
201
+
202
+ // colmn_message is handled called directly by the list table by naming it colmn_$name. All other columns pass this function and might be named column_overridden_$column_name for further adaptation on output.
203
+ if ( method_exists( $this, 'column_overridden_' . $column_name ) ) {
204
+ $column_content = call_user_func( array( $this, 'column_overridden_' . $column_name ), $item );
205
+ } elseif( array_key_exists( $column_name, $item ) ) {
206
+ $column_content = $item[ $column_name ];
207
+ } else {
208
+ // If we don't know this column maybe a hook does - if no hook extracted data (string) out of the array we can avoid the output of 'Array()' (array).
209
+ $column_content = ( is_array( $res = apply_filters( WPML_Plugin::HOOK_LOGGING_COLUMNS_RENDER, $item, $column_name ) ) ) ? '' : $res;
210
+ }
211
+
212
+ return $this->sanitize_text($column_content);
213
+ }
214
+
215
+ /**
216
+ * Sanitize text to remove unsafe html.
217
+ * @since 1.5.1
218
+ * @param string $message unsafe text.
219
+ * @return string safe text.
220
+ */
221
+ function sanitize_text( $message ) {
222
+ return $this->messageSanitizer->sanitize($message);
223
+ }
224
+
225
+ /**
226
+ * Renders the message column.
227
+ * @since 1.3
228
+ * @param array $item The current item.
229
+ * @return string
230
+ */
231
+ function column_message( $item ) {
232
+ $content = $item['mail_id'];
233
+ $message = '<a class="wp-mail-logging-view-message button button-secondary" href="#" data-mail-id="' . esc_attr( $content ) . '">View</a>';
234
+ return $message;
235
+ }
236
+
237
+ /**
238
+ * Renders the timestamp column.
239
+ * @since 1.5.0
240
+ * @param array $item The current item.
241
+ * @return string
242
+ */
243
+ function column_overridden_timestamp( $item ) {
244
+ return date_i18n( apply_filters( 'wpml_get_date_time_format', '' ), strtotime( $item['timestamp'] ) );
245
+ }
246
+
247
+ /**
248
+ * Renders the attachment column in compbat mode for mails prior 1.6.0.
249
+ * @since 1.6.0
250
+ * @param array $item The current item.
251
+ * @return string The attachment column.
252
+ */
253
+ function column_attachments_compat_152( $item ) {
254
+ $attachment_append = '';
255
+ $attachments = explode( ',\n', $item['attachments'] );
256
+ $attachments = is_array( $attachments ) ? $attachments : array( $attachments );
257
+ foreach ( $attachments as $attachment ) {
258
+ // $attachment can be an empty string ''.
259
+ if ( ! empty( $attachment ) ) {
260
+ $filename = basename( $attachment );
261
+ $attachment_path = WP_CONTENT_DIR . $attachment;
262
+ $attachment_url = WP_CONTENT_URL . $attachment;
263
+ if ( is_file( $attachment_path ) ) {
264
+ $attachment_append .= '<a href="' . $attachment_url . '" title="' . $filename . '">' . WPML_Utils::generate_attachment_icon( $attachment_path ) . '</a> ';
265
+ } else {
266
+ $message = sprintf( __( 'Attachment %s is not present', 'wp-mail-logging' ), $filename );
267
+ $attachment_append .= '<i class="fa fa-times" title="' . $message . '"></i>';
268
+ }
269
+ }
270
+ }
271
+ return $attachment_append;
272
+ }
273
+
274
+ /**
275
+ * Renders the attachment column.
276
+ * @since 1.3
277
+ * @param array $item The current item.
278
+ * @return string The attachment column.
279
+ */
280
+ function column_overridden_attachments( $item ) {
281
+
282
+ if ( version_compare( trim( $item ['plugin_version'] ), '1.6.0', '<' ) ) {
283
+ return $this->column_attachments_compat_152( $item );
284
+ }
285
+
286
+ $attachment_append = '';
287
+ $attachments = explode( ',\n', $item['attachments'] );
288
+ $attachments = is_array( $attachments ) ? $attachments : array( $attachments );
289
+ foreach ( $attachments as $attachment ) {
290
+ // $attachment can be an empty string ''.
291
+ if ( ! empty( $attachment ) ) {
292
+ $filename = basename( $attachment );
293
+ $basename = '/uploads';
294
+ $attachment_path = WP_CONTENT_DIR . $basename . $attachment;
295
+ $attachment_url = WP_CONTENT_URL . $basename . $attachment;
296
+
297
+ if ( is_file( $attachment_path ) ) {
298
+ $attachment_append .= '<a href="' . $attachment_url . '" title="' . $filename . '">' . WPML_Utils::generate_attachment_icon( $attachment_path ) . '</a> ';
299
+ } else {
300
+ $message = sprintf( __( 'Attachment %s is not present', 'wp-mail-logging' ), $filename );
301
+ $attachment_append .= '<i class="fa fa-times" title="' . $message . '"></i>';
302
+ }
303
+ }
304
+ }
305
+ return $attachment_append;
306
+ }
307
+
308
+ /**
309
+ * Renders the error column.
310
+ * @since 1.8.0
311
+ * @param $item
312
+ * @return string
313
+ */
314
+ function column_overridden_error($item ) {
315
+ $error = $item['error'];
316
+ if( empty($error)) return "";
317
+ $errorMessage = is_array($error) ? join(',', $error) : $error;
318
+ return "<i class='fa fa-exclamation-circle' title='{$errorMessage}' aria-hidden='true'></i>";
319
+ }
320
+
321
+ /**
322
+ * Renders all components of the mail.
323
+ * @since 1.3
324
+ * @param array $item The current item.
325
+ * @return string The mail as html
326
+ */
327
+ function render_mail( $item ) {
328
+ $mailAppend = '';
329
+ foreach ( $item as $key => $value ) {
330
+ if ( array_key_exists( $key, $this->get_columns() ) && ! in_array( $key, $this->get_hidden_columns() ) ) {
331
+ $display = $this->get_columns();
332
+ $column_name = $key;
333
+ $title = "<span class=\"title\">{$display[$key]}: </span>";
334
+ $content = '';
335
+ if ( 'message' !== $column_name && method_exists( $this, 'column_' . $column_name ) ) {
336
+ if( 'error' === $column_name || 'attachments' === $column_name ) {
337
+ // don't render with icons and stuff, just plain
338
+ $content .= is_array($item[$column_name]) ? join("\n", $item[$column_name]) : $item[$column_name];
339
+ } else {
340
+ $content .= call_user_func( array( $this, 'column_' . $column_name ), $item );
341
+ }
342
+ } else {
343
+ $content .= $this->column_default( $item, $column_name );
344
+ }
345
+ $mailAppend .= $title . htmlentities( $content );
346
+ }
347
+ }
348
+
349
+ return $mailAppend;
350
+ }
351
+
352
+ /**
353
+ * Renders all components of the mail.
354
+ * @since 1.6.0
355
+ * @param array $item The current item.
356
+ * @return string The mail as html
357
+ */
358
+ function render_mail_html( $item ) {
359
+ $mailAppend = '';
360
+ foreach ( $item as $key => $value ) {
361
+ if ( array_key_exists( $key, $this->get_columns() ) && ! in_array( $key, $this->get_hidden_columns() ) ) {
362
+ $display = $this->get_columns();
363
+ $column_name = $key;
364
+ $mailAppend .= "<span class=\"title\">{$display[$key]}: </span>";
365
+ if ( 'message' !== $column_name && method_exists( $this, 'column_' . $column_name ) ) {
366
+ $mailAppend .= call_user_func( array( $this, 'column_' . $column_name ), $item );
367
+ } else {
368
+ $mailAppend .= $this->column_default( $item, $column_name );
369
+ }
370
+ }
371
+ }
372
+ return $mailAppend;
373
+ }
374
+ /**
375
+ * Defines available bulk actions.
376
+ * @since 1.0
377
+ * @see WP_List_Table::get_bulk_actions()
378
+ */
379
+ function get_bulk_actions() {
380
+ $actions = array(
381
+ 'delete' => 'Delete',
382
+ 'resend' => 'Resend'
383
+ );
384
+ return $actions;
385
+ }
386
+
387
+ /**
388
+ * Processes bulk actions.
389
+ * @since 1.0
390
+ */
391
+ function process_bulk_action() {
392
+ if ( false === $this->current_action() ) {
393
+ return;
394
+ }
395
+
396
+ if ( check_admin_referer( WPML_Email_Log_List::NONCE_LIST_TABLE, WPML_Email_Log_List::NONCE_LIST_TABLE . '_nonce' ) ) {
397
+ $name = $this->_args['singular'];
398
+
399
+ // Detect when a bulk action is being triggered.
400
+ if ( 'delete' === $this->current_action() ) {
401
+ foreach ( $_REQUEST[$name] as $item_id ) {
402
+ $mail = Mail::find_one( $item_id );
403
+ if ( false !== $mail ) {
404
+ $mail->delete();
405
+ }
406
+ }
407
+ } else if ( 'resend' == $this->current_action() ) {
408
+ foreach ( $_REQUEST[$name] as $item_id ) {
409
+ $mail = Mail::find_one( $item_id );
410
+ if ( false !== $mail ) {
411
+ $this->resend_email( $mail );
412
+ }
413
+ }
414
+ }
415
+ }
416
+ }
417
+
418
+ /**
419
+ * Send logged email via wp_mail
420
+ * @param Mail $mail the email object to resend
421
+ * @since 1.8.0
422
+ */
423
+ function resend_email( $mail ) {
424
+ $this->emailResender->resendMail( $mail );
425
+ }
426
+
427
+ /**
428
+ * Render the cb column
429
+ * @since 1.0
430
+ * @param array $item The current item.
431
+ * @return string the rendered cb cell content
432
+ */
433
+ function column_cb($item) {
434
+ $name = $this->_args['singular'];
435
+ return sprintf(
436
+ '<input type="checkbox" name="%1$s[]" value="%2$s" />', $name, $item['mail_id']
437
+ );
438
+ }
439
+
440
+ /**
441
+ * Define the sortable columns
442
+ * @since 1.0
443
+ * @return array
444
+ */
445
+ function get_sortable_columns() {
446
+ return array(
447
+ // Description: column_name => array( 'display_name', true[asc] | false[desc] ).
448
+ 'mail_id' => array( 'mail_id', false ),
449
+ 'timestamp' => array( 'timestamp', true ),
450
+ 'host' => array( 'host', true ),
451
+ 'receiver' => array( 'receiver', true ),
452
+ 'subject' => array( 'subject', true ),
453
+ 'message' => array( 'message', true ),
454
+ 'headers' => array( 'headers', true ),
455
+ 'attachments' => array( 'attachments', true ),
456
+ 'plugin_version'=> array( 'plugin_version', true ),
457
+ );
458
+ }
459
+
460
+ /**
461
+ * Ajax function to retrieve rendered mail in certain format.
462
+ * @since 1.6.0
463
+ */
464
+ public static function ajax_wpml_email_get() {
465
+ $formats = is_array( $additional = apply_filters( WPML_Plugin::HOOK_LOGGING_SUPPORTED_FORMATS, array() ) ) ? $additional : array();
466
+
467
+ check_ajax_referer( 'wpml-modal-show', 'ajax_nonce', true );
468
+
469
+ if( ! isset( $_POST['id'] ) )
470
+ wp_die( "huh?" );
471
+ $id = intval( $_POST['id'] );
472
+
473
+ $format_requested = isset( $_POST['format'] ) ? $_POST['format'] : 'html';
474
+ if ( ! in_array( $format_requested, $formats ) ) {
475
+ echo "Unsupported Format. Using html as fallback.";
476
+ $format_requested = WPML_Utils::sanitize_expected_value($format_requested, $formats, 'html');
477
+ }
478
+ $mail = Mail::find_one( $id );
479
+ /* @var $instance WPML_Email_Log_List */
480
+ $instance = WPML_Init::getInstance()->getService( 'emailLogList' );
481
+ $mailAppend = '';
482
+ switch( $format_requested ) {
483
+ case 'html': {
484
+ $mailAppend .= $instance->render_mail_html( $mail->to_array() );
485
+ break;
486
+ }
487
+ case 'raw': {
488
+ $mailAppend .= $instance->render_mail( $mail->to_array() );
489
+ break;
490
+ }
491
+ case 'json': {
492
+ if( stristr( str_replace(' ', '', $mail->get_headers()), "Content-Type:text/html")) {
493
+ // Fallback to raw in case it is a html mail
494
+ $mailAppend .= sprintf("<span class='info'>%s</span>", __("Fallback to raw format because html is not convertible to json.", 'wp-mail-logging' ) );
495
+ $mailAppend .= $instance->render_mail( $mail->to_array() );
496
+ } else {
497
+ $mailAppend .= "<pre>" . json_encode( $mail->to_array(), JSON_PRETTY_PRINT ) . "</pre>";
498
+ }
499
+ break;
500
+ }
501
+ default:
502
+ $mailAppend .= apply_filters( WPML_Plugin::HOOK_LOGGING_FORMAT_CONTENT . "_{$format_requested}", $mail->to_array() );
503
+ break;
504
+ }
505
+
506
+ echo $instance->sanitize_text($mailAppend);
507
+ wp_die(); // this is required to terminate immediately and return a proper response
508
+ }
509
+ }
 
WPML_Email_Resender.php → src/WPML_Email_Resender.php RENAMED
@@ -1,29 +1,29 @@
1
- <?php
2
-
3
- namespace No3x\WPML;
4
-
5
- use No3x\WPML\Model\WPML_Mail;
6
-
7
- class WPML_Email_Resender {
8
-
9
- /** @var WPML_Email_Dispatcher $dispatcher */
10
- private $dispatcher;
11
-
12
- public function __construct($dispatcher) {
13
- $this->dispatcher = $dispatcher;
14
- }
15
-
16
- /**
17
- * Resend mail
18
- * @param WPML_Mail $mail
19
- */
20
- public function resendMail($mail) {
21
- $headers = explode( "\\n", str_replace( "\\r\\n", "\\n", $mail->get_headers() ) );
22
- $headers = array_map(function ($header) {
23
- return rtrim($header, ",");
24
- }, $headers);
25
-
26
- $this->dispatcher->dispatch($mail->get_receiver(), $mail->get_subject(), $mail->get_message(), $headers, $mail->get_attachments() );
27
- }
28
-
29
- }
1
+ <?php
2
+
3
+ namespace No3x\WPML;
4
+
5
+ use No3x\WPML\Model\WPML_Mail;
6
+
7
+ class WPML_Email_Resender {
8
+
9
+ /** @var WPML_Email_Dispatcher $dispatcher */
10
+ private $dispatcher;
11
+
12
+ public function __construct($dispatcher) {
13
+ $this->dispatcher = $dispatcher;
14
+ }
15
+
16
+ /**
17
+ * Resend mail
18
+ * @param WPML_Mail $mail
19
+ */
20
+ public function resendMail($mail) {
21
+ $headers = explode( "\\n", str_replace( "\\r\\n", "\\n", $mail->get_headers() ) );
22
+ $headers = array_map(function ($header) {
23
+ return rtrim($header, ",");
24
+ }, $headers);
25
+
26
+ $this->dispatcher->dispatch($mail->get_receiver(), $mail->get_subject(), $mail->get_message(), $headers, $mail->get_attachments() );
27
+ }
28
+
29
+ }
src/WPML_Hook_Remover.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace No3x\WPML;
4
+
5
+ /**
6
+ * Class for removing hooks by class name
7
+ * https://gist.github.com/tripflex/c6518efc1753cf2392559866b4bd1a53
8
+ */
9
+ class WPML_Hook_Remover {
10
+
11
+ /**
12
+ * Remove Class Filter Without Access to Class Object
13
+ *
14
+ * In order to use the core WordPress remove_filter() on a filter added with the callback
15
+ * to a class, you either have to have access to that class object, or it has to be a call
16
+ * to a static method. This method allows you to remove filters with a callback to a class
17
+ * you don't have access to.
18
+ *
19
+ * Works with WordPress 1.2+ (4.7+ support added 9-19-2016)
20
+ * Updated 2-27-2017 to use internal WordPress removal for 4.7+ (to prevent PHP warnings output)
21
+ *
22
+ * @param string $tag Filter to remove
23
+ * @param string $class_name Class name for the filter's callback
24
+ * @param string $method_name Method name for the filter's callback
25
+ * @param int $priority Priority of the filter (default 10)
26
+ *
27
+ * @return bool Whether the function is removed.
28
+ */
29
+ function remove_class_hook( $tag, $class_name = '', $method_name = '', $priority = 10 ) {
30
+ global $wp_filter;
31
+ // Check that filter actually exists first
32
+ if ( ! isset( $wp_filter[ $tag ] ) ) {
33
+ return FALSE;
34
+ }
35
+ /**
36
+ * If filter config is an object, means we're using WordPress 4.7+ and the config is no longer
37
+ * a simple array, rather it is an object that implements the ArrayAccess interface.
38
+ *
39
+ * To be backwards compatible, we set $callbacks equal to the correct array as a reference (so $wp_filter is updated)
40
+ *
41
+ * @see https://make.wordpress.org/core/2016/09/08/wp_hook-next-generation-actions-and-filters/
42
+ */
43
+ if ( is_object( $wp_filter[ $tag ] ) && isset( $wp_filter[ $tag ]->callbacks ) ) {
44
+ // Create $fob object from filter tag, to use below
45
+ $fob = $wp_filter[ $tag ];
46
+ $callbacks = &$wp_filter[ $tag ]->callbacks;
47
+ } else {
48
+ $callbacks = &$wp_filter[ $tag ];
49
+ }
50
+ // Exit if there aren't any callbacks for specified priority
51
+ if ( ! isset( $callbacks[ $priority ] ) || empty( $callbacks[ $priority ] ) ) {
52
+ return FALSE;
53
+ }
54
+ // Loop through each filter for the specified priority, looking for our class & method
55
+ foreach ( (array) $callbacks[ $priority ] as $filter_id => $filter ) {
56
+ // Filter should always be an array - array( $this, 'method' ), if not goto next
57
+ if ( ! isset( $filter['function'] ) || ! is_array( $filter['function'] ) ) {
58
+ continue;
59
+ }
60
+ // If first value in array is not an object, it can't be a class
61
+ if ( ! is_object( $filter['function'][0] ) ) {
62
+ continue;
63
+ }
64
+ // Method doesn't match the one we're looking for, goto next
65
+ if ( $filter['function'][1] !== $method_name ) {
66
+ continue;
67
+ }
68
+ // Method matched, now let's check the Class
69
+ if ( get_class( $filter['function'][0] ) === $class_name ) {
70
+ // WordPress 4.7+ use core remove_filter() since we found the class object
71
+ if ( isset( $fob ) ) {
72
+ // Handles removing filter, reseting callback priority keys mid-iteration, etc.
73
+ $fob->remove_filter( $tag, $filter['function'], $priority );
74
+ } else {
75
+ // Use legacy removal process (pre 4.7)
76
+ unset( $callbacks[ $priority ][ $filter_id ] );
77
+ // and if it was the only filter in that priority, unset that priority
78
+ if ( empty( $callbacks[ $priority ] ) ) {
79
+ unset( $callbacks[ $priority ] );
80
+ }
81
+ // and if the only filter for that tag, set the tag to an empty array
82
+ if ( empty( $callbacks ) ) {
83
+ $callbacks = array();
84
+ }
85
+ // Remove this filter from merged_filters, which specifies if filters have been sorted
86
+ unset( $GLOBALS['merged_filters'][ $tag ] );
87
+ }
88
+ return TRUE;
89
+ }
90
+ }
91
+ return FALSE;
92
+ }
93
+ }
WPML_Init.php → src/WPML_Init.php RENAMED
@@ -1,158 +1,161 @@
1
- <?php
2
- /*
3
- "WordPress Plugin Template" Copyright (C) 2013 Michael Simpson (email : michael.d.simpson@gmail.com)
4
-
5
- This file is part of WordPress Plugin Template for WordPress.
6
-
7
- WordPress Plugin Template is free software: you can redistribute it and/or modify
8
- it under the terms of the GNU General Public License as published by
9
- the Free Software Foundation, either version 3 of the License, or
10
- (at your option) any later version.
11
-
12
- WordPress Plugin Template is distributed in the hope that it will be useful,
13
- but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- GNU General Public License for more details.
16
-
17
- You should have received a copy of the GNU General Public License
18
- along with Contact Form to Database Extension.
19
- If not, see http://www.gnu.org/licenses/gpl-3.0.html
20
- */
21
-
22
- namespace No3x\WPML;
23
-
24
- use No3x\WPML\Settings\WPML_Redux_Framework_config;
25
-
26
- // Exit if accessed directly.
27
- if ( ! defined( 'ABSPATH' ) ) exit;
28
-
29
- class WPML_Init {
30
-
31
- /**
32
- * @var Singleton The reference to *Singleton* instance of this class
33
- */
34
- private static $instance;
35
- /**
36
- * @var WPML_DI_Container The DI Container
37
- */
38
- private $container;
39
-
40
- /**
41
- * Returns the *Singleton* instance of this class.
42
- *
43
- * @return WPML_Init The *Singleton* instance.
44
- */
45
- public static function getInstance() {
46
- if (null === static::$instance) {
47
- static::$instance = new static();
48
- }
49
-
50
- return static::$instance;
51
- }
52
-
53
- /**
54
- * Protected constructor to prevent creating a new instance of the
55
- * *Singleton* via the `new` operator from outside of this class.
56
- */
57
- protected function __construct() {
58
- $this->container = new WPML_DI_Container();
59
- }
60
-
61
- public function getClosure() {
62
- return function ($prop) {
63
- return $this->$prop;
64
- };
65
- }
66
-
67
- public function init( $file ) {
68
-
69
- $this->container['plugin'] = function ($c) {
70
- return new WPML_Plugin();
71
- };
72
- $this->container['plugin-meta'] = function ($c) {
73
- /* @var $plugin WPML_Plugin */
74
- $plugin = $c['plugin'];
75
- return array(
76
- 'path' => realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR,
77
- 'uri' => plugin_dir_url( __FILE__ ),
78
- 'display_name' => $plugin->getPluginDisplayName(),
79
- 'slug' => $plugin->getPluginSlug(),
80
- 'main_file' => $plugin->getMainPluginFileName(),
81
- 'description' => $plugin->getPluginHeaderValue( 'Description' ),
82
- 'version' => $plugin->getVersion(),
83
- 'version_installed' => $plugin->getVersionSaved(),
84
- 'author_name' => $plugin->getPluginHeaderValue( 'Author' ),
85
- 'author_uri' => $plugin->getPluginHeaderValue( 'Author URI' ),
86
- 'wp_uri' => $plugin->getPluginHeaderValue( 'Plugin URI' ),
87
- 'support_uri' => $plugin->getPluginHeaderValue( 'Support URI' ),
88
- 'license' => $plugin->getPluginHeaderValue( 'License' ),
89
- );
90
- };
91
- $this->container['emailLogList-supported-formats'] = function ($c) {
92
- return array(
93
- 'html',
94
- 'raw',
95
- 'json'
96
- );
97
- };
98
- $this->container['emailLogList'] = function ($c) {
99
- return new WPML_Email_Log_List( $c['emailLogList-supported-formats'], $c['emailResender'] );
100
- };
101
- $this->container['emailResender'] = function ($c) {
102
- return new WPML_Email_Resender( $c['emailDispatcher'] );
103
- };
104
- $this->container['emailDispatcher'] = function () {
105
- return new WPML_Email_Dispatcher();
106
- };
107
- $this->container['redux'] = function ($c) {
108
- return new WPML_Redux_Framework_config( $c['plugin-meta'] );
109
- };
110
- $this->container['logRotation'] = function ($c) {
111
- return new WPML_LogRotation( $c['plugin-meta'] );
112
- };
113
- $this->container['api'] = function ($c) {
114
- // Uncomment for an API Example
115
- // return new WPML_API_Example();
116
- };
117
- $this->container->addActionsAndFilters();
118
-
119
- add_filter( 'wpml_get_di_container', function() {
120
- return $this->container;
121
- } );
122
-
123
- add_filter( 'wpml_get_di_service', function( $service ) {
124
- return $this->getService( $service );
125
- } );
126
-
127
- /*
128
- * Install the plugin
129
- * NOTE: this file gets run each time you *activate* the plugin.
130
- * So in WP when you "install" the plugin, all that does it dump its files in the plugin-templates directory
131
- * but it does not call any of its code.
132
- * So here, the plugin tracks whether or not it has run its install operation, and we ensure it is run only once
133
- * on the first activation
134
- */
135
- if ( ! $this->container['plugin']->isInstalled() ) {
136
- $this->container['plugin']->install();
137
- } else {
138
- // Perform any version-upgrade activities prior to activation (e.g. database changes).
139
- $this->container['plugin']->upgrade();
140
- }
141
-
142
- if ( ! $file ) {
143
- $file = __FILE__;
144
- }
145
- // Register the Plugin Activation Hook.
146
- register_activation_hook( $file, array( &$this->container['plugin'], 'activate' ) );
147
-
148
- // Register the Plugin Deactivation Hook.
149
- register_deactivation_hook( $file, array( &$this->container['plugin'], 'deactivate' ) );
150
- }
151
-
152
- public function getService( $key ) {
153
- if( in_array( $key, $this->container->keys() ) ) {
154
- return $this->container[ $key ];
155
- }
156
- throw new \Exception("Service '{$key}' is not registered");
157
- }
158
- }
 
 
 
1
+ <?php
2
+ /*
3
+ "WordPress Plugin Template" Copyright (C) 2013 Michael Simpson (email : michael.d.simpson@gmail.com)
4
+
5
+ This file is part of WordPress Plugin Template for WordPress.
6
+
7
+ WordPress Plugin Template is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ WordPress Plugin Template is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with Contact Form to Database Extension.
19
+ If not, see http://www.gnu.org/licenses/gpl-3.0.html
20
+ */
21
+
22
+ namespace No3x\WPML;
23
+
24
+ use No3x\WPML\Settings\WPML_Redux_Framework_config;
25
+
26
+ // Exit if accessed directly.
27
+ if ( ! defined( 'ABSPATH' ) ) exit;
28
+
29
+ class WPML_Init {
30
+
31
+ /**
32
+ * @var Singleton The reference to *Singleton* instance of this class
33
+ */
34
+ private static $instance;
35
+ /**
36
+ * @var WPML_DI_Container The DI Container
37
+ */
38
+ private $container;
39
+
40
+ /**
41
+ * Returns the *Singleton* instance of this class.
42
+ *
43
+ * @return WPML_Init The *Singleton* instance.
44
+ */
45
+ public static function getInstance() {
46
+ if (null === static::$instance) {
47
+ static::$instance = new static();
48
+ }
49
+
50
+ return static::$instance;
51
+ }
52
+
53
+ /**
54
+ * Protected constructor to prevent creating a new instance of the
55
+ * *Singleton* via the `new` operator from outside of this class.
56
+ */
57
+ protected function __construct() {
58
+ $this->container = new WPML_DI_Container();
59
+ }
60
+
61
+ public function getClosure() {
62
+ return function ($prop) {
63
+ return $this->$prop;
64
+ };
65
+ }
66
+
67
+ public function init( $file ) {
68
+
69
+ $this->container['plugin'] = function ($c) {
70
+ return new WPML_Plugin();
71
+ };
72
+ $this->container['plugin-meta'] = function ($c) {
73
+ /* @var $plugin WPML_Plugin */
74
+ $plugin = $c['plugin'];
75
+ return array(
76
+ 'path' => realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR,
77
+ 'uri' => plugin_dir_url( __FILE__ ),
78
+ 'display_name' => $plugin->getPluginDisplayName(),
79
+ 'slug' => $plugin->getPluginSlug(),
80
+ 'main_file' => $plugin->getMainPluginFileName(),
81
+ 'description' => $plugin->getPluginHeaderValue( 'Description' ),
82
+ 'version' => $plugin->getVersion(),
83
+ 'version_installed' => $plugin->getVersionSaved(),
84
+ 'author_name' => $plugin->getPluginHeaderValue( 'Author' ),
85
+ 'author_uri' => $plugin->getPluginHeaderValue( 'Author URI' ),
86
+ 'wp_uri' => $plugin->getPluginHeaderValue( 'Plugin URI' ),
87
+ 'support_uri' => $plugin->getPluginHeaderValue( 'Support URI' ),
88
+ 'license' => $plugin->getPluginHeaderValue( 'License' ),
89
+ );
90
+ };
91
+ $this->container['emailLogList-supported-formats'] = function ($c) {
92
+ return array(
93
+ 'html',
94
+ 'raw',
95
+ 'json'
96
+ );
97
+ };
98
+ $this->container['emailLogList'] = function ($c) {
99
+ return new WPML_Email_Log_List( $c['emailLogList-supported-formats'], $c['emailResender'] );
100
+ };
101
+ $this->container['emailResender'] = function ($c) {
102
+ return new WPML_Email_Resender( $c['emailDispatcher'] );
103
+ };
104
+ $this->container['emailDispatcher'] = function () {
105
+ return new WPML_Email_Dispatcher();
106
+ };
107
+ $this->container['redux'] = function ($c) {
108
+ return new WPML_Redux_Framework_config( $c['plugin-meta'] );
109
+ };
110
+ $this->container['logRotation'] = function ($c) {
111
+ return new WPML_LogRotation( $c['plugin-meta'] );
112
+ };
113
+ $this->container['privacyController'] = function ($c) {
114
+ return new WPML_PrivacyController($c['plugin-meta']);
115
+ };
116
+ $this->container['api'] = function ($c) {
117
+ // Uncomment for an API Example
118
+ // return new WPML_API_Example();
119
+ };
120
+ $this->container->addActionsAndFilters();
121
+
122
+ add_filter( 'wpml_get_di_container', function() {
123
+ return $this->container;
124
+ } );
125
+
126
+ add_filter( 'wpml_get_di_service', function( $service ) {
127
+ return $this->getService( $service );
128
+ } );
129
+
130
+ /*
131
+ * Install the plugin
132
+ * NOTE: this file gets run each time you *activate* the plugin.
133
+ * So in WP when you "install" the plugin, all that does it dump its files in the plugin-templates directory
134
+ * but it does not call any of its code.
135
+ * So here, the plugin tracks whether or not it has run its install operation, and we ensure it is run only once
136
+ * on the first activation
137
+ */
138
+ if ( ! $this->container['plugin']->isInstalled() ) {
139
+ $this->container['plugin']->install();
140
+ } else {
141
+ // Perform any version-upgrade activities prior to activation (e.g. database changes).
142
+ $this->container['plugin']->upgrade();
143
+ }
144
+
145
+ if ( ! $file ) {
146
+ $file = __FILE__;
147
+ }
148
+ // Register the Plugin Activation Hook.
149
+ register_activation_hook( $file, array( &$this->container['plugin'], 'activate' ) );
150
+
151
+ // Register the Plugin Deactivation Hook.
152
+ register_deactivation_hook( $file, array( &$this->container['plugin'], 'deactivate' ) );
153
+ }
154
+
155
+ public function getService( $key ) {
156
+ if( in_array( $key, $this->container->keys() ) ) {
157
+ return $this->container[ $key ];
158
+ }
159
+ throw new \Exception("Service '{$key}' is not registered");
160
+ }
161
+ }
WPML_InstallIndicator.php → src/WPML_InstallIndicator.php RENAMED
@@ -1,171 +1,186 @@
1
- <?php
2
- /*
3
- "WordPress Plugin Template" Copyright (C) 2013 Michael Simpson (email : michael.d.simpson@gmail.com)
4
-
5
- This file is part of WordPress Plugin Template for WordPress.
6
-
7
- WordPress Plugin Template is free software: you can redistribute it and/or modify
8
- it under the terms of the GNU General Public License as published by
9
- the Free Software Foundation, either version 3 of the License, or
10
- (at your option) any later version.
11
-
12
- WordPress Plugin Template is distributed in the hope that it will be useful,
13
- but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- GNU General Public License for more details.
16
-
17
- You should have received a copy of the GNU General Public License
18
- along with Contact Form to Database Extension.
19
- If not, see http://www.gnu.org/licenses/gpl-3.0.html
20
- */
21
-
22
- namespace No3x\WPML;
23
-
24
- // Exit if accessed directly.
25
- if ( ! defined( 'ABSPATH' ) ) exit;
26
-
27
- class WPML_InstallIndicator extends WPML_OptionsManager {
28
-
29
- const optionInstalled = '_installed';
30
- const optionVersion = '_version';
31
-
32
- /**
33
- * Checks if the plugin is installed.
34
- * @return bool indicating if the plugin is installed already
35
- */
36
- public function isInstalled() {
37
- global $wpdb;
38
- $mails = $this->getTablename('mails');
39
- $query = $wpdb->query("SHOW TABLES LIKE \"$mails\"");
40
- return (bool) $query;
41
- }
42
-
43
- /**
44
- * Set a version string in the options. This is useful if you install upgrade and
45
- * need to check if an older version was installed to see if you need to do certain
46
- * upgrade housekeeping (e.g. changes to DB schema).
47
- * @return null
48
- */
49
- protected function getVersionSaved() {
50
- return $this->getOption( self::optionVersion );
51
- }
52
-
53
- /**
54
- * Set a version string in the options.
55
- * need to check if
56
- * @param string $version string best practice: use a dot-delimited string like '1.2.3' so version strings can be easily
57
- * compared using version_compare (http://php.net/manual/en/function.version-compare.php)
58
- * @return null
59
- */
60
- protected function setVersionSaved( $version ) {
61
- return $this->updateOption( self::optionVersion, $version );
62
- }
63
-
64
- /**
65
- * @return string name of the main plugin file that has the header section with
66
- * "Plugin Name", "Version", "Description", "Text Domain", etc.
67
- */
68
- protected function getMainPluginFileName() {
69
- return basename( dirname( __FILE__ ) ) . 'php';
70
- }
71
-
72
- /**
73
- * Get a value for input key in the header section of main plugin file.
74
- * E.g. "Plugin Name", "Version", "Description", "Text Domain", etc.
75
- * @param $key string plugin header key
76
- * @return string if found, otherwise null
77
- */
78
- public function getPluginHeaderValue($key) {
79
- // Read the string from the comment header of the main plugin file.
80
- $data = file_get_contents( $this->getPluginDir() . DIRECTORY_SEPARATOR . $this->getMainPluginFileName() );
81
- $match = array();
82
- preg_match( '/' . $key . ':\s*(.*)/', $data, $match );
83
- if ( count( $match ) >= 1 ) {
84
- return $match[1];
85
- }
86
- return null;
87
- }
88
-
89
- /**
90
- * If your subclass of this class lives in a different directory,
91
- * override this method with the exact same code. Since __FILE__ will
92
- * be different, you will then get the right dir returned.
93
- * @return string
94
- */
95
- protected function getPluginDir() {
96
- return dirname( __FILE__ );
97
- }
98
-
99
- /**
100
- * Version of this code.
101
- * Best practice: define version strings to be easily compared using version_compare()
102
- * (http://php.net/manual/en/function.version-compare.php)
103
- * NOTE: You should manually make this match the SVN tag for your main plugin file 'Version' release and 'Stable tag' in readme.txt
104
- * @return string
105
- */
106
- public function getVersion() {
107
- return $this->getPluginHeaderValue( 'Version' );
108
- }
109
-
110
- /**
111
- * Useful when checking for upgrades, can tell if the currently installed version is earlier than the
112
- * newly installed code. This case indicates that an upgrade has been installed and this is the first time it
113
- * has been activated, so any upgrade actions should be taken.
114
- * @return bool true if the version saved in the options is earlier than the version declared in getVersion().
115
- * true indicates that new code is installed and this is the first time it is activated, so upgrade actions
116
- * should be taken. Assumes that version string comparable by version_compare, examples: '1', '1.1', '1.1.1', '2.0', etc.
117
- */
118
- public function isInstalledCodeAnUpgrade() {
119
- return $this->isSavedVersionLessThan( $this->getVersion() );
120
- }
121
-
122
- /**
123
- * Used to see if the installed code is an earlier version than the input version
124
- * @param string $aVersion version string.
125
- * @return bool true if the saved version is earlier (by natural order) than the input version
126
- */
127
- public function isSavedVersionLessThan( $aVersion ) {
128
- return $this->isVersionLessThan( $this->getVersionSaved(), $aVersion );
129
- }
130
-
131
- /**
132
- * Used to see if the installed code is the same or earlier than the input version.
133
- * Useful when checking for an upgrade. If you haven't specified the number of the newer version yet,
134
- * but the last version (installed) was 2.3 (for example) you could check if
135
- * For example, $this->isSavedVersionLessThanEqual('2.3') == true indicates that the saved version is not upgraded
136
- * past 2.3 yet and therefore you would perform some appropriate upgrade action.
137
- * @param string $aVersion version string.
138
- * @return bool true if the saved version is earlier (by natural order) than the input version
139
- */
140
- public function isSavedVersionLessThanEqual( $aVersion ) {
141
- return $this->isVersionLessThanEqual( $this->getVersionSaved(), $aVersion );
142
- }
143
-
144
- /**
145
- * @param string $version1 version string such as '1', '1.1', '1.1.1', '2.0', etc.
146
- * @param string $version2 version string such as '1', '1.1', '1.1.1', '2.0', etc.
147
- * @return bool true if version_compare of $versions1 and $version2 shows $version1 as the same or earlier
148
- */
149
- public function isVersionLessThanEqual( $version1, $version2 ) {
150
- return ( version_compare( $version1, $version2 ) <= 0 );
151
- }
152
-
153
- /**
154
- * @param string $version1 version string such as '1', '1.1', '1.1.1', '2.0', etc.
155
- * @param string $version2 version string such as '1', '1.1', '1.1.1', '2.0', etc.
156
- * @return bool true if version_compare of $versions1 and $version2 shows $version1 as earlier
157
- */
158
- public function isVersionLessThan( $version1, $version2 ) {
159
- return ( version_compare( $version1, $version2 ) < 0 );
160
- }
161
-
162
- /**
163
- * Record the installed version to options.
164
- * This helps track was version is installed so when an upgrade is installed, it should call this when finished
165
- * upgrading to record the new current version
166
- * @return void
167
- */
168
- protected function saveInstalledVersion() {
169
- $this->setVersionSaved( $this->getVersion() );
170
- }
171
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ "WordPress Plugin Template" Copyright (C) 2013 Michael Simpson (email : michael.d.simpson@gmail.com)
4
+
5
+ This file is part of WordPress Plugin Template for WordPress.
6
+
7
+ WordPress Plugin Template is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ WordPress Plugin Template is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with Contact Form to Database Extension.
19
+ If not, see http://www.gnu.org/licenses/gpl-3.0.html
20
+ */
21
+
22
+ namespace No3x\WPML;
23
+
24
+ // Exit if accessed directly.
25
+ if ( ! defined( 'ABSPATH' ) ) exit;
26
+
27
+ class WPML_InstallIndicator extends WPML_OptionsManager {
28
+
29
+ const optionInstalled = '_installed';
30
+ const optionVersion = '_version';
31
+ const CACHE_GROUP = 'wp_mail_logging';
32
+ const CACHE_INSTALLED_KEY = 'installed';
33
+
34
+ /**
35
+ * Checks if the plugin is installed.
36
+ * @return bool indicating if the plugin is installed already
37
+ */
38
+ public function isInstalled() {
39
+ $installed = false;
40
+
41
+ // We don't use the cached value, only its presence.
42
+ // This is because we never cache not installed state.
43
+ wp_cache_get(self::CACHE_INSTALLED_KEY, self::CACHE_GROUP, false, $installed);
44
+ if (!$installed) {
45
+ global $wpdb;
46
+
47
+ $mails = $this->getTablename('mails');
48
+ $query = $wpdb->query("SHOW TABLES LIKE \"$mails\"");
49
+ $installed = (bool) $query;
50
+
51
+ if ($installed) {
52
+ wp_cache_set(self::CACHE_INSTALLED_KEY, true, self::CACHE_GROUP, 3600);
53
+ }
54
+ }
55
+ return $installed;
56
+ }
57
+
58
+ /**
59
+ * Set a version string in the options. This is useful if you install upgrade and
60
+ * need to check if an older version was installed to see if you need to do certain
61
+ * upgrade housekeeping (e.g. changes to DB schema).
62
+ * @return null
63
+ */
64
+ protected function getVersionSaved() {
65
+ return $this->getOption( self::optionVersion );
66
+ }
67
+
68
+ /**
69
+ * Set a version string in the options.
70
+ * need to check if
71
+ * @param string $version string best practice: use a dot-delimited string like '1.2.3' so version strings can be easily
72
+ * compared using version_compare (http://php.net/manual/en/function.version-compare.php)
73
+ * @return null
74
+ */
75
+ protected function setVersionSaved( $version ) {
76
+ return $this->updateOption( self::optionVersion, $version );
77
+ }
78
+
79
+ /**
80
+ * @return string name of the main plugin file that has the header section with
81
+ * "Plugin Name", "Version", "Description", "Text Domain", etc.
82
+ */
83
+ protected function getMainPluginFileName() {
84
+ return basename( dirname( __FILE__ ) ) . 'php';
85
+ }
86
+
87
+ /**
88
+ * Get a value for input key in the header section of main plugin file.
89
+ * E.g. "Plugin Name", "Version", "Description", "Text Domain", etc.
90
+ * @param $key string plugin header key
91
+ * @return string if found, otherwise null
92
+ */
93
+ public function getPluginHeaderValue($key) {
94
+ // Read the string from the comment header of the main plugin file.
95
+ $data = file_get_contents( $this->getPluginDir() . DIRECTORY_SEPARATOR . $this->getMainPluginFileName() );
96
+ $match = array();
97
+ preg_match( '/' . $key . ':\s*(.*)/', $data, $match );
98
+ if ( count( $match ) >= 1 ) {
99
+ return $match[1];
100
+ }
101
+ return null;
102
+ }
103
+
104
+ /**
105
+ * If your subclass of this class lives in a different directory,
106
+ * override this method with the exact same code. Since __FILE__ will
107
+ * be different, you will then get the right dir returned.
108
+ * @return string
109
+ */
110
+ protected function getPluginDir() {
111
+ return dirname( dirname( __FILE__ ) );
112
+ }
113
+
114
+ /**
115
+ * Version of this code.
116
+ * Best practice: define version strings to be easily compared using version_compare()
117
+ * (http://php.net/manual/en/function.version-compare.php)
118
+ * NOTE: You should manually make this match the SVN tag for your main plugin file 'Version' release and 'Stable tag' in readme.txt
119
+ * @return string
120
+ */
121
+ public function getVersion() {
122
+ return $this->getPluginHeaderValue( 'Version' );
123
+ }
124
+
125
+ /**
126
+ * Useful when checking for upgrades, can tell if the currently installed version is earlier than the
127
+ * newly installed code. This case indicates that an upgrade has been installed and this is the first time it
128
+ * has been activated, so any upgrade actions should be taken.
129
+ * @return bool true if the version saved in the options is earlier than the version declared in getVersion().
130
+ * true indicates that new code is installed and this is the first time it is activated, so upgrade actions
131
+ * should be taken. Assumes that version string comparable by version_compare, examples: '1', '1.1', '1.1.1', '2.0', etc.
132
+ */
133
+ public function isInstalledCodeAnUpgrade() {
134
+ return $this->isSavedVersionLessThan( $this->getVersion() );
135
+ }
136
+
137
+ /**
138
+ * Used to see if the installed code is an earlier version than the input version
139
+ * @param string $aVersion version string.
140
+ * @return bool true if the saved version is earlier (by natural order) than the input version
141
+ */
142
+ public function isSavedVersionLessThan( $aVersion ) {
143
+ return $this->isVersionLessThan( $this->getVersionSaved(), $aVersion );
144
+ }
145
+
146
+ /**
147
+ * Used to see if the installed code is the same or earlier than the input version.
148
+ * Useful when checking for an upgrade. If you haven't specified the number of the newer version yet,
149
+ * but the last version (installed) was 2.3 (for example) you could check if
150
+ * For example, $this->isSavedVersionLessThanEqual('2.3') == true indicates that the saved version is not upgraded
151
+ * past 2.3 yet and therefore you would perform some appropriate upgrade action.
152
+ * @param string $aVersion version string.
153
+ * @return bool true if the saved version is earlier (by natural order) than the input version
154
+ */
155
+ public function isSavedVersionLessThanEqual( $aVersion ) {
156
+ return $this->isVersionLessThanEqual( $this->getVersionSaved(), $aVersion );
157
+ }
158
+
159
+ /**
160
+ * @param string $version1 version string such as '1', '1.1', '1.1.1', '2.0', etc.
161
+ * @param string $version2 version string such as '1', '1.1', '1.1.1', '2.0', etc.
162
+ * @return bool true if version_compare of $versions1 and $version2 shows $version1 as the same or earlier
163
+ */
164
+ public function isVersionLessThanEqual( $version1, $version2 ) {
165
+ return ( version_compare( $version1, $version2 ) <= 0 );
166
+ }
167
+
168
+ /**
169
+ * @param string $version1 version string such as '1', '1.1', '1.1.1', '2.0', etc.
170
+ * @param string $version2 version string such as '1', '1.1', '1.1.1', '2.0', etc.
171
+ * @return bool true if version_compare of $versions1 and $version2 shows $version1 as earlier
172
+ */
173
+ public function isVersionLessThan( $version1, $version2 ) {
174
+ return ( version_compare( $version1, $version2 ) < 0 );
175
+ }
176
+
177
+ /**
178
+ * Record the installed version to options.
179
+ * This helps track was version is installed so when an upgrade is installed, it should call this when finished
180
+ * upgrading to record the new current version
181
+ * @return void
182
+ */
183
+ protected function saveInstalledVersion() {
184
+ $this->setVersionSaved( $this->getVersion() );
185
+ }
186
+ }
WPML_LifeCycle.php → src/WPML_LifeCycle.php RENAMED
@@ -1,211 +1,211 @@
1
- <?php
2
- /*
3
- "WordPress Plugin Template" Copyright (C) 2013 Michael Simpson (email : michael.d.simpson@gmail.com)
4
-
5
- This file is part of WordPress Plugin Template for WordPress.
6
-
7
- WordPress Plugin Template is free software: you can redistribute it and/or modify
8
- it under the terms of the GNU General Public License as published by
9
- the Free Software Foundation, either version 3 of the License, or
10
- (at your option) any later version.
11
-
12
- WordPress Plugin Template is distributed in the hope that it will be useful,
13
- but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- GNU General Public License for more details.
16
-
17
- You should have received a copy of the GNU General Public License
18
- along with Contact Form to Database Extension.
19
- If not, see http://www.gnu.org/licenses/gpl-3.0.html
20
- */
21
-
22
- namespace No3x\WPML;
23
-
24
- // Exit if accessed directly.
25
- if ( ! defined( 'ABSPATH' ) ) exit;
26
-
27
- class WPML_LifeCycle extends WPML_InstallIndicator {
28
-
29
- public function install() {
30
-
31
- // Initialize Plugin Options
32
- $this->initOptions();
33
-
34
- // Initialize DB Tables used by the plugin
35
- $this->installDatabaseTables();
36
-
37
- // Other Plugin initialization - for the plugin writer to override as needed
38
- $this->otherInstall();
39
-
40
- // Record the installed version
41
- $this->saveInstalledVersion();
42
-
43
- }
44
-
45
- public function uninstall() {
46
- $this->otherUninstall();
47
-
48
- if ( $this->getSetting('delete-on-deactivation', false) == true ) {
49
- //TOOD: is multi site?
50
- $this->unInstallDatabaseTables();
51
- $this->deleteSavedOptions();
52
- $this->deleteVersionOption();
53
- }
54
- }
55
-
56
- /**
57
- * Perform any version-upgrade activities prior to activation (e.g. database changes)
58
- * @return void
59
- */
60
- public function upgrade() {
61
- }
62
-
63
- /**
64
- * See: http://plugin.michael-simpson.com/?page_id=105
65
- * @return void
66
- */
67
- public function activate() {
68
- }
69
-
70
- /**
71
- * See: http://plugin.michael-simpson.com/?page_id=105
72
- * @return void
73
- */
74
- public function deactivate() {
75
- $this->uninstall();
76
- }
77
-
78
- /**
79
- * See: http://plugin.michael-simpson.com/?page_id=31
80
- * @return void
81
- */
82
- protected function initOptions() {
83
- }
84
-
85
- public function addActionsAndFilters() {
86
- }
87
-
88
- /**
89
- * See: http://plugin.michael-simpson.com/?page_id=101
90
- * Called by install() to create any database tables if needed.
91
- * Best Practice:
92
- * (1) Prefix all table names with $wpdb->prefix
93
- * (2) make table names lower case only
94
- * @return void
95
- */
96
- protected function installDatabaseTables() {
97
- }
98
-
99
- /**
100
- * See: http://plugin.michael-simpson.com/?page_id=101
101
- * Drop plugin-created tables on uninstall.
102
- * @return void
103
- */
104
- protected function unInstallDatabaseTables() {
105
- }
106
-
107
- /**
108
- * Override to add any additional actions to be done at install time
109
- * See: http://plugin.michael-simpson.com/?page_id=33
110
- * @return void
111
- */
112
- protected function otherInstall() {
113
- }
114
-
115
- /**
116
- * Override to add any additional actions to be done at uninstall time
117
- * See: http://plugin.michael-simpson.com/?page_id=33
118
- * @return void
119
- */
120
- protected function otherUninstall() {
121
- }
122
-
123
- /**
124
- * Puts the configuration page in the Plugins menu by default.
125
- * Override to put it elsewhere or create a set of submenus
126
- * Override with an empty implementation if you don't want a configuration page
127
- * @return void
128
- */
129
- public function addSettingsSubMenuPage() {
130
- $this->addSettingsSubMenuPageToPluginsMenu();
131
- //$this->addSettingsSubMenuPageToSettingsMenu();
132
- }
133
-
134
-
135
- protected function requireExtraPluginFiles() {
136
- require_once(ABSPATH . 'wp-includes/pluggable.php');
137
- require_once(ABSPATH . 'wp-admin/includes/plugin.php');
138
- }
139
-
140
- /**
141
- * @return string Slug name for the URL to the Setting page
142
- * (i.e. the page for setting options)
143
- */
144
- protected function getSettingsSlug() {
145
- return get_class($this) . 'Settings';
146
- }
147
-
148
- protected function addSettingsSubMenuPageToPluginsMenu() {
149
- $this->requireExtraPluginFiles();
150
- $displayName = $this->getPluginDisplayName();
151
- add_submenu_page('plugins.php',
152
- $displayName,
153
- $displayName,
154
- 'manage_options',
155
- $this->getSettingsSlug(),
156
- array(&$this, 'settingsPage'));
157
- }
158
-
159
-
160
- protected function addSettingsSubMenuPageToSettingsMenu() {
161
- $this->requireExtraPluginFiles();
162
- $displayName = $this->getPluginDisplayName();
163
- add_options_page($displayName,
164
- $displayName,
165
- 'manage_options',
166
- $this->getSettingsSlug(),
167
- array(&$this, 'settingsPage'));
168
- }
169
-
170
- /**
171
- * @param $name string name of a database table
172
- * @return string input prefixed with the WordPress DB table prefix
173
- * plus the prefix for this plugin (lower-cased) to avoid table name collisions.
174
- * The plugin prefix is lower-cases as a best practice that all DB table names are lower case to
175
- * avoid issues on some platforms
176
- */
177
- protected function prefixTableName($name) {
178
- global $wpdb;
179
- return $wpdb->prefix . strtolower($this->prefix($name));
180
- }
181
-
182
-
183
- /**
184
- * Convenience function for creating AJAX URLs.
185
- *
186
- * @param $actionName string the name of the ajax action registered in a call like
187
- * add_action('wp_ajax_actionName', array(&$this, 'functionName'));
188
- * and/or
189
- * add_action('wp_ajax_nopriv_actionName', array(&$this, 'functionName'));
190
- *
191
- * If have an additional parameters to add to the Ajax call, e.g. an "id" parameter,
192
- * you could call this function and append to the returned string like:
193
- * $url = $this->getAjaxUrl('myaction&id=') . urlencode($id);
194
- * or more complex:
195
- * $url = sprintf($this->getAjaxUrl('myaction&id=%s&var2=%s&var3=%s'), urlencode($id), urlencode($var2), urlencode($var3));
196
- *
197
- * @return string URL that can be used in a web page to make an Ajax call to $this->functionName
198
- */
199
- public function getAjaxUrl($actionName) {
200
- return admin_url('admin-ajax.php') . '?action=' . $actionName;
201
- }
202
-
203
- public function registerPluginActionLinks( $actions, $plugin_file ) {
204
- if ($this->getMainPluginFileName() == basename($plugin_file)) {
205
- $settings = array('settings' => '<a href="admin.php?page=wpml_plugin_settings">' . __('Settings', 'General') . '</a>');
206
- $actions = array_merge($settings, $actions);
207
- }
208
- return $actions;
209
- }
210
-
211
- }
1
+ <?php
2
+ /*
3
+ "WordPress Plugin Template" Copyright (C) 2013 Michael Simpson (email : michael.d.simpson@gmail.com)
4
+
5
+ This file is part of WordPress Plugin Template for WordPress.
6
+
7
+ WordPress Plugin Template is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ WordPress Plugin Template is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with Contact Form to Database Extension.
19
+ If not, see http://www.gnu.org/licenses/gpl-3.0.html
20
+ */
21
+
22
+ namespace No3x\WPML;
23
+
24
+ // Exit if accessed directly.
25
+ if ( ! defined( 'ABSPATH' ) ) exit;
26
+
27
+ class WPML_LifeCycle extends WPML_InstallIndicator {
28
+
29
+ public function install() {
30
+
31
+ // Initialize Plugin Options
32
+ $this->initOptions();
33
+
34
+ // Initialize DB Tables used by the plugin
35
+ $this->installDatabaseTables();
36
+
37
+ // Other Plugin initialization - for the plugin writer to override as needed
38
+ $this->otherInstall();
39
+
40
+ // Record the installed version
41
+ $this->saveInstalledVersion();
42
+
43
+ }
44
+
45
+ public function uninstall() {
46
+ $this->otherUninstall();
47
+
48
+ if ( $this->getSetting('delete-on-deactivation', false) == true ) {
49
+ //TOOD: is multi site?
50
+ $this->unInstallDatabaseTables();
51
+ $this->deleteSavedOptions();
52
+ $this->deleteVersionOption();
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Perform any version-upgrade activities prior to activation (e.g. database changes)
58
+ * @return void
59
+ */
60
+ public function upgrade() {
61
+ }
62
+
63
+ /**
64
+ * See: http://plugin.michael-simpson.com/?page_id=105
65
+ * @return void
66
+ */
67
+ public function activate() {
68
+ }
69
+
70
+ /**
71
+ * See: http://plugin.michael-simpson.com/?page_id=105
72
+ * @return void
73
+ */
74
+ public function deactivate() {
75
+ $this->uninstall();
76
+ }
77
+
78
+ /**
79
+ * See: http://plugin.michael-simpson.com/?page_id=31
80
+ * @return void
81
+ */
82
+ protected function initOptions() {
83
+ }
84
+
85
+ public function addActionsAndFilters() {
86
+ }
87
+
88
+ /**
89
+ * See: http://plugin.michael-simpson.com/?page_id=101
90
+ * Called by install() to create any database tables if needed.
91
+ * Best Practice:
92
+ * (1) Prefix all table names with $wpdb->prefix
93
+ * (2) make table names lower case only
94
+ * @return void
95
+ */
96
+ protected function installDatabaseTables() {
97
+ }
98
+
99
+ /**
100
+ * See: http://plugin.michael-simpson.com/?page_id=101
101
+ * Drop plugin-created tables on uninstall.
102
+ * @return void
103
+ */
104
+ protected function unInstallDatabaseTables() {
105
+ }
106
+
107
+ /**
108
+ * Override to add any additional actions to be done at install time
109
+ * See: http://plugin.michael-simpson.com/?page_id=33
110
+ * @return void
111
+ */
112
+ protected function otherInstall() {
113
+ }
114
+
115
+ /**
116
+ * Override to add any additional actions to be done at uninstall time
117
+ * See: http://plugin.michael-simpson.com/?page_id=33
118
+ * @return void
119
+ */
120
+ protected function otherUninstall() {
121
+ }
122
+
123
+ /**
124
+ * Puts the configuration page in the Plugins menu by default.
125
+ * Override to put it elsewhere or create a set of submenus
126
+ * Override with an empty implementation if you don't want a configuration page
127
+ * @return void
128
+ */
129
+ public function addSettingsSubMenuPage() {
130
+ $this->addSettingsSubMenuPageToPluginsMenu();
131
+ //$this->addSettingsSubMenuPageToSettingsMenu();
132
+ }
133
+
134
+
135
+ protected function requireExtraPluginFiles() {
136
+ require_once(ABSPATH . 'wp-includes/pluggable.php');
137
+ require_once(ABSPATH . 'wp-admin/includes/plugin.php');
138
+ }
139
+
140
+ /**
141
+ * @return string Slug name for the URL to the Setting page
142
+ * (i.e. the page for setting options)
143
+ */
144
+ protected function getSettingsSlug() {
145
+ return get_class($this) . 'Settings';
146
+ }
147
+
148
+ protected function addSettingsSubMenuPageToPluginsMenu() {
149
+ $this->requireExtraPluginFiles();
150
+ $displayName = $this->getPluginDisplayName();
151
+ add_submenu_page('plugins.php',
152
+ $displayName,
153
+ $displayName,
154
+ 'manage_options',
155
+ $this->getSettingsSlug(),
156
+ array(&$this, 'settingsPage'));
157
+ }
158
+
159
+
160
+ protected function addSettingsSubMenuPageToSettingsMenu() {
161
+ $this->requireExtraPluginFiles();
162
+ $displayName = $this->getPluginDisplayName();
163
+ add_options_page($displayName,
164
+ $displayName,
165
+ 'manage_options',
166
+ $this->getSettingsSlug(),
167
+ array(&$this, 'settingsPage'));
168
+ }
169
+
170
+ /**
171
+ * @param $name string name of a database table
172
+ * @return string input prefixed with the WordPress DB table prefix
173
+ * plus the prefix for this plugin (lower-cased) to avoid table name collisions.
174
+ * The plugin prefix is lower-cases as a best practice that all DB table names are lower case to
175
+ * avoid issues on some platforms
176
+ */
177
+ protected function prefixTableName($name) {
178
+ global $wpdb;
179
+ return $wpdb->prefix . strtolower($this->prefix($name));
180
+ }
181
+
182
+
183
+ /**
184
+ * Convenience function for creating AJAX URLs.
185
+ *
186
+ * @param $actionName string the name of the ajax action registered in a call like
187
+ * add_action('wp_ajax_actionName', array(&$this, 'functionName'));
188
+ * and/or
189
+ * add_action('wp_ajax_nopriv_actionName', array(&$this, 'functionName'));
190
+ *
191
+ * If have an additional parameters to add to the Ajax call, e.g. an "id" parameter,
192
+ * you could call this function and append to the returned string like:
193
+ * $url = $this->getAjaxUrl('myaction&id=') . urlencode($id);
194
+ * or more complex:
195
+ * $url = sprintf($this->getAjaxUrl('myaction&id=%s&var2=%s&var3=%s'), urlencode($id), urlencode($var2), urlencode($var3));
196
+ *
197
+ * @return string URL that can be used in a web page to make an Ajax call to $this->functionName
198
+ */
199
+ public function getAjaxUrl($actionName) {
200
+ return admin_url('admin-ajax.php') . '?action=' . $actionName;
201
+ }
202
+
203
+ public function registerPluginActionLinks( $actions, $plugin_file ) {
204
+ if ($this->getMainPluginFileName() == basename($plugin_file)) {
205
+ $settings = array('settings' => '<a href="admin.php?page=wpml_plugin_settings">' . __('Settings', 'General') . '</a>');
206
+ $actions = array_merge($settings, $actions);
207
+ }
208
+ return $actions;
209
+ }
210
+
211
+ }
WPML_LogRotation.php → src/WPML_LogRotation.php RENAMED
@@ -1,131 +1,131 @@
1
- <?php
2
-
3
- namespace No3x\WPML;
4
-
5
- // Exit if accessed directly.
6
- if ( ! defined( 'ABSPATH' ) ) exit;
7
-
8
- /**
9
- * Log rotation for database.
10
- * @author No3x
11
- * @since 1.4
12
- */
13
- class WPML_LogRotation {
14
-
15
- const WPML_LOGROTATION_SCHEDULE_HOOK = 'wpml_log_rotation';
16
- const WPML_LOGROTATION_SCHEDULE_ACTION = 'LogRotationSchedule';
17
- private $plugin_meta;
18
-
19
- function __construct( $plugin_meta ) {
20
- $this->plugin_meta = $plugin_meta;
21
- }
22
-
23
- /**
24
- * Add actions and filters for this module.
25
- * @since 1.6.0
26
- */
27
- public function addActionsAndFilters() {
28
- add_action( 'plugins_loaded', array( $this, 'init') );
29
- add_action( self::WPML_LOGROTATION_SCHEDULE_HOOK , array( __CLASS__, self::WPML_LOGROTATION_SCHEDULE_ACTION) );
30
- register_deactivation_hook( plugin_dir_path( __FILE__ ) . $this->plugin_meta['main_file'], array( $this, 'unschedule' ) );
31
- }
32
-
33
- /**
34
- * Init this module.
35
- * @since 1.6.0
36
- */
37
- public function init() {
38
- global $wpml_settings;
39
-
40
- // if plugin is installed the first time settings are not initialized properly so quit early.
41
- if( !isset($wpml_settings) || !array_key_exists('log-rotation-limit-amout', $wpml_settings) ) {
42
- return;
43
- }
44
-
45
- if ( $wpml_settings['log-rotation-limit-amout'] == true || $wpml_settings['log-rotation-delete-time'] == true ) {
46
- $this->schedule();
47
- } else {
48
- $this->unschedule();
49
- }
50
- }
51
-
52
- /**
53
- * Schedules an event.
54
- * @since 1.4
55
- */
56
- function schedule() {
57
- if ( ! wp_next_scheduled( self::WPML_LOGROTATION_SCHEDULE_HOOK ) ) {
58
- wp_schedule_event( time(), 'hourly', self::WPML_LOGROTATION_SCHEDULE_HOOK );
59
- }
60
- }
61
-
62
- /**
63
- * Unschedules an event.
64
- * @since 1.4
65
- */
66
- function unschedule() {
67
- wp_clear_scheduled_hook( self::WPML_LOGROTATION_SCHEDULE_HOOK );
68
- }
69
-
70
- /**
71
- * The LogRotation supports the limitation of stored mails by amount.
72
- * @since 1.6.0
73
- */
74
- static function limitNumberOfMailsByAmount() {
75
- global $wpml_settings, $wpdb;
76
-
77
- if(!isset($wpml_settings)) {
78
- return;
79
- }
80
-
81
- $tableName = WPML_Plugin::getTablename( 'mails' );
82
-
83
- if ( $wpml_settings['log-rotation-limit-amout'] == true) {
84
- $keep = $wpml_settings['log-rotation-limit-amout-keep'];
85
- if ( $keep > 0 ) {
86
- $wpdb->query(
87
- "DELETE p
88
- FROM
89
- $tableName AS p
90
- JOIN
91
- ( SELECT mail_id
92
- FROM $tableName
93
- ORDER BY mail_id DESC
94
- LIMIT 1 OFFSET $keep
95
- ) AS lim
96
- ON p.mail_id <= lim.mail_id;"
97
- );
98
- }
99
- }
100
- }
101
-
102
- /**
103
- * The LogRotation supports the limitation of stored mails by date.
104
- * @since 1.6.0
105
- */
106
- static function limitNumberOfMailsByTime() {
107
- global $wpml_settings, $wpdb;
108
-
109
- if(!isset($wpml_settings)) {
110
- return;
111
- }
112
-
113
- $tableName = WPML_Plugin::getTablename( 'mails' );
114
-
115
- if ( $wpml_settings['log-rotation-delete-time'] == true) {
116
- $days = $wpml_settings['log-rotation-delete-time-days'];
117
- if ( $days > 0 ) {
118
- $wpdb->query( "DELETE FROM `$tableName` WHERE DATEDIFF( NOW(), `timestamp` ) >= $days" );
119
- }
120
- }
121
- }
122
-
123
- /**
124
- * Executes log rotation periodically.
125
- * @since 1.4
126
- */
127
- static function LogRotationSchedule() {
128
- self::limitNumberOfMailsByAmount();
129
- self::limitNumberOfMailsByTime();
130
- }
131
- }
1
+ <?php
2
+
3
+ namespace No3x\WPML;
4
+
5
+ // Exit if accessed directly.
6
+ if ( ! defined( 'ABSPATH' ) ) exit;
7
+
8
+ /**
9
+ * Log rotation for database.
10
+ * @author No3x
11
+ * @since 1.4
12
+ */
13
+ class WPML_LogRotation {
14
+
15
+ const WPML_LOGROTATION_SCHEDULE_HOOK = 'wpml_log_rotation';
16
+ const WPML_LOGROTATION_SCHEDULE_ACTION = 'LogRotationSchedule';
17
+ private $plugin_meta;
18
+
19
+ function __construct( $plugin_meta ) {
20
+ $this->plugin_meta = $plugin_meta;
21
+ }
22
+
23
+ /**
24
+ * Add actions and filters for this module.
25
+ * @since 1.6.0
26
+ */
27
+ public function addActionsAndFilters() {
28
+ add_action( 'plugins_loaded', array( $this, 'init') );
29
+ add_action( self::WPML_LOGROTATION_SCHEDULE_HOOK , array( __CLASS__, self::WPML_LOGROTATION_SCHEDULE_ACTION) );
30
+ register_deactivation_hook( plugin_dir_path( __FILE__ ) . $this->plugin_meta['main_file'], array( $this, 'unschedule' ) );
31
+ }
32
+
33
+ /**
34
+ * Init this module.
35
+ * @since 1.6.0
36
+ */
37
+ public function init() {
38
+ global $wpml_settings;
39
+
40
+ // if plugin is installed the first time settings are not initialized properly so quit early.
41
+ if( !isset($wpml_settings) || !array_key_exists('log-rotation-limit-amout', $wpml_settings) ) {
42
+ return;
43
+ }
44
+
45
+ if ( $wpml_settings['log-rotation-limit-amout'] == true || $wpml_settings['log-rotation-delete-time'] == true ) {
46
+ $this->schedule();
47
+ } else {
48
+ $this->unschedule();
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Schedules an event.
54
+ * @since 1.4
55
+ */
56
+ function schedule() {
57
+ if ( ! wp_next_scheduled( self::WPML_LOGROTATION_SCHEDULE_HOOK ) ) {
58
+ wp_schedule_event( time(), 'hourly', self::WPML_LOGROTATION_SCHEDULE_HOOK );
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Unschedules an event.
64
+ * @since 1.4
65
+ */
66
+ function unschedule() {
67
+ wp_clear_scheduled_hook( self::WPML_LOGROTATION_SCHEDULE_HOOK );
68
+ }
69
+
70
+ /**
71
+ * The LogRotation supports the limitation of stored mails by amount.
72
+ * @since 1.6.0
73
+ */
74
+ static function limitNumberOfMailsByAmount() {
75
+ global $wpml_settings, $wpdb;
76
+
77
+ if(!isset($wpml_settings)) {
78
+ return;
79
+ }
80
+
81
+ $tableName = WPML_Plugin::getTablename( 'mails' );
82
+
83
+ if ( $wpml_settings['log-rotation-limit-amout'] == true) {
84
+ $keep = $wpml_settings['log-rotation-limit-amout-keep'];
85
+ if ( $keep > 0 ) {
86
+ $wpdb->query(
87
+ "DELETE p
88
+ FROM
89
+ $tableName AS p
90
+ JOIN
91
+ ( SELECT mail_id
92
+ FROM $tableName
93
+ ORDER BY mail_id DESC
94
+ LIMIT 1 OFFSET $keep
95
+ ) AS lim
96
+ ON p.mail_id <= lim.mail_id;"
97
+ );
98
+ }
99
+ }
100
+ }
101
+
102
+ /**
103
+ * The LogRotation supports the limitation of stored mails by date.
104
+ * @since 1.6.0
105
+ */
106
+ static function limitNumberOfMailsByTime() {
107
+ global $wpml_settings, $wpdb;
108
+
109
+ if(!isset($wpml_settings)) {
110
+ return;
111
+ }
112
+
113
+ $tableName = WPML_Plugin::getTablename( 'mails' );
114
+
115
+ if ( $wpml_settings['log-rotation-delete-time'] == true) {
116
+ $days = $wpml_settings['log-rotation-delete-time-days'];
117
+ if ( $days > 0 ) {
118
+ $wpdb->query( "DELETE FROM `$tableName` WHERE DATEDIFF( NOW(), `timestamp` ) >= $days" );
119
+ }
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Executes log rotation periodically.
125
+ * @since 1.4
126
+ */
127
+ static function LogRotationSchedule() {
128
+ self::limitNumberOfMailsByAmount();
129
+ self::limitNumberOfMailsByTime();
130
+ }
131
+ }
src/WPML_MailExtractor.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace No3x\WPML;
4
+
5
+
6
+ use No3x\WPML\Model\WPML_Mail as Mail;
7
+
8
+ class WPML_MailExtractor {
9
+
10
+ const ERROR_NO_FIELD = "The message is not valid because it contains no message or html field.";
11
+
12
+ public function __construct() {
13
+ }
14
+
15
+ public function extract($mailArray) {
16
+ return Mail::create([
17
+ 'receiver' => $this->extractReceiver($mailArray['to']),
18
+ 'subject' => $mailArray['subject'],
19
+ 'message' => $this->extractMessage($mailArray),
20
+ 'headers' => $this->extractHeader($mailArray),
21
+ 'attachments' => $this->extractAttachments($mailArray),
22
+ ]);
23
+ }
24
+
25
+ private function extractReceiver( $receiver ) {
26
+ return $this->convertMultipartsToString($receiver);
27
+ }
28
+
29
+ private function extractMessage( $mail ) {
30
+ if ( isset($mail['message']) ) {
31
+ // usually the message is stored in the message field
32
+ return $mail['message'];
33
+ } elseif ( isset($mail['html']) ) {
34
+ // for example Mandrill stores the message in the 'html' field (see gh-22)
35
+ return $mail['html'];
36
+ }
37
+ throw new \Exception(self::ERROR_NO_FIELD);
38
+ }
39
+
40
+ private function extractHeader( $mail ) {
41
+ $headers = isset($mail['headers']) ? $mail['headers'] : array();
42
+ return $this->joinMultiParts($headers);
43
+ }
44
+
45
+ private function extractAttachments( $mail ) {
46
+ $attachments = isset($mail['attachments']) ? $mail['attachments'] : array();
47
+
48
+ if(!is_array($attachments)) {
49
+ $attachments = $this->splitAtComma($attachments);
50
+ }
51
+
52
+ $attachment_urls = array();
53
+ $basename = 'uploads';
54
+ $basename_needle = '/'.$basename.'/';
55
+ foreach ($attachments as $attachment) {
56
+ $posAttachmentInUploads = strrpos($attachment, $basename_needle);
57
+ if( false !== $posAttachmentInUploads) {
58
+ $append_url = substr( $attachment, $posAttachmentInUploads + strlen($basename_needle) - 1 );
59
+ } else {
60
+ // not found, save the path unmodified
61
+ $append_url = $attachment;
62
+ }
63
+ $attachment_urls[] = $append_url;
64
+ }
65
+
66
+ $string = $this->joinArrayWithCommaAndNewLine($attachment_urls);
67
+
68
+ return $string;
69
+ }
70
+
71
+ private function convertMultipartsToString($multiparts) {
72
+
73
+ if(is_array($multiparts)) {
74
+ $multiPartArray = $multiparts;
75
+ } else {
76
+ $multiPartArray = $this->splitAtComma($multiparts);
77
+ }
78
+
79
+ $string = $this->joinArrayWithCommaAndNewLine($multiPartArray);
80
+
81
+ return $string;
82
+ }
83
+
84
+ private function splitAtComma($string) {
85
+ $parts = preg_split( "/(,|,\s)/", $string );
86
+ return $parts;
87
+ }
88
+
89
+ private function joinMultiParts($multiPart) {
90
+ return is_array($multiPart) ? $this->joinArrayWithCommaAndNewLine($multiPart) : $multiPart;
91
+ }
92
+
93
+ private function joinArrayWithCommaAndNewLine(array $array) {
94
+ return implode(',\n', $array);
95
+ }
96
+ }
src/WPML_MessageSanitizer.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace No3x\WPML;
4
+
5
+
6
+ class WPML_MessageSanitizer {
7
+
8
+ const SAVED_COMMENT_HTMLEntity_OPEN = "savedcommenthtmldentittyopen";
9
+ const SAVED_COMMENT_HTMLEntity_CLOSE = "savedcommenthtmlentittclose";
10
+ const SAVED_COMMENT_HTMLCode_OPEN = "savedcommenthtmlcodeopen";
11
+ const SAVED_COMMENT_HTMLCode_CLOSE = "savedcommenthtmlcodeclose";
12
+
13
+ private $mapping;
14
+ private $buffer;
15
+
16
+ public function __construct() {
17
+ $this->mapping = [
18
+ "&lt;!--" => '<' . self::SAVED_COMMENT_HTMLEntity_OPEN . '>',
19
+ "--&gt;" => '<' . self::SAVED_COMMENT_HTMLEntity_CLOSE . '>',
20
+ "<!--" => '<' . self::SAVED_COMMENT_HTMLCode_OPEN . '>',
21
+ "-->" => '<' . self::SAVED_COMMENT_HTMLCode_CLOSE . '>',
22
+ ];
23
+ }
24
+
25
+ public function sanitize($message) {
26
+ $this->buffer = $message;
27
+
28
+ $this->saveComments();
29
+ $this->stripEvilCode();
30
+ $this->recoverComments();
31
+
32
+ return $this->buffer;
33
+ }
34
+
35
+ private function saveComments() {
36
+ $this->swapCommentsInStringWithMapping($this->mapping);
37
+ }
38
+
39
+ private function recoverComments() {
40
+ $this->swapCommentsInStringWithMapping(array_flip($this->mapping));
41
+ }
42
+
43
+ private function swapCommentsInStringWithMapping($mapping) {
44
+ foreach ($mapping as $from => $to) {
45
+ $this->buffer = str_replace($from, $to , $this->buffer);
46
+ }
47
+ }
48
+
49
+ private function stripEvilCode() {
50
+ $allowed_tags = wp_kses_allowed_html( 'post' );
51
+ $allowed_tags['style'][''] = true;
52
+ $allowed_tags[self::SAVED_COMMENT_HTMLEntity_OPEN][''] = true;
53
+ $allowed_tags[self::SAVED_COMMENT_HTMLEntity_CLOSE][''] = true;
54
+ $allowed_tags[self::SAVED_COMMENT_HTMLCode_OPEN][''] = true;
55
+ $allowed_tags[self::SAVED_COMMENT_HTMLCode_CLOSE][''] = true;
56
+
57
+ $this->buffer = wp_kses( $this->buffer, $allowed_tags );
58
+ }
59
+
60
+ }
WPML_OptionsManager.php → src/WPML_OptionsManager.php RENAMED
@@ -1,604 +1,604 @@
1
- <?php
2
- /*
3
- "WordPress Plugin Template" Copyright (C) 2013 Michael Simpson (email : michael.d.simpson@gmail.com)
4
-
5
- This file is part of WordPress Plugin Template for WordPress.
6
-
7
- WordPress Plugin Template is free software: you can redistribute it and/or modify
8
- it under the terms of the GNU General Public License as published by
9
- the Free Software Foundation, either version 3 of the License, or
10
- (at your option) any later version.
11
-
12
- WordPress Plugin Template is distributed in the hope that it will be useful,
13
- but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- GNU General Public License for more details.
16
-
17
- You should have received a copy of the GNU General Public License
18
- along with Contact Form to Database Extension.
19
- If not, see http://www.gnu.org/licenses/gpl-3.0.html
20
- */
21
-
22
- namespace No3x\WPML;
23
-
24
- // Exit if accessed directly.
25
- if ( ! defined( 'ABSPATH' ) ) exit;
26
-
27
- class WPML_OptionsManager {
28
- /**
29
- * Is used to retrive a settings value
30
- * Important: This implementation understands bool for $default. (unlikely in comparision to all other settings implementation)
31
- * @since 1.4
32
- * @param string $settingName The option name to return
33
- * @param mixed $default (null) The value to return if option not set.
34
- * @return ambigous <string, mixed> the options value or $default if not found.
35
- */
36
- public function getSetting($settingName, $default = null) {
37
- global $wpml_settings;
38
-
39
- if ( array_key_exists($settingName, $wpml_settings)) {
40
- $retVal = $wpml_settings[$settingName];
41
- }
42
- if (!isset($retVal) && $default !== null) {
43
- $retVal = $default;
44
- }
45
- return $retVal;
46
- }
47
-
48
- /**
49
- * Returns the appropriate datetime format string.
50
- * @since 1.5.0
51
- * @return string datetime format string
52
- */
53
- public function getDateTimeFormatString() {
54
- // default database like format
55
- $format = 'Y-m-d G:i:s';
56
- $date_format = get_option( 'date_format' );
57
- $time_format = get_option( 'time_format' );
58
- // get option or change to user friendly format as the options maybe not set at all
59
- $date_format = empty( $date_format ) ? 'F j, Y' : $date_format;
60
- $time_format = empty( $time_format ) ? 'g:i a' : $time_format;
61
- if ( $this->getSetting( 'datetimeformat-use-wordpress', false) == true )
62
- // Overwrite with defined values or default
63
- $format = $date_format . " " . $time_format;
64
- return $format;
65
- }
66
-
67
- public function getOptionNamePrefix() {
68
- return $this->getClassnameWithoutNamespace() . '_';
69
- }
70
-
71
- /**
72
- * Define your options meta data here as an array, where each element in the array
73
- * @return array of key=>display-name and/or key=>array(display-name, choice1, choice2, ...)
74
- * key: an option name for the key (this name will be given a prefix when stored in
75
- * the database to ensure it does not conflict with other plugin options)
76
- * value: can be one of two things:
77
- * (1) string display name for displaying the name of the option to the user on a web page
78
- * (2) array where the first element is a display name (as above) and the rest of
79
- * the elements are choices of values that the user can select
80
- * e.g.
81
- * array(
82
- * 'item' => 'Item:', // key => display-name
83
- * 'rating' => array( // key => array ( display-name, choice1, choice2, ...)
84
- * 'CanDoOperationX' => array('Can do Operation X', 'Administrator', 'Editor', 'Author', 'Contributor', 'Subscriber'),
85
- * 'Rating:', 'Excellent', 'Good', 'Fair', 'Poor')
86
- */
87
- public function getOptionMetaData() {
88
- return array();
89
- }
90
-
91
- /**
92
- * @return array of string name of options
93
- */
94
- public function getOptionNames() {
95
- return array_keys($this->getOptionMetaData());
96
- }
97
-
98
- /**
99
- * Override this method to initialize options to default values and save to the database with add_option
100
- * @return void
101
- */
102
- protected function initOptions() {
103
- }
104
-
105
- /**
106
- * Cleanup: remove all options from the DB
107
- * @return void
108
- */
109
- protected function deleteSavedOptions() {
110
- $optionMetaData = $this->getOptionMetaData();
111
- if (is_array($optionMetaData)) {
112
- foreach ($optionMetaData as $aOptionKey => $aOptionMeta) {
113
- $prefixedOptionName = $this->prefix($aOptionKey); // how it is stored in DB
114
- delete_option($prefixedOptionName);
115
- }
116
- }
117
- }
118
-
119
- /**
120
- * Cleanup: remove version option
121
- * @since 1.6.0
122
- * @return void
123
- */
124
- protected function deleteVersionOption() {
125
- delete_option( $this->prefix( WPML_Plugin::optionVersion ) );
126
- }
127
-
128
- /**
129
- * @return string display name of the plugin to show as a name/title in HTML.
130
- * Just returns the class name. Override this method to return something more readable
131
- */
132
- public function getPluginDisplayName() {
133
- return get_class($this);
134
- }
135
-
136
- /**
137
- * @return string slug of the plugin to use as identifier.
138
- * Just returns the class name in lowercase.
139
- */
140
- public function getPluginSlug() {
141
- return strtolower( $this->getClassnameWithoutNamespace() );
142
- }
143
-
144
- /**
145
- * Get the class name without the namespace
146
- * @return string class name without the namespace.
147
- * @link http://php.net/manual/de/function.get-class.php#114568
148
- */
149
- private function getClassnameWithoutNamespace() {
150
- $classname = get_class($this);
151
- if ($pos = strrpos( $classname, '\\')) {
152
- return substr($classname, $pos + 1);
153
- }
154
- return $classname;
155
- }
156
-
157
- /**
158
- * Get the prefixed version input $name suitable for storing in WP options
159
- * Idempotent: if $optionName is already prefixed, it is not prefixed again, it is returned without change
160
- * @param $name string option name to prefix. Defined in settings.php and set as keys of $this->optionMetaData
161
- * @return string
162
- */
163
- public function prefix($name) {
164
- $optionNamePrefix = $this->getOptionNamePrefix();
165
- if (strpos($name, $optionNamePrefix) === 0) { // 0 but not false
166
- return $name; // already prefixed
167
- }
168
- return $optionNamePrefix . $name;
169
- }
170
-
171
- /**
172
- * Remove the prefix from the input $name.
173
- * Idempotent: If no prefix found, just returns what was input.
174
- * @param $name string
175
- * @return string $optionName without the prefix.
176
- */
177
- public function &unPrefix($name) {
178
- $optionNamePrefix = $this->getOptionNamePrefix();
179
- if (strpos($name, $optionNamePrefix) === 0) {
180
- return substr($name, strlen($optionNamePrefix));
181
- }
182
- return $name;
183
- }
184
-
185
- /**
186
- * A wrapper function delegating to WP get_option() but it prefixes the input $optionName
187
- * to enforce "scoping" the options in the WP options table thereby avoiding name conflicts
188
- * @param $optionName string defined in settings.php and set as keys of $this->optionMetaData
189
- * @param $default string default value to return if the option is not set
190
- * @return string the value from delegated call to get_option(), or optional default value
191
- * if option is not set.
192
- */
193
- public function getOption($optionName, $default = null) {
194
- $prefixedOptionName = $this->prefix($optionName); // how it is stored in DB
195
- $retVal = get_option($prefixedOptionName);
196
- if (!$retVal && $default) {
197
- $retVal = $default;
198
- }
199
- return $retVal;
200
- }
201
-
202
- /**
203
- * A wrapper function delegating to WP delete_option() but it prefixes the input $optionName
204
- * to enforce "scoping" the options in the WP options table thereby avoiding name conflicts
205
- * @param $optionName string defined in settings.php and set as keys of $this->optionMetaData
206
- * @return bool from delegated call to delete_option()
207
- */
208
- public function deleteOption($optionName) {
209
- $prefixedOptionName = $this->prefix($optionName); // how it is stored in DB
210
- return delete_option($prefixedOptionName);
211
- }
212
-
213
- /**
214
- * A wrapper function delegating to WP add_option() but it prefixes the input $optionName
215
- * to enforce "scoping" the options in the WP options table thereby avoiding name conflicts
216
- * @param $optionName string defined in settings.php and set as keys of $this->optionMetaData
217
- * @param $value mixed the new value
218
- * @return null from delegated call to delete_option()
219
- */
220
- public function addOption($optionName, $value) {
221
- $prefixedOptionName = $this->prefix($optionName); // how it is stored in DB
222
- return add_option($prefixedOptionName, $value);
223
- }
224
-
225
- /**
226
- * A wrapper function delegating to WP add_option() but it prefixes the input $optionName
227
- * to enforce "scoping" the options in the WP options table thereby avoiding name conflicts
228
- * @param $optionName string defined in settings.php and set as keys of $this->optionMetaData
229
- * @param $value mixed the new value
230
- * @return null from delegated call to delete_option()
231
- */
232
- public function updateOption($optionName, $value) {
233
- $prefixedOptionName = $this->prefix($optionName); // how it is stored in DB
234
- return update_option($prefixedOptionName, $value);
235
- }
236
-
237
- /**
238
- * A Role Option is an option defined in getOptionMetaData() as a choice of WP standard roles, e.g.
239
- * 'CanDoOperationX' => array('Can do Operation X', 'Administrator', 'Editor', 'Author', 'Contributor', 'Subscriber')
240
- * The idea is use an option to indicate what role level a user must minimally have in order to do some operation.
241
- * So if a Role Option 'CanDoOperationX' is set to 'Editor' then users which role 'Editor' or above should be
242
- * able to do Operation X.
243
- * Also see: canUserDoRoleOption()
244
- * @param $optionName
245
- * @return string role name
246
- */
247
- public function getRoleOption($optionName) {
248
- $roleAllowed = $this->getOption($optionName);
249
- if (!$roleAllowed || $roleAllowed == '') {
250
- $roleAllowed = 'Administrator';
251
- }
252
- return $roleAllowed;
253
- }
254
-
255
- /**
256
- * Given a WP role name (case insensitive), return a WP capability which only that role and roles above it have.
257
- * http://codex.wordpress.org/Roles_and_Capabilities
258
- * @param $roleName
259
- * @return string a WP capability or '' if unknown input role
260
- */
261
- protected function roleToCapability($roleName) {
262
- switch ( ucfirst( $roleName ) ) {
263
- case 'Super Admin':
264
- return 'manage_options';
265
- case 'Administrator':
266
- return 'manage_options';
267
- case 'Editor':
268
- return 'publish_pages';
269
- case 'Author':
270
- return 'publish_posts';
271
- case 'Contributor':
272
- return 'edit_posts';
273
- case 'Subscriber':
274
- return 'read';
275
- case 'Anyone':
276
- return 'read';
277
- }
278
- return '';
279
- }
280
-
281
- /**
282
- * @param $roleName string a standard WP role name like 'Administrator'
283
- * @return bool
284
- */
285
- public function isUserRoleEqualOrBetterThan($roleName) {
286
- if ('Anyone' == $roleName) {
287
- return true;
288
- }
289
- $capability = $this->roleToCapability($roleName);
290
- return current_user_can($capability);
291
- }
292
-
293
- /**
294
- * @param $optionName string name of a Role option (see comments in getRoleOption())
295
- * @return bool indicates if the user has adequate permissions
296
- */
297
- public function canUserDoRoleOption($optionName) {
298
- $roleAllowed = $this->getRoleOption($optionName);
299
- if ('Anyone' == $roleAllowed) {
300
- return true;
301
- }
302
- return $this->isUserRoleEqualOrBetterThan($roleAllowed);
303
- }
304
-
305
- /**
306
- * see: http://codex.wordpress.org/Creating_Options_Pages
307
- * @return void
308
- */
309
- public function createSettingsMenu() {
310
-
311
- global $wp_version;
312
- global $wp_logging_list_page;
313
-
314
- $pluginIcon = '';
315
- if ( $wp_version >= 3.8 ) $pluginIcon = 'dashicons-email-alt';
316
-
317
- $pluginNameSlug = $this->getPluginSlug();
318
- $capability = $this->getSetting( 'can-see-submission-data', 'manage_options' );
319
-
320
- //create new top-level menu
321
- $wp_logging_list_page = add_menu_page(__('WP Mail Log', 'wp-mail-logging'),
322
- __('WP Mail Log', 'wp-mail-logging'),
323
- $capability,
324
- $pluginNameSlug . '_log',
325
- array(&$this, 'LogMenu'),
326
- $pluginIcon
327
- );
328
-
329
- // Add Action to load assets when page is loaded
330
- add_action( 'load-' . $wp_logging_list_page, array( $this, 'load_assets' ) );
331
-
332
- add_submenu_page($pluginNameSlug . '_log',
333
- __('About', 'wp-mail-logging'),
334
- __('About', 'wp-mail-logging'),
335
- $capability,
336
- $pluginNameSlug . '_about',
337
- array(&$this, 'LogSubMenuAbout') );
338
-
339
- add_action( 'contextual_help', array( &$this, 'create_settings_panel' ), 10, 3 );
340
- }
341
-
342
- public function LogSubMenuAbout() {
343
- ?>
344
- <div class="wrap">
345
- <h2><?php echo $this->getPluginDisplayName(); echo ' '; _e('About', 'wp-mail-logging'); ?></h2>
346
- <h3>Why use?</h3>
347
- <p>Sometimes you may ask yourself if a mail was actually sent by WordPress - with
348
- <strong>With <?php echo $this->getPluginDisplayName(); ?>, you can:</strong></p>
349
- <ul>
350
- <li>View a complete list of sent mails.</li>
351
- <li>Search for mails.</li>
352
- <li>Count on regular updates, enhancements, and troubleshooting.</li>
353
- <li>DevOP: IP of server sent the mail</li>
354
- <li>Developer: Boost your development performance by keeping track of sent mails from your WordPress site.</li>
355
- <li>Developer: Use Filters that are provided to extend the columns.</li>
356
- </ul>
357
- <h3>Contributors</h3>
358
- <p>This plugin is open source and some people helped to make it better:</p>
359
- <ul>
360
- <li>tripflex</li>
361
- <li><a href="http://www.grafixone.co.za" title="GrafixONE">Andr&eacute; Groenewald</a> (Icon before version 1.8.0, icon after this version slightly modified)</li>
362
- </ul>
363
- <h3>Donate</h3>
364
- <p>Please consider to make a donation if you like the plugin. I spent a lot of time for support, enhancements and updates in general.</p>
365
- <a title="Donate" class="button button-primary" href="http://no3x.de/web/donate">Donate</a>
366
- </div>
367
- <?php
368
- }
369
-
370
- public function load_assets() {
371
-
372
- global $wp_logging_list_page;
373
- $screen = get_current_screen();
374
-
375
- if ( $screen->id != $wp_logging_list_page )
376
- return;
377
-
378
- // Enqueue Styles and Scripts if we're on the list page
379
- wp_enqueue_script( 'wp-logging-modal', untrailingslashit( plugin_dir_url( __FILE__ ) ) . '/js/modal.js', array( 'jquery' ), '1.0.0', true );
380
- wp_localize_script( 'wp-logging-modal', 'wpml_modal', array('ajax_nonce' => wp_create_nonce( 'wpml-modal-show' ) ) );
381
- wp_enqueue_style( 'wp-logging-modal', untrailingslashit( plugin_dir_url( __FILE__ ) ) . '/css/modal.css', array(), '1.0.0' );
382
- wp_enqueue_style( 'wp-logging-icons', untrailingslashit( plugin_dir_url( __FILE__ ) ) . '/lib/font-awesome/css/font-awesome.min.css', array(), '4.1.0' );
383
- wp_enqueue_script( 'icheck', untrailingslashit( plugin_dir_url( __FILE__ ) ) . '/lib/icheck/icheck.min.js', array(), '1.0.2' );
384
- wp_enqueue_style( 'icheck-square', untrailingslashit( plugin_dir_url( __FILE__ ) ) . '/lib/icheck/square/blue.css', array(), '1.0.2' );
385
- }
386
-
387
- /**
388
- * Add settings Panel
389
- */
390
- function create_settings_panel($contextual_help, $screen_id, $screen) {
391
-
392
- global $hook_suffix;
393
-
394
- // Just add if we are at the plugin page
395
- if ( strpos($hook_suffix, $this->getPluginSlug() . '_log' ) == false )
396
- return $contextual_help;
397
-
398
- // The add_help_tab function for screen was introduced in WordPress 3.3.
399
- if ( ! method_exists( $screen, 'add_help_tab' ) )
400
- return $contextual_help;
401
-
402
-
403
- // List screen properties
404
- $left = '<div style="width:50%;float:left;">'
405
- . '<h4>About this plugin</h4>'
406
- . '<p>This plugin is open source.</p>'
407
- . '</div>';
408
-
409
-
410
- $right = '<div style="width:50%;float:right;">'
411
- . '<h4>Donate</h4>'
412
- . '<p>If you like the plugin please consider to make a donation. More information are provided on my <a href="http://no3x.de/web/donate">website</a>.</p>'
413
- . '</div>';
414
-
415
- $help_content = $left . $right;
416
-
417
- /**
418
- * Content specified inline
419
- */
420
- $screen->add_help_tab(
421
- array(
422
- 'title' => __('About Plugin', 'wp-mail-logging'),
423
- 'id' => 'about_tab',
424
- 'content' => '<p>' . __( "{$this->getPluginDisplayName()}, logs each email sent by WordPress.", 'wp-mail-logging') . '</p>' . $help_content,
425
- 'callback' => false
426
- )
427
- );
428
-
429
- // Add help sidebar
430
- $screen->set_help_sidebar(
431
- '<p><strong>' . __('More information', 'wp-mail-logging') . '</strong></p>' .
432
- '<p><a href = "http://wordpress.org/extend/plugins/wp-mail-logging/">' . __('Plugin Homepage/support', 'wp-mail-logging') . '</a></p>' .
433
- '<p><a href = "http://no3x.de/">' . __("Plugin author's blog", 'wp-mail-logging') . '</a></p>'
434
- );
435
-
436
- // Add screen options
437
- $screen->add_option(
438
- 'per_page',
439
- array(
440
- 'label' => __('Entries per page', 'wp-mail-logging'),
441
- 'default' => 25,
442
- 'option' => 'per_page'
443
- )
444
- );
445
-
446
- return $contextual_help;
447
- }
448
-
449
- /**
450
- * Save Screen option
451
- * @since 1.3
452
- */
453
- function save_screen_options( $status, $option, $value ) {
454
- if ( 'per_page' == $option ) return $value;
455
- return $status;
456
- }
457
-
458
- public function LogMenu() {
459
- global $wp_version, $wpml_settings;
460
-
461
- if ( !current_user_can( $this->getSetting( 'can-see-submission-data', 'manage_options' ) ) ) {
462
- wp_die(__('You do not have sufficient permissions to access this page.', 'wp-mail-logging'));
463
- }
464
-
465
- if (!class_exists( 'Email_Log_List_Table' ) ) {
466
- require_once ( plugin_dir_path( __FILE__ ) . 'WPML_Email_Log_List.php' );
467
- }
468
-
469
- ?>
470
- <div class="wrap">
471
- <h2><?php echo $this->getPluginDisplayName(); echo ' '; _e('Log', 'wp-mail-logging'); ?></h2>
472
- <script>
473
- jQuery(document).ready(function($) {
474
- $('#wp-mail-logging-modal-content-header-format-switch input').iCheck({
475
- checkboxClass: 'icheckbox_square-blue',
476
- radioClass: 'iradio_square-blue',
477
- increaseArea: '20%' // optional
478
- });
479
- });
480
- </script>
481
- <div id="wp-mail-logging-modal-wrap">
482
- <div id="wp-mail-logging-modal-backdrop"></div>
483
- <div id="wp-mail-logging-modal-content-wrap">
484
- <div id="wp-mail-logging-modal-content">
485
- <div id="wp-mail-logging-modal-content-header">
486
- <a id="wp-mail-logging-modal-content-header-close" class="wp-mail-logging-modal-close" href="#" title="Close">
487
- <?php if ( $wp_version >= 3.8 ): ?>
488
- <div class="dashicons dashicons-no"></div>
489
- <?php else: ?>
490
- <span class="wp-mail-logging-modal-content-header-compat-close">X</span>
491
- <?php endif; ?>
492
- </a>
493
- <?php if ( $wp_version >= 3.8 ): ?>
494
- <div id="wp-mail-logging-modal-content-header-icon" class="dashicons dashicons-email-alt"></div>
495
- <?php endif; ?>
496
- <div id="wp-mail-logging-modal-content-header-title">
497
- <?php _e( 'Message', 'wp-mail-logging' ); ?>
498
- </div>
499
- <div id="wp-mail-logging-modal-content-header-format-switch">
500
- <?php
501
- $supported_formats = apply_filters( WPML_Plugin::HOOK_LOGGING_SUPPORTED_FORMATS, array('html') );
502
- foreach( $supported_formats as $key => $format ) {
503
- $checked = checked($format, $wpml_settings['preferred-mail-format'], false);
504
- echo ' <input type="radio" name="format" ' . $checked . ' id="' . esc_attr( $format ) . '"> ' . esc_html( $format ) . '</input> ';
505
- }
506
- ?>
507
- </div>
508
- </div>
509
- <div id="wp-mail-logging-modal-content-body">
510
- <div id="wp-mail-logging-modal-content-body-content">
511
-
512
- </div>
513
- </div>
514
- <div id="wp-mail-logging-modal-content-footer">
515
- <a class="wp-mail-logging-modal-close button button-primary" href="#"><?php _e( 'Close', 'wp-mail-logging' ); ?></a>
516
- </div>
517
- </div>
518
- </div>
519
- </div>
520
-
521
- <form id="email-list" method="get">
522
- <input type="hidden" name="page" value="<?php echo esc_attr( $_REQUEST['page'] ); ?>" />
523
- <?php
524
- wp_nonce_field( WPML_Email_Log_List::NONCE_LIST_TABLE, WPML_Email_Log_List::NONCE_LIST_TABLE . '_nonce' );
525
- $search = ( isset( $_REQUEST['s'] ) ) ? $_REQUEST['s'] : false;
526
- /** @var WPML_Email_Log_List $emailLogList */
527
- $emailLogList = WPML_Init::getInstance()->getService('emailLogList');
528
- $emailLogList->prepare_items( $search );
529
- $emailLogList->search_box( __( 'Search' ), 's' );
530
- $emailLogList->display();
531
- ?>
532
- </form>
533
- </div>
534
- <?php
535
- }
536
-
537
- /**
538
- * Override this method and follow its format.
539
- * The purpose of this method is to provide i18n display strings for the values of options.
540
- * For example, you may create a options with values 'true' or 'false'.
541
- * In the options page, this will show as a drop down list with these choices.
542
- * But when the the language is not English, you would like to display different strings
543
- * for 'true' and 'false' while still keeping the value of that option that is actually saved in
544
- * the DB as 'true' or 'false'.
545
- * To do this, follow the convention of defining option values in getOptionMetaData() as canonical names
546
- * (what you want them to literally be, like 'true') and then add each one to the switch statement in this
547
- * function, returning the "__()" i18n name of that string.
548
- * @param $optionValue string
549
- * @return string __($optionValue) if it is listed in this method, otherwise just returns $optionValue
550
- */
551
- protected function getOptionValueI18nString($optionValue) {
552
- switch ($optionValue) {
553
- case 'true':
554
- return __('true', 'wp-mail-logging');
555
- case 'false':
556
- return __('false', 'wp-mail-logging');
557
-
558
- case 'Administrator':
559
- return __('Administrator', 'wp-mail-logging');
560
- case 'Editor':
561
- return __('Editor', 'wp-mail-logging');
562
- case 'Author':
563
- return __('Author', 'wp-mail-logging');
564
- case 'Contributor':
565
- return __('Contributor', 'wp-mail-logging');
566
- case 'Subscriber':
567
- return __('Subscriber', 'wp-mail-logging');
568
- case 'Anyone':
569
- return __('Anyone', 'wp-mail-logging');
570
- }
571
- return $optionValue;
572
- }
573
-
574
- /**
575
- * Query MySQL DB for its version
576
- * @return string|false
577
- */
578
- protected function getMySqlVersion() {
579
- global $wpdb;
580
- $rows = $wpdb->get_results('select version() as mysqlversion');
581
- if (!empty($rows)) {
582
- return $rows[0]->mysqlversion;
583
- }
584
- return false;
585
- }
586
-
587
- /**
588
- * If you want to generate an email address like "no-reply@your-site.com" then
589
- * you can use this to get the domain name part.
590
- * E.g. 'no-reply@' . $this->getEmailDomain();
591
- * This code was stolen from the wp_mail function, where it generates a default
592
- * from "wordpress@your-site.com"
593
- * @return string domain name
594
- */
595
- public function getEmailDomain() {
596
- // Get the site domain and get rid of www.
597
- $sitename = strtolower($_SERVER['SERVER_NAME']);
598
- if (substr($sitename, 0, 4) == 'www.') {
599
- $sitename = substr($sitename, 4);
600
- }
601
- return $sitename;
602
- }
603
- }
604
-
1
+ <?php
2
+ /*
3
+ "WordPress Plugin Template" Copyright (C) 2013 Michael Simpson (email : michael.d.simpson@gmail.com)
4
+
5
+ This file is part of WordPress Plugin Template for WordPress.
6
+
7
+ WordPress Plugin Template is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ WordPress Plugin Template is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with Contact Form to Database Extension.
19
+ If not, see http://www.gnu.org/licenses/gpl-3.0.html
20
+ */
21
+
22
+ namespace No3x\WPML;
23
+
24
+ // Exit if accessed directly.
25
+ if ( ! defined( 'ABSPATH' ) ) exit;
26
+
27
+ class WPML_OptionsManager {
28
+ /**
29
+ * Is used to retrive a settings value
30
+ * Important: This implementation understands bool for $default. (unlikely in comparision to all other settings implementation)
31
+ * @since 1.4
32
+ * @param string $settingName The option name to return
33
+ * @param mixed $default (null) The value to return if option not set.
34
+ * @return ambigous <string, mixed> the options value or $default if not found.
35
+ */
36
+ public function getSetting($settingName, $default = null) {
37
+ global $wpml_settings;
38
+
39
+ if ( array_key_exists($settingName, $wpml_settings)) {
40
+ $retVal = $wpml_settings[$settingName];
41
+ }
42
+ if (!isset($retVal) && $default !== null) {
43
+ $retVal = $default;
44
+ }
45
+ return $retVal;
46
+ }
47
+
48
+ /**
49
+ * Returns the appropriate datetime format string.
50
+ * @since 1.5.0
51
+ * @return string datetime format string
52
+ */
53
+ public function getDateTimeFormatString() {
54
+ // default database like format
55
+ $format = 'Y-m-d G:i:s';
56
+ $date_format = get_option( 'date_format' );
57
+ $time_format = get_option( 'time_format' );
58
+ // get option or change to user friendly format as the options maybe not set at all
59
+ $date_format = empty( $date_format ) ? 'F j, Y' : $date_format;
60
+ $time_format = empty( $time_format ) ? 'g:i a' : $time_format;
61
+ if ( $this->getSetting( 'datetimeformat-use-wordpress', false) == true )
62
+ // Overwrite with defined values or default
63
+ $format = $date_format . " " . $time_format;
64
+ return $format;
65
+ }
66
+
67
+ public function getOptionNamePrefix() {
68
+ return $this->getClassnameWithoutNamespace() . '_';
69
+ }
70
+
71
+ /**
72
+ * Define your options meta data here as an array, where each element in the array
73
+ * @return array of key=>display-name and/or key=>array(display-name, choice1, choice2, ...)
74
+ * key: an option name for the key (this name will be given a prefix when stored in
75
+ * the database to ensure it does not conflict with other plugin options)
76
+ * value: can be one of two things:
77
+ * (1) string display name for displaying the name of the option to the user on a web page
78
+ * (2) array where the first element is a display name (as above) and the rest of
79
+ * the elements are choices of values that the user can select
80
+ * e.g.
81
+ * array(
82
+ * 'item' => 'Item:', // key => display-name
83
+ * 'rating' => array( // key => array ( display-name, choice1, choice2, ...)
84
+ * 'CanDoOperationX' => array('Can do Operation X', 'Administrator', 'Editor', 'Author', 'Contributor', 'Subscriber'),
85
+ * 'Rating:', 'Excellent', 'Good', 'Fair', 'Poor')
86
+ */
87
+ public function getOptionMetaData() {
88
+ return array();
89
+ }
90
+
91
+ /**
92
+ * @return array of string name of options
93
+ */
94
+ public function getOptionNames() {
95
+ return array_keys($this->getOptionMetaData());
96
+ }
97
+
98
+ /**
99
+ * Override this method to initialize options to default values and save to the database with add_option
100
+ * @return void
101
+ */
102
+ protected function initOptions() {
103
+ }
104
+
105
+ /**
106
+ * Cleanup: remove all options from the DB
107
+ * @return void
108
+ */
109
+ protected function deleteSavedOptions() {
110
+ $optionMetaData = $this->getOptionMetaData();
111
+ if (is_array($optionMetaData)) {
112
+ foreach ($optionMetaData as $aOptionKey => $aOptionMeta) {
113
+ $prefixedOptionName = $this->prefix($aOptionKey); // how it is stored in DB
114
+ delete_option($prefixedOptionName);
115
+ }
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Cleanup: remove version option
121
+ * @since 1.6.0
122
+ * @return void
123
+ */
124
+ protected function deleteVersionOption() {
125
+ delete_option( $this->prefix( WPML_Plugin::optionVersion ) );
126
+ }
127
+
128
+ /**
129
+ * @return string display name of the plugin to show as a name/title in HTML.
130
+ * Just returns the class name. Override this method to return something more readable
131
+ */
132
+ public function getPluginDisplayName() {
133
+ return get_class($this);
134
+ }
135
+
136
+ /**
137
+ * @return string slug of the plugin to use as identifier.
138
+ * Just returns the class name in lowercase.
139
+ */
140
+ public function getPluginSlug() {
141
+ return strtolower( $this->getClassnameWithoutNamespace() );
142
+ }
143
+
144
+ /**
145
+ * Get the class name without the namespace
146
+ * @return string class name without the namespace.
147
+ * @link http://php.net/manual/de/function.get-class.php#114568
148
+ */
149
+ private function getClassnameWithoutNamespace() {
150
+ $classname = get_class($this);
151
+ if ($pos = strrpos( $classname, '\\')) {
152
+ return substr($classname, $pos + 1);
153
+ }
154
+ return $classname;
155
+ }
156
+
157
+ /**
158
+ * Get the prefixed version input $name suitable for storing in WP options
159
+ * Idempotent: if $optionName is already prefixed, it is not prefixed again, it is returned without change
160
+ * @param $name string option name to prefix. Defined in settings.php and set as keys of $this->optionMetaData
161
+ * @return string
162
+ */
163
+ public function prefix($name) {
164
+ $optionNamePrefix = $this->getOptionNamePrefix();
165
+ if (strpos($name, $optionNamePrefix) === 0) { // 0 but not false
166
+ return $name; // already prefixed
167
+ }
168
+ return $optionNamePrefix . $name;
169
+ }
170
+
171
+ /**
172
+ * Remove the prefix from the input $name.
173
+ * Idempotent: If no prefix found, just returns what was input.
174
+ * @param $name string
175
+ * @return string $optionName without the prefix.
176
+ */
177
+ public function &unPrefix($name) {
178
+ $optionNamePrefix = $this->getOptionNamePrefix();
179
+ if (strpos($name, $optionNamePrefix) === 0) {
180
+ return substr($name, strlen($optionNamePrefix));
181
+ }
182
+ return $name;
183
+ }
184
+
185
+ /**
186
+ * A wrapper function delegating to WP get_option() but it prefixes the input $optionName
187
+ * to enforce "scoping" the options in the WP options table thereby avoiding name conflicts
188
+ * @param $optionName string defined in settings.php and set as keys of $this->optionMetaData
189
+ * @param $default string default value to return if the option is not set
190
+ * @return string the value from delegated call to get_option(), or optional default value
191
+ * if option is not set.
192
+ */
193
+ public function getOption($optionName, $default = null) {
194
+ $prefixedOptionName = $this->prefix($optionName); // how it is stored in DB
195
+ $retVal = get_option($prefixedOptionName);
196
+ if (!$retVal && $default) {
197
+ $retVal = $default;
198
+ }
199
+ return $retVal;
200
+ }
201
+
202
+ /**
203
+ * A wrapper function delegating to WP delete_option() but it prefixes the input $optionName
204
+ * to enforce "scoping" the options in the WP options table thereby avoiding name conflicts
205
+ * @param $optionName string defined in settings.php and set as keys of $this->optionMetaData
206
+ * @return bool from delegated call to delete_option()
207
+ */
208
+ public function deleteOption($optionName) {
209
+ $prefixedOptionName = $this->prefix($optionName); // how it is stored in DB
210
+ return delete_option($prefixedOptionName);
211
+ }
212
+
213
+ /**
214
+ * A wrapper function delegating to WP add_option() but it prefixes the input $optionName
215
+ * to enforce "scoping" the options in the WP options table thereby avoiding name conflicts
216
+ * @param $optionName string defined in settings.php and set as keys of $this->optionMetaData
217
+ * @param $value mixed the new value
218
+ * @return null from delegated call to delete_option()
219
+ */
220
+ public function addOption($optionName, $value) {
221
+ $prefixedOptionName = $this->prefix($optionName); // how it is stored in DB
222
+ return add_option($prefixedOptionName, $value);
223
+ }
224
+
225
+ /**
226
+ * A wrapper function delegating to WP add_option() but it prefixes the input $optionName
227
+ * to enforce "scoping" the options in the WP options table thereby avoiding name conflicts
228
+ * @param $optionName string defined in settings.php and set as keys of $this->optionMetaData
229
+ * @param $value mixed the new value
230
+ * @return null from delegated call to delete_option()
231
+ */
232
+ public function updateOption($optionName, $value) {
233
+ $prefixedOptionName = $this->prefix($optionName); // how it is stored in DB
234
+ return update_option($prefixedOptionName, $value);
235
+ }
236
+
237
+ /**
238
+ * A Role Option is an option defined in getOptionMetaData() as a choice of WP standard roles, e.g.
239
+ * 'CanDoOperationX' => array('Can do Operation X', 'Administrator', 'Editor', 'Author', 'Contributor', 'Subscriber')
240
+ * The idea is use an option to indicate what role level a user must minimally have in order to do some operation.
241
+ * So if a Role Option 'CanDoOperationX' is set to 'Editor' then users which role 'Editor' or above should be
242
+ * able to do Operation X.
243
+ * Also see: canUserDoRoleOption()
244
+ * @param $optionName
245
+ * @return string role name
246
+ */
247
+ public function getRoleOption($optionName) {
248
+ $roleAllowed = $this->getOption($optionName);
249
+ if (!$roleAllowed || $roleAllowed == '') {
250
+ $roleAllowed = 'Administrator';
251
+ }
252
+ return $roleAllowed;
253
+ }
254
+
255
+ /**
256
+ * Given a WP role name (case insensitive), return a WP capability which only that role and roles above it have.
257
+ * http://codex.wordpress.org/Roles_and_Capabilities
258
+ * @param $roleName
259
+ * @return string a WP capability or '' if unknown input role
260
+ */
261
+ protected function roleToCapability($roleName) {
262
+ switch ( ucfirst( $roleName ) ) {
263
+ case 'Super Admin':
264
+ return 'manage_options';
265
+ case 'Administrator':
266
+ return 'manage_options';
267
+ case 'Editor':
268
+ return 'publish_pages';
269
+ case 'Author':
270
+ return 'publish_posts';
271
+ case 'Contributor':
272
+ return 'edit_posts';
273
+ case 'Subscriber':
274
+ return 'read';
275
+ case 'Anyone':
276
+ return 'read';
277
+ }
278
+ return '';
279
+ }
280
+
281
+ /**
282
+ * @param $roleName string a standard WP role name like 'Administrator'
283
+ * @return bool
284
+ */
285
+ public function isUserRoleEqualOrBetterThan($roleName) {
286
+ if ('Anyone' == $roleName) {
287
+ return true;
288
+ }
289
+ $capability = $this->roleToCapability($roleName);
290
+ return current_user_can($capability);
291
+ }
292
+
293
+ /**
294
+ * @param $optionName string name of a Role option (see comments in getRoleOption())
295
+ * @return bool indicates if the user has adequate permissions
296
+ */
297
+ public function canUserDoRoleOption($optionName) {
298
+ $roleAllowed = $this->getRoleOption($optionName);
299
+ if ('Anyone' == $roleAllowed) {
300
+ return true;
301
+ }
302
+ return $this->isUserRoleEqualOrBetterThan($roleAllowed);
303
+ }
304
+
305
+ /**
306
+ * see: http://codex.wordpress.org/Creating_Options_Pages
307
+ * @return void
308
+ */
309
+ public function createSettingsMenu() {
310
+
311
+ global $wp_version;
312
+ global $wp_logging_list_page;
313
+
314
+ $pluginIcon = '';
315
+ if ( $wp_version >= 3.8 ) $pluginIcon = 'dashicons-email-alt';
316
+
317
+ $pluginNameSlug = $this->getPluginSlug();
318
+ $capability = $this->getSetting( 'can-see-submission-data', 'manage_options' );
319
+
320
+ //create new top-level menu
321
+ $wp_logging_list_page = add_menu_page(__('WP Mail Log', 'wp-mail-logging'),
322
+ __('WP Mail Log', 'wp-mail-logging'),
323
+ $capability,
324
+ $pluginNameSlug . '_log',
325
+ array(&$this, 'LogMenu'),
326
+ $pluginIcon
327
+ );
328
+
329
+ // Add Action to load assets when page is loaded
330
+ add_action( 'load-' . $wp_logging_list_page, array( $this, 'load_assets' ) );
331
+
332
+ add_submenu_page($pluginNameSlug . '_log',
333
+ __('About', 'wp-mail-logging'),
334
+ __('About', 'wp-mail-logging'),
335
+ $capability,
336
+ $pluginNameSlug . '_about',
337
+ array(&$this, 'LogSubMenuAbout') );
338
+
339
+ add_action( 'contextual_help', array( &$this, 'create_settings_panel' ), 10, 3 );
340
+ }
341
+
342
+ public function LogSubMenuAbout() {
343
+ ?>
344
+ <div class="wrap">
345
+ <h2><?php echo $this->getPluginDisplayName(); echo ' '; _e('About', 'wp-mail-logging'); ?></h2>
346
+ <h3>Why use?</h3>
347
+ <p>Sometimes you may ask yourself if a mail was actually sent by WordPress - with
348
+ <strong>With <?php echo $this->getPluginDisplayName(); ?>, you can:</strong></p>
349
+ <ul>
350
+ <li>View a complete list of sent mails.</li>
351
+ <li>Search for mails.</li>
352
+ <li>Count on regular updates, enhancements, and troubleshooting.</li>
353
+ <li>DevOP: IP of server sent the mail</li>
354
+ <li>Developer: Boost your development performance by keeping track of sent mails from your WordPress site.</li>
355
+ <li>Developer: Use Filters that are provided to extend the columns.</li>
356
+ </ul>
357
+ <h3>Contributors</h3>
358
+ <p>This plugin is open source and some people helped to make it better:</p>
359
+ <ul>
360
+ <li>tripflex</li>
361
+ <li><a href="http://www.grafixone.co.za" title="GrafixONE">Andr&eacute; Groenewald</a> (Icon before version 1.8.0, icon after this version slightly modified)</li>
362
+ </ul>
363
+ <h3>Donate</h3>
364
+ <p>Please consider to make a donation if you like the plugin. I spent a lot of time for support, enhancements and updates in general.</p>
365
+ <a title="Donate" class="button button-primary" href="http://no3x.de/web/donate">Donate</a>
366
+ </div>
367
+ <?php
368
+ }
369
+
370
+ public function load_assets() {
371
+
372
+ global $wp_logging_list_page;
373
+ $screen = get_current_screen();
374
+
375
+ if ( $screen->id != $wp_logging_list_page )
376
+ return;
377
+
378
+ // Enqueue Styles and Scripts if we're on the list page
379
+ wp_enqueue_script( 'wp-logging-modal', untrailingslashit( plugin_dir_url( __FILE__ ) ) . '/../js/modal.js', array( 'jquery' ), '1.0.0', true );
380
+ wp_localize_script( 'wp-logging-modal', 'wpml_modal', array('ajax_nonce' => wp_create_nonce( 'wpml-modal-show' ) ) );
381
+ wp_enqueue_style( 'wp-logging-modal', untrailingslashit( plugin_dir_url( __FILE__ ) ) . '/../css/modal.css', array(), '1.0.0' );
382
+ wp_enqueue_style( 'wp-logging-icons', untrailingslashit( plugin_dir_url( __FILE__ ) ) . '/../lib/font-awesome/css/font-awesome.min.css', array(), '4.1.0' );
383
+ wp_enqueue_script( 'icheck', untrailingslashit( plugin_dir_url( __FILE__ ) ) . '/../lib/icheck/icheck.min.js', array(), '1.0.2' );
384
+ wp_enqueue_style( 'icheck-square', untrailingslashit( plugin_dir_url( __FILE__ ) ) . '/../lib/icheck/square/blue.css', array(), '1.0.2' );
385
+ }
386
+
387
+ /**
388
+ * Add settings Panel
389
+ */
390
+ function create_settings_panel($contextual_help, $screen_id, $screen) {
391
+
392
+ global $hook_suffix;
393
+
394
+ // Just add if we are at the plugin page
395
+ if ( strpos($hook_suffix, $this->getPluginSlug() . '_log' ) == false )
396
+ return $contextual_help;
397
+
398
+ // The add_help_tab function for screen was introduced in WordPress 3.3.
399
+ if ( ! method_exists( $screen, 'add_help_tab' ) )
400
+ return $contextual_help;
401
+
402
+
403
+ // List screen properties
404
+ $left = '<div style="width:50%;float:left;">'
405
+ . '<h4>About this plugin</h4>'
406
+ . '<p>This plugin is open source.</p>'
407
+ . '</div>';
408
+
409
+
410
+ $right = '<div style="width:50%;float:right;">'
411
+ . '<h4>Donate</h4>'
412
+ . '<p>If you like the plugin please consider to make a donation. More information are provided on my <a href="http://no3x.de/web/donate">website</a>.</p>'
413
+ . '</div>';
414
+
415
+ $help_content = $left . $right;
416
+
417
+ /**
418
+ * Content specified inline
419
+ */
420
+ $screen->add_help_tab(
421
+ array(
422
+ 'title' => __('About Plugin', 'wp-mail-logging'),
423
+ 'id' => 'about_tab',
424
+ 'content' => '<p>' . __( "{$this->getPluginDisplayName()}, logs each email sent by WordPress.", 'wp-mail-logging') . '</p>' . $help_content,
425
+ 'callback' => false
426
+ )
427
+ );
428
+
429
+ // Add help sidebar
430
+ $screen->set_help_sidebar(
431
+ '<p><strong>' . __('More information', 'wp-mail-logging') . '</strong></p>' .
432
+ '<p><a href = "http://wordpress.org/extend/plugins/wp-mail-logging/">' . __('Plugin Homepage/support', 'wp-mail-logging') . '</a></p>' .
433
+ '<p><a href = "http://no3x.de/">' . __("Plugin author's blog", 'wp-mail-logging') . '</a></p>'
434
+ );
435
+
436
+ // Add screen options
437
+ $screen->add_option(
438
+ 'per_page',
439
+ array(
440
+ 'label' => __('Entries per page', 'wp-mail-logging'),
441
+ 'default' => 25,
442
+ 'option' => 'per_page'
443
+ )
444
+ );
445
+
446
+ return $contextual_help;
447
+ }
448
+
449
+ /**
450
+ * Save Screen option
451
+ * @since 1.3
452
+ */
453
+ function save_screen_options( $status, $option, $value ) {
454
+ if ( 'per_page' == $option ) return $value;
455
+ return $status;
456
+ }
457
+
458
+ public function LogMenu() {
459
+ global $wp_version, $wpml_settings;
460
+
461
+ if ( !current_user_can( $this->getSetting( 'can-see-submission-data', 'manage_options' ) ) ) {
462
+ wp_die(__('You do not have sufficient permissions to access this page.', 'wp-mail-logging'));
463
+ }
464
+
465
+ if (!class_exists( 'Email_Log_List_Table' ) ) {
466
+ require_once ( plugin_dir_path( __FILE__ ) . 'WPML_Email_Log_List.php' );
467
+ }
468
+
469
+ ?>
470
+ <div class="wrap">
471
+ <h2><?php echo $this->getPluginDisplayName(); echo ' '; _e('Log', 'wp-mail-logging'); ?></h2>
472
+ <script>
473
+ jQuery(document).ready(function($) {
474
+ $('#wp-mail-logging-modal-content-header-format-switch input').iCheck({
475
+ checkboxClass: 'icheckbox_square-blue',
476
+ radioClass: 'iradio_square-blue',
477
+ increaseArea: '20%' // optional
478
+ });
479
+ });
480
+ </script>
481
+ <div id="wp-mail-logging-modal-wrap">
482
+ <div id="wp-mail-logging-modal-backdrop"></div>
483
+ <div id="wp-mail-logging-modal-content-wrap">
484
+ <div id="wp-mail-logging-modal-content">
485
+ <div id="wp-mail-logging-modal-content-header">
486
+ <a id="wp-mail-logging-modal-content-header-close" class="wp-mail-logging-modal-close" href="#" title="Close">
487
+ <?php if ( $wp_version >= 3.8 ): ?>
488
+ <div class="dashicons dashicons-no"></div>
489
+ <?php else: ?>
490
+ <span class="wp-mail-logging-modal-content-header-compat-close">X</span>
491
+ <?php endif; ?>
492
+ </a>
493
+ <?php if ( $wp_version >= 3.8 ): ?>
494
+ <div id="wp-mail-logging-modal-content-header-icon" class="dashicons dashicons-email-alt"></div>
495
+ <?php endif; ?>
496
+ <div id="wp-mail-logging-modal-content-header-title">
497
+ <?php _e( 'Message', 'wp-mail-logging' ); ?>
498
+ </div>
499
+ <div id="wp-mail-logging-modal-content-header-format-switch">
500
+ <?php
501
+ $supported_formats = apply_filters( WPML_Plugin::HOOK_LOGGING_SUPPORTED_FORMATS, array('html') );
502
+ foreach( $supported_formats as $key => $format ) {
503
+ $checked = checked($format, $wpml_settings['preferred-mail-format'], false);
504
+ echo ' <input type="radio" name="format" ' . $checked . ' id="' . esc_attr( $format ) . '"> ' . esc_html( $format ) . '</input> ';
505
+ }
506
+ ?>
507
+ </div>
508
+ </div>
509
+ <div id="wp-mail-logging-modal-content-body">
510
+ <div id="wp-mail-logging-modal-content-body-content">
511
+
512
+ </div>
513
+ </div>
514
+ <div id="wp-mail-logging-modal-content-footer">
515
+ <a class="wp-mail-logging-modal-close button button-primary" href="#"><?php _e( 'Close', 'wp-mail-logging' ); ?></a>
516
+ </div>
517
+ </div>
518
+ </div>
519
+ </div>
520
+
521
+ <form id="email-list" method="get">
522
+ <input type="hidden" name="page" value="<?php echo esc_attr( $_REQUEST['page'] ); ?>" />
523
+ <?php
524
+ wp_nonce_field( WPML_Email_Log_List::NONCE_LIST_TABLE, WPML_Email_Log_List::NONCE_LIST_TABLE . '_nonce' );
525
+ $search = ( isset( $_REQUEST['s'] ) ) ? $_REQUEST['s'] : false;
526
+ /** @var WPML_Email_Log_List $emailLogList */
527
+ $emailLogList = WPML_Init::getInstance()->getService('emailLogList');
528
+ $emailLogList->prepare_items( $search );
529
+ $emailLogList->search_box( __( 'Search' ), 's' );
530
+ $emailLogList->display();
531
+ ?>
532
+ </form>
533
+ </div>
534
+ <?php
535
+ }
536
+
537
+ /**
538
+ * Override this method and follow its format.
539
+ * The purpose of this method is to provide i18n display strings for the values of options.
540
+ * For example, you may create a options with values 'true' or 'false'.
541
+ * In the options page, this will show as a drop down list with these choices.
542
+ * But when the the language is not English, you would like to display different strings
543
+ * for 'true' and 'false' while still keeping the value of that option that is actually saved in
544
+ * the DB as 'true' or 'false'.
545
+ * To do this, follow the convention of defining option values in getOptionMetaData() as canonical names
546
+ * (what you want them to literally be, like 'true') and then add each one to the switch statement in this
547
+ * function, returning the "__()" i18n name of that string.
548
+ * @param $optionValue string
549
+ * @return string __($optionValue) if it is listed in this method, otherwise just returns $optionValue
550
+ */
551
+ protected function getOptionValueI18nString($optionValue) {
552
+ switch ($optionValue) {
553
+ case 'true':
554
+ return __('true', 'wp-mail-logging');
555
+ case 'false':
556
+ return __('false', 'wp-mail-logging');
557
+
558
+ case 'Administrator':
559
+ return __('Administrator', 'wp-mail-logging');
560
+ case 'Editor':
561
+ return __('Editor', 'wp-mail-logging');
562
+ case 'Author':
563
+ return __('Author', 'wp-mail-logging');
564
+ case 'Contributor':
565
+ return __('Contributor', 'wp-mail-logging');
566
+ case 'Subscriber':
567
+ return __('Subscriber', 'wp-mail-logging');
568
+ case 'Anyone':
569
+ return __('Anyone', 'wp-mail-logging');
570
+ }
571
+ return $optionValue;
572
+ }
573
+
574
+ /**
575
+ * Query MySQL DB for its version
576
+ * @return string|false
577
+ */
578
+ protected function getMySqlVersion() {
579
+ global $wpdb;
580
+ $rows = $wpdb->get_results('select version() as mysqlversion');
581
+ if (!empty($rows)) {
582
+ return $rows[0]->mysqlversion;
583
+ }
584
+ return false;
585
+ }
586
+
587
+ /**
588
+ * If you want to generate an email address like "no-reply@your-site.com" then
589
+ * you can use this to get the domain name part.
590
+ * E.g. 'no-reply@' . $this->getEmailDomain();
591
+ * This code was stolen from the wp_mail function, where it generates a default
592
+ * from "wordpress@your-site.com"
593
+ * @return string domain name
594
+ */
595
+ public function getEmailDomain() {
596
+ // Get the site domain and get rid of www.
597
+ $sitename = strtolower($_SERVER['SERVER_NAME']);
598
+ if (substr($sitename, 0, 4) == 'www.') {
599
+ $sitename = substr($sitename, 4);
600
+ }
601
+ return $sitename;
602
+ }
603
+ }
604
+
WPML_Plugin.php → src/WPML_Plugin.php RENAMED
@@ -11,6 +11,8 @@ class WPML_Plugin extends WPML_LifeCycle {
11
 
12
  protected $emailLogList;
13
 
 
 
14
  const HOOK_LOGGING_COLUMNS = 'wpml_hook_mail_columns';
15
  const HOOK_LOGGING_COLUMNS_RENDER = 'wpml_hook_mail_columns_render';
16
  const HOOK_LOGGING_SUPPORTED_FORMATS = 'wpml_hook_supported_formats';
@@ -55,7 +57,7 @@ class WPML_Plugin extends WPML_LifeCycle {
55
  `attachments` VARCHAR(800) NOT NULL DEFAULT '0',
56
  `error` VARCHAR(400) NULL DEFAULT '',
57
  `plugin_version` VARCHAR(200) NOT NULL DEFAULT '0',
58
- PRIMARY KEY (`mail_id`)
59
  ) DEFAULT CHARACTER SET = utf8 DEFAULT COLLATE utf8_general_ci;");
60
  }
61
 
@@ -68,6 +70,8 @@ class WPML_Plugin extends WPML_LifeCycle {
68
  global $wpdb;
69
  $tableName = WPML_Plugin::getTablename('mails');
70
  $wpdb->query("DROP TABLE IF EXISTS `$tableName`");
 
 
71
  }
72
 
73
  /**
@@ -154,7 +158,7 @@ class WPML_Plugin extends WPML_LifeCycle {
154
  // Add Actions & Filters
155
  // http://plugin.michael-simpson.com/?page_id=37
156
  add_filter( 'plugin_action_links', array( &$this, 'registerPluginActionLinks'), 10, 5 );
157
- add_filter( 'wp_mail', array( &$this, 'log_email' ), PHP_INT_MAX );
158
  add_action( 'wp_mail_failed', array( &$this, 'log_email_failed' ) );
159
  add_filter( 'set-screen-option', array( &$this, 'save_screen_options' ), 10, 3);
160
  add_filter( 'wpml_get_plugin_version', array( &$this, 'getVersion' ) );
@@ -190,70 +194,28 @@ class WPML_Plugin extends WPML_LifeCycle {
190
  $failed_mail->set_error($wperror->get_error_message())->save();
191
  }
192
 
193
- private function extractReceiver( $receiver ) {
194
- return is_array( $receiver ) ? implode( ',\n', $receiver ) : $receiver;
195
- }
196
-
197
- private function extractHeader( $headers ) {
198
- return is_array( $headers ) ? implode( ',\n', $headers ) : $headers;
199
- }
200
-
201
- private function extractAttachments( $mail ) {
202
- $attachments = isset($mail['attachments']) ? $mail['attachments'] : array();
203
- $attachments = is_array( $attachments ) ? $attachments : array( $attachments );
204
- $attachment_urls = array();
205
- $uploads = wp_upload_dir();
206
- $basename = 'uploads';
207
- $basename_needle = '/'.$basename.'/';
208
- foreach ( $attachments as $attachment ) {
209
- $append_url = substr( $attachment, strrpos( $attachment, $basename_needle ) + strlen($basename_needle) - 1 );
210
- $attachment_urls[] = $append_url;
211
- }
212
- return implode( ',\n', $attachment_urls );
213
- }
214
-
215
- private function extractMessage( $mail ) {
216
- if ( isset($mail['message']) ) {
217
- // usually the message is stored in the message field
218
- return $mail['message'];
219
- } elseif ( isset($mail['html']) ) {
220
- // for example Mandrill stores the message in the 'html' field (see gh-22)
221
- return $mail['html'];
222
- }
223
- return "";
224
- }
225
-
226
-
227
- private function extractFields( $mail ) {
228
- return array(
229
- 'receiver' => $this->extractReceiver( $mail['to'] ),
230
- 'subject' => $mail['subject'],
231
- 'message' => $this->extractMessage( $mail ),
232
- 'headers' => $this->extractHeader( $mail['headers'] ),
233
- 'attachments' => $this->extractAttachments( $mail ),
234
- 'plugin_version' => $this->getVersionSaved(),
235
- 'timestamp' => current_time( 'mysql' ),
236
- 'host' => isset( $_SERVER['SERVER_ADDR'] ) ? $_SERVER['SERVER_ADDR'] : ''
237
- );
238
- }
239
-
240
-
241
  /**
242
  * Logs mail to database.
243
  *
244
- * @param array $mailOriginal
245
  * @global $wpml_current_mail_id
246
  * @since 1.0
247
  * @return array $mailOriginal
248
  */
249
- public function log_email( $mailOriginal ) {
250
  global $wpml_current_mail_id;
251
- // make copy to avoid any changes on the original mail
252
- $mail = $mailOriginal;
253
 
254
- $fields = $this->extractFields( $mail );
255
- $wpml_current_mail_id = Mail::create($fields)->save();
 
 
 
 
 
 
 
256
 
257
- return $mailOriginal;
 
258
  }
259
  }
11
 
12
  protected $emailLogList;
13
 
14
+ const HOOK_LOGGING_MAIL = 'log_email';
15
+ const HOOK_LOGGING_MAIL_PRIORITY = PHP_INT_MAX;
16
  const HOOK_LOGGING_COLUMNS = 'wpml_hook_mail_columns';
17
  const HOOK_LOGGING_COLUMNS_RENDER = 'wpml_hook_mail_columns_render';
18
  const HOOK_LOGGING_SUPPORTED_FORMATS = 'wpml_hook_supported_formats';
57
  `attachments` VARCHAR(800) NOT NULL DEFAULT '0',
58
  `error` VARCHAR(400) NULL DEFAULT '',
59
  `plugin_version` VARCHAR(200) NOT NULL DEFAULT '0',
60
+ PRIMARY KEY (`mail_id`)
61
  ) DEFAULT CHARACTER SET = utf8 DEFAULT COLLATE utf8_general_ci;");
62
  }
63
 
70
  global $wpdb;
71
  $tableName = WPML_Plugin::getTablename('mails');
72
  $wpdb->query("DROP TABLE IF EXISTS `$tableName`");
73
+ // Remove the cache option indicating tables are installed
74
+ wp_cache_delete(parent::CACHE_INSTALLED_KEY, parent::CACHE_GROUP);
75
  }
76
 
77
  /**
158
  // Add Actions & Filters
159
  // http://plugin.michael-simpson.com/?page_id=37
160
  add_filter( 'plugin_action_links', array( &$this, 'registerPluginActionLinks'), 10, 5 );
161
+ add_filter( 'wp_mail', array( $this, self::HOOK_LOGGING_MAIL ), self::HOOK_LOGGING_MAIL_PRIORITY );
162
  add_action( 'wp_mail_failed', array( &$this, 'log_email_failed' ) );
163
  add_filter( 'set-screen-option', array( &$this, 'save_screen_options' ), 10, 3);
164
  add_filter( 'wpml_get_plugin_version', array( &$this, 'getVersion' ) );
194
  $failed_mail->set_error($wperror->get_error_message())->save();
195
  }
196
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  /**
198
  * Logs mail to database.
199
  *
200
+ * @param array $mailArray
201
  * @global $wpml_current_mail_id
202
  * @since 1.0
203
  * @return array $mailOriginal
204
  */
205
+ public function log_email( $mailArray ) {
206
  global $wpml_current_mail_id;
 
 
207
 
208
+ $mail = (new WPML_MailExtractor())->extract($mailArray);
209
+ $mail->set_plugin_version($this->getVersionSaved());
210
+ $mail->set_timestamp(current_time( 'mysql' ));
211
+ $mail->set_host( isset( $_SERVER['SERVER_ADDR'] ) ? $_SERVER['SERVER_ADDR'] : '');
212
+
213
+ $wpml_current_mail_id = $mail->save();
214
+
215
+ return $mailArray;
216
+ }
217
 
218
+ public static function getClass() {
219
+ return __CLASS__;
220
  }
221
  }
src/WPML_PrivacyController.php ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace No3x\WPML;
3
+
4
+
5
+ use No3x\WPML\Model\WPML_Mail;
6
+
7
+ class WPML_PrivacyController {
8
+
9
+ const WPML_PRIVACY_EXPORTER = "wp-mail-logging-exporter";
10
+ const WPML_PRIVACY_ERASER = "wp-mail-logging-eraser";
11
+ const PER_PAGE = 500;
12
+
13
+ /**
14
+ * WPML_PrivacyController constructor.
15
+ */
16
+ private $plugin_meta;
17
+
18
+ function __construct( $plugin_meta ) {
19
+ $this->plugin_meta = $plugin_meta;
20
+ }
21
+
22
+ public function addActionsAndFilters() {
23
+ add_filter( 'wp_privacy_personal_data_exporters', [$this, 'register_exporter'], 10);
24
+ add_filter( 'wp_privacy_personal_data_erasers', [$this, 'register_eraser'], 10);
25
+ add_action( 'admin_init', [$this, 'register_privacy_policy_content'] );
26
+ add_action( 'wp_privacy_personal_data_erased', [$this, 'suspendLogging'], 9 );
27
+ }
28
+
29
+ function suspendLogging() {
30
+ (new WPML_Hook_Remover())->remove_class_hook(
31
+ 'wp_mail',
32
+ WPML_Plugin::getClass(),
33
+ WPML_Plugin::HOOK_LOGGING_MAIL,
34
+ WPML_Plugin::HOOK_LOGGING_MAIL_PRIORITY
35
+ );
36
+ }
37
+
38
+ function register_privacy_policy_content() {
39
+ if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) {
40
+ return;
41
+ }
42
+
43
+ $content = __( 'When you use this site several actions (e.g. commenting) trigger the dispatch of emails. They contain information about you associated with your email address. Which data are part of these emails depends on the action performed. These emails are stored and accessible to the site management as log.', 'wp-mail-logging' );
44
+
45
+ wp_add_privacy_policy_content(
46
+ $this->plugin_meta['display_name'],
47
+ wp_kses_post( wpautop( $content, false ) )
48
+ );
49
+
50
+ }
51
+
52
+ function register_exporter( $exporters ) {
53
+ $exporters[self::WPML_PRIVACY_EXPORTER] = array(
54
+ 'exporter_friendly_name' => __( 'WP Mail Logging' ),
55
+ 'callback' => [$this, 'export'],
56
+ );
57
+ return $exporters;
58
+ }
59
+
60
+ function register_eraser( $erasers ) {
61
+ $erasers[self::WPML_PRIVACY_ERASER] = array(
62
+ 'eraser_friendly_name' => __( 'WP Mail Logging' ),
63
+ 'callback' => [$this, 'erase'],
64
+ );
65
+ return $erasers;
66
+ }
67
+
68
+ /**
69
+ * @param $email_address
70
+ * @param $current_page
71
+ * @return array|WPML_Mail[]
72
+ */
73
+ private function queryMails($email_address, $current_page) {
74
+ $offset = ( $current_page - 1 ) * self::PER_PAGE;
75
+ return WPML_Mail::query()
76
+ ->search( $email_address )
77
+ ->limit( self::PER_PAGE )
78
+ ->offset( $offset )
79
+ ->find();
80
+ }
81
+
82
+ public function export($email_address, $page = 1) {
83
+ $mails = $this->queryMails($email_address, $page);
84
+
85
+ $export_items = [];
86
+ foreach ($mails as $mail) {
87
+ // Most item IDs should look like postType-postID
88
+ // If you don't have a post, comment or other ID to work with,
89
+ // use a unique value to avoid having this item's export
90
+ // combined in the final report with other items of the same id
91
+ $item_id = "mail-{$mail->get_mail_id()}";
92
+
93
+ // Core group IDs include 'comments', 'posts', etc.
94
+ // But you can add your own group IDs as needed
95
+ $group_id = 'mails';
96
+
97
+ // Optional group label. Core provides these for core groups.
98
+ // If you define your own group, the first exporter to
99
+ // include a label will be used as the group label in the
100
+ // final exported report
101
+ $group_label = __( 'Mails' );
102
+
103
+ // Plugins can add as many items in the item data array as they want
104
+ $mail_as_array = $mail->to_array();
105
+ $data = [];
106
+ foreach ($mail_as_array as $name => $value) {
107
+ $data[] = [
108
+ 'name' => $name, //TODO: translate function
109
+ 'value' => $value
110
+ ];
111
+ }
112
+
113
+ $export_items[] = array(
114
+ 'group_id' => $group_id,
115
+ 'group_label' => $group_label,
116
+ 'item_id' => $item_id,
117
+ 'data' => $data,
118
+ );
119
+ }
120
+
121
+ return array(
122
+ 'data' => $export_items,
123
+ 'done' => $this->isDone($mails),
124
+ );
125
+ }
126
+
127
+ function erase( $email_address, $page = 1 ) {
128
+ $mails = $this->queryMails($email_address, $page);
129
+
130
+ $items_removed = false;
131
+ $items_retained = false;
132
+ $messages = [];
133
+ foreach ($mails as $mail) {
134
+ if($mail->delete()) {
135
+ $items_removed = true;
136
+ } else {
137
+ $messages[] = sprintf( __( 'A mail with the id %d was unable to be removed at this time.', 'wp-mail-logging'), $mail->get_mail_id());
138
+ $items_retained = true;
139
+ }
140
+ }
141
+
142
+ return array( 'items_removed' => $items_removed,
143
+ 'items_retained' => $items_retained, // always false in this example
144
+ 'messages' => $messages, // no messages in this example
145
+ 'done' => $this->isDone($mails),
146
+ );
147
+ }
148
+
149
+ /**
150
+ * True if we have more mails to work on still.
151
+ * @param $mails
152
+ * @return bool
153
+ */
154
+ private function isDone($mails) {
155
+ return count($mails) < self::PER_PAGE;
156
+ }
157
+ }
WPML_Utils.php → src/WPML_Utils.php RENAMED
@@ -1,118 +1,118 @@
1
- <?php
2
-
3
- namespace No3x\WPML;
4
-
5
- // Exit if accessed directly.
6
- if ( ! defined( 'ABSPATH' ) ) exit;
7
-
8
- /**
9
- * Utils
10
- * @author No3x
11
- * @since 1.6.0
12
- */
13
- class WPML_Utils {
14
- /**
15
- * Ensure value is subset of given set
16
- * @since 1.6.0
17
- * @param string $value expected value.
18
- * @param array $allowed_values allowed values.
19
- * @param string $default_value default value.
20
- * @return mixed
21
- */
22
- public static function sanitize_expected_value( $value, $allowed_values, $default_value = null ) {
23
- $allowed_values = (is_array( $allowed_values ) ) ? $allowed_values : array( $allowed_values );
24
- if ( $value && in_array( $value, $allowed_values ) ) {
25
- return $value;
26
- }
27
- if ( null !== $default_value ) {
28
- return $default_value;
29
- }
30
- return false;
31
- }
32
-
33
- /**
34
- * Multilevel array_search
35
- * @since 1.3
36
- * @param string $needle the searched value.
37
- * @param array $haystack the array.
38
- * @return mixed Returns the value if needle is found in the array, false otherwise.
39
- * @see array_search()
40
- */
41
- public static function recursive_array_search( $needle, $haystack ) {
42
- foreach ( $haystack as $key => $value ) {
43
- $current_key = $key;
44
- if ( $needle === $value or ( is_array( $value ) && self::recursive_array_search( $needle, $value ) !== false ) ) {
45
- return $current_key;
46
- }
47
- }
48
- return false;
49
- }
50
-
51
- /**
52
- * Determines appropriate fa icon for a file
53
- * @sine 1.3
54
- * @param string $file_path path to file.
55
- * @return string returns the most suitable icon or generic one if not possible.
56
- */
57
- public static function determine_fa_icon( $file_path ) {
58
- $default_icon = '<i class="fa fa-file-o"></i>';
59
- $supported = array(
60
- 'archive' => array(
61
- 'application/zip',
62
- 'application/x-rar-compressed',
63
- 'application/x-rar',
64
- 'application/x-gzip',
65
- 'application/x-msdownload',
66
- 'application/x-msdownload',
67
- 'application/vnd.ms-cab-compressed',
68
- ),
69
- 'audio',
70
- 'code' => array(
71
- 'text/x-c',
72
- 'text/x-c++',
73
- ),
74
- 'excel' => array( 'application/vnd.ms-excel'
75
- ),
76
- 'image', 'text', 'movie', 'pdf', 'photo', 'picture',
77
- 'powerpoint' => array(
78
- 'application/vnd.ms-powerpoint'
79
- ), 'sound', 'video', 'word' => array(
80
- 'application/msword'
81
- ), 'zip'
82
- );
83
-
84
- if( !function_exists('mime_content_type') ) {
85
- return $default_icon;
86
- }
87
-
88
- $mime = mime_content_type( $file_path );
89
- $mime_parts = explode( '/', $mime );
90
- $attribute = $mime_parts[0];
91
- $type = $mime_parts[1];
92
-
93
- $fa_icon = false;
94
- if ( ($key = self::recursive_array_search( $mime, $supported ) ) !== false ) {
95
- // Use specific icon for mime first.
96
- $fa_icon = $key;
97
- } elseif ( in_array( $attribute, $supported ) ) {
98
- // Use generic file icon.
99
- $fa_icon = $attribute;
100
- }
101
-
102
- if ( false === $fa_icon ) {
103
- return $default_icon;
104
- } else {
105
- return '<i class="fa fa-file-' . $fa_icon . '-o"></i>';
106
- }
107
- }
108
-
109
- /**
110
- * Find appropriate fa icon from file path
111
- * @since 1.3
112
- * @param string $file_path path to file.
113
- * @return string
114
- */
115
- public static function generate_attachment_icon( $file_path ) {
116
- return self::determine_fa_icon( $file_path );
117
- }
118
- }
1
+ <?php
2
+
3
+ namespace No3x\WPML;
4
+
5
+ // Exit if accessed directly.
6
+ if ( ! defined( 'ABSPATH' ) ) exit;
7
+
8
+ /**
9
+ * Utils
10
+ * @author No3x
11
+ * @since 1.6.0
12
+ */
13
+ class WPML_Utils {
14
+ /**
15
+ * Ensure value is subset of given set
16
+ * @since 1.6.0
17
+ * @param string $value expected value.
18
+ * @param array $allowed_values allowed values.
19
+ * @param string $default_value default value.
20
+ * @return mixed
21
+ */
22
+ public static function sanitize_expected_value( $value, $allowed_values, $default_value = null ) {
23
+ $allowed_values = (is_array( $allowed_values ) ) ? $allowed_values : array( $allowed_values );
24
+ if ( $value && in_array( $value, $allowed_values ) ) {
25
+ return $value;
26
+ }
27
+ if ( null !== $default_value ) {
28
+ return $default_value;
29
+ }
30
+ return false;
31
+ }
32
+
33
+ /**
34
+ * Multilevel array_search
35
+ * @since 1.3
36
+ * @param string $needle the searched value.
37
+ * @param array $haystack the array.
38
+ * @return mixed Returns the value if needle is found in the array, false otherwise.
39
+ * @see array_search()
40
+ */
41
+ public static function recursive_array_search( $needle, $haystack ) {
42
+ foreach ( $haystack as $key => $value ) {
43
+ $current_key = $key;
44
+ if ( $needle === $value or ( is_array( $value ) && self::recursive_array_search( $needle, $value ) !== false ) ) {
45
+ return $current_key;
46
+ }
47
+ }
48
+ return false;
49
+ }
50
+
51
+ /**
52
+ * Determines appropriate fa icon for a file
53
+ * @sine 1.3
54
+ * @param string $file_path path to file.
55
+ * @return string returns the most suitable icon or generic one if not possible.
56
+ */
57
+ public static function determine_fa_icon( $file_path ) {
58
+ $default_icon = '<i class="fa fa-file-o"></i>';
59
+ $supported = array(
60
+ 'archive' => array(
61
+ 'application/zip',
62
+ 'application/x-rar-compressed',
63
+ 'application/x-rar',
64
+ 'application/x-gzip',
65
+ 'application/x-msdownload',
66
+ 'application/x-msdownload',
67
+ 'application/vnd.ms-cab-compressed',
68
+ ),
69
+ 'audio',
70
+ 'code' => array(
71
+ 'text/x-c',
72
+ 'text/x-c++',
73
+ ),
74
+ 'excel' => array( 'application/vnd.ms-excel'
75
+ ),
76
+ 'image', 'text', 'movie', 'pdf', 'photo', 'picture',
77
+ 'powerpoint' => array(
78
+ 'application/vnd.ms-powerpoint'
79
+ ), 'sound', 'video', 'word' => array(
80
+ 'application/msword'
81
+ ), 'zip'
82
+ );
83
+
84
+ if( !function_exists('mime_content_type') ) {
85
+ return $default_icon;
86
+ }
87
+
88
+ $mime = mime_content_type( $file_path );
89
+ $mime_parts = explode( '/', $mime );
90
+ $attribute = $mime_parts[0];
91
+ $type = $mime_parts[1];
92
+
93
+ $fa_icon = false;
94
+ if ( ($key = self::recursive_array_search( $mime, $supported ) ) !== false ) {
95
+ // Use specific icon for mime first.
96
+ $fa_icon = $key;
97
+ } elseif ( in_array( $attribute, $supported ) ) {
98
+ // Use generic file icon.
99
+ $fa_icon = $attribute;
100
+ }
101
+
102
+ if ( false === $fa_icon ) {
103
+ return $default_icon;
104
+ } else {
105
+ return '<i class="fa fa-file-' . $fa_icon . '-o"></i>';
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Find appropriate fa icon from file path
111
+ * @since 1.3
112
+ * @param string $file_path path to file.
113
+ * @return string
114
+ */
115
+ public static function generate_attachment_icon( $file_path ) {
116
+ return self::determine_fa_icon( $file_path );
117
+ }
118
+ }
{inc → src/inc}/class-wp-list-table.php RENAMED
File without changes
{inc → src/inc}/redux/WPML_Redux_Framework_config.php RENAMED
@@ -1,359 +1,359 @@
1
- <?php
2
-
3
- namespace No3x\WPML\Settings;
4
-
5
- /**
6
- * ReduxFramework Sample Config File
7
- * For full documentation, please visit: http://docs.reduxframework.com/
8
- */
9
-
10
- if (!class_exists('WPML_Redux_Framework_config')) {
11
-
12
- class WPML_Redux_Framework_config {
13
-
14
- public $args = array();
15
- public $sections = array();
16
- public $theme;
17
- public $ReduxFramework;
18
- protected $plugin_meta = array();
19
-
20
- public function __construct( $plugin_meta ) {
21
- $this->plugin_meta = $plugin_meta;
22
-
23
- if ( ! class_exists( 'ReduxFramework' ) ) {
24
- return;
25
- }
26
-
27
- // This is needed. Bah WordPress bugs. ;)
28
- if ( true == \Redux_Helpers::isTheme( __FILE__ ) ) {
29
- $this->initSettings();
30
- } else {
31
- add_action( 'plugins_loaded', array( $this, 'initSettings' ), 10 );
32
- }
33
-
34
- }
35
-
36
- public function initSettings() {
37
-
38
- // Just for demo purposes. Not needed per say.
39
- $this->theme = wp_get_theme();
40
-
41
- // Set the default arguments
42
- $this->setArguments();
43
-
44
- // Set a few help tabs so you can see how it's done
45
- // $this->setHelpTabs();
46
-
47
- // Create the sections and fields
48
- $this->setSections();
49
-
50
- if ( ! isset( $this->args['opt_name'] ) ) { // No errors please
51
- return;
52
- }
53
-
54
- // If Redux is running as a plugin, this will remove the demo notice and links
55
- //add_action( 'redux/loaded', array( $this, 'remove_demo' ) );
56
-
57
- // Function to test the compiler hook and demo CSS output.
58
- // Above 10 is a priority, but 2 in necessary to include the dynamically generated CSS to be sent to the function.
59
- //add_filter('redux/options/'.$this->args['opt_name'].'/compiler', array( $this, 'compiler_action' ), 10, 3);
60
-
61
- // Change the arguments after they've been declared, but before the panel is created
62
- //add_filter('redux/options/'.$this->args['opt_name'].'/args', array( $this, 'change_arguments' ) );
63
-
64
- // Change the default value of a field after it's been set, but before it's been useds
65
- //add_filter('redux/options/'.$this->args['opt_name'].'/defaults', array( $this,'change_defaults' ) );
66
-
67
- // Dynamically add a section. Can be also used to modify sections/fields
68
- //add_filter('redux/options/' . $this->args['opt_name'] . '/sections', array($this, 'dynamic_section'));
69
-
70
- $this->ReduxFramework = new \ReduxFramework( $this->sections, $this->args );
71
- }
72
-
73
- // Remove the demo link and the notice of integrated demo from the redux-framework plugin
74
- function remove_demo() {
75
-
76
- // Used to hide the demo mode link from the plugin page. Only used when Redux is a plugin.
77
- if ( class_exists( 'ReduxFrameworkPlugin' ) ) {
78
- remove_filter( 'plugin_row_meta', array(
79
- ReduxFrameworkPlugin::instance(),
80
- 'plugin_metalinks'
81
- ), null, 2 );
82
-
83
- // Used to hide the activation notice informing users of the demo panel. Only used when Redux is a plugin.
84
- remove_action( 'admin_notices', array( ReduxFrameworkPlugin::instance(), 'admin_notices' ) );
85
- }
86
- }
87
-
88
- public function setSections() {
89
-
90
- // ACTUAL DECLARATION OF SECTIONS
91
- $this->sections[] = array(
92
- 'title' => __('General Settings', 'wp-mail-logging'),
93
- 'desc' => __('', 'wp-mail-logging'),
94
- 'icon' => 'el-icon-cogs',
95
- // 'submenu' => false, // Setting submenu to false on a given section will hide it from the WordPress sidebar menu!
96
- 'fields' => array(
97
-
98
- array(
99
- 'id' => 'delete-on-deactivation',
100
- 'type' => 'switch',
101
- 'title' => __('Cleanup', 'wp-mail-logging' ),
102
- 'subtitle' => __('Delete all data on deactivation? (emails and settings)?', 'wp-mail-logging'),
103
- 'default' => 0,
104
- 'on' => __(__('Enabled', 'wp-mail-logging' ), 'wp-mail-logging' ),
105
- 'off' => __(__('Disabled', 'wp-mail-logging' ), 'wp-mail-logging' ),
106
- ),
107
- array(
108
- 'id' => 'can-see-submission-data',
109
- 'type' => 'select',
110
- 'data' => 'capabilities',
111
- 'default' => 'manage_options',
112
- 'title' => __('Can See Submission data', 'wp-mail-logging'),
113
- 'subtitle' => __('Select the minimum role.', 'wp-mail-logging'),
114
- ),
115
- array(
116
- 'id' => 'datetimeformat-use-wordpress',
117
- 'type' => 'switch',
118
- 'title' => __('WordPress Date Time Format', 'wp-mail-logging' ),
119
- 'subtitle' => sprintf( __( "Use format from WordPress settings (%s)", 'wp-mail-logging' ), date_i18n( $this->wordpress_default_format(), current_time( 'timestamp' ) ) ),
120
- 'default' => 0,
121
- 'on' => __('Enabled', 'wp-mail-logging' ),
122
- 'off' => __('Disabled', 'wp-mail-logging' ),
123
- ),
124
- array(
125
- 'id' => 'preferred-mail-format',
126
- 'type' => 'select',
127
- 'options' => array(
128
- 'html' => 'html',
129
- 'raw' => 'raw',
130
- 'json' => 'json'
131
- ),
132
- 'default' => 'html',
133
- 'title' => __('Default Format for Message', 'wp-mail-logging'),
134
- 'subtitle' => __('Select your preferred display format.', 'wp-mail-logging'),
135
- ),
136
- array(
137
- 'id' => 'display-host',
138
- 'type' => 'switch',
139
- 'title' => __('Display Host', 'wp-mail-logging' ),
140
- 'subtitle' => __('Display host column in list.', 'wp-mail-logging'),
141
- 'hint' => array(
142
- 'title' => 'Host',
143
- 'content' => 'Display the IP of the host WordPress is running on. This is useful when running it on multiple servers at the same time.',
144
- ),
145
- 'default' => 0,
146
- 'on' => __('Enabled', 'wp-mail-logging' ),
147
- 'off' => __('Disabled', 'wp-mail-logging' ),
148
- ),
149
- array(
150
- 'id' => 'section-log-rotation-start',
151
- 'type' => 'section',
152
- 'title' => __('Log Rotation', 'wp-mail-logging' ),
153
- 'subtitle' => __('Save space by deleting logs regularly.', 'wp-mail-logging'),
154
- 'indent' => true, // Indent all options below until the next 'section' option is set.
155
- ),
156
- array(
157
- 'id' => 'log-rotation-limit-amout',
158
- 'type' => 'switch',
159
- 'title' => __('Cleanup by Amount', 'wp-mail-logging' ),
160
- 'subtitle' => __('Setup a automated cleanup routine!', 'wp-mail-logging'),
161
- 'default' => 0,
162
- 'on' => __('Enabled', 'wp-mail-logging' ),
163
- 'off' => __('Disabled', 'wp-mail-logging' ),
164
- ),
165
- array(
166
- 'id' => 'log-rotation-limit-amout-keep',
167
- 'type' => 'slider',
168
- 'required' => array('log-rotation-limit-amout', '=', '1'),
169
- 'title' => __('Amount', 'wp-mail-logging' ),
170
- 'subtitle' => __('When should mails are deleted?', 'wp-mail-logging'),
171
- 'desc' => __('Cleanup when the stored mails exceed...', 'wp-mail-logging'),
172
- 'default' => 75,
173
- 'min' => 25,
174
- 'step' => 50,
175
- 'max' => 3000,
176
- 'display_value' => 'text'
177
- ),
178
- array(
179
- 'id' => 'log-rotation-delete-time',
180
- 'type' => 'switch',
181
- 'title' => __('Cleanup by Time', 'wp-mail-logging' ),
182
- 'subtitle' => __('Setup a automated cleanup routine!', 'wp-mail-logging'),
183
- 'default' => 0,
184
- 'on' => __('Enabled', 'wp-mail-logging' ),
185
- 'off' => __('Disabled', 'wp-mail-logging' ),
186
- ),
187
- array(
188
- 'id' => 'log-rotation-delete-time-days',
189
- 'type' => 'slider',
190
- 'required' => array('log-rotation-delete-time', '=', '1'),
191
- 'title' => __('Time', 'wp-mail-logging' ),
192
- 'subtitle' => __('When should mails are deleted?', 'wp-mail-logging'),
193
- 'desc' => __('Delete mails older than days...', 'wp-mail-logging'),
194
- 'default' => 30,
195
- 'min' => 1,
196
- 'step' => 7,
197
- 'max' => 400,
198
- 'display_value' => 'text'
199
- ),
200
- array(
201
- 'id' => 'section-log-rotation-end',
202
- 'type' => 'section',
203
- 'indent' => false // Indent all options below until the next 'section' option is set.
204
- ),
205
- ),
206
- );
207
- }
208
-
209
- public function wordpress_default_format()
210
- {
211
- $date_format = get_option( 'date_format' );
212
- $time_format = get_option( 'time_format' );
213
- $date_format = empty( $date_format ) ? 'F j, Y' : $date_format;
214
- $time_format = empty( $time_format ) ? 'g:i a' : $time_format;
215
- return "{$date_format} {$time_format}";
216
- }
217
-
218
- /**
219
- * All the possible arguments for Redux.
220
- * For full documentation on arguments, please refer to: https://github.com/ReduxFramework/ReduxFramework/wiki/Arguments
221
- * */
222
- public function setArguments() {
223
-
224
- $theme = wp_get_theme(); // For use with some settings. Not necessary.
225
-
226
- $this->args = array(
227
- // TYPICAL -> Change these values as you need/desire
228
- 'opt_name' => 'wpml_settings',
229
- // This is where your data is stored in the database and also becomes your global variable name.
230
- 'display_name' => 'WP Mail Logging Settings',
231
- // Name that appears at the top of your panel
232
- 'display_version' => $this->plugin_meta['version_installed'],
233
- // Version that appears at the top of your panel
234
- 'menu_type' => 'submenu',
235
- //Specify if the admin menu should appear or not. Options: menu or submenu (Under appearance only)
236
- 'allow_sub_menu' => true,
237
- // Show the sections below the admin menu item or not
238
- 'menu_title' => 'Settings',
239
- 'page_title' => $this->plugin_meta['display_name'],
240
- // You will need to generate a Google API key to use this feature.
241
- // Please visit: https://developers.google.com/fonts/docs/developer_api#Auth
242
- 'google_api_key' => '',
243
- // Set it you want google fonts to update weekly. A google_api_key value is required.
244
- 'google_update_weekly' => false,
245
- // Must be defined to add google fonts to the typography module
246
- 'async_typography' => true,
247
- // Use a asynchronous font on the front end or font string
248
- //'disable_google_fonts_link' => true, // Disable this in case you want to create your own google fonts loader
249
- 'admin_bar' => false,
250
- // Show the panel pages on the admin bar
251
- 'admin_bar_icon' => 'dashicons-portfolio',
252
- // Choose an icon for the admin bar menu
253
- 'admin_bar_priority' => 50,
254
- // Choose an priority for the admin bar menu
255
- 'global_variable' => '',
256
- // Set a different name for your global variable other than the opt_name
257
- 'dev_mode' => false,
258
- // Show the time the page took to load, etc
259
- 'update_notice' => true,
260
- // If dev_mode is enabled, will notify developer of updated versions available in the GitHub Repo
261
- 'customizer' => false,
262
- // Enable basic customizer support
263
- //'open_expanded' => true, // Allow you to start the panel in an expanded way initially.
264
- //'disable_save_warn' => true, // Disable the save warning when a user changes a field
265
-
266
- // OPTIONAL -> Give you extra features
267
- 'page_priority' => null,
268
- // Order where the menu appears in the admin area. If there is any conflict, something will not show. Warning.
269
- 'page_parent' => 'wpml_plugin_log',
270
- // For a full list of options, visit: http://codex.wordpress.org/Function_Reference/add_submenu_page#Parameters
271
- 'page_permissions' => 'manage_options',
272
- // Permissions needed to access the options panel.
273
- 'menu_icon' => '',
274
- // Specify a custom URL to an icon
275
- 'last_tab' => '',
276
- // Force your panel to always open to a specific tab (by id)
277
- 'page_icon' => 'icon-themes',
278
- // Icon displayed in the admin panel next to your menu_title
279
- 'page_slug' => 'wpml_plugin_settings',
280
- // Page slug used to denote the panel
281
- 'save_defaults' => true,
282
- // On load save the defaults to DB before user clicks save or not
283
- 'default_show' => false,
284
- // If true, shows the default value next to each field that is not the default value.
285
- 'default_mark' => '*',
286
- // What to print by the field's title if the value shown is default. Suggested: *
287
- 'show_import_export' => true,
288
- // Shows the Import/Export panel when not used as a field.
289
-
290
- // CAREFUL -> These options are for advanced use only
291
- 'transient_time' => 60 * MINUTE_IN_SECONDS,
292
- 'output' => true,
293
- // Global shut-off for dynamic CSS output by the framework. Will also disable google fonts output
294
- 'output_tag' => true,
295
- // Allows dynamic CSS to be generated for customizer and google fonts, but stops the dynamic CSS from going to the head
296
- // 'footer_credit' => '', // Disable the footer credit of Redux. Please leave if you can help it.
297
-
298
- // FUTURE -> Not in use yet, but reserved or partially implemented. Use at your own risk.
299
- 'database' => '',
300
- // possible: options, theme_mods, theme_mods_expanded, transient. Not fully functional, warning!
301
- 'system_info' => false,
302
- // REMOVE
303
-
304
- // HINTS
305
- 'hints' => array(
306
- 'icon' => 'el el-question-sign',
307
- 'icon_position' => 'right',
308
- 'icon_color' => 'lightgray',
309
- 'icon_size' => 'normal',
310
- 'tip_style' => array(
311
- 'color' => 'light',
312
- 'shadow' => true,
313
- 'rounded' => false,
314
- 'style' => 'bootstrap',
315
- ),
316
- 'tip_position' => array(
317
- 'my' => 'top left',
318
- 'at' => 'bottom right',
319
- ),
320
- 'tip_effect' => array(
321
- 'show' => array(
322
- 'effect' => 'slide',
323
- 'duration' => '500',
324
- 'event' => 'mouseover',
325
- ),
326
- 'hide' => array(
327
- 'effect' => 'slide',
328
- 'duration' => '500',
329
- 'event' => 'click mouseleave',
330
- ),
331
- ),
332
- )
333
- );
334
-
335
- // SOCIAL ICONS -> Setup custom links in the footer for quick links in your panel footer icons.
336
- $this->args['share_icons'][] = array(
337
- 'url' => 'https://github.com/No3x/wp-mail-logging',
338
- 'title' => 'Visit us on GitHub',
339
- 'icon' => 'el-icon-github'
340
- //'img' => '', // You can use icon OR img. IMG needs to be a full URL.
341
- );
342
- $this->args['share_icons'][] = array(
343
- 'url' => $this->plugin_meta['wp_uri'],
344
- 'title' => 'Visit us on WordPress',
345
- 'icon' => 'el-icon-wordpress'
346
- );
347
-
348
- // Add content before the form.
349
- // $this->args['intro_text'] = __( '<p>This text is displayed above the options panel. It isn\'t required, but more info is always better! The intro_text field accepts all HTML.</p>', 'redux-framework-demo' );
350
-
351
- // Add content after the form.
352
- // $this->args['footer_text'] = __( '<p>This text is displayed below the options panel. It isn\'t required, but more info is always better! The footer_text field accepts all HTML.</p>', 'redux-framework-demo' );
353
- }
354
- }
355
-
356
- global $reduxConfig;
357
- } else {
358
- echo "The class named Redux_Framework_sample_config has already been called. <strong>Developers, you need to prefix this class with your company name or you'll run into problems!</strong>";
359
- }
1
+ <?php
2
+
3
+ namespace No3x\WPML\Settings;
4
+
5
+ /**
6
+ * ReduxFramework Sample Config File
7
+ * For full documentation, please visit: http://docs.reduxframework.com/
8
+ */
9
+
10
+ if (!class_exists('WPML_Redux_Framework_config')) {
11
+
12
+ class WPML_Redux_Framework_config {
13
+
14
+ public $args = array();
15
+ public $sections = array();
16
+ public $theme;
17
+ public $ReduxFramework;
18
+ protected $plugin_meta = array();
19
+
20
+ public function __construct( $plugin_meta ) {
21
+ $this->plugin_meta = $plugin_meta;
22
+
23
+ if ( ! class_exists( 'ReduxFramework' ) ) {
24
+ return;
25
+ }
26
+
27
+ // This is needed. Bah WordPress bugs. ;)
28
+ if ( true == \Redux_Helpers::isTheme( __FILE__ ) ) {
29
+ $this->initSettings();
30
+ } else {
31
+ add_action( 'plugins_loaded', array( $this, 'initSettings' ), 10 );
32
+ }
33
+
34
+ }
35
+
36
+ public function initSettings() {
37
+
38
+ // Just for demo purposes. Not needed per say.
39
+ $this->theme = wp_get_theme();
40
+
41
+ // Set the default arguments
42
+ $this->setArguments();
43
+
44
+ // Set a few help tabs so you can see how it's done
45
+ // $this->setHelpTabs();
46
+
47
+ // Create the sections and fields
48
+ $this->setSections();
49
+
50
+ if ( ! isset( $this->args['opt_name'] ) ) { // No errors please
51
+ return;
52
+ }
53
+
54
+ // If Redux is running as a plugin, this will remove the demo notice and links
55
+ //add_action( 'redux/loaded', array( $this, 'remove_demo' ) );
56
+
57
+ // Function to test the compiler hook and demo CSS output.
58
+ // Above 10 is a priority, but 2 in necessary to include the dynamically generated CSS to be sent to the function.
59
+ //add_filter('redux/options/'.$this->args['opt_name'].'/compiler', array( $this, 'compiler_action' ), 10, 3);
60
+
61
+ // Change the arguments after they've been declared, but before the panel is created
62
+ //add_filter('redux/options/'.$this->args['opt_name'].'/args', array( $this, 'change_arguments' ) );
63
+
64
+ // Change the default value of a field after it's been set, but before it's been useds
65
+ //add_filter('redux/options/'.$this->args['opt_name'].'/defaults', array( $this,'change_defaults' ) );
66
+
67
+ // Dynamically add a section. Can be also used to modify sections/fields
68
+ //add_filter('redux/options/' . $this->args['opt_name'] . '/sections', array($this, 'dynamic_section'));
69
+
70
+ $this->ReduxFramework = new \ReduxFramework( $this->sections, $this->args );
71
+ }
72
+
73
+ // Remove the demo link and the notice of integrated demo from the redux-framework plugin
74
+ function remove_demo() {
75
+
76
+ // Used to hide the demo mode link from the plugin page. Only used when Redux is a plugin.
77
+ if ( class_exists( 'ReduxFrameworkPlugin' ) ) {
78
+ remove_filter( 'plugin_row_meta', array(
79
+ ReduxFrameworkPlugin::instance(),
80
+ 'plugin_metalinks'
81
+ ), null, 2 );
82
+
83
+ // Used to hide the activation notice informing users of the demo panel. Only used when Redux is a plugin.
84
+ remove_action( 'admin_notices', array( ReduxFrameworkPlugin::instance(), 'admin_notices' ) );
85
+ }
86
+ }
87
+
88
+ public function setSections() {
89
+
90
+ // ACTUAL DECLARATION OF SECTIONS
91
+ $this->sections[] = array(
92
+ 'title' => __('General Settings', 'wp-mail-logging'),
93
+ 'desc' => __('', 'wp-mail-logging'),
94
+ 'icon' => 'el-icon-cogs',
95
+ // 'submenu' => false, // Setting submenu to false on a given section will hide it from the WordPress sidebar menu!
96
+ 'fields' => array(
97
+
98
+ array(
99
+ 'id' => 'delete-on-deactivation',
100
+ 'type' => 'switch',
101
+ 'title' => __('Cleanup', 'wp-mail-logging' ),
102
+ 'subtitle' => __('Delete all data on deactivation? (emails and settings)?', 'wp-mail-logging'),
103
+ 'default' => 0,
104
+ 'on' => __(__('Enabled', 'wp-mail-logging' ), 'wp-mail-logging' ),
105
+ 'off' => __(__('Disabled', 'wp-mail-logging' ), 'wp-mail-logging' ),
106
+ ),
107
+ array(
108
+ 'id' => 'can-see-submission-data',
109
+ 'type' => 'select',
110
+ 'data' => 'capabilities',
111
+ 'default' => 'manage_options',
112
+ 'title' => __('Can See Submission data', 'wp-mail-logging'),
113
+ 'subtitle' => __('Select the minimum role.', 'wp-mail-logging'),
114
+ ),
115
+ array(
116
+ 'id' => 'datetimeformat-use-wordpress',
117
+ 'type' => 'switch',
118
+ 'title' => __('WordPress Date Time Format', 'wp-mail-logging' ),
119
+ 'subtitle' => sprintf( __( "Use format from WordPress settings (%s)", 'wp-mail-logging' ), date_i18n( $this->wordpress_default_format(), current_time( 'timestamp' ) ) ),
120
+ 'default' => 0,
121
+ 'on' => __('Enabled', 'wp-mail-logging' ),
122
+ 'off' => __('Disabled', 'wp-mail-logging' ),
123
+ ),
124
+ array(
125
+ 'id' => 'preferred-mail-format',
126
+ 'type' => 'select',
127
+ 'options' => array(
128
+ 'html' => 'html',
129
+ 'raw' => 'raw',
130
+ 'json' => 'json'
131
+ ),
132
+ 'default' => 'html',
133
+ 'title' => __('Default Format for Message', 'wp-mail-logging'),
134
+ 'subtitle' => __('Select your preferred display format.', 'wp-mail-logging'),
135
+ ),
136
+ array(
137
+ 'id' => 'display-host',
138
+ 'type' => 'switch',
139
+ 'title' => __('Display Host', 'wp-mail-logging' ),
140
+ 'subtitle' => __('Display host column in list.', 'wp-mail-logging'),
141
+ 'hint' => array(
142
+ 'title' => 'Host',
143
+ 'content' => 'Display the IP of the host WordPress is running on. This is useful when running it on multiple servers at the same time.',
144
+ ),
145
+ 'default' => 0,
146
+ 'on' => __('Enabled', 'wp-mail-logging' ),
147
+ 'off' => __('Disabled', 'wp-mail-logging' ),
148
+ ),
149
+ array(
150
+ 'id' => 'section-log-rotation-start',
151
+ 'type' => 'section',
152
+ 'title' => __('Log Rotation', 'wp-mail-logging' ),
153
+ 'subtitle' => __('Save space by deleting logs regularly.', 'wp-mail-logging'),
154
+ 'indent' => true, // Indent all options below until the next 'section' option is set.
155
+ ),
156
+ array(
157
+ 'id' => 'log-rotation-limit-amout',
158
+ 'type' => 'switch',
159
+ 'title' => __('Cleanup by Amount', 'wp-mail-logging' ),
160
+ 'subtitle' => __('Setup a automated cleanup routine!', 'wp-mail-logging'),
161
+ 'default' => 0,
162
+ 'on' => __('Enabled', 'wp-mail-logging' ),
163
+ 'off' => __('Disabled', 'wp-mail-logging' ),
164
+ ),
165
+ array(
166
+ 'id' => 'log-rotation-limit-amout-keep',
167
+ 'type' => 'slider',
168
+ 'required' => array('log-rotation-limit-amout', '=', '1'),
169
+ 'title' => __('Amount', 'wp-mail-logging' ),
170
+ 'subtitle' => __('When should mails are deleted?', 'wp-mail-logging'),
171
+ 'desc' => __('Cleanup when the stored mails exceed...', 'wp-mail-logging'),
172
+ 'default' => 75,
173
+ 'min' => 25,
174
+ 'step' => 50,
175
+ 'max' => 3000,
176
+ 'display_value' => 'text'
177
+ ),
178
+ array(
179
+ 'id' => 'log-rotation-delete-time',
180
+ 'type' => 'switch',
181
+ 'title' => __('Cleanup by Time', 'wp-mail-logging' ),
182
+ 'subtitle' => __('Setup a automated cleanup routine!', 'wp-mail-logging'),
183
+ 'default' => 0,
184
+ 'on' => __('Enabled', 'wp-mail-logging' ),
185
+ 'off' => __('Disabled', 'wp-mail-logging' ),
186
+ ),
187
+ array(
188
+ 'id' => 'log-rotation-delete-time-days',
189
+ 'type' => 'slider',
190
+ 'required' => array('log-rotation-delete-time', '=', '1'),
191
+ 'title' => __('Time', 'wp-mail-logging' ),
192
+ 'subtitle' => __('When should mails are deleted?', 'wp-mail-logging'),
193
+ 'desc' => __('Delete mails older than days...', 'wp-mail-logging'),
194
+ 'default' => 30,
195
+ 'min' => 1,
196
+ 'step' => 7,
197
+ 'max' => 400,
198
+ 'display_value' => 'text'
199
+ ),
200
+ array(
201
+ 'id' => 'section-log-rotation-end',
202
+ 'type' => 'section',
203
+ 'indent' => false // Indent all options below until the next 'section' option is set.
204
+ ),
205
+ ),
206
+ );
207
+ }
208
+
209
+ public function wordpress_default_format()
210
+ {
211
+ $date_format = get_option( 'date_format' );
212
+ $time_format = get_option( 'time_format' );
213
+ $date_format = empty( $date_format ) ? 'F j, Y' : $date_format;
214
+ $time_format = empty( $time_format ) ? 'g:i a' : $time_format;
215
+ return "{$date_format} {$time_format}";
216
+ }
217
+
218
+ /**
219
+ * All the possible arguments for Redux.
220
+ * For full documentation on arguments, please refer to: https://github.com/ReduxFramework/ReduxFramework/wiki/Arguments
221
+ * */
222
+ public function setArguments() {
223
+
224
+ $theme = wp_get_theme(); // For use with some settings. Not necessary.
225
+
226
+ $this->args = array(
227
+ // TYPICAL -> Change these values as you need/desire
228
+ 'opt_name' => 'wpml_settings',
229
+ // This is where your data is stored in the database and also becomes your global variable name.
230
+ 'display_name' => 'WP Mail Logging Settings',
231
+ // Name that appears at the top of your panel
232
+ 'display_version' => $this->plugin_meta['version_installed'],
233
+ // Version that appears at the top of your panel
234
+ 'menu_type' => 'submenu',
235
+ //Specify if the admin menu should appear or not. Options: menu or submenu (Under appearance only)
236
+ 'allow_sub_menu' => true,
237
+ // Show the sections below the admin menu item or not
238
+ 'menu_title' => 'Settings',
239
+ 'page_title' => $this->plugin_meta['display_name'],
240
+ // You will need to generate a Google API key to use this feature.
241
+ // Please visit: https://developers.google.com/fonts/docs/developer_api#Auth
242
+ 'google_api_key' => '',
243
+ // Set it you want google fonts to update weekly. A google_api_key value is required.
244
+ 'google_update_weekly' => false,
245
+ // Must be defined to add google fonts to the typography module
246
+ 'async_typography' => true,
247
+ // Use a asynchronous font on the front end or font string
248
+ //'disable_google_fonts_link' => true, // Disable this in case you want to create your own google fonts loader
249
+ 'admin_bar' => false,
250
+ // Show the panel pages on the admin bar
251
+ 'admin_bar_icon' => 'dashicons-portfolio',
252
+ // Choose an icon for the admin bar menu
253
+ 'admin_bar_priority' => 50,
254
+ // Choose an priority for the admin bar menu
255
+ 'global_variable' => '',
256
+ // Set a different name for your global variable other than the opt_name
257
+ 'dev_mode' => false,
258
+ // Show the time the page took to load, etc
259
+ 'update_notice' => true,
260
+ // If dev_mode is enabled, will notify developer of updated versions available in the GitHub Repo
261
+ 'customizer' => false,
262
+ // Enable basic customizer support
263
+ //'open_expanded' => true, // Allow you to start the panel in an expanded way initially.
264
+ //'disable_save_warn' => true, // Disable the save warning when a user changes a field
265
+
266
+ // OPTIONAL -> Give you extra features
267
+ 'page_priority' => null,
268
+ // Order where the menu appears in the admin area. If there is any conflict, something will not show. Warning.
269
+ 'page_parent' => 'wpml_plugin_log',
270
+ // For a full list of options, visit: http://codex.wordpress.org/Function_Reference/add_submenu_page#Parameters
271
+ 'page_permissions' => 'manage_options',
272
+ // Permissions needed to access the options panel.
273
+ 'menu_icon' => '',
274
+ // Specify a custom URL to an icon
275
+ 'last_tab' => '',
276
+ // Force your panel to always open to a specific tab (by id)
277
+ 'page_icon' => 'icon-themes',
278
+ // Icon displayed in the admin panel next to your menu_title
279
+ 'page_slug' => 'wpml_plugin_settings',
280
+ // Page slug used to denote the panel
281
+ 'save_defaults' => true,
282
+ // On load save the defaults to DB before user clicks save or not
283
+ 'default_show' => false,
284
+ // If true, shows the default value next to each field that is not the default value.
285
+ 'default_mark' => '*',
286
+ // What to print by the field's title if the value shown is default. Suggested: *
287
+ 'show_import_export' => true,
288
+ // Shows the Import/Export panel when not used as a field.
289
+
290
+ // CAREFUL -> These options are for advanced use only
291
+ 'transient_time' => 60 * MINUTE_IN_SECONDS,
292
+ 'output' => true,
293
+ // Global shut-off for dynamic CSS output by the framework. Will also disable google fonts output
294
+ 'output_tag' => true,
295
+ // Allows dynamic CSS to be generated for customizer and google fonts, but stops the dynamic CSS from going to the head
296
+ // 'footer_credit' => '', // Disable the footer credit of Redux. Please leave if you can help it.
297
+
298
+ // FUTURE -> Not in use yet, but reserved or partially implemented. Use at your own risk.
299
+ 'database' => '',
300
+ // possible: options, theme_mods, theme_mods_expanded, transient. Not fully functional, warning!
301
+ 'system_info' => false,
302
+ // REMOVE
303
+
304
+ // HINTS
305
+ 'hints' => array(
306
+ 'icon' => 'el el-question-sign',
307
+ 'icon_position' => 'right',
308
+ 'icon_color' => 'lightgray',
309
+ 'icon_size' => 'normal',
310
+ 'tip_style' => array(
311
+ 'color' => 'light',
312
+ 'shadow' => true,
313
+ 'rounded' => false,
314
+ 'style' => 'bootstrap',
315
+ ),
316
+ 'tip_position' => array(
317
+ 'my' => 'top left',
318
+ 'at' => 'bottom right',
319
+ ),
320
+ 'tip_effect' => array(
321
+ 'show' => array(
322
+ 'effect' => 'slide',
323
+ 'duration' => '500',
324
+ 'event' => 'mouseover',
325
+ ),
326
+ 'hide' => array(
327
+ 'effect' => 'slide',
328
+ 'duration' => '500',
329
+ 'event' => 'click mouseleave',
330
+ ),
331
+ ),
332
+ )
333
+ );
334
+
335
+ // SOCIAL ICONS -> Setup custom links in the footer for quick links in your panel footer icons.
336
+ $this->args['share_icons'][] = array(
337
+ 'url' => 'https://github.com/No3x/wp-mail-logging',
338
+ 'title' => 'Visit us on GitHub',
339
+ 'icon' => 'el-icon-github'
340
+ //'img' => '', // You can use icon OR img. IMG needs to be a full URL.
341
+ );
342
+ $this->args['share_icons'][] = array(
343
+ 'url' => $this->plugin_meta['wp_uri'],
344
+ 'title' => 'Visit us on WordPress',
345
+ 'icon' => 'el-icon-wordpress'
346
+ );
347
+
348
+ // Add content before the form.
349
+ // $this->args['intro_text'] = __( '<p>This text is displayed above the options panel. It isn\'t required, but more info is always better! The intro_text field accepts all HTML.</p>', 'redux-framework-demo' );
350
+
351
+ // Add content after the form.
352
+ // $this->args['footer_text'] = __( '<p>This text is displayed below the options panel. It isn\'t required, but more info is always better! The footer_text field accepts all HTML.</p>', 'redux-framework-demo' );
353
+ }
354
+ }
355
+
356
+ global $reduxConfig;
357
+ } else {
358
+ echo "The class named Redux_Framework_sample_config has already been called. <strong>Developers, you need to prefix this class with your company name or you'll run into problems!</strong>";
359
+ }
{inc → src/inc}/redux/admin-init.php RENAMED
@@ -1,8 +1,8 @@
1
  <?php
2
 
3
  // Load the embedded Redux Framework
4
- if ( file_exists( dirname( __FILE__ ).'/../../lib/vendor/redux-framework/framework.php' ) ) {
5
- require_once dirname(__FILE__).'/../../lib/vendor/redux-framework/framework.php';
6
  }
7
  // Load the theme/plugin options
8
  if ( file_exists( dirname( __FILE__ ) . '/options-init.php' ) ) {
1
  <?php
2
 
3
  // Load the embedded Redux Framework
4
+ if ( file_exists( dirname( __FILE__ ).'/../../../lib/vendor/redux-framework/framework.php' ) ) {
5
+ require_once dirname(__FILE__) . '/../../../lib/vendor/redux-framework/framework.php';
6
  }
7
  // Load the theme/plugin options
8
  if ( file_exists( dirname( __FILE__ ) . '/options-init.php' ) ) {
wp-mail-logging.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: WP Mail Logging
4
  Plugin URI: http://wordpress.org/extend/plugins/wp-mail-logging/
5
  Support URI: https://github.com/No3x/wp-mail-logging/issues
6
- Version: 1.8.4
7
  Author: Christian Z&ouml;ller
8
  Author URI: http://no3x.de/
9
  Description: Logs each email sent by WordPress.
@@ -95,10 +95,9 @@ if (WPML_PhpVersionCheck()) {
95
  $loader->register();
96
 
97
  // Add our namespace and the folder it maps to
98
- require_once __DIR__ . '/inc/redux/admin-init.php';
99
- $loader->addNamespace('No3x\\WPML\\', __DIR__ );
100
- $loader->addNamespace('No3x\\WPML\\Model\\', __DIR__ . '/model' );
101
- $loader->addNamespace('No3x\\WPML\\Settings\\', __DIR__ . '/inc/redux');
102
  $loader->addNamespace('No3x\\WPML\\ORM\\', __DIR__ . '/lib/vendor/brandonwamboldt/wp-orm/src');
103
  $loader->addNamespace('No3x\\WPML\\Pimple\\', __DIR__ . '/lib/vendor/pimple/pimple/src');
104
  if( file_exists( __DIR__ . '/vendor/autoload.php' ) ) {
3
  Plugin Name: WP Mail Logging
4
  Plugin URI: http://wordpress.org/extend/plugins/wp-mail-logging/
5
  Support URI: https://github.com/No3x/wp-mail-logging/issues
6
+ Version: 1.8.5
7
  Author: Christian Z&ouml;ller
8
  Author URI: http://no3x.de/
9
  Description: Logs each email sent by WordPress.
95
  $loader->register();
96
 
97
  // Add our namespace and the folder it maps to
98
+ require_once __DIR__ . '/src/inc/redux/admin-init.php';
99
+ $loader->addNamespace('No3x\\WPML\\', __DIR__ . '/src' );
100
+ $loader->addNamespace('No3x\\WPML\\Settings\\', __DIR__ . '/src/inc/redux');
 
101
  $loader->addNamespace('No3x\\WPML\\ORM\\', __DIR__ . '/lib/vendor/brandonwamboldt/wp-orm/src');
102
  $loader->addNamespace('No3x\\WPML\\Pimple\\', __DIR__ . '/lib/vendor/pimple/pimple/src');
103
  if( file_exists( __DIR__ . '/vendor/autoload.php' ) ) {