├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── CONTRIBUTING.md ├── Gruntfile.js ├── LICENSE.txt ├── README.md ├── assets ├── css │ ├── revisr-admin.css │ └── thickbox.css ├── img │ ├── loader.gif │ └── site5.png ├── index.php ├── js │ ├── revisr-dashboard.js │ ├── revisr-settings.js │ ├── revisr-setup.js │ └── revisr-staging.js └── lib │ ├── octicons │ ├── LICENSE.txt │ ├── README.md │ ├── octicons-local.ttf │ ├── octicons.css │ ├── octicons.eot │ ├── octicons.less │ ├── octicons.svg │ ├── octicons.ttf │ ├── octicons.woff │ └── sprockets-octicons.scss │ └── select2 │ ├── css │ ├── select2.css │ └── select2.min.css │ └── js │ ├── i18n │ ├── az.js │ ├── bg.js │ ├── ca.js │ ├── cs.js │ ├── da.js │ ├── de.js │ ├── en.js │ ├── es.js │ ├── et.js │ ├── eu.js │ ├── fa.js │ ├── fi.js │ ├── fr.js │ ├── gl.js │ ├── he.js │ ├── hi.js │ ├── hr.js │ ├── hu.js │ ├── id.js │ ├── is.js │ ├── it.js │ ├── ko.js │ ├── lt.js │ ├── lv.js │ ├── mk.js │ ├── nb.js │ ├── nl.js │ ├── pl.js │ ├── pt-BR.js │ ├── pt.js │ ├── ro.js │ ├── ru.js │ ├── sk.js │ ├── sr.js │ ├── sv.js │ ├── th.js │ ├── tr.js │ ├── uk.js │ ├── vi.js │ ├── zh-CN.js │ └── zh-TW.js │ ├── select2.full.js │ ├── select2.full.min.js │ ├── select2.js │ └── select2.min.js ├── bin └── install-wp-tests.sh ├── classes ├── class-revisr-activity-table.php ├── class-revisr-admin-pages.php ├── class-revisr-admin.php ├── class-revisr-branch-table.php ├── class-revisr-commits-table.php ├── class-revisr-compatibility.php ├── class-revisr-cron.php ├── class-revisr-db-backup.php ├── class-revisr-db-import.php ├── class-revisr-db.php ├── class-revisr-git-callback.php ├── class-revisr-git.php ├── class-revisr-i18n.php ├── class-revisr-meta-boxes.php ├── class-revisr-process.php ├── class-revisr-remote.php ├── class-revisr-settings-fields.php ├── class-revisr-settings.php └── index.php ├── index.php ├── languages ├── index.php └── revisr.pot ├── package.json ├── phpunit.xml ├── readme.txt ├── revisr.php ├── templates ├── index.php ├── pages │ ├── branches.php │ ├── commits.php │ ├── dashboard.php │ ├── help.php │ ├── index.php │ ├── new-commit.php │ ├── settings.php │ ├── setup.php │ └── view-commit.php └── partials │ ├── checkout-remote-form.php │ ├── delete-branch-form.php │ ├── discard-form.php │ ├── import-tables-form.php │ ├── index.php │ ├── merge-branch-form.php │ ├── pull-form.php │ ├── push-form.php │ └── revert-form.php ├── tests ├── bootstrap.php ├── test-admin.php ├── test-compatibility.php ├── test-db-backup.php ├── test-db-import.php ├── test-db.php ├── test-git.php ├── test-remote.php └── test-revisr.php └── uninstall.php /.gitignore: -------------------------------------------------------------------------------- 1 | # Operating Systems 2 | Thumbs.db 3 | ehthumbs.db 4 | Desktop.ini 5 | $RECYCLE.BIN/ 6 | .DS_Store 7 | *~ 8 | 9 | # IDEs 10 | *.sublime-project 11 | *.sublime-workspace 12 | .idea 13 | *.pydevproject 14 | .project 15 | .metadata 16 | build/ 17 | tmp/ 18 | tests/clover.xml 19 | 20 | # Grunt 21 | node_modules 22 | 23 | # Vendor 24 | vendor 25 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | # .scrutinizer.yml 2 | tools: 3 | external_code_coverage: true 4 | sensiolabs_security_checker: true 5 | php_mess_detector: true 6 | php_code_sniffer: true 7 | php_code_coverage: true 8 | php_sim: true 9 | php_analyzer: true 10 | php_pdepend: true 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | sudo: false 4 | 5 | php: 6 | - 5.3 7 | - 5.4 8 | - 5.5 9 | 10 | env: 11 | - WP_VERSION=latest WP_MULTISITE=0 12 | - WP_VERSION=latest WP_MULTISITE=1 13 | - WP_VERSION=4.0 WP_MULTISITE=0 14 | - WP_VERSION=4.0 WP_MULTISITE=1 15 | - WP_VERSION=3.9.2 WP_MULTISITE=0 16 | - WP_VERSION=3.9.2 WP_MULTISITE=1 17 | 18 | before_script: 19 | - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION 20 | - cd /tmp/wordpress/ 21 | - git init . 22 | - git config user.name "revisr" 23 | - git config user.email "support@expandedfronts.com" 24 | - cd /home/travis/build/ExpandedFronts/Revisr/ 25 | 26 | script: phpunit --coverage-clover=coverage.clover 27 | 28 | after_script: 29 | - wget https://scrutinizer-ci.com/ocular.phar 30 | - php ocular.phar code-coverage:upload --format=php-clover coverage.clover 31 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | #Contributing to Revisr 2 | 3 | Revisr is open source to encourage feedback and community patches. 4 | 5 | Please check the guidelines below before contributing to make sure that everything stays in order. 6 | 7 | __Please Note:__ GitHub is for bug reports and contributions only - if you have a support question please don't post here, go to the [Support Forum](https://wordpress.org/support/plugin/revisr) instead. 8 | 9 | ## Getting Started 10 | 11 | * Submit a ticket for your issue, assuming one does not already exist. 12 | * Raise it on the [Issue Tracker](https://github.com/expandedfronts/revisr/issues) 13 | * Clearly describe the issue including steps to reproduce the bug. 14 | * Make sure you fill in the earliest version that you know has the issue as well as the version of WordPress you're using. 15 | 16 | ## Making Changes 17 | 18 | * Fork the repository on GitHub 19 | * Make the changes to your forked repository 20 | * Ensure you stick to the [WordPress Coding Standards](https://codex.wordpress.org/WordPress_Coding_Standards) 21 | * When committing, reference your issue (if present) and include a note about the fix 22 | * If possible, and if applicable, please also add/update unit tests for your changes 23 | * Push the changes to your fork and submit a pull request to the 'master' branch of the repository 24 | 25 | ## Code Documentation 26 | 27 | * Please make sure that every function is documented! 28 | * If you're adding/editing a function in a class, make sure to add `@access {private|public|protected}` 29 | * Finally, please use tabs and not spaces. The tab indent size should be 4 for all code. 30 | 31 | Once you've submitted your pull request, it will be reviewed and merged in if all looks good. 32 | 33 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.initConfig({ 4 | pkg: grunt.file.readJSON('package.json'), 5 | makepot: { 6 | target: { 7 | options: { 8 | domainPath: '/languages/', 9 | mainFile: 'revisr.php', 10 | potFilename: 'revisr.pot', 11 | potHeaders: { 12 | poedit: true, 13 | 'report-msgid-bugs-to': 'http://wordpress.org/support/plugin/revisr', 14 | 'last-translator': 'Revisr ', 15 | 'language-team': 'Revisr ' 16 | }, 17 | type: 'wp-plugin', 18 | updateTimestamp: true, 19 | } 20 | } 21 | } 22 | }); 23 | 24 | grunt.loadNpmTasks('grunt-wp-i18n'); 25 | 26 | }; 27 | -------------------------------------------------------------------------------- /assets/css/revisr-admin.css: -------------------------------------------------------------------------------- 1 | /** 2 | * revisr-admin.css 3 | * 4 | * @package Revisr 5 | * @license GPLv3 6 | * @link https://revisr.io 7 | * @copyright Expanded Fronts, LLC 8 | */ 9 | 10 | /*-------------------------------------------------------------- 11 | >>> TABLE OF CONTENTS: 12 | ---------------------------------------------------------------- 13 | # Dashboard Page 14 | ## Recent Activity 15 | ## "Quick Actions" metabox 16 | ## "Branches/Tags" metabox 17 | # Branches Page 18 | # Commits Pages 19 | ## Committed 20 | ## Staging 21 | # Settings Pages 22 | # Setup 23 | # Misc 24 | --------------------------------------------------------------*/ 25 | 26 | /*-------------------------------------------------------------- 27 | # Dashboard Page 28 | --------------------------------------------------------------*/ 29 | .revisr-poststuff { padding-top: 0 !important; } 30 | 31 | /*-------------------------------------------------------------- 32 | ## Recent Activity 33 | --------------------------------------------------------------*/ 34 | #revisr-activity-form table th[id=message] { width: 75%; } 35 | #revisr-activity-form .alignleft { display: none; } 36 | 37 | /*-------------------------------------------------------------- 38 | ## "Quick Actions" metabox 39 | --------------------------------------------------------------*/ 40 | .revisr-quick-action-btn { width: 100%; text-align: left !important; margin-bottom: 4px !important; } 41 | .revisr-quick-action-btn:before { margin: 5px; display: inline-block; float: left; color: #fff; -webkit-font-smoothing: antialiased; } 42 | .revisr-quick-action-btn-txt { float: left; } 43 | #revisr-commit-btn:before { content: "\f132"; margin: 5px 1px !important; font: normal 20px/1 'dashicons'; color: #444; } 44 | #revisr-discard-btn:before { content: "\f158"; margin: 4px 1px !important; font: normal 20px/1 'dashicons'; color: #444; } 45 | #revisr-backup-btn:before { content: "\f096"; font: normal 17px/1 'octicons'; color: #444; } 46 | #revisr-push-btn:before { content: "\f03d"; font: normal 20px/1 'octicons'; color: #444; } 47 | #revisr-pull-btn:before { content: "\f03f"; font: normal 20px/1 'octicons'; color: #444; } 48 | #revisr-loader { float: right; } 49 | 50 | /*-------------------------------------------------------------- 51 | ## "Branches/Tags" metabox 52 | --------------------------------------------------------------*/ 53 | #revisr-branches-tags-widget #branches { padding: 0; } 54 | #revisr-branches-tags-widget #branches-table { border: 0; } 55 | #revisr-branches-tags-widget #branches-table tr:nth-child(odd) { background-color: #f9f9f9; } 56 | #revisr-manage-branches-link { font-size: 12px; } 57 | 58 | /*-------------------------------------------------------------- 59 | # Branches Page 60 | --------------------------------------------------------------*/ 61 | .revisr-col-container { margin-top: 25px !important; } 62 | #revisr-branch-form .tablenav.top { display: none; } 63 | #revisr-add-branch-box { max-width: 280px; } 64 | #revisr-add-branch-box h3 { font-size: 14px; padding: 8px 12px; margin: 0; line-height: 1.4; } 65 | #revisr-add-branch-box #add-branch-submit { text-align: center; margin-bottom: 0; padding-bottom: 0; } 66 | 67 | /*-------------------------------------------------------------- 68 | # Commits 69 | --------------------------------------------------------------*/ 70 | .revisr_page_revisr_commits .alignleft.actions.bulkactions { display: none; } 71 | #revisr-commits-filter #hash, #revisr-commits-filter .column-hash { width:70px !important; } 72 | #revisr-commits-filter .column-title { width: 400px !important; } 73 | #revisr-commits-filter #branch, #revisr-commits-filter #tag, #files_changed, #revisr-commits-filter .column-branch, #revisr-commits-filter .column-tag, .column-files_changed { text-align: center !important; } 74 | .revisr_page_revisr_commits .wrap { margin-top: 27px !important; } 75 | 76 | /*-------------------------------------------------------------- 77 | ## Committed 78 | --------------------------------------------------------------*/ 79 | #committed { width: 90%; } 80 | .admin_page_revisr_view_commit .wrap { margin-top: 27px !important; } 81 | 82 | /*-------------------------------------------------------------- 83 | ## Staging 84 | --------------------------------------------------------------*/ 85 | #revisr_save_commit .inside, #revisr_view_commit .inside { padding: 0; } 86 | .revisr-timestamp:before { margin-right: 3px; } 87 | #misc-publishing-actions .revisr-octicon-label:before { color: #888; display: inline-block; font: 400 20px/1 octicons; speak: none; left: -1px; position: relative; top: 0; text-decoration: none!important; vertical-align: top; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } 88 | #misc-publishing-actions label[for=revisr-branch]:before { content: '\f020'; padding: 0 7px 0 5px; } 89 | #misc-publishing-actions label[for=revisr-tag]:before { content: '\f015'; padding: 0 5px 0 3px; } 90 | .stage-container { width: 100%; display: inline-block; } 91 | #staged { width: 80%; float: left; overflow-y: scroll; } 92 | #unstaged { width: 80%; float: left; overflow-y: scroll; } 93 | .stage-nav { float: left; margin: 5px; } 94 | .stage-nav-button { margin-top: 7px !important; } 95 | .diff_added { background-color: #cfc; } 96 | .diff_removed { background-color: #fdd; } 97 | .admin_page_revisr_new_commit .wrap { margin-top: 27px !important; } 98 | #revisr-commit-form #title { line-height: normal; } 99 | 100 | /*-------------------------------------------------------------- 101 | # Settings 102 | --------------------------------------------------------------*/ 103 | .revisr-settings-form { margin-left: 15px; } 104 | #verify-remote { margin-left: 10px; padding: 4px; font-size: 11px; border-radius: 4px; color: #fff; margin-left: 10px; } 105 | .verify-remote-success { background-color: #5cb85c; } 106 | .verify-remote-error { background-color: #AFAFAF; } 107 | #gitignore { width: 35em; } 108 | .revisr-description { width: 35em; } 109 | .revisr-text { width: 35em !important; } 110 | #post-hook-input { width: 35em; } 111 | #revisr-debug-table { max-width: 750px; } 112 | body.revisr_page_revisr_settings #site5_wrapper { margin-right: 20px; } 113 | 114 | /*-------------------------------------------------------------- 115 | # Setup 116 | --------------------------------------------------------------*/ 117 | #revisr-setup-container { max-width: 400px; background-color: #fff; color: #444; margin: 140px auto 25px; padding: 30px; -webkit-font-smoothing: subpixel-antialiased; -webkit-box-shadow: 0 1px 3px rgba(0,0,0,.13); box-shadow: 0 1px 3px rgba(0,0,0,.13); } 118 | .revisr-setup-input { width: 100% !important; } 119 | .select2-hidden { display:none; } 120 | .revisr-setup-nav { margin-top: 10px; width: 100%; } 121 | .revisr-setup-nav button { width: 48%; } 122 | .revisr-setup-nav:last-child { float: right; } 123 | #revisr-setup-h2 { font-size: 23px; font-weight: 400; padding: 9px 15px 4px 0; line-height: 29px; margin: 0; } 124 | 125 | /*-------------------------------------------------------------- 126 | # Misc 127 | --------------------------------------------------------------*/ 128 | .revisr-arrow-logo { background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOC4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjI0NS44IDM4MS4xIDgxLjkgODkuNSIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAyNDUuOCAzODEuMSA4MS45IDg5LjUiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggZmlsbD0iIzQ0NCIgZD0iTTI5NS4yLDM4Ny4yYy01LjEsNS4xLTUuMSwxMy4zLDAsMTguM2MzLjgsMy44LDkuMyw0LjcsMTMuOSwyLjlsNy4yLTcuMmMxLjgtNC43LDAuOS0xMC4yLTIuOS0xMy45DQoJQzMwOC41LDM4Mi4xLDMwMC4zLDM4Mi4xLDI5NS4yLDM4Ny4yeiBNMzA5LjcsNDAxLjZjLTIuOSwyLjktNy42LDIuOS0xMC42LDBjLTIuOS0yLjktMi45LTcuNiwwLTEwLjZjMi45LTIuOSw3LjYtMi45LDEwLjYsMA0KCUMzMTIuNiwzOTQsMzEyLjYsMzk4LjcsMzA5LjcsNDAxLjZ6Ii8+DQo8cGF0aCBmaWxsPSIjNDQ0IiBkPSJNMjY4LjEsNDU0Yy0xMy4yLTEwLjEtMTYuMS0yOS02LjQtNDIuNmM0LTUuNiw5LjQtOS40LDE1LjQtMTEuNGwtMi0xMC4yYy04LjUsMi41LTE2LjIsNy43LTIxLjcsMTUuNQ0KCWMtMTIuOSwxOC4yLTguOSw0My41LDguOCw1N2wtNS42LDguM2wyNS45LTEuMmwtOC42LTIzLjZMMjY4LjEsNDU0eiIvPg0KPHBhdGggZmlsbD0iIzQ0NCIgZD0iTTMxOC4zLDQwMy4zYzEuMS0yLjEsMS43LTQuNSwxLjctN2MwLTguNC02LjgtMTUuMi0xNS4yLTE1LjJzLTE1LjIsNi44LTE1LjIsMTUuMnM2LjgsMTUuMiwxNS4yLDE1LjINCgljMi4xLDAsNC4xLTAuNCw1LjktMS4yYzguNCwxMC42LDkuMiwyNS44LDEsMzcuMmMtMy45LDUuNi05LjQsOS40LTE1LjQsMTEuNGwyLDEwLjJjOC41LTIuNSwxNi4yLTcuNywyMS43LTE1LjUNCglDMzMxLjIsNDM4LjEsMzI5LjksNDE3LjQsMzE4LjMsNDAzLjN6IE0zMDQuOCw0MDMuM2MtMy44LDAtNi45LTMuMS02LjktNi45czMuMS02LjksNi45LTYuOXM2LjksMy4xLDYuOSw2LjkNCglTMzA4LjcsNDAzLjMsMzA0LjgsNDAzLjN6Ii8+DQo8L3N2Zz4=); background-repeat: no-repeat; width: 24px; height: 24px; margin-top: 3px; margin-right: 8px; float: left; } 129 | #site5_wrapper { width: 80px; text-align: center; font-size: 11px; float: right; margin: 0 10px 10px 10px; padding: 0 5px; background-color: #fff; border: 1px solid #ddd; } 130 | #site5_logo { width: 80px; margin-top: -5px; } 131 | .revisr-alert { margin: 20px 0 !important;} 132 | -------------------------------------------------------------------------------- /assets/css/thickbox.css: -------------------------------------------------------------------------------- 1 | /* Thickbox Styles */ 2 | html { 3 | background-color: #fff; 4 | color: #444; 5 | font-family: "Open Sans",sans-serif; 6 | font-size: 14px; 7 | line-height: 1.4em; 8 | } 9 | body { 10 | margin: 0 !important; 11 | overflow: hidden; 12 | } 13 | input[type="text"] { 14 | height: 25px; 15 | font-size: 13px; 16 | } 17 | a { 18 | color: #0074a2 !important; 19 | } 20 | select { 21 | border: 1px solid #ddd; 22 | padding: 2px; 23 | line-height: 28px; 24 | height: 28px; 25 | vertical-align: middle; 26 | font-size: 14px; 27 | background: #fff; 28 | color: #32373c; 29 | outline: 0; 30 | } 31 | .revisr-tb-description { 32 | padding: 10px 15px 10px 15px; 33 | overflow-y: scroll; 34 | height: 155px; 35 | } 36 | .revisr-tb-submit { 37 | width: 100%; 38 | position: fixed; 39 | bottom: 0px; 40 | padding: 15px 0 15px 0; 41 | border-top: 1px solid #ddd; 42 | background-color: #f5f5f5; 43 | text-align: right; 44 | } 45 | .revisr-tb-btn { 46 | height: 30px; 47 | font-size: 14px; 48 | padding: 0 15px; 49 | margin: 0 15px 0 0; 50 | border-radius: 4px; 51 | } 52 | .revisr-tb-btn:hover { 53 | cursor: pointer; 54 | } 55 | .revisr-tb-danger { 56 | background-color:#e14d43; 57 | border:1px #d02c21 solid; 58 | color:#fff; 59 | -webkit-box-shadow: inset 0 1px 0 #ec8b85,0 1px 0 rgba(0,0,0,.15); 60 | box-shadow: inset 0 1px 0 #ec8b85,0 1px 0 rgba(0,0,0,.15); 61 | } 62 | .revisr-tb-danger:hover { 63 | background: #dd382d; 64 | border-color: #ba281e; 65 | color: #fff; 66 | -webkit-box-shadow: inset 0 1px 0 #e8776f; 67 | box-shadow: inset 0 1px 0 #e8776f; 68 | } 69 | .revisr-btn-cancel { 70 | background-color: #f7f7f7; 71 | border: 1px #ccc solid; 72 | color: #555; 73 | } 74 | .revisr-btn-cancel:hover { 75 | background-color: #fafafa; 76 | border: 1px solid #999; 77 | color: #222; 78 | } 79 | -------------------------------------------------------------------------------- /assets/img/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/expandedfronts/revisr/271228b624042b5fbc509af774bec873a3e2f648/assets/img/loader.gif -------------------------------------------------------------------------------- /assets/img/site5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/expandedfronts/revisr/271228b624042b5fbc509af774bec873a3e2f648/assets/img/site5.png -------------------------------------------------------------------------------- /assets/index.php: -------------------------------------------------------------------------------- 1 | ' + revisr_dashboard_vars.login_prompt + '

