Query Monitor - Version 3.10.0

Version Description

Download this release

Release Info

Developer johnbillion
Plugin Icon 128x128 Query Monitor
Version 3.10.0
Comparing to
See all releases

Code changes from version 3.9.0 to 3.10.0

Files changed (66) hide show
  1. assets/icons/admin-generic.svg +3 -0
  2. assets/icons/arrow-down.svg +3 -0
  3. assets/icons/edit.svg +3 -0
  4. assets/icons/external.svg +3 -0
  5. assets/icons/filter.svg +3 -0
  6. assets/icons/image-rotate-left.svg +3 -0
  7. assets/icons/image-rotate-right.svg +3 -0
  8. assets/icons/info.svg +3 -0
  9. assets/icons/no-alt.svg +3 -0
  10. assets/icons/warning.svg +3 -0
  11. assets/icons/yes-alt.svg +5 -0
  12. assets/query-monitor.css +127 -103
  13. classes/Activation.php +1 -21
  14. classes/Backtrace.php +31 -7
  15. classes/PHP.php +21 -1
  16. classes/Plugin.php +34 -0
  17. classes/QM_DB.php +94 -0
  18. classes/QueryMonitor.php +4 -4
  19. classes/Util.php +4 -0
  20. classes/debug_bar.php +0 -2
  21. collectors/assets.php +12 -6
  22. collectors/db_dupes.php +8 -0
  23. collectors/debug_bar.php +1 -4
  24. collectors/languages.php +34 -12
  25. collectors/logger.php +5 -1
  26. collectors/overview.php +1 -1
  27. collectors/php_errors.php +14 -9
  28. collectors/raw_request.php +1 -13
  29. collectors/theme.php +38 -0
  30. composer.json +12 -4
  31. dispatchers/AJAX.php +0 -3
  32. dispatchers/Html.php +25 -10
  33. dispatchers/REST.php +0 -3
  34. dispatchers/REST_Envelope.php +0 -2
  35. dispatchers/Redirect.php +0 -3
  36. dispatchers/WP_Die.php +24 -12
  37. output/Html.php +42 -5
  38. output/html/assets.php +19 -11
  39. output/html/block_editor.php +8 -4
  40. output/html/db_callers.php +3 -1
  41. output/html/db_components.php +2 -1
  42. output/html/db_dupes.php +7 -3
  43. output/html/db_queries.php +6 -3
  44. output/html/environment.php +6 -3
  45. output/html/hooks.php +4 -2
  46. output/html/http.php +23 -18
  47. output/html/languages.php +75 -7
  48. output/html/logger.php +4 -2
  49. output/html/overview.php +35 -19
  50. output/html/php_errors.php +4 -2
  51. output/html/request.php +3 -4
  52. output/html/timing.php +3 -1
  53. output/raw/cache.php +3 -3
  54. output/raw/http.php +2 -2
  55. query-monitor.php +11 -16
  56. readme.txt +16 -27
  57. vendor/autoload.php +12 -0
  58. vendor/composer/ClassLoader.php +572 -0
  59. vendor/composer/LICENSE +21 -0
  60. vendor/composer/autoload_classmap.php +64 -0
  61. vendor/composer/autoload_namespaces.php +9 -0
  62. vendor/composer/autoload_psr4.php +9 -0
  63. vendor/composer/autoload_real.php +38 -0
  64. vendor/composer/autoload_static.php +74 -0
  65. vendor/composer/platform_check.php +26 -0
  66. wp-content/db.php +11 -94
assets/icons/admin-generic.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20">
2
+ <path d="M18 12h-2.18c-0.17 0.7-0.44 1.35-0.81 1.93l1.54 1.54-2.1 2.1-1.54-1.54c-0.58 0.36-1.23 0.63-1.91 0.79v2.18h-3v-2.18c-0.68-0.16-1.33-0.43-1.91-0.79l-1.54 1.54-2.12-2.12 1.54-1.54c-0.36-0.58-0.63-1.23-0.79-1.91h-2.18v-2.97h2.17c0.16-0.7 0.44-1.35 0.8-1.94l-1.54-1.54 2.1-2.1 1.54 1.54c0.58-0.37 1.24-0.64 1.93-0.81v-2.18h3v2.18c0.68 0.16 1.33 0.43 1.91 0.79l1.54-1.54 2.12 2.12-1.54 1.54c0.36 0.59 0.64 1.24 0.8 1.94h2.17v2.97zM9.5 13.5c1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3 1.34 3 3 3z"></path>
3
+ </svg>
assets/icons/arrow-down.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20">
2
+ <path d="M15 8l-4.030 6-3.97-6h8z"></path>
3
+ </svg>
assets/icons/edit.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20">
2
+ <path d="M13.89 3.39l2.71 2.72c0.46 0.46 0.42 1.24 0.030 1.64l-8.010 8.020-5.56 1.16 1.16-5.58s7.6-7.63 7.99-8.030c0.39-0.39 1.22-0.39 1.68 0.070zM11.16 6.18l-5.59 5.61 1.11 1.11 5.54-5.65zM8.19 14.41l5.58-5.6-1.070-1.080-5.59 5.6z"></path>
3
+ </svg>
assets/icons/external.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20">
2
+ <path d="M9 3h8v8l-2-1v-3.080l-5.6 5.59-1.41-1.41 6.090-6.1h-4.080zM12 15v-3l2-2v7h-11v-11h8l-2 2h-4v7h7z"></path>
3
+ </svg>
assets/icons/filter.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20">
2
+ <path d="M3 4.5v-2s3.34-1 7-1 7 1 7 1v2l-5 7.030v6.97s-1.22-0.090-2.25-0.59-1.75-1.41-1.75-1.41v-4.97z"></path>
3
+ </svg>
assets/icons/image-rotate-left.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20">
2
+ <path d="M7 5h-1.95c0-1.74 0.85-2.9 2.95-2.9v-2.1c-3.15 0-5.040 2.11-5.040 5h-1.78l2.62 3.39zM20 1v14h-5v5h-14v-10h9v-9h10zM18 3h-6v7h3v3h3v-10zM13 12h-10v6h10v-6z"></path>
3
+ </svg>
assets/icons/image-rotate-right.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20">
2
+ <path d="M15.95 5h-1.95l3.2 3.39 2.62-3.39h-1.78c0-2.89-1.89-5-5.040-5v2.1c2.1 0 2.95 1.16 2.95 2.9zM1 1h10v9h9v10h-14v-5h-5v-14zM3 3v10h3v-3h3v-7h-6zM8 12v6h10v-6h-10z"></path>
3
+ </svg>
assets/icons/info.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20">
2
+ <path d="M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zM11 6c0-0.55-0.45-1-1-1s-1 0.45-1 1 0.45 1 1 1 1-0.45 1-1zM11 15v-6h-2v6h2z"></path>
3
+ </svg>
assets/icons/no-alt.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20">
2
+ <path d="M14.95 6.46l-3.54 3.54 3.54 3.54-1.41 1.41-3.54-3.53-3.53 3.53-1.42-1.42 3.53-3.53-3.53-3.53 1.42-1.42 3.53 3.53 3.54-3.53z"></path>
3
+ </svg>
assets/icons/warning.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20">
2
+ <path d="M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zM11.13 11.38l0.35-6.46h-2.96l0.35 6.46h2.26zM11.040 14.74c0.24-0.23 0.37-0.55 0.37-0.96 0-0.42-0.12-0.74-0.36-0.97s-0.59-0.35-1.060-0.35-0.82 0.12-1.070 0.35-0.37 0.55-0.37 0.97c0 0.41 0.13 0.73 0.38 0.96 0.26 0.23 0.61 0.34 1.060 0.34s0.8-0.11 1.050-0.34z"></path>
3
+ </svg>
assets/icons/yes-alt.svg ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
2
+ width="20px" height="20px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
3
+ <path d="M10,2c-4.42,0-8,3.58-8,8s3.58,8,8,8s8-3.58,8-8S14.42,2,10,2z M9.385,14.66h-1.34l-3.24-4.54l1.341-1.25l2.569,2.4
4
+ l5.141-5.931l1.34,0.94L9.385,14.66z"/>
5
+ </svg>
assets/query-monitor.css CHANGED
@@ -4,9 +4,6 @@
4
  *
5
  * @package query-monitor
6
  */
7
- /* Functions */
8
- /* Fonts */
9
- /* Admin Menu */
10
  #query-monitor-main {
11
  --qm-container-fg: #444;
12
  --qm-container-bg: #f3f3f3;
@@ -506,17 +503,38 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
506
  #query-monitor-main #qm-title .qm-title-button {
507
  flex-shrink: 0 !important;
508
  }
509
- #query-monitor-main #qm-title .dashicons {
510
- transition: none !important;
 
 
511
  height: 20px !important;
512
  width: 20px !important;
 
513
  }
514
  #query-monitor-main #qm-title .qm-button-container-close {
515
  margin-right: 10px !important;
516
  }
517
- #query-monitor-main #qm-title .qm-button-container-close .dashicons {
518
- font-size: 20px !important;
519
- margin: 3px 0 3px !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
520
  }
521
  @media screen and (max-width: 960px) {
522
  #query-monitor-main #qm-title .qm-button-container-position {
@@ -525,40 +543,30 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
525
  }
526
  #query-monitor-main #qm-title button {
527
  background: var(--qm-title-button-bg) !important;
528
- color: var(--qm-title-button-fg) !important;
529
  cursor: pointer !important;
530
  display: inline-block !important;
531
- margin: 0 0 0 0px !important;
532
  min-width: auto !important;
533
- padding: 0px 4px !important;
534
  }
535
  #query-monitor-main #qm-title button:focus *,
536
  #query-monitor-main #qm-title button:hover *,
537
  #query-monitor-main #qm-title button:focus,
538
  #query-monitor-main #qm-title button:hover {
539
  background: var(--qm-title-button-bg-hover) !important;
540
- color: var(--qm-title-button-fg-hover) !important;
 
 
 
 
 
541
  }
542
  #query-monitor-main #qm-title button:active *,
543
  #query-monitor-main #qm-title button:active {
544
- /* @TODO */
545
  background: #ccc !important;
546
  }
547
- #query-monitor-main #qm-title button.qm-button-active {
548
- /* @TODO */
549
- color: #3879d9 !important;
550
- }
551
- #query-monitor-main #qm-title .qm-button-container-settings .dashicons {
552
- font-size: 17px !important;
553
- margin: 4px 0 2px !important;
554
- }
555
- #query-monitor-main #qm-title .qm-button-container-position .dashicons {
556
- font-size: 15px !important;
557
- margin: 2px -1px 3px 4px !important;
558
- transform: scaleX(-1) rotate(90deg) !important;
559
- }
560
- #query-monitor-main.qm-show-right #qm-title .qm-button-container-position .dashicons {
561
- margin: 4px 1px 0px 1px !important;
562
  transform: none !important;
563
  }
564
  #query-monitor-main .qm {
@@ -570,6 +578,7 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
570
  overflow-y: scroll !important;
571
  overscroll-behavior: contain !important;
572
  height: auto !important;
 
573
  }
574
  #query-monitor-main #qm-panel-menu ul {
575
  display: block !important;
@@ -669,8 +678,7 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
669
  display: block !important;
670
  }
671
  #query-monitor-main .qm:focus {
672
- outline: 0 !important;
673
- /* @TODO might not need this any more */
674
  }
675
  #query-monitor-main .qm-boxed {
676
  display: flex !important;
@@ -697,7 +705,7 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
697
  #query-monitor-main .qm table {
698
  border: none !important;
699
  border-collapse: collapse !important;
700
- box-shadow: 0px 1px 0px 0px var(--qm-panel-border) !important;
701
  color: var(--qm-panel-fg) !important;
702
  margin: 0 !important;
703
  table-layout: auto !important;
@@ -707,8 +715,15 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
707
  border-top: 1px solid var(--qm-cell-border) !important;
708
  margin-top: 5px !important;
709
  }
 
 
 
 
 
 
710
  #query-monitor-main .qm tr {
711
  border: none !important;
 
712
  }
713
  #query-monitor-main .qm tbody th,
714
  #query-monitor-main .qm tbody td,
@@ -727,7 +742,7 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
727
  background: var(--qm-table-header-bg) !important;
728
  border: 1px solid var(--qm-cell-border) !important;
729
  border-top: none !important;
730
- box-shadow: 0px 1px 0px var(--qm-cell-border) !important;
731
  padding: 5px !important;
732
  position: -webkit-sticky !important;
733
  position: sticky !important;
@@ -746,7 +761,7 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
746
  background: var(--qm-table-footer-bg) !important;
747
  border: none !important;
748
  bottom: 0 !important;
749
- box-shadow: inset 0px 1px 0px var(--qm-cell-border) !important;
750
  position: -webkit-sticky !important;
751
  position: sticky !important;
752
  }
@@ -866,6 +881,12 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
866
  #query-monitor-main .qm-non-tabular table {
867
  border-bottom-color: var(--qm-cell-border) !important;
868
  }
 
 
 
 
 
 
869
  #query-monitor-main #qm-conditionals li {
870
  display: inline-block !important;
871
  margin: 0 20px 5px 0 !important;
@@ -1031,6 +1052,11 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
1031
  background-color: var(--qm-warn-bg) !important;
1032
  color: var(--qm-warn-fg) !important;
1033
  }
 
 
 
 
 
1034
  #query-monitor-main .qm tbody tr th.qm-warn,
1035
  #query-monitor-main .qm tbody tr td.qm-warn,
1036
  #query-monitor-main .qm tbody tr.qm-warn td,
@@ -1038,6 +1064,12 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
1038
  background-color: var(--qm-warn-bg) !important;
1039
  color: var(--qm-warn-fg) !important;
1040
  }
 
 
 
 
 
 
1041
  #query-monitor-main .qm tbody tr.qm-odd th.qm-warn,
1042
  #query-monitor-main .qm tbody tr.qm-odd td.qm-warn,
1043
  #query-monitor-main .qm tbody tr.qm-odd.qm-warn td,
@@ -1051,6 +1083,12 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
1051
  background-color: transparent !important;
1052
  color: var(--qm-warn-fg) !important;
1053
  }
 
 
 
 
 
 
1054
  #query-monitor-main .qm .qm-notice {
1055
  background: var(--qm-panel-menu-bg-current) !important;
1056
  border: 1px solid var(--qm-panel-menu-bg-hover) !important;
@@ -1058,19 +1096,20 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
1058
  max-width: 40em !important;
1059
  padding: 10px 20px 0 !important;
1060
  }
1061
- #query-monitor-main .qm .dashicons {
1062
- font-size: 16px !important;
1063
- height: 16px !important;
1064
  margin-right: 0.3em !important;
1065
- transition: none !important;
 
1066
  width: 16px !important;
1067
  }
1068
- #query-monitor-main .qm .qm-dashicons-yes {
1069
- /* @TODO */
1070
- background-color: #0a0 !important;
1071
- border-radius: 50% !important;
1072
- /* @TODO */
1073
- color: #fff !important;
 
 
1074
  }
1075
  #query-monitor-main .qm tbody tr td.qm-highlight,
1076
  #query-monitor-main .qm tbody tr.qm-highlight th,
@@ -1131,46 +1170,28 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
1131
  color: var(--qm-link-fg-active) !important;
1132
  text-decoration: underline !important;
1133
  }
1134
- #query-monitor-main .qm a.qm-external-link:after,
1135
- #query-monitor-main .qm a.qm-link:after,
1136
- #query-monitor-main .qm a.qm-edit-link:after,
1137
- #query-monitor-main .qm button.qm-filter-info:before,
1138
- #query-monitor-main .qm button.qm-filter-trigger:after {
1139
- display: inline-block !important;
1140
- font-family: dashicons !important;
1141
- font-size: 14px !important;
1142
  left: 2px !important;
1143
- line-height: 13px !important;
1144
  position: relative !important;
1145
  text-decoration: none !important;
1146
  top: 2px !important;
1147
  visibility: hidden !important;
1148
  }
1149
- #query-monitor-main .qm button.qm-filter-info:before {
1150
- left: unset !important;
1151
- right: 2px !important;
1152
- content: "\f534" !important;
1153
- visibility: visible !important;
1154
- }
1155
- #query-monitor-main .qm a.qm-external-link:after,
1156
- #query-monitor-main .qm a.qm-link:hover:after,
1157
- #query-monitor-main .qm a.qm-link:focus:after,
1158
- #query-monitor-main .qm a.qm-edit-link:hover:after,
1159
- #query-monitor-main .qm a.qm-edit-link:focus:after,
1160
- #query-monitor-main .qm button.qm-filter-trigger:hover:after,
1161
- #query-monitor-main .qm button.qm-filter-trigger:focus:after {
1162
  visibility: visible !important;
1163
  }
1164
- #query-monitor-main .qm button.qm-filter-trigger:after {
1165
- content: "\f536" !important;
1166
- }
1167
- #query-monitor-main .qm a.qm-edit-link:after {
1168
- content: "\f464" !important;
1169
- }
1170
- #query-monitor-main .qm a.qm-external-link:after,
1171
- #query-monitor-main .qm a.qm-link:after {
1172
- content: "\f504" !important;
1173
- }
1174
  #query-monitor-main #qm-ajax-errors {
1175
  display: none;
1176
  }
@@ -1257,31 +1278,21 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
1257
  flex-shrink: 0 !important;
1258
  text-align: right !important;
1259
  }
1260
- #query-monitor-main .qm .qm-sortable-column .qm-sort-arrow {
1261
- /* @TODO */
1262
- color: #ccc !important;
1263
- display: block !important;
1264
- font-family: dashicons !important;
1265
- font-size: 23px !important;
1266
- height: 10px !important;
1267
- margin: 0 !important;
1268
- width: 16px !important;
1269
  }
1270
- #query-monitor-main .qm .qm-sortable-column .qm-sort-arrow::before {
1271
- content: "\f140" !important;
1272
- position: absolute !important;
1273
- right: 0 !important;
1274
- top: 4px !important;
1275
  }
1276
- #query-monitor-main .qm .qm-sorted-desc .qm-sort-arrow,
1277
- #query-monitor-main .qm .qm-sorted-asc .qm-sort-arrow {
1278
- color: var(--qm-container-fg) !important;
1279
  }
1280
- #query-monitor-main .qm thead th.qm-sortable-column:hover .qm-sort-arrow {
1281
- color: var(--qm-panel-menu-bg-selected) !important;
1282
  }
1283
- #query-monitor-main .qm .qm-sortable-column.qm-sorted-asc .qm-sort-arrow::before {
1284
- content: "\f142" !important;
1285
  }
1286
  #query-monitor-main .qm button:focus,
1287
  #query-monitor-main .qm a:focus,
@@ -1340,15 +1351,18 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
1340
  margin: 4px 6px 15px !important;
1341
  }
1342
  #query-monitor-main .qm.qm-debug-bar h3 {
 
1343
  clear: none !important;
1344
  float: left !important;
1345
- /* why */
1346
  font-size: 14px !important;
1347
- margin: 3px 8px 15px 0 !important;
1348
  min-width: 150px !important;
1349
- padding: 5px 10px 15px !important;
1350
  text-align: center !important;
1351
  }
 
 
 
1352
  #query-monitor-main .qm.qm-debug-bar h3 small {
1353
  font-size: 14px !important;
1354
  }
@@ -1380,6 +1394,17 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
1380
  #query-monitor-main #debug-menu-target-Debug_Bar_Rewrite_Rules_Panel .dbrr {
1381
  margin: 0 !important;
1382
  }
 
 
 
 
 
 
 
 
 
 
 
1383
  #query-monitor-main #qm-broken {
1384
  display: none !important;
1385
  }
@@ -1433,9 +1458,8 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
1433
  background: #f3f3f3 !important;
1434
  margin: 0 !important;
1435
  }
1436
- #qm-fatal .dashicons {
1437
- /* @TODO */
1438
- color: #c00 !important;
1439
  }
1440
  #qm-fatal ol,
1441
  #qm-fatal p {
@@ -1458,4 +1482,4 @@ body.admin-color-light #wp-admin-bar-query-monitor:not(.qm-all-clear):not(:hover
1458
  body#error-page #qm-fatal {
1459
  margin: 0 !important;
1460
  border: none !important;
1461
- }
4
  *
5
  * @package query-monitor
6
  */
 
 
 
7
  #query-monitor-main {
8
  --qm-container-fg: #444;
9
  --qm-container-bg: #f3f3f3;
503
  #query-monitor-main #qm-title .qm-title-button {
504
  flex-shrink: 0 !important;
505
  }
506
+ #query-monitor-main #qm-title .qm-icon {
507
+ display: inline-block !important;
508
+ }
509
+ #query-monitor-main #qm-title .qm-icon svg {
510
  height: 20px !important;
511
  width: 20px !important;
512
+ fill: var(--qm-title-button-fg) !important;
513
  }
514
  #query-monitor-main #qm-title .qm-button-container-close {
515
  margin-right: 10px !important;
516
  }
517
+ #query-monitor-main #qm-title .qm-button-container-close .qm-icon {
518
+ margin: 4px 0 0 !important;
519
+ }
520
+ #query-monitor-main #qm-title .qm-button-container-close .qm-icon svg {
521
+ width: 18px !important;
522
+ height: 18px !important;
523
+ }
524
+ #query-monitor-main #qm-title .qm-button-container-position {
525
+ transform: scaleX(-1) rotate(90deg) !important;
526
+ padding-top: 5px !important;
527
+ }
528
+ #query-monitor-main #qm-title .qm-button-container-position .qm-icon svg {
529
+ width: 14px !important;
530
+ height: 14px !important;
531
+ }
532
+ #query-monitor-main #qm-title .qm-button-container-settings .qm-icon {
533
+ margin: 4px 0 0 !important;
534
+ }
535
+ #query-monitor-main #qm-title .qm-button-container-settings .qm-icon svg {
536
+ width: 16px !important;
537
+ height: 16px !important;
538
  }
539
  @media screen and (max-width: 960px) {
540
  #query-monitor-main #qm-title .qm-button-container-position {
543
  }
544
  #query-monitor-main #qm-title button {
545
  background: var(--qm-title-button-bg) !important;
 
546
  cursor: pointer !important;
547
  display: inline-block !important;
548
+ margin: 0 !important;
549
  min-width: auto !important;
550
+ padding: 0 5px !important;
551
  }
552
  #query-monitor-main #qm-title button:focus *,
553
  #query-monitor-main #qm-title button:hover *,
554
  #query-monitor-main #qm-title button:focus,
555
  #query-monitor-main #qm-title button:hover {
556
  background: var(--qm-title-button-bg-hover) !important;
557
+ }
558
+ #query-monitor-main #qm-title button:focus * svg,
559
+ #query-monitor-main #qm-title button:hover * svg,
560
+ #query-monitor-main #qm-title button:focus svg,
561
+ #query-monitor-main #qm-title button:hover svg {
562
+ fill: var(--qm-title-button-fg-hover) !important;
563
  }
564
  #query-monitor-main #qm-title button:active *,
565
  #query-monitor-main #qm-title button:active {
 
566
  background: #ccc !important;
