edit.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. <?php
  2. defined('ABSPATH') || exit;
  3. /* @var $wpdb wpdb */
  4. require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
  5. $controls = new NewsletterControls();
  6. $module = NewsletterEmails::instance();
  7. function tnp_prepare_controls($email, $controls) {
  8. $controls->data = $email;
  9. foreach ($email['options'] as $name => $value) {
  10. $controls->data['options_' . $name] = $value;
  11. }
  12. }
  13. // Always required
  14. $email = $module->get_email($_GET['id'], ARRAY_A);
  15. if (empty($email)) {
  16. echo 'Wrong email identifier';
  17. return;
  18. }
  19. $email_id = $email['id'];
  20. /* Satus changes which require a reload */
  21. if ($controls->is_action('pause')) {
  22. $wpdb->update(NEWSLETTER_EMAILS_TABLE, array('status' => 'paused'), array('id' => $email_id));
  23. $email = $module->get_email($_GET['id'], ARRAY_A);
  24. tnp_prepare_controls($email, $controls);
  25. }
  26. if ($controls->is_action('continue')) {
  27. $wpdb->update(NEWSLETTER_EMAILS_TABLE, array('status' => 'sending'), array('id' => $email_id));
  28. $email = $module->get_email($_GET['id'], ARRAY_A);
  29. tnp_prepare_controls($email, $controls);
  30. }
  31. if ($controls->is_action('abort')) {
  32. $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set last_id=0, sent=0, status='new' where id=" . $email_id);
  33. $email = $module->get_email($_GET['id'], ARRAY_A);
  34. tnp_prepare_controls($email, $controls);
  35. $controls->messages = __('Delivery definitively cancelled', 'newsletter');
  36. }
  37. if ($controls->is_action('change-private')) {
  38. $data = array();
  39. $data['private'] = $controls->data['private'] ? 1 : 0;
  40. $data['id'] = $email['id'];
  41. $email = Newsletter::instance()->save_email($data, ARRAY_A);
  42. $controls->add_message_saved();
  43. tnp_prepare_controls($email, $controls);
  44. }
  45. $editor_type = $module->get_editor_type($email);
  46. // Backward compatibility: preferences conversion
  47. if (!$controls->is_action()) {
  48. if (!isset($email['options']['lists'])) {
  49. $options_profile = get_option('newsletter_profile');
  50. if (empty($controls->data['preferences_status_operator'])) {
  51. $email['options']['lists_operator'] = 'or';
  52. } else {
  53. $email['options']['lists_operator'] = 'and';
  54. }
  55. $controls->data['options_lists'] = array();
  56. $controls->data['options_lists_exclude'] = array();
  57. if (!empty($email['preferences'])) {
  58. $preferences = explode(',', $email['preferences']);
  59. $value = empty($email['options']['preferences_status']) ? 'on' : 'off';
  60. foreach ($preferences as $x) {
  61. if ($value == 'on') {
  62. $controls->data['options_lists'][] = $x;
  63. } else {
  64. $controls->data['options_lists_exclude'][] = $x;
  65. }
  66. }
  67. }
  68. }
  69. }
  70. // End backward compatibility
  71. if (!$controls->is_action()) {
  72. tnp_prepare_controls($email, $controls);
  73. }
  74. if ($controls->is_action('html')) {
  75. $data = array();
  76. $data['editor'] = NewsletterEmails::EDITOR_HTML;
  77. $data['id'] = $email_id;
  78. // Backward compatibility: clean up the composer flag
  79. $data['options'] = $email['options'];
  80. unset($data['options']['composer']);
  81. // End backward compatibility
  82. $email = Newsletter::instance()->save_email($data, ARRAY_A);
  83. $controls->messages = 'You can now edit the newsletter as pure HTML';
  84. tnp_prepare_controls($email, $controls);
  85. $editor_type = NewsletterEmails::EDITOR_HTML;
  86. }
  87. if ($controls->is_action('test') || $controls->is_action('save') || $controls->is_action('send') || $controls->is_action('schedule')) {
  88. $email['subject'] = $controls->data['subject'];
  89. $email['track'] = $controls->data['track'];
  90. $email['editor'] = $editor_type;
  91. $email['private'] = $controls->data['private'];
  92. $email['message_text'] = $controls->data['message_text'];
  93. if ($controls->is_action('send')) {
  94. $email['send_on'] = time();
  95. } else {
  96. $email['send_on'] = $controls->data['send_on'];
  97. }
  98. // Reset and refill the options
  99. $email['options'] = array();
  100. foreach ($controls->data as $name => $value) {
  101. if (strpos($name, 'options_') === 0) {
  102. $email['options'][substr($name, 8)] = $value;
  103. }
  104. }
  105. // Before send, we build the query to extract subscriber, so the delivery engine does not
  106. // have to worry about the email parameters
  107. if ($email['options']['status'] == 'S') {
  108. $query = "select * from " . NEWSLETTER_USERS_TABLE . " where status='S'";
  109. } else {
  110. $query = "select * from " . NEWSLETTER_USERS_TABLE . " where status='C'";
  111. }
  112. if ($email['options']['wp_users'] == '1') {
  113. $query .= " and wp_user_id<>0";
  114. }
  115. $list_where = array();
  116. if (isset($email['options']['lists']) && count($email['options']['lists'])) {
  117. foreach ($email['options']['lists'] as $list) {
  118. $list = (int) $list;
  119. $list_where[] = 'list_' . $list . '=1';
  120. }
  121. }
  122. if (!empty($list_where)) {
  123. if (isset($email['options']['lists_operator']) && $email['options']['lists_operator'] == 'and') {
  124. $query .= ' and (' . implode(' and ', $list_where) . ')';
  125. } else {
  126. $query .= ' and (' . implode(' or ', $list_where) . ')';
  127. }
  128. }
  129. // Excluded lists
  130. $list_where = array();
  131. if (isset($email['options']['lists_exclude']) && count($email['options']['lists_exclude'])) {
  132. foreach ($email['options']['lists_exclude'] as $list) {
  133. $list = (int) $list;
  134. $list_where[] = 'list_' . $list . '=0';
  135. }
  136. }
  137. if (!empty($list_where)) {
  138. // Must not be in one of the excluded lists
  139. $query .= ' and (' . implode(' and ', $list_where) . ')';
  140. }
  141. // Gender
  142. if (isset($email['options']['sex'])) {
  143. $sex = $email['options']['sex'];
  144. if (is_array($sex) && count($sex)) {
  145. $query .= " and sex in (";
  146. foreach ($sex as $x) {
  147. $query .= "'" . esc_sql((string) $x) . "', ";
  148. }
  149. $query = substr($query, 0, -2);
  150. $query .= ")";
  151. }
  152. }
  153. // Temporary save to have an object and call the query filter
  154. $e = Newsletter::instance()->save_email($email);
  155. $query = apply_filters('newsletter_emails_email_query', $query, $e);
  156. $email['query'] = $query;
  157. if ($email['status'] == 'sent') {
  158. $email['total'] = $email['sent'];
  159. } else {
  160. $email['total'] = $wpdb->get_var(str_replace('*', 'count(*)', $query));
  161. }
  162. if ($controls->is_action('send') && $controls->data['send_on'] < time()) {
  163. $controls->data['send_on'] = time();
  164. }
  165. $email = Newsletter::instance()->save_email($email, ARRAY_A);
  166. tnp_prepare_controls($email, $controls);
  167. if ($email === false) {
  168. $controls->errors = 'Unable to save. Try to deactivate and reactivate the plugin may be the database is out of sync.';
  169. }
  170. $controls->add_message_saved();
  171. }
  172. if ($controls->is_action('send') || $controls->is_action('schedule')) {
  173. NewsletterStatistics::instance()->reset_stats($email);
  174. if ($email['subject'] == '') {
  175. $controls->errors = __('A subject is required to send', 'newsletter');
  176. } else {
  177. $wpdb->update(NEWSLETTER_EMAILS_TABLE, array('status' => 'sending'), array('id' => $email_id));
  178. $email['status'] = 'sending';
  179. if ($controls->is_action('send')) {
  180. $controls->messages = __( 'Now sending.', 'newsletter' );
  181. } else {
  182. $controls->messages = __( 'Scheduled.', 'newsletter' );
  183. }
  184. }
  185. }
  186. if (isset($email['options']['status']) && $email['options']['status'] == 'S') {
  187. $controls->warnings[] = __('This newsletter will be sent to not confirmed subscribers.', 'newsletter');
  188. }
  189. if (strpos($email['message'], '{profile_url}') === false && strpos($email['message'], '{unsubscription_url}') === false && strpos($email['message'], '{unsubscription_confirm_url}') === false) {
  190. $controls->warnings[] = __('The message is missing the subscriber profile or cancellation link.', 'newsletter');
  191. }
  192. if ($email['status'] != 'sent') {
  193. $subscriber_count = $wpdb->get_var(str_replace('*', 'count(*)', $email['query']));
  194. } else {
  195. $subscriber_count = $email['sent'];
  196. }
  197. ?>
  198. <style>
  199. .select2-container {
  200. max-width: 500px;
  201. display: block;
  202. margin: 1px;
  203. margin-top: 5px;
  204. }
  205. </style>
  206. <div class="wrap tnp-emails tnp-emails-edit" id="tnp-wrap">
  207. <?php include NEWSLETTER_DIR . '/tnp-header.php'; ?>
  208. <div id="tnp-heading">
  209. <h2><?php _e('Edit Newsletter', 'newsletter') ?></h2>
  210. </div>
  211. <div id="tnp-body">
  212. <form method="post" action="" id="newsletter-form">
  213. <?php $controls->init(array('cookie_name' => 'newsletter_emails_edit_tab')); ?>
  214. <div class="tnp-status-header">
  215. <div class="tnp-two-thirds">
  216. <div class="tnp-submit">
  217. <?php if ($email['status'] == 'sending' || $email['status'] == 'sent') { ?>
  218. <?php $controls->button_back('?page=newsletter_emails_index') ?>
  219. <?php } else { ?>
  220. <a class="button-primary" href="<?php echo $module->get_editor_url($email_id, $editor_type)?>">
  221. <i class="fa fa-edit"></i> <?php _e('Edit', 'newsletter') ?>
  222. </a>
  223. <?php } ?>
  224. <?php if ($email['status'] != 'sending' && $email['status'] != 'sent') $controls->button_save(); ?>
  225. <?php if ($email['status'] == 'new') { ?>
  226. <?php $controls->button_confirm('send', __('Send now', 'newsletter'), __('Start real delivery?', 'newsletter')); ?>
  227. <a id="tnp-schedule-button" class="button-secondary" href="javascript:tnp_toggle_schedule()"><i class="far fa-clock"></i> <?php _e("Schedule") ?></a>
  228. <span id="tnp-schedule" style="display: none;">
  229. <?php $controls->datetime('send_on') ?>
  230. <?php $controls->button_confirm('schedule', __('Schedule', 'newsletter'), __('Schedule delivery?', 'newsletter')); ?>
  231. <a class="button-secondary tnp-button-cancel" href="javascript:tnp_toggle_schedule()"><?php _e("Cancel") ?></a>
  232. </span>
  233. <?php } ?>
  234. <?php if ($email['status'] == 'sending') $controls->button_confirm('pause', __('Pause', 'newsletter'), __('Pause the delivery?', 'newsletter')); ?>
  235. <?php if ($email['status'] == 'paused') $controls->button_confirm('continue', __('Continue', 'newsletter'), 'Continue the delivery?'); ?>
  236. <?php if ($email['status'] == 'paused') $controls->button_confirm('abort', __('Stop', 'newsletter'), __('This totally stop the delivery, ok?', 'newsletter')); ?>
  237. </div>
  238. <?php $controls->text('subject', null, 'Subject'); ?>
  239. <a href="#" class="tnp-suggest-button" onclick="tnp_suggest_subject(); return false;"><?php _e('Get ideas', 'newsletter') ?></a>
  240. <!--
  241. <a href="#" class="tnp-suggest-button" onclick="tnp_emoji(); return false;"><?php _e('Insert emoji', 'newsletter') ?></a>
  242. -->
  243. </div>
  244. <div class="tnp-one-third">
  245. <div id="tnp-nl-status">
  246. <span class="tnp-nl-status-title"><?php _e("Status:") ?></span>
  247. <span class="tnp-nl-status-title-value"><?php _e("") ?> <?php $module->show_email_status_label($email) ?></span>
  248. <?php $module->show_email_progress_bar($email, array('numbers' => $email['status'] == 'sent' ? false : true)) ?>
  249. <?php if ($email['status'] == 'sent' || $email['status'] == 'sending') { ?>
  250. <div class="tnp-nl-status-row">
  251. <span class="tnp-nl-status-schedule-value"><?php if ($email['status'] == 'sent') {
  252. echo __('Sent on'), ' ', $module->format_date( $email['send_on']);
  253. } else if ($email['status'] == 'sending' && $email['send_on'] > time()) {
  254. echo __('Scheduled on'), ' ', $module->format_date( $email['send_on']);
  255. }
  256. ?></span>
  257. </div>
  258. <?php } ?>
  259. <div class="tnp-nl-status-row">
  260. <span class="tnp-nl-status-schedule-targeting"><?php _e('Targeted subscribers', 'newsletter') ?>:</span>
  261. <span class="tnp-nl-status-schedule-value"><?php echo $subscriber_count ?></span>
  262. </div>
  263. </div>
  264. </div>
  265. </div>
  266. <div id="tabs">
  267. <ul>
  268. <li><a href="#tabs-options"><?php _e('Sending Options', 'newsletter') ?></a></li>
  269. <li><a href="#tabs-advanced"><?php _e('Advanced', 'newsletter') ?></a></li>
  270. <li><a href="#tabs-preview"><?php _e('Preview', 'newsletter') ?></a></li>
  271. </ul>
  272. <div id="tabs-options" class="tnp-list-conditions">
  273. <p>
  274. <?php $controls->panel_help('https://www.thenewsletterplugin.com/documentation/newsletter-targeting') ?>
  275. </p>
  276. <p>
  277. <?php _e('Leaving all multichoice options unselected is like to select all them', 'newsletter'); ?>
  278. </p>
  279. <table class="form-table">
  280. <tr>
  281. <th><?php _e('Lists', 'newsletter') ?></th>
  282. <td>
  283. <?php
  284. $lists = $controls->get_list_options();
  285. ?>
  286. <?php $controls->select('options_lists_operator', array('or' => __('Match at least one of', 'newsletter'), 'and' => __('Match all of', 'newsletter'))); ?>
  287. <?php $controls->select2('options_lists', $lists, null, true, null, __('All', 'newsletter')); ?>
  288. <br>
  289. <?php _e('must not in one of', 'newsletter') ?>
  290. <?php $controls->select2('options_lists_exclude', $lists, null, true, null, __('None', 'newsletter')); ?>
  291. </td>
  292. </tr>
  293. <tr>
  294. <th><?php _e('Gender', 'newsletter') ?></th>
  295. <td>
  296. <?php $controls->checkboxes_group('options_sex', array('f' => 'Women', 'm' => 'Men', 'n' => 'Not specified')); ?>
  297. </td>
  298. </tr>
  299. <tr>
  300. <th><?php _e('Status', 'newsletter') ?></th>
  301. <td>
  302. <?php $controls->select('options_status', array('C' => __('Confirmed', 'newsletter'), 'S' => __('Not confirmed', 'newsletter'))); ?>
  303. </td>
  304. </tr>
  305. <tr>
  306. <th><?php _e('Only to subscribers linked to WP users', 'newsletter') ?></th>
  307. <td>
  308. <?php $controls->yesno('options_wp_users'); ?>
  309. </td>
  310. </tr>
  311. </table>
  312. <?php do_action('newsletter_emails_edit_target', $module->get_email($email_id), $controls) ?>
  313. </div>
  314. <div id="tabs-advanced">
  315. <table class="form-table">
  316. <tr>
  317. <th><?php _e('Keep private', 'newsletter') ?></th>
  318. <td>
  319. <?php $controls->yesno('private'); ?>
  320. <?php if ($email['status'] == 'sent') { ?>
  321. <?php $controls->button('change-private', __('Toggle')) ?>
  322. <?php } ?>
  323. <p class="description">
  324. <?php _e('Hide/show from public sent newsletter list.', 'newsletter') ?>
  325. <?php _e('Required', 'newsletter') ?>: <a href="" target="_blank">Newsletter Archive Extension</a>
  326. </p>
  327. </td>
  328. </tr>
  329. <tr>
  330. <th><?php _e('Track clicks and message opening', 'newsletter') ?></th>
  331. <td>
  332. <?php $controls->yesno('track'); ?>
  333. </td>
  334. </tr>
  335. </table>
  336. <?php do_action('newsletter_emails_edit_other', $module->get_email($email_id), $controls) ?>
  337. <table class="form-table">
  338. <tr>
  339. <th>Query (tech)</th>
  340. <td><?php echo esc_html($email['query']); ?></td>
  341. </tr>
  342. <tr>
  343. <th>Token (tech)</th>
  344. <td><?php echo esc_html($email['token']); ?></td>
  345. </tr>
  346. <tr>
  347. <th>This is the textual version of your newsletter. If you empty it, only an HTML version will be sent but is an anti-spam best practice to include a text only version.</th>
  348. <td>
  349. <?php if (Newsletter::instance()->options['phpmailer'] == 0) { ?>
  350. <p class="tnp-tab-warning">The text part is sent only when Newsletter manages directly the sending process. <a href="admin.php?page=newsletter_main_main" target="_blank">See the main settings</a>.</p>
  351. <?php } ?>
  352. <?php $controls->textarea_fixed('message_text', '100%', '500'); ?>
  353. </td>
  354. </tr>
  355. </table>
  356. </div>
  357. <div id="tabs-preview">
  358. <div class="tnpc-preview">
  359. <!-- Flat Laptop Browser -->
  360. <div class="fake-browser-ui">
  361. <div class="frame">
  362. <span class="bt-1"></span>
  363. <span class="bt-2"></span>
  364. <span class="bt-3"></span>
  365. </div>
  366. <iframe id="tnpc-preview-desktop" src="" width="700" height="520" alt="" frameborder="0"></iframe>
  367. </div>
  368. <!-- Flat Mobile Browser -->
  369. <div class="fake-mobile-browser-ui">
  370. <iframe id="tnpc-preview-mobile" src="" width="320" height="445" alt="" frameborder="0"></iframe>
  371. <div class="frame">
  372. <span class="bt-4"></span>
  373. </div>
  374. </div>
  375. </div>
  376. <script type="text/javascript">
  377. preview_url = ajaxurl + "?action=tnpc_preview&id=<?php echo $email_id ?>";
  378. jQuery('#tnpc-preview-desktop, #tnpc-preview-mobile').attr("src", preview_url);
  379. setTimeout(function () {
  380. jQuery('#tnpc-preview-desktop, #tnpc-preview-mobile').contents().find("a").click(function (e) {
  381. e.preventDefault();
  382. })
  383. }, 500);
  384. </script>
  385. <p>
  386. <?php if ($editor_type != NewsletterEmails::EDITOR_HTML && $email['status'] != 'sending' && $email['status'] != 'sent') $controls->button_confirm('html', __('Convert to HTML newsletter', 'newsletter'), 'Attention: no way back!'); ?>
  387. </p>
  388. </div>
  389. </div>
  390. </form>
  391. </div>
  392. <?php include NEWSLETTER_DIR . '/emails/subjects.php'; ?>
  393. <?php include NEWSLETTER_DIR . '/tnp-footer.php'; ?>
  394. </div>