'; 69 | } else { 70 | jQuery('#revisr-loading-alert').hide(); 71 | jQuery('#revisr-processing-request').hide(); 72 | document.getElementById('revisr-alert-container').innerHTML = response; 73 | } 74 | } 75 | }); 76 | } 77 | 78 | /** 79 | * Update the AJAX button counts. 80 | */ 81 | function update_counts() { 82 | jQuery.post(ajaxurl, {action: 'ajax_button_count', data: 'unpulled'}, function(response) { 83 | if ( 0 == response ) { 84 | response = ''; 85 | } 86 | document.getElementById('revisr-unpulled').innerHTML = response; 87 | }); 88 | jQuery.post(ajaxurl, {action: 'ajax_button_count',data: 'unpushed'}, function(response) { 89 | if ( 0 == response ) { 90 | response = ''; 91 | } 92 | document.getElementById('revisr-unpushed').innerHTML = response; 93 | }); 94 | } 95 | 96 | /** 97 | * Display the loading message. 98 | */ 99 | function processing() { 100 | jQuery('.revisr-alert').hide(); 101 | jQuery('#revisr-loader').show(); 102 | jQuery('#revisr-processing-request').show(); 103 | } 104 | 105 | /** 106 | * Run when an AJAX request from the dashboard has been completed. 107 | */ 108 | function process_complete() { 109 | jQuery('#revisr-loader').hide(); 110 | update_alert(); 111 | revisr_list.update(); 112 | update_counts(); 113 | delayed_refresh(); 114 | } 115 | 116 | /** 117 | * Display the branches list. 118 | */ 119 | jQuery('#branches-link').click(function() { 120 | jQuery('#tags-tab').attr('class', 'hide-if-no-js'); 121 | jQuery('#branches-tab').attr('class', 'tabs'); 122 | jQuery('#tags').hide(); 123 | jQuery('#branches').show(); 124 | }); 125 | 126 | /** 127 | * Display the tags list. 128 | */ 129 | jQuery('#tags-link').click(function() { 130 | jQuery('#branches-tab').attr('class', 'hide-if-no-js'); 131 | jQuery('#tags-tab').attr('class', 'tabs'); 132 | jQuery('#branches').hide(); 133 | jQuery('#tags').show(); 134 | }); 135 | 136 | /** 137 | * Redirects to the new commit screen. 138 | */ 139 | jQuery('#revisr-commit-btn').click(function() { 140 | window.location = 'admin.php?page=revisr_new_commit'; 141 | }); 142 | 143 | /** 144 | * Runs when the 'Backup Database' button is clicked. 145 | */ 146 | jQuery('#revisr-backup-btn').click(function() { 147 | processing(); 148 | jQuery.post(ajaxurl, {action: 'backup_db', source: 'ajax_button', revisr_dashboard_nonce: revisr_dashboard_vars.ajax_nonce}, function(response) { 149 | process_complete(); 150 | }); 151 | }); 152 | 153 | 154 | var revisr_list = { 155 | /** 156 | * Register our triggers 157 | * 158 | * We want to capture clicks on specific links, but also value change in 159 | * the pagination input field. The links contain all the information we 160 | * need concerning the wanted page number or ordering, so we'll just 161 | * parse the URL to extract these variables. 162 | * 163 | * The page number input is trickier: it has no URL so we have to find a 164 | * way around. We'll use the hidden inputs added in TT_Example_List_Table::display() 165 | * to recover the ordering variables, and the default paged input added 166 | * automatically by WordPress. 167 | */ 168 | init: function() { 169 | // This will have its utility when dealing with the page number input 170 | var timer; 171 | var delay = 500; 172 | // Pagination links, sortable link 173 | jQuery('.tablenav-pages a, .manage-column.sortable a, .manage-column.sorted a').on('click', function(e) { 174 | // We don't want to actually follow these links 175 | e.preventDefault(); 176 | // Simple way: use the URL to extract our needed variables 177 | var query = this.search.substring( 1 ); 178 | 179 | var data = { 180 | paged: revisr_list.__query( query, 'paged' ) || '1', 181 | order: revisr_list.__query( query, 'order' ) || 'desc', 182 | orderby: revisr_list.__query( query, 'orderby' ) || 'time', 183 | revisr_event: revisr_list.__query( query, 'revisr_event' ) || 'all', 184 | revisr_user: revisr_list.__query( query, 'revisr_user' ) || 'all', 185 | revisr_time: revisr_list.__query( query, 'revisr_time' ) || 'all' 186 | }; 187 | revisr_list.update( data ); 188 | }); 189 | // Page number input 190 | jQuery('input[name=paged]').on('keyup', function(e) { 191 | // If user hit enter, we don't want to submit the form 192 | // We don't preventDefault() for all keys because it would 193 | // also prevent to get the page number! 194 | if ( 13 == e.which ) 195 | e.preventDefault(); 196 | // This time we fetch the variables in inputs 197 | var data = { 198 | paged: parseInt( jQuery('input[name=paged]').val() ) || '1', 199 | order: jQuery('input[name=order]').val() || 'asc', 200 | orderby: jQuery('input[name=orderby]').val() || 'title', 201 | revisr_event : jQuery('input[name=revisr_event]').val() || 'all', 202 | revisr_user : jQuery('input[name=revisr_user]').val() || 'all', 203 | revisr_time : jQuery('input[name=revisr_time]').val() || 'all' 204 | }; 205 | // Now the timer comes to use: we wait half a second after 206 | // the user stopped typing to actually send the call. If 207 | // we don't, the keyup event will trigger instantly and 208 | // thus may cause duplicate calls before sending the intended 209 | // value 210 | window.clearTimeout( timer ); 211 | timer = window.setTimeout(function() { 212 | revisr_list.update( data ); 213 | }, delay); 214 | }); 215 | }, 216 | /** 217 | * AJAX call 218 | * 219 | * Send the call and replace table parts with updated version! 220 | * 221 | * @param object data The data to pass through AJAX 222 | */ 223 | update: function( data ) { 224 | jQuery.ajax({ 225 | // /wp-admin/admin-ajax.php 226 | url: ajaxurl, 227 | // Add action and nonce to our collected data 228 | data: jQuery.extend( 229 | { 230 | revisr_list_nonce: jQuery('#revisr_list_nonce').val(), 231 | action: 'revisr_get_custom_list', 232 | }, 233 | data 234 | ), 235 | // Handle the successful result 236 | success: function( response ) { 237 | // WP_List_Table::ajax_response() returns json 238 | var response = jQuery.parseJSON( response ); 239 | // Add the requested rows 240 | if ( response.rows.length ) 241 | jQuery('#the-list').html( response.rows ); 242 | // Update column headers for sorting 243 | if ( response.column_headers.length ) 244 | jQuery('thead tr, tfoot tr').html( response.column_headers ); 245 | // Update pagination for navigation 246 | if ( response.pagination.bottom.length ) 247 | jQuery('.tablenav.top .tablenav-pages').html( jQuery(response.pagination.top).html() ); 248 | if ( response.pagination.top.length ) 249 | jQuery('.tablenav.bottom .tablenav-pages').html( jQuery(response.pagination.bottom).html() ); 250 | // Init back our event handlers 251 | revisr_list.init(); 252 | } 253 | }); 254 | }, 255 | /** 256 | * Filter the URL Query to extract variables 257 | * 258 | * @see http://css-tricks.com/snippets/javascript/get-url-variables/ 259 | * 260 | * @param string query The URL query part containing the variables 261 | * @param string variable Name of the variable we want to get 262 | * 263 | * @return string|boolean The variable value if available, false else. 264 | */ 265 | __query: function( query, variable ) { 266 | var vars = query.split("&"); 267 | for ( var i = 0; i 1&&(n+="a"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Моля въведете още "+t+" символ";return t>1&&(n+="a"),n},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(e){var t="Можете да направите до "+e.maximum+" ";return e.maximum>1?t+="избора":t+="избор",t},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/ca.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Si us plau, elimina "+t+" car";return t==1?n+="àcter":n+="àcters",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Si us plau, introdueix "+t+" car";return t==1?n+="àcter":n+="àcters",n},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var t="Només es pot seleccionar "+e.maximum+" element";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/cs.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/cs",[],function(){function e(e,t){switch(e){case 2:return t?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím zadejte o jeden znak méně":n<=4?"Prosím zadejte o "+e(n,!0)+" znaky méně":"Prosím zadejte o "+n+" znaků méně"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím zadejte ještě jeden znak":n<=4?"Prosím zadejte ještě další "+e(n,!0)+" znaky":"Prosím zadejte ještě dalších "+n+" znaků"},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(t){var n=t.maximum;return n==1?"Můžete zvolit jen jednu položku":n<=4?"Můžete zvolit maximálně "+e(n,!1)+" položky":"Můžete zvolit maximálně "+n+" položek"},noResults:function(){return"Nenalezeny žádné položky"},searching:function(){return"Vyhledávání…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/da.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Angiv venligst "+t+" tegn mindre";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Angiv venligst "+t+" tegn mere";return n},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var t="Du kan kun vælge "+e.maximum+" emne";return e.maximum!=1&&(t+="r"),t},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/de.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/de",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Bitte "+t+" Zeichen weniger eingeben"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Bitte "+t+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var t="Sie können nur "+e.maximum+" Eintr";return e.maximum===1?t+="ag":t+="äge",t+=" auswählen",t},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/en.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Please delete "+t+" character";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Please enter "+t+" or more characters";return n},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var t="You can only select "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/es.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"La carga falló"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor, elimine "+t+" car";return t==1?n+="ácter":n+="acteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Por favor, introduzca "+t+" car";return t==1?n+="ácter":n+="acteres",n},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var t="Sólo puede seleccionar "+e.maximum+" elemento";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/et.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" vähem",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" rohkem",n},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var t="Saad vaid "+e.maximum+" tulemus";return e.maximum==1?t+="e":t+="t",t+=" valida",t},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/eu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gutxiago",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gehiago",n},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return e.maximum===1?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/fa.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="لطفاً "+t+" کاراکتر را حذف نمایید";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="لطفاً تعداد "+t+" کاراکتر یا بیشتر وارد نمایید";return n},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(e){var t="شما تنها می‌توانید "+e.maximum+" آیتم را انتخاب نمایید";return t},noResults:function(){return"هیچ نتیجه‌ای یافت نشد"},searching:function(){return"در حال جستجو..."}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/fi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Ole hyvä ja anna "+t+" merkkiä vähemmän"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Ole hyvä ja anna "+t+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(e){return"Voit valita ainoastaan "+e.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/fr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fr",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Supprimez "+t+" caractère";return t!==1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Saisissez "+t+" caractère";return t!==1&&(n+="s"),n},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){var t="Vous pouvez seulement sélectionner "+e.maximum+" élément";return e.maximum!==1&&(t+="s"),t},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/gl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/gl",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Engada ";return t===1?n+="un carácter":n+=t+" caracteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Elimine ";return t===1?n+="un carácter":n+=t+" caracteres",n},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){var t="Só pode ";return e.maximum===1?t+="un elemento":t+=e.maximum+" elementos",t},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/he.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"התוצאות לא נטענו בהלכה"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="נא למחוק "+t+" תווים";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="נא להכניס "+t+" תווים או יותר";return n},loadingMore:function(){return"טען תוצאות נוספות…"},maximumSelected:function(e){var t="באפשרותך לבחור רק "+e.maximum+" פריטים";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/hi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" अक्षर को हटा दें";return t>1&&(n=t+" अक्षरों को हटा दें "),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="कृपया "+t+" या अधिक अक्षर दर्ज करें";return n},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(e){var t="आप केवल "+e.maximum+" आइटम का चयन कर सकते हैं";return t},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/hr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hr",[],function(){function e(e){var t=" "+e+" znak";return e%10<5&&e%10>0&&(e%100<5||e%100>19)?e%10>1&&(t+="a"):t+="ova",t}return{inputTooLong:function(t){var n=t.input.length-t.maximum;return"Unesite "+e(n)},inputTooShort:function(t){var n=t.minimum-t.input.length;return"Unesite još "+e(n)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(e){return"Maksimalan broj odabranih stavki je "+e.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/hu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Túl hosszú. "+t+" karakterrel több, mint kellene."},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Túl rövid. Még "+t+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/id.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/id",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Hapuskan "+t+" huruf"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Masukkan "+t+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(e){return"Anda hanya dapat memilih "+e.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/is.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/is",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vinsamlegast styttið texta um "+t+" staf";return t<=1?n:n+"i"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vinsamlegast skrifið "+t+" staf";return t>1&&(n+="i"),n+=" í viðbót",n},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(e){return"Þú getur aðeins valið "+e.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/it.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Per favore cancella "+t+" caratter";return t!==1?n+="i":n+="e",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Per favore inserisci "+t+" o più caratteri";return n},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var t="Puoi selezionare solo "+e.maximum+" element";return e.maximum!==1?t+="i":t+="o",t},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/ko.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="너무 깁니다. "+t+" 글자 지워주세요.";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="너무 짧습니다. "+t+" 글자 더 입력해주세요.";return n},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(e){var t="최대 "+e.maximum+"개까지만 선택 가능합니다.";return t},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/lt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lt",[],function(){function e(e,t,n,r){return e%100>9&&e%100<21||e%10===0?e%10>1?n:r:t}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Pašalinkite "+n+" simbol";return r+=e(n,"ių","ius","į"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Įrašykite dar "+n+" simbol";return r+=e(n,"ių","ius","į"),r},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(t){var n="Jūs galite pasirinkti tik "+t.maximum+" element";return n+=e(t.maximum,"ų","us","ą"),n},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/lv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lv",[],function(){function e(e,t,n,r){return e===11?t:e%10===1?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Lūdzu ievadiet par "+n;return r+=" simbol"+e(n,"iem","u","iem"),r+" mazāk"},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Lūdzu ievadiet vēl "+n;return r+=" simbol"+e(n,"us","u","us"),r},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(t){var n="Jūs varat izvēlēties ne vairāk kā "+t.maximum;return n+=" element"+e(t.maximum,"us","u","us"),n},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/mk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/mk",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Ве молиме внесете "+e.maximum+" помалку карактер";return e.maximum!==1&&(n+="и"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Ве молиме внесете уште "+e.maximum+" карактер";return e.maximum!==1&&(n+="и"),n},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(e){var t="Можете да изберете само "+e.maximum+" ставк";return e.maximum===1?t+="а":t+="и",t},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/nb.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nb",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Vennligst fjern "+t+" tegn"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vennligst skriv inn ";return t>1?n+=" flere tegn":n+=" tegn til",n},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/nl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Gelieve "+t+" karakters te verwijderen";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Gelieve "+t+" of meer karakters in te voeren";return n},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var t="Er kunnen maar "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t+=" worden geselecteerd",t},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/pl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pl",[],function(){var e=["znak","znaki","znaków"],t=["element","elementy","elementów"],n=function(t,n){if(t===1)return n[0];if(t>1&&t<=4)return n[1];if(t>=5)return n[2]};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(t){var r=t.input.length-t.maximum;return"Usuń "+r+" "+n(r,e)},inputTooShort:function(t){var r=t.minimum-t.input.length;return"Podaj przynajmniej "+r+" "+n(r,e)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(e){return"Możesz zaznaczyć tylko "+e.maximum+" "+n(e.maxiumum,t)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/pt-BR.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Apague "+t+" caracter";return t!=1&&(n+="es"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Digite "+t+" ou mais caracteres";return n},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var t="Você só pode selecionar "+e.maximum+" ite";return e.maximum==1?t+="m":t+="ns",t},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/pt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor apague "+t+" ";return n+=t!=1?"caracteres":"carácter",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Introduza "+t+" ou mais caracteres";return n},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var t="Apenas pode seleccionar "+e.maximum+" ";return t+=e.maximum!=1?"itens":"item",t},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/ro.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ro",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să introduceți mai puțin de "+t;return n+=" caracter",n!==1&&(n+="e"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vă rugăm să introduceți incă "+t;return n+=" caracter",n!==1&&(n+="e"),n},loadingMore:function(){return"Se încarcă…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",t!==1&&(t+="e"),t},noResults:function(){return"Nu a fost găsit nimic"},searching:function(){return"Căutare…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/ru.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ru",[],function(){function e(e,t,n,r){return e%10<5&&e%10>0&&e%100<5||e%100>20?e%10>1?n:t:r}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Пожалуйста, введите на "+n+" символ";return r+=e(n,"","a","ов"),r+=" меньше",r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Пожалуйста, введите еще хотя бы "+n+" символ";return r+=e(n,"","a","ов"),r},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(t){var n="Вы можете выбрать не более "+t.maximum+" элемент";return n+=e(t.maximum,"","a","ов"),n},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/sk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím, zadajte o jeden znak menej":n>=2&&n<=4?"Prosím, zadajte o "+e[n](!0)+" znaky menej":"Prosím, zadajte o "+n+" znakov menej"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím, zadajte ešte jeden znak":n<=4?"Prosím, zadajte ešte ďalšie "+e[n](!0)+" znaky":"Prosím, zadajte ešte ďalších "+n+" znakov"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(t){return t.maximum==1?"Môžete zvoliť len jednu položku":t.maximum>=2&&t.maximum<=4?"Môžete zvoliť najviac "+e[t.maximum](!1)+" položky":"Môžete zvoliť najviac "+t.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/sr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Obrišite "+n+" simbol";return r+=e(n,"","a","a"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Ukucajte bar još "+n+" simbol";return r+=e(n,"","a","a"),r},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(t){var n="Možete izabrati samo "+t.maximum+" stavk";return n+=e(t.maximum,"u","e","i"),n},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/sv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vänligen sudda ut "+t+" tecken";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vänligen skriv in "+t+" eller fler tecken";return n},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(e){var t="Du kan max välja "+e.maximum+" element";return t},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/th.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/th",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="โปรดลบออก "+t+" ตัวอักษร";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="โปรดพิมพ์เพิ่มอีก "+t+" ตัวอักษร";return n},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(e){var t="คุณสามารถเลือกได้ไม่เกิน "+e.maximum+" รายการ";return t},noResults:function(){return"ม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/tr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/tr",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" karakter daha girmelisiniz";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="En az "+t+" karakter daha girmelisiniz";return n},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(e){var t="Sadece "+e.maximum+" seçim yapabilirsiniz";return t},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/uk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/uk",[],function(){function e(e,t,n,r){return e%100>10&&e%100<15?r:e%10===1?t:e%10>1&&e%10<5?n:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Будь ласка, видаліть "+n+" "+e(t.maximum,"літеру","літери","літер")},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Будь ласка, введіть "+t+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(t){return"Ви можете вибрати лише "+t.maximum+" "+e(t.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/vi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/vi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vui lòng nhập ít hơn "+t+" ký tự";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vui lòng nhập nhiều hơn "+t+' ký tự"';return n},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(e){var t="Chỉ có thể chọn được "+e.maximum+" lựa chọn";return t},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/zh-CN.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="请删除"+t+"个字符";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="请再输入至少"+t+"个字符";return n},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(e){var t="最多只能选择"+e.maximum+"个项目";return t},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /assets/lib/select2/js/i18n/zh-TW.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="請刪掉"+t+"個字元";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="請再輸入"+t+"個字元";return n},loadingMore:function(){return"載入中…"},maximumSelected:function(e){var t="你只能選擇最多"+e.maximum+"項";return t},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /bin/install-wp-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ $# -lt 3 ]; then 4 | echo "usage: $0 [db-host] [wp-version]" 5 | exit 1 6 | fi 7 | 8 | DB_NAME=$1 9 | DB_USER=$2 10 | DB_PASS=$3 11 | DB_HOST=${4-localhost} 12 | WP_VERSION=${5-latest} 13 | 14 | WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} 15 | WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} 16 | 17 | download() { 18 | if [ `which curl` ]; then 19 | curl -s "$1" > "$2"; 20 | elif [ `which wget` ]; then 21 | wget -nv -O "$2" "$1" 22 | fi 23 | } 24 | 25 | if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then 26 | WP_TESTS_TAG="tags/$WP_VERSION" 27 | else 28 | # http serves a single offer, whereas https serves multiple. we only want one 29 | download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json 30 | grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json 31 | LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//') 32 | if [[ -z "$LATEST_VERSION" ]]; then 33 | echo "Latest WordPress version could not be found" 34 | exit 1 35 | fi 36 | WP_TESTS_TAG="tags/$LATEST_VERSION" 37 | fi 38 | 39 | set -ex 40 | 41 | install_wp() { 42 | 43 | if [ -d $WP_CORE_DIR ]; then 44 | return; 45 | fi 46 | 47 | mkdir -p $WP_CORE_DIR 48 | 49 | if [ $WP_VERSION == 'latest' ]; then 50 | local ARCHIVE_NAME='latest' 51 | else 52 | local ARCHIVE_NAME="wordpress-$WP_VERSION" 53 | fi 54 | 55 | download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz 56 | tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR 57 | 58 | download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php 59 | } 60 | 61 | install_test_suite() { 62 | # portable in-place argument for both GNU sed and Mac OSX sed 63 | if [[ $(uname -s) == 'Darwin' ]]; then 64 | local ioption='-i .bak' 65 | else 66 | local ioption='-i' 67 | fi 68 | 69 | # set up testing suite if it doesn't yet exist 70 | if [ ! -d $WP_TESTS_DIR ]; then 71 | # set up testing suite 72 | mkdir -p $WP_TESTS_DIR 73 | svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes 74 | fi 75 | 76 | cd $WP_TESTS_DIR 77 | 78 | if [ ! -f wp-tests-config.php ]; then 79 | download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php 80 | sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" "$WP_TESTS_DIR"/wp-tests-config.php 81 | sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php 82 | sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php 83 | sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php 84 | sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php 85 | fi 86 | 87 | } 88 | 89 | install_db() { 90 | # parse DB_HOST for port or socket references 91 | local PARTS=(${DB_HOST//\:/ }) 92 | local DB_HOSTNAME=${PARTS[0]}; 93 | local DB_SOCK_OR_PORT=${PARTS[1]}; 94 | local EXTRA="" 95 | 96 | if ! [ -z $DB_HOSTNAME ] ; then 97 | if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then 98 | EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" 99 | elif ! [ -z $DB_SOCK_OR_PORT ] ; then 100 | EXTRA=" --socket=$DB_SOCK_OR_PORT" 101 | elif ! [ -z $DB_HOSTNAME ] ; then 102 | EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" 103 | fi 104 | fi 105 | 106 | # create database 107 | mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA 108 | } 109 | 110 | install_wp 111 | install_test_suite 112 | install_db 113 | -------------------------------------------------------------------------------- /classes/class-revisr-admin.php: -------------------------------------------------------------------------------- 1 | Click here for more details, or try again.', 'revisr' ), $error_url ); 35 | } 36 | 37 | set_transient( 'revisr_error', $message, 10 ); 38 | 39 | } else { 40 | set_transient( 'revisr_alert', $message, 3 ); 41 | } 42 | } 43 | 44 | /** 45 | * Returns the data for the AJAX buttons. 46 | * @access public 47 | */ 48 | public function ajax_button_count() { 49 | if ( $_REQUEST['data'] == 'unpulled' ) { 50 | echo revisr()->git->count_unpulled(); 51 | } else { 52 | echo revisr()->git->count_unpushed(); 53 | } 54 | exit(); 55 | } 56 | 57 | /** 58 | * Deletes existing transients. 59 | * @access public 60 | */ 61 | public static function clear_transients( $errors = true ) { 62 | if ( true === $errors ) { 63 | delete_transient( 'revisr_error' ); 64 | delete_transient( 'revisr_error_details' ); 65 | } else { 66 | delete_transient( 'revisr_alert' ); 67 | } 68 | } 69 | 70 | /** 71 | * Helper function for determining if we're in setup mode. 72 | * @access public 73 | * @return boolean 74 | */ 75 | public static function is_doing_setup() { 76 | 77 | if ( revisr()->git->is_repo ) { 78 | return false; 79 | } else { 80 | if ( defined( 'REVISR_SKIP_SETUP' ) || get_transient( 'revisr_skip_setup' ) ) { 81 | return false; 82 | } 83 | return true; 84 | } 85 | 86 | } 87 | 88 | /** 89 | * Escapes a shell arguement. 90 | * @access public 91 | * @param string $string The string to escape. 92 | * @return string $string The escaped string. 93 | */ 94 | public static function escapeshellarg( $string ) { 95 | $os = Revisr_Compatibility::get_os(); 96 | if ( 'WIN' !== $os['code'] ) { 97 | return escapeshellarg( $string ); 98 | } else { 99 | // Windows-friendly workaround. 100 | return '"' . str_replace( "'", "'\\''", $string ) . '"'; 101 | } 102 | } 103 | 104 | /** 105 | * Logs an event to the database. 106 | * @access public 107 | * @param string $message The message to show in the Recent Activity. 108 | * @param string $event Will be used for filtering later. 109 | * @param string $user An optional user to associate the record with. 110 | */ 111 | public static function log( $message, $event, $user = '' ) { 112 | 113 | global $wpdb; 114 | 115 | $time = current_time( 'mysql' ); 116 | $table = Revisr::get_table_name(); 117 | 118 | if ( '' === $user ) { 119 | $user = wp_get_current_user(); 120 | $username = $user->user_login; 121 | } else { 122 | $username = $user; 123 | } 124 | 125 | if ( ! $username || '' === $username ) { 126 | $username = __( 'Revisr Bot', 'revisr' ); 127 | } 128 | 129 | $wpdb->insert( 130 | "$table", 131 | array( 132 | 'time' => $time, 133 | 'message' => $message, 134 | 'event' => $event, 135 | 'user' => $username, 136 | ), 137 | array( 138 | '%s', 139 | '%s', 140 | '%s', 141 | '%s', 142 | ) 143 | ); 144 | } 145 | 146 | /** 147 | * Notifies the admin if notifications are enabled. 148 | * @access private 149 | * @param string $subject The subject line of the email. 150 | * @param string $message The message for the email. 151 | */ 152 | public static function notify( $subject, $message ) { 153 | $options = Revisr::get_options(); 154 | $url = get_admin_url() . 'admin.php?page=revisr'; 155 | 156 | if ( isset( $options['notifications'] ) ) { 157 | $email = $options['email']; 158 | $message .= '

