.htaccess
1 year ago
Abilities.php
1 day ago
Blog.php
1 year ago
Helper.php
5 months ago
Init.php
5 months ago
Installer.php
7 months ago
MySQL.php
1 year ago
UI.php
4 months ago
Update.php
1 year ago
Wordpress.php
1 day ago
index.html
1 year ago
web.config
1 year ago
UI.php
236 lines
| 1 | <?php |
| 2 | |
| 3 | namespace JetBackup\Wordpress; |
| 4 | |
| 5 | use JetBackup\Alert\Alert; |
| 6 | use JetBackup\Config\System; |
| 7 | use JetBackup\Factory; |
| 8 | use JetBackup\JetBackup; |
| 9 | use JetBackup\MFA\GoogleAuthenticator; |
| 10 | use SleekDB\Exceptions\InvalidArgumentException; |
| 11 | use SleekDB\Exceptions\IOException; |
| 12 | |
| 13 | if (!defined( '__JETBACKUP__')) die('Direct access is not allowed'); |
| 14 | |
| 15 | class UI { |
| 16 | |
| 17 | const PUBLIC_PATH = 'public'; |
| 18 | const PUBLIC_LIBRARIES = self::PUBLIC_PATH . '/libraries'; |
| 19 | const PUBLIC_CSS = self::PUBLIC_PATH . '/css'; |
| 20 | const PUBLIC_IMAGES = self::PUBLIC_PATH . '/images'; |
| 21 | const PUBLIC_JS = self::PUBLIC_PATH . '/js'; |
| 22 | |
| 23 | const PAGES = [ |
| 24 | [ 'menu_title' => 'Backups', 'page_title' => 'Restore Entire Site Backups', 'slug' => 'backups' ], |
| 25 | [ 'menu_title' => 'Backup Jobs', 'page_title' => 'Backup Jobs', 'slug' => 'jobs' ], |
| 26 | [ 'menu_title' => 'Destinations', 'page_title' => 'Destinations', 'slug' => 'destinations' ], |
| 27 | [ 'menu_title' => 'Schedules', 'page_title' => 'Schedules', 'slug' => 'schedules' ], |
| 28 | [ 'menu_title' => 'Queue', 'page_title' => 'Queue', 'slug' => 'queue' ], |
| 29 | [ 'menu_title' => 'Downloads', 'page_title' => 'Downloads', 'slug' => 'downloads' ], |
| 30 | [ 'menu_title' => 'Alerts', 'page_title' => 'Alerts', 'slug' => 'alerts' ], |
| 31 | [ 'menu_title' => 'Settings', 'page_title' => 'Settings', 'slug' => 'settings/general' ], |
| 32 | [ 'menu_title' => 'System Info', 'page_title' => 'System Info', 'slug' => 'system' ], |
| 33 | ]; |
| 34 | |
| 35 | /** |
| 36 | * @throws IOException |
| 37 | * @throws \JetBackup\Exception\IOException |
| 38 | * @throws InvalidArgumentException |
| 39 | */ |
| 40 | public static function main() { |
| 41 | |
| 42 | $site_url = self::getPluginPath() . '/'; |
| 43 | wp_enqueue_script('jetbackup-lib-main-js', $site_url . self::PUBLIC_LIBRARIES . '/main.js'); |
| 44 | $eddie_icon = $site_url . '/' . self::PUBLIC_IMAGES . '/eddie-menu.svg'; |
| 45 | |
| 46 | $hook = add_menu_page('JetBackup', __('JetBackup','jetbackup'), 'manage_options', 'jetbackup', [ '\JetBackup\Wordpress\UI', 'loadUI'], $eddie_icon, 74); |
| 47 | add_action('admin_print_scripts-' . $hook, [ '\JetBackup\Wordpress\UI', 'enqueueCSS' ]); |
| 48 | add_action('admin_print_scripts-' . $hook, [ '\JetBackup\Wordpress\UI', 'removeAdminNotices']); |
| 49 | |
| 50 | foreach (self::PAGES as $position => $page) { |
| 51 | |
| 52 | if($page['menu_title'] == 'System Info' && System::getTotalAlerts() > 1) { |
| 53 | $page['menu_title'] = __('System Info','jetbackup').'<span class="update-plugins count-2"><span class="plugin-count">'.System::getTotalAlerts().'</span></span>'; |
| 54 | } |
| 55 | |
| 56 | if($page['menu_title'] == 'Alerts' && Alert::getTotalCriticalAlerts() > 1) { |
| 57 | $page['menu_title'] = __('Alerts','jetbackup'). '<span class="update-plugins count-2"><span class="plugin-count">'.Alert::getTotalCriticalAlerts().'</span></span>'; |
| 58 | } |
| 59 | |
| 60 | $hook = add_submenu_page('jetbackup', $page['page_title'], __($page['menu_title'],'jetbackup'), 'manage_options', 'jetbackup#!/' . $page['slug'], function() {}, $position+1); |
| 61 | add_action('admin_print_scripts-' . $hook, [ '\JetBackup\Wordpress\UI', 'removeAdminNotices']); |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | public static function enqueueCSS() { |
| 66 | |
| 67 | $base_url = self::getPluginPath() . '/'; |
| 68 | $css_url = $base_url . self::PUBLIC_CSS . '/'; |
| 69 | $lib_url = $base_url . self::PUBLIC_LIBRARIES . '/'; |
| 70 | |
| 71 | // do not use @import in main.css (wordpress.com compatability) |
| 72 | wp_enqueue_style('jetbackup-common', $css_url . 'common.css'); |
| 73 | wp_enqueue_style('jetbackup-checkbox', $css_url . 'checkbox.min.css', ['jetbackup-common']); |
| 74 | wp_enqueue_style('jetbackup-loading-bar', $lib_url . 'angular-loading-bar/loading-bar.css', ['jetbackup-checkbox']); |
| 75 | wp_enqueue_style('jetbackup-moment-picker', $lib_url . 'angular-moment-picker/angular-moment-picker.min.css', ['jetbackup-loading-bar']); |
| 76 | wp_enqueue_style('jetbackup-bootstrap', $lib_url . 'bootstrap/css/bootstrap.min.css', ['jetbackup-moment-picker']); |
| 77 | wp_enqueue_style('jetbackup-fontawesome', $lib_url . 'fontawesome/css/all.min.css', ['jetbackup-bootstrap']); |
| 78 | wp_enqueue_style('jetbackup-style', $css_url . 'style.css', ['jetbackup-fontawesome']); |
| 79 | wp_enqueue_style('jetbackup-media', $css_url . 'media.css', ['jetbackup-style']); |
| 80 | } |
| 81 | |
| 82 | |
| 83 | /** |
| 84 | * @param $links |
| 85 | * |
| 86 | * @return array |
| 87 | */ |
| 88 | public static function addActionLinks($links): array { |
| 89 | $custom_links = [ |
| 90 | '<a href="' . admin_url('admin.php?page=jetbackup') . '">' . __('Dashboard', 'jetbackup') . '</a>', |
| 91 | '<a href="' . admin_url('admin.php?page=jetbackup#!/settings/general') . '">' . __('Settings', 'jetbackup') . '</a>', |
| 92 | ]; |
| 93 | return array_merge($custom_links, $links); |
| 94 | } |
| 95 | |
| 96 | /** |
| 97 | * @param $links |
| 98 | * @param $file |
| 99 | * |
| 100 | * @return array |
| 101 | */ |
| 102 | public static function addRowMeta($links, $file) : array { |
| 103 | if ($file != 'backup/backup.php') return $links; |
| 104 | $custom_links = [ |
| 105 | '<a href="https://docs.jetbackup.com/wordpress/jbwp" target="_blank">' . __('Documentation', 'jetbackup') . '</a>', |
| 106 | '<a href="https://www.jetbackup.com/contact" target="_blank">' . __('Support', 'jetbackup') . '</a>', |
| 107 | '<a href="https://wordpress.org/support/plugin/backup/reviews/?filter=5#new-post" target="_blank">' . __('Rate � |
| 108 | � |
| 109 | � |
| 110 | � |
| 111 | � |
| 112 | ', 'jetbackup') . '</a>', |
| 113 | ]; |
| 114 | return array_merge($links, $custom_links); |
| 115 | } |
| 116 | |
| 117 | /** |
| 118 | * @param $admin_bar |
| 119 | * |
| 120 | * @return void |
| 121 | */ |
| 122 | public static function addTopMenuBarIntegration($admin_bar) : void { |
| 123 | if (!Factory::getSettingsGeneral()->isAdminTopMenuIntegrationEnabled()) return; |
| 124 | if (!current_user_can('manage_options')) return; |
| 125 | |
| 126 | $admin_bar->add_menu(array( |
| 127 | 'id' => 'jetbackup', |
| 128 | 'title' => '<img src="' . esc_url(UI::getPluginPath() . '/public/images/logo-loader.png' ) . '" alt="JetBackup" style="height: 15px; vertical-align: middle;" />', |
| 129 | 'href' => admin_url('admin.php?page=jetbackup'), |
| 130 | 'meta' => array( |
| 131 | 'title' => __('JetBackup'), |
| 132 | ), |
| 133 | )); |
| 134 | } |
| 135 | |
| 136 | public static function convertPhpToMomentFormat($phpFormat) : string { |
| 137 | $replacements = [ |
| 138 | 'F' => 'MMMM', // Full month name |
| 139 | 'j' => 'D', // Day without leading zero |
| 140 | 'S' => 'o', // Day with ordinal suffix (6th, 7th) |
| 141 | 'd' => 'DD', // Day with leading zero |
| 142 | 'm' => 'MM', // Month with leading zero |
| 143 | 'n' => 'M', // Month without leading zero |
| 144 | 'Y' => 'YYYY', // Full year |
| 145 | 'y' => 'YY', // 2-digit year |
| 146 | 'H' => 'HH', // 24-hour with leading zero |
| 147 | 'G' => 'H', // 24-hour format without leading zero |
| 148 | 'h' => 'hh', // 12-hour with leading zero |
| 149 | 'g' => 'h', // 12-hour without leading zero |
| 150 | 'i' => 'mm', // Minutes |
| 151 | 's' => 'ss', // Seconds |
| 152 | 'A' => 'A', // Uppercase AM/PM |
| 153 | 'a' => 'a', // Lowercase am/pm |
| 154 | 'l' => 'dddd', // Full day of the week |
| 155 | 'D' => 'ddd', // Abbreviated day of the week |
| 156 | ]; |
| 157 | |
| 158 | $format = ''; |
| 159 | |
| 160 | for($i = 0; $i < strlen($phpFormat); $i++) { |
| 161 | if($phpFormat[$i] == '\\') { |
| 162 | $i++; |
| 163 | if(!isset($phpFormat[$i])) break; |
| 164 | $format .= '[' . $phpFormat[$i] . ']'; |
| 165 | } else { |
| 166 | $format .= $replacements[$phpFormat[$i]] ?? $phpFormat[$i]; |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | return $format; |
| 171 | } |
| 172 | |
| 173 | |
| 174 | public static function loadUI() { |
| 175 | |
| 176 | $dateFormat = self::convertPhpToMomentFormat(Wordpress::getDateFormat()); |
| 177 | $timeFormat = self::convertPhpToMomentFormat(Wordpress::getTimeFormat()); |
| 178 | |
| 179 | $lang = Wordpress::getLocale(); |
| 180 | $version = JetBackup::VERSION; |
| 181 | $public_path = self::getPluginPath() . '/' . self::PUBLIC_PATH; |
| 182 | $nonce = Wordpress::createNonce(); |
| 183 | |
| 184 | echo <<<HTML |
| 185 | <div ng-include="'$public_path/views/main.htm?v=$version'" ng-controller="JetBackup" id="JetBackup"></div> |
| 186 | <script type="text/javascript"> |
| 187 | new JetBackup({ |
| 188 | nonce: '$nonce', |
| 189 | language: '$lang', |
| 190 | dateFormat: '$dateFormat', |
| 191 | timeFormat: '$timeFormat', |
| 192 | plugin_path: '$public_path' |
| 193 | }); |
| 194 | </script> |
| 195 | HTML; |
| 196 | } |
| 197 | |
| 198 | public static function removeAdminNotices() { |
| 199 | remove_all_actions('admin_notices'); |
| 200 | remove_all_actions('all_admin_notices'); |
| 201 | remove_all_actions('network_admin_notices'); |
| 202 | } |
| 203 | |
| 204 | public static function getPluginPath(): string { |
| 205 | if (function_exists('plugins_url')) return plugins_url(JetBackup::PLUGIN_NAME); |
| 206 | return Wordpress::getSiteURL() . '/' . Wordpress::WP_CONTENT . '/' . Wordpress::WP_PLUGINS . '/' . JetBackup::PLUGIN_NAME; |
| 207 | } |
| 208 | |
| 209 | public static function validateMFA(): bool { |
| 210 | return isset($_COOKIE[GoogleAuthenticator::MFA_COOKIE_KEY]) && |
| 211 | hash_equals(Wordpress::getUnslash($_COOKIE[GoogleAuthenticator::MFA_COOKIE_KEY]), GoogleAuthenticator::getCookieHash()); |
| 212 | } |
| 213 | |
| 214 | public static function heartbeat() { |
| 215 | $ttl = Factory::getSettingsAutomation()->getHeartbeatTTL(); |
| 216 | $nonce = Wordpress::createNonce(); |
| 217 | |
| 218 | echo <<<HTML |
| 219 | <script type="text/javascript"> |
| 220 | var nonce = '$nonce'; |
| 221 | setInterval(function () { |
| 222 | const request = new XMLHttpRequest(); |
| 223 | request.open('POST', ajaxurl, true); |
| 224 | request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); |
| 225 | request.onreadystatechange = () => { |
| 226 | if (request.readyState !== XMLHttpRequest.DONE || request.status !== 200) return; |
| 227 | const data = JSON.parse(request.responseText); |
| 228 | if(nonce !== data.system.nonce) nonce = data.system.nonce; |
| 229 | }; |
| 230 | request.send('action=jetbackup_heartbeat&nonce=' + nonce); |
| 231 | }, $ttl) |
| 232 | </script> |
| 233 | HTML; |
| 234 | } |
| 235 | } |
| 236 |