UpdraftPlus WordPress Backup Plugin - Version 1.14.12

Version Description

  • 17/July/2018 =

  • FEATURE: Added UpdraftCentral's theme management module handler

  • FEATURE: User can mark any backup as "do not delete", and it will then not be deleted even when retention limits are hit

  • FEATURE: WP-CLI - add a 'restore' command

  • FEATURE: WP-CLI - Add an option 'delete-during-restore' in the 'restore' command

  • FEATURE: Add optional 'fingerprint' configuration for sftp/scp remote storage, allowing the connection to be halted if the server's fingerprint does not match what was entered

  • FEATURE: Added the ability to take an incremental backup via WP-CLI (note: incremental backups are still considered an experimental/work-in-progress feature)

  • FIX: If a user gave the wrong key to decrypt an encrypted database, the "Decryption failed" message did not display

  • FIX: The Migration was not changing an unsupported database table engine with the MyISAM engine automatically

  • FIX: Issue with the Dropbox account API call on some installs

  • FIX: The web server disk space refresh link of the existing backups is not working

  • FIX: The UpdraftPlus News couldn't print first time when the news cache was not made

  • FIX: Activating the "all addons" licence did not remove the corresponding 'activate on this account' link in the "Premium / Extensions" tab

  • FIX: When set names query character set hadnt support by the current MySQL server, the restoration process wasn't gave replace the character set

  • TWEAK: Updated the plugin.php handler for UpdraftCentral's new plugin management module

  • TWEAK: Update posts handler to fix and update pagination in UpdraftCentral

  • TWEAK: Refresh UpdraftCentral keys upon successful login or registration using the UpdraftCentral Cloud wizard

  • TWEAK: Correct admin page URL in WP-CLI 'restore' command when on multisite without multisite add-on

  • TWEAK: Prevent PHP notice when checking non-existent files in relation to an extraneous whitespace warning

  • TWEAK: Prevent PHP notices in add-ons with non-present settings

  • TWEAK: Add the "Migrate / Clone" tab in place of the "Migrate / Clone" dialog

  • TWEAK: Prevent call to the the wp_get_sites() deprecated function on WP 4.6 and newer

  • TWEAK: Prevent a potential PHP debugging notice when displaying the 'Connect with your UpdraftPlus.com' form

  • TWEAK: Do not show the confusing JetPack 'backup' notice on the 'Updates' page

  • TWEAK: Added clone notices and commands for when UpdraftPlus is running on a UpdraftClone

  • TWEAK: Move 'Log all messages to syslog (only server admins are likely to want this)' into the 'expert' settings section

  • TWEAK: Replace a missing class constant in the Dropbox SDK (only relevant to people upgrading from Dropbox API v1 tokens - indicates upgrading UpdraftPlus from a very old version that previously used Dropbox APIv1 but never v2)

  • TWEAK: It's "backup", not "back up"

  • TWEAK: Prevent potential PHP debugging notices in restoration step 2

  • TWEAK: Allow non-Super Admins to access UpdraftPlus Premium if they have 'manage_network_plugins' capability and the updraft_user_can_manage filter is used

  • TWEAK: Improved code in a way that prevents continuous polling in the themes page, thes plugins page and the updates page

Download this release

Release Info

Developer DavidAnderson
Plugin Icon 128x128 UpdraftPlus WordPress Backup Plugin
Version 1.14.12
Comparing to
See all releases

Code changes from version 1.14.10 to 1.14.12

admin.php CHANGED
@@ -67,6 +67,15 @@ class UpdraftPlus_Admin {
67
 
68
  }
69
 
 
 
 
 
 
 
 
 
 
70
  public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) {
71
  if ($return_instead_of_echo) ob_start();
72
 
@@ -78,9 +87,7 @@ class UpdraftPlus_Admin {
78
  }
79
  }
80
 
81
- if (!isset($template_file)) {
82
- $template_file = UPDRAFTPLUS_DIR.'/templates/'.$path;
83
- }
84
 
85
  $template_file = apply_filters('updraftplus_template', $template_file, $path);
86
 