'; 159 | $message .= sprintf( __( 'Click here for more details.', 'revisr' ), $url ); 160 | $headers = "Content-Type: text/html; charset=ISO-8859-1\r\n"; 161 | wp_mail( $email, $subject, $message, $headers ); 162 | } 163 | } 164 | 165 | /** 166 | * Renders an alert and removes the old data. 167 | * @access public 168 | * @param boolean $errors_only Whether or not to only display errors. 169 | */ 170 | public static function render_alert( $errors_only = false ) { 171 | $alert = get_transient( 'revisr_alert' ); 172 | $error = get_transient( 'revisr_error' ); 173 | 174 | if ( $error ) { 175 | $alert = '
' . wpautop( $error ) . '
'; 176 | } else if ( $alert ) { 177 | $alert = '
' . wpautop( $alert ) . '
'; 178 | } else { 179 | if ( revisr()->git->count_untracked() == '0' ) { 180 | $msg = sprintf( __( 'There are currently no untracked files on branch %s.', 'revisr' ), revisr()->git->branch ); 181 | $alert = '

' . $msg . '

'; 182 | } else { 183 | $link = get_admin_url() . 'admin.php?page=revisr_new_commit'; 184 | $msg = sprintf( __( 'There are currently %d untracked files on branch %s. Commit your changes to save them.', 'revisr' ), revisr()->git->count_untracked(), revisr()->git->branch, $link ); 185 | $alert = '

' . $msg . '