567
  }
568
+ #query-monitor-main.qm-show-right #qm-title .qm-button-container-position .qm-icon {
569
+ margin: 4px 1px 0 1px !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
570
  transform: none !important;
571
  }
572
  #query-monitor-main .qm {
578
  overflow-y: scroll !important;
579
  overscroll-behavior: contain !important;
580
  height: auto !important;
581
+ min-width: 160px !important;
582
  }
583
  #query-monitor-main #qm-panel-menu ul {
584
  display: block !important;
678
  display: block !important;
679
  }
680
  #query-monitor-main .qm:focus {
681
+ outline: 0 !important; /* @TODO might not need this any more */
 
682
  }
683
  #query-monitor-main .qm-boxed {
684
  display: flex !important;
705
  #query-monitor-main .qm table {
706
  border: none !important;
707
  border-collapse: collapse !important;
708
+ box-shadow: 0 1px 0 0 var(--qm-panel-border) !important;
709
  color: var(--qm-panel-fg) !important;
710
  margin: 0 !important;
711
  table-layout: auto !important;
715
  border-top: 1px solid var(--qm-cell-border) !important;
716
  margin-top: 5px !important;
717
  }
718
+ #query-monitor-main .qm thead,
719
+ #query-monitor-main .qm tbody,
720
+ #query-monitor-main .qm tfoot {
721
+ border: none !important;
722
+ background-color: inherit !important;
723
+ }
724
  #query-monitor-main .qm tr {
725
  border: none !important;
726
+ background-color: inherit !important;
727
  }
728
  #query-monitor-main .qm tbody th,
729
  #query-monitor-main .qm tbody td,
742
  background: var(--qm-table-header-bg) !important;
743
  border: 1px solid var(--qm-cell-border) !important;
744
  border-top: none !important;
745
+ box-shadow: 0 1px 0 var(--qm-cell-border) !important;
746
  padding: 5px !important;
747
  position: -webkit-sticky !important;
748
  position: sticky !important;
761
  background: var(--qm-table-footer-bg) !important;
762
  border: none !important;
763
  bottom: 0 !important;
764
+ box-shadow: inset 0 1px 0 var(--qm-cell-border) !important;
765
  position: -webkit-sticky !important;
766
  position: sticky !important;
767
  }
881
  #query-monitor-main .qm-non-tabular table {
882
  border-bottom-color: var(--qm-cell-border) !important;
883
  }
884
+ #query-monitor-main .qm-non-tabular .qm-full-width {
885
+ border-top: 1px solid var(--qm-cell-border) !important;
886
+ margin-right: -20px !important;
887
+ margin-left: -20px !important;
888
+ width: calc(100% + 40px) !important;
889
+ }
890
  #query-monitor-main #qm-conditionals li {
891
  display: inline-block !important;
892
  margin: 0 20px 5px 0 !important;
1052
  background-color: var(--qm-warn-bg) !important;
1053
  color: var(--qm-warn-fg) !important;
1054
  }
1055
+ #query-monitor-main .qm-non-tabular .qm-warn .qm-icon svg,
1056
+ #query-monitor-main .qm thead tr .qm-warn .qm-icon svg,
1057
+ #query-monitor-main .qm tbody tr .qm-warn .qm-icon svg {
1058
+ fill: var(--qm-warn-fg) !important;
1059
+ }
1060
  #query-monitor-main .qm tbody tr th.qm-warn,
1061
  #query-monitor-main .qm tbody tr td.qm-warn,
1062
  #query-monitor-main .qm tbody tr.qm-warn td,
1064
  background-color: var(--qm-warn-bg) !important;
1065
  color: var(--qm-warn-fg) !important;
1066
  }
1067
+ #query-monitor-main .qm tbody tr th.qm-warn .qm-icon svg,
1068
+ #query-monitor-main .qm tbody tr td.qm-warn .qm-icon svg,
1069
+ #query-monitor-main .qm tbody tr.qm-warn td .qm-icon svg,
1070
+ #query-monitor-main .qm tbody tr.qm-warn th .qm-icon svg {
1071
+ fill: var(--qm-warn-fg) !important;
1072
+ }
1073
  #query-monitor-main .qm tbody tr.qm-odd th.qm-warn,
1074
  #query-monitor-main .qm tbody tr.qm-odd td.qm-warn,
1075
  #query-monitor-main .qm tbody tr.qm-odd.qm-warn td,
1083
  background-color: transparent !important;
1084
  color: var(--qm-warn-fg) !important;
1085
  }
1086
+ #query-monitor-main .qm-non-tabular .qm-warn code .qm-icon svg,
1087
+ #query-monitor-main .qm tbody .qm-warn li .qm-icon svg,
1088
+ #query-monitor-main .qm tbody .qm-warn .qm-info .qm-icon svg,
1089
+ #query-monitor-main .qm tbody .qm-warn code .qm-icon svg {
1090
+ fill: var(--qm-warn-fg) !important;
1091
+ }
1092
  #query-monitor-main .qm .qm-notice {
1093
  background: var(--qm-panel-menu-bg-current) !important;
1094
  border: 1px solid var(--qm-panel-menu-bg-hover) !important;
1096
  max-width: 40em !important;
1097
  padding: 10px 20px 0 !important;
1098
  }
1099
+ #query-monitor-main .qm .qm-icon {
 
 
1100
  margin-right: 0.3em !important;
1101
+ display: inline-block !important;
1102
+ height: 16px !important;
1103
  width: 16px !important;
1104
  }
1105
+ #query-monitor-main .qm .qm-icon svg {
1106
+ height: 16px !important;
1107
+ width: 16px !important;
1108
+ fill: var(--qm-container-fg) !important;
1109
+ vertical-align: top !important;
1110
+ }
1111
+ #query-monitor-main .qm .qm-icon-yes-alt svg {
1112
+ fill: #0a0 !important;
1113
  }
1114
  #query-monitor-main .qm tbody tr td.qm-highlight,
1115
  #query-monitor-main .qm tbody tr.qm-highlight th,
1170
  color: var(--qm-link-fg-active) !important;
1171
  text-decoration: underline !important;
1172
  }
1173
+ #query-monitor-main .qm a.qm-external-link svg,
1174
+ #query-monitor-main .qm a.qm-link svg,
1175
+ #query-monitor-main .qm a.qm-edit-link svg,
1176
+ #query-monitor-main .qm button.qm-filter-trigger svg {
1177
+ fill: var(--qm-link-fg-hover) !important;
1178
+ width: 16px;
1179
+ height: 16px;
 
1180
  left: 2px !important;
 
1181
  position: relative !important;
1182
  text-decoration: none !important;
1183
  top: 2px !important;
1184
  visibility: hidden !important;
1185
  }
1186
+ #query-monitor-main .qm a.qm-external-link svg,
1187
+ #query-monitor-main .qm a.qm-link:hover svg,
1188
+ #query-monitor-main .qm a.qm-link:focus svg,
1189
+ #query-monitor-main .qm a.qm-edit-link:hover svg,
1190
+ #query-monitor-main .qm a.qm-edit-link:focus svg,
1191
+ #query-monitor-main .qm button.qm-filter-trigger:hover svg,
1192
+ #query-monitor-main .qm button.qm-filter-trigger:focus svg {
 
 
 
 
 
 
1193
  visibility: visible !important;
1194
  }
 
 
 
 
 
 
 
 
 
 
1195
  #query-monitor-main #qm-ajax-errors {
1196
  display: none;
1197
  }
1278
  flex-shrink: 0 !important;
1279
  text-align: right !important;
1280
  }
1281
+ #query-monitor-main .qm .qm-sort-controls .qm-icon {
1282
+ margin-right: 0 !important;
 
 
 
 
 
 
 
1283
  }
1284
+ #query-monitor-main .qm .qm-sort-controls svg {
1285
+ fill: #ccc !important;
 
 
 
1286
  }
1287
+ #query-monitor-main .qm .qm-sorted-desc .qm-sort-controls svg,
1288
+ #query-monitor-main .qm .qm-sorted-asc .qm-sort-controls svg {
1289
+ fill: var(--qm-container-fg) !important;
1290
  }
1291
+ #query-monitor-main .qm thead th.qm-sortable-column:hover .qm-sort-controls svg {
1292
+ fill: var(--qm-panel-menu-bg-selected) !important;
1293
  }
1294
+ #query-monitor-main .qm .qm-sortable-column.qm-sorted-asc .qm-sort-controls {
1295
+ transform: scaleY(-1) !important;
1296
  }
1297
  #query-monitor-main .qm button:focus,
1298
  #query-monitor-main .qm a:focus,
1351
  margin: 4px 6px 15px !important;
1352
  }
1353
  #query-monitor-main .qm.qm-debug-bar h3 {
1354
+ border-left: 1px solid var(--qm-panel-separator) !important;
1355
  clear: none !important;
1356
  float: left !important;
 
1357
  font-size: 14px !important;
1358
+ margin: 3px 0 15px !important;
1359
  min-width: 150px !important;
1360
+ padding: 5px 15px 15px !important;
1361
  text-align: center !important;
1362
  }
1363
+ #query-monitor-main .qm.qm-debug-bar h3:first-child {
1364
+ border-left: none !important;
1365
+ }
1366
  #query-monitor-main .qm.qm-debug-bar h3 small {
1367
  font-size: 14px !important;
1368
  }
1394
  #query-monitor-main #debug-menu-target-Debug_Bar_Rewrite_Rules_Panel .dbrr {
1395
  margin: 0 !important;
1396
  }
1397
+ #query-monitor-main #debug-menu-target-Debug_Bar_Rewrite_Testing_Panel {
1398
+ padding: 10px 0 !important;
1399
+ }
1400
+ #query-monitor-main #debug-menu-target-EP_Debug_Bar_ElasticPress li {
1401
+ border-top: 1px solid var(--qm-panel-separator) !important;
1402
+ line-height: 20px !important;
1403
+ padding: 20px 0 !important;
1404
+ }
1405
+ #query-monitor-main #debug-menu-target-EP_Debug_Bar_ElasticPress li .dashicons:hover {
1406
+ background-color: var(--qm-panel-menu-bg-hover) !important;
1407
+ }
1408
  #query-monitor-main #qm-broken {
1409
  display: none !important;
1410
  }
1458
  background: #f3f3f3 !important;
1459
  margin: 0 !important;
1460
  }
1461
+ #qm-fatal .qm-icon path {
1462
+ fill: #c00 !important;
 
1463
  }
1464
  #qm-fatal ol,
1465
  #qm-fatal p {
1482
  body#error-page #qm-fatal {
1483
  margin: 0 !important;
1484
  border: none !important;
