Update of site.
3
cleanup
|
|
@ -1,3 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
sudo rm -fv xmlrpc.php readme* licens* wp-content/debug.log
|
||||
#sudo rm -fv xmlrpc.php readme* licens* wp-content/debug.log
|
||||
sudo rm -fv readme* licens* wp-content/debug.log
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
{"translation-revision-date":"2019-11-06 00:54:14+0000","generator":"GlotPress\/2.4.0-alpha","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"sv_SE"},"block search term\u0004map":["karta"],"block search term\u0004navigation":["navigering"],"Terrain":["Terr\u00e4ng"],"Satellite":["Satellit"],"Black and white":["Svart och vit"],"Basic":["Grundl\u00e4ggande"],"Delete Marker":["Ta bort mark\u00f6r"],"Add an interactive map showing one or more locations.":["L\u00e4gg till en interaktiv karta som visar en eller flera platser."],"block search term\u0004location":["plats"],"Marker Caption":["Tidsmark\u00f6rstext"],"Marker Title":["Tidsmark\u00f6rstitel"],"Map":["Karta"]}},"comment":{"reference":"_inc\/blocks\/map\/view.js"}}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
#health-check-dashboard-widget {
|
||||
display: grid;
|
||||
grid-gap: 2%;
|
||||
grid-template-columns: 100%;
|
||||
padding: 13px;
|
||||
background: #fff;
|
||||
/* Accordion styles */
|
||||
}
|
||||
|
||||
@media all and (min-width: 783px) {
|
||||
#health-check-dashboard-widget {
|
||||
margin-top: 3rem;
|
||||
grid-template-columns: 49% 49%;
|
||||
}
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget h2 .green {
|
||||
color: #40860a;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .welcome-panel-content {
|
||||
max-width: initial;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget #health-check-accordion-block-notices .no-notices p {
|
||||
color: #72777c;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget #health-check-accordion-block-notices .notice {
|
||||
color: #72777c;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget #health-check-accordion-block-notices .notice p {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget #health-check-accordion-block-notices .dismiss-notices {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .disable-troubleshooting-mode {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
@media all and (min-width: 960px) {
|
||||
#health-check-dashboard-widget .disable-troubleshooting-mode {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget ul li {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
@media all and (max-width: 870px) {
|
||||
#health-check-dashboard-widget ul li {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .about-description {
|
||||
margin: 1em 0;
|
||||
max-width: 700px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .about-description p {
|
||||
color: inherit;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion {
|
||||
border: 1px solid #e2e4e7;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-heading {
|
||||
margin: 0;
|
||||
border-top: 1px solid #e2e4e7;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
font-weight: 600;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-heading:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger {
|
||||
background: #fff;
|
||||
border: 0;
|
||||
color: #32373c;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
padding: 1em 3.5em 1em 1.5em;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger:hover, #health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger:active {
|
||||
background: #f8f9f9;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger:focus {
|
||||
color: #191e23;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
outline-offset: -2px;
|
||||
outline: 1px dotted #555d66;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger .title {
|
||||
display: inline-block;
|
||||
pointer-events: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger .icon {
|
||||
border: solid #555d66;
|
||||
border-width: 0 2px 2px 0;
|
||||
height: 0.5rem;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
right: 1.5em;
|
||||
top: 50%;
|
||||
transform: translateY(-70%) rotate(45deg);
|
||||
width: 0.5rem;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger .badge {
|
||||
float: right;
|
||||
padding: 0.1rem 0.5rem 0.15rem;
|
||||
color: #32373c;
|
||||
font-weight: 600;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger .badge.blue {
|
||||
border: 1px solid #bfe7f3;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger .badge.orange {
|
||||
border: 1px solid #ffb900;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger .badge.red {
|
||||
border: 1px solid #dc3232;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger .badge.green {
|
||||
border: 1px solid #46b450;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger .badge.purple {
|
||||
border: 1px solid #826eb4;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger .badge.gray {
|
||||
border: 1px solid #ccd0d4;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-trigger[aria-expanded="true"] .icon {
|
||||
transform: translateY(-30%) rotate(-135deg);
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-panel {
|
||||
margin: 0;
|
||||
padding: 1em 1.5em;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-panel > div {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-panel[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion .health-check-accordion-panel a .dashicons {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#health-check-dashboard-widget .health-check-accordion dl dd {
|
||||
margin: 0 0 0.5em 2em;
|
||||
}
|
||||
|
|
@ -0,0 +1,651 @@
|
|||
body {
|
||||
/* Accordion styles */
|
||||
}
|
||||
|
||||
body.tools_page_health-check {
|
||||
/* Better position for the WordPress admin notices and update nag. */
|
||||
/* Info screen styles */
|
||||
/* Tools screen styles */
|
||||
/* Diff viewer styles */
|
||||
/* Site Status styles */
|
||||
}
|
||||
|
||||
body.tools_page_health-check #wpcontent {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .notice {
|
||||
margin: 5px 20px 15px 22px;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .update-nag {
|
||||
margin-bottom: 20px;
|
||||
margin-left: 22px;
|
||||
}
|
||||
|
||||
body.tools_page_health-check h2 {
|
||||
padding: 1rem 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .wrap {
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .wrap h2 {
|
||||
padding: 1rem 0.5rem;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 600;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
@media all and (min-width: 960px) {
|
||||
body.tools_page_health-check .wrap h2 {
|
||||
padding: 1rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
body.tools_page_health-check ul li,
|
||||
body.tools_page_health-check ol li {
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .wp-core-ui .button {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-header {
|
||||
text-align: center;
|
||||
margin: 0 0 1rem;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #e2e4e7;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-header .health-check-tabs-wrapper {
|
||||
/* IE 11 */
|
||||
display: -ms-inline-grid;
|
||||
-ms-grid-columns: 1fr 1fr 1fr 1fr;
|
||||
vertical-align: top;
|
||||
/* modern browsers */
|
||||
display: inline-grid;
|
||||
/* stylelint-disable-line declaration-block-no-duplicate-properties */
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab {
|
||||
display: block;
|
||||
/* IE 11 */
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
padding: 0.5rem 1rem 1rem;
|
||||
margin: 0 1rem;
|
||||
transition: box-shadow 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab:nth-child(1) {
|
||||
-ms-grid-column: 1;
|
||||
/* IE 11 */
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab:nth-child(2) {
|
||||
-ms-grid-column: 2;
|
||||
/* IE 11 */
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab:nth-child(3) {
|
||||
-ms-grid-column: 3;
|
||||
/* IE 11 */
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab:nth-child(4) {
|
||||
-ms-grid-column: 4;
|
||||
/* IE 11 */
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab.active {
|
||||
box-shadow: inset 0 -3px #007cba;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab:focus {
|
||||
color: #191e23;
|
||||
outline: 1px solid #6c7781;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-body {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-table {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-table thead th,
|
||||
body.tools_page_health-check .health-check-table thead td {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-table thead th:first-child,
|
||||
body.tools_page_health-check .health-check-table thead td:first-child {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-table tbody td {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-table tbody td:first-child {
|
||||
width: 100%;
|
||||
padding-bottom: 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-table tbody td ul,
|
||||
body.tools_page_health-check .health-check-table tbody td ol {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .pass:before,
|
||||
body.tools_page_health-check .good:before {
|
||||
content: "\f147";
|
||||
display: inline-block;
|
||||
color: #46b450;
|
||||
font-family: dashicons;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .warning:before {
|
||||
content: "\f460";
|
||||
display: inline-block;
|
||||
color: #ffb900;
|
||||
font-family: dashicons;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .info:before {
|
||||
content: "\f348";
|
||||
display: inline-block;
|
||||
color: #00a0d2;
|
||||
font-family: dashicons;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .fail:before,
|
||||
body.tools_page_health-check .error:before {
|
||||
content: "\f335";
|
||||
display: inline-block;
|
||||
color: #dc3232;
|
||||
font-family: dashicons;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .spinner {
|
||||
float: none;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-health-copy-buttons {
|
||||
display: block;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-health-copy-buttons .copy-button-wrapper {
|
||||
margin: 0.5rem 0 1rem;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-health-copy-buttons .success {
|
||||
display: none;
|
||||
color: #40860a;
|
||||
height: 28px;
|
||||
line-height: 2.2;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-health-copy-buttons .success.visible {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
body.tools_page_health-check #health-check-debug {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .health-check-wp-paths-sizes.spinner {
|
||||
position: absolute;
|
||||
visibility: visible;
|
||||
float: none;
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .file-integrity-table thead th:first-child,
|
||||
body.tools_page_health-check .file-integrity-table thead td:first-child,
|
||||
body.tools_page_health-check .file-integrity-table tbody th:first-child,
|
||||
body.tools_page_health-check .file-integrity-table tbody td:first-child,
|
||||
body.tools_page_health-check .file-integrity-table tfoot th:first-child,
|
||||
body.tools_page_health-check .file-integrity-table tfoot td:first-child {
|
||||
text-align: center;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .tools-email-table {
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .tools-email-table td:first-child {
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
body.tools_page_health-check .tools-email-table td {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
body.tools_page_health-check .tools-email-table input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .tools-email-table label {
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
body.tools_page_health-check #health-check-mail-check,
|
||||
body.tools_page_health-check #health-check-file-integrity {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
body.tools_page_health-check #health-check-diff-modal {
|
||||
width: 100vw;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
display: none;
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
body.tools_page_health-check #health-check-diff-modal #health-check-diff-modal-content {
|
||||
background: #fff;
|
||||
height: calc(100% - 120px);
|
||||
width: calc(100% - 120px);
|
||||
margin-top: 40px;
|
||||
margin-left: 40px;
|
||||
padding: 20px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
body.tools_page_health-check #health-check-diff-modal #health-check-diff-modal-diff {
|
||||
width: 100%;
|
||||
height: calc(100% - 80px);
|
||||
overflow-y: auto;
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body.tools_page_health-check #health-check-diff-modal #health-check-diff-modal-diff table.diff td:nth-child(2) {
|
||||
background: #f3f3f3;
|
||||
}
|
||||
|
||||
body.tools_page_health-check #health-check-diff-modal-close-ref {
|
||||
position: relative;
|
||||
display: block;
|
||||
float: right;
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-health-issues-wrapper {
|
||||
margin-bottom: 3rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-health-issues-wrapper:first-of-type {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-status-has-issues {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-status-has-issues.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.tools_page_health-check h3 {
|
||||
padding: 0;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-health-view-more {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .issues-wrapper {
|
||||
margin-bottom: 5rem;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-status-all-clear {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@media all and (min-width: 784px) {
|
||||
body.tools_page_health-check .site-status-all-clear {
|
||||
margin: 5rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-status-all-clear.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-status-all-clear .dashicons {
|
||||
font-size: 150px;
|
||||
height: 130px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-status-all-clear .encouragement {
|
||||
font-family: inherit;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-status-all-clear p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-health-view-passed {
|
||||
position: relative;
|
||||
padding-right: 40px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-health-view-passed .icon {
|
||||
border: solid #555d66;
|
||||
border-width: 0 2px 2px 0;
|
||||
height: 0.5rem;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
right: 1.5em;
|
||||
top: 50%;
|
||||
transform: translateY(-70%) rotate(45deg);
|
||||
width: 0.5rem;
|
||||
}
|
||||
|
||||
body.tools_page_health-check .site-health-view-passed[aria-expanded="true"] .icon {
|
||||
transform: translateY(-30%) rotate(-135deg);
|
||||
}
|
||||
|
||||
body .health-check-accordion {
|
||||
border: 1px solid #e2e4e7;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-heading {
|
||||
margin: 0;
|
||||
border-top: 1px solid #e2e4e7;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
font-weight: 600;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-heading:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-trigger {
|
||||
background: #fff;
|
||||
border: 0;
|
||||
color: #32373c;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
padding: 1em 3.5em 1em 1.5em;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-trigger:hover, body .health-check-accordion .health-check-accordion-trigger:active {
|
||||
background: #f8f9f9;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-trigger:focus {
|
||||
color: #191e23;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
outline-offset: -2px;
|
||||
outline: 1px dotted #555d66;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-trigger .title {
|
||||
display: inline-block;
|
||||
pointer-events: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-trigger .icon {
|
||||
border: solid #555d66;
|
||||
border-width: 0 2px 2px 0;
|
||||
height: 0.5rem;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
right: 1.5em;
|
||||
top: 50%;
|
||||
transform: translateY(-70%) rotate(45deg);
|
||||
width: 0.5rem;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-trigger .badge {
|
||||
float: right;
|
||||
padding: 0.1rem 0.5rem 0.15rem;
|
||||
color: #32373c;
|
||||
font-weight: 600;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-trigger .badge.blue {
|
||||
border: 1px solid #bfe7f3;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-trigger .badge.orange {
|
||||
border: 1px solid #ffb900;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-trigger .badge.red {
|
||||
border: 1px solid #dc3232;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-trigger .badge.green {
|
||||
border: 1px solid #46b450;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-trigger .badge.purple {
|
||||
border: 1px solid #826eb4;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-trigger .badge.gray {
|
||||
border: 1px solid #ccd0d4;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-trigger[aria-expanded="true"] .icon {
|
||||
transform: translateY(-30%) rotate(-135deg);
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-panel {
|
||||
margin: 0;
|
||||
padding: 1em 1.5em;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-panel > div {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-panel[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body .health-check-accordion .health-check-accordion-panel a .dashicons {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
body .health-check-accordion dl dd {
|
||||
margin: 0 0 0.5em 2em;
|
||||
}
|
||||
|
||||
/* Modal styles */
|
||||
.health-check-modal {
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
padding-top: 50px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: black;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
@media all and (min-width: 1024px) {
|
||||
.health-check-modal {
|
||||
padding-top: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
.health-check-modal.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.health-check-modal .modal-content {
|
||||
background-color: #fefefe;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #888;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
@media all and (min-width: 1024px) {
|
||||
.health-check-modal .modal-content {
|
||||
width: 30%;
|
||||
}
|
||||
}
|
||||
|
||||
.health-check-modal .modal-content .modal-close {
|
||||
color: #aaa;
|
||||
float: right;
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.health-check-modal .modal-content #dynamic-content {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.health-check-modal .modal-close:hover, .health-check-modal .modal-close:focus {
|
||||
color: #aaa;
|
||||
float: right;
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Progress indicator styles */
|
||||
.health-check-title-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.health-check-title-section h1 {
|
||||
display: inline-block;
|
||||
font-weight: 600;
|
||||
font-size: 23px;
|
||||
margin: 0 0.8rem 1rem;
|
||||
padding: 9px 0 4px;
|
||||
line-height: 1.3;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.health-check-title-section.site-health-progress-wrapper {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.health-check-title-section.site-health-progress-wrapper.loading .site-health-progress svg #bar {
|
||||
stroke-dashoffset: 0;
|
||||
stroke: #adc5d2;
|
||||
animation: loadingPulse 3s infinite ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes loadingPulse {
|
||||
0% {
|
||||
stroke: #adc5d2;
|
||||
}
|
||||
50% {
|
||||
stroke: #00a0d2;
|
||||
}
|
||||
100% {
|
||||
stroke: #adc5d2;
|
||||
}
|
||||
}
|
||||
|
||||
.health-check-title-section.site-health-progress-wrapper.green #bar {
|
||||
stroke: #46b450;
|
||||
}
|
||||
|
||||
.health-check-title-section.site-health-progress-wrapper.green .site-health-progress-label {
|
||||
color: #46b450;
|
||||
}
|
||||
|
||||
.health-check-title-section.site-health-progress-wrapper.orange #bar {
|
||||
stroke: #ffb900;
|
||||
}
|
||||
|
||||
.health-check-title-section.site-health-progress-wrapper.orange .site-health-progress-label {
|
||||
color: #ffb900;
|
||||
}
|
||||
|
||||
.health-check-title-section.site-health-progress-wrapper .site-health-progress {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
margin: 0;
|
||||
border-radius: 100%;
|
||||
position: relative;
|
||||
font-weight: 600;
|
||||
font-size: 0.4rem;
|
||||
}
|
||||
|
||||
.health-check-title-section.site-health-progress-wrapper .site-health-progress svg circle {
|
||||
stroke-dashoffset: 0;
|
||||
transition: stroke-dashoffset 1s linear;
|
||||
stroke: #ccc;
|
||||
stroke-width: 3em;
|
||||
}
|
||||
|
||||
.health-check-title-section.site-health-progress-wrapper .site-health-progress svg #bar {
|
||||
stroke-dashoffset: 565;
|
||||
}
|
||||
|
||||
.health-check-title-section.site-health-progress-wrapper .site-health-progress-label {
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
margin-left: 0.3rem;
|
||||
}
|
||||
|
|
@ -0,0 +1,590 @@
|
|||
jQuery( document ).ready( function( $ ) {
|
||||
$( '.health-check-accordion' ).on( 'click', '.health-check-accordion-trigger', function() {
|
||||
const isExpanded = ( 'true' === $( this ).attr( 'aria-expanded' ) );
|
||||
|
||||
if ( isExpanded ) {
|
||||
$( this ).attr( 'aria-expanded', 'false' );
|
||||
$( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', true );
|
||||
} else {
|
||||
$( this ).attr( 'aria-expanded', 'true' );
|
||||
$( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', false );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
/* global ClipboardJS, SiteHealth */
|
||||
jQuery( document ).ready( function( $ ) {
|
||||
let clipboard;
|
||||
|
||||
if ( 'undefined' !== typeof ClipboardJS ) {
|
||||
clipboard = new ClipboardJS( '.site-health-copy-buttons .copy-button' );
|
||||
|
||||
// Debug information copy section.
|
||||
clipboard.on( 'success', function( e ) {
|
||||
const $wrapper = $( e.trigger ).closest( 'div' );
|
||||
|
||||
$( '.success', $wrapper ).addClass( 'visible' );
|
||||
|
||||
wp.a11y.speak( SiteHealth.string.site_info_copied );
|
||||
} );
|
||||
}
|
||||
} );
|
||||
|
||||
/* global ajaxurl, SiteHealth */
|
||||
jQuery( document ).ready( function( $ ) {
|
||||
const isDebugTab = $( '.health-check-debug-tab.active' ).length;
|
||||
const pathsSizesSection = $( '#health-check-accordion-block-wp-paths-sizes' );
|
||||
|
||||
function getDirectorySizes() {
|
||||
const data = {
|
||||
action: 'health-check-get-sizes',
|
||||
_wpnonce: SiteHealth.nonce.site_status_result,
|
||||
};
|
||||
|
||||
const timestamp = ( new Date().getTime() );
|
||||
|
||||
// After 3 seconds announce that we're still waiting for directory sizes.
|
||||
const timeout = window.setTimeout( function() {
|
||||
wp.a11y.speak( SiteHealth.string.please_wait );
|
||||
}, 3000 );
|
||||
|
||||
$.post( {
|
||||
type: 'POST',
|
||||
url: ajaxurl,
|
||||
data,
|
||||
dataType: 'json',
|
||||
} ).done( function( response ) {
|
||||
updateDirSizes( response.data || {} );
|
||||
} ).always( function() {
|
||||
let delay = ( new Date().getTime() ) - timestamp;
|
||||
|
||||
$( '.health-check-wp-paths-sizes.spinner' ).css( 'visibility', 'hidden' );
|
||||
|
||||
if ( delay > 3000 ) {
|
||||
// We have announced that we're waiting.
|
||||
// Announce that we're ready after giving at least 3 seconds for the first announcement
|
||||
// to be read out, or the two may collide.
|
||||
if ( delay > 6000 ) {
|
||||
delay = 0;
|
||||
} else {
|
||||
delay = 6500 - delay;
|
||||
}
|
||||
|
||||
window.setTimeout( function() {
|
||||
wp.a11y.speak( SiteHealth.string.site_health_complete );
|
||||
}, delay );
|
||||
} else {
|
||||
// Cancel the announcement.
|
||||
window.clearTimeout( timeout );
|
||||
}
|
||||
|
||||
$( document ).trigger( 'site-health-info-dirsizes-done' );
|
||||
} );
|
||||
}
|
||||
|
||||
function updateDirSizes( data ) {
|
||||
const copyButton = $( 'button.button.copy-button' );
|
||||
let clipdoardText = copyButton.attr( 'data-clipboard-text' );
|
||||
|
||||
$.each( data, function( name, value ) {
|
||||
const text = value.debug || value.size;
|
||||
|
||||
if ( 'undefined' !== typeof text ) {
|
||||
clipdoardText = clipdoardText.replace( name + ': loading...', name + ': ' + text );
|
||||
}
|
||||
} );
|
||||
|
||||
copyButton.attr( 'data-clipboard-text', clipdoardText );
|
||||
|
||||
pathsSizesSection.find( 'td[class]' ).each( function( i, element ) {
|
||||
const td = $( element );
|
||||
const name = td.attr( 'class' );
|
||||
|
||||
if ( data.hasOwnProperty( name ) && data[ name ].size ) {
|
||||
td.text( data[ name ].size );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
if ( isDebugTab ) {
|
||||
if ( pathsSizesSection.length ) {
|
||||
getDirectorySizes();
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
/* global ajaxurl */
|
||||
jQuery( document ).ready( function( $ ) {
|
||||
function healthCheckFailureModal( markup, action, parent ) {
|
||||
$( '#dynamic-content' ).html( markup );
|
||||
$( '.health-check-modal' ).data( 'modal-action', action ).data( 'parent-field', parent ).show();
|
||||
}
|
||||
|
||||
function healthCheckFailureModalClose( modal ) {
|
||||
modal.hide();
|
||||
}
|
||||
|
||||
$( '.modal-close' ).click( function( e ) {
|
||||
e.preventDefault();
|
||||
healthCheckFailureModalClose( $( this ).closest( '.health-check-modal' ) );
|
||||
} );
|
||||
|
||||
$( '.health-check-modal' ).on( 'submit', 'form', function( e ) {
|
||||
const data = $( this ).serializeArray(),
|
||||
modal = $( this ).closest( '.health-check-modal' );
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function( response ) {
|
||||
if ( true === response.success ) {
|
||||
$( modal.data( 'parent-field' ) ).append( response.data.message );
|
||||
} else {
|
||||
healthCheckFailureModal( response.data.message, data.action, modal.data( 'parent-field' ) );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
healthCheckFailureModalClose( modal );
|
||||
} );
|
||||
} );
|
||||
|
||||
/* global SiteHealth, ajaxurl, healthCheckFailureModal */
|
||||
jQuery( document ).ready( function( $ ) {
|
||||
function testDefaultTheme() {
|
||||
const $parent = $( '.individual-loopback-test-status', '#test-single-no-theme' ),
|
||||
data = {
|
||||
action: 'health-check-loopback-default-theme',
|
||||
_wpnonce: SiteHealth.nonce.loopback_default_theme,
|
||||
};
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function( response ) {
|
||||
if ( true === response.success ) {
|
||||
$parent.html( response.data.message );
|
||||
} else {
|
||||
healthCheckFailureModal( response.data, data.action, $parent );
|
||||
}
|
||||
},
|
||||
'json'
|
||||
);
|
||||
}
|
||||
|
||||
function testSinglePlugin() {
|
||||
const $testLines = $( '.not-tested', '#loopback-individual-plugins-list' );
|
||||
|
||||
if ( $testLines.length < 1 ) {
|
||||
testDefaultTheme();
|
||||
return null;
|
||||
}
|
||||
|
||||
const $testLine = $testLines.first();
|
||||
const data = {
|
||||
action: 'health-check-loopback-individual-plugins',
|
||||
plugin: $testLine.data( 'test-plugin' ),
|
||||
_wpnonce: SiteHealth.nonce.loopback_individual_plugins,
|
||||
};
|
||||
|
||||
const $parentField = $( '.individual-loopback-test-status', $testLine );
|
||||
|
||||
$parentField.html( SiteHealth.string.running_tests );
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function( response ) {
|
||||
if ( true === response.success ) {
|
||||
$testLine.removeClass( 'not-tested' );
|
||||
$parentField.html( response.data.message );
|
||||
testSinglePlugin();
|
||||
} else {
|
||||
healthCheckFailureModal( response.data, data.action, $parentField );
|
||||
}
|
||||
},
|
||||
'json'
|
||||
);
|
||||
}
|
||||
|
||||
$( '.dashboard_page_health-check' ).on( 'click', '#loopback-no-plugins', function( e ) {
|
||||
const $trigger = $( this ),
|
||||
$parent = $( this ).closest( 'p' ),
|
||||
data = {
|
||||
action: 'health-check-loopback-no-plugins',
|
||||
_wpnonce: SiteHealth.nonce.loopback_no_plugins,
|
||||
};
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$( this ).html( '<span class="spinner" style="visibility: visible;"></span> ' + SiteHealth.string.please_wait );
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function( response ) {
|
||||
$trigger.remove();
|
||||
if ( true === response.success ) {
|
||||
$parent.append( response.data.message );
|
||||
} else {
|
||||
healthCheckFailureModal( response.data, data.action, $parent );
|
||||
}
|
||||
},
|
||||
'json'
|
||||
);
|
||||
} ).on( 'click', '#loopback-individual-plugins', function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
$( this ).remove();
|
||||
|
||||
testSinglePlugin();
|
||||
} );
|
||||
} );
|
||||
|
||||
/* global ajaxurl, SiteHealth */
|
||||
jQuery( document ).ready( function( $ ) {
|
||||
let data;
|
||||
const isDebugTab = $( '.health-check-debug-tab.active' ).length;
|
||||
|
||||
$( '.site-health-view-passed' ).on( 'click', function() {
|
||||
const goodIssuesWrapper = $( '#health-check-issues-good' );
|
||||
|
||||
goodIssuesWrapper.toggleClass( 'hidden' );
|
||||
$( this ).attr( 'aria-expanded', ! goodIssuesWrapper.hasClass( 'hidden' ) );
|
||||
} );
|
||||
|
||||
function AppendIssue( issue ) {
|
||||
if ( typeof issue === 'undefined' || typeof issue.status === 'undefined' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const template = wp.template( 'health-check-issue' ),
|
||||
issueWrapper = $( '#health-check-issues-' + issue.status );
|
||||
|
||||
let heading;
|
||||
|
||||
SiteHealth.site_status.issues[ issue.status ]++;
|
||||
|
||||
const count = SiteHealth.site_status.issues[ issue.status ];
|
||||
|
||||
if ( 'critical' === issue.status ) {
|
||||
if ( count <= 1 ) {
|
||||
heading = SiteHealth.string.site_info_heading_critical_single.replace( '%s', '<span class="issue-count">' + count + '</span>' );
|
||||
} else {
|
||||
heading = SiteHealth.string.site_info_heading_critical_plural.replace( '%s', '<span class="issue-count">' + count + '</span>' );
|
||||
}
|
||||
} else if ( 'recommended' === issue.status ) {
|
||||
if ( count <= 1 ) {
|
||||
heading = SiteHealth.string.site_info_heading_recommended_single.replace( '%s', '<span class="issue-count">' + count + '</span>' );
|
||||
} else {
|
||||
heading = SiteHealth.string.site_info_heading_recommended_plural.replace( '%s', '<span class="issue-count">' + count + '</span>' );
|
||||
}
|
||||
} else if ( 'good' === issue.status ) {
|
||||
if ( count <= 1 ) {
|
||||
heading = SiteHealth.string.site_info_heading_good_single.replace( '%s', '<span class="issue-count">' + count + '</span>' );
|
||||
} else {
|
||||
heading = SiteHealth.string.site_info_heading_good_plural.replace( '%s', '<span class="issue-count">' + count + '</span>' );
|
||||
}
|
||||
}
|
||||
|
||||
if ( heading ) {
|
||||
$( '.site-health-issue-count-title', issueWrapper ).html( heading );
|
||||
}
|
||||
|
||||
$( '.issues', '#health-check-issues-' + issue.status ).append( template( issue ) );
|
||||
}
|
||||
|
||||
function RecalculateProgression() {
|
||||
const $progress = $( '.site-health-progress' );
|
||||
const $wrapper = $progress.closest( '.site-health-progress-wrapper' );
|
||||
const $progressLabel = $( '.site-health-progress-label', $wrapper );
|
||||
const $circle = $( '.site-health-progress svg #bar' );
|
||||
const totalTests = parseInt( SiteHealth.site_status.issues.good, 0 ) + parseInt( SiteHealth.site_status.issues.recommended, 0 ) + ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
|
||||
const failedTests = ( parseInt( SiteHealth.site_status.issues.recommended, 0 ) * 0.5 ) + ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
|
||||
let val = 100 - Math.ceil( ( failedTests / totalTests ) * 100 );
|
||||
|
||||
if ( 0 === totalTests ) {
|
||||
$progress.addClass( 'hidden' );
|
||||
return;
|
||||
}
|
||||
|
||||
$wrapper.removeClass( 'loading' );
|
||||
|
||||
const r = $circle.attr( 'r' );
|
||||
const c = Math.PI * ( r * 2 );
|
||||
|
||||
if ( 0 > val ) {
|
||||
val = 0;
|
||||
}
|
||||
if ( 100 < val ) {
|
||||
val = 100;
|
||||
}
|
||||
|
||||
const pct = ( ( 100 - val ) / 100 ) * c;
|
||||
|
||||
$circle.css( { strokeDashoffset: pct } );
|
||||
|
||||
if ( 1 > parseInt( SiteHealth.site_status.issues.critical, 0 ) ) {
|
||||
$( '#health-check-issues-critical' ).addClass( 'hidden' );
|
||||
}
|
||||
|
||||
if ( 1 > parseInt( SiteHealth.site_status.issues.recommended, 0 ) ) {
|
||||
$( '#health-check-issues-recommended' ).addClass( 'hidden' );
|
||||
}
|
||||
|
||||
if ( ! isDebugTab ) {
|
||||
$.post(
|
||||
ajaxurl,
|
||||
{
|
||||
action: 'health-check-site-status-result',
|
||||
_wpnonce: SiteHealth.nonce.site_status_result,
|
||||
counts: SiteHealth.site_status.issues,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if ( 80 <= val && 0 === parseInt( SiteHealth.site_status.issues.critical, 0 ) ) {
|
||||
$wrapper.addClass( 'green' ).removeClass( 'orange' );
|
||||
|
||||
$progressLabel.text( SiteHealth.string.site_health_complete_pass );
|
||||
wp.a11y.speak( SiteHealth.string.site_health_complete_pass_sr );
|
||||
} else {
|
||||
$wrapper.addClass( 'orange' ).removeClass( 'green' );
|
||||
|
||||
$progressLabel.text( SiteHealth.string.site_health_complete_fail );
|
||||
wp.a11y.speak( SiteHealth.string.site_health_complete_fail_sr );
|
||||
}
|
||||
|
||||
if ( 100 === val ) {
|
||||
$( '.site-status-all-clear' ).removeClass( 'hide' );
|
||||
$( '.site-status-has-issues' ).addClass( 'hide' );
|
||||
}
|
||||
}
|
||||
|
||||
function maybeRunNextAsyncTest() {
|
||||
let doCalculation = true;
|
||||
|
||||
if ( 1 <= SiteHealth.site_status.async.length ) {
|
||||
$.each( SiteHealth.site_status.async, function() {
|
||||
data = {
|
||||
action: 'health-check-site-status',
|
||||
feature: this.test,
|
||||
_wpnonce: SiteHealth.nonce.site_status,
|
||||
};
|
||||
|
||||
if ( this.completed ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
doCalculation = false;
|
||||
|
||||
this.completed = true;
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function( response ) {
|
||||
if ( typeof wp.hooks !== 'undefined' ) {
|
||||
AppendIssue( wp.hooks.applyFilters( 'site_status_test_result', response.data ) );
|
||||
} else {
|
||||
AppendIssue( response.data );
|
||||
}
|
||||
maybeRunNextAsyncTest();
|
||||
}
|
||||
);
|
||||
|
||||
return false;
|
||||
} );
|
||||
}
|
||||
|
||||
if ( doCalculation ) {
|
||||
RecalculateProgression();
|
||||
}
|
||||
}
|
||||
|
||||
if ( 'undefined' !== typeof SiteHealth ) {
|
||||
if ( 0 === SiteHealth.site_status.direct.length && 0 === SiteHealth.site_status.async.length ) {
|
||||
RecalculateProgression();
|
||||
} else {
|
||||
SiteHealth.site_status.issues = {
|
||||
good: 0,
|
||||
recommended: 0,
|
||||
critical: 0,
|
||||
};
|
||||
}
|
||||
|
||||
if ( 0 < SiteHealth.site_status.direct.length ) {
|
||||
$.each( SiteHealth.site_status.direct, function() {
|
||||
AppendIssue( this );
|
||||
} );
|
||||
}
|
||||
|
||||
if ( 0 < SiteHealth.site_status.async.length ) {
|
||||
data = {
|
||||
action: 'health-check-site-status',
|
||||
feature: SiteHealth.site_status.async[ 0 ].test,
|
||||
_wpnonce: SiteHealth.nonce.site_status,
|
||||
};
|
||||
|
||||
SiteHealth.site_status.async[ 0 ].completed = true;
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function( response ) {
|
||||
AppendIssue( response.data );
|
||||
maybeRunNextAsyncTest();
|
||||
}
|
||||
);
|
||||
} else {
|
||||
RecalculateProgression();
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
jQuery( document ).ready( function( $ ) {
|
||||
$( '.show-remaining' ).click( function() {
|
||||
$( '.hidden', $( this ).closest( 'ul' ) ).removeClass( 'hidden' );
|
||||
} );
|
||||
} );
|
||||
|
||||
/* global ajaxurl, SiteHealth */
|
||||
jQuery( document ).ready( function( $ ) {
|
||||
$( '#health-check-file-integrity' ).submit( function( e ) {
|
||||
const data = {
|
||||
action: 'health-check-files-integrity-check',
|
||||
_wpnonce: SiteHealth.nonce.files_integrity_check,
|
||||
};
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$( '#tools-file-integrity-response-holder' ).html( '<span class="spinner"></span>' );
|
||||
$( '#tools-file-integrity-response-holder .spinner' ).addClass( 'is-active' );
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function( response ) {
|
||||
$( '#tools-file-integrity-response-holder .spinner' ).removeClass( 'is-active' );
|
||||
$( '#tools-file-integrity-response-holder' ).parent().css( 'height', 'auto' );
|
||||
$( '#tools-file-integrity-response-holder' ).html( response.data.message );
|
||||
}
|
||||
);
|
||||
} );
|
||||
|
||||
$( '#tools-file-integrity-response-holder' ).on( 'click', 'a[href="#health-check-diff"]', function( e ) {
|
||||
const file = $( this ).data( 'file' );
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$( '#health-check-diff-modal' ).toggle();
|
||||
$( '#health-check-diff-modal #health-check-diff-modal-content .spinner' ).addClass( 'is-active' );
|
||||
|
||||
const data = {
|
||||
action: 'health-check-view-file-diff',
|
||||
file,
|
||||
_wpnonce: SiteHealth.nonce.view_file_diff,
|
||||
};
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function( response ) {
|
||||
$( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( response.data.message );
|
||||
$( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( file );
|
||||
$( '#health-check-diff-modal #health-check-diff-modal-content .spinner' ).removeClass( 'is-active' );
|
||||
}
|
||||
);
|
||||
} );
|
||||
} );
|
||||
|
||||
jQuery( document ).ready( function( $ ) {
|
||||
$( '#health-check-diff-modal' ).on( 'click', 'a[href="#health-check-diff-modal-close"]', function( e ) {
|
||||
e.preventDefault();
|
||||
$( '#health-check-diff-modal' ).toggle();
|
||||
$( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( '' );
|
||||
$( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( '' );
|
||||
} );
|
||||
|
||||
$( document ).keyup( function( e ) {
|
||||
if ( 27 === e.which ) {
|
||||
$( '#health-check-diff-modal' ).css( 'display', 'none' );
|
||||
$( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( '' );
|
||||
$( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( '' );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
/* global ajaxurl, SiteHealth */
|
||||
jQuery( document ).ready( function( $ ) {
|
||||
$( '#health-check-mail-check' ).submit( function( e ) {
|
||||
const email = $( '#health-check-mail-check #email' ).val(),
|
||||
emailMessage = $( '#health-check-mail-check #email_message' ).val();
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$( '#tools-mail-check-response-holder' ).html( '<span class="spinner"></span>' );
|
||||
$( '#tools-mail-check-response-holder .spinner' ).addClass( 'is-active' );
|
||||
|
||||
const data = {
|
||||
action: 'health-check-mail-check',
|
||||
email,
|
||||
email_message: emailMessage,
|
||||
_wpnonce: SiteHealth.nonce.mail_check,
|
||||
};
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function( response ) {
|
||||
$( '#tools-mail-check-response-holder .spinner' ).removeClass( 'is-active' );
|
||||
$( '#tools-mail-check-response-holder' ).parent().css( 'height', 'auto' );
|
||||
$( '#tools-mail-check-response-holder' ).html( response.data.message );
|
||||
}
|
||||
);
|
||||
} );
|
||||
} );
|
||||
|
||||
/* global ajaxurl, SiteHealth */
|
||||
jQuery( document ).ready( function( $ ) {
|
||||
$( '#health-check-tool-plugin-compat' ).click( function() {
|
||||
$( 'tr', '#health-check-tool-plugin-compat-list' ).data( 'plugin-checked', false );
|
||||
$( '.spinner', '#health-check-tool-plugin-compat-list' ).addClass( 'is-active' );
|
||||
|
||||
$( this ).attr( 'disabled', true );
|
||||
|
||||
HealthCheckToolsPluginCompatTest();
|
||||
} );
|
||||
|
||||
function HealthCheckToolsPluginCompatTest() {
|
||||
const $plugins = $( '[data-plugin-checked="false"]', '#health-check-tool-plugin-compat-list' );
|
||||
|
||||
if ( $plugins.length <= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $nextPlugin = $( $plugins[ 0 ] );
|
||||
|
||||
$nextPlugin.attr( 'data-plugin-checked', 'true' );
|
||||
|
||||
const data = {
|
||||
action: 'health-check-tools-plugin-compat',
|
||||
slug: $nextPlugin.data( 'plugin-slug' ),
|
||||
version: $nextPlugin.data( 'plugin-version' ),
|
||||
_wpnonce: SiteHealth.nonce.tools_plugin_compat,
|
||||
};
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function( response ) {
|
||||
$( '.spinner', $nextPlugin ).removeClass( 'is-active' );
|
||||
$( '.supported-version', $nextPlugin ).append( response.data.version );
|
||||
|
||||
HealthCheckToolsPluginCompatTest();
|
||||
}
|
||||
);
|
||||
}
|
||||
} );
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
= v1.3.2 =
|
||||
* Add polyfill for directory size calculations for sites running WordPress versions older than 5.2.0
|
||||
* Fix link for the extended PHP information
|
||||
|
||||
= v1.3.1 =
|
||||
* Include missing dependency for JavaScript files, first introduced in WordPress 5.2
|
||||
|
||||
= v1.3.0 =
|
||||
* Plugin moved to the Tools section in the admin menu
|
||||
* New UI/UX for the plugin pages
|
||||
* New troubleshooting mode UI/UX
|
||||
* Removed the backup reminder nag
|
||||
* Improved security hardening
|
||||
* Changed cookie names for improved hosting compatibility
|
||||
* Improved accessibility
|
||||
* Automatically check for critical issues once a week (adds a counter next to the menu item)
|
||||
* Dates in the email tester now follow your site settings
|
||||
|
||||
= v1.2.5 =
|
||||
* Fix: Ensure the REST API status test runs as intended.
|
||||
* Fix: Remove warning on plugin screens when premium plugins are used.
|
||||
* Fix: Backup reminder would not remain dismissed in all scenarios after the recent update.
|
||||
|
||||
= v1.2.4 =
|
||||
* Security: Prevent arbitrary file viewing through the integrity file actions. Independently reported by Julien Legras of [Synacktiv](https://synacktiv.com) and siliconforks.
|
||||
* Security: Site status was available to any user with a subscriber role or higher on a site. Reported by Julien Legras of [Synacktiv](https://synacktiv.com).
|
||||
* Security: Hardened the troubleshooting mode session so it is locked to the users location when active.
|
||||
* New enhancement: Check that various PHP extensions exist, as recommended by the WordPress Hosting Community.
|
||||
* New enhancement: Check if update APIs are being manipulated by plugins or themes.
|
||||
* Fix: Copying debug information had the wrong indentation for easier readability.
|
||||
* Fix: Toggling plugins and themes from the troubleshooting widget on in the dashboard now lets you expand/collapse them as intended.
|
||||
* Fix: When debugging was enabled in WordPress, disabling a plugin in troubleshooting mode would cause a WSOD if the disabled plugin caused a fatal error.
|
||||
|
||||
= v1.2.3 =
|
||||
* Added REST API availability test to the Site Status
|
||||
|
||||
= v 1.2.2 =
|
||||
* Added Twenty Nineteen as a recognized core theme.
|
||||
|
||||
= v 1.2.1 =
|
||||
* Make sure only those with access to the plugin see the backup encouragement notice.
|
||||
* Make sure the `is_troubleshooting()` checks are available to the Site Status tester when the MU plugin may not have updated yet.
|
||||
* Avoid a warning of an undefined variable if you have the latest WordPress version installed.
|
||||
|
||||
= v 1.2.0 =
|
||||
* Changed plugin name, it now better describes the plugins two primary purposes.
|
||||
* Changed the `Health Check` tab, it's now named `Site Status`, as we used the old name too many places and it was confusing.
|
||||
* Site status tests now run asynchronously, making the page load much faster.
|
||||
* The HTTPS tests now also check your Site URL settings to make sure they are following recommended best practices.
|
||||
* Fixed a warning preventing plugin names from displaying on the front-end in some cases.
|
||||
* Fixed an issue where you might get a 500 error if you tried using Troubleshooting Mode while using a child theme.
|
||||
* Automatically disable/enable a plugin or theme in Troubleshooting Mode if they are detected to cause errors.
|
||||
* Introduce a new dashboard widget during Troubleshooting Mode (and a simplified version on the plugins screen) to better explain what is going on, and make available actions more discoverable than the admin menu is.
|
||||
* Some text improvements throughout the plugin.
|
||||
* When loopback tests fail, we previously tested all plugins at once, for sites that have many plugins this may fail as the request times out. We now test one plugin at a time to avoid this, while also showing more information at the tests are running to the end user.
|
||||
|
||||
= v 1.1.2 =
|
||||
* Fixed child themes not displaying properly in Troubleshooting Mode.
|
||||
* Improved styling for the backup warning, shown when activating the plugin, so it doesn't block mobile users.
|
||||
* Added explanations to the plugins screen if you enter Troubleshooting Mode there, so users know what is going on.
|
||||
* Fixed admin menu overflowing if too many plugins exist.
|
||||
|
||||
= v 1.1.1 =
|
||||
* Fixed a fatal error that would occur if a user had an older version of Troubleshooting Mode on their system.
|
||||
|
||||
= v 1.1.0 =
|
||||
* Check for theme, plugin and WordPress updates when visiting the debug tab.
|
||||
* Improved wording on some failure situations.
|
||||
* Made the Debug Information tab a bit easier to read with fixed table styles.
|
||||
* Redesigned tools page, with added accordion to avoid information overload, and different features mixing together.
|
||||
* Mail test tool now allows you to include an optional customized message.
|
||||
* Users can now change between any installed theme while in troubleshooting mode.
|
||||
* Renamed the Must-Use plugin, making it align with what features present in the file.
|
||||
* Improved the plugin cleanup process, when the plugin is deleted.
|
||||
* Show full plugin names, and not slugs, in the troubleshooting admin bar menu.
|
||||
* Check if the .htaccess file contains any rules not added by WordPress core in the debug section.
|
||||
* Allow the disabling of Troubleshooting Mode from the same page as you previously enabled it from.
|
||||
* Removed cURL checks from the automated test page, this was more confusion than help.
|
||||
* Add installation size to the debug information.
|
||||
|
||||
= v 1.0.1 =
|
||||
* Fixed email tester having the wrong class reference, preventing it from running.
|
||||
* Add some missing text domains preventing full translations.
|
||||
|
||||
= v 1.0.0 =
|
||||
* Added minimum PHP version checks with documentation links.
|
||||
* Added testing with a default theme to the loopback checker.
|
||||
* Added cURL version checker to the health check tab.
|
||||
* Added simple e-mail tester.
|
||||
* Added core file integrity checker.
|
||||
* Added capability checks, to avoid installing things that may modify the database while troubleshooting.
|
||||
* Added a prompt to install a default theme if none exist.
|
||||
* Added a warning encouraging users to maintain up to date backups when troubleshooting.
|
||||
* Fixed MU plugin not always updating (if available) when a user tries to troubleshoot.
|
||||
* Fixed fatal error when trying to troubleshoot "too early".
|
||||
* Updated troubleshooting drop down, it no longer shows theme switching if no default theme exists.
|
||||
* Removed the checkbox requirement from the Troubleshooting tab, it wasn't needed any more, and added pointless complexity now.
|
||||
|
||||
= v 0.9.0 =
|
||||
* Various string changes, typo fixes and translation enhancements.
|
||||
* Added conditional hiding of the plugins list from the admin bar, if there's too many plugins it becomes a bad experience. (Hidden if there are more than 20 active plugins)
|
||||
* Added ability to enable/disable plugins in Troubleshooting Mode from the plugins list.
|
||||
* Added filter to remove actions from the plugin list in Troubleshooting Mode.
|
||||
* Fixed notices on the plugin screen when plugin data may be inconsistent.
|
||||
* Fixed jumping directly to troubleshooting mode for single file plugins placed directly in the plugin directory root.
|
||||
* Fixed issue where troubleshooting a plugin directly made it impossible to disable it while in Troubleshooting Mode.
|
||||
* Fixed so that the original language is returned when translating the debug data for copying.
|
||||
* Fixed issue where the Debug screen would turn to half-English when using a non-English language.
|
||||
* Fixed an issue where plugins could become truly disabled on a site when in Troubleshooting Mode.
|
||||
* Fixed so that enabled/disabled plugins don't carry over between troubleshooting sessions.
|
||||
|
||||
= v 0.8.0 =
|
||||
* Updated recommended PHP version to mirror WordPress.org.
|
||||
* Updated texts for troubleshooting mode.
|
||||
* Re-labeled database terms to be more user friendly.
|
||||
* Added media information to the debug tab.
|
||||
* Added individual `Troubleshoot` links for the list of active plugins.
|
||||
* Added automatic copy to clipboard with supported browsers in the debug tab.
|
||||
|
||||
= v 0.7.0 =
|
||||
* Troubleshooting mode now also switches to a default theme.
|
||||
* Introduced a method for toggling default or active theme use when in troubleshooting mode.
|
||||
* Introduced a method for enabling/disabling plugins while in troubleshooting mode.
|
||||
* Introduced a method for disabling troubleshooting mode without needing to log out and back in again.
|
||||
|
||||
= v 0.6.0 =
|
||||
* Improved loopback tests
|
||||
* Check if loopbacks can be completed without plugins activated
|
||||
* Test individual plugins to identify loopback blockers
|
||||
* Add troubleshooting mode, test your website without any plugins for your session without disabling functionality for visitors.
|
||||
|
||||
= v 0.5.1 =
|
||||
* Introduced loopback check to the health checker status.
|
||||
|
||||
= v 0.5.0 =
|
||||
* Added clarity to many text strings.
|
||||
* Avoid listing MU directories if it's not being used.
|
||||
* Add a Table of Contents heading and make navigating the debug page from it smoother.
|
||||
* Only enqueue our CSS and JavaScript if we are on the health check pages.
|
||||
* Add some missing version numbers nor being included in text strings.
|
||||
* Avoid fatal errors if accessing files directly, caused by translation functions being used when they don't exist.
|
||||
* Avoid "empty" strings when author or version is missing from plugins or themes.
|
||||
* Make the health checker test background updates.
|
||||
* Make the health checker look for missed scheduled events.
|
||||
* If using a localized version of WordPress, also display the copy and paste field in English if using an international support resource.
|
||||
* Indicate if 64bit values are supported by PHP in the debug section.
|
||||
* Improved MariaDB version detection/comparison.
|
||||
|
||||
= v 0.4.1 =
|
||||
* Better SQL version detection to account for MariaDB versions
|
||||
* Added translation support
|
||||
* Removed unintentional indentations in the debug copying field
|
||||
|
||||
= v 0.4 =
|
||||
* Added debug section
|
||||
* Added PHP info section
|
||||
* Cleaned up the health check
|
||||
* Added WordPress.org connectivity check
|
||||
* Added HTTPS check
|
||||
|
||||
= v 0.3.1 =
|
||||
* Fixed a few typos
|
||||
|
||||
= v 0.3 =
|
||||
* Added recommended PHP and MySQL versions
|
||||
* Check for utf8mb4 support
|
||||
* Fixed a bunch of PHP warnings
|
||||
|
||||
= v 0.2.1 =
|
||||
* Fixed version comparision bug - When the server had the exact required versions we reported it as out of date.
|
||||
|
||||
= v 0.2 =
|
||||
* Updated with actual PHP and MySQL version requirements for WordPress 3.2
|
||||
|
||||
= v 0.1 =
|
||||
* Initial release with checks for the PHP and MySQL versions we will likely target for WordPress 3.2
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
/**
|
||||
* Plugins primary file, in charge of including all other dependencies.
|
||||
*
|
||||
* @package Health Check
|
||||
*
|
||||
* @wordpress-plugin
|
||||
* Plugin Name: Health Check & Troubleshooting
|
||||
* Plugin URI: https://wordpress.org/plugins/health-check/
|
||||
* Description: Checks the health of your WordPress install.
|
||||
* Author: The WordPress.org community
|
||||
* Version: 1.4.2
|
||||
* Author URI: https://wordpress.org/plugins/health-check/
|
||||
* Text Domain: health-check
|
||||
*/
|
||||
|
||||
// Check that the file is not accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
// Set the minimum PHP version WordPress supports.
|
||||
define( 'HEALTH_CHECK_PHP_MIN_VERSION', '5.2.4' );
|
||||
|
||||
// Set the lowest PHP version still receiving security updates.
|
||||
define( 'HEALTH_CHECK_PHP_SUPPORTED_VERSION', '5.6' );
|
||||
|
||||
// Set the PHP version WordPress recommends.
|
||||
define( 'HEALTH_CHECK_PHP_REC_VERSION', '7.2' );
|
||||
|
||||
// Set the minimum MySQL version WordPress supports.
|
||||
define( 'HEALTH_CHECK_MYSQL_MIN_VERSION', '5.0' );
|
||||
|
||||
// Set the MySQL version WordPress recommends.
|
||||
define( 'HEALTH_CHECK_MYSQL_REC_VERSION', '5.6' );
|
||||
|
||||
// Set the plugin version.
|
||||
define( 'HEALTH_CHECK_PLUGIN_VERSION', '1.4.2' );
|
||||
|
||||
// Set the plugin file.
|
||||
define( 'HEALTH_CHECK_PLUGIN_FILE', __FILE__ );
|
||||
|
||||
// Set the absolute path for the plugin.
|
||||
define( 'HEALTH_CHECK_PLUGIN_DIRECTORY', plugin_dir_path( __FILE__ ) );
|
||||
|
||||
// Set the plugin URL root.
|
||||
define( 'HEALTH_CHECK_PLUGIN_URL', plugins_url( '/', __FILE__ ) );
|
||||
|
||||
// Set the current cURL version.
|
||||
define( 'HEALTH_CHECK_CURL_VERSION', '7.58' );
|
||||
|
||||
// Set the minimum cURL version that we've tested that core works with.
|
||||
define( 'HEALTH_CHECK_CURL_MIN_VERSION', '7.38' );
|
||||
|
||||
// Always include our compatibility file first.
|
||||
require_once( dirname( __FILE__ ) . '/includes/compat.php' );
|
||||
|
||||
// Include class-files used by our plugin.
|
||||
require_once( dirname( __FILE__ ) . '/includes/class-health-check.php' );
|
||||
require_once( dirname( __FILE__ ) . '/includes/class-health-check-auto-updates.php' );
|
||||
require_once( dirname( __FILE__ ) . '/includes/class-health-check-wp-cron.php' );
|
||||
require_once( dirname( __FILE__ ) . '/includes/class-health-check-debug-data.php' );
|
||||
require_once( dirname( __FILE__ ) . '/includes/class-health-check-loopback.php' );
|
||||
require_once( dirname( __FILE__ ) . '/includes/class-health-check-troubleshoot.php' );
|
||||
require_once( dirname( __FILE__ ) . '/includes/class-health-check-site-status.php' );
|
||||
require_once( dirname( __FILE__ ) . '/includes/class-health-check-updates.php' );
|
||||
require_once( dirname( __FILE__ ) . '/includes/class-health-check-dashboard-widget.php' );
|
||||
|
||||
// Tools section.
|
||||
require_once( dirname( __FILE__ ) . '/includes/tools/class-health-check-tool.php' );
|
||||
require_once( dirname( __FILE__ ) . '/includes/tools/class-health-check-files-integrity.php' );
|
||||
require_once( dirname( __FILE__ ) . '/includes/tools/class-health-check-mail-check.php' );
|
||||
require_once( dirname( __FILE__ ) . '/includes/tools/class-health-check-plugin-compatibility.php' );
|
||||
|
||||
// Initialize our plugin.
|
||||
new Health_Check();
|
||||
|
||||
// Initialize the dashboard widget.
|
||||
new Health_Check_Dashboard_Widget();
|
||||
|
||||
// Setup up scheduled events.
|
||||
register_activation_hook( __FILE__, array( 'Health_Check', 'plugin_activation' ) );
|
||||
register_deactivation_hook( __FILE__, array( 'Health_Check', 'plugin_deactivation' ) );
|
||||
|
||||
if ( defined( 'WP_CLI' ) && WP_CLI ) {
|
||||
require_once( dirname( __FILE__ ) . '/includes/class-health-check-wp-cli.php' );
|
||||
}
|
||||
|
|
@ -0,0 +1,453 @@
|
|||
<?php
|
||||
/**
|
||||
* Class for testing automatic updates in the WordPress code.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Health_Check_Auto_Updates
|
||||
*/
|
||||
class Health_Check_Auto_Updates {
|
||||
/**
|
||||
* WP_Site_Health_Auto_Updates constructor.
|
||||
* @since 5.2.0
|
||||
*/
|
||||
public function __construct() {
|
||||
include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
||||
}
|
||||
|
||||
public function run_tests() {
|
||||
$tests = array();
|
||||
|
||||
foreach ( get_class_methods( $this ) as $method ) {
|
||||
if ( 'test_' !== substr( $method, 0, 5 ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = call_user_func( array( $this, $method ) );
|
||||
|
||||
if ( false === $result || null === $result ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = (object) $result;
|
||||
|
||||
if ( empty( $result->severity ) ) {
|
||||
$result->severity = 'warning';
|
||||
}
|
||||
|
||||
$tests[ $method ] = $result;
|
||||
}
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
public function test_contant_DISALLOW_FILE_MODS() {
|
||||
return $this->check_constants( 'DISALLOW_FILE_MODS', false );
|
||||
}
|
||||
|
||||
public function test_contant_AUTOMATIC_UPDATER_DISABLED() {
|
||||
return $this->check_constants( 'AUTOMATIC_UPDATER_DISABLED', false );
|
||||
}
|
||||
|
||||
public function test_contant_WP_AUTO_UPDATE_CORE() {
|
||||
return $this->check_constants( 'WP_AUTO_UPDATE_CORE', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if auto-updates related constants are set correctly.
|
||||
*
|
||||
* @since 5.2.0
|
||||
*
|
||||
* @param string $constant The name of the constant to check.
|
||||
* @param bool $value The value that the constant should be, if set.
|
||||
* @return array The test results.
|
||||
*/
|
||||
public function check_constants( $constant, $value ) {
|
||||
if ( defined( $constant ) && constant( $constant ) != $value ) {
|
||||
return array(
|
||||
'description' => sprintf(
|
||||
/* translators: %s: Name of the constant used. */
|
||||
__( 'The %s constant is defined and enabled.', 'health-check' ),
|
||||
"<code>$constant</code>"
|
||||
),
|
||||
'severity' => 'fail',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if updates are intercepted by a filter.
|
||||
*
|
||||
* @since 5.2.0
|
||||
*
|
||||
* @return array The test results.
|
||||
*/
|
||||
public function test_wp_version_check_attached() {
|
||||
if ( ! is_main_site() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cookies = wp_unslash( $_COOKIE );
|
||||
$timeout = 10;
|
||||
$headers = array(
|
||||
'Cache-Control' => 'no-cache',
|
||||
);
|
||||
|
||||
// Include Basic auth in loopback requests.
|
||||
if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
|
||||
$headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
|
||||
}
|
||||
|
||||
$url = add_query_arg(
|
||||
array(
|
||||
'health-check-test-wp_version_check' => true,
|
||||
),
|
||||
admin_url( '' )
|
||||
);
|
||||
|
||||
$test = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
|
||||
|
||||
if ( is_wp_error( $test ) ) {
|
||||
return array(
|
||||
'description' => sprintf(
|
||||
/* translators: %s: Name of the filter used. */
|
||||
__( 'Could not confirm that the %s filter is available.', 'health-check' ),
|
||||
'<code>wp_version_check()</code>'
|
||||
),
|
||||
'severity' => 'warning',
|
||||
);
|
||||
}
|
||||
|
||||
$response = wp_remote_retrieve_body( $test );
|
||||
|
||||
if ( 'yes' !== $response ) {
|
||||
return array(
|
||||
'description' => sprintf(
|
||||
/* translators: %s: Name of the filter used. */
|
||||
__( 'A plugin has prevented updates by disabling %s.', 'health-check' ),
|
||||
'<code>wp_version_check()</code>'
|
||||
),
|
||||
'severity' => 'fail',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if automatic updates are disabled by a filter.
|
||||
*
|
||||
* @since 5.2.0
|
||||
*
|
||||
* @return array The test results.
|
||||
*/
|
||||
public function test_filters_automatic_updater_disabled() {
|
||||
if ( apply_filters( 'automatic_updater_disabled', false ) ) {
|
||||
return array(
|
||||
'description' => sprintf(
|
||||
/* translators: %s: Name of the filter used. */
|
||||
__( 'The %s filter is enabled.', 'health-check' ),
|
||||
'<code>automatic_updater_disabled</code>'
|
||||
),
|
||||
'severity' => 'fail',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if automatic updates have tried to run, but failed, previously.
|
||||
*
|
||||
* @since 5.2.0
|
||||
*
|
||||
* @return array|bool The test results. false if the auto updates failed.
|
||||
*/
|
||||
function test_if_failed_update() {
|
||||
$failed = get_site_option( 'auto_core_update_failed' );
|
||||
|
||||
if ( ! $failed ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! empty( $failed['critical'] ) ) {
|
||||
$description = __( 'A previous automatic background update ended with a critical failure, so updates are now disabled.', 'health-check' );
|
||||
$description .= ' ' . __( 'You would have received an email because of this.', 'health-check' );
|
||||
$description .= ' ' . __( "When you've been able to update using the \"Update Now\" button on Dashboard > Updates, we'll clear this error for future update attempts.", 'health-check' );
|
||||
$description .= ' ' . sprintf(
|
||||
/* translators: %s: Code of error shown. */
|
||||
__( 'The error code was %s.', 'health-check' ),
|
||||
'<code>' . $failed['error_code'] . '</code>'
|
||||
);
|
||||
return array(
|
||||
'description' => $description,
|
||||
'severity' => 'warning',
|
||||
);
|
||||
}
|
||||
|
||||
$description = __( 'A previous automatic background update could not occur.', 'health-check' );
|
||||
if ( empty( $failed['retry'] ) ) {
|
||||
$description .= ' ' . __( 'You would have received an email because of this.', 'health-check' );
|
||||
}
|
||||
|
||||
$description .= ' ' . __( "We'll try again with the next release.", 'health-check' );
|
||||
$description .= ' ' . sprintf(
|
||||
/* translators: %s: Code of error shown. */
|
||||
__( 'The error code was %s.', 'health-check' ),
|
||||
'<code>' . $failed['error_code'] . '</code>'
|
||||
);
|
||||
return array(
|
||||
'description' => $description,
|
||||
'severity' => 'warning',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if WordPress is controlled by a VCS (Git, Subversion etc).
|
||||
*
|
||||
* @since 5.2.0
|
||||
*
|
||||
* @return array The test results.
|
||||
*/
|
||||
public function test_vcs_abspath() {
|
||||
$context_dirs = array( ABSPATH );
|
||||
$vcs_dirs = array( '.svn', '.git', '.hg', '.bzr' );
|
||||
$check_dirs = array();
|
||||
|
||||
foreach ( $context_dirs as $context_dir ) {
|
||||
// Walk up from $context_dir to the root.
|
||||
do {
|
||||
$check_dirs[] = $context_dir;
|
||||
|
||||
// Once we've hit '/' or 'C:\', we need to stop. dirname will keep returning the input here.
|
||||
if ( dirname( $context_dir ) == $context_dir ) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Continue one level at a time.
|
||||
} while ( $context_dir = dirname( $context_dir ) );
|
||||
}
|
||||
|
||||
$check_dirs = array_unique( $check_dirs );
|
||||
|
||||
// Search all directories we've found for evidence of version control.
|
||||
foreach ( $vcs_dirs as $vcs_dir ) {
|
||||
foreach ( $check_dirs as $check_dir ) {
|
||||
// phpcs:ignore
|
||||
if ( $checkout = @is_dir( rtrim( $check_dir, '\\/' ) . "/$vcs_dir" ) ) {
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $checkout && ! apply_filters( 'automatic_updates_is_vcs_checkout', true, ABSPATH ) ) {
|
||||
return array(
|
||||
'description' => sprintf(
|
||||
// translators: 1: Folder name. 2: Version control directory. 3: Filter name.
|
||||
__( 'The folder %1$s was detected as being under version control (%2$s), but the %3$s filter is allowing updates.', 'health-check' ),
|
||||
'<code>' . $check_dir . '</code>',
|
||||
"<code>$vcs_dir</code>",
|
||||
'<code>automatic_updates_is_vcs_checkout</code>'
|
||||
),
|
||||
'severity' => 'info',
|
||||
);
|
||||
}
|
||||
|
||||
if ( $checkout ) {
|
||||
return array(
|
||||
'description' => sprintf(
|
||||
// translators: 1: Folder name. 2: Version control directory.
|
||||
__( 'The folder %1$s was detected as being under version control (%2$s).', 'health-check' ),
|
||||
'<code>' . $check_dir . '</code>',
|
||||
"<code>$vcs_dir</code>"
|
||||
),
|
||||
'severity' => 'fail',
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'description' => __( 'No version control systems were detected.', 'health-check' ),
|
||||
'severity' => 'pass',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we can access files without providing credentials.
|
||||
*
|
||||
* @since 5.2.0
|
||||
*
|
||||
* @return array The test results.
|
||||
*/
|
||||
function test_check_wp_filesystem_method() {
|
||||
$skin = new Automatic_Upgrader_Skin;
|
||||
$success = $skin->request_filesystem_credentials( false, ABSPATH );
|
||||
|
||||
if ( ! $success ) {
|
||||
$description = __( 'Your installation of WordPress prompts for FTP credentials to perform updates.', 'health-check' );
|
||||
$description .= ' ' . __( '(Your site is performing updates over FTP due to file ownership. Talk to your hosting company.)', 'health-check' );
|
||||
|
||||
return array(
|
||||
'description' => $description,
|
||||
'severity' => 'fail',
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'description' => __( "Your installation of WordPress doesn't require FTP credentials to perform updates.", 'health-check' ),
|
||||
'severity' => 'pass',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if core files are writable by the web user/group.
|
||||
*
|
||||
* @since 5.2.0
|
||||
*
|
||||
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
|
||||
*
|
||||
* @return array|bool The test results. false if they're not writeable.
|
||||
*/
|
||||
function test_all_files_writable() {
|
||||
global $wp_filesystem;
|
||||
|
||||
include ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
|
||||
|
||||
$skin = new Automatic_Upgrader_Skin;
|
||||
$success = $skin->request_filesystem_credentials( false, ABSPATH );
|
||||
|
||||
if ( ! $success ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WP_Filesystem();
|
||||
|
||||
if ( 'direct' != $wp_filesystem->method ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$checksums = get_core_checksums( $wp_version, 'en_US' );
|
||||
$dev = ( false !== strpos( $wp_version, '-' ) );
|
||||
// Get the last stable version's files and test against that
|
||||
if ( ! $checksums && $dev ) {
|
||||
$checksums = get_core_checksums( (float) $wp_version - 0.1, 'en_US' );
|
||||
}
|
||||
|
||||
// There aren't always checksums for development releases, so just skip the test if we still can't find any
|
||||
if ( ! $checksums && $dev ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $checksums ) {
|
||||
$description = sprintf(
|
||||
// translators: %s: WordPress version
|
||||
__( "Couldn't retrieve a list of the checksums for WordPress %s.", 'health-check' ),
|
||||
$wp_version
|
||||
);
|
||||
$description .= ' ' . __( 'This could mean that connections are failing to WordPress.org.', 'health-check' );
|
||||
return array(
|
||||
'description' => $description,
|
||||
'severity' => 'warning',
|
||||
);
|
||||
}
|
||||
|
||||
$unwritable_files = array();
|
||||
foreach ( array_keys( $checksums ) as $file ) {
|
||||
if ( 'wp-content' == substr( $file, 0, 10 ) ) {
|
||||
continue;
|
||||
}
|
||||
if ( ! file_exists( ABSPATH . $file ) ) {
|
||||
continue;
|
||||
}
|
||||
if ( ! is_writable( ABSPATH . $file ) ) {
|
||||
$unwritable_files[] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $unwritable_files ) {
|
||||
if ( count( $unwritable_files ) > 20 ) {
|
||||
$unwritable_files = array_slice( $unwritable_files, 0, 20 );
|
||||
$unwritable_files[] = '...';
|
||||
}
|
||||
return array(
|
||||
'description' => __( 'Some files are not writable by WordPress:', 'health-check' ) . ' <ul><li>' . implode( '</li><li>', $unwritable_files ) . '</li></ul>',
|
||||
'severity' => 'fail',
|
||||
);
|
||||
} else {
|
||||
return array(
|
||||
'description' => __( 'All of your WordPress files are writable.', 'health-check' ),
|
||||
'severity' => 'pass',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the install is using a development branch and can use nightly packages.
|
||||
*
|
||||
* @since 5.2.0
|
||||
*
|
||||
* @return array|bool The test results. false if it isn't a development version.
|
||||
*/
|
||||
function test_accepts_dev_updates() {
|
||||
include ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
|
||||
// Only for dev versions
|
||||
if ( false === strpos( $wp_version, '-' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( defined( 'WP_AUTO_UPDATE_CORE' ) && ( 'minor' === WP_AUTO_UPDATE_CORE || false === WP_AUTO_UPDATE_CORE ) ) {
|
||||
return array(
|
||||
'description' => sprintf(
|
||||
/* translators: %s: Name of the constant used. */
|
||||
__( 'WordPress development updates are blocked by the %s constant.', 'health-check' ),
|
||||
'<code>WP_AUTO_UPDATE_CORE</code>'
|
||||
),
|
||||
'severity' => 'fail',
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! apply_filters( 'allow_dev_auto_core_updates', $wp_version ) ) {
|
||||
return array(
|
||||
'description' => sprintf(
|
||||
/* translators: %s: Name of the filter used. */
|
||||
__( 'WordPress development updates are blocked by the %s filter.', 'health-check' ),
|
||||
'<code>allow_dev_auto_core_updates</code>'
|
||||
),
|
||||
'severity' => 'fail',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the site supports automatic minor updates.
|
||||
*
|
||||
* @since 5.2.0
|
||||
*
|
||||
* @return array The test results.
|
||||
*/
|
||||
function test_accepts_minor_updates() {
|
||||
if ( defined( 'WP_AUTO_UPDATE_CORE' ) && false === WP_AUTO_UPDATE_CORE ) {
|
||||
return array(
|
||||
'description' => sprintf(
|
||||
/* translators: %s: Name of the constant used. */
|
||||
__( 'WordPress security and maintenance releases are blocked by %s.', 'health-check' ),
|
||||
"<code>define( 'WP_AUTO_UPDATE_CORE', false );</code>"
|
||||
),
|
||||
'severity' => 'fail',
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! apply_filters( 'allow_minor_auto_core_updates', true ) ) {
|
||||
return array(
|
||||
'description' => sprintf(
|
||||
/* translators: %s: Name of the filter used. */
|
||||
__( 'WordPress security and maintenance releases are blocked by the %s filter.', 'health-check' ),
|
||||
'<code>allow_minor_auto_core_updates</code>'
|
||||
),
|
||||
'severity' => 'fail',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
// Check that the file is not accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
class Health_Check_Dashboard_Widget {
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'wp_dashboard_setup', array( $this, 'dashboard_setup' ) );
|
||||
}
|
||||
|
||||
function dashboard_setup() {
|
||||
wp_add_dashboard_widget(
|
||||
'health_check_status',
|
||||
__( 'Site Health Status', 'health-check' ),
|
||||
array( $this, 'widget_render' )
|
||||
);
|
||||
}
|
||||
|
||||
function widget_render() {
|
||||
$get_issues = get_transient( 'health-check-site-status-result' );
|
||||
|
||||
if ( false !== $get_issues ) {
|
||||
$issue_counts = json_decode( $get_issues );
|
||||
} else {
|
||||
$issue_counts = (object) array(
|
||||
'good' => 0,
|
||||
'recommended' => 0,
|
||||
'critical' => 0,
|
||||
);
|
||||
}
|
||||
|
||||
$issues_total = $issue_counts->recommended + $issue_counts->critical;
|
||||
?>
|
||||
<div class="health-check-title-section site-health-progress-wrapper loading hide-if-no-js">
|
||||
<div class="site-health-progress">
|
||||
<svg role="img" aria-hidden="true" focusable="false" width="100%" height="100%" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle>
|
||||
<circle id="bar" r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="site-health-progress-label">
|
||||
<?php if ( false === $get_issues ) : ?>
|
||||
<?php _e( 'No information yet…', 'health-check' ); ?>
|
||||
<?php else : ?>
|
||||
<?php _e( 'Results are still loading…', 'health-check' ); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ( false === $get_issues ) : ?>
|
||||
<p>
|
||||
<?php _e( 'No Site Health information has been gathered yet, you can do so by visiting the Site Health page, alternatively the checks will run automatically once every week.', 'health-check' ); ?>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
// translators: %s: URL for the Site Health page.
|
||||
__( '<a href="%s">Visit the Site Health page</a> to gather information on about your site..', 'health-check' ),
|
||||
esc_url( admin_url( 'tools.php?page=health-check' ) )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
|
||||
<?php else : ?>
|
||||
<p>
|
||||
<?php if ( $issue_counts->critical > 0 ) : ?>
|
||||
<?php _e( 'Your site has critical issues that should be addressed as soon as possible to improve the performance or security of your website.', 'health-check' ); ?>
|
||||
<?php elseif ( $issues_total <= 0 ) : ?>
|
||||
<?php _e( 'Great job! Your site currently passes all site health checks.', 'health-check' ); ?>
|
||||
<?php else : ?>
|
||||
<?php _e( 'Your site scores pretty well on the Health Check, but there are still some things you can do to improve the performance and security of your website.', 'health-check' ); ?>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( $issues_total > 0 && false !== $get_issues ) : ?>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
// translators: 1: Count of issues. 2: URL for the Site Health page.
|
||||
__( 'Take a look at the <strong>%1$d items</strong> on the <a href="%2$s">Site Health Check status page</a>.', 'health-check' ),
|
||||
$issues_total,
|
||||
esc_url( admin_url( 'tools.php?page=health-check' ) )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,349 @@
|
|||
<?php
|
||||
/**
|
||||
* Tests to determine if the WordPress loopbacks are able to run unhindered.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Health_Check_Loopback
|
||||
*/
|
||||
class Health_Check_Loopback {
|
||||
/**
|
||||
* Run a loopback test on our site.
|
||||
*
|
||||
* @uses wp_unslash()
|
||||
* @uses base64_encode()
|
||||
* @uses admin_url()
|
||||
* @uses add_query_arg()
|
||||
* @uses is_array()
|
||||
* @uses implode()
|
||||
* @uses wp_remote_get()
|
||||
* @uses compact()
|
||||
* @uses is_wp_error()
|
||||
* @uses wp_remote_retrieve_response_code()
|
||||
* @uses sprintf()
|
||||
*
|
||||
* @param null|string $disable_plugin_hash Optional. A hash to send with our request to disable any plugins.
|
||||
* @param null|string|array $allowed_plugins Optional. A string or array of approved plugin slugs that can run even when we globally ignore plugins.
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
static function can_perform_loopback( $disable_plugin_hash = null, $allowed_plugins = null ) {
|
||||
$cookies = wp_unslash( $_COOKIE );
|
||||
$timeout = 10;
|
||||
$headers = array(
|
||||
'Cache-Control' => 'no-cache',
|
||||
);
|
||||
|
||||
// Include Basic auth in loopback requests.
|
||||
if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
|
||||
$headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
|
||||
}
|
||||
|
||||
$url = admin_url();
|
||||
|
||||
if ( ! empty( $disable_plugin_hash ) ) {
|
||||
$url = add_query_arg(
|
||||
array(
|
||||
'health-check-disable-plugin-hash' => $disable_plugin_hash,
|
||||
),
|
||||
$url
|
||||
);
|
||||
}
|
||||
if ( ! empty( $allowed_plugins ) ) {
|
||||
if ( ! is_array( $allowed_plugins ) ) {
|
||||
$allowed_plugins = (array) $allowed_plugins;
|
||||
}
|
||||
|
||||
$url = add_query_arg(
|
||||
array(
|
||||
'health-check-allowed-plugins' => implode( ',', $allowed_plugins ),
|
||||
),
|
||||
$url
|
||||
);
|
||||
}
|
||||
|
||||
$r = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
|
||||
|
||||
if ( is_wp_error( $r ) ) {
|
||||
return (object) array(
|
||||
'status' => 'critical',
|
||||
'message' => sprintf(
|
||||
'%s<br>%s',
|
||||
esc_html__( 'The loopback request to your site failed, this means features relying on them are not currently working as expected.', 'health-check' ),
|
||||
sprintf(
|
||||
/* translators: %1$d: The HTTP response code. %2$s: The error message returned. */
|
||||
esc_html__( 'Error encountered: (%1$d) %2$s', 'health-check' ),
|
||||
wp_remote_retrieve_response_code( $r ),
|
||||
$r->get_error_message()
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if ( 200 !== wp_remote_retrieve_response_code( $r ) ) {
|
||||
return (object) array(
|
||||
'status' => 'recommended',
|
||||
'message' => sprintf(
|
||||
/* translators: %d: The HTTP response code returned. */
|
||||
esc_html__( 'The loopback request returned an unexpected http status code, %d, it was not possible to determine if this will prevent features from working as expected.', 'health-check' ),
|
||||
wp_remote_retrieve_response_code( $r )
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return (object) array(
|
||||
'status' => 'good',
|
||||
'message' => __( 'The loopback request to your site completed successfully.', 'health-check' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the loopback check, but ensure no plugins are enabled when we do so.
|
||||
*
|
||||
* @uses ob_start()
|
||||
* @uses Health_Check_Troubleshoot::mu_plugin_exists()
|
||||
* @uses Health_Check::get_filesystem_credentials()
|
||||
* @uses Health_Check_Troubleshoot::setup_must_use_plugin()
|
||||
* @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
|
||||
* @uses ob_get_clean()
|
||||
* @uses wp_send_json_error()
|
||||
* @uses md5()
|
||||
* @uses rand()
|
||||
* @uses update_option()
|
||||
* @uses Health_Check_Loopback::can_perform_loopback()
|
||||
* @uses sprintf()
|
||||
* @uses esc_attr()
|
||||
* @uses esc_html__()
|
||||
* @uses esc_html()
|
||||
* @uses wp_send_json_success()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
static function loopback_no_plugins() {
|
||||
check_ajax_referer( 'health-check-loopback-no-plugins' );
|
||||
|
||||
if ( ! current_user_can( 'view_site_health_checks' ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
$needs_creds = false;
|
||||
|
||||
if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
|
||||
if ( ! Health_Check::get_filesystem_credentials() ) {
|
||||
$needs_creds = true;
|
||||
} else {
|
||||
$check_output = Health_Check_Troubleshoot::setup_must_use_plugin();
|
||||
if ( false === $check_output ) {
|
||||
$needs_creds = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( ! Health_Check_Troubleshoot::maybe_update_must_use_plugin() ) {
|
||||
$needs_creds = true;
|
||||
}
|
||||
}
|
||||
|
||||
$result = ob_get_clean();
|
||||
|
||||
if ( $needs_creds ) {
|
||||
wp_send_json_error( $result );
|
||||
die();
|
||||
}
|
||||
|
||||
$loopback_hash = md5( rand() );
|
||||
update_option( 'health-check-disable-plugin-hash', $loopback_hash );
|
||||
update_option( 'health-check-default-theme', 'yes' );
|
||||
|
||||
$no_plugin_test = Health_Check_Loopback::can_perform_loopback( $loopback_hash );
|
||||
|
||||
$message = sprintf(
|
||||
'<br><span class="%s"></span> %s: %s',
|
||||
esc_attr( $no_plugin_test->status ),
|
||||
esc_html__( 'Result from testing without any plugins active and a default theme', 'health-check' ),
|
||||
$no_plugin_test->message
|
||||
);
|
||||
|
||||
if ( 'error' !== $no_plugin_test->status ) {
|
||||
$plugins = wp_get_active_and_valid_plugins();
|
||||
$theme = wp_get_theme();
|
||||
|
||||
$message .= '<table id="loopback-individual-plugins-list">';
|
||||
|
||||
foreach ( $plugins as $single_plugin ) {
|
||||
$plugin = get_plugin_data( $single_plugin );
|
||||
|
||||
$message .= sprintf(
|
||||
'<tr data-test-plugin="%s" class="not-tested"><td>%s</td><td class="individual-loopback-test-status">%s</td></tr>',
|
||||
esc_attr( plugin_basename( $single_plugin ) ),
|
||||
esc_html( $plugin['Name'] ),
|
||||
esc_html__( 'Waiting...', 'health-check' )
|
||||
);
|
||||
}
|
||||
|
||||
$message .= sprintf(
|
||||
'<tr id="test-single-no-theme"><td>%s</td><td class="individual-loopback-test-status">%s</td></tr>',
|
||||
sprintf(
|
||||
// translators: %s: The active theme name.
|
||||
esc_html__( 'Active theme: %s', 'health-check' ),
|
||||
$theme->name
|
||||
),
|
||||
esc_html__( 'Waiting...', 'health-check' )
|
||||
);
|
||||
|
||||
$message .= '</table>';
|
||||
|
||||
$message .= '<br><button type="button" id="loopback-individual-plugins" class="button button-primary">Test individual plugins</button>';
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'message' => $message,
|
||||
);
|
||||
|
||||
delete_option( 'health-check-default-theme' );
|
||||
|
||||
wp_send_json_success( $response );
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test individual plugins for loopback compatibility issues.
|
||||
*
|
||||
* This function will perform the loopback check, without any plugins, then conditionally enables one plugin at a time.
|
||||
*
|
||||
* @uses ob_start()
|
||||
* @uses Health_Check_Troubleshoot::mu_plugin_exists()
|
||||
* @uses Health_Check::get_filesystem_credentials()
|
||||
* @uses Health_Check_Troubleshoot::setup_must_use_plugin()
|
||||
* @uses ob_get_clean()
|
||||
* @uses wp_send_json_error()
|
||||
* @uses delete_option()
|
||||
* @uses get_option()
|
||||
* @uses md5()
|
||||
* @uses rand()
|
||||
* @uses update_option()
|
||||
* @uses explode()
|
||||
* @uses Health_Check_Loopback::can_perform_loopback()
|
||||
* @uses sprintf()
|
||||
* @uses esc_attr()
|
||||
* @uses esc_html__()
|
||||
* @uses esc_html()
|
||||
* @uses wp_send_json_success()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
static function loopback_test_individual_plugins() {
|
||||
check_ajax_referer( 'health-check-loopback-individual-plugins' );
|
||||
|
||||
if ( ! current_user_can( 'view_site_health_checks' ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
$needs_creds = false;
|
||||
|
||||
if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
|
||||
if ( ! Health_Check::get_filesystem_credentials() ) {
|
||||
$needs_creds = true;
|
||||
} else {
|
||||
Health_Check_Troubleshoot::setup_must_use_plugin();
|
||||
}
|
||||
}
|
||||
|
||||
$result = ob_get_clean();
|
||||
|
||||
if ( $needs_creds ) {
|
||||
wp_send_json_error( $result );
|
||||
die();
|
||||
}
|
||||
|
||||
delete_option( 'health-check-disable-plugin-hash' );
|
||||
|
||||
$loopback_hash = md5( rand() );
|
||||
update_option( 'health-check-disable-plugin-hash', $loopback_hash );
|
||||
|
||||
$plugin_slug = explode( '/', $_POST['plugin'] );
|
||||
$plugin_slug = $plugin_slug[0];
|
||||
|
||||
$single_test = Health_Check_Loopback::can_perform_loopback( $loopback_hash, $plugin_slug );
|
||||
|
||||
$message = sprintf(
|
||||
'<span class="%s"></span> %s',
|
||||
esc_attr( $single_test->status ),
|
||||
$single_test->message
|
||||
);
|
||||
|
||||
$response = array(
|
||||
'message' => $message,
|
||||
);
|
||||
|
||||
wp_send_json_success( $response );
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
static function loopback_test_default_theme() {
|
||||
check_ajax_referer( 'health-check-loopback-default-theme' );
|
||||
|
||||
if ( ! current_user_can( 'view_site_health_checks' ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
$needs_creds = false;
|
||||
|
||||
if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
|
||||
if ( ! Health_Check::get_filesystem_credentials() ) {
|
||||
$needs_creds = true;
|
||||
} else {
|
||||
Health_Check_Troubleshoot::setup_must_use_plugin();
|
||||
}
|
||||
}
|
||||
|
||||
$result = ob_get_clean();
|
||||
|
||||
if ( $needs_creds ) {
|
||||
wp_send_json_error( $result );
|
||||
die();
|
||||
}
|
||||
|
||||
delete_option( 'health-check-disable-plugin-hash' );
|
||||
|
||||
$loopback_hash = md5( rand() );
|
||||
update_option( 'health-check-disable-plugin-hash', $loopback_hash );
|
||||
|
||||
$message = '';
|
||||
|
||||
// Test without a theme active.
|
||||
update_option( 'health-check-default-theme', 'yes' );
|
||||
|
||||
$theme_test = Health_Check_Loopback::can_perform_loopback( $loopback_hash, '' );
|
||||
|
||||
$message .= sprintf(
|
||||
'<span class="%s"></span> %s',
|
||||
esc_attr( $theme_test->status ),
|
||||
$theme_test->message
|
||||
);
|
||||
|
||||
delete_option( 'health-check-default-theme' );
|
||||
|
||||
$response = array(
|
||||
'message' => $message,
|
||||
);
|
||||
|
||||
wp_send_json_success( $response );
|
||||
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
<?php
|
||||
/**
|
||||
* Handle troubleshooting options.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Health_Check_Troubleshoot
|
||||
*/
|
||||
class Health_Check_Troubleshoot {
|
||||
|
||||
/**
|
||||
* Initiate the troubleshooting mode by setting meta data and cookies.
|
||||
*
|
||||
* @uses is_array()
|
||||
* @uses md5()
|
||||
* @uses rand()
|
||||
* @uses update_option()
|
||||
* @uses setcookie()
|
||||
*
|
||||
* @param array $allowed_plugins An array of plugins that may be active right away.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
static function initiate_troubleshooting_mode( $allowed_plugins = array() ) {
|
||||
if ( ! is_array( $allowed_plugins ) ) {
|
||||
$allowed_plugins = (array) $allowed_plugins;
|
||||
}
|
||||
|
||||
$loopback_hash = md5( rand() );
|
||||
|
||||
update_option( 'health-check-allowed-plugins', $allowed_plugins );
|
||||
|
||||
update_option( 'health-check-disable-plugin-hash', $loopback_hash . md5( $_SERVER['REMOTE_ADDR'] ) );
|
||||
|
||||
setcookie( 'wp-health-check-disable-plugins', $loopback_hash, 0, COOKIEPATH, COOKIE_DOMAIN );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if our Must-Use plugin exists.
|
||||
*
|
||||
* @uses file_exists()
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
static function mu_plugin_exists() {
|
||||
return file_exists( WPMU_PLUGIN_DIR . '/health-check-troubleshooting-mode.php' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the old Must-Use plugin exists.
|
||||
*
|
||||
* @uses file_exists()
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
static function old_mu_plugin_exists() {
|
||||
return file_exists( WPMU_PLUGIN_DIR . '/health-check-disable-plugins.php' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Introduce our Must-Use plugin.
|
||||
*
|
||||
* Move the Must-Use plugin out to the correct directory, and prompt for credentials if required.
|
||||
*
|
||||
* @global $wp_filesystem
|
||||
*
|
||||
* @uses is_dir()
|
||||
* @uses WP_Filesystem::mkdir()
|
||||
* @uses Health_Check::display_notice()
|
||||
* @uses esc_html__()
|
||||
* @uses WP_Filesystem::copy()
|
||||
* @uses trailingslashit()
|
||||
* @uses Health_Check_Troubleshoot::session_started()
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
static function setup_must_use_plugin( $redirect = true ) {
|
||||
global $wp_filesystem;
|
||||
|
||||
// Make sure the `mu-plugins` directory exists.
|
||||
if ( ! is_dir( WPMU_PLUGIN_DIR ) ) {
|
||||
if ( ! $wp_filesystem->mkdir( WPMU_PLUGIN_DIR ) ) {
|
||||
Health_Check::display_notice( esc_html__( 'We were unable to create the mu-plugins directory.', 'health-check' ), 'error' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove instances of the old plugin, to avoid collisions.
|
||||
if ( Health_Check_Troubleshoot::old_mu_plugin_exists() ) {
|
||||
if ( ! $wp_filesystem->delete( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' ) ) {
|
||||
Health_Check::display_notice( esc_html__( 'We could not remove the old must-use plugin.', 'health-check' ), 'error' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the must-use plugin to the local directory.
|
||||
if ( ! $wp_filesystem->copy( trailingslashit( HEALTH_CHECK_PLUGIN_DIRECTORY ) . 'assets/mu-plugin/health-check-troubleshooting-mode.php', trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php' ) ) {
|
||||
Health_Check::display_notice( esc_html__( 'We were unable to copy the plugin file required to enable the Troubleshooting Mode.', 'health-check' ), 'error' );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $redirect ) {
|
||||
Health_Check_Troubleshoot::session_started();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if our Must-Use plugin needs updating, and do so if necessary.
|
||||
*
|
||||
* @global $wp_filesystem
|
||||
*
|
||||
* @uses Health_Check_Troubleshoot::mu_plugin_exists()
|
||||
* @uses Health_Check::get_filesystem_credentials()
|
||||
* @uses get_plugin_data()
|
||||
* @uses trailingslashit()
|
||||
* @uses version_compare()
|
||||
* @uses WP_Filesystem::copy()
|
||||
* @uses esc_html__()
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
static function maybe_update_must_use_plugin() {
|
||||
if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! Health_Check::get_filesystem_credentials() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$current = get_plugin_data( trailingslashit( HEALTH_CHECK_PLUGIN_DIRECTORY ) . 'assets/mu-plugin/health-check-troubleshooting-mode.php' );
|
||||
$active = get_plugin_data( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php' );
|
||||
|
||||
$current_version = ( isset( $current['Version'] ) ? $current['Version'] : '0.0' );
|
||||
$active_version = ( isset( $active['Version'] ) ? $active['Version'] : '0.0' );
|
||||
|
||||
if ( version_compare( $current_version, $active_version, '>' ) ) {
|
||||
global $wp_filesystem;
|
||||
|
||||
if ( ! $wp_filesystem->copy( trailingslashit( HEALTH_CHECK_PLUGIN_DIRECTORY ) . 'assets/mu-plugin/health-check-troubleshooting-mode.php', trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php', true ) ) {
|
||||
Health_Check::display_notice( esc_html__( 'We were unable to replace the plugin file required to enable the Troubleshooting Mode.', 'health-check' ), 'error' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a notice if our Troubleshooting Mode has been initiated.
|
||||
*
|
||||
* @uses Health_Check::display_notice()
|
||||
* @uses sprintf()
|
||||
* @uses esc_html__()
|
||||
* @uses esc_url()
|
||||
* @uses admin_url()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
static function session_started() {
|
||||
Health_Check::display_notice(
|
||||
sprintf(
|
||||
'%s<br>%s',
|
||||
esc_html__( 'You have successfully enabled Troubleshooting Mode, all plugins will appear inactive until you disable Troubleshooting Mode, or log out and back in again.', 'health-check' ),
|
||||
sprintf(
|
||||
'<a href="%1$s">%2$s</a><script type="text/javascript">window.location = "%1$s";</script>',
|
||||
esc_url( admin_url( '/' ) ),
|
||||
esc_html__( 'Return to the Dashboard', 'health-check' )
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the form for enabling troubleshooting mode.
|
||||
*
|
||||
* @uses printf()
|
||||
* @uses esc_html__()
|
||||
* @uses Health_Check_Troubleshoot::mu_plugin_exists()
|
||||
* @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
|
||||
* @uses Health_Check_Troubleshoot::session_started()
|
||||
* @uses Health_Check::get_filesystem_credentials()
|
||||
* @uses Health_Check_Troubleshoot::setup_must_use_plugin()
|
||||
* @uses esc_html_e()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
/**
|
||||
* Display the form for enabling troubleshooting mode.
|
||||
*
|
||||
* @uses printf()
|
||||
* @uses esc_html__()
|
||||
* @uses Health_Check_Troubleshoot::mu_plugin_exists()
|
||||
* @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
|
||||
* @uses Health_Check_Troubleshoot::session_started()
|
||||
* @uses Health_Check::get_filesystem_credentials()
|
||||
* @uses Health_Check_Troubleshoot::setup_must_use_plugin()
|
||||
* @uses Health_Check_Troubleshooting_MU::is_troubleshooting()
|
||||
* @uses esc_url()
|
||||
* @uses add_query_arg()
|
||||
* @uses esc_html_e()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
static function show_enable_troubleshoot_form() {
|
||||
if ( isset( $_POST['health-check-troubleshoot-mode'] ) ) {
|
||||
if ( Health_Check_Troubleshoot::mu_plugin_exists() ) {
|
||||
if ( ! Health_Check_Troubleshoot::maybe_update_must_use_plugin() ) {
|
||||
return;
|
||||
}
|
||||
Health_Check_Troubleshoot::session_started();
|
||||
} else {
|
||||
if ( ! Health_Check::get_filesystem_credentials() ) {
|
||||
return;
|
||||
} else {
|
||||
Health_Check_Troubleshoot::setup_must_use_plugin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<div>
|
||||
|
||||
<?php
|
||||
$troubleshooting = null;
|
||||
|
||||
if ( class_exists( 'Health_Check_Troubleshooting_MU' ) ) {
|
||||
$troubleshooting = new Health_Check_Troubleshooting_MU();
|
||||
}
|
||||
|
||||
if ( null !== $troubleshooting && is_callable( array( $troubleshooting, 'is_troubleshooting' ) ) && $troubleshooting->is_troubleshooting() ) :
|
||||
?>
|
||||
<p style="text-align: center;">
|
||||
<a class="button button-primary" href="<?php echo esc_url( add_query_arg( array( 'health-check-disable-troubleshooting' => true ) ) ); ?>">
|
||||
<?php esc_html_e( 'Disable Troubleshooting Mode', 'health-check' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<?php else : ?>
|
||||
|
||||
<form action="" method="post" class="form" style="text-align: center;">
|
||||
<?php wp_nonce_field( 'health-check-enable-troubleshooting' ); ?>
|
||||
<input type="hidden" name="health-check-troubleshoot-mode" value="true">
|
||||
<p>
|
||||
<button type="submit" class="button button-primary">
|
||||
<?php esc_html_e( 'Enable Troubleshooting Mode', 'health-check' ); ?>
|
||||
</button>
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,592 @@
|
|||
<?php
|
||||
/**
|
||||
* Class for testing plugin/theme updates in the WordPress code.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Health_Check_Updates
|
||||
*/
|
||||
class Health_Check_Updates {
|
||||
private $plugins_before;
|
||||
private $plugins_after;
|
||||
private static $plugins_blocked;
|
||||
private $themes_before;
|
||||
private $themes_after;
|
||||
private static $themes_blocked;
|
||||
|
||||
/**
|
||||
* Health_Check_Updates constructor.
|
||||
*
|
||||
* @uses Health_Check_Updates::init()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate the plugin class.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init() {
|
||||
$this->plugins_before = (array) array();
|
||||
$this->plugins_after = (array) array();
|
||||
self::$plugins_blocked = (bool) false;
|
||||
|
||||
$this->themes_before = (array) array();
|
||||
$this->themes_after = (array) array();
|
||||
self::$themes_blocked = (bool) false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run tests to determine if auto-updates can run.
|
||||
*
|
||||
* @uses get_class_methods()
|
||||
* @uses substr()
|
||||
* @uses call_user_func()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function run_tests() {
|
||||
$tests = array();
|
||||
|
||||
foreach ( get_class_methods( $this ) as $method ) {
|
||||
if ( 'test_' !== substr( $method, 0, 5 ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = call_user_func( array( $this, $method ) );
|
||||
|
||||
if ( false === $result || null === $result ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = (object) $result;
|
||||
|
||||
if ( empty( $result->severity ) ) {
|
||||
$result->severity = 'warning';
|
||||
}
|
||||
|
||||
$tests[ $method ] = $result;
|
||||
}
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plugin updates have been tampered with.
|
||||
*
|
||||
* @uses Health_Check_Updates::check_plugin_update_hooks()
|
||||
* @uses esc_html__()
|
||||
* @uses Health_Check_Updates::check_plugin_update_pre_request()
|
||||
* @uses Health_Check_Updates::check_plugin_update_request_args()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function test_plugin_updates() {
|
||||
// Check if any update hooks have been removed.
|
||||
$hooks = $this->check_plugin_update_hooks();
|
||||
if ( ! $hooks ) {
|
||||
return array(
|
||||
'desc' => esc_html__( 'Plugin update hooks have been removed.', 'health-check' ),
|
||||
'severity' => 'fail',
|
||||
);
|
||||
}
|
||||
|
||||
// Check if update requests are being blocked.
|
||||
$blocked = $this->check_plugin_update_pre_request();
|
||||
if ( true === $blocked ) {
|
||||
return array(
|
||||
'desc' => esc_html__( 'Plugin update requests have been blocked.', 'health-check' ),
|
||||
'severity' => 'fail',
|
||||
);
|
||||
}
|
||||
|
||||
// Check if plugins have been removed from the update requests.
|
||||
$diff = (array) $this->check_plugin_update_request_args();
|
||||
if ( 0 !== count( $diff ) ) {
|
||||
return array(
|
||||
'desc' => sprintf(
|
||||
/* translators: %s: List of plugin names. */
|
||||
esc_html__( 'The following Plugins have been removed from update checks: %s.', 'health-check' ),
|
||||
implode( ',', $diff )
|
||||
),
|
||||
'severity' => 'warning',
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'desc' => esc_html__( 'Plugin updates should be working as expected.', 'health-check' ),
|
||||
'severity' => 'pass',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any plugin update hooks have been removed.
|
||||
*
|
||||
* @uses has_filter()
|
||||
* @uses wp_next_scheduled()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function check_plugin_update_hooks() {
|
||||
$test1 = has_filter( 'load-plugins.php', 'wp_update_plugins' );
|
||||
$test2 = has_filter( 'load-update.php', 'wp_update_plugins' );
|
||||
$test3 = has_filter( 'load-update-core.php', 'wp_update_plugins' );
|
||||
$test4 = has_filter( 'wp_update_plugins', 'wp_update_plugins' );
|
||||
$test5 = has_filter( 'admin_init', '_maybe_update_plugins' );
|
||||
$test6 = wp_next_scheduled( 'wp_update_plugins' );
|
||||
|
||||
return $test1 && $test2 && $test3 && $test4 && $test5 && $test6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plugin update request checks are being tampered with at the 'pre_http_request' filter.
|
||||
*
|
||||
* @uses add_action()
|
||||
* @uses Health_Check_Updates::wp_plugin_update_fake_request()
|
||||
* @uses esc_html__()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function check_plugin_update_pre_request() {
|
||||
add_action( 'pre_http_request', array( $this, 'plugin_pre_request_check' ), PHP_INT_MAX, 3 );
|
||||
add_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX, 3 );
|
||||
|
||||
$this->plugin_update_fake_request();
|
||||
|
||||
remove_action( 'pre_http_request', array( $this, 'plugin_pre_request_check' ), PHP_INT_MAX );
|
||||
remove_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX );
|
||||
|
||||
return self::$plugins_blocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check plugin update requests to see if they are being blocked.
|
||||
*
|
||||
* @param bool $pre If not false, request cancelled.
|
||||
* @param array $r Request parameters.
|
||||
* @param string $url Request URL.
|
||||
* @return bool
|
||||
*/
|
||||
function plugin_pre_request_check( $pre, $r, $url ) {
|
||||
$check_url = 'api.wordpress.org/plugins/update-check/1.1/';
|
||||
if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
|
||||
return $pre; // Not a plugin update request.
|
||||
}
|
||||
|
||||
// If not false something is blocking update checks
|
||||
if ( false !== $pre ) {
|
||||
self::$plugins_blocked = (bool) true;
|
||||
}
|
||||
|
||||
return $pre;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plugins are being removed at the 'http_request_args' filter.
|
||||
*
|
||||
* @uses add_action()
|
||||
* @uses Health_Check_Updates::wp_plugin_update_fake_request()
|
||||
* @uses remove_action()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function check_plugin_update_request_args() {
|
||||
add_action( 'http_request_args', array( $this, 'plugin_request_args_before' ), 1, 2 );
|
||||
add_action( 'http_request_args', array( $this, 'plugin_request_args_after' ), PHP_INT_MAX, 2 );
|
||||
add_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX, 3 );
|
||||
|
||||
$this->plugin_update_fake_request();
|
||||
|
||||
remove_action( 'http_request_args', array( $this, 'plugin_request_args_before' ), 1 );
|
||||
remove_action( 'http_request_args', array( $this, 'plugin_request_args_after' ), PHP_INT_MAX );
|
||||
remove_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX );
|
||||
|
||||
$diff = array_diff_key( $this->plugins_before['plugins'], $this->plugins_after['plugins'] );
|
||||
|
||||
$titles = array();
|
||||
foreach ( $diff as $item ) {
|
||||
$titles[] = $item['Title'];
|
||||
}
|
||||
|
||||
return $titles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the list of plugins from plugin update requests at the start of filtering.
|
||||
*
|
||||
* @param array $r Request parameters.
|
||||
* @param string $url Request URL.
|
||||
* @return array
|
||||
*/
|
||||
function plugin_request_args_before( $r, $url ) {
|
||||
$check_url = 'api.wordpress.org/plugins/update-check/1.1/';
|
||||
if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
|
||||
return $r; // Not a plugin update request.
|
||||
}
|
||||
|
||||
$this->plugins_before = (array) json_decode( $r['body']['plugins'], true );
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the list of plugins from plugin update requests at the end of filtering.
|
||||
*
|
||||
* @param array $r Request parameters.
|
||||
* @param string $url Request URL.
|
||||
* @return array
|
||||
*/
|
||||
function plugin_request_args_after( $r, $url ) {
|
||||
$check_url = 'api.wordpress.org/plugins/update-check/1.1/';
|
||||
if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
|
||||
return $r; // Not a plugin update request.
|
||||
}
|
||||
|
||||
$this->plugins_after = (array) json_decode( $r['body']['plugins'], true );
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and trigger a fake plugin update check request.
|
||||
*
|
||||
* @uses get_plugins()
|
||||
* @uses get_option()
|
||||
* @uses wp_get_installed_translations()
|
||||
* @uses apply_filters()
|
||||
* @uses wp_json_encode()
|
||||
* @uses get_bloginfo()
|
||||
* @uses home_url()
|
||||
* @uses wp_http_supports()
|
||||
* @uses set_url_scheme()
|
||||
* @uses wp_remote_post()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function plugin_update_fake_request() {
|
||||
if ( ! function_exists( 'get_plugins' ) ) {
|
||||
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
||||
}
|
||||
|
||||
// Prepare data for the request.
|
||||
$plugins = get_plugins();
|
||||
$active = get_option( 'active_plugins', array() );
|
||||
$to_send = compact( 'plugins', 'active' );
|
||||
$translations = wp_get_installed_translations( 'plugins' );
|
||||
$locales = array_values( get_available_languages() );
|
||||
$locales = (array) apply_filters( 'plugins_update_check_locales', $locales );
|
||||
$locales = array_unique( $locales );
|
||||
$timeout = 3 + (int) ( count( $plugins ) / 10 );
|
||||
|
||||
// Setup the request options.
|
||||
if ( function_exists( 'wp_json_encode' ) ) {
|
||||
$options = array(
|
||||
'timeout' => $timeout,
|
||||
'body' => array(
|
||||
'plugins' => wp_json_encode( $to_send ),
|
||||
'translations' => wp_json_encode( $translations ),
|
||||
'locale' => wp_json_encode( $locales ),
|
||||
'all' => wp_json_encode( true ),
|
||||
),
|
||||
'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
|
||||
);
|
||||
} else {
|
||||
$options = array(
|
||||
'timeout' => $timeout,
|
||||
'body' => array(
|
||||
'plugins' => json_encode( $to_send ),
|
||||
'translations' => json_encode( $translations ),
|
||||
'locale' => json_encode( $locales ),
|
||||
'all' => json_encode( true ),
|
||||
),
|
||||
'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
|
||||
);
|
||||
}
|
||||
|
||||
// Set the URL
|
||||
$http_url = 'http://api.wordpress.org/plugins/update-check/1.1/';
|
||||
$url = wp_http_supports( array( 'ssl' ) ) ? set_url_scheme( $http_url, 'https' ) : $http_url;
|
||||
|
||||
// Ignore the response. Just need the hooks to fire.
|
||||
wp_remote_post( $url, $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if theme updates have been tampered with.
|
||||
*
|
||||
* @uses Health_Check_Updates::check_theme_update_hooks()
|
||||
* @uses esc_html__()
|
||||
* @uses Health_Check_Updates::check_theme_update_pre_request()
|
||||
* @uses Health_Check_Updates::check_theme_update_request_args()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function test_constant_theme_updates() {
|
||||
// Check if any update hooks have been removed.
|
||||
$hooks = $this->check_theme_update_hooks();
|
||||
if ( ! $hooks ) {
|
||||
return array(
|
||||
'desc' => esc_html__( 'Theme update hooks have been removed.', 'health-check' ),
|
||||
'severity' => 'fail',
|
||||
);
|
||||
}
|
||||
|
||||
// Check if update requests are being blocked.
|
||||
$blocked = $this->check_theme_update_pre_request();
|
||||
if ( true === $blocked ) {
|
||||
return array(
|
||||
'desc' => esc_html__( 'Theme update requests have been blocked.', 'health-check' ),
|
||||
'severity' => 'fail',
|
||||
);
|
||||
}
|
||||
|
||||
// Check if themes have been removed from the update requests.
|
||||
$diff = (array) $this->check_theme_update_request_args();
|
||||
if ( 0 !== count( $diff ) ) {
|
||||
return array(
|
||||
'desc' => sprintf(
|
||||
/* translators: %s: List of theme names. */
|
||||
esc_html__( 'The following Themes have been removed from update checks: %s.', 'health-check' ),
|
||||
implode( ',', $diff )
|
||||
),
|
||||
'severity' => 'warning',
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'desc' => esc_html__( 'Theme updates should be working as expected.', 'health-check' ),
|
||||
'severity' => 'pass',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any theme update hooks have been removed.
|
||||
*
|
||||
* @uses has_filter()
|
||||
* @uses wp_next_scheduled()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function check_theme_update_hooks() {
|
||||
$test1 = has_filter( 'load-themes.php', 'wp_update_themes' );
|
||||
$test2 = has_filter( 'load-update.php', 'wp_update_themes' );
|
||||
$test3 = has_filter( 'load-update-core.php', 'wp_update_themes' );
|
||||
$test4 = has_filter( 'wp_update_themes', 'wp_update_themes' );
|
||||
$test5 = has_filter( 'admin_init', '_maybe_update_themes' );
|
||||
$test6 = wp_next_scheduled( 'wp_update_themes' );
|
||||
|
||||
return $test1 && $test2 && $test3 && $test4 && $test5 && $test6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if theme update request checks are being tampered with at the 'pre_http_request' filter.
|
||||
*
|
||||
* @uses add_action()
|
||||
* @uses Health_Check_Updates::wp_theme_update_fake_request()
|
||||
* @uses esc_html__()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function check_theme_update_pre_request() {
|
||||
add_action( 'pre_http_request', array( $this, 'theme_pre_request_check' ), PHP_INT_MAX, 3 );
|
||||
add_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX, 3 );
|
||||
|
||||
$this->theme_update_fake_request();
|
||||
|
||||
remove_action( 'pre_http_request', array( $this, 'theme_pre_request_check' ), PHP_INT_MAX );
|
||||
remove_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX );
|
||||
|
||||
return self::$themes_blocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check theme update requests to see if they are being blocked.
|
||||
*
|
||||
* @param bool $pre If not false, request cancelled.
|
||||
* @param array $r Request parameters.
|
||||
* @param string $url Request URL.
|
||||
* @return bool
|
||||
*/
|
||||
function theme_pre_request_check( $pre, $r, $url ) {
|
||||
$check_url = 'api.wordpress.org/themes/update-check/1.1/';
|
||||
if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
|
||||
return $pre; // Not a theme update request.
|
||||
}
|
||||
|
||||
// If not false something is blocking update checks
|
||||
if ( false !== $pre ) {
|
||||
self::$themes_blocked = (bool) true;
|
||||
}
|
||||
|
||||
return $pre;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if themes are being removed at the 'http_request_args' filter.
|
||||
*
|
||||
* @uses add_action()
|
||||
* @uses Health_Check_Updates::wp_theme_update_fake_request()
|
||||
* @uses remove_action()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function check_theme_update_request_args() {
|
||||
add_action( 'http_request_args', array( $this, 'theme_request_args_before' ), 1, 2 );
|
||||
add_action( 'http_request_args', array( $this, 'theme_request_args_after' ), PHP_INT_MAX, 2 );
|
||||
add_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX, 3 );
|
||||
|
||||
$this->theme_update_fake_request();
|
||||
|
||||
remove_action( 'http_request_args', array( $this, 'theme_request_args_before' ), 1 );
|
||||
remove_action( 'http_request_args', array( $this, 'theme_request_args_after' ), PHP_INT_MAX );
|
||||
remove_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX );
|
||||
|
||||
$diff = array_diff_key( $this->themes_before['themes'], $this->themes_after['themes'] );
|
||||
|
||||
$titles = array();
|
||||
foreach ( $diff as $item ) {
|
||||
$titles[] = $item['Title'];
|
||||
}
|
||||
|
||||
return $titles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the list of themes from theme update requests at the start of filtering.
|
||||
*
|
||||
* @param array $r Request parameters.
|
||||
* @param string $url Request URL.
|
||||
* @return array
|
||||
*/
|
||||
function theme_request_args_before( $r, $url ) {
|
||||
$check_url = 'api.wordpress.org/themes/update-check/1.1/';
|
||||
if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
|
||||
return $r; // Not a theme update request.
|
||||
}
|
||||
|
||||
$this->themes_before = (array) json_decode( $r['body']['themes'], true );
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the list of themes from theme update requests at the end of filtering.
|
||||
*
|
||||
* @param array $r Request parameters.
|
||||
* @param string $url Request URL.
|
||||
* @return array
|
||||
*/
|
||||
function theme_request_args_after( $r, $url ) {
|
||||
$check_url = 'api.wordpress.org/themes/update-check/1.1/';
|
||||
if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
|
||||
return $r; // Not a theme update request.
|
||||
}
|
||||
|
||||
$this->themes_after = (array) json_decode( $r['body']['themes'], true );
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and trigger a fake theme update check request.
|
||||
*
|
||||
* @uses wp_get_themes()
|
||||
* @uses wp_get_installed_translations()
|
||||
* @uses get_option()
|
||||
* @uses get_available_languages()
|
||||
* @uses wp_json_encode()
|
||||
* @uses get_bloginfo()
|
||||
* @uses home_url()
|
||||
* @uses wp_http_supports()
|
||||
* @uses set_url_scheme()
|
||||
* @uses wp_remote_post()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function theme_update_fake_request() {
|
||||
$themes = array();
|
||||
$checked = array();
|
||||
$request = array();
|
||||
$installed_themes = wp_get_themes();
|
||||
$translations = wp_get_installed_translations( 'themes' );
|
||||
$request['active'] = get_option( 'stylesheet' );
|
||||
|
||||
foreach ( $installed_themes as $theme ) {
|
||||
$checked[ $theme->get_stylesheet() ] = $theme->get( 'Version' );
|
||||
|
||||
$themes[ $theme->get_stylesheet() ] = array(
|
||||
'Name' => $theme->get( 'Name' ),
|
||||
'Title' => $theme->get( 'Name' ),
|
||||
'Version' => $theme->get( 'Version' ),
|
||||
'Author' => $theme->get( 'Author' ),
|
||||
'Author URI' => $theme->get( 'AuthorURI' ),
|
||||
'Template' => $theme->get_template(),
|
||||
'Stylesheet' => $theme->get_stylesheet(),
|
||||
);
|
||||
}
|
||||
|
||||
$request['themes'] = $themes;
|
||||
|
||||
$locales = array_values( get_available_languages() );
|
||||
$timeout = 3 + (int) ( count( $themes ) / 10 );
|
||||
|
||||
if ( function_exists( 'wp_json_encode' ) ) {
|
||||
$options = array(
|
||||
'timeout' => $timeout,
|
||||
'body' => array(
|
||||
'themes' => wp_json_encode( $request ),
|
||||
'translations' => wp_json_encode( $translations ),
|
||||
'locale' => wp_json_encode( $locales ),
|
||||
),
|
||||
'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
|
||||
);
|
||||
} else {
|
||||
$options = array(
|
||||
'timeout' => $timeout,
|
||||
'body' => array(
|
||||
'themes' => json_encode( $request ),
|
||||
'translations' => json_encode( $translations ),
|
||||
'locale' => json_encode( $locales ),
|
||||
),
|
||||
'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
|
||||
);
|
||||
}
|
||||
|
||||
// Set the URL
|
||||
$http_url = 'http://api.wordpress.org/themes/update-check/1.1/';
|
||||
$url = wp_http_supports( array( 'ssl' ) ) ? set_url_scheme( $http_url, 'https' ) : $http_url;
|
||||
|
||||
// Ignore the response. Just need the hooks to fire.
|
||||
wp_remote_post( $url, $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks the fake update requests, ensuring they do not slow down page loads.
|
||||
*
|
||||
* @param bool $pre If not false, request cancelled.
|
||||
* @param array $r Request parameters.
|
||||
* @param string $url Request URL.
|
||||
* @return bool
|
||||
*/
|
||||
function block_fake_request( $pre, $r, $url ) {
|
||||
switch ( $url ) {
|
||||
case 'https://api.wordpress.org/plugins/update-check/1.1/':
|
||||
return 'block_request';
|
||||
case 'https://api.wordpress.org/themes/update-check/1.1/':
|
||||
return 'block_request';
|
||||
default:
|
||||
return $pre;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
/**
|
||||
* WP-CLI Commands for the Health Check plugin
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
use WP_CLI\Utils;
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Health_Check_WP_CLI
|
||||
*/
|
||||
class Health_Check_WP_CLI {
|
||||
/**
|
||||
* See the sites status based on best practices and WordPress recommendations.
|
||||
*
|
||||
* ## EXAMPLES
|
||||
*
|
||||
* wp health-check status
|
||||
*
|
||||
* ## OPTIONS
|
||||
*
|
||||
* [--format=<format>]
|
||||
* : Render the output in a particular format.
|
||||
* ---
|
||||
* default: table
|
||||
* options:
|
||||
* - table
|
||||
* - csv
|
||||
* - json
|
||||
* - yaml
|
||||
* ---
|
||||
*/
|
||||
public function status( $args, $assoc_args ) {
|
||||
global $health_check_site_status;
|
||||
|
||||
$all_tests = $health_check_site_status::get_tests();
|
||||
|
||||
$test_result = array();
|
||||
|
||||
foreach ( $all_tests['direct'] as $test ) {
|
||||
$test_output = call_user_func( $test['test'] );
|
||||
|
||||
$test_result[] = array(
|
||||
'test' => $test['label'],
|
||||
'type' => wp_kses( $test_output['badge']['label'], array() ),
|
||||
'result' => wp_kses( $test_output['status'], array() ),
|
||||
);
|
||||
}
|
||||
foreach ( $all_tests['async'] as $test ) {
|
||||
$test_output = call_user_func( array( $health_check_site_status, 'get_test_' . $test['test'] ) );
|
||||
|
||||
$test_result[] = array(
|
||||
'test' => $test['label'],
|
||||
'type' => wp_kses( $test_output['badge']['label'], array() ),
|
||||
'result' => wp_kses( $test_output['status'], array() ),
|
||||
);
|
||||
}
|
||||
|
||||
if ( WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'json' ) {
|
||||
WP_CLI\Utils\format_items( 'json', $test_result, array( 'test', 'type', 'result' ) );
|
||||
} elseif ( WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'csv' ) {
|
||||
WP_CLI\Utils\format_items( 'csv', $test_result, array( 'test', 'type', 'result' ) );
|
||||
} elseif ( WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'yaml' ) {
|
||||
WP_CLI\Utils\format_items( 'yaml', $test_result, array( 'test', 'type', 'result' ) );
|
||||
} else {
|
||||
WP_CLI\Utils\format_items( 'table', $test_result, array( 'test', 'type', 'result' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WP_CLI::add_command( 'health-check', 'Health_Check_WP_CLI' );
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
/**
|
||||
* Perform tests to see if WP_Cron is operating as it should.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Health_Check_WP_Cron
|
||||
*/
|
||||
class Health_Check_WP_Cron {
|
||||
public $schedules;
|
||||
public $crons;
|
||||
public $last_missed_cron = null;
|
||||
public $last_late_cron = null;
|
||||
private $timeout_missed_cron = null;
|
||||
private $timeout_late_cron = null;
|
||||
|
||||
/**
|
||||
* Health_Check_WP_Cron constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->init();
|
||||
|
||||
$this->timeout_late_cron = 0;
|
||||
$this->timeout_missed_cron = - 5 * MINUTE_IN_SECONDS;
|
||||
|
||||
if ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) {
|
||||
$this->timeout_late_cron = - 15 * MINUTE_IN_SECONDS;
|
||||
$this->timeout_missed_cron = - 1 * HOUR_IN_SECONDS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate the class
|
||||
*
|
||||
* @uses wp_get_schedules()
|
||||
* @uses Health_Check_WP_Cron::get_cron_tasks()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init() {
|
||||
$this->schedules = wp_get_schedules();
|
||||
$this->get_cron_tasks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate our list of cron events and store them to a class-wide variable.
|
||||
*
|
||||
* Derived from `get_cron_events()` in WP Crontrol (https://plugins.svn.wordpress.org/wp-crontrol)
|
||||
* by John Blackburn.
|
||||
*
|
||||
* @uses _get_cron_array()
|
||||
* @uses WP_Error
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function get_cron_tasks() {
|
||||
$cron_tasks = _get_cron_array();
|
||||
|
||||
if ( empty( $cron_tasks ) ) {
|
||||
$this->crons = new WP_Error( 'no_tasks', __( 'No scheduled events exist on this site.', 'health-check' ) );
|
||||
return;
|
||||
}
|
||||
|
||||
$this->crons = array();
|
||||
|
||||
foreach ( $cron_tasks as $time => $cron ) {
|
||||
foreach ( $cron as $hook => $dings ) {
|
||||
foreach ( $dings as $sig => $data ) {
|
||||
|
||||
$this->crons[ "$hook-$sig-$time" ] = (object) array(
|
||||
'hook' => $hook,
|
||||
'time' => $time,
|
||||
'sig' => $sig,
|
||||
'args' => $data['args'],
|
||||
'schedule' => $data['schedule'],
|
||||
'interval' => isset( $data['interval'] ) ? $data['interval'] : null,
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any scheduled tasks have been missed.
|
||||
*
|
||||
* Returns a boolean value of `true` if a scheduled task has been missed and ends processing.
|
||||
* If the list of crons is an instance of WP_Error, return the instance instead of a boolean value.
|
||||
*
|
||||
* @uses is_wp_error()
|
||||
* @uses time()
|
||||
*
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function has_missed_cron() {
|
||||
if ( is_wp_error( $this->crons ) ) {
|
||||
return $this->crons;
|
||||
}
|
||||
|
||||
foreach ( $this->crons as $id => $cron ) {
|
||||
if ( ( $cron->time - time() ) < $this->timeout_missed_cron ) {
|
||||
$this->last_missed_cron = $cron->hook;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any scheduled tasks are late.
|
||||
*
|
||||
* Returns a boolean value of `true` if a scheduled task is late and ends processing. If the list of
|
||||
* crons is an instance of WP_Error, return the instance instead of a boolean value.
|
||||
*
|
||||
* @return bool|WP_Error true if a cron is late, false if it wasn't. WP_Error if the cron is set to that.
|
||||
*/
|
||||
public function has_late_cron() {
|
||||
if ( is_wp_error( $this->crons ) ) {
|
||||
return $this->crons;
|
||||
}
|
||||
|
||||
foreach ( $this->crons as $id => $cron ) {
|
||||
$cron_offset = $cron->time - time();
|
||||
if (
|
||||
$cron_offset >= $this->timeout_missed_cron &&
|
||||
$cron_offset < $this->timeout_late_cron
|
||||
) {
|
||||
$this->last_late_cron = $cron->hook;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,597 @@
|
|||
<?php
|
||||
/**
|
||||
* Primary class file for the Health Check plugin.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class HealthCheck
|
||||
*/
|
||||
class Health_Check {
|
||||
|
||||
/**
|
||||
* Notices to show at the head of the admin screen.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $admin_notices = array();
|
||||
|
||||
/**
|
||||
* HealthCheck constructor.
|
||||
*
|
||||
* @uses Health_Check::init()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin initiation.
|
||||
*
|
||||
* A helper function, called by `HealthCheck::__construct()` to initiate actions, hooks and other features needed.
|
||||
*
|
||||
* @uses add_action()
|
||||
* @uses add_filter()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init() {
|
||||
add_action( 'plugins_loaded', array( $this, 'load_i18n' ) );
|
||||
|
||||
add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );
|
||||
|
||||
add_filter( 'plugin_action_links', array( $this, 'troubleshoot_plugin_action' ), 20, 4 );
|
||||
add_filter( 'plugin_action_links_' . plugin_basename( HEALTH_CHECK_PLUGIN_FILE ), array( $this, 'page_plugin_action' ) );
|
||||
|
||||
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
|
||||
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'enqueues' ) );
|
||||
|
||||
add_action( 'init', array( $this, 'start_troubleshoot_mode' ) );
|
||||
add_action( 'load-plugins.php', array( $this, 'start_troubleshoot_single_plugin_mode' ) );
|
||||
|
||||
add_action( 'wp_ajax_health-check-loopback-no-plugins', array( 'Health_Check_Loopback', 'loopback_no_plugins' ) );
|
||||
add_action( 'wp_ajax_health-check-loopback-individual-plugins', array( 'Health_Check_Loopback', 'loopback_test_individual_plugins' ) );
|
||||
add_action( 'wp_ajax_health-check-loopback-default-theme', array( 'Health_Check_Loopback', 'loopback_test_default_theme' ) );
|
||||
add_action( 'wp_ajax_health-check-get-sizes', array( 'Health_Check_Debug_Data', 'ajax_get_sizes' ) );
|
||||
|
||||
add_filter( 'cron_schedules', array( $this, 'cron_schedules' ) );
|
||||
|
||||
add_filter( 'user_has_cap', array( $this, 'maybe_grant_site_health_caps' ), 1, 4 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the user capabilities to grant the 'view_site_health_checks' capabilities as necessary.
|
||||
*
|
||||
* @since 5.2.2
|
||||
*
|
||||
* @param bool[] $allcaps An array of all the user's capabilities.
|
||||
* @param string[] $caps Required primitive capabilities for the requested capability.
|
||||
* @param array $args {
|
||||
* Arguments that accompany the requested capability check.
|
||||
*
|
||||
* @type string $0 Requested capability.
|
||||
* @type int $1 Concerned user ID.
|
||||
* @type mixed ...$2 Optional second and further parameters, typically object ID.
|
||||
* }
|
||||
* @param WP_User $user The user object.
|
||||
* @return bool[] Filtered array of the user's capabilities.
|
||||
*/
|
||||
function maybe_grant_site_health_caps( $allcaps, $caps, $args, $user ) {
|
||||
if ( ! empty( $allcaps['install_plugins'] ) && ( ! is_multisite() || is_super_admin( $user->ID ) ) ) {
|
||||
$allcaps['view_site_health_checks'] = true;
|
||||
}
|
||||
|
||||
return $allcaps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate troubleshooting mode.
|
||||
*
|
||||
* Catch when the troubleshooting form has been submitted, and appropriately set required options and cookies.
|
||||
*
|
||||
* @uses current_user_can()
|
||||
* @uses Health_Check_Troubleshoot::initiate_troubleshooting_mode()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function start_troubleshoot_mode() {
|
||||
if ( ! isset( $_POST['health-check-troubleshoot-mode'] ) || ! current_user_can( 'view_site_health_checks' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't enable troubleshooting if nonces are missing or do not match.
|
||||
if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'health-check-enable-troubleshooting' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Health_Check_Troubleshoot::initiate_troubleshooting_mode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate troubleshooting mode for a specific plugin.
|
||||
*
|
||||
* Catch when the troubleshooting link on an individual plugin has been clicked, and appropriately sets the
|
||||
* required options and cookies.
|
||||
*
|
||||
* @uses current_user_can()
|
||||
* @uses ob_start()
|
||||
* @uses Health_Check_Troubleshoot::mu_plugin_exists()
|
||||
* @uses Health_Check::get_filesystem_credentials()
|
||||
* @uses Health_Check_Troubleshoot::setup_must_use_plugin()
|
||||
* @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
|
||||
* @uses ob_get_clean()
|
||||
* @uses Health_Check_Troubleshoot::initiate_troubleshooting_mode()
|
||||
* @uses wp_redirect()
|
||||
* @uses admin_url()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function start_troubleshoot_single_plugin_mode() {
|
||||
if ( ! isset( $_GET['health-check-troubleshoot-plugin'] ) || ! current_user_can( 'view_site_health_checks' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't enable troubleshooting for an individual plugin if the nonce is missing or invalid.
|
||||
if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'health-check-troubleshoot-plugin-' . $_GET['health-check-troubleshoot-plugin'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
$needs_credentials = false;
|
||||
|
||||
if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
|
||||
if ( ! Health_Check::get_filesystem_credentials() ) {
|
||||
$needs_credentials = true;
|
||||
} else {
|
||||
$check_output = Health_Check_Troubleshoot::setup_must_use_plugin( false );
|
||||
if ( false === $check_output ) {
|
||||
$needs_credentials = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( ! Health_Check_Troubleshoot::maybe_update_must_use_plugin() ) {
|
||||
$needs_credentials = true;
|
||||
}
|
||||
}
|
||||
|
||||
$result = ob_get_clean();
|
||||
|
||||
if ( $needs_credentials ) {
|
||||
$this->admin_notices[] = (object) array(
|
||||
'message' => $result,
|
||||
'type' => 'warning',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Health_Check_Troubleshoot::initiate_troubleshooting_mode(
|
||||
array(
|
||||
$_GET['health-check-troubleshoot-plugin'] => $_GET['health-check-troubleshoot-plugin'],
|
||||
)
|
||||
);
|
||||
|
||||
wp_redirect( admin_url( 'plugins.php' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Load translations.
|
||||
*
|
||||
* Loads the textdomain needed to get translations for our plugin.
|
||||
*
|
||||
* @uses load_plugin_textdomain()
|
||||
* @uses basename()
|
||||
* @uses dirname()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load_i18n() {
|
||||
load_plugin_textdomain( 'health-check', false, basename( dirname( __FILE__ ) ) . '/languages/' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue assets.
|
||||
*
|
||||
* Conditionally enqueue our CSS and JavaScript when viewing plugin related pages in wp-admin.
|
||||
*
|
||||
* @uses wp_enqueue_style()
|
||||
* @uses plugins_url()
|
||||
* @uses wp_enqueue_script()
|
||||
* @uses wp_localize_script()
|
||||
* @uses esc_html__()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueues() {
|
||||
$screen = get_current_screen();
|
||||
|
||||
// Don't enqueue anything unless we're on the health check page.
|
||||
if ( ( ! isset( $_GET['page'] ) || 'health-check' !== $_GET['page'] ) && 'dashboard' !== $screen->base ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$health_check_js_variables = array(
|
||||
'string' => array(
|
||||
'please_wait' => esc_html__( 'Please wait...', 'health-check' ),
|
||||
'copied' => esc_html__( 'Copied', 'health-check' ),
|
||||
'running_tests' => esc_html__( 'Currently being tested...', 'health-check' ),
|
||||
'site_health_complete' => esc_html__( 'All site health tests have finished running.', 'health-check' ),
|
||||
'site_health_complete_pass_sr' => esc_html__( 'All site health tests have finished running. Your site is looking good, and the results are now available on the page.', 'health-check' ),
|
||||
'site_health_complete_fail_sr' => esc_html__( 'All site health tests have finished running. There are items that should be addressed, and the results are now available on the page.', 'health-check' ),
|
||||
'site_health_complete_pass' => esc_html__( 'Good', 'health-check' ),
|
||||
'site_health_complete_fail' => esc_html__( 'Should be improved', 'health-check' ),
|
||||
'site_info_copied' => esc_html__( 'Site information has been added to your clipboard.', 'health-check' ),
|
||||
// translators: %s: Amount of critical issues.
|
||||
'site_info_heading_critical_single' => esc_html__( '%s Critical issue', 'health-check' ),
|
||||
// translators: %s: Amount of critical issues.
|
||||
'site_info_heading_critical_plural' => esc_html__( '%s Critical issues', 'health-check' ),
|
||||
// translators: %s: Amount of recommended issues.
|
||||
'site_info_heading_recommended_single' => esc_html__( '%s Recommended improvement', 'health-check' ),
|
||||
// translators: %s: Amount of recommended issues.
|
||||
'site_info_heading_recommended_plural' => esc_html__( '%s Recommended improvements', 'health-check' ),
|
||||
// translators: %s: Amount of passed tests.
|
||||
'site_info_heading_good_single' => esc_html__( '%s Item with no issues detected', 'health-check' ),
|
||||
// translators: %s: Amount of passed tests.
|
||||
'site_info_heading_good_plural' => esc_html__( '%s Items with no issues detected', 'health-check' ),
|
||||
),
|
||||
'nonce' => array(
|
||||
'loopback_no_plugins' => wp_create_nonce( 'health-check-loopback-no-plugins' ),
|
||||
'loopback_individual_plugins' => wp_create_nonce( 'health-check-loopback-individual-plugins' ),
|
||||
'loopback_default_theme' => wp_create_nonce( 'health-check-loopback-default-theme' ),
|
||||
'files_integrity_check' => wp_create_nonce( 'health-check-files-integrity-check' ),
|
||||
'view_file_diff' => wp_create_nonce( 'health-check-view-file-diff' ),
|
||||
'mail_check' => wp_create_nonce( 'health-check-mail-check' ),
|
||||
'site_status' => wp_create_nonce( 'health-check-site-status' ),
|
||||
'site_status_result' => wp_create_nonce( 'health-check-site-status-result' ),
|
||||
'tools_plugin_compat' => wp_create_nonce( 'health-check-tools-plugin-compat' ),
|
||||
),
|
||||
'site_status' => array(
|
||||
'direct' => array(),
|
||||
'async' => array(),
|
||||
'issues' => array(
|
||||
'good' => 0,
|
||||
'recommended' => 0,
|
||||
'critical' => 0,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$issue_counts = get_transient( 'health-check-site-status-result' );
|
||||
|
||||
if ( false !== $issue_counts ) {
|
||||
$issue_counts = json_decode( $issue_counts );
|
||||
|
||||
$health_check_js_variables['site_status']['issues'] = $issue_counts;
|
||||
}
|
||||
|
||||
if ( 'dashboard' !== $screen->base && ( ! isset( $_GET['tab'] ) || ( isset( $_GET['tab'] ) && 'site-status' === $_GET['tab'] ) ) ) {
|
||||
$tests = Health_Check_Site_Status::get_tests();
|
||||
|
||||
// Don't run https test on localhost
|
||||
if ( 'localhost' === preg_replace( '|https?://|', '', get_site_url() ) ) {
|
||||
unset( $tests['direct']['https_status'] );
|
||||
}
|
||||
|
||||
foreach ( $tests['direct'] as $test ) {
|
||||
if ( is_string( $test['test'] ) ) {
|
||||
$test_function = sprintf(
|
||||
'get_test_%s',
|
||||
$test['test']
|
||||
);
|
||||
|
||||
if ( method_exists( $this, $test_function ) && is_callable( array( $this, $test_function ) ) ) {
|
||||
/**
|
||||
* Filter the output of a finished Site Health test.
|
||||
*
|
||||
* @since 5.3.0
|
||||
*
|
||||
* @param array $test_result {
|
||||
* An associated array of test result data.
|
||||
*
|
||||
* @param string $label A label describing the test, and is used as a header in the output.
|
||||
* @param string $status The status of the test, which can be a value of `good`, `recommended` or `critical`.
|
||||
* @param array $badge {
|
||||
* Tests are put into categories which have an associated badge shown, these can be modified and assigned here.
|
||||
*
|
||||
* @param string $label The test label, for example `Performance`.
|
||||
* @param string $color Default `blue`. A string representing a color to use for the label.
|
||||
* }
|
||||
* @param string $description A more descriptive explanation of what the test looks for, and why it is important for the end user.
|
||||
* @param string $actions An action to direct the user to where they can resolve the issue, if one exists.
|
||||
* @param string $test The name of the test being ran, used as a reference point.
|
||||
* }
|
||||
*/
|
||||
$health_check_js_variables['site_status']['direct'][] = apply_filters( 'site_status_test_result', call_user_func( array( $this, $test_function ) ) );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_callable( $test['test'] ) ) {
|
||||
$health_check_js_variables['site_status']['direct'][] = apply_filters( 'site_status_test_result', call_user_func( $test['test'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $tests['async'] as $test ) {
|
||||
if ( is_string( $test['test'] ) ) {
|
||||
$health_check_js_variables['site_status']['async'][] = array(
|
||||
'test' => $test['test'],
|
||||
'completed' => false,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! wp_script_is( 'clipboard', 'registered' ) ) {
|
||||
wp_register_script( 'clipboard', trailingslashit( HEALTH_CHECK_PLUGIN_URL ) . 'assets/javascript/clipboard.min.js', array(), '2.0.4' );
|
||||
}
|
||||
|
||||
wp_enqueue_style( 'health-check', trailingslashit( HEALTH_CHECK_PLUGIN_URL ) . 'assets/css/health-check.css', array(), HEALTH_CHECK_PLUGIN_VERSION );
|
||||
|
||||
wp_enqueue_script( 'health-check', trailingslashit( HEALTH_CHECK_PLUGIN_URL ) . 'assets/javascript/health-check.js', array( 'jquery', 'wp-a11y', 'clipboard', 'wp-util' ), HEALTH_CHECK_PLUGIN_VERSION, true );
|
||||
|
||||
wp_localize_script( 'health-check', 'SiteHealth', $health_check_js_variables );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add item to the admin menu.
|
||||
*
|
||||
* @uses add_dashboard_page()
|
||||
* @uses __()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function action_admin_menu() {
|
||||
$critical_issues = 0;
|
||||
$issue_counts = get_transient( 'health-check-site-status-result' );
|
||||
|
||||
if ( false !== $issue_counts ) {
|
||||
$issue_counts = json_decode( $issue_counts );
|
||||
|
||||
$critical_issues = absint( $issue_counts->critical );
|
||||
}
|
||||
|
||||
$critical_count = sprintf(
|
||||
'<span class="update-plugins count-%d"><span class="update-count">%s</span></span>',
|
||||
esc_attr( $critical_issues ),
|
||||
sprintf(
|
||||
'%d<span class="screen-reader-text"> %s</span>',
|
||||
esc_html( $critical_issues ),
|
||||
esc_html_x( 'Critical issues', 'Issue counter label for the admin menu', 'health-check' )
|
||||
)
|
||||
);
|
||||
|
||||
$menu_title =
|
||||
sprintf(
|
||||
// translators: %s: Critical issue counter, if any.
|
||||
_x( 'Site Health %s', 'Menu Title', 'health-check' ),
|
||||
( ! $issue_counts || $critical_issues < 1 ? '' : $critical_count )
|
||||
);
|
||||
|
||||
remove_submenu_page( 'tools.php', 'site-health.php' );
|
||||
|
||||
add_submenu_page(
|
||||
'tools.php',
|
||||
_x( 'Site Health', 'Page Title', 'health-check' ),
|
||||
$menu_title,
|
||||
'view_site_health_checks',
|
||||
'health-check',
|
||||
array( $this, 'dashboard_page' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a troubleshooting action link to plugins.
|
||||
*
|
||||
* @param $actions
|
||||
* @param $plugin_file
|
||||
* @param $plugin_data
|
||||
* @param $context
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function troubleshoot_plugin_action( $actions, $plugin_file, $plugin_data, $context ) {
|
||||
// Don't add anything if this is a Must-Use plugin, we can't touch those.
|
||||
if ( 'mustuse' === $context ) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
// Only add troubleshooting actions to active plugins.
|
||||
if ( ! is_plugin_active( $plugin_file ) ) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
// Set a slug if the plugin lives in the plugins directory root.
|
||||
if ( ! stristr( $plugin_file, '/' ) ) {
|
||||
$plugin_slug = $plugin_file;
|
||||
} else { // Set the slug for plugin inside a folder.
|
||||
$plugin_slug = explode( '/', $plugin_file );
|
||||
$plugin_slug = $plugin_slug[0];
|
||||
}
|
||||
|
||||
$actions['troubleshoot'] = sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
esc_url(
|
||||
add_query_arg(
|
||||
array(
|
||||
'health-check-troubleshoot-plugin' => $plugin_slug,
|
||||
'_wpnonce' => wp_create_nonce( 'health-check-troubleshoot-plugin-' . $plugin_slug ),
|
||||
),
|
||||
admin_url( 'plugins.php' )
|
||||
)
|
||||
),
|
||||
esc_html__( 'Troubleshoot', 'health-check' )
|
||||
);
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a quick-access action link to the Heath Check page.
|
||||
*
|
||||
* @param $actions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function page_plugin_action( $actions ) {
|
||||
|
||||
$page_link = sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
menu_page_url( 'health-check', false ),
|
||||
_x( 'Health Check', 'Menu, Section and Page Title', 'health-check' )
|
||||
);
|
||||
array_unshift( $actions, $page_link );
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render our admin page.
|
||||
*
|
||||
* @uses _e()
|
||||
* @uses esc_html__()
|
||||
* @uses printf()
|
||||
* @uses sprintf()
|
||||
* @uses menu_page_url()
|
||||
* @uses dirname()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dashboard_page() {
|
||||
include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/site-health-header.php' );
|
||||
|
||||
switch ( Health_Check::current_tab() ) {
|
||||
case 'debug':
|
||||
include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/debug-data.php' );
|
||||
break;
|
||||
case 'phpinfo':
|
||||
include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/phpinfo.php' );
|
||||
break;
|
||||
case 'troubleshoot':
|
||||
include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/troubleshoot.php' );
|
||||
break;
|
||||
case 'tools':
|
||||
include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/tools.php' );
|
||||
break;
|
||||
case 'site-status':
|
||||
default:
|
||||
include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/site-status.php' );
|
||||
}
|
||||
|
||||
// Close out the div tag opened as a wrapper in the header.
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
static function tabs() {
|
||||
return array(
|
||||
'site-status' => esc_html__( 'Status', 'health-check' ),
|
||||
'debug' => esc_html__( 'Info', 'health-check' ),
|
||||
'troubleshoot' => esc_html__( 'Troubleshooting', 'health-check' ),
|
||||
'tools' => esc_html__( 'Tools', 'health-check' ),
|
||||
);
|
||||
}
|
||||
|
||||
static function current_tab() {
|
||||
return ( isset( $_GET['tab'] ) ? $_GET['tab'] : 'site-status' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display styled admin notices.
|
||||
*
|
||||
* @uses printf()
|
||||
*
|
||||
* @param string $message A sanitized string containing our notice message.
|
||||
* @param string $status A string representing the status type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
static function display_notice( $message, $status = 'success' ) {
|
||||
printf(
|
||||
'<div class="notice notice-%s inline"><p>%s</p></div>',
|
||||
esc_attr( $status ),
|
||||
$message
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display admin notices if we have any queued.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_notices() {
|
||||
foreach ( $this->admin_notices as $admin_notice ) {
|
||||
printf(
|
||||
'<div class="notice notice-%s"><p>%s</p></div>',
|
||||
esc_attr( $admin_notice->type ),
|
||||
$admin_notice->message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function cron_schedules( $schedules ) {
|
||||
if ( ! isset( $schedules['weekly'] ) ) {
|
||||
$schedules['weekly'] = array(
|
||||
'interval' => 7 * DAY_IN_SECONDS,
|
||||
'display' => __( 'Once weekly', 'health-check' ),
|
||||
);
|
||||
}
|
||||
|
||||
return $schedules;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Conditionally show a form for providing filesystem credentials when introducing our troubleshooting mode plugin.
|
||||
*
|
||||
* @uses wp_nonce_url()
|
||||
* @uses add_query_arg()
|
||||
* @uses admin_url()
|
||||
* @uses request_filesystem_credentials()
|
||||
* @uses WP_Filesystem
|
||||
*
|
||||
* @param array $args Any WP_Filesystem arguments you wish to pass.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
static function get_filesystem_credentials( $args = array() ) {
|
||||
$args = array_merge(
|
||||
array(
|
||||
'page' => 'health-check',
|
||||
'tab' => 'troubleshoot',
|
||||
),
|
||||
$args
|
||||
);
|
||||
|
||||
$url = wp_nonce_url( add_query_arg( $args, admin_url() ) );
|
||||
$creds = request_filesystem_credentials( $url, '', false, WP_CONTENT_DIR, array( 'health-check-troubleshoot-mode', 'action', '_wpnonce' ) );
|
||||
if ( false === $creds ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! WP_Filesystem( $creds ) ) {
|
||||
request_filesystem_credentials( $url, '', true, WPMU_PLUGIN_DIR, array( 'health-check-troubleshoot-mode', 'action', '_wpnonce' ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function plugin_activation() {
|
||||
if ( ! wp_next_scheduled( 'health-check-scheduled-site-status-check' ) ) {
|
||||
wp_schedule_event( time(), 'weekly', 'health-check-scheduled-site-status-check' );
|
||||
}
|
||||
}
|
||||
|
||||
public static function plugin_deactivation() {
|
||||
wp_clear_scheduled_hook( 'health-check-scheduled-site-status-check' );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
<?php
|
||||
|
||||
// Manually include the versions file as we can't always rely on `get_bloginfo()` to fetch versions.
|
||||
include ABSPATH . WPINC . '/version.php';
|
||||
|
||||
if ( ! function_exists( 'wp_check_php_version' ) && version_compare( '5.1', $wp_version, '>' ) ) {
|
||||
/**
|
||||
* Fallback function replicating core behavior from WordPress 5.1.0 to check PHP versions.
|
||||
*
|
||||
* @return array|bool|mixed|object|WP_Error
|
||||
*/
|
||||
function wp_check_php_version() {
|
||||
$version = phpversion();
|
||||
$key = md5( $version );
|
||||
|
||||
$response = get_site_transient( 'php_check_' . $key );
|
||||
if ( false === $response ) {
|
||||
$url = 'http://api.wordpress.org/core/serve-happy/1.0/';
|
||||
if ( wp_http_supports( array( 'ssl' ) ) ) {
|
||||
$url = set_url_scheme( $url, 'https' );
|
||||
}
|
||||
|
||||
$url = add_query_arg( 'php_version', $version, $url );
|
||||
|
||||
$response = wp_remote_get( $url );
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Response should be an array with:
|
||||
* 'recommended_version' - string - The PHP version recommended by WordPress.
|
||||
* 'is_supported' - boolean - Whether the PHP version is actively supported.
|
||||
* 'is_secure' - boolean - Whether the PHP version receives security updates.
|
||||
* 'is_acceptable' - boolean - Whether the PHP version is still acceptable for WordPress.
|
||||
*/
|
||||
$response = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
|
||||
if ( ! is_array( $response ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
set_site_transient( 'php_check_' . $key, $response, WEEK_IN_SECONDS );
|
||||
}
|
||||
|
||||
if ( isset( $response['is_acceptable'] ) && $response['is_acceptable'] ) {
|
||||
/**
|
||||
* Filters whether the active PHP version is considered acceptable by WordPress.
|
||||
*
|
||||
* Returning false will trigger a PHP version warning to show up in the admin dashboard to administrators.
|
||||
*
|
||||
* This filter is only run if the wordpress.org Serve Happy API considers the PHP version acceptable, ensuring
|
||||
* that this filter can only make this check stricter, but not loosen it.
|
||||
*
|
||||
* @since 5.1.1
|
||||
*
|
||||
* @param bool $is_acceptable Whether the PHP version is considered acceptable. Default true.
|
||||
* @param string $version PHP version checked.
|
||||
*/
|
||||
$response['is_acceptable'] = (bool) apply_filters( 'wp_is_php_version_acceptable', true, $version );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'wp_get_update_php_url' ) && version_compare( '5.1', $wp_version, '>' ) ) {
|
||||
/**
|
||||
* Fallback function replicating core behavior from WordPress 5.1.0 to check PHP versions.
|
||||
*
|
||||
* @return string URL to learn more about updating PHP.
|
||||
*/
|
||||
function wp_get_update_php_url() {
|
||||
$default_url = _x( 'https://wordpress.org/support/update-php/', 'localized PHP upgrade information page', 'health-check' );
|
||||
|
||||
$update_url = $default_url;
|
||||
if ( false !== getenv( 'WP_UPDATE_PHP_URL' ) ) {
|
||||
$update_url = getenv( 'WP_UPDATE_PHP_URL' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the URL to learn more about updating the PHP version the site is running on.
|
||||
*
|
||||
* Providing an empty string is not allowed and will result in the default URL being used. Furthermore
|
||||
* the page the URL links to should preferably be localized in the site language.
|
||||
*
|
||||
* @since 5.1.0
|
||||
*
|
||||
* @param string $update_url URL to learn more about updating PHP.
|
||||
*/
|
||||
$update_url = apply_filters( 'wp_update_php_url', $update_url );
|
||||
|
||||
if ( empty( $update_url ) ) {
|
||||
$update_url = $default_url;
|
||||
}
|
||||
|
||||
return $update_url;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'is_countable' ) && version_compare( '4.9.6', $wp_version, '>' ) ) {
|
||||
/**
|
||||
* Fallback function replicating core behavior from WordPress 4.9.6 to check PHP versions.
|
||||
*
|
||||
* Polyfill for is_countable() function added in PHP 7.3.
|
||||
*
|
||||
* Verify that the content of a variable is an array or an object
|
||||
* implementing the Countable interface.
|
||||
*
|
||||
* @param mixed $var The value to check.
|
||||
*
|
||||
* @return bool True if `$var` is countable, false otherwise.
|
||||
*/
|
||||
function is_countable( $var ) {
|
||||
return ( is_array( $var )
|
||||
|| $var instanceof Countable
|
||||
|| $var instanceof SimpleXMLElement
|
||||
|| $var instanceof ResourceBundle
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'get_user_count' ) && version_compare( '4.8', $wp_version, '>' ) ) {
|
||||
/**
|
||||
* Fallback function replicating core behavior from WordPress 4.8.0 to check PHP versions.
|
||||
*
|
||||
* @return int Number of active users on the network.
|
||||
*/
|
||||
function get_user_count( $network_id = null ) {
|
||||
return get_network_option( $network_id, 'user_count' );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'get_user_locale' ) && version_compare( '4.7', $wp_version, '>' ) ) {
|
||||
/**
|
||||
* Fallback function replicating core behavior from WordPress 4.7.0 to check PHP versions.
|
||||
*
|
||||
* @return string The locale of the user.
|
||||
*/
|
||||
function get_user_locale( $user_id = 0 ) {
|
||||
$user = false;
|
||||
if ( 0 === $user_id && function_exists( 'wp_get_current_user' ) ) {
|
||||
$user = wp_get_current_user();
|
||||
} elseif ( $user_id instanceof WP_User ) {
|
||||
$user = $user_id;
|
||||
} elseif ( $user_id && is_numeric( $user_id ) ) {
|
||||
$user = get_user_by( 'id', $user_id );
|
||||
}
|
||||
|
||||
if ( ! $user ) {
|
||||
return get_locale();
|
||||
}
|
||||
|
||||
$locale = $user->locale;
|
||||
return $locale ? $locale : get_locale();
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'wp_get_upload_dir' ) && version_compare( '4.5', $wp_version, '>' ) ) {
|
||||
/**
|
||||
* Fallback function replicating core behavior from WordPress 4.5.0 to check PHP versions.
|
||||
*
|
||||
* @return array See `wp_upload_dir()` for description.
|
||||
*/
|
||||
function wp_get_upload_dir() {
|
||||
return wp_upload_dir( null, false );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Check all core files against the checksums provided by WordPress API.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Files_Integrity
|
||||
*/
|
||||
class Health_Check_Files_Integrity extends Health_Check_Tool {
|
||||
|
||||
public function __construct() {
|
||||
$this->label = __( 'File integrity', 'health-check' );
|
||||
$this->description = __( 'The File Integrity checks all the core files with the <code>checksums</code> provided by the WordPress API to see if they are intact. If there are changes you will be able to make a Diff between the files hosted on WordPress.org and your installation to see what has been changed.', 'health-check' );
|
||||
|
||||
add_action( 'wp_ajax_health-check-files-integrity-check', array( $this, 'run_files_integrity_check' ) );
|
||||
add_action( 'wp_ajax_health-check-view-file-diff', array( $this, 'view_file_diff' ) );
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers checksums from WordPress API and cross checks the core files in the current installation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function run_files_integrity_check() {
|
||||
check_ajax_referer( 'health-check-files-integrity-check' );
|
||||
|
||||
$checksums = $this->call_checksum_api();
|
||||
|
||||
$files = $this->parse_checksum_results( $checksums );
|
||||
|
||||
$this->create_the_response( $files );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the WordPress API on the checksums endpoint
|
||||
*
|
||||
* @uses get_bloginfo()
|
||||
* @uses get_locale()
|
||||
* @uses ABSPATH
|
||||
* @uses wp_remote_get()
|
||||
* @uses get_bloginfo()
|
||||
* @uses strpos()
|
||||
* @uses unset()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function call_checksum_api() {
|
||||
// Setup variables.
|
||||
$wpversion = get_bloginfo( 'version' );
|
||||
$wplocale = get_locale();
|
||||
|
||||
// Setup API Call.
|
||||
$checksums = get_core_checksums( $wpversion, $wplocale );
|
||||
|
||||
if ( false === $checksums ) {
|
||||
return $checksums;
|
||||
}
|
||||
|
||||
set_transient( 'health-check-checksums', $checksums, 2 * HOUR_IN_SECONDS );
|
||||
|
||||
// Remove the wp-content/ files from checking
|
||||
foreach ( $checksums as $file => $checksum ) {
|
||||
if ( false !== strpos( $file, 'wp-content/' ) ) {
|
||||
unset( $checksums[ $file ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $checksums;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the results from the WordPress API call
|
||||
*
|
||||
* @uses file_exists()
|
||||
* @uses md5_file()
|
||||
* @uses ABSPATH
|
||||
*
|
||||
* @param array $checksums
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
function parse_checksum_results( $checksums ) {
|
||||
// Check if the checksums are valid
|
||||
if ( false === $checksums ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$filepath = ABSPATH;
|
||||
$files = array();
|
||||
// Parse the results.
|
||||
foreach ( $checksums as $file => $checksum ) {
|
||||
// Check the files.
|
||||
if ( file_exists( $filepath . $file ) && md5_file( $filepath . $file ) !== $checksum ) {
|
||||
$reason = esc_html__( 'Content changed', 'health-check' ) . ' <a href="#health-check-diff" data-file="' . $file . '">' . esc_html__( '(View Diff)', 'health-check' ) . '</a>';
|
||||
array_push( $files, array( $file, $reason ) );
|
||||
} elseif ( ! file_exists( $filepath . $file ) ) {
|
||||
$reason = esc_html__( 'File not found', 'health-check' );
|
||||
array_push( $files, array( $file, $reason ) );
|
||||
}
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the response
|
||||
*
|
||||
* @uses wp_send_json_success()
|
||||
* @uses wp_die()
|
||||
* @uses ABSPATH
|
||||
*
|
||||
* @param null|array $files
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function create_the_response( $files ) {
|
||||
$filepath = ABSPATH;
|
||||
$output = '';
|
||||
|
||||
if ( empty( $files ) ) {
|
||||
$output .= '<div class="notice notice-success inline"><p>';
|
||||
$output .= esc_html__( 'All files passed the check. Everything seems to be ok!', 'health-check' );
|
||||
$output .= '</p></div>';
|
||||
} else {
|
||||
$output .= '<div class="notice notice-error inline"><p>';
|
||||
$output .= esc_html__( 'It appears as if some files may have been modified.', 'health-check' );
|
||||
$output .= '<br>' . esc_html__( 'One possible reason for this may be that your installation contains translated versions. An easy way to clear this is to reinstall WordPress. Don\'t worry. This will only affect WordPress\' own files, not your themes, plugins or uploaded media.', 'health-check' );
|
||||
$output .= '</p></div><table class="widefat striped file-integrity-table"><thead><tr><th>';
|
||||
$output .= esc_html__( 'Status', 'health-check' );
|
||||
$output .= '</th><th>';
|
||||
$output .= esc_html__( 'File', 'health-check' );
|
||||
$output .= '</th><th>';
|
||||
$output .= esc_html__( 'Reason', 'health-check' );
|
||||
$output .= '</th></tr></thead><tfoot><tr><td>';
|
||||
$output .= esc_html__( 'Status', 'health-check' );
|
||||
$output .= '</td><td>';
|
||||
$output .= esc_html__( 'File', 'health-check' );
|
||||
$output .= '</td><td>';
|
||||
$output .= esc_html__( 'Reason', 'health-check' );
|
||||
$output .= '</td></tr></tfoot><tbody>';
|
||||
foreach ( $files as $tampered ) {
|
||||
$output .= '<tr>';
|
||||
$output .= '<td><span class="error"><span class="screen-reader-text">' . esc_html__( 'Error', 'health-check' ) . '</span></span></td>';
|
||||
$output .= '<td>' . $filepath . $tampered[0] . '</td>';
|
||||
$output .= '<td>' . $tampered[1] . '</td>';
|
||||
$output .= '</tr>';
|
||||
}
|
||||
$output .= '</tbody>';
|
||||
$output .= '</table>';
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'message' => $output,
|
||||
);
|
||||
|
||||
wp_send_json_success( $response );
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates Diff view
|
||||
*
|
||||
* @uses get_bloginfo()
|
||||
* @uses wp_remote_get()
|
||||
* @uses wp_remote_retrieve_body()
|
||||
* @uses wp_send_json_success()
|
||||
* @uses wp_die()
|
||||
* @uses ABSPATH
|
||||
* @uses FILE_USE_INCLUDE_PATH
|
||||
* @uses wp_text_diff()
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function view_file_diff() {
|
||||
check_ajax_referer( 'health-check-view-file-diff' );
|
||||
|
||||
if ( ! current_user_can( 'view_site_health_checks' ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
$filepath = ABSPATH;
|
||||
$file = $_POST['file'];
|
||||
$wpversion = get_bloginfo( 'version' );
|
||||
|
||||
if ( 0 !== validate_file( $file ) ) {
|
||||
wp_send_json_error( array( 'message' => esc_html__( 'You do not have access to this file.', 'health-check' ) ) );
|
||||
}
|
||||
|
||||
$allowed_files = get_transient( 'health-check-checksums' );
|
||||
if ( false === $allowed_files ) {
|
||||
$allowed_files = $this->call_checksum_api();
|
||||
}
|
||||
|
||||
if ( ! isset( $allowed_files[ $file ] ) ) {
|
||||
wp_send_json_error( array( 'message' => esc_html__( 'You do not have access to this file.', 'health-check' ) ) );
|
||||
}
|
||||
|
||||
$local_file_body = file_get_contents( $filepath . $file, FILE_USE_INCLUDE_PATH );
|
||||
$remote_file = wp_remote_get( 'https://core.svn.wordpress.org/tags/' . $wpversion . '/' . $file );
|
||||
$remote_file_body = wp_remote_retrieve_body( $remote_file );
|
||||
$diff_args = array(
|
||||
'show_split_view' => true,
|
||||
);
|
||||
|
||||
$output = '<table class="diff"><thead><tr class="diff-sub-title"><th>';
|
||||
$output .= esc_html__( 'Original', 'health-check' );
|
||||
$output .= '</th><th>';
|
||||
$output .= esc_html__( 'Modified', 'health-check' );
|
||||
$output .= '</th></tr></table>';
|
||||
$output .= wp_text_diff( $remote_file_body, $local_file_body, $diff_args );
|
||||
$response = array(
|
||||
'message' => $output,
|
||||
);
|
||||
|
||||
wp_send_json_success( $response );
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the Files integrity checker to the tools tab.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tab_content() {
|
||||
?>
|
||||
<form action="#" id="health-check-file-integrity" method="POST">
|
||||
<p>
|
||||
<input type="submit" class="button button-primary" value="<?php esc_html_e( 'Check the Files Integrity', 'health-check' ); ?>">
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<div id="tools-file-integrity-response-holder">
|
||||
<span class="spinner"></span>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
new Health_Check_Files_Integrity();
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Checks if wp_mail() works.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Mail Check
|
||||
*/
|
||||
class Health_Check_Mail_Check extends Health_Check_Tool {
|
||||
|
||||
public function __construct() {
|
||||
$this->label = __( 'Mail Check', 'health-check' );
|
||||
$this->description = __( 'The Mail Check will invoke the <code>wp_mail()</code> function and check if it succeeds. We will use the E-mail address you have set up, but you can change it below if you like.', 'health-check' );
|
||||
|
||||
add_action( 'wp_ajax_health-check-mail-check', array( $this, 'run_mail_check' ) );
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if wp_mail() works.
|
||||
*
|
||||
* @uses sanitize_email()
|
||||
* @uses wp_mail()
|
||||
* @uses wp_send_json_success()
|
||||
* @uses wp_die()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
static function run_mail_check() {
|
||||
check_ajax_referer( 'health-check-mail-check' );
|
||||
|
||||
if ( ! current_user_can( 'view_site_health_checks' ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
$output = '';
|
||||
$sendmail = false;
|
||||
$email = sanitize_email( $_POST['email'] );
|
||||
$email_message = sanitize_text_field( $_POST['email_message'] );
|
||||
$wp_address = get_bloginfo( 'url' );
|
||||
$wp_name = get_bloginfo( 'name' );
|
||||
$date = date_i18n( get_option( 'date_format' ), current_time( 'timestamp' ) );
|
||||
$time = date_i18n( get_option( 'time_format' ), current_time( 'timestamp' ) );
|
||||
|
||||
// translators: %s: website url.
|
||||
$email_subject = sprintf( esc_html__( 'Health Check – Test Message from %s', 'health-check' ), $wp_address );
|
||||
|
||||
$email_body = sprintf(
|
||||
// translators: %1$s: website name. %2$s: website url. %3$s: The date the message was sent. %4$s: The time the message was sent.
|
||||
__( 'Hi! This test message was sent by the Health Check plugin from %1$s (%2$s) on %3$s at %4$s. Since you’re reading this, it obviously works.', 'health-check' ),
|
||||
$wp_name,
|
||||
$wp_address,
|
||||
$date,
|
||||
$time,
|
||||
$email_message
|
||||
);
|
||||
|
||||
if ( ! empty( $email_message ) ) {
|
||||
$email_body .= "\n\n" . sprintf(
|
||||
// translators: %s: The custom message that may be included with the email.
|
||||
__( 'Additional message from admin: %s', 'health-check' ),
|
||||
$email_message
|
||||
);
|
||||
}
|
||||
|
||||
$sendmail = wp_mail( $email, $email_subject, $email_body );
|
||||
|
||||
if ( ! empty( $sendmail ) ) {
|
||||
$output .= '<div class="notice notice-success inline"><p>';
|
||||
$output .= __( 'We have just sent an e-mail using <code>wp_mail()</code> and it seems to work. Please check your inbox and spam folder to see if you received it.', 'health-check' );
|
||||
$output .= '</p></div>';
|
||||
} else {
|
||||
$output .= '<div class="notice notice-error inline"><p>';
|
||||
$output .= esc_html__( 'It seems there was a problem sending the e-mail.', 'health-check' );
|
||||
$output .= '</p></div>';
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'message' => $output,
|
||||
);
|
||||
|
||||
wp_send_json_success( $response );
|
||||
|
||||
wp_die();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the Mail Checker to the tools tab.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tab_content() {
|
||||
?>
|
||||
<form action="#" id="health-check-mail-check" method="POST">
|
||||
<table class="widefat tools-email-table">
|
||||
<tr>
|
||||
<td>
|
||||
<p>
|
||||
<?php
|
||||
$current_user = wp_get_current_user();
|
||||
?>
|
||||
<label for="email"><?php _e( 'Email', 'health-check' ); ?></label>
|
||||
<input type="text" name="email" id="email" value="<?php echo $current_user->user_email; ?>">
|
||||
</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>
|
||||
<label for="email_message"><?php _e( 'Additional message', 'health-check' ); ?></label>
|
||||
<input type="text" name="email_message" id="email_message" value="">
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<input type="submit" class="button button-primary" value="<?php esc_html_e( 'Send test mail', 'health-check' ); ?>">
|
||||
</form>
|
||||
|
||||
<div id="tools-mail-check-response-holder">
|
||||
<span class="spinner"></span>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
new Health_Check_Mail_Check();
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
class Health_Check_Plugin_Compatibility extends Health_Check_Tool {
|
||||
|
||||
public function __construct() {
|
||||
$this->label = __( 'Plugin compatibility', 'health-check' );
|
||||
$this->description = sprintf(
|
||||
'%s<br>%s',
|
||||
__( 'Attempt to identify the compatibility of your plugins before upgrading PHP, note that a compatibility check may not always be accurate, and you may want to contact the plugin author to confirm that things will continue working.', 'health-check' ),
|
||||
__( 'The compatibility check will need to send requests to the <a href="https://wptide.org">WPTide</a> project to fetch the test results for each of your plugins.', 'health-check' )
|
||||
);
|
||||
|
||||
add_action( 'wp_ajax_health-check-tools-plugin-compat', array( $this, 'check_plugin_version' ) );
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function tab_content() {
|
||||
?>
|
||||
<table class="wp-list-table widefat fixed striped" id="health-check-tool-plugin-compat-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e( 'Plugin', 'health-check' ); ?></th>
|
||||
<th><?php _e( 'Version', 'health-check' ); ?></th>
|
||||
<th><?php _e( 'Minimum PHP', 'health-check' ); ?></th>
|
||||
<th><?php _e( 'Highest supported PHP', 'health-check' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<?php
|
||||
$plugins = get_plugins();
|
||||
|
||||
foreach ( $plugins as $slug => $plugin ) {
|
||||
printf(
|
||||
'<tr data-plugin-slug="%s" data-plugin-version="%s" data-plugin-checked="false"><td>%s</td><td>%s</td><td>%s</td><td class="supported-version">%s</td></tr>',
|
||||
esc_attr( $slug ),
|
||||
esc_attr( $plugin['Version'] ),
|
||||
$plugin['Name'],
|
||||
$plugin['Version'],
|
||||
( isset( $plugin['RequiresPHP'] ) && ! empty( $plugin['RequiresPHP'] ) ? $plugin['RequiresPHP'] : '—' ),
|
||||
'<span class="spinner"></span>'
|
||||
);
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
<button type="button" class="button button-primary" id="health-check-tool-plugin-compat">
|
||||
<?php _e( 'Check plugins', 'health-check' ); ?>
|
||||
</button>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
function check_plugin_version() {
|
||||
check_ajax_referer( 'health-check-tools-plugin-compat' );
|
||||
|
||||
if ( ! current_user_can( 'view_site_health_checks' ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'version' => $this->get_highest_supported_php( $_POST['slug'], $_POST['version'] ),
|
||||
);
|
||||
|
||||
wp_send_json_success( $response );
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
function get_highest_supported_php( $slug, $version ) {
|
||||
$versions = $this->get_supported_php( $slug, $version );
|
||||
|
||||
if ( empty( $versions ) ) {
|
||||
return __( 'Could not be determined', 'health-check' );
|
||||
}
|
||||
|
||||
$highest = 0;
|
||||
|
||||
foreach ( $versions as $version ) {
|
||||
if ( $highest < $version ) {
|
||||
$highest = $version;
|
||||
}
|
||||
}
|
||||
|
||||
return $highest;
|
||||
}
|
||||
|
||||
function get_supported_php( $slug, $version ) {
|
||||
// Clean up the slug, in case it's got more details
|
||||
if ( stristr( $slug, '/' ) ) {
|
||||
$parts = explode( '/', $slug );
|
||||
$slug = $parts[0];
|
||||
}
|
||||
|
||||
$transient_name = sprintf(
|
||||
'health-check-tide-%s-%s',
|
||||
$slug,
|
||||
$version
|
||||
);
|
||||
|
||||
$tide_versions = get_transient( $transient_name );
|
||||
|
||||
if ( false === $tide_versions ) {
|
||||
$tide_api_respone = wp_remote_get(
|
||||
sprintf(
|
||||
'https://wptide.org/api/tide/v1/audit/wporg/plugin/%s',
|
||||
$slug
|
||||
)
|
||||
);
|
||||
|
||||
$tide_response = wp_remote_retrieve_body( $tide_api_respone );
|
||||
|
||||
$json = json_decode( $tide_response );
|
||||
|
||||
if ( empty( $json ) ) {
|
||||
$tide_versions = array();
|
||||
} else {
|
||||
$tide_versions = $json[0]->reports->phpcs_phpcompatibility->compatible_versions;
|
||||
}
|
||||
|
||||
set_transient( $transient_name, $tide_versions, 1 * WEEK_IN_SECONDS );
|
||||
}
|
||||
|
||||
return $tide_versions;
|
||||
}
|
||||
}
|
||||
|
||||
new Health_Check_Plugin_Compatibility();
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
/**
|
||||
* Base class for the Tools tab to be extended.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Health_Check_Tools
|
||||
*/
|
||||
abstract class Health_Check_Tool {
|
||||
protected $description;
|
||||
protected $label;
|
||||
|
||||
public function __construct() {
|
||||
add_filter( 'health_check_tools_tab', array( $this, 'tab_setup' ) );
|
||||
}
|
||||
|
||||
public function tab_setup( $tabs ) {
|
||||
if ( ! isset( $this->label ) || empty( $this->label ) ) {
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
<div>
|
||||
<?php if ( $this->has_description() ) : ?>
|
||||
<p><?php echo $this->get_description(); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php $this->tab_content(); ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
|
||||
$tab_content = ob_get_clean();
|
||||
|
||||
$tabs[] = array(
|
||||
'label' => $this->label,
|
||||
'content' => $tab_content,
|
||||
);
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
public function tab_content() {}
|
||||
|
||||
public function has_description() {
|
||||
return isset( $this->description ) && ! empty( $this->description );
|
||||
}
|
||||
|
||||
public function get_description() {
|
||||
return $this->description;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<div id="health-check-diff-modal">
|
||||
<div id="health-check-diff-modal-content">
|
||||
<a id="health-check-diff-modal-close-ref" href="#health-check-diff-modal-close"><span class="dashicons dashicons-no"></span></a>
|
||||
<span class="spinner"></span>
|
||||
<h3></h3>
|
||||
<div id="health-check-diff-modal-diff">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<div class="health-check-modal" data-modal-action="" data-parent-field="">
|
||||
<div class="modal-content">
|
||||
<span class="modal-close">×</span>
|
||||
<div id="dynamic-content">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
/**
|
||||
* Debug tab contents.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
Health_Check_Debug_Data::check_for_updates();
|
||||
|
||||
$info = Health_Check_Debug_Data::debug_data();
|
||||
?>
|
||||
|
||||
<h2>
|
||||
<?php esc_html_e( 'Site Health Info', 'health-check' ); ?>
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: URL to Site Health Status page */
|
||||
__( 'This page can show you every detail about the configuration of your WordPress website. For any improvements that could be made, see the <a href="%s">Site Health Status</a> page.', 'health-check' ),
|
||||
esc_url( admin_url( 'site-health.php' ) )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<p>
|
||||
<?php _e( 'If you want to export a handy list of all the information on this page, you can use the button below to copy it to the clipboard. You can then paste it in a text file and save it to your device, or paste it in an email exchange with a support engineer or theme/plugin developer for example.', 'health-check' ); ?>
|
||||
</p>
|
||||
|
||||
<div class="site-health-copy-buttons">
|
||||
<div class="copy-button-wrapper">
|
||||
<button type="button" class="button copy-button" data-clipboard-text="<?php echo esc_attr( Health_Check_Debug_Data::format( $info, 'debug' ) ); ?>">
|
||||
<?php _e( 'Copy site info to clipboard', 'health-check' ); ?>
|
||||
</button>
|
||||
<span class="success" aria-hidden="true"><?php _e( 'Copied!', 'health-check' ); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="health-check-debug" class="health-check-accordion">
|
||||
|
||||
<?php
|
||||
$sizes_fields = array( 'uploads_size', 'themes_size', 'plugins_size', 'wordpress_size', 'database_size', 'total_size' );
|
||||
|
||||
foreach ( $info as $section => $details ) {
|
||||
if ( ! isset( $details['fields'] ) || empty( $details['fields'] ) ) {
|
||||
continue;
|
||||
}
|
||||
?>
|
||||
<h3 class="health-check-accordion-heading">
|
||||
<button aria-expanded="false" class="health-check-accordion-trigger" aria-controls="health-check-accordion-block-<?php echo esc_attr( $section ); ?>" type="button">
|
||||
<span class="title">
|
||||
<?php echo esc_html( $details['label'] ); ?>
|
||||
<?php
|
||||
|
||||
if ( isset( $details['show_count'] ) && $details['show_count'] ) {
|
||||
printf( '(%d)', count( $details['fields'] ) );
|
||||
}
|
||||
|
||||
?>
|
||||
</span>
|
||||
<?php
|
||||
|
||||
if ( 'wp-paths-sizes' === $section ) {
|
||||
?>
|
||||
<span class="health-check-wp-paths-sizes spinner"></span>
|
||||
<?php
|
||||
}
|
||||
|
||||
?>
|
||||
<span class="icon"></span>
|
||||
</button>
|
||||
</h3>
|
||||
|
||||
<div id="health-check-accordion-block-<?php echo esc_attr( $section ); ?>" class="health-check-accordion-panel" hidden="hidden">
|
||||
<?php
|
||||
|
||||
if ( isset( $details['description'] ) && ! empty( $details['description'] ) ) {
|
||||
printf( '<p>%s</p>', $details['description'] );
|
||||
}
|
||||
|
||||
?>
|
||||
<table class="widefat striped health-check-table" role="presentation">
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
foreach ( $details['fields'] as $field_name => $field ) {
|
||||
if ( is_array( $field['value'] ) ) {
|
||||
$values = '<ul>';
|
||||
|
||||
foreach ( $field['value'] as $name => $value ) {
|
||||
$values .= sprintf( '<li>%s: %s</li>', esc_html( $name ), esc_html( $value ) );
|
||||
}
|
||||
|
||||
$values .= '</ul>';
|
||||
} else {
|
||||
$values = esc_html( $field['value'] );
|
||||
}
|
||||
|
||||
if ( in_array( $field_name, $sizes_fields, true ) ) {
|
||||
printf( '<tr><td>%s</td><td class="%s">%s</td></tr>', esc_html( $field['label'] ), esc_attr( $field_name ), $values );
|
||||
} else {
|
||||
printf( '<tr><td>%s</td><td>%s</td></tr>', esc_html( $field['label'] ), $values );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<div class="site-health-view-more">
|
||||
<?php
|
||||
printf(
|
||||
'<a href="%s" class="button button-primary">%s</a>',
|
||||
esc_url( admin_url( 'tools.php?page=health-check&tab=phpinfo' ) ),
|
||||
esc_html__( 'View extended PHP information', 'health-check' )
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/**
|
||||
* The PHPInfo tab contents.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
?>
|
||||
|
||||
<h2>
|
||||
<?php esc_html_e( 'Extended PHP Information', 'health-check' ); ?>
|
||||
</h2>
|
||||
|
||||
<?php
|
||||
if ( ! function_exists( 'phpinfo' ) ) {
|
||||
?>
|
||||
|
||||
<div class="notice notice-error inline">
|
||||
<p>
|
||||
<?php esc_html_e( 'The phpinfo() function has been disabled by your host. Please contact the host if you need more information about your setup.', 'health-check' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php } else { ?>
|
||||
|
||||
<div class="notice notice-warning inline">
|
||||
<p>
|
||||
<?php esc_html_e( 'Some scenarios require you to look up more detailed server configurations than what is normally required. This page allows you to view all available configuration options for your PHP setup. Please be advised that WordPress does not guarantee that any information shown on this page may not be considered private.', 'health-check' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
ob_start();
|
||||
phpinfo();
|
||||
$phpinfo_raw = ob_get_clean();
|
||||
|
||||
// Extract the body of the `phpinfo()` call, to avoid all the styles they introduce.
|
||||
preg_match_all( '/<body[^>]*>(.*)<\/body>/siU', $phpinfo_raw, $phpinfo );
|
||||
|
||||
// Extract the styles `phpinfo()` creates for this page.
|
||||
preg_match_all( '/<style[^>]*>(.*)<\/style>/siU', $phpinfo_raw, $styles );
|
||||
|
||||
// We remove various styles that break the visual flow of wp-admin.
|
||||
$remove_patterns = array(
|
||||
"/a:.+?\n/si",
|
||||
"/body.+?\n/si",
|
||||
);
|
||||
|
||||
// Output the styles as an inline style block.
|
||||
if ( isset( $styles[1][0] ) ) {
|
||||
$styles = preg_replace( $remove_patterns, '', $styles[1][0] );
|
||||
|
||||
echo '<style type="text/css">' . $styles . '</style>';
|
||||
}
|
||||
|
||||
// Output the actual phpinfo data.
|
||||
if ( isset( $phpinfo[1][0] ) ) {
|
||||
echo $phpinfo[1][0];
|
||||
}
|
||||
?>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
/**
|
||||
* The header template, printed on every Health Check related page.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="health-check-header">
|
||||
<div class="health-check-title-section">
|
||||
<h1>
|
||||
<?php esc_html_e( 'Site Health', 'health-check' ); ?>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="health-check-title-section site-health-progress-wrapper loading hide-if-no-js">
|
||||
<div class="site-health-progress">
|
||||
<svg role="img" aria-hidden="true" focusable="false" width="100%" height="100%" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle>
|
||||
<circle id="bar" r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="site-health-progress-label">
|
||||
<?php _e( 'Results are still loading…', 'health-check' ); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="health-check-tabs-wrapper hide-if-no-js" aria-label="<?php esc_attr_e( 'Secondary menu', 'health-check' ); ?>">
|
||||
<?php
|
||||
$tabs = Health_Check::tabs();
|
||||
$current_tab = Health_Check::current_tab();
|
||||
|
||||
foreach ( $tabs as $tab => $label ) {
|
||||
printf(
|
||||
'<a href="%s" class="health-check-tab health-check-%s-tab %s"%s>%s</a>',
|
||||
sprintf(
|
||||
'%s&tab=%s',
|
||||
menu_page_url( 'health-check', false ),
|
||||
$tab
|
||||
),
|
||||
esc_attr( $tab ),
|
||||
( $current_tab === $tab ? 'active' : '' ),
|
||||
( $current_tab === $tab ? ' aria-current="true"' : '' ),
|
||||
$label
|
||||
);
|
||||
}
|
||||
?>
|
||||
</nav>
|
||||
<div class="wp-clearfix"></div>
|
||||
</div>
|
||||
|
||||
<hr class="wp-header-end">
|
||||
|
||||
<div class="notice notice-error hide-if-js">
|
||||
<p><?php _e( 'The Site Health check requires JavaScript.', 'health-check' ); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="health-check-body hide-if-no-js">
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
/**
|
||||
* Health Check tab contents.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
global $health_check_site_status;
|
||||
?>
|
||||
|
||||
<div class="site-status-all-clear hide">
|
||||
<p class="icon">
|
||||
<span class="dashicons dashicons-yes"></span>
|
||||
</p>
|
||||
|
||||
<p class="encouragement">
|
||||
<?php _e( 'Great job!', 'health-check' ); ?>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<?php _e( 'Everything is running smoothly here.', 'health-check' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="site-status-has-issues">
|
||||
<h2>
|
||||
<?php _e( 'Site Health Status', 'health-check' ); ?>
|
||||
</h2>
|
||||
|
||||
<p><?php _e( 'The site health check shows critical information about your WordPress configuration and items that require your attention.', 'health-check' ); ?></p>
|
||||
|
||||
<div class="site-health-issues-wrapper" id="health-check-issues-critical">
|
||||
<h3 class="site-health-issue-count-title">
|
||||
<?php
|
||||
/* translators: %s: number of critical issues found */
|
||||
printf( _n( '%s Critical issue', '%s Critical issues', 0, 'health-check' ), '<span class="issue-count">0</span>' );
|
||||
?>
|
||||
</h3>
|
||||
|
||||
<div id="health-check-site-status-critical" class="health-check-accordion issues"></div>
|
||||
</div>
|
||||
|
||||
<div class="site-health-issues-wrapper" id="health-check-issues-recommended">
|
||||
<h3 class="site-health-issue-count-title">
|
||||
<?php
|
||||
/* translators: %s: number of recommended improvements */
|
||||
printf( _n( '%s Recommended improvement', '%s Recommended improvements', 0, 'health-check' ), '<span class="issue-count">0</span>' );
|
||||
?>
|
||||
</h3>
|
||||
|
||||
<div id="health-check-site-status-recommended" class="health-check-accordion issues"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="site-health-view-more">
|
||||
<button type="button" class="button site-health-view-passed" aria-expanded="false" aria-controls="health-check-issues-good">
|
||||
<?php _e( 'Passed tests', 'health-check' ); ?>
|
||||
<span class="icon"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="site-health-issues-wrapper hidden" id="health-check-issues-good">
|
||||
<h3 class="site-health-issue-count-title">
|
||||
<?php
|
||||
/* translators: %s: number of items with no issues */
|
||||
printf( _n( '%s Item with no issues detected', '%s Items with no issues detected', 0, 'health-check' ), '<span class="issue-count">0</span>' );
|
||||
?>
|
||||
</h3>
|
||||
|
||||
<div id="health-check-site-status-good" class="health-check-accordion issues"></div>
|
||||
</div>
|
||||
|
||||
<script id="tmpl-health-check-issue" type="text/template">
|
||||
<h4 class="health-check-accordion-heading">
|
||||
<button aria-expanded="false" class="health-check-accordion-trigger" aria-controls="health-check-accordion-block-{{ data.test }}" type="button">
|
||||
<span class="title">{{ data.label }}</span>
|
||||
<span class="badge {{ data.badge.color }}">{{ data.badge.label }}</span>
|
||||
<span class="icon"></span>
|
||||
</button>
|
||||
</h4>
|
||||
<div id="health-check-accordion-block-{{ data.test }}" class="health-check-accordion-panel" hidden="hidden">
|
||||
{{{ data.description }}}
|
||||
<div class="actions">
|
||||
<p class="button-container">{{{ data.actions }}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<?php
|
||||
include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/modals/js-result-warnings.php' );
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
/**
|
||||
* Health Check tab contents.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<h2>
|
||||
<?php esc_html_e( 'Tools', 'health-check' ); ?>
|
||||
</h2>
|
||||
|
||||
<div id="health-check-tools" role="presentation" class="health-check-accordion">
|
||||
<?php
|
||||
/**
|
||||
* Filter the features available under the Tools tab.
|
||||
*
|
||||
* You may introduce your own, or modify the behavior of existing tools here,
|
||||
* although we recommend not modifying anything provided by the plugin it self.
|
||||
*
|
||||
* Any interactive elements should be introduced using JavaScript and/or CSS, either
|
||||
* inline, or by enqueueing them via the appropriate actions.
|
||||
*
|
||||
* @param array $args {
|
||||
* An unassociated array of tabs, listed in the order they are registered.
|
||||
*
|
||||
* @type array $tab {
|
||||
* An associated array containing the tab title, and content.
|
||||
*
|
||||
* @type string $label A pre-escaped string used to label your tool section.
|
||||
* @type string $content The content of your tool tab, with any code you may need.
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
$tabs = apply_filters( 'health_check_tools_tab', array() );
|
||||
|
||||
foreach ( $tabs as $count => $tab ) :
|
||||
?>
|
||||
|
||||
<h3 class="health-check-accordion-heading">
|
||||
<button aria-expanded="false" class="health-check-accordion-trigger" aria-controls="health-check-accordion-block-<?php echo esc_attr( $count ); ?>" type="button">
|
||||
<span class="title">
|
||||
<?php echo $tab['label']; ?>
|
||||
</span>
|
||||
<span class="icon"></span>
|
||||
</button>
|
||||
</h3>
|
||||
<div id="health-check-accordion-block-<?php echo esc_attr( $count ); ?>" class="health-check-accordion-panel" hidden="hidden">
|
||||
<?php echo $tab['content']; ?>
|
||||
</div>
|
||||
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/modals/diff.php' );
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/**
|
||||
* The Troubleshooting tab contents.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
// Make sure the file is not directly accessible.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die( 'We\'re sorry, but you can not directly access this file.' );
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<h2>
|
||||
<?php esc_html_e( 'Troubleshooting mode', 'health-check' ); ?>
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<?php esc_html_e( 'When troubleshooting issues on your site, you are likely to be told to disable all plugins and switch to the default theme.', 'health-check' ); ?>
|
||||
<?php esc_html_e( 'Understandably, you do not wish to do so as it may affect your site visitors, leaving them with lost functionality.', 'health-check' ); ?>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<?php esc_html_e( 'By enabling the Troubleshooting Mode, all plugins will appear inactive and your site will switch to the default theme only for you. All other users will see your site as usual.', 'health-check' ); ?>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<?php esc_html_e( 'A Troubleshooting Mode menu is added to your admin bar, which will allow you to enable plugins individually, switch back to your current theme, and disable Troubleshooting Mode.', 'health-check' ); ?>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<?php esc_html_e( 'Please note, that due to how Must Use plugins work, any such plugin will not be disabled for the troubleshooting session.', 'health-check' ); ?>
|
||||
</p>
|
||||
|
||||
<?php
|
||||
Health_Check_Troubleshoot::show_enable_troubleshoot_form();
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
=== Health Check & Troubleshooting ===
|
||||
Tags: health check
|
||||
Contributors: wordpressdotorg, westi, pento, Clorith
|
||||
Requires at least: 4.0
|
||||
Requires PHP: 5.2
|
||||
Tested up to: 5.2
|
||||
Stable tag: 1.4.2
|
||||
License: GPLv2
|
||||
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
Health Check identifies common problems, and helps you troubleshoot plugin and theme conflicts.
|
||||
|
||||
== Description ==
|
||||
|
||||
This plugin will perform a number of checks on your WordPress installation to detect common configuration errors and known issues, and also allows plugins and themes to add their own checks.
|
||||
|
||||
The debug section, which allows you to gather information about your WordPress and server configuration that you may easily share with support representatives for themes, plugins or on the official WordPress.org support forums.
|
||||
|
||||
Troubleshooting allows you to have a clean WordPress session, where all plugins are disabled, and a default theme is used, but only for your user until you disable it or log out.
|
||||
|
||||
The Tools section allows you to check that WordPress files have not been tampered with, that emails can be sent, and if your plugins are compatible with any PHP version updates in the future.
|
||||
|
||||
For a more extensive example of how to efficiently use the Health Check plugin, check out the [WordPress.org support team handbook page about this plugin](https://make.wordpress.org/support/handbook/appendix/troubleshooting-using-the-health-check/).
|
||||
|
||||
Feedback is welcome both through the [WordPress.org forums](https://wordpress.org/support/plugin/health-check), the [GitHub project page](https://github.com/WordPress/health-check), or on [Slack](https://make.wordpress.org/chat) in either [#forums](https://wordpress.slack.com/messages/forums/) or [#core-site-health](https://wordpress.slack.com/messages/core-site-health/).
|
||||
|
||||
== Frequently Asked Questions ==
|
||||
|
||||
= I am unable to access my site after enabling troubleshooting =
|
||||
|
||||
If you should find your self stuck in Troubleshooting Mode for any reason, you can easily disable it by clearing your cookies.
|
||||
|
||||
Are you unfamiliar with how to clear your cookies? No worries, you may also close all your browser windows, or perform a computer restart and it will clear this specific cookie automatically.
|
||||
|
||||
= The PHP compatibility says this plugin only work with PHP version X? =
|
||||
|
||||
The plugin is made to be a support tool for as many users as possible, this means it needs code that is written for older sites as well.
|
||||
|
||||
Tools that check for PHP compatibility do not know how to separate this code from the real code, so it will give a false positive response.
|
||||
|
||||
At this time, the plugin has been tested with every version of PHP from 5.2 through 7.3, and works with all of these.
|
||||
|
||||
== Screenshots ==
|
||||
|
||||
1. The health check screen after the automated tests have gone over the system.
|
||||
2. The debug information, with the copy and paste field expanded.
|
||||
3. A selection of tools that can be ran on your site.
|
||||
4. Troubleshooting mode enabled, showing your website Dashboard
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= v1.4.2 =
|
||||
* Fix missing headers for a loopback request in the debug section
|
||||
|
||||
= v1.4.1 =
|
||||
* Fixed SQL version checks for various MariaDB installs.
|
||||
* Fixed a warning being generated in logfiles for first-time users with no existing Site Health history.
|
||||
* Added missing translation function for the new PHP compatibility tool.
|
||||
|
||||
= v1.4.0 =
|
||||
* Fix a bug when viewing the Site Health page if enabling the Health Check plugin in troubleshooting mode.
|
||||
* Fix an inconsistency with how database versions are checked.
|
||||
* Fix the file comparison view on Windows systems if there are modified core files.
|
||||
* Fix a bug where some premium plugins could not be enabled in troubleshooting mode
|
||||
* Improved styles for older browsers.
|
||||
* Improved the PHP module checks to allow for constant checks as well. Should help with some edge case tests.
|
||||
* Improved the core file integrity checker.
|
||||
* Improved testing of WP_cron, now works properly for those running a "real cron" outside of WordPress.
|
||||
* Improved the htaccess rule test to only run if using an Apache server that supports these.
|
||||
* Modify the Site Health grading indicator.
|
||||
* Modified strings to make them clearer.
|
||||
* Added server headers to the Debug information.
|
||||
* Added polyfills for core features from WordPress 5.2 so they work for older sites.
|
||||
* Added a link to the Site Health page from the plugin overview.
|
||||
* Added a custom capability, `view_site_health_checks` for the plugin.
|
||||
* Added support for parent/child theme output in the Debug screen.
|
||||
* Added system user information to the Debug information.
|
||||
* Added a Site Health test for timezone localization.
|
||||
* Added `mbstring` and `json` (again) as requirements to the list of PHP extensions.
|
||||
* Added a missing toggle to the list of plugins/themes to the troubleshooting dashboard widget.
|
||||
* Added bulk actions to enable or disable plugins when troubleshooting, or to initiate troubleshooting mode.
|
||||
* Added plugin compatibility checker ot the tools section.
|
||||
* Added a dashboard widget to show your Site Health status at a glance when logging in.
|
||||
* Added filters for Site Health test results.
|
||||
* Added WP-CLI support, you can now run `wp health-check status` for a list of test and their status.
|
||||
* Moved compatibility functions out of primary files and into a `compat.php` so they can be conditionally loaded.
|
||||
* Disable the Fatal Error (WSOD) protection in WordPress while in troubleshooting mode.
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* Perform plugin installation routines.
|
||||
*
|
||||
* @package Health Check
|
||||
*/
|
||||
|
||||
global $wpdb;
|
||||
|
||||
// Make sure the uninstall file can't be accessed directly.
|
||||
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
|
||||
die;
|
||||
}
|
||||
|
||||
// Remove options introduced by the plugin.
|
||||
delete_option( 'health-check-disable-plugin-hash' );
|
||||
delete_option( 'health-check-default-theme' );
|
||||
delete_option( 'health-check-current-theme' );
|
||||
delete_option( 'health-check-dashboard-notices' );
|
||||
|
||||
/*
|
||||
* Remove any user meta entries we made, done with a custom query as core
|
||||
* does not provide an option to clear them for all users.
|
||||
*/
|
||||
$wpdb->delete(
|
||||
$wpdb->usermeta,
|
||||
array(
|
||||
'meta_key' => 'health-check',
|
||||
)
|
||||
);
|
||||
|
||||
// Remove any transients and similar which the plugin may have left behind.
|
||||
$wpdb->query( "DELETE FROM {$wpdb->options} WHERE `option_name` LIKE '_transient_%_health-check%'" );
|
||||
|
||||
// Remove the old Must-Use plugin if it was implemented.
|
||||
if ( file_exists( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' ) ) {
|
||||
wp_delete_file( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' );
|
||||
}
|
||||
|
||||
// Remove the renamed Must-Use plugin if it exists.
|
||||
if ( file_exists( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php' ) ) {
|
||||
wp_delete_file( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php' );
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
.git/
|
||||
.gitignore
|
||||
.travis.yml
|
||||
readme.md
|
||||
tests/
|
||||
_inc/lib/icalendar-reader.php
|
||||
modules/shortcodes/upcoming-events.php
|
||||
modules/widgets/upcoming-events.php
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* Compatibility files for third-party plugins.
|
||||
* This is used to improve compatibility of specific Jetpack features with third-party plugins.
|
||||
*
|
||||
* @package Jetpack
|
||||
*/
|
||||
|
||||
// Array of third-party compat files to always require.
|
||||
$compat_files = array(
|
||||
'bbpress.php',
|
||||
'beaverbuilder.php',
|
||||
'bitly.php',
|
||||
'buddypress.php',
|
||||
'class.jetpack-amp-support.php',
|
||||
'class.jetpack-modules-overrides.php', // Special case. Tools to be used to override module settings.
|
||||
'debug-bar.php',
|
||||
'domain-mapping.php',
|
||||
'polldaddy.php',
|
||||
'qtranslate-x.php',
|
||||
'vaultpress.php',
|
||||
'wpml.php',
|
||||
'woocommerce.php',
|
||||
'woocommerce-services.php',
|
||||
);
|
||||
|
||||
foreach ( $compat_files as $file ) {
|
||||
if ( file_exists( JETPACK__PLUGIN_DIR . '/3rd-party/' . $file ) ) {
|
||||
require_once JETPACK__PLUGIN_DIR . '/3rd-party/' . $file;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
add_action( 'init', 'jetpack_bbpress_compat', 11 ); // Priority 11 needed to ensure sharing_display is loaded.
|
||||
|
||||
/**
|
||||
* Adds Jetpack + bbPress Compatibility filters.
|
||||
*
|
||||
* @author Brandon Kraft
|
||||
* @since 3.7.1
|
||||
*/
|
||||
function jetpack_bbpress_compat() {
|
||||
if ( function_exists( 'sharing_display' ) ) {
|
||||
add_filter( 'bbp_get_topic_content', 'sharing_display', 19 );
|
||||
add_action( 'bbp_template_after_single_forum', 'jetpack_sharing_bbpress' );
|
||||
add_action( 'bbp_template_after_single_topic', 'jetpack_sharing_bbpress' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Markdown support for bbpress post types.
|
||||
*
|
||||
* @author Brandon Kraft
|
||||
* @since 6.0.0
|
||||
*/
|
||||
if ( function_exists( 'bbp_get_topic_post_type' ) ) {
|
||||
add_post_type_support( bbp_get_topic_post_type(), 'wpcom-markdown' );
|
||||
add_post_type_support( bbp_get_reply_post_type(), 'wpcom-markdown' );
|
||||
add_post_type_support( bbp_get_forum_post_type(), 'wpcom-markdown' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Use Photon for all images in Topics and replies.
|
||||
*
|
||||
* @since 4.9.0
|
||||
*/
|
||||
if ( class_exists( 'Jetpack_Photon' ) && Jetpack::is_module_active( 'photon' ) ) {
|
||||
add_filter( 'bbp_get_topic_content', array( 'Jetpack_Photon', 'filter_the_content' ), 999999 );
|
||||
add_filter( 'bbp_get_reply_content', array( 'Jetpack_Photon', 'filter_the_content' ), 999999 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display Jetpack "Sharing" buttons on bbPress 2.x forums/ topics/ lead topics/ replies.
|
||||
*
|
||||
* Determination if the sharing buttons should display on the post type is handled within sharing_display().
|
||||
*
|
||||
* @author David Decker
|
||||
* @since 3.7.0
|
||||
*/
|
||||
function jetpack_sharing_bbpress() {
|
||||
sharing_display( null, true );
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
/**
|
||||
* Beaverbuilder Compatibility.
|
||||
*/
|
||||
class Jetpack_BeaverBuilderCompat {
|
||||
|
||||
function __construct() {
|
||||
add_action( 'init', array( $this, 'beaverbuilder_refresh' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* If masterbar module is active force BeaverBuilder to refresh when publishing a layout.
|
||||
*/
|
||||
function beaverbuilder_refresh() {
|
||||
if ( Jetpack::is_module_active( 'masterbar' ) ) {
|
||||
add_filter( 'fl_builder_should_refresh_on_publish', '__return_true' );
|
||||
}
|
||||
}
|
||||
}
|
||||
new Jetpack_BeaverBuilderCompat();
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Fixes issues with the Official Bitly for WordPress
|
||||
* https://wordpress.org/plugins/bitly/
|
||||
*/
|
||||
if( class_exists( 'Bitly' ) ) {
|
||||
|
||||
if( isset( $GLOBALS['bitly'] ) ) {
|
||||
if ( method_exists( $GLOBALS['bitly'], 'og_tags' ) ) {
|
||||
remove_action( 'wp_head', array( $GLOBALS['bitly'], 'og_tags' ) );
|
||||
}
|
||||
|
||||
add_action( 'wp_head', 'jetpack_bitly_og_tag', 100 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* jetpack_bitly_og_tag
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
function jetpack_bitly_og_tag() {
|
||||
if( has_filter( 'wp_head', 'jetpack_og_tags') === false ) {
|
||||
// Add the bitly part again back if we don't have any jetpack_og_tags added
|
||||
if ( method_exists( $GLOBALS['bitly'], 'og_tags' ) ) {
|
||||
$GLOBALS['bitly']->og_tags();
|
||||
}
|
||||
} elseif ( isset( $GLOBALS['posts'] ) && $GLOBALS['posts'][0]->ID > 0 ) {
|
||||
printf( "<meta property=\"bitly:url\" content=\"%s\" /> \n", esc_attr( $GLOBALS['bitly']->get_bitly_link_for_post_id( $GLOBALS['posts'][0]->ID ) ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
add_filter( 'bp_core_pre_avatar_handle_upload', 'blobphoto' );
|
||||
function blobphoto( $bool ) {
|
||||
|
||||
add_filter( 'jetpack_photon_skip_image', '__return_true' );
|
||||
|
||||
return $bool;
|
||||
}
|
||||
|
|
@ -0,0 +1,443 @@
|
|||
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
|
||||
|
||||
use Automattic\Jetpack\Sync\Functions;
|
||||
|
||||
/**
|
||||
* Manages compatibility with the amp-wp plugin
|
||||
*
|
||||
* @see https://github.com/Automattic/amp-wp
|
||||
*/
|
||||
class Jetpack_AMP_Support {
|
||||
|
||||
/**
|
||||
* Apply custom AMP changes onthe frontend.
|
||||
*/
|
||||
public static function init() {
|
||||
|
||||
// Add Stats tracking pixel on Jetpack sites when the Stats module is active.
|
||||
if (
|
||||
Jetpack::is_module_active( 'stats' )
|
||||
&& ! ( defined( 'IS_WPCOM' ) && IS_WPCOM )
|
||||
) {
|
||||
add_action( 'amp_post_template_footer', array( 'Jetpack_AMP_Support', 'add_stats_pixel' ) );
|
||||
}
|
||||
|
||||
// Sharing.
|
||||
add_filter( 'jetpack_sharing_display_markup', array( 'Jetpack_AMP_Support', 'render_sharing_html' ), 10, 2 );
|
||||
add_filter( 'sharing_enqueue_scripts', array( 'Jetpack_AMP_Support', 'amp_disable_sharedaddy_css' ) );
|
||||
|
||||
// enforce freedom mode for videopress.
|
||||
add_filter( 'videopress_shortcode_options', array( 'Jetpack_AMP_Support', 'videopress_enable_freedom_mode' ) );
|
||||
|
||||
// include Jetpack og tags when rendering native AMP head.
|
||||
add_action( 'amp_post_template_head', array( 'Jetpack_AMP_Support', 'amp_post_jetpack_og_tags' ) );
|
||||
|
||||
// Post rendering changes for legacy AMP.
|
||||
add_action( 'pre_amp_render_post', array( 'Jetpack_AMP_Support', 'amp_disable_the_content_filters' ) );
|
||||
|
||||
// Add post template metadata for legacy AMP.
|
||||
add_filter( 'amp_post_template_metadata', array( 'Jetpack_AMP_Support', 'amp_post_template_metadata' ), 10, 2 );
|
||||
|
||||
// Filter photon image args for AMP Stories.
|
||||
add_filter( 'jetpack_photon_post_image_args', array( 'Jetpack_AMP_Support', 'filter_photon_post_image_args_for_stories' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply custom AMP changes in wp-admin.
|
||||
*/
|
||||
public static function admin_init() {
|
||||
// disable Likes metabox for post editor if AMP canonical disabled.
|
||||
add_filter( 'post_flair_disable', array( 'Jetpack_AMP_Support', 'is_amp_canonical' ), 99 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the page in AMP 'canonical mode'.
|
||||
* Used when themes register support for AMP with `add_theme_support( 'amp' )`.
|
||||
*
|
||||
* @return bool is_amp_canonical
|
||||
*/
|
||||
public static function is_amp_canonical() {
|
||||
return function_exists( 'amp_is_canonical' ) && amp_is_canonical();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the page return AMP content.
|
||||
*
|
||||
* @return bool $is_amp_request Are we on am AMP view.
|
||||
*/
|
||||
public static function is_amp_request() {
|
||||
$is_amp_request = ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() );
|
||||
|
||||
/**
|
||||
* Returns true if the current request should return valid AMP content.
|
||||
*
|
||||
* @since 6.2.0
|
||||
*
|
||||
* @param boolean $is_amp_request Is this request supposed to return valid AMP content?
|
||||
*/
|
||||
return apply_filters( 'jetpack_is_amp_request', $is_amp_request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove content filters added by Jetpack.
|
||||
*/
|
||||
public static function amp_disable_the_content_filters() {
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
add_filter( 'videopress_show_2015_player', '__return_true' );
|
||||
add_filter( 'protected_embeds_use_form_post', '__return_false' );
|
||||
remove_filter( 'the_title', 'widont' );
|
||||
}
|
||||
|
||||
remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'filter' ), 11 );
|
||||
remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'maybe_create_links' ), 100 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Jetpack stats pixel.
|
||||
*
|
||||
* @since 6.2.1
|
||||
*/
|
||||
public static function add_stats_pixel() {
|
||||
if ( ! has_action( 'wp_footer', 'stats_footer' ) ) {
|
||||
return;
|
||||
}
|
||||
stats_render_amp_footer( stats_build_view_data() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add publisher and image metadata to legacy AMP post.
|
||||
*
|
||||
* @since 6.2.0
|
||||
*
|
||||
* @param array $metadata Metadata array.
|
||||
* @param WP_Post $post Post.
|
||||
* @return array Modified metadata array.
|
||||
*/
|
||||
public static function amp_post_template_metadata( $metadata, $post ) {
|
||||
if ( isset( $metadata['publisher'] ) && ! isset( $metadata['publisher']['logo'] ) ) {
|
||||
$metadata = self::add_site_icon_to_metadata( $metadata );
|
||||
}
|
||||
|
||||
if ( ! isset( $metadata['image'] ) ) {
|
||||
$metadata = self::add_image_to_metadata( $metadata, $post );
|
||||
}
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add blavatar to legacy AMP post metadata.
|
||||
*
|
||||
* @since 6.2.0
|
||||
*
|
||||
* @param array $metadata Metadata.
|
||||
*
|
||||
* @return array Metadata.
|
||||
*/
|
||||
private static function add_site_icon_to_metadata( $metadata ) {
|
||||
$size = 60;
|
||||
$site_icon_url = class_exists( 'Automattic\\Jetpack\\Sync\\Functions' ) ? Functions::site_icon_url( $size ) : '';
|
||||
|
||||
if ( function_exists( 'blavatar_domain' ) ) {
|
||||
$metadata['publisher']['logo'] = array(
|
||||
'@type' => 'ImageObject',
|
||||
'url' => blavatar_url( blavatar_domain( site_url() ), 'img', $size, self::staticize_subdomain( 'https://wordpress.com/i/favicons/apple-touch-icon-60x60.png' ) ),
|
||||
'width' => $size,
|
||||
'height' => $size,
|
||||
);
|
||||
} elseif ( $site_icon_url ) {
|
||||
$metadata['publisher']['logo'] = array(
|
||||
'@type' => 'ImageObject',
|
||||
'url' => $site_icon_url,
|
||||
'width' => $size,
|
||||
'height' => $size,
|
||||
);
|
||||
}
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add image to legacy AMP post metadata.
|
||||
*
|
||||
* @since 6.2.0
|
||||
*
|
||||
* @param array $metadata Metadata.
|
||||
* @param WP_Post $post Post.
|
||||
* @return array Metadata.
|
||||
*/
|
||||
private static function add_image_to_metadata( $metadata, $post ) {
|
||||
$image = Jetpack_PostImages::get_image(
|
||||
$post->ID,
|
||||
array(
|
||||
'fallback_to_avatars' => true,
|
||||
'avatar_size' => 200,
|
||||
// AMP already attempts these.
|
||||
'from_thumbnail' => false,
|
||||
'from_attachment' => false,
|
||||
)
|
||||
);
|
||||
|
||||
if ( empty( $image ) ) {
|
||||
return self::add_fallback_image_to_metadata( $metadata );
|
||||
}
|
||||
|
||||
if ( ! isset( $image['src_width'] ) ) {
|
||||
$dimensions = self::extract_image_dimensions_from_getimagesize(
|
||||
array(
|
||||
$image['src'] => false,
|
||||
)
|
||||
);
|
||||
|
||||
if ( false !== $dimensions[ $image['src'] ] ) {
|
||||
$image['src_width'] = $dimensions['width'];
|
||||
$image['src_height'] = $dimensions['height'];
|
||||
}
|
||||
}
|
||||
|
||||
$metadata['image'] = array(
|
||||
'@type' => 'ImageObject',
|
||||
'url' => $image['src'],
|
||||
);
|
||||
if ( isset( $image['src_width'] ) ) {
|
||||
$metadata['image']['width'] = $image['src_width'];
|
||||
}
|
||||
if ( isset( $image['src_width'] ) ) {
|
||||
$metadata['image']['height'] = $image['src_height'];
|
||||
}
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add fallback image to legacy AMP post metadata.
|
||||
*
|
||||
* @since 6.2.0
|
||||
*
|
||||
* @param array $metadata Metadata.
|
||||
* @return array Metadata.
|
||||
*/
|
||||
private static function add_fallback_image_to_metadata( $metadata ) {
|
||||
/** This filter is documented in functions.opengraph.php */
|
||||
$default_image = apply_filters( 'jetpack_open_graph_image_default', 'https://wordpress.com/i/blank.jpg' );
|
||||
|
||||
$metadata['image'] = array(
|
||||
'@type' => 'ImageObject',
|
||||
'url' => self::staticize_subdomain( $default_image ),
|
||||
'width' => 200,
|
||||
'height' => 200,
|
||||
);
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return static WordPress.com domain to use to load resources from WordPress.com.
|
||||
*
|
||||
* @param string $domain Asset URL.
|
||||
*/
|
||||
private static function staticize_subdomain( $domain ) {
|
||||
// deal with WPCOM vs Jetpack.
|
||||
if ( function_exists( 'staticize_subdomain' ) ) {
|
||||
return staticize_subdomain( $domain );
|
||||
} else {
|
||||
return Jetpack::staticize_subdomain( $domain );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract image dimensions via wpcom/imagesize, only on WPCOM
|
||||
*
|
||||
* @since 6.2.0
|
||||
*
|
||||
* @param array $dimensions Dimensions.
|
||||
* @return array Dimensions.
|
||||
*/
|
||||
private static function extract_image_dimensions_from_getimagesize( $dimensions ) {
|
||||
if ( ! ( defined( 'IS_WPCOM' ) && IS_WPCOM && function_exists( 'require_lib' ) ) ) {
|
||||
return $dimensions;
|
||||
}
|
||||
require_lib( 'wpcom/imagesize' );
|
||||
|
||||
foreach ( $dimensions as $url => $value ) {
|
||||
if ( is_array( $value ) ) {
|
||||
continue;
|
||||
}
|
||||
$result = wpcom_getimagesize( $url );
|
||||
if ( is_array( $result ) ) {
|
||||
$dimensions[ $url ] = array(
|
||||
'width' => $result[0],
|
||||
'height' => $result[1],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $dimensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display Open Graph Meta tags in AMP views.
|
||||
*/
|
||||
public static function amp_post_jetpack_og_tags() {
|
||||
if ( ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
|
||||
Jetpack::init()->check_open_graph();
|
||||
}
|
||||
|
||||
if ( function_exists( 'jetpack_og_tags' ) ) {
|
||||
jetpack_og_tags();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force Freedom mode in VideoPress.
|
||||
*
|
||||
* @param array $options Array of VideoPress shortcode options.
|
||||
*/
|
||||
public static function videopress_enable_freedom_mode( $options ) {
|
||||
if ( self::is_amp_request() ) {
|
||||
$options['freedom'] = true;
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display custom markup for the sharing buttons when in an AMP view.
|
||||
*
|
||||
* @param string $markup Content markup of the Jetpack sharing links.
|
||||
* @param array $sharing_enabled Array of Sharing Services currently enabled.
|
||||
*/
|
||||
public static function render_sharing_html( $markup, $sharing_enabled ) {
|
||||
if ( ! self::is_amp_request() ) {
|
||||
return $markup;
|
||||
}
|
||||
|
||||
remove_action( 'wp_footer', 'sharing_add_footer' );
|
||||
if ( empty( $sharing_enabled ) ) {
|
||||
return $markup;
|
||||
}
|
||||
$supported_services = array(
|
||||
'facebook' => array(
|
||||
/** This filter is documented in modules/sharedaddy/sharing-sources.php */
|
||||
'data-param-app_id' => apply_filters( 'jetpack_sharing_facebook_app_id', '249643311490' ),
|
||||
),
|
||||
'twitter' => array(),
|
||||
'pinterest' => array(),
|
||||
'whatsapp' => array(),
|
||||
'tumblr' => array(),
|
||||
'linkedin' => array(),
|
||||
);
|
||||
$sharing_links = array();
|
||||
foreach ( $sharing_enabled['visible'] as $id => $service ) {
|
||||
if ( ! isset( $supported_services[ $id ] ) ) {
|
||||
$sharing_links[] = "<!-- not supported: $id -->";
|
||||
continue;
|
||||
}
|
||||
$args = array_merge(
|
||||
array(
|
||||
'type' => $id,
|
||||
),
|
||||
$supported_services[ $id ]
|
||||
);
|
||||
$sharing_link = '<amp-social-share';
|
||||
foreach ( $args as $key => $value ) {
|
||||
$sharing_link .= sprintf( ' %s="%s"', sanitize_key( $key ), esc_attr( $value ) );
|
||||
}
|
||||
$sharing_link .= '></amp-social-share>';
|
||||
$sharing_links[] = $sharing_link;
|
||||
}
|
||||
|
||||
// Wrap AMP sharing buttons in container.
|
||||
$markup = preg_replace( '#(?<=<div class="sd-content">).+?(?=</div>)#s', implode( '', $sharing_links ), $markup );
|
||||
|
||||
// Remove any lingering share-end list items.
|
||||
$markup = str_replace( '<li class="share-end"></li>', '', $markup );
|
||||
|
||||
return $markup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells Jetpack not to enqueue CSS for share buttons.
|
||||
*
|
||||
* @param bool $enqueue Whether or not to enqueue.
|
||||
* @return bool Whether or not to enqueue.
|
||||
*/
|
||||
public static function amp_disable_sharedaddy_css( $enqueue ) {
|
||||
if ( self::is_amp_request() ) {
|
||||
$enqueue = false;
|
||||
}
|
||||
|
||||
return $enqueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure proper Photon image dimensions for AMP Stories.
|
||||
*
|
||||
* @param array $args Array of Photon Arguments.
|
||||
* @param array $details {
|
||||
* Array of image details.
|
||||
*
|
||||
* @type string $tag Image tag (Image HTML output).
|
||||
* @type string $src Image URL.
|
||||
* @type string $src_orig Original Image URL.
|
||||
* @type int|false $width Image width.
|
||||
* @type int|false $height Image height.
|
||||
* @type int|false $width_orig Original image width before constrained by content_width.
|
||||
* @type int|false $height_orig Original Image height before constrained by content_width.
|
||||
* @type string $transform_orig Original transform before constrained by content_width.
|
||||
* }
|
||||
* @return array Args.
|
||||
*/
|
||||
public static function filter_photon_post_image_args_for_stories( $args, $details ) {
|
||||
if ( ! is_singular( 'amp_story' ) ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
// Percentage-based dimensions are not allowed in AMP, so this shouldn't happen, but short-circuit just in case.
|
||||
if ( false !== strpos( $details['width_orig'], '%' ) || false !== strpos( $details['height_orig'], '%' ) ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
$max_height = 1280; // See image size with the slug \AMP_Story_Post_Type::MAX_IMAGE_SIZE_SLUG.
|
||||
$transform = $details['transform_orig'];
|
||||
$width = $details['width_orig'];
|
||||
$height = $details['height_orig'];
|
||||
|
||||
// If height is available, constrain to $max_height.
|
||||
if ( false !== $height ) {
|
||||
if ( $height > $max_height && false !== $height ) {
|
||||
$width = ( $max_height * $width ) / $height;
|
||||
$height = $max_height;
|
||||
} elseif ( $height > $max_height ) {
|
||||
$height = $max_height;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a height if none is found.
|
||||
* If height is set in this manner and height is available, use `fit` instead of `resize` to prevent skewing.
|
||||
*/
|
||||
if ( false === $height ) {
|
||||
$height = $max_height;
|
||||
if ( false !== $width ) {
|
||||
$transform = 'fit';
|
||||
}
|
||||
}
|
||||
|
||||
// Build array of Photon args and expose to filter before passing to Photon URL function.
|
||||
$args = array();
|
||||
|
||||
if ( false !== $width && false !== $height ) {
|
||||
$args[ $transform ] = $width . ',' . $height;
|
||||
} elseif ( false !== $width ) {
|
||||
$args['w'] = $width;
|
||||
} elseif ( false !== $height ) {
|
||||
$args['h'] = $height;
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
}
|
||||
|
||||
add_action( 'init', array( 'Jetpack_AMP_Support', 'init' ), 1 );
|
||||
|
||||
add_action( 'admin_init', array( 'Jetpack_AMP_Support', 'admin_init' ), 1 );
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Provides methods for dealing with module overrides.
|
||||
*
|
||||
* @since 5.9.0
|
||||
*/
|
||||
class Jetpack_Modules_Overrides {
|
||||
/**
|
||||
* Used to cache module overrides so that we minimize how many times we appy the
|
||||
* option_jetpack_active_modules filter.
|
||||
*
|
||||
* @var null|array
|
||||
*/
|
||||
private $overrides = null;
|
||||
|
||||
/**
|
||||
* Clears the $overrides member used for caching.
|
||||
*
|
||||
* Since get_overrides() can be passed a falsey value to skip caching, this is probably
|
||||
* most useful for clearing cache between tests.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clear_cache() {
|
||||
$this->overrides = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there is a filter on the jetpack_active_modules option.
|
||||
*
|
||||
* @return bool Whether there is a filter on the jetpack_active_modules option.
|
||||
*/
|
||||
public function do_overrides_exist() {
|
||||
return (bool) ( has_filter( 'option_jetpack_active_modules' ) || has_filter( 'jetpack_active_modules' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the override for a given module.
|
||||
*
|
||||
* @param string $module_slug The module's slug.
|
||||
* @param boolean $use_cache Whether or not cached overrides should be used.
|
||||
*
|
||||
* @return bool|string False if no override for module. 'active' or 'inactive' if there is an override.
|
||||
*/
|
||||
public function get_module_override( $module_slug, $use_cache = true ) {
|
||||
$overrides = $this->get_overrides( $use_cache );
|
||||
|
||||
if ( ! isset( $overrides[ $module_slug ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $overrides[ $module_slug ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of module overrides where the key is the module slug and the value
|
||||
* is true if the module is forced on and false if the module is forced off.
|
||||
*
|
||||
* @param bool $use_cache Whether or not cached overrides should be used.
|
||||
*
|
||||
* @return array The array of module overrides.
|
||||
*/
|
||||
public function get_overrides( $use_cache = true ) {
|
||||
if ( $use_cache && ! is_null( $this->overrides ) ) {
|
||||
return $this->overrides;
|
||||
}
|
||||
|
||||
if ( ! $this->do_overrides_exist() ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$available_modules = Jetpack::get_available_modules();
|
||||
|
||||
/**
|
||||
* First, let's get all modules that have been forced on.
|
||||
*/
|
||||
|
||||
/** This filter is documented in wp-includes/option.php */
|
||||
$filtered = apply_filters( 'option_jetpack_active_modules', array() );
|
||||
|
||||
/** This filter is documented in class.jetpack.php */
|
||||
$filtered = apply_filters( 'jetpack_active_modules', $filtered );
|
||||
|
||||
$forced_on = array_diff( $filtered, array() );
|
||||
|
||||
/**
|
||||
* Second, let's get all modules forced off.
|
||||
*/
|
||||
|
||||
/** This filter is documented in wp-includes/option.php */
|
||||
$filtered = apply_filters( 'option_jetpack_active_modules', $available_modules );
|
||||
|
||||
/** This filter is documented in class.jetpack.php */
|
||||
$filtered = apply_filters( 'jetpack_active_modules', $filtered );
|
||||
|
||||
$forced_off = array_diff( $available_modules, $filtered );
|
||||
|
||||
/**
|
||||
* Last, build the return value.
|
||||
*/
|
||||
$return_value = array();
|
||||
foreach ( $forced_on as $on ) {
|
||||
$return_value[ $on ] = 'active';
|
||||
}
|
||||
|
||||
foreach ( $forced_off as $off ) {
|
||||
$return_value[ $off ] = 'inactive';
|
||||
}
|
||||
|
||||
$this->overrides = $return_value;
|
||||
|
||||
return $return_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to an instance of this class.
|
||||
*
|
||||
* @var Jetpack_Modules_Overrides
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Returns the singleton instance of Jetpack_Modules_Overrides
|
||||
*
|
||||
* @return Jetpack_Modules_Overrides
|
||||
*/
|
||||
public static function instance() {
|
||||
if ( is_null( self::$instance ) ) {
|
||||
self::$instance = new Jetpack_Modules_Overrides();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private construct to enforce singleton.
|
||||
*/
|
||||
private function __construct() {
|
||||
}
|
||||
}
|
||||
|
||||
Jetpack_Modules_Overrides::instance();
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Checks if the search module is active, and if so, will initialize the singleton instance
|
||||
* of Jetpack_Search_Debug_Bar and add it to the array of debug bar panels.
|
||||
*
|
||||
* @param array $panels The array of debug bar panels.
|
||||
* @return array $panel The array of debug bar panels with our added panel.
|
||||
*/
|
||||
function init_jetpack_search_debug_bar( $panels ) {
|
||||
if ( ! Jetpack::is_module_active( 'search' ) ) {
|
||||
return $panels;
|
||||
}
|
||||
|
||||
require_once dirname( __FILE__ ) . '/debug-bar/class.jetpack-search-debug-bar.php';
|
||||
$panels[] = Jetpack_Search_Debug_Bar::instance();
|
||||
return $panels;
|
||||
}
|
||||
add_filter( 'debug_bar_panels', 'init_jetpack_search_debug_bar' );
|
||||
173
wp-content/plugins/jetpack/3rd-party/debug-bar/class.jetpack-search-debug-bar.php
vendored
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Singleton class instantiated by Jetpack_Searc_Debug_Bar::instance() that handles
|
||||
* rendering the Jetpack Search debug bar menu item and panel.
|
||||
*/
|
||||
class Jetpack_Search_Debug_Bar extends Debug_Bar_Panel {
|
||||
/**
|
||||
* Holds singleton instance
|
||||
*
|
||||
* @var Jetpack_Search_Debug_Bar
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* The title to use in the debug bar navigation
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $title;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->title( esc_html__( 'Jetpack Search', 'jetpack' ) );
|
||||
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
|
||||
add_action( 'login_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
|
||||
add_action( 'enqueue_embed_scripts', array( $this, 'enqueue_scripts' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the singleton instance of Jetpack_Search_Debug_Bar
|
||||
*
|
||||
* @return Jetpack_Search_Debug_Bar
|
||||
*/
|
||||
public static function instance() {
|
||||
if ( is_null( self::$instance ) ) {
|
||||
self::$instance = new Jetpack_Search_Debug_Bar();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues styles for our panel in the debug bar
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_scripts() {
|
||||
// Do not enqueue scripts if we haven't already enqueued Debug Bar or Query Monitor styles.
|
||||
if ( ! wp_style_is( 'debug-bar' ) && ! wp_style_is( 'query-monitor' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_style(
|
||||
'jetpack-search-debug-bar',
|
||||
plugins_url( '3rd-party/debug-bar/debug-bar.css', JETPACK__PLUGIN_FILE )
|
||||
);
|
||||
wp_enqueue_script(
|
||||
'jetpack-search-debug-bar',
|
||||
plugins_url( '3rd-party/debug-bar/debug-bar.js', JETPACK__PLUGIN_FILE ),
|
||||
array( 'jquery' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the Jetpack Search Debug Bar show?
|
||||
*
|
||||
* Since we've previously done a check for the search module being activated, let's just return true.
|
||||
* Later on, we can update this to only show when `is_search()` is true.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_visible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the panel content
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render() {
|
||||
if ( ! class_exists( 'Jetpack_Search' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$jetpack_search = Jetpack_Search::instance();
|
||||
$last_query_info = $jetpack_search->get_last_query_info();
|
||||
|
||||
// If not empty, let's reshuffle the order of some things.
|
||||
if ( ! empty( $last_query_info ) ) {
|
||||
$args = $last_query_info['args'];
|
||||
$response = $last_query_info['response'];
|
||||
$response_code = $last_query_info['response_code'];
|
||||
|
||||
unset( $last_query_info['args'] );
|
||||
unset( $last_query_info['response'] );
|
||||
unset( $last_query_info['response_code'] );
|
||||
|
||||
if ( is_null( $last_query_info['es_time'] ) ) {
|
||||
$last_query_info['es_time'] = esc_html_x(
|
||||
'cache hit',
|
||||
'displayed in search results when results are cached',
|
||||
'jetpack'
|
||||
);
|
||||
}
|
||||
|
||||
$temp = array_merge(
|
||||
array( 'response_code' => $response_code ),
|
||||
array( 'args' => $args ),
|
||||
$last_query_info,
|
||||
array( 'response' => $response )
|
||||
);
|
||||
|
||||
$last_query_info = $temp;
|
||||
}
|
||||
?>
|
||||
<div class="jetpack-search-debug-bar">
|
||||
<h2><?php esc_html_e( 'Last query information:', 'jetpack' ); ?></h2>
|
||||
<?php if ( empty( $last_query_info ) ) : ?>
|
||||
<?php echo esc_html_x( 'None', 'Text displayed when there is no information', 'jetpack' ); ?>
|
||||
<?php
|
||||
else :
|
||||
foreach ( $last_query_info as $key => $info ) :
|
||||
?>
|
||||
<h3><?php echo esc_html( $key ); ?></h3>
|
||||
<?php
|
||||
if ( 'response' !== $key && 'args' !== $key ) :
|
||||
?>
|
||||
<pre><?php print_r( esc_html( $info ) ); ?></pre>
|
||||
<?php
|
||||
else :
|
||||
$this->render_json_toggle( $info );
|
||||
endif;
|
||||
?>
|
||||
<?php
|
||||
endforeach;
|
||||
endif;
|
||||
?>
|
||||
</div><!-- Closes .jetpack-search-debug-bar -->
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for rendering the HTML necessary for the JSON toggle
|
||||
*
|
||||
* @param array $value The resonse from the API as an array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_json_toggle( $value ) {
|
||||
?>
|
||||
<div class="json-toggle-wrap">
|
||||
<pre class="json"><?php
|
||||
// esc_html() will not double-encode entities (& -> &amp;).
|
||||
// If any entities are part of the JSON blob, we want to re-encoode them
|
||||
// (double-encode them) so that they are displayed correctly in the debug
|
||||
// bar.
|
||||
// Use _wp_specialchars() "manually" to ensure entities are encoded correctly.
|
||||
echo _wp_specialchars(
|
||||
wp_json_encode( $value ),
|
||||
ENT_NOQUOTES, // Don't need to encode quotes (output is for a text node).
|
||||
'UTF-8', // wp_json_encode() outputs UTF-8 (really just ASCII), not the blog's charset.
|
||||
true // Do "double-encode" existing HTML entities
|
||||
);
|
||||
?></pre>
|
||||
<span class="pretty toggle"><?php echo esc_html_x( 'Pretty', 'label for formatting JSON', 'jetpack' ); ?></span>
|
||||
<span class="ugly toggle"><?php echo esc_html_x( 'Minify', 'label for formatting JSON', 'jetpack' ); ?></span>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
.jetpack-search-debug-bar h2,
|
||||
.qm-debug-bar-output .jetpack-search-debug-bar h2 {
|
||||
float: none !important;
|
||||
padding: 0 !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.qm-debug-bar-output .jetpack-search-debug-bar h2 {
|
||||
margin-top: 1em !important;
|
||||
}
|
||||
|
||||
.qm-debug-bar-output .jetpack-search-debug-bar h2:first-child {
|
||||
margin-top: .5em !important;
|
||||
}
|
||||
|
||||
.debug-menu-target h3 {
|
||||
padding-top: 0
|
||||
}
|
||||
|
||||
.jetpack-search-debug-output-toggle .print-r {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.json-toggle-wrap {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.json-toggle-wrap .toggle {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
background: #fff;
|
||||
border: 1px solid #000;
|
||||
cursor: pointer;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
.json-toggle-wrap .ugly {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.json-toggle-wrap.pretty .pretty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.json-toggle-wrap.pretty .ugly {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.jetpack-search-debug-bar pre {
|
||||
white-space: pre-wrap;
|
||||
white-space: -moz-pre-wrap;
|
||||
white-space: -pre-wrap;
|
||||
white-space: -o-pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/* global jQuery, JSON */
|
||||
|
||||
( function( $ ) {
|
||||
$( document ).ready( function() {
|
||||
$( '.jetpack-search-debug-bar .json-toggle-wrap .toggle' ).click( function() {
|
||||
var t = $( this ),
|
||||
wrap = t.closest( '.json-toggle-wrap' ),
|
||||
pre = wrap.find( 'pre' ),
|
||||
content = pre.text(),
|
||||
isPretty = wrap.hasClass( 'pretty' );
|
||||
|
||||
if ( ! isPretty ) {
|
||||
pre.text( JSON.stringify( JSON.parse( content ), null, 2 ) );
|
||||
} else {
|
||||
content.replace( '\t', '' ).replace( '\n', '' ).replace( ' ', '' );
|
||||
pre.text( JSON.stringify( JSON.parse( content ) ) );
|
||||
}
|
||||
|
||||
wrap.toggleClass( 'pretty' );
|
||||
} );
|
||||
} );
|
||||
} )( jQuery );
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
|
||||
/**
|
||||
* Class Jetpack_3rd_Party_Domain_Mapping
|
||||
*
|
||||
* This class contains methods that are used to provide compatibility between Jetpack sync and domain mapping plugins.
|
||||
*/
|
||||
class Jetpack_3rd_Party_Domain_Mapping {
|
||||
|
||||
/**
|
||||
* @var Jetpack_3rd_Party_Domain_Mapping
|
||||
**/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* An array of methods that are used to hook the Jetpack sync filters for home_url and site_url to a mapping plugin.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static $test_methods = array(
|
||||
'hook_wordpress_mu_domain_mapping',
|
||||
'hook_wpmu_dev_domain_mapping'
|
||||
);
|
||||
|
||||
static function init() {
|
||||
if ( is_null( self::$instance ) ) {
|
||||
self::$instance = new Jetpack_3rd_Party_Domain_Mapping;
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
private function __construct() {
|
||||
add_action( 'plugins_loaded', array( $this, 'attempt_to_hook_domain_mapping_plugins' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called on the plugins_loaded action and will loop through the $test_methods
|
||||
* to try and hook a domain mapping plugin to the Jetpack sync filters for the home_url and site_url callables.
|
||||
*/
|
||||
function attempt_to_hook_domain_mapping_plugins() {
|
||||
if ( ! Constants::is_defined( 'SUNRISE' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$hooked = false;
|
||||
$count = count( self::$test_methods );
|
||||
for ( $i = 0; $i < $count && ! $hooked; $i++ ) {
|
||||
$hooked = call_user_func( array( $this, self::$test_methods[ $i ] ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will test for a constant and function that are known to be used with Donncha's WordPress MU
|
||||
* Domain Mapping plugin. If conditions are met, we hook the domain_mapping_siteurl() function to Jetpack sync
|
||||
* filters for home_url and site_url callables.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function hook_wordpress_mu_domain_mapping() {
|
||||
if ( ! Constants::is_defined( 'SUNRISE_LOADED' ) || ! $this->function_exists( 'domain_mapping_siteurl' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
add_filter( 'jetpack_sync_home_url', 'domain_mapping_siteurl' );
|
||||
add_filter( 'jetpack_sync_site_url', 'domain_mapping_siteurl' );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will test for a class and method known to be used in WPMU Dev's domain mapping plugin. If the
|
||||
* method exists, then we'll hook the swap_to_mapped_url() to our Jetpack sync filters for home_url and site_url.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function hook_wpmu_dev_domain_mapping() {
|
||||
if ( ! $this->class_exists( 'domain_map' ) || ! $this->method_exists( 'domain_map', 'utils' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$utils = $this->get_domain_mapping_utils_instance();
|
||||
add_filter( 'jetpack_sync_home_url', array( $utils, 'swap_to_mapped_url' ) );
|
||||
add_filter( 'jetpack_sync_site_url', array( $utils, 'swap_to_mapped_url' ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility Methods
|
||||
*
|
||||
* These methods are very minimal, and in most cases, simply pass on arguments. Why create them you ask?
|
||||
* So that we can test.
|
||||
*/
|
||||
|
||||
public function method_exists( $class, $method ) {
|
||||
return method_exists( $class, $method );
|
||||
}
|
||||
|
||||
public function class_exists( $class ) {
|
||||
return class_exists( $class );
|
||||
}
|
||||
|
||||
public function function_exists( $function ) {
|
||||
return function_exists( $function );
|
||||
}
|
||||
|
||||
public function get_domain_mapping_utils_instance() {
|
||||
return domain_map::utils();
|
||||
}
|
||||
}
|
||||
|
||||
Jetpack_3rd_Party_Domain_Mapping::init();
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
class Jetpack_Sync {
|
||||
static function sync_options() {
|
||||
_deprecated_function( __METHOD__, 'jetpack-4.2', 'jetpack_options_whitelist filter' );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
/**
|
||||
* Prevent qTranslate X from redirecting REST calls.
|
||||
*
|
||||
* @since 5.3
|
||||
*
|
||||
* @param string $url_lang Language URL to redirect to.
|
||||
* @param string $url_orig Original URL.
|
||||
* @param array $url_info Pieces of original URL.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function jetpack_no_qtranslate_rest_url_redirect( $url_lang, $url_orig, $url_info ) {
|
||||
if ( false !== strpos( $url_info['wp-path'], 'wp-json/jetpack' ) ) {
|
||||
return false;
|
||||
}
|
||||
return $url_lang;
|
||||
}
|
||||
add_filter( 'qtranslate_language_detect_redirect', 'jetpack_no_qtranslate_rest_url_redirect', 10, 3 );
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Notify user that VaultPress has been disabled. Hide VaultPress notice that requested attention.
|
||||
*
|
||||
* @since 5.8
|
||||
*/
|
||||
function jetpack_vaultpress_rewind_enabled_notice() {
|
||||
// The deactivation is performed here because there may be pages that admin_init runs on,
|
||||
// such as admin_ajax, that could deactivate the plugin without showing this notification.
|
||||
deactivate_plugins( 'vaultpress/vaultpress.php' );
|
||||
|
||||
// Remove WP core notice that says that the plugin was activated.
|
||||
if ( isset( $_GET['activate'] ) ) {
|
||||
unset( $_GET['activate'] );
|
||||
}
|
||||
?>
|
||||
<div class="notice notice-success is-dismissible vp-deactivated">
|
||||
<p style="margin-bottom: 0.25em;"><strong><?php esc_html_e( 'Jetpack is now handling your backups.', 'jetpack' ); ?></strong></p>
|
||||
<p>
|
||||
<?php esc_html_e( 'VaultPress is no longer needed and has been deactivated.', 'jetpack' ); ?>
|
||||
<?php
|
||||
echo sprintf(
|
||||
wp_kses(
|
||||
/* Translators: first variable is the URL of the web site without the protocol, e.g. mysite.com */
|
||||
__( 'You can access your backups on your site\'s <a href="https://wordpress.com/activity-log/%s" target="_blank" rel="noopener noreferrer">Activity</a> page.', 'jetpack' ),
|
||||
array(
|
||||
'a' => array(
|
||||
'href' => array(),
|
||||
'target' => array(),
|
||||
'rel' => array(),
|
||||
),
|
||||
)
|
||||
),
|
||||
esc_attr( Jetpack::build_raw_urls( get_home_url() ) )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<style>#vp-notice{display:none;}</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* If Backup & Scan is enabled, remove its entry in sidebar, deactivate VaultPress, and show a notification.
|
||||
*
|
||||
* @since 5.8
|
||||
*/
|
||||
function jetpack_vaultpress_rewind_check() {
|
||||
if ( Jetpack::is_active() &&
|
||||
Jetpack::is_plugin_active( 'vaultpress/vaultpress.php' ) &&
|
||||
Jetpack::is_rewind_enabled()
|
||||
) {
|
||||
remove_submenu_page( 'jetpack', 'vaultpress' );
|
||||
|
||||
add_action( 'admin_notices', 'jetpack_vaultpress_rewind_enabled_notice' );
|
||||
}
|
||||
}
|
||||
|
||||
add_action( 'admin_init', 'jetpack_vaultpress_rewind_check', 11 );
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs and activates the WooCommerce Services plugin.
|
||||
*/
|
||||
class WC_Services_Installer {
|
||||
|
||||
/**
|
||||
* The instance of the Jetpack class.
|
||||
*
|
||||
* @var Jetpack
|
||||
*/
|
||||
private $jetpack;
|
||||
|
||||
/**
|
||||
* The singleton instance of this class.
|
||||
*
|
||||
* @var WC_Services_Installer
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Returns the singleton instance of this class.
|
||||
*
|
||||
* @return object The WC_Services_Installer object.
|
||||
*/
|
||||
public static function init() {
|
||||
if ( is_null( self::$instance ) ) {
|
||||
self::$instance = new WC_Services_Installer();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->jetpack = Jetpack::init();
|
||||
|
||||
add_action( 'admin_init', array( $this, 'add_error_notice' ) );
|
||||
add_action( 'admin_init', array( $this, 'try_install' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the intent to install WooCommerce Services, and kick off installation.
|
||||
*/
|
||||
public function try_install() {
|
||||
if ( ! isset( $_GET['wc-services-action'] ) ) {
|
||||
return;
|
||||
}
|
||||
check_admin_referer( 'wc-services-install' );
|
||||
|
||||
$result = false;
|
||||
|
||||
switch ( $_GET['wc-services-action'] ) {
|
||||
case 'install':
|
||||
if ( current_user_can( 'install_plugins' ) ) {
|
||||
$this->jetpack->stat( 'jitm', 'wooservices-install-' . JETPACK__VERSION );
|
||||
$result = $this->install();
|
||||
if ( $result ) {
|
||||
$result = $this->activate();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'activate':
|
||||
if ( current_user_can( 'activate_plugins' ) ) {
|
||||
$this->jetpack->stat( 'jitm', 'wooservices-activate-' . JETPACK__VERSION );
|
||||
$result = $this->activate();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( isset( $_GET['redirect'] ) ) {
|
||||
$redirect = home_url( esc_url_raw( wp_unslash( $_GET['redirect'] ) ) );
|
||||
} else {
|
||||
$redirect = admin_url();
|
||||
}
|
||||
|
||||
if ( $result ) {
|
||||
$this->jetpack->stat( 'jitm', 'wooservices-activated-' . JETPACK__VERSION );
|
||||
} else {
|
||||
$redirect = add_query_arg( 'wc-services-install-error', true, $redirect );
|
||||
}
|
||||
|
||||
wp_safe_redirect( $redirect );
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up installation error admin notice.
|
||||
*/
|
||||
public function add_error_notice() {
|
||||
if ( ! empty( $_GET['wc-services-install-error'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
add_action( 'admin_notices', array( $this, 'error_notice' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the user that the installation of WooCommerce Services failed.
|
||||
*/
|
||||
public function error_notice() {
|
||||
?>
|
||||
<div class="notice notice-error is-dismissible">
|
||||
<p><?php esc_html_e( 'There was an error installing WooCommerce Services.', 'jetpack' ); ?></p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Download and install the WooCommerce Services plugin.
|
||||
*
|
||||
* @return bool result of installation
|
||||
*/
|
||||
private function install() {
|
||||
include_once ABSPATH . '/wp-admin/includes/admin.php';
|
||||
include_once ABSPATH . '/wp-admin/includes/plugin-install.php';
|
||||
include_once ABSPATH . '/wp-admin/includes/plugin.php';
|
||||
include_once ABSPATH . '/wp-admin/includes/class-wp-upgrader.php';
|
||||
include_once ABSPATH . '/wp-admin/includes/class-plugin-upgrader.php';
|
||||
|
||||
$api = plugins_api( 'plugin_information', array( 'slug' => 'woocommerce-services' ) );
|
||||
|
||||
if ( is_wp_error( $api ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$upgrader = new Plugin_Upgrader( new Automatic_Upgrader_Skin() );
|
||||
$result = $upgrader->install( $api->download_link );
|
||||
|
||||
return true === $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate the WooCommerce Services plugin.
|
||||
*
|
||||
* @return bool result of activation
|
||||
*/
|
||||
private function activate() {
|
||||
$result = activate_plugin( 'woocommerce-services/woocommerce-services.php' );
|
||||
|
||||
// Activate_plugin() returns null on success.
|
||||
return is_null( $result );
|
||||
}
|
||||
}
|
||||
|
||||
WC_Services_Installer::init();
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
/**
|
||||
* This file contains compatibility functions for WooCommerce to improve Jetpack feature support.
|
||||
*/
|
||||
add_action( 'woocommerce_init', 'jetpack_woocommerce_integration' );
|
||||
|
||||
function jetpack_woocommerce_integration() {
|
||||
/**
|
||||
* Double check WooCommerce exists - unlikely to fail due to the hook being used but better safe than sorry.
|
||||
*/
|
||||
if ( ! class_exists( 'WooCommerce' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( 'woocommerce_share', 'jetpack_woocommerce_social_share_icons', 10 );
|
||||
|
||||
/**
|
||||
* Wrap in function exists check since this requires WooCommerce 3.3+.
|
||||
*/
|
||||
if ( function_exists( 'wc_get_default_products_per_row' ) ) {
|
||||
add_filter( 'infinite_scroll_render_callbacks', 'jetpack_woocommerce_infinite_scroll_render_callback', 10 );
|
||||
add_action( 'wp_enqueue_scripts', 'jetpack_woocommerce_infinite_scroll_style', 10 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the social sharing icons show up under the product's short description
|
||||
*/
|
||||
function jetpack_woocommerce_social_share_icons() {
|
||||
if ( function_exists( 'sharing_display' ) ) {
|
||||
remove_filter( 'the_content', 'sharing_display', 19 );
|
||||
remove_filter( 'the_excerpt', 'sharing_display', 19 );
|
||||
echo sharing_display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove sharing display from account, cart, and checkout pages in WooCommerce.
|
||||
*/
|
||||
function jetpack_woocommerce_remove_share() {
|
||||
/**
|
||||
* Double check WooCommerce exists - unlikely to fail due to the hook being used but better safe than sorry.
|
||||
*/
|
||||
if ( ! class_exists( 'WooCommerce' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( is_cart() || is_checkout() || is_account_page() ) {
|
||||
remove_filter( 'the_content', 'sharing_display', 19 );
|
||||
if ( class_exists( 'Jetpack_Likes' ) ) {
|
||||
remove_filter( 'the_content', array( Jetpack_Likes::init(), 'post_likes' ), 30, 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
add_action( 'loop_start', 'jetpack_woocommerce_remove_share' );
|
||||
|
||||
/**
|
||||
* Add a callback for WooCommerce product rendering in infinite scroll.
|
||||
*
|
||||
* @param array $callbacks
|
||||
* @return array
|
||||
*/
|
||||
function jetpack_woocommerce_infinite_scroll_render_callback( $callbacks ) {
|
||||
$callbacks[] = 'jetpack_woocommerce_infinite_scroll_render';
|
||||
return $callbacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a default renderer for WooCommerce products within infinite scroll.
|
||||
*/
|
||||
function jetpack_woocommerce_infinite_scroll_render() {
|
||||
if ( ! is_shop() && ! is_product_taxonomy() && ! is_product_category() && ! is_product_tag() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
woocommerce_product_loop_start();
|
||||
|
||||
while ( have_posts() ) {
|
||||
the_post();
|
||||
wc_get_template_part( 'content', 'product' );
|
||||
}
|
||||
|
||||
woocommerce_product_loop_end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic styling when infinite scroll is active only.
|
||||
*/
|
||||
function jetpack_woocommerce_infinite_scroll_style() {
|
||||
$custom_css = "
|
||||
.infinite-scroll .woocommerce-pagination {
|
||||
display: none;
|
||||
}";
|
||||
wp_add_inline_style( 'woocommerce-layout', $custom_css );
|
||||
}
|
||||
|
||||
function jetpack_woocommerce_lazy_images_compat() {
|
||||
wp_add_inline_script( 'wc-cart-fragments', "
|
||||
jQuery( 'body' ).bind( 'wc_fragments_refreshed', function() {
|
||||
jQuery( 'body' ).trigger( 'jetpack-lazy-images-load' );
|
||||
} );
|
||||
" );
|
||||
}
|
||||
|
||||
add_action( 'wp_enqueue_scripts', 'jetpack_woocommerce_lazy_images_compat', 11 );
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
/**
|
||||
* Only load these if WPML plugin is installed and active.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Load routines only if WPML is loaded.
|
||||
*
|
||||
* @since 4.4.0
|
||||
*/
|
||||
function wpml_jetpack_init() {
|
||||
add_action( 'jetpack_widget_get_top_posts', 'wpml_jetpack_widget_get_top_posts', 10, 3 );
|
||||
add_filter( 'grunion_contact_form_field_html', 'grunion_contact_form_field_html_filter', 10, 3 );
|
||||
}
|
||||
add_action( 'wpml_loaded', 'wpml_jetpack_init' );
|
||||
|
||||
/**
|
||||
* Filter the Top Posts and Pages by language.
|
||||
*
|
||||
* @param array $posts Array of the most popular posts.
|
||||
* @param array $post_ids Array of Post IDs.
|
||||
* @param string $count Number of Top Posts we want to display.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function wpml_jetpack_widget_get_top_posts( $posts, $post_ids, $count ) {
|
||||
global $sitepress;
|
||||
|
||||
foreach ( $posts as $k => $post ) {
|
||||
$lang_information = wpml_get_language_information( $post['post_id'] );
|
||||
if ( ! is_wp_error( $lang_information ) ) {
|
||||
$post_language = substr( $lang_information['locale'], 0, 2 );
|
||||
if ( $post_language !== $sitepress->get_current_language() ) {
|
||||
unset( $posts[ $k ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the HTML of the Contact Form and output the one requested by language.
|
||||
*
|
||||
* @param string $r Contact Form HTML output.
|
||||
* @param string $field_label Field label.
|
||||
* @param int|null $id Post ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function grunion_contact_form_field_html_filter( $r, $field_label, $id ){
|
||||
global $sitepress;
|
||||
|
||||
if ( function_exists( 'icl_translate' ) ) {
|
||||
if ( $sitepress->get_current_language() !== $sitepress->get_default_language() ) {
|
||||
$label_translation = icl_translate( 'jetpack ', $field_label . '_label', $field_label );
|
||||
$r = str_replace( $field_label, $label_translation, $r );
|
||||
}
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
# Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information, such as physical or electronic addresses, without explicit permission
|
||||
* Other unethical or unprofessional conduct
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by emailing a project maintainer via [this contact form](https://developer.wordpress.com/contact/?g21-subject=Code%20of%20Conduct), with a subject that includes `Code of Conduct`. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.3.0, available at [http://contributor-covenant.org/version/1/3/0/][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/3/0/
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
var keyboardNavigation = false,
|
||||
keyboardNavigationKeycodes = [ 9, 32, 37, 38, 39, 40 ]; // keyCodes for tab, space, left, up, right, down respectively
|
||||
|
||||
document.addEventListener( 'keydown', function( event ) {
|
||||
if ( keyboardNavigation ) {
|
||||
return;
|
||||
}
|
||||
if ( keyboardNavigationKeycodes.indexOf( event.keyCode ) !== -1 ) {
|
||||
keyboardNavigation = true;
|
||||
document.documentElement.classList.add( 'accessible-focus' );
|
||||
}
|
||||
} );
|
||||
document.addEventListener( 'mouseup', function() {
|
||||
if ( ! keyboardNavigation ) {
|
||||
return;
|
||||
}
|
||||
keyboardNavigation = false;
|
||||
document.documentElement.classList.remove( 'accessible-focus' );
|
||||
} );
|
||||
|
|
@ -0,0 +1 @@
|
|||
@media (min-width:480px){.jetpack-business-hours dd,.jetpack-business-hours dt{display:inline-block}}.jetpack-business-hours dt{font-weight:700;margin-right:.5em;min-width:30%;vertical-align:top}.jetpack-business-hours dd{margin:0}@media (min-width:480px){.jetpack-business-hours dd{max-width:calc(70% - .5em)}}.jetpack-business-hours__item{margin-bottom:.5em}
|
||||
|
|
@ -0,0 +1 @@
|
|||
["wp-polyfill"]
|
||||
|
|
@ -0,0 +1 @@
|
|||
!function(e,t){for(var n in t)e[n]=t[n]}(window,function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=249)}({249:function(e,t,n){n(39),e.exports=n(250)},250:function(e,t,n){"use strict";n.r(t);n(80)},30:function(e,t,n){"object"==typeof window&&window.Jetpack_Block_Assets_Base_Url&&(n.p=window.Jetpack_Block_Assets_Base_Url)},39:function(e,t,n){"use strict";n.r(t);n(30)},80:function(e,t,n){}}));
|
||||
|
|
@ -0,0 +1 @@
|
|||
@media (min-width:480px){.jetpack-business-hours dd,.jetpack-business-hours dt{display:inline-block}}.jetpack-business-hours dt{font-weight:700;margin-left:.5em;min-width:30%;vertical-align:top}.jetpack-business-hours dd{margin:0}@media (min-width:480px){.jetpack-business-hours dd{max-width:calc(70% - .5em)}}.jetpack-business-hours__item{margin-bottom:.5em}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.jetpack-block-nudge.editor-warning{margin-bottom:0}.jetpack-block-nudge .editor-warning__message{margin:13px 0}.jetpack-block-nudge .editor-warning__actions{line-height:1}.jetpack-block-nudge .jetpack-block-nudge__info{font-size:13px;display:flex;flex-direction:row;line-height:1.4}.jetpack-block-nudge .jetpack-block-nudge__text-container{display:flex;flex-direction:column}.jetpack-block-nudge .jetpack-block-nudge__title{font-size:14px}.jetpack-block-nudge .jetpack-block-nudge__message{color:#646970}.jetpack-upgrade-nudge__icon{align-self:center;background:#dbae17;border-radius:50%;box-sizing:content-box;color:#fff;fill:#fff;flex-shrink:0;margin-right:16px;padding:6px}.block-editor-warning{border:1px solid #e2e4e7;padding:10px 14px}.block-editor-warning .block-editor-warning__message{line-height:1.4;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px}.block-editor-warning .block-editor-warning__actions .components-button{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-weight:inherit;text-decoration:none}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.jetpack-block-nudge.editor-warning{margin-bottom:0}.jetpack-block-nudge .editor-warning__message{margin:13px 0}.jetpack-block-nudge .editor-warning__actions{line-height:1}.jetpack-block-nudge .jetpack-block-nudge__info{font-size:13px;display:flex;flex-direction:row;line-height:1.4}.jetpack-block-nudge .jetpack-block-nudge__text-container{display:flex;flex-direction:column}.jetpack-block-nudge .jetpack-block-nudge__title{font-size:14px}.jetpack-block-nudge .jetpack-block-nudge__message{color:#646970}.jetpack-upgrade-nudge__icon{align-self:center;background:#dbae17;border-radius:50%;box-sizing:content-box;color:#fff;fill:#fff;flex-shrink:0;margin-left:16px;padding:6px}.block-editor-warning{border:1px solid #e2e4e7;padding:10px 14px}.block-editor-warning .block-editor-warning__message{line-height:1.4;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px}.block-editor-warning .block-editor-warning__actions .components-button{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-weight:inherit;text-decoration:none}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.wp-block-jetpack-contact-info{margin-bottom:1.5em}
|
||||
|
|
@ -0,0 +1 @@
|
|||
["wp-polyfill"]
|
||||
|
|
@ -0,0 +1 @@
|
|||
!function(e,t){for(var n in t)e[n]=t[n]}(window,function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=251)}({251:function(e,t,n){n(39),e.exports=n(252)},252:function(e,t,n){"use strict";n.r(t);n(83)},30:function(e,t,n){"object"==typeof window&&window.Jetpack_Block_Assets_Base_Url&&(n.p=window.Jetpack_Block_Assets_Base_Url)},39:function(e,t,n){"use strict";n.r(t);n(30)},83:function(e,t,n){}}));
|
||||
|
|
@ -0,0 +1 @@
|
|||
.wp-block-jetpack-contact-info{margin-bottom:1.5em}
|
||||
|
|
@ -0,0 +1 @@
|
|||
["lodash","moment","react","wp-api-fetch","wp-blob","wp-blocks","wp-components","wp-compose","wp-data","wp-date","wp-edit-post","wp-editor","wp-element","wp-escape-html","wp-hooks","wp-i18n","wp-keycodes","wp-notices","wp-plugins","wp-polyfill","wp-token-list","wp-url"]
|
||||
|
|
@ -0,0 +1 @@
|
|||
["lodash","moment","react","wp-api-fetch","wp-blob","wp-blocks","wp-components","wp-compose","wp-data","wp-date","wp-edit-post","wp-editor","wp-element","wp-escape-html","wp-hooks","wp-i18n","wp-keycodes","wp-notices","wp-plugins","wp-polyfill","wp-token-list","wp-url"]
|
||||
|
|
@ -0,0 +1 @@
|
|||
.wp-block-jetpack-gif{clear:both;margin:0 0 20px}.wp-block-jetpack-gif figure{margin:0;position:relative;width:100%}.wp-block-jetpack-gif.aligncenter{text-align:center}.wp-block-jetpack-gif.alignleft,.wp-block-jetpack-gif.alignright{min-width:300px}.wp-block-jetpack-gif .wp-block-jetpack-gif-caption{margin-top:.5em;margin-bottom:1em;color:#555d66;text-align:center}.wp-block-jetpack-gif .wp-block-jetpack-gif-wrapper{height:0;margin:0;padding:calc(56.2% + 12px) 0 0;position:relative;width:100%}.wp-block-jetpack-gif .wp-block-jetpack-gif-wrapper iframe{border:0;left:0;height:100%;position:absolute;top:0;width:100%}
|
||||
|
|
@ -0,0 +1 @@
|
|||
["wp-polyfill"]
|
||||
|
|
@ -0,0 +1 @@
|
|||
!function(e,t){for(var n in t)e[n]=t[n]}(window,function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=253)}({253:function(e,t,n){n(39),e.exports=n(254)},254:function(e,t,n){"use strict";n.r(t);n(84)},30:function(e,t,n){"object"==typeof window&&window.Jetpack_Block_Assets_Base_Url&&(n.p=window.Jetpack_Block_Assets_Base_Url)},39:function(e,t,n){"use strict";n.r(t);n(30)},84:function(e,t,n){}}));
|
||||
|
|
@ -0,0 +1 @@
|
|||
.wp-block-jetpack-gif{clear:both;margin:0 0 20px}.wp-block-jetpack-gif figure{margin:0;position:relative;width:100%}.wp-block-jetpack-gif.aligncenter{text-align:center}.wp-block-jetpack-gif.alignleft,.wp-block-jetpack-gif.alignright{min-width:300px}.wp-block-jetpack-gif .wp-block-jetpack-gif-caption{margin-top:.5em;margin-bottom:1em;color:#555d66;text-align:center}.wp-block-jetpack-gif .wp-block-jetpack-gif-wrapper{height:0;margin:0;padding:calc(56.2% + 12px) 0 0;position:relative;width:100%}.wp-block-jetpack-gif .wp-block-jetpack-gif-wrapper iframe{border:0;right:0;height:100%;position:absolute;top:0;width:100%}
|
||||
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="32px" height="38px" viewBox="0 0 32 38" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 52.1 (67048) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Oval Copy</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<path d="M119,136 C119,136 135,124.692424 135,114 C135,103.307576 127.836556,98 119,98 C110.163444,98 103,103.307576 103,114 C103,124.692424 119,136 119,136 Z" id="path-1"></path>
|
||||
<mask id="mask-2" maskContentUnits="userSpaceOnUse" maskUnits="objectBoundingBox" x="0" y="0" width="32" height="38" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
</defs>
|
||||
<g id="Map-Block" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-dasharray="4">
|
||||
<g id="Revised-01-Placeholder-Copy" transform="translate(-496.000000, -376.000000)" stroke="#444444" stroke-width="4">
|
||||
<g id="Group" transform="translate(393.000000, 278.000000)">
|
||||
<use id="Oval-Copy" mask="url(#mask-2)" xlink:href="#path-1"></use>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 38 KiB |