'; 186 | } 187 | } 188 | 189 | if ( $errors_only && false !== $error ) { 190 | echo $alert; 191 | } else if ( ! $errors_only ) { 192 | echo $alert; 193 | } 194 | 195 | if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) { 196 | exit(); 197 | } 198 | 199 | } 200 | 201 | /** 202 | * Updates user settings to be compatible with 1.8. 203 | * @access public 204 | */ 205 | public function do_upgrade() { 206 | global $wpdb; 207 | 208 | // For users upgrading from 1.7 and older. 209 | if ( get_option( 'revisr_db_version' ) === '1.0' ) { 210 | 211 | // Check for the "auto_push" option and save it to the config. 212 | if ( isset( revisr()->options['auto_push'] ) ) { 213 | revisr()->git->set_config( 'revisr', 'auto-push', 'true' ); 214 | } 215 | 216 | // Check for the "auto_pull" option and save it to the config. 217 | if ( isset( revisr()->options['auto_pull'] ) ) { 218 | revisr()->git->set_config( 'revisr', 'auto-pull', 'true' ); 219 | } 220 | 221 | // Check for the "reset_db" option and save it to the config. 222 | if ( isset( revisr()->options['reset_db'] ) ) { 223 | revisr()->git->set_config( 'revisr', 'import-checkouts', 'true' ); 224 | } 225 | 226 | // Check for the "mysql_path" option and save it to the config. 227 | if ( isset( revisr()->options['mysql_path'] ) ) { 228 | revisr()->git->set_config( 'revisr', 'mysql-path', revisr()->options['mysql_path'] ); 229 | } 230 | 231 | // Configure the database tracking to use all tables, as this was how it behaved in 1.7. 232 | revisr()->git->set_config( 'revisr', 'db_tracking', 'all_tables' ); 233 | } 234 | 235 | // Upgrades from the "revisr_commits" custom post type to pure Git. 236 | $table = Revisr::get_table_name(); 237 | $commits = $wpdb->get_results( "SELECT * FROM $table WHERE event = 'commit'", ARRAY_A ); 238 | 239 | if ( is_array( $commits ) && ! empty( $commits ) ) { 240 | 241 | foreach ( $commits as $commit ) { 242 | // Get the commit short hash from the message. 243 | $msg_array = explode( '#', $commit['message'] ); 244 | $commit_id = substr( $msg_array[1], 0, 7 ); 245 | 246 | // Prepare the new message. 247 | $new_msg = sprintf( 248 | __( 'Committed #%s to the local repository.', 'revisr' ), 249 | get_admin_url() . 'admin.php?page=revisr_view_commit&commit=' . $commit_id, 250 | $commit_id 251 | ); 252 | 253 | // Update the existing message. 254 | $query = $wpdb->prepare( 255 | "UPDATE $table SET message = %s WHERE id = '%d'", 256 | $new_msg, 257 | $commit['id'] 258 | ); 259 | 260 | $wpdb->query( $query ); 261 | } 262 | 263 | } 264 | 265 | // Update the database schema using dbDelta. 266 | Revisr::install(); 267 | 268 | } 269 | 270 | /** 271 | * Helper function for writing to the wp-config.php file, 272 | * taken from WP Super Cache. 273 | * 274 | * @access public 275 | * @return boolean 276 | */ 277 | public static function replace_config_line( $old, $new, $file = '' ) { 278 | 279 | if ( $file === '' ) { 280 | if ( file_exists( ABSPATH . 'wp-config.php') ) { 281 | $file = ABSPATH . 'wp-config.php'; 282 | } else { 283 | $file = dirname(ABSPATH) . '/wp-config.php'; 284 | } 285 | } 286 | 287 | if ( @is_file( $file ) == false ) { 288 | return false; 289 | } 290 | if (!is_writeable( $file ) ) { 291 | return false; 292 | } 293 | 294 | $found = false; 295 | $lines = file($file); 296 | foreach( (array)$lines as $line ) { 297 | if ( preg_match("/$old/", $line)) { 298 | $found = true; 299 | break; 300 | } 301 | } 302 | if ($found) { 303 | $fd = fopen($file, 'w'); 304 | foreach( (array)$lines as $line ) { 305 | if ( !preg_match("/$old/", $line)) 306 | fputs($fd, $line); 307 | else { 308 | fputs($fd, "$new // Added by Revisr\n"); 309 | } 310 | } 311 | fclose($fd); 312 | return true; 313 | } 314 | $fd = fopen($file, 'w'); 315 | $done = false; 316 | foreach( (array)$lines as $line ) { 317 | if ( $done || !preg_match('/^(if\ \(\ \!\ )?define|\$|\?>/', $line) ) { 318 | fputs($fd, $line); 319 | } else { 320 | fputs($fd, "$new // Added by Revisr\n"); 321 | fputs($fd, $line); 322 | $done = true; 323 | } 324 | } 325 | fclose($fd); 326 | return true; 327 | 328 | } 329 | 330 | /** 331 | * Wrapper for wp_verify_nonce. 332 | * 333 | * @access public 334 | */ 335 | public static function verify_nonce( $nonce, $action ) { 336 | 337 | if ( ! wp_verify_nonce( $nonce, $action ) ) { 338 | wp_die( __( 'Cheatin’ uh?', 'revisr' ) ); 339 | } 340 | 341 | } 342 | 343 | /** 344 | * Helper function for processing redirects. 345 | * 346 | * @access public 347 | * @param string $url The URL to redirect to. 348 | * @param bool $echo Set to true if the redirect should be done in Javascript. 349 | */ 350 | public static function redirect( $url = '', $echo = false ) { 351 | 352 | if ( '' === $url ) { 353 | $url = get_admin_url() . 'admin.php?page=revisr'; 354 | } 355 | 356 | if ( $echo || isset( $_REQUEST['echo_redirect'] ) ) { 357 | _e( 'Processing...', 'revisr' ); 358 | ?> 359 | 362 | 'branch', 42 | 'plural' => 'branches' 43 | ) ); 44 | 45 | add_screen_option( 46 | 'per_page', 47 | array( 48 | 'default' => 10, 49 | 'label' => __( 'Branches per page', 'revisr' ), 50 | 'option' => 'edit_revisr_branches_per_page', 51 | ) 52 | ); 53 | 54 | set_screen_options(); 55 | } 56 | 57 | /** 58 | * Sets the screen options for the Revisr branches page. 59 | * @access public 60 | * @param boolean $status This seems to be false 61 | * @param string $option The name of the option 62 | * @param int $value The number of events to display 63 | * @return int|boolean 64 | */ 65 | public function set_screen_option( $status, $option, $value ) { 66 | if ( 'edit_revisr_branches_per_page' === $option ) { 67 | return $value; 68 | } 69 | return $status; 70 | } 71 | 72 | /** 73 | * Returns an array of the column names. 74 | * @access public 75 | * @return array 76 | */ 77 | public function get_columns() { 78 | $columns = array( 79 | 'branch' => __( 'Branch', 'revisr' ), 80 | 'updated' => __( 'Last Updated', 'revisr' ), 81 | 'actions' => __( 'Actions', 'revisr' ), 82 | ); 83 | return $columns; 84 | } 85 | 86 | /** 87 | * Returns an array of columns that are sortable. 88 | * @access public 89 | * @return array 90 | */ 91 | public function get_sortable_columns() { 92 | $sortable_columns = array( 93 | 'branch' => array( 'branch', false ), 94 | 'updated' => array( 'updated', false ) 95 | ); 96 | return $sortable_columns; 97 | } 98 | 99 | /** 100 | * Returns an array containing the branch information. 101 | * @access public 102 | * @return array 103 | */ 104 | public function get_data() { 105 | 106 | // Basic filter for viewing remote branches. 107 | if ( isset( $_GET['branches'] ) && $_GET['branches'] === 'remote' ) { 108 | // We may need to clear out the cache for the remote branches. 109 | revisr()->git->run( 'remote', array( 'update', '--prune' ) ); 110 | $remote = true; 111 | } else { 112 | $remote = false; 113 | } 114 | 115 | // Get the branches. 116 | $branches = revisr()->git->get_branches( $remote ); 117 | $branches_array = array(); 118 | 119 | if ( is_array( $branches ) && ! empty( $branches ) ) { 120 | 121 | $count = 0; 122 | 123 | foreach ( $branches as $key => $value ) { 124 | 125 | $branch = substr( $value, 2 ); 126 | $updated = revisr()->git->get_branch_last_updated( $branch ); 127 | 128 | if ( substr( $value, 0, 1 ) === '*' ) { 129 | $current = true; 130 | $branch_title = sprintf( '%s %s', $branch, __( '(current branch)', 'revisr' ) ); 131 | } else { 132 | $current = false; 133 | $branch_title = $branch; 134 | } 135 | 136 | $branches_array[$count]['branch'] = $branch_title; 137 | $branches_array[$count]['updated'] = $updated; 138 | $branches_array[$count]['actions'] = $this->get_actions( $branch, $remote, $current ); 139 | 140 | $count++; 141 | 142 | } 143 | 144 | } 145 | 146 | return $branches_array; 147 | } 148 | 149 | /** 150 | * Returns possible actions for a given branch. 151 | * @access public 152 | * @return string 153 | */ 154 | public function get_actions( $branch, $remote, $current ) { 155 | 156 | $admin_url = get_admin_url(); 157 | $checkout_text = __( 'Checkout', 'revisr' ); 158 | $merge_text = __( 'Merge', 'revisr' ); 159 | $delete_text = __( 'Delete', 'revisr' ); 160 | $checkout_title = __( 'Checkout Branch', 'revisr' ); 161 | $merge_title = __( 'Merge Branch', 'revisr' ); 162 | $delete_title = __( 'Delete Branch', 'revisr' ); 163 | $checkout_url = wp_nonce_url( $admin_url . "admin-post.php?action=process_checkout&branch=" . $branch, 'process_checkout', 'revisr_checkout_nonce' ); 164 | $merge_url = $admin_url . "admin-post.php?action=revisr_merge_branch_form&branch=" . $branch . "&TB_iframe=true&width=400&height=225"; 165 | $delete_url = $admin_url . "admin-post.php?action=revisr_delete_branch_form&branch=" . $branch . "&TB_iframe=true&width=400&height=225"; 166 | 167 | if ( $current ) { 168 | return sprintf( 169 | '%s 170 | %s 171 | %s', 172 | $checkout_text, 173 | $merge_text, 174 | $delete_text 175 | ); 176 | } 177 | 178 | if ( ! $remote ) { 179 | 180 | return sprintf( 181 | '%s 182 | %s 183 | %s', 184 | $checkout_url, 185 | $checkout_text, 186 | $merge_url, 187 | $merge_title, 188 | $merge_text, 189 | $delete_url, 190 | $delete_title, 191 | $delete_text 192 | ); 193 | 194 | } else { 195 | $checkout_url = esc_url( $admin_url . 'admin-post.php?action=revisr_checkout_remote_form&branch=' . $branch . '&TB_iframe=true&width=400&height=225' ); 196 | $merge_url = esc_url( $admin_url . 'admin-post.php?action=revisr_merge_branch_form&branch=' . $branch . '&TB_iframe=true&width=400&height=225' ); 197 | $delete_url = esc_url( $admin_url . 'admin-post.php?action=revisr_delete_branch_form&branch=' . $branch . '&remote=true&TB_iframe=true&width=400&height=225' ); 198 | 199 | return sprintf( 200 | '%s 201 | %s 202 | %s', 203 | $checkout_url, 204 | $checkout_title, 205 | $checkout_text, 206 | $merge_url, 207 | $merge_title, 208 | $merge_text, 209 | $delete_url, 210 | $delete_title, 211 | $delete_text 212 | ); 213 | } 214 | 215 | } 216 | 217 | /** 218 | * Renders the default data for a column. 219 | * @access public 220 | * @param array $item A singular item (one full row's worth of data) 221 | * @param array $column_name The name/slug of the column to be processed 222 | * @return string 223 | */ 224 | public function column_default( $item, $column_name ) { 225 | return $item[$column_name]; 226 | } 227 | 228 | /** 229 | * Called when no branches are found. 230 | * @access public 231 | */ 232 | public function no_items() { 233 | _e( 'No branches found.', 'revisr' ); 234 | } 235 | 236 | /** 237 | * Prepares the data for display. 238 | * @access public 239 | */ 240 | public function prepare_items() { 241 | global $wpdb; 242 | 243 | // Number of items per page. 244 | $per_page = $this->get_items_per_page( 'edit_revisr_branches_per_page', 10 ); 245 | 246 | // Set up the custom columns. 247 | $columns = $this->get_columns(); 248 | $hidden = array(); 249 | $sortable = $this->get_sortable_columns(); 250 | 251 | // Builds the list of column headers. 252 | $this->_column_headers = array( $columns, $hidden, $sortable ); 253 | 254 | // Get the data to populate into the table. 255 | $data = $this->get_data(); 256 | 257 | // Handle sorting of the data. 258 | function usort_reorder($a,$b){ 259 | $orderby = ( ! empty( $_REQUEST['orderby'] ) ) ? $_REQUEST['orderby'] : 'branch'; //If no sort, default to time. 260 | $order = ( ! empty( $_REQUEST['order'] ) ) ? $_REQUEST['order'] : 'desc'; //If no order, default to desc 261 | $result = strcmp($a[$orderby], $b[$orderby]); //Determine sort order 262 | return ( $order==='asc' ) ? $result : -$result; //Send final sort direction to usort 263 | } 264 | usort( $data, 'usort_reorder' ); 265 | 266 | // Pagination. 267 | $current_page = $this->get_pagenum(); 268 | $total_items = count($data); 269 | $data = array_slice($data,(($current_page-1)*$per_page),$per_page); 270 | 271 | $this->items = $data; 272 | $this->set_pagination_args( array( 273 | 'total_items' => $total_items, 274 | 'per_page' => $per_page, 275 | 'total_pages' => ceil($total_items/$per_page), 276 | 'orderby' => ! empty( $_REQUEST['orderby'] ) && '' != $_REQUEST['orderby'] ? $_REQUEST['orderby'] : 'time', 277 | 'order' => ! empty( $_REQUEST['order'] ) && '' != $_REQUEST['order'] ? $_REQUEST['order'] : 'desc' 278 | ) ); 279 | } 280 | 281 | /** 282 | * Displays the table. 283 | * @access public 284 | */ 285 | public function display() { 286 | wp_nonce_field( 'revisr-branches-nonce', 'revisr_branches_nonce' ); 287 | 288 | echo ''; 289 | echo ''; 290 | 291 | parent::display(); 292 | } 293 | 294 | /** 295 | * Extra table navigation. 296 | * @access public 297 | * @param string $which 298 | * @return string 299 | */ 300 | public function extra_tablenav( $which ) { 301 | if ( 'top' != $which && revisr()->git->has_remote() ) { 302 | 303 | if ( isset( $_GET['branches'] ) && $_GET['branches'] == 'remote' ) { 304 | $url = esc_url( add_query_arg( array( 'branches' => 'local' ) ) ); 305 | printf( '%s', $url, __( 'Local Branches', 'revisr' ) ); 306 | 307 | } else { 308 | $url = esc_url( add_query_arg( array( 'branches' => 'remote' ) ) ); 309 | printf( '%s', $url, __( 'Remote Branches', 'revisr' ) ); 310 | } 311 | 312 | } 313 | } 314 | 315 | } 316 | -------------------------------------------------------------------------------- /classes/class-revisr-compatibility.php: -------------------------------------------------------------------------------- 1 | prefix ) . "\n"; 37 | $return .= 'WP_DEBUG: ' . ( defined( 'WP_DEBUG' ) ? WP_DEBUG ? 'Enabled' : 'Disabled' : 'Not set' ) . "\n"; 38 | $return .= 'Memory Limit: ' . WP_MEMORY_LIMIT . "\n"; 39 | 40 | // Revisr Configuration 41 | $return .= "\n" . '-- Revisr Configuration' . "\n\n"; 42 | $return .= 'Plugin Version: ' . REVISR_VERSION . "\n"; 43 | 44 | if ( isset( revisr()->options['automatic_backups'] ) && 'none' !== revisr()->options['automatic_backups'] ) { 45 | $backups = 'Enabled'; 46 | } else { 47 | $backups = 'Disabled'; 48 | } 49 | $return .= 'Automatic Backups: ' . $backups . "\n"; 50 | 51 | if ( revisr()->git->get_config( 'revisr', 'auto-push' ) === 'true' ) { 52 | $auto_push = 'Enabled'; 53 | } else { 54 | $auto_push = 'Disabled'; 55 | } 56 | $return .= 'Auto-Push: ' . $auto_push . "\n"; 57 | 58 | if ( revisr()->git->get_config( 'revisr', 'auto-pull' ) === 'true' ) { 59 | $auto_pull = 'Enabled'; 60 | } else { 61 | $auto_pull = 'Disabled'; 62 | } 63 | $return .= 'Auto-Pull: ' . $auto_pull . "\n"; 64 | 65 | if ( revisr()->git->get_config( 'revisr', 'import-checkouts' ) === 'true' ) { 66 | $import_checkouts = 'Enabled'; 67 | } else { 68 | $import_checkouts = 'Disabled'; 69 | } 70 | $return .= 'Import checkouts: ' . $import_checkouts . "\n"; 71 | 72 | if ( revisr()->git->get_config( 'revisr', 'import-pulls' ) === 'true' ) { 73 | $import_pulls = 'Enabled'; 74 | } else { 75 | $import_pulls = 'Disabled'; 76 | } 77 | $return .= 'Import pulls: ' . $import_pulls . "\n"; 78 | $return .= 'Work Tree: ' . revisr()->git->get_work_tree() . "\n"; 79 | $return .= 'Git Dir: ' . revisr()->git->get_git_dir() . "\n"; 80 | 81 | if ( revisr()->git->is_repo ) { 82 | $detected = 'true'; 83 | } else { 84 | $detected = 'false'; 85 | } 86 | $return .= 'Repository Detected: ' . $detected . "\n"; 87 | if ( 'true' === $detected ) { 88 | $return .= 'Repository Writable: ' . Revisr_Compatibility::server_has_permissions( revisr()->git->get_git_dir() ) . "\n"; 89 | } 90 | 91 | 92 | // Server Configuration 93 | $return .= "\n" . '-- Server Configuration' . "\n\n"; 94 | $os = Revisr_Compatibility::get_os(); 95 | $return .= 'Operating System: ' . $os['name'] . "\n"; 96 | $return .= 'PHP Version: ' . PHP_VERSION . "\n"; 97 | $return .= 'MySQL Version: ' . $wpdb->db_version() . "\n"; 98 | $return .= 'Git Version: ' . revisr()->git->version() . "\n"; 99 | 100 | $return .= 'Git Install Path: ' . Revisr_Compatibility::guess_path( 'git' ) . "\n"; 101 | $return .= 'MySQL Install Path: ' . Revisr_Compatibility::guess_path( 'mysql' ) . "\n"; 102 | 103 | $return .= 'Server Software: ' . $_SERVER['SERVER_SOFTWARE'] . "\n"; 104 | $return .= 'Server User: ' . Revisr_Compatibility::get_user() . "\n"; 105 | 106 | // PHP configs... now we're getting to the important stuff 107 | $return .= "\n" . '-- PHP Configuration' . "\n\n"; 108 | $return .= 'Safe Mode: ' . ( ini_get( 'safe_mode' ) ? 'Enabled' : 'Disabled' . "\n" ); 109 | 110 | if ( function_exists( 'exec' ) ) { 111 | $exec = 'Enabled'; 112 | } else { 113 | $exec = 'Disabled'; 114 | } 115 | 116 | $return .= 'Exec Enabled: ' . $exec . "\n"; 117 | $return .= 'Memory Limit: ' . ini_get( 'memory_limit' ) . "\n"; 118 | $return .= 'Upload Max Size: ' . ini_get( 'upload_max_filesize' ) . "\n"; 119 | $return .= 'Post Max Size: ' . ini_get( 'post_max_size' ) . "\n"; 120 | $return .= 'Upload Max Filesize: ' . ini_get( 'upload_max_filesize' ) . "\n"; 121 | $return .= 'Time Limit: ' . ini_get( 'max_execution_time' ) . "\n"; 122 | $return .= 'Max Input Vars: ' . ini_get( 'max_input_vars' ) . "\n"; 123 | $return .= 'Display Errors: ' . ( ini_get( 'display_errors' ) ? 'On (' . ini_get( 'display_errors' ) . ')' : 'N/A' ) . "\n"; 124 | 125 | // WordPress active plugins 126 | $return .= "\n" . '-- WordPress Active Plugins' . "\n\n"; 127 | $plugins = get_plugins(); 128 | $active_plugins = get_option( 'active_plugins', array() ); 129 | foreach( $plugins as $plugin_path => $plugin ) { 130 | if( !in_array( $plugin_path, $active_plugins ) ) 131 | continue; 132 | $return .= $plugin['Name'] . ': ' . $plugin['Version'] . "\n"; 133 | } 134 | 135 | // WordPress inactive plugins 136 | $return .= "\n" . '-- WordPress Inactive Plugins' . "\n\n"; 137 | foreach( $plugins as $plugin_path => $plugin ) { 138 | if( in_array( $plugin_path, $active_plugins ) ) 139 | continue; 140 | $return .= $plugin['Name'] . ': ' . $plugin['Version'] . "\n"; 141 | } 142 | 143 | if( is_multisite() ) { 144 | // WordPress Multisite active plugins 145 | $return .= "\n" . '-- Network Active Plugins' . "\n\n"; 146 | $plugins = wp_get_active_network_plugins(); 147 | $active_plugins = get_site_option( 'active_sitewide_plugins', array() ); 148 | foreach( $plugins as $plugin_path ) { 149 | $plugin_base = plugin_basename( $plugin_path ); 150 | if( !array_key_exists( $plugin_base, $active_plugins ) ) 151 | continue; 152 | $plugin = get_plugin_data( $plugin_path ); 153 | $return .= $plugin['Name'] . ': ' . $plugin['Version'] . "\n"; 154 | } 155 | } 156 | 157 | $return .= "\n" . '### End System Info ###'; 158 | return $return; 159 | } 160 | 161 | /** 162 | * Determines the current operating system. 163 | * @access public 164 | * @return array 165 | */ 166 | public static function get_os() { 167 | $os = array(); 168 | $uname = php_uname( 's' ); 169 | $os['code'] = strtoupper( substr( $uname, 0, 3 ) ); 170 | $os['name'] = $uname; 171 | return $os; 172 | } 173 | 174 | /** 175 | * Gets the user running this PHP process. 176 | * @access public 177 | * @return string 178 | */ 179 | public static function get_user() { 180 | if ( function_exists( 'exec' ) ) { 181 | return exec( 'whoami' ); 182 | } 183 | return __( 'Unknown', 'revisr' ); 184 | } 185 | 186 | /** 187 | * Tries to guess the install path to the provided program. 188 | * @access public 189 | * @param string $program The program to check for. 190 | * @return string 191 | */ 192 | public static function guess_path( $program ) { 193 | $os = Revisr_Compatibility::get_os(); 194 | $program = Revisr_Admin::escapeshellarg( $program ); 195 | 196 | if ( $os['code'] !== 'WIN' ) { 197 | $path = exec( "which $program" ); 198 | } else { 199 | $path = exec( "where $program" ); 200 | } 201 | 202 | if ( $path ) { 203 | return $path; 204 | } else { 205 | return __( 'Not Found', 'revisr' ); 206 | } 207 | } 208 | 209 | /** 210 | * Checks if the exec() function is enabled. 211 | * @access public 212 | * @return string 213 | */ 214 | public static function server_has_exec() { 215 | if ( function_exists( 'exec' ) ) { 216 | return 'true'; 217 | } 218 | return 'false'; 219 | } 220 | 221 | /** 222 | * Checks if Revisr has write permissions to the repository. 223 | * @access public 224 | * @param string $path The path to the repository. 225 | * @return string 226 | */ 227 | public static function server_has_permissions( $path ) { 228 | if ( ! is_writable( $path ) || ! is_writeable( $path . DIRECTORY_SEPARATOR . 'config' ) ) { 229 | return 'false'; 230 | } 231 | return 'true'; 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /classes/class-revisr-cron.php: -------------------------------------------------------------------------------- 1 | 604800, 27 | 'display' => __( 'Weekly', 'revisr' ) 28 | ); 29 | return $schedules; 30 | } 31 | 32 | /** 33 | * The main "automatic backup" event. 34 | * @access public 35 | */ 36 | public function run_automatic_backup() { 37 | 38 | revisr()->git = new Revisr_Git(); 39 | revisr()->db = new Revisr_DB(); 40 | $backup_type = revisr()->git->get_config( 'revisr', 'automatic-backups' ) ? revisr()->git->get_config( 'revisr', 'automatic-backups' ) : 'none'; 41 | 42 | // Make sure backups have been enabled for this environment. 43 | if ( 'none' !== $backup_type ) { 44 | 45 | // Defaults. 46 | $date = date("F j, Y"); 47 | $files = revisr()->git->status() ? revisr()->git->status() : array(); 48 | $commit_msg = sprintf( __( '%s backup - %s', 'revisr' ), ucfirst( $backup_type ), $date ); 49 | 50 | // Stage the files and commit. 51 | revisr()->git->stage_files( $files ); 52 | revisr()->git->commit( $commit_msg ); 53 | 54 | // Backup the DB. 55 | revisr()->db->backup(); 56 | 57 | // Log result - TODO: improve error handling as necessary. 58 | $log_msg = sprintf( __( 'The %s backup was successful.', 'revisr' ), $backup_type ); 59 | Revisr_Admin::log( $log_msg, 'backup' ); 60 | 61 | } 62 | 63 | } 64 | 65 | /** 66 | * Processes the "auto-pull" functionality. 67 | * @access public 68 | */ 69 | public function run_autopull() { 70 | 71 | revisr()->git = new Revisr_Git(); 72 | 73 | // If auto-pull isn't enabled, we definitely don't want to do this. 74 | if ( revisr()->git->get_config( 'revisr', 'auto-pull' ) !== 'true' ) { 75 | wp_die( __( 'Cheatin’ uh?', 'revisr' ) ); 76 | } 77 | 78 | // Verify the provided token matches the token stored locally. 79 | $remote = new Revisr_Remote(); 80 | $remote->check_token(); 81 | 82 | // If we're still running at this point, we've successfully authenticated. 83 | revisr()->git->reset(); 84 | revisr()->git->fetch(); 85 | 86 | // Grab the commits that need to be pulled. 87 | $commits_since = revisr()->git->run( 'log', array( revisr()->git->branch . '..' . revisr()->git->remote . '/' . revisr()->git->branch, '--pretty=oneline' ) ); 88 | 89 | // Maybe backup the database. 90 | if ( revisr()->git->get_config( 'revisr', 'import-pulls' ) === 'true' ) { 91 | revisr()->db = new Revisr_DB(); 92 | revisr()->db->backup(); 93 | $undo_hash = revisr()->git->current_commit(); 94 | revisr()->git->set_config( 'revisr', 'last-db-backup', $undo_hash ); 95 | } 96 | 97 | // Pull the changes or return an error on failure. 98 | revisr()->git->pull( $commits_since ); 99 | 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /classes/class-revisr-db-backup.php: -------------------------------------------------------------------------------- 1 | build_conn( $table ); 28 | 29 | // Grab the path to use for mysqldump. 30 | $path = $this->get_path(); 31 | 32 | // Backup the table. 33 | $current_dir = getcwd(); 34 | chdir( $this->backup_dir ); 35 | exec( "{$path}mysqldump $conn > revisr_$table.sql --skip-comments", $output, $return_code ); 36 | chdir( $current_dir ); 37 | 38 | // Handle any errors 39 | if ( 0 !== $return_code ) { 40 | return false; 41 | } 42 | 43 | // Add the table into version control. 44 | $this->add_table( $table ); 45 | 46 | // Makes sure that the backup file exists and is not empty. 47 | return $this->verify_backup( $table ); 48 | 49 | } 50 | 51 | /** 52 | * Backs up a single database table using the WordPress database class. 53 | * @access public 54 | * @param string $table The database table to backup. 55 | * @return boolean 56 | */ 57 | public function backup_table_wpdb( $table ) { 58 | 59 | $table = esc_sql( $table ); 60 | 61 | // Initialize the results, ultimately stored in the backup file. 62 | $results = ''; 63 | 64 | // An empty array to store the queries for the table in later. 65 | $queries = array(); 66 | 67 | // Grab the SQL needed to create the table. 68 | $show_create = $this->wpdb->get_row( "SHOW CREATE TABLE `$table`" ); 69 | $want = 'Create Table'; 70 | 71 | if ( $show_create ) { 72 | 73 | // Store the table schema in the backup file. 74 | $results .= "DROP TABLE IF EXISTS `$table`;" . PHP_EOL; 75 | $results .= $show_create->$want . ';' . PHP_EOL; 76 | 77 | // Grab the content of the database table. 78 | foreach ( $this->wpdb->get_results( "SELECT * FROM `$table`" ) as $row ) { 79 | 80 | $vals = array(); 81 | 82 | foreach ( get_object_vars( $row ) as $i => $v ) { 83 | $vals[] = sprintf( "'%s'", esc_sql( $v ) ); 84 | } 85 | 86 | $queries[] = sprintf( "(%s)", implode( ',', $vals ) ); 87 | } 88 | 89 | if ( ! empty( $queries ) ) { 90 | // Implode the queries and generate the rest of the SQL file. 91 | $results .= "LOCK TABLES `$table` WRITE;" . PHP_EOL; 92 | $results .= "INSERT INTO `$table` VALUES " . implode( ', ', $queries ) . ';' . PHP_EOL; 93 | $results .= 'UNLOCK TABLES;' . PHP_EOL; 94 | } 95 | 96 | } 97 | 98 | // Store the contents of the SQL file. 99 | file_put_contents( $this->backup_dir . "revisr_$table.sql", $results ); 100 | $this->add_table( $table ); 101 | 102 | // Verify the backup was successful and return a boolean. 103 | return $this->verify_backup( $table ); 104 | } 105 | 106 | /** 107 | * Processes the results and alerts the user as necessary. 108 | * @access public 109 | * @param array $args An array containing the results of the backup. 110 | * @return boolean 111 | */ 112 | public function callback( $args ) { 113 | 114 | if ( in_array( false, $args ) ) { 115 | $msg = __( 'Error backing up the database.', 'revisr' ); 116 | Revisr_Admin::alert( $msg, true ); 117 | Revisr_Admin::log( $msg, 'error' ); 118 | } else { 119 | $msg = __( 'Successfully backed up the database.', 'revisr' ); 120 | Revisr_Admin::alert( $msg ); 121 | Revisr_Admin::log( $msg, 'backup' ); 122 | 123 | // Fires after a successful database backup. 124 | do_action( 'revisr_post_db_backup' ); 125 | 126 | return true; 127 | } 128 | 129 | return false; 130 | } 131 | 132 | } 133 | 134 | -------------------------------------------------------------------------------- /classes/class-revisr-db-import.php: -------------------------------------------------------------------------------- 1 | build_conn(); 28 | 29 | // Grab the path to use for MySQL. 30 | $path = $this->get_path(); 31 | 32 | // Grab the site url. 33 | $live_url = site_url(); 34 | 35 | // Import the table. 36 | $current_dir = getcwd(); 37 | chdir( $this->backup_dir ); 38 | exec( "{$path}mysql {$conn} < revisr_$table.sql", $output, $return_code ); 39 | chdir( $current_dir ); 40 | 41 | // Handle any errors. 42 | if ( 0 !== $return_code ) { 43 | Revisr_Admin::log( implode( '
', $output ), 'error' ); 44 | return false; 45 | } 46 | 47 | // Run a search replace if necessary. 48 | if ( $replace_url !== '' && $replace_url !== false ) { 49 | $this->revisr_srdb( $table, $replace_url, $live_url ); 50 | } 51 | 52 | // If we're still running at this point, everything worked. 53 | return true; 54 | } 55 | 56 | /** 57 | * Imports a single database table using the WordPress database class. 58 | * @access public 59 | * @param string $table The table to import 60 | * @return array An array of the results. 61 | */ 62 | public function import_table_wpdb( $table, $replace_url = '' ) { 63 | 64 | $live_url = site_url(); 65 | $fh = fopen( "{$this->backup_dir}revisr_$table.sql", 'r' ); 66 | $size = filesize( "{$this->backup_dir}revisr_$table.sql" ); 67 | $status = array( 68 | 'errors' => 0, 69 | 'updates' => 0 70 | ); 71 | 72 | while( !feof( $fh ) ) { 73 | $query = trim( stream_get_line( $fh, $size, ';' . PHP_EOL ) ); 74 | if ( empty( $query ) ) { 75 | $status['dropped_queries'][] = $query; 76 | continue; 77 | } 78 | if ( $this->wpdb->query( $query ) === false ) { 79 | $status['errors']++; 80 | $status['bad_queries'][] = $query; 81 | } else { 82 | $status['updates']++; 83 | $status['good_queries'][] = $query; 84 | } 85 | } 86 | 87 | fclose( $fh ); 88 | 89 | if ( '' !== $replace_url ) { 90 | $this->revisr_srdb( $table, $replace_url, $live_url ); 91 | } 92 | 93 | if ( 0 !== $status['errors'] ) { 94 | return false; 95 | } 96 | return true; 97 | } 98 | 99 | /** 100 | * Processes the results and alerts the user as necessary. 101 | * @access public 102 | * @param array $args An array containing the results of the backup. 103 | * @return boolean 104 | */ 105 | public function callback( $args ) { 106 | 107 | if ( in_array( false, $args ) ) { 108 | 109 | // There were one or more errors with the import. 110 | $msg = __( 'Error importing the database.', 'revisr' ); 111 | Revisr_Admin::log( $msg, 'error' ); 112 | Revisr_Admin::alert( $msg, true ); 113 | 114 | } else { 115 | 116 | // Everything imported properly. 117 | $get_hash = revisr()->git->run( 'config', array( 'revisr.last-db-backup' ) ); 118 | $revert_link = ''; 119 | 120 | if ( is_array( $get_hash ) ) { 121 | $undo_hash = $get_hash[0]; 122 | $undo_url = get_admin_url() . 'admin-post.php?action=process_revert&revert_type=db&db_hash=' . $undo_hash; 123 | $undo_nonced = wp_nonce_url( $undo_url, 'revisr_revert_nonce', 'revisr_revert_nonce' ); 124 | $revert_link = '' . __( 'Undo', 'revisr') . ''; 125 | revisr()->git->run( 'config', array( '--unset', 'revisr.last-db-backup' ) ); 126 | } 127 | 128 | // Alert the user. 129 | $msg = sprintf( __( 'Successfully imported the database. %s', 'revisr'), $revert_link ); 130 | Revisr_Admin::log( $msg, 'import' ); 131 | Revisr_Admin::alert( $msg ); 132 | 133 | // Fires after a successful database import. 134 | do_action( 'revisr_post_db_import' ); 135 | 136 | return true; 137 | } 138 | 139 | return false; 140 | } 141 | 142 | /** 143 | * Gets the columns in a table. 144 | * @access public 145 | * @param string $table The table to check. 146 | * @return array 147 | */ 148 | public function get_columns( $table ) { 149 | $primary_key = null; 150 | $columns = array(); 151 | $fields = $this->wpdb->get_results( 'DESCRIBE ' . $table ); 152 | 153 | if ( is_array( $fields ) ) { 154 | foreach ( $fields as $column ) { 155 | $columns[] = $column->Field; 156 | if ( $column->Key == 'PRI' ) { 157 | $primary_key = $column->Field; 158 | } 159 | } 160 | } 161 | 162 | return array( $primary_key, $columns ); 163 | } 164 | 165 | /** 166 | * Adapated from interconnect/it's search/replace script. 167 | * Modified to use WordPress wpdb functions instead of PHP's native mysql/pdo functions. 168 | * 169 | * @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/ 170 | * 171 | * @access private 172 | * @param string $table The table to run the replacement on. 173 | * @param string $search The string to replace. 174 | * @param string $replace The string to replace with. 175 | * @return boolean 176 | */ 177 | private function revisr_srdb( $table, $search = '', $replace = '' ) { 178 | 179 | $table = esc_sql( $table ); 180 | 181 | // Get a list of columns in this table. 182 | list( $primary_key, $columns ) = $this->get_columns( $table ); 183 | 184 | // Bail out early if there isn't a primary key. 185 | if ( null === $primary_key ) { 186 | return false; 187 | } 188 | 189 | // Count the number of rows we have in the table if large we'll split into blocks, This is a mod from Simon Wheatley 190 | $row_count = $this->wpdb->get_var( "SELECT COUNT(*) FROM $table" ); 191 | if ( $row_count == 0 ) { 192 | return true; 193 | } 194 | 195 | $page_size = 50000; 196 | $pages = ceil( $row_count / $page_size ); 197 | 198 | for( $page = 0; $page < $pages; $page++ ) { 199 | 200 | $current_row = 0; 201 | $start = $page * $page_size; 202 | $end = $page_size; 203 | 204 | // Grab the content of the table. 205 | $data = $this->wpdb->get_results( "SELECT * FROM $table LIMIT $start, $end", ARRAY_A ); 206 | 207 | // Loop through the data. 208 | foreach ( $data as $row ) { 209 | $current_row++; 210 | $update_sql = array(); 211 | $where_sql = array(); 212 | $upd = false; 213 | 214 | foreach( $columns as $column ) { 215 | 216 | $data_to_fix = $row[ $column ]; 217 | 218 | if ( $column == $primary_key ) { 219 | $where_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $data_to_fix ) . '"'; 220 | continue; 221 | } 222 | 223 | // Run a search replace on the data that'll respect the serialisation. 224 | $edited_data = $this->recursive_unserialize_replace( $search, $replace, $data_to_fix ); 225 | 226 | // Something was changed 227 | if ( $edited_data != $data_to_fix ) { 228 | $update_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $edited_data ) . '"'; 229 | $upd = true; 230 | } 231 | 232 | } 233 | 234 | if ( $upd && ! empty( $where_sql ) ) { 235 | $sql = 'UPDATE ' . $table . ' SET ' . implode( ', ', $update_sql ) . ' WHERE ' . implode( ' AND ', array_filter( $where_sql ) ); 236 | $result = $this->wpdb->query( $sql ); 237 | if ( ! $result ) { 238 | $error_msg = sprintf( __( 'Error updating the table: %s.', 'revisr' ), $table ); 239 | } 240 | } 241 | 242 | } 243 | 244 | } 245 | 246 | $this->wpdb->flush(); 247 | if ( isset( $error_msg ) ) { 248 | Revisr_Admin::log( $error_msg, 'error' ); 249 | return false; 250 | } 251 | 252 | } 253 | 254 | /** 255 | * Adapated from interconnect/it's search/replace script. 256 | * 257 | * @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/ 258 | * 259 | * Take a serialised array and unserialise it replacing elements as needed and 260 | * unserialising any subordinate arrays and performing the replace on those too. 261 | * 262 | * @access private 263 | * @param string $from String we're looking to replace. 264 | * @param string $to What we want it to be replaced with. 265 | * @param array $data Used to pass any subordinate arrays back to in. 266 | * @param bool $serialised Does the array passed via $data need serialising. 267 | * 268 | * @return string|array The original array with all elements replaced as needed. 269 | */ 270 | private function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialised = false ) { 271 | try { 272 | 273 | if ( is_string( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) { 274 | $data = $this->recursive_unserialize_replace( $from, $to, $unserialized, true ); 275 | } 276 | 277 | elseif ( is_array( $data ) ) { 278 | $_tmp = array( ); 279 | foreach ( $data as $key => $value ) { 280 | $_tmp[ $key ] = $this->recursive_unserialize_replace( $from, $to, $value, false ); 281 | } 282 | 283 | $data = $_tmp; 284 | unset( $_tmp ); 285 | } 286 | 287 | // Submitted by Tina Matter 288 | elseif ( is_object( $data ) ) { 289 | // $data_class = get_class( $data ); 290 | $_tmp = $data; // new $data_class( ); 291 | $props = get_object_vars( $data ); 292 | foreach ( $props as $key => $value ) { 293 | $_tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false ); 294 | } 295 | 296 | $data = $_tmp; 297 | unset( $_tmp ); 298 | } 299 | 300 | else { 301 | if ( is_string( $data ) ) 302 | $data = str_replace( $from, $to, $data ); 303 | } 304 | 305 | if ( $serialised ) 306 | return serialize( $data ); 307 | 308 | } catch( Exception $error ) { 309 | Revisr_Admin::log( $error, 'error' ); 310 | } 311 | 312 | return $data; 313 | } 314 | 315 | } 316 | -------------------------------------------------------------------------------- /classes/class-revisr-i18n.php: -------------------------------------------------------------------------------- 1 | domain, 35 | false, 36 | dirname( dirname( plugin_basename( __FILE__ ) ) ) . 'languages/' 37 | ); 38 | } 39 | 40 | /** 41 | * Set the domain equal to that of the specified domain. 42 | * @access public 43 | * @param string $domain The domain that represents the locale of this plugin. 44 | */ 45 | public function set_domain( $domain ) { 46 | $this->domain = $domain; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /classes/class-revisr-meta-boxes.php: -------------------------------------------------------------------------------- 1 | 2, 'default' => 2 ) ); 32 | } 33 | 34 | /** 35 | * Initializes JS for the Revisr custom meta boxes. 36 | * @access public 37 | */ 38 | public function init_meta_boxes() { 39 | ?> 40 | 41 | git->status(); 63 | $total_pending = count( $output ); 64 | $text = sprintf( __( 'There are %s untracked files that can be added to this commit.', 'revisr' ), $total_pending, revisr()->git->branch ); 65 | echo "
" . $text . "

"; 66 | _e( 'Use the boxes below to select the files to include in this commit. Only files in the "Staged Files" section will be included.
Double-click files marked as "Modified" to view the changes to the file.

', 'revisr' ); 67 | if ( is_array( $output ) ) { 68 | ?> 69 | 70 |
71 |

72 | 84 |
85 | 86 |
87 | 88 |
89 |
90 |
91 | 92 | 93 |
94 |

95 | 97 |
98 | 99 |
100 | 101 |
102 |
103 | 104 |
'; 121 | 122 | // Files were included in this commit. 123 | if ( 0 !== count( $commit['committed_files'] ) ) { 124 | 125 | printf( __('
%s files were included in this commit. Double-click files marked as "Modified" to view the changes in a diff.', 'revisr' ), $commit['files_changed'] ); 126 | 127 | echo ''; 128 | echo '

'; 142 | 143 | } else { 144 | printf( '

%s

', __( 'No files were included in this commit.', 'revisr' ) ); 145 | } 146 | 147 | echo '
'; 148 | 149 | } 150 | 151 | /** 152 | * Displays the "Add Tag" meta box on the sidebar. 153 | * @access public 154 | */ 155 | public function add_tag_meta() { 156 | printf( 157 | ' 158 | ', 159 | __( 'Tag Name:', 'revisr' ) 160 | ); 161 | } 162 | 163 | /** 164 | * Displays the "Save Commit" meta box in the sidebar. 165 | * @access public 166 | */ 167 | public function save_commit_meta() { 168 | ?> 169 | 170 |
171 |
172 | 173 |
174 | 175 | 176 |
177 | 178 |
179 | 180 | git->branch; ?> 181 |
182 | 183 |
184 | 185 | 186 |
187 | 188 |
189 | git->get_config( 'revisr', 'auto-push' ) == 'true' ): ?> 190 | 191 | 192 | 193 | 194 | 195 | 196 |
197 | 198 |
199 |
200 | 201 |
202 |
203 |
204 | 205 | 206 | 207 |
208 |
209 |
210 | 211 | %s', 'revisr' ), date_i18n( $time_format, $commit['time'] ) ); 228 | 229 | if ( false === $commit['status'] ) { 230 | $commit['status'] = __( 'Error', 'revisr' ); 231 | $revert_btn = '' . __( 'Revert to this Commit', 'revisr' ) . ''; 232 | } else { 233 | $revert_btn = '' . __( 'Revert to this Commit', 'revisr' ) . ''; 234 | } 235 | 236 | ?> 237 |
238 |
239 | 240 |
241 | 242 | 243 |
244 | 245 |
246 | 247 | 248 |
249 | 250 |
251 | 252 |
253 | 254 | 255 |
256 | 257 | 258 |
259 | 260 | 261 |
262 |
263 | 264 |
265 |
266 |
267 | 268 | 269 |
270 |
271 |
272 | 281 |
"; 282 | } 283 | 284 | } 285 | -------------------------------------------------------------------------------- /classes/class-revisr-remote.php: -------------------------------------------------------------------------------- 1 | git->get_config( 'revisr', 'token' ); 25 | 26 | if ( $check === false ) { 27 | 28 | // If there is no token, generate a new one and save it. 29 | $token = wp_generate_password( 16, false, false ); 30 | revisr()->git->set_config( 'revisr', 'token', $token ); 31 | 32 | // Make sure that the token saved correctly. 33 | $new_token = revisr()->git->get_config( 'revisr', 'token' ); 34 | if ( is_string( $new_token ) && hash_equals( $new_token, $token ) ) { 35 | if ( $new_token !== false ) { 36 | return $new_token; 37 | } 38 | } else { 39 | return false; 40 | } 41 | 42 | } else { 43 | // Return the already saved token. 44 | return $check; 45 | } 46 | } 47 | 48 | /** 49 | * Verifies a token is valid. 50 | * @access public 51 | * @return boolean 52 | */ 53 | public function check_token( $token = '' ) { 54 | 55 | // Allow testing of this function. 56 | if ( $token !== '' ) { 57 | $token_to_check = $token; 58 | } 59 | 60 | // This is set in the Webhook URL. 61 | if ( isset( $_REQUEST['token'] ) && $_REQUEST['token'] !== '' ) { 62 | $token_to_check = $_REQUEST['token']; 63 | } 64 | 65 | // Compare the tokens and return true if a complete match. 66 | if ( isset( $token_to_check ) ) { 67 | $safe_token = revisr()->git->get_config( 'revisr', 'token' ); 68 | if ( hash_equals( $safe_token, $token_to_check ) ) { 69 | return true; 70 | } 71 | } 72 | 73 | // Die if not. 74 | wp_die( __( 'Cheatin’ uh?', 'revisr' ) ); 75 | } 76 | 77 | /** 78 | * Sends a new HTTP request to the live site. 79 | * @access public 80 | */ 81 | public function send_request() { 82 | $body = array( 83 | 'action' => 'revisr_update' 84 | ); 85 | $args = array( 86 | 'method' => 'POST', 87 | 'timeout' => '30', 88 | 'redirection' => '5', 89 | 'httpversion' => '1.0', 90 | 'blocking' => true, 91 | 'headers' => array(), 92 | 'body' => $body 93 | ); 94 | 95 | // Get the URL and send the request. 96 | $get_url = revisr()->git->get_config( 'revisr', 'webhook-url' ); 97 | 98 | if ( $get_url !== false ) { 99 | $webhook = urldecode( $get_url ); 100 | $request = wp_remote_post( $webhook, $args ); 101 | if ( is_wp_error( $request ) ) { 102 | Revisr_Admin::log( __( 'Error contacting webhook URL.', 'revisr' ), 'error' ); 103 | } else { 104 | Revisr_Admin::log( __( 'Sent update request to the webhook.', 'revisr' ), 'push' ); 105 | } 106 | } 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /classes/class-revisr-settings.php: -------------------------------------------------------------------------------- 1 | settings_fields = new Revisr_Settings_Fields(); 30 | } 31 | 32 | /** 33 | * Initialize the settings. 34 | * @access public 35 | */ 36 | public function init_settings() { 37 | $this->revisr_add_settings_sections(); 38 | $this->revisr_add_settings_fields(); 39 | $this->revisr_register_settings(); 40 | } 41 | 42 | /** 43 | * Registers the settings sections. 44 | * @access public 45 | */ 46 | public function revisr_add_settings_sections() { 47 | add_settings_section( 48 | 'revisr_general_settings', 49 | 'General Settings', 50 | array( $this->settings_fields, 'revisr_general_settings_callback' ), 51 | 'revisr_general_settings' 52 | ); 53 | add_settings_section( 54 | 'revisr_remote_settings', 55 | 'Repository Settings', 56 | array( $this->settings_fields, 'revisr_remote_settings_callback' ), 57 | 'revisr_remote_settings' 58 | ); 59 | add_settings_section( 60 | 'revisr_database_settings', 61 | 'Database Settings', 62 | array( $this->settings_fields, 'revisr_database_settings_callback' ), 63 | 'revisr_database_settings' 64 | ); 65 | } 66 | 67 | /** 68 | * Registers the settings fields. 69 | * @access public 70 | */ 71 | public function revisr_add_settings_fields() { 72 | add_settings_field( 73 | 'username', 74 | __( 'Git Username', 'revisr' ), 75 | array( $this->settings_fields, 'username_callback' ), 76 | 'revisr_general_settings', 77 | 'revisr_general_settings' 78 | ); 79 | add_settings_field( 80 | 'email', 81 | __( 'Git Email', 'revisr'), 82 | array( $this->settings_fields, 'email_callback' ), 83 | 'revisr_general_settings', 84 | 'revisr_general_settings' 85 | ); 86 | add_settings_field( 87 | 'git_path', 88 | __( 'Git Path', 'revisr' ), 89 | array( $this->settings_fields, 'git_path_callback' ), 90 | 'revisr_general_settings', 91 | 'revisr_general_settings' 92 | ); 93 | add_settings_field( 94 | 'gitignore', 95 | __( 'Files/Directories to ignore', 'revisr'), 96 | array( $this->settings_fields, 'gitignore_callback' ), 97 | 'revisr_general_settings', 98 | 'revisr_general_settings' 99 | ); 100 | add_settings_field( 101 | 'automatic_backups', 102 | __( 'Automatic backup schedule', 'revisr' ), 103 | array( $this->settings_fields, 'automatic_backups_callback' ), 104 | 'revisr_general_settings', 105 | 'revisr_general_settings' 106 | ); 107 | add_settings_field( 108 | 'notifications', 109 | __( 'Enable email notifications?', 'revisr' ), 110 | array( $this->settings_fields, 'notifications_callback' ), 111 | 'revisr_general_settings', 112 | 'revisr_general_settings' 113 | ); 114 | add_settings_field( 115 | 'uninstall_on_delete', 116 | __( 'Remove data on uninstall?', 'revisr' ), 117 | array( $this->settings_fields, 'uninstall_on_delete_callback' ), 118 | 'revisr_general_settings', 119 | 'revisr_general_settings' 120 | ); 121 | add_settings_field( 122 | 'remote_name', 123 | __( 'Remote Name', 'revisr'), 124 | array( $this->settings_fields, 'remote_name_callback' ), 125 | 'revisr_remote_settings', 126 | 'revisr_remote_settings' 127 | ); 128 | add_settings_field( 129 | 'remote_url', 130 | __( 'Remote URL', 'revisr'), 131 | array( $this->settings_fields, 'remote_url_callback' ), 132 | 'revisr_remote_settings', 133 | 'revisr_remote_settings' 134 | ); 135 | add_settings_field( 136 | 'webhook_url', 137 | __( 'Revisr Webhook URL', 'revisr' ), 138 | array( $this->settings_fields, 'webhook_url_callback' ), 139 | 'revisr_remote_settings', 140 | 'revisr_remote_settings' 141 | ); 142 | add_settings_field( 143 | 'auto_push', 144 | __( 'Automatically push new commits?', 'revisr' ), 145 | array( $this->settings_fields, 'auto_push_callback' ), 146 | 'revisr_remote_settings', 147 | 'revisr_remote_settings' 148 | ); 149 | add_settings_field( 150 | 'auto_pull', 151 | __( 'Automatically pull new commits?', 'revisr' ), 152 | array( $this->settings_fields, 'auto_pull_callback' ), 153 | 'revisr_remote_settings', 154 | 'revisr_remote_settings' 155 | ); 156 | add_settings_field( 157 | 'tracked_tables', 158 | __( 'Database tables to track', 'revisr' ), 159 | array( $this->settings_fields, 'tracked_tables_callback' ), 160 | 'revisr_database_settings', 161 | 'revisr_database_settings' 162 | ); 163 | add_settings_field( 164 | 'reset_db', 165 | __( 'Import Options', 'revisr' ), 166 | array( $this->settings_fields, 'reset_db_callback' ), 167 | 'revisr_database_settings', 168 | 'revisr_database_settings' 169 | ); 170 | add_settings_field( 171 | 'development_url', 172 | __( 'Development URL', 'revisr'), 173 | array( $this->settings_fields, 'development_url_callback' ), 174 | 'revisr_database_settings', 175 | 'revisr_database_settings' 176 | ); 177 | add_settings_field( 178 | 'db_driver', 179 | __( 'Database Driver', 'revisr' ), 180 | array( $this->settings_fields, 'db_driver_callback' ), 181 | 'revisr_database_settings', 182 | 'revisr_database_settings' 183 | ); 184 | add_settings_field( 185 | 'mysql_path', 186 | __( 'Path to MySQL', 'revisr' ), 187 | array( $this->settings_fields, 'mysql_path_callback' ), 188 | 'revisr_database_settings', 189 | 'revisr_database_settings' 190 | ); 191 | } 192 | 193 | /** 194 | * Register the settings fields with WordPress. 195 | * @access public 196 | */ 197 | public function revisr_register_settings() { 198 | register_setting( 199 | 'revisr_general_settings', 200 | 'revisr_general_settings' 201 | ); 202 | register_setting( 203 | 'revisr_remote_settings', 204 | 'revisr_remote_settings', 205 | array( $this, 'sanitize_remote' ) 206 | ); 207 | register_setting( 208 | 'revisr_database_settings', 209 | 'revisr_database_settings' 210 | ); 211 | } 212 | 213 | /** 214 | * Sanitizes the "Remote Settings" fields so that URL's can be stored. 215 | * @access public 216 | * @param array $input The data from the form. 217 | * @return array 218 | */ 219 | public function sanitize_remote( $input ) { 220 | if ( isset( $input['webhook_url'] ) ) { 221 | $input['webhook_url'] = urlencode( $input['webhook_url'] ); 222 | } 223 | return $input; 224 | } 225 | 226 | } 227 | -------------------------------------------------------------------------------- /classes/index.php: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | ./tests/ 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /templates/index.php: -------------------------------------------------------------------------------- 1 | branch_table->prepare_items(); 18 | 19 | ?> 20 | 21 |
22 | 23 |

24 | 25 |

' . $msg . '

'; 31 | break; 32 | case "create_error": 33 | $msg = __( 'Failed to create the new branch.', 'revisr' ); 34 | if ( revisr()->git->is_branch( $_GET['branch'] ) ) { 35 | $msg = sprintf( esc_html__( 'Failed to create branch: %s (branch already exists).', 'revisr' ), $_GET['branch'] ); 36 | } 37 | echo '

' . $msg . '

'; 38 | break; 39 | case "delete_success": 40 | $msg = sprintf( esc_html__( 'Successfully deleted branch: %s.', 'revisr' ), $_GET['branch'] ); 41 | echo '

' . $msg . '

'; 42 | break; 43 | case "delete_fail": 44 | $msg = sprintf( esc_html__( 'Failed to delete branch: %s.', 'revisr' ), $_GET['branch'] ); 45 | echo '

' . $msg . '

'; 46 | default: 47 | // Do nothing. 48 | } 49 | } 50 | ?> 51 | 52 |
53 | 54 |
55 |
56 | branch_table->display(); ?> 57 |
58 |
59 | 60 |
61 | 62 |
63 |

64 |
65 |
66 |
67 | 68 | 69 |


70 |
71 |
72 | 73 | 74 | 75 | 76 |

77 |
78 |
79 |
80 |
81 |
82 | 83 |
84 | 85 | 86 | -------------------------------------------------------------------------------- /templates/pages/commits.php: -------------------------------------------------------------------------------- 1 | commits_table->prepare_items(); 18 | 19 | // Gets current branches for filtering. 20 | $branches = revisr()->git->get_branches(); 21 | 22 | ?> 23 | 24 |
25 | 26 |

27 | 28 | commits_table->render_views(); ?> 29 | 30 |
31 | 32 | commits_table->render_search(); ?> 33 | commits_table->display(); ?> 34 |
35 | 36 |
37 | -------------------------------------------------------------------------------- /templates/pages/dashboard.php: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | activity_table->prepare_items(); 32 | ?> 33 | 34 |
35 |
36 |

37 |
38 |

39 | 40 |
41 | 42 |
43 |
44 | 45 | 46 |
47 |
48 | 49 |
50 | 51 | activity_table->display(); ?> 52 |
53 | 54 |
55 |
56 | 57 | 58 |
59 |
60 | 61 | 62 |
63 |

64 |
65 | 66 | | 67 | 68 | | 69 | | 70 |
71 |
72 | 73 | 74 | 75 |
76 |

77 |
78 |
79 |
    80 |
  • 81 |
  • 82 |
83 |
84 | 85 | 86 | git->get_branches(); 90 | 91 | if ( is_array( $branches ) && ! empty( $branches ) ) { 92 | 93 | foreach ( $branches as $key => $value ){ 94 | 95 | $branch = substr( $value, 2 ); 96 | 97 | if ( '*' === substr( $value, 0, 1 ) ) { 98 | printf( '', 99 | $branch, 100 | __( 'Checked Out', 'revisr' ) 101 | ); 102 | } else { 103 | $branch_url = wp_nonce_url( $admin_url . "admin-post.php?action=process_checkout&branch={$branch}", 'process_checkout', 'revisr_checkout_nonce' ); 104 | printf( '', 105 | $branch, 106 | $branch_url, 107 | __( 'Checkout', 'revisr' ) 108 | ); 109 | } 110 | 111 | } 112 | 113 | } else { 114 | printf( '', __( 'No branches found.', 'revisr' ) ); 115 | } 116 | ?> 117 |
%s%s
%s%s
%s
118 |
119 | 120 | 155 | 156 |
157 |

158 |
159 | 160 |
161 | 162 |
163 | 164 |
165 | 166 | 167 |
168 |

169 |
170 | http://docs.revisr.io' ); ?> 171 |

172 | 173 |
174 |
175 | 176 |
177 |
178 |
179 |
180 |
181 |
182 | 183 | 184 | -------------------------------------------------------------------------------- /templates/pages/help.php: -------------------------------------------------------------------------------- 1 | 15 | 16 |

17 | 18 |

plugin support forums.', 'revisr' ); ?>

19 | 20 |

GitHub!', 'revisr' ); ?>

21 | 22 |
23 | 24 |

25 | 26 | 27 | 28 | git->is_repo ) { 30 | $status_text = __( 'View Status', 'revisr' ); 31 | $status_nonce = wp_create_nonce( 'revisr_view_status' ); 32 | printf( '%s', 33 | get_admin_url() . 'admin-post.php?action=process_view_status&revisr_status_nonce=' . $status_nonce . '&TB_iframe=true', 34 | $status_text, 35 | $status_text 36 | ); 37 | } 38 | ?> 39 |

40 |
41 | -------------------------------------------------------------------------------- /templates/pages/index.php: -------------------------------------------------------------------------------- 1 | 17 | 18 |
19 | 20 |

21 | 22 | 23 | 24 |
25 | 26 | 27 | 32 | 33 |
34 | 35 |
36 | 37 |
38 |
39 |
40 | 41 |
42 |
43 |
44 | 45 |
46 | 47 |
48 | 49 |
50 | 51 |
52 | 53 |
54 | 55 |
56 | 57 |
58 | 59 |
60 | -------------------------------------------------------------------------------- /templates/pages/settings.php: -------------------------------------------------------------------------------- 1 | 18 |
19 |
20 |

21 | 22 |

Settings updated successfully.

', 'revisr' ); 26 | } 27 | if ( isset( $_GET['init'] ) && $_GET['init'] == 'success' ) { 28 | printf( '

%s

', 29 | __( 'Successfully initialized a new repository. Please confirm the settings below before creating your first commit.', 'revisr' ) 30 | ); 31 | } 32 | ?> 33 | 34 | 40 | 41 |
42 | 71 |
72 |
73 | 74 | -------------------------------------------------------------------------------- /templates/pages/view-commit.php: -------------------------------------------------------------------------------- 1 | 21 | 22 |
23 | 24 |