1485
+ }
classes/Activation.php CHANGED
@@ -14,7 +14,7 @@ class QM_Activation extends QM_Plugin {
14
 
15
  # PHP version handling
16
  if ( ! QM_PHP::version_met() ) {
17
- add_action( 'all_admin_notices', array( $this, 'php_notice' ) );
18
  return;
19
  }
20
 
@@ -116,26 +116,6 @@ class QM_Activation extends QM_Plugin {
116
 
117
  }
118
 
119
- /**
120
- * @return void
121
- */
122
- public function php_notice() {
123
- ?>
124
- <div id="qm_php_notice" class="notice notice-error">
125
- <p>
126
- <?php
127
- echo esc_html( sprintf(
128
- /* Translators: 1: Minimum required PHP version, 2: Current PHP version. */
129
- __( 'The Query Monitor plugin requires PHP version %1$s or higher. This site is running version %2$s.', 'query-monitor' ),
130
- QM_PHP::$minimum_version,
131
- PHP_VERSION
132
- ) );
133
- ?>
134
- </p>
135
- </div>
136
- <?php
137
- }
138
-
139
  /**
140
  * @param string $file
141
  * @return self
14
 
15
  # PHP version handling
16
  if ( ! QM_PHP::version_met() ) {
17
+ add_action( 'all_admin_notices', 'QM_PHP::php_version_nope' );
18
  return;
19
  }
20
 
116
 
117
  }
118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  /**
120
  * @param string $file
121
  * @return self
classes/Backtrace.php CHANGED
@@ -18,10 +18,12 @@ class QM_Backtrace {
18
  protected static $ignore_class = array(
19
  'wpdb' => true,
20
  'hyperdb' => true,
 
21
  'QueryMonitor' => true,
22
  'W3_Db' => true,
23
  'Debug_Bar_PHP' => true,
24
  'WP_Hook' => true,
 
25
  );
26
 
27
  /**
@@ -66,7 +68,6 @@ class QM_Backtrace {
66
  'get_header' => 1,
67
  'get_sidebar' => 1,
68
  'get_footer' => 1,
69
- 'get_option' => 1,
70
  'update_option' => 1,
71
  'get_transient' => 1,
72
  'set_transient' => 1,
@@ -117,6 +118,11 @@ class QM_Backtrace {
117
  */
118
  protected $component = null;
119
 
 
 
 
 
 
120
  /**
121
  * @param array<string, mixed[]> $args
122
  * @param mixed[] $trace
@@ -152,6 +158,14 @@ class QM_Backtrace {
152
  }
153
  }
154
 
 
 
 
 
 
 
 
 
155
  /**
156
  * @return array<int, string>
157
  */
@@ -165,7 +179,7 @@ class QM_Backtrace {
165
  }
166
 
167
  /**
168
- * @return mixed[]
169
  */
170
  public function get_caller() {
171
 
@@ -184,8 +198,13 @@ class QM_Backtrace {
184
  }
185
 
186
  $components = array();
 
187
 
188
- foreach ( $this->get_filtered_trace() as $frame ) {
 
 
 
 
189
  $component = self::get_frame_component( $frame );
190
 
191
  if ( $component ) {
@@ -284,7 +303,12 @@ class QM_Backtrace {
284
  $lowest['display'] = $file;
285
  $lowest['id'] = $file;
286
  unset( $lowest['class'], $lowest['args'], $lowest['type'] );
287
- $trace[0] = $lowest;
 
 
 
 
 
288
  }
289
 
290
  $this->filtered_trace = $trace;
@@ -366,7 +390,7 @@ class QM_Backtrace {
366
  * @param bool[] $ignore_class Array of class names to ignore. The array keys are class names to ignore,
367
  * the array values are whether to ignore the class or not (usually true).
368
  */
369
- self::$ignore_class = apply_filters( 'qm/trace/ignore_class', self::$ignore_class );
370
 
371
  /**
372
  * Filters which class methods to ignore when constructing user-facing call stacks.
@@ -386,7 +410,7 @@ class QM_Backtrace {
386
  * @param bool[] $ignore_func Array of function names to ignore. The array keys are function names to ignore,
387
  * the array values are whether to ignore the function or not (usually true).
388
  */
389
- self::$ignore_func = apply_filters( 'qm/trace/ignore_func', self::$ignore_func );
390
 
391
  /**
392
  * Filters which action and filter names to ignore when constructing user-facing call stacks.
@@ -408,7 +432,7 @@ class QM_Backtrace {
408
  * array keys are function names, the array values are either integers or
409
  * "dir" to specifically treat the function argument as a directory path.
410
  */
411
- self::$show_args = apply_filters( 'qm/trace/show_args', self::$show_args );
412
 
413
  self::$filtered = true;
414
 
18
  protected static $ignore_class = array(
19
  'wpdb' => true,
20
  'hyperdb' => true,
21
+ 'LudicrousDB' => true,
22
  'QueryMonitor' => true,
23
  'W3_Db' => true,
24
  'Debug_Bar_PHP' => true,
25
  'WP_Hook' => true,
26
+ 'Altis\Cloud\DB' => true,
27
  );
28
 
29
  /**
68
  'get_header' => 1,
69
  'get_sidebar' => 1,
70
  'get_footer' => 1,
 
71
  'update_option' => 1,
72
  'get_transient' => 1,
73
  'set_transient' => 1,
118
  */
119
  protected $component = null;
120
 
121
+ /**
122
+ * @var mixed[]|null
123
+ */
124
+ protected $top_frame = null;
125
+
126
  /**
127
  * @param array<string, mixed[]> $args
128
  * @param mixed[] $trace
158
  }
159
  }
160
 
161
+ /**
162
+ * @param mixed[] $frame
163
+ * @return void
164
+ */
165
+ public function push_frame( array $frame ) {
166
+ $this->top_frame = $frame;
167
+ }
168
+
169
  /**
170
  * @return array<int, string>
171
  */
179
  }
180
 
181
  /**
182
+ * @return mixed[]|false
183
  */
184
  public function get_caller() {
185
 
198
  }
199
 
200
  $components = array();
201
+ $frames = $this->get_filtered_trace();
202
 
203
+ if ( $this->top_frame ) {
204
+ array_unshift( $frames, $this->top_frame );
205
+ }
206
+
207
+ foreach ( $frames as $frame ) {
208
  $component = self::get_frame_component( $frame );
209
 
210
  if ( $component ) {
303
  $lowest['display'] = $file;
304
  $lowest['id'] = $file;
305
  unset( $lowest['class'], $lowest['args'], $lowest['type'] );
306
+
307
+ // When a PHP error is triggered which doesn't have a stack trace, for example a
308
+ // deprecated error, QM will blame itself due to its error handler. This prevents that.
309
+ if ( false === strpos( $file, 'query-monitor/collectors/php_errors.php' ) ) {
310
+ $trace[0] = $lowest;
311
+ }
312
  }
313
 
314
  $this->filtered_trace = $trace;
390
  * @param bool[] $ignore_class Array of class names to ignore. The array keys are class names to ignore,
391
  * the array values are whether to ignore the class or not (usually true).
392
  */
393
+ self::$ignore_class = apply_filters( 'qm/trace/ignore_class', self::$ignore_class );
394
 
395
  /**
396
  * Filters which class methods to ignore when constructing user-facing call stacks.
410
  * @param bool[] $ignore_func Array of function names to ignore. The array keys are function names to ignore,
411
  * the array values are whether to ignore the function or not (usually true).
412
  */
413
+ self::$ignore_func = apply_filters( 'qm/trace/ignore_func', self::$ignore_func );
414
 
415
  /**
416
  * Filters which action and filter names to ignore when constructing user-facing call stacks.
432
  * array keys are function names, the array values are either integers or
433
  * "dir" to specifically treat the function argument as a directory path.
434
  */
435
+ self::$show_args = apply_filters( 'qm/trace/show_args', self::$show_args );
436
 
437
  self::$filtered = true;
438
 
classes/PHP.php CHANGED
@@ -5,12 +5,13 @@
5
  * @package query-monitor
6
  */
7
 
 
8
  class QM_PHP {
9
 
10
  /**
11
  * @var string
12
  */
13
- public static $minimum_version = '5.3.6';
14
 
15
  /**
16
  * @return bool
@@ -42,4 +43,23 @@ class QM_PHP {
42
  );
43
  }
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  }
5
  * @package query-monitor
6
  */
7
 
8
+ if ( ! class_exists( 'QM_PHP' ) ) {
9
  class QM_PHP {
10
 
11
  /**
12
  * @var string
13
  */
14
+ public static $minimum_version = '5.6.20';
15
 
16
  /**
17
  * @return bool
43
  );
44
  }
45
 
46
+ /**
47
+ * @return void
48
+ */
49
+ public static function vendor_nope() {
50
+ printf(
51
+ '<div id="qm-built-nope" class="notice notice-error"><p>%s</p></div>',
52
+ sprintf(
53
+ /* translators: 1: CLI command to run, 2: plugin directory name */
54
+ esc_html__( 'Dependencies for Query Monitor need to be installed. Run %1$s from the %2$s directory.', 'query-monitor' ),
55
+ '<code>composer install --no-dev</code>',
56
+ sprintf(
57
+ '<code>%s</code>',
58
+ esc_html( dirname( dirname( __FILE__ ) ) )
59
+ )
60
+ )
61
+ );
62
+ }
63
+
64
+ }
65
  }
classes/Plugin.php CHANGED
@@ -18,6 +18,11 @@ abstract class QM_Plugin {
18
  */
19
  public $file = '';
20
 
 
 
 
 
 
21
  /**
22
  * Class constructor
23
  *
@@ -95,5 +100,34 @@ abstract class QM_Plugin {
95
  }
96
  return $this->plugin[ $item ] . ltrim( $file, '/' );
97
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  }
99
  }
18
  */
19
  public $file = '';
20
 
21
+ /**
22
+ * @var array<string, string>
23
+ */
24
+ private $icons = array();
25
+
26
  /**
27
  * Class constructor
28
  *
100
  }
101
  return $this->plugin[ $item ] . ltrim( $file, '/' );
102
  }
103
+
104
+ /**
105
+ * @param string $name Icon name.
106
+ * @return string Icon HTML.
107
+ */
108
+ public function icon( $name ) {
109
+ if ( 'blank' === $name ) {
110
+ return '<span class="qm-icon qm-icon-blank"></span>';
111
+ }
112
+
113
+ if ( isset( $this->icons[ $name ] ) ) {
114
+ return $this->icons[ $name ];
115
+ }
116
+
117
+ $file = $this->plugin_path( "assets/icons/{$name}.svg" );
118
+
119
+ if ( ! file_exists( $file ) ) {
120
+ return '';
121
+ }
122
+
123
+ $this->icons[ $name ] = sprintf(
124
+ '<span class="qm-icon qm-icon-%1$s" aria-hidden="true">%2$s</span>',
125
+ esc_attr( $name ),
126
+ file_get_contents( $file )
127
+ );
128
+
129
+ return $this->icons[ $name ];
130
+ }
131
+
132
  }
133
  }
classes/QM_DB.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Database class used by the database dropin.
4
+ *
5
+ * @package query-monitor
6
+ */
7
+
8
+ class QM_DB extends wpdb {
9
+
10
+ /**
11
+ * @var float
12
+ */
13
+ public $time_start;
14
+
15
+ /**
16
+ * @var array<string, string|null>
17
+ */
18
+ public $qm_php_vars = array(
19
+ 'max_execution_time' => null,
20
+ 'memory_limit' => null,
21
+ 'upload_max_filesize' => null,
22
+ 'post_max_size' => null,
23
+ 'display_errors' => null,
24
+ 'log_errors' => null,
25
+ );
26
+
27
+ /**
28
+ * Class constructor
29
+ */
30
+ public function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) {
31
+
32
+ foreach ( $this->qm_php_vars as $setting => &$val ) {
33
+ $val = ini_get( $setting );
34
+ }
35
+
36
+ parent::__construct( $dbuser, $dbpassword, $dbname, $dbhost );
37
+
38
+ }
39
+
40
+ /**
41
+ * Performs a MySQL database query, using current database connection.
42
+ *
43
+ * @see wpdb::query()
44
+ *
45
+ * @param string $query Database query
46
+ * @return int|bool Boolean true for CREATE, ALTER, TRUNCATE and DROP queries. Number of rows
47
+ * affected/selected for all other queries. Boolean false on error.
48
+ */
49
+ public function query( $query ) {
50
+ if ( $this->show_errors ) {
51
+ $this->hide_errors();
52
+ }
53
+
54
+ $result = parent::query( $query );
55
+ $i = $this->num_queries - 1;
56
+
57
+ if ( did_action( 'qm/cease' ) ) {
58
+ // It's not possible to prevent the parent class from logging queries because it reads
59
+ // the `SAVEQUERIES` constant and I don't want to override more methods than necessary.
60
+ $this->queries = array();
61
+ }
62
+
63
+ if ( ! isset( $this->queries[ $i ] ) ) {
64
+ return $result;
65
+ }
66
+
67
+ $this->queries[ $i ]['trace'] = new QM_Backtrace();
68
+
69
+ if ( ! isset( $this->queries[ $i ][3] ) ) {
70
+ $this->queries[ $i ][3] = $this->time_start;
71
+ }
72
+
73
+ if ( $this->last_error ) {
74
+ $code = 'qmdb';
75
+
76
+ if ( $this->dbh instanceof mysqli ) {
77
+ $code = mysqli_errno( $this->dbh );
78
+ }
79
+
80
+ if ( is_resource( $this->dbh ) ) {
81
+ // Please do not report this code as a PHP 7 incompatibility. Observe the surrounding logic.
82
+ // phpcs:ignore
83
+ $code = mysql_errno( $this->dbh );
84
+ }
85
+
86
+ $this->queries[ $i ]['result'] = new WP_Error( $code, $this->last_error );
87
+ } else {
88
+ $this->queries[ $i ]['result'] = $result;
89
+ }
90
+
91
+ return $result;
92
+ }
93
+
94
+ }
classes/QueryMonitor.php CHANGED
@@ -212,8 +212,8 @@ class QueryMonitor extends QM_Plugin {
212
  *
213
  * @link https://wordpress.org/plugins/user-role-editor/
214
  *
215
- * @param array<string, array<string, mixed>> $groups Array of existing groups.
216
- * @return array<string, array<string, mixed>> Updated array of groups.
217
  */
218
  public function filter_ure_groups( array $groups ) {
219
  $groups['query_monitor'] = array(
@@ -230,8 +230,8 @@ class QueryMonitor extends QM_Plugin {
230
  *
231
  * @link https://wordpress.org/plugins/user-role-editor/
232
  *
233
- * @param array<string, array<string, mixed>> $caps Array of existing capabilities.
234
- * @return array<string, array<string, mixed>> Updated array of capabilities.
235
  */
236
  public function filter_ure_caps( array $caps ) {
237
  $caps['view_query_monitor'] = array(
212
  *
213
  * @link https://wordpress.org/plugins/user-role-editor/
214
  *
215
+ * @param array<string, array<string, array<string, mixed>>> $groups Array of existing groups.
216
+ * @return array<string, array<string, array<string, mixed>>> Updated array of groups.
217
  */
218
  public function filter_ure_groups( array $groups ) {
219
  $groups['query_monitor'] = array(
230
  *
231
  * @link https://wordpress.org/plugins/user-role-editor/
232
  *
233
+ * @param array<string, array<int, string>> $caps Array of existing capabilities.
234
+ * @return array<string, array<int, string>> Updated array of capabilities.
235
  */
236
  public function filter_ure_caps( array $caps ) {
237
  $caps['view_query_monitor'] = array(
classes/Util.php CHANGED
@@ -589,6 +589,10 @@ class QM_Util {
589
  * @return string A shortened version of the name.
590
  */
591
  public static function shorten_fqn( $fqn ) {
 
 
 
 
592
  return preg_replace_callback( '#\\\\[a-zA-Z0-9_\\\\]{4,}\\\\#', function( array $matches ) {
593
  preg_match_all( '#\\\\([a-zA-Z0-9_])#', $matches[0], $m );
594
  return '\\' . implode( '\\', $m[1] ) . '\\';
589
  * @return string A shortened version of the name.
590
  */
591
  public static function shorten_fqn( $fqn ) {
592
+ if ( substr_count( $fqn, '\\' ) < 3 ) {
593
+ return $fqn;
594
+ }
595
+
596
  return preg_replace_callback( '#\\\\[a-zA-Z0-9_\\\\]{4,}\\\\#', function( array $matches ) {
597
  preg_match_all( '#\\\\([a-zA-Z0-9_])#', $matches[0], $m );
598
  return '\\' . implode( '\\', $m[1] ) . '\\';
classes/debug_bar.php CHANGED
@@ -43,8 +43,6 @@ class Debug_Bar {
43
  * @return void
44
  */
45
  public function init_panels() {
46
- require_once 'debug_bar_panel.php';
47
-
48
  /**
49
  * Filters the debug bar panel list. This mimics the same filter called in the Debug Bar plugin.
50
  *
43
  * @return void
44
  */
45
  public function init_panels() {
 
 
46
  /**
47
  * Filters the debug bar panel list. This mimics the same filter called in the Debug Bar plugin.
48
  *
collectors/assets.php CHANGED
@@ -79,7 +79,6 @@ abstract class QM_Collector_Assets extends QM_Collector {
79
  $this->data['default_version'] = get_bloginfo( 'version' );
80
  $this->data['port'] = (string) parse_url( $this->data['host'], PHP_URL_PORT );
81
 
82
- $home_url = home_url();
83
  $positions = array(
84
  'missing',
85
  'broken',
@@ -169,7 +168,7 @@ abstract class QM_Collector_Assets extends QM_Collector {
169
  if ( is_wp_error( $source ) ) {
170
  $display = $source->get_error_message();
171
  } else {
172
- $display = ltrim( str_replace( "{$home_url}/", '/', remove_query_arg( 'ver', $source ) ), '/' );
173
  }
174
 
175
  $dependencies = $dependency->deps;
@@ -256,7 +255,8 @@ abstract class QM_Collector_Assets extends QM_Collector {
256
 
257
  /**
258
  * @param _WP_Dependency $dependency
259
- * @return array{
 
260
  * 0: string,
261
  * 1: string|WP_Error,
262
  * 2: bool,
@@ -267,6 +267,9 @@ abstract class QM_Collector_Assets extends QM_Collector {
267
  $data = $this->get_data();
268
  $loader = rtrim( $this->get_dependency_type(), 's' );
269
  $src = $dependency->src;
 
 
 
270
 
271
  if ( null === $dependency->ver ) {
272
  $ver = '';
@@ -281,9 +284,12 @@ abstract class QM_Collector_Assets extends QM_Collector {
281
  /** This filter is documented in wp-includes/class.wp-scripts.php */
282
  $source = apply_filters( "{$loader}_loader_src", $src, $dependency->handle );
283
 
284
- $host = (string) parse_url( $source, PHP_URL_HOST );
285
- $scheme = (string) parse_url( $source, PHP_URL_SCHEME );
286
- $port = (string) parse_url( $source, PHP_URL_PORT );
 
 
 
287
  $http_host = $data['host'];
288
  $http_port = $data['port'];
289
 
79
  $this->data['default_version'] = get_bloginfo( 'version' );
80
  $this->data['port'] = (string) parse_url( $this->data['host'], PHP_URL_PORT );
81
 
 
82
  $positions = array(
83
  'missing',
84
  'broken',
168
  if ( is_wp_error( $source ) ) {
169
  $display = $source->get_error_message();
170
  } else {
171
+ $display = ltrim( str_replace( "https://{$this->data['host']}/", '', remove_query_arg( 'ver', $source ) ), '/' );
172
  }
173
 
174
  $dependencies = $dependency->deps;
255
 
256
  /**
257
  * @param _WP_Dependency $dependency
258
+ * @return mixed[]
259
+ * @phpstan-return array{
260
  * 0: string,
261
  * 1: string|WP_Error,
262
  * 2: bool,
267
  $data = $this->get_data();
268
  $loader = rtrim( $this->get_dependency_type(), 's' );
269
  $src = $dependency->src;
270
+ $host = '';
271
+ $scheme = '';
272
+ $port = '';
273
 
274
  if ( null === $dependency->ver ) {
275
  $ver = '';
284
  /** This filter is documented in wp-includes/class.wp-scripts.php */
285
  $source = apply_filters( "{$loader}_loader_src", $src, $dependency->handle );
286
 
287
+ if ( is_string( $source ) ) {
288
+ $host = (string) parse_url( $source, PHP_URL_HOST );
289
+ $scheme = (string) parse_url( $source, PHP_URL_SCHEME );
290
+ $port = (string) parse_url( $source, PHP_URL_PORT );
291
+ }
292
+
293
  $http_host = $data['host'];
294
  $http_port = $data['port'];
295
 
collectors/db_dupes.php CHANGED
@@ -35,6 +35,7 @@ class QM_Collector_DB_Dupes extends QM_Collector {
35
  $stacks = array();
36
  $callers = array();
37
  $components = array();
 
38
 
39
  // Loop over all SQL queries that have dupes
40
  foreach ( $this->data['dupes'] as $sql => $query_ids ) {
@@ -67,6 +68,12 @@ class QM_Collector_DB_Dupes extends QM_Collector {
67
  // Populate the stack for this query
68
  $stacks[ $sql ][] = $stack;
69
 
 
 
 
 
 
 
70
  }
71
 
72
  // Get the callers which are common to all stacks for this query
@@ -91,6 +98,7 @@ class QM_Collector_DB_Dupes extends QM_Collector {
91
  $this->data['dupe_sources'] = $sources;
92
  $this->data['dupe_callers'] = $callers;
93
  $this->data['dupe_components'] = $components;
 
94
  }
95
 
96
  }
35
  $stacks = array();
36
  $callers = array();
37
  $components = array();
38
+ $times = array();
39
 
40
  // Loop over all SQL queries that have dupes
41
  foreach ( $this->data['dupes'] as $sql => $query_ids ) {
68
  // Populate the stack for this query
69
  $stacks[ $sql ][] = $stack;
70
 
71
+ // Populate the time for this query
72
+ if ( isset( $times[ $sql ] ) ) {
73
+ $times[ $sql ] += $dbq->data['dbs']['$wpdb']->rows[ $query_id ]['ltime'];
74
+ } else {
75
+ $times[ $sql ] = $dbq->data['dbs']['$wpdb']->rows[ $query_id ]['ltime'];
76
+ }
77
  }
78
 
79
  // Get the callers which are common to all stacks for this query
98
  $this->data['dupe_sources'] = $sources;
99
  $this->data['dupe_callers'] = $callers;
100
  $this->data['dupe_components'] = $components;
101
+ $this->data['dupe_times'] = $times;
102
  }
103
 
104
  }
collectors/debug_bar.php CHANGED
@@ -66,14 +66,11 @@ function register_qm_collectors_debug_bar() {
66
 
67
  global $debug_bar;
68
 
69
- if ( class_exists( 'Debug_Bar' ) || qm_debug_bar_being_activated() ) {
70
  return;
71
  }
72
 
73
  $collectors = QM_Collectors::init();
74
- $qm = QueryMonitor::init();
75
-
76
- require_once $qm->plugin_path( 'classes/debug_bar.php' );
77
 
78
  $debug_bar = new Debug_Bar();
79
  $redundant = array(
66
 
67
  global $debug_bar;
68
 
69
+ if ( class_exists( 'Debug_Bar', false ) || qm_debug_bar_being_activated() ) {
70
  return;
71
  }
72
 
73
  $collectors = QM_Collectors::init();
 
 
 
74
 
75
  $debug_bar = new Debug_Bar();
76
  $redundant = array(
collectors/languages.php CHANGED
@@ -20,8 +20,9 @@ class QM_Collector_Languages extends QM_Collector {
20
 
21
  parent::set_up();
22
 
23
- add_filter( 'override_load_textdomain', array( $this, 'log_file_load' ), 9999, 3 );
24
  add_filter( 'load_script_translation_file', array( $this, 'log_script_file_load' ), 9999, 3 );
 
25
 
26
  }
27
 
@@ -29,12 +30,31 @@ class QM_Collector_Languages extends QM_Collector {
29
  * @return void
30
  */
31
  public function tear_down() {
32
- remove_filter( 'override_load_textdomain', array( $this, 'log_file_load' ), 9999 );
33
  remove_filter( 'load_script_translation_file', array( $this, 'log_script_file_load' ), 9999 );
 
34
 
35
  parent::tear_down();
36
  }
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  /**
39
  * @return array<int, string>
40
  */
@@ -53,6 +73,7 @@ class QM_Collector_Languages extends QM_Collector {
53
  'determine_locale',
54
  'gettext',
55
  'gettext_with_context',
 
56
  'load_script_textdomain_relative_path',
57
  'load_script_translation_file',
58
  'load_script_translations',
@@ -95,13 +116,15 @@ class QM_Collector_Languages extends QM_Collector {
95
  return;
96
  }
97
 
98
- $this->data['locale'] = get_locale();
99
- $this->data['user_locale'] = function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale();
100
  ksort( $this->data['languages'] );
101
 
102
  foreach ( $this->data['languages'] as & $mofiles ) {
103
  foreach ( $mofiles as & $mofile ) {
104
- $mofile['found_formatted'] = $mofile['found'] ? size_format( $mofile['found'] ) : '';
 
 
105
  }
106
  }
107
  }
@@ -109,14 +132,13 @@ class QM_Collector_Languages extends QM_Collector {
109
  /**
110
  * Store log data.
111
  *
112
- * @param bool $override Whether to override the text domain. Default false.
113
- * @param string $domain Text domain. Unique identifier for retrieving translated strings.
114
- * @param string $mofile Path to the MO file.
115
- * @return bool
116
  */
117
- public function log_file_load( $override, $domain, $mofile ) {
118
  if ( 'query-monitor' === $domain && self::hide_qm() ) {
119
- return $override;
120
  }
121
 
122
  $trace = new QM_Backtrace( array(
@@ -144,7 +166,7 @@ class QM_Collector_Languages extends QM_Collector {
144
  'type' => 'gettext',
145
  );
146
 
147
- return $override;
148
 
149
  }
150
 
20
 
21
  parent::set_up();
22
 
23
+ add_filter( 'load_textdomain_mofile', array( $this, 'log_file_load' ), 9999, 2 );
24
  add_filter( 'load_script_translation_file', array( $this, 'log_script_file_load' ), 9999, 3 );
25
+ add_filter( 'init', array( $this, 'collect_locale_data' ), 9999 );
26
 
27
  }
28
 
30
  * @return void
31
  */
32
  public function tear_down() {
33
+ remove_filter( 'load_textdomain_mofile', array( $this, 'log_file_load' ), 9999 );
34
  remove_filter( 'load_script_translation_file', array( $this, 'log_script_file_load' ), 9999 );
35
+ remove_filter( 'init', array( $this, 'collect_locale_data' ), 9999 );
36
 
37
  parent::tear_down();
38
  }
39
 
40
+ /**
41
+ * @return void
42
+ */
43
+ public function collect_locale_data() {
44
+ $this->data['locale'] = get_locale();
45
+ $this->data['user_locale'] = function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale();
46
+ $this->data['determined_locale'] = function_exists( 'determine_locale' ) ? determine_locale() : get_locale();
47
+ $this->data['language_attributes'] = get_language_attributes();
48
+
49
+ if ( function_exists( '\Inpsyde\MultilingualPress\siteLanguageTag' ) ) {
50
+ $this->data['mlp_language'] = \Inpsyde\MultilingualPress\siteLanguageTag();
51
+ }
52
+
53
+ if ( function_exists( 'pll_current_language' ) ) {
54
+ $this->data['pll_language'] = pll_current_language();
55
+ }
56
+ }
57
+
58
  /**
59
  * @return array<int, string>
60
  */
73
  'determine_locale',
74
  'gettext',
75
  'gettext_with_context',
76
+ 'language_attributes',
77
  'load_script_textdomain_relative_path',
78
  'load_script_translation_file',
79
  'load_script_translations',
116
  return;
117
  }
118
 
119
+ $this->data['total_size'] = 0;
120
+
121
  ksort( $this->data['languages'] );
122
 
123
  foreach ( $this->data['languages'] as & $mofiles ) {
124
  foreach ( $mofiles as & $mofile ) {
125
+ if ( $mofile['found'] ) {
126
+ $this->data['total_size'] += $mofile['found'];
127
+ }
128
  }
129
  }
130
  }
132
  /**
133
  * Store log data.
134
  *
135
+ * @param string $mofile Path to the MO file.
136
+ * @param string $domain Text domain.
137
+ * @return string
 
138
  */
139
+ public function log_file_load( $mofile, $domain ) {
140
  if ( 'query-monitor' === $domain && self::hide_qm() ) {
141
+ return $mofile;
142
  }
143
 
144
  $trace = new QM_Backtrace( array(
166
  'type' => 'gettext',
167
  );
168
 
169
+ return $mofile;
170
 
171
  }
172
 
collectors/logger.php CHANGED
@@ -160,7 +160,11 @@ class QM_Collector_Logger extends QM_Collector {
160
  }
161
 
162
  if ( ( $message instanceof Exception ) || ( $message instanceof Throwable ) ) {
163
- $message = get_class( $message ) . ': ' . $message->getMessage();
 
 
 
 
164
  }
165
 
166
  if ( ! QM_Util::is_stringy( $message ) ) {
160
  }
161
 
162
  if ( ( $message instanceof Exception ) || ( $message instanceof Throwable ) ) {
163
+ $message = sprintf(
164
+ '%1$s: %2$s',
165
+ get_class( $message ),
166
+ $message->getMessage()
167
+ );
168
  }
169
 
170
  if ( ! QM_Util::is_stringy( $message ) ) {
collectors/overview.php CHANGED
@@ -57,7 +57,7 @@ class QM_Collector_Overview extends QM_Collector {
57
  $this->process_timing();
58
  }
59
 
60
- $this->data['time_limit'] = ini_get( 'max_execution_time' );
61
  $this->data['time_start'] = $GLOBALS['timestart'];
62
 
63
  if ( ! empty( $this->data['time_limit'] ) ) {
57
  $this->process_timing();
58
  }
59
 
60
+ $this->data['time_limit'] = (int) ini_get( 'max_execution_time' );
61
  $this->data['time_start'] = $GLOBALS['timestart'];
62
 
63
  if ( ! empty( $this->data['time_limit'] ) ) {
collectors/php_errors.php CHANGED
@@ -240,8 +240,17 @@ class QM_Collector_PHP_Errors extends QM_Collector {
240
  }
241
 
242
  $trace = new QM_Backtrace();
 
 
 
 
243
  $caller = $trace->get_caller();
244
- $key = md5( $message . $file . $line . $caller['id'] );
 
 
 
 
 
245
 
246
  if ( isset( $this->data[ $error_group ][ $type ][ $key ] ) ) {
247
  $this->data[ $error_group ][ $type ][ $key ]['calls']++;
@@ -320,17 +329,10 @@ class QM_Collector_PHP_Errors extends QM_Collector {
320
  wp_load_translations_early();
321
  }
322
 
323
- require_once dirname( __DIR__ ) . '/output/Html.php';
324
-
325
  // This hides the subsequent message from the fatal error handler in core. It cannot be
326
  // disabled by a plugin so we'll just hide its output.
327
  echo '<style type="text/css"> .wp-die-message { display: none; } </style>';
328
 
329
- printf(
330
- // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
331
- '<link rel="stylesheet" href="%s" media="all" />',
332
- esc_url( includes_url( 'css/dashicons.css' ) )
333
- );
334
  printf(
335
  // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
336
  '<link rel="stylesheet" href="%s" media="all" />',
@@ -356,8 +358,11 @@ class QM_Collector_PHP_Errors extends QM_Collector {
356
  $file = esc_html( $e['file'] );
357
  }
358
 
 
 
359
  printf(
360
- '<p><span class="dashicons dashicons-warning" aria-hidden="true"></span> <b>%1$s</b>: %2$s<br>in <b>%3$s</b> on line <b>%4$d</b></p>',
 
361
  esc_html( $error ),
362
  nl2br( esc_html( $e['message'] ), false ),
363
  $file,
240
  }
241
 
242
  $trace = new QM_Backtrace();
243
+ $trace->push_frame( array(
244
+ 'file' => $file,
245
+ 'line' => $line,
246
+ ) );
247
  $caller = $trace->get_caller();
248
+
249
+ if ( $caller ) {
250
+ $key = md5( $message . $file . $line . $caller['id'] );
251
+ } else {
252
+ $key = md5( $message . $file . $line );
253
+ }
254
 
255
  if ( isset( $this->data[ $error_group ][ $type ][ $key ] ) ) {
256
  $this->data[ $error_group ][ $type ][ $key ]['calls']++;
329
  wp_load_translations_early();
330
  }
331
 
 
 
332
  // This hides the subsequent message from the fatal error handler in core. It cannot be
333
  // disabled by a plugin so we'll just hide its output.
334
  echo '<style type="text/css"> .wp-die-message { display: none; } </style>';
335
 
 
 
 
 
 
336
  printf(
337
  // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
338
  '<link rel="stylesheet" href="%s" media="all" />',
358
  $file = esc_html( $e['file'] );
359
  }
360
 
361
+ $warning = QueryMonitor::init()->icon( 'warning' );
362
+
363
  printf(
364
+ '<p>%1$s <b>%2$s</b>: %3$s<br>in <b>%4$s</b> on line <b>%5$d</b></p>',
365
+ $warning,
366
  esc_html( $error ),
367
  nl2br( esc_html( $e['message'] ), false ),
368
  $file,
collectors/raw_request.php CHANGED
@@ -69,24 +69,12 @@ class QM_Collector_Raw_Request extends QM_Collector {
69
  ksort( $headers );
70
 
71
  $response = array(
72
- 'status' => self::http_response_code(),
73
  'headers' => $headers,
74
  );
75
 
76
  $this->data['response'] = $response;
77
  }
78
-
79
- /**
80
- * @return int|bool|null
81
- */
82
- public static function http_response_code() {
83
- if ( function_exists( 'http_response_code' ) ) {
84
- // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.http_response_codeFound
85
- return http_response_code();
86
- }
87
-
88
- return null;
89
- }
90
  }
91
 
92
  /**
69
  ksort( $headers );
70
 
71
  $response = array(
72
+ 'status' => http_response_code(),
73
  'headers' => $headers,
74
  );
75
 
76
  $this->data['response'] = $response;
77
  }
 
 
 
 
 
 
 
 
 
 
 
 
78
  }
79
 
80
  /**
collectors/theme.php CHANGED
@@ -31,6 +31,9 @@ class QM_Collector_Theme extends QM_Collector {
31
  add_filter( 'timber/output', array( $this, 'filter_timber_output' ), 9999, 3 );
32
  add_action( 'template_redirect', array( $this, 'action_template_redirect' ) );
33
  add_action( 'get_template_part', array( $this, 'action_get_template_part' ), 10, 3 );
 
 
 
34
  add_action( 'render_block_core_template_part_post', array( $this, 'action_render_block_core_template_part_post' ), 10, 3 );
35
  add_action( 'render_block_core_template_part_file', array( $this, 'action_render_block_core_template_part_file' ), 10, 3 );
36
  add_action( 'render_block_core_template_part_none', array( $this, 'action_render_block_core_template_part_none' ), 10, 3 );
@@ -44,6 +47,9 @@ class QM_Collector_Theme extends QM_Collector {
44
  remove_filter( 'timber/output', array( $this, 'filter_timber_output' ), 9999 );
45
  remove_action( 'template_redirect', array( $this, 'action_template_redirect' ) );
46
  remove_action( 'get_template_part', array( $this, 'action_get_template_part' ), 10 );
 
 
 
47
  remove_action( 'render_block_core_template_part_post', array( $this, 'action_render_block_core_template_part_post' ), 10 );
48
  remove_action( 'render_block_core_template_part_file', array( $this, 'action_render_block_core_template_part_file' ), 10 );
49
  remove_action( 'render_block_core_template_part_none', array( $this, 'action_render_block_core_template_part_none' ), 10 );
@@ -51,6 +57,38 @@ class QM_Collector_Theme extends QM_Collector {
51
  parent::tear_down();
52
  }
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  /**
55
  * @return array<int, string>
56
  */
31
  add_filter( 'timber/output', array( $this, 'filter_timber_output' ), 9999, 3 );
32
  add_action( 'template_redirect', array( $this, 'action_template_redirect' ) );
33
  add_action( 'get_template_part', array( $this, 'action_get_template_part' ), 10, 3 );
34
+ add_action( 'get_header', array( $this, 'action_get_position' ) );
35
+ add_action( 'get_sidebar', array( $this, 'action_get_position' ) );
36
+ add_action( 'get_footer', array( $this, 'action_get_position' ) );
37
  add_action( 'render_block_core_template_part_post', array( $this, 'action_render_block_core_template_part_post' ), 10, 3 );
38
  add_action( 'render_block_core_template_part_file', array( $this, 'action_render_block_core_template_part_file' ), 10, 3 );
39
  add_action( 'render_block_core_template_part_none', array( $this, 'action_render_block_core_template_part_none' ), 10, 3 );
47
  remove_filter( 'timber/output', array( $this, 'filter_timber_output' ), 9999 );
48
  remove_action( 'template_redirect', array( $this, 'action_template_redirect' ) );
49
  remove_action( 'get_template_part', array( $this, 'action_get_template_part' ), 10 );
50
+ remove_action( 'get_header', array( $this, 'action_get_position' ) );
51
+ remove_action( 'get_sidebar', array( $this, 'action_get_position' ) );
52
+ remove_action( 'get_footer', array( $this, 'action_get_position' ) );
53
  remove_action( 'render_block_core_template_part_post', array( $this, 'action_render_block_core_template_part_post' ), 10 );
54
  remove_action( 'render_block_core_template_part_file', array( $this, 'action_render_block_core_template_part_file' ), 10 );
55
  remove_action( 'render_block_core_template_part_none', array( $this, 'action_render_block_core_template_part_none' ), 10 );
57
  parent::tear_down();
58
  }
59
 
60
+ /**
61
+ * Fires before the header/sidebar/footer template file is loaded.
62
+ *
63
+ * @param string|null $name Name of the specific file to use. Null for the default.
64
+ * @return void
65
+ */
66
+ public function action_get_position( $name ) {
67
+ $filter = current_filter();
68
+ $trace = new QM_Backtrace( array(
69
+ 'ignore_hook' => array(
70
+ $filter => true,
71
+ ),
72
+ ) );
73
+
74
+ $position = str_replace( 'get_', '', $filter );
75
+ $templates = array();
76
+ if ( '' !== (string) $name ) {
77
+ $templates[] = "{$position}-{$name}.php";
78
+ }
79
+
80
+ $templates[] = "{$position}.php";
81
+
82
+ $data = array(
83
+ 'slug' => $position,
84
+ 'name' => $name,
85
+ 'templates' => $templates,
86
+ 'caller' => $trace->get_caller(),
87
+ );
88
+
89
+ $this->data['requested_template_parts'][] = $data;
90
+ }
91
+
92
  /**
93
  * @return array<int, string>
94
  */
composer.json CHANGED
@@ -11,7 +11,7 @@
11
  }
12
  ],
13
  "require": {
14
- "php": ">=5.3.6",
15
  "composer/installers": "~1.0"
16
  },
17
  "require-dev": {
@@ -43,33 +43,41 @@
43
  },
44
  "scripts": {
45
  "test": [
 
46
  "@test:phpstan",
47
  "@test:cs",
48
  "@test:integration",
49
  "@test:acceptance"
50
  ],
51
  "test:cs": [
 
52
  "phpcs -nps --colors --report-code --report-width=80 --cache=tests/cache/phpcs --basepath='./' ."
53
  ],
54
  "test:phpstan": [
55
  "codecept build",
56
- "phpstan analyze"
57
  ],
58
  "test:integration": [
59
  "bin/integration-tests.sh"
60
  ],
61
  "test:start": [
62
- "[[ `uname -m` = \"arm64\" ]] && export CHROME_IMAGE=\"seleniarm/standalone-chromium\"; docker-compose up -d"
63
  ],
64
  "test:acceptance": [
65
  "npm run build",
66
  "bin/acceptance-tests.sh"
67
  ],
68
  "test:stop": [
69
- "[[ `uname -m` = \"arm64\" ]] && export CHROME_IMAGE=\"seleniarm/standalone-chromium\"; docker-compose down"
70
  ]
71
  },
72
  "autoload": {
 
 
 
 
 
 
73
  "psr-4": {
74
  "QM\\Tests\\": "tests/integration"
75
  }
11
  }
12
  ],
13
  "require": {
14
+ "php": ">=5.6.20",
15
  "composer/installers": "~1.0"
16
  },
17
  "require-dev": {
43
  },
44
  "scripts": {
45
  "test": [
46
+ "composer validate --strict",
47
  "@test:phpstan",
48
  "@test:cs",
49
  "@test:integration",
50
  "@test:acceptance"
51
  ],
52
  "test:cs": [
53
+ "phpcs -nps --colors --report-code --report-width=80 --cache=tests/cache/phpcs --basepath='./' --standard=phpcs53.xml",
54
  "phpcs -nps --colors --report-code --report-width=80 --cache=tests/cache/phpcs --basepath='./' ."
55
  ],
56
  "test:phpstan": [
57
  "codecept build",
58
+ "phpstan analyze --memory-limit=1024M"
59
  ],
60
  "test:integration": [
61
  "bin/integration-tests.sh"
62
  ],
63
  "test:start": [
64
+ "docker-compose up -d"
65
  ],
66
  "test:acceptance": [
67
  "npm run build",
68
  "bin/acceptance-tests.sh"
69
  ],
70
  "test:stop": [
71
+ "docker-compose down"
72
  ]
73
  },
74
  "autoload": {
75
+ "classmap": [
76
+ "classes",
77
+ "output"
78
+ ]
79
+ },
80
+ "autoload-dev": {
81
  "psr-4": {
82
  "QM\\Tests\\": "tests/integration"
83
  }
dispatchers/AJAX.php CHANGED
@@ -62,9 +62,6 @@ class QM_Dispatcher_AJAX extends QM_Dispatcher {
62
  * @return void
63
  */
64
  protected function before_output() {
65
-
66
- require_once $this->qm->plugin_path( 'output/Headers.php' );
67
-
68
  foreach ( glob( $this->qm->plugin_path( 'output/headers/*.php' ) ) as $file ) {
69
  require_once $file;
70
  }
62
  * @return void
63
  */
64
  protected function before_output() {
 
 
 
65
  foreach ( glob( $this->qm->plugin_path( 'output/headers/*.php' ) ) as $file ) {
66
  require_once $file;
67
  }
dispatchers/Html.php CHANGED
@@ -46,7 +46,7 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
46
  add_action( 'wp_ajax_qm_editor_set', array( $this, 'ajax_editor_set' ) );
47
  add_action( 'wp_ajax_nopriv_qm_auth_off', array( $this, 'ajax_off' ) );
48
 
49
- add_action( 'shutdown', array( $this, 'dispatch' ), 0 );
50
 
51
  add_action( 'wp_footer', array( $this, 'action_footer' ) );
52
  add_action( 'admin_footer', array( $this, 'action_footer' ) );
@@ -170,6 +170,7 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
170
 
171
  if ( ! file_exists( $this->qm->plugin_path( 'assets/query-monitor.css' ) ) ) {
172
  add_action( 'admin_notices', array( $this, 'build_warning' ) );
 
173
  }
174
 
175
  add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ), -9999 );
@@ -229,7 +230,7 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
229
  wp_enqueue_style(
230
  'query-monitor',
231
  $this->qm->plugin_url( 'assets/query-monitor.css' ),
232
- array( 'dashicons' ),
233
  $this->qm->plugin_ver( 'assets/query-monitor.css' )
234
  );
235
  wp_enqueue_script(
@@ -337,9 +338,6 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
337
  * @return void
338
  */
339
  protected function before_output() {
340
-
341
- require_once $this->qm->plugin_path( 'output/Html.php' );
342
-
343
  foreach ( glob( $this->qm->plugin_path( 'output/html/*.php' ) ) as $file ) {
344
  require_once $file;
345
  }
@@ -444,10 +442,17 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
444
 
445
  echo '</select>';
446
 
 
 
 
 
447
  echo '</div>';
448
- echo '<button class="qm-title-button qm-button-container-settings" aria-label="' . esc_attr__( 'Settings', 'query-monitor' ) . '"><span class="dashicons dashicons-admin-generic" aria-hidden="true"></span></button>';
449
- echo '<button class="qm-title-button qm-button-container-position" aria-label="' . esc_html__( 'Toggle panel position', 'query-monitor' ) . '"><span class="dashicons dashicons-image-rotate-left" aria-hidden="true"></span></button>';
450
- echo '<button class="qm-title-button qm-button-container-close" aria-label="' . esc_attr__( 'Close Panel', 'query-monitor' ) . '"><span class="dashicons dashicons-no-alt" aria-hidden="true"></span></button>';
 
 
 
451
  echo '</div>'; // #qm-title
452
 
453
  echo '<div id="qm-wrapper">';
@@ -518,7 +523,10 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
518
 
519
  echo '<p><button class="qm-auth qm-button" data-qm-text-on="' . esc_attr( $text['on'] ) . '" data-qm-text-off="' . esc_attr( $text['off'] ) . '">' . esc_html( $text[ $state ] ) . '</button></p>';
520
 
521
- echo '<p data-qm-state-visibility="on"><span class="dashicons dashicons-yes qm-dashicons-yes"></span> ' . esc_html__( 'Authentication cookie is set', 'query-monitor' ) . '</p>';
 
 
 
522
 
523
  echo '</section>';
524
 
@@ -549,7 +557,6 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
549
  echo '</p><p>';
550
  echo '<button class="qm-editor-button qm-button">' . esc_html__( 'Set editor cookie', 'query-monitor' ) . '</button>';
551
  echo '</p>';
552
- echo '<p id="qm-editor-save-status"><span class="dashicons dashicons-yes qm-dashicons-yes"></span> ' . esc_html__( 'Saved! Reload to apply changes.', 'query-monitor' ) . '</p>';
553
  echo '</section>';
554
 
555
  echo '<section>';
@@ -563,6 +570,10 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
563
  echo '<li><label><input type="radio" class="qm-theme-toggle qm-radio" name="qm-theme" value="dark"/>' . esc_html_x( 'Dark', 'colour scheme', 'query-monitor' ) . '</label></li>';
564
  echo '</ul>';
565
 
 
 
 
 
566
  echo '</section>';
567
  echo '</div>';
568
 
@@ -834,6 +845,10 @@ class QM_Dispatcher_Html extends QM_Dispatcher {
834
  return false;
835
  }
836
 
 
 
 
 
837
  return true;
838
 
839
  }
46
  add_action( 'wp_ajax_qm_editor_set', array( $this, 'ajax_editor_set' ) );
47
  add_action( 'wp_ajax_nopriv_qm_auth_off', array( $this, 'ajax_off' ) );
48
 
49
+ add_action( 'shutdown', array( $this, 'dispatch' ), PHP_INT_MAX );
50
 
51
  add_action( 'wp_footer', array( $this, 'action_footer' ) );
52
  add_action( 'admin_footer', array( $this, 'action_footer' ) );
170
 
171
  if ( ! file_exists( $this->qm->plugin_path( 'assets/query-monitor.css' ) ) ) {
172
  add_action( 'admin_notices', array( $this, 'build_warning' ) );
173
+ return;
174
  }
175
 
176
  add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ), -9999 );
230
  wp_enqueue_style(
231
  'query-monitor',
232
  $this->qm->plugin_url( 'assets/query-monitor.css' ),
233
+ array(),
234
  $this->qm->plugin_ver( 'assets/query-monitor.css' )
235
  );
236
  wp_enqueue_script(
338
  * @return void
339
  */
340
  protected function before_output() {
 
 
 
341
  foreach ( glob( $this->qm->plugin_path( 'output/html/*.php' ) ) as $file ) {
342
  require_once $file;
343
  }
442
 
443
  echo '</select>';
444
 
445
+ $settings = QueryMonitor::init()->icon( 'admin-generic' );
446
+ $toggle = QueryMonitor::init()->icon( 'image-rotate-left' );
447
+ $close = QueryMonitor::init()->icon( 'no-alt' );
448
+
449
  echo '</div>';
450
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
451
+ echo '<button class="qm-title-button qm-button-container-settings" aria-label="' . esc_attr__( 'Settings', 'query-monitor' ) . '">' . $settings . '</button>';
452
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
453
+ echo '<button class="qm-title-button qm-button-container-position" aria-label="' . esc_html__( 'Toggle panel position', 'query-monitor' ) . '">' . $toggle . '</button>';
454
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
455
+ echo '<button class="qm-title-button qm-button-container-close" aria-label="' . esc_attr__( 'Close Panel', 'query-monitor' ) . '">' . $close . '</button>';
456
  echo '</div>'; // #qm-title
457
 
458
  echo '<div id="qm-wrapper">';
523
 
524
  echo '<p><button class="qm-auth qm-button" data-qm-text-on="' . esc_attr( $text['on'] ) . '" data-qm-text-off="' . esc_attr( $text['off'] ) . '">' . esc_html( $text[ $state ] ) . '</button></p>';
525
 
526
+ $yes = QueryMonitor::init()->icon( 'yes-alt' );
527
+
528
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
529
+ echo '<p data-qm-state-visibility="on">' . $yes . ' ' . esc_html__( 'Authentication cookie is set', 'query-monitor' ) . '</p>';
530
 
531
  echo '</section>';
532
 
557
  echo '</p><p>';
558
  echo '<button class="qm-editor-button qm-button">' . esc_html__( 'Set editor cookie', 'query-monitor' ) . '</button>';
559
  echo '</p>';
 
560
  echo '</section>';
561
 
562
  echo '<section>';
570
  echo '<li><label><input type="radio" class="qm-theme-toggle qm-radio" name="qm-theme" value="dark"/>' . esc_html_x( 'Dark', 'colour scheme', 'query-monitor' ) . '</label></li>';
571
  echo '</ul>';
572
 
573
+ $yes = QueryMonitor::init()->icon( 'yes-alt' );
574
+
575
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
576
+ echo '<p id="qm-editor-save-status">' . $yes . ' ' . esc_html__( 'Saved! Reload to apply changes.', 'query-monitor' ) . '</p>';
577
  echo '</section>';
578
  echo '</div>';
579
 
845
  return false;
846
  }
847
 
848
+ if ( ! file_exists( $this->qm->plugin_path( 'assets/query-monitor.css' ) ) ) {
849
+ return false;
850
+ }
851
+
852
  return true;
853
 
854
  }
dispatchers/REST.php CHANGED
@@ -51,9 +51,6 @@ class QM_Dispatcher_REST extends QM_Dispatcher {
51
  * @return void
52
  */
53
  protected function before_output() {
54
-
55
- require_once $this->qm->plugin_path( 'output/Headers.php' );
56
-
57
  foreach ( glob( $this->qm->plugin_path( 'output/headers/*.php' ) ) as $file ) {
58
  include_once $file;
59
  }
51
  * @return void
52
  */
53
  protected function before_output() {
 
 
 
54
  foreach ( glob( $this->qm->plugin_path( 'output/headers/*.php' ) ) as $file ) {
55
  include_once $file;
56
  }
dispatchers/REST_Envelope.php CHANGED
@@ -47,8 +47,6 @@ class QM_Dispatcher_REST_Envelope extends QM_Dispatcher {
47
  * @return void
48
  */
49
  protected function before_output() {
50
- require_once $this->qm->plugin_path( 'output/Raw.php' );
51
-
52
  foreach ( glob( $this->qm->plugin_path( 'output/raw/*.php' ) ) as $file ) {
53
  include_once $file;
54
  }
47
  * @return void
48
  */
49
  protected function before_output() {
 
 
50
  foreach ( glob( $this->qm->plugin_path( 'output/raw/*.php' ) ) as $file ) {
51
  include_once $file;
52
  }
dispatchers/Redirect.php CHANGED
@@ -50,9 +50,6 @@ class QM_Dispatcher_Redirect extends QM_Dispatcher {
50
  * @return void
51
  */
52
  protected function before_output() {
53
-
54
- require_once $this->qm->plugin_path( 'output/Headers.php' );
55
-
56
  foreach ( glob( $this->qm->plugin_path( 'output/headers/*.php' ) ) as $file ) {
57
  require_once $file;
58
  }
50
  * @return void
51
  */
52
  protected function before_output() {
 
 
 
53
  foreach ( glob( $this->qm->plugin_path( 'output/headers/*.php' ) ) as $file ) {
54
  require_once $file;
55
  }
dispatchers/WP_Die.php CHANGED
@@ -51,8 +51,6 @@ class QM_Dispatcher_WP_Die extends QM_Dispatcher {
51
  return;
52
  }
53
 
54
- require_once $this->qm->plugin_path( 'output/Html.php' );
55
-
56
  $switched_locale = self::switch_to_locale( get_user_locale() );
57
  $stack = array();
58
  $filtered_trace = $this->trace->get_filtered_trace();
@@ -62,12 +60,6 @@ class QM_Dispatcher_WP_Die extends QM_Dispatcher {
62
  $stack[] = QM_Output_Html::output_filename( $item['display'], $item['file'], $item['line'] );
63
  }
64
 
65
- printf(
66
- // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
67
- '<link rel="stylesheet" href="%s" media="all" />',
68
- esc_url( includes_url( 'css/dashicons.css' ) )
69
- );
70
-
71
  ?>
72
  <style>
73
  #query-monitor {
@@ -109,19 +101,39 @@ class QM_Dispatcher_WP_Die extends QM_Dispatcher {
109
  color: #666;
110
  }
111
 
112
- #query-monitor .dashicons-info {
113
- color: #0071a1;
114
- vertical-align: bottom;
115
  margin-right: 5px;
116
  }
117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  </style>
119
  <?php
120
 
121
  echo '<div id="query-monitor">';
122
 
123
  echo '<p>';
124
- echo '<span class="dashicons dashicons-info" aria-hidden="true"></span>';
 
125
 
126
  if ( 'unknown' !== $component->type ) {
127
  $name = ( 'plugin' === $component->type ) ? $component->context : $component->name;
51
  return;
52
  }
53
 
 
 
54
  $switched_locale = self::switch_to_locale( get_user_locale() );
55
  $stack = array();
56
  $filtered_trace = $this->trace->get_filtered_trace();
60
  $stack[] = QM_Output_Html::output_filename( $item['display'], $item['file'], $item['line'] );
61
  }
62
 
 
 
 
 
 
 
63
  ?>
64
  <style>
65
  #query-monitor {
101
  color: #666;
102
  }
103
 
104
+ #query-monitor .qm-icon-info {
105
+ vertical-align: middle;
 
106
  margin-right: 5px;
107
  }
108
 
109
+ #query-monitor .qm-icon-info svg {
110
+ fill: #0071a1;
111
+ }
112
+
113
+ #query-monitor a.qm-edit-link svg {
114
+ fill: #0071a1 !important;
115
+ width: 16px;
116
+ height: 16px;
117
+ left: 2px !important;
118
+ position: relative !important;
119
+ text-decoration: none !important;
120
+ top: 2px !important;
121
+ visibility: hidden !important;
122
+ }
123
+
124
+ #query-monitor a.qm-edit-link:hover svg,
125
+ #query-monitor a.qm-edit-link:focus svg {
126
+ visibility: visible !important;
127
+ }
128
+
129
  </style>
130
  <?php
131
 
132
  echo '<div id="query-monitor">';
133
 
134
  echo '<p>';
135
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
136
+ echo QueryMonitor::init()->icon( 'info' );
137
 
138
  if ( 'unknown' !== $component->type ) {
139
  $name = ( 'plugin' === $component->type ) ? $component->context : $component->name;
output/Html.php CHANGED
@@ -246,7 +246,7 @@ abstract class QM_Output_Html extends QM_Output {
246
  * @param array<string, mixed> $vars
247
  * @return void
248
  */
249
- public static function output_inner( $vars ) {
250
 
251
  echo '<table>';
252
 
@@ -378,7 +378,7 @@ abstract class QM_Output_Html extends QM_Output {
378
 
379
  $out .= '</span>';
380
  $out .= '<button class="qm-sort-controls" aria-label="' . esc_attr__( 'Sort data by this column', 'query-monitor' ) . '">';
381
- $out .= '<span class="qm-sort-arrow" aria-hidden="true"></span>';
382
  $out .= '</button>';
383
  $out .= '</label>';
384
  return $out;
@@ -394,6 +394,42 @@ abstract class QM_Output_Html extends QM_Output {
394
  return $out;
395
  }
396
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
  /**
398
  * @param array<string, mixed> $args
399
  * @return array<string, mixed>
@@ -488,15 +524,16 @@ abstract class QM_Output_Html extends QM_Output {
488
  $link = sprintf( self::get_file_link_format(), rawurlencode( $file ), intval( $link_line ) );
489
 
490
  if ( $is_filename ) {
491
- $format = '<a href="%s" class="qm-edit-link">%s</a>';
492
  } else {
493
- $format = '<a href="%s" class="qm-edit-link"><code>%s</code></a>';
494
  }
495
 
496
  return sprintf(
497
  $format,
498
  esc_attr( $link ),
499
- esc_html( $text )
 
500
  );
501
  }
502
 
246
  * @param array<string, mixed> $vars
247
  * @return void
248
  */
249
+ public static function output_inner( array $vars ) {
250
 
251
  echo '<table>';
252
 
378
 
379
  $out .= '</span>';
380
  $out .= '<button class="qm-sort-controls" aria-label="' . esc_attr__( 'Sort data by this column', 'query-monitor' ) . '">';
381
+ $out .= QueryMonitor::init()->icon( 'arrow-down' );
382
  $out .= '</button>';
383
  $out .= '</label>';
384
  return $out;
394
  return $out;
395
  }
396
 
397
+ /**
398
+ * Returns a filter trigger.
399
+ *
400
+ * @param string $target
401
+ * @param string $filter
402
+ * @param string $value
403
+ * @param string $label
404
+ * @return string
405
+ */
406
+ protected static function build_filter_trigger( $target, $filter, $value, $label ) {
407
+ return sprintf(
408
+ '<button class="qm-filter-trigger" data-qm-target="%1$s" data-qm-filter="%2$s" data-qm-value="%3$s">%4$s%5$s</button>',
409
+ esc_attr( $target ),
410
+ esc_attr( $filter ),
411
+ esc_attr( $value ),
412
+ $label,
413
+ QueryMonitor::init()->icon( 'filter' )
414
+ );
415
+ }
416
+
417
+ /**
418
+ * Returns a link.
419
+ *
420
+ * @param string $href
421
+ * @param string $label
422
+ * @return string
423
+ */
424
+ protected static function build_link( $href, $label ) {
425
+ return sprintf(
426
+ '<a href="%1$s" class="qm-link">%2$s%3$s</a>',
427
+ esc_attr( $href ),
428
+ $label,
429
+ QueryMonitor::init()->icon( 'external' )
430
+ );
431
+ }
432
+
433
  /**
434
  * @param array<string, mixed> $args
435
  * @return array<string, mixed>
524
  $link = sprintf( self::get_file_link_format(), rawurlencode( $file ), intval( $link_line ) );
525
 
526
  if ( $is_filename ) {
527
+ $format = '<a href="%1$s" class="qm-edit-link">%2$s%3$s</a>';
528
  } else {
529
+ $format = '<a href="%1$s" class="qm-edit-link"><code>%2$s</code>%3$s</a>';
530
  }
531
 
532
  return sprintf(
533
  $format,
534
  esc_attr( $link ),
535
+ esc_html( $text ),
536
+ QueryMonitor::init()->icon( 'edit' )
537
  );
538
  }
539
 
output/html/assets.php CHANGED
@@ -131,8 +131,11 @@ abstract class QM_Output_Html_Assets extends QM_Output_Html {
131
 
132
  foreach ( $asset['dependencies'] as $dep ) {
133
  if ( isset( $data['missing_dependencies'][ $dep ] ) ) {
 
 
134
  $dependency_output[] = sprintf(
135
- '<span style="white-space:nowrap"><span class="dashicons dashicons-warning" aria-hidden="true"></span>%s</span>',
 
136
  sprintf(
137
  /* translators: %s: Name of missing script or style dependency */
138
  __( '%s (missing)', 'query-monitor' ),
@@ -157,8 +160,11 @@ abstract class QM_Output_Html_Assets extends QM_Output_Html {
157
  echo '<tr data-qm-subject="' . esc_attr( $type . '-' . $handle ) . '" data-qm-' . esc_attr( $type ) . '-host="' . esc_attr( $qm_host ) . '" data-qm-' . esc_attr( $type ) . '-dependents="' . esc_attr( $dependents_list ) . '" data-qm-' . esc_attr( $type ) . '-dependencies="' . esc_attr( $dependencies_list ) . '" class="' . esc_attr( $class ) . '">';
158
  echo '<td class="qm-nowrap">';
159
 
 
 
160
  if ( $asset['warning'] ) {
161
- echo '<span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
162
  }
163
 
164
  echo esc_html( $label );
@@ -186,22 +192,24 @@ abstract class QM_Output_Html_Assets extends QM_Output_Html {
186
  $error_data = $asset['source']->get_error_data();
187
  if ( $error_data && isset( $error_data['src'] ) ) {
188
  printf(
189
- '<span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>%1$s:</span><br><a href="%2$s" class="qm-link">%2$s</a>',
190
- esc_html( $asset['source']->get_error_message() ),
191
- esc_url( $error_data['src'] )
 
192
  );
 
 
193
  } else {
194
  printf(
195
- '<span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>%s</span>',
 
 
196
  esc_html( $asset['source']->get_error_message() )
197
  );
198
  }
199
  } elseif ( ! empty( $asset['source'] ) ) {
200
- printf(
201
- '<a href="%s" class="qm-link">%s</a>',
202
- esc_url( $asset['source'] ),
203
- esc_html( $asset['display'] )
204
- );
205
  }
206
  echo '</td>';
207
  echo '<td class="qm-ltr qm-highlighter" data-qm-highlight="' . esc_attr( implode( ' ', $highlight_deps ) ) . '">';
131
 
132
  foreach ( $asset['dependencies'] as $dep ) {
133
  if ( isset( $data['missing_dependencies'][ $dep ] ) ) {
134
+ $warning = QueryMonitor::init()->icon( 'warning' );
135
+
136
  $dependency_output[] = sprintf(
137
+ '<span style="white-space:nowrap">%1$s%2$s</span>',
138
+ $warning,
139
  sprintf(
140
  /* translators: %s: Name of missing script or style dependency */
141
  __( '%s (missing)', 'query-monitor' ),
160
  echo '<tr data-qm-subject="' . esc_attr( $type . '-' . $handle ) . '" data-qm-' . esc_attr( $type ) . '-host="' . esc_attr( $qm_host ) . '" data-qm-' . esc_attr( $type ) . '-dependents="' . esc_attr( $dependents_list ) . '" data-qm-' . esc_attr( $type ) . '-dependencies="' . esc_attr( $dependencies_list ) . '" class="' . esc_attr( $class ) . '">';
161
  echo '<td class="qm-nowrap">';
162
 
163
+ $warning = QueryMonitor::init()->icon( 'warning' );
164
+
165
  if ( $asset['warning'] ) {
166
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
167
+ echo $warning;
168
  }
169
 
170
  echo esc_html( $label );
192
  $error_data = $asset['source']->get_error_data();
193
  if ( $error_data && isset( $error_data['src'] ) ) {
194
  printf(
195
+ '<span class="qm-warn">%1$s%2$s:</span><br>',
196
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
197
+ $warning,
198
+ esc_html( $asset['source']->get_error_message() )
199
  );
200
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
201
+ echo self::build_link( $error_data['src'], esc_html( $error_data['src'] ) );
202
  } else {
203
  printf(
204
+ '<span class="qm-warn">%1$s%2$s</span>',
205
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
206
+ $warning,
207
  esc_html( $asset['source']->get_error_message() )
208
  );
209
  }
210
  } elseif ( ! empty( $asset['source'] ) ) {
211
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
212
+ echo self::build_link( $asset['source'], esc_html( $asset['display'] ) );
 
 
 
213
  }
214
  echo '</td>';
215
  echo '<td class="qm-ltr qm-highlighter" data-qm-highlight="' . esc_attr( implode( ' ', $highlight_deps ) ) . '">';
output/html/block_editor.php CHANGED
@@ -193,13 +193,16 @@ class QM_Output_Html_Block_Editor extends QM_Output_Html {
193
 
194
  if ( $error_message ) {
195
  echo '<br>';
196
- echo '<span class="dashicons dashicons-warning" aria-hidden="true"></span>';
197
- echo $error_message; // WPCS: XSS ok;
 
 
198
  }
199
 
200
  if ( ! empty( $referenced_post ) && ! empty( $referenced_pto ) ) {
201
  echo '<br>';
202
- echo '<a href="' . esc_url( get_edit_post_link( $referenced_post ) ) . '" class="qm-link">' . esc_html( $referenced_pto->labels->edit_item ) . '</a>';
 
203
  }
204
 
205
  echo '</span></td>';
@@ -244,7 +247,8 @@ class QM_Output_Html_Block_Editor extends QM_Output_Html {
244
  echo '<code>' . esc_html( $block['callback']['name'] ) . '</code>';
245
 
246
  if ( isset( $block['callback']['error'] ) ) {
247
- echo '<br><span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
248
  echo esc_html( sprintf(
249
  /* translators: %s: Error message text */
250
  __( 'Error: %s', 'query-monitor' ),
193
 
194
  if ( $error_message ) {
195
  echo '<br>';
196
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
197
+ echo QueryMonitor::init()->icon( 'warning' );
198
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
199
+ echo $error_message;
200
  }
201
 
202
  if ( ! empty( $referenced_post ) && ! empty( $referenced_pto ) ) {
203
  echo '<br>';
204
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
205
+ echo self::build_link( get_edit_post_link( $referenced_post ), esc_html( $referenced_pto->labels->edit_item ) );
206
  }
207
 
208
  echo '</span></td>';
247
  echo '<code>' . esc_html( $block['callback']['name'] ) . '</code>';
248
 
249
  if ( isset( $block['callback']['error'] ) ) {
250
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
251
+ echo '<br>' . QueryMonitor::init()->icon( 'warning' );
252
  echo esc_html( sprintf(
253
  /* translators: %s: Error message text */
254
  __( 'Error: %s', 'query-monitor' ),
output/html/db_callers.php CHANGED
@@ -69,7 +69,9 @@ class QM_Output_Html_DB_Callers extends QM_Output_Html {
69
  $stime = number_format_i18n( $row['ltime'], 4 );
70
 
71
  echo '<tr>';
72
- echo '<td class="qm-ltr"><button class="qm-filter-trigger" data-qm-target="db_queries-wpdb" data-qm-filter="caller" data-qm-value="' . esc_attr( $row['caller'] ) . '"><code>' . esc_html( $row['caller'] ) . '</code></button></td>';
 
 
73
 
74
  foreach ( $data['types'] as $type_name => $type_count ) {
75
  if ( isset( $row['types'][ $type_name ] ) ) {
69
  $stime = number_format_i18n( $row['ltime'], 4 );
70
 
71
  echo '<tr>';
72
+ echo '<td class="qm-ltr">';
73
+ echo self::build_filter_trigger( 'db_queries-wpdb', 'caller', $row['caller'], '<code>' . esc_html( $row['caller'] ) . '</code>' ); // WPCS: XSS ok;
74
+ echo '</td>';
75
 
76
  foreach ( $data['types'] as $type_name => $type_count ) {
77
  if ( isset( $row['types'][ $type_name ] ) ) {
output/html/db_components.php CHANGED
@@ -70,7 +70,8 @@ class QM_Output_Html_DB_Components extends QM_Output_Html {
70
  $total_time += $row['ltime'];
71
 
72
  echo '<tr>';
73
- echo '<td class="qm-row-component"><button class="qm-filter-trigger" data-qm-target="db_queries-wpdb" data-qm-filter="component" data-qm-value="' . esc_attr( $row['component'] ) . '">' . esc_html( $row['component'] ) . '</button></td>';
 
74
 
75
  foreach ( $data['types'] as $type_name => $type_count ) {
76
  if ( isset( $row['types'][ $type_name ] ) ) {
70
  $total_time += $row['ltime'];
71
 
72
  echo '<tr>';
73
+ echo '<td class="qm-row-component">';
74
+ echo self::build_filter_trigger( 'db_queries-wpdb', 'component', $row['component'], esc_html( $row['component'] ) ); // WPCS: XSS ok;
75
 
76
  foreach ( $data['types'] as $type_name => $type_count ) {
77
  if ( isset( $row['types'][ $type_name ] ) ) {
output/html/db_dupes.php CHANGED
@@ -49,6 +49,7 @@ class QM_Output_Html_DB_Dupes extends QM_Output_Html {
49
  echo '<tr>';
50
  echo '<th scope="col">' . esc_html__( 'Query', 'query-monitor' ) . '</th>';
51
  echo '<th scope="col" class="qm-num">' . esc_html__( 'Count', 'query-monitor' ) . '</th>';
 
52
  echo '<th scope="col">' . esc_html__( 'Callers', 'query-monitor' ) . '</th>';
53
  if ( ! empty( $data['dupe_components'] ) ) {
54
  echo '<th scope="col">' . esc_html__( 'Components', 'query-monitor' ) . '</th>';
@@ -68,6 +69,7 @@ class QM_Output_Html_DB_Dupes extends QM_Output_Html {
68
  // This should probably happen in the collector's processor
69
  $type = QM_Util::get_query_type( $sql );
70
  $sql_out = self::format_sql( $sql );
 
71
 
72
  if ( 'SELECT' !== $type ) {
73
  $sql_out = "<span class='qm-nonselectsql'>{$sql_out}</span>";
@@ -80,12 +82,14 @@ class QM_Output_Html_DB_Dupes extends QM_Output_Html {
80
  echo '<td class="qm-num">';
81
  echo esc_html( number_format_i18n( count( $queries ), 0 ) );
82
  echo '</td>';
 
 
 
83
  echo '<td class="qm-row-caller qm-nowrap qm-ltr">';
84
  foreach ( $data['dupe_callers'][ $sql ] as $caller => $calls ) {
 
85
  printf(
86
- '<button class="qm-filter-trigger" data-qm-target="db_queries-wpdb" data-qm-filter="caller" data-qm-value="%s"><code>%s</code></button><br><span class="qm-info qm-supplemental">%s</span><br>',
87
- esc_attr( $caller ),
88
- esc_html( $caller ),
89
  esc_html( sprintf(
90
  translate_nooped_plural( $call_text, $calls, 'query-monitor' ),
91
  number_format_i18n( $calls )
49
  echo '<tr>';
50
  echo '<th scope="col">' . esc_html__( 'Query', 'query-monitor' ) . '</th>';
51
  echo '<th scope="col" class="qm-num">' . esc_html__( 'Count', 'query-monitor' ) . '</th>';
52
+ echo '<th scope="col" class="qm-num">' . esc_html__( 'Time', 'query-monitor' ) . '</th>';
53
  echo '<th scope="col">' . esc_html__( 'Callers', 'query-monitor' ) . '</th>';
54
  if ( ! empty( $data['dupe_components'] ) ) {
55
  echo '<th scope="col">' . esc_html__( 'Components', 'query-monitor' ) . '</th>';
69
  // This should probably happen in the collector's processor
70
  $type = QM_Util::get_query_type( $sql );
71
  $sql_out = self::format_sql( $sql );
72
+ $time = $data['dupe_times'][ $sql ];
73
 
74
  if ( 'SELECT' !== $type ) {
75
  $sql_out = "<span class='qm-nonselectsql'>{$sql_out}</span>";
82
  echo '<td class="qm-num">';
83
  echo esc_html( number_format_i18n( count( $queries ), 0 ) );
84
  echo '</td>';
85
+ echo '<td class="qm-num">';
86
+ echo esc_html( number_format_i18n( $time, 4 ) );
87
+ echo '</td>';
88
  echo '<td class="qm-row-caller qm-nowrap qm-ltr">';
89
  foreach ( $data['dupe_callers'][ $sql ] as $caller => $calls ) {
90
+ echo self::build_filter_trigger( 'db_queries-wpdb', 'caller', $caller, '<code>' . esc_html( $caller ) . '</code>' ); // WPCS: XSS ok;
91
  printf(
92
+ '<br><span class="qm-info qm-supplemental">%s</span><br>',
 
 
93
  esc_html( sprintf(
94
  translate_nooped_plural( $call_text, $calls, 'query-monitor' ),
95
  number_format_i18n( $calls )
output/html/db_queries.php CHANGED
@@ -202,7 +202,8 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
202
  */
203
  if ( apply_filters( 'qm/show_extended_query_prompt', true ) && ! $db->has_trace && ( '$wpdb' === $name ) ) {
204
  echo '<tr>';
205
- echo '<th colspan="' . intval( $span ) . '" class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
206
  if ( file_exists( WP_CONTENT_DIR . '/db.php' ) ) {
207
  /* translators: %s: File name */
208
  $message = __( 'Extended query information such as the component and affected rows is not available. A conflicting %s file is present.', 'query-monitor' );
@@ -471,7 +472,8 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
471
 
472
  if ( isset( $cols['result'] ) ) {
473
  if ( is_wp_error( $row['result'] ) ) {
474
- echo "<td class='qm-row-result qm-row-error'><span class='dashicons dashicons-warning' aria-hidden='true'></span>" . esc_html( $row['result']->get_error_message() ) . "</td>\n";
 
475
  } else {
476
  echo "<td class='qm-row-result qm-num'>" . esc_html( $row['result'] ) . "</td>\n";
477
  }
@@ -488,7 +490,8 @@ class QM_Output_Html_DB_Queries extends QM_Output_Html {
488
  echo '<td class="qm-num qm-row-time' . esc_attr( $td_class ) . '" data-qm-sort-weight="' . esc_attr( $row['ltime'] ) . '">';
489
 
490
  if ( $expensive ) {
491
- echo '<span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
492
  }
493
 
494
  echo esc_html( $stime );
202
  */
203
  if ( apply_filters( 'qm/show_extended_query_prompt', true ) && ! $db->has_trace && ( '$wpdb' === $name ) ) {
204
  echo '<tr>';
205
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
206
+ echo '<th colspan="' . intval( $span ) . '" class="qm-warn">' . QueryMonitor::init()->icon( 'warning' );
207
  if ( file_exists( WP_CONTENT_DIR . '/db.php' ) ) {
208
  /* translators: %s: File name */
209
  $message = __( 'Extended query information such as the component and affected rows is not available. A conflicting %s file is present.', 'query-monitor' );
472
 
473
  if ( isset( $cols['result'] ) ) {
474
  if ( is_wp_error( $row['result'] ) ) {
475
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
476
+ echo "<td class='qm-row-result qm-row-error'>" . QueryMonitor::init()->icon( 'warning' ) . esc_html( $row['result']->get_error_message() ) . "</td>\n";
477
  } else {
478
  echo "<td class='qm-row-result qm-num'>" . esc_html( $row['result'] ) . "</td>\n";
479
  }
490
  echo '<td class="qm-num qm-row-time' . esc_attr( $td_class ) . '" data-qm-sort-weight="' . esc_attr( $row['ltime'] ) . '">';
491
 
492
  if ( $expensive ) {
493
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
494
+ echo QueryMonitor::init()->icon( 'warning' );
495
  }
496
 
497
  echo esc_html( $stime );
output/html/environment.php CHANGED
@@ -63,7 +63,8 @@ class QM_Output_Html_Environment extends QM_Output_Html {
63
  echo '<td>';
64
 
65
  if ( $php_warning ) {
66
- echo '<span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
67
  }
68
 
69
  echo esc_html( $data['php']['version'] );
@@ -101,7 +102,8 @@ class QM_Output_Html_Environment extends QM_Output_Html {
101
  echo '<td>';
102
 
103
  if ( 'qm-warn' === $class ) {
104
- echo '<span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
105
  }
106
 
107
  echo esc_html( $val['after'] );
@@ -203,7 +205,8 @@ class QM_Output_Html_Environment extends QM_Output_Html {
203
  echo '<th scope="row">' . esc_html( $label ) . '</th>';
204
 
205
  if ( ! isset( $db['info'][ $field ] ) ) {
206
- echo '<td><span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>' . esc_html__( 'Unknown', 'query-monitor' ) . '</span></td>';
 
207
  } else {
208
  echo '<td>' . esc_html( $db['info'][ $field ] ) . '</td>';
209
  }
63
  echo '<td>';
64
 
65
  if ( $php_warning ) {
66
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
67
+ echo QueryMonitor::init()->icon( 'warning' );
68
  }
69
 
70
  echo esc_html( $data['php']['version'] );
102
  echo '<td>';
103
 
104
  if ( 'qm-warn' === $class ) {
105
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
106
+ echo QueryMonitor::init()->icon( 'warning' );
107
  }
108
 
109
  echo esc_html( $val['after'] );
205
  echo '<th scope="row">' . esc_html( $label ) . '</th>';
206
 
207
  if ( ! isset( $db['info'][ $field ] ) ) {
208
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
209
+ echo '<td><span class="qm-warn">' . QueryMonitor::init()->icon( 'warning' ) . esc_html__( 'Unknown', 'query-monitor' ) . '</span></td>';
210
  } else {
211
  echo '<td>' . esc_html( $db['info'][ $field ] ) . '</td>';
212
  }
output/html/hooks.php CHANGED
@@ -123,7 +123,8 @@ class QM_Output_Html_Hooks extends QM_Output_Html {
123
  echo '<th scope="row" rowspan="' . intval( $rowspan ) . '" class="qm-nowrap qm-ltr"><span class="qm-sticky">';
124
  echo '<code>' . esc_html( $hook['name'] ) . '</code>';
125
  if ( 'all' === $hook['name'] ) {
126
- echo '<br><span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
127
  printf(
128
  /* translators: %s: Action name */
129
  esc_html__( 'Warning: The %s action is extremely resource intensive. Try to avoid using it.', 'query-monitor' ),
@@ -175,7 +176,8 @@ class QM_Output_Html_Hooks extends QM_Output_Html {
175
  echo '<code>' . esc_html( $action['callback']['name'] ) . '</code>';
176
 
177
  if ( isset( $action['callback']['error'] ) ) {
178
- echo '<br><span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
179
  echo esc_html( sprintf(
180
  /* translators: %s: Error message text */
181
  __( 'Error: %s', 'query-monitor' ),
123
  echo '<th scope="row" rowspan="' . intval( $rowspan ) . '" class="qm-nowrap qm-ltr"><span class="qm-sticky">';
124
  echo '<code>' . esc_html( $hook['name'] ) . '</code>';
125
  if ( 'all' === $hook['name'] ) {
126
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
127
+ echo '<br><span class="qm-warn">' . QueryMonitor::init()->icon( 'warning' );
128
  printf(
129
  /* translators: %s: Action name */
130
  esc_html__( 'Warning: The %s action is extremely resource intensive. Try to avoid using it.', 'query-monitor' ),
176
  echo '<code>' . esc_html( $action['callback']['name'] ) . '</code>';
177
 
178
  if ( isset( $action['callback']['error'] ) ) {
179
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
180
+ echo '<br>' . QueryMonitor::init()->icon( 'warning' );
181
  echo esc_html( sprintf(
182
  /* translators: %s: Error message text */
183
  __( 'Error: %s', 'query-monitor' ),
output/html/http.php CHANGED
@@ -71,6 +71,7 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
71
  echo '<th scope="col" class="qm-filterable-column">';
72
  echo $this->build_filter( 'component', $components, __( 'Component', 'query-monitor' ) ); // WPCS: XSS ok.
73
  echo '</th>';
 
74
  echo '<th scope="col" class="qm-num">' . esc_html__( 'Timeout', 'query-monitor' ) . '</th>';
75
  echo '<th scope="col" class="qm-num">' . esc_html__( 'Time', 'query-monitor' ) . '</th>';
76
  echo '</tr>';
@@ -115,7 +116,7 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
115
 
116
  if ( 'https' === parse_url( $row['url'], PHP_URL_SCHEME ) ) {
117
  if ( empty( $row['args']['sslverify'] ) && ! $row['local'] ) {
118
- $info .= '<span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>' . esc_html( sprintf(
119
  /* translators: An HTTP API request has disabled certificate verification. 1: Relevant argument name */
120
  __( 'Certificate verification disabled (%s)', 'query-monitor' ),
121
  'sslverify=false'
@@ -160,7 +161,8 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
160
 
161
  if ( ! empty( $row['redirected_to'] ) ) {
162
  $url .= sprintf(
163
- '<br><span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>%1$s</span><br>%2$s',
 
164
  /* translators: An HTTP API request redirected to another URL */
165
  __( 'Redirected to:', 'query-monitor' ),
166
  self::format_url( $row['redirected_to'] )
@@ -177,7 +179,8 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
177
 
178
  echo '<td class="qm-has-toggle qm-col-status">';
179
  if ( $is_error ) {
180
- echo '<span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
181
  }
182
  echo esc_html( $response );
183
 
@@ -215,20 +218,6 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
215
  );
216
  }
217
 
218
- $size_fields = array(
219
- 'size_download' => __( 'Response Size', 'query-monitor' ),
220
- );
221
- foreach ( $size_fields as $key => $value ) {
222
- if ( ! isset( $row['info'][ $key ] ) ) {
223
- continue;
224
- }
225
- printf(
226
- '<li><span class="qm-info qm-supplemental">%1$s: %2$s</span></li>',
227
- esc_html( $value ),
228
- esc_html( size_format( $row['info'][ $key ] ) )
229
- );
230
- }
231
-
232
  $other_fields = array(
233
  'content_type' => __( 'Response Content Type', 'query-monitor' ),
234
  'primary_ip' => __( 'IP Address', 'query-monitor' ),
@@ -273,6 +262,22 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
273
  '<td class="qm-nowrap">%s</td>',
274
  esc_html( $component->name )
275
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
276
  printf(
277
  '<td class="qm-num">%s</td>',
278
  esc_html( $row['args']['timeout'] )
@@ -299,7 +304,7 @@ class QM_Output_Html_HTTP extends QM_Output_Html {
299
 
300
  echo '<tr>';
301
  printf(
302
- '<td colspan="6">%s</td>',
303
  sprintf(
304
  /* translators: %s: Number of HTTP API requests */
305
  esc_html( _nx( 'Total: %s', 'Total: %s', $count, 'HTTP API calls', 'query-monitor' ) ),
71
  echo '<th scope="col" class="qm-filterable-column">';
72
  echo $this->build_filter( 'component', $components, __( 'Component', 'query-monitor' ) ); // WPCS: XSS ok.
73
  echo '</th>';
74
+ echo '<th scope="col" class="qm-num">' . esc_html__( 'Size', 'query-monitor' ) . '</th>';
75
  echo '<th scope="col" class="qm-num">' . esc_html__( 'Timeout', 'query-monitor' ) . '</th>';
76
  echo '<th scope="col" class="qm-num">' . esc_html__( 'Time', 'query-monitor' ) . '</th>';
77
  echo '</tr>';
116
 
117
  if ( 'https' === parse_url( $row['url'], PHP_URL_SCHEME ) ) {
118
  if ( empty( $row['args']['sslverify'] ) && ! $row['local'] ) {
119
+ $info .= '<span class="qm-warn">' . QueryMonitor::init()->icon( 'warning' ) . esc_html( sprintf(
120
  /* translators: An HTTP API request has disabled certificate verification. 1: Relevant argument name */
121
  __( 'Certificate verification disabled (%s)', 'query-monitor' ),
122
  'sslverify=false'
161
 
162
  if ( ! empty( $row['redirected_to'] ) ) {
163
  $url .= sprintf(
164
+ '<br><span class="qm-warn">%1$s%2$s</span><br>%3$s',
165
+ QueryMonitor::init()->icon( 'warning' ),
166
  /* translators: An HTTP API request redirected to another URL */
167
  __( 'Redirected to:', 'query-monitor' ),
168
  self::format_url( $row['redirected_to'] )
179
 
180
  echo '<td class="qm-has-toggle qm-col-status">';
181
  if ( $is_error ) {
182
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
183
+ echo QueryMonitor::init()->icon( 'warning' );
184
  }
185
  echo esc_html( $response );
186
 
218
  );
219
  }
220
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  $other_fields = array(
222
  'content_type' => __( 'Response Content Type', 'query-monitor' ),
223
  'primary_ip' => __( 'IP Address', 'query-monitor' ),
262
  '<td class="qm-nowrap">%s</td>',
263
  esc_html( $component->name )
264
  );
265
+
266
+ $size = '';
267
+
268
+ if ( isset( $row['info']['size_download'] ) ) {
269
+ $size = sprintf(
270
+ /* translators: %s: Memory used in kilobytes */
271
+ __( '%s kB', 'query-monitor' ),
272
+ number_format_i18n( $row['info']['size_download'] / 1024, 1 )
273
+ );
274
+ }
275
+
276
+ printf(
277
+ '<td class="qm-nowrap qm-num">%s</td>',
278
+ esc_html( $size )
279
+ );
280
+
281
  printf(
282
  '<td class="qm-num">%s</td>',
283
  esc_html( $row['args']['timeout'] )
304
 
305
  echo '<tr>';
306
  printf(
307
+ '<td colspan="7">%s</td>',
308
  sprintf(
309
  /* translators: %s: Number of HTTP API requests */
310
  esc_html( _nx( 'Total: %s', 'Total: %s', $count, 'HTTP API calls', 'query-monitor' ) ),
output/html/languages.php CHANGED
@@ -41,8 +41,55 @@ class QM_Output_Html_Languages extends QM_Output_Html {
41
  return;
42
  }
43
 
44
- $this->before_tabular_output();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
 
46
  echo '<thead>';
47
  echo '<tr>';
48
  echo '<th scope="col">' . esc_html__( 'Text Domain', 'query-monitor' ) . '</th>';
@@ -93,23 +140,44 @@ class QM_Output_Html_Languages extends QM_Output_Html {
93
  }
94
  echo '</td>';
95
 
96
- echo '<td class="qm-nowrap">';
97
-
98
  if ( $mofile['found'] ) {
99
- echo esc_html( $mofile['found_formatted'] );
 
 
 
 
 
 
100
  } else {
 
101
  echo esc_html__( 'Not Found', 'query-monitor' );
 
102
  }
103
 
104
- echo '</td>';
105
-
106
  echo '</tr>';
107
  }
108
  }
109
 
110
  echo '</tbody>';
111
 
112
- $this->after_tabular_output();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  }
114
 
115
  /**
41
  return;
42
  }
43
 
44
+ $this->before_non_tabular_output();
45
+
46
+ echo '<section>';
47
+ echo '<h3><code>get_locale()</code></h3>';
48
+ echo '<p>' . esc_html( $data['locale'] ) . '</p>';
49
+ echo '</section>';
50
+
51
+ echo '<section>';
52
+ echo '<h3><code>get_user_locale()</code></h3>';
53
+ echo '<p>' . esc_html( $data['user_locale'] ) . '</p>';
54
+ echo '</section>';
55
+
56
+ echo '<section>';
57
+ echo '<h3><code>determine_locale()</code></h3>';
58
+ echo '<p>' . esc_html( $data['determined_locale'] ) . '</p>';
59
+ echo '</section>';
60
+
61
+ if ( isset( $data['mlp_language'] ) ) {
62
+ echo '<section>';
63
+ echo '<h3>';
64
+ printf(
65
+ /* translators: %s: Name of a multilingual plugin */
66
+ esc_html__( '%s Language', 'query-monitor' ),
67
+ 'MultilingualPress'
68
+ );
69
+ echo '</h3>';
70
+ echo '<p>' . esc_html( $data['mlp_language'] ) . '</p>';
71
+ echo '</section>';
72
+ }
73
+
74
+ if ( isset( $data['pll_language'] ) ) {
75
+ echo '<section>';
76
+ echo '<h3>';
77
+ printf(
78
+ /* translators: %s: Name of a multilingual plugin */
79
+ esc_html__( '%s Language', 'query-monitor' ),
80
+ 'Polylang'
81
+ );
82
+ echo '</h3>';
83
+ echo '<p>' . esc_html( $data['pll_language'] ) . '</p>';
84
+ echo '</section>';
85
+ }
86
+
87
+ echo '<section>';
88
+ echo '<h3><code>get_language_attributes()</code></h3>';
89
+ echo '<p><code>' . esc_html( $data['language_attributes'] ) . '</code></p>';
90
+ echo '</section>';
91
 
92
+ echo '<table class="qm-full-width">';
93
  echo '<thead>';
94
  echo '<tr>';
95
  echo '<th scope="col">' . esc_html__( 'Text Domain', 'query-monitor' ) . '</th>';
140
  }
141
  echo '</td>';
142
 
 
 
143
  if ( $mofile['found'] ) {
144
+ echo '<td class="qm-nowrap qm-num">';
145
+ echo esc_html( sprintf(
146
+ /* translators: %s: Memory used in kilobytes */
147
+ __( '%s kB', 'query-monitor' ),
148
+ number_format_i18n( $mofile['found'] / 1024, 1 )
149
+ ) );
150
+ echo '</td>';
151
  } else {
152
+ echo '<td class="qm-nowrap">';
153
  echo esc_html__( 'Not Found', 'query-monitor' );
154
+ echo '</td>';
155
  }
156
 
 
 
157
  echo '</tr>';
158
  }
159
  }
160
 
161
  echo '</tbody>';
162
 
163
+ echo '<tfoot>';
164
+ echo '<tr>';
165
+ echo '<td colspan="4">&nbsp;</td>';
166
+ echo '<td class="qm-num">';
167
+
168
+ echo esc_html( sprintf(
169
+ /* translators: %s: Memory used in kilobytes */
170
+ __( '%s kB', 'query-monitor' ),
171
+ number_format_i18n( $data['total_size'] / 1024, 1 )
172
+ ) );
173
+
174
+ echo '</td>';
175
+ echo '</tr>';
176
+ echo '</tfoot>';
177
+
178
+ echo '</table>';
179
+
180
+ $this->after_non_tabular_output();
181
  }
182
 
183
  /**
output/html/logger.php CHANGED
@@ -118,9 +118,11 @@ class QM_Output_Html_Logger extends QM_Output_Html {
118
  echo '<td class="qm-nowrap">';
119
 
120
  if ( $is_warning ) {
121
- echo '<span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
122
  } else {
123
- echo '<span class="dashicons" aria-hidden="true"></span>';
 
124
  }
125
 
126
  echo esc_html( ucfirst( $row['level'] ) );
118
  echo '<td class="qm-nowrap">';
119
 
120
  if ( $is_warning ) {
121
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
122
+ echo QueryMonitor::init()->icon( 'warning' );
123
  } else {
124
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
125
+ echo QueryMonitor::init()->icon( 'blank' );
126
  }
127
 
128
  echo esc_html( ucfirst( $row['level'] ) );
output/html/overview.php CHANGED
@@ -57,11 +57,13 @@ class QM_Output_Html_Overview extends QM_Output_Html {
57
  $this->before_non_tabular_output();
58
 
59
  echo '<section id="qm-broken">';
60
- echo '<p class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>' . esc_html( $qm_broken ) . '</p>';
 
61
  echo '</section>';
62
 
63
  echo '<section id="qm-ajax-errors">';
64
- echo '<p class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>' . esc_html( $ajax_errors ) . '</p>';
 
65
  echo '</section>';
66
 
67
  if ( $raw_request ) {
@@ -99,7 +101,8 @@ class QM_Output_Html_Overview extends QM_Output_Html {
99
 
100
  if ( $data['time_limit'] > 0 ) {
101
  if ( $data['display_time_usage_warning'] ) {
102
- echo '<br><span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
103
  } else {
104
  echo '<br><span class="qm-info">';
105
  }
@@ -111,7 +114,8 @@ class QM_Output_Html_Overview extends QM_Output_Html {
111
  ) );
112
  echo '</span>';
113
  } else {
114
- echo '<br><span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
115
  printf(
116
  /* translators: 1: Name of the PHP directive, 2: Value of the PHP directive */
117
  esc_html__( 'No execution time limit. The %1$s PHP configuration directive is set to %2$s.', 'query-monitor' ),
@@ -139,7 +143,10 @@ class QM_Output_Html_Overview extends QM_Output_Html {
139
 
140
  if ( $data['wp_memory_limit'] > 0 ) {
141
  if ( $data['display_memory_usage_warning'] ) {
142
- echo '<br><span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
 
 
143
  } else {
144
  echo '<br><span class="qm-info">';
145
  }
@@ -154,7 +161,8 @@ class QM_Output_Html_Overview extends QM_Output_Html {
154
 
155
  if ( $data['memory_limit'] > 0 ) {
156
  if ( $data['display_memory_usage_warning'] ) {
157
- echo '<br><span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
158
  } else {
159
  echo '<br><span class="qm-info">';
160
  }
@@ -166,7 +174,8 @@ class QM_Output_Html_Overview extends QM_Output_Html {
166
  ) );
167
  echo '</span>';
168
  } else {
169
- echo '<br><span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
170
  printf(
171
  /* translators: 1: Name of the PHP directive, 2: Value of the PHP directive */
172
  esc_html__( 'No memory limit. The %1$s PHP configuration directive is set to %2$s.', 'query-monitor' ),
@@ -198,20 +207,22 @@ class QM_Output_Html_Overview extends QM_Output_Html {
198
 
199
  if ( ! isset( $db_query_num['SELECT'] ) || count( $db_query_num ) > 1 ) {
200
  foreach ( $db_query_num as $type_name => $type_count ) {
201
- printf(
202
- '<button class="qm-filter-trigger" data-qm-target="db_queries-wpdb" data-qm-filter="type" data-qm-value="%1$s">%2$s: %3$s</button><br>',
203
- esc_attr( $type_name ),
204
  esc_html( $type_name ),
205
  esc_html( number_format_i18n( $type_count ) )
206
  );
 
 
207
  }
208
  }
209
 
210
- printf(
211
- '<button class="qm-filter-trigger" data-qm-target="db_queries-wpdb" data-qm-filter="type" data-qm-value="">%1$s: %2$s</button>',
212
  esc_html( _x( 'Total', 'database queries', 'query-monitor' ) ),
213
  esc_html( number_format_i18n( $db_queries_data['total_qs'] ) )
214
  );
 
215
 
216
  echo '</p>';
217
  echo '</section>';
@@ -234,11 +245,12 @@ class QM_Output_Html_Overview extends QM_Output_Html {
234
  );
235
  echo '</p>';
236
 
237
- printf(
238
- '<button class="qm-filter-trigger" data-qm-target="http" data-qm-filter="type" data-qm-value="">%1$s: %2$s</button>',
239
  esc_html( _x( 'Total', 'HTTP API calls', 'query-monitor' ) ),
240
  esc_html( number_format_i18n( count( $http_data['http'] ) ) )
241
  );
 
242
  } else {
243
  printf(
244
  '<p><em>%s</em></p>',
@@ -272,14 +284,16 @@ class QM_Output_Html_Overview extends QM_Output_Html {
272
 
273
  if ( $cache_data['has_object_cache'] ) {
274
  echo '<p><span class="qm-info">';
275
- printf(
276
- '<a href="%s" class="qm-link">%s</a>',
277
- esc_url( network_admin_url( 'plugins.php?plugin_status=dropins' ) ),
278
  esc_html__( 'Persistent object cache plugin in use', 'query-monitor' )
279
  );
280
  echo '</span></p>';
281
  } else {
282
- echo '<p><span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
 
283
  echo esc_html__( 'Persistent object cache plugin not in use', 'query-monitor' );
284
  echo '</span></p>';
285
 
@@ -340,7 +354,9 @@ class QM_Output_Html_Overview extends QM_Output_Html {
340
  echo '</p>';
341
  }
342
  } else {
343
- echo '<p><span class="qm-warn"><span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
 
344
  echo esc_html__( 'Opcode cache not in use', 'query-monitor' );
345
  echo '</span></p>';
346
  echo '<p>';
57
  $this->before_non_tabular_output();
58
 
59
  echo '<section id="qm-broken">';
60
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
61
+ echo '<p class="qm-warn">' . QueryMonitor::init()->icon( 'warning' ) . esc_html( $qm_broken ) . '</p>';
62
  echo '</section>';
63
 
64
  echo '<section id="qm-ajax-errors">';
65
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
66
+ echo '<p class="qm-warn">' . QueryMonitor::init()->icon( 'warning' ) . esc_html( $ajax_errors ) . '</p>';
67
  echo '</section>';
68
 
69
  if ( $raw_request ) {
101
 
102
  if ( $data['time_limit'] > 0 ) {
103
  if ( $data['display_time_usage_warning'] ) {
104
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
105
+ echo '<br><span class="qm-warn">' . QueryMonitor::init()->icon( 'warning' );
106
  } else {
107
  echo '<br><span class="qm-info">';
108
  }
114
  ) );
115
  echo '</span>';
116
  } else {
117
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
118
+ echo '<br><span class="qm-warn">' . QueryMonitor::init()->icon( 'warning' );
119
  printf(
120
  /* translators: 1: Name of the PHP directive, 2: Value of the PHP directive */
121
  esc_html__( 'No execution time limit. The %1$s PHP configuration directive is set to %2$s.', 'query-monitor' ),
143
 
144
  if ( $data['wp_memory_limit'] > 0 ) {
145
  if ( $data['display_memory_usage_warning'] ) {
146
+ echo '<br><span class="qm-warn">';
147
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
148
+ echo QueryMonitor::init()->icon( 'warning' );
149
+ echo '</span>';
150
  } else {
151
  echo '<br><span class="qm-info">';
152
  }
161
 
162
  if ( $data['memory_limit'] > 0 ) {
163
  if ( $data['display_memory_usage_warning'] ) {
164
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
165
+ echo '<br><span class="qm-warn">' . QueryMonitor::init()->icon( 'warning' );
166
  } else {
167
  echo '<br><span class="qm-info">';
168
  }
174
  ) );
175
  echo '</span>';
176
  } else {
177
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
178
+ echo '<br><span class="qm-warn">' . QueryMonitor::init()->icon( 'warning' );
179
  printf(
180
  /* translators: 1: Name of the PHP directive, 2: Value of the PHP directive */
181
  esc_html__( 'No memory limit. The %1$s PHP configuration directive is set to %2$s.', 'query-monitor' ),
207
 
208
  if ( ! isset( $db_query_num['SELECT'] ) || count( $db_query_num ) > 1 ) {
209
  foreach ( $db_query_num as $type_name => $type_count ) {
210
+ $label = sprintf(
211
+ '%1$s: %2$s',
 
212
  esc_html( $type_name ),
213
  esc_html( number_format_i18n( $type_count ) )
214
  );
215
+ echo self::build_filter_trigger( 'db_queries-wpdb', 'type', $type_name, esc_html( $label ) ); // WPCS: XSS ok;
216
+ echo '<br>';
217
  }
218
  }
219
 
220
+ $label = sprintf(
221
+ '%1$s: %2$s',
222
  esc_html( _x( 'Total', 'database queries', 'query-monitor' ) ),
223
  esc_html( number_format_i18n( $db_queries_data['total_qs'] ) )
224
  );
225
+ echo self::build_filter_trigger( 'db_queries-wpdb', 'type', '', esc_html( $label ) ); // WPCS: XSS ok;
226
 
227
  echo '</p>';
228
  echo '</section>';
245
  );
246
  echo '</p>';
247
 
248
+ $label = sprintf(
249
+ '%1$s: %2$s',
250
  esc_html( _x( 'Total', 'HTTP API calls', 'query-monitor' ) ),
251
  esc_html( number_format_i18n( count( $http_data['http'] ) ) )
252
  );
253
+ echo self::build_filter_trigger( 'http', 'type', '', esc_html( $label ) ); // WPCS: XSS ok;
254
  } else {
255
  printf(
256
  '<p><em>%s</em></p>',
284
 
285
  if ( $cache_data['has_object_cache'] ) {
286
  echo '<p><span class="qm-info">';
287
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
288
+ echo self::build_link(
289
+ network_admin_url( 'plugins.php?plugin_status=dropins' ),
290
  esc_html__( 'Persistent object cache plugin in use', 'query-monitor' )
291
  );
292
  echo '</span></p>';
293
  } else {
294
+ echo '<p><span class="qm-warn">';
295
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
296
+ echo QueryMonitor::init()->icon( 'warning' );
297
  echo esc_html__( 'Persistent object cache plugin not in use', 'query-monitor' );
298
  echo '</span></p>';
299
 
354
  echo '</p>';
355
  }
356
  } else {
357
+ echo '<p><span class="qm-warn">';
358
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
359
+ echo QueryMonitor::init()->icon( 'warning' );
360
  echo esc_html__( 'Opcode cache not in use', 'query-monitor' );
361
  echo '</span></p>';
362
  echo '<p>';
output/html/php_errors.php CHANGED
@@ -111,9 +111,11 @@ class QM_Output_Html_PHP_Errors extends QM_Output_Html {
111
  echo '<td class="qm-nowrap">';
112
 
113
  if ( $is_warning ) {
114
- echo '<span class="dashicons dashicons-warning" aria-hidden="true"></span>';
 
115
  } else {
116
- echo '<span class="dashicons" aria-hidden="true"></span>';
 
117
  }
118
 
119
  echo esc_html( $title );
111
  echo '<td class="qm-nowrap">';
112
 
113
  if ( $is_warning ) {
114
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
115
+ echo QueryMonitor::init()->icon( 'warning' );
116
  } else {
117
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
118
+ echo QueryMonitor::init()->icon( 'blank' );
119
  }
120
 
121
  echo esc_html( $title );
output/html/request.php CHANGED
@@ -100,10 +100,9 @@ class QM_Output_Html_Request extends QM_Output_Html {
100
  if ( $db_queries ) {
101
  $db_queries_data = $db_queries->get_data();
102
  if ( ! empty( $db_queries_data['dbs']['$wpdb']->has_main_query ) ) {
103
- printf(
104
- '<p><button class="qm-filter-trigger" data-qm-target="db_queries-wpdb" data-qm-filter="caller" data-qm-value="qm-main-query">%s</button></p>',
105
- esc_html__( 'View Main Query', 'query-monitor' )
106
- );
107
  }
108
  }
109
 
100
  if ( $db_queries ) {
101
  $db_queries_data = $db_queries->get_data();
102
  if ( ! empty( $db_queries_data['dbs']['$wpdb']->has_main_query ) ) {
103
+ echo '<p>';
104
+ echo self::build_filter_trigger( 'db_queries-wpdb', 'caller', 'qm-main-query', esc_html__( 'View Main Query', 'query-monitor' ) ); // WPCS: XSS ok;
105
+ echo '</p>';
 
106
  }
107
  }
108
 
output/html/timing.php CHANGED
@@ -163,7 +163,9 @@ class QM_Output_Html_Timing extends QM_Output_Html {
163
  }
164
 
165
  printf(
166
- '<td colspan="4"><span class="dashicons dashicons-warning" aria-hidden="true"></span>%s</td>',
 
 
167
  esc_html( $row['message'] )
168
  );
169
 
163
  }
164
 
165
  printf(
166
+ '<td colspan="4">%1$s%2$s</td>',
167
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
168
+ QueryMonitor::init()->icon( 'warning' ),
169
  esc_html( $row['message'] )
170
  );
171
 
output/raw/cache.php CHANGED
@@ -33,9 +33,9 @@ class QM_Output_Raw_Cache extends QM_Output_Raw {
33
  $data = $this->collector->get_data();
34
 
35
  if ( isset( $data['stats'] ) && isset( $data['cache_hit_percentage'] ) ) {
36
- $output['hit_percentage'] = (float) number_format_i18n( $data['cache_hit_percentage'], 1 );
37
- $output['hits'] = (int) number_format_i18n( $data['stats']['cache_hits'], 0 );
38
- $output['misses'] = (int) number_format_i18n( $data['stats']['cache_misses'], 0 );
39
  }
40
 
41
  return $output;
33
  $data = $this->collector->get_data();
34
 
35
  if ( isset( $data['stats'] ) && isset( $data['cache_hit_percentage'] ) ) {
36
+ $output['hit_percentage'] = round( $data['cache_hit_percentage'], 1 );
37
+ $output['hits'] = (int) $data['stats']['cache_hits'];
38
+ $output['misses'] = (int) $data['stats']['cache_misses'];
39
  }
40
 
41
  return $output;
output/raw/http.php CHANGED
@@ -49,13 +49,13 @@ class QM_Output_Raw_HTTP extends QM_Output_Raw {
49
  'url' => $http['url'],
50
  'method' => $http['args']['method'],
51
  'response' => is_wp_error( $http['response'] ) ? $http['response']->get_error_message() : $http['response']['response'],
52
- 'time' => (float) number_format_i18n( $http['end'] - $http['start'], 4 ),
53
  'stack' => $stack,
54
  );
55
  }
56
 
57
  $output['total'] = count( $requests );
58
- $output['time'] = (float) number_format_i18n( $data['ltime'], 4 );
59
  $output['requests'] = $requests;
60
 
61
  return $output;
49
  'url' => $http['url'],
50
  'method' => $http['args']['method'],
51
  'response' => is_wp_error( $http['response'] ) ? $http['response']->get_error_message() : $http['response']['response'],
52
+ 'time' => round( $http['end'] - $http['start'], 4 ),
53
  'stack' => $stack,
54
  );
55
  }
56
 
57
  $output['total'] = count( $requests );
58
+ $output['time'] = round( $data['ltime'], 4 );
59
  $output['requests'] = $requests;
60
 
61
  return $output;
query-monitor.php CHANGED
@@ -10,13 +10,13 @@
10
  *
11
  * Plugin Name: Query Monitor
12
  * Description: The developer tools panel for WordPress.
13
- * Version: 3.9.0
14
  * Plugin URI: https://querymonitor.com/
15
  * Author: John Blackbourn
16
  * Author URI: https://querymonitor.com/
17
  * Text Domain: query-monitor
18
  * Domain Path: /languages/
19
- * Requires PHP: 5.3.6
20
  *
21
  * This program is free software; you can redistribute it and/or modify
22
  * it under the terms of the GNU General Public License as published by
@@ -33,26 +33,28 @@ if ( ! defined( 'ABSPATH' ) ) {
33
  exit;
34
  }
35
 
36
- define( 'QM_VERSION', '3.9.0' );
37
 
38
  $qm_dir = dirname( __FILE__ );
39
 
 
40
  require_once "{$qm_dir}/classes/PHP.php";
41
 
42
  if ( ! QM_PHP::version_met() ) {
43
- add_action( 'admin_notices', 'QM_PHP::php_version_nope' );
44
  return;
45
  }
46
 
47
- # No autoloaders for us. See https://github.com/johnbillion/query-monitor/issues/7
48
- foreach ( array( 'Plugin', 'Activation', 'Util', 'QM' ) as $qm_class ) {
49
- require_once "{$qm_dir}/classes/{$qm_class}.php";
50
  }
51
 
 
 
52
  QM_Activation::init( __FILE__ );
53
 
54
  if ( defined( 'WP_CLI' ) && WP_CLI ) {
55
- require_once "{$qm_dir}/classes/CLI.php";
56
  QM_CLI::init( __FILE__ );
57
  }
58
 
@@ -71,13 +73,6 @@ if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
71
  return;
72
  }
73
 
74
- foreach ( array( 'QueryMonitor', 'Backtrace', 'Collectors', 'Collector', 'Dispatchers', 'Dispatcher', 'Hook', 'Output', 'Timer' ) as $qm_class ) {
75
- require_once "{$qm_dir}/classes/{$qm_class}.php";
76
- }
77
-
78
- unset(
79
- $qm_dir,
80
- $qm_class
81
- );
82
 
83
  QueryMonitor::init( __FILE__ )->set_up();
10
  *
11
  * Plugin Name: Query Monitor
12
  * Description: The developer tools panel for WordPress.
13
+ * Version: 3.10.0
14
  * Plugin URI: https://querymonitor.com/
15
  * Author: John Blackbourn
16
  * Author URI: https://querymonitor.com/
17
  * Text Domain: query-monitor
18
  * Domain Path: /languages/
19
+ * Requires PHP: 5.6.20
20
  *
21
  * This program is free software; you can redistribute it and/or modify
22
  * it under the terms of the GNU General Public License as published by
33
  exit;
34
  }
35
 
36
+ define( 'QM_VERSION', '3.10.0' );
37
 
38
  $qm_dir = dirname( __FILE__ );
39
 
40
+ // This must be required before vendor/autoload.php so QM can serve its own message about PHP compatibility.
41
  require_once "{$qm_dir}/classes/PHP.php";
42
 
43
  if ( ! QM_PHP::version_met() ) {
44
+ add_action( 'all_admin_notices', 'QM_PHP::php_version_nope' );
45
  return;
46
  }
47
 
48
+ if ( ! file_exists( "{$qm_dir}/vendor/autoload.php" ) ) {
49
+ add_action( 'all_admin_notices', 'QM_PHP::vendor_nope' );
50
+ return;
51
  }
52
 
53
+ require_once "{$qm_dir}/vendor/autoload.php";
54
+
55
  QM_Activation::init( __FILE__ );
56
 
57
  if ( defined( 'WP_CLI' ) && WP_CLI ) {
 
58
  QM_CLI::init( __FILE__ );
59
  }
60
 
73
  return;
74
  }
75
 
76
+ unset( $qm_dir );
 
 
 
 
 
 
 
77
 
78
  QueryMonitor::init( __FILE__ )->set_up();
readme.txt CHANGED
@@ -3,9 +3,9 @@ Contributors: johnbillion
3
  Tags: debug, debug-bar, debugging, development, developer, performance, profiler, queries, query monitor, rest-api
4
  Requires at least: 3.7
5
  Tested up to: 6.0
6
- Stable tag: 3.9.0
7
  License: GPLv2 or later
8
- Requires PHP: 5.3
9
  Donate link: https://johnblackbourn.com/donations/
10
 
11
  Query Monitor is the developer tools panel for WordPress.
@@ -72,7 +72,7 @@ Query Monitor is private by default and always will be. It does not persistently
72
 
73
  ### Does this plugin work with PHP 8?
74
 
75
- Yes.
76
 
77
  ### Who can access Query Monitor's output?
78
 
@@ -94,7 +94,7 @@ Yes, if anything calls `do_action( 'qm/cease' )` then Query Monitor will cease o
94
 
95
  This is useful for long-running operations that perform a very high number of database queries, consume a lot of memory, or otherwise are of no concern to Query Monitor, for example:
96
 
97
- * Backuping up or restoring your site
98
  * Exporting a large amount of data
99
  * Running security scans
100
 
@@ -141,6 +141,18 @@ In addition, if you like the plugin then I'd love for you to [leave a review](ht
141
 
142
  ## Changelog ##
143
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  ### 3.9.0 ###
145
 
146
  * Introduces a dark mode toggle on the Settings panel, which replaces the `QM_DARK_MODE` constant
@@ -403,26 +415,3 @@ New features! Read about them here: https://querymonitor.com/blog/2019/02/new-fe
403
  ### 3.2.1 ###
404
 
405
  * Fix a fatal error for < 5.0 sites that are not running the Gutenberg plugin.
406
-
407
- ### 3.2.0 ###
408
-
409
- * Add a new `Blocks` panel for debugging blocks in post content. Supports WordPress 5.0 and the Gutenberg plugin.
410
- * Display the number of times that each template part was included.
411
- * Allow the scripts and styles output to be filtered based on Dependencies and Dependents.
412
- * Remove the `Pin` button in favour of always pinning QM when it's open.
413
- * Add a "Settings" link to the Plugins screen that opens the settings panel.
414
- * Add a link to the Add-ons page on the wiki.
415
- * Add some more verbose and visible error notices for suboptimal PHP configuration directives.
416
- * Add support for identifying any RDBMS, not just MySQL and MariaDB.
417
- * Perform the PHP version check earlier on so that fewer parts of QM need to be compatible with PHP 5.2.
418
- * Highlight plain `http` requests to the HTTP API as insecure.
419
- * Ensure the `Template` admin menu is always shown, even if the template file name isn't known.
420
- * Adjust the JS and CSS asset source to not include the host.
421
- * Add a warning for insecure JS and CSS assets.
422
- * Remove before and after pseudo-elements in the style reset.
423
- * Show as much theme and template information as possible, even if QM doesn't know the template name.
424
- * Highlight non-core rows when filtering the Hooks & Actions panel by Non-Core.
425
- * Add a filter for environment constants.
426
- * Min width CSS for buttons.
427
- * First pass at documenting filters and hooks.
428
- * More coding standards updates.
3
  Tags: debug, debug-bar, debugging, development, developer, performance, profiler, queries, query monitor, rest-api
4
  Requires at least: 3.7
5
  Tested up to: 6.0
6
+ Stable tag: 3.10.0
7
  License: GPLv2 or later
8
+ Requires PHP: 5.6
9
  Donate link: https://johnblackbourn.com/donations/
10
 
11
  Query Monitor is the developer tools panel for WordPress.
72
 
73
  ### Does this plugin work with PHP 8?
74
 
75
+ Yes, it's actively tested and working up to PHP 8.1.
76
 
77
  ### Who can access Query Monitor's output?
78
 
94
 
95
  This is useful for long-running operations that perform a very high number of database queries, consume a lot of memory, or otherwise are of no concern to Query Monitor, for example:
96
 
97
+ * Backing up or restoring your site
98
  * Exporting a large amount of data
99
  * Running security scans
100
 
141
 
142
  ## Changelog ##
143
 
144
+ ### 3.10.0 ###
145
+
146
+ * Adds information about the current language on the Languages panel
147
+ * Reduces the chance that Query Monitor blames itself for PHP errors that don't have a stack trace
148
+ * Replaces the use of Dashicons with inline SVGs and removes the `dashicons` dependency
149
+ * Switches to class autoloading via Composer for reduced memory usage
150
+ * Changes the priority of the `shutdown` dispatcher from `0` to `PHP_INT_MAX` to ensure as much data as possible is collected
151
+ * Improves the styling of Debug Bar add-ons
152
+ * Fixes some erroneous localisation of float values in REST API output
153
+ * Bumps the minimum supported PHP version to 5.6
154
+ * Improves various other bits and bobs
155
+
156
  ### 3.9.0 ###
157
 
158
  * Introduces a dark mode toggle on the Settings panel, which replaces the `QM_DARK_MODE` constant
415
  ### 3.2.1 ###
416
 
417
  * Fix a fatal error for < 5.0 sites that are not running the Gutenberg plugin.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/autoload.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload.php @generated by Composer
4
+
5
+ if (PHP_VERSION_ID < 50600) {
6
+ echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
7
+ exit(1);
8
+ }
9
+
10
+ require_once __DIR__ . '/composer/autoload_real.php';
11
+
12
+ return ComposerAutoloaderInit40cfb9a65b1f406b0b0dc047560cd137::getLoader();
vendor/composer/ClassLoader.php ADDED
@@ -0,0 +1,572 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Composer.
5
+ *
6
+ * (c) Nils Adermann <naderman@naderman.de>
7
+ * Jordi Boggiano <j.boggiano@seld.be>
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ namespace Composer\Autoload;
14
+
15
+ /**
16
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
17
+ *
18
+ * $loader = new \Composer\Autoload\ClassLoader();
19
+ *
20
+ * // register classes with namespaces
21
+ * $loader->add('Symfony\Component', __DIR__.'/component');
22
+ * $loader->add('Symfony', __DIR__.'/framework');
23
+ *
24
+ * // activate the autoloader
25
+ * $loader->register();
26
+ *
27
+ * // to enable searching the include path (eg. for PEAR packages)
28
+ * $loader->setUseIncludePath(true);
29
+ *
30
+ * In this example, if you try to use a class in the Symfony\Component
31
+ * namespace or one of its children (Symfony\Component\Console for instance),
32
+ * the autoloader will first look for the class under the component/
33
+ * directory, and it will then fallback to the framework/ directory if not
34
+ * found before giving up.
35
+ *
36
+ * This class is loosely based on the Symfony UniversalClassLoader.
37
+ *
38
+ * @author Fabien Potencier <fabien@symfony.com>
39
+ * @author Jordi Boggiano <j.boggiano@seld.be>
40
+ * @see https://www.php-fig.org/psr/psr-0/
41
+ * @see https://www.php-fig.org/psr/psr-4/
42
+ */
43
+ class ClassLoader
44
+ {
45
+ /** @var ?string */
46
+ private $vendorDir;
47
+
48
+ // PSR-4
49
+ /**
50
+ * @var array[]
51
+ * @psalm-var array<string, array<string, int>>
52
+ */
53
+ private $prefixLengthsPsr4 = array();
54
+ /**
55
+ * @var array[]
56
+ * @psalm-var array<string, array<int, string>>
57
+ */
58
+ private $prefixDirsPsr4 = array();
59
+ /**
60
+ * @var array[]
61
+ * @psalm-var array<string, string>
62
+ */
63
+ private $fallbackDirsPsr4 = array();
64
+
65
+ // PSR-0
66
+ /**
67
+ * @var array[]
68
+ * @psalm-var array<string, array<string, string[]>>
69
+ */
70
+ private $prefixesPsr0 = array();
71
+ /**
72
+ * @var array[]
73
+ * @psalm-var array<string, string>
74
+ */
75
+ private $fallbackDirsPsr0 = array();
76
+
77
+ /** @var bool */
78
+ private $useIncludePath = false;
79
+
80
+ /**
81
+ * @var string[]
82
+ * @psalm-var array<string, string>
83
+ */
84
+ private $classMap = array();
85
+
86
+ /** @var bool */
87
+ private $classMapAuthoritative = false;
88
+
89
+ /**
90
+ * @var bool[]
91
+ * @psalm-var array<string, bool>
92
+ */
93
+ private $missingClasses = array();
94
+
95
+ /** @var ?string */
96
+ private $apcuPrefix;
97
+
98
+ /**
99
+ * @var self[]
100
+ */
101
+ private static $registeredLoaders = array();
102
+
103
+ /**
104
+ * @param ?string $vendorDir
105
+ */
106
+ public function __construct($vendorDir = null)
107
+ {
108
+ $this->vendorDir = $vendorDir;
109
+ }
110
+
111
+ /**
112
+ * @return string[]
113
+ */
114
+ public function getPrefixes()
115
+ {
116
+ if (!empty($this->prefixesPsr0)) {
117
+ return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
118
+ }
119
+
120
+ return array();
121
+ }
122
+
123
+ /**
124
+ * @return array[]
125
+ * @psalm-return array<string, array<int, string>>
126
+ */
127
+ public function getPrefixesPsr4()
128
+ {
129
+ return $this->prefixDirsPsr4;
130
+ }
131
+
132
+ /**
133
+ * @return array[]
134
+ * @psalm-return array<string, string>
135
+ */
136
+ public function getFallbackDirs()
137
+ {
138
+ return $this->fallbackDirsPsr0;
139
+ }
140
+
141
+ /**
142
+ * @return array[]
143
+ * @psalm-return array<string, string>
144
+ */
145
+ public function getFallbackDirsPsr4()
146
+ {
147
+ return $this->fallbackDirsPsr4;
148
+ }
149
+
150
+ /**
151
+ * @return string[] Array of classname => path
152
+ * @psalm-return array<string, string>
153
+ */
154
+ public function getClassMap()
155
+ {
156
+ return $this->classMap;
157
+ }
158
+
159
+ /**
160
+ * @param string[] $classMap Class to filename map
161
+ * @psalm-param array<string, string> $classMap
162
+ *
163
+ * @return void
164
+ */
165
+ public function addClassMap(array $classMap)
166
+ {
167
+ if ($this->classMap) {
168
+ $this->classMap = array_merge($this->classMap, $classMap);
169
+ } else {
170
+ $this->classMap = $classMap;
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Registers a set of PSR-0 directories for a given prefix, either
176
+ * appending or prepending to the ones previously set for this prefix.
177
+ *
178
+ * @param string $prefix The prefix
179
+ * @param string[]|string $paths The PSR-0 root directories
180
+ * @param bool $prepend Whether to prepend the directories
181
+ *
182
+ * @return void
183
+ */
184
+ public function add($prefix, $paths, $prepend = false)
185
+ {
186
+ if (!$prefix) {
187
+ if ($prepend) {
188
+ $this->fallbackDirsPsr0 = array_merge(
189
+ (array) $paths,
190
+ $this->fallbackDirsPsr0
191
+ );
192
+ } else {
193
+ $this->fallbackDirsPsr0 = array_merge(
194
+ $this->fallbackDirsPsr0,
195
+ (array) $paths
196
+ );
197
+ }
198
+
199
+ return;
200
+ }
201
+
202
+ $first = $prefix[0];
203
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
204
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
205
+
206
+ return;
207
+ }
208
+ if ($prepend) {
209
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
210
+ (array) $paths,
211
+ $this->prefixesPsr0[$first][$prefix]
212
+ );
213
+ } else {
214
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
215
+ $this->prefixesPsr0[$first][$prefix],
216
+ (array) $paths
217
+ );
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Registers a set of PSR-4 directories for a given namespace, either
223
+ * appending or prepending to the ones previously set for this namespace.
224
+ *
225
+ * @param string $prefix The prefix/namespace, with trailing '\\'
226
+ * @param string[]|string $paths The PSR-4 base directories
227
+ * @param bool $prepend Whether to prepend the directories
228
+ *
229
+ * @throws \InvalidArgumentException
230
+ *
231
+ * @return void
232
+ */
233
+ public function addPsr4($prefix, $paths, $prepend = false)
234
+ {
235
+ if (!$prefix) {
236
+ // Register directories for the root namespace.
237
+ if ($prepend) {
238
+ $this->fallbackDirsPsr4 = array_merge(
239
+ (array) $paths,
240
+ $this->fallbackDirsPsr4
241
+ );
242
+ } else {
243
+ $this->fallbackDirsPsr4 = array_merge(
244
+ $this->fallbackDirsPsr4,
245
+ (array) $paths
246
+ );
247
+ }
248
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
249
+ // Register directories for a new namespace.
250
+ $length = strlen($prefix);
251
+ if ('\\' !== $prefix[$length - 1]) {
252
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
253
+ }
254
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
255
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
256
+ } elseif ($prepend) {
257
+ // Prepend directories for an already registered namespace.
258
+ $this->prefixDirsPsr4[$prefix] = array_merge(
259
+ (array) $paths,
260
+ $this->prefixDirsPsr4[$prefix]
261
+ );
262
+ } else {
263
+ // Append directories for an already registered namespace.
264
+ $this->prefixDirsPsr4[$prefix] = array_merge(
265
+ $this->prefixDirsPsr4[$prefix],
266
+ (array) $paths
267
+ );
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Registers a set of PSR-0 directories for a given prefix,
273
+ * replacing any others previously set for this prefix.
274
+ *
275
+ * @param string $prefix The prefix
276
+ * @param string[]|string $paths The PSR-0 base directories
277
+ *
278
+ * @return void
279
+ */
280
+ public function set($prefix, $paths)
281
+ {
282
+ if (!$prefix) {
283
+ $this->fallbackDirsPsr0 = (array) $paths;
284
+ } else {
285
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Registers a set of PSR-4 directories for a given namespace,
291
+ * replacing any others previously set for this namespace.
292
+ *
293
+ * @param string $prefix The prefix/namespace, with trailing '\\'
294
+ * @param string[]|string $paths The PSR-4 base directories
295
+ *
296
+ * @throws \InvalidArgumentException
297
+ *
298
+ * @return void
299
+ */
300
+ public function setPsr4($prefix, $paths)
301
+ {
302
+ if (!$prefix) {
303
+ $this->fallbackDirsPsr4 = (array) $paths;
304
+ } else {
305
+ $length = strlen($prefix);
306
+ if ('\\' !== $prefix[$length - 1]) {
307
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
308
+ }
309
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
310
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
311
+ }
312
+ }
313
+
314
+ /**
315
+ * Turns on searching the include path for class files.
316
+ *
317
+ * @param bool $useIncludePath
318
+ *
319
+ * @return void
320
+ */
321
+ public function setUseIncludePath($useIncludePath)
322
+ {
323
+ $this->useIncludePath = $useIncludePath;
324
+ }
325
+
326
+ /**
327
+ * Can be used to check if the autoloader uses the include path to check
328
+ * for classes.
329
+ *
330
+ * @return bool
331
+ */
332
+ public function getUseIncludePath()
333
+ {
334
+ return $this->useIncludePath;
335
+ }
336
+
337
+ /**
338
+ * Turns off searching the prefix and fallback directories for classes
339
+ * that have not been registered with the class map.
340
+ *
341
+ * @param bool $classMapAuthoritative
342
+ *
343
+ * @return void
344
+ */
345
+ public function setClassMapAuthoritative($classMapAuthoritative)
346
+ {
347
+ $this->classMapAuthoritative = $classMapAuthoritative;
348
+ }
349
+
350
+ /**
351
+ * Should class lookup fail if not found in the current class map?
352
+ *
353
+ * @return bool
354
+ */
355
+ public function isClassMapAuthoritative()
356
+ {
357
+ return $this->classMapAuthoritative;
358
+ }
359
+
360
+ /**
361
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
362
+ *
363
+ * @param string|null $apcuPrefix
364
+ *
365
+ * @return void
366
+ */
367
+ public function setApcuPrefix($apcuPrefix)
368
+ {
369
+ $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
370
+ }
371
+
372
+ /**
373
+ * The APCu prefix in use, or null if APCu caching is not enabled.
374
+ *
375
+ * @return string|null
376
+ */
377
+ public function getApcuPrefix()
378
+ {
379
+ return $this->apcuPrefix;
380
+ }
381
+
382
+ /**
383
+ * Registers this instance as an autoloader.
384
+ *
385
+ * @param bool $prepend Whether to prepend the autoloader or not
386
+ *
387
+ * @return void
388
+ */
389
+ public function register($prepend = false)
390
+ {
391
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
392
+
393
+ if (null === $this->vendorDir) {
394
+ return;
395
+ }
396
+
397
+ if ($prepend) {
398
+ self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
399
+ } else {
400
+ unset(self::$registeredLoaders[$this->vendorDir]);
401
+ self::$registeredLoaders[$this->vendorDir] = $this;
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Unregisters this instance as an autoloader.
407
+ *
408
+ * @return void
409
+ */
410
+ public function unregister()
411
+ {
412
+ spl_autoload_unregister(array($this, 'loadClass'));
413
+
414
+ if (null !== $this->vendorDir) {
415
+ unset(self::$registeredLoaders[$this->vendorDir]);
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Loads the given class or interface.
421
+ *
422
+ * @param string $class The name of the class
423
+ * @return true|null True if loaded, null otherwise
424
+ */
425
+ public function loadClass($class)
426
+ {
427
+ if ($file = $this->findFile($class)) {
428
+ includeFile($file);
429
+
430
+ return true;
431
+ }
432
+
433
+ return null;
434
+ }
435
+
436
+ /**
437
+ * Finds the path to the file where the class is defined.
438
+ *
439
+ * @param string $class The name of the class
440
+ *
441
+ * @return string|false The path if found, false otherwise
442
+ */
443
+ public function findFile($class)
444
+ {
445
+ // class map lookup
446
+ if (isset($this->classMap[$class])) {
447
+ return $this->classMap[$class];
448
+ }
449
+ if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
450
+ return false;
451
+ }
452
+ if (null !== $this->apcuPrefix) {
453
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
454
+ if ($hit) {
455
+ return $file;
456
+ }
457
+ }
458
+
459
+ $file = $this->findFileWithExtension($class, '.php');
460
+
461
+ // Search for Hack files if we are running on HHVM
462
+ if (false === $file && defined('HHVM_VERSION')) {
463
+ $file = $this->findFileWithExtension($class, '.hh');
464
+ }
465
+
466
+ if (null !== $this->apcuPrefix) {
467
+ apcu_add($this->apcuPrefix.$class, $file);
468
+ }
469
+
470
+ if (false === $file) {
471
+ // Remember that this class does not exist.
472
+ $this->missingClasses[$class] = true;
473
+ }
474
+
475
+ return $file;
476
+ }
477
+
478
+ /**
479
+ * Returns the currently registered loaders indexed by their corresponding vendor directories.
480
+ *
481
+ * @return self[]
482
+ */
483
+ public static function getRegisteredLoaders()
484
+ {
485
+ return self::$registeredLoaders;
486
+ }
487
+
488
+ /**
489
+ * @param string $class
490
+ * @param string $ext
491
+ * @return string|false
492
+ */
493
+ private function findFileWithExtension($class, $ext)
494
+ {
495
+ // PSR-4 lookup
496
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
497
+
498
+ $first = $class[0];
499
+ if (isset($this->prefixLengthsPsr4[$first])) {
500
+ $subPath = $class;
501
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
502
+ $subPath = substr($subPath, 0, $lastPos);
503
+ $search = $subPath . '\\';
504
+ if (isset($this->prefixDirsPsr4[$search])) {
505
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
506
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
507
+ if (file_exists($file = $dir . $pathEnd)) {
508
+ return $file;
509
+ }
510
+ }
511
+ }
512
+ }
513
+ }
514
+
515
+ // PSR-4 fallback dirs
516
+ foreach ($this->fallbackDirsPsr4 as $dir) {
517
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
518
+ return $file;
519
+ }
520
+ }
521
+
522
+ // PSR-0 lookup
523
+ if (false !== $pos = strrpos($class, '\\')) {
524
+ // namespaced class name
525
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
526
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
527
+ } else {
528
+ // PEAR-like class name
529
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
530
+ }
531
+
532
+ if (isset($this->prefixesPsr0[$first])) {
533
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
534
+ if (0 === strpos($class, $prefix)) {
535
+ foreach ($dirs as $dir) {
536
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
537
+ return $file;
538
+ }
539
+ }
540
+ }
541
+ }
542
+ }
543
+
544
+ // PSR-0 fallback dirs
545
+ foreach ($this->fallbackDirsPsr0 as $dir) {
546
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
547
+ return $file;
548
+ }
549
+ }
550
+
551
+ // PSR-0 include paths.
552
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
553
+ return $file;
554
+ }
555
+
556
+ return false;
557
+ }
558
+ }
559
+
560
+ /**
561
+ * Scope isolated include.
562
+ *
563
+ * Prevents access to $this/self from included files.
564
+ *
565
+ * @param string $file
566
+ * @return void
567
+ * @private
568
+ */
569
+ function includeFile($file)
570
+ {
571
+ include $file;
572
+ }
vendor/composer/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Copyright (c) Nils Adermann, Jordi Boggiano
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is furnished
9
+ to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+
vendor/composer/autoload_classmap.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_classmap.php @generated by Composer
4
+
5
+ $vendorDir = dirname(__DIR__);
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
10
+ 'Debug_Bar' => $baseDir . '/classes/debug_bar.php',
11
+ 'Debug_Bar_Panel' => $baseDir . '/classes/debug_bar_panel.php',
12
+ 'QM' => $baseDir . '/classes/QM.php',
13
+ 'QM_Activation' => $baseDir . '/classes/Activation.php',
14
+ 'QM_Backtrace' => $baseDir . '/classes/Backtrace.php',
15
+ 'QM_CLI' => $baseDir . '/classes/CLI.php',
16
+ 'QM_Collector' => $baseDir . '/classes/Collector.php',
17
+ 'QM_Collectors' => $baseDir . '/classes/Collectors.php',
18
+ 'QM_DB' => $baseDir . '/classes/QM_DB.php',
19
+ 'QM_Dispatcher' => $baseDir . '/classes/Dispatcher.php',
20
+ 'QM_Dispatchers' => $baseDir . '/classes/Dispatchers.php',
21
+ 'QM_Hook' => $baseDir . '/classes/Hook.php',
22
+ 'QM_Output' => $baseDir . '/classes/Output.php',
23
+ 'QM_Output_Headers' => $baseDir . '/output/Headers.php',
24
+ 'QM_Output_Headers_Overview' => $baseDir . '/output/headers/overview.php',
25
+ 'QM_Output_Headers_PHP_Errors' => $baseDir . '/output/headers/php_errors.php',
26
+ 'QM_Output_Headers_Redirects' => $baseDir . '/output/headers/redirects.php',
27
+ 'QM_Output_Html' => $baseDir . '/output/Html.php',
28
+ 'QM_Output_Html_Admin' => $baseDir . '/output/html/admin.php',
29
+ 'QM_Output_Html_Assets' => $baseDir . '/output/html/assets.php',
30
+ 'QM_Output_Html_Assets_Scripts' => $baseDir . '/output/html/assets_scripts.php',
31
+ 'QM_Output_Html_Assets_Styles' => $baseDir . '/output/html/assets_styles.php',
32
+ 'QM_Output_Html_Block_Editor' => $baseDir . '/output/html/block_editor.php',
33
+ 'QM_Output_Html_Caps' => $baseDir . '/output/html/caps.php',
34
+ 'QM_Output_Html_Conditionals' => $baseDir . '/output/html/conditionals.php',
35
+ 'QM_Output_Html_DB_Callers' => $baseDir . '/output/html/db_callers.php',
36
+ 'QM_Output_Html_DB_Components' => $baseDir . '/output/html/db_components.php',
37
+ 'QM_Output_Html_DB_Dupes' => $baseDir . '/output/html/db_dupes.php',
38
+ 'QM_Output_Html_DB_Queries' => $baseDir . '/output/html/db_queries.php',
39
+ 'QM_Output_Html_Debug_Bar' => $baseDir . '/output/html/debug_bar.php',
40
+ 'QM_Output_Html_Environment' => $baseDir . '/output/html/environment.php',
41
+ 'QM_Output_Html_HTTP' => $baseDir . '/output/html/http.php',
42
+ 'QM_Output_Html_Headers' => $baseDir . '/output/html/headers.php',
43
+ 'QM_Output_Html_Hooks' => $baseDir . '/output/html/hooks.php',
44
+ 'QM_Output_Html_Languages' => $baseDir . '/output/html/languages.php',
45
+ 'QM_Output_Html_Logger' => $baseDir . '/output/html/logger.php',
46
+ 'QM_Output_Html_Overview' => $baseDir . '/output/html/overview.php',
47
+ 'QM_Output_Html_PHP_Errors' => $baseDir . '/output/html/php_errors.php',
48
+ 'QM_Output_Html_Request' => $baseDir . '/output/html/request.php',
49
+ 'QM_Output_Html_Theme' => $baseDir . '/output/html/theme.php',
50
+ 'QM_Output_Html_Timing' => $baseDir . '/output/html/timing.php',
51
+ 'QM_Output_Html_Transients' => $baseDir . '/output/html/transients.php',
52
+ 'QM_Output_Raw' => $baseDir . '/output/Raw.php',
53
+ 'QM_Output_Raw_Cache' => $baseDir . '/output/raw/cache.php',
54
+ 'QM_Output_Raw_Conditionals' => $baseDir . '/output/raw/conditionals.php',
55
+ 'QM_Output_Raw_DB_Queries' => $baseDir . '/output/raw/db_queries.php',
56
+ 'QM_Output_Raw_HTTP' => $baseDir . '/output/raw/http.php',
57
+ 'QM_Output_Raw_Logger' => $baseDir . '/output/raw/logger.php',
58
+ 'QM_Output_Raw_Transients' => $baseDir . '/output/raw/transients.php',
59
+ 'QM_PHP' => $baseDir . '/classes/PHP.php',
60
+ 'QM_Plugin' => $baseDir . '/classes/Plugin.php',
61
+ 'QM_Timer' => $baseDir . '/classes/Timer.php',
62
+ 'QM_Util' => $baseDir . '/classes/Util.php',
63
+ 'QueryMonitor' => $baseDir . '/classes/QueryMonitor.php',
64
+ );
vendor/composer/autoload_namespaces.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_namespaces.php @generated by Composer
4
+
5
+ $vendorDir = dirname(__DIR__);
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ );
vendor/composer/autoload_psr4.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_psr4.php @generated by Composer
4
+
5
+ $vendorDir = dirname(__DIR__);
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ );
vendor/composer/autoload_real.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_real.php @generated by Composer
4
+
5
+ class ComposerAutoloaderInit40cfb9a65b1f406b0b0dc047560cd137
6
+ {
7
+ private static $loader;
8
+
9
+ public static function loadClassLoader($class)
10
+ {
11
+ if ('Composer\Autoload\ClassLoader' === $class) {
12
+ require __DIR__ . '/ClassLoader.php';
13
+ }
14
+ }
15
+
16
+ /**
17
+ * @return \Composer\Autoload\ClassLoader
18
+ */
19
+ public static function getLoader()
20
+ {
21
+ if (null !== self::$loader) {
22
+ return self::$loader;
23
+ }
24
+
25
+ require __DIR__ . '/platform_check.php';
26
+
27
+ spl_autoload_register(array('ComposerAutoloaderInit40cfb9a65b1f406b0b0dc047560cd137', 'loadClassLoader'), true, true);
28
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
29
+ spl_autoload_unregister(array('ComposerAutoloaderInit40cfb9a65b1f406b0b0dc047560cd137', 'loadClassLoader'));
30
+
31
+ require __DIR__ . '/autoload_static.php';
32
+ call_user_func(\Composer\Autoload\ComposerStaticInit40cfb9a65b1f406b0b0dc047560cd137::getInitializer($loader));
33
+
34
+ $loader->register(true);
35
+
36
+ return $loader;
37
+ }
38
+ }
vendor/composer/autoload_static.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_static.php @generated by Composer
4
+
5
+ namespace Composer\Autoload;
6
+
7
+ class ComposerStaticInit40cfb9a65b1f406b0b0dc047560cd137
8
+ {
9
+ public static $classMap = array (
10
+ 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
11
+ 'Debug_Bar' => __DIR__ . '/../..' . '/classes/debug_bar.php',
12
+ 'Debug_Bar_Panel' => __DIR__ . '/../..' . '/classes/debug_bar_panel.php',
13
+ 'QM' => __DIR__ . '/../..' . '/classes/QM.php',
14
+ 'QM_Activation' => __DIR__ . '/../..' . '/classes/Activation.php',
15
+ 'QM_Backtrace' => __DIR__ . '/../..' . '/classes/Backtrace.php',
16
+ 'QM_CLI' => __DIR__ . '/../..' . '/classes/CLI.php',
17
+ 'QM_Collector' => __DIR__ . '/../..' . '/classes/Collector.php',
18
+ 'QM_Collectors' => __DIR__ . '/../..' . '/classes/Collectors.php',
19
+ 'QM_DB' => __DIR__ . '/../..' . '/classes/QM_DB.php',
20
+ 'QM_Dispatcher' => __DIR__ . '/../..' . '/classes/Dispatcher.php',
21
+ 'QM_Dispatchers' => __DIR__ . '/../..' . '/classes/Dispatchers.php',
22
+ 'QM_Hook' => __DIR__ . '/../..' . '/classes/Hook.php',
23
+ 'QM_Output' => __DIR__ . '/../..' . '/classes/Output.php',
24
+ 'QM_Output_Headers' => __DIR__ . '/../..' . '/output/Headers.php',
25
+ 'QM_Output_Headers_Overview' => __DIR__ . '/../..' . '/output/headers/overview.php',
26
+ 'QM_Output_Headers_PHP_Errors' => __DIR__ . '/../..' . '/output/headers/php_errors.php',
27
+ 'QM_Output_Headers_Redirects' => __DIR__ . '/../..' . '/output/headers/redirects.php',
28
+ 'QM_Output_Html' => __DIR__ . '/../..' . '/output/Html.php',
29
+ 'QM_Output_Html_Admin' => __DIR__ . '/../..' . '/output/html/admin.php',
30
+ 'QM_Output_Html_Assets' => __DIR__ . '/../..' . '/output/html/assets.php',
31
+ 'QM_Output_Html_Assets_Scripts' => __DIR__ . '/../..' . '/output/html/assets_scripts.php',
32
+ 'QM_Output_Html_Assets_Styles' => __DIR__ . '/../..' . '/output/html/assets_styles.php',
33
+ 'QM_Output_Html_Block_Editor' => __DIR__ . '/../..' . '/output/html/block_editor.php',
34
+ 'QM_Output_Html_Caps' => __DIR__ . '/../..' . '/output/html/caps.php',
35
+ 'QM_Output_Html_Conditionals' => __DIR__ . '/../..' . '/output/html/conditionals.php',
36
+ 'QM_Output_Html_DB_Callers' => __DIR__ . '/../..' . '/output/html/db_callers.php',
37
+ 'QM_Output_Html_DB_Components' => __DIR__ . '/../..' . '/output/html/db_components.php',
38
+ 'QM_Output_Html_DB_Dupes' => __DIR__ . '/../..' . '/output/html/db_dupes.php',
39
+ 'QM_Output_Html_DB_Queries' => __DIR__ . '/../..' . '/output/html/db_queries.php',
40
+ 'QM_Output_Html_Debug_Bar' => __DIR__ . '/../..' . '/output/html/debug_bar.php',
41
+ 'QM_Output_Html_Environment' => __DIR__ . '/../..' . '/output/html/environment.php',
42
+ 'QM_Output_Html_HTTP' => __DIR__ . '/../..' . '/output/html/http.php',
43
+ 'QM_Output_Html_Headers' => __DIR__ . '/../..' . '/output/html/headers.php',
44
+ 'QM_Output_Html_Hooks' => __DIR__ . '/../..' . '/output/html/hooks.php',
45
+ 'QM_Output_Html_Languages' => __DIR__ . '/../..' . '/output/html/languages.php',
46
+ 'QM_Output_Html_Logger' => __DIR__ . '/../..' . '/output/html/logger.php',
47
+ 'QM_Output_Html_Overview' => __DIR__ . '/../..' . '/output/html/overview.php',
48
+ 'QM_Output_Html_PHP_Errors' => __DIR__ . '/../..' . '/output/html/php_errors.php',
49
+ 'QM_Output_Html_Request' => __DIR__ . '/../..' . '/output/html/request.php',
50
+ 'QM_Output_Html_Theme' => __DIR__ . '/../..' . '/output/html/theme.php',
51
+ 'QM_Output_Html_Timing' => __DIR__ . '/../..' . '/output/html/timing.php',
52
+ 'QM_Output_Html_Transients' => __DIR__ . '/../..' . '/output/html/transients.php',
53
+ 'QM_Output_Raw' => __DIR__ . '/../..' . '/output/Raw.php',
54
+ 'QM_Output_Raw_Cache' => __DIR__ . '/../..' . '/output/raw/cache.php',
55
+ 'QM_Output_Raw_Conditionals' => __DIR__ . '/../..' . '/output/raw/conditionals.php',
56
+ 'QM_Output_Raw_DB_Queries' => __DIR__ . '/../..' . '/output/raw/db_queries.php',
57
+ 'QM_Output_Raw_HTTP' => __DIR__ . '/../..' . '/output/raw/http.php',
58
+ 'QM_Output_Raw_Logger' => __DIR__ . '/../..' . '/output/raw/logger.php',
59
+ 'QM_Output_Raw_Transients' => __DIR__ . '/../..' . '/output/raw/transients.php',
60
+ 'QM_PHP' => __DIR__ . '/../..' . '/classes/PHP.php',
61
+ 'QM_Plugin' => __DIR__ . '/../..' . '/classes/Plugin.php',
62
+ 'QM_Timer' => __DIR__ . '/../..' . '/classes/Timer.php',
63
+ 'QM_Util' => __DIR__ . '/../..' . '/classes/Util.php',
64
+ 'QueryMonitor' => __DIR__ . '/../..' . '/classes/QueryMonitor.php',
65
+ );
66
+
67
+ public static function getInitializer(ClassLoader $loader)
68
+ {
69
+ return \Closure::bind(function () use ($loader) {
70
+ $loader->classMap = ComposerStaticInit40cfb9a65b1f406b0b0dc047560cd137::$classMap;
71
+
72
+ }, null, ClassLoader::class);
73
+ }
74
+ }
vendor/composer/platform_check.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // platform_check.php @generated by Composer
4
+
5
+ $issues = array();
6
+
7
+ if (!(PHP_VERSION_ID >= 50620)) {
8
+ $issues[] = 'Your Composer dependencies require a PHP version ">= 5.6.20". You are running ' . PHP_VERSION . '.';
9
+ }
10
+
11
+ if ($issues) {
12
+ if (!headers_sent()) {
13
+ header('HTTP/1.1 500 Internal Server Error');
14
+ }
15
+ if (!ini_get('display_errors')) {
16
+ if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
17
+ fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
18
+ } elseif (!headers_sent()) {
19
+ echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
20
+ }
21
+ }
22
+ trigger_error(
23
+ 'Composer detected issues in your platform: ' . implode(' ', $issues),
24
+ E_USER_ERROR
25
+ );
26
+ }
wp-content/db.php CHANGED
@@ -1,8 +1,8 @@
1
  <?php
2
  /**
3
  * Plugin Name: Query Monitor Database Class (Drop-in)
4
- * Description: Database class for Query Monitor, the developer tools panel for WordPress.
5
- * Version: 3.9.0
6
  * Plugin URI: https://querymonitor.com/
7
  * Author: John Blackbourn
8
  * Author URI: https://querymonitor.com/
@@ -42,7 +42,7 @@ if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
42
  return;
43
  }
44
 
45
- # No autoloaders for us. See https://github.com/johnbillion/query-monitor/issues/7
46
  $qm_dir = dirname( dirname( __FILE__ ) );
47
  $qm_php = "{$qm_dir}/classes/PHP.php";
48
 
@@ -55,102 +55,19 @@ if ( ! QM_PHP::version_met() ) {
55
  return;
56
  }
57
 
58
- $backtrace = "{$qm_dir}/classes/Backtrace.php";
59
- if ( ! is_readable( $backtrace ) ) {
60
  return;
61
  }
62
- require_once $backtrace;
63
 
64
- if ( ! defined( 'SAVEQUERIES' ) ) {
65
- define( 'SAVEQUERIES', true );
66
- }
67
-
68
- class QM_DB extends wpdb {
69
-
70
- /**
71
- * @var float
72
- */
73
- public $time_start;
74
-
75
- /**
76
- * @var array<string, string|null>
77
- */
78
- public $qm_php_vars = array(
79
- 'max_execution_time' => null,
80
- 'memory_limit' => null,
81
- 'upload_max_filesize' => null,
82
- 'post_max_size' => null,
83
- 'display_errors' => null,
84
- 'log_errors' => null,
85
- );
86
-
87
- /**
88
- * Class constructor
89
- */
90
- public function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) {
91
-
92
- foreach ( $this->qm_php_vars as $setting => &$val ) {
93
- $val = ini_get( $setting );
94
- }
95
-
96
- parent::__construct( $dbuser, $dbpassword, $dbname, $dbhost );
97
-
98
- }
99
-
100
- /**
101
- * Performs a MySQL database query, using current database connection.
102
- *
103
- * @see wpdb::query()
104
- *
105
- * @param string $query Database query
106
- * @return int|bool Boolean true for CREATE, ALTER, TRUNCATE and DROP queries. Number of rows
107
- * affected/selected for all other queries. Boolean false on error.
108
- */
109
- public function query( $query ) {
110
- if ( $this->show_errors ) {
111
- $this->hide_errors();
112
- }
113
-
114
- $result = parent::query( $query );
115
- $i = $this->num_queries - 1;
116
 
117
- if ( did_action( 'qm/cease' ) ) {
118
- // It's not possible to prevent the parent class from logging queries because it reads
119
- // the `SAVEQUERIES` constant and I don't want to override more methods than necessary.
120
- $this->queries = array();
121
- }
122
-
123
- if ( ! isset( $this->queries[ $i ] ) ) {
124
- return $result;
125
- }
126
-
127
- $this->queries[ $i ]['trace'] = new QM_Backtrace();
128
-
129
- if ( ! isset( $this->queries[ $i ][3] ) ) {
130
- $this->queries[ $i ][3] = $this->time_start;
131
- }
132
-
133
- if ( $this->last_error ) {
134
- $code = 'qmdb';
135
-
136
- if ( $this->dbh instanceof mysqli ) {
137
- $code = mysqli_errno( $this->dbh );
138
- }
139
-
140
- if ( is_resource( $this->dbh ) ) {
141
- // Please do not report this code as a PHP 7 incompatibility. Observe the surrounding logic.
142
- // phpcs:ignore
143
- $code = mysql_errno( $this->dbh );
144
- }
145
-
146
- $this->queries[ $i ]['result'] = new WP_Error( $code, $this->last_error );
147
- } else {
148
- $this->queries[ $i ]['result'] = $result;
149
- }
150
-
151
- return $result;
152
- }
153
 
 
 
154
  }
155
 
156
  // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
1
  <?php
2
  /**
3
  * Plugin Name: Query Monitor Database Class (Drop-in)
4
+ * Description: Database drop-in for Query Monitor, the developer tools panel for WordPress.
5
+ * Version: 3.10.0
6
  * Plugin URI: https://querymonitor.com/
7
  * Author: John Blackbourn
8
  * Author URI: https://querymonitor.com/
42
  return;
43
  }
44
 
45
+ // This must be required before vendor/autoload.php so QM can serve its own message about PHP compatibility.
46
  $qm_dir = dirname( dirname( __FILE__ ) );
47
  $qm_php = "{$qm_dir}/classes/PHP.php";
48
 
55
  return;
56
  }
57
 
58
+ if ( ! file_exists( "{$qm_dir}/vendor/autoload.php" ) ) {
59
+ add_action( 'all_admin_notices', 'QM_PHP::vendor_nope' );
60
  return;
61
  }
 
62
 
63
+ require_once "{$qm_dir}/vendor/autoload.php";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
+ if ( ! class_exists( 'QM_Backtrace' ) ) {
66
+ return;
67
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
+ if ( ! defined( 'SAVEQUERIES' ) ) {
70
+ define( 'SAVEQUERIES', true );
71
  }
72
 
73
  // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited