Menu Icons by ThemeIsle - Version 0.11.5

Version Description

  • 2019-05-23
Download this release

Release Info

Developer codeinwp
Plugin Icon 128x128 Menu Icons by ThemeIsle
Version 0.11.5
Comparing to
See all releases

Code changes from version 0.11.4 to 0.11.5

Files changed (65) hide show
  1. CHANGELOG.md +4 -0
  2. mailin.php +459 -459
  3. menu-icons.php +3 -3
  4. readme.md +5 -0
  5. readme.txt +5 -0
  6. vendor/autoload.php +1 -1
  7. vendor/codeinwp/icon-picker/assets/screenshot-1.png +0 -0
  8. vendor/codeinwp/icon-picker/assets/screenshot-2.png +0 -0
  9. vendor/codeinwp/icon-picker/js/src/icon-picker.js +101 -0
  10. vendor/codeinwp/icon-picker/js/src/media/controllers/font.js +69 -0
  11. vendor/codeinwp/icon-picker/js/src/media/controllers/img.js +148 -0
  12. vendor/codeinwp/icon-picker/js/src/media/controllers/mixin.js +35 -0
  13. vendor/codeinwp/icon-picker/js/src/media/manifest.js +16 -0
  14. vendor/codeinwp/icon-picker/js/src/media/models/fonts.js +77 -0
  15. vendor/codeinwp/icon-picker/js/src/media/models/target.js +18 -0
  16. vendor/codeinwp/icon-picker/js/src/media/views/browser.js +15 -0
  17. vendor/codeinwp/icon-picker/js/src/media/views/font-browser.js +65 -0
  18. vendor/codeinwp/icon-picker/js/src/media/views/font-filter.js +33 -0
  19. vendor/codeinwp/icon-picker/js/src/media/views/font-item.js +30 -0
  20. vendor/codeinwp/icon-picker/js/src/media/views/font-library.js +100 -0
  21. vendor/codeinwp/icon-picker/js/src/media/views/frame.js +118 -0
  22. vendor/codeinwp/icon-picker/js/src/media/views/img-browser.js +6 -0
  23. vendor/codeinwp/icon-picker/js/src/media/views/sidebar.js +29 -0
  24. vendor/codeinwp/icon-picker/js/src/media/views/svg-item.js +8 -0
  25. vendor/codeinwp/icon-picker/phpcs.ruleset.xml +17 -0
  26. vendor/codeinwp/icon-picker/readme.md +85 -0
  27. vendor/codeinwp/menu-item-custom-fields/phpcs.ruleset.xml +18 -0
  28. vendor/codeinwp/menu-item-custom-fields/readme.md +66 -0
  29. vendor/codeinwp/themeisle-sdk/CHANGELOG.md +50 -0
  30. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-endpoints.php +0 -312
  31. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-feedback-deactivate.php +0 -556
  32. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-feedback-factory.php +0 -50
  33. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-feedback-review.php +0 -209
  34. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-feedback-translate.php +0 -983
  35. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-feedback.php +0 -90
  36. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-licenser.php +0 -686
  37. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-loader.php +0 -96
  38. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-logger.php +0 -227
  39. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-notification-manager.php +0 -105
  40. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-product.php +0 -635
  41. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-rollback.php +0 -223
  42. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-widget-dashboard-blog.php +0 -412
  43. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-widget.php +0 -50
  44. vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-widgets-factory.php +0 -37
  45. vendor/codeinwp/themeisle-sdk/composer.json +0 -24
  46. vendor/codeinwp/themeisle-sdk/index.php +2 -4
  47. vendor/codeinwp/themeisle-sdk/load.php +17 -3
  48. vendor/codeinwp/themeisle-sdk/src/Common/Abstract_module.php +66 -0
  49. vendor/codeinwp/themeisle-sdk/src/Common/Module_factory.php +108 -0
  50. vendor/codeinwp/themeisle-sdk/src/Loader.php +126 -0
  51. vendor/codeinwp/themeisle-sdk/src/Modules/Dashboard_widget.php +464 -0
  52. vendor/codeinwp/themeisle-sdk/src/Modules/Endpoint.php +358 -0
  53. vendor/codeinwp/themeisle-sdk/src/Modules/Licenser.php +719 -0
  54. vendor/codeinwp/themeisle-sdk/src/Modules/Logger.php +177 -0
  55. vendor/codeinwp/themeisle-sdk/src/Modules/Notification.php +456 -0
  56. vendor/codeinwp/themeisle-sdk/src/Modules/Recommendation.php +374 -0
  57. vendor/codeinwp/themeisle-sdk/src/Modules/Review.php +117 -0
  58. vendor/codeinwp/themeisle-sdk/src/Modules/Rollback.php +376 -0
  59. vendor/codeinwp/themeisle-sdk/src/Modules/Translate.php +918 -0
  60. vendor/codeinwp/themeisle-sdk/src/Modules/Uninstall_feedback.php +734 -0
  61. vendor/codeinwp/themeisle-sdk/src/Product.php +396 -0
  62. vendor/codeinwp/themeisle-sdk/start.php +32 -21
  63. vendor/composer/autoload_files.php +0 -1
  64. vendor/composer/autoload_real.php +5 -5
  65. vendor/composer/installed.json +42 -42
CHANGELOG.md CHANGED
@@ -1,4 +1,8 @@
1
 
 
 
 
 
2
  ### v0.11.4 - 2018-12-10
3
  **Changes:**
4
  * fix issue with composer libraries.
1
 
2
+ ### v0.11.5 - 2019-05-23
3
+ **Changes:**
4
+ * Sync composer dependencies with the latest version
5
+
6
  ### v0.11.4 - 2018-12-10
7
  **Changes:**
8
  * fix issue with composer libraries.
mailin.php CHANGED
@@ -55,155 +55,155 @@ class Mailin {
55
  }
56
 
57
  /*
58
- Get Account.
59
- No input required
60
- */
61
  public function get_account() {
62
  return $this->get( 'account', '' );
63
  }
64
 
65
  /*
66
- Get SMTP details.
67
- No input required
68
- */
69
  public function get_smtp_details() {
70
  return $this->get( 'account/smtpdetail', '' );
71
  }
72
 
73
  /*
74
- Create Child Account.
75
- @param {Array} data contains php array with key value pair.
76
- @options data {String} child_email: Email address of Reseller child [Mandatory]
77
- @options data {String} password: Password of Reseller child to login [Mandatory]
78
- @options data {String} company_org: Name of Reseller child’s company [Mandatory]
79
- @options data {String} first_name: First name of Reseller child [Mandatory]
80
- @options data {String} last_name: Last name of Reseller child [Mandatory]
81
- @options data {Array} credits: Number of email & sms credits respectively, which will be assigned to the Reseller child’s account [Optional]
82
- - email_credit {Integer} number of email credits
83
- - sms_credit {Integer} Number of sms credts
84
- @options data {Array} associate_ip: Associate dedicated IPs to reseller child. You can use commas to separate multiple IPs [Optional]
85
- */
86
  public function create_child_account( $data ) {
87
  return $this->post( 'account', json_encode( $data ) );
88
  }
89
 
90
  /*
91
- Update Child Account.
92
- @param {Array} data contains php array with key value pair.
93
- @options data {String} auth_key: 16 character authorization key of Reseller child to be modified [Mandatory]
94
- @options data {String} company_org: Name of Reseller child’s company [Optional]
95
- @options data {String} first_name: First name of Reseller child [Optional]
96
- @options data {String} last_name: Last name of Reseller child [Optional]
97
- @options data {String} password: Password of Reseller child to login [Optional]
98
- @options data {Array} associate_ip: Associate dedicated IPs to reseller child. You can use commas to separate multiple IPs [Optional]
99
- @options data {Array} disassociate_ip: Disassociate dedicated IPs from reseller child. You can use commas to separate multiple IPs [Optional]
100
- */
101
  public function update_child_account( $data ) {
102
  return $this->put( 'account', json_encode( $data ) );
103
  }
104
 
105
  /*
106
- Delete Child Account.
107
- @param {Array} data contains php array with key value pair.
108
- @options data {String} auth_key: 16 character authorization key of Reseller child to be deleted [Mandatory]
109
- */
110
  public function delete_child_account( $data ) {
111
  return $this->delete( 'account/' . $data['auth_key'], '' );
112
  }
113
 
114
  /*
115
- Get Reseller child Account.
116
- @param {Array} data contains php array with key value pair.
117
- @options data {String} auth_key: 16 character authorization key of Reseller child. Example : To get the details of more than one child account, use, {"key1":"abC01De2fGHI3jkL","key2":"mnO45Pq6rSTU7vWX"} [Mandatory]
118
- */
119
  public function get_reseller_child( $data ) {
120
  return $this->post( 'account/getchildv2', json_encode( $data ) );
121
  }
122
 
123
  /*
124
- Add/Remove Reseller child's Email/Sms credits.
125
- @param {Array} data contains php array with key value pair.
126
- @options data {String} auth_key: 16 character authorization key of Reseller child to modify credits [Mandatory]
127
- @options data {Array} add_credit: Number of email & sms credits to be added. You can assign either email or sms credits, one at a time other will remain 0. [Mandatory: if rmv_credit is empty]
128
- - email_credit {Integer} number of email credits
129
- - sms_credit {Integer} Number of sms credts
130
- @options data {Array} rmv_credit: Number of email & sms credits to be removed. You can assign either email or sms credits, one at a time other will remain 0. [Mandatory: if add_credits is empty]
131
- - email_credit {Integer} number of email credits
132
- - sms_credit {Integer} Number of sms credts
133
- */
134
  public function add_remove_child_credits( $data ) {
135
  return $this->post( 'account/addrmvcredit', json_encode( $data ) );
136
  }
137
 
138
  /*
139
- Get a particular campaign detail.
140
- @param {Array} data contains php array with key value pair.
141
- @options data {Integer} id: Unique Id of the campaign [Mandatory]
142
- */
143
  public function get_campaign_v2( $data ) {
144
  return $this->get( 'campaign/' . $data['id'] . '/detailsv2', '' );
145
  }
146
 
147
  /*
148
- Get all campaigns detail.
149
- @param {Array} data contains php array with key value pair.
150
- @options data {String} type: Type of campaign. Possible values – classic, trigger, sms, template ( case sensitive ) [Optional]
151
- @options data {String} status: Status of campaign. Possible values – draft, sent, archive, queued, suspended, in_process, temp_active, temp_inactive ( case sensitive ) [Optional]
152
- @options data {Integer} page: Maximum number of records per request is 500, if there are more than 500 campaigns then you can use this parameter to get next 500 results [Optional]
153
- @options data {Integer} page_limit: This should be a valid number between 1-500 [Optional]
154
- */
155
  public function get_campaigns_v2( $data ) {
156
  return $this->get( 'campaign/detailsv2', json_encode( $data ) );
157
  }
158
 
159
  /*
160
- Create and Schedule your campaigns. It returns the ID of the created campaign.
161
- @param {Array} data contains php array with key value pair.
162
- @options data {String} category: Tag name of the campaign [Optional]
163
- @options data {String} from_name: Sender name from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
164
- @options data {String} name: Name of the campaign [Mandatory]
165
- @options data {String} bat: Email address for test mail [Optional]
166
- @options data {String} html_content: Body of the content. The HTML content field must have more than 10 characters [Mandatory: if html_url is empty]
167
- @options data {String} html_url: Url which content is the body of content [Mandatory: if html_content is empty]
168
- @options data {Array} listid: These are the lists to which the campaign has been sent [Mandatory: if scheduled_date is not empty]
169
- @options data {String} scheduled_date: The day on which the campaign is supposed to run[Optional]
170
- @options data {String} subject: Subject of the campaign [Mandatory]
171
- @options data {String} from_email: Sender email from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
172
- @options data {String} reply_to: The reply to email in the campaign emails [Optional]
173
- @options data {String} to_field: This is to personalize the «To» Field. If you want to include the first name and last name of your recipient, add [PRENOM] [NOM] To use the contact attributes here, these should already exist in SendinBlue account [Optional]
174
- @options data {Array} exclude_list: These are the lists which must be excluded from the campaign [Optional]
175
- @options data {String} attachment_url: Provide the absolute url of the attachment [Optional]
176
- @options data {Integer} inline_image: Status of inline image. Possible values = 0 (default) & 1. inline_image = 0 means image can’t be embedded, & inline_image = 1 means image can be embedded, in the email [Optional]
177
- @options data {Integer} mirror_active: Status of mirror links in campaign. Possible values = 0 & 1 (default). mirror_active = 0 means mirror links are deactivated, & mirror_active = 1 means mirror links are activated, in the campaign [Optional]
178
- @options data {Integer} send_now: Flag to send campaign now. Possible values = 0 (default) & 1. send_now = 0 means campaign can’t be send now, & send_now = 1 means campaign ready to send now [Optional]
179
-
180
- */
181
  public function create_campaign( $data ) {
182
  return $this->post( 'campaign', json_encode( $data ) );
183
  }
184
 
185
  /*
186
- Update your campaign.
187
- @param {Array} data contains php array with key value pair.
188
- @options data {Integer} id: Id of campaign to be modified [Mandatory]
189
- @options data {String} category: Tag name of the campaign [Optional]
190
- @options data {String} from_name: Sender name from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
191
- @options data {String} name: Name of the campaign [Optional]
192
- @options data {String} bat: Email address for test mail [Optional]
193
- @options data {String} html_content: Body of the content. The HTML content field must have more than 10 characters [Optional]
194
- @options data {String} html_url: Url which content is the body of content [Optional]
195
- @options data {Array} listid These are the lists to which the campaign has been sent [Mandatory: if scheduled_date is not empty]
196
- @options data {String} scheduled_date: The day on which the campaign is supposed to run[Optional]
197
- @options data {String} subject: Subject of the campaign.
198
- @options data {String} from_email: Sender email from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
199
- @options data {String} reply_to: The reply to email in the campaign emails [Optional]
200
- @options data {String} to_field: This is to personalize the «To» Field. If you want to include the first name and last name of your recipient, add [PRENOM] [NOM]. To use the contact attributes here, these should already exist in SendinBlue account [Optional]
201
- @options data {Array} exclude_list: These are the lists which must be excluded from the campaign [Optional]
202
- @options data {String} attachment_url: Provide the absolute url of the attachment [Optional]
203
- @options data {Integer} inline_image: Status of inline image. Possible values = 0 (default) & 1. inline_image = 0 means image can’t be embedded, & inline_image = 1 means image can be embedded, in the email [Optional]
204
- @options data {Integer} mirror_active: Status of mirror links in campaign. Possible values = 0 & 1 (default). mirror_active = 0 means mirror links are deactivated, & mirror_active = 1 means mirror links are activated, in the campaign [Optional]
205
- @options data {Integer} send_now: Flag to send campaign now. Possible values = 0 (default) & 1. send_now = 0 means campaign can’t be send now, & send_now = 1 means campaign ready to send now [Optional]
206
- */
207
  public function update_campaign( $data ) {
208
  $id = $data['id'];
209
  unset( $data['id'] );
@@ -211,26 +211,26 @@ class Mailin {
211
  }
212
 
213
  /*
214
- Delete your campaigns.
215
- @param {Array} data contains php array with key value pair.
216
- @options data {Integer} id: Id of campaign to be deleted [Mandatory]
217
- */
218
  public function delete_campaign( $data ) {
219
  return $this->delete( 'campaign/' . $data['id'], '' );
220
  }
221
 
222
  /*
223
- Send report of Sent and Archived campaign.
224
- @param {Array} data contains php array with key value pair.
225
- @options data {Integer} id: Id of campaign to send its report [Mandatory]
226
- @options data {String} lang: Language of email content. Possible values – fr (default), en, es, it & pt [Optional]
227
- @options data {String} email_subject: Message subject [Mandatory]
228
- @options data {Array} email_to: Email address of the recipient(s). Example: "test@example.net". You can use commas to separate multiple recipients [Mandatory]
229
- @options data {String} email_content_type: Body of the message in text/HTML version. Possible values – text & html [Mandatory]
230
- @options data {Array} email_bcc: Same as email_to but for Bcc [Optional]
231
- @options data {Array} email_cc: Same as email_to but for Cc [Optional]
232
- @options data {String} email_body: Body of the message [Mandatory]
233
- */
234
  public function campaign_report_email( $data ) {
235
  $id = $data['id'];
236
  unset( $data['id'] );
@@ -238,12 +238,12 @@ class Mailin {
238
  }
239
 
240
  /*
241
- Export the recipients of a specified campaign.
242
- @param {Array} data contains php array with key value pair.
243
- @options data {Integer} id: Id of campaign to export its recipients [Mandatory]
244
- @options data {String} notify_url: URL that will be called once the export process is finished [Mandatory]
245
- @options data {String} type: Type of recipients. Possible values – all, non_clicker, non_opener, clicker, opener, soft_bounces, hard_bounces & unsubscribes [Mandatory]
246
- */
247
  public function campaign_recipients_export( $data ) {
248
  $id = $data['id'];
249
  unset( $data['id'] );
@@ -251,21 +251,21 @@ class Mailin {
251
  }
252
 
253
  /*
254
- Get the Campaign name, subject and share link of the classic type campaigns only which are sent, for those which are not sent and the rest of campaign types like trigger, template & sms, will return an error message of share link not available.
255
- @param {Array} data contains php array with key value pair.
256
- @options data {Array} camp_ids: Id of campaign to get share link. You can use commas to separate multiple ids [Mandatory]
257
- */
258
 
259
  public function share_campaign( $data ) {
260
  return $this->post( 'campaign/sharelinkv2', json_encode( $data ) );
261
  }
262
 
263
  /*
264
- Send a Test Campaign.
265
- @param {Array} data contains php array with key value pair.
266
- @options data {Integer} id: Id of the campaign [Mandatory]
267
- @options data {Array} emails: Email address of recipient(s) existing in the one of the lists & should not be blacklisted. Example: "test@example.net". You can use commas to separate multiple recipients [Mandatory]
268
- */
269
  public function send_bat_email( $data ) {
270
  $id = $data['id'];
271
  unset( $data['id'] );
@@ -273,11 +273,11 @@ class Mailin {
273
  }
274
 
275
  /*
276
- Update the Campaign status.
277
- @param {Array} data contains php array with key value pair.
278
- @options data {Integer} id: Id of campaign to update its status [Mandatory]
279
- @options data {String} status: Types of status. Possible values – suspended, archive, darchive, sent, queued, replicate and replicate_template ( case sensitive ) [Mandatory]
280
- */
281
  public function update_campaign_status( $data ) {
282
  $id = $data['id'];
283
  unset( $data['id'] );
@@ -285,54 +285,54 @@ class Mailin {
285
  }
286
 
287
  /*
288
- Create and schedule your Trigger campaigns.
289
- @param {Array} data contains php array with key value pair.
290
- @options data {String} category: Tag name of the campaign [Optional]
291
- @options data {String} from_name: Sender name from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
292
- @options data {String} trigger_name: Name of the campaign [Mandatory]
293
- @options data {String} bat: Email address for test mail [Optional]
294
- @options data {String} html_content: Body of the content. The HTML content field must have more than 10 characters [Mandatory: if html_url is empty]
295
- @options data {String} html_url: Url which content is the body of content [Mandatory: if html_content is empty]
296
- @options data {Array} listid: These are the lists to which the campaign has been sent [Mandatory: if scheduled_date is not empty]
297
- @options data {String} scheduled_date: The day on which the campaign is supposed to run[Optional]
298
- @options data {String} subject: Subject of the campaign [Mandatory]
299
- @options data {String} from_email: Sender email from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
300
- @options data {String} reply_to: The reply to email in the campaign emails [Optional]
301
- @options data {String} to_field: This is to personalize the «To» Field. If you want to include the first name and last name of your recipient, add [PRENOM] [NOM]. To use the contact attributes here, these should already exist in SendinBlue account [Optional]
302
- @options data {Array} exclude_list: These are the lists which must be excluded from the campaign [Optional]
303
- @options data {Integer} recurring: Type of trigger campaign. Possible values = 0 (default) & 1. recurring = 0 means contact can receive the same Trigger campaign only once, & recurring = 1 means contact can receive the same Trigger campaign several times [Optional]
304
- @options data {String} attachment_url: Provide the absolute url of the attachment [Optional]
305
- @options data {Integer} inline_image: Status of inline image. Possible values = 0 (default) & 1. inline_image = 0 means image can’t be embedded, & inline_image = 1 means image can be embedded, in the email [Optional]
306
- @options data {Integer} mirror_active: Status of mirror links in campaign. Possible values = 0 & 1 (default). mirror_active = 0 means mirror links are deactivated, & mirror_active = 1 means mirror links are activated, in the campaign [Optional]
307
- @options data {Integer} send_now: Flag to send campaign now. Possible values = 0 (default) & 1. send_now = 0 means campaign can’t be send now, & send_now = 1 means campaign ready to send now [Optional]
308
- */
309
  public function create_trigger_campaign( $data ) {
310
  return $this->post( 'campaign', json_encode( $data ) );
311
  }
312
 
313
  /*
314
- Update and schedule your Trigger campaigns.
315
- @param {Array} data contains php array with key value pair.
316
- @options data {Integer} id: Id of Trigger campaign to be modified [Mandatory]
317
- @options data {String} category: Tag name of the campaign [Optional]
318
- @options data {String} from_name: Sender name from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
319
- @options data {String} trigger_name: Name of the campaign [Mandatory]
320
- @options data {String} bat Email address for test mail [Optional]
321
- @options data {String} html_content: Body of the content. The HTML content field must have more than 10 characters [Mandatory: if html_url is empty]
322
- @options data {String} html_url: Url which content is the body of content [Mandatory: if html_content is empty]
323
- @options data {Array} listid: These are the lists to which the campaign has been sent [Mandatory: if scheduled_date is not empty]
324
- @options data {String} scheduled_date: The day on which the campaign is supposed to run[Optional]
325
- @options data {String} subject: Subject of the campaign [Mandatory]
326
- @options data {String} from_email: Sender email from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
327
- @options data {String} reply_to: The reply to email in the campaign emails [Optional]
328
- @options data {String} to_field: This is to personalize the «To» Field. If you want to include the first name and last name of your recipient, add [PRENOM] [NOM]. To use the contact attributes here, these should already exist in SendinBlue account [Optional]
329
- @options data {Array} exclude_list: These are the lists which must be excluded from the campaign [Optional]
330
- @options data {Integer} recurring: Type of trigger campaign. Possible values = 0 (default) & 1. recurring = 0 means contact can receive the same Trigger campaign only once, & recurring = 1 means contact can receive the same Trigger campaign several times [Optional]
331
- @options data {String} attachment_url: Provide the absolute url of the attachment [Optional]
332
- @options data {Integer} inline_image: Status of inline image. Possible values = 0 (default) & 1. inline_image = 0 means image can’t be embedded, & inline_image = 1 means image can be embedded, in the email [Optional]
333
- @options data {Integer} mirror_active: Status of mirror links in campaign. Possible values = 0 & 1 (default). mirror_active = 0 means mirror links are deactivated, & mirror_active = 1 means mirror links are activated, in the campaign [Optional]
334
- @options data {Integer} send_now: Flag to send campaign now. Possible values = 0 (default) & 1. send_now = 0 means campaign can’t be send now, & send_now = 1 means campaign ready to send now [Optional]
335
- */
336
  public function update_trigger_campaign( $data ) {
337
  $id = $data['id'];
338
  unset( $data['id'] );
@@ -340,48 +340,48 @@ class Mailin {
340
  }
341
 
342
  /*
343
- Get all folders detail.
344
- @param {Array} data contains php array with key value pair.
345
- @options data {Integer} page: Maximum number of records per request is 50, if there are more than 50 folders then you can use this parameter to get next 50 results [Mandatory]
346
- @options data {Integer} page_limit: This should be a valid number between 1-50 [Mandatory]
347
- */
348
  public function get_folders( $data ) {
349
  return $this->get( 'folder', json_encode( $data ) );
350
  }
351
 
352
  /*
353
- Get a particular folder detail.
354
- @param {Array} data contains php array with key value pair.
355
- @options data {Integer} id: Id of folder to get details [Mandatory]
356
- */
357
  public function get_folder( $data ) {
358
  return $this->get( 'folder/' . $data['id'], '' );
359
  }
360
 
361
  /*
362
- Create a new folder.
363
- @param {Array} data contains php array with key value pair.
364
- @options data {String} name: Desired name of the folder to be created [Mandatory]
365
- */
366
  public function create_folder( $data ) {
367
  return $this->post( 'folder', json_encode( $data ) );
368
  }
369
 
370
  /*
371
- Delete a specific folder information.
372
- @param {Array} data contains php array with key value pair.
373
- @options data {Integer} id: Id of folder to be deleted [Mandatory]
374
- */
375
  public function delete_folder( $data ) {
376
  return $this->delete( 'folder/' . $data['id'], '' );
377
  }
378
 
379
  /*
380
- Update an existing folder.
381
- @param {Array} data contains php array with key value pair.
382
- @options data {Integer} id: Id of folder to be modified [Mandatory]
383
- @options data {String} name: Desired name of the folder to be modified [Mandatory]
384
- */
385
  public function update_folder( $data ) {
386
  $id = $data['id'];
387
  unset( $data['id'] );
@@ -389,42 +389,42 @@ class Mailin {
389
  }
390
 
391
  /*
392
- Get all lists detail.
393
- @param {Array} data contains php array with key value pair.
394
- @options data {Integer} list_parent: This is the existing folder id & can be used to get all lists belonging to it [Optional]
395
- @options data {Integer} page: Maximum number of records per request is 50, if there are more than 50 processes then you can use this parameter to get next 50 results [Mandatory]
396
- @options data {Integer} page_limit: This should be a valid number between 1-50 [Mandatory]
397
- */
398
  public function get_lists( $data ) {
399
  return $this->get( 'list', json_encode( $data ) );
400
  }
401
 
402
  /*
403
- Get a particular list detail.
404
- @param {Array} data contains php array with key value pair.
405
- @options data {Integer} id: Id of list to get details [Mandatory]
406
- */
407
  public function get_list( $data ) {
408
  return $this->get( 'list/' . $data['id'], '' );
409
  }
410
 
411
  /*
412
- Create a new list.
413
- @param {Array} data contains php array with key value pair.
414
- @options data {String} list_name: Desired name of the list to be created [Mandatory]
415
- @options data {Integer} list_parent: Folder ID [Mandatory]
416
- */
417
  public function create_list( $data ) {
418
  return $this->post( 'list', json_encode( $data ) );
419
  }
420
 
421
  /*
422
- Update a list.
423
- @param {Array} data contains php array with key value pair.
424
- @options data {Integer} id: Id of list to be modified [Mandatory]
425
- @options data {String} list_name: Desired name of the list to be modified [Optional]
426
- @options data {Integer} list_parent: Folder ID [Mandatory]
427
- */
428
  public function update_list( $data ) {
429
  $id = $data['id'];
430
  unset( $data['id'] );
@@ -432,32 +432,32 @@ class Mailin {
432
  }
433
 
434
  /*
435
- Delete a specific list.
436
- @param {Array} data contains php array with key value pair.
437
- @options data {Integer} id: Id of list to be deleted [Mandatory]
438
- */
439
  public function delete_list( $data ) {
440
  return $this->delete( 'list/' . $data['id'], '' );
441
  }
442
 
443
  /*
444
- Display details of all users for the given lists.
445
- @param {Array} data contains php array with key value pair.
446
- @options data {Array} listids: These are the list ids to get their data. The ids found will display records [Mandatory]
447
- @options data {String} timestamp: This is date-time filter to fetch modified user records >= this time. Valid format Y-m-d H:i:s. Example: "2015-05-22 14:30:00" [Optional]
448
- @options data {Integer} page: Maximum number of records per request is 500, if in your list there are more than 500 users then you can use this parameter to get next 500 results [Optional]
449
- @options data {Integer} page_limit: This should be a valid number between 1-500 [Optional]
450
- */
451
  public function display_list_users( $data ) {
452
  return $this->post( 'list/display', json_encode( $data ) );
453
  }
454
 
455
  /*
456
- Add already existing users in the SendinBlue contacts to the list.
457
- @param {Array} data contains php array with key value pair.
458
- @options data {Integer} id: Id of list to link users in it [Mandatory]
459
- @options data {Array} users: Email address of the already existing user(s) in the SendinBlue contacts. Example: "test@example.net". You can use commas to separate multiple users [Mandatory]
460
- */
461
 
462
  public function add_users_list( $data ) {
463
  $id = $data['id'];
@@ -466,11 +466,11 @@ class Mailin {
466
  }
467
 
468
  /*
469
- Delete already existing users in the SendinBlue contacts from the list.
470
- @param {Array} data contains php array with key value pair.
471
- @options data {Integer} id: Id of list to unlink users from it [Mandatory]
472
- @options data {Array} users: Email address of the already existing user(s) in the SendinBlue contacts to be modified. Example: "test@example.net". You can use commas to separate multiple users [Mandatory]
473
- */
474
  public function delete_users_list( $data ) {
475
  $id = $data['id'];
476
  unset( $data['id'] );
@@ -478,38 +478,38 @@ class Mailin {
478
  }
479
 
480
  /*
481
- Access all the attributes information under the account.
482
- No input required
483
- */
484
  public function get_attributes() {
485
  return $this->get( 'attribute', '' );
486
  }
487
 
488
  /*
489
- Access the specific type of attribute information.
490
- @param {Array} data contains php array with key value pair.
491
- @options data {String} type: Type of attribute. Possible values – normal, transactional, category, calculated & global [Optional]
492
- */
493
  public function get_attribute( $data ) {
494
  return $this->get( 'attribute/' . $data['type'], '' );
495
  }
496
 
497
  /*
498
- Create an Attribute.
499
- @param {Array} data contains php array with key value pair.
500
- @options data {String} type: Type of attribute. Possible values – normal, transactional, category, calculated & global ( case sensitive ) [Mandatory]
501
- @options data {Array} data: The name and data type of ‘normal’ & ‘transactional’ attribute to be created in your SendinBlue account. It should be sent as an associative array. Example: array(‘ATTRIBUTE_NAME1′ => ‘DATA_TYPE1′, ‘ATTRIBUTE_NAME2’=> ‘DATA_TYPE2′).
502
- The name and data value of ‘category’, ‘calculated’ & ‘global’, should be sent as JSON string. Example: ‘[{ "name":"ATTRIBUTE_NAME1", "value":"Attribute_value1" }, { "name":"ATTRIBUTE_NAME2", "value":"Attribute_value2" }]’. You can use commas to separate multiple attributes [Mandatory]
503
- */
504
  public function create_attribute( $data ) {
505
  return $this->post( 'attribute/', json_encode( $data ) );
506
  }
507
 
508
  /*
509
- Delete a specific type of attribute information.
510
- @param {Array} data contains php array with key value pair.
511
- @options data {Integer} type: Type of attribute to be deleted [Mandatory]
512
- */
513
  public function delete_attribute( $type, $data ) {
514
  $type = $data['type'];
515
  unset( $data['type'] );
@@ -517,128 +517,128 @@ class Mailin {
517
  }
518
 
519
  /*
520
- Create a new user if an email provided as input, doesn’t exists in the contact list of your SendinBlue account, otherwise it will update the existing user.
521
- @param {Array} data contains php array with key value pair.
522
- @options data {String} email: Email address of the user to be created in SendinBlue contacts. Already existing email address of user in the SendinBlue contacts to be modified [Mandatory]
523
- @options data {Array} attributes: The name of attribute present in your SendinBlue account. It should be sent as an associative array. Example: array("NAME"=>"name"). You can use commas to separate multiple attributes [Optional]
524
- @options data {Integer} blacklisted: This is used to blacklist/ Unblacklist a user. Possible values – 0 & 1. blacklisted = 1 means user has been blacklisted [Optional]
525
- @options data {Array} listid: The list id(s) to be linked from user [Optional]
526
- @options data {Array} listid_unlink: The list id(s) to be unlinked from user [Optional]
527
- @options data {Array} blacklisted_sms: This is used to blacklist/ Unblacklist a user’s SMS number. Possible values – 0 & 1. blacklisted_sms = 1 means user’s SMS number has been blacklisted [Optional]
528
- */
529
  public function create_update_user( $data ) {
530
  return $this->post( 'user/createdituser', json_encode( $data ) );
531
  }
532
 
533
  /*
534
- Get Access a specific user Information.
535
- @param {Array} data contains php array with key value pair.
536
- @options data {String} email: Email address of the already existing user in the SendinBlue contacts [Mandatory]
537
- */
538
  public function get_user( $data ) {
539
  return $this->get( 'user/' . $data['email'], '' );
540
  }
541
 
542
  /*
543
- Unlink existing user from all lists.
544
- @param {Array} data contains php array with key value pair.
545
- @options data {String} email: Email address of the already existing user in the SendinBlue contacts to be unlinked from all lists [Mandatory]
546
- */
547
  public function delete_user( $data ) {
548
  return $this->delete( 'user/' . $data['email'], '' );
549
  }
550
 
551
  /*
552
- Import Users Information.
553
- @param {Array} data contains php array with key value pair.
554
- @options data {String} url: The URL of the file to be imported. Possible file types – .txt, .csv [Mandatory: if body is empty]
555
- @options data {String} body: The Body with csv content to be imported. Example: ‘NAME;SURNAME;EMAIL\n"Name1";"Surname1";"example1@example.net"\n"Name2";"Surname2";"example2@example.net"‘, where \n separates each user data. You can use semicolon to separate multiple attributes [Mandatory: if url is empty]
556
- @options data {Array} listids: These are the list ids in which the the users will be imported [Mandatory: if name is empty]
557
- @options data {String} notify_url: URL that will be called once the import process is finished [Optional] In notify_url, we are sending the content using POST method
558
- @options data {String} name: This is new list name which will be created first & then users will be imported in it [Mandatory: if listids is empty]
559
- @options data {Integer} list_parent: This is the existing folder id & can be used with name parameter to make newly created list’s desired parent [Optional]
560
- */
561
  public function import_users( $data ) {
562
  return $this->post( 'user/import', json_encode( $data ) );
563
  }
564
 
565
  /*
566
- Export Users Information.
567
- @param {Array} data contains php array with key value pair.
568
- @options data {String} export_attrib: The name of attribute present in your SendinBlue account. You can use commas to separate multiple attributes. Example: "EMAIL,NAME,SMS" [Optional]
569
- @options data {String} filter: Filter can be added to export users. Example: "{\"blacklisted\":1}", will export all blacklisted users [Mandatory]
570
- @options data {String} notify_url: URL that will be called once the export process is finished [Optional]
571
- */
572
  public function export_users( $data ) {
573
  return $this->post( 'user/export', json_encode( $data ) );
574
  }
575
 
576
  /*
577
- Get all the processes information under the account.
578
- @param {Array} data contains php array with key value pair.
579
- @options data {Integer} page: Maximum number of records per request is 50, if there are more than 50 processes then you can use this parameter to get next 50 results [Mandatory]
580
- @options data {Integer} page_limit: This should be a valid number between 1-50 [Mandatory]
581
- */
582
  public function get_processes( $data ) {
583
  return $this->get( 'process', json_encode( $data ) );
584
  }
585
 
586
  /*
587
- Get the process information.
588
- @param {Array} data contains php array with key value pair.
589
- @options data {Integer} id: Id of process to get details [Mandatory]
590
- */
591
  public function get_process( $data ) {
592
  return $this->get( 'process/' . $data['id'], '' );
593
  }
594
 
595
  /*
596
- To retrieve details of all webhooks.
597
- @param {Array} data contains php array with key value pair.
598
- @options data {String} is_plat: Flag to get webhooks. Possible values – 0 & 1. Example: to get Transactional webhooks, use $is_plat=0, to get Marketing webhooks, use $is_plat=1, & to get all webhooks, use $is_plat="" [Optional]
599
- */
600
  public function get_webhooks( $data ) {
601
  return $this->get( 'webhook', json_encode( $data ) );
602
  }
603
 
604
  /*
605
- To retrieve details of any particular webhook.
606
- @param {Array} data contains php array with key value pair.
607
- @options data {Integer} id: Id of webhook to get details [Mandatory]
608
- */
609
  public function get_webhook( $data ) {
610
  return $this->get( 'webhook/' . $data['id'], '' );
611
  }
612
 
613
  /*
614
- Create a Webhook.
615
- @param {Array} data contains php array with key value pair.
616
- @options data {String} url: URL that will be triggered by a webhook [Mandatory]
617
- @options data {String} description: Webook description [Optional]
618
- @options data {Array} events: Set of events. You can use commas to separate multiple events. Possible values for Transcational webhook – request, delivered, hard_bounce, soft_bounce, blocked, spam, invalid_email, deferred, click, & opened and Possible Values for Marketing webhook – spam, opened, click, hard_bounce, unsubscribe, soft_bounce & list_addition ( case sensitive ) [Mandatory]
619
- @options data {Integer} is_plat: Flag to create webhook type. Possible values – 0 (default) & 1. Example: to create Transactional webhooks, use $is_plat=0, & to create Marketing webhooks, use $is_plat=1 [Optional]
620
- */
621
  public function create_webhook( $data ) {
622
  return $this->post( 'webhook', json_encode( $data ) );
623
  }
624
 
625
  /*
626
- Delete a webhook.
627
- @param {Array} data contains php array with key value pair.
628
- @options data {Integer} id: Id of webhook to be deleted [Mandatory]
629
- */
630
  public function delete_webhook( $data ) {
631
  return $this->delete( 'webhook/' . $data['id'], '' );
632
  }
633
 
634
  /*
635
- Update a webhook.
636
- @param {Array} data contains php array with key value pair.
637
- @options data {Integer} id: Id of webhook to be modified [Mandatory]
638
- @options data {String} url: URL that will be triggered by a webhook [Mandatory]
639
- @options data {String} description: Webook description [Optional]
640
- @options data {Array} events: Set of events. You can use commas to separate multiple events. Possible values for Transcational webhook – request, delivered, hard_bounce, soft_bounce, blocked, spam, invalid_email, deferred, click, & opened and Possible Values for Marketing webhook – spam, opened, click, hard_bounce, unsubscribe, soft_bounce & list_addition ( case sensitive ) [Mandatory]
641
- */
642
  public function update_webhook( $data ) {
643
  $id = $data['id'];
644
  unset( $data['id'] );
@@ -646,32 +646,32 @@ class Mailin {
646
  }
647
 
648
  /*
649
- Get Access of created senders information.
650
- @param {Array} data contains php array with key value pair.
651
- @options data {String} option: Options to get senders. Possible options – IP-wise, & Domain-wise ( only for dedicated IP clients ). Example: to get senders with specific IP, use $option=’1.2.3.4′, to get senders with specific domain use, $option=’domain.com’, & to get all senders, use $option="" [Optional]
652
- */
653
  public function get_senders( $data ) {
654
  return $this->get( 'advanced', json_encode( $data ) );
655
  }
656
 
657
  /*
658
- Create your Senders.
659
- @param {Array} data contains php array with key value pair.
660
- @options data {String} name: Name of the sender [Mandatory]
661
- @options data {String} email: Email address of the sender [Mandatory]
662
- @options data {Array} ip_domain: Pass pipe ( | ) separated Dedicated IP and its associated Domain. Example: "1.2.3.4|mydomain.com". You can use commas to separate multiple ip_domain’s [Mandatory: Only for Dedicated IP clients, for Shared IP clients, it should be kept blank]
663
- */
664
  public function create_sender( $data ) {
665
  return $this->post( 'advanced', json_encode( $data ) );
666
  }
667
 
668
  /*
669
- Update your Senders.
670
- @param {Array} data contains php array with key value pair.
671
- @options data {Integer} id: Id of sender to be modified [Mandatory]
672
- @options data {String} name: Name of the sender [Mandatory]
673
- @options data {Array} ip_domain: Pass pipe ( | ) separated Dedicated IP and its associated Domain. Example: "1.2.3.4|mydomain.com". You can use commas to separate multiple ip_domain’s [Mandatory: Only for Dedicated IP clients, for Shared IP clients, it should be kept blank]
674
- */
675
  public function update_sender( $data ) {
676
  $id = $data['id'];
677
  unset( $data['id'] );
@@ -679,83 +679,83 @@ class Mailin {
679
  }
680
 
681
  /*
682
- Delete your Sender Information.
683
- @param {Array} data contains php array with key value pair.
684
- @options data {Integer} id: Id of sender to be deleted [Mandatory]
685
- */
686
  public function delete_sender( $data ) {
687
  return $this->delete( 'advanced/' . $data['id'], '' );
688
  }
689
 
690
  /*
691
- Send Transactional Email.
692
- @param {Array} data contains php array with key value pair.
693
- @options data {Array} to: Email address of the recipient(s). It should be sent as an associative array. Example: array("to@example.net"=>"to whom"). You can use commas to separate multiple recipients [Mandatory]
694
- @options data {String} subject: Message subject [Mandatory]
695
- @options data {Array} from Email address for From header. It should be sent as an array. Example: array("from@email.com","from email") [Mandatory]
696
- @options data {String} html: Body of the message. (HTML version) [Mandatory]. To send inline images, use <img src="{YourFileName.Extension}" alt="image" border="0" >, the 'src' attribute value inside {} (curly braces) should be same as the filename used in 'inline_image' parameter
697
- @options data {String} text: Body of the message. (text version) [Optional]
698
- @options data {Array} cc: Same as to but for Cc. Example: array("cc@example.net","cc whom") [Optional]
699
- @options data {Array} bcc: Same as to but for Bcc. Example: array("bcc@example.net","bcc whom") [Optional]
700
- @options data {Array} replyto: Same as from but for Reply To. Example: array("from@email.com","from email") [Optional]
701
- @options data {Array} attachment: Provide the absolute url of the attachment/s. Possible extension values = gif, png, bmp, cgm, jpg, jpeg, txt, css, shtml, html, htm, csv, zip, pdf, xml, doc, xls, ppt, tar, and ez. To send attachment/s generated on the fly you have to pass your attachment/s filename & its base64 encoded chunk data as an associative array. Example: array("YourFileName.Extension"=>"Base64EncodedChunkData"). You can use commas to separate multiple attachments [Optional]
702
- @options data {Array} headers: The headers will be sent along with the mail headers in original email. Example: array("Content-Type"=>"text/html; charset=iso-8859-1"). You can use commas to separate multiple headers [Optional]
703
- @options data {Array} inline_image: Pass your inline image/s filename & its base64 encoded chunk data as an associative array. Example: array("YourFileName.Extension"=>"Base64EncodedChunkData"). You can use commas to separate multiple inline images [Optional]
704
- */
705
  public function send_email( $data ) {
706
  return $this->post( 'email', json_encode( $data ) );
707
  }
708
 
709
  /*
710
- Aggregate / date-wise report of the SendinBlue SMTP account.
711
- @param {Array} data contains php array with key value pair.
712
- @options data {Integer} aggregate: This is used to indicate, you are interested in all-time totals. Possible values – 0 & 1. aggregate = 0 means it will not aggregate records, and will show stats per day/date wise [Optional]
713
- @options data {String} start_date: The start date to look up statistics. Date must be in YYYY-MM-DD format and should be before the end_date [Optional]
714
- @options data {String} end_date: The end date to look up statistics. Date must be in YYYY-MM-DD format and should be after the start_date [Optional]
715
- @options data {Integer} days: Number of days in the past to include statistics ( Includes today ). It must be an integer greater than 0 [Optional]
716
- @options data {String} tag: The tag you will specify to retrieve detailed stats. It must be an existing tag that has statistics [Optional]
717
- */
718
  public function get_statistics( $data ) {
719
  return $this->post( 'statistics', json_encode( $data ) );
720
  }
721
 
722
  /*
723
- Get Email Event report.
724
- @param {Array} data contains php array with key value pair.
725
- @options data {Integer} limit: To limit the number of results returned. It should be an integer [Optional]
726
- @options data {String} start_date: The start date to get report from. Date must be in YYYY-MM-DD format and should be before the end_date [Optional]
727
- @options data {String} end_date: The end date to get report till date. Date must be in YYYY-MM-DD format and should be after the start_date [Optional]
728
- @options data {Integer} offset: Beginning point in the list to retrieve from. It should be an integer [Optional]
729
- @options data {String} date: Specific date to get its report. Date must be in YYYY-MM-DD format and should be earlier than todays date [Optional]
730
- @options data {Integer} days: Number of days in the past (includes today). If specified, must be an integer greater than 0 [Optional]
731
- @options data {String} email: Email address to search report for [Optional]
732
- */
733
  public function get_report( $data ) {
734
  return $this->post( 'report', json_encode( $data ) );
735
  }
736
 
737
  /*
738
- Delete any hardbounce, which actually would have been blocked due to some temporary ISP failures.
739
- @param {Array} data contains php array with key value pair.
740
- @options data {String} start_date: The start date to get report from. Date must be in YYYY-MM-DD format and should be before the end_date [Optional]
741
- @options data {String} end_date: The end date to get report till date. Date must be in YYYY-MM-DD format and should be after the start_date [Optional]
742
- @options data {String} email: Email address to delete its bounces [Optional]
743
- */
744
  public function delete_bounces( $data ) {
745
  return $this->post( 'bounces', json_encode( $data ) );
746
  }
747
 
748
  /*
749
- Send templates created on SendinBlue, through SendinBlue SMTP (transactional mails).
750
- @param {Array} data contains php array with key value pair.
751
- @options data {Integer} id: Id of the template created on SendinBlue account [Mandatory]
752
- @options data {String} to: Email address of the recipient(s). You can use pipe ( | ) to separate multiple recipients. Example: "to-example@example.net|to2-example@example.net" [Mandatory]
753
- @options data {String} cc: Same as to but for Cc [Optional]
754
- @options data {String} bcc: Same as to but for Bcc [Optional]
755
- @options data {Array} attrv The name of attribute present in your SendinBlue account. It should be sent as an associative array. Example: array("NAME"=>"name"). You can use commas to separate multiple attributes [Optional]
756
- @options data {String} attachment_url: Provide the absolute url of the attachment. Url not allowed from local machine. File must be hosted somewhere [Optional]
757
- @options data {Array} attachment: To send attachment/s generated on the fly you have to pass your attachment/s filename & its base64 encoded chunk data as an associative array [Optional]
758
- */
759
  public function send_transactional_template( $data ) {
760
  $id = $data['id'];
761
  unset( $data['id'] );
@@ -763,40 +763,40 @@ class Mailin {
763
  }
764
 
765
  /*
766
- Create a Template.
767
- @param {Array} data contains php array with key value pair.
768
- @options data {String} from_name: Sender name from which the campaign emails are sent [Mandatory: for Dedicated IP clients & for Shared IP clients, if sender exists]
769
- @options data {String} template_name: Name of the Template [Mandatory]
770
- @options data {String} bat: Email address for test mail [Optional]
771
- @options data {String} html_content: Body of the content. The HTML content field must have more than 10 characters [Mandatory: if html_url is empty]
772
- @options data {String} html_url Url: which content is the body of content [Mandatory: if html_content is empty]
773
- @options data {String} subject: Subject of the campaign [Mandatory]
774
- @options data {String} from_email: Sender email from which the campaign emails are sent [Mandatory: for Dedicated IP clients & for Shared IP clients, if sender exists]
775
- @options data {String} reply_to: The reply to email in the campaign emails [Optional]
776
- @options data {String} to_fieldv This is to personalize the «To» Field. If you want to include the first name and last name of your recipient, add [PRENOM] [NOM]. To use the contact attributes here, these should already exist in SendinBlue account [Optional]
777
- @options data {Integer} status: Status of template. Possible values = 0 (default) & 1. status = 0 means template is inactive, & status = 1 means template is active [Optional]
778
- @options data {Integer} attachment: Status of attachment. Possible values = 0 (default) & 1. attach = 0 means an attachment can’t be sent, & attach = 1 means an attachment can be sent, in the email [Optional]
779
- */
780
  public function create_template( $data ) {
781
  return $this->post( 'template', json_encode( $data ) );
782
  }
783
 
784
  /*
785
- Update a Template.
786
- @param {Array} data contains php array with key value pair.
787
- @options data {Integer} id: Id of Template to be modified [Mandatory]
788
- @options data {String} from_name: Sender name from which the campaign emails are sent [Mandatory: for Dedicated IP clients & for Shared IP clients, if sender exists]
789
- @options data {String} template_name: Name of the Template [Mandatory]
790
- @options data {String} bat: Email address for test mail [Optional]
791
- @options data {String} html_content: Body of the content. The HTML content field must have more than 10 characters [Mandatory: if html_url is empty]
792
- @options data {String} html_url: Url which content is the body of content [Mandatory: if html_content is empty]
793
- @options data {String} subject: Subject of the campaign [Mandatory]
794
- @options data {String} from_email: Sender email from which the campaign emails are sent [Mandatory: for Dedicated IP clients & for Shared IP clients, if sender exists]
795
- @options data {String} reply_to: The reply to email in the campaign emails [Optional]
796
- @options data {String} to_field: This is to personalize the «To» Field. If you want to include the first name and last name of your recipient, add [PRENOM] [NOM]. To use the contact attributes here, these should already exist in SendinBlue account [Optional]
797
- @options data {Integer} status: Status of template. Possible values = 0 (default) & 1. status = 0 means template is inactive, & status = 1 means template is active [Optional]
798
- @options data {Integer} attachment: Status of attachment. Possible values = 0 (default) & 1. attach = 0 means an attachment can’t be sent, & attach = 1 means an attachment can be sent, in the email [Optional]
799
- */
800
  public function update_template( $data ) {
801
  $id = $data['id'];
802
  unset( $data['id'] );
@@ -804,48 +804,48 @@ class Mailin {
804
  }
805
 
806
  /*
807
- Send a transactional SMS.
808
- @param {Array} data contains php array with key value pair.
809
- @options data {String} to: The mobile number to send SMS to with country code [Mandatory]
810
- @options data {String} from: The name of the sender. The number of characters is limited to 11 (alphanumeric format) [Mandatory]
811
- @options data {String} text: The text of the message. The maximum characters used per SMS is 160, if used more than that, it will be counted as more than one SMS [Mandatory]
812
- @options data {String} web_url: The web URL that can be called once the message is successfully delivered [Optional]
813
- @options data {String} tag: The tag that you can associate with the message [Optional]
814
- @options data {String} type: Type of message. Possible values – marketing (default) & transactional. You can use marketing for sending marketing SMS, & for sending transactional SMS, use transactional type [Optional]
815
- */
816
  public function send_sms( $data ) {
817
  return $this->post( 'sms', json_encode( $data ) );
818
  }
819
 
820
  /*
821
- Create & Schedule your SMS campaigns.
822
- @param {Array} data contains php array with key value pair.
823
- @options data {String} name: Name of the SMS campaign [Mandatory]
824
- @options data {String} sender: This allows you to customize the SMS sender. The number of characters is limited to 11 ( alphanumeric format ) [Optional]
825
- @options data {String} content: Content of the message. The maximum characters used per SMS is 160, if used more than that, it will be counted as more than one SMS [Optional]
826
- @options data {String} bat: Mobile number with the country code to send test SMS. The mobile number defined here should belong to one of your contacts in SendinBlue account and should not be blacklisted [Optional]
827
- @options data {Array} listid: These are the list ids to which the SMS campaign is sent [Mandatory: if scheduled_date is not empty]
828
- @options data {Array} exclude_list: These are the list ids which will be excluded from the SMS campaign [Optional]
829
- @options data {String} scheduled_date: The day on which the SMS campaign is supposed to run [Optional]
830
- @options data {Integer} send_now: Flag to send campaign now. Possible values = 0 (default) & 1. send_now = 0 means campaign can’t be send now, & send_now = 1 means campaign ready to send now [Optional]
831
- */
832
  public function create_sms_campaign( $data ) {
833
  return $this->post( 'sms', json_encode( $data ) );
834
  }
835
 
836
  /*
837
- Update your SMS campaigns.
838
- @param {Array} data contains php array with key value pair.
839
- @options data {Integer} id: Id of the SMS campaign [Mandatory]
840
- @options data {String} name: Name of the SMS campaign [Optional]
841
- @options data {String} sender: This allows you to customize the SMS sender. The number of characters is limited to 11 ( alphanumeric format ) [Optional]
842
- @options data {String} content: Content of the message. The maximum characters used per SMS is 160, if used more than that, it will be counted as more than one SMS [Optional]
843
- @options data {String} bat: Mobile number with the country code to send test SMS. The mobile number defined here should belong to one of your contacts in SendinBlue account and should not be blacklisted [Optional]
844
- @options data {Array} listid: hese are the list ids to which the SMS campaign is sent [Mandatory: if scheduled_date is not empty]
845
- @options data {Array} exclude_list: These are the list ids which will be excluded from the SMS campaign [Optional]
846
- @options data {String} scheduled_date: The day on which the SMS campaign is supposed to run [Optional]
847
- @options data {Integer} send_now: Flag to send campaign now. Possible values = 0 (default) & 1. send_now = 0 means campaign can’t be send now, & send_now = 1 means campaign ready to send now [Optional]
848
- */
849
  public function update_sms_campaign( $data ) {
850
  $id = $data['id'];
851
  unset( $data['id'] );
@@ -853,11 +853,11 @@ class Mailin {
853
  }
854
 
855
  /*
856
- Send a Test SMS.
857
- @param {Array} data contains php array with key value pair.
858
- @options data {Integer} id: Id of the SMS campaign [Mandatory]
859
- @options data {String} to: Mobile number with the country code to send test SMS. The mobile number defined here should belong to one of your contacts in SendinBlue account and should not be blacklisted [Mandatory]
860
- */
861
  public function send_bat_sms( $data ) {
862
  $id = $data['id'];
863
  unset( $data['id'] );
55
  }
56
 
57
  /*
58
+ Get Account.
59
+ No input required
60
+ */
61
  public function get_account() {
62
  return $this->get( 'account', '' );
63
  }
64
 
65
  /*
66
+ Get SMTP details.
67
+ No input required
68
+ */
69
  public function get_smtp_details() {
70
  return $this->get( 'account/smtpdetail', '' );
71
  }
72
 
73
  /*
74
+ Create Child Account.
75
+ @param {Array} data contains php array with key value pair.
76
+ @options data {String} child_email: Email address of Reseller child [Mandatory]
77
+ @options data {String} password: Password of Reseller child to login [Mandatory]
78
+ @options data {String} company_org: Name of Reseller child’s company [Mandatory]
79
+ @options data {String} first_name: First name of Reseller child [Mandatory]
80
+ @options data {String} last_name: Last name of Reseller child [Mandatory]
81
+ @options data {Array} credits: Number of email & sms credits respectively, which will be assigned to the Reseller child’s account [Optional]
82
+ - email_credit {Integer} number of email credits
83
+ - sms_credit {Integer} Number of sms credts
84
+ @options data {Array} associate_ip: Associate dedicated IPs to reseller child. You can use commas to separate multiple IPs [Optional]
85
+ */
86
  public function create_child_account( $data ) {
87
  return $this->post( 'account', json_encode( $data ) );
88
  }
89
 
90
  /*
91
+ Update Child Account.
92
+ @param {Array} data contains php array with key value pair.
93
+ @options data {String} auth_key: 16 character authorization key of Reseller child to be modified [Mandatory]
94
+ @options data {String} company_org: Name of Reseller child’s company [Optional]
95
+ @options data {String} first_name: First name of Reseller child [Optional]
96
+ @options data {String} last_name: Last name of Reseller child [Optional]
97
+ @options data {String} password: Password of Reseller child to login [Optional]
98
+ @options data {Array} associate_ip: Associate dedicated IPs to reseller child. You can use commas to separate multiple IPs [Optional]
99
+ @options data {Array} disassociate_ip: Disassociate dedicated IPs from reseller child. You can use commas to separate multiple IPs [Optional]
100
+ */
101
  public function update_child_account( $data ) {
102
  return $this->put( 'account', json_encode( $data ) );
103
  }
104
 
105
  /*
106
+ Delete Child Account.
107
+ @param {Array} data contains php array with key value pair.
108
+ @options data {String} auth_key: 16 character authorization key of Reseller child to be deleted [Mandatory]
109
+ */
110
  public function delete_child_account( $data ) {
111
  return $this->delete( 'account/' . $data['auth_key'], '' );
112
  }
113
 
114
  /*
115
+ Get Reseller child Account.
116
+ @param {Array} data contains php array with key value pair.
117
+ @options data {String} auth_key: 16 character authorization key of Reseller child. Example : To get the details of more than one child account, use, {"key1":"abC01De2fGHI3jkL","key2":"mnO45Pq6rSTU7vWX"} [Mandatory]
118
+ */
119
  public function get_reseller_child( $data ) {
120
  return $this->post( 'account/getchildv2', json_encode( $data ) );
121
  }
122
 
123
  /*
124
+ Add/Remove Reseller child's Email/Sms credits.
125
+ @param {Array} data contains php array with key value pair.
126
+ @options data {String} auth_key: 16 character authorization key of Reseller child to modify credits [Mandatory]
127
+ @options data {Array} add_credit: Number of email & sms credits to be added. You can assign either email or sms credits, one at a time other will remain 0. [Mandatory: if rmv_credit is empty]
128
+ - email_credit {Integer} number of email credits
129
+ - sms_credit {Integer} Number of sms credts
130
+ @options data {Array} rmv_credit: Number of email & sms credits to be removed. You can assign either email or sms credits, one at a time other will remain 0. [Mandatory: if add_credits is empty]
131
+ - email_credit {Integer} number of email credits
132
+ - sms_credit {Integer} Number of sms credts
133
+ */
134
  public function add_remove_child_credits( $data ) {
135
  return $this->post( 'account/addrmvcredit', json_encode( $data ) );
136
  }
137
 
138
  /*
139
+ Get a particular campaign detail.
140
+ @param {Array} data contains php array with key value pair.
141
+ @options data {Integer} id: Unique Id of the campaign [Mandatory]
142
+ */
143
  public function get_campaign_v2( $data ) {
144
  return $this->get( 'campaign/' . $data['id'] . '/detailsv2', '' );
145
  }
146
 
147
  /*
148
+ Get all campaigns detail.
149
+ @param {Array} data contains php array with key value pair.
150
+ @options data {String} type: Type of campaign. Possible values – classic, trigger, sms, template ( case sensitive ) [Optional]
151
+ @options data {String} status: Status of campaign. Possible values – draft, sent, archive, queued, suspended, in_process, temp_active, temp_inactive ( case sensitive ) [Optional]
152
+ @options data {Integer} page: Maximum number of records per request is 500, if there are more than 500 campaigns then you can use this parameter to get next 500 results [Optional]
153
+ @options data {Integer} page_limit: This should be a valid number between 1-500 [Optional]
154
+ */
155
  public function get_campaigns_v2( $data ) {
156
  return $this->get( 'campaign/detailsv2', json_encode( $data ) );
157
  }
158
 
159
  /*
160
+ Create and Schedule your campaigns. It returns the ID of the created campaign.
161
+ @param {Array} data contains php array with key value pair.
162
+ @options data {String} category: Tag name of the campaign [Optional]
163
+ @options data {String} from_name: Sender name from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
164
+ @options data {String} name: Name of the campaign [Mandatory]
165
+ @options data {String} bat: Email address for test mail [Optional]
166
+ @options data {String} html_content: Body of the content. The HTML content field must have more than 10 characters [Mandatory: if html_url is empty]
167
+ @options data {String} html_url: Url which content is the body of content [Mandatory: if html_content is empty]
168
+ @options data {Array} listid: These are the lists to which the campaign has been sent [Mandatory: if scheduled_date is not empty]
169
+ @options data {String} scheduled_date: The day on which the campaign is supposed to run[Optional]
170
+ @options data {String} subject: Subject of the campaign [Mandatory]
171
+ @options data {String} from_email: Sender email from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
172
+ @options data {String} reply_to: The reply to email in the campaign emails [Optional]
173
+ @options data {String} to_field: This is to personalize the «To» Field. If you want to include the first name and last name of your recipient, add [PRENOM] [NOM] To use the contact attributes here, these should already exist in SendinBlue account [Optional]
174
+ @options data {Array} exclude_list: These are the lists which must be excluded from the campaign [Optional]
175
+ @options data {String} attachment_url: Provide the absolute url of the attachment [Optional]
176
+ @options data {Integer} inline_image: Status of inline image. Possible values = 0 (default) & 1. inline_image = 0 means image can’t be embedded, & inline_image = 1 means image can be embedded, in the email [Optional]
177
+ @options data {Integer} mirror_active: Status of mirror links in campaign. Possible values = 0 & 1 (default). mirror_active = 0 means mirror links are deactivated, & mirror_active = 1 means mirror links are activated, in the campaign [Optional]
178
+ @options data {Integer} send_now: Flag to send campaign now. Possible values = 0 (default) & 1. send_now = 0 means campaign can’t be send now, & send_now = 1 means campaign ready to send now [Optional]
179
+
180
+ */
181
  public function create_campaign( $data ) {
182
  return $this->post( 'campaign', json_encode( $data ) );
183
  }
184
 
185
  /*
186
+ Update your campaign.
187
+ @param {Array} data contains php array with key value pair.
188
+ @options data {Integer} id: Id of campaign to be modified [Mandatory]
189
+ @options data {String} category: Tag name of the campaign [Optional]
190
+ @options data {String} from_name: Sender name from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
191
+ @options data {String} name: Name of the campaign [Optional]
192
+ @options data {String} bat: Email address for test mail [Optional]
193
+ @options data {String} html_content: Body of the content. The HTML content field must have more than 10 characters [Optional]
194
+ @options data {String} html_url: Url which content is the body of content [Optional]
195
+ @options data {Array} listid These are the lists to which the campaign has been sent [Mandatory: if scheduled_date is not empty]
196
+ @options data {String} scheduled_date: The day on which the campaign is supposed to run[Optional]
197
+ @options data {String} subject: Subject of the campaign.
198
+ @options data {String} from_email: Sender email from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
199
+ @options data {String} reply_to: The reply to email in the campaign emails [Optional]
200
+ @options data {String} to_field: This is to personalize the «To» Field. If you want to include the first name and last name of your recipient, add [PRENOM] [NOM]. To use the contact attributes here, these should already exist in SendinBlue account [Optional]
201
+ @options data {Array} exclude_list: These are the lists which must be excluded from the campaign [Optional]
202
+ @options data {String} attachment_url: Provide the absolute url of the attachment [Optional]
203
+ @options data {Integer} inline_image: Status of inline image. Possible values = 0 (default) & 1. inline_image = 0 means image can’t be embedded, & inline_image = 1 means image can be embedded, in the email [Optional]
204
+ @options data {Integer} mirror_active: Status of mirror links in campaign. Possible values = 0 & 1 (default). mirror_active = 0 means mirror links are deactivated, & mirror_active = 1 means mirror links are activated, in the campaign [Optional]
205
+ @options data {Integer} send_now: Flag to send campaign now. Possible values = 0 (default) & 1. send_now = 0 means campaign can’t be send now, & send_now = 1 means campaign ready to send now [Optional]
206
+ */
207
  public function update_campaign( $data ) {
208
  $id = $data['id'];
209
  unset( $data['id'] );
211
  }
212
 
213
  /*
214
+ Delete your campaigns.
215
+ @param {Array} data contains php array with key value pair.
216
+ @options data {Integer} id: Id of campaign to be deleted [Mandatory]
217
+ */
218
  public function delete_campaign( $data ) {
219
  return $this->delete( 'campaign/' . $data['id'], '' );
220
  }
221
 
222
  /*
223
+ Send report of Sent and Archived campaign.
224
+ @param {Array} data contains php array with key value pair.
225
+ @options data {Integer} id: Id of campaign to send its report [Mandatory]
226
+ @options data {String} lang: Language of email content. Possible values – fr (default), en, es, it & pt [Optional]
227
+ @options data {String} email_subject: Message subject [Mandatory]
228
+ @options data {Array} email_to: Email address of the recipient(s). Example: "test@example.net". You can use commas to separate multiple recipients [Mandatory]
229
+ @options data {String} email_content_type: Body of the message in text/HTML version. Possible values – text & html [Mandatory]
230
+ @options data {Array} email_bcc: Same as email_to but for Bcc [Optional]
231
+ @options data {Array} email_cc: Same as email_to but for Cc [Optional]
232
+ @options data {String} email_body: Body of the message [Mandatory]
233
+ */
234
  public function campaign_report_email( $data ) {
235
  $id = $data['id'];
236
  unset( $data['id'] );
238
  }
239
 
240
  /*
241
+ Export the recipients of a specified campaign.
242
+ @param {Array} data contains php array with key value pair.
243
+ @options data {Integer} id: Id of campaign to export its recipients [Mandatory]
244
+ @options data {String} notify_url: URL that will be called once the export process is finished [Mandatory]
245
+ @options data {String} type: Type of recipients. Possible values – all, non_clicker, non_opener, clicker, opener, soft_bounces, hard_bounces & unsubscribes [Mandatory]
246
+ */
247
  public function campaign_recipients_export( $data ) {
248
  $id = $data['id'];
249
  unset( $data['id'] );
251
  }
252
 
253
  /*
254
+ Get the Campaign name, subject and share link of the classic type campaigns only which are sent, for those which are not sent and the rest of campaign types like trigger, template & sms, will return an error message of share link not available.
255
+ @param {Array} data contains php array with key value pair.
256
+ @options data {Array} camp_ids: Id of campaign to get share link. You can use commas to separate multiple ids [Mandatory]
257
+ */
258
 
259
  public function share_campaign( $data ) {
260
  return $this->post( 'campaign/sharelinkv2', json_encode( $data ) );
261
  }
262
 
263
  /*
264
+ Send a Test Campaign.
265
+ @param {Array} data contains php array with key value pair.
266
+ @options data {Integer} id: Id of the campaign [Mandatory]
267
+ @options data {Array} emails: Email address of recipient(s) existing in the one of the lists & should not be blacklisted. Example: "test@example.net". You can use commas to separate multiple recipients [Mandatory]
268
+ */
269
  public function send_bat_email( $data ) {
270
  $id = $data['id'];
271
  unset( $data['id'] );
273
  }
274
 
275
  /*
276
+ Update the Campaign status.
277
+ @param {Array} data contains php array with key value pair.
278
+ @options data {Integer} id: Id of campaign to update its status [Mandatory]
279
+ @options data {String} status: Types of status. Possible values – suspended, archive, darchive, sent, queued, replicate and replicate_template ( case sensitive ) [Mandatory]
280
+ */
281
  public function update_campaign_status( $data ) {
282
  $id = $data['id'];
283
  unset( $data['id'] );
285
  }
286
 
287
  /*
288
+ Create and schedule your Trigger campaigns.
289
+ @param {Array} data contains php array with key value pair.
290
+ @options data {String} category: Tag name of the campaign [Optional]
291
+ @options data {String} from_name: Sender name from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
292
+ @options data {String} trigger_name: Name of the campaign [Mandatory]
293
+ @options data {String} bat: Email address for test mail [Optional]
294
+ @options data {String} html_content: Body of the content. The HTML content field must have more than 10 characters [Mandatory: if html_url is empty]
295
+ @options data {String} html_url: Url which content is the body of content [Mandatory: if html_content is empty]
296
+ @options data {Array} listid: These are the lists to which the campaign has been sent [Mandatory: if scheduled_date is not empty]
297
+ @options data {String} scheduled_date: The day on which the campaign is supposed to run[Optional]
298
+ @options data {String} subject: Subject of the campaign [Mandatory]
299
+ @options data {String} from_email: Sender email from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
300
+ @options data {String} reply_to: The reply to email in the campaign emails [Optional]
301
+ @options data {String} to_field: This is to personalize the «To» Field. If you want to include the first name and last name of your recipient, add [PRENOM] [NOM]. To use the contact attributes here, these should already exist in SendinBlue account [Optional]
302
+ @options data {Array} exclude_list: These are the lists which must be excluded from the campaign [Optional]
303
+ @options data {Integer} recurring: Type of trigger campaign. Possible values = 0 (default) & 1. recurring = 0 means contact can receive the same Trigger campaign only once, & recurring = 1 means contact can receive the same Trigger campaign several times [Optional]
304
+ @options data {String} attachment_url: Provide the absolute url of the attachment [Optional]
305
+ @options data {Integer} inline_image: Status of inline image. Possible values = 0 (default) & 1. inline_image = 0 means image can’t be embedded, & inline_image = 1 means image can be embedded, in the email [Optional]
306
+ @options data {Integer} mirror_active: Status of mirror links in campaign. Possible values = 0 & 1 (default). mirror_active = 0 means mirror links are deactivated, & mirror_active = 1 means mirror links are activated, in the campaign [Optional]
307
+ @options data {Integer} send_now: Flag to send campaign now. Possible values = 0 (default) & 1. send_now = 0 means campaign can’t be send now, & send_now = 1 means campaign ready to send now [Optional]
308
+ */
309
  public function create_trigger_campaign( $data ) {
310
  return $this->post( 'campaign', json_encode( $data ) );
311
  }
312
 
313
  /*
314
+ Update and schedule your Trigger campaigns.
315
+ @param {Array} data contains php array with key value pair.
316
+ @options data {Integer} id: Id of Trigger campaign to be modified [Mandatory]
317
+ @options data {String} category: Tag name of the campaign [Optional]
318
+ @options data {String} from_name: Sender name from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
319
+ @options data {String} trigger_name: Name of the campaign [Mandatory]
320
+ @options data {String} bat Email address for test mail [Optional]
321
+ @options data {String} html_content: Body of the content. The HTML content field must have more than 10 characters [Mandatory: if html_url is empty]
322
+ @options data {String} html_url: Url which content is the body of content [Mandatory: if html_content is empty]
323
+ @options data {Array} listid: These are the lists to which the campaign has been sent [Mandatory: if scheduled_date is not empty]
324
+ @options data {String} scheduled_date: The day on which the campaign is supposed to run[Optional]
325
+ @options data {String} subject: Subject of the campaign [Mandatory]
326
+ @options data {String} from_email: Sender email from which the campaign emails are sent [Mandatory: for Dedicated IP clients, please make sure that the sender details are defined here, and in case of no sender, you can add them also via API & for Shared IP clients, if sender exists]
327
+ @options data {String} reply_to: The reply to email in the campaign emails [Optional]
328
+ @options data {String} to_field: This is to personalize the «To» Field. If you want to include the first name and last name of your recipient, add [PRENOM] [NOM]. To use the contact attributes here, these should already exist in SendinBlue account [Optional]
329
+ @options data {Array} exclude_list: These are the lists which must be excluded from the campaign [Optional]
330
+ @options data {Integer} recurring: Type of trigger campaign. Possible values = 0 (default) & 1. recurring = 0 means contact can receive the same Trigger campaign only once, & recurring = 1 means contact can receive the same Trigger campaign several times [Optional]
331
+ @options data {String} attachment_url: Provide the absolute url of the attachment [Optional]
332
+ @options data {Integer} inline_image: Status of inline image. Possible values = 0 (default) & 1. inline_image = 0 means image can’t be embedded, & inline_image = 1 means image can be embedded, in the email [Optional]
333
+ @options data {Integer} mirror_active: Status of mirror links in campaign. Possible values = 0 & 1 (default). mirror_active = 0 means mirror links are deactivated, & mirror_active = 1 means mirror links are activated, in the campaign [Optional]
334
+ @options data {Integer} send_now: Flag to send campaign now. Possible values = 0 (default) & 1. send_now = 0 means campaign can’t be send now, & send_now = 1 means campaign ready to send now [Optional]
335
+ */
336
  public function update_trigger_campaign( $data ) {
337
  $id = $data['id'];
338
  unset( $data['id'] );
340
  }
341
 
342
  /*
343
+ Get all folders detail.
344
+ @param {Array} data contains php array with key value pair.
345
+ @options data {Integer} page: Maximum number of records per request is 50, if there are more than 50 folders then you can use this parameter to get next 50 results [Mandatory]
346
+ @options data {Integer} page_limit: This should be a valid number between 1-50 [Mandatory]
347
+ */
348
  public function get_folders( $data ) {
349
  return $this->get( 'folder', json_encode( $data ) );
350
  }
351
 
352
  /*
353
+ Get a particular folder detail.
354
+ @param {Array} data contains php array with key value pair.
355
+ @options data {Integer} id: Id of folder to get details [Mandatory]
356
+ */
357
  public function get_folder( $data ) {
358
  return $this->get( 'folder/' . $data['id'], '' );
359
  }
360
 
361
  /*
362
+ Create a new folder.
363
+ @param {Array} data contains php array with key value pair.
364
+ @options data {String} name: Desired name of the folder to be created [Mandatory]
365
+ */
366
  public function create_folder( $data ) {
367
  return $this->post( 'folder', json_encode( $data ) );
368
  }
369
 
370
  /*
371
+ Delete a specific folder information.
372
+ @param {Array} data contains php array with key value pair.
373
+ @options data {Integer} id: Id of folder to be deleted [Mandatory]
374
+ */
375
  public function delete_folder( $data ) {
376
  return $this->delete( 'folder/' . $data['id'], '' );
377
  }
378
 
379
  /*
380
+ Update an existing folder.
381
+ @param {Array} data contains php array with key value pair.
382
+ @options data {Integer} id: Id of folder to be modified [Mandatory]
383
+ @options data {String} name: Desired name of the folder to be modified [Mandatory]
384
+ */
385
  public function update_folder( $data ) {
386
  $id = $data['id'];
387
  unset( $data['id'] );
389
  }
390
 
391
  /*
392
+ Get all lists detail.
393
+ @param {Array} data contains php array with key value pair.
394
+ @options data {Integer} list_parent: This is the existing folder id & can be used to get all lists belonging to it [Optional]
395
+ @options data {Integer} page: Maximum number of records per request is 50, if there are more than 50 processes then you can use this parameter to get next 50 results [Mandatory]
396
+ @options data {Integer} page_limit: This should be a valid number between 1-50 [Mandatory]
397
+ */
398
  public function get_lists( $data ) {
399
  return $this->get( 'list', json_encode( $data ) );
400
  }
401
 
402
  /*
403
+ Get a particular list detail.
404
+ @param {Array} data contains php array with key value pair.
405
+ @options data {Integer} id: Id of list to get details [Mandatory]
406
+ */
407
  public function get_list( $data ) {
408
  return $this->get( 'list/' . $data['id'], '' );
409
  }
410
 
411
  /*
412
+ Create a new list.
413
+ @param {Array} data contains php array with key value pair.
414
+ @options data {String} list_name: Desired name of the list to be created [Mandatory]
415
+ @options data {Integer} list_parent: Folder ID [Mandatory]
416
+ */
417
  public function create_list( $data ) {
418
  return $this->post( 'list', json_encode( $data ) );
419
  }
420
 
421
  /*
422
+ Update a list.
423
+ @param {Array} data contains php array with key value pair.
424
+ @options data {Integer} id: Id of list to be modified [Mandatory]
425
+ @options data {String} list_name: Desired name of the list to be modified [Optional]
426
+ @options data {Integer} list_parent: Folder ID [Mandatory]
427
+ */
428
  public function update_list( $data ) {
429
  $id = $data['id'];
430
  unset( $data['id'] );
432
  }
433
 
434
  /*
435
+ Delete a specific list.
436
+ @param {Array} data contains php array with key value pair.
437
+ @options data {Integer} id: Id of list to be deleted [Mandatory]
438
+ */
439
  public function delete_list( $data ) {
440
  return $this->delete( 'list/' . $data['id'], '' );
441
  }
442
 
443
  /*
444
+ Display details of all users for the given lists.
445
+ @param {Array} data contains php array with key value pair.
446
+ @options data {Array} listids: These are the list ids to get their data. The ids found will display records [Mandatory]
447
+ @options data {String} timestamp: This is date-time filter to fetch modified user records >= this time. Valid format Y-m-d H:i:s. Example: "2015-05-22 14:30:00" [Optional]
448
+ @options data {Integer} page: Maximum number of records per request is 500, if in your list there are more than 500 users then you can use this parameter to get next 500 results [Optional]
449
+ @options data {Integer} page_limit: This should be a valid number between 1-500 [Optional]
450
+ */
451
  public function display_list_users( $data ) {
452
  return $this->post( 'list/display', json_encode( $data ) );
453
  }
454
 
455
  /*
456
+ Add already existing users in the SendinBlue contacts to the list.
457
+ @param {Array} data contains php array with key value pair.
458
+ @options data {Integer} id: Id of list to link users in it [Mandatory]
459
+ @options data {Array} users: Email address of the already existing user(s) in the SendinBlue contacts. Example: "test@example.net". You can use commas to separate multiple users [Mandatory]
460
+ */
461
 
462
  public function add_users_list( $data ) {
463
  $id = $data['id'];
466
  }
467
 
468
  /*
469
+ Delete already existing users in the SendinBlue contacts from the list.
470
+ @param {Array} data contains php array with key value pair.
471
+ @options data {Integer} id: Id of list to unlink users from it [Mandatory]
472
+ @options data {Array} users: Email address of the already existing user(s) in the SendinBlue contacts to be modified. Example: "test@example.net". You can use commas to separate multiple users [Mandatory]
473
+ */
474
  public function delete_users_list( $data ) {
475
  $id = $data['id'];
476
  unset( $data['id'] );
478
  }
479
 
480
  /*
481
+ Access all the attributes information under the account.
482
+ No input required
483
+ */
484
  public function get_attributes() {
485
  return $this->get( 'attribute', '' );
486
  }
487
 
488
  /*
489
+ Access the specific type of attribute information.
490
+ @param {Array} data contains php array with key value pair.
491
+ @options data {String} type: Type of attribute. Possible values – normal, transactional, category, calculated & global [Optional]
492
+ */
493
  public function get_attribute( $data ) {
494
  return $this->get( 'attribute/' . $data['type'], '' );
495
  }
496
 
497
  /*
498
+ Create an Attribute.
499
+ @param {Array} data contains php array with key value pair.
500
+ @options data {String} type: Type of attribute. Possible values – normal, transactional, category, calculated & global ( case sensitive ) [Mandatory]
501
+ @options data {Array} data: The name and data type of ‘normal’ & ‘transactional’ attribute to be created in your SendinBlue account. It should be sent as an associative array. Example: array(‘ATTRIBUTE_NAME1′ => ‘DATA_TYPE1′, ‘ATTRIBUTE_NAME2’=> ‘DATA_TYPE2′).
502
+ The name and data value of ‘category’, ‘calculated’ & ‘global’, should be sent as JSON string. Example: ‘[{ "name":"ATTRIBUTE_NAME1", "value":"Attribute_value1" }, { "name":"ATTRIBUTE_NAME2", "value":"Attribute_value2" }]’. You can use commas to separate multiple attributes [Mandatory]
503
+ */
504
  public function create_attribute( $data ) {
505
  return $this->post( 'attribute/', json_encode( $data ) );
506
  }
507
 
508
  /*
509
+ Delete a specific type of attribute information.
510
+ @param {Array} data contains php array with key value pair.
511
+ @options data {Integer} type: Type of attribute to be deleted [Mandatory]
512
+ */
513
  public function delete_attribute( $type, $data ) {
514
  $type = $data['type'];
515
  unset( $data['type'] );
517
  }
518
 
519
  /*
520
+ Create a new user if an email provided as input, doesn’t exists in the contact list of your SendinBlue account, otherwise it will update the existing user.
521
+ @param {Array} data contains php array with key value pair.
522
+ @options data {String} email: Email address of the user to be created in SendinBlue contacts. Already existing email address of user in the SendinBlue contacts to be modified [Mandatory]
523
+ @options data {Array} attributes: The name of attribute present in your SendinBlue account. It should be sent as an associative array. Example: array("NAME"=>"name"). You can use commas to separate multiple attributes [Optional]
524
+ @options data {Integer} blacklisted: This is used to blacklist/ Unblacklist a user. Possible values – 0 & 1. blacklisted = 1 means user has been blacklisted [Optional]
525
+ @options data {Array} listid: The list id(s) to be linked from user [Optional]
526
+ @options data {Array} listid_unlink: The list id(s) to be unlinked from user [Optional]
527
+ @options data {Array} blacklisted_sms: This is used to blacklist/ Unblacklist a user’s SMS number. Possible values – 0 & 1. blacklisted_sms = 1 means user’s SMS number has been blacklisted [Optional]
528
+ */
529
  public function create_update_user( $data ) {
530
  return $this->post( 'user/createdituser', json_encode( $data ) );
531
  }
532
 
533
  /*
534
+ Get Access a specific user Information.
535
+ @param {Array} data contains php array with key value pair.
536
+ @options data {String} email: Email address of the already existing user in the SendinBlue contacts [Mandatory]
537
+ */
538
  public function get_user( $data ) {
539
  return $this->get( 'user/' . $data['email'], '' );
540
  }
541
 
542
  /*
543
+ Unlink existing user from all lists.
544
+ @param {Array} data contains php array with key value pair.
545
+ @options data {String} email: Email address of the already existing user in the SendinBlue contacts to be unlinked from all lists [Mandatory]
546
+ */
547
  public function delete_user( $data ) {
548
  return $this->delete( 'user/' . $data['email'], '' );
549
  }
550
 
551
  /*
552
+ Import Users Information.
553
+ @param {Array} data contains php array with key value pair.
554
+ @options data {String} url: The URL of the file to be imported. Possible file types – .txt, .csv [Mandatory: if body is empty]
555
+ @options data {String} body: The Body with csv content to be imported. Example: ‘NAME;SURNAME;EMAIL\n"Name1";"Surname1";"example1@example.net"\n"Name2";"Surname2";"example2@example.net"‘, where \n separates each user data. You can use semicolon to separate multiple attributes [Mandatory: if url is empty]
556
+ @options data {Array} listids: These are the list ids in which the the users will be imported [Mandatory: if name is empty]
557
+ @options data {String} notify_url: URL that will be called once the import process is finished [Optional] In notify_url, we are sending the content using POST method
558
+ @options data {String} name: This is new list name which will be created first & then users will be imported in it [Mandatory: if listids is empty]
559
+ @options data {Integer} list_parent: This is the existing folder id & can be used with name parameter to make newly created list’s desired parent [Optional]
560
+ */
561
  public function import_users( $data ) {
562
  return $this->post( 'user/import', json_encode( $data ) );
563
  }
564
 
565
  /*
566
+ Export Users Information.
567
+ @param {Array} data contains php array with key value pair.
568
+ @options data {String} export_attrib: The name of attribute present in your SendinBlue account. You can use commas to separate multiple attributes. Example: "EMAIL,NAME,SMS" [Optional]
569
+ @options data {String} filter: Filter can be added to export users. Example: "{\"blacklisted\":1}", will export all blacklisted users [Mandatory]
570
+ @options data {String} notify_url: URL that will be called once the export process is finished [Optional]
571
+ */
572
  public function export_users( $data ) {
573
  return $this->post( 'user/export', json_encode( $data ) );
574
  }
575
 
576
  /*
577
+ Get all the processes information under the account.
578
+ @param {Array} data contains php array with key value pair.
579
+ @options data {Integer} page: Maximum number of records per request is 50, if there are more than 50 processes then you can use this parameter to get next 50 results [Mandatory]
580
+ @options data {Integer} page_limit: This should be a valid number between 1-50 [Mandatory]
581
+ */
582
  public function get_processes( $data ) {
583
  return $this->get( 'process', json_encode( $data ) );
584
  }
585
 
586
  /*
587
+ Get the process information.
588
+ @param {Array} data contains php array with key value pair.
589
+ @options data {Integer} id: Id of process to get details [Mandatory]
590
+ */
591
  public function get_process( $data ) {
592
  return $this->get( 'process/' . $data['id'], '' );
593
  }
594
 
595
  /*
596
+ To retrieve details of all webhooks.
597
+ @param {Array} data contains php array with key value pair.
598
+ @options data {String} is_plat: Flag to get webhooks. Possible values – 0 & 1. Example: to get Transactional webhooks, use $is_plat=0, to get Marketing webhooks, use $is_plat=1, & to get all webhooks, use $is_plat="" [Optional]
599
+ */
600
  public function get_webhooks( $data ) {
601
  return $this->get( 'webhook', json_encode( $data ) );
602
  }
603
 
604
  /*
605
+ To retrieve details of any particular webhook.
606
+ @param {Array} data contains php array with key value pair.
607
+ @options data {Integer} id: Id of webhook to get details [Mandatory]
608
+ */
609
  public function get_webhook( $data ) {
610
  return $this->get( 'webhook/' . $data['id'], '' );
611
  }
612
 
613
  /*
614
+ Create a Webhook.
615
+ @param {Array} data contains php array with key value pair.
616
+ @options data {String} url: URL that will be triggered by a webhook [Mandatory]
617
+ @options data {String} description: Webook description [Optional]
618
+ @options data {Array} events: Set of events. You can use commas to separate multiple events. Possible values for Transcational webhook – request, delivered, hard_bounce, soft_bounce, blocked, spam, invalid_email, deferred, click, & opened and Possible Values for Marketing webhook – spam, opened, click, hard_bounce, unsubscribe, soft_bounce & list_addition ( case sensitive ) [Mandatory]
619
+ @options data {Integer} is_plat: Flag to create webhook type. Possible values – 0 (default) & 1. Example: to create Transactional webhooks, use $is_plat=0, & to create Marketing webhooks, use $is_plat=1 [Optional]
620
+ */
621
  public function create_webhook( $data ) {
622
  return $this->post( 'webhook', json_encode( $data ) );
623
  }
624
 
625
  /*
626
+ Delete a webhook.
627
+ @param {Array} data contains php array with key value pair.
628
+ @options data {Integer} id: Id of webhook to be deleted [Mandatory]
629
+ */
630
  public function delete_webhook( $data ) {
631
  return $this->delete( 'webhook/' . $data['id'], '' );
632
  }
633
 
634
  /*
635
+ Update a webhook.
636
+ @param {Array} data contains php array with key value pair.
637
+ @options data {Integer} id: Id of webhook to be modified [Mandatory]
638
+ @options data {String} url: URL that will be triggered by a webhook [Mandatory]
639
+ @options data {String} description: Webook description [Optional]
640
+ @options data {Array} events: Set of events. You can use commas to separate multiple events. Possible values for Transcational webhook – request, delivered, hard_bounce, soft_bounce, blocked, spam, invalid_email, deferred, click, & opened and Possible Values for Marketing webhook – spam, opened, click, hard_bounce, unsubscribe, soft_bounce & list_addition ( case sensitive ) [Mandatory]
641
+ */
642
  public function update_webhook( $data ) {
643
  $id = $data['id'];
644
  unset( $data['id'] );
646
  }
647
 
648
  /*
649
+ Get Access of created senders information.
650
+ @param {Array} data contains php array with key value pair.
651
+ @options data {String} option: Options to get senders. Possible options – IP-wise, & Domain-wise ( only for dedicated IP clients ). Example: to get senders with specific IP, use $option=’1.2.3.4′, to get senders with specific domain use, $option=’domain.com’, & to get all senders, use $option="" [Optional]
652
+ */
653
  public function get_senders( $data ) {
654
  return $this->get( 'advanced', json_encode( $data ) );
655
  }
656
 
657
  /*
658
+ Create your Senders.
659
+ @param {Array} data contains php array with key value pair.
660
+ @options data {String} name: Name of the sender [Mandatory]
661
+ @options data {String} email: Email address of the sender [Mandatory]
662
+ @options data {Array} ip_domain: Pass pipe ( | ) separated Dedicated IP and its associated Domain. Example: "1.2.3.4|mydomain.com". You can use commas to separate multiple ip_domain’s [Mandatory: Only for Dedicated IP clients, for Shared IP clients, it should be kept blank]
663
+ */
664
  public function create_sender( $data ) {
665
  return $this->post( 'advanced', json_encode( $data ) );
666
  }
667
 
668
  /*
669
+ Update your Senders.
670
+ @param {Array} data contains php array with key value pair.
671
+ @options data {Integer} id: Id of sender to be modified [Mandatory]
672
+ @options data {String} name: Name of the sender [Mandatory]
673
+ @options data {Array} ip_domain: Pass pipe ( | ) separated Dedicated IP and its associated Domain. Example: "1.2.3.4|mydomain.com". You can use commas to separate multiple ip_domain’s [Mandatory: Only for Dedicated IP clients, for Shared IP clients, it should be kept blank]
674
+ */
675
  public function update_sender( $data ) {
676
  $id = $data['id'];
677
  unset( $data['id'] );
679
  }
680
 
681
  /*
682
+ Delete your Sender Information.
683
+ @param {Array} data contains php array with key value pair.
684
+ @options data {Integer} id: Id of sender to be deleted [Mandatory]
685
+ */
686
  public function delete_sender( $data ) {
687
  return $this->delete( 'advanced/' . $data['id'], '' );
688
  }
689
 
690
  /*
691
+ Send Transactional Email.
692
+ @param {Array} data contains php array with key value pair.
693
+ @options data {Array} to: Email address of the recipient(s). It should be sent as an associative array. Example: array("to@example.net"=>"to whom"). You can use commas to separate multiple recipients [Mandatory]
694
+ @options data {String} subject: Message subject [Mandatory]
695
+ @options data {Array} from Email address for From header. It should be sent as an array. Example: array("from@email.com","from email") [Mandatory]
696
+ @options data {String} html: Body of the message. (HTML version) [Mandatory]. To send inline images, use <img src="{YourFileName.Extension}" alt="image" border="0" >, the 'src' attribute value inside {} (curly braces) should be same as the filename used in 'inline_image' parameter
697
+ @options data {String} text: Body of the message. (text version) [Optional]
698
+ @options data {Array} cc: Same as to but for Cc. Example: array("cc@example.net","cc whom") [Optional]
699
+ @options data {Array} bcc: Same as to but for Bcc. Example: array("bcc@example.net","bcc whom") [Optional]
700
+ @options data {Array} replyto: Same as from but for Reply To. Example: array("from@email.com","from email") [Optional]
701
+ @options data {Array} attachment: Provide the absolute url of the attachment/s. Possible extension values = gif, png, bmp, cgm, jpg, jpeg, txt, css, shtml, html, htm, csv, zip, pdf, xml, doc, xls, ppt, tar, and ez. To send attachment/s generated on the fly you have to pass your attachment/s filename & its base64 encoded chunk data as an associative array. Example: array("YourFileName.Extension"=>"Base64EncodedChunkData"). You can use commas to separate multiple attachments [Optional]
702
+ @options data {Array} headers: The headers will be sent along with the mail headers in original email. Example: array("Content-Type"=>"text/html; charset=iso-8859-1"). You can use commas to separate multiple headers [Optional]
703
+ @options data {Array} inline_image: Pass your inline image/s filename & its base64 encoded chunk data as an associative array. Example: array("YourFileName.Extension"=>"Base64EncodedChunkData"). You can use commas to separate multiple inline images [Optional]
704
+ */
705
  public function send_email( $data ) {
706
  return $this->post( 'email', json_encode( $data ) );
707
  }
708
 
709
  /*
710
+ Aggregate / date-wise report of the SendinBlue SMTP account.
711
+ @param {Array} data contains php array with key value pair.
712
+ @options data {Integer} aggregate: This is used to indicate, you are interested in all-time totals. Possible values – 0 & 1. aggregate = 0 means it will not aggregate records, and will show stats per day/date wise [Optional]
713
+ @options data {String} start_date: The start date to look up statistics. Date must be in YYYY-MM-DD format and should be before the end_date [Optional]
714
+ @options data {String} end_date: The end date to look up statistics. Date must be in YYYY-MM-DD format and should be after the start_date [Optional]
715
+ @options data {Integer} days: Number of days in the past to include statistics ( Includes today ). It must be an integer greater than 0 [Optional]
716
+ @options data {String} tag: The tag you will specify to retrieve detailed stats. It must be an existing tag that has statistics [Optional]
717
+ */
718
  public function get_statistics( $data ) {
719
  return $this->post( 'statistics', json_encode( $data ) );
720
  }
721
 
722
  /*
723
+ Get Email Event report.
724
+ @param {Array} data contains php array with key value pair.
725
+ @options data {Integer} limit: To limit the number of results returned. It should be an integer [Optional]
726
+ @options data {String} start_date: The start date to get report from. Date must be in YYYY-MM-DD format and should be before the end_date [Optional]
727
+ @options data {String} end_date: The end date to get report till date. Date must be in YYYY-MM-DD format and should be after the start_date [Optional]
728
+ @options data {Integer} offset: Beginning point in the list to retrieve from. It should be an integer [Optional]
729
+ @options data {String} date: Specific date to get its report. Date must be in YYYY-MM-DD format and should be earlier than todays date [Optional]
730
+ @options data {Integer} days: Number of days in the past (includes today). If specified, must be an integer greater than 0 [Optional]
731
+ @options data {String} email: Email address to search report for [Optional]
732
+ */
733
  public function get_report( $data ) {
734
  return $this->post( 'report', json_encode( $data ) );
735
  }
736
 
737
  /*
738
+ Delete any hardbounce, which actually would have been blocked due to some temporary ISP failures.
739
+ @param {Array} data contains php array with key value pair.
740
+ @options data {String} start_date: The start date to get report from. Date must be in YYYY-MM-DD format and should be before the end_date [Optional]
741
+ @options data {String} end_date: The end date to get report till date. Date must be in YYYY-MM-DD format and should be after the start_date [Optional]
742
+ @options data {String} email: Email address to delete its bounces [Optional]
743
+ */
744
  public function delete_bounces( $data ) {
745
  return $this->post( 'bounces', json_encode( $data ) );
746
  }
747
 
748
  /*
749
+ Send templates created on SendinBlue, through SendinBlue SMTP (transactional mails).
750
+ @param {Array} data contains php array with key value pair.
751
+ @options data {Integer} id: Id of the template created on SendinBlue account [Mandatory]
752
+ @options data {String} to: Email address of the recipient(s). You can use pipe ( | ) to separate multiple recipients. Example: "to-example@example.net|to2-example@example.net" [Mandatory]
753
+ @options data {String} cc: Same as to but for Cc [Optional]
754
+ @options data {String} bcc: Same as to but for Bcc [Optional]
755
+ @options data {Array} attrv The name of attribute present in your SendinBlue account. It should be sent as an associative array. Example: array("NAME"=>"name"). You can use commas to separate multiple attributes [Optional]
756
+ @options data {String} attachment_url: Provide the absolute url of the attachment. Url not allowed from local machine. File must be hosted somewhere [Optional]
757
+ @options data {Array} attachment: To send attachment/s generated on the fly you have to pass your attachment/s filename & its base64 encoded chunk data as an associative array [Optional]
758
+ */
759
  public function send_transactional_template( $data ) {
760
  $id = $data['id'];
761
  unset( $data['id'] );
763
  }
764
 
765
  /*
766
+ Create a Template.
767
+ @param {Array} data contains php array with key value pair.
768
+ @options data {String} from_name: Sender name from which the campaign emails are sent [Mandatory: for Dedicated IP clients & for Shared IP clients, if sender exists]
769
+ @options data {String} template_name: Name of the Template [Mandatory]
770
+ @options data {String} bat: Email address for test mail [Optional]
771
+ @options data {String} html_content: Body of the content. The HTML content field must have more than 10 characters [Mandatory: if html_url is empty]
772
+ @options data {String} html_url Url: which content is the body of content [Mandatory: if html_content is empty]
773
+ @options data {String} subject: Subject of the campaign [Mandatory]
774
+ @options data {String} from_email: Sender email from which the campaign emails are sent [Mandatory: for Dedicated IP clients & for Shared IP clients, if sender exists]
775
+ @options data {String} reply_to: The reply to email in the campaign emails [Optional]
776
+ @options data {String} to_fieldv This is to personalize the «To» Field. If you want to include the first name and last name of your recipient, add [PRENOM] [NOM]. To use the contact attributes here, these should already exist in SendinBlue account [Optional]
777
+ @options data {Integer} status: Status of template. Possible values = 0 (default) & 1. status = 0 means template is inactive, & status = 1 means template is active [Optional]
778
+ @options data {Integer} attachment: Status of attachment. Possible values = 0 (default) & 1. attach = 0 means an attachment can’t be sent, & attach = 1 means an attachment can be sent, in the email [Optional]
779
+ */
780
  public function create_template( $data ) {
781
  return $this->post( 'template', json_encode( $data ) );
782
  }
783
 
784
  /*
785
+ Update a Template.
786
+ @param {Array} data contains php array with key value pair.
787
+ @options data {Integer} id: Id of Template to be modified [Mandatory]
788
+ @options data {String} from_name: Sender name from which the campaign emails are sent [Mandatory: for Dedicated IP clients & for Shared IP clients, if sender exists]
789
+ @options data {String} template_name: Name of the Template [Mandatory]
790
+ @options data {String} bat: Email address for test mail [Optional]
791
+ @options data {String} html_content: Body of the content. The HTML content field must have more than 10 characters [Mandatory: if html_url is empty]
792
+ @options data {String} html_url: Url which content is the body of content [Mandatory: if html_content is empty]
793
+ @options data {String} subject: Subject of the campaign [Mandatory]
794
+ @options data {String} from_email: Sender email from which the campaign emails are sent [Mandatory: for Dedicated IP clients & for Shared IP clients, if sender exists]
795
+ @options data {String} reply_to: The reply to email in the campaign emails [Optional]
796
+ @options data {String} to_field: This is to personalize the «To» Field. If you want to include the first name and last name of your recipient, add [PRENOM] [NOM]. To use the contact attributes here, these should already exist in SendinBlue account [Optional]
797
+ @options data {Integer} status: Status of template. Possible values = 0 (default) & 1. status = 0 means template is inactive, & status = 1 means template is active [Optional]
798
+ @options data {Integer} attachment: Status of attachment. Possible values = 0 (default) & 1. attach = 0 means an attachment can’t be sent, & attach = 1 means an attachment can be sent, in the email [Optional]
799
+ */
800
  public function update_template( $data ) {
801
  $id = $data['id'];
802
  unset( $data['id'] );
804
  }
805
 
806
  /*
807
+ Send a transactional SMS.
808
+ @param {Array} data contains php array with key value pair.
809
+ @options data {String} to: The mobile number to send SMS to with country code [Mandatory]
810
+ @options data {String} from: The name of the sender. The number of characters is limited to 11 (alphanumeric format) [Mandatory]
811
+ @options data {String} text: The text of the message. The maximum characters used per SMS is 160, if used more than that, it will be counted as more than one SMS [Mandatory]
812
+ @options data {String} web_url: The web URL that can be called once the message is successfully delivered [Optional]
813
+ @options data {String} tag: The tag that you can associate with the message [Optional]
814
+ @options data {String} type: Type of message. Possible values – marketing (default) & transactional. You can use marketing for sending marketing SMS, & for sending transactional SMS, use transactional type [Optional]
815
+ */
816
  public function send_sms( $data ) {
817
  return $this->post( 'sms', json_encode( $data ) );
818
  }
819
 
820
  /*
821
+ Create & Schedule your SMS campaigns.
822
+ @param {Array} data contains php array with key value pair.
823
+ @options data {String} name: Name of the SMS campaign [Mandatory]
824
+ @options data {String} sender: This allows you to customize the SMS sender. The number of characters is limited to 11 ( alphanumeric format ) [Optional]
825
+ @options data {String} content: Content of the message. The maximum characters used per SMS is 160, if used more than that, it will be counted as more than one SMS [Optional]
826
+ @options data {String} bat: Mobile number with the country code to send test SMS. The mobile number defined here should belong to one of your contacts in SendinBlue account and should not be blacklisted [Optional]
827
+ @options data {Array} listid: These are the list ids to which the SMS campaign is sent [Mandatory: if scheduled_date is not empty]
828
+ @options data {Array} exclude_list: These are the list ids which will be excluded from the SMS campaign [Optional]
829
+ @options data {String} scheduled_date: The day on which the SMS campaign is supposed to run [Optional]
830
+ @options data {Integer} send_now: Flag to send campaign now. Possible values = 0 (default) & 1. send_now = 0 means campaign can’t be send now, & send_now = 1 means campaign ready to send now [Optional]
831
+ */
832
  public function create_sms_campaign( $data ) {
833
  return $this->post( 'sms', json_encode( $data ) );
834
  }
835
 
836
  /*
837
+ Update your SMS campaigns.
838
+ @param {Array} data contains php array with key value pair.
839
+ @options data {Integer} id: Id of the SMS campaign [Mandatory]
840
+ @options data {String} name: Name of the SMS campaign [Optional]
841
+ @options data {String} sender: This allows you to customize the SMS sender. The number of characters is limited to 11 ( alphanumeric format ) [Optional]
842
+ @options data {String} content: Content of the message. The maximum characters used per SMS is 160, if used more than that, it will be counted as more than one SMS [Optional]
843
+ @options data {String} bat: Mobile number with the country code to send test SMS. The mobile number defined here should belong to one of your contacts in SendinBlue account and should not be blacklisted [Optional]
844
+ @options data {Array} listid: hese are the list ids to which the SMS campaign is sent [Mandatory: if scheduled_date is not empty]
845
+ @options data {Array} exclude_list: These are the list ids which will be excluded from the SMS campaign [Optional]
846
+ @options data {String} scheduled_date: The day on which the SMS campaign is supposed to run [Optional]
847
+ @options data {Integer} send_now: Flag to send campaign now. Possible values = 0 (default) & 1. send_now = 0 means campaign can’t be send now, & send_now = 1 means campaign ready to send now [Optional]
848
+ */
849
  public function update_sms_campaign( $data ) {
850
  $id = $data['id'];
851
  unset( $data['id'] );
853
  }
854
 
855
  /*
856
+ Send a Test SMS.
857
+ @param {Array} data contains php array with key value pair.
858
+ @options data {Integer} id: Id of the SMS campaign [Mandatory]
859
+ @options data {String} to: Mobile number with the country code to send test SMS. The mobile number defined here should belong to one of your contacts in SendinBlue account and should not be blacklisted [Mandatory]
860
+ */
861
  public function send_bat_sms( $data ) {
862
  $id = $data['id'];
863
  unset( $data['id'] );
menu-icons.php CHANGED
@@ -11,7 +11,7 @@
11
  * Plugin name: Menu Icons
12
  * Plugin URI: https://github.com/Codeinwp/wp-menu-icons
13
  * Description: Spice up your navigation menus with pretty icons, easily.
14
- * Version: 0.11.4
15
  * Author: ThemeIsle
16
  * Author URI: https://themeisle.com
17
  * License: GPLv2
@@ -27,7 +27,7 @@
27
  */
28
  final class Menu_Icons {
29
 
30
- const VERSION = '0.11.4';
31
 
32
  /**
33
  * Holds plugin data
@@ -176,4 +176,4 @@ function kucrut_register_sdk( $products ) {
176
 
177
  $products[] = __FILE__;
178
  return $products;
179
- }
11
  * Plugin name: Menu Icons
12
  * Plugin URI: https://github.com/Codeinwp/wp-menu-icons
13
  * Description: Spice up your navigation menus with pretty icons, easily.
14
+ * Version: 0.11.5
15
  * Author: ThemeIsle
16
  * Author URI: https://themeisle.com
17
  * License: GPLv2
27
  */
28
  final class Menu_Icons {
29
 
30
+ const VERSION = '0.11.5';
31
 
32
  /**
33
  * Holds plugin data
176
 
177
  $products[] = __FILE__;
178
  return $products;
179
+ }
readme.md CHANGED
@@ -224,6 +224,11 @@ Add this block of code to your [mu-plugin file](http://codex.wordpress.org/Must_
224
  Read [this blog post](http://kucrut.org/add-custom-image-sizes-right-way/).
225
 
226
  ## Changelog ##
 
 
 
 
 
227
  ### 0.11.4 - 2018-12-10 ###
228
 
229
  * fix issue with composer libraries.
224
  Read [this blog post](http://kucrut.org/add-custom-image-sizes-right-way/).
225
 
226
  ## Changelog ##
227
+ ### 0.11.5 - 2019-05-23 ###
228
+
229
+ * Sync composer dependencies with the latest version
230
+
231
+
232
  ### 0.11.4 - 2018-12-10 ###
233
 
234
  * fix issue with composer libraries.
readme.txt CHANGED
@@ -224,6 +224,11 @@ add_filter( 'menu_icons_menu_settings', 'my_menu_icons_menu_settings', 10, 2 );
224
  Read [this blog post](http://kucrut.org/add-custom-image-sizes-right-way/).
225
 
226
  == Changelog ==
 
 
 
 
 
227
  = 0.11.4 - 2018-12-10 =
228
 
229
  * fix issue with composer libraries.
224
  Read [this blog post](http://kucrut.org/add-custom-image-sizes-right-way/).
225
 
226
  == Changelog ==
227
+ = 0.11.5 - 2019-05-23 =
228
+
229
+ * Sync composer dependencies with the latest version
230
+
231
+
232
  = 0.11.4 - 2018-12-10 =
233
 
234
  * fix issue with composer libraries.
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit13eb48706f29258ff3a0d5c6cbadd39c::getLoader();
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInited3d108ddbcd41f318ae3324c5a3c8ce::getLoader();
vendor/codeinwp/icon-picker/assets/screenshot-1.png ADDED
Binary file
vendor/codeinwp/icon-picker/assets/screenshot-2.png ADDED
Binary file
vendor/codeinwp/icon-picker/js/src/icon-picker.js ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ require( './media/manifest' );
2
+
3
+ ( function( $ ) {
4
+ var l10n = wp.media.view.l10n.iconPicker,
5
+ templates = {},
6
+ frame, selectIcon, removeIcon, getFrame, updateField, updatePreview, $field;
7
+
8
+ getFrame = function() {
9
+ if ( ! frame ) {
10
+ frame = new wp.media.view.MediaFrame.IconPicker();
11
+
12
+ frame.target.on( 'change', updateField );
13
+ }
14
+
15
+ return frame;
16
+ };
17
+
18
+ updateField = function( model ) {
19
+ _.each( model.get( 'inputs' ), function( $input, key ) {
20
+ $input.val( model.get( key ) );
21
+ });
22
+
23
+ model.clear({ silent: true });
24
+ $field.trigger( 'ipf:update' );
25
+ };
26
+
27
+ updatePreview = function( e ) {
28
+ var $el = $( e.currentTarget ),
29
+ $select = $el.find( 'a.ipf-select' ),
30
+ $remove = $el.find( 'a.ipf-remove' ),
31
+ type = $el.find( 'input.ipf-type' ).val(),
32
+ icon = $el.find( 'input.ipf-icon' ).val(),
33
+ url = $el.find( 'input.url' ).val(),
34
+ template;
35
+
36
+ if ( type === '' || icon === '' || ! _.has( iconPicker.types, type ) ) {
37
+ $remove.addClass( 'hidden' );
38
+ $select
39
+ .removeClass( 'has-icon' )
40
+ .addClass( 'button' )
41
+ .text( l10n.selectIcon )
42
+ .attr( 'title', '' );
43
+
44
+ return;
45
+ }
46
+
47
+ if ( templates[ type ]) {
48
+ template = templates[ type ];
49
+ } else {
50
+ template = templates[ type ] = wp.template( 'iconpicker-' + iconPicker.types[ type ].templateId + '-icon' );
51
+ }
52
+
53
+ $remove.removeClass( 'hidden' );
54
+ $select
55
+ .attr( 'title', l10n.selectIcon )
56
+ .addClass( 'has-icon' )
57
+ .removeClass( 'button' )
58
+ .html( template({
59
+ type: type,
60
+ icon: icon,
61
+ url: url
62
+ }) );
63
+ };
64
+
65
+ selectIcon = function( e ) {
66
+ var frame = getFrame(),
67
+ model = { inputs: {} };
68
+
69
+ e.preventDefault();
70
+
71
+ $field = $( e.currentTarget ).closest( '.ipf' );
72
+ model.id = $field.attr( 'id' );
73
+
74
+ // Collect input fields and use them as the model's attributes.
75
+ $field.find( 'input' ).each( function() {
76
+ var $input = $( this ),
77
+ key = $input.attr( 'class' ).replace( 'ipf-', '' ),
78
+ value = $input.val();
79
+
80
+ model[ key ] = value;
81
+ model.inputs[ key ] = $input;
82
+ });
83
+
84
+ frame.target.set( model, { silent: true });
85
+ frame.open();
86
+ };
87
+
88
+ removeIcon = function( e ) {
89
+ var $el = $( e.currentTarget ).closest( 'div.ipf' );
90
+
91
+ $el.find( 'input' ).val( '' );
92
+ $el.trigger( 'ipf:update' );
93
+ };
94
+
95
+ $( document )
96
+ .on( 'click', 'a.ipf-select', selectIcon )
97
+ .on( 'click', 'a.ipf-remove', removeIcon )
98
+ .on( 'ipf:update', 'div.ipf', updatePreview );
99
+
100
+ $( 'div.ipf' ).trigger( 'ipf:update' );
101
+ }( jQuery ) );
vendor/codeinwp/icon-picker/js/src/media/controllers/font.js ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * wp.media.controller.IconPickerFont
3
+ *
4
+ * @class
5
+ * @augments wp.media.controller.State
6
+ * @augments Backbone.Model
7
+ * @mixes wp.media.controller.iconPickerMixin
8
+ */
9
+ var IconPickerFont = wp.media.controller.State.extend( _.extend({}, wp.media.controller.iconPickerMixin, {
10
+ defaults: {
11
+ multiple: false,
12
+ menu: 'default',
13
+ toolbar: 'select',
14
+ baseType: 'font'
15
+ },
16
+
17
+ initialize: function() {
18
+ var data = this.get( 'data' );
19
+
20
+ this.set( 'groups', new Backbone.Collection( data.groups ) );
21
+ this.set( 'library', new wp.media.model.IconPickerFonts( data.items ) );
22
+ this.set( 'selection', new wp.media.model.Selection( null, {
23
+ multiple: this.get( 'multiple' )
24
+ }) );
25
+ },
26
+
27
+ activate: function() {
28
+ this.frame.on( 'open', this.updateSelection, this );
29
+ this.resetFilter();
30
+ this.updateSelection();
31
+ },
32
+
33
+ deactivate: function() {
34
+ this.frame.off( 'open', this.updateSelection, this );
35
+ },
36
+
37
+ resetFilter: function() {
38
+ this.get( 'library' ).props.set( 'group', 'all' );
39
+ },
40
+
41
+ updateSelection: function() {
42
+ var selection = this.get( 'selection' ),
43
+ library = this.get( 'library' ),
44
+ target = this.frame.target,
45
+ icon = target.get( 'icon' ),
46
+ type = target.get( 'type' ),
47
+ selected;
48
+
49
+ if ( this.id === type ) {
50
+ selected = library.findWhere({ id: icon });
51
+ }
52
+
53
+ selection.reset( selected ? selected : null );
54
+ },
55
+
56
+ getContentView: function() {
57
+ return new wp.media.view.IconPickerFontBrowser( _.extend({
58
+ controller: this.frame,
59
+ model: this,
60
+ groups: this.get( 'groups' ),
61
+ collection: this.get( 'library' ),
62
+ selection: this.get( 'selection' ),
63
+ baseType: this.get( 'baseType' ),
64
+ type: this.get( 'id' )
65
+ }, this.ipGetSidebarOptions() ) );
66
+ }
67
+ }) );
68
+
69
+ module.exports = IconPickerFont;
vendor/codeinwp/icon-picker/js/src/media/controllers/img.js ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var Library = wp.media.controller.Library,
2
+ l10n = wp.media.view.l10n,
3
+ models = wp.media.model,
4
+ views = wp.media.view,
5
+ IconPickerImg;
6
+
7
+ /**
8
+ * wp.media.controller.IconPickerImg
9
+ *
10
+ * @augments wp.media.controller.Library
11
+ * @augments wp.media.controller.State
12
+ * @augments Backbone.Model
13
+ * @mixes media.selectionSync
14
+ * @mixes wp.media.controller.iconPickerMixin
15
+ */
16
+ IconPickerImg = Library.extend( _.extend({}, wp.media.controller.iconPickerMixin, {
17
+ defaults: _.defaults({
18
+ id: 'image',
19
+ baseType: 'image',
20
+ syncSelection: false
21
+ }, Library.prototype.defaults ),
22
+
23
+ initialize: function( options ) {
24
+ var selection = this.get( 'selection' );
25
+
26
+ this.options = options;
27
+
28
+ this.set( 'library', wp.media.query({ type: options.data.mimeTypes }) );
29
+
30
+ this.routers = {
31
+ upload: {
32
+ text: l10n.uploadFilesTitle,
33
+ priority: 20
34
+ },
35
+ browse: {
36
+ text: l10n.mediaLibraryTitle,
37
+ priority: 40
38
+ }
39
+ };
40
+
41
+ if ( ! ( selection instanceof models.Selection ) ) {
42
+ this.set( 'selection', new models.Selection( selection, {
43
+ multiple: false
44
+ }) );
45
+ }
46
+
47
+ Library.prototype.initialize.apply( this, arguments );
48
+ },
49
+
50
+ activate: function() {
51
+ Library.prototype.activate.apply( this, arguments );
52
+ this.get( 'library' ).observe( wp.Uploader.queue );
53
+ this.frame.on( 'open', this.updateSelection, this );
54
+ this.updateSelection();
55
+ },
56
+
57
+ deactivate: function() {
58
+ Library.prototype.deactivate.apply( this, arguments );
59
+ this.get( 'library' ).unobserve( wp.Uploader.queue );
60
+ this.frame.off( 'open', this.updateSelection, this );
61
+ },
62
+
63
+ getContentView: function( mode ) {
64
+ var content = ( mode === 'upload' ) ? this.uploadContent() : this.browseContent();
65
+
66
+ this.frame.$el.removeClass( 'hide-toolbar' );
67
+
68
+ return content;
69
+ },
70
+
71
+ /**
72
+ * Media library content
73
+ *
74
+ * @returns {wp.media.view.IconPickerImgBrowser} "Browse" content view.
75
+ */
76
+ browseContent: function() {
77
+ var options = _.extend({
78
+ model: this,
79
+ controller: this.frame,
80
+ collection: this.get( 'library' ),
81
+ selection: this.get( 'selection' ),
82
+ sortable: this.get( 'sortable' ),
83
+ search: this.get( 'searchable' ),
84
+ filters: this.get( 'filterable' ),
85
+ dragInfo: this.get( 'dragInfo' ),
86
+ idealColumnWidth: this.get( 'idealColumnWidth' ),
87
+ suggestedWidth: this.get( 'suggestedWidth' ),
88
+ suggestedHeight: this.get( 'suggestedHeight' )
89
+ }, this.ipGetSidebarOptions() );
90
+
91
+ if ( this.id === 'svg' ) {
92
+ options.AttachmentView = views.IconPickerSvgItem;
93
+ }
94
+
95
+ return new views.IconPickerImgBrowser( options );
96
+ },
97
+
98
+ /**
99
+ * Render callback for the content region in the `upload` mode.
100
+ *
101
+ * @returns {wp.media.view.UploaderInline} "Upload" content view.
102
+ */
103
+ uploadContent: function() {
104
+ return new wp.media.view.UploaderInline({
105
+ controller: this.frame
106
+ });
107
+ },
108
+
109
+ updateSelection: function() {
110
+ var selection = this.get( 'selection' ),
111
+ target = this.frame.target,
112
+ icon = target.get( 'icon' ),
113
+ type = target.get( 'type' ),
114
+ selected;
115
+
116
+ if ( this.id === type ) {
117
+ selected = models.Attachment.get( icon );
118
+ this.dfd = selected.fetch();
119
+ }
120
+
121
+ selection.reset( selected ? selected : null );
122
+ },
123
+
124
+ /**
125
+ * Get image icon URL
126
+ *
127
+ * @param {object} model - Selected icon model.
128
+ * @param {string} size - Image size.
129
+ *
130
+ * @returns {string} Icon URL.
131
+ */
132
+ ipGetIconUrl: function( model, size ) {
133
+ var url = model.get( 'url' ),
134
+ sizes = model.get( 'sizes' );
135
+
136
+ if ( undefined === size ) {
137
+ size = 'thumbnail';
138
+ }
139
+
140
+ if ( sizes && sizes[ size ]) {
141
+ url = sizes[ size ].url;
142
+ }
143
+
144
+ return url;
145
+ }
146
+ }) );
147
+
148
+ module.exports = IconPickerImg;
vendor/codeinwp/icon-picker/js/src/media/controllers/mixin.js ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Methods for the state
3
+ *
4
+ * @mixin
5
+ */
6
+ var iconPickerMixin = {
7
+
8
+ /**
9
+ * @returns {object}
10
+ */
11
+ ipGetSidebarOptions: function() {
12
+ var frameOptions = this.frame.options,
13
+ options = {};
14
+
15
+ if ( frameOptions.SidebarView && frameOptions.SidebarView.prototype instanceof wp.media.view.IconPickerSidebar ) {
16
+ options.sidebar = true;
17
+ options.SidebarView = frameOptions.SidebarView;
18
+ } else {
19
+ options.sidebar = false;
20
+ }
21
+
22
+ return options;
23
+ },
24
+
25
+ /**
26
+ * Get image icon URL
27
+ *
28
+ * @returns {string}
29
+ */
30
+ ipGetIconUrl: function() {
31
+ return '';
32
+ }
33
+ };
34
+
35
+ module.exports = iconPickerMixin;
vendor/codeinwp/icon-picker/js/src/media/manifest.js ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ wp.media.model.IconPickerTarget = require( './models/target.js' );
2
+ wp.media.model.IconPickerFonts = require( './models/fonts.js' );
3
+
4
+ wp.media.controller.iconPickerMixin = require( './controllers/mixin.js' );
5
+ wp.media.controller.IconPickerFont = require( './controllers/font.js' );
6
+ wp.media.controller.IconPickerImg = require( './controllers/img.js' );
7
+
8
+ wp.media.view.IconPickerBrowser = require( './views/browser.js' );
9
+ wp.media.view.IconPickerSidebar = require( './views/sidebar.js' );
10
+ wp.media.view.IconPickerFontItem = require( './views/font-item.js' );
11
+ wp.media.view.IconPickerFontLibrary = require( './views/font-library.js' );
12
+ wp.media.view.IconPickerFontFilter = require( './views/font-filter.js' );
13
+ wp.media.view.IconPickerFontBrowser = require( './views/font-browser.js' );
14
+ wp.media.view.IconPickerImgBrowser = require( './views/img-browser.js' );
15
+ wp.media.view.IconPickerSvgItem = require( './views/svg-item.js' );
16
+ wp.media.view.MediaFrame.IconPicker = require( './views/frame.js' );
vendor/codeinwp/icon-picker/js/src/media/models/fonts.js ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * wp.media.model.IconPickerFonts
3
+ */
4
+ var IconPickerFonts = Backbone.Collection.extend({
5
+ constructor: function() {
6
+ Backbone.Collection.prototype.constructor.apply( this, arguments );
7
+
8
+ this.items = new Backbone.Collection( this.models );
9
+ this.props = new Backbone.Model({
10
+ group: 'all',
11
+ search: ''
12
+ });
13
+
14
+ this.props.on( 'change', this.refresh, this );
15
+ },
16
+
17
+ /**
18
+ * Refresh library when props is changed
19
+ *
20
+ * @param {Backbone.Model} props
21
+ */
22
+ refresh: function( props ) {
23
+ let items = _.clone( this.items.models );
24
+
25
+ _.each( props.toJSON(), ( value, filter ) => {
26
+ const method = this.filters[ filter ];
27
+
28
+ if ( method ) {
29
+ items = items.filter( item => {
30
+ return method( item, value );
31
+ });
32
+ }
33
+ });
34
+
35
+ this.reset( items );
36
+ },
37
+
38
+ filters: {
39
+ /**
40
+ * @static
41
+ *
42
+ * @param {Backbone.Model} item Item model.
43
+ * @param {string} group Group ID.
44
+ *
45
+ * @returns {Boolean}
46
+ */
47
+ group: function( item, group ) {
48
+ return ( group === 'all' || item.get( 'group' ) === group || item.get( 'group' ) === '' );
49
+ },
50
+
51
+ /**
52
+ * @static
53
+ *
54
+ * @param {Backbone.Model} item Item model.
55
+ * @param {string} term Search term.
56
+ *
57
+ * @returns {Boolean}
58
+ */
59
+ search: function( item, term ) {
60
+ let result;
61
+
62
+ if ( term === '' ) {
63
+ result = true;
64
+ } else {
65
+ result = _.any([ 'id', 'name' ], attribute => {
66
+ const value = item.get( attribute );
67
+
68
+ return value && value.search( term ) >= 0;
69
+ }, term );
70
+ }
71
+
72
+ return result;
73
+ }
74
+ }
75
+ });
76
+
77
+ module.exports = IconPickerFonts;
vendor/codeinwp/icon-picker/js/src/media/models/target.js ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * wp.media.model.IconPickerTarget
3
+ *
4
+ * A target where the picked icon should be sent to
5
+ *
6
+ * @augments Backbone.Model
7
+ */
8
+ var IconPickerTarget = Backbone.Model.extend({
9
+ defaults: {
10
+ type: '',
11
+ group: 'all',
12
+ icon: '',
13
+ url: '',
14
+ sizes: []
15
+ }
16
+ });
17
+
18
+ module.exports = IconPickerTarget;
vendor/codeinwp/icon-picker/js/src/media/views/browser.js ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Methods for the browser views
3
+ */
4
+ var IconPickerBrowser = {
5
+ createSidebar: function() {
6
+ this.sidebar = new this.options.SidebarView({
7
+ controller: this.controller,
8
+ selection: this.options.selection
9
+ });
10
+
11
+ this.views.add( this.sidebar );
12
+ }
13
+ };
14
+
15
+ module.exports = IconPickerBrowser;
vendor/codeinwp/icon-picker/js/src/media/views/font-browser.js ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * wp.media.view.IconPickerFontBrowser
3
+ */
4
+ var IconPickerFontBrowser = wp.media.View.extend( _.extend({
5
+ className: function() {
6
+ var className = 'attachments-browser iconpicker-fonts-browser';
7
+
8
+ if ( ! this.options.sidebar ) {
9
+ className += ' hide-sidebar';
10
+ }
11
+
12
+ return className;
13
+ },
14
+
15
+ initialize: function() {
16
+ this.groups = this.options.groups;
17
+
18
+ this.createToolbar();
19
+ this.createLibrary();
20
+
21
+ if ( this.options.sidebar ) {
22
+ this.createSidebar();
23
+ }
24
+ },
25
+
26
+ createLibrary: function() {
27
+ this.items = new wp.media.view.IconPickerFontLibrary({
28
+ controller: this.controller,
29
+ collection: this.collection,
30
+ selection: this.options.selection,
31
+ baseType: this.options.baseType,
32
+ type: this.options.type
33
+ });
34
+
35
+ // Add keydown listener to the instance of the library view
36
+ this.items.listenTo( this.controller, 'attachment:keydown:arrow', this.items.arrowEvent );
37
+ this.items.listenTo( this.controller, 'attachment:details:shift-tab', this.items.restoreFocus );
38
+
39
+ this.views.add( this.items );
40
+ },
41
+
42
+ createToolbar: function() {
43
+ this.toolbar = new wp.media.view.Toolbar({
44
+ controller: this.controller
45
+ });
46
+
47
+ this.views.add( this.toolbar );
48
+
49
+ // Dropdown filter
50
+ this.toolbar.set( 'filters', new wp.media.view.IconPickerFontFilter({
51
+ controller: this.controller,
52
+ model: this.collection.props,
53
+ priority: - 80
54
+ }).render() );
55
+
56
+ // Search field
57
+ this.toolbar.set( 'search', new wp.media.view.Search({
58
+ controller: this.controller,
59
+ model: this.collection.props,
60
+ priority: 60
61
+ }).render() );
62
+ }
63
+ }, wp.media.view.IconPickerBrowser ) );
64
+
65
+ module.exports = IconPickerFontBrowser;
vendor/codeinwp/icon-picker/js/src/media/views/font-filter.js ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * wp.media.view.IconPickerFontFilter
3
+ */
4
+ var IconPickerFontFilter = wp.media.view.AttachmentFilters.extend({
5
+ createFilters: function() {
6
+ var groups = this.controller.state().get( 'groups' ),
7
+ filters = {};
8
+
9
+ filters.all = {
10
+ text: wp.media.view.l10n.iconPicker.allFilter,
11
+ props: { group: 'all' }
12
+ };
13
+
14
+ groups.each( function( group ) {
15
+ filters[ group.id ] = {
16
+ text: group.get( 'name' ),
17
+ props: { group: group.id }
18
+ };
19
+ });
20
+
21
+ this.filters = filters;
22
+ },
23
+
24
+ change: function() {
25
+ var filter = this.filters[ this.el.value ];
26
+
27
+ if ( filter ) {
28
+ this.model.set( 'group', filter.props.group );
29
+ }
30
+ }
31
+ });
32
+
33
+ module.exports = IconPickerFontFilter;
vendor/codeinwp/icon-picker/js/src/media/views/font-item.js ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var Attachment = wp.media.view.Attachment.Library,
2
+ IconPickerFontItem;
3
+
4
+ /**
5
+ * wp.media.view.IconPickerFontItem
6
+ */
7
+ IconPickerFontItem = Attachment.extend({
8
+ className: 'attachment iconpicker-item',
9
+
10
+ initialize: function() {
11
+ this.template = wp.media.template( 'iconpicker-' + this.options.baseType + '-item' );
12
+ Attachment.prototype.initialize.apply( this, arguments );
13
+ },
14
+
15
+ render: function() {
16
+ var options = _.defaults( this.model.toJSON(), {
17
+ baseType: this.options.baseType,
18
+ type: this.options.type
19
+ });
20
+
21
+ this.views.detach();
22
+ this.$el.html( this.template( options ) );
23
+ this.updateSelect();
24
+ this.views.render();
25
+
26
+ return this;
27
+ }
28
+ });
29
+
30
+ module.exports = IconPickerFontItem;
vendor/codeinwp/icon-picker/js/src/media/views/font-library.js ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var $ = jQuery,
2
+ Attachments = wp.media.view.Attachments,
3
+ IconPickerFontLibrary;
4
+
5
+ /**
6
+ * wp.media.view.IconPickerFontLibrary
7
+ */
8
+ IconPickerFontLibrary = Attachments.extend({
9
+ className: 'attachments iconpicker-items clearfix',
10
+
11
+ initialize: function() {
12
+ Attachments.prototype.initialize.apply( this, arguments );
13
+
14
+ _.bindAll( this, 'scrollToSelected' );
15
+ _.defer( this.scrollToSelected, this );
16
+ this.controller.on( 'open', this.scrollToSelected, this );
17
+ $( this.options.scrollElement ).off( 'scroll', this.scroll );
18
+ },
19
+
20
+ _addItem: function( model ) {
21
+ this.views.add( this.createAttachmentView( model ), {
22
+ at: this.collection.indexOf( model )
23
+ });
24
+ },
25
+
26
+ _removeItem: function( model ) {
27
+ var view = this._viewsByCid[ model.cid ];
28
+ delete this._viewsByCid[ model.cid ];
29
+
30
+ if ( view ) {
31
+ view.remove();
32
+ }
33
+ },
34
+
35
+ render: function() {
36
+ _.each( this._viewsByCid, this._removeItem, this );
37
+ this.collection.each( this._addItem, this );
38
+
39
+ return this;
40
+ },
41
+
42
+ createAttachmentView: function( model ) {
43
+ var view = new wp.media.view.IconPickerFontItem({
44
+ controller: this.controller,
45
+ model: model,
46
+ collection: this.collection,
47
+ selection: this.options.selection,
48
+ baseType: this.options.baseType,
49
+ type: this.options.type
50
+ });
51
+
52
+ return this._viewsByCid[ view.cid ] = view;
53
+ },
54
+
55
+ /**
56
+ * Scroll to selected item
57
+ */
58
+ scrollToSelected: function() {
59
+ var selected = this.options.selection.single(),
60
+ singleView, distance;
61
+
62
+ if ( ! selected ) {
63
+ return;
64
+ }
65
+
66
+ singleView = this.getView( selected );
67
+
68
+ if ( singleView && ! this.isInView( singleView.$el ) ) {
69
+ distance = (
70
+ singleView.$el.offset().top -
71
+ parseInt( singleView.$el.css( 'paddingTop' ), 10 ) -
72
+ this.$el.offset().top +
73
+ this.$el.scrollTop() -
74
+ parseInt( this.$el.css( 'paddingTop' ), 10 )
75
+ );
76
+
77
+ this.$el.scrollTop( distance );
78
+ }
79
+ },
80
+
81
+ getView: function( model ) {
82
+ return _.findWhere( this._viewsByCid, { model: model });
83
+ },
84
+
85
+ isInView: function( $elem ) {
86
+ var docViewTop = this.$window.scrollTop(),
87
+ docViewBottom = docViewTop + this.$window.height(),
88
+ elemTop = $elem.offset().top,
89
+ elemBottom = elemTop + $elem.height();
90
+
91
+ return ( ( elemBottom <= docViewBottom ) && ( elemTop >= docViewTop ) );
92
+ },
93
+
94
+ prepare: function() {},
95
+ ready: function() {},
96
+ initSortable: function() {},
97
+ scroll: function() {}
98
+ });
99
+
100
+ module.exports = IconPickerFontLibrary;
vendor/codeinwp/icon-picker/js/src/media/views/frame.js ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * wp.media.view.MediaFrame.IconPicker
3
+ *
4
+ * A frame for selecting an icon.
5
+ *
6
+ * @class
7
+ * @augments wp.media.view.MediaFrame.Select
8
+ * @augments wp.media.view.MediaFrame
9
+ * @augments wp.media.view.Frame
10
+ * @augments wp.media.View
11
+ * @augments wp.Backbone.View
12
+ * @augments Backbone.View
13
+ * @mixes wp.media.controller.StateMachine
14
+ */
15
+
16
+ var l10n = wp.media.view.l10n,
17
+ Select = wp.media.view.MediaFrame.Select,
18
+ IconPicker;
19
+
20
+ IconPicker = Select.extend({
21
+ initialize: function() {
22
+ _.defaults( this.options, {
23
+ title: l10n.iconPicker.frameTitle,
24
+ multiple: false,
25
+ ipTypes: iconPicker.types,
26
+ target: null,
27
+ SidebarView: null
28
+ });
29
+
30
+ if ( this.options.target instanceof wp.media.model.IconPickerTarget ) {
31
+ this.target = this.options.target;
32
+ } else {
33
+ this.target = new wp.media.model.IconPickerTarget();
34
+ }
35
+
36
+ Select.prototype.initialize.apply( this, arguments );
37
+ },
38
+
39
+ createStates: function() {
40
+ var Controller;
41
+
42
+ _.each( this.options.ipTypes, function( props ) {
43
+ if ( ! wp.media.controller.hasOwnProperty( 'IconPicker' + props.controller ) ) {
44
+ return;
45
+ }
46
+
47
+ Controller = wp.media.controller[ 'IconPicker' + props.controller ];
48
+
49
+ this.states.add( new Controller({
50
+ id: props.id,
51
+ content: props.id,
52
+ title: props.name,
53
+ data: props.data
54
+ }) );
55
+ }, this );
56
+ },
57
+
58
+ /**
59
+ * Bind region mode event callbacks.
60
+ */
61
+ bindHandlers: function() {
62
+ this.on( 'router:create:browse', this.createRouter, this );
63
+ this.on( 'router:render:browse', this.browseRouter, this );
64
+ this.on( 'content:render', this.ipRenderContent, this );
65
+ this.on( 'toolbar:create:select', this.createSelectToolbar, this );
66
+ this.on( 'open', this._ipSetState, this );
67
+ this.on( 'select', this._ipUpdateTarget, this );
68
+ },
69
+
70
+ /**
71
+ * Set state based on the target's icon type
72
+ */
73
+ _ipSetState: function() {
74
+ var stateId = this.target.get( 'type' );
75
+
76
+ if ( ! stateId || ! this.states.findWhere({ id: stateId }) ) {
77
+ stateId = this.states.at( 0 ).id;
78
+ }
79
+
80
+ this.setState( stateId );
81
+ },
82
+
83
+ /**
84
+ * Update target's attributes after selecting an icon
85
+ */
86
+ _ipUpdateTarget: function() {
87
+ var state = this.state(),
88
+ selected = state.get( 'selection' ).single(),
89
+ props;
90
+
91
+ props = {
92
+ type: state.id,
93
+ icon: selected.get( 'id' ),
94
+ sizes: selected.get( 'sizes' ),
95
+ url: state.ipGetIconUrl( selected )
96
+ };
97
+
98
+ this.target.set( props );
99
+ },
100
+
101
+ browseRouter: function( routerView ) {
102
+ var routers = this.state().routers;
103
+
104
+ if ( routers ) {
105
+ routerView.set( routers );
106
+ }
107
+ },
108
+
109
+ ipRenderContent: function() {
110
+ var state = this.state(),
111
+ mode = this.content.mode(),
112
+ content = state.getContentView( mode );
113
+
114
+ this.content.set( content );
115
+ }
116
+ });
117
+
118
+ module.exports = IconPicker;
vendor/codeinwp/icon-picker/js/src/media/views/img-browser.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ /**
2
+ * wp.media.view.IconPickerImgBrowser
3
+ */
4
+ var IconPickerImgBrowser = wp.media.view.AttachmentsBrowser.extend( wp.media.view.IconPickerBrowser );
5
+
6
+ module.exports = IconPickerImgBrowser;
vendor/codeinwp/icon-picker/js/src/media/views/sidebar.js ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * wp.media.view.IconPickerSidebar
3
+ */
4
+ var IconPickerSidebar = wp.media.view.Sidebar.extend({
5
+ initialize: function() {
6
+ var selection = this.options.selection;
7
+
8
+ wp.media.view.Sidebar.prototype.initialize.apply( this, arguments );
9
+
10
+ selection.on( 'selection:single', this.createSingle, this );
11
+ selection.on( 'selection:unsingle', this.disposeSingle, this );
12
+
13
+ if ( selection.single() ) {
14
+ this.createSingle();
15
+ }
16
+ },
17
+
18
+ /**
19
+ * @abstract
20
+ */
21
+ createSingle: function() {},
22
+
23
+ /**
24
+ * @abstract
25
+ */
26
+ disposeSingle: function() {}
27
+ });
28
+
29
+ module.exports = IconPickerSidebar;
vendor/codeinwp/icon-picker/js/src/media/views/svg-item.js ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ /**
2
+ * wp.media.view.IconPickerSvgItem
3
+ */
4
+ var IconPickerSvgItem = wp.media.view.Attachment.Library.extend({
5
+ template: wp.template( 'iconpicker-svg-item' )
6
+ });
7
+
8
+ module.exports = IconPickerSvgItem;
vendor/codeinwp/icon-picker/phpcs.ruleset.xml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <ruleset name="Icon Picker Coding Standards">
3
+ <config name="installed_paths" value="vendor/wp-coding-standards/wpcs" />
4
+
5
+ <exclude-pattern>*/node_modules/*</exclude-pattern>
6
+ <exclude-pattern>*/vendor/*</exclude-pattern>
7
+
8
+ <rule ref="WordPress-VIP">
9
+ <!-- ...Except for VIP-specific things -->
10
+ <exclude name="WordPress.VIP.FileSystemWritesDisallow" />
11
+ <exclude name="WordPress.VIP.RestrictedFunctions" />
12
+ <exclude name="WordPress.VIP.RestrictedVariables" />
13
+ <exclude name="WordPress.VIP.SuperGlobalInputUsage" />
14
+ <exclude name="WordPress.VIP.ValidatedSanitizedInput" />
15
+ <exclude name="WordPress.VIP.DirectDatabaseQuery" />
16
+ </rule>
17
+ </ruleset>
vendor/codeinwp/icon-picker/readme.md ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- DO NOT EDIT THIS FILE; it is auto-generated from readme.txt -->
2
+ # Icon Picker
3
+
4
+ Pick an icon of your choice.
5
+
6
+ **Contributors:** [kucrut](https://profiles.wordpress.org/kucrut)
7
+ **Tags:** [icons](https://wordpress.org/plugins/tags/icons), [image](https://wordpress.org/plugins/tags/image), [svg](https://wordpress.org/plugins/tags/svg)
8
+ **Requires at least:** 4.3
9
+ **Tested up to:** 4.7.2
10
+ **Stable tag:** 0.5.0
11
+ **License:** [GPLv2](http://www.gnu.org/licenses/gpl-2.0.html)
12
+ **Donate Link:** http://kucrut.org/#coffee
13
+
14
+ [![Build Status](https://travis-ci.org/kucrut/wp-icon-picker.svg?branch=master)](https://travis-ci.org/kucrut/wp-icon-picker) [![Built with Grunt](https://cdn.gruntjs.com/builtwith.svg)](http://gruntjs.com)
15
+
16
+ ## Description ##
17
+
18
+ An icon picker library plugin.
19
+
20
+ ## Screenshots ##
21
+
22
+ ### Icon selector
23
+
24
+ ![Icon selector](assets/screenshot-1.png)
25
+
26
+ ### Icon fields in a post meta box using [CMB](https://github.com/humanmade/Custom-Meta-Boxes/)
27
+
28
+ ![Icon fields in a post meta box using [CMB](https://github.com/humanmade/Custom-Meta-Boxes/)](assets/screenshot-2.png)
29
+
30
+ ## Frequently Asked Questions ##
31
+
32
+ ### How do I use css file from CDN? ###
33
+ You can use the `icon_picker_icon_type_stylesheet_uri` filter, eg:
34
+ ```php
35
+ /**
36
+ * Load Font Awesome's CSS from CDN
37
+ *
38
+ * @param string $stylesheet_uri Icon type's stylesheet URI.
39
+ * @param string $icon_type_id Icon type's ID.
40
+ * @param Icon_Picker_Type_Font $icon_type Icon type's instance.
41
+ *
42
+ * @return string
43
+ */
44
+ function myprefix_font_awesome_css_from_cdn( $stylesheet_uri, $icon_type_id, $icon_type ) {
45
+ if ( 'fa' === $icon_type_id ) {
46
+ $stylesheet_uri = sprintf(
47
+ 'https://maxcdn.bootstrapcdn.com/font-awesome/%s/css/font-awesome.min.css',
48
+ $icon_type->version
49
+ );
50
+ }
51
+
52
+ return $stylesheet_uri;
53
+ }
54
+ add_filter( 'icon_picker_icon_type_stylesheet_uri', 'myprefix_font_awesome_css_from_cdn', 10, 3 );
55
+ ```
56
+
57
+
58
+ ## Changelog ##
59
+
60
+ ### 0.5.0 ###
61
+ * Update Font Awesome to 4.7.0.
62
+ * Switch to Webpack.
63
+ * Various [bug fixes and enhancements](https://github.com/kucrut/wp-icon-picker/issues?q=is%3Aissue+milestone%3A0.5.0+is%3Aclosed).
64
+
65
+ ### 0.4.1 ###
66
+ * Improve support for CMB: Make the field usable in a repeatable field.
67
+
68
+ ### 0.4.0 ###
69
+ * Introduce `icon_picker_icon_type_stylesheet_uri` filter hook.
70
+ * Font Awesome 4.6.1
71
+
72
+ ### 0.3.0 ###
73
+ * Fix CSS classname conflicts.
74
+
75
+ ### 0.2.0 ###
76
+ * Introduce `icon_picker_field()`.
77
+ * Add support for [CMB](https://github.com/humanmade/Custom-Meta-Boxes/).
78
+
79
+ ### 0.1.1 ###
80
+ * Load translation, props [Eduardo Larequi](https://wordpress.org/support/profile/elarequi).
81
+
82
+ ### 0.1.0 ###
83
+ * Initial
84
+
85
+
vendor/codeinwp/menu-item-custom-fields/phpcs.ruleset.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <ruleset name="Icon Picker Coding Standards">
3
+ <config name="installed_paths" value="vendor/wp-coding-standards/wpcs" />
4
+
5
+ <exclude-pattern>*/node_modules/*</exclude-pattern>
6
+ <exclude-pattern>*/vendor/*</exclude-pattern>
7
+
8
+ <rule ref="WordPress-VIP">
9
+ <!-- ...Except for VIP-specific things -->
10
+ <exclude name="Squiz.PHP.CommentedOutCode.Found" />
11
+ <exclude name="WordPress.VIP.FileSystemWritesDisallow" />
12
+ <exclude name="WordPress.VIP.RestrictedFunctions" />
13
+ <exclude name="WordPress.VIP.RestrictedVariables" />
14
+ <exclude name="WordPress.VIP.SuperGlobalInputUsage" />
15
+ <exclude name="WordPress.VIP.ValidatedSanitizedInput" />
16
+ <exclude name="WordPress.VIP.DirectDatabaseQuery" />
17
+ </rule>
18
+ </ruleset>
vendor/codeinwp/menu-item-custom-fields/readme.md ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- DO NOT EDIT THIS FILE; it is auto-generated from readme.txt -->
2
+ # Menu Item Custom Fields
3
+
4
+ Easily add custom fields to nav menu items.
5
+
6
+ **Contributors:** [kucrut](https://profiles.wordpress.org/kucrut)
7
+ **Tags:** [menu](https://wordpress.org/plugins/tags/menu), [nav-menu](https://wordpress.org/plugins/tags/nav-menu), [custom-fields](https://wordpress.org/plugins/tags/custom-fields), [metadata](https://wordpress.org/plugins/tags/metadata)
8
+ **Requires at least:** 3.8
9
+ **Tested up to:** 4.7.2
10
+ **Stable tag:** 1.0.0
11
+ **License:** [GPLv2](http://www.gnu.org/licenses/gpl-2.0.html)
12
+ **Donate Link:** https://www.paypal.me/kucrut
13
+
14
+ [![Build Status](https://travis-ci.org/kucrut/wp-menu-item-custom-fields.svg?branch=master)](https://travis-ci.org/kucrut/wp-menu-item-custom-fields)
15
+
16
+ ## Description ##
17
+
18
+ ### Breaking Change ###
19
+ Since version `1.0.0`, the first parameter passed to the `wp_nav_menu_item_custom_fields` is the menu item ID, instead of the nav menu ID. This should not have a big impact, since the nav menu ID passed was always `0` (not used by core).
20
+
21
+ This is a *library* plugin. It doesn't do anything visible on its own. It was written to allow other plugins/themes to add custom fields to menu items *easily*. See **Installation**.
22
+
23
+ Development of this plugin is done on [GitHub](https://github.com/kucrut/wp-menu-item-custom-fields). **Pull requests welcome**. Please see [issues reported](https://github.com/kucrut/wp-menu-item-custom-fields/issues) there before going to the plugin forum.
24
+
25
+
26
+ ## Installation ##
27
+
28
+ ### As regular plugin ###
29
+ 1. Upload `menu-item-custom-fields` to the `/wp-content/plugins/` directory
30
+ 1. Activate the plugin through the 'Plugins' menu in WordPress
31
+
32
+ ### As library in your plugin/theme ###
33
+ Simply copy `menu-item-custom-fields` to your plugin directory and require the main plugin file, eg:
34
+ `
35
+ require_once dirname( __FILE__ ) . '/menu-item-custom-fields/menu-item-custom-fields.php';
36
+ `
37
+
38
+ ### Usage ###
39
+ Copy (and customize) and include the `menu-item-custom-fields-example.php` file found in the `doc/` directory of this plugin into your plugin/theme.
40
+
41
+
42
+ ## Changelog ##
43
+
44
+ ### 1.0.0 ###
45
+ * Pass correct parameters to the `wp_nav_menu_item_custom_fields` hook, props [@helgatheviking](https://github.com/helgatheviking).
46
+
47
+ ### 0.4.0 ###
48
+ * Support WordPress 4.7, props [rahulnever2far](https://github.com/rahulnever2far).
49
+
50
+ ### 0.3.0 ###
51
+ * Use `wp_nav_menu_item_custom_fields` as walker hook. See this [blog post](http://shazdeh.me/2014/06/25/custom-fields-nav-menu-items/).
52
+ * Update example plugin
53
+
54
+ ### 0.2.1 ###
55
+ * Update compatibility info
56
+
57
+ ### 0.2.0 ###
58
+ * Improve walker class loader
59
+
60
+ ### 0.1.1 ###
61
+ * Move custom fields up (before `<p.field-move />`)
62
+
63
+ ### 0.1.0 ###
64
+ * Initial public release
65
+
66
+
vendor/codeinwp/themeisle-sdk/CHANGELOG.md ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## [3.0.6](https://github.com/Codeinwp/themeisle-sdk/compare/v3.0.5...v3.0.6) (2019-05-21)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * build php version for deployment stage ([a785699](https://github.com/Codeinwp/themeisle-sdk/commit/a785699))
7
+ * uninstall feedback should load only on the proper pages ([259e78f](https://github.com/Codeinwp/themeisle-sdk/commit/259e78f))
8
+
9
+ ## [3.0.5](https://github.com/Codeinwp/themeisle-sdk/compare/v3.0.4...v3.0.5) (2019-03-07)
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * dashboard widget issues and recommended module inconsistency fix [#50](https://github.com/Codeinwp/themeisle-sdk/issues/50), [#49](https://github.com/Codeinwp/themeisle-sdk/issues/49), [#47](https://github.com/Codeinwp/themeisle-sdk/issues/47) ([757eb02](https://github.com/Codeinwp/themeisle-sdk/commit/757eb02))
15
+
16
+ ## [3.0.4](https://github.com/Codeinwp/themeisle-sdk/compare/v3.0.3...v3.0.4) (2019-01-28)
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * uninstall feedback disclosure issues when one of the feedback fields is open ([4631eef](https://github.com/Codeinwp/themeisle-sdk/commit/4631eef))
22
+
23
+ ## [3.0.3](https://github.com/Codeinwp/themeisle-sdk/compare/v3.0.2...v3.0.3) (2019-01-07)
24
+
25
+
26
+ ### Bug Fixes
27
+
28
+ * **build:** fix exit code when is running outside wordpress context ([d298bb5](https://github.com/Codeinwp/themeisle-sdk/commit/d298bb5))
29
+
30
+ ## [3.0.2](https://github.com/Codeinwp/themeisle-sdk/compare/v3.0.1...v3.0.2) (2018-12-28)
31
+
32
+
33
+ ### Bug Fixes
34
+
35
+ * remove composer/installers from package requirements ([a0ad543](https://github.com/Codeinwp/themeisle-sdk/commit/a0ad543))
36
+
37
+ ## [3.0.1](https://github.com/Codeinwp/themeisle-sdk/compare/v3.0.0...v3.0.1) (2018-12-24)
38
+
39
+
40
+ ### Bug Fixes
41
+
42
+ * notifications setup triggers after all products register their n… ([999a944](https://github.com/Codeinwp/themeisle-sdk/commit/999a944))
43
+ * notifications setup triggers after all products register their notices ([ec3cacc](https://github.com/Codeinwp/themeisle-sdk/commit/ec3cacc))
44
+
45
+ # 1.0.0 (2018-12-21)
46
+
47
+
48
+ ### Features
49
+
50
+ * adds uninstall feedback privacy policy info ([ed17943](https://github.com/Codeinwp/themeisle-sdk/commit/ed17943))
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-endpoints.php DELETED
@@ -1,312 +0,0 @@
1
- <?php
2
- /**
3
- * The class that exposes endpoints.
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Endpoints
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- // Exit if accessed directly.
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
- if ( ! class_exists( 'ThemeIsle_SDK_Endpoints' ) ) :
16
- /**
17
- * Expose endpoints for ThemeIsle SDK.
18
- */
19
- final class ThemeIsle_SDK_Endpoints {
20
-
21
- const SDK_ENDPOINT = 'themeisle-sdk';
22
- const SDK_ENDPOINT_VERSION = 1;
23
-
24
- const HASH_FILE = 'themeisle-hash.json';
25
-
26
- // if true, the endpoint will expect a product slug and will return the value only for that.
27
- const PRODUCT_SPECIFIC = false;
28
-
29
- /**
30
- * @var ThemeIsle_SDK_Product $products Array of Themeisle Product.
31
- */
32
- static protected $products = array();
33
-
34
- /**
35
- * ThemeIsle_SDK_Endpoints constructor.
36
- *
37
- * @param ThemeIsle_SDK_Product $product_object Product Object.
38
- */
39
- public function __construct( $product_object ) {
40
- if ( $product_object instanceof ThemeIsle_SDK_Product ) {
41
- self::$products[] = $product_object;
42
- }
43
- $this->setup_endpoints();
44
- }
45
-
46
- /**
47
- * Setup endpoints.
48
- */
49
- private function setup_endpoints() {
50
- global $wp_version;
51
- if ( version_compare( $wp_version, '4.4', '<' ) ) {
52
- // no REST support.
53
- return;
54
- }
55
-
56
- $this->setup_rest();
57
- }
58
-
59
- /**
60
- * Setup REST endpoints.
61
- */
62
- private function setup_rest() {
63
- add_action( 'rest_api_init', array( $this, 'rest_register' ) );
64
- }
65
-
66
- /**
67
- * Registers the endpoints
68
- */
69
- function rest_register() {
70
- register_rest_route(
71
- self::SDK_ENDPOINT . '/v' . self::SDK_ENDPOINT_VERSION,
72
- '/checksum/' . ( self::PRODUCT_SPECIFIC ? '(?P<slug>.*)/' : '' ),
73
- array(
74
- 'methods' => 'GET',
75
- 'callback' => array( $this, 'checksum' ),
76
- )
77
- );
78
- }
79
-
80
- /**
81
- * The checksum endpoint.
82
- *
83
- * @param WP_REST_Request $data the request.
84
- *
85
- * @return WP_REST_Response Response or the error
86
- */
87
- function checksum( WP_REST_Request $data ) {
88
- $products = self::$products;
89
- if ( self::PRODUCT_SPECIFIC ) {
90
- $params = $this->validate_params( $data, array( 'slug' ) );
91
- foreach ( self::$products as $product ) {
92
- if ( $params['slug'] === $product->get_slug() ) {
93
- $products = array( $product );
94
- break;
95
- }
96
- }
97
- }
98
- $response = array();
99
- $custom_css = $this->has_custom_css();
100
- if ( is_bool( $custom_css ) ) {
101
- $response['custom_css'] = $custom_css;
102
- }
103
-
104
- $response['child_theme'] = $this->get_theme_properties();
105
-
106
- foreach ( $products as $product ) {
107
- $files = array();
108
- switch ( $product->get_type() ) {
109
- case 'plugin':
110
- $files = array();
111
- break;
112
- case 'theme':
113
- $files = array( 'style.css', 'functions.php' );
114
- break;
115
- }
116
-
117
- $error = '';
118
-
119
- // if any element in the $files array contains a '/', this would imply recursion is required.
120
- $diff = $this->generate_diff( $product, $files, array_reduce( $files, array( $this, 'is_recursion_required' ), false ) );
121
- if ( is_wp_error( $diff ) ) {
122
- $error = $diff->get_error_message();
123
- $diff = array();
124
- }
125
-
126
- $response['products'][] = array(
127
- 'slug' => $product->get_slug(),
128
- 'version' => $product->get_version(),
129
- 'diffs' => $diff,
130
- 'error' => $error,
131
- );
132
- }
133
-
134
- return new WP_REST_Response( array( 'checksum' => $response ) );
135
- }
136
-
137
- /**
138
- * Get the current theme properties.
139
- *
140
- * @return array Properties of the current theme.
141
- */
142
- function get_theme_properties() {
143
- if ( ! is_child_theme() ) {
144
- return false;
145
- }
146
-
147
- $properties = array();
148
- $theme = wp_get_theme();
149
- // @codingStandardsIgnoreStart
150
- $properties['name'] = $theme->Name;
151
- // @codingStandardsIgnoreEnd
152
-
153
- // get the files in the child theme.
154
- require_once( ABSPATH . 'wp-admin/includes/file.php' );
155
- WP_Filesystem();
156
- global $wp_filesystem;
157
- $path = str_replace( ABSPATH, $wp_filesystem->abspath(), get_stylesheet_directory() );
158
- $list = $wp_filesystem->dirlist( $path, false, false );
159
- if ( $list ) {
160
- $list = array_keys( self::flatten_dirlist( $list ) );
161
- $properties['files'] = $list;
162
- }
163
- return $properties;
164
- }
165
-
166
- /**
167
- * Check if custom css has been added to the theme.
168
- *
169
- * @return bool Whether custom css has been added to the theme.
170
- */
171
- private function has_custom_css() {
172
- $query = new WP_Query(
173
- array(
174
- 'post_type' => 'custom_css',
175
- 'post_status' => 'publish',
176
- 'numberposts' => 1,
177
- 'update_post_meta_cache' => false,
178
- 'update_post_term_cache' => false,
179
- )
180
- );
181
-
182
- if ( $query->have_posts() ) {
183
- $query->the_post();
184
- $content = get_the_content();
185
- // if the content contains a colon, a CSS rule has been added.
186
- return strpos( $content, ':' ) === false ? false : true;
187
- }
188
- return false;
189
- }
190
-
191
- /**
192
- * Check if recursion needs to be enabled on the WP_Filesystem by reducing the array of files to a boolean.
193
- *
194
- * @param string $carry Value of the previous iteration.
195
- * @param string $item Value of the current iteration.
196
- *
197
- * @return bool Whether to recurse or not.
198
- */
199
- function is_recursion_required( $carry, $item ) {
200
- if ( ! $carry ) {
201
- return ( strpos( $item, '/' ) !== false );
202
- }
203
- return $carry;
204
- }
205
-
206
- /**
207
- * Generate the diff of the files.
208
- *
209
- * @param ThemeIsle_SDK_Product $product Themeisle Product.
210
- * @param array $files Array of files.
211
- * @param bool $recurse Whether to recurse or not.
212
- *
213
- * @return string
214
- */
215
- private function generate_diff( $product, $files, $recurse = false ) {
216
- require_once( ABSPATH . 'wp-admin/includes/file.php' );
217
- WP_Filesystem();
218
- global $wp_filesystem;
219
-
220
- $diff = array();
221
- $path = str_replace( ABSPATH, $wp_filesystem->abspath(), plugin_dir_path( $product->get_basefile() ) );
222
- $list = $wp_filesystem->dirlist( $path, false, $recurse );
223
- // nothing found.
224
- if ( ! $list ) {
225
- return $diff;
226
- }
227
- $list = array_keys( self::flatten_dirlist( $list ) );
228
-
229
- // now let's get the valid files that actually exist.
230
- if ( empty( $files ) ) {
231
- $files = $list;
232
- } else {
233
- $files = array_intersect( $files, $list );
234
- }
235
-
236
- // fetch the calculated hashes.
237
- if ( ! $wp_filesystem->is_readable( $path . '/' . self::HASH_FILE ) ) {
238
- return new WP_Error( 'themeisle_sdk_hash_not_found', sprintf( '%s not found', self::HASH_FILE ) );
239
- }
240
-
241
- $hashes = json_decode( $wp_filesystem->get_contents( $path . '/' . self::HASH_FILE ), true );
242
- ksort( $hashes );
243
-
244
- $diff = array();
245
- foreach ( $files as $file ) {
246
- // file does not exist in the hashes.
247
- if ( ! array_key_exists( $file, $hashes ) ) {
248
- continue;
249
- }
250
- $new = md5( $wp_filesystem->get_contents( $path . $file ) );
251
- $old = $hashes[ $file ];
252
-
253
- // same hash, bail.
254
- if ( $new === $old ) {
255
- continue;
256
- }
257
- $diff[] = $file;
258
- }
259
- return $diff;
260
- }
261
-
262
- /**
263
- * Flatten the results of WP_Filesystem::dirlist() for iterating over.
264
- *
265
- * @access private
266
- *
267
- * @param array $nested_files Array of files as returned by WP_Filesystem::dirlist().
268
- * @param string $path Relative path to prepend to child nodes. Optional.
269
- * @return array $files A flattened array of the $nested_files specified.
270
- */
271
- private static function flatten_dirlist( $nested_files, $path = '' ) {
272
- $files = array();
273
- foreach ( $nested_files as $name => $details ) {
274
- $files[ $path . $name ] = $details;
275
- // Append children recursively
276
- if ( ! empty( $details['files'] ) ) {
277
- $children = self::flatten_dirlist( $details['files'], $path . $name . '/' );
278
- // Merge keeping possible numeric keys, which array_merge() will reindex from 0..n
279
- $files = $files + $children;
280
- }
281
- }
282
- return $files;
283
- }
284
-
285
- /**
286
- * Validates the parameters to the API
287
- *
288
- * @param WP_REST_Request $data the request.
289
- * @param array $params the parameters to validate.
290
- *
291
- * @return array of parameter name=>value
292
- */
293
- private function validate_params( WP_REST_Request $data, $params ) {
294
- $collect = array();
295
- foreach ( $params as $param ) {
296
- $value = sanitize_text_field( $data[ $param ] );
297
- if ( empty( $value ) ) {
298
- return new WP_Error(
299
- 'themeisle_' . $param . '_invalid', sprintf( 'Invalid %', $param ), array(
300
- 'status' => 403,
301
- )
302
- );
303
- } else {
304
- $collect[ $param ] = $value;
305
- }
306
- }
307
-
308
- return $collect;
309
- }
310
-
311
- }
312
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-feedback-deactivate.php DELETED
@@ -1,556 +0,0 @@
1
- <?php
2
- /**
3
- * The deactivate feedback model class for ThemeIsle SDK
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Feedback
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- // Exit if accessed directly.
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
- if ( ! class_exists( 'ThemeIsle_SDK_Feedback_Deactivate' ) ) :
16
- /**
17
- * Deactivate feedback model for ThemeIsle SDK.
18
- */
19
- class ThemeIsle_SDK_Feedback_Deactivate extends ThemeIsle_SDK_Feedback {
20
-
21
- /**
22
- * @var array $options_plugin The main options list for plugins.
23
- */
24
- private $options_plugin = array(
25
- 'I found a better plugin' => array(
26
- 'id' => 3,
27
- 'type' => 'text',
28
- 'placeholder' => 'What\'s the plugin\'s name?',
29
- ),
30
- 'I could not get the plugin to work' => array(
31
- 'id' => 4,
32
- ),
33
- 'I no longer need the plugin' => array(
34
- 'id' => 5,
35
- 'type' => 'textarea',
36
- 'placeholder' => 'If you could improve one thing about our product, what would it be?',
37
- ),
38
- 'It\'s a temporary deactivation. I\'m just debugging an issue.' => array(
39
- 'id' => 6,
40
- ),
41
- );
42
-
43
- /**
44
- * @var array $options_theme The main options list for themes.
45
- */
46
- private $options_theme = array(
47
- 'I don\'t know how to make it look like demo' => array(
48
- 'id' => 7,
49
- ),
50
- 'It lacks options' => array(
51
- 'id' => 8,
52
- ),
53
- 'Is not working with a plugin that I need' => array(
54
- 'id' => 9,
55
- 'type' => 'text',
56
- 'placeholder' => 'What is the name of the plugin',
57
- ),
58
- 'I want to try a new design, I don\'t like {theme} style' => array(
59
- 'id' => 10,
60
- ),
61
- );
62
-
63
- /**
64
- * @var array $other The other option
65
- */
66
- private $other = array(
67
- 'Other' => array(
68
- 'id' => 999,
69
- 'type' => 'textarea',
70
- 'placeholder' => 'cmon cmon tell us',
71
- ),
72
- );
73
-
74
- /**
75
- * @var string $heading_plugin The heading of the modal
76
- */
77
- private $heading_plugin = 'Quick Feedback <span>Because we care about our clients, please leave us a feedback.</span>';
78
-
79
- /**
80
- * @var string $heading_theme The heading of the modal
81
- */
82
- private $heading_theme = 'Looking to change {theme} <span> What does not work for you?</span>';
83
-
84
- /**
85
- * @var string $button_submit_before The text of the deactivate button before an option is chosen
86
- */
87
- private $button_submit_before = 'Skip &amp; Deactivate';
88
-
89
- /**
90
- * @var string $button_submit The text of the deactivate button
91
- */
92
- private $button_submit = 'Submit &amp; Deactivate';
93
-
94
- /**
95
- * @var string $button_cancel The text of the cancel button
96
- */
97
- private $button_cancel = 'Skip &amp; Deactivate';
98
-
99
- /**
100
- * @var int how many seconds before the deactivation window is triggered for themes
101
- */
102
- const AUTO_TRIGGER_DEACTIVATE_WINDOW_SECONDS = 3;
103
-
104
- /**
105
- * @var int how many days before the deactivation window pops up again for the theme
106
- */
107
- const PAUSE_DEACTIVATE_WINDOW_DAYS = 100;
108
-
109
- /**
110
- * ThemeIsle_SDK_Feedback_Deactivate constructor.
111
- *
112
- * @param ThemeIsle_SDK_Product $product_object The product object.
113
- */
114
- public function __construct( $product_object ) {
115
- parent::__construct( $product_object );
116
- }
117
-
118
- /**
119
- * Registers the hooks
120
- */
121
- public function setup_hooks_child() {
122
- global $pagenow;
123
-
124
- if ( ( $this->product->get_type() === 'plugin' && $pagenow === 'plugins.php' ) || ( $this->product->get_type() === 'theme' && $pagenow === 'theme-install.php' ) ) {
125
- add_action( 'admin_head', array( $this, 'load_resources' ) );
126
- }
127
- add_action( 'wp_ajax_' . $this->product->get_key() . __CLASS__, array( $this, 'post_deactivate' ) );
128
- }
129
-
130
- /**
131
- * Loads the additional resources
132
- */
133
- function load_resources() {
134
- add_thickbox();
135
-
136
- $id = $this->product->get_key() . '_deactivate';
137
-
138
- $this->add_css( $this->product->get_type(), $this->product->get_key() );
139
- $this->add_js( $this->product->get_type(), $this->product->get_key(), '#TB_inline?' . apply_filters( $this->product->get_key() . '_feedback_deactivate_attributes', 'width=600&height=550' ) . '&inlineId=' . $id );
140
-
141
- echo '<div id="' . $id . '" style="display:none;" class="themeisle-deactivate-box">' . $this->get_html( $this->product->get_type(), $this->product->get_key() ) . '</div>';
142
- }
143
-
144
- /**
145
- * Loads the css
146
- *
147
- * @param string $type The type of product.
148
- * @param string $key The product key.
149
- */
150
- function add_css( $type, $key ) {
151
- $suffix = 'theme' === $type ? 'theme-install-php' : 'plugins-php';
152
- ?>
153
- <style type="text/css" id="<?php echo $key; ?>ti-deactivate-css">
154
- input[name="ti-deactivate-option"] ~ div {
155
- display: none;
156
- }
157
-
158
- input[name="ti-deactivate-option"]:checked ~ div {
159
- display: block;
160
- }
161
-
162
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container #TB_window.thickbox-loading:before {
163
- background: none !important;
164
- }
165
-
166
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container #TB_title {
167
- background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQyIDc5LjE2MDkyNCwgMjAxNy8wNy8xMy0wMTowNjozOSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpDNkVDM0M4RkYxMzMxMUU3OEMyMkQ0NTIxRTVEQ0ZBRiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpDNkVDM0M5MEYxMzMxMUU3OEMyMkQ0NTIxRTVEQ0ZBRiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkM2RUMzQzhERjEzMzExRTc4QzIyRDQ1MjFFNURDRkFGIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkM2RUMzQzhFRjEzMzExRTc4QzIyRDQ1MjFFNURDRkFGIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+KBNOswAAFtFJREFUeNrkWwmUXVWV3W/8Y81zkVAhgUwQg00IAYIRGcRuERDSKqALtVEbxRYcGzWIuhatKCYuUXQtERRtFAccQCDtckCZwpRISEIlIXMqlaGGP///ht7n3vd//YRUUkljN718a53U+++//97d95yzz3BvjDAM8fd02May4YndaZhoDErYeu/laCyN8rN16PuDAPA83mcAjjOxd8jcVypydhrlKspCSidlhPIk5T8p9/+PAP8fTrZJaaQ0UFxKiVKk/CvlU5Rk3b0C+gTKFZRvUa75/wJ4EuVcyimU2RGQdkqCkoOBDExjBoJx3Uwm5OlXt4bFrIPgTXSJK+DY59PEO8a5s0mPiEPyfUrwMieh3ED57qsTsJBhoXAOmps+gd6u85AvGtgxQEOmJcfj+vvxDsvS/hzsB5pkgA9QplJuoux59QD2g1ZUvCXhVe+4pnjxJc5gdx8SxTza1jwDY9ntMDdsBlLJQ4O2CTogRs+vBzydFmLCMm98NWl4OvL5O3Hd+09/9p8/iK/9GOjfRHZKpnHZWy7AlbfPRuK918DYTm3H3PHZWrQbVnHKtUBbh201EvSFvHLX0TLlK3ksRLG4HPPmnL7+0vfiaz8EOkwP+aduwPKbZ+DadyzBnVuPBa4nEQf+/hqW0zKvZcqkJoYmi0DTMXo2+cyltiu8oSi+HQrR3UG5+n9Fw6bFmRYJOVehUf/VAsrPacodOPtM3LcmjmPSwMz4cvzXAJEXt6C89gv49rJTcMk3zkdPL8e9e0iTVNHTTziuGTi9D5jF73oaNVg5RnLAjiywagfwp01ybiJufQOOuYMTdf9hg3s5H83oEQIWhYwOMGySf2KNFTjJchW0EMmPKB1KMx2d2LQFGCKtvPD0A1izbitnitcZbrat+T12Fi8i4C5g6y49kDkk7re/RoNtTmo+DiKmFlPupaZPbAPOp3VceSLwYD/fttrFUPlbSNsL+YgtB48QjGKmje+ceBlKlqsATBywIe82sG9TC5OhONqP2wOnucB0wRY13Cn6qQWPYgEtVNZvf8/J3RhnZAprrtjY81qkxHX3jGrtvn8esHgm0wzek6Vf76Y2Q19ncibBmymeM1Mz+H1IS2ji9XfPAuZzAm5+ajLWDn8JKfvymgprQczHyvbpGEh14f2nX89sLyVsehQmbQewKj5GBxtQzMXQ3DvyWcvxz9rPvFf9Fed+ELjnl8Q07To07FyJ3MATCDouxXmL344pO55nmsFs8avMHE8jmH1/puzmkEsarBo7n2dweCbn06YFxJizWJzFErVW5Kwez8m45VTgM08txqqhu5C0HxyDHNIIDSxedCP6Ozk5Bb6rNHzkpCWQTJqlwQcWcgkUh+NXG2b4sf1uSjDGPvQITh98Bh/5F35s6UXTovvR+eaVuPD6O/DRt8bg/uL7CK+nj75mI7DtD0CefhkUopfYkUZtDdyn75Y2kMz+wvtW6s8yMRmCaCLwG2Za6E5ch4xnoMLPZUo2g3uPPQfr25iNFob3U76BpUMTVK2JBLOmP37hU5hE5yzBvbZz2p6lyXYSiH/AvBVLCI/pRvnmG7Fy8nysYtgVEz+jIYPuu7+NSvIe2OfZMIvh4YuQevIRkxYtx6fxd662hkZOzu9257Fk/esZrlaI2arY+PY70d8yhRNZOWKWPobSS4fPFBx37YaeHkwdGrgCqfDWZGveRHAQI6GWje07EXvfRzB/0XzMn0UfzdBnH/oLwrOogTcfS7BbtSaPxL7kfp+aLayliR+nJytDEz8jnsRpDW/F45kVFTfE0rmXo7+VPOqXjygOn0f5qXgk5QnKc9Ty50MVfozbGjqyVFFwIFWM0XkioXPiB8hct9wGfI15Qmo3gnfSb3MZVW4e1SGmHtL8K1u1G1QYciyCflPqPFRK9ouN0/CJM6+LNBtOKA6Lqy6hfJri1H5jWbFUIX9D75597yM/NSWaiwfG4ZeDlpw4ldLvjXO23zOPeYMPw9/HqY5pRj+qg8/1yebYp0ktzwfNDGdgvnvcKnd6P7yKDmcTzLQE7Oc4SMflty1xA21JEyazng8v/4110uDmrrAphBXzdK47kUNYdS7j94ITEI7uhOkEh56sCefsGQ1cEotkIV3+ePKUm856txCXlKCXqLzgMIDfqEowaqQ1YaCv0URrjJyciGHu9k24+k8PsiB1EW8q6rg40S6GzPbZ3bSnOK1xAJZtHrpwmHDM4HODnDbtcAiPetNnb8x1fBFmebnK+oBHKVeOZ9JMBPEfHKDbTrBdKZMZX4gS3TDvmHjvA79BayGDYSONWKo8ce36BNZGgCd3EmyRRDt8BMw8kaNquhXmLC3vrHhOj2GXqp54POUHUVL0hQM1fBXvOjnlGOgm2Arjrcdn5VwHJ2zZggueXYEc4tSOD8vxxupW4zDAJcuaxBDSmUaQzzKS5HXV87cowWFMgWPElBtSHLPGW1I/L64HzGwB75KTjqShrI3JlBprgbnoPz3xONqZrVRoEKYVQrGzmJSkhgJ6PABGBLiPBBW3SJySXHhjJd8rfhiK/CVtF8X1pk3EdP4iL/x36ZOZtUonxClJ3iQ3lqldscQK70tmczj/mRUoE6z8TqolBboKWDqSVeDjabvZ0n7MxCH0A/ytjqyf5msspTCxTpvDEdCmHtZrKYuqgC8VbTe5ot1QZWjyg6ztYNbmzZi+Y5tkViqlNKhdQ4BVw45Dc3Uj0CIHalvuFfsJyuqrMLReAcI6+DGCHsX+AccZRPSR4JCa40bVtF8no4tJ4a7GxXELWLnRDyUBt7DghReQCop8gHFAmhdGPWd7f007ddqu4hLt+gX6vuTJCX4MXnHvlVRzS2lmrfgQxYVROtDg1sb+D6Zql4Y4PsY6ltasAQfanA3Px4xtWyIXqFZd9EXF0KFuw4h2rQioAu3UmbmpQUtiIKHDFKtoQTlb0t+9YkeFFtmNFUNMJw0ydGjUwErH16VNR6/rkT9zJCSJc8tNnjLnkD5rIp3N44TB7UzHx8KI75mcxGiw5XIENgLp2AdoPLq2Tx6aV1qOt01CcUieUTk8w0848SpjXeFUPDvUQmCBAloFK2IyZzC1jlIy8mnqN2bVlDWPlqnVhlwO7SOj/DymjYCARdRgBbA8yHXHfLhewwJW/GSbaJkaDrKwk0m4bXMwujkLv1JSWaJ6vIyoKvJMSWwM6XuVyXWM374kO8FBJknYKYn1T07hKzxyjPbfsE7qWoEyIsxU8SliNvFdZdJ8sctEIVEq1/xXDCVkdVQpOHAk+ZDYVSCQpubIj0w9SDVoQycnTGIwyAcOcBr7mAp6MSS6ephenonsrrX06wzcRJSLmJoMaYD0FpvjINsZbeQhxvAKx5HfiFR7hWltXV9bUtyB45G6YzPMS0scq1XTcFjT8Jiz26r0k4nlVS9ATUJ+jpVKcFgD1/uwvKY4GkeyI6fnbZQgWlt0fSqrDPJ039DgxfSFmkd5/Uk+9DiadSWrfhZjgRxrWohyIY+glFcmboQmgcdYVzTDdJs4KQ0E18RrBGi5KA3vRqb/e2jsLfKxjp5ctxW4mwnRmgHFlZ7y33BMwxHVBDqSlgVwuxF94YU6u/KV8UtzkjE3Yrux0B4qwGHF4kB4U5GmNkoQba21RoGWqI8soMVzHufnN1CaWc/6jh4N73HTSdJoS9TlqIoVdTwkhPH54u+Bg1hbL7zhhfByD8BtciS7AJa3oXD3Ls73ND7Oh7TpqiYtMELolkBkEFmzuqajTDnyYb/6i4NkRAKYZSdBM5pZUWjas0f/KBar8+U6ApNguJevepD3S1oq5WFYjjqT9GOPbiEpZ00KWgLpcVV0p0OE1uE0dHGiCLSBz3osicqyvchk5V1mzb9rJh2pStrdUSDca0buq8ZbZWgvMt4SycejnRgHKYCkiad8VF5C08fOnWPsXGXsGmh+bqTJ/5Gv+4skeOL/uxWJVTMwMuH+f2vnVcCVKMaWYIiKfsf33pLF8EuuKtsrDv1eIkagDTqo8+OSF1Y1vM6MNF5LOJT/Rg5QJPuWGGfNAzoH8rk4EkdxOKGb8uI8+6i1wUHdxKuxdB14N5J7ONCnKEkBRMuo7NXaRtSDluEoYNXzYIxn42KFW2H8mr/9RoD8YAK5bJqG7yGXSMC3rJqGa2YtU1RbnsJacZS9QlyS45vRzETxB3kOcJQAmlnlAC8v6Ya2NaG7saTSTbUSsX2H1mZ3J99i6BaPYYyJpO5Fyvd8zdxn82Ux+nSZBOinOIBG3cEQkgqicCXEZEvSQlm5De6d62CtcMmPDvYNtCh05GXsaGmlm/Pd5aI230hpokBZoeF8+VXA2yX58ALNxYrMOMNhpYJhFv4bWzswbe+gWp4/0JdL+RiGCbplCrVbbeYx91Ya6u2l9jy9hUHFV1NPgISpMuUXPF8VgZ7O8zSBm6MRUdmatITtZa1pE8H+gdHg90xP88yVYw72bGiHR841VdAMsbp7kn5HqJspSsOGNueK1uJW6cvZ0Yr6BWOa9RnfPSU+zbm/vRMX9P91nGIsxMiuBrXkku6kFXhV0FsYn8mufX3UakL7uBFpu8ri0vXYxGvfpbRR+qQ/ymE2+nqhf4TnWzlhLxLwFko+VGwfsHzd3d+OYjamwIp2C2T21cccq0mwluqHKsUs+DV3FJy7BfCDlE+q7ocCW1Ga0H+BZ6YcC+8xs6b9AwHLRO3a1KxCTLo9r8OQaGcX/ZmlJSZz5pv5vR1qbVc3usgT04a+f4R/VxDg414UNH3USjaJ55KvM8Hw6Q4717eiRP5wIt5leoLdqUb0d3VANe/qxik/r/PfX1cbAOTN8F7RqMkSzvA9DVYYkgnBo32TsT3Vwhf44y4/BjTnLRtbMTSQ1pwvaaGQlmRh617UMjwytvovImvDVUJL8LzBlrKGk0CRxSdh9WaGuTSvxwzkMzG8tJYxl2DdCFKoSj0Pz07qow83wygXUQ1Gmp1R5SQx598qwAZ1bwTBZw2/sgu+NmVEJm0z192VTuGxqceypK1gvCpW6ksh602bmrCV4rGiUhqVBN3k+fAwTZOgX1jDV/PdmYzWpLCqG9XTMgFy7lRragkbJKB8EQMbXWxY08yCy1Wldf3CiVS/D594orIaQ1mo7pULCZfHNsfcSxnU+7Sk7RJiA5/+Sf7gzv1MWkyLL//ZSSfirc8/zzwjPKAuHnt5Ujieyf3OXUkMZ1z09mTR0soUUIBX15IlKxOti7nXJyhG3Sq/76kmurx+eNjFjp2NJPE4Gvn8GIz9Jl2UsLmhDQ/PnKUX2eQdQri81w9q95JR8c0xi4wiMjV9l+GX51C7HzUi4hJN28UAj0yZhGe6e3Dqzu3Iwh23G5siMGmrDBdsrNnYgPSuBDoIurWpzCTMZ4IU+a56pRexeFhXaxsoknn3jiSxZyiGQs5BOrTQRgDmAWCrgH8697UYbOZ00BoNy9HRgn4fmrWGrCwobKgDnNAxTmvu0wQ7jdq9WJk1NW3zb9G1cMcpc3Dab7brimmcJpzyKYLu5PAkaR3OGViXt2EPkNASHhqZbCQI3LGDagRRIMuUfNFGJm+xxONAPQspPqNLadXcr8yrHi45ZWeiEXedOo+2WyJ1cGRq+cZSZaTkBtT0V3jh9v04x3SeQpibxxtGRKPSLriaoNtpWgurmnaLJfxqxhRc8WwfXrd9G0Zgjdt3rA6skeWdLEEXGY4ynLgcZ2AoK9SnSa32+9BQnmhT4jxvJcAUn+9EXYvxmkEpavfW+QuxpZ2ESu2GaoVfp6msukbD0FrCRy57Wa8g9p5f0s+eRzi0AIYnhWmZEc94yPTKi0hkvaJpiw5VJE+v7whx0Ysb4Pr2YZeFor6m0riYZRMhNfJvo3wmoJQ6t9DMJKOV0hY6PLcI+uDmW//cBpTxdFcvPn7hBZxAQ2l3LKMz/0jbvoqgfnawBTvLeRvhpVfDSD3Hp3GWStKkdzJGJfaQEeTONYJyl1FxOePD2HT2UnrALrxx5SSUEE60vVYDL3bhEk6cwJIEFuNfV5X7Ri3OH+6pYsoVMvn7Lv5HvNTWBlfiOlSltJl+chOB/htls+ztODjgxbKKx9fGNsFs+gPM9ntZkrK+tEdGjHz3b81ifD7cHZPDObfAbFmJJ2ZmMXVLA07d2oa8mt8j7i++TCa+ZhgyGnhYsuhM/Oqk6YiXmDeY5mBoWt8kwA9QHmYY9BXYcQDbtWEECf3XGoLR8X2QMSgztgT5rvuQ2ngG0ttglRLw3AAfvfZpdIzE8PrVnRhGpa67ZEZtfh0fxwCadZVW9bpRIz8j+nSo60Jdab7rK/Pm4tvzZiNeLA7CjP2ARHUbtfvShNcmEj9JtEWl0J66TZ6S2b4OZmkx06+FLDSVFdRWP8m07QT8nS/NxzmruzEkoGMBUhcW4E4vo9zvIv/LJIKyLLP6SF2Uh9PnofRXF7n7Eyp0WC28fnEOdpeP4tMMQcvjasKc7gqSb8nDag5QfDSO/J8lswoU2K/PnYUbz16wwTGdH5pm7K7QcjZSFGGFJsWOxIrxL8W0Dgp4drSzzVHNSr3Fty3a0jv+ki9BNzHkfHXpPFzy5CTElg0geWlG0yqDcf7HDdjzuVZ0LtuN+Hl5XWyzasrc3ozh25rQ+d1diJ1WrDWbRm5uRebeNLp/NAB7dinaZ2lg9DOt2Ht3E76+YMajSxfM/QFJ7Sem6exToBTYIwcsfxdR7o7ATsw0JFelVg1iuXXzdFy7uEHFT5BtmQUwQlRQejyO+MKC6lQq77HKCAs+ys/FEDtLth/FdP/KLiEYZhnX7yB2ulyXriSvx3i+r1z6ycfmfehtfed/H+1WOc2iIqiCOgrAJC21sYRFLO6LAM+e6Hq0RQ2ULQ99cwy8OdHNCyIs4o0043ce9hQBm6Tt9PB6g4qehpGFPZlAPH52u/X1MAnDzcCeRAMrs7Jy5DoLkYATksoWEyflbyqY7s7n9/WgUIrBdkNNSgKoKkbd+SFIq/6KOP5llPOjnaq7J7QIz/LOzUlY4ODcTmqL3uB06hXYkpR3BGx31V3nfaVQA3Wi+90u1ZVU99ukEIelnt2uvy+45tSpQ6nvXPgAnrrsDlwxaxUrRwsFz8HRHPYBw1+ktv8CA9FC7oSOuBnuYaLcBrvDqHU7jfU6T5LNKwJA9aaCqKMRRDvsOnV3RJp0og11Pa0nSMrRIK9VUtLLE3M6d+Dui36IM57ehqWr3oD+zGRYTFmtowQcQv9HC9Hy6ye42WCfZeDz81NSxFpfVqZbXVU0qsCk5OvV8xdGSyWmdD9oAW5v1I2sjO3ZkL2V1fv90aoidJzypca2cc3Jf8a7pq/CHS8uwJfXnIvthW7FsbI74Uj3Sz9GOScC/fNqDXmQTRXS87mlFARnzYwnll3U1JZFmR7g7dba9Bjh1F4Ot4IKjSUY0vslKzs0CLle3qZ70GLS5c16c4rBqqL8kloN1PsqX9K9aea7+42gHEfaKeLDJz+MNRd/HjedfB+unPYnloQWg4F52Dh8qO8lHk+Jtv+INWSjpp+MarjAYvvnfVNxSXOrlJWP8pY07BaClRLUl//g8Fma7FJqmfVAU3Q9WMfrzFF9ZkdxQ5GTtGoN40lev4cfblVmbST0xBnmI/xHdhcVDo6A8++UlH0+t28qrlxxPVbnZnBOjYOy9OG2Hm6OZPz9/q6EHNG4eTlHuIQaPY7mzN+Yn1N9JMMq0mQ/icquHmpwLa/LXotHVPEalD5EP23l9VUc+fUc9UoOKQU/9x7OLSndelJfHwesckRqtKyVdnLbOjQ4hUPuATP+3v4r3n8LMAAsR90w+kkNLQAAAABJRU5ErkJggg==') 40px 30px no-repeat;
168
- border: none;
169
- box-sizing: border-box;
170
- color: #373e40;
171
- font-size: 24px;
172
- font-weight: 700;
173
- height: 90px;
174
- padding: 40px 40px 0 120px;
175
- text-transform: uppercase;
176
- width: 100%;
177
- }
178
-
179
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container div.actions {
180
- box-sizing: border-box;
181
- padding: 30px 40px;
182
- background-color: #eaeaea;
183
- }
184
-
185
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button {
186
- background: #ec5d60;
187
- border: none;
188
- box-shadow: none;
189
- color: #ffffff;
190
- font-size: 15px;
191
- font-weight: 700;
192
- height: auto;
193
- line-height: 20px;
194
- padding: 10px 15px;
195
- text-transform: uppercase;
196
- -webkit-transition: 0.3s ease;
197
- -moz-transition: 0.3s ease;
198
- -ms-transition: 0.3s ease;
199
- -o-transition: 0.3s ease;
200
- transition: 0.3s ease;
201
- }
202
-
203
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button.button-primary {
204
- background: transparent;
205
- box-shadow: none;
206
- color: #8d9192;
207
- font-weight: 400;
208
- float: right;
209
- line-height: 40px;
210
- padding: 0;
211
- text-decoration: underline;
212
- text-shadow: none;
213
- text-transform: none;
214
- }
215
-
216
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button:hover {
217
- background: #e83f42;
218
- }
219
-
220
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button.button-primary:hover {
221
- background: transparent;
222
- }
223
-
224
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button:focus {
225
- box-shadow: none;
226
- outline: none;
227
- }
228
-
229
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button:active {
230
- box-shadow: none;
231
- transform: translateY(0);
232
- }
233
-
234
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button:disabled {
235
- cursor: not-allowed;
236
- }
237
-
238
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button.button-primary:hover {
239
- text-decoration: none;
240
- }
241
-
242
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container div.revive_network-container {
243
- background-color: #ffffff;
244
- }
245
-
246
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container ul.ti-list {
247
- margin: 0;
248
- }
249
-
250
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container ul.ti-list li {
251
- color: #373e40;
252
- font-size: 13px;
253
- margin-bottom: 5px;
254
- }
255
-
256
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container ul.ti-list li label {
257
- margin-left: 10px;
258
- line-height: 28px;
259
- font-size: 15px;
260
- }
261
-
262
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container ul.ti-list input[type=radio] {
263
- margin-top: 1px;
264
- }
265
-
266
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container #TB_ajaxContent {
267
- box-sizing: border-box;
268
- height: auto !important;
269
- padding: 20px 40px;
270
- width: 100% !important;
271
- }
272
-
273
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container li div textarea {
274
- padding: 10px 15px;
275
- width: 100%;
276
- }
277
-
278
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container ul.ti-list li div {
279
- margin: 10px 30px;
280
- }
281
-
282
- .<?php echo $key; ?>-container #TB_title #TB_ajaxWindowTitle {
283
- box-sizing: border-box;
284
- display: block;
285
- float: none;
286
- font-weight: 700;
287
- line-height: 1;
288
- padding: 0;
289
- text-align: left;
290
- width: 100%;
291
- }
292
-
293
- .<?php echo $key; ?>-container #TB_title #TB_ajaxWindowTitle span {
294
- color: #8d9192;
295
- display: block;
296
- font-size: 15px;
297
- font-weight: 400;
298
- margin-top: 5px;
299
- text-transform: none;
300
- }
301
-
302
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container .actions {
303
- width: 100%;
304
- display: block;
305
- position: absolute;
306
- left: 0;
307
- bottom: 0;
308
- }
309
-
310
- .theme-install-php .<?php echo $key; ?>-container #TB_closeWindowButton .tb-close-icon:before {
311
- font-size: 32px;
312
- }
313
-
314
- .<?php echo $key; ?>-container #TB_closeWindowButton .tb-close-icon {
315
- color: #eee;
316
- }
317
-
318
- .<?php echo $key; ?>-container #TB_closeWindowButton {
319
- left: auto;
320
- right: -5px;
321
- top: -35px;
322
- color: #eee;
323
- }
324
-
325
- .<?php echo $key; ?>-container #TB_closeWindowButton .tb-close-icon {
326
- text-align: right;
327
- line-height: 25px;
328
- width: 25px;
329
- height: 25px;
330
- }
331
-
332
- .<?php echo $key; ?>-container #TB_closeWindowButton:focus .tb-close-icon {
333
- box-shadow: none;
334
- outline: none;
335
- }
336
-
337
- .<?php echo $key; ?>-container #TB_closeWindowButton .tb-close-icon:before {
338
- font: normal 25px dashicons;
339
- }
340
-
341
- body.<?php echo $suffix; ?> .<?php echo $key; ?>-container {
342
- margin: auto !important;
343
- height: 500px !important;
344
- top: 0 !important;
345
- left: 0 !important;
346
- bottom: 0 !important;
347
- right: 0 !important;
348
- width: 600px !important;
349
- }
350
- </style>
351
- <?php
352
- }
353
-
354
- /**
355
- * Loads the js
356
- *
357
- * @param string $type The type of product.
358
- * @param string $key The product key.
359
- * @param string $src The url that will hijack the deactivate button url.
360
- */
361
- function add_js( $type, $key, $src ) {
362
- $heading = 'plugin' === $type ? $this->heading_plugin : str_replace( '{theme}', $this->product->get_name(), $this->heading_theme );
363
- $heading = apply_filters( $this->product->get_key() . '_feedback_deactivate_heading', $heading );
364
- ?>
365
- <script type="text/javascript" id="ti-deactivate-js">
366
- (function ($) {
367
- $(document).ready(function () {
368
- var auto_trigger = false;
369
- var target_element = 'tr[data-plugin^="<?php echo $this->product->get_slug(); ?>/"] span.deactivate a';
370
- <?php
371
- if ( 'theme' === $type ) {
372
- ?>
373
- auto_trigger = true;
374
- if ($('a.ti-auto-anchor').length == 0) {
375
- $('body').append($('<a class="ti-auto-anchor" href=""></a>'));
376
- }
377
- target_element = 'a.ti-auto-anchor';
378
- <?php
379
- }
380
- ?>
381
-
382
- if (auto_trigger) {
383
- setTimeout(function () {
384
- $('a.ti-auto-anchor').trigger('click');
385
- }, <?php echo self::AUTO_TRIGGER_DEACTIVATE_WINDOW_SECONDS * 1000; ?> );
386
- }
387
- $(document).on('thickbox:removed', function () {
388
- $.ajax({
389
- url: ajaxurl,
390
- method: 'post',
391
- data: {
392
- 'action': '<?php echo $key . __CLASS__; ?>',
393
- 'nonce': '<?php echo wp_create_nonce( (string) __CLASS__ ); ?>',
394
- 'type': '<?php echo $type; ?>',
395
- 'key': '<?php echo $key; ?>'
396
- },
397
- });
398
- });
399
- var href = $(target_element).attr('href');
400
- $('#<?php echo $key; ?>ti-deactivate-no').attr('data-ti-action', href).on('click', function (e) {
401
- e.preventDefault();
402
- e.stopPropagation();
403
-
404
- $('body').unbind('thickbox:removed');
405
- tb_remove();
406
- var redirect = $(this).attr('data-ti-action');
407
- if (redirect != '') {
408
- location.href = redirect;
409
- }
410
- });
411
-
412
- $('#<?php echo $key; ?> ul.ti-list label, #<?php echo $key; ?> ul.ti-list input[name="ti-deactivate-option"]').on('click', function (e) {
413
- $('#<?php echo $key; ?>ti-deactivate-yes').val($('#<?php echo $key; ?>ti-deactivate-yes').attr('data-after-text'));
414
-
415
- var radio = $(this).prop('tagName') === 'LABEL' ? $(this).parent() : $(this);
416
- if (radio.parent().find('textarea').length > 0 && radio.parent().find('textarea').val().length === 0) {
417
- $('#<?php echo $key; ?>ti-deactivate-yes').attr('disabled', 'disabled');
418
- radio.parent().find('textarea').on('keyup', function (ee) {
419
- if ($(this).val().length === 0) {
420
- $('#<?php echo $key; ?>ti-deactivate-yes').attr('disabled', 'disabled');
421
- } else {
422
- $('#<?php echo $key; ?>ti-deactivate-yes').removeAttr('disabled');
423
- }
424
- });
425
- } else {
426
- $('#<?php echo $key; ?>ti-deactivate-yes').removeAttr('disabled');
427
- }
428
- });
429
-
430
- $('#<?php echo $key; ?>ti-deactivate-yes').attr('data-ti-action', href).on('click', function (e) {
431
- e.preventDefault();
432
- e.stopPropagation();
433
- $.ajax({
434
- url: ajaxurl,
435
- method: 'post',
436
- data: {
437
- 'action': '<?php echo $key . __CLASS__; ?>',
438
- 'nonce': '<?php echo wp_create_nonce( (string) __CLASS__ ); ?>',
439
- 'id': $('#<?php echo $key; ?> input[name="ti-deactivate-option"]:checked').parent().attr('ti-option-id'),
440
- 'msg': $('#<?php echo $key; ?> input[name="ti-deactivate-option"]:checked').parent().find('textarea').val(),
441
- 'type': '<?php echo $type; ?>',
442
- 'key': '<?php echo $key; ?>'
443
- },
444
- });
445
- var redirect = $(this).attr('data-ti-action');
446
- if (redirect != '') {
447
- location.href = redirect;
448
- } else {
449
- $('body').unbind('thickbox:removed');
450
- tb_remove();
451
- }
452
- });
453
-
454
- $(target_element).attr('name', '<?php echo wp_kses( $heading, array( 'span' => array() ) ); ?>').attr('href', '<?php echo $src; ?>').addClass('thickbox');
455
- var thicbox_timer;
456
- $(target_element).on('click', function () {
457
- tiBindThickbox();
458
- });
459
-
460
- function tiBindThickbox() {
461
- var thicbox_timer = setTimeout(function () {
462
- if ($("#<?php echo esc_html( $key ); ?>").is(":visible")) {
463
- $("body").trigger('thickbox:iframe:loaded');
464
- $("#TB_window").addClass("<?php echo $key; ?>-container");
465
- clearTimeout(thicbox_timer);
466
- $('body').unbind('thickbox:removed');
467
- } else {
468
- tiBindThickbox();
469
- }
470
- }, 100);
471
- }
472
- });
473
- })(jQuery);
474
- </script>
475
- <?php
476
- }
477
-
478
- /**
479
- * Generates the HTML
480
- *
481
- * @param string $type The type of product.
482
- * @param string $key The product key.
483
- */
484
- function get_html( $type, $key ) {
485
- $options = 'plugin' === $type ? $this->options_plugin : $this->options_theme;
486
- $button_submit_before = 'plugin' === $type ? $this->button_submit_before : 'Submit';
487
- $button_submit = 'plugin' === $type ? $this->button_submit : 'Submit';
488
- $options = $this->randomize_options( apply_filters( $this->product->get_key() . '_feedback_deactivate_options', $options ) );
489
- $button_submit_before = apply_filters( $this->product->get_key() . '_feedback_deactivate_button_submit_before', $button_submit_before );
490
- $button_submit = apply_filters( $this->product->get_key() . '_feedback_deactivate_button_submit', $button_submit );
491
- $button_cancel = apply_filters( $this->product->get_key() . '_feedback_deactivate_button_cancel', $this->button_cancel );
492
-
493
- $options += $this->other;
494
-
495
- $list = '';
496
- foreach ( $options as $title => $attributes ) {
497
- $id = $attributes['id'];
498
- $list .= '<li ti-option-id="' . $id . '"><input type="radio" name="ti-deactivate-option" id="' . $key . $id . '"><label for="' . $key . $id . '">' . str_replace( '{theme}', $this->product->get_name(), $title ) . '</label>';
499
- if ( array_key_exists( 'type', $attributes ) ) {
500
- $list .= '<div>';
501
- $placeholder = array_key_exists( 'placeholder', $attributes ) ? $attributes['placeholder'] : '';
502
- switch ( $attributes['type'] ) {
503
- case 'text':
504
- $list .= '<textarea style="width: 100%" rows="1" name="comments" placeholder="' . $placeholder . '"></textarea>';
505
- break;
506
- case 'textarea':
507
- $list .= '<textarea style="width: 100%" rows="2" name="comments" placeholder="' . $placeholder . '"></textarea>';
508
- break;
509
- }
510
- $list .= '</div>';
511
- }
512
- $list .= '</li>';
513
- }
514
-
515
- return '<div id="' . $this->product->get_key() . '">'
516
- . '<ul class="ti-list">' . $list . '</ul>'
517
- . '<div class="actions">'
518
- . get_submit_button(
519
- $button_submit, 'secondary', $this->product->get_key() . 'ti-deactivate-yes', false, array(
520
- 'data-after-text' => $button_submit,
521
- 'disabled' => true,
522
- )
523
- )
524
- . get_submit_button( $button_cancel, 'primary', $this->product->get_key() . 'ti-deactivate-no', false )
525
- . '</div></div>';
526
- }
527
-
528
- /**
529
- * Called when the deactivate button is clicked
530
- */
531
- function post_deactivate() {
532
- check_ajax_referer( (string) __CLASS__, 'nonce' );
533
-
534
- if ( ! empty( $_POST['id'] ) ) {
535
- $this->call_api(
536
- array(
537
- 'type' => 'deactivate',
538
- 'id' => $_POST['id'],
539
- 'comment' => isset( $_POST['msg'] ) ? $_POST['msg'] : '',
540
- )
541
- );
542
- }
543
-
544
- $this->post_deactivate_or_cancel();
545
- }
546
-
547
- /**
548
- * Called when the deactivate/cancel button is clicked
549
- */
550
- private function post_deactivate_or_cancel() {
551
- if ( isset( $_POST['type'] ) && isset( $_POST['key'] ) && 'theme' === $_POST['type'] ) {
552
- set_transient( 'ti_sdk_pause_' . $_POST['key'], true, PAUSE_DEACTIVATE_WINDOW_DAYS * DAY_IN_SECONDS );
553
- }
554
- }
555
- }
556
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-feedback-factory.php DELETED
@@ -1,50 +0,0 @@
1
- <?php
2
- /**
3
- * The feedback factory class for ThemeIsle SDK
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Feedback
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- // Exit if accessed directly.
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
- if ( ! class_exists( 'ThemeIsle_SDK_Feedback_Factory' ) ) :
16
- /**
17
- * Feedback model for ThemeIsle SDK.
18
- */
19
- class ThemeIsle_SDK_Feedback_Factory {
20
-
21
- /**
22
- * @var array $instances collection of the instances that are registered with the factory
23
- */
24
- private $_instances = array();
25
-
26
- /**
27
- * ThemeIsle_SDK_Feedback_Factory constructor.
28
- *
29
- * @param ThemeIsle_SDK_Product $product_object Product Object.
30
- * @param array $feedback_types the feedback types.
31
- */
32
- public function __construct( $product_object, $feedback_types ) {
33
- if ( $product_object instanceof ThemeIsle_SDK_Product && $feedback_types && is_array( $feedback_types ) ) {
34
- foreach ( $feedback_types as $type ) {
35
- $class = 'ThemeIsle_SDK_Feedback_' . ucwords( $type );
36
- $instance = new $class( $product_object );
37
- $this->_instances[ $type ] = $instance;
38
- $instance->setup_hooks();
39
- }
40
- }
41
- }
42
-
43
- /**
44
- * Get the registered instances
45
- */
46
- public function get_instances() {
47
- return $this->_instances;
48
- }
49
- }
50
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-feedback-review.php DELETED
@@ -1,209 +0,0 @@
1
- <?php
2
- /**
3
- * The review feedback model class for ThemeIsle SDK
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Feedback
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- // Exit if accessed directly.
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
- if ( ! class_exists( 'ThemeIsle_SDK_Feedback_Review' ) ) :
16
- /**
17
- * Deactivate feedback model for ThemeIsle SDK.
18
- */
19
- class ThemeIsle_SDK_Feedback_Review extends ThemeIsle_SDK_Feedback {
20
-
21
- /**
22
- * @var string $heading The heading of the modal
23
- */
24
- private $heading = 'Hey, it’s great to see you have <b>{product}</b> active for a few days now. How is everything going? If you can spare a few moments to rate it on WordPress.org it would help us a lot (and boost my motivation). Cheers! <br/> <br/>~ {developer}, developer of {product}';
25
-
26
- /**
27
- * @var string $msg The text of the modal
28
- */
29
- private $msg = '';
30
-
31
- /**
32
- * @var string $button_cancel The text of the cancel button
33
- */
34
- private $button_cancel = 'No, thanks.';
35
- /**
36
- * @var array Developers who work for each type of product for review purpose.
37
- */
38
- private $developers = array(
39
- 'plugin' => array( 'Marius', 'Bogdan' ),
40
- 'theme' => array( 'Rodica', 'Andrei', 'Bogdan', 'Cristi' ),
41
- );
42
- /**
43
- * @var string $button_already The text of the already did it button
44
- */
45
- private $button_do = 'Ok, I will gladly help.';
46
-
47
- /**
48
- * ThemeIsle_SDK_Feedback_Deactivate constructor.
49
- *
50
- * @param ThemeIsle_SDK_Product $product_object The product object.
51
- */
52
- public function __construct( $product_object ) {
53
- parent::__construct( $product_object );
54
- }
55
-
56
- /**
57
- * Registers the hooks
58
- */
59
- public function setup_hooks_child() {
60
- add_action( 'wp_ajax_' . $this->product->get_key() . __CLASS__, array( $this, 'dismiss' ) );
61
- }
62
-
63
- /**
64
- * Either we can notify or not.
65
- *
66
- * @return bool Notification available or not.
67
- */
68
- public function can_notify() {
69
- if ( ! $this->product->is_wordpress_available() ) {
70
- $this->disable();
71
-
72
- return false;
73
- }
74
- $show = get_option( $this->product->get_key() . '_review_flag', 'yes' );
75
- if ( 'no' === $show ) {
76
- return false;
77
- }
78
- $finally_show = apply_filters( $this->product->get_key() . '_feedback_review_trigger', true );
79
- if ( false !== $finally_show ) {
80
- if ( is_array( $finally_show ) && ! empty( $finally_show ) ) {
81
- $this->heading = $finally_show['heading'];
82
- $this->msg = $finally_show['msg'];
83
- }
84
- } else {
85
- return false;
86
- }
87
-
88
- return true;
89
- }
90
-
91
- /**
92
- * Shows the notification
93
- */
94
- function show_notification() {
95
- add_action( 'admin_notices', array( $this, 'admin_notices' ) );
96
- }
97
-
98
- /**
99
- * Shows the admin notice
100
- */
101
- function admin_notices() {
102
- $id = $this->product->get_key() . '_review';
103
-
104
- $this->add_css( $this->product->get_key() );
105
- $this->add_js( $this->product->get_key() );
106
-
107
- echo '<div class="notice notice-success is-dismissible" id="' . $id . '" ><div class="themeisle-review-box">' . $this->get_html( $this->product->get_key() ) . '</div></div>';
108
- }
109
-
110
- /**
111
- * Loads the css
112
- *
113
- * @param string $key The product key.
114
- */
115
- function add_css( $key ) {
116
- ?>
117
- <style type="text/css" id="<?php echo $key; ?>ti-review-css">
118
- #<?php echo $key; ?>-review-notification {
119
- padding-bottom: 5px;
120
- }
121
-
122
- #<?php echo $key; ?>-review-notification .review-dismiss {
123
- margin-left: 5px;
124
- }
125
- </style>
126
- <?php
127
- }
128
-
129
- /**
130
- * Loads the js
131
- *
132
- * @param string $key The product key.
133
- */
134
- function add_js( $key ) {
135
- ?>
136
- <script type="text/javascript" id="<?php echo $key; ?>ti-review-js">
137
- (function ($) {
138
- $(document).ready(function () {
139
- $('#<?php echo $key; ?>_review').on('click', '.notice-dismiss, .review-dismiss', function (e) {
140
-
141
- $.ajax({
142
- url: ajaxurl,
143
- method: "post",
144
- data: {
145
- 'nonce': '<?php echo wp_create_nonce( (string) __CLASS__ ); ?>',
146
- 'action': '<?php echo $this->product->get_key() . __CLASS__; ?>'
147
- },
148
- success: function () {
149
- $('#<?php echo $key; ?>_review').html('<p><b>Thanks for your answer.</b></p>');
150
- }
151
- });
152
- });
153
- });
154
- })(jQuery);
155
- </script>
156
- <?php
157
- }
158
-
159
- /**
160
- * Generates the HTML
161
- *
162
- * @param string $key The product key.
163
- */
164
- function get_html( $key ) {
165
- $link = 'https://wordpress.org/support/' . $this->product->get_type() . '/' . $this->product->get_slug() . '/reviews/#wporg-footer';
166
- $heading = apply_filters( $this->product->get_key() . '_feedback_review_heading', $this->heading );
167
- $heading = str_replace(
168
- array( '{product}' ),
169
- $this->product->get_friendly_name(), $heading
170
- );
171
- $heading = str_replace( '{developer}', $this->developers[ $this->product->get_type() ][ rand( 0, ( count( $this->developers[ $this->product->get_type() ] ) - 1 ) ) ], $heading );
172
-
173
- $button_cancel = apply_filters( $this->product->get_key() . '_feedback_review_button_cancel', $this->button_cancel );
174
- $button_do = apply_filters( $this->product->get_key() . '_feedback_review_button_do', $this->button_do );
175
- $msg = apply_filters( $this->product->get_key() . '_feedback_review_message', $this->msg );
176
-
177
- return '<div id="' . $this->product->get_key() . '-review-notification" class="themeisle-sdk-review-box">'
178
- . '<p>' . $heading . '</p>'
179
- . ( $msg ? '<p>' . $msg . '</p>' : '' )
180
- . '<div class="actions">'
181
- . '<a href="' . $link . '" target="_blank" class="button button-primary review-dismiss"> ' . $button_do . '</a>'
182
- . get_submit_button( $button_cancel, 'review-dismiss ' . $this->product->get_key() . '-ti-review', $this->product->get_key() . 'ti-review-no', false )
183
- . '</div></div>';
184
- }
185
-
186
- /**
187
- * Called when the either button is clicked
188
- */
189
- function dismiss() {
190
- check_ajax_referer( (string) __CLASS__, 'nonce' );
191
-
192
- $this->disable();
193
- }
194
-
195
- /**
196
- * Disables the notification
197
- */
198
- protected function disable() {
199
- update_option( $this->product->get_key() . '_review_flag', 'no' );
200
- }
201
-
202
- /**
203
- * Enables the notification
204
- */
205
- protected function enable() {
206
- update_option( $this->product->get_key() . '_review_flag', 'yes' );
207
- }
208
- }
209
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-feedback-translate.php DELETED
@@ -1,983 +0,0 @@
1
- <?php
2
- /**
3
- * The Translate feedback model class for ThemeIsle SDK
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Feedback
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- // Exit if accessed directly.
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
- if ( ! class_exists( 'ThemeIsle_SDK_Feedback_Translate' ) ) :
16
- /**
17
- * Translate feedback model for ThemeIsle SDK.
18
- */
19
- class ThemeIsle_SDK_Feedback_Translate extends ThemeIsle_SDK_Feedback {
20
-
21
- /**
22
- * @var string $heading The heading of the modal
23
- */
24
- private $heading = 'Improve {product}';
25
- /**
26
- * @var string The message.
27
- */
28
- private $msg = 'Translating <b>{product}</b> into as many languages as possible is a huge project. We still need help with a lot of them, so if you are good at translating into <b>{language}</b>, it would be greatly appreciated.
29
- The process is easy, and you can join by following the link below!';
30
- /**
31
- * @var string $button_cancel The text of the cancel button
32
- */
33
- private $button_cancel = 'No, thanks.';
34
- /**
35
- * @var string $button_already The text of the already did it button
36
- */
37
- private $button_do = 'Ok, I will gladly help.';
38
- /**
39
- * @var array Array of available locals.
40
- */
41
- private $locales = array(
42
- 'af' => array(
43
- 'slug' => 'af',
44
- 'name' => 'Afrikaans',
45
- ),
46
- 'ak' => array(
47
- 'slug' => 'ak',
48
- 'name' => 'Akan',
49
- ),
50
- 'am' => array(
51
- 'slug' => 'am',
52
- 'name' => 'Amharic',
53
- ),
54
- 'ar' => array(
55
- 'slug' => 'ar',
56
- 'name' => 'Arabic',
57
- ),
58
- 'arq' => array(
59
- 'slug' => 'arq',
60
- 'name' => 'Algerian Arabic',
61
- ),
62
- 'ary' => array(
63
- 'slug' => 'ary',
64
- 'name' => 'Moroccan Arabic',
65
- ),
66
- 'as' => array(
67
- 'slug' => 'as',
68
- 'name' => 'Assamese',
69
- ),
70
- 'ast' => array(
71
- 'slug' => 'ast',
72
- 'name' => 'Asturian',
73
- ),
74
- 'az' => array(
75
- 'slug' => 'az',
76
- 'name' => 'Azerbaijani',
77
- ),
78
- 'azb' => array(
79
- 'slug' => 'azb',
80
- 'name' => 'South Azerbaijani',
81
- ),
82
- 'az_TR' => array(
83
- 'slug' => 'az-tr',
84
- 'name' => 'Azerbaijani (Turkey)',
85
- ),
86
- 'ba' => array(
87
- 'slug' => 'ba',
88
- 'name' => 'Bashkir',
89
- ),
90
- 'bal' => array(
91
- 'slug' => 'bal',
92
- 'name' => 'Catalan (Balear)',
93
- ),
94
- 'bcc' => array(
95
- 'slug' => 'bcc',
96
- 'name' => 'Balochi Southern',
97
- ),
98
- 'bel' => array(
99
- 'slug' => 'bel',
100
- 'name' => 'Belarusian',
101
- ),
102
- 'bg_BG' => array(
103
- 'slug' => 'bg',
104
- 'name' => 'Bulgarian',
105
- ),
106
- 'bn_BD' => array(
107
- 'slug' => 'bn',
108
- 'name' => 'Bengali',
109
- ),
110
- 'bo' => array(
111
- 'slug' => 'bo',
112
- 'name' => 'Tibetan',
113
- ),
114
- 'bre' => array(
115
- 'slug' => 'br',
116
- 'name' => 'Breton',
117
- ),
118
- 'bs_BA' => array(
119
- 'slug' => 'bs',
120
- 'name' => 'Bosnian',
121
- ),
122
- 'ca' => array(
123
- 'slug' => 'ca',
124
- 'name' => 'Catalan',
125
- ),
126
- 'ceb' => array(
127
- 'slug' => 'ceb',
128
- 'name' => 'Cebuano',
129
- ),
130
- 'ckb' => array(
131
- 'slug' => 'ckb',
132
- 'name' => 'Kurdish (Sorani)',
133
- ),
134
- 'co' => array(
135
- 'slug' => 'co',
136
- 'name' => 'Corsican',
137
- ),
138
- 'cs_CZ' => array(
139
- 'slug' => 'cs',
140
- 'name' => 'Czech',
141
- ),
142
- 'cy' => array(
143
- 'slug' => 'cy',
144
- 'name' => 'Welsh',
145
- ),
146
- 'da_DK' => array(
147
- 'slug' => 'da',
148
- 'name' => 'Danish',
149
- ),
150
- 'de_DE' => array(
151
- 'slug' => 'de',
152
- 'name' => 'German',
153
- ),
154
- 'de_CH' => array(
155
- 'slug' => 'de-ch',
156
- 'name' => 'German (Switzerland)',
157
- ),
158
- 'dv' => array(
159
- 'slug' => 'dv',
160
- 'name' => 'Dhivehi',
161
- ),
162
- 'dzo' => array(
163
- 'slug' => 'dzo',
164
- 'name' => 'Dzongkha',
165
- ),
166
- 'el' => array(
167
- 'slug' => 'el',
168
- 'name' => 'Greek',
169
- ),
170
- 'art_xemoji' => array(
171
- 'slug' => 'art-xemoji',
172
- 'name' => 'Emoji',
173
- ),
174
- 'en_US' => array(
175
- 'slug' => 'en',
176
- 'name' => 'English',
177
- ),
178
- 'en_AU' => array(
179
- 'slug' => 'en-au',
180
- 'name' => 'English (Australia)',
181
- ),
182
- 'en_CA' => array(
183
- 'slug' => 'en-ca',
184
- 'name' => 'English (Canada)',
185
- ),
186
- 'en_GB' => array(
187
- 'slug' => 'en-gb',
188
- 'name' => 'English (UK)',
189
- ),
190
- 'en_NZ' => array(
191
- 'slug' => 'en-nz',
192
- 'name' => 'English (New Zealand)',
193
- ),
194
- 'en_ZA' => array(
195
- 'slug' => 'en-za',
196
- 'name' => 'English (South Africa)',
197
- ),
198
- 'eo' => array(
199
- 'slug' => 'eo',
200
- 'name' => 'Esperanto',
201
- ),
202
- 'es_ES' => array(
203
- 'slug' => 'es',
204
- 'name' => 'Spanish (Spain)',
205
- ),
206
- 'es_AR' => array(
207
- 'slug' => 'es-ar',
208
- 'name' => 'Spanish (Argentina)',
209
- ),
210
- 'es_CL' => array(
211
- 'slug' => 'es-cl',
212
- 'name' => 'Spanish (Chile)',
213
- ),
214
- 'es_CO' => array(
215
- 'slug' => 'es-co',
216
- 'name' => 'Spanish (Colombia)',
217
- ),
218
- 'es_CR' => array(
219
- 'slug' => 'es-cr',
220
- 'name' => 'Spanish (Costa Rica)',
221
- ),
222
- 'es_GT' => array(
223
- 'slug' => 'es-gt',
224
- 'name' => 'Spanish (Guatemala)',
225
- ),
226
- 'es_MX' => array(
227
- 'slug' => 'es-mx',
228
- 'name' => 'Spanish (Mexico)',
229
- ),
230
- 'es_PE' => array(
231
- 'slug' => 'es-pe',
232
- 'name' => 'Spanish (Peru)',
233
- ),
234
- 'es_PR' => array(
235
- 'slug' => 'es-pr',
236
- 'name' => 'Spanish (Puerto Rico)',
237
- ),
238
- 'es_VE' => array(
239
- 'slug' => 'es-ve',
240
- 'name' => 'Spanish (Venezuela)',
241
- ),
242
- 'et' => array(
243
- 'slug' => 'et',
244
- 'name' => 'Estonian',
245
- ),
246
- 'eu' => array(
247
- 'slug' => 'eu',
248
- 'name' => 'Basque',
249
- ),
250
- 'fa_IR' => array(
251
- 'slug' => 'fa',
252
- 'name' => 'Persian',
253
- ),
254
- 'fa_AF' => array(
255
- 'slug' => 'fa-af',
256
- 'name' => 'Persian (Afghanistan)',
257
- ),
258
- 'fuc' => array(
259
- 'slug' => 'fuc',
260
- 'name' => 'Fulah',
261
- ),
262
- 'fi' => array(
263
- 'slug' => 'fi',
264
- 'name' => 'Finnish',
265
- ),
266
- 'fo' => array(
267
- 'slug' => 'fo',
268
- 'name' => 'Faroese',
269
- ),
270
- 'fr_FR' => array(
271
- 'slug' => 'fr',
272
- 'name' => 'French (France)',
273
- ),
274
- 'fr_BE' => array(
275
- 'slug' => 'fr-be',
276
- 'name' => 'French (Belgium)',
277
- ),
278
- 'fr_CA' => array(
279
- 'slug' => 'fr-ca',
280
- 'name' => 'French (Canada)',
281
- ),
282
- 'frp' => array(
283
- 'slug' => 'frp',
284
- 'name' => 'Arpitan',
285
- ),
286
- 'fur' => array(
287
- 'slug' => 'fur',
288
- 'name' => 'Friulian',
289
- ),
290
- 'fy' => array(
291
- 'slug' => 'fy',
292
- 'name' => 'Frisian',
293
- ),
294
- 'ga' => array(
295
- 'slug' => 'ga',
296
- 'name' => 'Irish',
297
- ),
298
- 'gd' => array(
299
- 'slug' => 'gd',
300
- 'name' => 'Scottish Gaelic',
301
- ),
302
- 'gl_ES' => array(
303
- 'slug' => 'gl',
304
- 'name' => 'Galician',
305
- ),
306
- 'gn' => array(
307
- 'slug' => 'gn',
308
- 'name' => 'Guaraní',
309
- ),
310
- 'gsw' => array(
311
- 'slug' => 'gsw',
312
- 'name' => 'Swiss German',
313
- ),
314
- 'gu' => array(
315
- 'slug' => 'gu',
316
- 'name' => 'Gujarati',
317
- ),
318
- 'hat' => array(
319
- 'slug' => 'hat',
320
- 'name' => 'Haitian Creole',
321
- ),
322
- 'hau' => array(
323
- 'slug' => 'hau',
324
- 'name' => 'Hausa',
325
- ),
326
- 'haw_US' => array(
327
- 'slug' => 'haw',
328
- 'name' => 'Hawaiian',
329
- ),
330
- 'haz' => array(
331
- 'slug' => 'haz',
332
- 'name' => 'Hazaragi',
333
- ),
334
- 'he_IL' => array(
335
- 'slug' => 'he',
336
- 'name' => 'Hebrew',
337
- ),
338
- 'hi_IN' => array(
339
- 'slug' => 'hi',
340
- 'name' => 'Hindi',
341
- ),
342
- 'hr' => array(
343
- 'slug' => 'hr',
344
- 'name' => 'Croatian',
345
- ),
346
- 'hu_HU' => array(
347
- 'slug' => 'hu',
348
- 'name' => 'Hungarian',
349
- ),
350
- 'hy' => array(
351
- 'slug' => 'hy',
352
- 'name' => 'Armenian',
353
- ),
354
- 'id_ID' => array(
355
- 'slug' => 'id',
356
- 'name' => 'Indonesian',
357
- ),
358
- 'ido' => array(
359
- 'slug' => 'ido',
360
- 'name' => 'Ido',
361
- ),
362
- 'is_IS' => array(
363
- 'slug' => 'is',
364
- 'name' => 'Icelandic',
365
- ),
366
- 'it_IT' => array(
367
- 'slug' => 'it',
368
- 'name' => 'Italian',
369
- ),
370
- 'ja' => array(
371
- 'slug' => 'ja',
372
- 'name' => 'Japanese',
373
- ),
374
- 'jv_ID' => array(
375
- 'slug' => 'jv',
376
- 'name' => 'Javanese',
377
- ),
378
- 'ka_GE' => array(
379
- 'slug' => 'ka',
380
- 'name' => 'Georgian',
381
- ),
382
- 'kab' => array(
383
- 'slug' => 'kab',
384
- 'name' => 'Kabyle',
385
- ),
386
- 'kal' => array(
387
- 'slug' => 'kal',
388
- 'name' => 'Greenlandic',
389
- ),
390
- 'kin' => array(
391
- 'slug' => 'kin',
392
- 'name' => 'Kinyarwanda',
393
- ),
394
- 'kk' => array(
395
- 'slug' => 'kk',
396
- 'name' => 'Kazakh',
397
- ),
398
- 'km' => array(
399
- 'slug' => 'km',
400
- 'name' => 'Khmer',
401
- ),
402
- 'kn' => array(
403
- 'slug' => 'kn',
404
- 'name' => 'Kannada',
405
- ),
406
- 'ko_KR' => array(
407
- 'slug' => 'ko',
408
- 'name' => 'Korean',
409
- ),
410
- 'kir' => array(
411
- 'slug' => 'kir',
412
- 'name' => 'Kyrgyz',
413
- ),
414
- 'lb_LU' => array(
415
- 'slug' => 'lb',
416
- 'name' => 'Luxembourgish',
417
- ),
418
- 'li' => array(
419
- 'slug' => 'li',
420
- 'name' => 'Limburgish',
421
- ),
422
- 'lin' => array(
423
- 'slug' => 'lin',
424
- 'name' => 'Lingala',
425
- ),
426
- 'lo' => array(
427
- 'slug' => 'lo',
428
- 'name' => 'Lao',
429
- ),
430
- 'lt_LT' => array(
431
- 'slug' => 'lt',
432
- 'name' => 'Lithuanian',
433
- ),
434
- 'lv' => array(
435
- 'slug' => 'lv',
436
- 'name' => 'Latvian',
437
- ),
438
- 'me_ME' => array(
439
- 'slug' => 'me',
440
- 'name' => 'Montenegrin',
441
- ),
442
- 'mg_MG' => array(
443
- 'slug' => 'mg',
444
- 'name' => 'Malagasy',
445
- ),
446
- 'mk_MK' => array(
447
- 'slug' => 'mk',
448
- 'name' => 'Macedonian',
449
- ),
450
- 'ml_IN' => array(
451
- 'slug' => 'ml',
452
- 'name' => 'Malayalam',
453
- ),
454
- 'mlt' => array(
455
- 'slug' => 'mlt',
456
- 'name' => 'Maltese',
457
- ),
458
- 'mn' => array(
459
- 'slug' => 'mn',
460
- 'name' => 'Mongolian',
461
- ),
462
- 'mr' => array(
463
- 'slug' => 'mr',
464
- 'name' => 'Marathi',
465
- ),
466
- 'mri' => array(
467
- 'slug' => 'mri',
468
- 'name' => 'Maori',
469
- ),
470
- 'ms_MY' => array(
471
- 'slug' => 'ms',
472
- 'name' => 'Malay',
473
- ),
474
- 'my_MM' => array(
475
- 'slug' => 'mya',
476
- 'name' => 'Myanmar (Burmese)',
477
- ),
478
- 'ne_NP' => array(
479
- 'slug' => 'ne',
480
- 'name' => 'Nepali',
481
- ),
482
- 'nb_NO' => array(
483
- 'slug' => 'nb',
484
- 'name' => 'Norwegian (Bokmål)',
485
- ),
486
- 'nl_NL' => array(
487
- 'slug' => 'nl',
488
- 'name' => 'Dutch',
489
- ),
490
- 'nl_BE' => array(
491
- 'slug' => 'nl-be',
492
- 'name' => 'Dutch (Belgium)',
493
- ),
494
- 'nn_NO' => array(
495
- 'slug' => 'nn',
496
- 'name' => 'Norwegian (Nynorsk)',
497
- ),
498
- 'oci' => array(
499
- 'slug' => 'oci',
500
- 'name' => 'Occitan',
501
- ),
502
- 'ory' => array(
503
- 'slug' => 'ory',
504
- 'name' => 'Oriya',
505
- ),
506
- 'os' => array(
507
- 'slug' => 'os',
508
- 'name' => 'Ossetic',
509
- ),
510
- 'pa_IN' => array(
511
- 'slug' => 'pa',
512
- 'name' => 'Punjabi',
513
- ),
514
- 'pl_PL' => array(
515
- 'slug' => 'pl',
516
- 'name' => 'Polish',
517
- ),
518
- 'pt_BR' => array(
519
- 'slug' => 'pt-br',
520
- 'name' => 'Portuguese (Brazil)',
521
- ),
522
- 'pt_PT' => array(
523
- 'slug' => 'pt',
524
- 'name' => 'Portuguese (Portugal)',
525
- ),
526
- 'ps' => array(
527
- 'slug' => 'ps',
528
- 'name' => 'Pashto',
529
- ),
530
- 'rhg' => array(
531
- 'slug' => 'rhg',
532
- 'name' => 'Rohingya',
533
- ),
534
- 'ro_RO' => array(
535
- 'slug' => 'ro',
536
- 'name' => 'Romanian',
537
- ),
538
- 'roh' => array(
539
- 'slug' => 'roh',
540
- 'name' => 'Romansh',
541
- ),
542
- 'ru_RU' => array(
543
- 'slug' => 'ru',
544
- 'name' => 'Russian',
545
- ),
546
- 'rue' => array(
547
- 'slug' => 'rue',
548
- 'name' => 'Rusyn',
549
- ),
550
- 'rup_MK' => array(
551
- 'slug' => 'rup',
552
- 'name' => 'Aromanian',
553
- ),
554
- 'sah' => array(
555
- 'slug' => 'sah',
556
- 'name' => 'Sakha',
557
- ),
558
- 'sa_IN' => array(
559
- 'slug' => 'sa-in',
560
- 'name' => 'Sanskrit',
561
- ),
562
- 'scn' => array(
563
- 'slug' => 'scn',
564
- 'name' => 'Sicilian',
565
- ),
566
- 'si_LK' => array(
567
- 'slug' => 'si',
568
- 'name' => 'Sinhala',
569
- ),
570
- 'sk_SK' => array(
571
- 'slug' => 'sk',
572
- 'name' => 'Slovak',
573
- ),
574
- 'sl_SI' => array(
575
- 'slug' => 'sl',
576
- 'name' => 'Slovenian',
577
- ),
578
- 'sna' => array(
579
- 'slug' => 'sna',
580
- 'name' => 'Shona',
581
- ),
582
- 'snd' => array(
583
- 'slug' => 'snd',
584
- 'name' => 'Sindhi',
585
- ),
586
- 'so_SO' => array(
587
- 'slug' => 'so',
588
- 'name' => 'Somali',
589
- ),
590
- 'sq' => array(
591
- 'slug' => 'sq',
592
- 'name' => 'Albanian',
593
- ),
594
- 'sq_XK' => array(
595
- 'slug' => 'sq-xk',
596
- 'name' => 'Shqip (Kosovo)',
597
- ),
598
- 'sr_RS' => array(
599
- 'slug' => 'sr',
600
- 'name' => 'Serbian',
601
- ),
602
- 'srd' => array(
603
- 'slug' => 'srd',
604
- 'name' => 'Sardinian',
605
- ),
606
- 'su_ID' => array(
607
- 'slug' => 'su',
608
- 'name' => 'Sundanese',
609
- ),
610
- 'sv_SE' => array(
611
- 'slug' => 'sv',
612
- 'name' => 'Swedish',
613
- ),
614
- 'sw' => array(
615
- 'slug' => 'sw',
616
- 'name' => 'Swahili',
617
- ),
618
- 'syr' => array(
619
- 'slug' => 'syr',
620
- 'name' => 'Syriac',
621
- ),
622
- 'szl' => array(
623
- 'slug' => 'szl',
624
- 'name' => 'Silesian',
625
- ),
626
- 'ta_IN' => array(
627
- 'slug' => 'ta',
628
- 'name' => 'Tamil',
629
- ),
630
- 'ta_LK' => array(
631
- 'slug' => 'ta-lk',
632
- 'name' => 'Tamil (Sri Lanka)',
633
- ),
634
- 'tah' => array(
635
- 'slug' => 'tah',
636
- 'name' => 'Tahitian',
637
- ),
638
- 'te' => array(
639
- 'slug' => 'te',
640
- 'name' => 'Telugu',
641
- ),
642
- 'tg' => array(
643
- 'slug' => 'tg',
644
- 'name' => 'Tajik',
645
- ),
646
- 'th' => array(
647
- 'slug' => 'th',
648
- 'name' => 'Thai',
649
- ),
650
- 'tir' => array(
651
- 'slug' => 'tir',
652
- 'name' => 'Tigrinya',
653
- ),
654
- 'tl' => array(
655
- 'slug' => 'tl',
656
- 'name' => 'Tagalog',
657
- ),
658
- 'tr_TR' => array(
659
- 'slug' => 'tr',
660
- 'name' => 'Turkish',
661
- ),
662
- 'tt_RU' => array(
663
- 'slug' => 'tt',
664
- 'name' => 'Tatar',
665
- ),
666
- 'tuk' => array(
667
- 'slug' => 'tuk',
668
- 'name' => 'Turkmen',
669
- ),
670
- 'twd' => array(
671
- 'slug' => 'twd',
672
- 'name' => 'Tweants',
673
- ),
674
- 'tzm' => array(
675
- 'slug' => 'tzm',
676
- 'name' => 'Tamazight (Central Atlas)',
677
- ),
678
- 'ug_CN' => array(
679
- 'slug' => 'ug',
680
- 'name' => 'Uighur',
681
- ),
682
- 'uk' => array(
683
- 'slug' => 'uk',
684
- 'name' => 'Ukrainian',
685
- ),
686
- 'ur' => array(
687
- 'slug' => 'ur',
688
- 'name' => 'Urdu',
689
- ),
690
- 'uz_UZ' => array(
691
- 'slug' => 'uz',
692
- 'name' => 'Uzbek',
693
- ),
694
- 'vi' => array(
695
- 'slug' => 'vi',
696
- 'name' => 'Vietnamese',
697
- ),
698
- 'wa' => array(
699
- 'slug' => 'wa',
700
- 'name' => 'Walloon',
701
- ),
702
- 'xho' => array(
703
- 'slug' => 'xho',
704
- 'name' => 'Xhosa',
705
- ),
706
- 'xmf' => array(
707
- 'slug' => 'xmf',
708
- 'name' => 'Mingrelian',
709
- ),
710
- 'yor' => array(
711
- 'slug' => 'yor',
712
- 'name' => 'Yoruba',
713
- ),
714
- 'zh_CN' => array(
715
- 'slug' => 'zh-cn',
716
- 'name' => 'Chinese (China)',
717
- ),
718
- 'zh_HK' => array(
719
- 'slug' => 'zh-hk',
720
- 'name' => 'Chinese (Hong Kong)',
721
- ),
722
- 'zh_TW' => array(
723
- 'slug' => 'zh-tw',
724
- 'name' => 'Chinese (Taiwan)',
725
- ),
726
- 'de_DE_formal' => array(
727
- 'slug' => 'de/formal',
728
- 'name' => 'German (Formal)',
729
- ),
730
- 'nl_NL_formal' => array(
731
- 'slug' => 'nl/formal',
732
- 'name' => 'Dutch (Formal)',
733
- ),
734
- 'de_CH_informal' => array(
735
- 'slug' => 'de-ch/informal',
736
- 'name' => 'Chinese (Taiwan)',
737
- ),
738
- 'pt_PT_ao90' => array(
739
- 'slug' => 'pt/ao90',
740
- 'name' => 'Portuguese (Portugal, AO90)',
741
- ),
742
- );
743
-
744
- /**
745
- * ThemeIsle_SDK_Feedback_Translate constructor.
746
- *
747
- * @param ThemeIsle_SDK_Product $product_object The product object.
748
- */
749
- public function __construct( $product_object ) {
750
- parent::__construct( $product_object );
751
- }
752
-
753
- /**
754
- * Return the locale path.
755
- *
756
- * @param string $locale Locale code.
757
- *
758
- * @return string Locale path.
759
- */
760
- private function get_locale_paths( $locale ) {
761
- if ( empty( $locale ) ) {
762
- return '';
763
- }
764
-
765
- $slug = isset( $this->locales[ $locale ] ) ? $this->locales[ $locale ]['slug'] : '';
766
- if ( empty( $slug ) ) {
767
- return '';
768
- }
769
- if ( strpos( $slug, '/' ) === false ) {
770
- $slug .= '/default';
771
- }
772
- $url = 'https://translate.wordpress.org/projects/wp-' . $this->product->get_type() . 's/' . $this->product->get_slug() . '/' . ( $this->product->get_type() === 'plugin' ? 'dev/' : '' ) . $slug . '?filters%5Bstatus%5D=untranslated&sort%5Bby%5D=random';
773
-
774
- return $url;
775
- }
776
-
777
- /**
778
- * Registers the hooks
779
- */
780
- public function setup_hooks_child() {
781
- add_action( 'wp_ajax_' . $this->product->get_key() . __CLASS__, array( $this, 'dismiss' ) );
782
- }
783
-
784
- /**
785
- * Either we should show the notification or not.
786
- *
787
- * @return bool Valid notification.
788
- */
789
- function can_notify() {
790
- if ( ! $this->product->is_wordpress_available() ) {
791
- $this->disable();
792
- return false;
793
- }
794
- $show = get_option( $this->product->get_key() . '_translate_flag', 'yes' );
795
- if ( 'no' === $show ) {
796
- return false;
797
- }
798
- $lang = $this->get_user_locale();
799
- if ( 'en_US' === $lang ) {
800
- return false;
801
- }
802
- $languages = $this->get_translations();
803
- if ( ! is_array( $languages ) ) {
804
- return false;
805
- }
806
- if ( ! isset( $languages['translations'] ) ) {
807
- return false;
808
- }
809
-
810
- $languages = $languages['translations'];
811
- $available = wp_list_pluck( $languages, 'language' );
812
- if ( in_array( $lang, $available ) ) {
813
- return false;
814
- }
815
- if ( ! isset( $this->locales[ $lang ] ) ) {
816
- return false;
817
- }
818
-
819
- return true;
820
- }
821
-
822
- /**
823
- * Get the user's locale.
824
- */
825
- private function get_user_locale() {
826
- global $wp_version;
827
- if ( version_compare( $wp_version, '4.7.0', '>=' ) ) {
828
- return get_user_locale();
829
- }
830
- $user = wp_get_current_user();
831
- if ( $user ) {
832
- $locale = $user->locale;
833
- }
834
- return $locale ? $locale : get_locale();
835
- }
836
-
837
- /**
838
- * Shows the notification
839
- */
840
- function show_notification() {
841
- add_action( 'admin_notices', array( $this, 'admin_notices' ) );
842
- }
843
-
844
- /**
845
- * Shows the admin notice
846
- */
847
- function admin_notices() {
848
- $id = $this->product->get_key() . '_translate';
849
-
850
- $this->add_css( $this->product->get_key() );
851
- $this->add_js( $this->product->get_key() );
852
- $html = $this->get_html( $this->product->get_key() );
853
-
854
- if ( $html ) {
855
- echo '<div class="notice notice-success is-dismissible" id="' . $id . '" ><div class="themeisle-translate-box">' . $html . '</div></div>';
856
- }
857
- }
858
-
859
- /**
860
- * Loads the css
861
- *
862
- * @param string $key The product key.
863
- */
864
- function add_css( $key ) {
865
- ?>
866
- <style type="text/css" id="<?php echo $key; ?>ti-translate-css">
867
- </style>
868
- <?php
869
- }
870
-
871
- /**
872
- * Loads the js
873
- *
874
- * @param string $key The product key.
875
- */
876
- function add_js( $key ) {
877
- ?>
878
- <script type="text/javascript" id="<?php echo $key; ?>ti-translate-js">
879
- (function ($) {
880
- $(document).ready(function () {
881
- $('#<?php echo $key; ?>_translate').on('click', '.translate-dismiss', function (e) {
882
-
883
- $.ajax({
884
- url: ajaxurl,
885
- method: "post",
886
- data: {
887
- 'nonce': '<?php echo wp_create_nonce( (string) __CLASS__ ); ?>',
888
- 'action': '<?php echo $this->product->get_key() . __CLASS__; ?>'
889
- },
890
- success: function () {
891
- $('#<?php echo $key; ?>_translate').html('<p><b>Thanks for your answer.</b></p>');
892
- }
893
- });
894
- });
895
- });
896
- })(jQuery);
897
- </script>
898
- <?php
899
- }
900
-
901
- /**
902
- * Fetch translations from api.
903
- *
904
- * @return mixed Translation array.
905
- */
906
- private function get_translations() {
907
- $cache_key = $this->product->get_key() . '_all_languages';
908
- $translations = get_transient( $cache_key );
909
-
910
- if ( $translations === false ) {
911
- require_once( ABSPATH . 'wp-admin/includes/translation-install.php' );
912
- $translations = translations_api(
913
- $this->product->get_type() . 's',
914
- array(
915
- 'slug' => $this->product->get_slug(),
916
- 'version' => $this->product->get_version(),
917
- )
918
- );
919
- set_transient( $cache_key, $translations, WEEK_IN_SECONDS );
920
- }
921
-
922
- return $translations;
923
-
924
- }
925
-
926
- /**
927
- * Generates the HTML
928
- *
929
- * @param string $key The product key.
930
- *
931
- * @return void|string Html code of the notification.
932
- */
933
- function get_html( $key ) {
934
- $lang = $this->get_user_locale();
935
- $link = $this->get_locale_paths( $lang );
936
- $heading = apply_filters( $this->product->get_key() . '_feedback_translate_heading', $this->heading );
937
- $product = $this->product->get_friendly_name();
938
- $heading = str_replace(
939
- array( '{product}' ),
940
- $product, $heading
941
- );
942
-
943
- $message = apply_filters( $this->product->get_key() . '_feedback_translation', $this->msg );
944
- $language_meta = $this->locales[ $lang ];
945
- $message = str_replace( '{language}', $language_meta['name'], $message );
946
- $message = str_replace( '{product}', $product, $message );
947
- $button_cancel = apply_filters( $this->product->get_key() . '_feedback_translate_button_cancel', $this->button_cancel );
948
- $button_do = apply_filters( $this->product->get_key() . '_feedback_translate_button_do', $this->button_do );
949
-
950
- return '<div id="' . $this->product->get_key() . '-translate-notification" class="themeisle-sdk-translate-box">'
951
- . '<h2>' . $heading . '</h2>'
952
- . '<p>' . $message . '</p>'
953
- . '<div class="actions">'
954
- . '<a href="' . $link . '" target="_blank" class="button button-primary translate-dismiss"> ' . $button_do . '</a>&nbsp;'
955
- . get_submit_button( $button_cancel, 'translate-dismiss ' . $this->product->get_key() . '-ti-translate', $this->product->get_key() . 'ti-translate-no', false )
956
- . '</div></br></div>';
957
- }
958
-
959
- /**
960
- * Called when the either button is clicked
961
- */
962
- function dismiss() {
963
- check_ajax_referer( (string) __CLASS__, 'nonce' );
964
-
965
- $this->disable();
966
- }
967
-
968
- /**
969
- * Disables the notification
970
- */
971
- protected function disable() {
972
-
973
- update_option( $this->product->get_key() . '_translate_flag', 'no' );
974
- }
975
-
976
- /**
977
- * Enables the notification
978
- */
979
- protected function enable() {
980
- update_option( $this->product->get_key() . '_translate_flag', 'yes' );
981
- }
982
- }
983
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-feedback.php DELETED
@@ -1,90 +0,0 @@
1
- <?php
2
- /**
3
- * The feedback model class for ThemeIsle SDK
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Feedback
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- // Exit if accessed directly.
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
- if ( ! class_exists( 'ThemeIsle_SDK_Feedback' ) ) :
16
- /**
17
- * Feedback model for ThemeIsle SDK.
18
- */
19
- abstract class ThemeIsle_SDK_Feedback {
20
- /**
21
- * @var ThemeIsle_SDK_Product $product Themeisle Product.
22
- */
23
- protected $product;
24
-
25
- /**
26
- * @var string $feedback_url Url where to send the feedback
27
- */
28
- private $feedback_url = 'http://feedback.themeisle.com/wordpress/wp-json/__pirate_feedback_/v1/feedback';
29
-
30
- /**
31
- * ThemeIsle_SDK_Feedback constructor.
32
- *
33
- * @param ThemeIsle_SDK_Product $product_object Product Object.
34
- */
35
- public function __construct( $product_object ) {
36
- if ( $product_object instanceof ThemeIsle_SDK_Product ) {
37
- $this->product = $product_object;
38
- }
39
- $this->setup_hooks();
40
- }
41
-
42
- /**
43
- * Registers the hooks and then delegates to the child
44
- */
45
- public function setup_hooks() {
46
- $this->setup_hooks_child();
47
- }
48
-
49
- /**
50
- * Calls the API
51
- *
52
- * @param string $attributes The attributes of the post body.
53
- */
54
- protected function call_api( $attributes ) {
55
- $slug = $this->product->get_slug();
56
- $version = $this->product->get_version();
57
- $attributes['slug'] = $slug;
58
- $attributes['version'] = $version;
59
-
60
- $response = wp_remote_post(
61
- $this->feedback_url, array(
62
- 'body' => $attributes,
63
- )
64
- );
65
- }
66
-
67
- /**
68
- * Randomizes the options array
69
- *
70
- * @param array $options The options array.
71
- */
72
- function randomize_options( $options ) {
73
- $new = array();
74
- $keys = array_keys( $options );
75
- shuffle( $keys );
76
-
77
- foreach ( $keys as $key ) {
78
- $new[ $key ] = $options[ $key ];
79
- }
80
-
81
- return $new;
82
- }
83
-
84
- /**
85
- * Abstract function for delegating to the child
86
- */
87
- protected abstract function setup_hooks_child();
88
-
89
- }
90
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-licenser.php DELETED
@@ -1,686 +0,0 @@
1
- <?php
2
- /**
3
- * The main loader class for license handling.
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Licenser
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- if ( ! class_exists( 'ThemeIsle_SDK_Licenser' ) ) :
12
- /**
13
- * Class ThemeIsle_SDK_Licenser
14
- *
15
- * Used to update the themeisle products
16
- */
17
- class ThemeIsle_SDK_Licenser {
18
-
19
- /**
20
- * @var string $license_key The license key string
21
- */
22
- public $license_key;
23
-
24
- /**
25
- * @var bool $do_check This ensures that the custom API request only runs on the second time that WP fires the update check
26
- */
27
- private $do_check = false;
28
-
29
- /**
30
- * @var bool $failed_checks Number of failed checks to the api endpoint
31
- */
32
- private $failed_checks = 0;
33
- /**
34
- * @var ThemeIsle_SDK_Product $product The ThemeIsle Product.
35
- */
36
- private $product;
37
- /**
38
- * @var string $product_key The product update response key.
39
- */
40
- private $product_key;
41
- /**
42
- * @var int $max_failed Maximum failed checks allowed before show the notice
43
- */
44
- private static $max_failed = 5;
45
-
46
- /**
47
- * ThemeIsle_SDK_Licenser constructor.
48
- *
49
- * @param ThemeIsle_SDK_Product $product The product object.
50
- */
51
- public function __construct( $product ) {
52
- $this->product = $product;
53
-
54
- $this->product_key = $this->product->get_key() . '-update-response';
55
- if ( ! $this->product->requires_license() ) {
56
- $this->license_key = 'free';
57
- } else {
58
- $license_data = get_option( $this->product->get_key() . '_license_data', '' );
59
- $this->failed_checks = intval( get_option( $this->product->get_key() . '_failed_checks', 0 ) );
60
- if ( $license_data !== '' ) {
61
- $this->license_key = isset( $license_data->key ) ? $license_data->key : get_option( $this->product->get_key() . '_license', '' );
62
- } else {
63
- $this->license_key = get_option( $this->product->get_key() . '_license', '' );
64
- }
65
- $this->register_license_hooks();
66
- }
67
- }
68
-
69
- /**
70
- * Register license hooks for the themeisle products
71
- */
72
- public function register_license_hooks() {
73
- add_action( 'admin_init', array( $this, 'register_settings' ) );
74
- add_action( 'admin_init', array( $this, 'activate_license' ) );
75
- add_action( 'admin_init', array( $this, 'product_valid' ), 99999999 );
76
- add_action( 'admin_notices', array( $this, 'show_notice' ) );
77
- add_filter( $this->product->get_key() . '_license_status', array( $this, 'get_license_status' ) );
78
- }
79
-
80
- /**
81
- * @param string $r Update payload.
82
- * @param string $url The api url.
83
- *
84
- * @return mixed List of themes to check for update.
85
- */
86
- function disable_wporg_update( $r, $url ) {
87
-
88
- if ( 0 !== strpos( $url, 'https://api.wordpress.org/themes/update-check/' ) ) {
89
- return $r;
90
- }
91
-
92
- // Decode the JSON response
93
- $themes = json_decode( $r['body']['themes'] );
94
-
95
- unset( $themes->themes->{$this->product->get_slug()} );
96
-
97
- // Encode the updated JSON response
98
- $r['body']['themes'] = json_encode( $themes );
99
-
100
- return $r;
101
- }
102
-
103
- /**
104
- * Register the setting for the license of the product
105
- *
106
- * @return bool
107
- */
108
- public function register_settings() {
109
- if ( ! is_admin() ) {
110
- return false;
111
- }
112
- add_settings_field(
113
- $this->product->get_key() . '_license',
114
- $this->product->get_name() . ' license',
115
- array( $this, 'license_view' ),
116
- 'general'
117
- );
118
- }
119
-
120
- /**
121
- * The license view field
122
- */
123
- public function license_view() {
124
- $status = $this->get_license_status();
125
- $value = $this->license_key;
126
-
127
- $activate_string = apply_filters( $this->product->get_key() . '_lc_activate_string', 'Activate' );
128
- $deactivate_string = apply_filters( $this->product->get_key() . '_lc_deactivate_string', 'Deactivate' );
129
- $valid_string = apply_filters( $this->product->get_key() . '_lc_valid_string', 'Valid' );
130
- $invalid_string = apply_filters( $this->product->get_key() . '_lc_invalid_string', 'Invalid' );
131
- $license_message = apply_filters( $this->product->get_key() . '_lc_license_message', 'Enter your license from %s purchase history in order to get %s updates' );
132
-
133
- echo '<p ><input ' . ( ( $status === 'valid' ) ? ( 'style="border:1px solid #7ad03a; "' ) : '' ) . ' type="text" id="' . $this->product->get_key() . '_license" name="' . $this->product->get_key() . '_license" value="' . $value . '" /><a ' . ( ( $status === 'valid' ) ? ( 'style="color:#fff;background: #7ad03a; display: inline-block;text-decoration: none;font-size: 13px;line-height: 26px;height: 26px; margin-left:5px; padding: 0 10px 1px; -webkit-border-radius: 3px;border-radius: 3px; ">' . $valid_string ) : ( 'style="color:#fff;background: #dd3d36; display: inline-block;text-decoration: none;font-size: 13px;line-height: 26px;height: 26px; margin-left:5px; padding: 0 10px 1px; -webkit-border-radius: 3px;border-radius: 3px; ">' . $invalid_string ) ) . ' </a>&nbsp;&nbsp;&nbsp;<button name="' . $this->product->get_key() . '_btn_trigger" ' . ( ( $status === 'valid' ) ? ( ' class="button button-primary">' . $deactivate_string ) : ( ' class="button button-primary" value="yes" type="submit" >' . $activate_string ) ) . ' </button></p><p class="description">' . sprintf( $license_message, '<a href="' . $this->product->get_store_url() . '">' . $this->product->get_store_name() . '</a> ', $this->product->get_type() ) . '</p>';
134
-
135
- }
136
-
137
- /**
138
- * Return the license status.
139
- *
140
- * @return string The License status.
141
- */
142
- public function get_license_status() {
143
- $license_data = get_option( $this->product->get_key() . '_license_data', '' );
144
- if ( $license_data !== '' ) {
145
- return isset( $license_data->license ) ? $license_data->license : get_option( $this->product->get_key() . '_license_status', 'not_active' );
146
- } else {
147
- return get_option( $this->product->get_key() . '_license_status', 'not_active' );
148
- }
149
-
150
- }
151
-
152
- /**
153
- * Check if the license is active or not
154
- *
155
- * @return bool
156
- */
157
- public function check_activation() {
158
- $license_data = get_option( $this->product->get_key() . '_license_data', '' );
159
- if ( $license_data !== '' ) {
160
- return isset( $license_data->error ) ? ( $license_data->error == 'no_activations_left' ) : false;
161
- }
162
-
163
- return false;
164
- }
165
-
166
- /**
167
- * Check if the license is about to expire in the next month
168
- *
169
- * @return bool
170
- */
171
- function check_expiration() {
172
- $license_data = get_option( $this->product->get_key() . '_license_data', '' );
173
- if ( $license_data !== '' ) {
174
- if ( isset( $license_data->expires ) ) {
175
- if ( strtotime( $license_data->expires ) - time() < 30 * 24 * 3600 ) {
176
- return true;
177
- }
178
- }
179
- }
180
-
181
- return false;
182
- }
183
-
184
- /**
185
- * Return the renew url from the store used
186
- *
187
- * @return string The renew url.
188
- */
189
- function renew_url() {
190
- $license_data = get_option( $this->product->get_key() . '_license_data', '' );
191
- if ( $license_data !== '' ) {
192
- if ( isset( $license_data->download_id ) && isset( $license_data->key ) ) {
193
- return $this->product->get_store_url() . '/checkout/?edd_license_key=' . $license_data->key . '&download_id=' . $license_data->download_id;
194
- }
195
- }
196
-
197
- return $this->product->get_store_url();
198
- }
199
-
200
- /**
201
- * Check if we hide the notificatin nag or not
202
- *
203
- * @param string $hide The notification to hide.
204
- *
205
- * @return bool Either hide them or not.
206
- */
207
- function check_hide( $hide ) {
208
- return true;
209
- }
210
-
211
- /**
212
- * Show the admin notice regarding the license status
213
- *
214
- * @return bool
215
- */
216
- function show_notice() {
217
- if ( ! is_admin() ) {
218
- return false;
219
- }
220
- $status = $this->get_license_status();
221
- $no_activations_string = apply_filters(
222
- $this->product->get_key() . '_lc_no_activations_string', 'No activations left for %s !!!. You need to
223
- upgrade your plan in order to use %s on more
224
- websites. Please ask the %s
225
- Staff for more details.'
226
- );
227
- $no_valid_string = apply_filters(
228
- $this->product->get_key() . '_lc_no_valid_string', 'In order to benefit from updates and support for %s, please add
229
- your license code from your <a href="%s" target="_blank">purchase history</a> and validate it <a
230
- href="%s">here</a>. '
231
- );
232
- $expiration_string = apply_filters(
233
- $this->product->get_key() . '_lc_expiration_string', 'Your license is about to expire
234
- for %s. You can go to %s and renew it '
235
- );
236
- if ( $status != 'valid' ) {
237
- if ( $this->check_activation() ) {
238
- if ( $this->check_hide( 'activation' ) ) {
239
- ?>
240
- <div class="error">
241
- <p><strong>
242
- <?php
243
- echo sprintf(
244
- $no_activations_string, $this->product->get_name(), $this->product->get_name(), '<a href="' . $this->product->get_store_url() . '"
245
- target="_blank">' . $this->product->get_store_name() . '</a>'
246
- );
247
- ?>
248
- </strong>
249
- </p>
250
- </div>
251
- <?php
252
- return false;
253
- }
254
- }
255
- ?>
256
- <?php if ( $this->check_hide( 'valid' ) ) : ?>
257
- <div class="error">
258
- <p>
259
- <strong><?php echo sprintf( $no_valid_string, $this->product->get_name() . ' ' . $this->product->get_type(), $this->product->get_store_url(), admin_url( 'options-general.php' ) . '#' . $this->product->get_key() ); ?> </strong>
260
- </p>
261
- </div>
262
- <?php endif; ?>
263
- <?php
264
- } else {
265
- if ( $this->check_expiration() ) {
266
- if ( $this->check_hide( 'expiration' ) ) {
267
- ?>
268
- <div class="update-nag">
269
- <p>
270
- <strong>
271
- <?php
272
- echo sprintf(
273
- $expiration_string, $this->product->get_name() . ' ' . $this->product->get_type(), '<a
274
- href="' . $this->renew_url() . '"
275
- target="_blank">' . $this->product->get_store_name() . '</a>'
276
- );
277
- ?>
278
- </strong>
279
- </p>
280
- </div>
281
- <?php
282
- }
283
- }
284
- }
285
- }
286
-
287
- /**
288
- * Run the license check call
289
- */
290
- public function product_valid() {
291
- if ( false === ( $license = get_transient( $this->product->get_key() . '_license_data' ) ) ) {
292
- $license = $this->check_license();
293
- set_transient( $this->product->get_key() . '_license_data', $license, 12 * HOUR_IN_SECONDS );
294
- update_option( $this->product->get_key() . '_license_data', $license );
295
- }
296
-
297
- }
298
-
299
- /**
300
- * Increment the failed checks
301
- */
302
- private function increment_failed_checks() {
303
- $this->failed_checks ++;
304
- update_option( $this->product->get_key() . '_failed_checks', $this->failed_checks );
305
- }
306
-
307
- /**
308
- * Reset the failed checks
309
- */
310
- private function reset_failed_checks() {
311
- $this->failed_checks = 1;
312
- update_option( $this->product->get_key() . '_failed_checks', $this->failed_checks );
313
- }
314
-
315
- /**
316
- * Check the license status
317
- *
318
- * @return object The license data.
319
- */
320
- public function check_license() {
321
- $status = $this->get_license_status();
322
- if ( $status == 'not_active' ) {
323
- $license_data = new stdClass();
324
- $license_data->license = 'not_active';
325
-
326
- return $license_data;
327
- }
328
- $license = trim( $this->license_key );
329
- $api_params = array(
330
- 'edd_action' => 'check_license',
331
- 'license' => $license,
332
- 'item_name' => rawurlencode( $this->product->get_name() ),
333
- 'url' => rawurlencode( home_url() ),
334
- );
335
- // Call the custom API.
336
- $response = wp_remote_get(
337
- add_query_arg( $api_params, $this->product->get_store_url() ), array(
338
- 'timeout' => 15,
339
- 'sslverify' => false,
340
- )
341
- );
342
- if ( is_wp_error( $response ) ) {
343
- $license_data = new stdClass();
344
- $license_data->license = 'valid';
345
-
346
- } else {
347
- $license_data = json_decode( wp_remote_retrieve_body( $response ) );
348
- if ( ! is_object( $license_data ) ) {
349
- $license_data = new stdClass();
350
- $license_data->license = 'valid';
351
- }
352
- }
353
- $license_old = get_option( $this->product->get_key() . '_license_data', '' );
354
- if ( $license_old->license == 'valid' && ( $license_data->license != $license_old->license ) ) {
355
- $this->increment_failed_checks();
356
- } else {
357
- $this->reset_failed_checks();
358
- }
359
-
360
- if ( $this->failed_checks <= self::$max_failed ) {
361
- return $license_old;
362
- }
363
-
364
- if ( isset( $license_old->hide_valid ) ) {
365
- $license_data->hide_valid = true;
366
- }
367
-
368
- if ( ! isset( $license_data->key ) ) {
369
- $license_data->key = isset( $license_old->key ) ? $license_old->key : '';
370
- }
371
-
372
- if ( isset( $license_old->hide_expiration ) ) {
373
- $license_data->hide_expiration = true;
374
- }
375
-
376
- if ( isset( $license_old->hide_activation ) ) {
377
- $license_data->hide_activation = true;
378
- }
379
-
380
- return $license_data;
381
-
382
- }
383
-
384
- /**
385
- * Activate the license remotely
386
- */
387
- function activate_license() {
388
- // listen for our activate button to be clicked
389
- if ( isset( $_POST[ $this->product->get_key() . '_btn_trigger' ] ) ) {
390
- $status = $this->get_license_status();
391
- // retrieve the license from the database
392
- $license = $_POST[ $this->product->get_key() . '_license' ];
393
- $api_params = array(
394
- 'license' => $license,
395
- 'item_name' => rawurlencode( $this->product->get_name() ),
396
- 'url' => rawurlencode( home_url() ),
397
- );
398
- if ( $status != 'valid' ) {
399
- // data to send in our API request
400
- $api_params['edd_action'] = 'activate_license';
401
- } else {
402
- $api_params['edd_action'] = 'deactivate_license';
403
- }
404
- // Call the custom API.
405
- $response = wp_remote_get( add_query_arg( $api_params, $this->product->get_store_url() ) );
406
- // make sure the response came back okay
407
- if ( is_wp_error( $response ) ) {
408
- $license_data = new stdClass();
409
- $license_data->license = ( $status != 'valid' ) ? 'valid' : 'invalid';
410
-
411
- } else {
412
- $license_data = json_decode( wp_remote_retrieve_body( $response ) );
413
- if ( ! is_object( $license_data ) ) {
414
- $license_data = new stdClass();
415
- $license_data->license = ( $status != 'valid' ) ? 'valid' : 'invalid';
416
- }
417
- }
418
- if ( ! isset( $license_data->key ) ) {
419
- $license_data->key = $license;
420
- }
421
- if ( $license_data->license == 'valid' ) {
422
- $this->reset_failed_checks();
423
- }
424
-
425
- if ( isset( $license_data->plan ) ) {
426
- update_option( $this->product->get_key() . '_license_plan', $license_data->plan );
427
- }
428
-
429
- update_option( $this->product->get_key() . '_license_data', $license_data );
430
- delete_transient( $this->product->get_key() . '_license_data' );
431
- set_transient( $this->product->get_key() . '_license_data', $license_data, 12 * HOUR_IN_SECONDS );
432
-
433
- }
434
- }
435
-
436
- /**
437
- * Enable the license system
438
- */
439
- public function enable() {
440
- if ( $this->product->get_type() == 'plugin' ) {
441
- add_filter(
442
- 'pre_set_site_transient_update_plugins', array(
443
- $this,
444
- 'pre_set_site_transient_update_plugins_filter',
445
- )
446
- );
447
- add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
448
- add_filter( 'http_request_args', array( $this, 'http_request_args' ), 10, 2 );
449
- }
450
- if ( $this->product->get_type() == 'theme' ) {
451
- add_filter( 'site_transient_update_themes', array( &$this, 'theme_update_transient' ) );
452
- add_filter( 'delete_site_transient_update_themes', array( &$this, 'delete_theme_update_transient' ) );
453
- add_action( 'load-update-core.php', array( &$this, 'delete_theme_update_transient' ) );
454
- add_action( 'load-themes.php', array( &$this, 'delete_theme_update_transient' ) );
455
- add_action( 'load-themes.php', array( &$this, 'load_themes_screen' ) );
456
- add_filter( 'http_request_args', array( $this, 'disable_wporg_update' ), 5, 2 );
457
-
458
- }
459
-
460
- }
461
-
462
- /**
463
- * Load the Themes screen
464
- */
465
- function load_themes_screen() {
466
- add_thickbox();
467
- add_action( 'admin_notices', array( &$this, 'update_nag' ) );
468
- }
469
-
470
- /**
471
- * Alter the nag for themes update
472
- */
473
- function update_nag() {
474
- $theme = wp_get_theme( $this->product->get_slug() );
475
- $api_response = get_transient( $this->product_key );
476
- if ( false === $api_response ) {
477
- return;
478
- }
479
- $update_url = wp_nonce_url( 'update.php?action=upgrade-theme&amp;theme=' . urlencode( $this->product->get_slug() ), 'upgrade-theme_' . $this->product->get_slug() );
480
- $update_message = apply_filters( 'themeisle_sdk_license_update_message', 'Updating this theme will lose any customizations you have made. Cancel to stop, OK to update.' );
481
- $update_onclick = ' onclick="if ( confirm(\'' . esc_js( $update_message ) . '\') ) {return true;}return false;"';
482
- if ( version_compare( $this->product->get_version(), $api_response->new_version, '<' ) ) {
483
- echo '<div id="update-nag">';
484
- printf(
485
- '<strong>%1$s %2$s</strong> is available. <a href="%3$s" class="thickbox" title="%4s">Check out what\'s new</a> or <a href="%5$s"%6$s>update now</a>.',
486
- $theme->get( 'Name' ),
487
- $api_response->new_version,
488
- '#TB_inline?width=640&amp;inlineId=' . $this->product->get_version() . '_changelog',
489
- $theme->get( 'Name' ),
490
- $update_url,
491
- $update_onclick
492
- );
493
- echo '</div>';
494
- echo '<div id="' . $this->product->get_slug() . '_' . 'changelog" style="display:none;">';
495
- echo wpautop( $api_response->sections['changelog'] );
496
- echo '</div>';
497
- }
498
- }
499
-
500
- /**
501
- * @param mixed $value The transient data.
502
- *
503
- * @return mixed
504
- */
505
- function theme_update_transient( $value ) {
506
- $update_data = $this->check_for_update();
507
- if ( $update_data ) {
508
- $value->response[ $this->product->get_slug() ] = $update_data;
509
- }
510
-
511
- return $value;
512
- }
513
-
514
- /**
515
- * Delete the update transient
516
- */
517
- function delete_theme_update_transient() {
518
- delete_transient( $this->product_key );
519
- }
520
-
521
- /**
522
- * Check remote api for latest version.
523
- *
524
- * @return bool|mixed Update api response.
525
- */
526
- private function get_version_data() {
527
- $api_params = array(
528
- 'edd_action' => 'get_version',
529
- 'version' => $this->product->get_version(),
530
- 'license' => $this->license_key,
531
- 'name' => $this->product->get_name(),
532
- 'slug' => $this->product->get_slug(),
533
- 'author' => $this->product->get_store_name(),
534
- 'url' => rawurlencode( home_url() ),
535
- );
536
- $response = wp_remote_post(
537
- $this->product->get_store_url(), array(
538
- 'timeout' => 15,
539
- 'sslverify' => false,
540
- 'body' => $api_params,
541
- )
542
- );
543
- if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) {
544
- return false;
545
- }
546
- $update_data = json_decode( wp_remote_retrieve_body( $response ) );
547
- if ( ! is_object( $update_data ) ) {
548
- return false;
549
- }
550
-
551
- return $update_data;
552
- }
553
-
554
- /**
555
- * Check for updates
556
- *
557
- * @return array|bool Either the update data or false in case of failure
558
- */
559
- function check_for_update() {
560
- $theme = wp_get_theme( $this->product->get_slug() );
561
- $update_data = get_transient( $this->product_key );
562
-
563
- if ( false === $update_data ) {
564
- $failed = false;
565
-
566
- $update_data = $this->get_version_data();
567
- if ( empty( $update_data ) ) {
568
- $failed = true;
569
- }
570
- // If the response failed, try again in 30 minutes.
571
- if ( $failed ) {
572
- $data = new stdClass;
573
- $data->new_version = $this->product->get_version();
574
- set_transient( $this->product_key, $data, strtotime( '+30 minutes' ) );
575
-
576
- return false;
577
- } else {
578
- $update_data->sections = maybe_unserialize( $update_data->sections );
579
- set_transient( $this->product_key, $update_data, strtotime( '+12 hours' ) );
580
- }
581
- }
582
- if ( ! isset( $update_data->new_version ) ) {
583
- return false;
584
- }
585
- if ( version_compare( $this->product->get_version(), $update_data->new_version, '>=' ) ) {
586
- return false;
587
- }
588
-
589
- return (array) $update_data;
590
- }
591
-
592
- /**
593
- * Check for Updates at the defined API endpoint and modify the update array.
594
- *
595
- * This function dives into the update API just when WordPress creates its update array,
596
- * then adds a custom API call and injects the custom plugin data retrieved from the API.
597
- * It is reassembled from parts of the native WordPress plugin update code.
598
- * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
599
- *
600
- * @uses api_request()
601
- *
602
- * @param array $_transient_data Update array build by WordPress.
603
- *
604
- * @return array Modified update array with custom plugin data.
605
- */
606
- public function pre_set_site_transient_update_plugins_filter( $_transient_data ) {
607
- if ( empty( $_transient_data ) || ! $this->do_check ) {
608
- $this->do_check = true;
609
-
610
- return $_transient_data;
611
- }
612
- $api_response = $this->api_request();
613
- if ( false !== $api_response && is_object( $api_response ) && isset( $api_response->new_version ) ) {
614
- if ( version_compare( $this->product->get_version(), $api_response->new_version, '<' ) ) {
615
- $_transient_data->response[ $this->product->get_slug() . '/' . $this->product->get_file() ] = $api_response;
616
- }
617
- }
618
-
619
- return $_transient_data;
620
- }
621
-
622
- /**
623
- * Calls the API and, if successfull, returns the object delivered by the API.
624
- *
625
- * @uses get_bloginfo()
626
- * @uses wp_remote_post()
627
- * @uses is_wp_error()
628
- *
629
- * @param string $_action The requested action.
630
- * @param array $_data Parameters for the API action.
631
- *
632
- * @return false||object
633
- */
634
- private function api_request( $_action = '', $_data = '' ) {
635
- $update_data = $this->get_version_data();
636
- if ( empty( $update_data ) ) {
637
- return false;
638
- }
639
- if ( $update_data && isset( $update_data->sections ) ) {
640
- $update_data->sections = maybe_unserialize( $update_data->sections );
641
- }
642
- return $update_data;
643
- }
644
-
645
- /**
646
- * Updates information on the "View version x.x details" page with custom data.
647
- *
648
- * @uses api_request()
649
- *
650
- * @param mixed $_data Plugin data.
651
- * @param string $_action Action to send.
652
- * @param object $_args Arguments to use.
653
- *
654
- * @return object $_data
655
- */
656
- public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
657
- if ( ( $_action != 'plugin_information' ) || ! isset( $_args->slug ) || ( $_args->slug != $this->product->get_slug() ) ) {
658
- return $_data;
659
- }
660
- $api_response = $this->api_request();
661
- if ( false !== $api_response ) {
662
- $_data = $api_response;
663
- }
664
-
665
- return $_data;
666
- }
667
-
668
- /**
669
- * Disable SSL verification in order to prevent download update failures
670
- *
671
- * @param array $args Http args.
672
- * @param string $url Url to check.
673
- *
674
- * @return object $array
675
- */
676
- function http_request_args( $args, $url ) {
677
- // If it is an https request and we are performing a package download, disable ssl verification
678
- if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
679
- $args['sslverify'] = false;
680
- }
681
-
682
- return $args;
683
- }
684
-
685
- }
686
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-loader.php DELETED
@@ -1,96 +0,0 @@
1
- <?php
2
- /**
3
- * The main loader class for ThemeIsle SDK
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Loader
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- // Exit if accessed directly.
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
- if ( ! class_exists( 'ThemeIsle_SDK_Loader' ) ) :
16
- /**
17
- * Singleton loader for ThemeIsle SDK.
18
- */
19
- final class ThemeIsle_SDK_Loader {
20
- /**
21
- * @var ThemeIsle_SDK_Loader instance The singleton instance
22
- */
23
- private static $instance;
24
- /**
25
- * @var string $version The class version.
26
- */
27
- private static $version = '1.0.0';
28
- /**
29
- * @var array The products which use the SDK.
30
- */
31
- private static $products;
32
-
33
- /**
34
- * Register product into SDK.
35
- *
36
- * @param string $basefile The product basefile.
37
- *
38
- * @return ThemeIsle_SDK_Loader The singleton object.
39
- */
40
- public static function init_product( $basefile ) {
41
-
42
- if ( ! isset( self::$instance ) && ! ( self::$instance instanceof ThemeIsle_SDK_Loader ) ) {
43
- self::$instance = new ThemeIsle_SDK_Loader;
44
-
45
- }
46
- $product_object = new ThemeIsle_SDK_Product( $basefile );
47
- self::$products[ $product_object->get_slug() ] = $product_object;
48
-
49
- $notifications = array();
50
- // Based on the WordPress Available file header we enable the logger or not.
51
- if ( ! $product_object->is_wordpress_available() && apply_filters( $product_object->get_key() . '_enable_licenser', true ) === true ) {
52
- $licenser = new ThemeIsle_SDK_Licenser( $product_object );
53
- $licenser->enable();
54
- }
55
-
56
- $logger = new ThemeIsle_SDK_Logger( $product_object );
57
- if ( $product_object->is_logger_active() ) {
58
- $logger->enable();
59
- } else {
60
- $notifications[] = $logger;
61
- }
62
-
63
- $feedback = new ThemeIsle_SDK_Feedback_Factory( $product_object, $product_object->get_feedback_types() );
64
-
65
- $instances = $feedback->get_instances();
66
- if ( array_key_exists( 'review', $instances ) ) {
67
- $notifications[] = $instances['review'];
68
- }
69
- if ( array_key_exists( 'translate', $instances ) ) {
70
- $notifications[] = $instances['translate'];
71
- }
72
- new ThemeIsle_SDK_Notification_Manager( $product_object, $notifications );
73
- if ( ! $product_object->is_external_author() ) {
74
- new ThemeIsle_SDK_Widgets_Factory( $product_object, $product_object->get_widget_types() );
75
- }
76
- if ( ! $product_object->is_external_author() ) {
77
- new ThemeIsle_SDK_Rollback( $product_object );
78
- }
79
-
80
- new ThemeIsle_SDK_Endpoints( $product_object );
81
-
82
- return self::$instance;
83
- }
84
-
85
- /**
86
- * Get all products using the SDK.
87
- *
88
- * @return array Products available.
89
- */
90
- public static function get_products() {
91
- return self::$products;
92
- }
93
-
94
-
95
- }
96
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-logger.php DELETED
@@ -1,227 +0,0 @@
1
- <?php
2
- /**
3
- * The main loader class for ThemeIsle SDK
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Logger
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- if ( ! class_exists( 'ThemeIsle_SDK_Logger' ) ) :
12
- /**
13
- * Class ThemeIsle_SDK_Logger
14
- *
15
- * Send the statistics to the Themeisle Endpoint
16
- */
17
- /**
18
- * Class ThemeIsle_SDK_Logger
19
- */
20
- class ThemeIsle_SDK_Logger {
21
-
22
- /**
23
- * @var string $logging_url Url where to send the logs
24
- */
25
- private $logging_url = 'http://log.themeisle.com/wp-json/v1/logs/';
26
-
27
- /**
28
- * @var ThemeIsle_SDK_Product $product Themeisle Product.
29
- */
30
- private $product;
31
-
32
- /**
33
- * @var string $product_cron Cron name handler
34
- */
35
- private $product_cron;
36
-
37
- /**
38
- * @var string $heading The heading of the modal
39
- */
40
- private $heading = 'Do you enjoy <b>{product}</b>? Become a contributor by opting in to our anonymous data tracking. We guarantee no sensitive data is collected.';
41
-
42
- /**
43
- * @var string $button_submit The text of the submit button
44
- */
45
- private $button_submit = 'Sure, I would love to help.';
46
-
47
- /**
48
- * @var string $button_cancel The text of the cancel button
49
- */
50
- private $button_cancel = 'No, thanks.';
51
-
52
- /**
53
- * ThemeIsle_SDK_Logger constructor.
54
- *
55
- * @param ThemeIsle_SDK_Product $product_object Product Object.
56
- */
57
- public function __construct( $product_object ) {
58
- if ( $product_object instanceof ThemeIsle_SDK_Product ) {
59
- $this->product = $product_object;
60
- $this->product_cron = $product_object->get_key() . '_log_activity';
61
- }
62
- add_action( 'wp_ajax_' . $this->product->get_key() . __CLASS__, array( $this, 'dismiss' ) );
63
- }
64
-
65
-
66
- /**
67
- * Start the cron to send the log. It will randomize the interval in order to not send all the logs at the same time.
68
- */
69
- public function enable() {
70
- if ( ! wp_next_scheduled( $this->product_cron ) ) {
71
- wp_schedule_single_event( time() + ( rand( 15, 24 ) * 3600 ), $this->product_cron );
72
- }
73
- add_action( $this->product_cron, array( $this, 'send_log' ) );
74
- }
75
-
76
- /**
77
- * Send the statistics to the api endpoint
78
- */
79
- public function send_log() {
80
- $environment = array();
81
- $theme = wp_get_theme();
82
- $environment['theme'] = array();
83
- $environment['theme']['name'] = $theme->get( 'Name' );
84
- $environment['theme']['author'] = $theme->get( 'Author' );
85
- $environment['plugins'] = get_option( 'active_plugins' );
86
-
87
- wp_remote_post(
88
- $this->logging_url, array(
89
- 'method' => 'POST',
90
- 'timeout' => 3,
91
- 'redirection' => 5,
92
- 'headers' => array(
93
- 'X-ThemeIsle-Event' => 'log_site',
94
- ),
95
- 'body' => array(
96
- 'site' => get_site_url(),
97
- 'slug' => $this->product->get_slug(),
98
- 'version' => $this->product->get_version(),
99
- 'data' => apply_filters( $this->product->get_key() . '_logger_data', array() ),
100
- 'environment' => $environment,
101
- 'license' => apply_filters( $this->product->get_key() . '_license_status', '' ),
102
- ),
103
- )
104
- );
105
- }
106
-
107
- /**
108
- * Dismiss the notification
109
- */
110
- function dismiss() {
111
- check_ajax_referer( (string) __CLASS__, 'nonce' );
112
-
113
- $flag = intval( $_POST['enable'] ) === 1;
114
- update_option( $this->product->logger_option, ( $flag ? 'yes' : 'no' ) );
115
-
116
- if ( true === $flag ) {
117
- $this->enable();
118
- }
119
- }
120
-
121
- /**
122
- * Either we should show the notification or not.
123
- *
124
- * @return bool Valida notification.
125
- */
126
- function can_notify() {
127
- $show = $this->product->is_logger_active();
128
- $checked = get_option( $this->product->logger_option, '' );
129
- if ( ! $show && $checked == '' ) {
130
- return true;
131
- }
132
-
133
- return false;
134
- }
135
-
136
- /**
137
- * Shows the notification
138
- */
139
- function show_notification() {
140
- add_action( 'admin_notices', array( $this, 'admin_notices' ) );
141
- }
142
-
143
- /**
144
- * Shows the admin notice
145
- */
146
- function admin_notices() {
147
- $id = $this->product->get_key() . '_logger';
148
-
149
- $this->add_media( $this->product->get_key() );
150
-
151
- echo '<div class="notice notice-success is-dismissible " id="' . $this->product->get_key() . '-logger-notification" ><div id="' . $id . '" class="themeisle-logger-box">' . $this->get_html( $this->product->get_key() ) . '</div></div>';
152
- }
153
-
154
- /**
155
- * Generates the HTML
156
- *
157
- * @param string $key The product key.
158
- */
159
- function get_html( $key ) {
160
- $heading = apply_filters( $this->product->get_key() . '_logger_heading', $this->heading );
161
- $heading = str_replace(
162
- array( '{product}' ), array(
163
- trim( str_replace( 'Lite', '', $this->product->get_name() ) ),
164
- ),
165
- $heading
166
- );
167
- $button_submit = apply_filters( $this->product->get_key() . '_logger_button_submit', $this->button_submit );
168
- $button_cancel = apply_filters( $this->product->get_key() . '_logger_button_cancel', $this->button_cancel );
169
-
170
- return '<div >'
171
- . '<p>' . $heading . '</p>'
172
- . '<div class="actions">'
173
- . get_submit_button(
174
- $button_submit, 'primary ' . $this->product->get_key() . '-ti-logger', $this->product->get_key() . 'ti-logger-yes', false, array(
175
- 'data-ti-log-enable' => 1,
176
- )
177
- )
178
- . get_submit_button(
179
- $button_cancel, 'secondary ' . $this->product->get_key() . '-ti-logger', $this->product->get_key() . 'ti-logger-no', false, array(
180
- 'data-ti-log-enable' => 0,
181
- )
182
- )
183
- . '</div></div>';
184
- }
185
-
186
- /**
187
- * Loads the js
188
- *
189
- * @param string $key The product key.
190
- */
191
- function add_media( $key ) {
192
- ?>
193
- <style type="text/css">
194
- #<?php echo $key; ?>-logger-notification {
195
- padding-bottom: 5px;
196
- }
197
-
198
- #<?php echo $key; ?>-logger-notification .button {
199
- margin-left: 5px;
200
- }
201
- </style>
202
- <script type="text/javascript" id="<?php echo $key; ?>ti-logger-js">
203
- (function ($) {
204
- $(document).ready(function () {
205
- $('.<?php echo $key; ?>-ti-logger').on('click', function (e) {
206
-
207
- $.ajax({
208
- url: ajaxurl,
209
- method: "post",
210
- data: {
211
- 'nonce': '<?php echo wp_create_nonce( (string) __CLASS__ ); ?>',
212
- 'action': '<?php echo $this->product->get_key() . __CLASS__; ?>',
213
- 'enable': $(this).attr('data-ti-log-enable')
214
- },
215
- success: function () {
216
- $('#<?php echo $key; ?>-logger-notification').hide();
217
- }
218
- });
219
- });
220
- });
221
- })(jQuery);
222
- </script>
223
- <?php
224
- }
225
-
226
- }
227
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-notification-manager.php DELETED
@@ -1,105 +0,0 @@
1
- <?php
2
- /**
3
- * The notification manager class for ThemeIsle SDK
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Notification
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- // Exit if accessed directly.
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
- if ( ! class_exists( 'ThemeIsle_SDK_Notification_Manager' ) ) :
16
- /**
17
- * Notification manager model for ThemeIsle SDK.
18
- */
19
- class ThemeIsle_SDK_Notification_Manager {
20
- /**
21
- * Time between notifications.
22
- */
23
- const NOTIFICATION_INTERVAL_HOURS = 100;
24
- /**
25
- * @var array Notifications for the current product.
26
- */
27
- static private $notifications = array();
28
- /**
29
- * @var ThemeIsle_SDK_Product Current product.
30
- */
31
- private $product;
32
- /**
33
- * @var array ThemeIsle_SDK_Feedback Feedbacks available.
34
- */
35
- private $callbacks = array();
36
-
37
- /**
38
- * ThemeIsle_SDK_Notification_Manager constructor.
39
- *
40
- * @param ThemeIsle_SDK_Product $product_object Product Object.
41
- * @param array $callbacks the objects that will be called when a notification is due.
42
- */
43
- public function __construct( $product_object, $callbacks ) {
44
- $this->product = $product_object;
45
- $this->callbacks = $callbacks;
46
- $this->setup_hooks();
47
- }
48
-
49
- /**
50
- * Setup the notifications.
51
- */
52
- function setup_notifications() {
53
- if ( ! current_user_can( 'manage_options' ) ) {
54
- return;
55
- }
56
- // Load the notifications only if we have it installed after the required interval.
57
- if ( ( time() - $this->product->get_install_time() ) > self::NOTIFICATION_INTERVAL_HOURS * HOUR_IN_SECONDS ) {
58
- if ( $this->product instanceof ThemeIsle_SDK_Product && $this->callbacks && is_array( $this->callbacks ) ) {
59
- foreach ( $this->callbacks as $instance ) {
60
- self::$notifications[ $this->product->get_key() . get_class( $instance ) ] = $instance;
61
- }
62
- }
63
- }
64
- }
65
-
66
- /**
67
- * Setup the internal hooks
68
- */
69
- private function setup_hooks() {
70
- add_action( 'admin_head', array( $this, 'show_notification' ) );
71
- add_action( 'admin_init', array( $this, 'setup_notifications' ) );
72
- }
73
-
74
- /**
75
- * Shows the notification
76
- */
77
- function show_notification() {
78
- $instances = self::$notifications;
79
- if ( empty( $instances ) ) {
80
- return;
81
- }
82
-
83
- $available = array_keys( $instances );
84
- $active = get_option( 'themeisle_sdk_active_notification', array() );
85
-
86
- foreach ( $available as $key ) {
87
- $instance = $instances[ $key ];
88
- if ( $instance->can_notify() ) {
89
-
90
- // Detect notification switch.
91
- if ( empty( $active['key'] ) || ( $active['key'] != $key ) ) {
92
- $active['key'] = $key;
93
- $active['time'] = time();
94
- update_option( 'themeisle_sdk_active_notification', $active );
95
- }
96
- if ( ( time() - $active['time'] ) > ( self::NOTIFICATION_INTERVAL_HOURS * HOUR_IN_SECONDS ) ) {
97
- $instance->show_notification();
98
- }
99
- break;
100
- }
101
- }
102
-
103
- }
104
- }
105
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-product.php DELETED
@@ -1,635 +0,0 @@
1
- <?php
2
- /**
3
- * The product model class for ThemeIsle SDK
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Product
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- // Exit if accessed directly.
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
- if ( ! class_exists( 'ThemeIsle_SDK_Product' ) ) :
16
- /**
17
- * Product model for ThemeIsle SDK.
18
- */
19
- class ThemeIsle_SDK_Product {
20
- /**
21
- * @var string $slug THe product slug.
22
- */
23
- private $slug;
24
- /**
25
- * @var string $basefile The file with headers.
26
- */
27
- private $basefile;
28
- /**
29
- * @var string $type The product type ( plugin | theme ).
30
- */
31
- private $type;
32
- /**
33
- * @var string $file The file name.
34
- */
35
- private $file;
36
- /**
37
- * @var string $name The product name.
38
- */
39
- private $name;
40
- /**
41
- * @var string $key The product ready key.
42
- */
43
- private $key;
44
- /**
45
- * @var string $author_url The url of the author.
46
- */
47
- private $author_url;
48
- /**
49
- * @var string $store_url The store url.
50
- */
51
- private $store_url;
52
- /**
53
- * @var int $install The date of install.
54
- */
55
- private $install;
56
- /**
57
- * @var string $store_name The store name.
58
- */
59
- private $store_name;
60
- /**
61
- * @var array $allowed_authors The allowed authors.
62
- */
63
- private $allowed_authors = array(
64
- 'proteusthemes.com',
65
- 'anarieldesign.com',
66
- 'prothemedesign.com',
67
- 'cssigniter.com',
68
- );
69
- /**
70
- * @var array $allowed_external_products The allowed external_products.
71
- */
72
- private $allowed_products = array(
73
- 'zermatt',
74
- 'neto',
75
- 'olsen',
76
- 'benson',
77
- 'romero',
78
- 'carmack',
79
- 'puzzle',
80
- 'broadsheet',
81
- 'girlywp',
82
- 'veggie',
83
- 'zeko',
84
- 'maishawp',
85
- 'didi',
86
- 'liber',
87
- 'medicpress-pt',
88
- 'adrenaline-pt',
89
- 'consultpress-pt',
90
- 'legalpress-pt',
91
- 'gympress-pt',
92
- 'readable-pt',
93
- 'bolts-pt',
94
- );
95
- /**
96
- * @var bool $requires_license Either user needs to activate it with license.
97
- */
98
- private $requires_license;
99
- /**
100
- * @var bool $wordpress_available Either is available on WordPress or not.
101
- */
102
- private $wordpress_available;
103
- /**
104
- * @var string $version The product version.
105
- */
106
- private $version;
107
- /**
108
- * @var string $logger_option Logger option key.
109
- */
110
- public $logger_option;
111
- /**
112
- * @var string $pro_slug Pro slug, if available.
113
- */
114
- public $pro_slug;
115
- /**
116
- * @var string $feedback_types All the feedback types the product supports
117
- */
118
- private $feedback_types = array();
119
-
120
- /**
121
- * @var string $widget_types All the widget types the product supports
122
- */
123
- private $widget_types = array( 'dashboard_blog' );
124
-
125
- /**
126
- * ThemeIsle_SDK_Product constructor.
127
- *
128
- * @param string $basefile Product basefile.
129
- */
130
- public function __construct( $basefile ) {
131
- if ( ! empty( $basefile ) ) {
132
- if ( is_readable( $basefile ) ) {
133
- $this->basefile = $basefile;
134
- $this->setup_from_path();
135
- $this->setup_from_fileheaders();
136
- }
137
- }
138
- $install = get_option( $this->get_key() . '_install', 0 );
139
- if ( $install === 0 ) {
140
- $install = time();
141
- update_option( $this->get_key() . '_install', time() );
142
- }
143
- $this->install = $install;
144
-
145
- $this->logger_option = $this->get_key() . '_logger_flag';
146
-
147
- }
148
-
149
- /**
150
- * Setup props from fileheaders.
151
- */
152
- public function setup_from_fileheaders() {
153
- $file_headers = array(
154
- 'Requires License' => 'Requires License',
155
- 'WordPress Available' => 'WordPress Available',
156
- 'Pro Slug' => 'Pro Slug',
157
- 'Version' => 'Version',
158
- );
159
- if ( $this->type == 'plugin' ) {
160
- $file_headers['Name'] = 'Plugin Name';
161
- $file_headers['AuthorName'] = 'Author';
162
- $file_headers['AuthorURI'] = 'Author URI';
163
- }
164
- if ( $this->type == 'theme' ) {
165
- $file_headers['Name'] = 'Theme Name';
166
- $file_headers['AuthorName'] = 'Author';
167
- $file_headers['AuthorURI'] = 'Author URI';
168
- }
169
- $file_headers = get_file_data( $this->basefile, $file_headers );
170
-
171
- $this->name = $file_headers['Name'];
172
- $this->store_name = $file_headers['AuthorName'];
173
- $this->author_url = $file_headers['AuthorURI'];
174
- $this->store_url = $file_headers['AuthorURI'];
175
- if ( $this->is_external_author() ) {
176
- $this->store_url = 'https://themeisle.com';
177
- $this->store_name = 'ThemeIsle';
178
- }
179
- $this->requires_license = ( $file_headers['Requires License'] == 'yes' ) ? true : false;
180
- $this->wordpress_available = ( $file_headers['WordPress Available'] == 'yes' ) ? true : false;
181
- $this->pro_slug = ! empty( $file_headers['Pro Slug'] ) ? $file_headers['Pro Slug'] : '';
182
- $this->version = $file_headers['Version'];
183
- if ( $this->require_uninstall_feedback() ) {
184
- $this->feedback_types[] = 'deactivate';
185
- }
186
- if ( $this->is_wordpress_available() ) {
187
- $this->feedback_types[] = 'review';
188
- $this->feedback_types[] = 'translate';
189
- }
190
- }
191
-
192
- /**
193
- * Check if the product is by external author or not.
194
- *
195
- * @return bool Either is external author or no.
196
- */
197
- public function is_external_author() {
198
- foreach ( $this->allowed_authors as $author ) {
199
- if ( strpos( $this->author_url, $author ) !== false ) {
200
- return true;
201
- }
202
- if ( in_array( $this->get_slug(), $this->allowed_products ) ) {
203
- return true;
204
- }
205
- }
206
-
207
- return false;
208
- }
209
-
210
- /**
211
- * The magic var_dump info method.
212
- *
213
- * @return array Debug info.
214
- */
215
- public function __debugInfo() {
216
- return array(
217
- 'name' => $this->name,
218
- 'slug' => $this->slug,
219
- 'version' => $this->version,
220
- 'basefile' => $this->basefile,
221
- 'key' => $this->key,
222
- 'type' => $this->type,
223
- 'store_name' => $this->store_name,
224
- 'store_url' => $this->store_url,
225
- 'wordpress_available' => $this->wordpress_available,
226
- 'requires_license' => $this->requires_license,
227
- );
228
-
229
- }
230
-
231
- /**
232
- * Setup props from path.
233
- */
234
- public function setup_from_path() {
235
- $this->file = basename( $this->basefile );
236
- $dir = dirname( $this->basefile );
237
- $this->slug = basename( $dir );
238
- $exts = explode( '.', $this->basefile );
239
- $ext = $exts[ count( $exts ) - 1 ];
240
- if ( $ext == 'css' ) {
241
- $this->type = 'theme';
242
- }
243
- if ( $ext == 'php' ) {
244
- $this->type = 'plugin';
245
- }
246
- $this->key = self::key_ready_name( $this->slug );
247
- }
248
-
249
- /**
250
- * @param string $string the String to be normalized for cron handler.
251
- *
252
- * @return string $name The normalized string.
253
- */
254
- static function key_ready_name( $string ) {
255
- return str_replace( '-', '_', strtolower( trim( $string ) ) );
256
- }
257
-
258
- /**
259
- * Getter for product name.
260
- *
261
- * @return string The product name.
262
- */
263
- public function get_name() {
264
- return $this->name;
265
- }
266
-
267
- /**
268
- * Getter for product version.
269
- *
270
- * @return string The product version.
271
- */
272
- public function get_version() {
273
- return $this->version;
274
- }
275
-
276
- /**
277
- * If product is available on wordpress.org or not.
278
- *
279
- * @return bool Either is wp available or not.
280
- */
281
- public function is_wordpress_available() {
282
- return $this->wordpress_available;
283
- }
284
-
285
- /**
286
- * @return array Array of available versions.
287
- */
288
- private function get_plugin_versions() {
289
-
290
- $url = sprintf( 'https://api.wordpress.org/plugins/info/1.0/%s', $this->get_slug() );
291
- $response = wp_remote_get( $url );
292
- if ( is_wp_error( $response ) ) {
293
- return array();
294
- }
295
- $response = wp_remote_retrieve_body( $response );
296
- $response = maybe_unserialize( $response );
297
-
298
- if ( ! is_object( $response ) ) {
299
- return array();
300
- }
301
- if ( ! isset( $response->versions ) ) {
302
- return array();
303
- }
304
- $versions = array();
305
- foreach ( $response->versions as $version => $zip ) {
306
- $versions[] = array(
307
- 'version' => $version,
308
- 'url' => $zip,
309
- );
310
- }
311
-
312
- return $versions;
313
- }
314
-
315
- /**
316
- * @return string Return license key, if available.
317
- */
318
- private function get_license() {
319
- $license_data = get_option( $this->get_key() . '_license_data', '' );
320
-
321
- if ( empty( $license_data ) ) {
322
- return '';
323
- }
324
- if ( ! isset( $license_data->key ) ) {
325
- return '';
326
- }
327
-
328
- return $license_data->key;
329
- }
330
-
331
- /**
332
- * @return array Array of available versions.
333
- */
334
- private function get_pro_versions() {
335
- $license = $this->get_license();
336
- $store_url = trailingslashit( $this->store_url );
337
- $url = sprintf( '%s?edd_action=get_versions&name=%s&url=%s&license=%s', $store_url, urlencode( $this->get_name() ), urlencode( get_site_url() ), $license );
338
- $response = wp_remote_get( $url );
339
- if ( is_wp_error( $response ) ) {
340
- return array();
341
- }
342
- $response = wp_remote_retrieve_body( $response );
343
- $response = json_decode( $response );
344
- if ( ! is_object( $response ) ) {
345
- return array();
346
- }
347
- if ( ! isset( $response->versions ) ) {
348
- return array();
349
- }
350
- $versions = array();
351
- foreach ( $response->versions as $key => $version ) {
352
- $versions[] = array(
353
- 'version' => $version->version,
354
- 'url' => $version->file,
355
- );
356
- }
357
-
358
- return $versions;
359
- }
360
-
361
- /**
362
- * Return theme versions.
363
- *
364
- * @return array Theme versions array.
365
- */
366
- public function get_theme_versions() {
367
- $url = sprintf( 'https://api.wordpress.org/themes/info/1.1/?action=theme_information&request[slug]=%s&request[fields][versions]=true', $this->get_slug() );
368
- $response = wp_remote_get( $url );
369
- if ( is_wp_error( $response ) ) {
370
- return array();
371
- }
372
- $response = wp_remote_retrieve_body( $response );
373
- $response = json_decode( $response );
374
-
375
- if ( ! is_object( $response ) ) {
376
- return array();
377
- }
378
- if ( ! isset( $response->versions ) ) {
379
- return array();
380
- }
381
- $versions = array();
382
- foreach ( $response->versions as $version => $zip ) {
383
- $versions[] = array(
384
- 'version' => $version,
385
- 'url' => $zip,
386
- );
387
- }
388
-
389
- return $versions;
390
- }
391
-
392
- /**
393
- * Get versions array from wp.org
394
- *
395
- * @return array Array of versions.
396
- */
397
- private function get_api_versions() {
398
-
399
- $cache_key = $this->get_key() . '_' . preg_replace( '/[^0-9a-zA-Z ]/m', '', $this->version ) . 'versions';
400
- $cache_versions = get_transient( $cache_key );
401
- if ( false === $cache_versions ) {
402
- $versions = array();
403
- if ( ! $this->is_wordpress_available() ) {
404
- $versions = $this->get_pro_versions();
405
- } else {
406
- if ( $this->get_type() === 'plugin' ) {
407
- $versions = $this->get_plugin_versions();
408
- }
409
- if ( $this->get_type() === 'theme' ) {
410
- $versions = $this->get_theme_versions();
411
- }
412
- }
413
- set_transient( $cache_key, $versions, 5 * DAY_IN_SECONDS );
414
- } else {
415
- $versions = is_array( $cache_versions ) ? $cache_versions : array();
416
- }
417
-
418
- return $versions;
419
- }
420
-
421
- /**
422
- * Get the last rollback for this product.
423
- *
424
- * @return array The rollback version.
425
- */
426
- public function get_rollback() {
427
- $rollback = array();
428
- $versions = $this->get_api_versions();
429
- $versions = apply_filters( $this->get_key() . '_rollbacks', $versions );
430
-
431
- if ( $versions ) {
432
- usort( $versions, array( $this, 'sort_rollback_array' ) );
433
- foreach ( $versions as $version ) {
434
- if ( isset( $version['version'] ) && isset( $version['url'] ) && version_compare( $this->version, $version['version'], '>' ) ) {
435
- $rollback = $version;
436
- break;
437
- }
438
- }
439
- }
440
-
441
- return $rollback;
442
- }
443
-
444
- /**
445
- * Sort the rollbacks array in descending order.
446
- */
447
- public function sort_rollback_array( $a, $b ) {
448
- return version_compare( $a['version'], $b['version'], '<' ) > 0;
449
- }
450
-
451
- /**
452
- * If product can be rolled back.
453
- *
454
- * @return bool Can the product be rolled back or not.
455
- */
456
- public function can_rollback() {
457
- if ( $this->get_type() === 'theme' ) {
458
- if ( ! current_user_can( 'switch_themes' ) ) {
459
- return false;
460
- }
461
- }
462
- if ( $this->get_type() === 'plugin' ) {
463
- if ( ! current_user_can( 'install_plugins' ) ) {
464
- return false;
465
- }
466
- }
467
- $rollback = $this->get_rollback();
468
-
469
- return ! empty( $rollback );
470
- }
471
-
472
- /**
473
- * Return the product key.
474
- *
475
- * @return string The product key.
476
- */
477
- public function get_key() {
478
- return $this->key;
479
- }
480
-
481
- /**
482
- * Return friendly name.
483
- *
484
- * @return string Friendly name.
485
- */
486
- public function get_friendly_name() {
487
- $name = apply_filters( $this->get_key() . '_friendly_name', trim( str_replace( 'Lite', '', $this->get_name() ) ) );
488
- $name = rtrim( $name, '- ' );
489
-
490
- return $name;
491
- }
492
-
493
- /**
494
- * Either the product requires license or not.
495
- *
496
- * @return bool Either requires license or not.
497
- */
498
- public function requires_license() {
499
- return $this->requires_license;
500
- }
501
-
502
- /**
503
- * Check if the product is either theme or plugin.
504
- *
505
- * @return string Product type.
506
- */
507
- public function get_type() {
508
- return $this->type;
509
- }
510
-
511
- /**
512
- * Returns the Store name.
513
- *
514
- * @return string Store name.
515
- */
516
- public function get_store_name() {
517
- return $this->store_name;
518
- }
519
-
520
- /**
521
- * Returns the store url.
522
- *
523
- * @return string The store url.
524
- */
525
- public function get_store_url() {
526
- return $this->store_url;
527
- }
528
-
529
- /**
530
- * Returns the product slug.
531
- *
532
- * @return string The product slug.
533
- */
534
- public function get_slug() {
535
- return $this->slug;
536
- }
537
-
538
- /**
539
- * Returns product basefile, which holds the metaheaders.
540
- *
541
- * @return string The product basefile.
542
- */
543
- public function get_basefile() {
544
- return $this->basefile;
545
- }
546
-
547
- /**
548
- * Returns product filename.
549
- *
550
- * @return string The product filename.
551
- */
552
- public function get_file() {
553
- return $this->file;
554
- }
555
-
556
- /**
557
- * Returns feedback types
558
- *
559
- * @return array The feedback types.
560
- */
561
- public function get_feedback_types() {
562
- return apply_filters( $this->get_key() . '_feedback_types', $this->feedback_types );
563
- }
564
-
565
- /**
566
- * Returns widget types
567
- *
568
- * @return array The widget types.
569
- */
570
- public function get_widget_types() {
571
- return apply_filters( $this->get_key() . '_widget_types', $this->widget_types );
572
- }
573
-
574
- /**
575
- * We log the user website and product version.
576
- *
577
- * @return bool Either we log the data or not.
578
- */
579
- public function is_logger_active() {
580
- // If is not available on WordPress log this automatically.
581
- if ( ! $this->is_wordpress_available() ) {
582
- return true;
583
- } else {
584
- $pro_slug = $this->get_pro_slug();
585
- if ( ! empty( $pro_slug ) ) {
586
-
587
- $all_products = ThemeIsle_SDK_Loader::get_products();
588
- if ( isset( $all_products[ $pro_slug ] ) ) {
589
- return true;
590
- }
591
- }
592
-
593
- return ( get_option( $this->get_key() . '_logger_flag', 'no' ) === 'yes' );
594
-
595
- }
596
- }
597
-
598
- /**
599
- * Returns the pro slug, if available.
600
- *
601
- * @return string The pro slug.
602
- */
603
- public function get_pro_slug() {
604
- return $this->pro_slug;
605
- }
606
-
607
- /**
608
- * Return the install timestamp.
609
- *
610
- * @return int The install timestamp.
611
- */
612
- public function get_install_time() {
613
- return $this->install;
614
- }
615
-
616
- /**
617
- * We require feedback on uninstall.
618
- *
619
- * @return bool Either we should require feedback on uninstall or not.
620
- */
621
- public function require_uninstall_feedback() {
622
- if ( $this->get_type() == 'theme' && ! $this->is_external_author() ) {
623
- return ! get_transient( 'ti_sdk_pause_' . $this->get_key(), false );
624
- }
625
-
626
- if ( $this->get_type() == 'plugin' ) {
627
-
628
- return true;
629
- }
630
-
631
- return false;
632
- }
633
-
634
- }
635
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-rollback.php DELETED
@@ -1,223 +0,0 @@
1
- <?php
2
- /**
3
- * The rollback class for ThemeIsle SDK
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Rollback
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- // Exit if accessed directly.
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
- if ( ! class_exists( 'ThemeIsle_SDK_Rollback' ) ) :
16
- /**
17
- * Rollback for ThemeIsle SDK.
18
- */
19
- class ThemeIsle_SDK_Rollback {
20
-
21
- /**
22
- * @var ThemeIsle_SDK_Product $product Themeisle Product.
23
- */
24
- protected $product;
25
-
26
-
27
- /**
28
- * ThemeIsle_SDK_Rollback constructor.
29
- *
30
- * @param ThemeIsle_SDK_Product $product_object Product Object.
31
- */
32
- public function __construct( $product_object ) {
33
- if ( $product_object instanceof ThemeIsle_SDK_Product ) {
34
- $this->product = $product_object;
35
- }
36
- if ( $this->product->can_rollback() ) {
37
- $this->show_link();
38
- $this->add_hooks();
39
-
40
- }
41
- }
42
-
43
- /**
44
- * Add js scripts for themes rollback.
45
- */
46
- public function add_footer() {
47
- $screen = get_current_screen();
48
- if ( ! isset( $screen->parent_file ) ) {
49
- return;
50
- }
51
- if ( $screen->parent_file !== 'themes.php' ) {
52
- return;
53
- }
54
- if ( $this->product->get_type() === 'plugin' ) {
55
- return;
56
- }
57
-
58
- $version = $this->product->get_rollback();
59
- ?>
60
- <script type="text/javascript">
61
- jQuery(document).ready(function ($) {
62
- setInterval(checkTheme, 500);
63
-
64
- function checkTheme() {
65
- var theme = '<?php echo esc_attr( $this->product->get_slug() ); ?>-action';
66
-
67
- if (jQuery('#' + theme).length > 0) {
68
- if (jQuery('.theme-overlay.active').is(':visible')) {
69
- if (jQuery('#' + theme + '-rollback').length === 0) {
70
- jQuery('.theme-actions .active-theme').prepend('<a class="button" style="float:left" id="' + theme + '-rollback" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin-post.php?action=' . $this->product->get_key() . '_rollback' ), $this->product->get_key() . '_rollback' ) ); ?>">Rollback to v<?php echo esc_attr( $version['version'] ); ?></a>')
71
- }
72
- }
73
-
74
- }
75
- }
76
- })
77
-
78
- </script>
79
- <?php
80
-
81
- }
82
-
83
- /**
84
- * Set the rollback hook. Strangely, this does not work if placed in the ThemeIsle_SDK_Rollback class, so it is being called from there instead.
85
- */
86
- public function add_hooks() {
87
- add_action( 'admin_post_' . $this->product->get_key() . '_rollback', array( $this, 'start_rollback' ) );
88
- add_action( 'admin_footer', array( $this, 'add_footer' ) );
89
- }
90
-
91
- /**
92
- * If product can be rolled back, show the link to rollback.
93
- */
94
- private function show_link() {
95
- add_filter(
96
- 'plugin_action_links_' . plugin_basename( $this->product->get_basefile() ), array(
97
- $this,
98
- 'add_rollback_link',
99
- )
100
- );
101
- }
102
-
103
- /**
104
- * Show the rollback links in the plugin page.
105
- *
106
- * @return array The links.
107
- */
108
- public function add_rollback_link( $links ) {
109
- $version = $this->product->get_rollback();
110
- $links[] = '<a href="' . wp_nonce_url( admin_url( 'admin-post.php?action=' . $this->product->get_key() . '_rollback' ), $this->product->get_key() . '_rollback' ) . '">' . sprintf( apply_filters( $this->product->get_key() . '_rollback_label', 'Rollback to v%s' ), $version['version'] ) . '</a>';
111
-
112
- return $links;
113
- }
114
-
115
- /**
116
- * Start the rollback operation.
117
- */
118
- public function start_rollback() {
119
- if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], $this->product->get_key() . '_rollback' ) ) {
120
- wp_nonce_ays( '' );
121
- }
122
-
123
- if ( $this->product->get_type() === 'plugin' ) {
124
- $this->start_rollback_plugin();
125
- } elseif ( $this->product->get_type() === 'theme' ) {
126
- $this->start_rollback_theme();
127
- }
128
- }
129
-
130
- /**
131
- * Alter links and remove duplicate customize message.
132
- *
133
- * @param array $links Array of old links.
134
- *
135
- * @return mixed Array of links.
136
- */
137
- public function alter_links_theme_upgrade( $links ) {
138
- if ( isset( $links['preview'] ) ) {
139
- $links['preview'] = str_replace( '<span aria-hidden="true">Customize</span>', '', $links['preview'] );
140
- }
141
-
142
- return $links;
143
- }
144
-
145
- /**
146
- * Start the rollback operation for the theme.
147
- */
148
- private function start_rollback_theme() {
149
- add_filter( 'update_theme_complete_actions', array( $this, 'alter_links_theme_upgrade' ) );
150
- $rollback = $this->product->get_rollback();
151
- $transient = get_site_transient( 'update_themes' );
152
- $folder = $this->product->get_slug();
153
- $version = $rollback['version'];
154
- $temp_array = array(
155
- 'new_version' => $version,
156
- 'package' => $rollback['url'],
157
- );
158
-
159
- $transient->response[ $folder . '/style.css' ] = $temp_array;
160
- set_site_transient( 'update_themes', $transient );
161
-
162
- $transient = get_transient( $this->product->get_key() . '_warning_rollback' );
163
-
164
- if ( false === $transient ) {
165
- set_transient( $this->product->get_key() . '_warning_rollback', 'in progress', 30 );
166
- require_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
167
- $title = sprintf( apply_filters( $this->product->get_key() . '_rollback_message', 'Rolling back %s to v%s' ), $this->product->get_name(), $version );
168
- $theme = $folder . '/style.css';
169
- $nonce = 'upgrade-theme_' . $theme;
170
- $url = 'update.php?action=upgrade-theme&theme=' . urlencode( $theme );
171
-
172
- $upgrader = new Theme_Upgrader( new Theme_Upgrader_Skin( compact( 'title', 'nonce', 'url', 'theme' ) ) );
173
- $upgrader->upgrade( $theme );
174
- delete_transient( $this->product->get_key() . '_warning_rollback' );
175
- wp_die(
176
- '', $title, array(
177
- 'response' => 200,
178
- )
179
- );
180
- }
181
- }
182
-
183
- /**
184
- * Start the rollback operation for the plugin.
185
- */
186
- private function start_rollback_plugin() {
187
- $rollback = $this->product->get_rollback();
188
- $plugin_transient = get_site_transient( 'update_plugins' );
189
- $plugin_folder = $this->product->get_slug();
190
- $plugin_file = $this->product->get_file();
191
- $version = $rollback['version'];
192
- $temp_array = array(
193
- 'slug' => $plugin_folder,
194
- 'new_version' => $version,
195
- 'package' => $rollback['url'],
196
- );
197
-
198
- $temp_object = (object) $temp_array;
199
- $plugin_transient->response[ $plugin_folder . '/' . $plugin_file ] = $temp_object;
200
- set_site_transient( 'update_plugins', $plugin_transient );
201
-
202
- $transient = get_transient( $this->product->get_key() . '_warning_rollback' );
203
-
204
- if ( false === $transient ) {
205
- set_transient( $this->product->get_key() . '_warning_rollback', 'in progress', 30 );
206
- require_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
207
- $title = sprintf( apply_filters( $this->product->get_key() . '_rollback_message', 'Rolling back %s to v%s' ), $this->product->get_name(), $version );
208
- $plugin = $plugin_folder . '/' . $plugin_file;
209
- $nonce = 'upgrade-plugin_' . $plugin;
210
- $url = 'update.php?action=upgrade-plugin&plugin=' . urlencode( $plugin );
211
- $upgrader_skin = new Plugin_Upgrader_Skin( compact( 'title', 'nonce', 'url', 'plugin' ) );
212
- $upgrader = new Plugin_Upgrader( $upgrader_skin );
213
- $upgrader->upgrade( $plugin );
214
- delete_transient( $this->product->get_key() . '_warning_rollback' );
215
- wp_die(
216
- '', $title, array(
217
- 'response' => 200,
218
- )
219
- );
220
- }
221
- }
222
- }
223
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-widget-dashboard-blog.php DELETED
@@ -1,412 +0,0 @@
1
- <?php
2
- /**
3
- * The blog dashboard model class for ThemeIsle SDK
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Widgets
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- // Exit if accessed directly.
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
- if ( ! class_exists( 'ThemeIsle_SDK_Widget_Dashboard_Blog' ) ) :
16
- /**
17
- * Blog dashboard widget model for ThemeIsle SDK.
18
- */
19
- class ThemeIsle_SDK_Widget_Dashboard_Blog extends ThemeIsle_SDK_Widget {
20
-
21
- /**
22
- * @var array instance The instances.
23
- */
24
- protected $product;
25
- /**
26
- * @var array Feed items.
27
- */
28
- private $items = array();
29
-
30
- /**
31
- * ThemeIsle_SDK_Widget_Dashboard_Blog constructor.
32
- *
33
- * @param ThemeIsle_SDK_Product $product_object The product object.
34
- */
35
- public function __construct( $product_object ) {
36
- $this->product = $product_object;
37
- parent::__construct( $product_object );
38
- }
39
-
40
- /**
41
- * Registers the hooks
42
- */
43
- public function setup_hooks_child() {
44
- $this->setup_vars();
45
- add_action( 'wp_dashboard_setup', array( &$this, 'add_widget' ) );
46
- add_action( 'wp_network_dashboard_setup', array( &$this, 'add_widget' ) );
47
- add_filter( 'themeisle_sdk_recommend_plugin_or_theme', array( &$this, 'recommend_plugin_or_theme' ) );
48
- }
49
-
50
- /**
51
- * Setup class variables
52
- */
53
- function setup_vars() {
54
- $this->dashboard_name = apply_filters( 'themeisle_sdk_dashboard_widget_name', 'WordPress Guides/Tutorials' );
55
- $this->feeds = apply_filters(
56
- 'themeisle_sdk_dashboard_widget_feeds', array(
57
- 'https://themeisle.com/blog/feed',
58
- )
59
- );
60
- }
61
-
62
- /**
63
- * Add widget to the dashboard
64
- *
65
- * @return string|void
66
- */
67
- function add_widget() {
68
- global $wp_meta_boxes;
69
- if ( isset( $wp_meta_boxes['dashboard']['normal']['core']['themeisle'] ) ) {
70
- return;
71
- }
72
- wp_add_dashboard_widget(
73
- 'themeisle', $this->dashboard_name, array(
74
- &$this,
75
- 'render_dashboard_widget',
76
- )
77
- );
78
- }
79
-
80
- /**
81
- * Setup feed items.
82
- */
83
- private function setup_feeds() {
84
- $items_normalized = array();
85
- if ( false === ( $items_normalized = get_transient( 'themeisle_sdk_feed_items' ) ) ) {
86
- // Load SimplePie Instance
87
- $feed = fetch_feed( $this->feeds );
88
- // TODO report error when is an error loading the feed
89
- if ( is_wp_error( $feed ) ) {
90
- return;
91
- }
92
-
93
- $items = $feed->get_items( 0, 5 );
94
- foreach ( (array) $items as $item ) {
95
- $items_normalized[] = array(
96
- 'title' => $item->get_title(),
97
- 'date' => $item->get_date( 'U' ),
98
- 'link' => $item->get_permalink(),
99
- );
100
- }
101
- set_transient( 'themeisle_sdk_feed_items', $items_normalized, 48 * HOUR_IN_SECONDS );
102
- }
103
- $this->items = $items_normalized;
104
- }
105
-
106
- /**
107
- * Render widget content
108
- */
109
- function render_dashboard_widget() {
110
- $this->setup_feeds();
111
- if ( empty( $this->items ) || ! is_array( $this->items ) ) {
112
- return;
113
- }
114
- ?>
115
- <style type="text/css">
116
- #themeisle ul li.ti-dw-recommend-item {
117
- padding-left: 7px;
118
- border-top: 1px solid #eee;
119
- margin-bottom: 0px;
120
- padding-top: 6px;
121
- }
122
-
123
- #themeisle h2.hndle {
124
- background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3Ny4xMiA3Ny4xMiI+PHRpdGxlPkFzc2V0IDM8L3RpdGxlPjxwYXRoIGQ9Ik03NS43Niw0Ny42cS0xLjUsNi40Ni00LjA3LDkuMjZBMzYuMjIsMzYuMjIsMCwwLDEsNjMuMjYsNjNhNTEsNTEsMCwwLDEtOS43OSw0LjZoLS4xNXY0LjgyQTQuNjYsNC42NiwwLDAsMSw1Miw3NS43Niw0LjA3LDQuMDcsMCwwLDEsNDksNzcuMTJhNCw0LDAsMCwxLTIuMTgtLjYxQTQuOTQsNC45NCwwLDAsMSw0NS4xOSw3NWE0LjQyLDQuNDIsMCwwLDEtNy41NCwwLDQuOTQsNC45NCwwLDAsMS0xLjU4LDEuNSwzLjc1LDMuNzUsMCwwLDEtMiwuNjFBNC4yNyw0LjI3LDAsMCwxLDMwLjI3LDc1YTQuOTQsNC45NCwwLDAsMS0xLjU4LDEuNSw0LDQsMCwwLDEtMi4xOC42MSwzLjkzLDMuOTMsMCwwLDEtMy4xNi0xLjQzLDUuMyw1LjMsMCwwLDEtMS4yMS0zLjU0LDEzLjgxLDEzLjgxLDAsMCwxLTguNTgsMywxMy4yMywxMy4yMywwLDAsMS05LTMuNDdBMTguMjEsMTguMjEsMCwwLDAsOSw3MC43OWExNC4yNiwxNC4yNiwwLDAsMS03LjgzLTUuNDIsMTYuMTIsMTYuMTIsMCwwLDAsNS4xOS4wNywxMi44OSwxMi44OSwwLDAsMCw0LjktMS43M1EzLjE1LDU1LjQzLDEuMDUsNTAuNDZhMTgsMTgsMCwwLDEtMS02LjkzQTQwLDQwLDAsMCwxLDEuMjEsMzQsMjYuNTksMjYuNTksMCwwLDEsNS4yNywyNC4xUTguNDQsMTkuNDMsMTMsMTkuNDNhMy40MSwzLjQxLDAsMCwxLDMuNDcsMi4yNmMuNi0uOCwxLjItMS41NiwxLjgxLTIuMjZsLjQ1LS40NS43NS0uNzUsMS4wNS0xLjgxYTM1LjIsMzUuMiwwLDAsMSwyLjExLTMuMzIsMjguNTcsMjguNTcsMCwwLDEsOS4xMi03LjY4QTIzLjQsMjMuNCwwLDAsMSw0Mi45MywyLjU2YTIyLjIyLDIyLjIyLDAsMCwxLDIuNzEuMTVBOC4xNiw4LjE2LDAsMCwxLDUxLjgxLDAsOC42OSw4LjY5LDAsMCwxLDU4LDIuNDFhMS41MSwxLjUxLDAsMCwxLC4xNS42OGMwLC4yNS0uNTUuOTMtMS42NiwybC0uMy4zYTkuNjksOS42OSwwLDAsMSwxLjU4LjgzYy41NS4zNS44My42NS44My45YTEuNjIsMS42MiwwLDAsMS0uNiwxbC0uMTUuMTVxNi43OCw2LDguNTgsMTYuMjdBMy4zLDMuMywwLDAsMSw2OSwyMy4zNWE2LjQ4LDYuNDgsMCwwLDEsNC4yMiwyLjFxMy45MiwzLjMyLDMuOTIsMTEuOUE0Mi4wNSw0Mi4wNSwwLDAsMSw3NS43Niw0Ny42Wk01My42Miw1NC4wN2EyNCwyNCwwLDAsMS0xNCw0LjUyQTIxLjQxLDIxLjQxLDAsMCwxLDI3LDU0LjY3LDI0LjI4LDI0LjI4LDAsMCwxLDE4LjUzLDQ1YTI5LDI5LDAsMCwxLTMtMTMsMzEuNzgsMzEuNzgsMCwwLDEsLjkxLTcuNTNBMzIuMTcsMzIuMTcsMCwwLDAsMTEuOSw0MS4yN2EzMy41LDMzLjUsMCwwLDAsMi43OSwxMy40LDI5LjEsMjkuMSwwLDAsMCw3LjksMTAuODUsNC42OCw0LjY4LDAsMCwxLDEuNjYtMS44OCw0LjE3LDQuMTcsMCwwLDEsNC40NC0uMDgsNC41LDQuNSwwLDAsMSwxLjU4LDEuNjZBNC4yLDQuMiwwLDAsMSwzNCw2M2EzLjgzLDMuODMsMCwwLDEsMiwuNiw0LjUsNC41LDAsMCwxLDEuNTgsMS42Niw0LjI3LDQuMjcsMCwwLDEsNy41NCwwLDQuNSw0LjUsMCwwLDEsMS41OC0xLjY2LDQuMTcsNC4xNywwLDAsMSw0LjQ0LjA4LDMuODYsMy44NiwwLDAsMSwxLjUxLDEuNzMsMzAuMTcsMzAuMTcsMCwwLDAsNy42OC05Ljk0LDMxLjE4LDMxLjE4LDAsMCwwLDMuMTYtMTIuMzVBMjguMzksMjguMzksMCwwLDEsNTMuNjIsNTQuMDdaTTI4Ljc3LDY1LjM3YTMuMSwzLjEsMCwwLDAtNC4zNywwLDMuMDYsMy4wNiwwLDAsMC0uOSwyLjI2djQuODJhMy4zMiwzLjMyLDAsMCwwLC45LDIuMzMsMi45MywyLjkzLDAsMCwwLDQuMzcsMCwzLjMyLDMuMzIsMCwwLDAsLjktMi4zM1Y2Ny42M0EzLjA2LDMuMDYsMCwwLDAsMjguNzcsNjUuMzdabS45LTQ4YTQuMjQsNC4yNCwwLDAsMCwzLjQ3LDEuNzMsNC40NSw0LjQ1LDAsMCwwLDMuNTQtMS43Myw2LDYsMCwwLDAsMS40My0zLjkyLDUuNyw1LjcsMCwwLDAtMS40My0zLjg0QTQuNTMsNC41MywwLDAsMCwzMy4xNCw4YTQuMzEsNC4zMSwwLDAsMC0zLjQ3LDEuNjYsNS43OSw1Ljc5LDAsMCwwLTEuMzUsMy43N0E2LjMzLDYuMzMsMCwwLDAsMjkuNjcsMTcuNFptNi40OCw0OGEzLjEsMy4xLDAsMCwwLTQuMzcsMCwzLjA2LDMuMDYsMCwwLDAtLjksMi4yNnY0LjgyYTMuMzIsMy4zMiwwLDAsMCwuOSwyLjMzLDIuOTMsMi45MywwLDAsMCw0LjM3LDAsMy4zMiwzLjMyLDAsMCwwLC45LTIuMzNWNjcuNjNBMy4wNiwzLjA2LDAsMCwwLDM2LjE1LDY1LjM3Wm0tNC4wNy01NC4zYTIuMzcsMi4zNywwLDAsMSwyLTEsMi4xNywyLjE3LDAsMCwxLDEuODgsMSw0LjEsNC4xLDAsMCwxLDAsNC41MiwyLjE3LDIuMTcsMCwwLDEtMS44OCwxLDIuMzcsMi4zNywwLDAsMS0yLTEsMy43MiwzLjcyLDAsMCwxLS43NS0yLjM0QTMuNDksMy40OSwwLDAsMSwzMi4wOCwxMS4wN1ptNSw5LjQxYTIwLjYxLDIwLjYxLDAsMCwwLTMuNTQsMTIuMjgsMTcuMTUsMTcuMTUsMCwwLDAsNC4wNywxMSwxMi40MywxMi40MywwLDAsMCw5Ljg3LDQuNDUsMTUuMywxNS4zLDAsMCwwLDktMywxMywxMywwLDAsMCwuNi0zLjMycTAtMy4zMi0zLjE2LTMuMzFhOC41OCw4LjU4LDAsMCwwLTIsLjNxLTcuODMsMS41LTExLjU5LS4zLTQuNTMtMi4xMi00LjUyLTkuMzRBMzcuOTIsMzcuOTIsMCwwLDEsMzcuMDUsMjAuNDhaTTYxLjQ1LDE3QTEyLjg0LDEyLjg0LDAsMCwwLDUxLjIxLDEyLjJhMTUuMTEsMTUuMTEsMCwwLDAtNi40LDEuNDMsMTcuODMsMTcuODMsMCwwLDAtNS41LDRxLTYuMTgsMjAuNjQsNi4xOCwyMC42NEEyNC43NSwyNC43NSwwLDAsMCw0OSwzNy44MWEzOC45MiwzOC45MiwwLDAsMSw0LjgyLS40NmMxLjgxLDAsMy4wNi40NiwzLjc3LDEuMzZxMS4zNSwxLjUuNzUsNS4xMmEyMS43MiwyMS43MiwwLDAsMCw1LTcuMTVBMjEuMzgsMjEuMzgsMCwwLDAsNjUuMDcsMjgsMTcuNDQsMTcuNDQsMCwwLDAsNjEuNDUsMTdaTTQzLjYsNjUuMzdhMi43MiwyLjcyLDAsMCwwLTIuMS0uOSwzLDMsMCwwLDAtMi4xOS45LDMuMDYsMy4wNiwwLDAsMC0uOSwyLjI2djQuODJhMy4zMiwzLjMyLDAsMCwwLC45LDIuMzMsMi44NCwyLjg0LDAsMCwwLDIuMTksMSwyLjYxLDIuNjEsMCwwLDAsMi4xLTEsMy40NSwzLjQ1LDAsMCwwLC44My0yLjMzVjY3LjYzQTMuMTcsMy4xNywwLDAsMCw0My42LDY1LjM3Wm03LjQ2LDBhMywzLDAsMCwwLTIuMTgtLjksMi43MywyLjczLDAsMCwwLTIuMTEuOSwzLjE3LDMuMTcsMCwwLDAtLjgzLDIuMjZ2NC44MmEzLjQ1LDMuNDUsMCwwLDAsLjgzLDIuMzMsMi42MSwyLjYxLDAsMCwwLDIuMTEsMSwyLjgzLDIuODMsMCwwLDAsMi4xOC0xLDMuMzIsMy4zMiwwLDAsMCwuOS0yLjMzVjY3LjYzQTMuMDYsMy4wNiwwLDAsMCw1MS4wNiw2NS4zN1oiLz48L3N2Zz4=');
125
- background-repeat: no-repeat;
126
- background-position: 92% 50%;
127
- background-size: 30px;
128
- }
129
-
130
- #themeisle .inside {
131
- padding: 0;
132
- }
133
-
134
- .ti-feed-list {
135
- padding: 0 12px 5px;
136
- margin-bottom: 10px;
137
- border-bottom: 1px solid #eee;
138
- }
139
-
140
- .ti-dw-feed-item a {
141
- display: flex;
142
- align-items: center;
143
- margin-bottom: 5px;
144
- padding: 5px;
145
- transition: .2s ease;
146
- border-radius: 3px;
147
- }
148
-
149
- .ti-dw-feed-item a:hover {
150
- background-color: #f8f8f8;
151
- }
152
-
153
- .ti-dw-feed-item a:hover .ti-dw-date-container {
154
- opacity: .9;
155
- }
156
-
157
- .ti-dw-feed-item .ti-dw-month-container {
158
- margin-top: -5px;
159
- text-transform: uppercase;
160
- font-size: 10px;
161
- letter-spacing: 1px;
162
- font-weight: 700;
163
- }
164
-
165
- .ti-dw-feed-item .ti-dw-date-container {
166
- border-radius: 3px;
167
- transition: .2s ease;
168
- min-height: 35px;
169
- margin-right: 5px;
170
- min-width: 35px;
171
- text-align: center;
172
- border: 1px solid #2a6f97;
173
- color: #fff;
174
- background: #2ea2cc;
175
- display: flex;
176
- flex-direction: column;
177
- justify-content: center;
178
- }
179
-
180
- .ti-dw-footer {
181
- padding: 0 12px 5px;
182
- text-align: center;
183
- }
184
-
185
- .ti-dw-recommend-item {
186
- display: block;
187
- }
188
-
189
- .ti-dw-recommend-item span {
190
- color: #72777c;
191
- }
192
-
193
- .ti-dw-powered-by {
194
- font-size: 11px;
195
- margin-top: 3px;
196
- display: block;
197
- color: #72777c;
198
- }
199
-
200
- .ti-dw-powered-by span {
201
- font-weight: 600;
202
- }
203
-
204
- </style>
205
- <ul class="ti-feed-list">
206
- <?php
207
- foreach ( $this->items as $item ) {
208
- ?>
209
- <li class="ti-dw-feed-item">
210
- <a href="
211
- <?php
212
- echo add_query_arg(
213
- array(
214
- 'utm_campaign' => 'feed',
215
- 'utm_medium' => 'dashboard_widget',
216
- ), $item['link']
217
- );
218
- ?>
219
- " target="_blank">
220
- <span class="ti-dw-date-container"><span
221
- class="ti-dw-day-container"><?php echo date( 'd', $item['date'] ); ?></span> <span
222
- class="ti-dw-month-container"><?php echo substr( date( 'M', $item['date'] ), 0, 3 ); ?></span></span><?php echo $item['title']; ?>
223
- </a>
224
- </li>
225
- <?php
226
- }
227
- ?>
228
- </ul>
229
- <?php
230
- $recommend = apply_filters( 'themeisle_sdk_recommend_plugin_or_theme', array() );
231
- if ( is_array( $recommend ) && ! empty( $recommend ) ) {
232
-
233
- $type = $recommend['type'];
234
- if ( ( $type == 'theme' && current_user_can( 'install_themes' ) ) || ( $type == 'plugin' && current_user_can( 'install_plugins' ) ) ) {
235
- add_thickbox();
236
- $url = add_query_arg(
237
- array(
238
- 'theme' => $recommend['slug'],
239
- ), network_admin_url( 'theme-install.php' )
240
- );
241
-
242
- if ( 'plugin' === $type ) {
243
-
244
- $url = add_query_arg(
245
- array(
246
- 'tab' => 'plugin-information',
247
- 'plugin' => $recommend['slug'],
248
- ), network_admin_url( 'plugin-install.php' )
249
- );
250
- }
251
- ?>
252
- <div class="ti-dw-footer">
253
- <span class="ti-dw-recommend-item ">
254
- <span class="ti-dw-recommend"><?php echo apply_filters( 'themeisle_sdk_dashboard_popular_label', sprintf( 'Popular %s', ucwords( $type ) ) ); ?>
255
- : </span>
256
- <?php
257
- echo trim(
258
- str_replace(
259
- array(
260
- 'lite',
261
- 'Lite',
262
- ), '', $recommend['name']
263
- )
264
- );
265
- ?>
266
- (<a class="thickbox open-plugin-details-modal"
267
- href="<?php echo $url . '&TB_iframe=true&width=600&height=500'; ?>"><?php echo apply_filters( 'themeisle_sdk_dashboard_install_label', 'Install' ); ?></a>)
268
- </span>
269
- <span class="ti-dw-powered-by">
270
- Powered by <span><?php echo esc_attr( $this->product->get_friendly_name() ); ?></span>
271
- </span>
272
- </div>
273
-
274
- <?php
275
- }
276
- }
277
- ?>
278
-
279
- <?php
280
-
281
- }
282
-
283
- /**
284
- * Either the current product is installed or not.
285
- *
286
- * @param array $val The current recommended product.
287
- *
288
- * @return bool Either we should exclude the plugin or not.
289
- */
290
- public function remove_current_products( $val ) {
291
- if ( $val['type'] === 'theme' ) {
292
- $exist = wp_get_theme( $val['slug'] );
293
-
294
- return ! $exist->exists();
295
- } else {
296
- $all_plugins = array_keys( get_plugins() );
297
- foreach ( $all_plugins as $slug ) {
298
- if ( strpos( $slug, $val['slug'] ) !== false ) {
299
- return false;
300
- }
301
- }
302
-
303
- return true;
304
- }
305
- }
306
-
307
- /**
308
- * Fetch themes from wporg api.
309
- *
310
- * @param string $author The author name.
311
- *
312
- * @return array The list of themes.
313
- */
314
- function get_themes_from_wporg( $author ) {
315
- $products = wp_remote_get(
316
- 'https://api.wordpress.org/themes/info/1.1/?action=query_themes&request[author]=' . $author . '&request[per_page]=30&request[fields][active_installs]=true'
317
- );
318
- $products = json_decode( wp_remote_retrieve_body( $products ) );
319
- if ( is_object( $products ) ) {
320
- $products = isset( $products->themes ) ? $products->themes : array();
321
- } else {
322
- $products = array();
323
- }
324
-
325
- return $products;
326
- }
327
-
328
- /**
329
- * Fetch plugin from wporg api.
330
- *
331
- * @param string $author The author slug.
332
- *
333
- * @return array The list of plugins for the selected author.
334
- */
335
- function get_plugins_from_wporg( $author ) {
336
- $products = wp_remote_get(
337
- 'https://api.wordpress.org/plugins/info/1.1/?action=query_plugins&request[author]=' . $author . '&request[author]=codeinwp&request[per_page]=20&request[fields][active_installs]=true'
338
- );
339
- $products = json_decode( wp_remote_retrieve_body( $products ) );
340
- if ( is_object( $products ) ) {
341
- $products = isset( $products->plugins ) ? $products->plugins : array();
342
- } else {
343
- $products = array();
344
- }
345
-
346
- return $products;
347
- }
348
-
349
- /**
350
- * Fetch products from the recomended section.
351
- *
352
- * @return array|mixed The list of products to use in recomended section.
353
- */
354
- function get_product_from_api() {
355
- if ( false === ( $products = get_transient( 'themeisle_sdk_products' ) ) ) {
356
- $products = array();
357
- $themeisle_themes = $this->get_themes_from_wporg( 'themeisle' );
358
- $codeinwp_themes = $this->get_themes_from_wporg( 'codeinwp' );
359
-
360
- $themeisle_plugins = $this->get_plugins_from_wporg( 'themeisle' );
361
- $codeinwp_plugins = $this->get_plugins_from_wporg( 'codeinwp' );
362
-
363
- $all_themes = array_merge( $themeisle_themes, $codeinwp_themes );
364
- foreach ( $all_themes as $theme ) {
365
- if ( $theme->active_installs < 4999 ) {
366
- continue;
367
- }
368
- $products[] = array(
369
- 'name' => $theme->name,
370
- 'type' => 'theme',
371
- 'slug' => $theme->slug,
372
- 'installs' => $theme->active_installs,
373
- );
374
- }
375
- $all_plugins = array_merge( $themeisle_plugins, $codeinwp_plugins );
376
- foreach ( $all_plugins as $plugin ) {
377
- if ( $plugin->active_installs < 5999 ) {
378
- continue;
379
- }
380
- $products[] = array(
381
- 'name' => $plugin->name,
382
- 'type' => 'plugin',
383
- 'slug' => $plugin->slug,
384
- 'installs' => $plugin->active_installs,
385
- );
386
- }
387
- set_transient( 'themeisle_sdk_products', $products, 6 * HOUR_IN_SECONDS );
388
- }
389
-
390
- return $products;
391
- }
392
-
393
- /**
394
- * Contact the API and fetch the recommended plugins/themes
395
- */
396
- function recommend_plugin_or_theme() {
397
- $products = $this->get_product_from_api();
398
- if ( ! is_array( $products ) ) {
399
- $products = array();
400
- }
401
- $products = array_filter( $products, array( $this, 'remove_current_products' ) );
402
- $products = array_merge( $products );
403
- if ( count( $products ) > 1 ) {
404
- shuffle( $products );
405
- $products = array_slice( $products, 0, 1 );
406
- }
407
- $to_recommend = isset( $products[0] ) ? $products[0] : $products;
408
-
409
- return $to_recommend;
410
- }
411
- }
412
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-widget.php DELETED
@@ -1,50 +0,0 @@
1
- <?php
2
- /**
3
- * The widget model class for ThemeIsle SDK
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Widgets
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- // Exit if accessed directly.
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
- if ( ! class_exists( 'ThemeIsle_SDK_Widget' ) ) :
16
- /**
17
- * Widget model for ThemeIsle SDK.
18
- */
19
- abstract class ThemeIsle_SDK_Widget {
20
- /**
21
- * @var ThemeIsle_SDK_Product $product Themeisle Product.
22
- */
23
- protected $product;
24
-
25
- /**
26
- * ThemeIsle_SDK_Widget constructor.
27
- *
28
- * @param ThemeIsle_SDK_Product $product_object Product Object.
29
- */
30
- public function __construct( $product_object ) {
31
- if ( $product_object instanceof ThemeIsle_SDK_Product ) {
32
- $this->product = $product_object;
33
- }
34
- $this->setup_hooks();
35
- }
36
-
37
- /**
38
- * Registers the hooks and then delegates to the child
39
- */
40
- public function setup_hooks() {
41
- $this->setup_hooks_child();
42
- }
43
-
44
- /**
45
- * Abstract function for delegating to the child
46
- */
47
- protected abstract function setup_hooks_child();
48
-
49
- }
50
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-widgets-factory.php DELETED
@@ -1,37 +0,0 @@
1
- <?php
2
- /**
3
- * The widgets factory class for ThemeIsle SDK
4
- *
5
- * @package ThemeIsleSDK
6
- * @subpackage Widgets
7
- * @copyright Copyright (c) 2017, Marius Cristea
8
- * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
- * @since 1.0.0
10
- */
11
- // Exit if accessed directly.
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
- if ( ! class_exists( 'ThemeIsle_SDK_Widgets_Factory' ) ) :
16
- /**
17
- * Widgets factory model for ThemeIsle SDK.
18
- */
19
- class ThemeIsle_SDK_Widgets_Factory {
20
-
21
- /**
22
- * ThemeIsle_SDK_Widgets_Factory constructor.
23
- *
24
- * @param ThemeIsle_SDK_Product $product_object Product Object.
25
- * @param array $widgets the widgets.
26
- */
27
- public function __construct( $product_object, $widgets ) {
28
- if ( $product_object instanceof ThemeIsle_SDK_Product && $widgets && is_array( $widgets ) ) {
29
- foreach ( $widgets as $widget ) {
30
- $class = 'ThemeIsle_SDK_Widget_' . str_replace( ' ', '_', ucwords( str_replace( '_', ' ', $widget ) ) );
31
- $instance = new $class( $product_object );
32
- $instance->setup_hooks();
33
- }
34
- }
35
- }
36
- }
37
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/composer.json DELETED
@@ -1,24 +0,0 @@
1
- {
2
- "name": "codeinwp/themeisle-sdk",
3
- "description": "ThemeIsle SDK ",
4
- "keywords": [
5
- "wordpress"
6
- ],
7
- "homepage": "https://github.com/Codeinwp/themeisle-sdk",
8
- "license": "GPL-2.0+",
9
- "authors": [
10
- {
11
- "name": "ThemeIsle team",
12
- "email": "friends@themeisle.com",
13
- "homepage": "https://themeisle.com"
14
- }
15
- ],
16
- "autoload": {
17
- "files": [
18
- "load.php"
19
- ]
20
- },
21
- "support": {
22
- "issues": "https://github.com/Codeinwp/themeisle-sdk/issues"
23
- }
24
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/codeinwp/themeisle-sdk/index.php CHANGED
@@ -1,5 +1,3 @@
1
  <?php
2
- /**
3
- * @package ThemeIsleSDK
4
- * Ignore this.
5
- */
1
  <?php
2
+ // phpcs:ignoreFile
3
+ // Nothing here.
 
 
vendor/codeinwp/themeisle-sdk/load.php CHANGED
@@ -10,24 +10,38 @@
10
  * @since 1.1.0
11
  */
12
 
 
 
 
13
  // Current SDK version and path.
14
- $themeisle_sdk_version = '2.2.8';
15
  $themeisle_sdk_path = dirname( __FILE__ );
16
 
17
  global $themeisle_sdk_max_version;
18
  global $themeisle_sdk_max_path;
19
 
20
- if ( version_compare( $themeisle_sdk_version, $themeisle_sdk_max_version ) >= 0 ) {
 
 
 
 
 
21
  $themeisle_sdk_max_version = $themeisle_sdk_version;
22
  $themeisle_sdk_max_path = $themeisle_sdk_path;
23
  }
24
 
25
- // load the latest sdk version from the active Themeisle products
26
  if ( ! function_exists( 'themeisle_sdk_load_latest' ) ) :
27
  /**
28
  * Always load the latest sdk version.
29
  */
30
  function themeisle_sdk_load_latest() {
 
 
 
 
 
 
31
  global $themeisle_sdk_max_path;
32
  require_once $themeisle_sdk_max_path . '/start.php';
33
  }
10
  * @since 1.1.0
11
  */
12
 
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ return;
15
+ }
16
  // Current SDK version and path.
17
+ $themeisle_sdk_version = '3.0.6';
18
  $themeisle_sdk_path = dirname( __FILE__ );
19
 
20
  global $themeisle_sdk_max_version;
21
  global $themeisle_sdk_max_path;
22
 
23
+ if ( version_compare( $themeisle_sdk_version, $themeisle_sdk_max_path ) == 0 &&
24
+ apply_filters( 'themeisle_sdk_should_overwrite_path', false, $themeisle_sdk_path, $themeisle_sdk_max_path ) ) {
25
+ $themeisle_sdk_max_path = $themeisle_sdk_path;
26
+ }
27
+
28
+ if ( version_compare( $themeisle_sdk_version, $themeisle_sdk_max_version ) > 0 ) {
29
  $themeisle_sdk_max_version = $themeisle_sdk_version;
30
  $themeisle_sdk_max_path = $themeisle_sdk_path;
31
  }
32
 
33
+ // load the latest sdk version from the active Themeisle products.
34
  if ( ! function_exists( 'themeisle_sdk_load_latest' ) ) :
35
  /**
36
  * Always load the latest sdk version.
37
  */
38
  function themeisle_sdk_load_latest() {
39
+ /**
40
+ * Don't load the library if we are on < 5.4.
41
+ */
42
+ if ( version_compare( PHP_VERSION, '5.4.32', '<' ) ) {
43
+ return;
44
+ }
45
  global $themeisle_sdk_max_path;
46
  require_once $themeisle_sdk_max_path . '/start.php';
47
  }
vendor/codeinwp/themeisle-sdk/src/Common/Abstract_module.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The abstract class for module definition.
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Loader
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 3.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK\Common;
13
+
14
+ use ThemeisleSDK\Product;
15
+
16
+ if ( ! defined( 'ABSPATH' ) ) {
17
+ exit;
18
+ }
19
+
20
+ /**
21
+ * Class Abstract_Module.
22
+ *
23
+ * @package ThemeisleSDK\Common
24
+ */
25
+ abstract class Abstract_Module {
26
+ /**
27
+ * Product which use the module.
28
+ *
29
+ * @var Product $product Product object.
30
+ */
31
+ protected $product = null;
32
+
33
+ /**
34
+ * Can load the module for the selected product.
35
+ *
36
+ * @param Product $product Product data.
37
+ *
38
+ * @return bool Should load module?
39
+ */
40
+ public abstract function can_load( $product );
41
+
42
+ /**
43
+ * Bootstrap the module.
44
+ *
45
+ * @param Product $product Product object.
46
+ */
47
+ public abstract function load( $product );
48
+
49
+ /**
50
+ * Check if the product is from partner.
51
+ *
52
+ * @param Product $product Product data.
53
+ *
54
+ * @return bool Is product from partner.
55
+ */
56
+ public function is_from_partner( $product ) {
57
+
58
+ foreach ( Module_Factory::$domains as $partner_domain ) {
59
+ if ( strpos( $product->get_store_url(), $partner_domain ) !== false ) {
60
+ return true;
61
+ }
62
+ }
63
+
64
+ return array_key_exists( $product->get_slug(), Module_Factory::$slugs );
65
+ }
66
+ }
vendor/codeinwp/themeisle-sdk/src/Common/Module_factory.php ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The module factory class.
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Loader
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 3.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK\Common;
13
+
14
+ use ThemeisleSDK\Product;
15
+
16
+ if ( ! defined( 'ABSPATH' ) ) {
17
+ exit;
18
+ }
19
+
20
+ /**
21
+ * Class Job_Factory
22
+ *
23
+ * @package ThemeisleSDK\Common
24
+ */
25
+ class Module_Factory {
26
+ /**
27
+ * Partners slugs.
28
+ *
29
+ * @var array $SLUGS Partners product slugs.
30
+ */
31
+ public static $slugs = [
32
+ 'zermatt' => true,
33
+ 'neto' => true,
34
+ 'olsen' => true,
35
+ 'benson' => true,
36
+ 'romero' => true,
37
+ 'carmack' => true,
38
+ 'puzzle' => true,
39
+ 'broadsheet' => true,
40
+ 'girlywp' => true,
41
+ 'veggie' => true,
42
+ 'zeko' => true,
43
+ 'maishawp' => true,
44
+ 'didi' => true,
45
+ 'liber' => true,
46
+ 'medicpress-pt' => true,
47
+ 'adrenaline-pt' => true,
48
+ 'consultpress-pt' => true,
49
+ 'legalpress-pt' => true,
50
+ 'gympress-pt' => true,
51
+ 'readable-pt' => true,
52
+ 'bolts-pt' => true,
53
+ ];
54
+ /**
55
+ * Partners domains.
56
+ *
57
+ * @var array $DOMAINS Partners domains.
58
+ */
59
+ public static $domains = [
60
+ 'proteusthemes.com',
61
+ 'anarieldesign.com',
62
+ 'prothemedesign.com',
63
+ 'cssigniter.com',
64
+ ];
65
+ /**
66
+ * Map which contains all the modules loaded for each product.
67
+ *
68
+ * @var array Mapping array.
69
+ */
70
+ private static $modules_attached = [];
71
+
72
+ /**
73
+ * Load availabe modules for the selected product.
74
+ *
75
+ * @param Product $product Loaded product.
76
+ * @param array $modules List of modules.
77
+ */
78
+ public static function attach( $product, $modules ) {
79
+
80
+ if ( ! isset( self::$modules_attached[ $product->get_slug() ] ) ) {
81
+ self::$modules_attached[ $product->get_slug() ] = [];
82
+ }
83
+
84
+ foreach ( $modules as $module ) {
85
+ $class = 'ThemeisleSDK\\Modules\\' . ucwords( $module, '_' );
86
+ /**
87
+ * Module object.
88
+ *
89
+ * @var Abstract_Module $module_object Module instance.
90
+ */
91
+ $module_object = new $class( $product );
92
+
93
+ if ( ! $module_object->can_load( $product ) ) {
94
+ continue;
95
+ }
96
+ self::$modules_attached[ $product->get_slug() ][ $module ] = $module_object->load( $product );
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Products/Modules loaded map.
102
+ *
103
+ * @return array Modules map.
104
+ */
105
+ public static function get_modules_map() {
106
+ return self::$modules_attached;
107
+ }
108
+ }
vendor/codeinwp/themeisle-sdk/src/Loader.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The main loader class for ThemeIsle SDK
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Loader
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 1.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK;
13
+
14
+ use ThemeisleSDK\Common\Module_Factory;
15
+
16
+ if ( ! defined( 'ABSPATH' ) ) {
17
+ exit;
18
+ }
19
+
20
+
21
+ /**
22
+ * Singleton loader for ThemeIsle SDK.
23
+ */
24
+ final class Loader {
25
+ /**
26
+ * Singleton instance.
27
+ *
28
+ * @var Loader instance The singleton instance
29
+ */
30
+ private static $instance;
31
+ /**
32
+ * Current loader version.
33
+ *
34
+ * @var string $version The class version.
35
+ */
36
+ private static $version = '2.0.0';
37
+ /**
38
+ * Holds registered products.
39
+ *
40
+ * @var array The products which use the SDK.
41
+ */
42
+ private static $products = [];
43
+ /**
44
+ * Holds available modules to load.
45
+ *
46
+ * @var array The modules which SDK will be using.
47
+ */
48
+ private static $available_modules = [
49
+ 'dashboard_widget',
50
+ 'rollback',
51
+ 'uninstall_feedback',
52
+ 'licenser',
53
+ 'endpoint',
54
+ 'notification',
55
+ 'logger',
56
+ 'translate',
57
+ 'review',
58
+ 'recommendation',
59
+
60
+ ];
61
+
62
+ /**
63
+ * Initialize the sdk logic.
64
+ */
65
+ public static function init() {
66
+ if ( ! isset( self::$instance ) && ! ( self::$instance instanceof Loader ) ) {
67
+ self::$instance = new Loader();
68
+ $modules = array_merge( self::$available_modules, apply_filters( 'themeisle_sdk_modules', [] ) );
69
+ foreach ( $modules as $key => $module ) {
70
+ if ( ! class_exists( 'ThemeisleSDK\\Modules\\' . ucwords( $module, '_' ) ) ) {
71
+ unset( $modules[ $key ] );
72
+ }
73
+ }
74
+ self::$available_modules = $modules;
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Register product into SDK.
80
+ *
81
+ * @param string $base_file The product base file.
82
+ *
83
+ * @return Loader The singleton object.
84
+ */
85
+ public static function add_product( $base_file ) {
86
+
87
+ if ( ! is_readable( $base_file ) ) {
88
+ return self::$instance;
89
+ }
90
+ $product = new Product( $base_file );
91
+
92
+ Module_Factory::attach( $product, self::get_modules() );
93
+
94
+ self::$products[ $product->get_slug() ] = $product;
95
+
96
+ return self::$instance;
97
+ }
98
+
99
+ /**
100
+ * Get all registered modules by the SDK.
101
+ *
102
+ * @return array Modules available.
103
+ */
104
+ public static function get_modules() {
105
+ return self::$available_modules;
106
+ }
107
+
108
+ /**
109
+ * Get all products using the SDK.
110
+ *
111
+ * @return array Products available.
112
+ */
113
+ public static function get_products() {
114
+ return self::$products;
115
+ }
116
+
117
+ /**
118
+ * Get the version of the SDK.
119
+ *
120
+ * @return string The version.
121
+ */
122
+ public static function get_version() {
123
+ return self::$version;
124
+ }
125
+
126
+ }
vendor/codeinwp/themeisle-sdk/src/Modules/Dashboard_widget.php ADDED
@@ -0,0 +1,464 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The blog dashboard model class for ThemeIsle SDK
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Modules
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 1.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK\Modules;
13
+
14
+ use ThemeisleSDK\Common\Abstract_Module;
15
+ use ThemeisleSDK\Product;
16
+
17
+ // Exit if accessed directly.
18
+ if ( ! defined( 'ABSPATH' ) ) {
19
+ exit;
20
+ }
21
+
22
+ /**
23
+ * Blog dashboard widget module for ThemeIsle SDK.
24
+ */
25
+ class Dashboard_Widget extends Abstract_Module {
26
+
27
+ /**
28
+ * Fetched feeds items.
29
+ *
30
+ * @var array Feed items.
31
+ */
32
+ private $items = array();
33
+
34
+ /**
35
+ * Dashboard widget title.
36
+ *
37
+ * @var string $dashboard_name Dashboard name.
38
+ */
39
+ private $dashboard_name = '';
40
+
41
+ /**
42
+ * Dashboard widget feed sources.
43
+ *
44
+ * @var array $feeds Feed url.
45
+ */
46
+ private $feeds = [];
47
+
48
+ /**
49
+ * Should we load this module.
50
+ *
51
+ * @param Product $product Product object.
52
+ *
53
+ * @return bool
54
+ */
55
+ public function can_load( $product ) {
56
+ if ( $this->is_from_partner( $product ) ) {
57
+ return false;
58
+ }
59
+
60
+ if ( ! apply_filters( $product->get_slug() . '_load_dashboard_widget', true ) ) {
61
+ return false;
62
+ }
63
+
64
+ return true;
65
+ }
66
+
67
+ /**
68
+ * Registers the hooks.
69
+ *
70
+ * @param Product $product Product to load.
71
+ *
72
+ * @return Dashboard_Widget Module instance.
73
+ */
74
+ public function load( $product ) {
75
+
76
+ $this->product = $product;
77
+ $this->dashboard_name = apply_filters( 'themeisle_sdk_dashboard_widget_name', 'WordPress Guides/Tutorials' );
78
+ $this->feeds = apply_filters(
79
+ 'themeisle_sdk_dashboard_widget_feeds',
80
+ [
81
+ 'https://themeisle.com/blog/feed',
82
+ ]
83
+ );
84
+ add_action( 'wp_dashboard_setup', array( &$this, 'add_widget' ) );
85
+ add_action( 'wp_network_dashboard_setup', array( &$this, 'add_widget' ) );
86
+ add_filter( 'themeisle_sdk_recommend_plugin_or_theme', array( &$this, 'recommend_plugin_or_theme' ) );
87
+
88
+ return $this;
89
+ }
90
+
91
+
92
+ /**
93
+ * Add widget to the dashboard
94
+ *
95
+ * @return string|void
96
+ */
97
+ function add_widget() {
98
+ global $wp_meta_boxes;
99
+ if ( isset( $wp_meta_boxes['dashboard']['normal']['core']['themeisle'] ) ) {
100
+ return;
101
+ }
102
+ wp_add_dashboard_widget(
103
+ 'themeisle',
104
+ $this->dashboard_name,
105
+ [
106
+ $this,
107
+ 'render_dashboard_widget',
108
+ ]
109
+ );
110
+ }
111
+
112
+ /**
113
+ * Render widget content
114
+ */
115
+ function render_dashboard_widget() {
116
+ $this->setup_feeds();
117
+ if ( empty( $this->items ) || ! is_array( $this->items ) ) {
118
+ return;
119
+ }
120
+ ?>
121
+ <style type="text/css">
122
+ #themeisle ul li.ti-dw-recommend-item {
123
+ padding-left: 7px;
124
+ border-top: 1px solid #eee;
125
+ margin-bottom: 0px;
126
+ padding-top: 6px;
127
+ }
128
+
129
+ #themeisle h2.hndle {
130
+ background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3Ny4xMiA3Ny4xMiI+PHRpdGxlPkFzc2V0IDM8L3RpdGxlPjxwYXRoIGQ9Ik03NS43Niw0Ny42cS0xLjUsNi40Ni00LjA3LDkuMjZBMzYuMjIsMzYuMjIsMCwwLDEsNjMuMjYsNjNhNTEsNTEsMCwwLDEtOS43OSw0LjZoLS4xNXY0LjgyQTQuNjYsNC42NiwwLDAsMSw1Miw3NS43Niw0LjA3LDQuMDcsMCwwLDEsNDksNzcuMTJhNCw0LDAsMCwxLTIuMTgtLjYxQTQuOTQsNC45NCwwLDAsMSw0NS4xOSw3NWE0LjQyLDQuNDIsMCwwLDEtNy41NCwwLDQuOTQsNC45NCwwLDAsMS0xLjU4LDEuNSwzLjc1LDMuNzUsMCwwLDEtMiwuNjFBNC4yNyw0LjI3LDAsMCwxLDMwLjI3LDc1YTQuOTQsNC45NCwwLDAsMS0xLjU4LDEuNSw0LDQsMCwwLDEtMi4xOC42MSwzLjkzLDMuOTMsMCwwLDEtMy4xNi0xLjQzLDUuMyw1LjMsMCwwLDEtMS4yMS0zLjU0LDEzLjgxLDEzLjgxLDAsMCwxLTguNTgsMywxMy4yMywxMy4yMywwLDAsMS05LTMuNDdBMTguMjEsMTguMjEsMCwwLDAsOSw3MC43OWExNC4yNiwxNC4yNiwwLDAsMS03LjgzLTUuNDIsMTYuMTIsMTYuMTIsMCwwLDAsNS4xOS4wNywxMi44OSwxMi44OSwwLDAsMCw0LjktMS43M1EzLjE1LDU1LjQzLDEuMDUsNTAuNDZhMTgsMTgsMCwwLDEtMS02LjkzQTQwLDQwLDAsMCwxLDEuMjEsMzQsMjYuNTksMjYuNTksMCwwLDEsNS4yNywyNC4xUTguNDQsMTkuNDMsMTMsMTkuNDNhMy40MSwzLjQxLDAsMCwxLDMuNDcsMi4yNmMuNi0uOCwxLjItMS41NiwxLjgxLTIuMjZsLjQ1LS40NS43NS0uNzUsMS4wNS0xLjgxYTM1LjIsMzUuMiwwLDAsMSwyLjExLTMuMzIsMjguNTcsMjguNTcsMCwwLDEsOS4xMi03LjY4QTIzLjQsMjMuNCwwLDAsMSw0Mi45MywyLjU2YTIyLjIyLDIyLjIyLDAsMCwxLDIuNzEuMTVBOC4xNiw4LjE2LDAsMCwxLDUxLjgxLDAsOC42OSw4LjY5LDAsMCwxLDU4LDIuNDFhMS41MSwxLjUxLDAsMCwxLC4xNS42OGMwLC4yNS0uNTUuOTMtMS42NiwybC0uMy4zYTkuNjksOS42OSwwLDAsMSwxLjU4LjgzYy41NS4zNS44My42NS44My45YTEuNjIsMS42MiwwLDAsMS0uNiwxbC0uMTUuMTVxNi43OCw2LDguNTgsMTYuMjdBMy4zLDMuMywwLDAsMSw2OSwyMy4zNWE2LjQ4LDYuNDgsMCwwLDEsNC4yMiwyLjFxMy45MiwzLjMyLDMuOTIsMTEuOUE0Mi4wNSw0Mi4wNSwwLDAsMSw3NS43Niw0Ny42Wk01My42Miw1NC4wN2EyNCwyNCwwLDAsMS0xNCw0LjUyQTIxLjQxLDIxLjQxLDAsMCwxLDI3LDU0LjY3LDI0LjI4LDI0LjI4LDAsMCwxLDE4LjUzLDQ1YTI5LDI5LDAsMCwxLTMtMTMsMzEuNzgsMzEuNzgsMCwwLDEsLjkxLTcuNTNBMzIuMTcsMzIuMTcsMCwwLDAsMTEuOSw0MS4yN2EzMy41LDMzLjUsMCwwLDAsMi43OSwxMy40LDI5LjEsMjkuMSwwLDAsMCw3LjksMTAuODUsNC42OCw0LjY4LDAsMCwxLDEuNjYtMS44OCw0LjE3LDQuMTcsMCwwLDEsNC40NC0uMDgsNC41LDQuNSwwLDAsMSwxLjU4LDEuNjZBNC4yLDQuMiwwLDAsMSwzNCw2M2EzLjgzLDMuODMsMCwwLDEsMiwuNiw0LjUsNC41LDAsMCwxLDEuNTgsMS42Niw0LjI3LDQuMjcsMCwwLDEsNy41NCwwLDQuNSw0LjUsMCwwLDEsMS41OC0xLjY2LDQuMTcsNC4xNywwLDAsMSw0LjQ0LjA4LDMuODYsMy44NiwwLDAsMSwxLjUxLDEuNzMsMzAuMTcsMzAuMTcsMCwwLDAsNy42OC05Ljk0LDMxLjE4LDMxLjE4LDAsMCwwLDMuMTYtMTIuMzVBMjguMzksMjguMzksMCwwLDEsNTMuNjIsNTQuMDdaTTI4Ljc3LDY1LjM3YTMuMSwzLjEsMCwwLDAtNC4zNywwLDMuMDYsMy4wNiwwLDAsMC0uOSwyLjI2djQuODJhMy4zMiwzLjMyLDAsMCwwLC45LDIuMzMsMi45MywyLjkzLDAsMCwwLDQuMzcsMCwzLjMyLDMuMzIsMCwwLDAsLjktMi4zM1Y2Ny42M0EzLjA2LDMuMDYsMCwwLDAsMjguNzcsNjUuMzdabS45LTQ4YTQuMjQsNC4yNCwwLDAsMCwzLjQ3LDEuNzMsNC40NSw0LjQ1LDAsMCwwLDMuNTQtMS43Myw2LDYsMCwwLDAsMS40My0zLjkyLDUuNyw1LjcsMCwwLDAtMS40My0zLjg0QTQuNTMsNC41MywwLDAsMCwzMy4xNCw4YTQuMzEsNC4zMSwwLDAsMC0zLjQ3LDEuNjYsNS43OSw1Ljc5LDAsMCwwLTEuMzUsMy43N0E2LjMzLDYuMzMsMCwwLDAsMjkuNjcsMTcuNFptNi40OCw0OGEzLjEsMy4xLDAsMCwwLTQuMzcsMCwzLjA2LDMuMDYsMCwwLDAtLjksMi4yNnY0LjgyYTMuMzIsMy4zMiwwLDAsMCwuOSwyLjMzLDIuOTMsMi45MywwLDAsMCw0LjM3LDAsMy4zMiwzLjMyLDAsMCwwLC45LTIuMzNWNjcuNjNBMy4wNiwzLjA2LDAsMCwwLDM2LjE1LDY1LjM3Wm0tNC4wNy01NC4zYTIuMzcsMi4zNywwLDAsMSwyLTEsMi4xNywyLjE3LDAsMCwxLDEuODgsMSw0LjEsNC4xLDAsMCwxLDAsNC41MiwyLjE3LDIuMTcsMCwwLDEtMS44OCwxLDIuMzcsMi4zNywwLDAsMS0yLTEsMy43MiwzLjcyLDAsMCwxLS43NS0yLjM0QTMuNDksMy40OSwwLDAsMSwzMi4wOCwxMS4wN1ptNSw5LjQxYTIwLjYxLDIwLjYxLDAsMCwwLTMuNTQsMTIuMjgsMTcuMTUsMTcuMTUsMCwwLDAsNC4wNywxMSwxMi40MywxMi40MywwLDAsMCw5Ljg3LDQuNDUsMTUuMywxNS4zLDAsMCwwLDktMywxMywxMywwLDAsMCwuNi0zLjMycTAtMy4zMi0zLjE2LTMuMzFhOC41OCw4LjU4LDAsMCwwLTIsLjNxLTcuODMsMS41LTExLjU5LS4zLTQuNTMtMi4xMi00LjUyLTkuMzRBMzcuOTIsMzcuOTIsMCwwLDEsMzcuMDUsMjAuNDhaTTYxLjQ1LDE3QTEyLjg0LDEyLjg0LDAsMCwwLDUxLjIxLDEyLjJhMTUuMTEsMTUuMTEsMCwwLDAtNi40LDEuNDMsMTcuODMsMTcuODMsMCwwLDAtNS41LDRxLTYuMTgsMjAuNjQsNi4xOCwyMC42NEEyNC43NSwyNC43NSwwLDAsMCw0OSwzNy44MWEzOC45MiwzOC45MiwwLDAsMSw0LjgyLS40NmMxLjgxLDAsMy4wNi40NiwzLjc3LDEuMzZxMS4zNSwxLjUuNzUsNS4xMmEyMS43MiwyMS43MiwwLDAsMCw1LTcuMTVBMjEuMzgsMjEuMzgsMCwwLDAsNjUuMDcsMjgsMTcuNDQsMTcuNDQsMCwwLDAsNjEuNDUsMTdaTTQzLjYsNjUuMzdhMi43MiwyLjcyLDAsMCwwLTIuMS0uOSwzLDMsMCwwLDAtMi4xOS45LDMuMDYsMy4wNiwwLDAsMC0uOSwyLjI2djQuODJhMy4zMiwzLjMyLDAsMCwwLC45LDIuMzMsMi44NCwyLjg0LDAsMCwwLDIuMTksMSwyLjYxLDIuNjEsMCwwLDAsMi4xLTEsMy40NSwzLjQ1LDAsMCwwLC44My0yLjMzVjY3LjYzQTMuMTcsMy4xNywwLDAsMCw0My42LDY1LjM3Wm03LjQ2LDBhMywzLDAsMCwwLTIuMTgtLjksMi43MywyLjczLDAsMCwwLTIuMTEuOSwzLjE3LDMuMTcsMCwwLDAtLjgzLDIuMjZ2NC44MmEzLjQ1LDMuNDUsMCwwLDAsLjgzLDIuMzMsMi42MSwyLjYxLDAsMCwwLDIuMTEsMSwyLjgzLDIuODMsMCwwLDAsMi4xOC0xLDMuMzIsMy4zMiwwLDAsMCwuOS0yLjMzVjY3LjYzQTMuMDYsMy4wNiwwLDAsMCw1MS4wNiw2NS4zN1oiLz48L3N2Zz4=');
131
+ background-repeat: no-repeat;
132
+ background-position: 92% 50%;
133
+ background-size: 30px;
134
+ }
135
+
136
+ #themeisle .inside {
137
+ padding: 0;
138
+ }
139
+
140
+ .ti-feed-list {
141
+ padding: 0 12px 5px;
142
+ margin-bottom: 10px;
143
+ border-bottom: 1px solid #eee;
144
+ }
145
+
146
+ .ti-dw-feed-item a {
147
+ display: flex;
148
+ align-items: center;
149
+ margin-bottom: 5px;
150
+ padding: 5px;
151
+ transition: .2s ease;
152
+ border-radius: 3px;
153
+ }
154
+
155
+ .ti-dw-feed-item a:hover {
156
+ background-color: #f8f8f8;
157
+ }
158
+
159
+ .ti-dw-feed-item a:hover .ti-dw-date-container {
160
+ opacity: .9;
161
+ }
162
+
163
+ .ti-dw-feed-item .ti-dw-month-container {
164
+ margin-top: -5px;
165
+ text-transform: uppercase;
166
+ font-size: 10px;
167
+ letter-spacing: 1px;
168
+ font-weight: 700;
169
+ }
170
+
171
+ .ti-dw-feed-item .ti-dw-date-container {
172
+ border-radius: 3px;
173
+ transition: .2s ease;
174
+ min-height: 35px;
175
+ margin-right: 5px;
176
+ min-width: 35px;
177
+ text-align: center;
178
+ border: 1px solid #2a6f97;
179
+ color: #fff;
180
+ background: #2ea2cc;
181
+ display: flex;
182
+ flex-direction: column;
183
+ justify-content: center;
184
+ }
185
+
186
+ .ti-dw-footer {
187
+ padding: 0 12px 5px;
188
+ text-align: center;
189
+ }
190
+
191
+ .ti-dw-recommend-item {
192
+ display: block;
193
+ }
194
+
195
+ .ti-dw-recommend-item span {
196
+ color: #72777c;
197
+ }
198
+
199
+ .ti-dw-powered-by {
200
+ font-size: 11px;
201
+ margin-top: 3px;
202
+ display: block;
203
+ color: #72777c;
204
+ }
205
+
206
+ .ti-dw-powered-by span {
207
+ font-weight: 600;
208
+ }
209
+
210
+ </style>
211
+ <?php do_action( 'themeisle_sdk_dashboard_widget_before', $this->product ); ?>
212
+
213
+ <ul class="ti-feed-list">
214
+ <?php
215
+
216
+ foreach ( $this->items as $item ) {
217
+ ?>
218
+ <li class="ti-dw-feed-item">
219
+ <a href="
220
+ <?php
221
+ echo add_query_arg(
222
+ array(
223
+ 'utm_source' => 'wpadmin',
224
+ 'utm_campaign' => 'feed',
225
+ 'utm_medium' => 'dashboard_widget',
226
+ ),
227
+ $item['link']
228
+ );
229
+ ?>
230
+ " target="_blank">
231
+ <span class="ti-dw-date-container"><span
232
+ class="ti-dw-day-container"><?php echo date( 'd', $item['date'] ); ?></span> <span
233
+ class="ti-dw-month-container"><?php echo substr( date( 'M', $item['date'] ), 0, 3 ); ?></span></span><?php echo $item['title']; ?>
234
+ </a>
235
+ </li>
236
+ <?php
237
+ }
238
+ ?>
239
+ </ul>
240
+ <?php
241
+ $recommend = apply_filters( 'themeisle_sdk_recommend_plugin_or_theme', array() );
242
+ if ( ! is_array( $recommend ) || empty( $recommend ) ) {
243
+ return;
244
+ }
245
+
246
+ $type = $recommend['type'];
247
+
248
+ if ( ( 'theme' === $type && ! current_user_can( 'install_themes' ) ) ) {
249
+ return;
250
+ }
251
+ if ( ( 'plugin' === $type && ! current_user_can( 'install_plugins' ) ) ) {
252
+ return;
253
+ }
254
+
255
+ add_thickbox();
256
+ $url = add_query_arg(
257
+ [
258
+ 'theme' => $recommend['slug'],
259
+ ],
260
+ network_admin_url( 'theme-install.php' )
261
+ );
262
+
263
+ if ( 'plugin' === $type ) {
264
+
265
+ $url = add_query_arg(
266
+ array(
267
+ 'tab' => 'plugin-information',
268
+ 'plugin' => $recommend['slug'],
269
+ ),
270
+ network_admin_url( 'plugin-install.php' )
271
+ );
272
+ }
273
+ ?>
274
+ <div class="ti-dw-footer">
275
+ <span class="ti-dw-recommend-item ">
276
+ <span class="ti-dw-recommend"><?php echo apply_filters( 'themeisle_sdk_dashboard_popular_label', sprintf( 'Popular %s', ucwords( $type ) ) ); ?>
277
+ : </span>
278
+ <?php
279
+ echo trim(
280
+ str_replace(
281
+ array(
282
+ 'lite',
283
+ 'Lite',
284
+ '(Lite)',
285
+ '(lite)',
286
+ ),
287
+ '',
288
+ $recommend['name']
289
+ )
290
+ );
291
+ ?>
292
+ (<a class="thickbox open-plugin-details-modal"
293
+ href="<?php echo $url . '&TB_iframe=true&width=600&height=500'; ?>"><?php echo apply_filters( 'themeisle_sdk_dashboard_install_label', 'Install' ); ?></a>)
294
+ </span>
295
+ <span class="ti-dw-powered-by"><span><?php echo apply_filters( 'themeisle_sdk_dashboard_widget_powered_by', esc_attr( sprintf( 'Powered by %s', $this->product->get_friendly_name() ) ) ); ?></span></span>
296
+ </div>
297
+
298
+ <?php
299
+
300
+ }
301
+
302
+ /**
303
+ * Setup feed items.
304
+ */
305
+ private function setup_feeds() {
306
+ if ( false === ( $items_normalized = get_transient( 'themeisle_sdk_feed_items' ) ) ) {
307
+ // Load SimplePie Instance.
308
+ $feed = fetch_feed( $this->feeds );
309
+ // TODO report error when is an error loading the feed.
310
+ if ( is_wp_error( $feed ) ) {
311
+ return;
312
+ }
313
+
314
+ $items = $feed->get_items( 0, 5 );
315
+ foreach ( (array) $items as $item ) {
316
+ $items_normalized[] = array(
317
+ 'title' => $item->get_title(),
318
+ 'date' => $item->get_date( 'U' ),
319
+ 'link' => $item->get_permalink(),
320
+ );
321
+ }
322
+ set_transient( 'themeisle_sdk_feed_items', $items_normalized, 48 * HOUR_IN_SECONDS );
323
+ }
324
+ $this->items = $items_normalized;
325
+ }
326
+
327
+ /**
328
+ * Either the current product is installed or not.
329
+ *
330
+ * @param array $val The current recommended product.
331
+ *
332
+ * @return bool Either we should exclude the plugin or not.
333
+ */
334
+ public function remove_current_products( $val ) {
335
+ if ( 'theme' === $val['type'] ) {
336
+ $exist = wp_get_theme( $val['slug'] );
337
+
338
+ return ! $exist->exists();
339
+ } else {
340
+ $all_plugins = array_keys( get_plugins() );
341
+ foreach ( $all_plugins as $slug ) {
342
+ if ( strpos( $slug, $val['slug'] ) !== false ) {
343
+ return false;
344
+ }
345
+ }
346
+
347
+ return true;
348
+ }
349
+ }
350
+
351
+ /**
352
+ * Contact the API and fetch the recommended plugins/themes
353
+ */
354
+ function recommend_plugin_or_theme() {
355
+ $products = $this->get_product_from_api();
356
+ if ( ! is_array( $products ) ) {
357
+ $products = array();
358
+ }
359
+ $products = array_filter( $products, array( $this, 'remove_current_products' ) );
360
+ $products = array_merge( $products );
361
+ if ( count( $products ) > 1 ) {
362
+ shuffle( $products );
363
+ $products = array_slice( $products, 0, 1 );
364
+ }
365
+ $to_recommend = isset( $products[0] ) ? $products[0] : $products;
366
+
367
+ return $to_recommend;
368
+ }
369
+
370
+ /**
371
+ * Fetch products from the recomended section.
372
+ *
373
+ * @return array|mixed The list of products to use in recomended section.
374
+ */
375
+ function get_product_from_api() {
376
+ if ( false === ( $products = get_transient( 'themeisle_sdk_products' ) ) ) {
377
+ $products = array();
378
+ $all_themes = $this->get_themes_from_wporg( 'themeisle' );
379
+ $all_plugins = $this->get_plugins_from_wporg( 'themeisle' );
380
+ static $allowed_products = [
381
+ 'hestia' => true,
382
+ 'neve' => true,
383
+ 'visualizer' => true,
384
+ 'feedzy-rss-feeds' => true,
385
+ 'wp-product-review' => true,
386
+ 'otter-blocks' => true,
387
+ 'themeisle-companion' => true,
388
+ ];
389
+ foreach ( $all_themes as $theme ) {
390
+ if ( $theme->active_installs < 4999 ) {
391
+ continue;
392
+ }
393
+ if ( ! isset( $allowed_products[ $theme->slug ] ) ) {
394
+ continue;
395
+ }
396
+ $products[] = array(
397
+ 'name' => $theme->name,
398
+ 'type' => 'theme',
399
+ 'slug' => $theme->slug,
400
+ 'installs' => $theme->active_installs,
401
+ );
402
+ }
403
+ foreach ( $all_plugins as $plugin ) {
404
+ if ( $plugin->active_installs < 4999 ) {
405
+ continue;
406
+ }
407
+ if ( ! isset( $allowed_products[ $plugin->slug ] ) ) {
408
+ continue;
409
+ }
410
+ $products[] = array(
411
+ 'name' => $plugin->name,
412
+ 'type' => 'plugin',
413
+ 'slug' => $plugin->slug,
414
+ 'installs' => $plugin->active_installs,
415
+ );
416
+ }
417
+ set_transient( 'themeisle_sdk_products', $products, 6 * HOUR_IN_SECONDS );
418
+ }
419
+
420
+ return $products;
421
+ }
422
+
423
+ /**
424
+ * Fetch themes from wporg api.
425
+ *
426
+ * @param string $author The author name.
427
+ *
428
+ * @return array The list of themes.
429
+ */
430
+ function get_themes_from_wporg( $author ) {
431
+ $products = wp_remote_get(
432
+ 'https://api.wordpress.org/themes/info/1.1/?action=query_themes&request[author]=' . $author . '&request[per_page]=30&request[fields][active_installs]=true'
433
+ );
434
+ $products = json_decode( wp_remote_retrieve_body( $products ) );
435
+ if ( is_object( $products ) ) {
436
+ $products = isset( $products->themes ) ? $products->themes : array();
437
+ } else {
438
+ $products = array();
439
+ }
440
+
441
+ return (array) $products;
442
+ }
443
+
444
+ /**
445
+ * Fetch plugin from wporg api.
446
+ *
447
+ * @param string $author The author slug.
448
+ *
449
+ * @return array The list of plugins for the selected author.
450
+ */
451
+ function get_plugins_from_wporg( $author ) {
452
+ $products = wp_remote_get(
453
+ 'https://api.wordpress.org/plugins/info/1.1/?action=query_plugins&request[author]=' . $author . '&request[per_page]=40&request[fields][active_installs]=true'
454
+ );
455
+ $products = json_decode( wp_remote_retrieve_body( $products ) );
456
+ if ( is_object( $products ) ) {
457
+ $products = isset( $products->plugins ) ? $products->plugins : array();
458
+ } else {
459
+ $products = array();
460
+ }
461
+
462
+ return (array) $products;
463
+ }
464
+ }
vendor/codeinwp/themeisle-sdk/src/Modules/Endpoint.php ADDED
@@ -0,0 +1,358 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The class that exposes endpoints.
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Rollback
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 1.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK\Modules;
13
+
14
+ // Exit if accessed directly.
15
+ use ThemeisleSDK\Common\Abstract_Module;
16
+ use ThemeisleSDK\Loader;
17
+ use ThemeisleSDK\Product;
18
+
19
+ if ( ! defined( 'ABSPATH' ) ) {
20
+ exit;
21
+ }
22
+
23
+ /**
24
+ * Expose endpoints for ThemeIsle SDK.
25
+ */
26
+ class Endpoint extends Abstract_Module {
27
+ /**
28
+ * Endpoint slug.
29
+ */
30
+ const SDK_ENDPOINT = 'themeisle-sdk';
31
+ /**
32
+ * Endpoint version.
33
+ */
34
+ const SDK_ENDPOINT_VERSION = 1;
35
+ /**
36
+ * Hash file which contains the checksum.
37
+ */
38
+ const HASH_FILE = 'themeisle-hash.json';
39
+
40
+ /*
41
+ * If true, the endpoint will expect a product slug and will return the value only for that.
42
+ */
43
+ const PRODUCT_SPECIFIC = false;
44
+
45
+ /**
46
+ * Registers the endpoints.
47
+ */
48
+ function rest_register() {
49
+ register_rest_route(
50
+ self::SDK_ENDPOINT . '/v' . self::SDK_ENDPOINT_VERSION,
51
+ '/checksum/' . ( self::PRODUCT_SPECIFIC ? '(?P<slug>.*)/' : '' ),
52
+ array(
53
+ 'methods' => 'GET',
54
+ 'callback' => array( $this, 'checksum' ),
55
+ )
56
+ );
57
+ }
58
+
59
+ /**
60
+ * The checksum endpoint.
61
+ *
62
+ * @param \WP_REST_Request $data the request.
63
+ *
64
+ * @return \WP_REST_Response Response or the error
65
+ */
66
+ function checksum( \WP_REST_Request $data ) {
67
+ $products = Loader::get_products();
68
+ if ( self::PRODUCT_SPECIFIC ) {
69
+ $params = $this->validate_params( $data, array( 'slug' ) );
70
+ foreach ( $products as $product ) {
71
+ if ( $params['slug'] === $product->get_slug() ) {
72
+ $products = array( $product );
73
+ break;
74
+ }
75
+ }
76
+ }
77
+ $response = array();
78
+ $custom_css = $this->has_custom_css();
79
+ if ( is_bool( $custom_css ) ) {
80
+ $response['custom_css'] = $custom_css;
81
+ }
82
+
83
+ $response['child_theme'] = $this->get_theme_properties();
84
+
85
+ foreach ( $products as $product ) {
86
+ $files = array();
87
+ switch ( $product->get_type() ) {
88
+ case 'plugin':
89
+ $files = array();
90
+ break;
91
+ case 'theme':
92
+ $files = array( 'style.css', 'functions.php' );
93
+ break;
94
+ }
95
+
96
+ $error = '';
97
+
98
+ // if any element in the $files array contains a '/', this would imply recursion is required.
99
+ $diff = $this->generate_diff(
100
+ $product,
101
+ $files,
102
+ array_reduce(
103
+ $files,
104
+ array(
105
+ $this,
106
+ 'is_recursion_required',
107
+ ),
108
+ false
109
+ )
110
+ );
111
+ if ( is_wp_error( $diff ) ) {
112
+ /**
113
+ * Error returner by the diff checker method.
114
+ *
115
+ * @var \WP_Error $diff Error returned.
116
+ */
117
+ $error = $diff->get_error_message();
118
+ $diff = array();
119
+ }
120
+
121
+ $response['products'][] = array(
122
+ 'slug' => $product->get_slug(),
123
+ 'version' => $product->get_version(),
124
+ 'diffs' => $diff,
125
+ 'error' => $error,
126
+ );
127
+ }
128
+
129
+ return new \WP_REST_Response( array( 'checksum' => $response ) );
130
+ }
131
+
132
+ /**
133
+ * Validates the parameters to the API
134
+ *
135
+ * @param \WP_REST_Request $data the request.
136
+ * @param array $params the parameters to validate.
137
+ *
138
+ * @return array of parameter name=>value
139
+ */
140
+ private function validate_params( \WP_REST_Request $data, $params ) {
141
+ $collect = array();
142
+ foreach ( $params as $param ) {
143
+ $value = sanitize_text_field( $data[ $param ] );
144
+ if ( empty( $value ) ) {
145
+ return rest_ensure_response(
146
+ new \WP_Error(
147
+ 'themeisle_' . $param . '_invalid',
148
+ sprintf( 'Invalid %', $param ),
149
+ array(
150
+ 'status' => 403,
151
+ )
152
+ )
153
+ );
154
+ } else {
155
+ $collect[ $param ] = $value;
156
+ }
157
+ }
158
+
159
+ return $collect;
160
+ }
161
+
162
+ /**
163
+ * Check if custom css has been added to the theme.
164
+ *
165
+ * @return bool Whether custom css has been added to the theme.
166
+ */
167
+ private function has_custom_css() {
168
+ $query = new \WP_Query(
169
+ array(
170
+ 'post_type' => 'custom_css',
171
+ 'post_status' => 'publish',
172
+ 'numberposts' => 1,
173
+ 'update_post_meta_cache' => false,
174
+ 'update_post_term_cache' => false,
175
+ )
176
+ );
177
+
178
+ if ( $query->have_posts() ) {
179
+ $query->the_post();
180
+ $content = get_the_content();
181
+
182
+ // if the content contains a colon, a CSS rule has been added.
183
+ return strpos( $content, ':' ) === false ? false : true;
184
+ }
185
+
186
+ return false;
187
+ }
188
+
189
+ /**
190
+ * Get the current theme properties.
191
+ *
192
+ * @return mixed Properties of the current theme.
193
+ */
194
+ function get_theme_properties() {
195
+ if ( ! is_child_theme() ) {
196
+ return false;
197
+ }
198
+
199
+ $properties = array();
200
+ $theme = wp_get_theme();
201
+ // @codingStandardsIgnoreStart
202
+ $properties['name'] = $theme->Name;
203
+ // @codingStandardsIgnoreEnd
204
+
205
+ // get the files in the child theme.
206
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
207
+ WP_Filesystem();
208
+ global $wp_filesystem;
209
+ $path = str_replace( ABSPATH, $wp_filesystem->abspath(), get_stylesheet_directory() );
210
+ $list = $wp_filesystem->dirlist( $path, false, false );
211
+ if ( $list ) {
212
+ $list = array_keys( self::flatten_dirlist( $list ) );
213
+ $properties['files'] = $list;
214
+ }
215
+
216
+ return $properties;
217
+ }
218
+
219
+ /**
220
+ * Flatten the results of WP_Filesystem::dirlist() for iterating over.
221
+ *
222
+ * @access private
223
+ *
224
+ * @param array $nested_files Array of files as returned by WP_Filesystem::dirlist().
225
+ * @param string $path Relative path to prepend to child nodes. Optional.
226
+ *
227
+ * @return array $files A flattened array of the $nested_files specified.
228
+ */
229
+ private static function flatten_dirlist( $nested_files, $path = '' ) {
230
+ $files = array();
231
+ foreach ( $nested_files as $name => $details ) {
232
+ $files[ $path . $name ] = $details;
233
+ // Append children recursively.
234
+ if ( ! empty( $details['files'] ) ) {
235
+ $children = self::flatten_dirlist( $details['files'], $path . $name . '/' );
236
+ // Merge keeping possible numeric keys, which array_merge() will reindex from 0..n.
237
+ $files = $files + $children;
238
+ }
239
+ }
240
+
241
+ return $files;
242
+ }
243
+
244
+ /**
245
+ * Generate the diff of the files.
246
+ *
247
+ * @param Product $product Themeisle Product.
248
+ * @param array $files Array of files.
249
+ * @param bool $recurse Whether to recurse or not.
250
+ *
251
+ * @return mixed Diff data.
252
+ */
253
+ private function generate_diff( $product, $files, $recurse = false ) {
254
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
255
+ WP_Filesystem();
256
+ global $wp_filesystem;
257
+
258
+ $diff = array();
259
+ $path = str_replace( ABSPATH, $wp_filesystem->abspath(), plugin_dir_path( $product->get_basefile() ) );
260
+ $list = $wp_filesystem->dirlist( $path, false, $recurse );
261
+ // nothing found.
262
+ if ( ! $list ) {
263
+ return $diff;
264
+ }
265
+ $list = array_keys( self::flatten_dirlist( $list ) );
266
+
267
+ // now let's get the valid files that actually exist.
268
+ if ( empty( $files ) ) {
269
+ $files = $list;
270
+ } else {
271
+ $files = array_intersect( $files, $list );
272
+ }
273
+
274
+ // fetch the calculated hashes.
275
+ if ( ! $wp_filesystem->is_readable( $path . '/' . self::HASH_FILE ) ) {
276
+ return new WP_Error( 'themeisle_sdk_hash_not_found', sprintf( '%s not found', self::HASH_FILE ) );
277
+ }
278
+
279
+ $hashes = json_decode( $wp_filesystem->get_contents( $path . '/' . self::HASH_FILE ), true );
280
+ ksort( $hashes );
281
+
282
+ $diff = array();
283
+ foreach ( $files as $file ) {
284
+ // file does not exist in the hashes.
285
+ if ( ! array_key_exists( $file, $hashes ) ) {
286
+ continue;
287
+ }
288
+ $new = md5( $wp_filesystem->get_contents( $path . $file ) );
289
+ $old = $hashes[ $file ];
290
+
291
+ // same hash, bail.
292
+ if ( $new === $old ) {
293
+ continue;
294
+ }
295
+ $diff[] = $file;
296
+ }
297
+
298
+ return $diff;
299
+ }
300
+
301
+ /**
302
+ * Check if recursion needs to be enabled on the WP_Filesystem by reducing the array of files to a boolean.
303
+ *
304
+ * @param string $carry Value of the previous iteration.
305
+ * @param string $item Value of the current iteration.
306
+ *
307
+ * @return bool Whether to recurse or not.
308
+ */
309
+ function is_recursion_required( $carry, $item ) {
310
+ if ( ! $carry ) {
311
+ return ( strpos( $item, '/' ) !== false );
312
+ }
313
+
314
+ return $carry;
315
+ }
316
+
317
+ /**
318
+ * Load module for this product.
319
+ *
320
+ * @param Product $product Product to check.
321
+ *
322
+ * @return bool Should we load this?
323
+ */
324
+ public function can_load( $product ) {
325
+ return true;
326
+ }
327
+
328
+ /**
329
+ * Load module logic.
330
+ *
331
+ * @param Product $product Product to load.
332
+ */
333
+ public function load( $product ) {
334
+ $this->setup_endpoints();
335
+
336
+ return $this;
337
+ }
338
+
339
+ /**
340
+ * Setup endpoints.
341
+ */
342
+ private function setup_endpoints() {
343
+ global $wp_version;
344
+ if ( version_compare( $wp_version, '4.4', '<' ) ) {
345
+ // no REST support.
346
+ return;
347
+ }
348
+
349
+ $this->setup_rest();
350
+ }
351
+
352
+ /**
353
+ * Setup REST endpoints.
354
+ */
355
+ private function setup_rest() {
356
+ add_action( 'rest_api_init', array( $this, 'rest_register' ) );
357
+ }
358
+ }
vendor/codeinwp/themeisle-sdk/src/Modules/Licenser.php ADDED
@@ -0,0 +1,719 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The main loader class for license handling.
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Modules
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 1.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK\Modules;
13
+
14
+ // Exit if accessed directly.
15
+ use ThemeisleSDK\Common\Abstract_Module;
16
+ use ThemeisleSDK\Product;
17
+
18
+ if ( ! defined( 'ABSPATH' ) ) {
19
+ exit;
20
+ }
21
+
22
+ /**
23
+ * Licenser module for ThemeIsle SDK.
24
+ */
25
+ class Licenser extends Abstract_Module {
26
+
27
+ /**
28
+ * Number of max failed checks before showing the license message.
29
+ *
30
+ * @var int $max_failed Maximum failed checks allowed before show the notice
31
+ */
32
+ private static $max_failed = 5;
33
+ /**
34
+ * License key string.
35
+ *
36
+ * @var string $license_key The license key string
37
+ */
38
+ public $license_key;
39
+ /**
40
+ * This ensures that the custom API request only runs on the second time that WP fires the update check.
41
+ *
42
+ * @var bool $do_check Flag for request.
43
+ */
44
+ private $do_check = false;
45
+ /**
46
+ * Number of failed checks to the api endpoint.
47
+ *
48
+ * @var bool $failed_checks
49
+ */
50
+ private $failed_checks = 0;
51
+ /**
52
+ * The product update response key.
53
+ *
54
+ * @var string $product_key Product key.
55
+ */
56
+ private $product_key;
57
+
58
+ /**
59
+ * Disable wporg updates for premium products.
60
+ *
61
+ * @param string $r Update payload.
62
+ * @param string $url The api url.
63
+ *
64
+ * @return mixed List of themes to check for update.
65
+ */
66
+ function disable_wporg_update( $r, $url ) {
67
+
68
+ if ( 0 !== strpos( $url, 'https://api.wordpress.org/themes/update-check/' ) ) {
69
+ return $r;
70
+ }
71
+
72
+ // Decode the JSON response.
73
+ $themes = json_decode( $r['body']['themes'] );
74
+
75
+ unset( $themes->themes->{$this->product->get_slug()} );
76
+
77
+ // Encode the updated JSON response.
78
+ $r['body']['themes'] = json_encode( $themes );
79
+
80
+ return $r;
81
+ }
82
+
83
+ /**
84
+ * Register the setting for the license of the product.
85
+ *
86
+ * @return bool
87
+ */
88
+ public function register_settings() {
89
+ if ( ! is_admin() ) {
90
+ return false;
91
+ }
92
+ add_settings_field(
93
+ $this->product->get_key() . '_license',
94
+ $this->product->get_name() . ' license',
95
+ array( $this, 'license_view' ),
96
+ 'general'
97
+ );
98
+ }
99
+
100
+ /**
101
+ * The license view field.
102
+ */
103
+ public function license_view() {
104
+ $status = $this->get_license_status();
105
+ $value = $this->license_key;
106
+
107
+ $activate_string = apply_filters( $this->product->get_key() . '_lc_activate_string', 'Activate' );
108
+ $deactivate_string = apply_filters( $this->product->get_key() . '_lc_deactivate_string', 'Deactivate' );
109
+ $valid_string = apply_filters( $this->product->get_key() . '_lc_valid_string', 'Valid' );
110
+ $invalid_string = apply_filters( $this->product->get_key() . '_lc_invalid_string', 'Invalid' );
111
+ $license_message = apply_filters( $this->product->get_key() . '_lc_license_message', 'Enter your license from %s purchase history in order to get %s updates' );
112
+
113
+ echo '<p ><input ' . ( ( 'valid' === $status ) ? ( 'style="border:1px solid #7ad03a; "' ) : '' ) . ' type="text" id="' . $this->product->get_key() . '_license" name="' . $this->product->get_key() . '_license" value="' . $value . '" /><a ' . ( ( 'valid' === $status ) ? ( 'style="color:#fff;background: #7ad03a; display: inline-block;text-decoration: none;font-size: 13px;line-height: 26px;height: 26px; margin-left:5px; padding: 0 10px 1px; -webkit-border-radius: 3px;border-radius: 3px; ">' . $valid_string ) : ( 'style="color:#fff;background: #dd3d36; display: inline-block;text-decoration: none;font-size: 13px;line-height: 26px;height: 26px; margin-left:5px; padding: 0 10px 1px; -webkit-border-radius: 3px;border-radius: 3px; ">' . $invalid_string ) ) . ' </a>&nbsp;&nbsp;&nbsp;<button name="' . $this->product->get_key() . '_btn_trigger" ' . ( ( 'valid' === $status ) ? ( ' class="button button-primary">' . $deactivate_string ) : ( ' class="button button-primary" value="yes" type="submit" >' . $activate_string ) ) . ' </button></p><p class="description">' . sprintf( $license_message, '<a href="' . $this->get_api_url() . '">' . $this->get_distributor_name() . '</a> ', $this->product->get_type() ) . '</p>';
114
+
115
+ }
116
+
117
+ /**
118
+ * Return the license status.
119
+ *
120
+ * @return string The License status.
121
+ */
122
+ public function get_license_status() {
123
+
124
+ $license_data = get_option( $this->product->get_key() . '_license_data', '' );
125
+
126
+ if ( '' === $license_data ) {
127
+ return get_option( $this->product->get_key() . '_license_status', 'not_active' );
128
+ }
129
+
130
+ return isset( $license_data->license ) ? $license_data->license : get_option( $this->product->get_key() . '_license_status', 'not_active' );
131
+
132
+ }
133
+
134
+ /**
135
+ * Get remote api url.
136
+ *
137
+ * @return string Remote api url.
138
+ */
139
+ public function get_api_url() {
140
+ if ( $this->is_from_partner( $this->product ) ) {
141
+ return 'https://themeisle.com';
142
+ }
143
+
144
+ return $this->product->get_store_url();
145
+ }
146
+
147
+ /**
148
+ * Get remote api url.
149
+ *
150
+ * @return string Remote api url.
151
+ */
152
+ public function get_distributor_name() {
153
+ if ( $this->is_from_partner( $this->product ) ) {
154
+ return 'ThemeIsle';
155
+ }
156
+
157
+ return $this->product->get_store_name();
158
+ }
159
+
160
+ /**
161
+ * Show the admin notice regarding the license status.
162
+ *
163
+ * @return bool Should we show the notice ?
164
+ */
165
+ function show_notice() {
166
+ if ( ! is_admin() ) {
167
+ return false;
168
+ }
169
+ $status = $this->get_license_status();
170
+ $no_activations_string = apply_filters( $this->product->get_key() . '_lc_no_activations_string', 'No activations left for %s !!!. You need to upgrade your plan in order to use %s on more websites. Please ask the %s Staff for more details.' );
171
+ $no_valid_string = apply_filters( $this->product->get_key() . '_lc_no_valid_string', 'In order to benefit from updates and support for %s, please add your license code from your <a href="%s" target="_blank">purchase history</a> and validate it <a href="%s">here</a>. ' );
172
+ $expiration_string = apply_filters( $this->product->get_key() . '_lc_expiration_string', 'Your license is about to expire for %s. You can go to %s and renew it ' );
173
+
174
+ // No activations left for this license.
175
+ if ( 'valid' != $status && $this->check_activation() ) {
176
+ ?>
177
+ <div class="error">
178
+ <p><strong>
179
+ <?php
180
+ echo sprintf(
181
+ $no_activations_string,
182
+ $this->product->get_name(),
183
+ $this->product->get_name(),
184
+ '<a href="' . $this->get_api_url() . '" target="_blank">' . $this->get_distributor_name() . '</a>'
185
+ );
186
+ ?>
187
+ </strong>
188
+ </p>
189
+ </div>
190
+ <?php
191
+ return false;
192
+ }
193
+ // Invalid license key.
194
+ if ( 'valid' != $status ) {
195
+ ?>
196
+ <div class="error">
197
+ <p>
198
+ <strong><?php echo sprintf( $no_valid_string, $this->product->get_name() . ' ' . $this->product->get_type(), $this->get_api_url(), admin_url( 'options-general.php' ) . '#' . $this->product->get_key() ); ?> </strong>
199
+ </p>
200
+ </div>
201
+ <?php
202
+
203
+ return false;
204
+ }
205
+
206
+ // Expired and soon to expire license.
207
+ if ( 'valid' == $status && $this->check_expiration() ) {
208
+ ?>
209
+ <div class="update-nag">
210
+ <p>
211
+ <strong>
212
+ <?php
213
+ echo sprintf(
214
+ $expiration_string,
215
+ $this->product->get_name() . ' ' . $this->product->get_type(),
216
+ '<a href="' . $this->renew_url() . '" target="_blank">' . $this->get_distributor_name() . '</a>'
217
+ );
218
+ ?>
219
+ </strong>
220
+ </p>
221
+ </div>
222
+ <?php
223
+ return false;
224
+ }
225
+
226
+ return true;
227
+ }
228
+
229
+ /**
230
+ * Check if the license is active or not.
231
+ *
232
+ * @return bool
233
+ */
234
+ public function check_activation() {
235
+ $license_data = get_option( $this->product->get_key() . '_license_data', '' );
236
+ if ( '' === $license_data ) {
237
+ return false;
238
+ }
239
+
240
+ return isset( $license_data->error ) ? ( 'no_activations_left' == $license_data->error ) : false;
241
+
242
+ }
243
+
244
+ /**
245
+ * Check if the license is about to expire in the next month.
246
+ *
247
+ * @return bool
248
+ */
249
+ function check_expiration() {
250
+ $license_data = get_option( $this->product->get_key() . '_license_data', '' );
251
+ if ( '' === $license_data ) {
252
+ return false;
253
+ }
254
+ if ( ! isset( $license_data->expires ) ) {
255
+ return false;
256
+ }
257
+ if ( strtotime( $license_data->expires ) - time() > 30 * 24 * 3600 ) {
258
+ return false;
259
+ }
260
+
261
+ return true;
262
+ }
263
+
264
+ /**
265
+ * Return the renew url from the store used.
266
+ *
267
+ * @return string The renew url.
268
+ */
269
+ function renew_url() {
270
+ $license_data = get_option( $this->product->get_key() . '_license_data', '' );
271
+ if ( '' === $license_data ) {
272
+ return $this->get_api_url();
273
+ }
274
+ if ( ! isset( $license_data->download_id ) || ! isset( $license_data->key ) ) {
275
+ return $this->get_api_url();
276
+ }
277
+
278
+ return $this->get_api_url() . '/checkout/?edd_license_key=' . $license_data->key . '&download_id=' . $license_data->download_id;
279
+ }
280
+
281
+ /**
282
+ * Run the license check call.
283
+ */
284
+ public function product_valid() {
285
+ if ( false !== ( $license = get_transient( $this->product->get_key() . '_license_data' ) ) ) {
286
+ return;
287
+ }
288
+ $license = $this->check_license();
289
+ set_transient( $this->product->get_key() . '_license_data', $license, 12 * HOUR_IN_SECONDS );
290
+ update_option( $this->product->get_key() . '_license_data', $license );
291
+ }
292
+
293
+ /**
294
+ * Check the license status.
295
+ *
296
+ * @return object The license data.
297
+ */
298
+ public function check_license() {
299
+ $status = $this->get_license_status();
300
+ if ( 'not_active' == $status ) {
301
+ $license_data = new \stdClass();
302
+ $license_data->license = 'not_active';
303
+
304
+ return $license_data;
305
+ }
306
+ $license = trim( $this->license_key );
307
+ $api_params = array(
308
+ 'edd_action' => 'check_license',
309
+ 'license' => $license,
310
+ 'item_name' => rawurlencode( $this->product->get_name() ),
311
+ 'url' => rawurlencode( home_url() ),
312
+ );
313
+ // Call the custom API.
314
+ $response = wp_remote_get(
315
+ add_query_arg( $api_params, $this->get_api_url() ),
316
+ array(
317
+ 'timeout' => 15,
318
+ 'sslverify' => false,
319
+ )
320
+ );
321
+ if ( is_wp_error( $response ) ) {
322
+ $license_data = new \stdClass();
323
+ $license_data->license = 'valid';
324
+
325
+ } else {
326
+ $license_data = json_decode( wp_remote_retrieve_body( $response ) );
327
+ if ( ! is_object( $license_data ) ) {
328
+ $license_data = new \stdClass();
329
+ $license_data->license = 'valid';
330
+ }
331
+ }
332
+ $license_old = get_option( $this->product->get_key() . '_license_data', '' );
333
+ if ( 'valid' == $license_old->license && ( $license_data->license != $license_old->license ) ) {
334
+ $this->increment_failed_checks();
335
+ } else {
336
+ $this->reset_failed_checks();
337
+ }
338
+
339
+ if ( $this->failed_checks <= self::$max_failed ) {
340
+ return $license_old;
341
+ }
342
+
343
+ if ( isset( $license_old->hide_valid ) ) {
344
+ $license_data->hide_valid = true;
345
+ }
346
+
347
+ if ( ! isset( $license_data->key ) ) {
348
+ $license_data->key = isset( $license_old->key ) ? $license_old->key : '';
349
+ }
350
+
351
+ if ( isset( $license_old->hide_expiration ) ) {
352
+ $license_data->hide_expiration = true;
353
+ }
354
+
355
+ if ( isset( $license_old->hide_activation ) ) {
356
+ $license_data->hide_activation = true;
357
+ }
358
+
359
+ return $license_data;
360
+
361
+ }
362
+
363
+ /**
364
+ * Increment the failed checks.
365
+ */
366
+ private function increment_failed_checks() {
367
+ $this->failed_checks ++;
368
+ update_option( $this->product->get_key() . '_failed_checks', $this->failed_checks );
369
+ }
370
+
371
+ /**
372
+ * Reset the failed checks
373
+ */
374
+ private function reset_failed_checks() {
375
+ $this->failed_checks = 1;
376
+ update_option( $this->product->get_key() . '_failed_checks', $this->failed_checks );
377
+ }
378
+
379
+ /**
380
+ * Activate the license remotely.
381
+ */
382
+ function activate_license() {
383
+ // listen for our activate button to be clicked.
384
+ if ( ! isset( $_POST[ $this->product->get_key() . '_btn_trigger' ] ) ) {
385
+ return;
386
+ }
387
+ $status = $this->get_license_status();
388
+ // retrieve the license from the database.
389
+ $license = $_POST[ $this->product->get_key() . '_license' ];
390
+ $api_params = array(
391
+ 'license' => $license,
392
+ 'item_name' => rawurlencode( $this->product->get_name() ),
393
+ 'url' => rawurlencode( home_url() ),
394
+ );
395
+ if ( 'valid' != $status ) {
396
+ // data to send in our API request.
397
+ $api_params['edd_action'] = 'activate_license';
398
+ } else {
399
+ $api_params['edd_action'] = 'deactivate_license';
400
+ }
401
+ // Call the custom API.
402
+ $response = wp_remote_get( add_query_arg( $api_params, $this->get_api_url() ) );
403
+ // make sure the response came back okay.
404
+ if ( is_wp_error( $response ) ) {
405
+ $license_data = new \stdClass();
406
+ $license_data->license = ( 'valid' != $status ) ? 'valid' : 'invalid';
407
+
408
+ } else {
409
+ $license_data = json_decode( wp_remote_retrieve_body( $response ) );
410
+ if ( ! is_object( $license_data ) ) {
411
+ $license_data = new \stdClass();
412
+ $license_data->license = ( 'valid' != $status ) ? 'valid' : 'invalid';
413
+ }
414
+ if ( ! isset( $license_data->license ) ) {
415
+ $license_data->license = 'invalid';
416
+ }
417
+ }
418
+ if ( ! isset( $license_data->key ) ) {
419
+ $license_data->key = $license;
420
+ }
421
+ if ( 'valid' == $license_data->license ) {
422
+ $this->reset_failed_checks();
423
+ }
424
+
425
+ if ( isset( $license_data->plan ) ) {
426
+ update_option( $this->product->get_key() . '_license_plan', $license_data->plan );
427
+ }
428
+
429
+ update_option( $this->product->get_key() . '_license_data', $license_data );
430
+ set_transient( $this->product->get_key() . '_license_data', $license_data, 12 * HOUR_IN_SECONDS );
431
+
432
+ }
433
+
434
+ /**
435
+ * Load the Themes screen.
436
+ */
437
+ function load_themes_screen() {
438
+ add_thickbox();
439
+ add_action( 'admin_notices', array( &$this, 'update_nag' ) );
440
+ }
441
+
442
+ /**
443
+ * Alter the nag for themes update.
444
+ */
445
+ function update_nag() {
446
+ $theme = wp_get_theme( $this->product->get_slug() );
447
+ $api_response = get_transient( $this->product_key );
448
+ if ( false === $api_response ) {
449
+ return;
450
+ }
451
+ $update_url = wp_nonce_url( 'update.php?action=upgrade-theme&amp;theme=' . urlencode( $this->product->get_slug() ), 'upgrade-theme_' . $this->product->get_slug() );
452
+ $update_message = apply_filters( 'themeisle_sdk_license_update_message', 'Updating this theme will lose any customizations you have made. Cancel to stop, OK to update.' );
453
+ $update_onclick = ' onclick="if ( confirm(\'' . esc_js( $update_message ) . '\') ) {return true;}return false;"';
454
+ if ( version_compare( $this->product->get_version(), $api_response->new_version, '<' ) ) {
455
+ echo '<div id="update-nag">';
456
+ printf(
457
+ '<strong>%1$s %2$s</strong> is available. <a href="%3$s" class="thickbox" title="%4s">Check out what\'s new</a> or <a href="%5$s"%6$s>update now</a>.',
458
+ $theme->get( 'Name' ),
459
+ $api_response->new_version,
460
+ '#TB_inline?width=640&amp;inlineId=' . $this->product->get_version() . '_changelog',
461
+ $theme->get( 'Name' ),
462
+ $update_url,
463
+ $update_onclick
464
+ );
465
+ echo '</div>';
466
+ echo '<div id="' . $this->product->get_slug() . '_' . 'changelog" style="display:none;">';
467
+ echo wpautop( $api_response->sections['changelog'] );
468
+ echo '</div>';
469
+ }
470
+ }
471
+
472
+ /**
473
+ * Alter update transient.
474
+ *
475
+ * @param mixed $value The transient data.
476
+ *
477
+ * @return mixed
478
+ */
479
+ function theme_update_transient( $value ) {
480
+ $update_data = $this->check_for_update();
481
+ if ( $update_data ) {
482
+ $value->response[ $this->product->get_slug() ] = $update_data;
483
+ }
484
+
485
+ return $value;
486
+ }
487
+
488
+ /**
489
+ * Check for updates
490
+ *
491
+ * @return array|bool Either the update data or false in case of failure.
492
+ */
493
+ function check_for_update() {
494
+ $update_data = get_transient( $this->product_key );
495
+
496
+ if ( false === $update_data ) {
497
+ $failed = false;
498
+ $update_data = $this->get_version_data();
499
+ if ( empty( $update_data ) ) {
500
+ $failed = true;
501
+ }
502
+ // If the response failed, try again in 30 minutes.
503
+ if ( $failed ) {
504
+ $data = new \stdClass();
505
+ $data->new_version = $this->product->get_version();
506
+ set_transient( $this->product_key, $data, 30 * MINUTE_IN_SECONDS );
507
+
508
+ return false;
509
+ }
510
+ $update_data->sections = maybe_unserialize( $update_data->sections );
511
+
512
+ set_transient( $this->product_key, $update_data, 12 * HOUR_IN_SECONDS );
513
+ }
514
+ if ( ! isset( $update_data->new_version ) ) {
515
+ return false;
516
+ }
517
+ if ( version_compare( $this->product->get_version(), $update_data->new_version, '>=' ) ) {
518
+ return false;
519
+ }
520
+
521
+ return (array) $update_data;
522
+ }
523
+
524
+ /**
525
+ * Check remote api for latest version.
526
+ *
527
+ * @return bool|mixed Update api response.
528
+ */
529
+ private function get_version_data() {
530
+ $api_params = array(
531
+ 'edd_action' => 'get_version',
532
+ 'version' => $this->product->get_version(),
533
+ 'license' => $this->license_key,
534
+ 'name' => $this->product->get_name(),
535
+ 'slug' => $this->product->get_slug(),
536
+ 'author' => $this->get_distributor_name(),
537
+ 'url' => rawurlencode( home_url() ),
538
+ );
539
+ $response = wp_remote_get(
540
+ $this->get_api_url(),
541
+ array(
542
+ 'timeout' => 15,
543
+ 'sslverify' => false,
544
+ 'body' => $api_params,
545
+ )
546
+ );
547
+ if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) {
548
+ return false;
549
+ }
550
+ $update_data = json_decode( wp_remote_retrieve_body( $response ) );
551
+ if ( ! is_object( $update_data ) ) {
552
+ return false;
553
+ }
554
+
555
+ return $update_data;
556
+ }
557
+
558
+ /**
559
+ * Delete the update transient
560
+ */
561
+ function delete_theme_update_transient() {
562
+ delete_transient( $this->product_key );
563
+ }
564
+
565
+ /**
566
+ * Check for Updates at the defined API endpoint and modify the update array.
567
+ *
568
+ * @param array $_transient_data Update array build by WordPress.
569
+ *
570
+ * @return mixed Modified update array with custom plugin data.
571
+ */
572
+ public function pre_set_site_transient_update_plugins_filter( $_transient_data ) {
573
+ if ( empty( $_transient_data ) || ! $this->do_check ) {
574
+ $this->do_check = true;
575
+
576
+ return $_transient_data;
577
+ }
578
+ $api_response = $this->api_request();
579
+ if ( false !== $api_response && is_object( $api_response ) && isset( $api_response->new_version ) ) {
580
+ if ( version_compare( $this->product->get_version(), $api_response->new_version, '<' ) ) {
581
+ $_transient_data->response[ $this->product->get_slug() . '/' . $this->product->get_file() ] = $api_response;
582
+ }
583
+ }
584
+
585
+ return $_transient_data;
586
+ }
587
+
588
+ /**
589
+ * Calls the API and, if successfull, returns the object delivered by the API.
590
+ *
591
+ * @param string $_action The requested action.
592
+ * @param array $_data Parameters for the API action.
593
+ *
594
+ * @return false||object
595
+ */
596
+ private function api_request( $_action = '', $_data = '' ) {
597
+ $update_data = $this->get_version_data();
598
+ if ( empty( $update_data ) ) {
599
+ return false;
600
+ }
601
+ if ( $update_data && isset( $update_data->sections ) ) {
602
+ $update_data->sections = maybe_unserialize( $update_data->sections );
603
+ }
604
+
605
+ return $update_data;
606
+ }
607
+
608
+ /**
609
+ * Updates information on the "View version x.x details" page with custom data.
610
+ *
611
+ * @param mixed $_data Plugin data.
612
+ * @param string $_action Action to send.
613
+ * @param object $_args Arguments to use.
614
+ *
615
+ * @return object $_data
616
+ */
617
+ public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
618
+ if ( ( 'plugin_information' != $_action ) || ! isset( $_args->slug ) || ( $_args->slug != $this->product->get_slug() ) ) {
619
+ return $_data;
620
+ }
621
+ $api_response = $this->api_request();
622
+ if ( false !== $api_response ) {
623
+ $_data = $api_response;
624
+ }
625
+
626
+ return $_data;
627
+ }
628
+
629
+ /**
630
+ * Disable SSL verification in order to prevent download update failures.
631
+ *
632
+ * @param array $args Http args.
633
+ * @param string $url Url to check.
634
+ *
635
+ * @return array $array
636
+ */
637
+ function http_request_args( $args, $url ) {
638
+ // If it is an https request and we are performing a package download, disable ssl verification.
639
+ if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
640
+ $args['sslverify'] = false;
641
+ }
642
+
643
+ return $args;
644
+ }
645
+
646
+ /**
647
+ * Check if we should load the module for this product.
648
+ *
649
+ * @param Product $product Product data.
650
+ *
651
+ * @return bool Should we load the module?
652
+ */
653
+ public function can_load( $product ) {
654
+
655
+ if ( $product->is_wordpress_available() ) {
656
+ return false;
657
+ }
658
+
659
+ return ( apply_filters( $product->get_key() . '_enable_licenser', true ) === true );
660
+
661
+ }
662
+
663
+ /**
664
+ * Load module logic.
665
+ *
666
+ * @param Product $product Product to load the module for.
667
+ *
668
+ * @return Licenser Module object.
669
+ */
670
+ public function load( $product ) {
671
+ $this->product = $product;
672
+
673
+ $this->product_key = $this->product->get_key() . '-update-response';
674
+
675
+ $this->license_key = $this->product->get_license();
676
+ if ( $this->product->requires_license() ) {
677
+ $this->failed_checks = intval( get_option( $this->product->get_key() . '_failed_checks', 0 ) );
678
+ $this->register_license_hooks();
679
+ }
680
+
681
+ if ( $this->product->is_plugin() ) {
682
+ add_filter(
683
+ 'pre_set_site_transient_update_plugins',
684
+ [
685
+ $this,
686
+ 'pre_set_site_transient_update_plugins_filter',
687
+ ]
688
+ );
689
+ add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
690
+ add_filter( 'http_request_args', array( $this, 'http_request_args' ), 10, 2 );
691
+
692
+ return $this;
693
+ }
694
+ if ( $this->product->is_theme() ) {
695
+ add_filter( 'site_transient_update_themes', array( &$this, 'theme_update_transient' ) );
696
+ add_filter( 'delete_site_transient_update_themes', array( &$this, 'delete_theme_update_transient' ) );
697
+ add_action( 'load-update-core.php', array( &$this, 'delete_theme_update_transient' ) );
698
+ add_action( 'load-themes.php', array( &$this, 'delete_theme_update_transient' ) );
699
+ add_action( 'load-themes.php', array( &$this, 'load_themes_screen' ) );
700
+ add_filter( 'http_request_args', array( $this, 'disable_wporg_update' ), 5, 2 );
701
+
702
+ return $this;
703
+
704
+ }
705
+
706
+ return $this;
707
+ }
708
+
709
+ /**
710
+ * Register license fields for the products.
711
+ */
712
+ public function register_license_hooks() {
713
+ add_action( 'admin_init', array( $this, 'register_settings' ) );
714
+ add_action( 'admin_init', array( $this, 'activate_license' ) );
715
+ add_action( 'admin_init', array( $this, 'product_valid' ), 99999999 );
716
+ add_action( 'admin_notices', array( $this, 'show_notice' ) );
717
+ add_filter( $this->product->get_key() . '_license_status', array( $this, 'get_license_status' ) );
718
+ }
719
+ }
vendor/codeinwp/themeisle-sdk/src/Modules/Logger.php ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The logger model class for ThemeIsle SDK
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Modules
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 1.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK\Modules;
13
+
14
+ use ThemeisleSDK\Common\Abstract_Module;
15
+ use ThemeisleSDK\Loader;
16
+ use ThemeisleSDK\Product;
17
+
18
+ // Exit if accessed directly.
19
+ if ( ! defined( 'ABSPATH' ) ) {
20
+ exit;
21
+ }
22
+
23
+ /**
24
+ * Logger module for ThemeIsle SDK.
25
+ */
26
+ class Logger extends Abstract_Module {
27
+ /**
28
+ * Endpoint where to collect logs.
29
+ */
30
+ const TRACKING_ENDPOINT = 'http://log.themeisle.com/wp-json/v1/logs/';
31
+
32
+
33
+ /**
34
+ * Check if we should load the module for this product.
35
+ *
36
+ * @param Product $product Product to load the module for.
37
+ *
38
+ * @return bool Should we load ?
39
+ */
40
+ public function can_load( $product ) {
41
+
42
+ return apply_filters( $product->get_slug() . '_sdk_enable_logger', true );
43
+ }
44
+
45
+ /**
46
+ * Load module logic.
47
+ *
48
+ * @param Product $product Product to load.
49
+ *
50
+ * @return Logger Module object.
51
+ */
52
+ public function load( $product ) {
53
+ $this->product = $product;
54
+ $this->setup_notification();
55
+ $this->setup_actions();
56
+
57
+ return $this;
58
+ }
59
+
60
+ /**
61
+ * Setup notification on admin.
62
+ */
63
+ public function setup_notification() {
64
+ if ( ! $this->product->is_wordpress_available() ) {
65
+ return;
66
+ }
67
+
68
+ add_filter( 'themeisle_sdk_registered_notifications', [ $this, 'add_notification' ] );
69
+
70
+ }
71
+
72
+ /**
73
+ * Setup tracking actions.
74
+ */
75
+ public function setup_actions() {
76
+ if ( ! $this->is_logger_active() ) {
77
+ return;
78
+ }
79
+ $action_key = $this->product->get_key() . '_log_activity';
80
+ if ( ! wp_next_scheduled( $action_key ) ) {
81
+ wp_schedule_single_event( time() + ( rand( 1, 24 ) * 3600 ), $action_key );
82
+ }
83
+ add_action( $action_key, array( $this, 'send_log' ) );
84
+
85
+ }
86
+
87
+ /**
88
+ * Check if the logger is active.
89
+ *
90
+ * @return bool Is logger active?
91
+ */
92
+ private function is_logger_active() {
93
+ if ( ! $this->product->is_wordpress_available() ) {
94
+ return true;
95
+ }
96
+ $pro_slug = $this->product->get_pro_slug();
97
+
98
+ if ( ! empty( $pro_slug ) ) {
99
+ $all_products = Loader::get_products();
100
+ if ( isset( $all_products[ $pro_slug ] ) ) {
101
+ return true;
102
+ }
103
+ }
104
+
105
+ return ( get_option( $this->product->get_key() . '_logger_flag', 'no' ) === 'yes' );
106
+ }
107
+
108
+ /**
109
+ * Add notification to queue.
110
+ *
111
+ * @param array $all_notifications Previous notification.
112
+ *
113
+ * @return array All notifications.
114
+ */
115
+ public function add_notification( $all_notifications ) {
116
+
117
+ $message = apply_filters( $this->product->get_key() . '_logger_heading', 'Do you enjoy <b>{product}</b>? Become a contributor by opting in to our anonymous data tracking. We guarantee no sensitive data is collected.' );
118
+
119
+ $message = str_replace(
120
+ array( '{product}' ),
121
+ $this->product->get_friendly_name(),
122
+ $message
123
+ );
124
+ $button_submit = apply_filters( $this->product->get_key() . '_logger_button_submit', 'Sure, I would love to help.' );
125
+ $button_cancel = apply_filters( $this->product->get_key() . '_logger_button_cancel', 'No, thanks.' );
126
+
127
+ $all_notifications[] = [
128
+ 'id' => $this->product->get_key() . '_logger_flag',
129
+ 'message' => $message,
130
+ 'ctas' => [
131
+ 'confirm' => [
132
+ 'link' => '#',
133
+ 'text' => $button_submit,
134
+ ],
135
+ 'cancel' => [
136
+ 'link' => '#',
137
+ 'text' => $button_cancel,
138
+ ],
139
+ ],
140
+ ];
141
+
142
+ return $all_notifications;
143
+ }
144
+
145
+ /**
146
+ * Send the statistics to the api endpoint.
147
+ */
148
+ public function send_log() {
149
+ $environment = array();
150
+ $theme = wp_get_theme();
151
+ $environment['theme'] = array();
152
+ $environment['theme']['name'] = $theme->get( 'Name' );
153
+ $environment['theme']['author'] = $theme->get( 'Author' );
154
+ $environment['plugins'] = get_option( 'active_plugins' );
155
+ global $wp_version;
156
+ wp_remote_post(
157
+ self::TRACKING_ENDPOINT,
158
+ array(
159
+ 'method' => 'POST',
160
+ 'timeout' => 3,
161
+ 'redirection' => 5,
162
+ 'headers' => array(
163
+ 'X-ThemeIsle-Event' => 'log_site',
164
+ ),
165
+ 'body' => array(
166
+ 'site' => get_site_url(),
167
+ 'slug' => $this->product->get_slug(),
168
+ 'version' => $this->product->get_version(),
169
+ 'wp_version' => $wp_version,
170
+ 'data' => apply_filters( $this->product->get_key() . '_logger_data', array() ),
171
+ 'environment' => $environment,
172
+ 'license' => apply_filters( $this->product->get_key() . '_license_status', '' ),
173
+ ),
174
+ )
175
+ );
176
+ }
177
+ }
vendor/codeinwp/themeisle-sdk/src/Modules/Notification.php ADDED
@@ -0,0 +1,456 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The notification model class for ThemeIsle SDK
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Modules
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 1.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK\Modules;
13
+
14
+ use ThemeisleSDK\Common\Abstract_Module;
15
+ use ThemeisleSDK\Product;
16
+
17
+ // Exit if accessed directly.
18
+ if ( ! defined( 'ABSPATH' ) ) {
19
+ exit;
20
+ }
21
+
22
+ /**
23
+ * Notification module for ThemeIsle SDK.
24
+ */
25
+ class Notification extends Abstract_Module {
26
+ /**
27
+ * Show notifications only after the user has the product installed after this amount of time, in hours.
28
+ */
29
+ const MIN_INSTALL_TIME = 100;
30
+ /**
31
+ * How much time should we show the notification, in days.
32
+ */
33
+ const MAX_TIME_TO_LIVE = 7;
34
+
35
+ /**
36
+ * Number of days between notifications.
37
+ */
38
+ const TIME_BETWEEN_NOTIFICATIONS = 5;
39
+
40
+ /**
41
+ * Holds a possible notification list.
42
+ *
43
+ * @var array Notifications list.
44
+ */
45
+ private static $notifications = [];
46
+
47
+ /**
48
+ * Show notification data.
49
+ */
50
+ public static function show_notification() {
51
+
52
+ $current_notification = self::get_last_notification();
53
+
54
+ $notification_details = [];
55
+ // Check if the saved notification is still present among the possible ones.
56
+ if ( ! empty( $current_notification ) ) {
57
+ $notification_details = self::get_notification_details( $current_notification );
58
+ if ( empty( $notification_details ) ) {
59
+ $current_notification = [];
60
+ }
61
+ }
62
+ // Check if the notificatin is expired.
63
+ if ( ! empty( $current_notification ) && self::is_notification_expired( $current_notification ) ) {
64
+ update_option( $current_notification['id'], 'no' );
65
+ self::set_last_active_notification_timestamp();
66
+ $current_notification = [];
67
+ }
68
+ // If we don't have any saved notification, get a new one.
69
+ if ( empty( $current_notification ) ) {
70
+ $notification_details = self::get_random_notification();
71
+ if ( empty( $notification_details ) ) {
72
+ return;
73
+ }
74
+ self::set_active_notification(
75
+ [
76
+ 'id' => $notification_details['id'],
77
+ 'display_at' => time(),
78
+ ]
79
+ );
80
+ }
81
+ if ( empty( $notification_details ) ) {
82
+ return;
83
+ }
84
+ $notification_html = self::get_notification_html( $notification_details );
85
+ do_action( $notification_details['id'] . '_before_render' );
86
+
87
+ echo $notification_html;
88
+
89
+ do_action( $notification_details['id'] . '_after_render' );
90
+ self::render_snippets();
91
+ }
92
+
93
+ /**
94
+ * Get last notification details.
95
+ *
96
+ * @return array Last notification details.
97
+ */
98
+ private static function get_last_notification() {
99
+ $notification = self::get_notifications_metadata();
100
+
101
+ return isset( $notification['last_notification'] ) ? $notification['last_notification'] : [];
102
+ }
103
+
104
+ /**
105
+ * Get notification center details.
106
+ *
107
+ * @return array Notification center details.
108
+ */
109
+ private static function get_notifications_metadata() {
110
+
111
+ $data = get_option(
112
+ 'themeisle_sdk_notifications',
113
+ [
114
+ 'last_notification' => [],
115
+ 'last_notification_active' => 0,
116
+ ]
117
+ );
118
+
119
+ return $data;
120
+
121
+ }
122
+
123
+ /**
124
+ * Check if the notification is still possible.
125
+ *
126
+ * @param array $notification Notification to check.
127
+ *
128
+ * @return array Either is still active or not.
129
+ */
130
+ private static function get_notification_details( $notification ) {
131
+ $notifications = array_filter(
132
+ self::$notifications,
133
+ function ( $value ) use ( $notification ) {
134
+ if ( isset( $value['id'] ) && isset( $notification['id'] ) && $value['id'] === $notification['id'] ) {
135
+ return true;
136
+ }
137
+
138
+ return false;
139
+ }
140
+ );
141
+
142
+ return ! empty( $notifications ) ? reset( $notifications ) : [];
143
+ }
144
+
145
+ /**
146
+ * Check if the notification is expired.
147
+ *
148
+ * @param array $notification Notification to check.
149
+ *
150
+ * @return bool Either the notification is due.
151
+ */
152
+ private static function is_notification_expired( $notification ) {
153
+ if ( ! isset( $notification['display_at'] ) ) {
154
+ return true;
155
+ }
156
+
157
+ $notifications = array_filter(
158
+ self::$notifications,
159
+ function ( $value ) use ( $notification ) {
160
+ if ( isset( $value['id'] ) && isset( $notification['id'] ) && $value['id'] === $notification['id'] ) {
161
+ return true;
162
+ }
163
+
164
+ return false;
165
+ }
166
+ );
167
+
168
+ if ( empty( $notifications ) ) {
169
+ return true;
170
+ }
171
+ $notification_definition = reset( $notifications );
172
+
173
+ $when_to_expire = isset( $notification_definition['expires_at'] )
174
+ ? $notification_definition['expires_at'] :
175
+ ( isset( $notification_definition['expires'] )
176
+ ? ( $notification['display_at'] + $notification_definition['expires'] ) :
177
+ ( $notification['display_at'] + self::MAX_TIME_TO_LIVE * DAY_IN_SECONDS )
178
+ );
179
+
180
+ return ( $when_to_expire - time() ) < 0;
181
+ }
182
+
183
+ /**
184
+ * Set last notification details.
185
+ */
186
+ private static function set_last_active_notification_timestamp() {
187
+ $metadata = self::get_notifications_metadata();
188
+ $metadata['last_notification_active'] = time();
189
+ update_option( 'themeisle_sdk_notifications', $metadata );
190
+ }
191
+
192
+ /**
193
+ * Return notification to show.
194
+ *
195
+ * @return array Notification data.
196
+ */
197
+ public static function get_random_notification() {
198
+ if ( ( time() - self::get_last_active_notification_timestamp() ) < self::TIME_BETWEEN_NOTIFICATIONS * DAY_IN_SECONDS ) {
199
+ return [];
200
+ }
201
+
202
+ $notifications = self::$notifications;
203
+ $notifications = array_filter(
204
+ $notifications,
205
+ function ( $value ) {
206
+ if ( isset( $value['sticky'] ) && true === $value['sticky'] ) {
207
+ return true;
208
+ }
209
+
210
+ return false;
211
+ }
212
+ );
213
+ // No priority notifications, use all.
214
+ if ( empty( $notifications ) ) {
215
+ $notifications = self::$notifications;
216
+ }
217
+ if ( empty( $notifications ) ) {
218
+ return [];
219
+ }
220
+ $notifications = array_values( $notifications );
221
+
222
+ return $notifications[ array_rand( $notifications, 1 ) ];
223
+
224
+ }
225
+
226
+ /**
227
+ * Get last notification details.
228
+ *
229
+ * @return array Last notification details.
230
+ */
231
+ private static function get_last_active_notification_timestamp() {
232
+ $notification = self::get_notifications_metadata();
233
+
234
+ return isset( $notification['last_notification_active'] ) ? $notification['last_notification_active'] : 0;
235
+ }
236
+
237
+ /**
238
+ * Get last notification details.
239
+ *
240
+ * @param array $notification Notification data.
241
+ */
242
+ private static function set_active_notification( $notification ) {
243
+ $metadata = self::get_notifications_metadata();
244
+ $metadata['last_notification'] = $notification;
245
+ update_option( 'themeisle_sdk_notifications', $metadata );
246
+ }
247
+
248
+ /**
249
+ * Get notification html.
250
+ *
251
+ * @param array $notification_details Notification details.
252
+ *
253
+ * @return string Html for notice.
254
+ */
255
+ public static function get_notification_html( $notification_details ) {
256
+ $default = [
257
+ 'id' => '',
258
+ 'heading' => '',
259
+ 'message' => '',
260
+ 'ctas' => [
261
+ 'confirm' => [
262
+ 'link' => '#',
263
+ 'text' => '',
264
+ ],
265
+ 'cancel' => [
266
+ 'link' => '#',
267
+ 'text' => '',
268
+ ],
269
+ ],
270
+ ];
271
+ $notification_details = wp_parse_args( $notification_details, $default );
272
+
273
+ $notification_html = '<div class="notice notice-success is-dismissible themeisle-sdk-notice" data-notification-id="' . esc_attr( $notification_details['id'] ) . '" id="' . esc_attr( $notification_details['id'] ) . '-notification"> <div class="themeisle-sdk-notification-box">';
274
+
275
+ if ( ! empty( $notification_details['heading'] ) ) {
276
+ $notification_html .= sprintf( '<h4>%s</h4>', wp_kses_post( $notification_details['heading'] ) );
277
+ }
278
+ if ( ! empty( $notification_details['message'] ) ) {
279
+ $notification_html .= wp_kses_post( $notification_details['message'] );
280
+ }
281
+ $notification_html .= '<div class="actions">';
282
+
283
+ if ( ! empty( $notification_details['ctas']['confirm']['text'] ) ) {
284
+ $notification_html .= sprintf(
285
+ '<a href="%s" target="_blank" class=" button button-primary %s" data-confirm="yes" >%s</a>',
286
+ esc_url( $notification_details['ctas']['confirm']['link'] ),
287
+ esc_attr( $notification_details['id'] . '_confirm' ),
288
+ wp_kses_post( $notification_details['ctas']['confirm']['text'] )
289
+ );
290
+ }
291
+
292
+ if ( ! empty( $notification_details['ctas']['cancel']['text'] ) ) {
293
+ $notification_html .= sprintf(
294
+ '<a href="%s" class=" button %s" data-confirm="no">%s</a>',
295
+ esc_url( $notification_details['ctas']['cancel']['link'] ),
296
+ esc_attr( $notification_details['id'] ) . '_cancel',
297
+ wp_kses_post( $notification_details['ctas']['cancel']['text'] )
298
+ );
299
+ }
300
+
301
+ $notification_html .= '</div>';
302
+ $notification_html .= ' </div>';
303
+ $notification_html .= ' </div>';
304
+
305
+ return $notification_html;
306
+ }
307
+
308
+ /**
309
+ * Adds js snippet for hiding the notice.
310
+ */
311
+ public static function render_snippets() {
312
+
313
+ ?>
314
+ <style type="text/css">
315
+ .themeisle-sdk-notification-box {
316
+ padding: 3px;
317
+ }
318
+
319
+ .themeisle-sdk-notification-box .actions {
320
+ margin-top: 6px;
321
+ margin-bottom: 4px;
322
+ }
323
+
324
+ .themeisle-sdk-notification-box .button {
325
+ margin-right: 5px;
326
+ }
327
+ </style>
328
+ <script type="text/javascript">
329
+ (function ($) {
330
+ $(document).ready(function () {
331
+ $('#wpbody-content').on('click', ".themeisle-sdk-notice a.button, .themeisle-sdk-notice .notice-dismiss", function (e) {
332
+
333
+ var container = $('.themeisle-sdk-notice');
334
+ var link = $(this);
335
+ var notification_id = container.attr('data-notification-id');
336
+ var confirm = link.attr('data-confirm');
337
+ if (typeof confirm === "undefined") {
338
+ confirm = 'no';
339
+ }
340
+ $.post(
341
+ ajaxurl,
342
+ {
343
+ 'nonce': '<?php echo wp_create_nonce( (string) __CLASS__ ); ?>',
344
+ 'action': 'themeisle_sdk_dismiss_notice',
345
+ 'id': notification_id,
346
+ 'confirm': confirm
347
+ }
348
+ );
349
+ if (confirm === 'yes') {
350
+ $(this).trigger('themeisle-sdk:confirmed');
351
+ } else {
352
+ $(this).trigger('themeisle-sdk:canceled');
353
+ }
354
+ container.hide();
355
+ if (link.attr('href') === '#') {
356
+ return false;
357
+ }
358
+ });
359
+ });
360
+ })(jQuery);
361
+ </script>
362
+ <?php
363
+ }
364
+
365
+ /**
366
+ * Dismiss the notification.
367
+ */
368
+ static function dismiss() {
369
+ check_ajax_referer( (string) __CLASS__, 'nonce' );
370
+
371
+ $id = isset( $_POST['id'] ) ? sanitize_text_field( $_POST['id'] ) : '';
372
+ $confirm = isset( $_POST['confirm'] ) ? sanitize_text_field( $_POST['confirm'] ) : 'no';
373
+
374
+ if ( empty( $id ) ) {
375
+ wp_send_json( [] );
376
+ }
377
+ self::set_last_active_notification_timestamp();
378
+ update_option( $id, $confirm );
379
+ do_action( $id . '_process_confirm', $confirm );
380
+ wp_send_json( [] );
381
+ }
382
+
383
+ /**
384
+ * Check if we should load the notification module.
385
+ *
386
+ * @param Product $product Product to check.
387
+ *
388
+ * @return bool Should we load this?
389
+ */
390
+ public function can_load( $product ) {
391
+
392
+ if ( $this->is_from_partner( $product ) ) {
393
+ return false;
394
+ }
395
+ if ( ! current_user_can( 'manage_options' ) ) {
396
+ return false;
397
+ }
398
+ if ( ( time() - $product->get_install_time() ) < ( self::MIN_INSTALL_TIME * HOUR_IN_SECONDS ) ) {
399
+ return false;
400
+ }
401
+
402
+ return true;
403
+ }
404
+
405
+ /**
406
+ * Setup notifications queue.
407
+ */
408
+ public static function setup_notifications() {
409
+ $notifications = apply_filters( 'themeisle_sdk_registered_notifications', [] );
410
+ $notifications = array_filter(
411
+ $notifications,
412
+ function ( $value ) {
413
+ if ( ! isset( $value['id'] ) ) {
414
+ return false;
415
+ }
416
+ if ( get_option( $value['id'], '' ) !== '' ) {
417
+ return false;
418
+ }
419
+
420
+ return apply_filters( $value['id'] . '_should_show', true );
421
+ }
422
+ );
423
+ self::$notifications = $notifications;
424
+ }
425
+ /**
426
+ * Load the module logic.
427
+ *
428
+ * @param Product $product Product to load the module for.
429
+ *
430
+ * @return Notification Module instance.
431
+ */
432
+ public function load( $product ) {
433
+ $this->product = $product;
434
+
435
+ $notifications = apply_filters( 'themeisle_sdk_registered_notifications', [] );
436
+ $notifications = array_filter(
437
+ $notifications,
438
+ function ( $value ) {
439
+ if ( ! isset( $value['id'] ) ) {
440
+ return false;
441
+ }
442
+ if ( get_option( $value['id'], '' ) !== '' ) {
443
+ return false;
444
+ }
445
+
446
+ return apply_filters( $value['id'] . '_should_show', true );
447
+ }
448
+ );
449
+ self::$notifications = $notifications;
450
+ add_action( 'admin_notices', array( __CLASS__, 'show_notification' ) );
451
+ add_action( 'wp_ajax_themeisle_sdk_dismiss_notice', array( __CLASS__, 'dismiss' ) );
452
+ add_action( 'admin_head', array( __CLASS__, 'setup_notifications' ) );
453
+
454
+ return $this;
455
+ }
456
+ }
vendor/codeinwp/themeisle-sdk/src/Modules/Recommendation.php ADDED
@@ -0,0 +1,374 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The class that exposes hooks for recommend.
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Rollback
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 1.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK\Modules;
13
+
14
+ // Exit if accessed directly.
15
+ use ThemeisleSDK\Common\Abstract_Module;
16
+ use ThemeisleSDK\Product;
17
+
18
+ if ( ! defined( 'ABSPATH' ) ) {
19
+ exit;
20
+ }
21
+
22
+ /**
23
+ * Expose endpoints for ThemeIsle SDK.
24
+ */
25
+ class Recommendation extends Abstract_Module {
26
+
27
+
28
+ /**
29
+ * Load module logic.
30
+ *
31
+ * @param Product $product Product to load.
32
+ */
33
+ public function load( $product ) {
34
+ $this->product = $product;
35
+ $this->setup_hooks();
36
+
37
+ return $this;
38
+ }
39
+
40
+ /**
41
+ * Setup endpoints.
42
+ */
43
+ private function setup_hooks() {
44
+ add_action( $this->product->get_key() . '_recommend_products', array( $this, 'render_products_box' ), 10, 4 );
45
+ add_action( 'admin_head', array( $this, 'enqueue' ) );
46
+ }
47
+
48
+ /**
49
+ * Check if we should load the module for this product.
50
+ *
51
+ * @param Product $product Product data.
52
+ *
53
+ * @return bool Should we load the module?
54
+ */
55
+ public function can_load( $product ) {
56
+ return true;
57
+ }
58
+
59
+ /**
60
+ * Render products box content.
61
+ *
62
+ * @param array $plugins_list - list of useful plugins (in slug => nicename format).
63
+ * @param array $themes_list - list of useful themes (in slug => nicename format).
64
+ * @param array $strings - list of translated strings.
65
+ * @param array $preferences - list of preferences.
66
+ */
67
+ function render_products_box( $plugins_list, $themes_list, $strings, $preferences = array() ) {
68
+
69
+ if ( empty( $plugins_list ) && empty( $themes_list ) ) {
70
+ return;
71
+ }
72
+
73
+ if ( ! empty( $plugins_list ) && ! current_user_can( 'install_plugins' ) ) {
74
+ return;
75
+ }
76
+
77
+ if ( ! empty( $themes_list ) && ! current_user_can( 'install_themes' ) ) {
78
+ return;
79
+ }
80
+
81
+ add_thickbox();
82
+
83
+ if ( ! empty( $themes_list ) ) {
84
+ $list = $this->get_themes( $themes_list, $preferences );
85
+
86
+ if ( has_action( $this->product->get_key() . '_recommend_products_theme_template' ) ) {
87
+ do_action( $this->product->get_key() . '_recommend_products_theme_template', $list, $strings, $preferences );
88
+ } else {
89
+ echo '<div class="recommend-product">';
90
+
91
+ foreach ( $list as $theme ) {
92
+ echo '<div class="plugin_box">';
93
+ echo ' <img class="theme-banner" src="' . $theme->screenshot_url . '">';
94
+ echo ' <div class="title-action-wrapper">';
95
+ echo ' <span class="plugin-name">' . esc_html( $theme->custom_name ) . '</span>';
96
+ if ( ! isset( $preferences['description'] ) || ( isset( $preferences['description'] ) && $preferences['description'] ) ) {
97
+ echo '<span class="plugin-desc">' . esc_html( substr( $theme->description, 0, strpos( $theme->description, '.' ) ) ) . '.</span>';
98
+ }
99
+ echo ' </div>';
100
+ echo '<div class="plugin-box-footer">';
101
+ echo ' <div class="button-wrap">';
102
+ echo ' <a class="button button-primary " href="' . esc_url( $theme->custom_url ) . '"><span class="dashicons dashicons-external"></span>' . esc_html( $strings['install'] ) . '</a>';
103
+ echo ' </div>';
104
+ echo ' </div>';
105
+ echo '</div>';
106
+ }
107
+
108
+ echo '</div>';
109
+ }
110
+ }
111
+ if ( ! empty( $plugins_list ) ) {
112
+ $list = $this->get_plugins( $plugins_list, $preferences );
113
+
114
+ if ( has_action( $this->product->get_key() . '_recommend_products_plugin_template' ) ) {
115
+ do_action( $this->product->get_key() . '_recommend_products_plugin_template', $list, $strings, $preferences );
116
+ } else {
117
+ echo '<div class="recommend-product">';
118
+
119
+ foreach ( $list as $current_plugin ) {
120
+ echo '<div class="plugin_box">';
121
+ echo ' <img class="plugin-banner" src="' . $current_plugin->custom_image . '">';
122
+ echo ' <div class="title-action-wrapper">';
123
+ echo ' <span class="plugin-name">' . esc_html( $current_plugin->custom_name ) . '</span>';
124
+ if ( ! isset( $preferences['description'] ) || ( isset( $preferences['description'] ) && $preferences['description'] ) ) {
125
+ echo '<span class="plugin-desc">' . esc_html( substr( $current_plugin->short_description, 0, strpos( $current_plugin->short_description, '.' ) ) ) . '. </span>';
126
+ }
127
+ echo ' </div>';
128
+ echo ' <div class="plugin-box-footer">';
129
+ echo ' <a class="button button-primary thickbox open-plugin-details-modal" href="' . esc_url( $current_plugin->custom_url ) . '"><span class="dashicons dashicons-external"></span>' . esc_html( $strings['install'] ) . '</a>';
130
+ echo ' </div>';
131
+ echo '</div>';
132
+ }
133
+
134
+ echo '</div>';
135
+ }
136
+ }
137
+
138
+ }
139
+
140
+ /**
141
+ * Collect all the information for the themes list.
142
+ *
143
+ * @param array $themes_list - list of useful themes (in slug => nicename format).
144
+ * @param array $preferences - list of preferences.
145
+ *
146
+ * @return array
147
+ */
148
+ private function get_themes( $themes_list, $preferences ) {
149
+ $list = array();
150
+ foreach ( $themes_list as $slug => $nicename ) {
151
+ $theme = $this->call_theme_api( $slug );
152
+ if ( ! $theme ) {
153
+ continue;
154
+ }
155
+
156
+ $url = add_query_arg(
157
+ array(
158
+ 'theme' => $theme->slug,
159
+ ),
160
+ network_admin_url( 'theme-install.php' )
161
+ );
162
+
163
+ $name = empty( $nicename ) ? $theme->name : $nicename;
164
+
165
+ $theme->custom_url = $url;
166
+ $theme->custom_name = $name;
167
+
168
+ $list[] = $theme;
169
+ }
170
+
171
+ return $list;
172
+ }
173
+
174
+ /**
175
+ * Call theme api
176
+ *
177
+ * @param string $slug theme slug.
178
+ *
179
+ * @return array|mixed|object
180
+ */
181
+ private function call_theme_api( $slug ) {
182
+ $theme = get_transient( 'ti_theme_info_' . $slug );
183
+
184
+ if ( false !== $theme ) {
185
+ return $theme;
186
+ }
187
+
188
+ $products = wp_remote_get(
189
+ 'https://api.wordpress.org/themes/info/1.1/?action=query_themes&request[theme]=' . $slug . '&request[per_page]=1'
190
+ );
191
+ $products = json_decode( wp_remote_retrieve_body( $products ) );
192
+ if ( is_object( $products ) ) {
193
+ $theme = $products->themes[0];
194
+ set_transient( 'ti_theme_info_' . $slug, $theme, 6 * HOUR_IN_SECONDS );
195
+ }
196
+
197
+ return $theme;
198
+ }
199
+
200
+ /**
201
+ * Collect all the information for the plugins list.
202
+ *
203
+ * @param array $plugins_list - list of useful plugins (in slug => nicename format).
204
+ * @param array $preferences - list of preferences.
205
+ *
206
+ * @return array
207
+ */
208
+ private function get_plugins( $plugins_list, $preferences ) {
209
+ $list = array();
210
+ foreach ( $plugins_list as $plugin => $nicename ) {
211
+ $current_plugin = $this->call_plugin_api( $plugin );
212
+
213
+ $name = empty( $nicename ) ? $current_plugin->name : $nicename;
214
+
215
+ $image = $current_plugin->banners['low'];
216
+ if ( isset( $preferences['image'] ) && 'icon' === $preferences['image'] ) {
217
+ $image = $current_plugin->icons['1x'];
218
+ }
219
+
220
+ $url = add_query_arg(
221
+ array(
222
+ 'tab' => 'plugin-information',
223
+ 'plugin' => $current_plugin->slug,
224
+ 'TB_iframe' => true,
225
+ 'width' => 800,
226
+ 'height' => 800,
227
+ ),
228
+ network_admin_url( 'plugin-install.php' )
229
+ );
230
+
231
+ $current_plugin->custom_url = $url;
232
+ $current_plugin->custom_name = $name;
233
+ $current_plugin->custom_image = $image;
234
+
235
+ $list[] = $current_plugin;
236
+ }
237
+
238
+ return $list;
239
+ }
240
+
241
+ /**
242
+ * Call plugin api
243
+ *
244
+ * @param string $slug plugin slug.
245
+ *
246
+ * @return array|mixed|object
247
+ */
248
+ private function call_plugin_api( $slug ) {
249
+ include_once( ABSPATH . 'wp-admin/includes/plugin-install.php' );
250
+
251
+ $call_api = get_transient( 'ti_plugin_info_' . $slug );
252
+
253
+ if ( false === $call_api ) {
254
+ $call_api = plugins_api(
255
+ 'plugin_information',
256
+ array(
257
+ 'slug' => $slug,
258
+ 'fields' => array(
259
+ 'downloaded' => false,
260
+ 'rating' => false,
261
+ 'description' => false,
262
+ 'short_description' => true,
263
+ 'donate_link' => false,
264
+ 'tags' => false,
265
+ 'sections' => true,
266
+ 'homepage' => true,
267
+ 'added' => false,
268
+ 'last_updated' => false,
269
+ 'compatibility' => false,
270
+ 'tested' => false,
271
+ 'requires' => false,
272
+ 'downloadlink' => false,
273
+ 'icons' => true,
274
+ 'banners' => true,
275
+ ),
276
+ )
277
+ );
278
+ set_transient( 'ti_plugin_info_' . $slug, $call_api, 30 * MINUTE_IN_SECONDS );
279
+ }
280
+
281
+ return $call_api;
282
+ }
283
+
284
+ /**
285
+ * Load css and scripts for the plugin recommend page.
286
+ */
287
+ public function enqueue() {
288
+ $screen = get_current_screen();
289
+
290
+ if ( ! isset( $screen->id ) ) {
291
+ return;
292
+ }
293
+ if ( false === apply_filters( $this->product->get_key() . '_enqueue_recommend', false, $screen->id ) ) {
294
+ return;
295
+ }
296
+
297
+ ?>
298
+ <style type="text/css">
299
+ .recommend-product {
300
+ display: flex;
301
+ justify-content: space-between;
302
+ flex-wrap: wrap;
303
+ }
304
+
305
+ .recommend-product .theme-banner {
306
+ width:200px;
307
+ margin: auto;
308
+ }
309
+ .recommend-product .plugin-banner {
310
+ width: 100px;
311
+ margin: auto;
312
+ }
313
+
314
+ .recommend-product .plugin_box .button span{
315
+
316
+ margin-top: 2px;
317
+ margin-right: 7px;
318
+ }
319
+ .recommend-product .plugin_box .button{
320
+ margin-bottom:10px;
321
+ }
322
+ .recommend-product .plugin_box {
323
+ margin-bottom: 20px;
324
+ padding-top: 5px;
325
+ display: flex;
326
+ box-shadow: 0px 0px 10px -5px rgba(0,0,0,0.55);
327
+ background: #fff;
328
+ border-radius: 5px;
329
+ flex-direction: column;
330
+ justify-content: flex-start;
331
+ width: 95%;
332
+ }
333
+
334
+ .recommend-product .title-action-wrapper {
335
+ padding: 15px 20px 5px 20px;
336
+ }
337
+
338
+ .recommend-product .plugin-name {
339
+ font-size: 18px;
340
+ display: block;
341
+ white-space: nowrap;
342
+ text-overflow: ellipsis;
343
+ margin-bottom: 10px;
344
+ overflow: hidden;
345
+ line-height: normal;
346
+ }
347
+
348
+
349
+ .recommend-product .plugin-desc {
350
+ display: block;
351
+ margin-bottom: 10px;
352
+ font-size: 13px;
353
+ color: #777;
354
+ line-height: 1.6;
355
+ }
356
+
357
+ .recommend-product .button-wrap > div {
358
+ padding: 0;
359
+ margin: 0;
360
+ }
361
+
362
+ .plugin-box-footer {
363
+ display: flex;
364
+ justify-content: space-around;
365
+ vertical-align: middle;
366
+ align-items: center;
367
+ padding: 0px 10px 5px;
368
+ flex: 1;
369
+ margin-top: auto;
370
+ }
371
+ </style>
372
+ <?php
373
+ }
374
+ }
vendor/codeinwp/themeisle-sdk/src/Modules/Review.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The Review model class for ThemeIsle SDK
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Modules
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 1.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK\Modules;
13
+
14
+ use ThemeisleSDK\Common\Abstract_Module;
15
+ use ThemeisleSDK\Product;
16
+
17
+ // Exit if accessed directly.
18
+ if ( ! defined( 'ABSPATH' ) ) {
19
+ exit;
20
+ }
21
+
22
+ /**
23
+ * Review module for ThemeIsle SDK.
24
+ */
25
+ class Review extends Abstract_Module {
26
+
27
+ /**
28
+ * Check if we should load module for this.
29
+ *
30
+ * @param Product $product Product to check.
31
+ *
32
+ * @return bool Should load ?
33
+ */
34
+ public function can_load( $product ) {
35
+ if ( $this->is_from_partner( $product ) ) {
36
+ return false;
37
+ }
38
+ if ( ! $product->is_wordpress_available() ) {
39
+ return false;
40
+ }
41
+
42
+ return apply_filters( $product->get_slug() . '_sdk_should_review', true );
43
+ }
44
+
45
+
46
+ /**
47
+ * Add notification to queue.
48
+ *
49
+ * @param array $all_notifications Previous notification.
50
+ *
51
+ * @return array All notifications.
52
+ */
53
+ public function add_notification( $all_notifications ) {
54
+
55
+ $developers = [
56
+ 'Bogdan',
57
+ 'Marius',
58
+ 'Hardeep',
59
+ 'Rodica',
60
+ 'Stefan',
61
+ 'Uriahs',
62
+ 'Madalin',
63
+ 'Radu',
64
+ 'Silviu',
65
+ 'Andrei',
66
+ ];
67
+
68
+ $link = 'https://wordpress.org/support/' . $this->product->get_type() . '/' . $this->product->get_slug() . '/reviews/#wporg-footer';
69
+
70
+ $message = apply_filters( $this->product->get_key() . '_feedback_review_message', '<p>Hey, it’s great to see you have <b>{product}</b> active for a few days now. How is everything going? If you can spare a few moments to rate it on WordPress.org it would help us a lot (and boost my motivation). Cheers! <br/> <br/>~ {developer}, developer of {product}</p>' );
71
+
72
+ $button_submit = apply_filters( $this->product->get_key() . '_feedback_review_button_do', 'Ok, I will gladly help.' );
73
+ $button_cancel = apply_filters( $this->product->get_key() . '_feedback_review_button_cancel', 'No, thanks.' );
74
+ $message = str_replace(
75
+ [ '{product}', '{developer}' ],
76
+ [
77
+ $this->product->get_friendly_name(),
78
+ $developers[ strlen( get_site_url() ) % 10 ],
79
+ ],
80
+ $message
81
+ );
82
+
83
+ $all_notifications[] = [
84
+ 'id' => $this->product->get_key() . '_review_flag',
85
+ 'message' => $message,
86
+ 'ctas' => [
87
+ 'confirm' => [
88
+ 'link' => $link,
89
+ 'text' => $button_submit,
90
+ ],
91
+ 'cancel' => [
92
+ 'link' => '#',
93
+ 'text' => $button_cancel,
94
+ ],
95
+ ],
96
+ ];
97
+
98
+ return $all_notifications;
99
+ }
100
+
101
+
102
+ /**
103
+ * Load module logic.
104
+ *
105
+ * @param Product $product Product to load.
106
+ *
107
+ * @return Review Module instance.
108
+ */
109
+ public function load( $product ) {
110
+
111
+ $this->product = $product;
112
+
113
+ add_filter( 'themeisle_sdk_registered_notifications', [ $this, 'add_notification' ] );
114
+
115
+ return $this;
116
+ }
117
+ }
vendor/codeinwp/themeisle-sdk/src/Modules/Rollback.php ADDED
@@ -0,0 +1,376 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The rollback class for ThemeIsle SDK.
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Rollback
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 1.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK\Modules;
13
+
14
+ // Exit if accessed directly.
15
+ use ThemeisleSDK\Common\Abstract_Module;
16
+ use ThemeisleSDK\Product;
17
+
18
+ if ( ! defined( 'ABSPATH' ) ) {
19
+ exit;
20
+ }
21
+
22
+ /**
23
+ * Rollback for ThemeIsle SDK.
24
+ */
25
+ class Rollback extends Abstract_Module {
26
+
27
+ /**
28
+ * Add js scripts for themes rollback.
29
+ */
30
+ public function add_footer() {
31
+ $screen = get_current_screen();
32
+ if ( ! isset( $screen->parent_file ) ) {
33
+ return;
34
+ }
35
+ if ( 'themes.php' !== $screen->parent_file ) {
36
+ return;
37
+ }
38
+ if ( ! $this->product->is_theme() ) {
39
+ return;
40
+ }
41
+ $version = $this->get_rollback();
42
+ if ( empty( $version ) ) {
43
+ return;
44
+ }
45
+ ?>
46
+ <script type="text/javascript">
47
+ jQuery(document).ready(function ($) {
48
+ setInterval(checkTheme, 500);
49
+
50
+ function checkTheme() {
51
+ var theme = '<?php echo esc_attr( $this->product->get_slug() ); ?>-action';
52
+
53
+ if (jQuery('#' + theme).length > 0) {
54
+ if (jQuery('.theme-overlay.active').is(':visible')) {
55
+ if (jQuery('#' + theme + '-rollback').length === 0) {
56
+ jQuery('.theme-actions .active-theme').prepend('<a class="button" style="float:left" id="' + theme + '-rollback" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin-post.php?action=' . $this->product->get_key() . '_rollback' ), $this->product->get_key() . '_rollback' ) ); ?>">Rollback to v<?php echo esc_attr( $version['version'] ); ?></a>')
57
+ }
58
+ }
59
+
60
+ }
61
+ }
62
+ })
63
+
64
+ </script>
65
+ <?php
66
+
67
+ }
68
+
69
+ /**
70
+ * Get the last rollback for this product.
71
+ *
72
+ * @return array The rollback version.
73
+ */
74
+ public function get_rollback() {
75
+ $rollback = array();
76
+ $versions = $this->get_api_versions();
77
+ $versions = apply_filters( $this->product->get_key() . '_rollbacks', $versions );
78
+ if ( empty( $versions ) ) {
79
+ return $rollback;
80
+ }
81
+ if ( $versions ) {
82
+ usort( $versions, array( $this, 'sort_rollback_array' ) );
83
+ foreach ( $versions as $version ) {
84
+ if ( isset( $version['version'] ) && isset( $version['url'] ) && version_compare( $this->product->get_version(), $version['version'], '>' ) ) {
85
+ $rollback = $version;
86
+ break;
87
+ }
88
+ }
89
+ }
90
+
91
+ return $rollback;
92
+ }
93
+
94
+ /**
95
+ * Get versions array from wp.org
96
+ *
97
+ * @return array Array of versions.
98
+ */
99
+ private function get_api_versions() {
100
+
101
+ $cache_key = $this->product->get_key() . '_' . preg_replace( '/[^0-9a-zA-Z ]/m', '', $this->product->get_version() ) . 'versions';
102
+ $cache_versions = get_transient( $cache_key );
103
+ if ( false === $cache_versions ) {
104
+ $versions = $this->get_remote_versions();
105
+ set_transient( $cache_key, $versions, 5 * DAY_IN_SECONDS );
106
+ } else {
107
+ $versions = is_array( $cache_versions ) ? $cache_versions : array();
108
+ }
109
+
110
+ return $versions;
111
+ }
112
+
113
+ /**
114
+ * Get remote versions zips.
115
+ *
116
+ * @return array Array of available versions.
117
+ */
118
+ private function get_remote_versions() {
119
+ $url = $this->get_versions_api_url();
120
+ if ( empty( $url ) ) {
121
+ return [];
122
+ }
123
+ $response = wp_remote_get( $url );
124
+ if ( is_wp_error( $response ) ) {
125
+ return array();
126
+ }
127
+ $response = wp_remote_retrieve_body( $response );
128
+
129
+ if ( is_serialized( $response ) ) {
130
+ $response = maybe_unserialize( $response );
131
+ } else {
132
+ $response = json_decode( $response );
133
+ }
134
+
135
+ if ( ! is_object( $response ) ) {
136
+ return array();
137
+ }
138
+ if ( ! isset( $response->versions ) ) {
139
+ return array();
140
+ }
141
+
142
+ $versions = array();
143
+ foreach ( $response->versions as $key => $value ) {
144
+ $versions[] = array(
145
+ 'version' => is_object( $value ) ? $value->version : $key,
146
+ 'url' => is_object( $value ) ? $value->file : $value,
147
+ );
148
+ }
149
+
150
+ return $versions;
151
+ }
152
+
153
+ /**
154
+ * Return url where to check for versions.
155
+ *
156
+ * @return string Url where to check for versions.
157
+ */
158
+ private function get_versions_api_url() {
159
+ if ( $this->product->is_wordpress_available() && $this->product->is_plugin() ) {
160
+ return sprintf( 'https://api.wordpress.org/plugins/info/1.0/%s', $this->product->get_slug() );
161
+ }
162
+ if ( $this->product->is_wordpress_available() && $this->product->is_theme() ) {
163
+ return sprintf( 'https://api.wordpress.org/themes/info/1.1/?action=theme_information&request[slug]=%s&request[fields][versions]=true', $this->product->get_slug() );
164
+ }
165
+ $license = $this->product->get_license();
166
+ if ( $this->product->requires_license() && strlen( $license ) < 10 ) {
167
+ return '';
168
+ }
169
+
170
+ return sprintf( '%s?edd_action=get_versions&name=%s&url=%s&license=%s', $this->product->get_store_url(), urlencode( $this->product->get_name() ), urlencode( get_site_url() ), $license );
171
+ }
172
+
173
+ /**
174
+ * Show the rollback links in the plugin page.
175
+ *
176
+ * @param array $links Plugin links.
177
+ *
178
+ * @return array $links Altered links.
179
+ */
180
+ public function add_rollback_link( $links ) {
181
+ $version = $this->get_rollback();
182
+ if ( empty( $version ) ) {
183
+ return $links;
184
+ }
185
+ $links[] = '<a href="' . wp_nonce_url( admin_url( 'admin-post.php?action=' . $this->product->get_key() . '_rollback' ), $this->product->get_key() . '_rollback' ) . '">' . sprintf( apply_filters( $this->product->get_key() . '_rollback_label', 'Rollback to v%s' ), $version['version'] ) . '</a>';
186
+
187
+ return $links;
188
+ }
189
+
190
+ /**
191
+ * Start the rollback operation.
192
+ */
193
+ public function start_rollback() {
194
+ if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], $this->product->get_key() . '_rollback' ) ) {
195
+ wp_nonce_ays( '' );
196
+ }
197
+
198
+ if ( $this->product->is_plugin() ) {
199
+ $this->start_rollback_plugin();
200
+
201
+ return;
202
+ }
203
+ if ( $this->product->is_theme() ) {
204
+ $this->start_rollback_theme();
205
+
206
+ return;
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Start the rollback operation for the plugin.
212
+ */
213
+ private function start_rollback_plugin() {
214
+ $rollback = $this->get_rollback();
215
+ $plugin_transient = get_site_transient( 'update_plugins' );
216
+ $plugin_folder = $this->product->get_slug();
217
+ $plugin_file = $this->product->get_file();
218
+ $version = $rollback['version'];
219
+ $temp_array = array(
220
+ 'slug' => $plugin_folder,
221
+ 'new_version' => $version,
222
+ 'package' => $rollback['url'],
223
+ );
224
+
225
+ $temp_object = (object) $temp_array;
226
+ $plugin_transient->response[ $plugin_folder . '/' . $plugin_file ] = $temp_object;
227
+ set_site_transient( 'update_plugins', $plugin_transient );
228
+
229
+ $transient = get_transient( $this->product->get_key() . '_warning_rollback' );
230
+
231
+ if ( false === $transient ) {
232
+ set_transient( $this->product->get_key() . '_warning_rollback', 'in progress', 30 );
233
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
234
+ $title = sprintf( apply_filters( $this->product->get_key() . '_rollback_message', 'Rolling back %s to v%s' ), $this->product->get_name(), $version );
235
+ $plugin = $plugin_folder . '/' . $plugin_file;
236
+ $nonce = 'upgrade-plugin_' . $plugin;
237
+ $url = 'update.php?action=upgrade-plugin&plugin=' . urlencode( $plugin );
238
+ $upgrader_skin = new \Plugin_Upgrader_Skin( compact( 'title', 'nonce', 'url', 'plugin' ) );
239
+ $upgrader = new \Plugin_Upgrader( $upgrader_skin );
240
+ $upgrader->upgrade( $plugin );
241
+ delete_transient( $this->product->get_key() . '_warning_rollback' );
242
+ wp_die(
243
+ '',
244
+ $title,
245
+ array(
246
+ 'response' => 200,
247
+ )
248
+ );
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Start the rollback operation for the theme.
254
+ */
255
+ private function start_rollback_theme() {
256
+ add_filter( 'update_theme_complete_actions', array( $this, 'alter_links_theme_upgrade' ) );
257
+ $rollback = $this->get_rollback();
258
+ $transient = get_site_transient( 'update_themes' );
259
+ $folder = $this->product->get_slug();
260
+ $version = $rollback['version'];
261
+ $temp_array = array(
262
+ 'new_version' => $version,
263
+ 'package' => $rollback['url'],
264
+ );
265
+
266
+ $transient->response[ $folder . '/style.css' ] = $temp_array;
267
+ set_site_transient( 'update_themes', $transient );
268
+
269
+ $transient = get_transient( $this->product->get_key() . '_warning_rollback' );
270
+
271
+ if ( false === $transient ) {
272
+ set_transient( $this->product->get_key() . '_warning_rollback', 'in progress', 30 );
273
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
274
+ $title = sprintf( apply_filters( $this->product->get_key() . '_rollback_message', 'Rolling back %s to v%s' ), $this->product->get_name(), $version );
275
+ $theme = $folder . '/style.css';
276
+ $nonce = 'upgrade-theme_' . $theme;
277
+ $url = 'update.php?action=upgrade-theme&theme=' . urlencode( $theme );
278
+
279
+ $upgrader = new \Theme_Upgrader( new \Theme_Upgrader_Skin( compact( 'title', 'nonce', 'url', 'theme' ) ) );
280
+ $upgrader->upgrade( $theme );
281
+ delete_transient( $this->product->get_key() . '_warning_rollback' );
282
+ wp_die(
283
+ '',
284
+ $title,
285
+ array(
286
+ 'response' => 200,
287
+ )
288
+ );
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Alter links and remove duplicate customize message.
294
+ *
295
+ * @param array $links Array of old links.
296
+ *
297
+ * @return mixed Array of links.
298
+ */
299
+ public function alter_links_theme_upgrade( $links ) {
300
+ if ( isset( $links['preview'] ) ) {
301
+ $links['preview'] = str_replace( '<span aria-hidden="true">Customize</span>', '', $links['preview'] );
302
+ }
303
+
304
+ return $links;
305
+ }
306
+
307
+ /**
308
+ * Loads product object.
309
+ *
310
+ * @param Product $product Product object.
311
+ *
312
+ * @return bool Should we load the module?
313
+ */
314
+ public function can_load( $product ) {
315
+ if ( $this->is_from_partner( $product ) ) {
316
+ return false;
317
+ }
318
+ if ( $product->is_theme() && ! current_user_can( 'switch_themes' ) ) {
319
+ return false;
320
+ }
321
+
322
+ if ( $product->is_plugin() && ! current_user_can( 'install_plugins' ) ) {
323
+ return false;
324
+ }
325
+
326
+ return true;
327
+ }
328
+
329
+ /**
330
+ * Sort the rollbacks array in descending order.
331
+ *
332
+ * @param mixed $a First version to compare.
333
+ * @param mixed $b Second version to compare.
334
+ *
335
+ * @return bool Which version is greater?
336
+ */
337
+ public function sort_rollback_array( $a, $b ) {
338
+ return version_compare( $a['version'], $b['version'], '<' ) > 0;
339
+ }
340
+
341
+ /**
342
+ * Load module logic.
343
+ *
344
+ * @param Product $product Product object.
345
+ *
346
+ * @return $this Module object.
347
+ */
348
+ public function load( $product ) {
349
+ $this->product = $product;
350
+ $this->show_link();
351
+ $this->add_hooks();
352
+
353
+ return $this;
354
+ }
355
+
356
+ /**
357
+ * If product can be rolled back, show the link to rollback.
358
+ */
359
+ private function show_link() {
360
+ add_filter(
361
+ 'plugin_action_links_' . plugin_basename( $this->product->get_basefile() ),
362
+ array(
363
+ $this,
364
+ 'add_rollback_link',
365
+ )
366
+ );
367
+ }
368
+
369
+ /**
370
+ * Set the rollback hook. Strangely, this does not work if placed in the ThemeIsle_SDK_Rollback class, so it is being called from there instead.
371
+ */
372
+ public function add_hooks() {
373
+ add_action( 'admin_post_' . $this->product->get_key() . '_rollback', array( $this, 'start_rollback' ) );
374
+ add_action( 'admin_footer', array( $this, 'add_footer' ) );
375
+ }
376
+ }
vendor/codeinwp/themeisle-sdk/src/Modules/Translate.php ADDED
@@ -0,0 +1,918 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The translate model class for ThemeIsle SDK
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Modules
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 1.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK\Modules;
13
+
14
+ use ThemeisleSDK\Common\Abstract_Module;
15
+ use ThemeisleSDK\Product;
16
+
17
+ // Exit if accessed directly.
18
+ if ( ! defined( 'ABSPATH' ) ) {
19
+ exit;
20
+ }
21
+
22
+ /**
23
+ * Translate module for ThemeIsle SDK.
24
+ */
25
+ class Translate extends Abstract_Module {
26
+ /**
27
+ * List of available locales.
28
+ *
29
+ * @var array Array of available locals.
30
+ */
31
+ private static $locales = array(
32
+ 'af' => array(
33
+ 'slug' => 'af',
34
+ 'name' => 'Afrikaans',
35
+ ),
36
+ 'ak' => array(
37
+ 'slug' => 'ak',
38
+ 'name' => 'Akan',
39
+ ),
40
+ 'am' => array(
41
+ 'slug' => 'am',
42
+ 'name' => 'Amharic',
43
+ ),
44
+ 'ar' => array(
45
+ 'slug' => 'ar',
46
+ 'name' => 'Arabic',
47
+ ),
48
+ 'arq' => array(
49
+ 'slug' => 'arq',
50
+ 'name' => 'Algerian Arabic',
51
+ ),
52
+ 'ary' => array(
53
+ 'slug' => 'ary',
54
+ 'name' => 'Moroccan Arabic',
55
+ ),
56
+ 'as' => array(
57
+ 'slug' => 'as',
58
+ 'name' => 'Assamese',
59
+ ),
60
+ 'ast' => array(
61
+ 'slug' => 'ast',
62
+ 'name' => 'Asturian',
63
+ ),
64
+ 'az' => array(
65
+ 'slug' => 'az',
66
+ 'name' => 'Azerbaijani',
67
+ ),
68
+ 'azb' => array(
69
+ 'slug' => 'azb',
70
+ 'name' => 'South Azerbaijani',
71
+ ),
72
+ 'az_TR' => array(
73
+ 'slug' => 'az-tr',
74
+ 'name' => 'Azerbaijani (Turkey)',
75
+ ),
76
+ 'ba' => array(
77
+ 'slug' => 'ba',
78
+ 'name' => 'Bashkir',
79
+ ),
80
+ 'bal' => array(
81
+ 'slug' => 'bal',
82
+ 'name' => 'Catalan (Balear)',
83
+ ),
84
+ 'bcc' => array(
85
+ 'slug' => 'bcc',
86
+ 'name' => 'Balochi Southern',
87
+ ),
88
+ 'bel' => array(
89
+ 'slug' => 'bel',
90
+ 'name' => 'Belarusian',
91
+ ),
92
+ 'bg_BG' => array(
93
+ 'slug' => 'bg',
94
+ 'name' => 'Bulgarian',
95
+ ),
96
+ 'bn_BD' => array(
97
+ 'slug' => 'bn',
98
+ 'name' => 'Bengali',
99
+ ),
100
+ 'bo' => array(
101
+ 'slug' => 'bo',
102
+ 'name' => 'Tibetan',
103
+ ),
104
+ 'bre' => array(
105
+ 'slug' => 'br',
106
+ 'name' => 'Breton',
107
+ ),
108
+ 'bs_BA' => array(
109
+ 'slug' => 'bs',
110
+ 'name' => 'Bosnian',
111
+ ),
112
+ 'ca' => array(
113
+ 'slug' => 'ca',
114
+ 'name' => 'Catalan',
115
+ ),
116
+ 'ceb' => array(
117
+ 'slug' => 'ceb',
118
+ 'name' => 'Cebuano',
119
+ ),
120
+ 'ckb' => array(
121
+ 'slug' => 'ckb',
122
+ 'name' => 'Kurdish (Sorani)',
123
+ ),
124
+ 'co' => array(
125
+ 'slug' => 'co',
126
+ 'name' => 'Corsican',
127
+ ),
128
+ 'cs_CZ' => array(
129
+ 'slug' => 'cs',
130
+ 'name' => 'Czech',
131
+ ),
132
+ 'cy' => array(
133
+ 'slug' => 'cy',
134
+ 'name' => 'Welsh',
135
+ ),
136
+ 'da_DK' => array(
137
+ 'slug' => 'da',
138
+ 'name' => 'Danish',
139
+ ),
140
+ 'de_DE' => array(
141
+ 'slug' => 'de',
142
+ 'name' => 'German',
143
+ ),
144
+ 'de_CH' => array(
145
+ 'slug' => 'de-ch',
146
+ 'name' => 'German (Switzerland)',
147
+ ),
148
+ 'dv' => array(
149
+ 'slug' => 'dv',
150
+ 'name' => 'Dhivehi',
151
+ ),
152
+ 'dzo' => array(
153
+ 'slug' => 'dzo',
154
+ 'name' => 'Dzongkha',
155
+ ),
156
+ 'el' => array(
157
+ 'slug' => 'el',
158
+ 'name' => 'Greek',
159
+ ),
160
+ 'art_xemoji' => array(
161
+ 'slug' => 'art-xemoji',
162
+ 'name' => 'Emoji',
163
+ ),
164
+ 'en_US' => array(
165
+ 'slug' => 'en',
166
+ 'name' => 'English',
167
+ ),
168
+ 'en_AU' => array(
169
+ 'slug' => 'en-au',
170
+ 'name' => 'English (Australia)',
171
+ ),
172
+ 'en_CA' => array(
173
+ 'slug' => 'en-ca',
174
+ 'name' => 'English (Canada)',
175
+ ),
176
+ 'en_GB' => array(
177
+ 'slug' => 'en-gb',
178
+ 'name' => 'English (UK)',
179
+ ),
180
+ 'en_NZ' => array(
181
+ 'slug' => 'en-nz',
182
+ 'name' => 'English (New Zealand)',
183
+ ),
184
+ 'en_ZA' => array(
185
+ 'slug' => 'en-za',
186
+ 'name' => 'English (South Africa)',
187
+ ),
188
+ 'eo' => array(
189
+ 'slug' => 'eo',
190
+ 'name' => 'Esperanto',
191
+ ),
192
+ 'es_ES' => array(
193
+ 'slug' => 'es',
194
+ 'name' => 'Spanish (Spain)',
195
+ ),
196
+ 'es_AR' => array(
197
+ 'slug' => 'es-ar',
198
+ 'name' => 'Spanish (Argentina)',
199
+ ),
200
+ 'es_CL' => array(
201
+ 'slug' => 'es-cl',
202
+ 'name' => 'Spanish (Chile)',
203
+ ),
204
+ 'es_CO' => array(
205
+ 'slug' => 'es-co',
206
+ 'name' => 'Spanish (Colombia)',
207
+ ),
208
+ 'es_CR' => array(
209
+ 'slug' => 'es-cr',
210
+ 'name' => 'Spanish (Costa Rica)',
211
+ ),
212
+ 'es_GT' => array(
213
+ 'slug' => 'es-gt',
214
+ 'name' => 'Spanish (Guatemala)',
215
+ ),
216
+ 'es_MX' => array(
217
+ 'slug' => 'es-mx',
218
+ 'name' => 'Spanish (Mexico)',
219
+ ),
220
+ 'es_PE' => array(
221
+ 'slug' => 'es-pe',
222
+ 'name' => 'Spanish (Peru)',
223
+ ),
224
+ 'es_PR' => array(
225
+ 'slug' => 'es-pr',
226
+ 'name' => 'Spanish (Puerto Rico)',
227
+ ),
228
+ 'es_VE' => array(
229
+ 'slug' => 'es-ve',
230
+ 'name' => 'Spanish (Venezuela)',
231
+ ),
232
+ 'et' => array(
233
+ 'slug' => 'et',
234
+ 'name' => 'Estonian',
235
+ ),
236
+ 'eu' => array(
237
+ 'slug' => 'eu',
238
+ 'name' => 'Basque',
239
+ ),
240
+ 'fa_IR' => array(
241
+ 'slug' => 'fa',
242
+ 'name' => 'Persian',
243
+ ),
244
+ 'fa_AF' => array(
245
+ 'slug' => 'fa-af',
246
+ 'name' => 'Persian (Afghanistan)',
247
+ ),
248
+ 'fuc' => array(
249
+ 'slug' => 'fuc',
250
+ 'name' => 'Fulah',
251
+ ),
252
+ 'fi' => array(
253
+ 'slug' => 'fi',
254
+ 'name' => 'Finnish',
255
+ ),
256
+ 'fo' => array(
257
+ 'slug' => 'fo',
258
+ 'name' => 'Faroese',
259
+ ),
260
+ 'fr_FR' => array(
261
+ 'slug' => 'fr',
262
+ 'name' => 'French (France)',
263
+ ),
264
+ 'fr_BE' => array(
265
+ 'slug' => 'fr-be',
266
+ 'name' => 'French (Belgium)',
267
+ ),
268
+ 'fr_CA' => array(
269
+ 'slug' => 'fr-ca',
270
+ 'name' => 'French (Canada)',
271
+ ),
272
+ 'frp' => array(
273
+ 'slug' => 'frp',
274
+ 'name' => 'Arpitan',
275
+ ),
276
+ 'fur' => array(
277
+ 'slug' => 'fur',
278
+ 'name' => 'Friulian',
279
+ ),
280
+ 'fy' => array(
281
+ 'slug' => 'fy',
282
+ 'name' => 'Frisian',
283
+ ),
284
+ 'ga' => array(
285
+ 'slug' => 'ga',
286
+ 'name' => 'Irish',
287
+ ),
288
+ 'gd' => array(
289
+ 'slug' => 'gd',
290
+ 'name' => 'Scottish Gaelic',
291
+ ),
292
+ 'gl_ES' => array(
293
+ 'slug' => 'gl',
294
+ 'name' => 'Galician',
295
+ ),
296
+ 'gn' => array(
297
+ 'slug' => 'gn',
298
+ 'name' => 'Guaraní',
299
+ ),
300
+ 'gsw' => array(
301
+ 'slug' => 'gsw',
302
+ 'name' => 'Swiss German',
303
+ ),
304
+ 'gu' => array(
305
+ 'slug' => 'gu',
306
+ 'name' => 'Gujarati',
307
+ ),
308
+ 'hat' => array(
309
+ 'slug' => 'hat',
310
+ 'name' => 'Haitian Creole',
311
+ ),
312
+ 'hau' => array(
313
+ 'slug' => 'hau',
314
+ 'name' => 'Hausa',
315
+ ),
316
+ 'haw_US' => array(
317
+ 'slug' => 'haw',
318
+ 'name' => 'Hawaiian',
319
+ ),
320
+ 'haz' => array(
321
+ 'slug' => 'haz',
322
+ 'name' => 'Hazaragi',
323
+ ),
324
+ 'he_IL' => array(
325
+ 'slug' => 'he',
326
+ 'name' => 'Hebrew',
327
+ ),
328
+ 'hi_IN' => array(
329
+ 'slug' => 'hi',
330
+ 'name' => 'Hindi',
331
+ ),
332
+ 'hr' => array(
333
+ 'slug' => 'hr',
334
+ 'name' => 'Croatian',
335
+ ),
336
+ 'hu_HU' => array(
337
+ 'slug' => 'hu',
338
+ 'name' => 'Hungarian',
339
+ ),
340
+ 'hy' => array(
341
+ 'slug' => 'hy',
342
+ 'name' => 'Armenian',
343
+ ),
344
+ 'id_ID' => array(
345
+ 'slug' => 'id',
346
+ 'name' => 'Indonesian',
347
+ ),
348
+ 'ido' => array(
349
+ 'slug' => 'ido',
350
+ 'name' => 'Ido',
351
+ ),
352
+ 'is_IS' => array(
353
+ 'slug' => 'is',
354
+ 'name' => 'Icelandic',
355
+ ),
356
+ 'it_IT' => array(
357
+ 'slug' => 'it',
358
+ 'name' => 'Italian',
359
+ ),
360
+ 'ja' => array(
361
+ 'slug' => 'ja',
362
+ 'name' => 'Japanese',
363
+ ),
364
+ 'jv_ID' => array(
365
+ 'slug' => 'jv',
366
+ 'name' => 'Javanese',
367
+ ),
368
+ 'ka_GE' => array(
369
+ 'slug' => 'ka',
370
+ 'name' => 'Georgian',
371
+ ),
372
+ 'kab' => array(
373
+ 'slug' => 'kab',
374
+ 'name' => 'Kabyle',
375
+ ),
376
+ 'kal' => array(
377
+ 'slug' => 'kal',
378
+ 'name' => 'Greenlandic',
379
+ ),
380
+ 'kin' => array(
381
+ 'slug' => 'kin',
382
+ 'name' => 'Kinyarwanda',
383
+ ),
384
+ 'kk' => array(
385
+ 'slug' => 'kk',
386
+ 'name' => 'Kazakh',
387
+ ),
388
+ 'km' => array(
389
+ 'slug' => 'km',
390
+ 'name' => 'Khmer',
391
+ ),
392
+ 'kn' => array(
393
+ 'slug' => 'kn',
394
+ 'name' => 'Kannada',
395
+ ),
396
+ 'ko_KR' => array(
397
+ 'slug' => 'ko',
398
+ 'name' => 'Korean',
399
+ ),
400
+ 'kir' => array(
401
+ 'slug' => 'kir',
402
+ 'name' => 'Kyrgyz',
403
+ ),
404
+ 'lb_LU' => array(
405
+ 'slug' => 'lb',
406
+ 'name' => 'Luxembourgish',
407
+ ),
408
+ 'li' => array(
409
+ 'slug' => 'li',
410
+ 'name' => 'Limburgish',
411
+ ),
412
+ 'lin' => array(
413
+ 'slug' => 'lin',
414
+ 'name' => 'Lingala',
415
+ ),
416
+ 'lo' => array(
417
+ 'slug' => 'lo',
418
+ 'name' => 'Lao',
419
+ ),
420
+ 'lt_LT' => array(
421
+ 'slug' => 'lt',
422
+ 'name' => 'Lithuanian',
423
+ ),
424
+ 'lv' => array(
425
+ 'slug' => 'lv',
426
+ 'name' => 'Latvian',
427
+ ),
428
+ 'me_ME' => array(
429
+ 'slug' => 'me',
430
+ 'name' => 'Montenegrin',
431
+ ),
432
+ 'mg_MG' => array(
433
+ 'slug' => 'mg',
434
+ 'name' => 'Malagasy',
435
+ ),
436
+ 'mk_MK' => array(
437
+ 'slug' => 'mk',
438
+ 'name' => 'Macedonian',
439
+ ),
440
+ 'ml_IN' => array(
441
+ 'slug' => 'ml',
442
+ 'name' => 'Malayalam',
443
+ ),
444
+ 'mlt' => array(
445
+ 'slug' => 'mlt',
446
+ 'name' => 'Maltese',
447
+ ),
448
+ 'mn' => array(
449
+ 'slug' => 'mn',
450
+ 'name' => 'Mongolian',
451
+ ),
452
+ 'mr' => array(
453
+ 'slug' => 'mr',
454
+ 'name' => 'Marathi',
455
+ ),
456
+ 'mri' => array(
457
+ 'slug' => 'mri',
458
+ 'name' => 'Maori',
459
+ ),
460
+ 'ms_MY' => array(
461
+ 'slug' => 'ms',
462
+ 'name' => 'Malay',
463
+ ),
464
+ 'my_MM' => array(
465
+ 'slug' => 'mya',
466
+ 'name' => 'Myanmar (Burmese)',
467
+ ),
468
+ 'ne_NP' => array(
469
+ 'slug' => 'ne',
470
+ 'name' => 'Nepali',
471
+ ),
472
+ 'nb_NO' => array(
473
+ 'slug' => 'nb',
474
+ 'name' => 'Norwegian (Bokmål)',
475
+ ),
476
+ 'nl_NL' => array(
477
+ 'slug' => 'nl',
478
+ 'name' => 'Dutch',
479
+ ),
480
+ 'nl_BE' => array(
481
+ 'slug' => 'nl-be',
482
+ 'name' => 'Dutch (Belgium)',
483
+ ),
484
+ 'nn_NO' => array(
485
+ 'slug' => 'nn',
486
+ 'name' => 'Norwegian (Nynorsk)',
487
+ ),
488
+ 'oci' => array(
489
+ 'slug' => 'oci',
490
+ 'name' => 'Occitan',
491
+ ),
492
+ 'ory' => array(
493
+ 'slug' => 'ory',
494
+ 'name' => 'Oriya',
495
+ ),
496
+ 'os' => array(
497
+ 'slug' => 'os',
498
+ 'name' => 'Ossetic',
499
+ ),
500
+ 'pa_IN' => array(
501
+ 'slug' => 'pa',
502
+ 'name' => 'Punjabi',
503
+ ),
504
+ 'pl_PL' => array(
505
+ 'slug' => 'pl',
506
+ 'name' => 'Polish',
507
+ ),
508
+ 'pt_BR' => array(
509
+ 'slug' => 'pt-br',
510
+ 'name' => 'Portuguese (Brazil)',
511
+ ),
512
+ 'pt_PT' => array(
513
+ 'slug' => 'pt',
514
+ 'name' => 'Portuguese (Portugal)',
515
+ ),
516
+ 'ps' => array(
517
+ 'slug' => 'ps',
518
+ 'name' => 'Pashto',
519
+ ),
520
+ 'rhg' => array(
521
+ 'slug' => 'rhg',
522
+ 'name' => 'Rohingya',
523
+ ),
524
+ 'ro_RO' => array(
525
+ 'slug' => 'ro',
526
+ 'name' => 'Romanian',
527
+ ),
528
+ 'roh' => array(
529
+ 'slug' => 'roh',
530
+ 'name' => 'Romansh',
531
+ ),
532
+ 'ru_RU' => array(
533
+ 'slug' => 'ru',
534
+ 'name' => 'Russian',
535
+ ),
536
+ 'rue' => array(
537
+ 'slug' => 'rue',
538
+ 'name' => 'Rusyn',
539
+ ),
540
+ 'rup_MK' => array(
541
+ 'slug' => 'rup',
542
+ 'name' => 'Aromanian',
543
+ ),
544
+ 'sah' => array(
545
+ 'slug' => 'sah',
546
+ 'name' => 'Sakha',
547
+ ),
548
+ 'sa_IN' => array(
549
+ 'slug' => 'sa-in',
550
+ 'name' => 'Sanskrit',
551
+ ),
552
+ 'scn' => array(
553
+ 'slug' => 'scn',
554
+ 'name' => 'Sicilian',
555
+ ),
556
+ 'si_LK' => array(
557
+ 'slug' => 'si',
558
+ 'name' => 'Sinhala',
559
+ ),
560
+ 'sk_SK' => array(
561
+ 'slug' => 'sk',
562
+ 'name' => 'Slovak',
563
+ ),
564
+ 'sl_SI' => array(
565
+ 'slug' => 'sl',
566
+ 'name' => 'Slovenian',
567
+ ),
568
+ 'sna' => array(
569
+ 'slug' => 'sna',
570
+ 'name' => 'Shona',
571
+ ),
572
+ 'snd' => array(
573
+ 'slug' => 'snd',
574
+ 'name' => 'Sindhi',
575
+ ),
576
+ 'so_SO' => array(
577
+ 'slug' => 'so',
578
+ 'name' => 'Somali',
579
+ ),
580
+ 'sq' => array(
581
+ 'slug' => 'sq',
582
+ 'name' => 'Albanian',
583
+ ),
584
+ 'sq_XK' => array(
585
+ 'slug' => 'sq-xk',
586
+ 'name' => 'Shqip (Kosovo)',
587
+ ),
588
+ 'sr_RS' => array(
589
+ 'slug' => 'sr',
590
+ 'name' => 'Serbian',
591
+ ),
592
+ 'srd' => array(
593
+ 'slug' => 'srd',
594
+ 'name' => 'Sardinian',
595
+ ),
596
+ 'su_ID' => array(
597
+ 'slug' => 'su',
598
+ 'name' => 'Sundanese',
599
+ ),
600
+ 'sv_SE' => array(
601
+ 'slug' => 'sv',
602
+ 'name' => 'Swedish',
603
+ ),
604
+ 'sw' => array(
605
+ 'slug' => 'sw',
606
+ 'name' => 'Swahili',
607
+ ),
608
+ 'syr' => array(
609
+ 'slug' => 'syr',
610
+ 'name' => 'Syriac',
611
+ ),
612
+ 'szl' => array(
613
+ 'slug' => 'szl',
614
+ 'name' => 'Silesian',
615
+ ),
616
+ 'ta_IN' => array(
617
+ 'slug' => 'ta',
618
+ 'name' => 'Tamil',
619
+ ),
620
+ 'ta_LK' => array(
621
+ 'slug' => 'ta-lk',
622
+ 'name' => 'Tamil (Sri Lanka)',
623
+ ),
624
+ 'tah' => array(
625
+ 'slug' => 'tah',
626
+ 'name' => 'Tahitian',
627
+ ),
628
+ 'te' => array(
629
+ 'slug' => 'te',
630
+ 'name' => 'Telugu',
631
+ ),
632
+ 'tg' => array(
633
+ 'slug' => 'tg',
634
+ 'name' => 'Tajik',
635
+ ),
636
+ 'th' => array(
637
+ 'slug' => 'th',
638
+ 'name' => 'Thai',
639
+ ),
640
+ 'tir' => array(
641
+ 'slug' => 'tir',
642
+ 'name' => 'Tigrinya',
643
+ ),
644
+ 'tl' => array(
645
+ 'slug' => 'tl',
646
+ 'name' => 'Tagalog',
647
+ ),
648
+ 'tr_TR' => array(
649
+ 'slug' => 'tr',
650
+ 'name' => 'Turkish',
651
+ ),
652
+ 'tt_RU' => array(
653
+ 'slug' => 'tt',
654
+ 'name' => 'Tatar',
655
+ ),
656
+ 'tuk' => array(
657
+ 'slug' => 'tuk',
658
+ 'name' => 'Turkmen',
659
+ ),
660
+ 'twd' => array(
661
+ 'slug' => 'twd',
662
+ 'name' => 'Tweants',
663
+ ),
664
+ 'tzm' => array(
665
+ 'slug' => 'tzm',
666
+ 'name' => 'Tamazight (Central Atlas)',
667
+ ),
668
+ 'ug_CN' => array(
669
+ 'slug' => 'ug',
670
+ 'name' => 'Uighur',
671
+ ),
672
+ 'uk' => array(
673
+ 'slug' => 'uk',
674
+ 'name' => 'Ukrainian',
675
+ ),
676
+ 'ur' => array(
677
+ 'slug' => 'ur',
678
+ 'name' => 'Urdu',
679
+ ),
680
+ 'uz_UZ' => array(
681
+ 'slug' => 'uz',
682
+ 'name' => 'Uzbek',
683
+ ),
684
+ 'vi' => array(
685
+ 'slug' => 'vi',
686
+ 'name' => 'Vietnamese',
687
+ ),
688
+ 'wa' => array(
689
+ 'slug' => 'wa',
690
+ 'name' => 'Walloon',
691
+ ),
692
+ 'xho' => array(
693
+ 'slug' => 'xho',
694
+ 'name' => 'Xhosa',
695
+ ),
696
+ 'xmf' => array(
697
+ 'slug' => 'xmf',
698
+ 'name' => 'Mingrelian',
699
+ ),
700
+ 'yor' => array(
701
+ 'slug' => 'yor',
702
+ 'name' => 'Yoruba',
703
+ ),
704
+ 'zh_CN' => array(
705
+ 'slug' => 'zh-cn',
706
+ 'name' => 'Chinese (China)',
707
+ ),
708
+ 'zh_HK' => array(
709
+ 'slug' => 'zh-hk',
710
+ 'name' => 'Chinese (Hong Kong)',
711
+ ),
712
+ 'zh_TW' => array(
713
+ 'slug' => 'zh-tw',
714
+ 'name' => 'Chinese (Taiwan)',
715
+ ),
716
+ 'de_DE_formal' => array(
717
+ 'slug' => 'de/formal',
718
+ 'name' => 'German (Formal)',
719
+ ),
720
+ 'nl_NL_formal' => array(
721
+ 'slug' => 'nl/formal',
722
+ 'name' => 'Dutch (Formal)',
723
+ ),
724
+ 'de_CH_informal' => array(
725
+ 'slug' => 'de-ch/informal',
726
+ 'name' => 'Chinese (Taiwan)',
727
+ ),
728
+ 'pt_PT_ao90' => array(
729
+ 'slug' => 'pt/ao90',
730
+ 'name' => 'Portuguese (Portugal, AO90)',
731
+ ),
732
+ );
733
+
734
+ /**
735
+ * Check if we should load module for this.
736
+ *
737
+ * @param Product $product Product to check.
738
+ *
739
+ * @return bool Should load ?
740
+ */
741
+ public function can_load( $product ) {
742
+ if ( $this->is_from_partner( $product ) ) {
743
+ return false;
744
+ }
745
+ if ( ! $product->is_wordpress_available() ) {
746
+ return false;
747
+ }
748
+
749
+ $lang = $this->get_user_locale();
750
+
751
+ if ( 'en_US' === $lang ) {
752
+ return false;
753
+ }
754
+
755
+ $languages = $this->get_translations( $product );
756
+
757
+ if ( ! is_array( $languages ) ) {
758
+ return false;
759
+ }
760
+
761
+ if ( ! isset( $languages['translations'] ) ) {
762
+ return false;
763
+ }
764
+
765
+ $languages = $languages['translations'];
766
+
767
+ $available = wp_list_pluck( $languages, 'language' );
768
+
769
+ if ( in_array( $lang, $available ) ) {
770
+ return false;
771
+ }
772
+
773
+ if ( ! isset( self::$locales[ $lang ] ) ) {
774
+ return false;
775
+ }
776
+
777
+ return apply_filters( $product->get_slug() . '_sdk_enable_translate', true );
778
+ }
779
+
780
+ /**
781
+ * Get the user's locale.
782
+ */
783
+ private function get_user_locale() {
784
+ global $wp_version;
785
+ if ( version_compare( $wp_version, '4.7.0', '>=' ) ) {
786
+ return get_user_locale();
787
+ }
788
+ $user = wp_get_current_user();
789
+ if ( $user ) {
790
+ $locale = $user->locale;
791
+ }
792
+
793
+ return $locale ? $locale : get_locale();
794
+ }
795
+
796
+ /**
797
+ * Fetch translations from api.
798
+ *
799
+ * @param Product $product Product to check.
800
+ *
801
+ * @return mixed Translation array.
802
+ */
803
+ private function get_translations( $product ) {
804
+ $cache_key = $product->get_key() . '_all_languages';
805
+ $translations = get_transient( $cache_key );
806
+
807
+ if ( false === $translations ) {
808
+ require_once( ABSPATH . 'wp-admin/includes/translation-install.php' );
809
+ $translations = translations_api(
810
+ $product->get_type() . 's',
811
+ array(
812
+ 'slug' => $product->get_slug(),
813
+ 'version' => $product->get_version(),
814
+ )
815
+ );
816
+ set_transient( $cache_key, $translations, WEEK_IN_SECONDS );
817
+ }
818
+
819
+ return $translations;
820
+
821
+ }
822
+
823
+ /**
824
+ * Add notification to queue.
825
+ *
826
+ * @param array $all_notifications Previous notification.
827
+ *
828
+ * @return array All notifications.
829
+ */
830
+ public function add_notification( $all_notifications ) {
831
+
832
+ $lang = $this->get_user_locale();
833
+ $link = $this->get_locale_paths( $lang );
834
+ $language_meta = self::$locales[ $lang ];
835
+
836
+ $heading = apply_filters( $this->product->get_key() . '_feedback_translate_heading', 'Improve {product}' );
837
+ $heading = str_replace(
838
+ array( '{product}' ),
839
+ $this->product->get_friendly_name(),
840
+ $heading
841
+ );
842
+ $message = apply_filters(
843
+ $this->product->get_key() . '_feedback_translation',
844
+ 'Translating <b>{product}</b> into as many languages as possible is a huge project. We still need help with a lot of them, so if you are good at translating into <b>{language}</b>, it would be greatly appreciated.
845
+ The process is easy, and you can join by following the link below!'
846
+ );
847
+
848
+ $message = str_replace(
849
+ [ '{product}', '{language}' ],
850
+ [
851
+ $this->product->get_friendly_name(),
852
+ $language_meta['name'],
853
+ ],
854
+ $message
855
+ );
856
+
857
+ $button_submit = apply_filters( $this->product->get_key() . '_feedback_translate_button_do', 'Ok, I will gladly help.' );
858
+ $button_cancel = apply_filters( $this->product->get_key() . '_feedback_translate_button_cancel', 'No, thanks.' );
859
+
860
+ $all_notifications[] = [
861
+ 'id' => $this->product->get_key() . '_translate_flag',
862
+ 'heading' => $heading,
863
+ 'message' => $message,
864
+ 'ctas' => [
865
+ 'confirm' => [
866
+ 'link' => $link,
867
+ 'text' => $button_submit,
868
+ ],
869
+ 'cancel' => [
870
+ 'link' => '#',
871
+ 'text' => $button_cancel,
872
+ ],
873
+ ],
874
+ ];
875
+
876
+ return $all_notifications;
877
+ }
878
+
879
+ /**
880
+ * Return the locale path.
881
+ *
882
+ * @param string $locale Locale code.
883
+ *
884
+ * @return string Locale path.
885
+ */
886
+ private function get_locale_paths( $locale ) {
887
+ if ( empty( $locale ) ) {
888
+ return '';
889
+ }
890
+
891
+ $slug = isset( self::$locales[ $locale ] ) ? self::$locales[ $locale ]['slug'] : '';
892
+ if ( empty( $slug ) ) {
893
+ return '';
894
+ }
895
+ if ( strpos( $slug, '/' ) === false ) {
896
+ $slug .= '/default';
897
+ }
898
+ $url = 'https://translate.wordpress.org/projects/wp-' . $this->product->get_type() . 's/' . $this->product->get_slug() . '/' . ( $this->product->get_type() === 'plugin' ? 'dev/' : '' ) . $slug . '?filters%5Bstatus%5D=untranslated&sort%5Bby%5D=random';
899
+
900
+ return $url;
901
+ }
902
+
903
+ /**
904
+ * Load module logic.
905
+ *
906
+ * @param Product $product Product to load.
907
+ *
908
+ * @return Translate Module instance.
909
+ */
910
+ public function load( $product ) {
911
+
912
+ $this->product = $product;
913
+
914
+ add_filter( 'themeisle_sdk_registered_notifications', [ $this, 'add_notification' ] );
915
+
916
+ return $this;
917
+ }
918
+ }
vendor/codeinwp/themeisle-sdk/src/Modules/Uninstall_feedback.php ADDED
@@ -0,0 +1,734 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The deactivate feedback model class for ThemeIsle SDK
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Feedback
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 1.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK\Modules;
13
+
14
+ use ThemeisleSDK\Common\Abstract_Module;
15
+ use ThemeisleSDK\Product;
16
+
17
+ // Exit if accessed directly.
18
+ if ( ! defined( 'ABSPATH' ) ) {
19
+ exit;
20
+ }
21
+
22
+ /**
23
+ * Uninstall feedback module for ThemeIsle SDK.
24
+ */
25
+ class Uninstall_Feedback extends Abstract_Module {
26
+ /**
27
+ * How many seconds before the deactivation window is triggered for themes?
28
+ *
29
+ * @var int Number of days.
30
+ */
31
+ const AUTO_TRIGGER_DEACTIVATE_WINDOW_SECONDS = 3;
32
+ /**
33
+ * How many days before the deactivation window pops up again for the theme?
34
+ *
35
+ * @var int Number of days.
36
+ */
37
+ const PAUSE_DEACTIVATE_WINDOW_DAYS = 100;
38
+ /**
39
+ * Where to send the data.
40
+ *
41
+ * @var string Endpoint url.
42
+ */
43
+ const FEEDBACK_ENDPOINT = 'http://feedback.themeisle.com/wordpress/wp-json/__pirate_feedback_/v1/feedback';
44
+
45
+ /**
46
+ * Default options for plugins.
47
+ *
48
+ * @var array $options_plugin The main options list for plugins.
49
+ */
50
+ private $options_plugin = array(
51
+ 'I found a better plugin' => array(
52
+ 'id' => 3,
53
+ 'type' => 'text',
54
+ 'placeholder' => 'What\'s the plugin\'s name?',
55
+ ),
56
+ 'I could not get the plugin to work' => array(
57
+ 'id' => 4,
58
+ ),
59
+ 'I no longer need the plugin' => array(
60
+ 'id' => 5,
61
+ 'type' => 'textarea',
62
+ 'placeholder' => 'If you could improve one thing about our product, what would it be?',
63
+ ),
64
+ 'It\'s a temporary deactivation. I\'m just debugging an issue.' => array(
65
+ 'id' => 6,
66
+ ),
67
+ );
68
+ /**
69
+ * Default options for theme.
70
+ *
71
+ * @var array $options_theme The main options list for themes.
72
+ */
73
+ private $options_theme = array(
74
+ 'I don\'t know how to make it look like demo' => array(
75
+ 'id' => 7,
76
+ ),
77
+ 'It lacks options' => array(
78
+ 'id' => 8,
79
+ ),
80
+ 'Is not working with a plugin that I need' => array(
81
+ 'id' => 9,
82
+ 'type' => 'text',
83
+ 'placeholder' => 'What is the name of the plugin',
84
+ ),
85
+ 'I want to try a new design, I don\'t like {theme} style' => array(
86
+ 'id' => 10,
87
+ ),
88
+ );
89
+ /**
90
+ * Default other option.
91
+ *
92
+ * @var array $other The other option
93
+ */
94
+ private $other = array(
95
+ 'Other' => array(
96
+ 'id' => 999,
97
+ 'type' => 'textarea',
98
+ 'placeholder' => 'cmon cmon tell us',
99
+ ),
100
+ );
101
+ /**
102
+ * Default heading for plugin.
103
+ *
104
+ * @var string $heading_plugin The heading of the modal
105
+ */
106
+ private $heading_plugin = 'Quick Feedback <span>Because we care about our clients, please leave us feedback.</span>';
107
+ /**
108
+ * Default heading for theme.
109
+ *
110
+ * @var string $heading_theme The heading of the modal
111
+ */
112
+ private $heading_theme = 'Looking to change {theme}? <span> What does not work for you?</span>';
113
+ /**
114
+ * Default submit button action text.
115
+ *
116
+ * @var string $button_submit The text of the deactivate button
117
+ */
118
+ private $button_submit = 'Submit &amp; Deactivate';
119
+ /**
120
+ * Default cancel button.
121
+ *
122
+ * @var string $button_cancel The text of the cancel button
123
+ */
124
+ private $button_cancel = 'Skip &amp; Deactivate';
125
+
126
+ /**
127
+ * Loads the additional resources
128
+ */
129
+ function load_resources() {
130
+ $screen = get_current_screen();
131
+
132
+ if ( ! $screen || ! in_array( $screen->id, array( 'theme-install', 'plugins' ) ) ) {
133
+ return;
134
+ }
135
+
136
+ add_thickbox();
137
+
138
+ $id = $this->product->get_key() . '_deactivate';
139
+
140
+ $this->add_css( $this->product->get_type(), $this->product->get_key() );
141
+ $this->add_js( $this->product->get_type(), $this->product->get_key(), '#TB_inline?' . apply_filters( $this->product->get_key() . '_feedback_deactivate_attributes', 'width=600&height=550' ) . '&inlineId=' . $id );
142
+
143
+ echo '<div id="' . $id . '" style="display:none;" class="themeisle-deactivate-box">' . $this->get_html( $this->product->get_type(), $this->product->get_key() ) . '</div>';
144
+ }
145
+
146
+ /**
147
+ * Loads the css
148
+ *
149
+ * @param string $type The type of product.
150
+ * @param string $key The product key.
151
+ */
152
+ function add_css( $type, $key ) {
153
+ $key = esc_attr( $key );
154
+ $suffix = Product::THEME_TYPE === $type ? 'theme-install-php' : 'plugins-php';
155
+ $icon = esc_attr( apply_filters( $this->product->get_slug() . '_uninstall_feedback_icon', '' ) );
156
+ if ( empty( $icon ) ) {
157
+ $icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQyIDc5LjE2MDkyNCwgMjAxNy8wNy8xMy0wMTowNjozOSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpDNkVDM0M4RkYxMzMxMUU3OEMyMkQ0NTIxRTVEQ0ZBRiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpDNkVDM0M5MEYxMzMxMUU3OEMyMkQ0NTIxRTVEQ0ZBRiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkM2RUMzQzhERjEzMzExRTc4QzIyRDQ1MjFFNURDRkFGIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkM2RUMzQzhFRjEzMzExRTc4QzIyRDQ1MjFFNURDRkFGIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+KBNOswAAFtFJREFUeNrkWwmUXVWV3W/8Y81zkVAhgUwQg00IAYIRGcRuERDSKqALtVEbxRYcGzWIuhatKCYuUXQtERRtFAccQCDtckCZwpRISEIlIXMqlaGGP///ht7n3vd//YRUUkljN718a53U+++//97d95yzz3BvjDAM8fd02May4YndaZhoDErYeu/laCyN8rN16PuDAPA83mcAjjOxd8jcVypydhrlKspCSidlhPIk5T8p9/+PAP8fTrZJaaQ0UFxKiVKk/CvlU5Rk3b0C+gTKFZRvUa75/wJ4EuVcyimU2RGQdkqCkoOBDExjBoJx3Uwm5OlXt4bFrIPgTXSJK+DY59PEO8a5s0mPiEPyfUrwMieh3ED57qsTsJBhoXAOmps+gd6u85AvGtgxQEOmJcfj+vvxDsvS/hzsB5pkgA9QplJuoux59QD2g1ZUvCXhVe+4pnjxJc5gdx8SxTza1jwDY9ntMDdsBlLJQ4O2CTogRs+vBzydFmLCMm98NWl4OvL5O3Hd+09/9p8/iK/9GOjfRHZKpnHZWy7AlbfPRuK918DYTm3H3PHZWrQbVnHKtUBbh201EvSFvHLX0TLlK3ksRLG4HPPmnL7+0vfiaz8EOkwP+aduwPKbZ+DadyzBnVuPBa4nEQf+/hqW0zKvZcqkJoYmi0DTMXo2+cyltiu8oSi+HQrR3UG5+n9Fw6bFmRYJOVehUf/VAsrPacodOPtM3LcmjmPSwMz4cvzXAJEXt6C89gv49rJTcMk3zkdPL8e9e0iTVNHTTziuGTi9D5jF73oaNVg5RnLAjiywagfwp01ybiJufQOOuYMTdf9hg3s5H83oEQIWhYwOMGySf2KNFTjJchW0EMmPKB1KMx2d2LQFGCKtvPD0A1izbitnitcZbrat+T12Fi8i4C5g6y49kDkk7re/RoNtTmo+DiKmFlPupaZPbAPOp3VceSLwYD/fttrFUPlbSNsL+YgtB48QjGKmje+ceBlKlqsATBywIe82sG9TC5OhONqP2wOnucB0wRY13Cn6qQWPYgEtVNZvf8/J3RhnZAprrtjY81qkxHX3jGrtvn8esHgm0wzek6Vf76Y2Q19ncibBmymeM1Mz+H1IS2ji9XfPAuZzAm5+ajLWDn8JKfvymgprQczHyvbpGEh14f2nX89sLyVsehQmbQewKj5GBxtQzMXQ3DvyWcvxz9rPvFf9Fed+ELjnl8Q07To07FyJ3MATCDouxXmL344pO55nmsFs8avMHE8jmH1/puzmkEsarBo7n2dweCbn06YFxJizWJzFErVW5Kwez8m45VTgM08txqqhu5C0HxyDHNIIDSxedCP6Ozk5Bb6rNHzkpCWQTJqlwQcWcgkUh+NXG2b4sf1uSjDGPvQITh98Bh/5F35s6UXTovvR+eaVuPD6O/DRt8bg/uL7CK+nj75mI7DtD0CefhkUopfYkUZtDdyn75Y2kMz+wvtW6s8yMRmCaCLwG2Za6E5ch4xnoMLPZUo2g3uPPQfr25iNFob3U76BpUMTVK2JBLOmP37hU5hE5yzBvbZz2p6lyXYSiH/AvBVLCI/pRvnmG7Fy8nysYtgVEz+jIYPuu7+NSvIe2OfZMIvh4YuQevIRkxYtx6fxd662hkZOzu9257Fk/esZrlaI2arY+PY70d8yhRNZOWKWPobSS4fPFBx37YaeHkwdGrgCqfDWZGveRHAQI6GWje07EXvfRzB/0XzMn0UfzdBnH/oLwrOogTcfS7BbtSaPxL7kfp+aLayliR+nJytDEz8jnsRpDW/F45kVFTfE0rmXo7+VPOqXjygOn0f5qXgk5QnKc9Ty50MVfozbGjqyVFFwIFWM0XkioXPiB8hct9wGfI15Qmo3gnfSb3MZVW4e1SGmHtL8K1u1G1QYciyCflPqPFRK9ouN0/CJM6+LNBtOKA6Lqy6hfJri1H5jWbFUIX9D75597yM/NSWaiwfG4ZeDlpw4ldLvjXO23zOPeYMPw9/HqY5pRj+qg8/1yebYp0ktzwfNDGdgvnvcKnd6P7yKDmcTzLQE7Oc4SMflty1xA21JEyazng8v/4110uDmrrAphBXzdK47kUNYdS7j94ITEI7uhOkEh56sCefsGQ1cEotkIV3+ePKUm856txCXlKCXqLzgMIDfqEowaqQ1YaCv0URrjJyciGHu9k24+k8PsiB1EW8q6rg40S6GzPbZ3bSnOK1xAJZtHrpwmHDM4HODnDbtcAiPetNnb8x1fBFmebnK+oBHKVeOZ9JMBPEfHKDbTrBdKZMZX4gS3TDvmHjvA79BayGDYSONWKo8ce36BNZGgCd3EmyRRDt8BMw8kaNquhXmLC3vrHhOj2GXqp54POUHUVL0hQM1fBXvOjnlGOgm2Arjrcdn5VwHJ2zZggueXYEc4tSOD8vxxupW4zDAJcuaxBDSmUaQzzKS5HXV87cowWFMgWPElBtSHLPGW1I/L64HzGwB75KTjqShrI3JlBprgbnoPz3xONqZrVRoEKYVQrGzmJSkhgJ6PABGBLiPBBW3SJySXHhjJd8rfhiK/CVtF8X1pk3EdP4iL/x36ZOZtUonxClJ3iQ3lqldscQK70tmczj/mRUoE6z8TqolBboKWDqSVeDjabvZ0n7MxCH0A/ytjqyf5msspTCxTpvDEdCmHtZrKYuqgC8VbTe5ot1QZWjyg6ztYNbmzZi+Y5tkViqlNKhdQ4BVw45Dc3Uj0CIHalvuFfsJyuqrMLReAcI6+DGCHsX+AccZRPSR4JCa40bVtF8no4tJ4a7GxXELWLnRDyUBt7DghReQCop8gHFAmhdGPWd7f007ddqu4hLt+gX6vuTJCX4MXnHvlVRzS2lmrfgQxYVROtDg1sb+D6Zql4Y4PsY6ltasAQfanA3Px4xtWyIXqFZd9EXF0KFuw4h2rQioAu3UmbmpQUtiIKHDFKtoQTlb0t+9YkeFFtmNFUNMJw0ydGjUwErH16VNR6/rkT9zJCSJc8tNnjLnkD5rIp3N44TB7UzHx8KI75mcxGiw5XIENgLp2AdoPLq2Tx6aV1qOt01CcUieUTk8w0848SpjXeFUPDvUQmCBAloFK2IyZzC1jlIy8mnqN2bVlDWPlqnVhlwO7SOj/DymjYCARdRgBbA8yHXHfLhewwJW/GSbaJkaDrKwk0m4bXMwujkLv1JSWaJ6vIyoKvJMSWwM6XuVyXWM374kO8FBJknYKYn1T07hKzxyjPbfsE7qWoEyIsxU8SliNvFdZdJ8sctEIVEq1/xXDCVkdVQpOHAk+ZDYVSCQpubIj0w9SDVoQycnTGIwyAcOcBr7mAp6MSS6ephenonsrrX06wzcRJSLmJoMaYD0FpvjINsZbeQhxvAKx5HfiFR7hWltXV9bUtyB45G6YzPMS0scq1XTcFjT8Jiz26r0k4nlVS9ATUJ+jpVKcFgD1/uwvKY4GkeyI6fnbZQgWlt0fSqrDPJ039DgxfSFmkd5/Uk+9DiadSWrfhZjgRxrWohyIY+glFcmboQmgcdYVzTDdJs4KQ0E18RrBGi5KA3vRqb/e2jsLfKxjp5ctxW4mwnRmgHFlZ7y33BMwxHVBDqSlgVwuxF94YU6u/KV8UtzkjE3Yrux0B4qwGHF4kB4U5GmNkoQba21RoGWqI8soMVzHufnN1CaWc/6jh4N73HTSdJoS9TlqIoVdTwkhPH54u+Bg1hbL7zhhfByD8BtciS7AJa3oXD3Ls73ND7Oh7TpqiYtMELolkBkEFmzuqajTDnyYb/6i4NkRAKYZSdBM5pZUWjas0f/KBar8+U6ApNguJevepD3S1oq5WFYjjqT9GOPbiEpZ00KWgLpcVV0p0OE1uE0dHGiCLSBz3osicqyvchk5V1mzb9rJh2pStrdUSDca0buq8ZbZWgvMt4SycejnRgHKYCkiad8VF5C08fOnWPsXGXsGmh+bqTJ/5Gv+4skeOL/uxWJVTMwMuH+f2vnVcCVKMaWYIiKfsf33pLF8EuuKtsrDv1eIkagDTqo8+OSF1Y1vM6MNF5LOJT/Rg5QJPuWGGfNAzoH8rk4EkdxOKGb8uI8+6i1wUHdxKuxdB14N5J7ONCnKEkBRMuo7NXaRtSDluEoYNXzYIxn42KFW2H8mr/9RoD8YAK5bJqG7yGXSMC3rJqGa2YtU1RbnsJacZS9QlyS45vRzETxB3kOcJQAmlnlAC8v6Ya2NaG7saTSTbUSsX2H1mZ3J99i6BaPYYyJpO5Fyvd8zdxn82Ux+nSZBOinOIBG3cEQkgqicCXEZEvSQlm5De6d62CtcMmPDvYNtCh05GXsaGmlm/Pd5aI230hpokBZoeF8+VXA2yX58ALNxYrMOMNhpYJhFv4bWzswbe+gWp4/0JdL+RiGCbplCrVbbeYx91Ya6u2l9jy9hUHFV1NPgISpMuUXPF8VgZ7O8zSBm6MRUdmatITtZa1pE8H+gdHg90xP88yVYw72bGiHR841VdAMsbp7kn5HqJspSsOGNueK1uJW6cvZ0Yr6BWOa9RnfPSU+zbm/vRMX9P91nGIsxMiuBrXkku6kFXhV0FsYn8mufX3UakL7uBFpu8ri0vXYxGvfpbRR+qQ/ymE2+nqhf4TnWzlhLxLwFko+VGwfsHzd3d+OYjamwIp2C2T21cccq0mwluqHKsUs+DV3FJy7BfCDlE+q7ocCW1Ga0H+BZ6YcC+8xs6b9AwHLRO3a1KxCTLo9r8OQaGcX/ZmlJSZz5pv5vR1qbVc3usgT04a+f4R/VxDg414UNH3USjaJ55KvM8Hw6Q4717eiRP5wIt5leoLdqUb0d3VANe/qxik/r/PfX1cbAOTN8F7RqMkSzvA9DVYYkgnBo32TsT3Vwhf44y4/BjTnLRtbMTSQ1pwvaaGQlmRh617UMjwytvovImvDVUJL8LzBlrKGk0CRxSdh9WaGuTSvxwzkMzG8tJYxl2DdCFKoSj0Pz07qow83wygXUQ1Gmp1R5SQx598qwAZ1bwTBZw2/sgu+NmVEJm0z192VTuGxqceypK1gvCpW6ksh602bmrCV4rGiUhqVBN3k+fAwTZOgX1jDV/PdmYzWpLCqG9XTMgFy7lRragkbJKB8EQMbXWxY08yCy1Wldf3CiVS/D594orIaQ1mo7pULCZfHNsfcSxnU+7Sk7RJiA5/+Sf7gzv1MWkyLL//ZSSfirc8/zzwjPKAuHnt5Ujieyf3OXUkMZ1z09mTR0soUUIBX15IlKxOti7nXJyhG3Sq/76kmurx+eNjFjp2NJPE4Gvn8GIz9Jl2UsLmhDQ/PnKUX2eQdQri81w9q95JR8c0xi4wiMjV9l+GX51C7HzUi4hJN28UAj0yZhGe6e3Dqzu3Iwh23G5siMGmrDBdsrNnYgPSuBDoIurWpzCTMZ4IU+a56pRexeFhXaxsoknn3jiSxZyiGQs5BOrTQRgDmAWCrgH8697UYbOZ00BoNy9HRgn4fmrWGrCwobKgDnNAxTmvu0wQ7jdq9WJk1NW3zb9G1cMcpc3Dab7brimmcJpzyKYLu5PAkaR3OGViXt2EPkNASHhqZbCQI3LGDagRRIMuUfNFGJm+xxONAPQspPqNLadXcr8yrHi45ZWeiEXedOo+2WyJ1cGRq+cZSZaTkBtT0V3jh9v04x3SeQpibxxtGRKPSLriaoNtpWgurmnaLJfxqxhRc8WwfXrd9G0Zgjdt3rA6skeWdLEEXGY4ynLgcZ2AoK9SnSa32+9BQnmhT4jxvJcAUn+9EXYvxmkEpavfW+QuxpZ2ESu2GaoVfp6msukbD0FrCRy57Wa8g9p5f0s+eRzi0AIYnhWmZEc94yPTKi0hkvaJpiw5VJE+v7whx0Ysb4Pr2YZeFor6m0riYZRMhNfJvo3wmoJQ6t9DMJKOV0hY6PLcI+uDmW//cBpTxdFcvPn7hBZxAQ2l3LKMz/0jbvoqgfnawBTvLeRvhpVfDSD3Hp3GWStKkdzJGJfaQEeTONYJyl1FxOePD2HT2UnrALrxx5SSUEE60vVYDL3bhEk6cwJIEFuNfV5X7Ri3OH+6pYsoVMvn7Lv5HvNTWBlfiOlSltJl+chOB/htls+ztODjgxbKKx9fGNsFs+gPM9ntZkrK+tEdGjHz3b81ifD7cHZPDObfAbFmJJ2ZmMXVLA07d2oa8mt8j7i++TCa+ZhgyGnhYsuhM/Oqk6YiXmDeY5mBoWt8kwA9QHmYY9BXYcQDbtWEECf3XGoLR8X2QMSgztgT5rvuQ2ngG0ttglRLw3AAfvfZpdIzE8PrVnRhGpa67ZEZtfh0fxwCadZVW9bpRIz8j+nSo60Jdab7rK/Pm4tvzZiNeLA7CjP2ARHUbtfvShNcmEj9JtEWl0J66TZ6S2b4OZmkx06+FLDSVFdRWP8m07QT8nS/NxzmruzEkoGMBUhcW4E4vo9zvIv/LJIKyLLP6SF2Uh9PnofRXF7n7Eyp0WC28fnEOdpeP4tMMQcvjasKc7gqSb8nDag5QfDSO/J8lswoU2K/PnYUbz16wwTGdH5pm7K7QcjZSFGGFJsWOxIrxL8W0Dgp4drSzzVHNSr3Fty3a0jv+ki9BNzHkfHXpPFzy5CTElg0geWlG0yqDcf7HDdjzuVZ0LtuN+Hl5XWyzasrc3ozh25rQ+d1diJ1WrDWbRm5uRebeNLp/NAB7dinaZ2lg9DOt2Ht3E76+YMajSxfM/QFJ7Sem6exToBTYIwcsfxdR7o7ATsw0JFelVg1iuXXzdFy7uEHFT5BtmQUwQlRQejyO+MKC6lQq77HKCAs+ys/FEDtLth/FdP/KLiEYZhnX7yB2ulyXriSvx3i+r1z6ycfmfehtfed/H+1WOc2iIqiCOgrAJC21sYRFLO6LAM+e6Hq0RQ2ULQ99cwy8OdHNCyIs4o0043ce9hQBm6Tt9PB6g4qehpGFPZlAPH52u/X1MAnDzcCeRAMrs7Jy5DoLkYATksoWEyflbyqY7s7n9/WgUIrBdkNNSgKoKkbd+SFIq/6KOP5llPOjnaq7J7QIz/LOzUlY4ODcTmqL3uB06hXYkpR3BGx31V3nfaVQA3Wi+90u1ZVU99ukEIelnt2uvy+45tSpQ6nvXPgAnrrsDlwxaxUrRwsFz8HRHPYBw1+ktv8CA9FC7oSOuBnuYaLcBrvDqHU7jfU6T5LNKwJA9aaCqKMRRDvsOnV3RJp0og11Pa0nSMrRIK9VUtLLE3M6d+Dui36IM57ehqWr3oD+zGRYTFmtowQcQv9HC9Hy6ye42WCfZeDz81NSxFpfVqZbXVU0qsCk5OvV8xdGSyWmdD9oAW5v1I2sjO3ZkL2V1fv90aoidJzypca2cc3Jf8a7pq/CHS8uwJfXnIvthW7FsbI74Uj3Sz9GOScC/fNqDXmQTRXS87mlFARnzYwnll3U1JZFmR7g7dba9Bjh1F4Ot4IKjSUY0vslKzs0CLle3qZ70GLS5c16c4rBqqL8kloN1PsqX9K9aea7+42gHEfaKeLDJz+MNRd/HjedfB+unPYnloQWg4F52Dh8qO8lHk+Jtv+INWSjpp+MarjAYvvnfVNxSXOrlJWP8pY07BaClRLUl//g8Fma7FJqmfVAU3Q9WMfrzFF9ZkdxQ5GTtGoN40lev4cfblVmbST0xBnmI/xHdhcVDo6A8++UlH0+t28qrlxxPVbnZnBOjYOy9OG2Hm6OZPz9/q6EHNG4eTlHuIQaPY7mzN+Yn1N9JMMq0mQ/icquHmpwLa/LXotHVPEalD5EP23l9VUc+fUc9UoOKQU/9x7OLSndelJfHwesckRqtKyVdnLbOjQ4hUPuATP+3v4r3n8LMAAsR90w+kkNLQAAAABJRU5ErkJggg==';
158
+ }
159
+ ?>
160
+ <style type="text/css" id="<?php echo $key; ?>ti-deactivate-css">
161
+ input[name="ti-deactivate-option"] ~ div {
162
+ display: none;
163
+ }
164
+
165
+ input[name="ti-deactivate-option"]:checked ~ div {
166
+ display: block;
167
+ }
168
+
169
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container #TB_window.thickbox-loading:before {
170
+ background: none !important;
171
+ }
172
+
173
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container #TB_title {
174
+ background: url('<?php echo $icon; ?>') 40px 30px no-repeat;
175
+ border: none;
176
+ box-sizing: border-box;
177
+ color: #373e40;
178
+ font-size: 24px;
179
+ font-weight: 700;
180
+ height: 90px;
181
+ padding: 40px 40px 0 120px;
182
+ text-transform: uppercase;
183
+ width: 100%;
184
+ }
185
+
186
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container #<?php echo $key; ?>-info-disclosure-content ul i {
187
+ padding-left: 5px;
188
+ margin: 0 1px;
189
+ }
190
+
191
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container #<?php echo $key; ?>-info-disclosure-content ul strong {
192
+ width: 125px;
193
+ display: block;
194
+ margin: 0;
195
+ float: left;
196
+ }
197
+
198
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container #<?php echo $key; ?>-info-disclosure-content ul {
199
+ margin-left: 39px;
200
+ margin-top: 2px;
201
+ padding-top: 0px;
202
+ }
203
+
204
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container #<?php echo $key; ?>-info-disclosure-content p {
205
+ font-style: italic;
206
+ margin-bottom: 0px;
207
+ }
208
+
209
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container #<?php echo $key; ?>-info-disclosure-content {
210
+ display: none;
211
+ }
212
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container.<?php echo $key; ?>-container-disc-open #<?php echo $key; ?>-info-disclosure-content {
213
+ display: block;
214
+ position:absolute;
215
+ bottom: 100px;
216
+ }
217
+
218
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container.<?php echo $key; ?>-container-disc-open #<?php echo $key; ?>-info-disclosure {
219
+ top: -130px;
220
+ }
221
+
222
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container.<?php echo $key; ?>-container-disc-open {
223
+ height: 590px !important;
224
+ }
225
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container #<?php echo $key; ?>-info-disclosure {
226
+ position: absolute;
227
+ top: -50px;
228
+ font-size: 13px;
229
+ color: #8d9192;
230
+ font-weight: 400;
231
+ right: 40px;
232
+ }
233
+
234
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container div.actions {
235
+ box-sizing: border-box;
236
+ padding: 30px 40px;
237
+ background-color: #eaeaea;
238
+ }
239
+
240
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button {
241
+ background: #ec5d60;
242
+ border: none;
243
+ box-shadow: none;
244
+ color: #ffffff;
245
+ font-size: 15px;
246
+ font-weight: 700;
247
+ height: auto;
248
+ line-height: 20px;
249
+ padding: 10px 15px;
250
+ text-transform: uppercase;
251
+ -webkit-transition: 0.3s ease;
252
+ -moz-transition: 0.3s ease;
253
+ -ms-transition: 0.3s ease;
254
+ -o-transition: 0.3s ease;
255
+ transition: 0.3s ease;
256
+ }
257
+
258
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button.button-primary {
259
+ background: transparent;
260
+ box-shadow: none;
261
+ color: #8d9192;
262
+ font-weight: 400;
263
+ float: right;
264
+ line-height: 40px;
265
+ padding: 0;
266
+ text-decoration: underline;
267
+ text-shadow: none;
268
+ text-transform: none;
269
+ }
270
+
271
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button:hover {
272
+ background: #e83f42;
273
+ }
274
+
275
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button.button-primary:hover {
276
+ background: transparent;
277
+ }
278
+
279
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button:focus {
280
+ box-shadow: none;
281
+ outline: none;
282
+ }
283
+
284
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button:active {
285
+ box-shadow: none;
286
+ transform: translateY(0);
287
+ }
288
+
289
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button:disabled {
290
+ cursor: not-allowed;
291
+ }
292
+
293
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container input.button.button-primary:hover {
294
+ text-decoration: none;
295
+ }
296
+
297
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container div.revive_network-container {
298
+ background-color: #ffffff;
299
+ }
300
+
301
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container ul.ti-list {
302
+ margin: 0;
303
+ }
304
+
305
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container ul.ti-list li {
306
+ color: #373e40;
307
+ font-size: 13px;
308
+ margin-bottom: 5px;
309
+ }
310
+
311
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container ul.ti-list li label {
312
+ margin-left: 10px;
313
+ line-height: 28px;
314
+ font-size: 15px;
315
+ }
316
+
317
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container ul.ti-list input[type=radio] {
318
+ margin-top: 1px;
319
+ }
320
+
321
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container #TB_ajaxContent {
322
+ box-sizing: border-box;
323
+ height: auto !important;
324
+ padding: 20px 40px;
325
+ width: 100% !important;
326
+ }
327
+
328
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container li div textarea {
329
+ padding: 10px 15px;
330
+ width: 100%;
331
+ }
332
+
333
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container ul.ti-list li div {
334
+ margin: 10px 30px;
335
+ }
336
+
337
+ .<?php echo $key; ?>-container #TB_title #TB_ajaxWindowTitle {
338
+ box-sizing: border-box;
339
+ display: block;
340
+ float: none;
341
+ font-weight: 700;
342
+ line-height: 1;
343
+ padding: 0;
344
+ text-align: left;
345
+ width: 100%;
346
+ }
347
+
348
+ .<?php echo $key; ?>-container #TB_title #TB_ajaxWindowTitle span {
349
+ color: #8d9192;
350
+ display: block;
351
+ font-size: 15px;
352
+ font-weight: 400;
353
+ margin-top: 5px;
354
+ text-transform: none;
355
+ }
356
+
357
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container .actions {
358
+ width: 100%;
359
+ display: block;
360
+ position: absolute;
361
+ left: 0;
362
+ bottom: 0;
363
+ }
364
+
365
+ .theme-install-php .<?php echo $key; ?>-container #TB_closeWindowButton .tb-close-icon:before {
366
+ font-size: 32px;
367
+ }
368
+
369
+ .<?php echo $key; ?>-container #TB_closeWindowButton .tb-close-icon {
370
+ color: #eee;
371
+ }
372
+
373
+ .<?php echo $key; ?>-container #TB_closeWindowButton {
374
+ left: auto;
375
+ right: -5px;
376
+ top: -35px;
377
+ color: #eee;
378
+ }
379
+
380
+ .<?php echo $key; ?>-container #TB_closeWindowButton .tb-close-icon {
381
+ text-align: right;
382
+ line-height: 25px;
383
+ width: 25px;
384
+ height: 25px;
385
+ }
386
+
387
+ .<?php echo $key; ?>-container #TB_closeWindowButton:focus .tb-close-icon {
388
+ box-shadow: none;
389
+ outline: none;
390
+ }
391
+
392
+ .<?php echo $key; ?>-container #TB_closeWindowButton .tb-close-icon:before {
393
+ font: normal 25px dashicons;
394
+ }
395
+
396
+ body.<?php echo $suffix; ?> .<?php echo $key; ?>-container {
397
+ margin: auto !important;
398
+ height: 500px !important;
399
+ top: 0 !important;
400
+ left: 0 !important;
401
+ bottom: 0 !important;
402
+ right: 0 !important;
403
+ width: 600px !important;
404
+ }
405
+ </style>
406
+ <?php
407
+ do_action( $this->product->get_key() . '_uninstall_feedback_after_css' );
408
+ }
409
+
410
+ /**
411
+ * Loads the js.
412
+ *
413
+ * @param string $type The type of product.
414
+ * @param string $key The product key.
415
+ * @param string $src The url that will hijack the deactivate button url.
416
+ */
417
+ function add_js( $type, $key, $src ) {
418
+ $heading = Product::PLUGIN_TYPE === $type ? $this->heading_plugin : str_replace( '{theme}', $this->product->get_name(), $this->heading_theme );
419
+ $key = esc_attr( $key );
420
+ $heading = apply_filters( $this->product->get_key() . '_feedback_deactivate_heading', $heading );
421
+ ?>
422
+ <script type="text/javascript" id="ti-deactivate-js">
423
+ (function ($) {
424
+ $(document).ready(function () {
425
+ var auto_trigger = false;
426
+ var target_element = 'tr[data-plugin^="<?php echo $this->product->get_slug(); ?>/"] span.deactivate a';
427
+ <?php
428
+ if ( 'theme' === $type ) {
429
+ ?>
430
+ auto_trigger = true;
431
+ if ($('a.ti-auto-anchor').length == 0) {
432
+ $('body').append($('<a class="ti-auto-anchor" href=""></a>'));
433
+ }
434
+ target_element = 'a.ti-auto-anchor';
435
+ <?php
436
+ }
437
+ ?>
438
+
439
+ if (auto_trigger) {
440
+ setTimeout(function () {
441
+ $('a.ti-auto-anchor').trigger('click');
442
+ }, <?php echo self::AUTO_TRIGGER_DEACTIVATE_WINDOW_SECONDS * 1000; ?> );
443
+ }
444
+ $(document).on('thickbox:removed', function () {
445
+ $.post(ajaxurl, {
446
+ 'action': '<?php echo $key . '_uninstall_feedback'; ?>',
447
+ 'nonce': '<?php echo wp_create_nonce( (string) __CLASS__ ); ?>',
448
+ 'type': '<?php echo $type; ?>',
449
+ 'key': '<?php echo $key; ?>'
450
+ });
451
+ });
452
+ var href = $(target_element).attr('href');
453
+ $('#<?php echo $key; ?>ti-deactivate-no').attr('data-ti-action', href).on('click', function (e) {
454
+ e.preventDefault();
455
+ e.stopPropagation();
456
+
457
+ $('body').unbind('thickbox:removed');
458
+ tb_remove();
459
+ var redirect = $(this).attr('data-ti-action');
460
+ if (redirect !== '') {
461
+ location.href = redirect;
462
+ }
463
+ });
464
+
465
+ $('#<?php echo $key; ?> ul.ti-list label, #<?php echo $key; ?> ul.ti-list input[name="ti-deactivate-option"]').on('click', function (e) {
466
+ $('#<?php echo $key; ?>ti-deactivate-yes').val($('#<?php echo $key; ?>ti-deactivate-yes').attr('data-after-text'));
467
+
468
+ var radio = $(this).prop('tagName') === 'LABEL' ? $(this).parent() : $(this);
469
+ if (radio.parent().find('textarea').length > 0 && radio.parent().find('textarea').val().length === 0) {
470
+ $('#<?php echo $key; ?>ti-deactivate-yes').attr('disabled', 'disabled');
471
+ radio.parent().find('textarea').on('keyup', function (ee) {
472
+ if ($(this).val().length === 0) {
473
+ $('#<?php echo $key; ?>ti-deactivate-yes').attr('disabled', 'disabled');
474
+ } else {
475
+ $('#<?php echo $key; ?>ti-deactivate-yes').removeAttr('disabled');
476
+ }
477
+ });
478
+ } else {
479
+ $('#<?php echo $key; ?>ti-deactivate-yes').removeAttr('disabled');
480
+ }
481
+ });
482
+ $("#<?php echo $key; ?>-info-disclosure").on('click', function () {
483
+ $("#TB_window").toggleClass("<?php echo $key; ?>-container-disc-open");
484
+ return false;
485
+ });
486
+ $('#<?php echo $key; ?>ti-deactivate-yes').attr('data-ti-action', href).on('click', function (e) {
487
+ e.preventDefault();
488
+ e.stopPropagation();
489
+ $.post(ajaxurl, {
490
+ 'action': '<?php echo $key . '_uninstall_feedback'; ?>',
491
+ 'nonce': '<?php echo wp_create_nonce( (string) __CLASS__ ); ?>',
492
+ 'id': $('#<?php echo $key; ?> input[name="ti-deactivate-option"]:checked').parent().attr('ti-option-id'),
493
+ 'msg': $('#<?php echo $key; ?> input[name="ti-deactivate-option"]:checked').parent().find('textarea').val(),
494
+ 'type': '<?php echo $type; ?>',
495
+ });
496
+ var redirect = $(this).attr('data-ti-action');
497
+ if (redirect != '') {
498
+ location.href = redirect;
499
+ } else {
500
+ $('body').unbind('thickbox:removed');
501
+ tb_remove();
502
+ }
503
+ });
504
+
505
+ $(target_element).attr('name', '<?php echo wp_kses( $heading, array( 'span' => array() ) ); ?>').attr('href', '<?php echo $src; ?>').addClass('thickbox');
506
+ var thicbox_timer;
507
+ $(target_element).on('click', function () {
508
+ tiBindThickbox();
509
+ });
510
+
511
+ function tiBindThickbox() {
512
+ var thicbox_timer = setTimeout(function () {
513
+ if ($("#<?php echo esc_html( $key ); ?>").is(":visible")) {
514
+ $("body").trigger('thickbox:iframe:loaded');
515
+ $("#TB_window").addClass("<?php echo $key; ?>-container");
516
+ clearTimeout(thicbox_timer);
517
+ $('body').unbind('thickbox:removed');
518
+ } else {
519
+ tiBindThickbox();
520
+ }
521
+ }, 100);
522
+ }
523
+ });
524
+ })(jQuery);
525
+ </script>
526
+ <?php
527
+
528
+ do_action( $this->product->get_key() . '_uninstall_feedback_after_js' );
529
+ }
530
+
531
+ /**
532
+ * Generates the HTML.
533
+ *
534
+ * @param string $type The type of product.
535
+ * @param string $key The product key.
536
+ */
537
+ function get_html( $type, $key ) {
538
+ $options = Product::PLUGIN_TYPE === $type ? $this->options_plugin : $this->options_theme;
539
+ $button_cancel = Product::PLUGIN_TYPE === $type ? $this->button_cancel : 'Skip';
540
+ $button_submit = Product::PLUGIN_TYPE === $type ? $this->button_submit : 'Submit';
541
+ $options = $this->randomize_options( apply_filters( $this->product->get_key() . '_feedback_deactivate_options', $options ) );
542
+ $button_submit = apply_filters( $this->product->get_key() . '_feedback_deactivate_button_submit', $button_submit );
543
+ $button_cancel = apply_filters( $this->product->get_key() . '_feedback_deactivate_button_cancel', $button_cancel );
544
+
545
+ $options += $this->other;
546
+
547
+ $list = '';
548
+ foreach ( $options as $title => $attributes ) {
549
+ $id = $attributes['id'];
550
+ $list .= '<li ti-option-id="' . $id . '"><input type="radio" name="ti-deactivate-option" id="' . $key . $id . '"><label for="' . $key . $id . '">' . str_replace( '{theme}', $this->product->get_name(), $title ) . '</label>';
551
+ if ( array_key_exists( 'type', $attributes ) ) {
552
+ $list .= '<div>';
553
+ $placeholder = array_key_exists( 'placeholder', $attributes ) ? $attributes['placeholder'] : '';
554
+ switch ( $attributes['type'] ) {
555
+ case 'text':
556
+ $list .= '<textarea style="width: 100%" rows="1" name="comments" placeholder="' . $placeholder . '"></textarea>';
557
+ break;
558
+ case 'textarea':
559
+ $list .= '<textarea style="width: 100%" rows="2" name="comments" placeholder="' . $placeholder . '"></textarea>';
560
+ break;
561
+ }
562
+ $list .= '</div>';
563
+ }
564
+ $list .= '</li>';
565
+ }
566
+
567
+ $disclosure_new_labels = apply_filters( $this->product->get_slug() . '_themeisle_sdk_disclosure_content_labels', [], $this->product );
568
+ $disclosure_labels = array_merge(
569
+ [
570
+ 'title' => 'Below is a detailed view of all data that ThemeIsle will receive if you fill in this survey. No domain name, email address or IP addresses are transmited after you submit the survey.',
571
+ 'items' => [
572
+ sprintf( '%s %s version %s %s %s %s', '<strong>', ucwords( $this->product->get_type() ), '</strong>', '<code>', $this->product->get_version(), '</code>' ),
573
+ sprintf( '%s Uninstall reason %s %s Selected reson from the above survey %s ', '<strong>', '</strong>', '<i>', '</i>' ),
574
+ ],
575
+ ],
576
+ $disclosure_new_labels
577
+ );
578
+
579
+ $info_disclosure_link = '<a href="#" id="' . $this->product->get_key() . '-info-disclosure">' . apply_filters( $this->product->get_slug() . '_themeisle_sdk_info_collect_cta', 'What info do we collect?' ) . '</a>';
580
+ $info_disclosure_content = '<div id="' . $this->product->get_key() . '-info-disclosure-content"><p>' . wp_kses_post( $disclosure_labels['title'] ) . '</p><ul>';
581
+ foreach ( $disclosure_labels['items'] as $disclosure_item ) {
582
+ $info_disclosure_content .= sprintf( '<li>%s</li>', wp_kses_post( $disclosure_item ) );
583
+ }
584
+ $info_disclosure_content .= '</ul></div>';
585
+
586
+ return
587
+ '<div id="' . $this->product->get_key() . '"><ul class="ti-list">' . $list . '</ul>'
588
+ . $info_disclosure_content
589
+ . '<div class="actions">'
590
+ . get_submit_button(
591
+ $button_submit,
592
+ 'secondary',
593
+ $this->product->get_key() . 'ti-deactivate-yes',
594
+ false,
595
+ array(
596
+ 'data-after-text' => $button_submit,
597
+ 'disabled' => true,
598
+ )
599
+ )
600
+ . wp_kses_post( $info_disclosure_link )
601
+ . get_submit_button( $button_cancel, 'primary', $this->product->get_key() . 'ti-deactivate-no', false )
602
+ . '</div></div>';
603
+ }
604
+
605
+ /**
606
+ * Randomizes the options array.
607
+ *
608
+ * @param array $options The options array.
609
+ */
610
+ function randomize_options( $options ) {
611
+ $new = array();
612
+ $keys = array_keys( $options );
613
+ shuffle( $keys );
614
+
615
+ foreach ( $keys as $key ) {
616
+ $new[ $key ] = $options[ $key ];
617
+ }
618
+
619
+ return $new;
620
+ }
621
+
622
+ /**
623
+ * Called when the deactivate button is clicked.
624
+ */
625
+ function post_deactivate() {
626
+ check_ajax_referer( (string) __CLASS__, 'nonce' );
627
+
628
+ $this->post_deactivate_or_cancel();
629
+
630
+ if ( empty( $_POST['id'] ) ) {
631
+
632
+ wp_send_json( [] );
633
+
634
+ return;
635
+ }
636
+ $this->call_api(
637
+ array(
638
+ 'type' => 'deactivate',
639
+ 'id' => $_POST['id'],
640
+ 'comment' => isset( $_POST['msg'] ) ? $_POST['msg'] : '',
641
+ )
642
+ );
643
+ wp_send_json( [] );
644
+
645
+ }
646
+
647
+ /**
648
+ * Called when the deactivate/cancel button is clicked.
649
+ */
650
+ private function post_deactivate_or_cancel() {
651
+ if ( ! isset( $_POST['type'] ) || ! isset( $_POST['key'] ) ) {
652
+ return;
653
+ }
654
+ if ( 'theme' !== $_POST['type'] ) {
655
+ return;
656
+ }
657
+
658
+ set_transient( 'ti_sdk_pause_' . $_POST['key'], true, self::PAUSE_DEACTIVATE_WINDOW_DAYS * DAY_IN_SECONDS );
659
+
660
+ }
661
+
662
+ /**
663
+ * Calls the API
664
+ *
665
+ * @param array $attributes The attributes of the post body.
666
+ *
667
+ * @return bool Is the request succesfull?
668
+ */
669
+ protected function call_api( $attributes ) {
670
+ $slug = $this->product->get_slug();
671
+ $version = $this->product->get_version();
672
+ $attributes['slug'] = $slug;
673
+ $attributes['version'] = $version;
674
+
675
+ $response = wp_remote_post(
676
+ self::FEEDBACK_ENDPOINT,
677
+ array(
678
+ 'body' => $attributes,
679
+ )
680
+ );
681
+
682
+ return is_wp_error( $response );
683
+ }
684
+
685
+ /**
686
+ * Should we load this object?.
687
+ *
688
+ * @param Product $product Product object.
689
+ *
690
+ * @return bool Should we load the module?
691
+ */
692
+ public function can_load( $product ) {
693
+ if ( $this->is_from_partner( $product ) ) {
694
+ return false;
695
+ }
696
+ if ( $product->is_theme() && ( false !== get_transient( 'ti_sdk_pause_' . $product->get_key(), false ) ) ) {
697
+ return false;
698
+ }
699
+
700
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
701
+ return true;
702
+ }
703
+ global $pagenow;
704
+
705
+ if ( ! isset( $pagenow ) || empty( $pagenow ) ) {
706
+ return false;
707
+ }
708
+
709
+ if ( $product->is_plugin() && 'plugins.php' !== $pagenow ) {
710
+ return false;
711
+
712
+ }
713
+ if ( $product->is_theme() && 'theme-install.php' !== $pagenow ) {
714
+ return false;
715
+ }
716
+
717
+ return true;
718
+ }
719
+
720
+ /**
721
+ * Loads module hooks.
722
+ *
723
+ * @param Product $product Product details.
724
+ *
725
+ * @return Uninstall_Feedback Current module instance.
726
+ */
727
+ public function load( $product ) {
728
+ $this->product = $product;
729
+ add_action( 'admin_head', array( $this, 'load_resources' ) );
730
+ add_action( 'wp_ajax_' . $this->product->get_key() . '_uninstall_feedback', array( $this, 'post_deactivate' ) );
731
+
732
+ return $this;
733
+ }
734
+ }
vendor/codeinwp/themeisle-sdk/src/Product.php ADDED
@@ -0,0 +1,396 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The product model class for ThemeIsle SDK
4
+ *
5
+ * @package ThemeIsleSDK
6
+ * @subpackage Product
7
+ * @copyright Copyright (c) 2017, Marius Cristea
8
+ * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9
+ * @since 1.0.0
10
+ */
11
+
12
+ namespace ThemeisleSDK;
13
+
14
+ // Exit if accessed directly.
15
+ if ( ! defined( 'ABSPATH' ) ) {
16
+ exit;
17
+ }
18
+
19
+ /**
20
+ * Product model for ThemeIsle SDK.
21
+ */
22
+ class Product {
23
+ /**
24
+ * Define plugin type string.
25
+ */
26
+ const PLUGIN_TYPE = 'plugin';
27
+ /**
28
+ * Define theme type string.
29
+ */
30
+ const THEME_TYPE = 'theme';
31
+ /**
32
+ * If the product has a pro version, contains the pro slug.
33
+ *
34
+ * @var string $pro_slug Pro slug, if available.
35
+ */
36
+ public $pro_slug;
37
+ /**
38
+ * Current product slug.
39
+ *
40
+ * @var string $slug THe product slug.
41
+ */
42
+ private $slug;
43
+ /**
44
+ * Product basefile, with the proper metadata.
45
+ *
46
+ * @var string $basefile The file with headers.
47
+ */
48
+ private $basefile;
49
+ /**
50
+ * Type of the product.
51
+ *
52
+ * @var string $type The product type ( plugin | theme ).
53
+ */
54
+ private $type;
55
+ /**
56
+ * The file name.
57
+ *
58
+ * @var string $file The file name.
59
+ */
60
+ private $file;
61
+ /**
62
+ * Product name, fetched from the file headers.
63
+ *
64
+ * @var string $name The product name.
65
+ */
66
+ private $name;
67
+ /**
68
+ * Product normalized key.
69
+ *
70
+ * @var string $key The product ready key.
71
+ */
72
+ private $key;
73
+ /**
74
+ * Product store url.
75
+ *
76
+ * @var string $store_url The store url.
77
+ */
78
+ private $store_url;
79
+ /**
80
+ * Product install timestamp.
81
+ *
82
+ * @var int $install The date of install.
83
+ */
84
+ private $install;
85
+ /**
86
+ * Product store/author name.
87
+ *
88
+ * @var string $store_name The store name.
89
+ */
90
+ private $store_name;
91
+ /**
92
+ * Does the product requires license.
93
+ *
94
+ * @var bool $requires_license Either user needs to activate it with license.
95
+ */
96
+ private $requires_license;
97
+ /**
98
+ * Is the product available on wordpress.org
99
+ *
100
+ * @var bool $wordpress_available Either is available on WordPress or not.
101
+ */
102
+ private $wordpress_available;
103
+ /**
104
+ * Current version of the product.
105
+ *
106
+ * @var string $version The product version.
107
+ */
108
+ private $version;
109
+
110
+ /**
111
+ * ThemeIsle_SDK_Product constructor.
112
+ *
113
+ * @param string $basefile Product basefile.
114
+ */
115
+ public function __construct( $basefile ) {
116
+ if ( ! empty( $basefile ) ) {
117
+ if ( is_readable( $basefile ) ) {
118
+ $this->basefile = $basefile;
119
+ $this->setup_from_path();
120
+ $this->setup_from_fileheaders();
121
+ }
122
+ }
123
+ $install = get_option( $this->get_key() . '_install', 0 );
124
+ if ( 0 === $install ) {
125
+ $install = time();
126
+ update_option( $this->get_key() . '_install', time() );
127
+ }
128
+ $this->install = $install;
129
+
130
+ }
131
+
132
+ /**
133
+ * Setup props from path.
134
+ */
135
+ public function setup_from_path() {
136
+ $this->file = basename( $this->basefile );
137
+ $dir = dirname( $this->basefile );
138
+ $this->slug = basename( $dir );
139
+ $exts = explode( '.', $this->basefile );
140
+ $ext = $exts[ count( $exts ) - 1 ];
141
+ if ( 'css' === $ext ) {
142
+ $this->type = 'theme';
143
+ }
144
+ if ( 'php' === $ext ) {
145
+ $this->type = 'plugin';
146
+ }
147
+ $this->key = self::key_ready_name( $this->slug );
148
+ }
149
+
150
+ /**
151
+ * Normalize string.
152
+ *
153
+ * @param string $string the String to be normalized for cron handler.
154
+ *
155
+ * @return string $name The normalized string.
156
+ */
157
+ static function key_ready_name( $string ) {
158
+ return str_replace( '-', '_', strtolower( trim( $string ) ) );
159
+ }
160
+
161
+ /**
162
+ * Setup props from fileheaders.
163
+ */
164
+ public function setup_from_fileheaders() {
165
+ $file_headers = array(
166
+ 'Requires License' => 'Requires License',
167
+ 'WordPress Available' => 'WordPress Available',
168
+ 'Pro Slug' => 'Pro Slug',
169
+ 'Version' => 'Version',
170
+ );
171
+ if ( 'plugin' === $this->type ) {
172
+ $file_headers['Name'] = 'Plugin Name';
173
+ $file_headers['AuthorName'] = 'Author';
174
+ $file_headers['AuthorURI'] = 'Author URI';
175
+ }
176
+ if ( 'theme' === $this->type ) {
177
+ $file_headers['Name'] = 'Theme Name';
178
+ $file_headers['AuthorName'] = 'Author';
179
+ $file_headers['AuthorURI'] = 'Author URI';
180
+ }
181
+ $file_headers = get_file_data( $this->basefile, $file_headers );
182
+
183
+ $this->name = $file_headers['Name'];
184
+ $this->store_name = $file_headers['AuthorName'];
185
+ $this->author_url = $file_headers['AuthorURI'];
186
+ $this->store_url = $file_headers['AuthorURI'];
187
+
188
+ $this->requires_license = ( 'yes' === $file_headers['Requires License'] ) ? true : false;
189
+ $this->wordpress_available = ( 'yes' === $file_headers['WordPress Available'] ) ? true : false;
190
+ $this->pro_slug = ! empty( $file_headers['Pro Slug'] ) ? $file_headers['Pro Slug'] : '';
191
+ $this->version = $file_headers['Version'];
192
+
193
+ }
194
+
195
+ /**
196
+ * Return the product key.
197
+ *
198
+ * @return string The product key.
199
+ */
200
+ public function get_key() {
201
+ return $this->key;
202
+ }
203
+ /**
204
+ * Check if the product is either theme or plugin.
205
+ *
206
+ * @return string Product type.
207
+ */
208
+ public function get_type() {
209
+ return $this->type;
210
+ }
211
+
212
+ /**
213
+ * Return if the product is used as a plugin.
214
+ *
215
+ * @return bool Is plugin?
216
+ */
217
+ public function is_plugin() {
218
+ return self::PLUGIN_TYPE === $this->type;
219
+ }
220
+
221
+ /**
222
+ * Return if the product is used as a theme.
223
+ *
224
+ * @return bool Is theme ?
225
+ */
226
+ public function is_theme() {
227
+ return self::THEME_TYPE === $this->type;
228
+ }
229
+
230
+ /**
231
+ * Returns the product slug.
232
+ *
233
+ * @return string The product slug.
234
+ */
235
+ public function get_slug() {
236
+ return $this->slug;
237
+ }
238
+
239
+ /**
240
+ * The magic var_dump info method.
241
+ *
242
+ * @return array Debug info.
243
+ */
244
+ public function __debugInfo() {
245
+ return array(
246
+ 'name' => $this->name,
247
+ 'slug' => $this->slug,
248
+ 'version' => $this->version,
249
+ 'basefile' => $this->basefile,
250
+ 'key' => $this->key,
251
+ 'type' => $this->type,
252
+ 'store_name' => $this->store_name,
253
+ 'store_url' => $this->store_url,
254
+ 'wordpress_available' => $this->wordpress_available,
255
+ 'requires_license' => $this->requires_license,
256
+ );
257
+
258
+ }
259
+
260
+ /**
261
+ * Getter for product version.
262
+ *
263
+ * @return string The product version.
264
+ */
265
+ public function get_version() {
266
+ return $this->version;
267
+ }
268
+
269
+ /**
270
+ * Returns current product license, if available.
271
+ *
272
+ * @return string Return license key, if available.
273
+ */
274
+ public function get_license() {
275
+
276
+ if ( ! $this->requires_license() && ! $this->is_wordpress_available() ) {
277
+ return 'free';
278
+ }
279
+ $license_data = get_option( $this->get_key() . '_license_data', '' );
280
+
281
+ if ( empty( $license_data ) ) {
282
+ return get_option( $this->get_key() . '_license', '' );
283
+ }
284
+ if ( ! isset( $license_data->key ) ) {
285
+ return get_option( $this->get_key() . '_license', '' );
286
+ }
287
+
288
+ return $license_data->key;
289
+ }
290
+
291
+ /**
292
+ * Either the product requires license or not.
293
+ *
294
+ * @return bool Either requires license or not.
295
+ */
296
+ public function requires_license() {
297
+ return $this->requires_license;
298
+ }
299
+
300
+ /**
301
+ * If product is available on wordpress.org or not.
302
+ *
303
+ * @return bool Either is wp available or not.
304
+ */
305
+ public function is_wordpress_available() {
306
+ return $this->wordpress_available;
307
+ }
308
+
309
+ /**
310
+ * Return friendly name.
311
+ *
312
+ * @return string Friendly name.
313
+ */
314
+ public function get_friendly_name() {
315
+ $name = apply_filters( $this->get_key() . '_friendly_name', trim( str_replace( 'Lite', '', $this->get_name() ) ) );
316
+ $name = rtrim( $name, '- ()' );
317
+
318
+ return $name;
319
+ }
320
+
321
+ /**
322
+ * Getter for product name.
323
+ *
324
+ * @return string The product name.
325
+ */
326
+ public function get_name() {
327
+ return $this->name;
328
+ }
329
+
330
+ /**
331
+ * Returns the Store name.
332
+ *
333
+ * @return string Store name.
334
+ */
335
+ public function get_store_name() {
336
+ return $this->store_name;
337
+ }
338
+
339
+ /**
340
+ * Returns the store url.
341
+ *
342
+ * @return string The store url.
343
+ */
344
+ public function get_store_url() {
345
+ return $this->store_url;
346
+ }
347
+
348
+ /**
349
+ * Returns product basefile, which holds the metaheaders.
350
+ *
351
+ * @return string The product basefile.
352
+ */
353
+ public function get_basefile() {
354
+ return $this->basefile;
355
+ }
356
+
357
+ /**
358
+ * Returns product filename.
359
+ *
360
+ * @return string The product filename.
361
+ */
362
+ public function get_file() {
363
+ return $this->file;
364
+ }
365
+ /**
366
+ * Returns the pro slug, if available.
367
+ *
368
+ * @return string The pro slug.
369
+ */
370
+ public function get_pro_slug() {
371
+ return $this->pro_slug;
372
+ }
373
+
374
+ /**
375
+ * Return the install timestamp.
376
+ *
377
+ * @return int The install timestamp.
378
+ */
379
+ public function get_install_time() {
380
+ return $this->install;
381
+ }
382
+
383
+ /**
384
+ * Returns the URL of the product base file.
385
+ *
386
+ * @param string $path The path to the file.
387
+ *
388
+ * @return string The URL of the product base file.
389
+ */
390
+ public function get_base_url( $path = '/' ) {
391
+ if ( $this->type ) {
392
+ return plugins_url( $path, $this->basefile );
393
+ }
394
+ }
395
+
396
+ }
vendor/codeinwp/themeisle-sdk/start.php CHANGED
@@ -7,32 +7,43 @@
7
  * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
8
  * @since 1.1.0
9
  */
 
 
 
 
 
 
10
  $products = apply_filters( 'themeisle_sdk_products', array() );
11
  $path = dirname( __FILE__ );
12
- $files_to_load = array(
13
- 'class-themeisle-sdk-loader.php',
14
- 'class-themeisle-sdk-product.php',
15
- 'class-themeisle-sdk-logger.php',
16
- 'class-themeisle-sdk-licenser.php',
17
- 'class-themeisle-sdk-rollback.php',
18
- 'class-themeisle-sdk-feedback-factory.php',
19
- 'class-themeisle-sdk-feedback.php',
20
- 'class-themeisle-sdk-feedback-deactivate.php',
21
- 'class-themeisle-sdk-feedback-review.php',
22
- 'class-themeisle-sdk-feedback-translate.php',
23
- 'class-themeisle-sdk-notification-manager.php',
24
- 'class-themeisle-sdk-widget.php',
25
- 'class-themeisle-sdk-widget-dashboard-blog.php',
26
- 'class-themeisle-sdk-widgets-factory.php',
27
- 'class-themeisle-sdk-endpoints.php',
28
- );
 
 
 
29
 
30
  foreach ( $files_to_load as $file ) {
31
- $file_path = $path . '/' . $file;
32
- if ( is_readable( $file_path ) ) {
33
- require_once $file_path;
34
  }
35
  }
 
 
 
36
  foreach ( $products as $product ) {
37
- ThemeIsle_SDK_Loader::init_product( $product );
38
  }
7
  * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
8
  * @since 1.1.0
9
  */
10
+
11
+ namespace ThemeisleSDK;
12
+
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
  $products = apply_filters( 'themeisle_sdk_products', array() );
17
  $path = dirname( __FILE__ );
18
+ $files_to_load = [
19
+ $path . '/src/' . 'Loader.php',
20
+ $path . '/src/' . 'Product.php',
21
+
22
+ $path . '/src/' . 'Common/Abstract_module.php',
23
+ $path . '/src/' . 'Common/Module_factory.php',
24
+
25
+ $path . '/src/' . 'Modules/Dashboard_widget.php',
26
+ $path . '/src/' . 'Modules/Rollback.php',
27
+ $path . '/src/' . 'Modules/Uninstall_feedback.php',
28
+ $path . '/src/' . 'Modules/Licenser.php',
29
+ $path . '/src/' . 'Modules/Endpoint.php',
30
+ $path . '/src/' . 'Modules/Notification.php',
31
+ $path . '/src/' . 'Modules/Logger.php',
32
+ $path . '/src/' . 'Modules/Translate.php',
33
+ $path . '/src/' . 'Modules/Review.php',
34
+ $path . '/src/' . 'Modules/Recommendation.php',
35
+ ];
36
+
37
+ $files_to_load = array_merge( $files_to_load, apply_filters( 'themeisle_sdk_required_files', [] ) );
38
 
39
  foreach ( $files_to_load as $file ) {
40
+ if ( is_readable( $file ) ) {
41
+ require_once $file;
 
42
  }
43
  }
44
+
45
+ Loader::init();
46
+
47
  foreach ( $products as $product ) {
48
+ Loader::add_product( $product );
49
  }
vendor/composer/autoload_files.php CHANGED
@@ -6,7 +6,6 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
- '957c51f8f334b5ea3be310bfb8b3492c' => $vendorDir . '/codeinwp/themeisle-sdk/load.php',
10
  '0498965e576e4ec1efaedeccfee8b5f0' => $vendorDir . '/codeinwp/menu-item-custom-fields/menu-item-custom-fields.php',
11
  '347e48cf03d89942a6ddafc17d247b11' => $vendorDir . '/codeinwp/icon-picker/icon-picker.php',
12
  '5a095c604245b0e67e4573f0a3b240cd' => $vendorDir . '/codeinwp/themeisle-sdk/load.php',
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
 
9
  '0498965e576e4ec1efaedeccfee8b5f0' => $vendorDir . '/codeinwp/menu-item-custom-fields/menu-item-custom-fields.php',
10
  '347e48cf03d89942a6ddafc17d247b11' => $vendorDir . '/codeinwp/icon-picker/icon-picker.php',
11
  '5a095c604245b0e67e4573f0a3b240cd' => $vendorDir . '/codeinwp/themeisle-sdk/load.php',
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit13eb48706f29258ff3a0d5c6cbadd39c
6
  {
7
  private static $loader;
8
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit13eb48706f29258ff3a0d5c6cbadd39c
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit13eb48706f29258ff3a0d5c6cbadd39c', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit13eb48706f29258ff3a0d5c6cbadd39c', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
@@ -42,14 +42,14 @@ class ComposerAutoloaderInit13eb48706f29258ff3a0d5c6cbadd39c
42
 
43
  $includeFiles = require __DIR__ . '/autoload_files.php';
44
  foreach ($includeFiles as $fileIdentifier => $file) {
45
- composerRequire13eb48706f29258ff3a0d5c6cbadd39c($fileIdentifier, $file);
46
  }
47
 
48
  return $loader;
49
  }
50
  }
51
 
52
- function composerRequire13eb48706f29258ff3a0d5c6cbadd39c($fileIdentifier, $file)
53
  {
54
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
55
  require $file;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInited3d108ddbcd41f318ae3324c5a3c8ce
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInited3d108ddbcd41f318ae3324c5a3c8ce', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInited3d108ddbcd41f318ae3324c5a3c8ce', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
42
 
43
  $includeFiles = require __DIR__ . '/autoload_files.php';
44
  foreach ($includeFiles as $fileIdentifier => $file) {
45
+ composerRequireed3d108ddbcd41f318ae3324c5a3c8ce($fileIdentifier, $file);
46
  }
47
 
48
  return $loader;
49
  }
50
  }
51
 
52
+ function composerRequireed3d108ddbcd41f318ae3324c5a3c8ce($fileIdentifier, $file)
53
  {
54
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
55
  require $file;
vendor/composer/installed.json CHANGED
@@ -1,44 +1,4 @@
1
  [
2
- {
3
- "name": "codeinwp/themeisle-sdk",
4
- "version": "dev-master",
5
- "version_normalized": "9999999-dev",
6
- "source": {
7
- "type": "git",
8
- "url": "https://github.com/Codeinwp/themeisle-sdk.git",
9
- "reference": "951cde6e799e00d46a52416b62221fd771ddc326"
10
- },
11
- "dist": {
12
- "type": "zip",
13
- "url": "https://api.github.com/repos/Codeinwp/themeisle-sdk/zipball/951cde6e799e00d46a52416b62221fd771ddc326",
14
- "reference": "951cde6e799e00d46a52416b62221fd771ddc326",
15
- "shasum": ""
16
- },
17
- "time": "2018-11-26 14:24:47",
18
- "type": "library",
19
- "installation-source": "dist",
20
- "autoload": {
21
- "files": [
22
- "load.php"
23
- ]
24
- },
25
- "notification-url": "https://packagist.org/downloads/",
26
- "license": [
27
- "GPL-2.0+"
28
- ],
29
- "authors": [
30
- {
31
- "name": "ThemeIsle team",
32
- "email": "friends@themeisle.com",
33
- "homepage": "https://themeisle.com"
34
- }
35
- ],
36
- "description": "ThemeIsle SDK ",
37
- "homepage": "https://github.com/Codeinwp/themeisle-sdk",
38
- "keywords": [
39
- "wordpress"
40
- ]
41
- },
42
  {
43
  "name": "codeinwp/icon-picker",
44
  "version": "dev-master",
@@ -62,7 +22,7 @@
62
  },
63
  "time": "2018-12-10 16:06:38",
64
  "type": "wordpress-plugin",
65
- "installation-source": "dist",
66
  "notification-url": "https://packagist.org/downloads/",
67
  "license": [
68
  "GPL-2.0"
@@ -103,7 +63,7 @@
103
  },
104
  "time": "2018-12-10 16:01:32",
105
  "type": "wordpress-plugin",
106
- "installation-source": "dist",
107
  "notification-url": "https://packagist.org/downloads/",
108
  "license": [
109
  "GPL-2.0"
@@ -116,5 +76,45 @@
116
  "plugin",
117
  "wordpress"
118
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  }
120
  ]
1
  [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  {
3
  "name": "codeinwp/icon-picker",
4
  "version": "dev-master",
22
  },
23
  "time": "2018-12-10 16:06:38",
24
  "type": "wordpress-plugin",
25
+ "installation-source": "source",
26
  "notification-url": "https://packagist.org/downloads/",
27
  "license": [
28
  "GPL-2.0"
63
  },
64
  "time": "2018-12-10 16:01:32",
65
  "type": "wordpress-plugin",
66
+ "installation-source": "source",
67
  "notification-url": "https://packagist.org/downloads/",
68
  "license": [
69
  "GPL-2.0"
76
  "plugin",
77
  "wordpress"
78
  ]
79
+ },
80
+ {
81
+ "name": "codeinwp/themeisle-sdk",
82
+ "version": "3.0.6",
83
+ "version_normalized": "3.0.6.0",
84
+ "source": {
85
+ "type": "git",
86
+ "url": "https://github.com/Codeinwp/themeisle-sdk.git",
87
+ "reference": "cde61ab54f93495f0c5b7901cc5072f320f969ff"
88
+ },
89
+ "dist": {
90
+ "type": "zip",
91
+ "url": "https://api.github.com/repos/Codeinwp/themeisle-sdk/zipball/cde61ab54f93495f0c5b7901cc5072f320f969ff",
92
+ "reference": "cde61ab54f93495f0c5b7901cc5072f320f969ff",
93
+ "shasum": ""
94
+ },
95
+ "require-dev": {
96
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4",
97
+ "squizlabs/php_codesniffer": "^3.1",
98
+ "wp-coding-standards/wpcs": "^1.0.0"
99
+ },
100
+ "time": "2019-05-21 11:49:48",
101
+ "type": "library",
102
+ "installation-source": "dist",
103
+ "notification-url": "https://packagist.org/downloads/",
104
+ "license": [
105
+ "GPL-2.0+"
106
+ ],
107
+ "authors": [
108
+ {
109
+ "name": "ThemeIsle team",
110
+ "email": "friends@themeisle.com",
111
+ "homepage": "https://themeisle.com"
112
+ }
113
+ ],
114
+ "description": "ThemeIsle SDK.",
115
+ "homepage": "https://github.com/Codeinwp/themeisle-sdk",
116
+ "keywords": [
117
+ "wordpress"
118
+ ]
119
  }
120
  ]