@@ -408,7 +415,7 @@ class UpdraftPlus_Admin {
408
  * Sets up what is needed to allow an in-page backup to be run. Will enqueue scripts and output appropriate HTML (so, should be run when at a suitable place). Not intended for use on the UpdraftPlus settings page.
409
  *
410
  * @param string $title Text to use for the title of the modal
411
- * @param callable $callback Callable function to output the contents of the updraft_inpage_prebackup element - i.e. what shows in the modal before a backup beings.
412
  */
413
  public function add_backup_scaffolding($title, $callback) {
414
  $this->admin_enqueue_scripts();
@@ -545,7 +552,7 @@ class UpdraftPlus_Admin {
545
 
546
  $args = array(
547
  'id' => 'updraft_admin_node_status',
548
- 'title' => __('Current Status', 'updraftplus').' / '.__('Backup Now', 'updraftplus'),
549
  'parent' => 'updraft_admin_node',
550
  'href' => $option_location.'?page=updraftplus&tab=status'
551
  );
@@ -671,6 +678,7 @@ class UpdraftPlus_Admin {
671
  $mday_selector .= "\n\t<option value='" . $mday_index . "' $selected>" . $mday_index . '</option>';
672
  }
673
  $remote_storage_options_and_templates = $updraftplus->get_remote_storage_options_and_templates();
 
674
  wp_localize_script('updraftplus-admin', 'updraftlion', array(
675
  'sendonlyonwarnings' => __('Send a report only when there are warnings/errors', 'updraftplus'),
676
  'wholebackup' => __('When the Email storage method is enabled, also send the backup', 'updraftplus'),
@@ -721,7 +729,8 @@ class UpdraftPlus_Admin {
721
  'unknownresp' => __('Unknown server response:', 'updraftplus'),
722
  'ukrespstatus' => __('Unknown server response status:', 'updraftplus'),
723
  'uploaded' => __('The file was uploaded.', 'updraftplus'),
724
- 'backupnow' => __('Backup Now', 'updraftplus'),
 
725
  'cancel' => __('Cancel', 'updraftplus'),
726
  'deletebutton' => __('Delete', 'updraftplus'),
727
  'createbutton' => __('Create', 'updraftplus'),
@@ -818,6 +827,7 @@ class UpdraftPlus_Admin {
818
  'data_consent_required' => __('You need to read and accept the UpdraftCentral Cloud data and privacy policies before you can proceed.', 'updraftplus'),
819
  'close_wizard' => __('You can also close this wizard.', 'updraftplus'),
820
  'control_udc_connections' => __('For future control of all your UpdraftCentral connections, go to the "Advanced Tools" tab.', 'updraftplus'),
 
821
  ));
822
  }
823
 
@@ -992,12 +1002,13 @@ class UpdraftPlus_Admin {
992
  }
993
 
994
  public function show_admin_warning_unwritable() {
995
- $unwritable_mess = htmlspecialchars(__("The 'Backup Now' button is disabled as your backup directory is not writable (go to the 'Settings' tab and find the relevant option).", 'updraftplus'));
 
996
  $this->show_admin_warning($unwritable_mess, "error");
997
  }
998
 
999
  public function show_admin_nosettings_warning() {
1000
- $this->show_admin_warning('<strong>'.__('Welcome to UpdraftPlus!', 'updraftplus').'</strong> '.__('To make a backup, just press the Backup Now button.', 'updraftplus').' <a href="#" id="updraft-navtab-settings2">'.__('To change any of the default settings of what is backed up, to configure scheduled backups, to send your backups to remote storage (recommended), and more, go to the settings tab.', 'updraftplus').'</a>', 'updated notice is-dismissible');
1001
  }
1002
 
1003
  public function show_admin_warning_execution_time() {
@@ -1950,6 +1961,8 @@ class UpdraftPlus_Admin {
1950
  if (!empty($request['extradata'])) {
1951
  $options['extradata'] = $request['extradata'];
1952
  }
 
 
1953
 
1954
  do_action($event, apply_filters('updraft_backupnow_options', $options, $request));
1955
  }
@@ -2530,16 +2543,8 @@ class UpdraftPlus_Admin {
2530
  }
2531
 
2532
  $tabflag = 'status';
2533
- $main_tabs = apply_filters(
2534
- 'updraftplus_main_tabs',
2535
- array(
2536
- 'status' => __('Current Status', 'updraftplus'),
2537
- 'backups' => __('Existing Backups', 'updraftplus').' ('.count($backup_history).')',
2538
- 'settings' => __('Settings', 'updraftplus'),
2539
- 'expert' => __('Advanced Tools', 'updraftplus'),
2540
- 'addons' => __('Premium / Extensions', 'updraftplus'),
2541
- )
2542
- );
2543
 
2544
  if (isset($_REQUEST['tab'])) {
2545
  $request_tab = sanitize_text_field($_REQUEST['tab']);
@@ -2573,6 +2578,16 @@ class UpdraftPlus_Admin {
2573
  ?>
2574
  </div>
2575
 
 
 
 
 
 
 
 
 
 
 
2576
  <div id="updraft-navtab-settings-content" <?php if ('settings' != $tabflag) echo 'class="updraft-hidden"'; ?> style="<?php if ('settings' != $tabflag) echo 'display:none;'; ?>">
2577
  <h2 class="updraft_settings_sectionheading"><?php _e('Backup Contents And Schedule', 'updraftplus');?></h2>
2578
  <?php UpdraftPlus_Options::options_form_begin(); ?>
@@ -2663,7 +2678,32 @@ class UpdraftPlus_Admin {
2663
  // settings_header() opens a div
2664
  echo '</div>';
2665
  }
2666
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2667
  private function print_restore_in_progress_box_if_needed() {
2668
  $restore_in_progress = get_site_option('updraft_restore_in_progress');
2669
  if (!empty($restore_in_progress)) {
@@ -2725,7 +2765,7 @@ class UpdraftPlus_Admin {
2725
 
2726
  $connect = htmlspecialchars(__('Connect', 'updraftplus'));
2727
 
2728
- $enter_credentials_end = '<p style="margin-left: 258px;"><input id="ud_connectsubmit" type="submit" class="button-primary" value="'.$connect.'" /></p>';
2729
 
2730
  $enter_credentials_end .= '<p style="margin-left: 258px; font-size: 70%"><em><a href="https://updraftplus.com/faqs/tell-me-about-my-updraftplus-com-account/">'.$interested.'</a></em></p>';
2731
 
@@ -2786,7 +2826,7 @@ class UpdraftPlus_Admin {
2786
  <th><?php _e('Password', 'updraftplus'); ?></th>
2787
  <td>
2788
  <label for="<?php echo $option_page; ?>'_options_password">
2789
- <input id="<?php echo $option_page; ?>_options_password" type="password" size="36" name="<?php echo $option_page; ?>_options[password]" value="<?php echo htmlspecialchars($options['password']); ?>" />
2790
  <br/>
2791
  <a href="https://updraftplus.com/my-account/?action=lostpassword"><?php _e('Forgotten your details?', 'updraftplus'); ?></a>
2792
  </label>
@@ -2811,7 +2851,8 @@ class UpdraftPlus_Admin {
2811
  }
2812
 
2813
  /**
2814
- * Return widgetry for the 'backup now' modal
 
2815
  *
2816
  * @return String
2817
  */
@@ -2842,6 +2883,8 @@ class UpdraftPlus_Admin {
2842
  $ret .= '<div id="backupnow_includefiles_moreoptions" class="updraft-hidden" style="display:none;"><em>'.__('Your saved settings also affect what is backed up - e.g. files excluded.', 'updraftplus').'</em><br>'.$this->files_selector_widgetry('backupnow_files_', false, 'sometimes').'</div></p>';
2843
 
2844
  $ret .= '<span id="backupnow_remote_container">'.$this->backup_now_remote_message().'</span>';
 
 
2845
 
2846
  $ret .= apply_filters('updraft_backupnow_modal_afteroptions', '', '');
2847
 
@@ -3754,7 +3797,15 @@ class UpdraftPlus_Admin {
3754
 
3755
  }
3756
 
3757
- private function raw_backup_info($backup_history, $key, $nonce) {
 
 
 
 
 
 
 
 
3758
 
3759
  global $updraftplus;
3760
 
@@ -3766,16 +3817,18 @@ class UpdraftPlus_Admin {
3766
 
3767
  if (!empty($backup['label'])) $rawbackup .= '<span class="raw-backup-info">'.$backup['label'].'</span>';
3768
 
3769
- $rawbackup .= '<hr><p>';
3770
-
3771
- $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
3772
-
3773
  if (!empty($nonce)) {
3774
  $jd = $updraftplus->jobdata_getarray($nonce);
3775
  } else {
3776
  $jd = array();
3777
  }
3778
 
 
 
 
 
 
 
3779
  $checksums = $updraftplus->which_checksums();
3780
 
3781
  foreach ($backupable_entities as $type => $info) {
@@ -3807,9 +3860,9 @@ class UpdraftPlus_Admin {
3807
  if ('none' == $serv || '' == $serv) {
3808
  $add_none = true;
3809
  } elseif (isset($updraftplus->backup_methods[$serv])) {
3810
- $show_services .= ($show_services) ? ', '.$updraftplus->backup_methods[$serv] : $updraftplus->backup_methods[$serv];
3811
  } else {
3812
- $show_services .= ($show_services) ? ', '.$serv : $serv;
3813
  }
3814
  }
3815
  if ('' == $show_services && $add_none) $show_services .= __('None', 'updraftplus');
@@ -3820,8 +3873,6 @@ class UpdraftPlus_Admin {
3820
  $rawbackup .= '</p><strong>'.__('Total backup size:', 'updraftplus').'</strong> '.UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($total_size).'<p>';
3821
  }
3822
 
3823
-
3824
-
3825
  $rawbackup .= '</p><hr><p><pre>'.print_r($backup, true).'</p></pre>';
3826
 
3827
  if (!empty($jd) && is_array($jd)) {
@@ -4171,34 +4222,7 @@ ENDHERE;
4171
  if (isset($backup[$entity.'-size'])) $file_backups[$entity.'-size'] = $backup[$entity.'-size'];
4172
  }
4173
 
4174
- $blog_name = '';
4175
-
4176
- /*
4177
- We need to tweak the database array here by setting each database entity to finished or encrypted if it's an encrypted archive.
4178
- I also grab the backups blog name here ready to be used later, just in case this backup set is from another site.
4179
- */
4180
- foreach ($db_backups as $key => $db_info) {
4181
- $status = 'finished';
4182
- $db_index = ('wp' == $key) ? 0 : $key;
4183
-
4184
- if (isset($backup['db'][$db_index])) {
4185
- $db_backup_name = $backup['db'][$db_index];
4186
-
4187
- if (preg_match('/^backup_([\-0-9]{15})_(.*)_([0-9a-f]{12})-[\-a-z]+([0-9]+)?+(\.(zip|gz|gz\.crypt))?$/i', $db_backup_name, $matches)) {
4188
- $blog_name = $matches[2];
4189
- }
4190
-
4191
- if (UpdraftPlus_Encryption::is_file_encrypted($db_backup_name)) $status = 'encrypted';
4192
-
4193
- if (is_array($db_info) && isset($db_info['status'])) {
4194
- $db_backups[$key]['status'] = $status;
4195
- } else {
4196
- $db_backups[$key] = $status;
4197
- }
4198
- } else {
4199
- unset($db_backups[$key]);
4200
- }
4201
- }
4202
 
4203
  // Next we need to build the services array using the remote storage destinations the user has selected to upload this backup set to
4204
  $selected_services = array();
@@ -4213,8 +4237,8 @@ ENDHERE;
4213
  $jobdata[] = 'backup_files_array';
4214
  $jobdata[] = $file_backups;
4215
  $jobdata[] = 'blog_name';
4216
- $jobdata[] = $blog_name;
4217
- $jobdata[$backup_database_key] = $db_backups;
4218
  if (!empty($selected_services)) $jobdata[$service_key] = $selected_services;
4219
 
4220
 
@@ -4485,7 +4509,7 @@ ENDHERE;
4485
  * @uses $GLOBALS['updraftplus_restorer']
4486
  * @uses UpdraftPlus::log()
4487
  */
4488
- private function post_restore_clean_up($successful = true, $browser_context = true) {
4489
 
4490
  global $updraftplus_restorer, $updraftplus;
4491
 
@@ -5165,6 +5189,7 @@ ENDHERE;
5165
  }
5166
  $corrupted_files = array();
5167
  foreach ($files_to_check as $file) {
 
5168
  if (false === ($fp = fopen($file, 'r'))) continue;
5169
  if (false === ($file_data = fread($fp, 8192)));
5170
  fclose($fp);
67
 
68
  }
69
 
70
+ /**
71
+ * Output, or return, the results of running a template (from the 'templates' directory, unless a filter over-rides it). Templates are run with $updraftplus, $updraftplus_admin and $wpdb set.
72
+ *
73
+ * @param String $path - path to the template
74
+ * @param Boolean $return_instead_of_echo - by default, the template is echo-ed; set this to instead return it
75
+ * @param Array $extract_these - variables to inject into the template's run context
76
+ *
77
+ * @return Void|String
78
+ */
79
  public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) {
80
  if ($return_instead_of_echo) ob_start();
81
 
87
  }
88
  }
89
 
90
+ if (!isset($template_file)) $template_file = UPDRAFTPLUS_DIR.'/templates/'.$path;
 
 
91
 
92
  $template_file = apply_filters('updraftplus_template', $template_file, $path);
93
 
415
  * Sets up what is needed to allow an in-page backup to be run. Will enqueue scripts and output appropriate HTML (so, should be run when at a suitable place). Not intended for use on the UpdraftPlus settings page.
416
  *
417
  * @param string $title Text to use for the title of the modal
418
+ * @param callable $callback Callable function to output the contents of the updraft_inpage_prebackup element - i.e. what shows in the modal before a backup begins.
419
  */
420
  public function add_backup_scaffolding($title, $callback) {
421
  $this->admin_enqueue_scripts();
552
 
553
  $args = array(
554
  'id' => 'updraft_admin_node_status',
555
+ 'title' => __('Current Status', 'updraftplus').' / '.str_ireplace('Back Up', 'Backup', __('Backup Now', 'updraftplus')),
556
  'parent' => 'updraft_admin_node',
557
  'href' => $option_location.'?page=updraftplus&tab=status'
558
  );
678
  $mday_selector .= "\n\t<option value='" . $mday_index . "' $selected>" . $mday_index . '</option>';
679
  }
680
  $remote_storage_options_and_templates = $updraftplus->get_remote_storage_options_and_templates();
681
+ $main_tabs = $this->get_main_tabs_array();
682
  wp_localize_script('updraftplus-admin', 'updraftlion', array(
683
  'sendonlyonwarnings' => __('Send a report only when there are warnings/errors', 'updraftplus'),
684
  'wholebackup' => __('When the Email storage method is enabled, also send the backup', 'updraftplus'),
729
  'unknownresp' => __('Unknown server response:', 'updraftplus'),
730
  'ukrespstatus' => __('Unknown server response status:', 'updraftplus'),
731
  'uploaded' => __('The file was uploaded.', 'updraftplus'),
732
+ // One of the translators has erroneously changed "Backup" into "Back up" (which means, "reverse" !)
733
+ 'backupnow' => str_ireplace('Back Up', 'Backup', __('Backup Now', 'updraftplus')),
734
  'cancel' => __('Cancel', 'updraftplus'),
735
  'deletebutton' => __('Delete', 'updraftplus'),
736
  'createbutton' => __('Create', 'updraftplus'),
827
  'data_consent_required' => __('You need to read and accept the UpdraftCentral Cloud data and privacy policies before you can proceed.', 'updraftplus'),
828
  'close_wizard' => __('You can also close this wizard.', 'updraftplus'),
829
  'control_udc_connections' => __('For future control of all your UpdraftCentral connections, go to the "Advanced Tools" tab.', 'updraftplus'),
830
+ 'main_tabs_keys' => array_keys($main_tabs),
831
  ));
832
  }
833
 
1002
  }
1003
 
1004
  public function show_admin_warning_unwritable() {
1005
+ // One of the translators has erroneously changed "Backup" into "Back up" (which means, "reverse" !)
1006
+ $unwritable_mess = htmlspecialchars(str_ireplace('Back Up', 'Backup', __("The 'Backup Now' button is disabled as your backup directory is not writable (go to the 'Settings' tab and find the relevant option).", 'updraftplus')));
1007
  $this->show_admin_warning($unwritable_mess, "error");
1008
  }
1009
 
1010
  public function show_admin_nosettings_warning() {
1011
+ $this->show_admin_warning('<strong>'.__('Welcome to UpdraftPlus!', 'updraftplus').'</strong> '.str_ireplace('Back Up', 'Backup', __('To make a backup, just press the Backup Now button.', 'updraftplus')).' <a href="#" id="updraft-navtab-settings2">'.__('To change any of the default settings of what is backed up, to configure scheduled backups, to send your backups to remote storage (recommended), and more, go to the settings tab.', 'updraftplus').'</a>', 'updated notice is-dismissible');
1012
  }
1013
 
1014
  public function show_admin_warning_execution_time() {
1961
  if (!empty($request['extradata'])) {
1962
  $options['extradata'] = $request['extradata'];
1963
  }
1964
+
1965
+ $options['always_keep'] = empty($request['always_keep']) ? false : true;
1966
 
1967
  do_action($event, apply_filters('updraft_backupnow_options', $options, $request));
1968
  }
2543
  }
2544
 
2545
  $tabflag = 'status';
2546
+ $backup_count = count($backup_history);
2547
+ $main_tabs = $this->get_main_tabs_array($backup_count);
 
 
 
 
 
 
 
 
2548
 
2549
  if (isset($_REQUEST['tab'])) {
2550
  $request_tab = sanitize_text_field($_REQUEST['tab']);
2578
  ?>
2579
  </div>
2580
 
2581
+ <div id="updraft-navtab-migrate-content"<?php if ('migrate' != $tabflag) echo ' class="updraft-hidden"'; ?> style="<?php if ('expert' != $tabflag) echo 'display:none;'; ?>">
2582
+ <?php
2583
+ if (has_action('updraftplus_migrate_tab_output')) {
2584
+ do_action('updraftplus_migrate_tab_output');
2585
+ } else {
2586
+ $this->include_template('wp-admin/settings/migrator-no-migrator.php');
2587
+ }
2588
+ ?>
2589
+ </div>
2590
+
2591
  <div id="updraft-navtab-settings-content" <?php if ('settings' != $tabflag) echo 'class="updraft-hidden"'; ?> style="<?php if ('settings' != $tabflag) echo 'display:none;'; ?>">
2592
  <h2 class="updraft_settings_sectionheading"><?php _e('Backup Contents And Schedule', 'updraftplus');?></h2>
2593
  <?php UpdraftPlus_Options::options_form_begin(); ?>
2678
  // settings_header() opens a div
2679
  echo '</div>';
2680
  }
2681
+
2682
+ /**
2683
+ * Get main tabs array
2684
+ *
2685
+ * @param Integer|Boolean $backup_count No. of backup exist or false by default
2686
+ * @return Array Array which have key as a tab key and value as tab label
2687
+ */
2688
+ private function get_main_tabs_array($backup_count = false) {
2689
+ if (false === $backup_count) {
2690
+ $backups_label_postfix = '';
2691
+ } else {
2692
+ $backups_label_postfix = ' ('.$backup_count.')';
2693
+ }
2694
+ return apply_filters(
2695
+ 'updraftplus_main_tabs',
2696
+ array(
2697
+ 'status' => __('Current Status', 'updraftplus'),
2698
+ 'backups' => __('Existing Backups', 'updraftplus').$backups_label_postfix,
2699
+ 'migrate' => __('Migrate / Clone', 'updraftplus'),
2700
+ 'settings' => __('Settings', 'updraftplus'),
2701
+ 'expert' => __('Advanced Tools', 'updraftplus'),
2702
+ 'addons' => __('Premium / Extensions', 'updraftplus'),
2703
+ )
2704
+ );
2705
+ }
2706
+
2707
  private function print_restore_in_progress_box_if_needed() {
2708
  $restore_in_progress = get_site_option('updraft_restore_in_progress');
2709
  if (!empty($restore_in_progress)) {
2765
 
2766
  $connect = htmlspecialchars(__('Connect', 'updraftplus'));
2767
 
2768
+ $enter_credentials_end = '<p style="margin-left: 258px;"><input id="ud_connectsubmit" type="submit" class="button-primary" value="'.$connect.'" /><span class="updraftplus_spinner spinner">' . __('Processing', 'updraftplus') . '...</span></p>';
2769
 
2770
  $enter_credentials_end .= '<p style="margin-left: 258px; font-size: 70%"><em><a href="https://updraftplus.com/faqs/tell-me-about-my-updraftplus-com-account/">'.$interested.'</a></em></p>';
2771
 
2826
  <th><?php _e('Password', 'updraftplus'); ?></th>
2827
  <td>
2828
  <label for="<?php echo $option_page; ?>'_options_password">
2829
+ <input id="<?php echo $option_page; ?>_options_password" type="password" size="36" name="<?php echo $option_page; ?>_options[password]" value="<?php echo empty($options['password']) ? '' : htmlspecialchars($options['password']); ?>" />
2830
  <br/>
2831
  <a href="https://updraftplus.com/my-account/?action=lostpassword"><?php _e('Forgotten your details?', 'updraftplus'); ?></a>
2832
  </label>
2851
  }
2852
 
2853
  /**
2854
+ * Return widgetry for the 'backup now' modal.
2855
+ * Don't optimise this method away; it's used by third-party plugins (e.g. EUM).
2856
  *
2857
  * @return String
2858
  */
2883
  $ret .= '<div id="backupnow_includefiles_moreoptions" class="updraft-hidden" style="display:none;"><em>'.__('Your saved settings also affect what is backed up - e.g. files excluded.', 'updraftplus').'</em><br>'.$this->files_selector_widgetry('backupnow_files_', false, 'sometimes').'</div></p>';
2884
 
2885
  $ret .= '<span id="backupnow_remote_container">'.$this->backup_now_remote_message().'</span>';
2886
+
2887
+ $ret .= '<p><input type="checkbox" id="always_keep"> <label for="always_keep">'.__("Only allow this backup to be deleted manually (i.e. keep it even if retention limits are hit).", 'updraftplus').'</label> ';
2888
 
2889
  $ret .= apply_filters('updraft_backupnow_modal_afteroptions', '', '');
2890
 
3797
 
3798
  }
3799
 
3800
+ /**
3801
+ * Get backup information in HTML format for a specific backup
3802
+ *
3803
+ * @param array $backup_history all backups history
3804
+ * @param string $key backup timestamp
3805
+ * @param string $nonce backup nonce
3806
+ * @return string HTML-formatted backup information
3807
+ */
3808
+ public function raw_backup_info($backup_history, $key, $nonce) {
3809
 
3810
  global $updraftplus;
3811
 
3817
 
3818
  if (!empty($backup['label'])) $rawbackup .= '<span class="raw-backup-info">'.$backup['label'].'</span>';
3819
 
 
 
 
 
3820
  if (!empty($nonce)) {
3821
  $jd = $updraftplus->jobdata_getarray($nonce);
3822
  } else {
3823
  $jd = array();
3824
  }
3825
 
3826
+ $rawbackup .= '<hr>';
3827
+ $rawbackup .= '<input type="checkbox" name="always_keep_this_backup" id="always_keep_this_backup" data-backup_key="'.$key.'" '.(empty($backup['always_keep']) ? '' : 'checked ').'><label for="always_keep_this_backup">'.__('Only allow this backup to be deleted manually (i.e. keep it even if retention limits are hit).', 'updraftplus').'</label>';
3828
+ $rawbackup .= '<hr><p>';
3829
+
3830
+ $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
3831
+
3832
  $checksums = $updraftplus->which_checksums();
3833
 
3834
  foreach ($backupable_entities as $type => $info) {
3860
  if ('none' == $serv || '' == $serv) {
3861
  $add_none = true;
3862
  } elseif (isset($updraftplus->backup_methods[$serv])) {
3863
+ $show_services .= $show_services ? ', '.$updraftplus->backup_methods[$serv] : $updraftplus->backup_methods[$serv];
3864
  } else {
3865
+ $show_services .= $show_services ? ', '.$serv : $serv;
3866
  }
3867
  }
3868
  if ('' == $show_services && $add_none) $show_services .= __('None', 'updraftplus');
3873
  $rawbackup .= '</p><strong>'.__('Total backup size:', 'updraftplus').'</strong> '.UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($total_size).'<p>';
3874
  }
3875
 
 
 
3876
  $rawbackup .= '</p><hr><p><pre>'.print_r($backup, true).'</p></pre>';
3877
 
3878
  if (!empty($jd) && is_array($jd)) {
4222
  if (isset($backup[$entity.'-size'])) $file_backups[$entity.'-size'] = $backup[$entity.'-size'];
4223
  }
4224
 
4225
+ $db_backup_info = $updraftplus->update_database_jobdata($db_backups, $backup);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4226
 
4227
  // Next we need to build the services array using the remote storage destinations the user has selected to upload this backup set to
4228
  $selected_services = array();
4237
  $jobdata[] = 'backup_files_array';
4238
  $jobdata[] = $file_backups;
4239
  $jobdata[] = 'blog_name';
4240
+ $jobdata[] = $db_backup_info['blog_name'];
4241
+ $jobdata[$backup_database_key] = $db_backup_info['db_backups'];
4242
  if (!empty($selected_services)) $jobdata[$service_key] = $selected_services;
4243
 
4244
 
4509
  * @uses $GLOBALS['updraftplus_restorer']
4510
  * @uses UpdraftPlus::log()
4511
  */
4512
+ public function post_restore_clean_up($successful = true, $browser_context = true) {
4513
 
4514
  global $updraftplus_restorer, $updraftplus;
4515
 
5189
  }
5190
  $corrupted_files = array();
5191
  foreach ($files_to_check as $file) {
5192
+ if (!file_exists($file)) continue;
5193
  if (false === ($fp = fopen($file, 'r'))) continue;
5194
  if (false === ($file_data = fread($fp, 8192)));
5195
  fclose($fp);
backup.php CHANGED
@@ -182,7 +182,7 @@ class UpdraftPlus_Backup {
182
  if (!function_exists('get_mu_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
183
  $mu_plugins = get_mu_plugins();
184
  if (count($mu_plugins) == 0) {
185
- $updraftplus->log("There appear to be no mu-plugins to back up. Will not raise an error.");
186
  $flag_error = false;
187
  }
188
  }
@@ -362,8 +362,8 @@ class UpdraftPlus_Backup {
362
 
363
  // We need to make sure that the loop below actually runs
364
  if (empty($services)) $services = array('none');
365
-
366
- $storage_objects_and_ids = $updraftplus->get_storage_objects_and_ids($services);
367
 
368
  $total_instances_count = 0;
369
 
@@ -589,7 +589,7 @@ class UpdraftPlus_Backup {
589
  if (!empty($ignored_because_imported)) {
590
  $updraftplus->log("These backup set(s) were imported from a remote location, so will not be counted or pruned. Skipping: ".implode(', ', $ignored_because_imported));
591
  }
592
-
593
  $backupable_entities = $updraftplus->get_backupable_file_entities(true);
594
 
595
  $database_backups_found = array();
@@ -627,10 +627,13 @@ class UpdraftPlus_Backup {
627
  // $backup_to_examine is an array of file names, keyed on db/plugins/themes/uploads
628
  // The new backup_history array is saved afterwards, so remember to unset the ones that are to be deleted
629
  $this->log_with_db_occasionally(sprintf("Examining (for databases) backup set with group_id=$group_id, nonce=%s, datestamp=%s (%s)", $nonce, $backup_datestamp, gmdate('M d Y H:i:s', $backup_datestamp)));
630
-
 
 
 
631
  // Auto-backups are only counted or deleted once we have reached the retain limit - before that, they are skipped
632
  $is_autobackup = !empty($backup_to_examine['autobackup']);
633
-
634
  $remote_sent = (!empty($backup_to_examine['service']) && ((is_array($backup_to_examine['service']) && in_array('remotesend', $backup_to_examine['service'])) || 'remotesend' === $backup_to_examine['service'])) ? true : false;
635
 
636
  $any_deleted_via_filter_yet = false;
@@ -647,6 +650,16 @@ class UpdraftPlus_Backup {
647
  continue;
648
  }
649
 
 
 
 
 
 
 
 
 
 
 
650
  if ($is_autobackup) {
651
  if ($any_deleted_via_filter_yet) {
652
  $this->log_with_db_occasionally("This backup set ($backup_datestamp) was an automatic backup, but we have previously deleted a backup due to a limit, so it will be pruned (but not counted towards numerical limits).");
@@ -761,6 +774,9 @@ class UpdraftPlus_Backup {
761
  // The new backup_history array is saved afterwards, so remember to unset the ones that are to be deleted
762
  $this->log_with_db_occasionally(sprintf("Examining (for files) backup set with nonce=%s, datestamp=%s (%s)", $nonce, $backup_datestamp, gmdate('M d Y H:i:s', $backup_datestamp)));
763
 
 
 
 
764
  // Auto-backups are only counted or deleted once we have reached the retain limit - before that, they are skipped
765
  $is_autobackup = !empty($backup_to_examine['autobackup']);
766
 
@@ -781,6 +797,16 @@ class UpdraftPlus_Backup {
781
  continue;
782
  }
783
 
 
 
 
 
 
 
 
 
 
 
784
  if ($is_autobackup) {
785
  if ($any_deleted_via_filter_yet) {
786
  $this->log_with_db_occasionally("This backup set was an automatic backup, but we have previously deleted a backup due to a limit, so it will be pruned (but not counted towards numerical limits).");
@@ -1436,7 +1462,7 @@ class UpdraftPlus_Backup {
1436
  // Now, store the results
1437
  if (!is_string($created) && !is_array($created)) $updraftplus->log("$youwhat: create_zip returned an error");
1438
  } else {
1439
- $updraftplus->log("No backup of $youwhat: there was nothing found to back up");
1440
  }
1441
  }
1442
 
@@ -1550,7 +1576,7 @@ class UpdraftPlus_Backup {
1550
 
1551
  if ('wp' == $this->whichdb) {
1552
  $this->wpdb_obj = $wpdb;
1553
- // The table prefix after being filtered - i.e. what filters what we'll actually back up
1554
  $this->table_prefix = $updraftplus->get_table_prefix(true);
1555
  // The unfiltered table prefix - i.e. the real prefix that things are relative to
1556
  $this->table_prefix_raw = $updraftplus->get_table_prefix(false);
182
  if (!function_exists('get_mu_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
183
  $mu_plugins = get_mu_plugins();
184
  if (count($mu_plugins) == 0) {
185
+ $updraftplus->log("There appear to be no mu-plugins to backup. Will not raise an error.");
186
  $flag_error = false;
187
  }
188
  }
362
 
363
  // We need to make sure that the loop below actually runs
364
  if (empty($services)) $services = array('none');
365
+
366
+ $storage_objects_and_ids = $updraftplus->get_enabled_storage_objects_and_ids($services);
367
 
368
  $total_instances_count = 0;
369
 
589
  if (!empty($ignored_because_imported)) {
590
  $updraftplus->log("These backup set(s) were imported from a remote location, so will not be counted or pruned. Skipping: ".implode(', ', $ignored_because_imported));
591
  }
592
+
593
  $backupable_entities = $updraftplus->get_backupable_file_entities(true);
594
 
595
  $database_backups_found = array();
627
  // $backup_to_examine is an array of file names, keyed on db/plugins/themes/uploads
628
  // The new backup_history array is saved afterwards, so remember to unset the ones that are to be deleted
629
  $this->log_with_db_occasionally(sprintf("Examining (for databases) backup set with group_id=$group_id, nonce=%s, datestamp=%s (%s)", $nonce, $backup_datestamp, gmdate('M d Y H:i:s', $backup_datestamp)));
630
+
631
+ // "Always Keep" Backups should be counted in the count of how many have been retained for purposes of the "how many to retain" count... but if that count is already matched, it's not a problem
632
+ $is_always_keep = !empty($backup_to_examine['always_keep']);
633
+
634
  // Auto-backups are only counted or deleted once we have reached the retain limit - before that, they are skipped
635
  $is_autobackup = !empty($backup_to_examine['autobackup']);
636
+
637
  $remote_sent = (!empty($backup_to_examine['service']) && ((is_array($backup_to_examine['service']) && in_array('remotesend', $backup_to_examine['service'])) || 'remotesend' === $backup_to_examine['service'])) ? true : false;
638
 
639
  $any_deleted_via_filter_yet = false;
650
  continue;
651
  }
652
 
653
+ if ($is_always_keep) {
654
+ if ($database_backups_found[$entity] < $updraft_retain) {
655
+ $this->log_with_db_occasionally("This backup set ($backup_datestamp) was an 'Always Keep' backup, and we have not yet reached any retain limits, so it should be counted in the count of how many have been retained for purposes of the 'how many to retain' count. It will not be pruned. Skipping.");
656
+ $database_backups_found[$key]++;
657
+ } else {
658
+ $this->log_with_db_occasionally("This backup set ($backup_datestamp) was an 'Always Keep' backup, so it will not be pruned. Skipping.");
659
+ }
660
+ continue;
661
+ }
662
+
663
  if ($is_autobackup) {
664
  if ($any_deleted_via_filter_yet) {
665
  $this->log_with_db_occasionally("This backup set ($backup_datestamp) was an automatic backup, but we have previously deleted a backup due to a limit, so it will be pruned (but not counted towards numerical limits).");
774
  // The new backup_history array is saved afterwards, so remember to unset the ones that are to be deleted
775
  $this->log_with_db_occasionally(sprintf("Examining (for files) backup set with nonce=%s, datestamp=%s (%s)", $nonce, $backup_datestamp, gmdate('M d Y H:i:s', $backup_datestamp)));
776
 
777
+ // "Always Keep" Backups should be counted in the count of how many have been retained for purposes of the "how many to retain" count... but if that count is already matched, it's not a problem
778
+ $is_always_keep = !empty($backup_to_examine['always_keep']);
779
+
780
  // Auto-backups are only counted or deleted once we have reached the retain limit - before that, they are skipped
781
  $is_autobackup = !empty($backup_to_examine['autobackup']);
782
 
797
  continue;
798
  }
799
 
800
+ if ($is_always_keep) {
801
+ if ($file_entities_backups_found[$entity] < $updraft_retain) {
802
+ $this->log_with_db_occasionally("This backup set ($backup_datestamp) was an 'Always Keep' backup, and we have not yet reached any retain limits, so it should be counted in the count of how many have been retained for purposes of the 'how many to retain' count. It will not be pruned. Skipping.");
803
+ $file_entities_backups_found[$entity]++;
804
+ } else {
805
+ $this->log_with_db_occasionally("This backup set ($backup_datestamp) was an 'Always Keep' backup, so it will not be pruned. Skipping.");
806
+ }
807
+ continue;
808
+ }
809
+
810
  if ($is_autobackup) {
811
  if ($any_deleted_via_filter_yet) {
812
  $this->log_with_db_occasionally("This backup set was an automatic backup, but we have previously deleted a backup due to a limit, so it will be pruned (but not counted towards numerical limits).");
1462
  // Now, store the results
1463
  if (!is_string($created) && !is_array($created)) $updraftplus->log("$youwhat: create_zip returned an error");
1464
  } else {
1465
+ $updraftplus->log("No backup of $youwhat: there was nothing found to backup");
1466
  }
1467
  }
1468
 
1576
 
1577
  if ('wp' == $this->whichdb) {
1578
  $this->wpdb_obj = $wpdb;
1579
+ // The table prefix after being filtered - i.e. what filters what we'll actually backup
1580
  $this->table_prefix = $updraftplus->get_table_prefix(true);
1581
  // The unfiltered table prefix - i.e. the real prefix that things are relative to
1582
  $this->table_prefix_raw = $updraftplus->get_table_prefix(false);
central/bootstrap.php CHANGED
@@ -30,6 +30,7 @@ class UpdraftPlus_UpdraftCentral_Main {
30
  'comments' => 'UpdraftCentral_Comments_Commands',
31
  'analytics' => 'UpdraftCentral_Analytics_Commands',
32
  'plugin' => 'UpdraftCentral_Plugin_Commands',
 
33
  'posts' => 'UpdraftCentral_Posts_Commands'
34
  ));
35
 
30
  'comments' => 'UpdraftCentral_Comments_Commands',
31
  'analytics' => 'UpdraftCentral_Analytics_Commands',
32
  'plugin' => 'UpdraftCentral_Plugin_Commands',
33
+ 'theme' => 'UpdraftCentral_Theme_Commands',
34
  'posts' => 'UpdraftCentral_Posts_Commands'
35
  ));
36
 
central/commands.php CHANGED
@@ -50,4 +50,27 @@ abstract class UpdraftCentral_Commands {
50
  'rpcerror'
51
  );
52
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  }
50
  'rpcerror'
51
  );
52
  }
53
+
54
+ /**
55
+ * Checks whether a backup and a security credentials is required for the given request
56
+ *
57
+ * @param array $dir The directory location to check
58
+ * @return array
59
+ */
60
+ final protected function _get_backup_credentials_settings($dir) {
61
+ // Do we need to ask the user for filesystem credentials? when installing and/or deleting items in the given directory
62
+ $filesystem_method = get_filesystem_method(array(), $dir);
63
+ ob_start();
64
+ $filesystem_credentials_are_stored = request_filesystem_credentials(site_url());
65
+ ob_end_clean();
66
+ $request_filesystem_credentials = ('direct' != $filesystem_method && !$filesystem_credentials_are_stored);
67
+
68
+ // Do we need to execute a backup process before installing/managing items
69
+ $automatic_backups = (class_exists('UpdraftPlus_Options') && class_exists('UpdraftPlus_Addon_Autobackup') && UpdraftPlus_Options::get_updraft_option('updraft_autobackup_default', true)) ? true : false;
70
+
71
+ return array(
72
+ 'request_filesystem_credentials' => $request_filesystem_credentials,
73
+ 'automatic_backups' => $automatic_backups
74
+ );
75
+ }
76
  }
central/modules/plugin.php CHANGED
@@ -8,11 +8,46 @@ if (!defined('UPDRAFTPLUS_DIR')) die('No access.');
8
  */
9
  class UpdraftCentral_Plugin_Commands extends UpdraftCentral_Commands {
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  /**
12
  * Constructor
13
  */
14
  public function __construct() {
15
- $this->_admin_include('plugin.php', 'file.php', 'template.php', 'class-wp-upgrader.php', 'plugin-install.php');
16
  }
17
 
18
  /**
@@ -24,13 +59,168 @@ class UpdraftCentral_Plugin_Commands extends UpdraftCentral_Commands {
24
  public function is_plugin_installed($query) {
25
 
26
  if (!isset($query['plugin']))
27
- return $this->_response(array('error' => true, 'message' => 'plugin_name_required', 'values' => array()));
28
 
29
 
30
- $result = $this->get_plugin_info($query['plugin']);
31
  return $this->_response($result);
32
  }
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  /**
35
  * Activates the plugin
36
  *
@@ -39,24 +229,35 @@ class UpdraftCentral_Plugin_Commands extends UpdraftCentral_Commands {
39
  */
40
  public function activate_plugin($query) {
41
 
42
- if (!isset($query['plugin']))
43
- return $this->_response(array('error' => true, 'message' => 'plugin_name_required', 'values' => array()));
 
 
44
 
45
- if (!current_user_can('activate_plugins'))
46
- return $this->_response(array('error' => true, 'message' => 'plugin_insufficient_permission', 'values' => array()));
 
 
47
 
 
 
48
 
49
- $info = $this->get_plugin_info($query['plugin']);
50
- if ($info['installed']) {
51
- $activate = activate_plugin($info['plugin_path']);
 
 
 
 
52
 
53
- if (is_wp_error($activate)) {
54
- $result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($activate->get_error_message()));
55
- } else {
56
- $result = array('activated' => true);
57
- }
58
- } else {
59
- $result = array('error' => true, 'message' => 'plugin_not_installed', 'values' => array($query['plugin']));
 
60
  }
61
 
62
  return $this->_response($result);
@@ -70,81 +271,109 @@ class UpdraftCentral_Plugin_Commands extends UpdraftCentral_Commands {
70
  */
71
  public function install_activate_plugin($query) {
72
 
73
- if (!isset($query['plugin']))
74
- return $this->_response(array('error' => true, 'message' => 'plugin_name_required', 'values' => array()));
 
 
75
 
76
- if (!isset($query['slug']))
77
- return $this->_response(array('error' => true, 'message' => 'plugin_slug_required', 'values' => array()));
78
 
79
- if (!current_user_can('install_plugins') || !current_user_can('activate_plugins'))
80
- return $this->_response(array('error' => true, 'message' => 'plugin_insufficient_permission', 'values' => array()));
 
 
 
 
 
 
 
81
 
 
 
82
 
83
- if (!empty($query) && isset($query['filesystem_credentials'])) {
84
- parse_str($query['filesystem_credentials'], $filesystem_credentials);
85
- if (is_array($filesystem_credentials)) {
86
- foreach ($filesystem_credentials as $key => $value) {
87
- // Put them into $_POST, which is where request_filesystem_credentials() checks for them.
88
- $_POST[$key] = $value;
89
- }
90
- }
 
 
 
91
  }
92
 
93
- $api = plugins_api('plugin_information', array(
94
- 'slug' => $query['slug'],
95
- 'fields' => array(
96
- 'short_description' => false,
97
- 'sections' => false,
98
- 'requires' => false,
99
- 'rating' => false,
100
- 'ratings' => false,
101
- 'downloaded' => false,
102
- 'last_updated' => false,
103
- 'added' => false,
104
- 'tags' => false,
105
- 'compatibility' => false,
106
- 'homepage' => false,
107
- 'donate_link' => false,
108
- )
109
- ));
110
-
111
- if (is_wp_error($api)) {
112
- $result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($api->get_error_message()));
113
- } else {
114
- $info = $this->get_plugin_info($query['plugin']);
115
- $installed = $info['installed'];
116
 
117
- if (!$installed) {
118
- // WP < 3.7
119
- if (!class_exists('Automatic_Upgrader_Skin')) include_once(UPDRAFTPLUS_DIR.'/central/classes/class-automatic-upgrader-skin.php');
 
120
 
121
- $skin = new Automatic_Upgrader_Skin();
122
- $upgrader = new Plugin_Upgrader($skin);
123
 
124
- $download_link = $api->download_link;
125
- $installed = $upgrader->install($download_link);
126
- }
127
 
128
- if (!$installed) {
129
- $result = array('error' => true, 'message' => 'plugin_install_failed', 'values' => array($query['plugin']));
130
  } else {
131
- // Here, we're pulling the information one more time to verify the installation and to
132
- // extract the plugin_path that will be used to activate the plugin in case it did not
133
- // get activated after the installation.
134
- $info = $this->get_plugin_info($query['plugin']);
 
135
 
136
- if (!$info['active']) {
137
- $activate = activate_plugin($info['plugin_path']);
138
 
139
- if (is_wp_error($activate)) {
140
- $result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($activate->get_error_message()));
141
- } else {
142
- $result = array('installed' => true);
143
- }
144
- } else {
145
- $result = array('installed' => true);
146
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  }
 
 
148
  }
149
 
150
  return $this->_response($result);
@@ -157,13 +386,17 @@ class UpdraftCentral_Plugin_Commands extends UpdraftCentral_Commands {
157
  * @param array $plugin The name of the plugin to pull the information from
158
  * @return array Contains the plugin information
159
  */
160
- private function get_plugin_info($plugin) {
161
 
162
  $info = array(
163
  'active' => false,
164
  'installed' => false
165
  );
166
 
 
 
 
 
167
  // Gets all plugins available.
168
  $get_plugins = get_plugins();
169
 
@@ -181,4 +414,86 @@ class UpdraftCentral_Plugin_Commands extends UpdraftCentral_Commands {
181
 
182
  return $info;
183
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  }
8
  */
9
  class UpdraftCentral_Plugin_Commands extends UpdraftCentral_Commands {
10
 
11
+ private $switched = false;
12
+
13
+ /**
14
+ * Function that gets called before every action
15
+ *
16
+ * @param string $command a string that corresponds to UDC command to call a certain method for this class.
17
+ * @param array $data an array of data post or get fields
18
+ * @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
19
+ *
20
+ * link to udrpc_action main function in class UpdraftPlus_UpdraftCentral_Listener
21
+ */
22
+ public function _pre_action($command, $data, $extra_info) {
23
+ // Here we assign the current blog_id to a variable $blog_id
24
+ $blog_id = get_current_blog_id();
25
+ if (!empty($data['site_id'])) $blog_id = $data['site_id'];
26
+
27
+ if (function_exists('switch_to_blog') && is_multisite() && $blog_id) {
28
+ $this->switched = switch_to_blog($blog_id);
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Function that gets called after every action
34
+ *
35
+ * @param string $command a string that corresponds to UDC command to call a certain method for this class.
36
+ * @param array $data an array of data post or get fields
37
+ * @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
38
+ *
39
+ * link to udrpc_action main function in class UpdraftPlus_UpdraftCentral_Listener
40
+ */
41
+ public function _post_action($command, $data, $extra_info) {
42
+ // Here, we're restoring to the current (default) blog before we switched
43
+ if ($this->switched) restore_current_blog();
44
+ }
45
+
46
  /**
47
  * Constructor
48
  */
49
  public function __construct() {
50
+ $this->_admin_include('plugin.php', 'file.php', 'template.php', 'class-wp-upgrader.php', 'plugin-install.php', 'update.php');
51
  }
52
 
53
  /**
59
  public function is_plugin_installed($query) {
60
 
61
  if (!isset($query['plugin']))
62
+ return $this->_generic_error_response('plugin_name_required');
63
 
64
 
65
+ $result = $this->_get_plugin_info($query['plugin']);
66
  return $this->_response($result);
67
  }
68
 
69
+ /**
70
+ * Applies currently requested action for plugin processing
71
+ *
72
+ * @param string $action The action to apply (e.g. activate or install)
73
+ * @param array $query Parameter array containing information for the currently requested action
74
+ *
75
+ * @return array
76
+ */
77
+ private function _apply_plugin_action($action, $query) {
78
+
79
+ $result = array();
80
+ switch ($action) {
81
+ case 'activate':
82
+ case 'network_activate':
83
+ $info = $this->_get_plugin_info($query['plugin']);
84
+ if ($info['installed']) {
85
+ if (is_multisite() && 'network_activate' === $action) {
86
+ $activate = activate_plugin($info['plugin_path'], '', true);
87
+ } else {
88
+ $activate = activate_plugin($info['plugin_path']);
89
+ }
90
+
91
+ if (is_wp_error($activate)) {
92
+ $result = $this->_generic_error_response('generic_response_error', array($activate->get_error_message()));
93
+ } else {
94
+ $result = array('activated' => true);
95
+ }
96
+ } else {
97
+ $result = $this->_generic_error_response('plugin_not_installed', array($query['plugin']));
98
+ }
99
+ break;
100
+ case 'deactivate':
101
+ case 'network_deactivate':
102
+ $info = $this->_get_plugin_info($query['plugin']);
103
+ if ($info['active']) {
104
+ if (is_multisite() && 'network_deactivate' === $action) {
105
+ deactivate_plugins($info['plugin_path'], false, true);
106
+ } else {
107
+ deactivate_plugins($info['plugin_path']);
108
+ }
109
+
110
+ if (!is_plugin_active($info['plugin_path'])) {
111
+ $result = array('deactivated' => true);
112
+ } else {
113
+ $result = $this->_generic_error_response('deactivate_plugin_failed', array($query['plugin']));
114
+ }
115
+ } else {
116
+ $result = $this->_generic_error_response('not_active', array($query['plugin']));
117
+ }
118
+ break;
119
+ case 'install':
120
+ $api = plugins_api('plugin_information', array(
121
+ 'slug' => $query['slug'],
122
+ 'fields' => array(
123
+ 'short_description' => false,
124
+ 'sections' => false,
125
+ 'requires' => false,
126
+ 'rating' => false,
127
+ 'ratings' => false,
128
+ 'downloaded' => false,
129
+ 'last_updated' => false,
130
+ 'added' => false,
131
+ 'tags' => false,
132
+ 'compatibility' => false,
133
+ 'homepage' => false,
134
+ 'donate_link' => false,
135
+ )
136
+ ));
137
+
138
+ if (is_wp_error($api)) {
139
+ $result = $this->_generic_error_response('generic_response_error', array($api->get_error_message()));
140
+ } else {
141
+ $info = $this->_get_plugin_info($query['plugin']);
142
+ $installed = $info['installed'];
143
+
144
+ if (!$installed) {
145
+ // WP < 3.7
146
+ if (!class_exists('Automatic_Upgrader_Skin')) include_once(UPDRAFTPLUS_DIR.'/central/classes/class-automatic-upgrader-skin.php');
147
+
148
+ $skin = new Automatic_Upgrader_Skin();
149
+ $upgrader = new Plugin_Upgrader($skin);
150
+
151
+ $download_link = $api->download_link;
152
+ $installed = $upgrader->install($download_link);
153
+ }
154
+
155
+ if (!$installed) {
156
+ $result = $this->_generic_error_response('plugin_install_failed', array($query['plugin']));
157
+ } else {
158
+ $result = array('installed' => true);
159
+ }
160
+ }
161
+ break;
162
+ }
163
+
164
+ return $result;
165
+ }
166
+
167
+ /**
168
+ * Preloads the submitted credentials to the global $_POST variable
169
+ *
170
+ * @param array $query Parameter array containing information for the currently requested action
171
+ */
172
+ private function _preload_credentials($query) {
173
+ if (!empty($query) && isset($query['filesystem_credentials'])) {
174
+ parse_str($query['filesystem_credentials'], $filesystem_credentials);
175
+ if (is_array($filesystem_credentials)) {
176
+ foreach ($filesystem_credentials as $key => $value) {
177
+ // Put them into $_POST, which is where request_filesystem_credentials() checks for them.
178
+ $_POST[$key] = $value;
179
+ }
180
+ }
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Checks whether we have the required fields submitted and the user has
186
+ * the capabilities to execute the requested action
187
+ *
188
+ * @param array $query The submitted information
189
+ * @param array $fields The required fields to check
190
+ * @param array $capabilities The capabilities to check and validate
191
+ *
192
+ * @return array|string
193
+ */
194
+ private function _validate_fields_and_capabilities($query, $fields, $capabilities) {
195
+
196
+ $error = '';
197
+ if (!empty($fields)) {
198
+ for ($i=0; $i<count($fields); $i++) {
199
+ $field = $fields[$i];
200
+
201
+ if (!isset($query[$field])) {
202
+ if ('keyword' === $field) {
203
+ $error = $this->_generic_error_response('keyword_required');
204
+ } else {
205
+ $error = $this->_generic_error_response('plugin_'.$query[$field].'_required');
206
+ }
207
+ break;
208
+ }
209
+ }
210
+ }
211
+
212
+ if (empty($error) && !empty($capabilities)) {
213
+ for ($i=0; $i<count($capabilities); $i++) {
214
+ if (!current_user_can($capabilities[$i])) {
215
+ $error = $this->_generic_error_response('plugin_insufficient_permission');
216
+ break;
217
+ }
218
+ }
219
+ }
220
+
221
+ return $error;
222
+ }
223
+
224
  /**
225
  * Activates the plugin
226
  *
229
  */
230
  public function activate_plugin($query) {
231
 
232
+ $error = $this->_validate_fields_and_capabilities($query, array('plugin'), array('activate_plugins'));
233
+ if (!empty($error)) {
234
+ return $error;
235
+ }
236
 
237
+ $result = $this->_apply_plugin_action('activate', $query);
238
+ if (empty($result['activated'])) {
239
+ return $result;
240
+ }
241
 
242
+ return $this->_response($result);
243
+ }
244
 
245
+ /**
246
+ * Deactivates the plugin
247
+ *
248
+ * @param array $query Parameter array containing the name of the plugin to deactivate
249
+ * @return array Contains the result of the current process
250
+ */
251
+ public function deactivate_plugin($query) {
252
 
253
+ $error = $this->_validate_fields_and_capabilities($query, array('plugin'), array('activate_plugins'));
254
+ if (!empty($error)) {
255
+ return $error;
256
+ }
257
+
258
+ $result = $this->_apply_plugin_action('deactivate', $query);
259
+ if (empty($result['deactivated'])) {
260
+ return $result;
261
  }
262
 
263
  return $this->_response($result);
271
  */
272
  public function install_activate_plugin($query) {
273
 
274
+ $error = $this->_validate_fields_and_capabilities($query, array('plugin', 'slug'), array('install_plugins', 'activate_plugins'));
275
+ if (!empty($error)) {
276
+ return $error;
277
+ }
278
 
279
+ $this->_preload_credentials($query);
 
280
 
281
+ $result = $this->_apply_plugin_action('install', $query);
282
+ if (!empty($result['installed']) && $result['installed']) {
283
+ $result = $this->_apply_plugin_action('activate', $query);
284
+ if (empty($result['activated'])) {
285
+ return $result;
286
+ }
287
+ } else {
288
+ return $result;
289
+ }
290
 
291
+ return $this->_response($result);
292
+ }
293
 
294
+ /**
295
+ * Download, install the plugin
296
+ *
297
+ * @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
298
+ * @return array Contains the result of the current process
299
+ */
300
+ public function install_plugin($query) {
301
+
302
+ $error = $this->_validate_fields_and_capabilities($query, array('plugin', 'slug'), array('install_plugins'));
303
+ if (!empty($error)) {
304
+ return $error;
305
  }
306
 
307
+ $this->_preload_credentials($query);
308
+
309
+ $result = $this->_apply_plugin_action('install', $query);
310
+ if (empty($result['installed'])) {
311
+ return $result;
312
+ }
313
+
314
+ return $this->_response($result);
315
+ }
316
+
317
+ /**
318
+ * Uninstall/delete the plugin
319
+ *
320
+ * @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
321
+ * @return array Contains the result of the current process
322
+ */
323
+ public function delete_plugin($query) {
 
 
 
 
 
 
324
 
325
+ $error = $this->_validate_fields_and_capabilities($query, array('plugin'), array('delete_plugins'));
326
+ if (!empty($error)) {
327
+ return $error;
328
+ }
329
 
330
+ $this->_preload_credentials($query);
331
+ $info = $this->_get_plugin_info($query['plugin']);
332
 
333
+ if ($info['installed']) {
334
+ $deleted = delete_plugins(array($info['plugin_path']));
 
335
 
336
+ if ($deleted) {
337
+ $result = array('deleted' => true);
338
  } else {
339
+ $result = $this->_generic_error_response('delete_plugin_failed', array($query['plugin']));
340
+ }
341
+ } else {
342
+ $result = $this->_generic_error_response('plugin_not_installed', array($query['plugin']));
343
+ }
344
 
345
+ return $this->_response($result);
346
+ }
347
 
348
+ /**
349
+ * Updates/upgrade the plugin
350
+ *
351
+ * @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
352
+ * @return array Contains the result of the current process
353
+ */
354
+ public function update_plugin($query) {
355
+
356
+ $error = $this->_validate_fields_and_capabilities($query, array('plugin', 'slug'), array('update_plugins'));
357
+ if (!empty($error)) {
358
+ return $error;
359
+ }
360
+
361
+ $this->_preload_credentials($query);
362
+ $info = $this->_get_plugin_info($query['plugin']);
363
+
364
+ // Make sure that we still have the plugin installed before running
365
+ // the update process
366
+ if ($info['installed']) {
367
+ // Load the updates command class if not existed
368
+ if (!class_exists('UpdraftCentral_Updates_Commands')) include_once('updates.php');
369
+ $update_command = new UpdraftCentral_Updates_Commands($this->rc);
370
+
371
+ $result = $update_command->update_plugin($info['plugin_path'], $query['slug']);
372
+ if (!empty($result['error'])) {
373
+ $result['values'] = array($query['plugin']);
374
  }
375
+ } else {
376
+ $result = $this->_generic_error_response('plugin_not_installed', array($query['plugin']));
377
  }
378
 
379
  return $this->_response($result);
386
  * @param array $plugin The name of the plugin to pull the information from
387
  * @return array Contains the plugin information
388
  */
389
+ private function _get_plugin_info($plugin) {
390
 
391
  $info = array(
392
  'active' => false,
393
  'installed' => false
394
  );
395
 
396
+ // Clear plugin cache so that newly installed/downloaded plugins
397
+ // gets reflected when calling "get_plugins"
398
+ wp_clean_plugins_cache();
399
+
400
  // Gets all plugins available.
401
  $get_plugins = get_plugins();
402
 
414
 
415
  return $info;
416
  }
417
+
418
+ /**
419
+ * Loads all available plugins with additional attributes and settings needed by UpdraftCentral
420
+ *
421
+ * @param array $query Parameter array Any available parameters needed for this action
422
+ * @return array Contains the result of the current process
423
+ */
424
+ public function load_plugins($query) {
425
+
426
+ $error = $this->_validate_fields_and_capabilities($query, array(), array('install_plugins', 'activate_plugins'));
427
+ if (!empty($error)) {
428
+ return $error;
429
+ }
430
+
431
+ $website = get_bloginfo('name');
432
+ $results = array();
433
+
434
+ // Load the updates command class if not existed
435
+ if (!class_exists('UpdraftCentral_Updates_Commands')) include_once('updates.php');
436
+ $updates = new UpdraftCentral_Updates_Commands($this->rc);
437
+
438
+ // Get plugins for update
439
+ $plugin_updates = $updates->get_item_updates('plugins');
440
+
441
+ // Get all plugins
442
+ $plugins = get_plugins();
443
+
444
+ foreach ($plugins as $key => $value) {
445
+ $slug = basename($key, '.php');
446
+
447
+ $plugin = new stdClass();
448
+ $plugin->name = $value['Name'];
449
+ $plugin->description = $value['Description'];
450
+ $plugin->slug = $slug;
451
+ $plugin->version = $value['Version'];
452
+ $plugin->author = $value['Author'];
453
+ $plugin->status = is_plugin_active($key) ? 'active' : 'inactive';
454
+ $plugin->website = $website;
455
+
456
+ if (!empty($plugin_updates[$key])) {
457
+ $update_info = $plugin_updates[$key];
458
+
459
+ if (version_compare($update_info->Version, $update_info->update->new_version, '<')) {
460
+ if (!empty($update_info->update->new_version)) $plugin->latest_version = $update_info->update->new_version;
461
+ if (!empty($update_info->update->package)) $plugin->download_link = $update_info->update->package;
462
+ if (!empty($update_info->update->sections)) $plugin->sections = $update_info->update->sections;
463
+ }
464
+ }
465
+
466
+ if (empty($plugin->short_description) && !empty($plugin->description)) {
467
+ // Only pull the first sentence as short description, it should be enough rather than displaying
468
+ // an empty description or a full blown one which the user can access anytime if they press on
469
+ // the view details link in UpdraftCentral.
470
+ $temp = explode('.', $plugin->description);
471
+ $short_description = $temp[0];
472
+
473
+ // Adding the second sentence wouldn't hurt, in case the first sentence is too short.
474
+ if (isset($temp[1])) $short_description .= '.'.$temp[1];
475
+
476
+ $plugin->short_description = $short_description.'.';
477
+ }
478
+
479
+ $results[] = $plugin;
480
+ }
481
+
482
+ $result = array(
483
+ 'plugins' => $results
484
+ );
485
+
486
+ $result = array_merge($result, $this->_get_backup_credentials_settings(WP_PLUGIN_DIR));
487
+ return $this->_response($result);
488
+ }
489
+
490
+ /**
491
+ * Gets the backup and security credentials settings for this website
492
+ *
493
+ * @param array $query Parameter array Any available parameters needed for this action
494
+ * @return array Contains the result of the current process
495
+ */
496
+ public function get_plugin_requirements() {
497
+ return $this->_response($this->_get_backup_credentials_settings(WP_PLUGIN_DIR));
498
+ }
499
  }
central/modules/posts.php CHANGED
@@ -55,29 +55,51 @@ class UpdraftCentral_Posts_Commands extends UpdraftCentral_Commands {
55
  */
56
  public function get_requested_posts($params) {
57
 
 
 
58
  // check paged parameter; if empty set to 1
59
- $paged = get_query_var('paged') ? get_query_var('paged') : 1;
60
-
 
 
 
 
 
 
 
 
 
 
 
61
 
62
  // Using default function get_posts to fetch all posts object from passed parameters
63
  // Count all fetch posts objects
64
  // get total fetch posts and divide to number of posts for pagination
65
- $query = new WP_Query($params);
66
  $result = $query->posts;
67
 
68
- $count_posts = wp_count_posts();
69
  $page_count = 0;
70
  $postdata = array();
71
 
72
- if ($count_posts->publish > 0) {
73
- if (empty($params['numberposts'])) return $this->_generic_error_response('numberposts_parameter_missing', $params);
74
- $page_count = absint($count_posts->publish / $params['numberposts']);
 
 
75
  }
76
 
 
 
 
 
 
 
77
  if (empty($result)) {
78
  $error_data = array(
79
  'count' => $page_count,
80
- 'paged' => $paged
 
81
  );
82
  return $this->_generic_error_response('post_not_found_with_keyword', $error_data);
83
  } else {
@@ -101,27 +123,22 @@ class UpdraftCentral_Posts_Commands extends UpdraftCentral_Commands {
101
  $data->category_name = $cat_array;
102
  $data->post_title = $post->post_title;
103
  $data->post_status = $post->post_status;
 
104
  $postdata[] = $data;
105
  }
106
 
107
- $cat_id = $params['category'][0];
108
- if (0 != $cat_id) {
109
- $count_category_posts = get_category($cat_id);
110
- if (empty($params['numberposts'])) return $this->_generic_error_response('numberposts_parameter_missing', $params);
111
- $page_count = absint($count_category_posts->category_count / $params['numberposts']);
112
- }
113
-
114
  $response = array(
115
  'posts' => $postdata,
116
  'count' => $page_count,
117
  'paged' => $paged,
118
  'categories' => $this->get_requested_categories(array('parent' => 0, 'return_object' => true)),
119
- 'message' => "found_posts_count"
 
 
120
  );
121
  }
122
 
123
  return $this->_response($response);
124
-
125
  }
126
 
127
  /**
@@ -297,7 +314,7 @@ class UpdraftCentral_Posts_Commands extends UpdraftCentral_Commands {
297
  // Check if result is false
298
  if (is_wp_error($post_id)) {
299
  $error_data = array(
300
- 'message' => 'Error inserting post',
301
  );
302
 
303
  return $this->_generic_error_response('post_insert_error', $error_data);
@@ -359,7 +376,7 @@ class UpdraftCentral_Posts_Commands extends UpdraftCentral_Commands {
359
  // Check if response is false
360
  if (is_wp_error($response)) {
361
  $error_data = array(
362
- 'message' => 'Error updating post',
363
  );
364
 
365
  return $this->_generic_error_response('post_update_error', $error_data);
@@ -418,7 +435,7 @@ class UpdraftCentral_Posts_Commands extends UpdraftCentral_Commands {
418
  // Check if response if false
419
  if (is_wp_error($response)) {
420
  $error_data = array(
421
- 'message' => 'Error deleting post'
422
  );
423
  return $this->_generic_error_response('post_delete_error', $error_data);
424
  }
@@ -481,7 +498,7 @@ class UpdraftCentral_Posts_Commands extends UpdraftCentral_Commands {
481
 
482
  if (is_wp_error($response)) {
483
  $error_data = array(
484
- 'message' => 'Error inserting category'
485
  );
486
  return $this->_generic_error_response('category_insert_error', $error_data);
487
  }
@@ -539,7 +556,7 @@ class UpdraftCentral_Posts_Commands extends UpdraftCentral_Commands {
539
  // Check if response is false
540
  if (is_wp_error($response)) {
541
  $error_data = array(
542
- 'message' => 'Error updating category'
543
  );
544
  return $this->_generic_error_response('category_update_error', $error_data);
545
  }
@@ -587,7 +604,7 @@ class UpdraftCentral_Posts_Commands extends UpdraftCentral_Commands {
587
 
588
  if (is_wp_error($response)) {
589
  $error_data = array(
590
- 'message' => 'Error deleting category'
591
  );
592
  return $this->_generic_error_response('user_no_permission_to_delete_category', $error_data);
593
  }
@@ -612,19 +629,40 @@ class UpdraftCentral_Posts_Commands extends UpdraftCentral_Commands {
612
  */
613
  public function find_post_by_title($params) {
614
 
 
 
615
  // Check if keyword is empty or null
616
  if (empty($params['s'])) {
617
  return $this->_generic_error_response('search_generated_no_result', array());
618
  }
619
 
620
  // Set an array with post_type to search only post
621
- $query_string = array('s' => $params['s'], 'post_type' => 'post');
 
 
 
 
 
622
  $query = new WP_Query($query_string);
623
- $published_posts = absint($query->post_count / 10);
624
  $postdata = array();
625
 
626
- $response = array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
627
 
 
628
  if ($query->have_posts()) {
629
 
630
  foreach ($query->posts as $post) {
@@ -655,14 +693,16 @@ class UpdraftCentral_Posts_Commands extends UpdraftCentral_Commands {
655
  'categories' => $this->get_requested_categories(array('parent' => 0, 'return_object' => true)),
656
  'posts' => $postdata,
657
  'n' => $arr,
658
- 'count' => $published_posts,
659
- 'paged' => 1,
660
- 'message' => "found_post"
 
661
  );
662
  } else {
663
  $error_data = array(
664
- 'count' => $published_posts,
665
- 'paged' => 1
 
666
  );
667
  return $this->_generic_error_response('post_not_found_with_keyword', $error_data);
668
  }
55
  */
56
  public function get_requested_posts($params) {
57
 
58
+ if (empty($params['numberposts'])) return $this->_generic_error_response('numberposts_parameter_missing', $params);
59
+
60
  // check paged parameter; if empty set to 1
61
+ $paged = !empty($params['paged']) ? (int) $params['paged'] : 1;
62
+
63
+ $args = array(
64
+ 'posts_per_page' => $params['numberposts'],
65
+ 'paged' => $paged,
66
+ 'post_type' => 'post',
67
+ 'post_status' => !empty($params['post_status']) ? $params['post_status'] : 'any'
68
+ );
69
+
70
+ if (!empty($params['category'][0])) {
71
+ $term_id = (int) $params['category'][0];
72
+ $args['category__in'] = array($term_id);
73
+ }
74
 
75
  // Using default function get_posts to fetch all posts object from passed parameters
76
  // Count all fetch posts objects
77
  // get total fetch posts and divide to number of posts for pagination
78
+ $query = new WP_Query($args);
79
  $result = $query->posts;
80
 
81
+ $count_posts = $query->found_posts;
82
  $page_count = 0;
83
  $postdata = array();
84
 
85
+ if ((int) $count_posts > 0) {
86
+ $page_count = absint((int) $count_posts / (int) $params['numberposts']);
87
+ $remainder = absint((int) $count_posts % (int) $params['numberposts']);
88
+
89
+ $page_count = ($remainder > 0) ? ++$page_count : $page_count;
90
  }
91
 
92
+ $info = array(
93
+ 'page' => $paged,
94
+ 'pages' => $page_count,
95
+ 'results' => $count_posts
96
+ );
97
+
98
  if (empty($result)) {
99
  $error_data = array(
100
  'count' => $page_count,
101
+ 'paged' => $paged,
102
+ 'info' => $info
103
  );
104
  return $this->_generic_error_response('post_not_found_with_keyword', $error_data);
105
  } else {
123
  $data->category_name = $cat_array;
124
  $data->post_title = $post->post_title;
125
  $data->post_status = $post->post_status;
126
+ $data->ID = $post->ID;
127
  $postdata[] = $data;
128
  }
129
 
 
 
 
 
 
 
 
130
  $response = array(
131
  'posts' => $postdata,
132
  'count' => $page_count,
133
  'paged' => $paged,
134
  'categories' => $this->get_requested_categories(array('parent' => 0, 'return_object' => true)),
135
+ 'message' => "found_posts_count",
136
+ 'params' => $params,
137
+ 'info' => $info
138
  );
139
  }
140
 
141
  return $this->_response($response);
 
142
  }
143
 
144
  /**
314
  // Check if result is false
315
  if (is_wp_error($post_id)) {
316
  $error_data = array(
317
+ 'message' => __('Error inserting post')
318
  );
319
 
320
  return $this->_generic_error_response('post_insert_error', $error_data);
376
  // Check if response is false
377
  if (is_wp_error($response)) {
378
  $error_data = array(
379
+ 'message' => __('Error updating post')
380
  );
381
 
382
  return $this->_generic_error_response('post_update_error', $error_data);
435
  // Check if response if false
436
  if (is_wp_error($response)) {
437
  $error_data = array(
438
+ 'message' => __('Error deleting post')
439
  );
440
  return $this->_generic_error_response('post_delete_error', $error_data);
441
  }
498
 
499
  if (is_wp_error($response)) {
500
  $error_data = array(
501
+ 'message' => __('Error inserting category')
502
  );
503
  return $this->_generic_error_response('category_insert_error', $error_data);
504
  }
556
  // Check if response is false
557
  if (is_wp_error($response)) {
558
  $error_data = array(
559
+ 'message' => __('Error updating category')
560
  );
561
  return $this->_generic_error_response('category_update_error', $error_data);
562
  }
604
 
605
  if (is_wp_error($response)) {
606
  $error_data = array(
607
+ 'message' => __('Error deleting category')
608
  );
609
  return $this->_generic_error_response('user_no_permission_to_delete_category', $error_data);
610
  }
629
  */
630
  public function find_post_by_title($params) {
631
 
632
+ $paged = !empty($params['paged']) ? (int) $params['paged'] : 1;
633
+
634
  // Check if keyword is empty or null
635
  if (empty($params['s'])) {
636
  return $this->_generic_error_response('search_generated_no_result', array());
637
  }
638
 
639
  // Set an array with post_type to search only post
640
+ $query_string = array(
641
+ 's' => $params['s'],
642
+ 'post_type' => 'post',
643
+ 'posts_per_page' => $params['numberposts'],
644
+ 'paged' => $paged
645
+ );
646
  $query = new WP_Query($query_string);
 
647
  $postdata = array();
648
 
649
+ $count_posts = $query->found_posts;
650
+ if ((int) $count_posts > 0) {
651
+ if (empty($params['numberposts'])) return $this->_generic_error_response('numberposts_parameter_missing', $params);
652
+
653
+ $page_count = absint((int) $count_posts / (int) $params['numberposts']);
654
+ $remainder = absint((int) $count_posts % (int) $params['numberposts']);
655
+
656
+ $page_count = ($remainder > 0) ? ++$page_count : $page_count;
657
+ }
658
+
659
+ $info = array(
660
+ 'page' => $paged,
661
+ 'pages' => $page_count,
662
+ 'results' => $count_posts
663
+ );
664
 
665
+ $response = array();
666
  if ($query->have_posts()) {
667
 
668
  foreach ($query->posts as $post) {
693
  'categories' => $this->get_requested_categories(array('parent' => 0, 'return_object' => true)),
694
  'posts' => $postdata,
695
  'n' => $arr,
696
+ 'count' => $count_posts,
697
+ 'paged' => $paged,
698
+ 'message' => "found_post",
699
+ 'info' => $info
700
  );
701
  } else {
702
  $error_data = array(
703
+ 'count' => $count_posts,
704
+ 'paged' => $paged,
705
+ 'info' => $info
706
  );
707
  return $this->_generic_error_response('post_not_found_with_keyword', $error_data);
708
  }
central/modules/theme.php ADDED
@@ -0,0 +1,503 @@