25 | 26 | %s.', 'revisr' ), revisr()->git->branch ); 29 | echo '

' . $msg . '

'; 30 | } 31 | ?> 32 | 33 |
34 | 35 | 36 | 41 | 42 |
43 | 44 |
45 | 46 |
47 |
48 |
49 | 50 |
51 |
52 |
53 | 54 |
55 | 56 |
57 | 58 |
59 | 60 |
61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 |
69 | -------------------------------------------------------------------------------- /templates/partials/checkout-remote-form.php: -------------------------------------------------------------------------------- 1 | git->current_remote() ) + 1 ); 20 | 21 | if ( revisr()->git->is_branch( $local ) ) { 22 | $text = sprintf( __( 'Revisr detected that local branch %s may already be tracking remote branch %s.

Do you want to checkout local branch %s?', 'revisr' ), $local, $remote, $local ); 23 | } else { 24 | $text = sprintf( __( 'This will checkout remote branch %s into a new local branch %s.', 'revisr' ), $remote, $local ); 25 | } 26 | 27 | ?> 28 | 29 | 30 | 31 |
32 | 33 |
34 |

35 | git->get_config( 'revisr', 'import-checkouts' ), 'true' ); ?> /> 36 | 37 |
38 | 39 |
40 | 41 | 42 | git->is_branch( $local ) ): ?> 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 | 52 |
53 | -------------------------------------------------------------------------------- /templates/partials/delete-branch-form.php: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | 23 |
24 | 25 |
26 | 27 | 28 |

This will delete all local work on branch %s.', 'revisr' ), $branch ); ?>

29 | 30 | 31 | 32 |

%s?', 'revisr' ), $branch ); ?>

33 | 34 | git->current_remote() ) + 1 ); ?> 35 | 36 | 37 |
38 | 39 |
40 | 41 | 42 | 43 | 44 |
45 | 46 |
47 | -------------------------------------------------------------------------------- /templates/partials/discard-form.php: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 |
23 | 24 |

25 |

26 | 27 |
28 | 29 |
30 | 31 |
32 | 33 | -------------------------------------------------------------------------------- /templates/partials/import-tables-form.php: -------------------------------------------------------------------------------- 1 | db->get_tables_not_in_db(); 18 | 19 | ?> 20 | 21 | 22 | 23 |
24 | 25 |
26 |

27 |
"; 30 | } 31 | ?> 32 |
33 | 34 |
35 | 36 | 37 | 38 |
39 | 40 |
41 | -------------------------------------------------------------------------------- /templates/partials/index.php: -------------------------------------------------------------------------------- 1 | %s into the current branch. In the event of conflicts, Revisr will keep the version from the branch being merged in.', 'revisr' ), esc_html( $_GET['branch'] ) ); 18 | 19 | ?> 20 | 21 | 22 | 23 |
24 | 25 |
26 |

27 | 28 | 29 |
30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 |
38 | 39 |
40 | -------------------------------------------------------------------------------- /templates/partials/pull-form.php: -------------------------------------------------------------------------------- 1 | git->run( 'log', array( revisr()->git->branch . '..' . revisr()->git->remote . '/' . revisr()->git->branch, '--format=%h - %s' ) ); 20 | 21 | // If none are detected, do an extra fetch, just to be sure. 22 | if ( is_array( $unpulled ) && 0 === count( $unpulled ) ) { 23 | revisr()->git->fetch(); 24 | $unpulled = revisr()->git->run( 'log', array( revisr()->git->branch . '..' . revisr()->git->remote . '/' . revisr()->git->branch, '--format=%h - %s' ) ); 25 | } 26 | 27 | ?> 28 | 29 | 30 | 31 |
32 | 33 |
34 | 35 | 36 | 37 |

38 | 39 |
    40 | 41 | 42 | 43 |
  • 44 | 45 | 46 | 47 |
48 | 49 | 50 | 51 |

52 | 53 | 54 | 55 |
56 | 57 |
58 | 59 |
60 | 61 |
62 | -------------------------------------------------------------------------------- /templates/partials/push-form.php: -------------------------------------------------------------------------------- 1 | git->run( 'log', array( revisr()->git->branch, '--not', '--remotes', '--oneline' ) ); 20 | 21 | ?> 22 | 23 | 24 | 25 |
26 | 27 |
28 | 29 | git->has_remote() ): ?> 30 | 31 |

32 | 33 | 34 | 35 |

36 | 37 |
    38 | 39 | 40 | 41 | ' . $hash . ''; 45 | $title = substr( $commit, 7 ); 46 | 47 | $commit_li = $link . $title; 48 | ?> 49 | 50 |
  • 51 | 52 | 53 | 54 |
55 | 56 | 57 | 58 |

59 | 60 | 61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 |
69 | -------------------------------------------------------------------------------- /templates/partials/revert-form.php: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | 23 |
24 | 25 |
26 | 27 |

28 | 29 |

30 | 31 | 32 |

33 | 38 |

39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 | 47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 |
55 | 56 |
57 | 58 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | revisr = revisr(); 15 | $this->revisr->git = new Revisr_Git(); 16 | $this->revisr->db = new Revisr_DB(); 17 | $this->revisr->admin = new Revisr_Admin(); 18 | } 19 | 20 | /** 21 | * Tests the alert() method. 22 | */ 23 | function test_alert() { 24 | // Tests for a standard alert. 25 | Revisr_Admin::alert( __( 'test_alert' ) ); 26 | $alert_transient = get_transient( 'revisr_alert' ); 27 | $this->assertEquals( 'test_alert', $alert_transient ); 28 | // Tests for an error. 29 | $this->revisr->admin->alert( 'test_error', true ); 30 | $error_transient = get_transient( 'revisr_error' ); 31 | $this->assertEquals( 'test_error', $error_transient ); 32 | } 33 | 34 | /** 35 | * Tests the Revisr_Admin::clear_transients() method. 36 | */ 37 | function test_clear_transients() { 38 | //First set a transient and make sure it exists. 39 | Revisr_Admin::alert( 'test_error', true ); 40 | $transient = get_transient( 'revisr_error' ); 41 | $this->assertEquals( 'test_error', $transient ); 42 | 43 | // Clear the transients and make sure they're really gone. 44 | Revisr_Admin::clear_transients(); 45 | $new_transient = get_transient( 'revisr_error' ); 46 | $this->assertEquals( false, $new_transient ); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /tests/test-compatibility.php: -------------------------------------------------------------------------------- 1 | assertArrayHasKey( 'code', $os ); 11 | $this->assertArrayHasKey( 'name', $os ); 12 | } 13 | 14 | /** 15 | * Tests the guess_path() method. 16 | */ 17 | function test_get_path() { 18 | $path = Revisr_Compatibility::guess_path( 'mysql' ); 19 | $this->assertContains( 'mysql', $path ); 20 | } 21 | 22 | /** 23 | * Tests the server_has_exec() method. 24 | */ 25 | function test_server_has_exec() { 26 | $this->assertEquals( 'true', Revisr_Compatibility::server_has_exec() ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /tests/test-db-backup.php: -------------------------------------------------------------------------------- 1 | revisr = revisr(); 23 | $this->revisr->git = new Revisr_Git; 24 | $this->revisr->db = new Revisr_DB; 25 | $this->backup = new Revisr_DB_Backup; 26 | } 27 | 28 | /** 29 | * Tests the Revisr_DB_Backup->backup_table_mysql() method. 30 | * @access public 31 | */ 32 | public function test_backup_table_mysql() { 33 | $backup = $this->backup->backup_table_mysql( 'wptests_posts' ); 34 | $verify = $this->revisr->db->verify_backup( 'wptests_posts' ); 35 | 36 | $this->assertEquals( true, $backup ); 37 | $this->assertEquals( true, $verify ); 38 | 39 | } 40 | 41 | /** 42 | * Tests the Revisr_DB_Backup->backup_table_wpdb() method. 43 | * @access public 44 | */ 45 | public function test_backup_table_wpdb() { 46 | $backup = $this->backup->backup_table_wpdb( 'wptests_posts' ); 47 | $verify = $this->revisr->db->verify_backup( 'wptests_posts' ); 48 | 49 | $this->assertEquals( true, $backup ); 50 | $this->assertEquals( true, $verify ); 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /tests/test-db-import.php: -------------------------------------------------------------------------------- 1 | revisr = revisr(); 23 | $this->revisr->git = new Revisr_Git; 24 | $this->revisr->db = new Revisr_DB; 25 | $this->import = new Revisr_DB_Import; 26 | } 27 | 28 | /** 29 | * Tests the Revisr_DB_Import->import_table_mysql method. 30 | * @access public 31 | */ 32 | public function test_import_table_mysql() { 33 | $import = $this->import->import_table_mysql( 'wptests_posts' ); 34 | $this->assertEquals( true, $import ); 35 | } 36 | 37 | /** 38 | * Tests the Revisr_DB_Import->import_table_wpdb method. 39 | * @access public 40 | */ 41 | public function test_import_table_wpdb() { 42 | $import = $this->import->import_table_wpdb( 'wptests_posts' ); 43 | $this->assertEquals( true, $import ); 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /tests/test-db.php: -------------------------------------------------------------------------------- 1 | revisr = revisr(); 15 | $this->revisr->git = new Revisr_Git(); 16 | $this->revisr->db = new Revisr_DB(); 17 | } 18 | 19 | /** 20 | * Tests the check_port_or_socket() function. 21 | */ 22 | function test_check_port_or_socket() { 23 | // Checks for ports or sockets. 24 | $no_port = $this->revisr->db->check_port_or_socket( 'localhost' ); 25 | $port = $this->revisr->db->check_port_or_socket( 'localhost:3306' ); 26 | $socket = $this->revisr->db->check_port_or_socket( 'localhost:/var/run/mysqld/mysqld.sock' ); 27 | $full_url = $this->revisr->db->check_port_or_socket( 'http://localhost:3306' ); 28 | 29 | // Runs the assertions. 30 | $this->assertEquals( false, $no_port ); 31 | 32 | $this->assertArrayHasKey( 'port', $port ); 33 | $this->assertArrayHasKey( 'socket', $port ); 34 | $this->assertEquals( 3306, $port['port'] ); 35 | $this->assertEquals( null, $port['socket'] ); 36 | 37 | $this->assertArrayHasKey( 'port', $socket ); 38 | $this->assertArrayHasKey( 'socket', $socket ); 39 | $this->assertEquals( null, $socket['port'] ); 40 | $this->assertEquals( '/var/run/mysqld/mysqld.sock', $socket['socket'] ); 41 | 42 | $this->assertArrayHasKey( 'port', $full_url ); 43 | $this->assertArrayHasKey( 'socket', $full_url ); 44 | $this->assertEquals( 3306, $full_url['port'] ); 45 | $this->assertEquals( null, $full_url['socket'] ); 46 | } 47 | 48 | /** 49 | * Tests the setup_env() method. 50 | */ 51 | function test_setup_env() { 52 | $this->assertFileExists( ABSPATH . 'wp-content/uploads/revisr-backups/.htaccess' ); 53 | $this->assertFileExists( ABSPATH . 'wp-content/uploads/revisr-backups/index.php' ); 54 | } 55 | 56 | /** 57 | * Tests the get_tables() method. 58 | */ 59 | function test_get_tables() { 60 | $tables = serialize( $this->revisr->db->get_tables() ); 61 | $this->assertContains( '_posts', $tables ); 62 | $this->assertContains( '_revisr', $tables ); 63 | 64 | } 65 | 66 | /** 67 | * Tests the get_sizes() method. 68 | */ 69 | function test_get_sizes() { 70 | global $wpdb; 71 | $sizes = $this->revisr->db->get_sizes(); 72 | $key = $wpdb->prefix . 'posts'; 73 | $this->assertArrayHasKey($key, $sizes ); 74 | $this->assertContains( 'MB)', $sizes[$key] ); 75 | } 76 | 77 | /** 78 | * Tests the get_tables_not_in_db() method. 79 | */ 80 | function test_get_tables_not_in_db() { 81 | file_put_contents( ABSPATH . 'wp-content/uploads/revisr-backups/revisr_faketable.sql', 'test' ); 82 | $tables = serialize( $this->revisr->db->get_tables_not_in_db() ); 83 | $this->assertContains( 'faketable', $tables ); 84 | } 85 | 86 | /** 87 | * Tests a database backup. 88 | */ 89 | function test_backup() { 90 | $this->revisr->git->set_config( 'revisr', 'db-tracking', 'all_tables' ); 91 | $this->revisr->db->backup(); 92 | $this->assertFileExists( ABSPATH . 'wp-content/uploads/revisr-backups/revisr_wptests_posts.sql' ); 93 | } 94 | 95 | /** 96 | * Tests the verify_backup() function. 97 | */ 98 | function test_verify_backup() { 99 | $verify = $this->revisr->db->verify_backup( 'wptests_posts' ); 100 | $this->assertEquals( true, $verify ); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /tests/test-git.php: -------------------------------------------------------------------------------- 1 | revisr = revisr(); 15 | $this->revisr->git = new Revisr_Git(); 16 | } 17 | 18 | /** 19 | * Restore the Git object. 20 | */ 21 | function tearDown() { 22 | if ( $this->revisr->git->current_branch() != 'master' ) { 23 | $this->revisr->git->checkout( 'master' ); 24 | } 25 | } 26 | 27 | /** 28 | * Tests the init function. 29 | */ 30 | function test_init_repo() { 31 | 32 | define( 'REVISR_SETUP_INIT', true ); 33 | 34 | if ( ! $this->revisr->git->is_repo ) { 35 | $this->revisr->git->init_repo(); 36 | } 37 | $this->assertEquals( true, $this->revisr->git->is_repo ); 38 | } 39 | 40 | /** 41 | * Tests setting the Git username. 42 | */ 43 | function test_config() { 44 | // Set the Git username and email address. 45 | $this->revisr->git->set_config( 'user', 'name', 'revisr' ); 46 | $this->revisr->git->set_config( 'user', 'email', 'support@expandedfronts.com' ); 47 | 48 | // Grab the values via get_config(). 49 | $current_user = $this->revisr->git->get_config( 'user', 'name' ); 50 | $current_email = $this->revisr->git->get_config( 'user', 'email' ); 51 | 52 | $this->assertEquals( 'revisr', $current_user ); 53 | $this->assertEquals( 'support@expandedfronts.com', $current_email ); 54 | } 55 | 56 | 57 | /** 58 | * Tests for the current Git version. 59 | * Expects string containing "git". 60 | */ 61 | function test_version() { 62 | $version = $this->revisr->git->version(); 63 | $this->assertStringStartsWith( 'git', $version ); 64 | } 65 | 66 | /** 67 | * Tests the current dir with an initialized repository. 68 | */ 69 | function test_git_dir() { 70 | $dir = $this->revisr->git->get_git_dir(); 71 | $this->assertFileExists( $dir ); 72 | $this->assertFileExists( $dir . '/config' ); 73 | } 74 | 75 | /** 76 | * Tests that we have the path to Git. 77 | */ 78 | function test_git_path() { 79 | $path = $this->revisr->git->get_git_path(); 80 | $this->assertContains('git', $path ); 81 | } 82 | 83 | /** 84 | * Tests a commit. 85 | */ 86 | function test_commit() { 87 | $this->revisr->git->run( 'add', array( '-A' ) ); 88 | $this->revisr->git->commit( 'Committed pending files' ); 89 | $this->assertEquals( 0, $this->revisr->git->count_untracked() ); 90 | } 91 | 92 | /** 93 | * Tests the branches function. 94 | */ 95 | function test_branches() { 96 | $branches = $this->revisr->git->get_branches(); 97 | $this->assertContains( '* ', $branches[0] ); 98 | } 99 | 100 | /** 101 | * Tests creating a new branch. 102 | */ 103 | function test_create_branch() { 104 | $this->revisr->git->create_branch( 'testbranch' ); 105 | $this->revisr->git->create_branch( 'deletethisbranch' ); 106 | $this->assertEquals( true, $this->revisr->git->is_branch( 'testbranch' ) ); 107 | $this->assertEquals( true, $this->revisr->git->is_branch( 'deletethisbranch' ) ); 108 | } 109 | 110 | /** 111 | * Tests the is_branch function. 112 | */ 113 | function test_is_branch() { 114 | $real_branch = $this->revisr->git->is_branch( 'testbranch' ); 115 | $fake_branch = $this->revisr->git->is_branch( 'fakebranch' ); 116 | $this->assertEquals( true, $real_branch ); 117 | $this->assertEquals( false, $fake_branch ); 118 | } 119 | 120 | /** 121 | * Tests checking out a branch. 122 | */ 123 | function test_checkout() { 124 | $this->revisr->git->checkout( 'testbranch' ); 125 | $current_branch = $this->revisr->git->current_branch(); 126 | $this->assertEquals( 'testbranch', $current_branch ); 127 | } 128 | 129 | /** 130 | * Tests deleting a branch. 131 | */ 132 | function test_delete_branch() { 133 | $this->revisr->git->delete_branch( 'testbranch', false ); 134 | $this->revisr->git->delete_branch( 'deletethisbranch', false ); 135 | $is_branch = $this->revisr->git->is_branch( 'deletethisbranch' ); 136 | $this->assertEquals( false, $is_branch ); 137 | } 138 | 139 | /** 140 | * Tests the count_untracked() function. 141 | */ 142 | function test_count_untracked() { 143 | $dir = $this->revisr->git->get_work_tree(); 144 | $time = time(); 145 | fopen( $dir . "/sample-file_$time.txt", "w" ); 146 | $new_untracked = $this->revisr->git->count_untracked(); 147 | $this->assertEquals( 1, $new_untracked ); 148 | } 149 | 150 | /** 151 | * Tests the reset functionality. 152 | */ 153 | function test_reset() { 154 | $this->revisr->git->reset( '--hard', 'HEAD', true ); 155 | $after_reset = $this->revisr->git->count_untracked(); 156 | $this->assertEquals( 0, $after_reset ); 157 | } 158 | 159 | /** 160 | * Tests the Git status functionality. 161 | */ 162 | function test_status() { 163 | $status = $this->revisr->git->status(); 164 | $this->assertNotEquals( false, $status ); 165 | } 166 | 167 | /** 168 | * Tests the current_commit() function. Expects 7 digit short SHA1 hash. 169 | */ 170 | function test_current_commit() { 171 | $current = $this->revisr->git->current_commit(); 172 | $length = strlen($current); 173 | $this->assertEquals( 7, $length ); 174 | } 175 | 176 | /** 177 | * Test the current_remote() method. Expects origin since we haven't changed it. 178 | */ 179 | function test_current_remote() { 180 | $remote = $this->revisr->git->current_remote(); 181 | $this->assertEquals( 'origin', $remote ); 182 | } 183 | 184 | /** 185 | * Tests the Revisr_Git::get_commit_details() method. 186 | */ 187 | function test_get_commit_details() { 188 | $commit = Revisr_Git::get_commit_details( 'abc1234' ); 189 | $this->assertArrayHasKey( 'hash', $commit ); 190 | $this->assertArrayHasKey( 'branch', $commit ); 191 | $this->assertArrayHasKey( 'author', $commit ); 192 | $this->assertArrayHasKey( 'subject', $commit ); 193 | $this->assertArrayHasKey( 'time', $commit ); 194 | $this->assertArrayHasKey( 'files_changed', $commit ); 195 | $this->assertArrayHasKey( 'committed_files', $commit ); 196 | $this->assertArrayHasKey( 'tag', $commit ); 197 | $this->assertArrayHasKey( 'status', $commit ); 198 | } 199 | 200 | /** 201 | * Tests the get_status() method. 202 | */ 203 | function test_get_status() { 204 | $test_modified = Revisr_Git::get_status( 'MM' ); 205 | $test_deleted = Revisr_Git::get_status( 'DD' ); 206 | $test_added = Revisr_Git::get_status( 'AA' ); 207 | $test_renamed = Revisr_Git::get_status( 'RR' ); 208 | $test_untracked = Revisr_Git::get_status( '??' ); 209 | $test_invalid = Revisr_Git::get_status( '$$' ); 210 | 211 | $this->assertEquals( 'Modified', $test_modified ); 212 | $this->assertEquals( 'Deleted', $test_deleted ); 213 | $this->assertEquals( 'Added', $test_added ); 214 | $this->assertEquals( 'Renamed', $test_renamed ); 215 | $this->assertEquals( 'Untracked', $test_untracked ); 216 | $this->assertFalse( $test_invalid ); 217 | 218 | } 219 | 220 | /** 221 | * Tests the tag() function. 222 | */ 223 | function test_tag() { 224 | $time = time(); 225 | $this->revisr->git->tag( $time ); 226 | $tags = serialize( $this->revisr->git->run( 'tag', array() ) ); 227 | $this->assertContains( "$time", $tags ); 228 | $this->revisr->git->run( 'tag', array( '-d', $time ) ); 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /tests/test-remote.php: -------------------------------------------------------------------------------- 1 | remote = new Revisr_Remote(); 10 | } 11 | 12 | /** 13 | * Tests the "get_token()" method. 14 | */ 15 | function test_get_token() { 16 | $token = $this->remote->get_token(); 17 | 18 | if ( is_string( $token ) && strlen( $token ) === 16 ) { 19 | $result = true; 20 | } else { 21 | $result = false; 22 | } 23 | 24 | $this->assertTrue( $result ); 25 | } 26 | 27 | /** 28 | * Tests the "check_token()" method. 29 | */ 30 | function test_check_token() { 31 | $token = $this->remote->get_token(); 32 | $result = $this->remote->check_token( $token ); 33 | $this->assertTrue( $result ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/test-revisr.php: -------------------------------------------------------------------------------- 1 | revisr = revisr(); 15 | } 16 | 17 | /** 18 | * Tests the revisr() method. 19 | */ 20 | function test_revisr() { 21 | revisr(); 22 | $this->assertClassHasStaticAttribute( 'instance', 'Revisr' ); 23 | } 24 | 25 | /** 26 | * Tests the define_constants() method. 27 | */ 28 | function test_define_constants() { 29 | // Plugin Folder URL 30 | $path = str_replace( 'tests/', '', plugin_dir_url( __FILE__ ) ); 31 | $this->assertSame( REVISR_URL, $path ); 32 | 33 | // Plugin Folder Path 34 | $path = str_replace( 'tests/', '', plugin_dir_path( __FILE__ ) ); 35 | $this->assertSame( REVISR_PATH, $path ); 36 | 37 | // Plugin Root File 38 | $path = str_replace( 'tests/', '', plugin_dir_path( __FILE__ ) ); 39 | $this->assertSame( REVISR_FILE, $path . 'revisr.php' ); 40 | } 41 | 42 | /** 43 | * Tests the load_dependencies() method. 44 | */ 45 | function test_load_dependencies() { 46 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-activity-table.php' ); 47 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-admin.php' ); 48 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-admin-pages.php' ); 49 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-branch-table.php' ); 50 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-commits-table.php' ); 51 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-meta-boxes.php' ); 52 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-compatibility.php' ); 53 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-cron.php' ); 54 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-db-backup.php' ); 55 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-db-import.php' ); 56 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-db.php' ); 57 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-git-callback.php' ); 58 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-git.php' ); 59 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-i18n.php' ); 60 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-process.php' ); 61 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-remote.php' ); 62 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-settings-fields.php' ); 63 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-settings.php' ); 64 | } 65 | 66 | /** 67 | * Tests get_table_name(). 68 | */ 69 | function test_get_table_name() { 70 | $revisr_table_name = Revisr::get_table_name(); 71 | $this->assertContains( 'revisr', $revisr_table_name ); 72 | } 73 | 74 | /** 75 | * Tests the get_options() method. 76 | */ 77 | function test_get_options() { 78 | $options = Revisr::get_options(); 79 | if ( is_array( $options ) ) { 80 | $result = true; 81 | } else { 82 | $result = false; 83 | } 84 | $this->assertTrue( $result ); 85 | } 86 | 87 | /** 88 | * Tests the database installation. 89 | */ 90 | function test_install() { 91 | Revisr::install(); 92 | global $wpdb; 93 | $table_name = $wpdb->prefix . 'revisr'; 94 | $table_check = $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" ); 95 | $this->assertEquals( $table_name, $table_check ); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /uninstall.php: -------------------------------------------------------------------------------- 1 | options['uninstall_on_delete'] ) { 20 | 21 | // Remove any set crons. 22 | wp_clear_scheduled_hook( 'revisr_cron' ); 23 | 24 | // Remove any set options. 25 | delete_option( 'revisr_settings' ); 26 | delete_option( 'revisr_general_settings' ); 27 | delete_option( 'revisr_remote_settings' ); 28 | delete_option( 'revisr_database_settings' ); 29 | 30 | // Remove any set transients. 31 | delete_transient( 'revisr_error_details' ); 32 | delete_transient( 'revisr_error' ); 33 | delete_transient( 'revisr_alert' ); 34 | delete_transient( 'revisr_skip_setup' ); 35 | 36 | // Delete any commits. 37 | $commits = get_posts( array( 'post_type' => 'revisr_commits', 'post_status' => 'any', 'number_posts' => -1, 'fields' => 'ids' ) ); 38 | foreach ( $commits as $commit ) { 39 | wp_delete_post( $commit, true ); 40 | } 41 | 42 | // Drop the Revisr database table. 43 | global $wpdb; 44 | $table_name = $wpdb->prefix . 'revisr'; 45 | $sql = "DROP TABLE $table_name"; 46 | $wpdb->query( $sql ); 47 | 48 | } 49 | --------------------------------------------------------------------------------