events
This commit is contained in:
parent
2e2cd8c9c4
commit
e3fbf9a239
|
|
@ -0,0 +1,2 @@
|
||||||
|
# tribe-common
|
||||||
|
Common classes and functions used in our plugins
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
If you are interested in contributing to translations, you can get started at https://translations.theeventscalendar.com/projects/tribe-common/
|
||||||
|
|
||||||
|
On that site you can also find the .po translation files for doing local translations. We do not include these in the plugin itself to save space.
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
7
wp-content/plugins/the-events-calendar/common/node_modules/clipboard/dist/clipboard.min.js
generated
vendored
Normal file
7
wp-content/plugins/the-events-calendar/common/node_modules/clipboard/dist/clipboard.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
4421
wp-content/plugins/the-events-calendar/common/node_modules/intro.js/intro.js
generated
vendored
Normal file
4421
wp-content/plugins/the-events-calendar/common/node_modules/intro.js/intro.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
23
wp-content/plugins/the-events-calendar/common/node_modules/intro.js/introjs-rtl.css
generated
vendored
Normal file
23
wp-content/plugins/the-events-calendar/common/node_modules/intro.js/introjs-rtl.css
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
.introjs-tooltipbuttons {
|
||||||
|
text-align: left; }
|
||||||
|
|
||||||
|
.introjs-skipbutton {
|
||||||
|
margin-left: 5px;
|
||||||
|
float: left; }
|
||||||
|
|
||||||
|
.introjs-tooltip-title {
|
||||||
|
float: right; }
|
||||||
|
|
||||||
|
.introjs-tooltip {
|
||||||
|
direction: rtl; }
|
||||||
|
|
||||||
|
.introjs-prevbutton {
|
||||||
|
border: 1px solid #d4d4d4;
|
||||||
|
float: right; }
|
||||||
|
|
||||||
|
.introjs-nextbutton {
|
||||||
|
border: 1px solid #d4d4d4;
|
||||||
|
float: left; }
|
||||||
|
|
||||||
|
.introjs-bullets ul li {
|
||||||
|
float: right; }
|
||||||
436
wp-content/plugins/the-events-calendar/common/node_modules/intro.js/introjs.css
generated
vendored
Normal file
436
wp-content/plugins/the-events-calendar/common/node_modules/intro.js/introjs.css
generated
vendored
Normal file
|
|
@ -0,0 +1,436 @@
|
||||||
|
/*
|
||||||
|
Buttons style by http://nicolasgallagher.com/lab/css3-github-buttons/
|
||||||
|
Changed by Afshin Mehrabani
|
||||||
|
*/
|
||||||
|
/* overrides extra padding on button elements in Firefox */
|
||||||
|
@-webkit-keyframes introjspulse {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: scale(0);
|
||||||
|
transform: scale(0);
|
||||||
|
opacity: 0; }
|
||||||
|
25% {
|
||||||
|
-webkit-transform: scale(0);
|
||||||
|
transform: scale(0);
|
||||||
|
opacity: 0.1; }
|
||||||
|
50% {
|
||||||
|
-webkit-transform: scale(0.1);
|
||||||
|
transform: scale(0.1);
|
||||||
|
opacity: 0.3; }
|
||||||
|
75% {
|
||||||
|
-webkit-transform: scale(0.5);
|
||||||
|
transform: scale(0.5);
|
||||||
|
opacity: 0.5; }
|
||||||
|
100% {
|
||||||
|
-webkit-transform: scale(1);
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 0; } }
|
||||||
|
@keyframes introjspulse {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: scale(0);
|
||||||
|
transform: scale(0);
|
||||||
|
opacity: 0; }
|
||||||
|
25% {
|
||||||
|
-webkit-transform: scale(0);
|
||||||
|
transform: scale(0);
|
||||||
|
opacity: 0.1; }
|
||||||
|
50% {
|
||||||
|
-webkit-transform: scale(0.1);
|
||||||
|
transform: scale(0.1);
|
||||||
|
opacity: 0.3; }
|
||||||
|
75% {
|
||||||
|
-webkit-transform: scale(0.5);
|
||||||
|
transform: scale(0.5);
|
||||||
|
opacity: 0.5; }
|
||||||
|
100% {
|
||||||
|
-webkit-transform: scale(1);
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 0; } }
|
||||||
|
|
||||||
|
.introjs-overlay {
|
||||||
|
position: absolute;
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
z-index: 999999;
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transition: all 0.3s ease-out;
|
||||||
|
-o-transition: all 0.3s ease-out;
|
||||||
|
transition: all 0.3s ease-out; }
|
||||||
|
|
||||||
|
.introjs-showElement {
|
||||||
|
z-index: 9999999 !important; }
|
||||||
|
|
||||||
|
tr.introjs-showElement > td {
|
||||||
|
z-index: 9999999 !important;
|
||||||
|
position: relative; }
|
||||||
|
|
||||||
|
tr.introjs-showElement > th {
|
||||||
|
z-index: 9999999 !important;
|
||||||
|
position: relative; }
|
||||||
|
|
||||||
|
.introjs-disableInteraction {
|
||||||
|
z-index: 99999999 !important;
|
||||||
|
position: absolute;
|
||||||
|
background-color: #ffffff;
|
||||||
|
opacity: 0;
|
||||||
|
filter: alpha(opacity=0); }
|
||||||
|
|
||||||
|
.introjs-relativePosition {
|
||||||
|
position: relative; }
|
||||||
|
|
||||||
|
.introjs-helperLayer {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 9999998;
|
||||||
|
border-radius: 4px;
|
||||||
|
-webkit-transition: all 0.3s ease-out;
|
||||||
|
-o-transition: all 0.3s ease-out;
|
||||||
|
transition: all 0.3s ease-out; }
|
||||||
|
.introjs-helperLayer * {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box; }
|
||||||
|
.introjs-helperLayer *:before {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box; }
|
||||||
|
.introjs-helperLayer *:after {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box; }
|
||||||
|
|
||||||
|
.introjs-tooltipReferenceLayer {
|
||||||
|
font-family: "Helvetica Neue", Inter, ui-sans-serif, "Apple Color Emoji", Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
position: absolute;
|
||||||
|
visibility: hidden;
|
||||||
|
z-index: 100000000;
|
||||||
|
background-color: transparent;
|
||||||
|
-webkit-transition: all 0.3s ease-out;
|
||||||
|
-o-transition: all 0.3s ease-out;
|
||||||
|
transition: all 0.3s ease-out; }
|
||||||
|
.introjs-tooltipReferenceLayer * {
|
||||||
|
font-family: "Helvetica Neue", Inter, ui-sans-serif, "Apple Color Emoji", Helvetica, Arial, sans-serif; }
|
||||||
|
|
||||||
|
.introjs-helperNumberLayer {
|
||||||
|
font-family: "Helvetica Neue", Inter, ui-sans-serif, "Apple Color Emoji", Helvetica, Arial, sans-serif;
|
||||||
|
color: #9e9e9e;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px; }
|
||||||
|
|
||||||
|
.introjs-arrow {
|
||||||
|
border: 5px solid transparent;
|
||||||
|
content: "";
|
||||||
|
position: absolute; }
|
||||||
|
|
||||||
|
.introjs-arrow.top {
|
||||||
|
top: -10px;
|
||||||
|
left: 10px;
|
||||||
|
border-bottom-color: #ffffff; }
|
||||||
|
|
||||||
|
.introjs-arrow.top-right {
|
||||||
|
top: -10px;
|
||||||
|
right: 10px;
|
||||||
|
border-bottom-color: #ffffff; }
|
||||||
|
|
||||||
|
.introjs-arrow.top-middle {
|
||||||
|
top: -10px;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -5px;
|
||||||
|
border-bottom-color: #ffffff; }
|
||||||
|
|
||||||
|
.introjs-arrow.right {
|
||||||
|
right: -10px;
|
||||||
|
top: 10px;
|
||||||
|
border-left-color: #ffffff; }
|
||||||
|
|
||||||
|
.introjs-arrow.right-bottom {
|
||||||
|
bottom: 10px;
|
||||||
|
right: -10px;
|
||||||
|
border-left-color: #ffffff; }
|
||||||
|
|
||||||
|
.introjs-arrow.bottom {
|
||||||
|
bottom: -10px;
|
||||||
|
left: 10px;
|
||||||
|
border-top-color: #ffffff; }
|
||||||
|
|
||||||
|
.introjs-arrow.bottom-right {
|
||||||
|
bottom: -10px;
|
||||||
|
right: 10px;
|
||||||
|
border-top-color: #ffffff; }
|
||||||
|
|
||||||
|
.introjs-arrow.bottom-middle {
|
||||||
|
bottom: -10px;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -5px;
|
||||||
|
border-top-color: #ffffff; }
|
||||||
|
|
||||||
|
.introjs-arrow.left {
|
||||||
|
left: -10px;
|
||||||
|
top: 10px;
|
||||||
|
border-right-color: #ffffff; }
|
||||||
|
|
||||||
|
.introjs-arrow.left-bottom {
|
||||||
|
left: -10px;
|
||||||
|
bottom: 10px;
|
||||||
|
border-right-color: #ffffff; }
|
||||||
|
|
||||||
|
.introjs-tooltip {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
position: absolute;
|
||||||
|
visibility: visible;
|
||||||
|
background-color: #ffffff;
|
||||||
|
min-width: 250px;
|
||||||
|
max-width: 300px;
|
||||||
|
border-radius: 5px;
|
||||||
|
-webkit-box-shadow: 0 3px 30px rgba(33, 33, 33, 0.3);
|
||||||
|
box-shadow: 0 3px 30px rgba(33, 33, 33, 0.3);
|
||||||
|
-webkit-transition: opacity 0.1s ease-out;
|
||||||
|
-o-transition: opacity 0.1s ease-out;
|
||||||
|
transition: opacity 0.1s ease-out; }
|
||||||
|
|
||||||
|
.introjs-tooltiptext {
|
||||||
|
padding: 20px; }
|
||||||
|
|
||||||
|
.introjs-tooltip-title {
|
||||||
|
font-size: 18px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-weight: 700;
|
||||||
|
float: left;
|
||||||
|
line-height: 32px; }
|
||||||
|
|
||||||
|
.introjs-tooltip-header {
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 20px;
|
||||||
|
padding-top: 10px; }
|
||||||
|
.introjs-tooltip-header:after {
|
||||||
|
content: ".";
|
||||||
|
visibility: hidden;
|
||||||
|
display: block;
|
||||||
|
height: 0;
|
||||||
|
clear: both; }
|
||||||
|
|
||||||
|
.introjs-tooltipbuttons {
|
||||||
|
border-top: 1px solid #e0e0e0;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: right;
|
||||||
|
white-space: nowrap; }
|
||||||
|
.introjs-tooltipbuttons:after {
|
||||||
|
content: "";
|
||||||
|
visibility: hidden;
|
||||||
|
display: block;
|
||||||
|
height: 0;
|
||||||
|
clear: both; }
|
||||||
|
|
||||||
|
.introjs-button {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
position: relative;
|
||||||
|
overflow: visible;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border: 1px solid #bdbdbd;
|
||||||
|
text-decoration: none;
|
||||||
|
text-shadow: 1px 1px 0 #ffffff;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #424242;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
border-radius: 0.2em;
|
||||||
|
zoom: 1;
|
||||||
|
*display: inline; }
|
||||||
|
.introjs-button:hover {
|
||||||
|
outline: none;
|
||||||
|
text-decoration: none;
|
||||||
|
border-color: #9e9e9e;
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
color: #212121; }
|
||||||
|
.introjs-button:focus {
|
||||||
|
outline: none;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: #eeeeee;
|
||||||
|
-webkit-box-shadow: 0 0 0 0.2rem rgba(158, 158, 158, 0.5);
|
||||||
|
box-shadow: 0 0 0 0.2rem rgba(158, 158, 158, 0.5);
|
||||||
|
border: 1px solid #616161;
|
||||||
|
color: #212121; }
|
||||||
|
.introjs-button:active {
|
||||||
|
outline: none;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
border-color: #9e9e9e;
|
||||||
|
color: #212121; }
|
||||||
|
.introjs-button::-moz-focus-inner {
|
||||||
|
padding: 0;
|
||||||
|
border: 0; }
|
||||||
|
|
||||||
|
.introjs-skipbutton {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
color: #616161;
|
||||||
|
float: right;
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1;
|
||||||
|
text-align: center;
|
||||||
|
padding: 7px 10px; }
|
||||||
|
.introjs-skipbutton:hover, .introjs-skipbutton:focus {
|
||||||
|
color: #212121;
|
||||||
|
outline: none;
|
||||||
|
text-decoration: none; }
|
||||||
|
|
||||||
|
.introjs-prevbutton {
|
||||||
|
float: left; }
|
||||||
|
|
||||||
|
.introjs-nextbutton {
|
||||||
|
float: right; }
|
||||||
|
|
||||||
|
.introjs-disabled {
|
||||||
|
color: #9e9e9e;
|
||||||
|
border-color: #bdbdbd;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
cursor: default;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
background-image: none;
|
||||||
|
text-decoration: none; }
|
||||||
|
.introjs-disabled:hover, .introjs-disabled:focus {
|
||||||
|
color: #9e9e9e;
|
||||||
|
border-color: #bdbdbd;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
cursor: default;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
background-image: none;
|
||||||
|
text-decoration: none; }
|
||||||
|
|
||||||
|
.introjs-hidden {
|
||||||
|
display: none; }
|
||||||
|
|
||||||
|
.introjs-bullets {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px; }
|
||||||
|
.introjs-bullets ul {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
clear: both;
|
||||||
|
margin: 0 auto 0;
|
||||||
|
padding: 0;
|
||||||
|
display: inline-block; }
|
||||||
|
.introjs-bullets ul li {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
list-style: none;
|
||||||
|
float: left;
|
||||||
|
margin: 0 2px; }
|
||||||
|
.introjs-bullets ul li a {
|
||||||
|
-webkit-transition: width 0.1s ease-in;
|
||||||
|
-o-transition: width 0.1s ease-in;
|
||||||
|
transition: width 0.1s ease-in;
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
display: block;
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
background: #ccc;
|
||||||
|
border-radius: 10px;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer; }
|
||||||
|
.introjs-bullets ul li a:hover, .introjs-bullets ul li a:focus {
|
||||||
|
width: 15px;
|
||||||
|
background: #999;
|
||||||
|
text-decoration: none;
|
||||||
|
outline: none; }
|
||||||
|
.introjs-bullets ul li a.active {
|
||||||
|
width: 15px;
|
||||||
|
background: #999; }
|
||||||
|
|
||||||
|
.introjs-progress {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 10px;
|
||||||
|
margin: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #e0e0e0; }
|
||||||
|
|
||||||
|
.introjs-progressbar {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
float: left;
|
||||||
|
width: 0%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 10px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #08c; }
|
||||||
|
|
||||||
|
.introjsFloatingElement {
|
||||||
|
position: absolute;
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%; }
|
||||||
|
|
||||||
|
.introjs-fixedTooltip {
|
||||||
|
position: fixed; }
|
||||||
|
|
||||||
|
.introjs-hint {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
position: absolute;
|
||||||
|
background: transparent;
|
||||||
|
width: 20px;
|
||||||
|
height: 15px;
|
||||||
|
cursor: pointer; }
|
||||||
|
.introjs-hint:focus {
|
||||||
|
border: 0;
|
||||||
|
outline: 0; }
|
||||||
|
.introjs-hint:hover > .introjs-hint-pulse {
|
||||||
|
border: 5px solid rgba(60, 60, 60, 0.57); }
|
||||||
|
|
||||||
|
.introjs-hidehint {
|
||||||
|
display: none; }
|
||||||
|
|
||||||
|
.introjs-fixedhint {
|
||||||
|
position: fixed; }
|
||||||
|
|
||||||
|
.introjs-hint-pulse {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border: 5px solid rgba(60, 60, 60, 0.27);
|
||||||
|
border-radius: 30px;
|
||||||
|
background-color: rgba(136, 136, 136, 0.24);
|
||||||
|
z-index: 10;
|
||||||
|
position: absolute;
|
||||||
|
-webkit-transition: all 0.2s ease-out;
|
||||||
|
-o-transition: all 0.2s ease-out;
|
||||||
|
transition: all 0.2s ease-out; }
|
||||||
|
|
||||||
|
.introjs-hint-no-anim .introjs-hint-dot {
|
||||||
|
-webkit-animation: none;
|
||||||
|
animation: none; }
|
||||||
|
|
||||||
|
.introjs-hint-dot {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
border: 10px solid rgba(146, 146, 146, 0.36);
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 60px;
|
||||||
|
height: 50px;
|
||||||
|
width: 50px;
|
||||||
|
-webkit-animation: introjspulse 3s ease-out;
|
||||||
|
animation: introjspulse 3s ease-out;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
position: absolute;
|
||||||
|
top: -25px;
|
||||||
|
left: -25px;
|
||||||
|
z-index: 1;
|
||||||
|
opacity: 0; }
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handles loading feature flags and other configuration values.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Configuration;
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace TEC\Common\Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Configuration.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Configuration;
|
||||||
|
*/
|
||||||
|
class Configuration implements Configuration_Provider_Interface {
|
||||||
|
/**
|
||||||
|
* The Configuration loader.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @var Configuration_Loader The loader.
|
||||||
|
*/
|
||||||
|
protected Configuration_Loader $loader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuration service.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @param Configuration_Loader $loader
|
||||||
|
*/
|
||||||
|
public function __construct( Configuration_Loader $loader ) {
|
||||||
|
$this->loader = $loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function all(): array {
|
||||||
|
$configs = [];
|
||||||
|
foreach ( $this->loader->all() as $provider ) {
|
||||||
|
$configs = array_merge( $configs, $provider->all() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $configs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get( $key ) {
|
||||||
|
foreach ( $this->loader->all() as $provider ) {
|
||||||
|
if ( $provider->has( $key ) ) {
|
||||||
|
return $provider->get( $key );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function has( $key ): bool {
|
||||||
|
foreach ( $this->loader->all() as $provider ) {
|
||||||
|
if ( $provider->has( $key ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handles loading configuration services.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Configuration;
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace TEC\Common\Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Configuration_Loader.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Configuration;
|
||||||
|
*/
|
||||||
|
class Configuration_Loader {
|
||||||
|
/**
|
||||||
|
* @var array<Configuration_Provider_Interface>
|
||||||
|
*/
|
||||||
|
protected static $providers = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a var provider to the list of providers referenced when accessing a variable
|
||||||
|
* from within the Configuration object.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @param Configuration_Provider_Interface $provider
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function add( Configuration_Provider_Interface $provider ): self {
|
||||||
|
if ( is_callable( [ $provider, 'register' ] ) ) {
|
||||||
|
$provider->register();
|
||||||
|
}
|
||||||
|
self::$providers[] = $provider;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a list of all Configuration_Provider_Interface providers loaded.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @return Configuration_Provider_Interface[]
|
||||||
|
*/
|
||||||
|
public function all(): array {
|
||||||
|
return self::$providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the providers.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function reset(): self {
|
||||||
|
self::$providers = [];
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Interface used to provider access to a particular configuration for the Configuration_Loader.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Configuration;
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace TEC\Common\Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface Configuration_Provider_Interface.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Configuration;
|
||||||
|
*/
|
||||||
|
interface Configuration_Provider_Interface {
|
||||||
|
/**
|
||||||
|
* Whether a particular variable is defined or not.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @param $key string Variable name.
|
||||||
|
*
|
||||||
|
* @return bool Whether the variable is defined or not.
|
||||||
|
*/
|
||||||
|
public function has( string $key ): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the value for the given variable.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @param $key string Variable name.
|
||||||
|
*
|
||||||
|
* @return null|mixed
|
||||||
|
*/
|
||||||
|
public function get( string $key );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve all variables defined in an associative array.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @return array All vars.
|
||||||
|
*/
|
||||||
|
public function all(): array;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Provides a constants value for the Configuration_Loader.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Configuration;
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace TEC\Common\Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Constants_Provider.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Configuration;
|
||||||
|
*/
|
||||||
|
class Constants_Provider implements Configuration_Provider_Interface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function has( $key ): bool {
|
||||||
|
return defined( $key );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get( $key ) {
|
||||||
|
if ( $this->has( $key ) ) {
|
||||||
|
return constant( $key );
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function all(): array {
|
||||||
|
return get_defined_constants( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
# System Configuration
|
||||||
|
|
||||||
|
Provides a system-wide set of configuration values. Easily access feature flags, and other immutable configurations.
|
||||||
|
|
||||||
|
Inspired by systems that load configurations from various sources, like retrieving `conf.ini` or `.env` values.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Add a configuration loader, so the system knows where to get the configuration values from.
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Constants_Provider.php
|
||||||
|
class Constants_Provider implements Configuration_Provider_Interface {
|
||||||
|
|
||||||
|
public function has( $key ): bool {
|
||||||
|
return defined( $key );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get( $key ) {
|
||||||
|
if ( $this->has( $key ) ) {
|
||||||
|
|
||||||
|
return constant( $key );
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function all(): array {
|
||||||
|
return get_defined_constants( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```php
|
||||||
|
// Provider.php
|
||||||
|
|
||||||
|
class Provider {
|
||||||
|
protected function register(): void {
|
||||||
|
// Can add other loaders with other configuration values, such as local vs prod configurations.
|
||||||
|
tribe( Configuration_Loader::class )->add( new Constants_Provider() )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This is an extensible loader to allow various configuration sources and application specific logic to bind configuration providers in different ways.
|
||||||
|
|
||||||
|
## Retrieve Configuration Value
|
||||||
|
|
||||||
|
```php
|
||||||
|
// wp-config.php
|
||||||
|
define('TEC_FEATURE_FLAG', true);
|
||||||
|
```
|
||||||
|
```php
|
||||||
|
// Model.php
|
||||||
|
public function tec_magic() {
|
||||||
|
// Feature enabled?
|
||||||
|
if ( tribe( Configuration::class )->get( 'TEC_FEATURE_FLAG' ) ) {
|
||||||
|
// do stuff...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Provides methods to check and get the post state from the current request context.
|
||||||
|
*
|
||||||
|
* @since 5.0.13
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Context;
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace TEC\Common\Context;
|
||||||
|
|
||||||
|
use WP_Post;
|
||||||
|
use Tribe__Utils__Array as Arr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Post_Request_Type.
|
||||||
|
*
|
||||||
|
* @since 5.0.13
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Context;
|
||||||
|
*/
|
||||||
|
class Post_Request_Type {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the current request is one to quick edit a single post of the specified post type or not.
|
||||||
|
*
|
||||||
|
* @since 5.0.13
|
||||||
|
*
|
||||||
|
* @param string|array<string> $post_type The post type or post types to check.
|
||||||
|
*
|
||||||
|
* @return bool Whether the current request is one to quick edit a single post of the specified post type or not.
|
||||||
|
*/
|
||||||
|
public function is_inline_editing_post( $post_type ): bool {
|
||||||
|
if ( ! ( ! empty( $post_type ) && wp_doing_ajax() && tribe_get_request_var( 'action' ) === 'inline-save' ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$post_id = tribe_get_request_var( 'post_ID', null );
|
||||||
|
|
||||||
|
if ( empty( $post_id ) || ! is_numeric( $post_id ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return in_array( get_post_type( $post_id ), (array) $post_type, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the current request is one to edit a list of the specified post types or not.
|
||||||
|
*
|
||||||
|
* The admin edit screen for a post type is the one that lists all the posts of that typ,
|
||||||
|
* it has the URL `/wp-admin/edit.php?post_type=<post_type>`.
|
||||||
|
*
|
||||||
|
* @since 5.0.13
|
||||||
|
*
|
||||||
|
* @param string|array<string> $post_type The post type or post types to check.
|
||||||
|
*
|
||||||
|
* @return bool Whether the current request is one to edit a list of the specified post types or not.
|
||||||
|
*/
|
||||||
|
public function is_editing_post_list( $post_type ): bool {
|
||||||
|
// Quick check: are we on the `/wp-admin/edit.php` page?
|
||||||
|
global $pagenow;
|
||||||
|
|
||||||
|
if ( $pagenow !== 'edit.php' ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run some more thorough checks for the post type(s).
|
||||||
|
$post_types = array_filter( (array) $post_type );
|
||||||
|
|
||||||
|
return $this->is_editing_post( $post_types );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether we are currently creating a new post, a post of post type(s) or not.
|
||||||
|
*
|
||||||
|
* @since 4.7.7
|
||||||
|
*
|
||||||
|
* @param null $post_type The optional post type to check.
|
||||||
|
*
|
||||||
|
* @return bool Whether we are currently creating a new post, a post of post type(s) or not.
|
||||||
|
*/
|
||||||
|
public function is_new_post( $post_type = null ): bool {
|
||||||
|
global $pagenow;
|
||||||
|
$is_new = 'post-new.php' === $pagenow;
|
||||||
|
|
||||||
|
return $is_new && $this->is_editing_post( $post_type );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether we are currently editing a post(s), post type(s) or not.
|
||||||
|
*
|
||||||
|
* @since 4.7.7
|
||||||
|
*
|
||||||
|
* @param null|array|string|int $post_or_type A post ID, post type, an array of post types or post IDs, `null`
|
||||||
|
* to just make sure we are currently editing a post.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function is_editing_post( $post_or_type = null ): bool {
|
||||||
|
global $pagenow;
|
||||||
|
$is_new = 'post-new.php' === $pagenow;
|
||||||
|
$is_post = 'post.php' === $pagenow;
|
||||||
|
$is_editing = 'edit.php' === $pagenow;
|
||||||
|
|
||||||
|
if ( ! ( $is_new || $is_post || $is_editing ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $post_or_type ) ) {
|
||||||
|
$lookup = [];
|
||||||
|
// Prevent a slew of warnings every time we call this.
|
||||||
|
if ( isset( $_REQUEST ) ) {
|
||||||
|
$lookup[] = (array) $_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset( $_GET ) ) {
|
||||||
|
$lookup[] = (array) $_GET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset( $_POST ) ) {
|
||||||
|
$lookup[] = (array) $_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty( $lookup ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$current_post = Arr::get_in_any( $lookup, 'post', get_post() );
|
||||||
|
|
||||||
|
if ( is_numeric( $post_or_type ) ) {
|
||||||
|
$post = $is_post ? get_post( $post_or_type ) : null;
|
||||||
|
|
||||||
|
return ! empty( $post ) && $post == $current_post;
|
||||||
|
}
|
||||||
|
|
||||||
|
$post_types = is_array( $post_or_type ) ? $post_or_type : [ $post_or_type ];
|
||||||
|
|
||||||
|
$post = $is_post ? get_post( $current_post ) : null;
|
||||||
|
|
||||||
|
if ( count( array_filter( $post_types, 'is_numeric' ) ) === count( $post_types ) ) {
|
||||||
|
return ! empty( $post ) && in_array( $post->ID, $post_types );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $is_post && $post instanceof WP_Post ) {
|
||||||
|
$post_type = $post->post_type;
|
||||||
|
} else {
|
||||||
|
$post_type = Arr::get_in_any( $lookup, 'post_type', 'post' );
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bool) count( array_intersect( $post_types, [ $post_type ] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $is_new || $is_post;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Contracts;
|
||||||
|
|
||||||
|
use TEC\Common\StellarWP\ContainerContract\ContainerInterface;
|
||||||
|
use TEC\Common\Exceptions\Not_Bound_Exception;
|
||||||
|
|
||||||
|
use TEC\Common\lucatume\DI52\Container as DI52_Container;
|
||||||
|
|
||||||
|
class Container extends DI52_Container implements ContainerInterface {
|
||||||
|
/**
|
||||||
|
* Finds an entry of the container by its identifier and returns it.
|
||||||
|
*
|
||||||
|
* @since 5.1.1.2
|
||||||
|
*
|
||||||
|
* @throws Not_Bound_Exception Error while retrieving the entry.
|
||||||
|
*
|
||||||
|
* @param string $id A fully qualified class or interface name or an already built object.
|
||||||
|
*
|
||||||
|
* @return mixed The entry for an id.
|
||||||
|
*/
|
||||||
|
public function get( $id ) {
|
||||||
|
try {
|
||||||
|
return parent::get( $id );
|
||||||
|
} catch ( \Exception $e ) {
|
||||||
|
// Do not chain the previous exception into ours, as it makes the error log confusing.
|
||||||
|
throw new Not_Bound_Exception( $e->getMessage(), $e->getCode() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The base class all Controllers should extend.
|
||||||
|
*
|
||||||
|
* @since 5.0.17
|
||||||
|
* @since 5.1.0 moved.
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Contracts\Provider;
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace TEC\Common\Contracts\Provider;
|
||||||
|
|
||||||
|
use TEC\Common\Contracts\Service_Provider as Service_Provider;
|
||||||
|
use TEC\Common\StellarWP\ContainerContract\ContainerInterface;
|
||||||
|
use Tribe__Log as Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Controller.
|
||||||
|
*
|
||||||
|
* @since 5.0.17
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Provider;
|
||||||
|
*
|
||||||
|
* @property ContainerInterface $container
|
||||||
|
*/
|
||||||
|
abstract class Controller extends Service_Provider {
|
||||||
|
/**
|
||||||
|
* Registers the filters and actions hooks added by the controller if the controller has not registered yet.
|
||||||
|
*
|
||||||
|
* @since 5.0.17
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register() {
|
||||||
|
/*
|
||||||
|
* Look up and set the value in the container request cache to allow building the same Controller
|
||||||
|
* with a **different** container. (e.g. in tests).
|
||||||
|
*/
|
||||||
|
if ( static::is_registered() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the controller as a singleton in the container.
|
||||||
|
// @todo remove when the Container is updated to bind Providers as singletons by default.
|
||||||
|
$this->container->singleton( static::class, $this );
|
||||||
|
|
||||||
|
if ( ! $this->is_active() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->container->setVar( static::class . '_registered', true );
|
||||||
|
|
||||||
|
$this->do_register();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the filters and actions hooks added by the controller.
|
||||||
|
*
|
||||||
|
* @since 5.0.17
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
abstract protected function do_register(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the filters and actions hooks added by the controller.
|
||||||
|
*
|
||||||
|
* Bound implementations should not be removed in this method!
|
||||||
|
*
|
||||||
|
* @since 5.0.17
|
||||||
|
*
|
||||||
|
* @return void Filters and actions hooks added by the controller are be removed.
|
||||||
|
*/
|
||||||
|
abstract public function unregister(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the controller is active or not.
|
||||||
|
*
|
||||||
|
* Controllers will be active by default, if that is not the case, the controller should override this method.
|
||||||
|
*
|
||||||
|
* @since 5.0.17
|
||||||
|
*
|
||||||
|
* @return bool Whether the controller is active or not.
|
||||||
|
*/
|
||||||
|
public function is_active(): bool {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a message at the `debug` level.
|
||||||
|
*
|
||||||
|
* @since 5.0.17
|
||||||
|
*
|
||||||
|
* @param string $message The message to log.
|
||||||
|
* @param array $context An array of context to log with the message.
|
||||||
|
*
|
||||||
|
* @return void The message is logged.
|
||||||
|
*/
|
||||||
|
protected function debug( string $message, array $context = [] ): void {
|
||||||
|
do_action( 'tribe_log', Log::DEBUG, $message, array_merge( [
|
||||||
|
'controller' => static::class,
|
||||||
|
], $context ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a message at the `warning` level.
|
||||||
|
*
|
||||||
|
* @since 5.0.17
|
||||||
|
*
|
||||||
|
* @param string $message The message to log.
|
||||||
|
* @param array $context An array of context to log with the message.
|
||||||
|
*
|
||||||
|
* @return void The message is logged.
|
||||||
|
*/
|
||||||
|
protected function warning( string $message, array $context = [] ): void {
|
||||||
|
do_action( 'tribe_log', Log::WARNING, $message, array_merge( [
|
||||||
|
'controller' => static::class,
|
||||||
|
], $context ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a message at the `error` level.
|
||||||
|
*
|
||||||
|
* @since 5.0.17
|
||||||
|
*
|
||||||
|
* @param string $message The message to log.
|
||||||
|
* @param array $context An array of context to log with the message.
|
||||||
|
*
|
||||||
|
* @return void The message is logged.
|
||||||
|
*/
|
||||||
|
protected function error( string $message, array $context = [] ): void {
|
||||||
|
do_action( 'tribe_log', Log::ERROR, $message, array_merge( [
|
||||||
|
'controller' => static::class,
|
||||||
|
], $context ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether any instance of this controller has been registered or not.
|
||||||
|
*
|
||||||
|
* @since 5.0.17
|
||||||
|
*
|
||||||
|
* @return bool Whether any instance of this controller has been registered or not.
|
||||||
|
*/
|
||||||
|
public static function is_registered(): bool {
|
||||||
|
return (bool) tribe()->getVar( static::class . '_registered' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Contracts;
|
||||||
|
|
||||||
|
use TEC\Common\lucatume\DI52\ServiceProvider as DI52_Service_Provider;
|
||||||
|
|
||||||
|
abstract class Service_Provider extends DI52_Service_Provider {
|
||||||
|
// Intentionally empty.
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Editor\Full_Site;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Template_Utils.
|
||||||
|
*
|
||||||
|
* @since 4.14.18
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Editor\Full_Site
|
||||||
|
*/
|
||||||
|
class Template_Utils {
|
||||||
|
/**
|
||||||
|
* Returns an array containing the references of the passed blocks and their inner blocks.
|
||||||
|
*
|
||||||
|
* When we return we are replacing/overwriting $blocks with $all_blocks so we pass-by-reference.
|
||||||
|
* If we don't pass-by-reference the non-event blocks get lost (ex: header and footer)
|
||||||
|
*
|
||||||
|
* @since 4.14.18
|
||||||
|
*
|
||||||
|
* @param array<array<string,mixed>> $blocks Array of parsed block objects.
|
||||||
|
*
|
||||||
|
* @return array<array<string,mixed>> Block references to the passed blocks and their inner blocks.
|
||||||
|
*/
|
||||||
|
public static function flatten_blocks( &$blocks ) {
|
||||||
|
$all_blocks = [];
|
||||||
|
$queue = [];
|
||||||
|
|
||||||
|
foreach ( $blocks as &$block ) {
|
||||||
|
$queue[] = &$block;
|
||||||
|
}
|
||||||
|
|
||||||
|
$queue_count = count( $queue );
|
||||||
|
|
||||||
|
while ( $queue_count > 0 ) {
|
||||||
|
$block = &$queue[0];
|
||||||
|
array_shift( $queue );
|
||||||
|
$all_blocks[] = &$block;
|
||||||
|
|
||||||
|
if ( ! empty( $block['innerBlocks'] ) ) {
|
||||||
|
foreach ( $block['innerBlocks'] as &$inner_block ) {
|
||||||
|
$queue[] = &$inner_block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$queue_count = count( $queue );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $all_blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses wp_template content and injects the current theme's stylesheet as a theme attribute into
|
||||||
|
* each wp_template_part.
|
||||||
|
*
|
||||||
|
* @since 4.14.18
|
||||||
|
*
|
||||||
|
* @param string $template_content serialized wp_template content.
|
||||||
|
*
|
||||||
|
* @return string Updated wp_template content.
|
||||||
|
*/
|
||||||
|
public static function inject_theme_attribute_in_content( $template_content ) {
|
||||||
|
$has_updated_content = false;
|
||||||
|
$new_content = '';
|
||||||
|
$template_blocks = parse_blocks( $template_content );
|
||||||
|
|
||||||
|
$blocks = static::flatten_blocks( $template_blocks );
|
||||||
|
foreach ( $blocks as &$block ) {
|
||||||
|
if (
|
||||||
|
'core/template-part' === $block['blockName'] &&
|
||||||
|
! isset( $block['attrs']['theme'] )
|
||||||
|
) {
|
||||||
|
$block['attrs']['theme'] = wp_get_theme()->get_stylesheet();
|
||||||
|
$has_updated_content = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $has_updated_content ) {
|
||||||
|
foreach ( $template_blocks as &$block ) {
|
||||||
|
$new_content .= serialize_block( $block );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $new_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $template_content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Exceptions;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Container_Exception.
|
||||||
|
*
|
||||||
|
* @since 5.1.1.2
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Exceptions
|
||||||
|
*/
|
||||||
|
class Container_Exception extends RuntimeException {
|
||||||
|
// Intentionally empty.
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Exceptions;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Not_Bound_Exception.
|
||||||
|
*
|
||||||
|
* @since 5.1.1.2
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Exceptions
|
||||||
|
*/
|
||||||
|
class Not_Bound_Exception extends Container_Exception {
|
||||||
|
// Intentionally empty.
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Abstract for Integrations.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Integrations
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace TEC\Common\Integrations;
|
||||||
|
use TEC\Common\Contracts\Service_Provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Integration_Abstract
|
||||||
|
*
|
||||||
|
* @link https://docs.theeventscalendar.com/apis/integrations/including-new-integrations/
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Integrations
|
||||||
|
*/
|
||||||
|
abstract class Integration_Abstract extends Service_Provider {
|
||||||
|
/**
|
||||||
|
* Binds and sets up implementations.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*/
|
||||||
|
public function register() {
|
||||||
|
// Registers this provider as a singleton for ease of use.
|
||||||
|
$this->container->singleton( self::class, self::class );
|
||||||
|
|
||||||
|
// Prevents any loading in case we shouldn't load.
|
||||||
|
if ( ! $this->should_load() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->load();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the slug for this integration parent, the main plugin that is being integrated to.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract public static function get_parent(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the slug for this integration.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract public static function get_slug(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether this integration should load.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function should_load(): bool {
|
||||||
|
return $this->filter_should_load( $this->load_conditionals() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters whether the integration should load.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @param bool $value Whether the integration should load.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function filter_should_load( bool $value ): bool {
|
||||||
|
$parent = static::get_parent();
|
||||||
|
$slug = static::get_slug();
|
||||||
|
$type = static::get_type();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters if integrations should be loaded.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @param bool $value Whether the integration should load.
|
||||||
|
* @param string $type Type of integration we are loading.
|
||||||
|
* @param string $slug Slug of the integration we are loading.
|
||||||
|
*/
|
||||||
|
$value = apply_filters( 'tec_integration:should_load', $value, $parent, $type, $slug );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters if integrations should be loaded.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @param bool $value Whether the integration should load.
|
||||||
|
* @param string $type Type of integration we are loading.
|
||||||
|
* @param string $slug Slug of the integration we are loading.
|
||||||
|
*/
|
||||||
|
$value = apply_filters( "tec_integration:{$parent}/should_load", $value, $type, $slug );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters if integrations of the current type should be loaded.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @param bool $value Whether the integration should load.
|
||||||
|
* @param string $slug Slug of the integration we are loading.
|
||||||
|
*/
|
||||||
|
$value = apply_filters( "tec_integration:{$parent}/{$type}/should_load", $value, $slug );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters if a specific integration (by type and slug) should be loaded.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @param bool $value Whether the integration should load.
|
||||||
|
*/
|
||||||
|
return (bool) apply_filters( "tec_integration:{$parent}/{$type}/{$slug}/should_load", $value );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the integration in question should be loaded.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
abstract public function load_conditionals(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the integration itself.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
abstract protected function load(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the integration type.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract public static function get_type(): string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handles Integrations.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Integrations
|
||||||
|
*/
|
||||||
|
namespace TEC\Common\Integrations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Provider.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Integrations
|
||||||
|
*/
|
||||||
|
class Provider extends \TEC\Common\Contracts\Service_Provider {
|
||||||
|
/**
|
||||||
|
* Binds and sets up implementations.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*/
|
||||||
|
public function register() {
|
||||||
|
$this->container->singleton( static::class, $this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Integrations\Traits;
|
||||||
|
|
||||||
|
trait Module_Integration {
|
||||||
|
/**
|
||||||
|
* Gets the integration type.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_type(): string {
|
||||||
|
return 'module';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Integrations\Traits;
|
||||||
|
|
||||||
|
trait Plugin_Integration {
|
||||||
|
/**
|
||||||
|
* Gets the integration type.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_type(): string {
|
||||||
|
return 'plugin';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Integrations\Traits;
|
||||||
|
|
||||||
|
trait Server_Integration {
|
||||||
|
/**
|
||||||
|
* Gets the integration type.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_type(): string {
|
||||||
|
return 'server';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Integrations\Traits;
|
||||||
|
|
||||||
|
trait Theme_Integration {
|
||||||
|
/**
|
||||||
|
* Gets the integration type.
|
||||||
|
*
|
||||||
|
* @since 5.1.1
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_type(): string {
|
||||||
|
return 'theme';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Libraries\Installer;
|
||||||
|
|
||||||
|
use TEC\Common\Libraries;
|
||||||
|
use TEC\Common\StellarWP\Installer;
|
||||||
|
use TEC\Common\Contracts\Service_Provider;
|
||||||
|
|
||||||
|
|
||||||
|
class Provider extends Service_Provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds and sets up implementations.
|
||||||
|
*
|
||||||
|
* @since 5.0.10
|
||||||
|
*/
|
||||||
|
public function register() {
|
||||||
|
$this->container->singleton( static::class, $this );
|
||||||
|
|
||||||
|
$hook_prefix = $this->container->make( Libraries\Provider::class )->get_hook_prefix();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Installer\Config::set_hook_prefix( $hook_prefix );
|
||||||
|
} catch ( \Exception $e ) {
|
||||||
|
// Ignore.
|
||||||
|
}
|
||||||
|
|
||||||
|
add_filter( "stellarwp/installer/{$hook_prefix}/button_classes", [ $this, 'filter_button_classes' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the installer button classes.
|
||||||
|
*
|
||||||
|
* @since 5.0.10
|
||||||
|
*
|
||||||
|
* @param array|mixed $classes The button classes.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function filter_button_classes( $classes ) {
|
||||||
|
if ( ! is_array( $classes ) ) {
|
||||||
|
$classes = (array) $classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
$classes[] = 'components-button';
|
||||||
|
$classes[] = 'is-primary';
|
||||||
|
$classes[] = 'tec-admin__notice-install-content-button';
|
||||||
|
return $classes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Libraries;
|
||||||
|
|
||||||
|
use TEC\Common\StellarWP\DB;
|
||||||
|
use TEC\Common\Contracts\Service_Provider;
|
||||||
|
|
||||||
|
|
||||||
|
class Provider extends Service_Provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook prefix.
|
||||||
|
*
|
||||||
|
* @since 5.0.10
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected static $hook_prefix = 'tec';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds and sets up implementations.
|
||||||
|
*
|
||||||
|
* @since 5.0.10
|
||||||
|
*/
|
||||||
|
public function register() {
|
||||||
|
$this->container->singleton( static::class, $this );
|
||||||
|
|
||||||
|
tribe_register_provider( Installer\Provider::class );
|
||||||
|
|
||||||
|
DB\Config::setHookPrefix( $this->get_hook_prefix() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the hook prefix.
|
||||||
|
*
|
||||||
|
* @since 5.0.10
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_hook_prefix(): string {
|
||||||
|
return static::$hook_prefix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Site_Health;
|
||||||
|
|
||||||
|
use Tribe__Main;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Factory
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/reference/hooks/debug_information/
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Site_Health
|
||||||
|
*/
|
||||||
|
class Factory {
|
||||||
|
/**
|
||||||
|
* Generates a Generic field from a set of arguments.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param string $label
|
||||||
|
* @param array|string|null $value
|
||||||
|
* @param int $priority (optional) By default all fields are generated with priority 50.
|
||||||
|
*
|
||||||
|
* @return Info_Field_Abstract
|
||||||
|
*/
|
||||||
|
public static function generate_generic_field( string $id, string $label, $value, int $priority = 50 ): Info_Field_Abstract {
|
||||||
|
return new Fields\Generic_Info_Field( $id, $label, $value, $priority );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a Post type count field from a set of arguments.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param string $post_type
|
||||||
|
* @param int $priority (optional) By default all fields are generated with priority 50.
|
||||||
|
*
|
||||||
|
* @return Info_Field_Abstract
|
||||||
|
*/
|
||||||
|
public static function generate_post_status_count_field( string $id, string $post_type, int $priority = 50 ): Info_Field_Abstract {
|
||||||
|
return new Fields\Post_Status_Count_Field( $id, $post_type, $priority );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all registered sections.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return array<string,Info_Section_Abstract>
|
||||||
|
*/
|
||||||
|
public function get_sections(): array {
|
||||||
|
/**
|
||||||
|
* Allows filtering of the Common Info Sections.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $sections Which sections exist.
|
||||||
|
*/
|
||||||
|
$sections = (array) apply_filters( 'tec_debug_info_sections', [] );
|
||||||
|
|
||||||
|
return array_filter( $sections, static function ( $section ) {
|
||||||
|
return $section instanceof Info_Section_Abstract;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the section after which we will insert all the factory-generated sections.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function get_insert_after_section_key(): string {
|
||||||
|
return 'wp-media';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the actual site health data to include our sections.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param array $info
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function filter_include_info_sections( array $info = [] ) {
|
||||||
|
$sections = [];
|
||||||
|
foreach ( $this->get_sections() as $key => $section ) {
|
||||||
|
$sections[ $key ] = $section->to_array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$info = Tribe__Main::array_insert_after_key( $this->get_insert_after_section_key(), $info, $sections );
|
||||||
|
|
||||||
|
return $info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Site_Health\Fields;
|
||||||
|
|
||||||
|
use TEC\Common\Site_Health\Info_Field_Abstract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Generic_Info_Field
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Site_Health
|
||||||
|
*/
|
||||||
|
class Generic_Info_Field extends Info_Field_Abstract {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure all the params for a generic field.
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param string $label
|
||||||
|
* @param array<string,string>|string|null $value
|
||||||
|
* @param int $priority
|
||||||
|
*/
|
||||||
|
public function __construct( string $id, string $label, $value = null, int $priority = 50 ) {
|
||||||
|
$this->id = $id;
|
||||||
|
$this->label = $label;
|
||||||
|
$this->value = $value;
|
||||||
|
$this->priority = $priority;
|
||||||
|
$this->is_private = true;
|
||||||
|
$this->debug = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an array of configurations sets up a new generic field instance.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param array $field
|
||||||
|
*
|
||||||
|
* @return Info_Field_Abstract
|
||||||
|
*/
|
||||||
|
public static function from_array( array $field ): Info_Field_Abstract {
|
||||||
|
return new static( $field['id'], $field['label'], $field['value'], $field['priority'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given all the arguments create a new Generic Field.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param string $label
|
||||||
|
* @param string|null $value
|
||||||
|
* @param int $priority
|
||||||
|
*
|
||||||
|
* @return Info_Field_Abstract
|
||||||
|
*/
|
||||||
|
public static function from_args( string $id, string $label, ?string $value, int $priority = 50 ): Info_Field_Abstract {
|
||||||
|
return new static( $id, $label, $value, $priority );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Site_Health\Fields;
|
||||||
|
|
||||||
|
use TEC\Common\Site_Health\Info_Field_Abstract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Post_Status_Count_Field
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Site_Health
|
||||||
|
*/
|
||||||
|
class Post_Status_Count_Field extends Generic_Info_Field {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the post type for the field.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected string $post_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure all the params for a generic field.
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param string $label
|
||||||
|
* @param array<string,string>|string|null $value
|
||||||
|
* @param int $priority
|
||||||
|
*/
|
||||||
|
public function __construct( string $id, string $post_type = null, int $priority = 50 ) {
|
||||||
|
$this->id = $id;
|
||||||
|
$this->post_type = $post_type;
|
||||||
|
$this->priority = $priority;
|
||||||
|
$this->is_private = true;
|
||||||
|
$this->debug = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get_label(): string {
|
||||||
|
$post_type_obj = get_post_type_object( $this->post_type );
|
||||||
|
$name = $post_type_obj->label;
|
||||||
|
|
||||||
|
if ( ! empty( $post_type_obj->labels->singular_name ) ) {
|
||||||
|
$name = $post_type_obj->labels->singular_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf(
|
||||||
|
/* Translators: %1$s the post type label. */
|
||||||
|
esc_html__( '%1$s counts', 'tribe-common' ),
|
||||||
|
$name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get_value() {
|
||||||
|
return $this->get_counts();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a post status count object to an array in the format
|
||||||
|
* [ (string) status_slug => (int) count]
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param stdClass $obj The object returned from wp_count_posts().
|
||||||
|
*
|
||||||
|
* @return array<string,int> An array of stati (key) with counts (value).
|
||||||
|
*/
|
||||||
|
protected function get_counts(): array {
|
||||||
|
$counts = (array) wp_count_posts( $this->post_type );
|
||||||
|
$stati = [
|
||||||
|
'publish',
|
||||||
|
'future',
|
||||||
|
'draft',
|
||||||
|
'pending',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows other plugins to add/remove stati to track.
|
||||||
|
*
|
||||||
|
* @param array<string|bool> $stati An array of stati to track.
|
||||||
|
* @param self $field The field instance.
|
||||||
|
*/
|
||||||
|
$stati = apply_filters( 'tec_site_heath_event_stati', $stati, $this );
|
||||||
|
|
||||||
|
$keys = array_keys( $counts );
|
||||||
|
foreach( $keys as $key ) {
|
||||||
|
if ( ! in_array( $key, $stati ) ) {
|
||||||
|
unset( $counts[ $key ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $counts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Site_Health;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Info_Field_Abstract
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/reference/hooks/debug_information/
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Site_Health
|
||||||
|
*/
|
||||||
|
abstract class Info_Field_Abstract implements Info_Field_Interface {
|
||||||
|
/**
|
||||||
|
* Stores the ID for the field.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected string $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the label for the field.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected string $label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the value for field.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return string|int|float|array<int>|array<float>|array<string>
|
||||||
|
*/
|
||||||
|
protected $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the priority for the field, used for sorting.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected int $priority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the flag for if the field is private.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected bool $is_private;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the debug value for the field.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected string $debug;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get_id(): string {
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get_label(): string {
|
||||||
|
return $this->label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get_value() {
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get_priority(): int {
|
||||||
|
return $this->priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function is_private(): bool {
|
||||||
|
return $this->is_private;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get_debug(): string {
|
||||||
|
return $this->debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function to_array(): array {
|
||||||
|
return [
|
||||||
|
'id' => $this->filter_param( 'id', $this->get_id() ),
|
||||||
|
'label' => $this->filter_param( 'label', $this->get_label() ),
|
||||||
|
'value' => $this->filter_param( 'value', $this->get_value() ),
|
||||||
|
'priority' => $this->filter_param( 'priority', $this->get_priority() ),
|
||||||
|
'private' => $this->filter_param( 'private', $this->is_private() ),
|
||||||
|
'debug' => $this->filter_param( 'debug', $this->get_debug() ),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method to the Field class, to allow filtering of specific values.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param string $param The field parameter we're filtering.
|
||||||
|
* @param mixed $value Value of the field.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
protected function filter_param( string $param, $value = null ) {
|
||||||
|
$field_id = $this->get_id();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the get of a particular param for all fields.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param mixed $value Value of the field.
|
||||||
|
* @param Info_Field_Abstract $field Current Field.
|
||||||
|
*/
|
||||||
|
$value = apply_filters( "tec_debug_info_field_get_{$param}", $value, $this );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the get of a particular param for a specific section + field combination.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param mixed $value Value of the field.
|
||||||
|
* @param Info_Field_Abstract $field Current Field.
|
||||||
|
*/
|
||||||
|
return apply_filters( "tec_debug_info_field_{$field_id}_get_{$param}", $value, $this );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Site_Health;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for Site Health Info Field.
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/reference/hooks/debug_information/
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Site_Health
|
||||||
|
*/
|
||||||
|
interface Info_Field_Interface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ID for this field.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_id(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the label for this field.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_label(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value for this field.
|
||||||
|
* Text should be translated. Can be an associative array that is displayed as name/value pairs.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return string|int|float|array<int>|array<float>|array<string>
|
||||||
|
*/
|
||||||
|
public function get_value();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the priority for the field, used to order fields in a section.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function get_priority(): int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the debug value for the field.
|
||||||
|
*
|
||||||
|
* Optional. The output that is used for this field when the user copies the data. It should be more concise and
|
||||||
|
* not translated. If not set, the content of $value is used. Note that the array keys are used as labels for
|
||||||
|
* the copied data.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_debug(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the field is private or not.
|
||||||
|
*
|
||||||
|
* Optional. If set to true, the field will be excluded from the copied data, allowing you to show, for example, API keys here. Default false.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function is_private(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pulls all the params for this field into an array consumable by the site health info page.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function to_array(): array;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,233 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Site_Health;
|
||||||
|
|
||||||
|
use stdClass;
|
||||||
|
use TEC\Common\Site_Health\Fields\Generic_Info_Field;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Abstract_Info_Section
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/reference/hooks/debug_information/
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Site_Health
|
||||||
|
*/
|
||||||
|
abstract class Info_Section_Abstract implements Info_Section_Interface {
|
||||||
|
/**
|
||||||
|
* Slug for the section.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string $slug
|
||||||
|
*/
|
||||||
|
protected static string $slug;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label for the section.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string $label
|
||||||
|
*/
|
||||||
|
protected string $label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we should show the count of fields in the site health info page.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var bool $show_count
|
||||||
|
*/
|
||||||
|
protected bool $show_count = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this section is private.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var bool $is_private
|
||||||
|
*/
|
||||||
|
protected bool $is_private = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description for the section.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string $description
|
||||||
|
*/
|
||||||
|
protected string $description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which fields are stored on this section.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var array<string, Info_Field_Abstract> $fields
|
||||||
|
*/
|
||||||
|
protected array $fields = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public static function get_slug(): string {
|
||||||
|
return static::$slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function to_array(): array {
|
||||||
|
$fields = [];
|
||||||
|
foreach ( $this->get_fields() as $key => $field ) {
|
||||||
|
$fields[ $key ] = $field->to_array();
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'label' => $this->filter_param( 'label', $this->get_label() ),
|
||||||
|
'description' => $this->filter_param( 'description', $this->get_description() ),
|
||||||
|
'private' => $this->filter_param( 'private', $this->is_private() ),
|
||||||
|
'show_count' => $this->filter_param( 'show_count', $this->get_show_count() ),
|
||||||
|
'fields' => $this->filter_param( 'fields', $fields ),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get_label(): string {
|
||||||
|
return $this->label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get_description(): string {
|
||||||
|
return $this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get_fields(): array {
|
||||||
|
return $this->fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get_show_count(): bool {
|
||||||
|
return $this->show_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function is_private(): bool {
|
||||||
|
return $this->is_private;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function has_field( $field ): bool {
|
||||||
|
// Assume field is a key first.
|
||||||
|
$id = $field;
|
||||||
|
|
||||||
|
// When it's a field use its ID.
|
||||||
|
if ( $field instanceof Info_Field_Abstract ) {
|
||||||
|
$id = $field->get_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keys can only be strings.
|
||||||
|
if ( ! is_string( $id ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields = $this->get_fields();
|
||||||
|
|
||||||
|
return isset( $fields[ $id ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function get_field( string $id ): ?Info_Field_Abstract {
|
||||||
|
if ( ! $this->has_field( $id ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->get_fields()[ $id ];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function add_field( Info_Field_Abstract $field, bool $overwrite = false ): bool {
|
||||||
|
// Allow the adding of a field to overwrite existing fields.
|
||||||
|
if ( ! $overwrite && $this->has_field( $field ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->fields[ $field->get_id() ] = $field;
|
||||||
|
|
||||||
|
$this->sort_fields();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method to the Section class, to allow filtering of specific values.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param string $param
|
||||||
|
* @param mixed $value
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
protected function filter_param( string $param, $value = null ) {
|
||||||
|
$section_slug = static::get_slug();
|
||||||
|
/**
|
||||||
|
* Filters the get of a particular param for all sections.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param mixed $value Value of the field.
|
||||||
|
* @param Info_Section_Abstract $section Current Section.
|
||||||
|
*/
|
||||||
|
$value = apply_filters( "tec_debug_info_section_get_{$param}", $value, $this );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the get of a particular param for a specific section.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param mixed $value Value of the field.
|
||||||
|
* @param Info_Section_Abstract $section Current Section.
|
||||||
|
*/
|
||||||
|
return apply_filters( "tec_debug_info_section_{$section_slug}_get_{$param}", $value, $this );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts the fields stored on this section, will retain keys.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function sort_fields(): void {
|
||||||
|
uasort( $this->fields, static function ( $field_a, $field_b ) {
|
||||||
|
$a = $field_a->get_priority();
|
||||||
|
$b = $field_b->get_priority();
|
||||||
|
|
||||||
|
if ( $a === $b ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( $a < $b ) ? - 1 : 1;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Site_Health;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for Site Health Info Section.
|
||||||
|
*
|
||||||
|
* @link https://developer.wordpress.org/reference/hooks/debug_information/
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Site_Health
|
||||||
|
*/
|
||||||
|
interface Info_Section_Interface {
|
||||||
|
/**
|
||||||
|
* Static way of fetching the slug of this section.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_slug(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the section as an array ready for WordPress site health.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function to_array(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the label for this section.
|
||||||
|
*
|
||||||
|
* @see Info_Section_Abstract::filter_param() For how to hook into this params.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_label(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the description for this section.
|
||||||
|
*
|
||||||
|
* @see Info_Section_Abstract::filter_param() For how to hook into this params.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_description(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether it should show the count of fields for this section.
|
||||||
|
*
|
||||||
|
* @see Info_Section_Abstract::filter_param() For how to hook into this params.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function get_show_count(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this particular section should be copied when using the Site Health.
|
||||||
|
*
|
||||||
|
* @see Info_Section_Abstract::filter_param() For how to hook into this params.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function is_private(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all the fields in this section.
|
||||||
|
*
|
||||||
|
* @see Info_Section_Abstract::filter_param() For how to hook into this params.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return array<string, Info_Field_Abstract>
|
||||||
|
*/
|
||||||
|
public function get_fields(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a given field exists.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param string|Info_Field_Abstract $field
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function has_field( $field ): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Based on the id of the field return the object.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
*
|
||||||
|
* @return Info_Field_Abstract|null
|
||||||
|
*/
|
||||||
|
public function get_field( string $id ): ?Info_Field_Abstract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a field to this section.
|
||||||
|
*
|
||||||
|
* @see Generic_Info_Field If you are looking on how to quickly generate a field without creating a new class.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param Info_Field_Abstract $field What field we are trying to add.
|
||||||
|
* @param bool $overwrite (optional) Determines if we will overwrite the field or not, if found.
|
||||||
|
*
|
||||||
|
* @return bool Determined by if we found a field with that id already.
|
||||||
|
*/
|
||||||
|
public function add_field( Info_Field_Abstract $field, bool $overwrite = false ): bool;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Site_Health;
|
||||||
|
|
||||||
|
use TEC\Common\Contracts\Service_Provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Provider
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Site_Health
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Provider extends Service_Provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the functionality related to this module.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register() {
|
||||||
|
$this->add_filters();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Include the filters related to this module.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function add_filters(): void {
|
||||||
|
add_filter( 'debug_information', [ $this, 'filter_include_info_section' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Includes the info sections controlled by Common.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param array $info Current set of info sections.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function filter_include_info_section( $info ): array {
|
||||||
|
return $this->container->make( Factory::class )->filter_include_info_sections( (array) $info );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,340 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TEC\Common\Storage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Timed_Option which will handle the storage of values that need to be transient in nature but without the
|
||||||
|
* performance cost of Transients. This is specially important when dealing with WordPress installs that have no Object
|
||||||
|
* Caching, on those cases Transients will execute two SQL queries when using `get_transient()`, which is demolishes
|
||||||
|
* the performance of certain pages.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @package TEC\Common
|
||||||
|
*/
|
||||||
|
class Timed_Option {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $active = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prefix for all the Timed Options stored on the database.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $option_name_prefix = 'tec_timed_';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local storage of the data on the Options. Keys will not have the prefix used on the database.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $data = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deactivate the usage of Database Timed Options, all timed options are only a glorified memoization.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function deactivate(): void {
|
||||||
|
$this->active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate the usage of Database Timed Options.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function activate(): void {
|
||||||
|
$this->active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the timed options active?
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function is_active(): bool {
|
||||||
|
/**
|
||||||
|
* Allows the modification of the state of usage for Timed Options.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @param bool $active Whether we use Database Timed Options or a glorified Memoization system.
|
||||||
|
*/
|
||||||
|
return (bool) apply_filters( 'tec_common_timed_option_is_active', $this->active );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the option name for a given timed option, by attaching a prefix and allowing filtering.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @param string $key Key for the option we are trying to get the option name for.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_option_name( string $key ): string {
|
||||||
|
/**
|
||||||
|
* Allows the modification of where we store the Transient Data.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @param string $option_name Name of the option where all the transient data will live.
|
||||||
|
*/
|
||||||
|
return (string) apply_filters( 'tec_common_timed_option_name', $this->option_name_prefix . $key, $this->option_name_prefix );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the value of a given timed option.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @param string $key Key for the option we are trying to get.
|
||||||
|
* @param mixed $default Default value when the option is either expired or not-set.
|
||||||
|
* @param bool $force If we should expire cache and fetch from the database.
|
||||||
|
*
|
||||||
|
* @return mixed|null
|
||||||
|
*/
|
||||||
|
public function get( $key, $default = null, bool $force = false ) {
|
||||||
|
/**
|
||||||
|
* Allows the filtering the default timed_option value.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @param mixed $default Default value when the option is either expired or not-set.
|
||||||
|
* @param string $key Key for the option we are trying to get.
|
||||||
|
* @param bool $force If we should expire cache and fetch from the database.
|
||||||
|
*/
|
||||||
|
$default = apply_filters( 'tec_common_timed_option_default_value', $default, $key, $force );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the filtering to short-circuit the whole fetch logic.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @param mixed|null $pre If anything diff than null it will short-circuit.
|
||||||
|
* @param string $key Key for the option we are trying to get.
|
||||||
|
* @param mixed $default Default value when the option is either expired or not-set.
|
||||||
|
* @param bool $force If we should expire cache and fetch from the database.
|
||||||
|
*/
|
||||||
|
$pre = apply_filters( 'tec_common_timed_option_pre_value', null, $key, $default, $force );
|
||||||
|
|
||||||
|
if ( null !== $pre ) {
|
||||||
|
return $pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
$time = time();
|
||||||
|
|
||||||
|
// If we have a stored value that is not expired, use it.
|
||||||
|
if (
|
||||||
|
! $force
|
||||||
|
&& isset( $this->data[ $key ] )
|
||||||
|
&& is_numeric( $this->data[ $key ]['expiration'] )
|
||||||
|
&& $time < $this->data[ $key ]['expiration']
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* Allows the filtering of the cached value of the timed option.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @param mixed $value If anything diff than null it will short-circuit.
|
||||||
|
* @param string $key Key for the option we are trying to get.
|
||||||
|
* @param mixed $default Default value when the option is either expired or not-set.
|
||||||
|
* @param bool $force If we should expire cache and fetch from the database.
|
||||||
|
* @param bool $cache If the value was pulled from cache.
|
||||||
|
*/
|
||||||
|
return apply_filters( 'tec_common_timed_option_value', $this->data[ $key ]['value'], $key, $default, $force, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
$timed_option = null;
|
||||||
|
|
||||||
|
if ( $this->is_active() ) {
|
||||||
|
$timed_option_name = $this->get_option_name( $key );
|
||||||
|
if ( true === $force ) {
|
||||||
|
wp_cache_delete( $timed_option_name, 'options' );
|
||||||
|
}
|
||||||
|
$timed_option = get_option( $timed_option_name, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bail with default when non-existent.
|
||||||
|
if ( empty( $timed_option ) ) {
|
||||||
|
if ( $this->is_active() ) {
|
||||||
|
// Avoids next request check, forces auto-loading.
|
||||||
|
$this->set( $key, null, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bail with default when expired.
|
||||||
|
if ( $time >= $timed_option['expiration'] ) {
|
||||||
|
$this->delete( $key );
|
||||||
|
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->data[ $key ] = $timed_option;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the filtering of the value of the timed option.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @param mixed $value If anything diff than null it will short-circuit.
|
||||||
|
* @param string $key Key for the option we are trying to get.
|
||||||
|
* @param mixed $default Default value when the option is either expired or not-set.
|
||||||
|
* @param bool $force If we should expire cache and fetch from the database.
|
||||||
|
* @param bool $cache If the value was pulled from cache.
|
||||||
|
*/
|
||||||
|
return apply_filters( 'tec_common_timed_option_value', $timed_option['value'], $key, $default, $force, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a given timed option based on a key.
|
||||||
|
* Will also clear local cache.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @param string $key Which timed option we are checking.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function delete( $key ): bool {
|
||||||
|
$key = (string) $key;
|
||||||
|
$updated = false;
|
||||||
|
|
||||||
|
if ( $this->is_active() ) {
|
||||||
|
$timed_option_name = $this->get_option_name( $key );
|
||||||
|
$updated = update_option( $timed_option_name, null, true );
|
||||||
|
wp_cache_delete( $timed_option_name, 'options' );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bail with default when non-existent.
|
||||||
|
if ( ! isset( $this->data[ $key ] ) ) {
|
||||||
|
return $updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
unset( $this->data[ $key ] );
|
||||||
|
|
||||||
|
return $updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a given timed option exists.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @param string $key Which timed option we are checking.
|
||||||
|
* @param bool $force Clears the cache before get_option()
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function exists( $key, bool $force = false ): bool {
|
||||||
|
/**
|
||||||
|
* Allows the filtering to short-circuit the whole exists logic.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @param mixed|null $pre If anything diff than null it will short-circuit.
|
||||||
|
* @param string $key Key for the option we are trying to get.
|
||||||
|
* @param bool $force If we should expire cache and fetch from the database.
|
||||||
|
*/
|
||||||
|
$pre = apply_filters( 'tec_common_timed_option_pre_exists', null, $key, $force );
|
||||||
|
|
||||||
|
if ( null !== $pre ) {
|
||||||
|
return (bool) $pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
$time = time();
|
||||||
|
$cached = false;
|
||||||
|
$timed_option = null;
|
||||||
|
|
||||||
|
// If we have a stored value that is not expired, use it.
|
||||||
|
if (
|
||||||
|
! $force
|
||||||
|
&& isset( $this->data[ $key ] )
|
||||||
|
&& is_numeric( $this->data[ $key ]['expiration'] )
|
||||||
|
&& $time < $this->data[ $key ]['expiration']
|
||||||
|
) {
|
||||||
|
$cached = true;
|
||||||
|
$timed_option = $this->data[ $key ];
|
||||||
|
} elseif ( $this->is_active() ) {
|
||||||
|
$timed_option_name = $this->get_option_name( $key );
|
||||||
|
if ( true === $force ) {
|
||||||
|
wp_cache_delete( $timed_option_name, 'options' );
|
||||||
|
}
|
||||||
|
$timed_option = get_option( $timed_option_name, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
$exists = true;
|
||||||
|
|
||||||
|
if ( null === $timed_option ) {
|
||||||
|
$exists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! is_array( $timed_option ) ) {
|
||||||
|
$exists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! isset( $timed_option['expiration'] ) || ! is_numeric( $timed_option['expiration'] ) ) {
|
||||||
|
$exists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does a particular timed option key exists.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @param mixed $exists If anything diff than null it will short-circuit.
|
||||||
|
* @param string $key Key for the option we are trying to get.
|
||||||
|
* @param bool $force If we should expire cache and fetch from the database.
|
||||||
|
* @param bool $cached If the value was pulled from cache.
|
||||||
|
*/
|
||||||
|
return (bool) apply_filters( 'tec_common_timed_option_exists', $exists, $key, $force, $cached );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the value of a timed option on the database and on local cache.
|
||||||
|
*
|
||||||
|
* @since 5.0.6
|
||||||
|
*
|
||||||
|
* @param string $key Key for this option.
|
||||||
|
* @param mixed $value Value stored for this option.
|
||||||
|
* @param int $expiration Expiration in seconds for this timed option.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function set( $key, $value, int $expiration = DAY_IN_SECONDS ): bool {
|
||||||
|
$key = (string) $key;
|
||||||
|
$data = [
|
||||||
|
'key' => $key,
|
||||||
|
'value' => $value,
|
||||||
|
'expiration' => time() + $expiration,
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->data[ $key ] = $data;
|
||||||
|
$updated = true;
|
||||||
|
|
||||||
|
if ( $this->is_active() ) {
|
||||||
|
$updated = update_option( $this->get_option_name( $key ), $data, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $updated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,314 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handles Telemetry migration from Freemius.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Telemetry
|
||||||
|
*/
|
||||||
|
namespace TEC\Common\Telemetry;
|
||||||
|
|
||||||
|
use TEC\Common\StellarWP\Telemetry\Config;
|
||||||
|
use TEC\Common\StellarWP\Telemetry\Opt_In\Opt_In_Subscriber;
|
||||||
|
use Tribe__Utils__Array as Arr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Migration
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
|
||||||
|
* @package TEC\Common\Telemetry
|
||||||
|
*/
|
||||||
|
class Migration {
|
||||||
|
/**
|
||||||
|
* The key we back up original fs_accounts data to.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public static $fs_accounts_slug = 'tec_freemius_accounts_archive';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key we back up modified fs_accounts data to.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public static $fs_accounts_data = 'tec_freemius_accounts_data_archive';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key we back up fs_active_plugins data to.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public static $fs_plugins_slug = 'tec_freemius_plugins_archive';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where Freemius stores the active plugins.
|
||||||
|
*
|
||||||
|
* @since TBD
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected static string $key_fs_active_plugins = 'fs_active_plugins';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of our plugins to check for.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $our_plugins = [
|
||||||
|
'the-events-calendar',
|
||||||
|
'event-tickets'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder for if the user has opted in via Freemius.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
public static $is_opted_in;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get and massage the fs_accounts
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function get_fs_accounts() {
|
||||||
|
// If we've already been here for some reason, don't do it all again.
|
||||||
|
$data = get_option( self::$fs_accounts_data );
|
||||||
|
if ( ! empty( $data ) ) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
global $wpdb;
|
||||||
|
$fs_accounts = $wpdb->get_var( "SELECT `option_value` FROM $wpdb->options WHERE `option_name` = 'fs_accounts' LIMIT 1" );
|
||||||
|
|
||||||
|
|
||||||
|
if ( empty( $fs_accounts ) || $fs_accounts instanceof \WP_Error ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store original here as backup.
|
||||||
|
update_option( static::$fs_accounts_slug, $fs_accounts );
|
||||||
|
|
||||||
|
// Prevent issues with incomplete classes
|
||||||
|
$fs_accounts = preg_replace_callback(
|
||||||
|
'/O:(\d+):"([^"]+)":([^:]+):\{/m',
|
||||||
|
static function( $matches ) {
|
||||||
|
if ( $matches[2] === 'stdClass' ) {
|
||||||
|
return $matches[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$key_slug = "tec_fs_key";
|
||||||
|
$key_slug_count = strlen( $key_slug );
|
||||||
|
$new_size = $matches[3] + 1;
|
||||||
|
|
||||||
|
return "a:{$new_size}:{s:{$key_slug_count}:\"{$key_slug}\";s:{$matches[1]}:\"{$matches[2]}\";";
|
||||||
|
},
|
||||||
|
$fs_accounts
|
||||||
|
);
|
||||||
|
|
||||||
|
$fs_accounts = maybe_unserialize( $fs_accounts );
|
||||||
|
|
||||||
|
// Store the modified data here.
|
||||||
|
update_option( static::$fs_accounts_data, $fs_accounts );
|
||||||
|
|
||||||
|
// return the modified data.
|
||||||
|
return $fs_accounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if we are opted-in to Freemius
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_opted_in(): bool {
|
||||||
|
if ( ! is_null( self::$is_opted_in ) ) {
|
||||||
|
return self::$is_opted_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fs_accounts = $this->get_fs_accounts();
|
||||||
|
|
||||||
|
$sites = Arr::get( $fs_accounts, 'sites', [] );
|
||||||
|
|
||||||
|
if ( empty( $sites ) ) {
|
||||||
|
self::$is_opted_in = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$disconnected = [];
|
||||||
|
|
||||||
|
foreach ( $this->our_plugins as $plugin ) {
|
||||||
|
if ( ! isset( $sites[ $plugin ] ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$disconnected[] = (bool) Arr::get( $sites, [ $plugin, 'is_disconnected' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( 1 > count( $disconnected ) ) {
|
||||||
|
self::$is_opted_in = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$is_opted_in = in_array( false, $disconnected, true );
|
||||||
|
return self::$is_opted_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the class should load/run.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function should_load(): bool {
|
||||||
|
// If we've already checked, bail.
|
||||||
|
if ( get_option( self::$fs_accounts_data ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When we have an archived plugin list we can bail.
|
||||||
|
if ( get_option( self::$fs_plugins_slug ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fs_active_plugins = get_option( self::$key_fs_active_plugins );
|
||||||
|
|
||||||
|
// Bail if empty.
|
||||||
|
if ( empty( $fs_active_plugins ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows filtering of whether the class should load/run.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param bool $should_load Whether the class should load/run.
|
||||||
|
*/
|
||||||
|
return apply_filters( 'tec_telemetry_migration_should_load', true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect if the user has opted in to Freemius and auto-opt them in to Telemetry.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*/
|
||||||
|
public function migrate_existing_opt_in(): void {
|
||||||
|
// Let's reduce the amount this triggers.
|
||||||
|
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! $this->should_load() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fs_active_plugins = get_option( self::$key_fs_active_plugins );
|
||||||
|
|
||||||
|
// Clean up our list.
|
||||||
|
$this->remove_inactive_plugins( $fs_active_plugins );
|
||||||
|
|
||||||
|
// Bail if none of our plugins are present.
|
||||||
|
if ( ! count( $this->our_plugins ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->auto_opt_in();
|
||||||
|
|
||||||
|
// Remove us from fs_active_plugins.
|
||||||
|
$this->handle_fs_active_plugins( $fs_active_plugins );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters our list of plugins to only the ones Freemius shows as active
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param Object $fs_active_plugins The stored list of active plugins from Freemius.
|
||||||
|
*/
|
||||||
|
private function remove_inactive_plugins( $fs_active_plugins ): void {
|
||||||
|
$freemius_plugins = ! empty( $fs_active_plugins->plugins ) ? (array) $fs_active_plugins->plugins : [];
|
||||||
|
|
||||||
|
foreach ( $this->our_plugins as $plugin ) {
|
||||||
|
if ( ! isset( $freemius_plugins[ $plugin ] ) ) {
|
||||||
|
unset( $this->our_plugins[ $plugin ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles our entries in the fs_active_plugins option.
|
||||||
|
* Removes them from the Freemius option and stores a backup of the original.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param Object $fs_active_plugins
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function handle_fs_active_plugins( $fs_active_plugins ): void {
|
||||||
|
// Store a backup of the original option.
|
||||||
|
update_option( self::$fs_plugins_slug, $fs_active_plugins );
|
||||||
|
|
||||||
|
foreach ( $this->our_plugins as $plugin ) {
|
||||||
|
$plugin .= '/common/vendor/freemius';
|
||||||
|
|
||||||
|
unset( $fs_active_plugins->plugins[ $plugin ] );
|
||||||
|
|
||||||
|
if ( ! empty( $fs_active_plugins->newest->sdk_path ) && $fs_active_plugins->newest->sdk_path === $plugin ) {
|
||||||
|
unset( $fs_active_plugins->newest );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the Freemius option in the database with our edits.
|
||||||
|
update_option( self::$key_fs_active_plugins, $fs_active_plugins );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opts the user in to Telemetry.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function auto_opt_in() {
|
||||||
|
$opt_in = $this->is_opted_in();
|
||||||
|
|
||||||
|
$opt_in_subscriber = Config::get_container()->get( Opt_In_Subscriber::class );
|
||||||
|
$telemetry = tribe( Telemetry::class );
|
||||||
|
$slug = Telemetry::get_stellar_slug();
|
||||||
|
|
||||||
|
$opt_in_subscriber->opt_in( $slug );
|
||||||
|
$telemetry->register_tec_telemetry_plugins( $opt_in );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows plugins to hook in and perform actions (like display a notice) when
|
||||||
|
* the user is automatically opted in to Telemetry.
|
||||||
|
*
|
||||||
|
* We also use this to trigger the actual auto-opt-in at the default priority.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*/
|
||||||
|
do_action( 'tec_telemetry_auto_opt_in' );
|
||||||
|
|
||||||
|
// Disable the modal on all migrations.
|
||||||
|
$telemetry::disable_modal( $slug, 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,158 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Service Provider for Telemetry.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Telemetry
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace TEC\Common\Telemetry;
|
||||||
|
|
||||||
|
use TEC\Common\Contracts\Service_Provider;
|
||||||
|
use TEC\Common\StellarWP\Telemetry\Admin\Admin_Subscriber as Asset_Subscriber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Provider
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
|
||||||
|
* @package TEC\Common\Telemetry
|
||||||
|
*/
|
||||||
|
class Provider extends Service_Provider {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the handlers and modifiers for notifying the site
|
||||||
|
* that Legacy views are removed.
|
||||||
|
*
|
||||||
|
* @since 5.13.0
|
||||||
|
*/
|
||||||
|
public function register() {
|
||||||
|
$this->container->bind( Telemetry::class, Telemetry::class );
|
||||||
|
|
||||||
|
$this->add_actions();
|
||||||
|
$this->add_filters();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the action hooks.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*/
|
||||||
|
public function add_actions() {
|
||||||
|
add_action( 'tribe_plugins_loaded', [ $this, 'boot_telemetry' ], 50 );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All these actions here need to be hooked from `tec_common_telemetry_preload` action to make sure that we have
|
||||||
|
* all the telemetry code loaded and ready to go.
|
||||||
|
*/
|
||||||
|
add_action( 'tec_common_telemetry_preload', [ $this, 'hook_telemetry_init' ], 5 );
|
||||||
|
|
||||||
|
add_action( 'tec_telemetry_modal', [ $this, 'show_optin_modal' ] );
|
||||||
|
add_action( 'tec_common_telemetry_preload', [ $this, 'migrate_existing_opt_in' ], 100 );
|
||||||
|
add_action( 'tec_common_telemetry_loaded', [ $this, 'maybe_enqueue_admin_modal_assets' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the filter hooks.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*/
|
||||||
|
public function add_filters() {
|
||||||
|
add_filter( 'stellarwp/telemetry/optin_args', [ $this, 'filter_optin_args' ] );
|
||||||
|
add_filter( 'stellarwp/telemetry/exit_interview_args', [ $this, 'filter_exit_interview_args' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It's super important to make sure when hooking to WordPress actions that we don't do before we are sure that
|
||||||
|
* telemetry was properly booted into the system.
|
||||||
|
*
|
||||||
|
* @since 5.1.3
|
||||||
|
*/
|
||||||
|
public function hook_telemetry_init(): void {
|
||||||
|
add_action( 'admin_init', [ $this, 'initialize_telemetry' ], 5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize our internal Telemetry code.
|
||||||
|
* Drivers, start your engines...
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot_telemetry() {
|
||||||
|
$this->container->make( Telemetry::class )->boot();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize our internal Telemetry code.
|
||||||
|
* Drivers, start your engines...
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function initialize_telemetry() {
|
||||||
|
$this->container->make( Telemetry::class )->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder for eventual Freemius removal hooking in to modify things.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function migrate_existing_opt_in() {
|
||||||
|
$this->container->make( Migration::class )->migrate_existing_opt_in();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logic for if the opt-in modal should be shown.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function show_optin_modal( $slug ) {
|
||||||
|
$this->container->make( Telemetry::class )->show_optin_modal( $slug );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the default opt-in modal args.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param array<string|mixed> $args The current optin modal args.
|
||||||
|
*
|
||||||
|
* @return array<string|mixed>
|
||||||
|
*/
|
||||||
|
public function filter_optin_args( $args ): array {
|
||||||
|
return $this->container->make( Telemetry::class )->filter_optin_args( $args );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the exit questionnaire shown during plugin deactivation/uninstall.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $args The current args.
|
||||||
|
*
|
||||||
|
* @return array<string,mixed> $args The modified args.
|
||||||
|
*/
|
||||||
|
public function filter_exit_interview_args( $args ) {
|
||||||
|
return $this->container->make( Telemetry::class )->filter_exit_interview_args( $args );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure the assets for the modal are enqueued, if needed.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*/
|
||||||
|
public function maybe_enqueue_admin_modal_assets(): void {
|
||||||
|
$this->container->make( Asset_Subscriber::class )->maybe_enqueue_admin_assets();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,592 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handles Telemetry setup and actions.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @package TEC\Common\Telemetry
|
||||||
|
*/
|
||||||
|
namespace TEC\Common\Telemetry;
|
||||||
|
|
||||||
|
use TEC\Common\StellarWP\Telemetry\Core;
|
||||||
|
use TEC\Common\StellarWP\Telemetry\Config;
|
||||||
|
use TEC\Common\StellarWP\Telemetry\Opt_In\Status;
|
||||||
|
use TEC\Common\StellarWP\Telemetry\Opt_In\Opt_In_Subscriber;
|
||||||
|
use Tribe__Container as Container;
|
||||||
|
use TEC\Common\StellarWP\Telemetry\Opt_In\Opt_In_Template;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Telemetry
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
|
||||||
|
* @package TEC\Common\Telemetry
|
||||||
|
*/
|
||||||
|
final class Telemetry {
|
||||||
|
/**
|
||||||
|
* The plugin slug used for identification
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected static $plugin_slug = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The custom hook prefix.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected static $hook_prefix = 'tec';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array to hold the opt-in args.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $optin_args = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The slug for the parent plugin.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $parent_plugin = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The slugs for the base TEC plugins.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private static $base_parent_slugs = [
|
||||||
|
'the-events-calendar',
|
||||||
|
'event-tickets'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path to main pugin file
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $plugin_path = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array for the TEC plugins to add themselves to.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @var array<string,string>
|
||||||
|
*/
|
||||||
|
public static $tec_slugs = [];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gentlefolk, start your engines.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot(): void {
|
||||||
|
/**
|
||||||
|
* Configure the container.
|
||||||
|
*
|
||||||
|
* The container must be compatible with stellarwp/container-contract.
|
||||||
|
* See here: https://github.com/stellarwp/container-contract#usage.
|
||||||
|
*
|
||||||
|
* If you do not have a container, we recommend https://github.com/lucatume/di52
|
||||||
|
* and the corresponding wrapper:
|
||||||
|
* https://github.com/stellarwp/container-contract/blob/main/examples/di52/Container.php
|
||||||
|
*/
|
||||||
|
$container = Container::init();
|
||||||
|
|
||||||
|
Config::set_container( $container );
|
||||||
|
|
||||||
|
static::clean_up();
|
||||||
|
|
||||||
|
self::$tec_slugs = self::get_tec_telemetry_slugs();
|
||||||
|
self::$plugin_slug = self::get_parent_plugin_slug();
|
||||||
|
self::$plugin_path = \Tribe__Main::instance()->get_parent_plugin_file_path();
|
||||||
|
$stellar_slug = self::get_stellar_slug();
|
||||||
|
|
||||||
|
if ( empty( $stellar_slug ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$telemetry_server = ! defined('TELEMETRY_SERVER') ? 'https://telemetry.stellarwp.com/api/v1': TELEMETRY_SERVER;
|
||||||
|
|
||||||
|
Config::set_server_url( $telemetry_server );
|
||||||
|
|
||||||
|
// Set a unique prefix for actions & filters.
|
||||||
|
Config::set_hook_prefix( self::$hook_prefix );
|
||||||
|
|
||||||
|
// Set a unique plugin slug.
|
||||||
|
Config::set_stellar_slug( $stellar_slug );
|
||||||
|
|
||||||
|
self::$plugin_path = \Tribe__Main::instance()->get_parent_plugin_file_path();
|
||||||
|
|
||||||
|
if ( empty( self::$plugin_path ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the library.
|
||||||
|
Core::instance()->init( self::$plugin_path );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow plugins to hook in and add themselves,
|
||||||
|
* running their own actions once Telemetry is initiated,
|
||||||
|
* but before we register all our plugins.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param self $telemetry The Telemetry instance.
|
||||||
|
*/
|
||||||
|
do_action( 'tec_common_telemetry_preload', $this );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the plugins and triggers the "loaded" action.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function init(): void {
|
||||||
|
$this->register_tec_telemetry_plugins();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow plugins to hook in and add themselves,
|
||||||
|
* running their own actions once Telemetry is initiated.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param self $telemetry The Telemetry instance.
|
||||||
|
*/
|
||||||
|
do_action( 'tec_common_telemetry_loaded', $this );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up some old data.
|
||||||
|
* If the "tec" plugin exists, and it has no wp_slug, remove it.
|
||||||
|
* This prevents a fatal with the Telemetry library when we call get_opted_in_plugins().
|
||||||
|
*
|
||||||
|
* @since 5.1.1.1
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function clean_up(): void {
|
||||||
|
$status = static::get_status_object();
|
||||||
|
$option = $status->get_option();
|
||||||
|
if ( ! empty( $option['plugins'][ 'tec' ] ) && empty( $option['plugins'][ 'tec' ]['wp_slug'] ) ) {
|
||||||
|
$status->remove_plugin( 'tec' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function get_plugin_slug() {
|
||||||
|
if ( empty( self::$plugin_slug ) ) {
|
||||||
|
self::$plugin_slug = self::get_parent_plugin_slug();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$plugin_slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the slug of the parent plugin.
|
||||||
|
* Hydrated lazily.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_parent_plugin_slug(): string {
|
||||||
|
if ( empty( self::$parent_plugin ) ) {
|
||||||
|
$file = \Tribe__Main::instance()->get_parent_plugin_file_path();
|
||||||
|
self::$parent_plugin = substr(
|
||||||
|
$file,
|
||||||
|
( strrpos( $file, '/' ) + 1 ),
|
||||||
|
( strlen( $file ) - ( strrpos( $file, '/' ) + 5 ) )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$parent_plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the stellar slug based on the parent plugin.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*/
|
||||||
|
public static function get_stellar_slug(): string {
|
||||||
|
$tec_slugs = self::get_tec_telemetry_slugs();
|
||||||
|
|
||||||
|
foreach( $tec_slugs as $slug => $path ) {
|
||||||
|
if ( stripos( self::$plugin_path, $path ) ) {
|
||||||
|
return $slug;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the default optin modal args.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param array<string|mixed> $args The current optin modal args.
|
||||||
|
*
|
||||||
|
* @return array<string|mixed>
|
||||||
|
*/
|
||||||
|
public function filter_optin_args( $args ): array {
|
||||||
|
$user_name = esc_html( wp_get_current_user()->display_name );
|
||||||
|
|
||||||
|
/*
|
||||||
|
if ET only change logo, name to Event Tickets
|
||||||
|
if TEC only change logo
|
||||||
|
If both, use The Events Calendar
|
||||||
|
*/
|
||||||
|
|
||||||
|
$optin_args = [
|
||||||
|
'plugin_logo' => tribe_resource_url( 'images/logo/tec-brand.svg', false, null, \Tribe__Main::instance() ),
|
||||||
|
'plugin_logo_width' => 'auto',
|
||||||
|
'plugin_logo_height' => 42,
|
||||||
|
'plugin_logo_alt' => 'TEC Common Logo',
|
||||||
|
'plugin_name' => 'TEC Common',
|
||||||
|
'plugin_slug' => self::get_plugin_slug(),
|
||||||
|
'user_name' => $user_name,
|
||||||
|
'permissions_url' => self::get_permissions_url(),
|
||||||
|
'tos_url' => self::get_terms_url(),
|
||||||
|
'privacy_url' => self::get_privacy_url(),
|
||||||
|
'opted_in_plugins_text' => __( 'See which plugins you have opted in to tracking for', 'tribe-common' ),
|
||||||
|
'heading' => __( 'We hope you love TEC Common!', 'tribe-common' ),
|
||||||
|
'intro' => __( "Hi, {$user_name}! This is an invitation to help our StellarWP community. If you opt-in, some data about your usage of TEC Common and future StellarWP Products will be shared with our teams (so they can work their butts off to improve). We will also share some helpful info on WordPress, and our products from time to time. And if you skip this, that’s okay! Our products still work just fine.", 'tribe-common' ),
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows overriding the modal optin args.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $optin_args The modal arguments to filter.
|
||||||
|
*/
|
||||||
|
$this->optin_args = apply_filters( 'tec_common_telemetry_optin_args', $optin_args );
|
||||||
|
|
||||||
|
return array_merge( $args, $this->optin_args );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the URL for the permission link in the optin modal.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_permissions_url(): string {
|
||||||
|
/**
|
||||||
|
* Allow overriding the permissions URL.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param string $url The URL to the permissions page.
|
||||||
|
*/
|
||||||
|
return esc_url( apply_filters( 'tec_common_telemetry_permissions_url', 'https://evnt.is/1bcl' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the URL for the Terms of Service link in the optin modal.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_terms_url(): string {
|
||||||
|
/**
|
||||||
|
* Allow overriding the Terms of Service URL.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param string $url The URL to the Terms of Service page.
|
||||||
|
*/
|
||||||
|
return esc_url( apply_filters( 'tec_common_telemetry_terms_url', 'https://evnt.is/1bcm' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the URL for the Privacy Policy link in the optin modal.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_privacy_url(): string {
|
||||||
|
/**
|
||||||
|
* Allow overriding the Privacy Policy URL.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param string $url The URL to the Privacy Policy page.
|
||||||
|
*/
|
||||||
|
return esc_url( apply_filters( 'tec_common_telemetry_privacy_url', 'https://evnt.is/1bcn' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the exit questionnaire shown during plugin deactivation/uninstall.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $args The current args.
|
||||||
|
*
|
||||||
|
* @return array<string,mixed> $args The modified args.
|
||||||
|
*/
|
||||||
|
public function filter_exit_interview_args( $args ) {
|
||||||
|
$new_args = [
|
||||||
|
'plugin_logo' => tribe_resource_url( 'images/logo/tec-brand.svg', false, null, \Tribe__Main::instance() ),
|
||||||
|
'plugin_logo_width' => 'auto',
|
||||||
|
'plugin_logo_height' => 32,
|
||||||
|
'plugin_logo_alt' => 'TEC Common Logo',
|
||||||
|
'heading' => __( 'We’re sorry to see you go.', 'tribe-common' ),
|
||||||
|
'intro' => __( 'We’d love to know why you’re leaving so we can improve our plugin.', 'tribe-common' ),
|
||||||
|
'uninstall_reasons' => [
|
||||||
|
[
|
||||||
|
'uninstall_reason_id' => 'confusing',
|
||||||
|
'uninstall_reason' => __( 'I couldn’t understand how to make it work.', 'tribe-common' ),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'uninstall_reason_id' => 'better-plugin',
|
||||||
|
'uninstall_reason' => __( 'I found a better plugin.', 'tribe-common' ),
|
||||||
|
'show_comment' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'uninstall_reason_id' => 'no-feature',
|
||||||
|
'uninstall_reason' => __( 'I need a specific feature it doesn’t provide.', 'tribe-common' ),
|
||||||
|
'show_comment' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'uninstall_reason_id' => 'broken',
|
||||||
|
'uninstall_reason' => __( 'The plugin doesn’t work.', 'tribe-common' ),
|
||||||
|
'show_comment' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'uninstall_reason_id' => 'other',
|
||||||
|
'uninstall_reason' => __( 'Other', 'tribe-common' ),
|
||||||
|
'show_comment' => true,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
return array_merge( $args, $new_args );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers Telemetry's opt-in modal with our parameters.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function show_optin_modal( $slug ): void {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter allowing disabling of the optin modal.
|
||||||
|
* Returning boolean false will disable the modal
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param bool $show Whether to show the modal or not.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
$show = (bool) apply_filters( 'tec_common_telemetry_show_optin_modal', true, $slug );
|
||||||
|
|
||||||
|
if ( ! $show ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Telemetry uses this to determine when/where the optin modal should be shown.
|
||||||
|
* i.e. the modal is shown when we run this.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param string $plugin_slug The slug of the plugin showing the modal.
|
||||||
|
*/
|
||||||
|
do_action( 'stellarwp/telemetry/optin', $slug );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sugar function to get the status object from the container.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return Status
|
||||||
|
*/
|
||||||
|
public static function get_status_object(): Status {
|
||||||
|
return Config::get_container()->get( Status::class );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows out plugins to hook in and add themselves,
|
||||||
|
* automating a lot of the registration and opt in/out process.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return array<string,string> An array of plugins in the format [ 'plugin_slug' => 'plugin_path' ]
|
||||||
|
*/
|
||||||
|
public static function get_tec_telemetry_slugs() {
|
||||||
|
/**
|
||||||
|
* Filter for plugins to hooked into Telemetry and add themselves.
|
||||||
|
* This acts a Telemetry "registry" for all TEC plugins.
|
||||||
|
* Used to ensure TEC plugins get (de)activated as a group.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @param array<string,string> $slugs An array of plugins in the format [ 'plugin_slug' => 'plugin_path' ]
|
||||||
|
*/
|
||||||
|
return apply_filters( 'tec_telemetry_slugs', [] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register and opt in/out the plugins that are hooked into `tec_telemetry_slugs`.
|
||||||
|
* This keeps all TEC plugins in sync and only requires one optin modal response.
|
||||||
|
*
|
||||||
|
* @since 5.1.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register_tec_telemetry_plugins( $opted = NULL ) {
|
||||||
|
$new_opted = $opted;
|
||||||
|
// Let's reduce the amount this triggers.
|
||||||
|
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tec_slugs = self::get_tec_telemetry_slugs();
|
||||||
|
|
||||||
|
// We've got no other plugins?
|
||||||
|
if ( empty( $tec_slugs ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case we're not specifically passed a status...
|
||||||
|
$new_opted = $this->calculate_optin_status( $opted );
|
||||||
|
|
||||||
|
$status = Config::get_container()->get( Status::class );
|
||||||
|
$opt_in_subscriber = Config::get_container()->get( Opt_In_Subscriber::class );
|
||||||
|
$opt_in_subscriber->initialize_optin_option();
|
||||||
|
|
||||||
|
foreach ( $tec_slugs as $slug => $path ) {
|
||||||
|
// Register each plugin with the already instantiated library.
|
||||||
|
Config::add_stellar_slug( $slug, $path );
|
||||||
|
$status->add_plugin( $slug, $new_opted, $path );
|
||||||
|
|
||||||
|
if ( $new_opted ) {
|
||||||
|
$opt_in_subscriber->opt_in( $slug );
|
||||||
|
$status->set_status( $new_opted, $slug );
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're manually opting in/out, don't show the modal(s).
|
||||||
|
if ( ! is_null( $opted ) || ! empty( $new_opted ) ) {
|
||||||
|
static::disable_modal( $slug );
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've already interacted with a modal, don't show another one.
|
||||||
|
$show = static::calculate_modal_status();
|
||||||
|
if ( ! $show ) {
|
||||||
|
static::disable_modal( $slug, $show );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the optin status for the TEC plugins from various sources.
|
||||||
|
*
|
||||||
|
* @since 6.1.0
|
||||||
|
*
|
||||||
|
* @param bool $opted
|
||||||
|
*
|
||||||
|
* @return bool $opted
|
||||||
|
*/
|
||||||
|
public function calculate_optin_status( $opted ) {
|
||||||
|
if ( NULL !== $opted ) {
|
||||||
|
return $opted;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If they have opted in to one plugin, opt them in to all TEC ones.
|
||||||
|
$status_obj = static::get_status_object();
|
||||||
|
$stati = [];
|
||||||
|
$option = $status_obj->get_option();
|
||||||
|
|
||||||
|
foreach ( static::$base_parent_slugs as $slug ) {
|
||||||
|
if ( $status_obj->plugin_exists( $slug ) ) {
|
||||||
|
$stati[ $slug ] = $option['plugins'][ $slug ][ 'optin' ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$status = array_filter( $stati );
|
||||||
|
|
||||||
|
return (bool) array_pop( $status );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the optin status for the TEC plugins from various sources.
|
||||||
|
*
|
||||||
|
* @since 5.1.1.1
|
||||||
|
*
|
||||||
|
* @return bool $show If the modal should show
|
||||||
|
*/
|
||||||
|
public static function calculate_modal_status() {
|
||||||
|
// If they have already interacted with a modal, find out.
|
||||||
|
$shows = array_flip( static::$base_parent_slugs );
|
||||||
|
$optin = Config::get_container()->get( Opt_In_Template::class );
|
||||||
|
|
||||||
|
foreach ( static::$base_parent_slugs as $slug ) {
|
||||||
|
$show = get_option( $optin->get_option_name( $slug ), null );
|
||||||
|
// Remove unset entries from the array.
|
||||||
|
if ( is_null( $show ) ) {
|
||||||
|
unset( $shows[ $slug ] );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$shows[ $slug ] = $show;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No entries - show modal.
|
||||||
|
if ( empty( $shows ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flip the array = duplicate entries will be overwritten.
|
||||||
|
$shows = array_flip( $shows );
|
||||||
|
|
||||||
|
// If we have interacted with any modals, don't show this one.
|
||||||
|
return ! isset( $shows[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sugar function to disable (or enable) the optin modal.
|
||||||
|
*
|
||||||
|
* @since 6.1.0
|
||||||
|
*
|
||||||
|
* @param string $slug The plugin slug for Telemetry.
|
||||||
|
* @param boolean|int $enable Opt out (0|false) or in (1|true).
|
||||||
|
*/
|
||||||
|
public static function disable_modal( $slug, $enable = false ) {
|
||||||
|
// Ensure we have a integer representation of a boolean value.
|
||||||
|
$enable = tec_bool_to_int( tribe_is_truthy( $enable ) );
|
||||||
|
|
||||||
|
$option_slug = Config::get_container()->get( Opt_In_Template::class )->get_option_name( $slug );
|
||||||
|
update_option( $option_slug, $enable );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,198 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handle the switching of the site locale with awareness of the plugin's context.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @package TEC\Common;
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace TEC\Common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Translations_Loader.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @package TEC\Common;
|
||||||
|
*/
|
||||||
|
class Translations_Loader {
|
||||||
|
/**
|
||||||
|
* The override locale that should be used.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $override_locale = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the locale has been switched or not.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $has_loaded_translations = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of the text domains translations have been loaded for.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @var array<string>
|
||||||
|
*/
|
||||||
|
protected $loaded_domains = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switches the locale to the one specified.
|
||||||
|
*
|
||||||
|
* Note: the method will not check what the current locale is and will just load the
|
||||||
|
* translations specified. The burden of checking the current locale is on the caller.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @param string $locale The locale to switch to.
|
||||||
|
* @param array<string,string> $domains A map from text domains to the directory containing the translations.
|
||||||
|
*
|
||||||
|
* @return bool Whether the locale was switched or not.
|
||||||
|
*/
|
||||||
|
public function load( string $locale, array $domains = [] ): bool {
|
||||||
|
if ( empty( $domains ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires before the locale translations are loaded.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @param string $locale The locale that will be loaded.
|
||||||
|
* @param array<string> $domains The list of domains translations will be loaded for.
|
||||||
|
*/
|
||||||
|
do_action( 'tec_locale_translations_load_before', $locale, $domains );
|
||||||
|
|
||||||
|
$this->has_loaded_translations = true;
|
||||||
|
$this->override_locale = $locale;
|
||||||
|
$this->loaded_domains = $domains;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The `plugin_locale` filter will be applied in `load_plugin_textdomain()` to determine
|
||||||
|
* the language file to load.
|
||||||
|
*/
|
||||||
|
add_filter( 'plugin_locale', [ $this, 'override_locale' ] );
|
||||||
|
|
||||||
|
$this->load_locale_translations( $domains, $locale );
|
||||||
|
|
||||||
|
remove_filter( 'plugin_locale', [ $this, 'override_locale' ] );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires after the locale translations are loaded.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @param string $locale The locale that has been loaded.
|
||||||
|
* @param array<string> $domains The list of domains translations have been loaded for.
|
||||||
|
*/
|
||||||
|
do_action( 'tec_locale_translations_load_after', $locale, $domains );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A proxy method to return the current override locale if set, or the input locale otherwise.
|
||||||
|
*
|
||||||
|
* Used during filter application.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @param string $locale The locale to override.
|
||||||
|
*
|
||||||
|
* @return string The overridden locale.
|
||||||
|
*
|
||||||
|
* @internal This function is public only for the purpose of being used as a filter callback.
|
||||||
|
*/
|
||||||
|
public function override_locale( $locale ) {
|
||||||
|
return $this->override_locale ?: $locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the locale has been switched or not.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @return bool Whether the locale has been switched or not.
|
||||||
|
*/
|
||||||
|
public function has_loaded_translations(): bool {
|
||||||
|
return $this->has_loaded_translations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restored the locale to the previous one and removes the class filters.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @return void Translations for each domain will be reloaded.
|
||||||
|
*/
|
||||||
|
public function restore() {
|
||||||
|
if ( ! $this->has_loaded_translations ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->override_locale = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires before the locale translations are restored.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @param array<string> $domains The list of domains translations will be loaded for.
|
||||||
|
*/
|
||||||
|
do_action( 'tec_locale_translations_restore_before', $this->loaded_domains );
|
||||||
|
|
||||||
|
// Reload the translations using the currently determined locale.
|
||||||
|
$this->load_locale_translations( $this->loaded_domains, determine_locale() );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires after the locale translations are restored.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @param array<string> $domains The list of domains translations have been loaded for.
|
||||||
|
*/
|
||||||
|
do_action( 'tec_locale_translations_restore_after', $this->loaded_domains );
|
||||||
|
|
||||||
|
$this->has_loaded_translations = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the translations for the map of domains for the current locale.
|
||||||
|
*
|
||||||
|
* @since 5.0.8
|
||||||
|
*
|
||||||
|
* @param array<string,string> $domains A map from text domains to the directory containing the translations.
|
||||||
|
* @param string $locale The locale to load the translations for.
|
||||||
|
*
|
||||||
|
* @return void Translations for each domain will be loaded for the current plugin locale.
|
||||||
|
*/
|
||||||
|
protected function load_locale_translations( array $domains, string $locale ): void {
|
||||||
|
global $l10n;
|
||||||
|
|
||||||
|
if ( ! is_array( $l10n ) ) {
|
||||||
|
$l10n = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ( $domains as $domain => $lang_dir ) {
|
||||||
|
unload_textdomain( $domain, true );
|
||||||
|
|
||||||
|
if ( $locale === 'en_US' ) {
|
||||||
|
// There is no `en_US` language pack since it's the default, no-op the translations.
|
||||||
|
$l10n[ $domain ] = new \NOOP_Translations();
|
||||||
|
} else {
|
||||||
|
// Load the translations using the wrapper Common function.
|
||||||
|
$dir = is_string( $lang_dir ) && ! empty( $lang_dir ) ? $lang_dir : false;
|
||||||
|
\Tribe__Main::instance()->load_text_domain( $domain, $dir );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class Tribe__Abstract_Deactivation {
|
||||||
|
protected $network = false;
|
||||||
|
|
||||||
|
public function __construct( $network ) {
|
||||||
|
$this->network = (bool) $network;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell WordPress to flush rewrite rules.
|
||||||
|
* Since our post types are already registered,
|
||||||
|
* we delete the option and let WP regenerate it
|
||||||
|
* on the next page load.
|
||||||
|
*/
|
||||||
|
protected function flush_rewrite_rules() {
|
||||||
|
delete_option( 'rewrite_rules' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deactivate the plugin. This should not remove data.
|
||||||
|
* It's job is to remove run-time traces of the plugin.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function deactivate() {
|
||||||
|
if ( is_multisite() && $this->network ) {
|
||||||
|
$this->multisite_deactivate();
|
||||||
|
} else {
|
||||||
|
$this->blog_deactivate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the deactivation script on every blog for a multisite install
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function multisite_deactivate() {
|
||||||
|
/** @var wpdb $wpdb */
|
||||||
|
global $wpdb;
|
||||||
|
$site = get_current_site();
|
||||||
|
$blog_ids = $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM {$wpdb->blogs} WHERE site_id=%d", $site->id ) );
|
||||||
|
$large = wp_is_large_network();
|
||||||
|
foreach ( $blog_ids as $blog ) {
|
||||||
|
tribe_set_time_limit( 30 );
|
||||||
|
switch_to_blog( $blog );
|
||||||
|
$large ? $this->short_blog_deactivate() : $this->blog_deactivate();
|
||||||
|
restore_current_blog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The deactivation routine for a single blog
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
abstract protected function blog_deactivate();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abridged version that is less DB intensive for use on large networks.
|
||||||
|
*
|
||||||
|
* @see wp_is_large_network() and the 'wp_is_large_network' filter
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function short_blog_deactivate() {
|
||||||
|
$this->blog_deactivate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base Plugin register
|
||||||
|
*
|
||||||
|
* Register all plugins to Dependency Class
|
||||||
|
*
|
||||||
|
* @package Tribe
|
||||||
|
* @since 4.9
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
abstract class Tribe__Abstract_Plugin_Register {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The absolute path to the plugin file, the one that contains the plugin header.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $base_dir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $main_class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 4.9.17
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $classes_req = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $dependencies = [
|
||||||
|
'parent-dependencies' => [],
|
||||||
|
'co-dependencies' => [],
|
||||||
|
'addon-dependencies' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a plugin with dependencies
|
||||||
|
*/
|
||||||
|
public function register_plugin() {
|
||||||
|
tribe_register_plugin(
|
||||||
|
$this->base_dir,
|
||||||
|
$this->main_class,
|
||||||
|
$this->version,
|
||||||
|
$this->classes_req,
|
||||||
|
$this->dependencies
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not the dependencies have been met
|
||||||
|
*
|
||||||
|
* This is basically an aliased function - register_plugins, upon
|
||||||
|
* second calling, returns whether or not a plugin should load.
|
||||||
|
*
|
||||||
|
* @deprecated since 4.9.17 It is unused by any Tribe plugins and returned void.
|
||||||
|
* @todo remove in 4.11
|
||||||
|
*/
|
||||||
|
public function has_valid_dependencies() {
|
||||||
|
_deprecated_function( __METHOD__, '4.9.17' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,380 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Shows a welcome or update message after the plugin is installed/updated.
|
||||||
|
*/
|
||||||
|
class Tribe__Admin__Activation_Page {
|
||||||
|
protected $args = [];
|
||||||
|
public $update_slug = 'update-message-';
|
||||||
|
public $welcome_slug = 'welcome-message-';
|
||||||
|
protected $current_context = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the update/welcome splash screen.
|
||||||
|
*
|
||||||
|
* @param array $args {
|
||||||
|
* Plugin specific slugs and option names used to manage when the splash screen displays.
|
||||||
|
*
|
||||||
|
* @type string $slug
|
||||||
|
* @type string $version
|
||||||
|
* @type string $plugin_path
|
||||||
|
* @type string $version_history_slug
|
||||||
|
* @type string $update_page_title
|
||||||
|
* @type string $update_page_template
|
||||||
|
* @type string $welcome_page_title
|
||||||
|
* @type string $welcome_page_template
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
public function __construct( array $args = [] ) {
|
||||||
|
$this->args = wp_parse_args( $args, [
|
||||||
|
'slug' => '',
|
||||||
|
'admin_page' => '',
|
||||||
|
'admin_url' => '',
|
||||||
|
'activation_transient' => '',
|
||||||
|
'version' => '',
|
||||||
|
'plugin_path' => '',
|
||||||
|
'version_history_slug' => '',
|
||||||
|
'update_page_title' => '',
|
||||||
|
'update_page_template' => '',
|
||||||
|
'welcome_page_title' => '',
|
||||||
|
'welcome_page_template' => '',
|
||||||
|
] );
|
||||||
|
|
||||||
|
$this->update_slug .= $this->args['slug'];
|
||||||
|
$this->welcome_slug .= $this->args['slug'];
|
||||||
|
|
||||||
|
$this->hooks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if we are currently on the Welcome page.
|
||||||
|
*
|
||||||
|
* @since 4.12.11
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function is_welcome_page() {
|
||||||
|
return isset( $_GET[ $this->welcome_slug ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if we are currently on the update page.
|
||||||
|
*
|
||||||
|
* @since 4.12.11
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function is_update_page() {
|
||||||
|
return isset( $_GET[ $this->update_slug ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen for opportunities to show update and welcome splash pages.
|
||||||
|
*/
|
||||||
|
public function hooks() {
|
||||||
|
// Never show this on the front-end.
|
||||||
|
if ( ! is_admin() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
tribe_is_truthy( get_option( 'tribe_skip_welcome', false ) )
|
||||||
|
|| tribe_is_truthy( tribe_get_option( 'skip_welcome', false ) )
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_action( 'admin_init', [ $this, 'maybe_redirect' ], 10, 0 );
|
||||||
|
add_action( 'admin_menu', [ $this, 'register_page' ], 100, 0 ); // Come in after the default page is registered.
|
||||||
|
|
||||||
|
add_action( 'update_plugin_complete_actions', [ $this, 'update_complete_actions' ], 15, 2 );
|
||||||
|
add_action( 'update_bulk_plugins_complete_actions', [ $this, 'update_complete_actions' ], 15, 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter the Default WordPress actions when updating the plugin to prevent users to be redirected if they have an
|
||||||
|
* specific intention of going back to the plugins page.
|
||||||
|
*
|
||||||
|
* @param array $actions The Array of links (html)
|
||||||
|
* @param string $plugin Which plugins are been updated
|
||||||
|
* @return array The filtered Links
|
||||||
|
*/
|
||||||
|
public function update_complete_actions( $actions, $plugin ) {
|
||||||
|
$plugins = [];
|
||||||
|
|
||||||
|
if ( ! empty( $_GET['plugins'] ) ) {
|
||||||
|
$plugins = explode( ',', esc_attr( $_GET['plugins'] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! in_array( $this->args['plugin_path'], $plugins ) ) {
|
||||||
|
return $actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset( $actions['plugins_page'] ) ) {
|
||||||
|
$actions['plugins_page'] = '<a href="' . esc_url( self_admin_url( 'plugins.php?tribe-skip-welcome' ) ) . '" title="' . esc_attr__( 'Go to plugins page', 'tribe-common' ) . '" target="_parent">' . esc_html__( 'Return to Plugins page' ) . '</a>';
|
||||||
|
|
||||||
|
if ( ! current_user_can( 'activate_plugins' ) ) {
|
||||||
|
unset( $actions['plugins_page'] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset( $actions['updates_page'] ) ) {
|
||||||
|
$actions['updates_page'] = '<a href="' . esc_url( self_admin_url( 'update-core.php?tribe-skip-welcome' ) ) . '" title="' . esc_attr__( 'Go to WordPress Updates page', 'tribe-common' ) . '" target="_parent">' . esc_html__( 'Return to WordPress Updates' ) . '</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maybe redirect to the welcome page (or to the update page - though this is
|
||||||
|
* currently disabled).
|
||||||
|
*/
|
||||||
|
public function maybe_redirect() {
|
||||||
|
if ( ! empty( $_POST ) ) {
|
||||||
|
return; // Don't interrupt anything the user's trying to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! is_admin() || defined( 'DOING_AJAX' ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( defined( 'IFRAME_REQUEST' ) && IFRAME_REQUEST ) {
|
||||||
|
return; // Probably the plugin update/install iframe.
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset( $_GET[ $this->welcome_slug ] ) || isset( $_GET[ $this->update_slug ] ) ) {
|
||||||
|
return; // No infinite redirects.
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset( $_GET['tribe-skip-welcome'] ) ) {
|
||||||
|
return; // A way to skip these checks and.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
! $this->showed_update_message_for_current_version()
|
||||||
|
&& ! $this->is_new_install()
|
||||||
|
) {
|
||||||
|
$page = tribe_get_request_var( 'page' );
|
||||||
|
if ( empty( $page ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$match_page = str_replace( 'tribe_events_page_', '', $this->args['admin_page'] );
|
||||||
|
|
||||||
|
if ( $page !== $match_page ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters whether we should disable the update page redirect.
|
||||||
|
*
|
||||||
|
* @since 5.0.0
|
||||||
|
*
|
||||||
|
* @param $bypass bool
|
||||||
|
*/
|
||||||
|
$bypass_update_page = apply_filters( 'tec_admin_update_page_bypass', false, $this );
|
||||||
|
|
||||||
|
if ( $bypass_update_page ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->redirect_to_update_page();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bail if we aren't activating a plugin.
|
||||||
|
if ( ! get_transient( $this->args['activation_transient'] ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_transient( $this->args['activation_transient'] );
|
||||||
|
|
||||||
|
if ( ! current_user_can( Tribe__Settings::instance()->requiredCap ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the redirect might be intercepted by another plugin, but
|
||||||
|
// we'll go ahead and mark it as viewed right now, just in case
|
||||||
|
// we end up in a redirect loop
|
||||||
|
// see #31088
|
||||||
|
$this->log_display_of_message_page();
|
||||||
|
|
||||||
|
if ( $this->is_new_install() ) {
|
||||||
|
$this->redirect_to_welcome_page();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Have we shown the welcome/update message for the current version?
|
||||||
|
*
|
||||||
|
* @since 5.0.0 Turned this method public.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function showed_update_message_for_current_version() {
|
||||||
|
$message_version_displayed = Tribe__Settings_Manager::get_option( 'last-update-message-' . $this->args['slug'] );
|
||||||
|
|
||||||
|
if ( empty( $message_version_displayed ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$current_version = explode( '.', $this->args['version'] );
|
||||||
|
$current_version = array_splice( $current_version, 0, 2 );
|
||||||
|
$current_version = array_pad( $current_version, 3, 0 );
|
||||||
|
$current_version = implode( '.', $current_version );
|
||||||
|
|
||||||
|
$message_version_displayed = explode( '.', $message_version_displayed );
|
||||||
|
$message_version_displayed = array_splice( $message_version_displayed, 0, 2 );
|
||||||
|
$message_version_displayed = array_pad( $message_version_displayed, 3, 0 );
|
||||||
|
$message_version_displayed = implode( '.', $message_version_displayed );
|
||||||
|
|
||||||
|
if ( version_compare( $message_version_displayed, $current_version, '<' ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records the fact that we displayed the update message in relation to a specific
|
||||||
|
* version of the plugin (so we don't show it again until/unless they update to
|
||||||
|
* a higher version).
|
||||||
|
*/
|
||||||
|
protected function log_display_of_message_page() {
|
||||||
|
Tribe__Settings_Manager::set_option( 'last-update-message-' . $this->args['slug'], $this->args['version'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The previous_ecp_versions option will be empty or set to 0
|
||||||
|
* if the current version is the first version to be installed.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* @see Tribe__Events__Main::maybeSetTECVersion()
|
||||||
|
*/
|
||||||
|
protected function is_new_install() {
|
||||||
|
$previous_versions = Tribe__Settings_Manager::get_option( $this->args['version_history_slug'] );
|
||||||
|
return empty( $previous_versions ) || ( end( $previous_versions ) == '0' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles taking a user to a post-installation welcome page.
|
||||||
|
*/
|
||||||
|
protected function redirect_to_welcome_page() {
|
||||||
|
$url = $this->get_message_page_url( $this->welcome_slug );
|
||||||
|
wp_safe_redirect( $url );
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles taking the user to a post-update splash screen.
|
||||||
|
*
|
||||||
|
* Disused since TEC PR 88 (targeting Tribe__Events__Activation_Page,
|
||||||
|
* which this class was derived from).
|
||||||
|
*
|
||||||
|
* @see https://github.com/the-events-calendar/the-events-calendar/pull/88
|
||||||
|
*
|
||||||
|
* @todo decide whether to reinstate or remove
|
||||||
|
*/
|
||||||
|
protected function redirect_to_update_page() {
|
||||||
|
$url = $this->get_message_page_url( $this->update_slug );
|
||||||
|
wp_safe_redirect( $url );
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the URL of the splash page.
|
||||||
|
*
|
||||||
|
* @param string $slug
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function get_message_page_url( $slug ) {
|
||||||
|
$settings = Tribe__Settings::instance();
|
||||||
|
|
||||||
|
$url = ! empty( $this->args['admin_url'] ) ? $this->args['admin_url'] : $settings->get_url();
|
||||||
|
|
||||||
|
$url = esc_url_raw( add_query_arg( $slug, 1, $url ) );
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamically registers the splash page when required.
|
||||||
|
*/
|
||||||
|
public function register_page() {
|
||||||
|
if ( isset( $_GET[ $this->welcome_slug ] ) ) {
|
||||||
|
$this->current_context = 'welcome';
|
||||||
|
} elseif ( isset( $_GET[ $this->update_slug ] ) ) {
|
||||||
|
$this->current_context = 'update';
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->disable_default_settings_page();
|
||||||
|
add_filter( 'admin_body_class', [ $this, 'admin_body_class' ] );
|
||||||
|
add_action( $this->args['admin_page'], [ $this, 'display_page' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hooked to admin_body_class to add a class for the update or welcome page
|
||||||
|
*
|
||||||
|
* @param string $classes a space separated string of classes to be added to body
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function admin_body_class( $classes ) {
|
||||||
|
$classes .= ' tribe-' . $this->current_context;
|
||||||
|
return $classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deactivates the regular settings screen (the splash screen will display
|
||||||
|
* in the Events > Settings slot instead, for this request only).
|
||||||
|
*/
|
||||||
|
protected function disable_default_settings_page() {
|
||||||
|
remove_action( $this->args['admin_page'], [ Tribe__Settings::instance(), 'generatePage' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the splash screen.
|
||||||
|
*
|
||||||
|
* @param string $context
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function display_page() {
|
||||||
|
if ( empty( $this->args[ $this->current_context . '_page_title' ] ) || empty( $this->args[ $this->current_context . '_page_template'] ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_action( 'tribe_settings_top' );
|
||||||
|
|
||||||
|
$context = isset( $_GET[ $this->welcome_slug ] ) ? 'welcome': 'update';
|
||||||
|
$title = esc_html( $this->args[ $context . '_page_title'] );
|
||||||
|
$html = $this->get_view( $this->args[ $context . '_page_template'] );
|
||||||
|
|
||||||
|
echo "
|
||||||
|
<div class='tribe_settings tribe_{$context}_page wrap'>
|
||||||
|
<h1> {$title} </h1>
|
||||||
|
{$html}
|
||||||
|
</div>
|
||||||
|
";
|
||||||
|
|
||||||
|
do_action( 'tribe_settings_bottom' );
|
||||||
|
$this->log_display_of_message_page();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the output of the specified template.
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function get_view( $path ) {
|
||||||
|
if ( ! file_exists( $path ) ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
include $path;
|
||||||
|
return ob_get_clean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
namespace Tribe\Admin\Conditional_Content;
|
||||||
|
|
||||||
|
use Tribe__Date_Utils as Dates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up for Black Friday promo.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
class Black_Friday extends Datetime_Conditional_Abstract {
|
||||||
|
/**
|
||||||
|
* Promo slug.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
protected $slug = 'black_friday';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start Date.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
protected $start_date = 'fourth Thursday of November';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End Date.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
protected $end_date = 'November 30th';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register actions and filters.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function hook() {
|
||||||
|
add_action( 'tribe_general_settings_tab_fields', [ $this, 'add_conditional_content' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the Monday before Thanksgiving.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
* @return \Tribe\Utils\Date_I18n - Date Object
|
||||||
|
*/
|
||||||
|
protected function get_start_time() {
|
||||||
|
$date = parent::get_start_time();
|
||||||
|
$date = $date->modify( '-3 days' );
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace the opening markup for the general settings info box.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function add_conditional_content( $fields ) {
|
||||||
|
// Check if the content should currently be displayed.
|
||||||
|
if( ! $this->should_display() ) {
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up template variables.
|
||||||
|
$images_dir = \Tribe__Main::instance()->plugin_url . 'src/resources/images/';
|
||||||
|
$template_args = [
|
||||||
|
'branding_logo' => $images_dir . 'logo/tec-brand.svg',
|
||||||
|
'background_image' => $images_dir . 'marketing/bf-promo.png',
|
||||||
|
'button_link' => 'https://evnt.is/1aqi',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Get the Black Friday promo content.
|
||||||
|
$content = $this->get_template()->template( 'conditional_content/black-friday', $template_args, false );
|
||||||
|
|
||||||
|
// Replace starting info box markup.
|
||||||
|
$fields['info-start']['html'] .= $content;
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,160 @@
|
||||||
|
<?php
|
||||||
|
namespace Tribe\Admin\Conditional_Content;
|
||||||
|
|
||||||
|
use Tribe__Date_Utils as Dates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class for conditional content.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
abstract class Datetime_Conditional_Abstract {
|
||||||
|
/**
|
||||||
|
* Item slug.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
protected $slug = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start date.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
protected $start_date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start time.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
protected $start_time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End date.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
protected $end_date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End time.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
protected $end_time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the instance of the template engine that we will use for rendering the page.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*
|
||||||
|
* @var \Tribe__Template
|
||||||
|
*/
|
||||||
|
protected $template;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register actions and filters.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
abstract function hook();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unix datetime for content start.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
* @return \Tribe\Utils\Date_I18n - Date Object
|
||||||
|
*/
|
||||||
|
protected function get_start_time() {
|
||||||
|
$date = Dates::build_date_object( $this->start_date, 'UTC' );
|
||||||
|
// If not set, set to midnight.
|
||||||
|
if ( empty( $this->start_time ) ) {
|
||||||
|
$this->start_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$date = $date->setTime( $this->start_time, 0 );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow filtering of the start date for testing.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
* @param \DateTime $date - Unix timestamp for start date
|
||||||
|
* @param object $this
|
||||||
|
*/
|
||||||
|
$date = apply_filters( "tec_admin_conditional_content_{$this->slug}_start_date", $date, $this );
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unix datetime for content end.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
* @return \Tribe\Utils\Date_I18n - Date Object
|
||||||
|
*/
|
||||||
|
protected function get_end_time() {
|
||||||
|
$date = Dates::build_date_object( $this->end_date, 'UTC' );
|
||||||
|
// If not set, set to midnight.
|
||||||
|
if ( empty( $this->end_time ) ) {
|
||||||
|
$this->end_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$date = $date->setTime( $this->end_time, 0 );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow filtering of the end date for testing.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
* @param \DateTime $date - Unix timestamp for end date
|
||||||
|
* @param object $this
|
||||||
|
*/
|
||||||
|
$date = apply_filters( "tec_admin_conditional_content_{$this->slug}_end_date", $date, $this );
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the content should display.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
* @return boolean - Whether the content should display
|
||||||
|
*/
|
||||||
|
protected function should_display() {
|
||||||
|
$now = Dates::build_date_object( 'now', 'UTC' );
|
||||||
|
$notice_start = $this->get_start_time();
|
||||||
|
$notice_end = $this->get_end_time();
|
||||||
|
$display = $notice_start <= $now && $now < $notice_end;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow filtering whether the content should display.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
* @param bool $should_display - whether the content should display
|
||||||
|
* @param object $this - the conditional content object
|
||||||
|
*/
|
||||||
|
$should_display = apply_filters( "tec_admin_conditional_content_{$this->slug}_should_display", $display, $this );
|
||||||
|
|
||||||
|
return $should_display;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the template instance used to setup the rendering of the page.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*
|
||||||
|
* @return \Tribe__Template
|
||||||
|
*/
|
||||||
|
public function get_template() {
|
||||||
|
if ( empty( $this->template ) ) {
|
||||||
|
$this->template = new \Tribe__Template();
|
||||||
|
$this->template->set_template_origin( \Tribe__Main::instance() );
|
||||||
|
$this->template->set_template_folder( 'src/admin-views' );
|
||||||
|
$this->template->set_template_context_extract( true );
|
||||||
|
$this->template->set_template_folder_lookup( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->template;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?php
|
||||||
|
namespace Tribe\Admin\Conditional_Content;
|
||||||
|
|
||||||
|
use Tribe__Date_Utils as Dates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up for end of year sale promo.
|
||||||
|
*
|
||||||
|
* @since 4.14.9
|
||||||
|
*/
|
||||||
|
class End_Of_Year_Sale extends Datetime_Conditional_Abstract {
|
||||||
|
/**
|
||||||
|
* Promo slug.
|
||||||
|
*
|
||||||
|
* @since 4.14.9
|
||||||
|
*/
|
||||||
|
protected $slug = 'end_of_year_sale';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start Date.
|
||||||
|
*
|
||||||
|
* @since 4.14.9
|
||||||
|
*/
|
||||||
|
protected $start_date = 'December 23';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End Date.
|
||||||
|
*
|
||||||
|
* @since 4.14.9
|
||||||
|
*/
|
||||||
|
protected $end_date = 'December 31';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register actions and filters.
|
||||||
|
*
|
||||||
|
* @since 4.14.9
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function hook() {
|
||||||
|
add_action( 'tribe_general_settings_tab_fields', [ $this, 'add_conditional_content' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace the opening markup for the general settings info box.
|
||||||
|
*
|
||||||
|
* @since 4.14.9
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function add_conditional_content( $fields ) {
|
||||||
|
// Check if the content should currently be displayed.
|
||||||
|
if( ! $this->should_display() ) {
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up template variables.
|
||||||
|
$images_dir = \Tribe__Main::instance()->plugin_url . 'src/resources/images/';
|
||||||
|
$template_args = [
|
||||||
|
'branding_logo' => $images_dir . 'logo/tec-brand.svg',
|
||||||
|
'background_image' => $images_dir . 'marketing/eoy-sale-promo.png',
|
||||||
|
'button_link' => 'https://evnt.is/1a-x',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Get the promo content.
|
||||||
|
$content = $this->get_template()->template( 'conditional_content/end-of-year-sale', $template_args, false );
|
||||||
|
|
||||||
|
// Replace starting info box markup.
|
||||||
|
$fields['info-start']['html'] .= $content;
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unix time for notice end.
|
||||||
|
*
|
||||||
|
* @since 4.14.9
|
||||||
|
*
|
||||||
|
* @return \Tribe\Utils\Date_I18n - Date Object
|
||||||
|
*/
|
||||||
|
public function get_end_time() {
|
||||||
|
$date = parent::get_end_time();
|
||||||
|
$date = $date->setTime( 23, 59 );
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handles admin conditional content.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
* @package Tribe\Admin\Conditional_Content;
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tribe\Admin\Conditional_Content;
|
||||||
|
|
||||||
|
use TEC\Common\Contracts\Service_Provider as Provider_Contract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conditional Content Provider.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
class Service_Provider extends Provider_Contract {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the required objects and filters.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
public function register() {
|
||||||
|
$this->container->singleton( Black_Friday::class, Black_Friday::class, [ 'hook' ] );
|
||||||
|
// EOY Sale disabled for 2022
|
||||||
|
// $this->container->singleton( End_Of_Year_Sale::class, End_Of_Year_Sale::class, [ 'hook' ] );
|
||||||
|
$this->hooks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up hooks for classes.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
protected function hooks() {
|
||||||
|
add_action( 'tribe_plugins_loaded', [ $this, 'plugins_loaded' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup for things that require plugins loaded first.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*/
|
||||||
|
public function plugins_loaded() {
|
||||||
|
$this->container->make( Black_Friday::class );
|
||||||
|
// EOY Sale disabled for 2022
|
||||||
|
// $this->container->make( End_Of_Year_Sale::class );
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,193 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Don't load directly
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
die( '-1' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class with a few helpers for the Administration Pages
|
||||||
|
*/
|
||||||
|
class Tribe__Admin__Helpers {
|
||||||
|
/**
|
||||||
|
* Static Singleton Holder
|
||||||
|
* @var Tribe__Admin__Helpers|null
|
||||||
|
*/
|
||||||
|
protected static $instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static Singleton Factory Method
|
||||||
|
*
|
||||||
|
* @return Tribe__Admin__Helpers
|
||||||
|
*/
|
||||||
|
public static function instance() {
|
||||||
|
if ( empty( self::$instance ) ) {
|
||||||
|
self::$instance = new self();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the current screen is an instance of WP_Screen
|
||||||
|
* Hijack the return for tests
|
||||||
|
*
|
||||||
|
* @since 4.9.5
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_wp_screen() {
|
||||||
|
global $current_screen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter `tribe_admin_is_wp_screen`
|
||||||
|
* Allows fo filter if we're on a WP_Screen
|
||||||
|
*
|
||||||
|
* @since 4.9.5
|
||||||
|
* @param bool null bypass if we want to return a bool of is_wp_scren
|
||||||
|
*/
|
||||||
|
$is_wp_screen = apply_filters( 'tribe_admin_is_wp_screen', null );
|
||||||
|
if ( null !== $is_wp_screen ) {
|
||||||
|
return $is_wp_screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bool) ( $current_screen instanceof WP_Screen );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matcher for Admin Pages related to Post Types
|
||||||
|
*
|
||||||
|
* @param string|array|null $id What will be checked to see if we return true or false
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_post_type_screen( $post_type = null ) {
|
||||||
|
global $current_screen;
|
||||||
|
|
||||||
|
// Not in the admin we don't even care
|
||||||
|
if ( ! is_admin() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Doing AJAX? bail.
|
||||||
|
if ( tribe( 'context' )->doing_ajax() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid Notices by checking the object type of WP_Screen
|
||||||
|
if ( ! $this->is_wp_screen() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$defaults = apply_filters( 'tribe_is_post_type_screen_post_types', Tribe__Main::get_post_types() );
|
||||||
|
|
||||||
|
// Match any Post Type from Tribe
|
||||||
|
if ( is_null( $post_type ) && in_array( $current_screen->post_type, $defaults ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match any of the post_types set
|
||||||
|
if ( ! is_scalar( $post_type ) && in_array( $current_screen->post_type, (array) $post_type ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match a specific Post Type
|
||||||
|
if ( $current_screen->post_type === $post_type ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matcher for administration pages that are from Tribe the easier way
|
||||||
|
*
|
||||||
|
* @param string|array|null $id What will be checked to see if we return true or false
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_screen( $id = null ) {
|
||||||
|
global $current_screen;
|
||||||
|
|
||||||
|
// Not in the admin we don't even care
|
||||||
|
if ( ! is_admin() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Doing AJAX? bail.
|
||||||
|
if ( tribe( 'context' )->doing_ajax() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid Notices by checking the object type of WP_Screen.
|
||||||
|
if ( ! $this->is_wp_screen() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match any screen from Tribe.
|
||||||
|
if ( is_null( $id ) && false !== strpos( $current_screen->id, 'tribe' ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match any screen from TEC.
|
||||||
|
if ( is_null( $id ) && false !== strpos( $current_screen->id, 'tec' ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match any of the pages set
|
||||||
|
if ( ! is_scalar( $id ) && in_array( $current_screen->id, (array) $id ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match a specific page.
|
||||||
|
if ( $current_screen->id === $id ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match any post type page in the supported post types.
|
||||||
|
$defaults = apply_filters( 'tribe_is_post_type_screen_post_types', Tribe__Main::get_post_types() );
|
||||||
|
if ( in_array( $current_screen->post_type, $defaults ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matcher for administration pages action
|
||||||
|
*
|
||||||
|
* @param string|array|null $action What will be checked to see if we return true or false
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_action( $action = null ) {
|
||||||
|
global $current_screen;
|
||||||
|
|
||||||
|
// Not in the admin we don't even care
|
||||||
|
if ( ! is_admin() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Doing AJAX? bail.
|
||||||
|
if ( tribe( 'context' )->doing_ajax() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid Notices by checking the object type of WP_Screen
|
||||||
|
if ( ! $this->is_wp_screen() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match any of the pages set
|
||||||
|
if ( ! is_scalar( $action ) && in_array( $current_screen->action, (array) $action ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match a specific page
|
||||||
|
if ( $current_screen->action === $action ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Facilitiates live date previews in the Events > Settings > Display admin screen.
|
||||||
|
*/
|
||||||
|
class Tribe__Admin__Live_Date_Preview {
|
||||||
|
protected $target_fields = [
|
||||||
|
'dateWithYearFormat',
|
||||||
|
'dateWithoutYearFormat',
|
||||||
|
'monthAndYearFormat',
|
||||||
|
'weekDayFormat',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static Singleton Holder
|
||||||
|
*
|
||||||
|
* @var self
|
||||||
|
*/
|
||||||
|
protected static $instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static Singleton Factory Method
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public static function instance() {
|
||||||
|
return self::$instance ? self::$instance : self::$instance = new self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds live date previews to the display settings tab (nothing is setup unless
|
||||||
|
* the user is actually on that tab).
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
add_action( 'tribe_settings_after_do_tabs', [ $this, 'listen' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the user looking at the Display settings tab, adds live date preview facilities.
|
||||||
|
*/
|
||||||
|
public function listen() {
|
||||||
|
// We are only interested in the "Display" tab
|
||||||
|
if ( 'display' !== Tribe__Settings::instance()->currentTab ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add or remove fields which should have live date/time preview facilities.
|
||||||
|
*
|
||||||
|
* @var array $target_fields
|
||||||
|
*/
|
||||||
|
$this->target_fields = (array) apply_filters( 'tribe_settings_date_preview_fields', $this->target_fields );
|
||||||
|
|
||||||
|
add_filter( 'tribe_field_div_end', [ $this, 'setup_date_previews' ], 10, 2 );
|
||||||
|
|
||||||
|
// We are still before `admin_enqueue_scripts` making it safe to use `tribe_asset`
|
||||||
|
tribe_asset( Tribe__Main::instance(), 'tribe-date-live-refresh', 'admin-date-preview.js', [ 'jquery' ], 'admin_enqueue_scripts' );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setup_date_previews( $html, $field ) {
|
||||||
|
// Not one of the fields we're interested in? Return without modification
|
||||||
|
if ( ! in_array( $field->id, $this->target_fields ) ) {
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
$preview = esc_html( date_i18n( $field->value ) );
|
||||||
|
return " <code class='live-date-preview'> $preview </code> $html";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,378 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Abstract for various date-based Marketing notices, e.g. Black Friday sales or special coupon initiatives.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tribe\Admin\Notice;
|
||||||
|
|
||||||
|
use Tribe__Date_Utils as Dates;
|
||||||
|
|
||||||
|
abstract class Date_Based {
|
||||||
|
/**
|
||||||
|
* The slug used to make filters specific to an individual notice.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $slug = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder for start date string.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $start_date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder for start time int.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $start_time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder for end date string.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $end_date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder for end time int.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $end_time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder for extension date string.
|
||||||
|
*
|
||||||
|
* @since 4.15.4
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $extension_date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder for extension time int.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $extension_time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not The Events Calendar is active.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
public $tec_is_active;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the instance of the template engine that we will use for rendering the page.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*
|
||||||
|
* @var \Tribe__Template
|
||||||
|
*/
|
||||||
|
protected $template;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not Event Tickets is active.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
public $et_is_active;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The screens we show the notice on.
|
||||||
|
*
|
||||||
|
* @since 4.15.4
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $screens = [
|
||||||
|
'tribe_events_page_tribe-app-shop', // App shop.
|
||||||
|
'events_page_tribe-app-shop', // App shop.
|
||||||
|
'toplevel_page_tec-events', // New Events Welcome.
|
||||||
|
'tribe_events_page_tec-events-settings', // New Events Settings.
|
||||||
|
'tribe_events_page_tec-events-help', // New Events Help.
|
||||||
|
'tribe_events_page_tec-troubleshooting', // New Events Troubleshooting.
|
||||||
|
'tickets_page_tec-tickets-settings', // New Tickets Settings.
|
||||||
|
'toplevel_page_tec-tickets', // New Tickets Welcome.
|
||||||
|
'tickets_page_tec-tickets-help', // New Tickets Help.
|
||||||
|
'tickets_page_tec-tickets-troubleshooting', // New Ticket Troubleshooting.
|
||||||
|
'tribe_events_page_tribe-common', // Old Settings & Welcome.
|
||||||
|
'events_page_tribe-common', // Settings & Welcome.
|
||||||
|
'toplevel_page_tribe-common', // Settings & Welcome.
|
||||||
|
'tribe_events_page_aggregator', // Import page
|
||||||
|
'edit-tribe_events', // Events admin list
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$tribe_dependency = tribe( \Tribe__Dependency::class );
|
||||||
|
$this->tec_is_active = $tribe_dependency->is_plugin_active( 'Tribe__Events__Main' );
|
||||||
|
$this->et_is_active = $tribe_dependency->is_plugin_active( 'Tribe__Tickets__Main' );
|
||||||
|
|
||||||
|
$now = Dates::build_date_object( 'now', 'UTC' );
|
||||||
|
$notice_start = $this->get_start_time();
|
||||||
|
$notice_end = $this->get_end_time();
|
||||||
|
$extension_date = $this->get_extension_time();
|
||||||
|
|
||||||
|
// If we have an extension date defined.
|
||||||
|
if ( ! empty( $this->get_extension_time() ) ) {
|
||||||
|
// If the sale has started and
|
||||||
|
if (
|
||||||
|
$notice_start <= $now
|
||||||
|
&& $notice_end < $now
|
||||||
|
&& $now < $extension_date
|
||||||
|
) {
|
||||||
|
add_filter( "tribe_{$this->slug}_notice_end_date", function() {
|
||||||
|
return $this->get_extension_time();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->hook();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the various Marketing notices.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*/
|
||||||
|
public function hook() {
|
||||||
|
$this->hook_notice();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the notice.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*/
|
||||||
|
public function hook_notice() {
|
||||||
|
tribe_notice(
|
||||||
|
$this->slug,
|
||||||
|
[ $this, "display_notice" ],
|
||||||
|
[
|
||||||
|
'type' => 'tribe-banner',
|
||||||
|
'dismiss' => 1,
|
||||||
|
'priority' => -1,
|
||||||
|
'wrap' => false,
|
||||||
|
],
|
||||||
|
[ $this, "should_display" ]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTML for the notice.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @return string The HTML string to be displayed.
|
||||||
|
*/
|
||||||
|
abstract function display_notice();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to get and filter the screens the notice is displayed on.
|
||||||
|
*
|
||||||
|
* @since 4.15.4
|
||||||
|
*
|
||||||
|
* @return array<string> List of allowed screens.
|
||||||
|
*/
|
||||||
|
public function get_screens() {
|
||||||
|
$screens = $this->screens;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows filtering of the screens for all date-based notices.
|
||||||
|
*
|
||||||
|
* @since 4.15.4
|
||||||
|
*
|
||||||
|
* @param array<string> $screens The current list of allowed screens.
|
||||||
|
* @param string $slug The slug for the current notice.
|
||||||
|
*
|
||||||
|
* @return array<string> $screens The modified list of allowed screens.
|
||||||
|
*/
|
||||||
|
$screens = apply_filters(
|
||||||
|
'tec_date_based_notice_get_screens',
|
||||||
|
$screens,
|
||||||
|
$this->slug
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows filtering of the screens for a specific date-based notice.
|
||||||
|
*
|
||||||
|
* @since 4.15.4
|
||||||
|
*
|
||||||
|
* @param array<string> $screens The current list of allowed screens.
|
||||||
|
*
|
||||||
|
* @return array<string> $screens The modified list of allowed screens.
|
||||||
|
*/
|
||||||
|
$screens = apply_filters(
|
||||||
|
"tec_date_based_notice_get_screens_{$this->slug}",
|
||||||
|
$screens
|
||||||
|
);
|
||||||
|
|
||||||
|
return $screens;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the notice should display.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @return boolean $should_display Whether the notice should display or not.
|
||||||
|
*/
|
||||||
|
public function should_display() {
|
||||||
|
// If upsells have been manually hidden, respect that.
|
||||||
|
if ( tec_should_hide_upsell() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$current_screen = get_current_screen();
|
||||||
|
|
||||||
|
$screens = $this->get_screens();
|
||||||
|
|
||||||
|
// If not a valid screen, don't display.
|
||||||
|
if ( empty( $current_screen->id ) || ! in_array( $current_screen->id, $screens, true ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = Dates::build_date_object( 'now', 'UTC' );
|
||||||
|
$notice_start = $this->get_start_time();
|
||||||
|
$notice_end = $this->get_end_time();
|
||||||
|
|
||||||
|
$should_display = $notice_start <= $now && $now < $notice_end;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow filtering of whether the notice should display.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @param boolean $should_display Whether the notice should display.
|
||||||
|
* @param Tribe__Admin__Notice_Date_Based $notice The notice object.
|
||||||
|
*/
|
||||||
|
return apply_filters( "tribe_{$this->slug}_notice_should_display", $should_display, $this );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unix time for notice start.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @return \Tribe\Utils\Date_I18n - Date Object
|
||||||
|
*/
|
||||||
|
public function get_start_time() {
|
||||||
|
$date = Dates::build_date_object( $this->start_date, 'UTC' );
|
||||||
|
if ( $this->start_time !== null ) {
|
||||||
|
$date = $date->setTime( $this->start_time, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow filtering of the start date DateTime object,
|
||||||
|
* to allow for things like "the day before" ( $date->modify( '-1 day' ) ) and such.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @param \DateTime $date Date object for the notice start.
|
||||||
|
*/
|
||||||
|
$date = apply_filters( "tribe_{$this->slug}_notice_start_date", $date, $this );
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unix time for notice end.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @return \Tribe\Utils\Date_I18n - Date Object
|
||||||
|
*/
|
||||||
|
public function get_end_time() {
|
||||||
|
$date = Dates::build_date_object( $this->end_date, 'UTC' );
|
||||||
|
if ( $this->end_time !== null ) {
|
||||||
|
$date = $date->setTime( $this->end_time, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow filtering of the end date DateTime object,
|
||||||
|
* to allow for things like "the day after" ( $date->modify( '+1 day' ) ) and such.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @param \DateTime $date Date object for the notice end.
|
||||||
|
*/
|
||||||
|
$date = apply_filters( "tribe_{$this->slug}_notice_end_date", $date, $this );
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unix time for notice extension end.
|
||||||
|
*
|
||||||
|
* @since 4.15.4
|
||||||
|
*
|
||||||
|
* @return int $end_time The date & time the notice should stop displaying, as a Unix timestamp.
|
||||||
|
*/
|
||||||
|
public function get_extension_time() {
|
||||||
|
if ( $this->extension_date === null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$date = Dates::build_date_object( $this->extension_date, 'UTC' );
|
||||||
|
|
||||||
|
if ( $this->extension_time !== null ) {
|
||||||
|
$date = $date->setTime( $this->extension_time, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow filtering of the extension date DateTime object,
|
||||||
|
* to allow for things like "the day after" ( $date->modify( '+1 day' ) ) and such.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @param \DateTime $date Date object for the notice end.
|
||||||
|
*/
|
||||||
|
$date = apply_filters( "tribe_{$this->slug}_notice_extension_date", $date, $this );
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the template instance used to setup the rendering of the page.
|
||||||
|
*
|
||||||
|
* @since 4.14.7
|
||||||
|
*
|
||||||
|
* @return \Tribe__Template
|
||||||
|
*/
|
||||||
|
public function get_template() {
|
||||||
|
if ( empty( $this->template ) ) {
|
||||||
|
$this->template = new \Tribe__Template();
|
||||||
|
$this->template->set_template_origin( \Tribe__Main::instance() );
|
||||||
|
$this->template->set_template_folder( 'src/admin-views' );
|
||||||
|
$this->template->set_template_context_extract( true );
|
||||||
|
$this->template->set_template_folder_lookup( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->template;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,190 @@
|
||||||
|
<?php
|
||||||
|
_deprecated_file(__FILE__, '4.14.2', 'Deprecated to a more granular approach.' );
|
||||||
|
/**
|
||||||
|
* Various Marketing notices, e.g. Black Friday sales or special coupon initiatives.
|
||||||
|
*
|
||||||
|
* @since 4.7.23
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Tribe__Date_Utils as Dates;
|
||||||
|
|
||||||
|
class Tribe__Admin__Notice__Marketing {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not The Events Calendar is active.
|
||||||
|
*
|
||||||
|
* @since 4.7.23
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
public $tec_is_active;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not Event Tickets is active.
|
||||||
|
*
|
||||||
|
* @since 4.7.23
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
public $et_is_active;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$tribe_dependency = Tribe__Dependency::instance();
|
||||||
|
$this->tec_is_active = $tribe_dependency->is_plugin_active( 'Tribe__Events__Main' );
|
||||||
|
$this->et_is_active = $tribe_dependency->is_plugin_active( 'Tribe__Tickets__Main' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the various Marketing notices.
|
||||||
|
*
|
||||||
|
* @since 4.7.23
|
||||||
|
*/
|
||||||
|
public function hook() {
|
||||||
|
$this->black_friday_hook_notice();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the Black Friday notice.
|
||||||
|
*
|
||||||
|
* @since 4.12.14
|
||||||
|
*/
|
||||||
|
public function black_friday_hook_notice() {
|
||||||
|
|
||||||
|
tribe_notice(
|
||||||
|
'black-friday',
|
||||||
|
[ $this, 'black_friday_display_notice' ],
|
||||||
|
[
|
||||||
|
'type' => 'tribe-banner',
|
||||||
|
'dismiss' => 1,
|
||||||
|
'priority' => -1,
|
||||||
|
'wrap' => false,
|
||||||
|
],
|
||||||
|
[ $this, 'black_friday_should_display' ]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unix time for Monday of Thanksgiving week @ 11am UTC. (11am UTC is 6am EST).
|
||||||
|
*
|
||||||
|
* @since 4.12.14
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function get_black_friday_start_time() {
|
||||||
|
$date = Dates::build_date_object( 'fourth Thursday of November ' . date( 'Y' ), 'UTC' );
|
||||||
|
$date = $date->modify( '-3 days' );
|
||||||
|
$date = $date->setTime( 11, 0 );
|
||||||
|
|
||||||
|
$start_time = $date->format( 'U' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow filtering of the Black Friday sale start date, mainly for testing purposes.
|
||||||
|
*
|
||||||
|
* @since 4.12.14
|
||||||
|
*
|
||||||
|
* @param int $bf_start_date Unix time for the Monday of Thanksgiving week @ 6am UTC.
|
||||||
|
*/
|
||||||
|
return apply_filters( 'tribe_black_friday_start_time', $start_time );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unix time for Dec 1 @ 5am UTC. (5am UTC is 12am EST).
|
||||||
|
*
|
||||||
|
* @since 4.12.14
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function get_black_friday_end_time() {
|
||||||
|
$date = Dates::build_date_object( 'December 1st', 'UTC' );
|
||||||
|
$date = $date->setTime( 5, 0 );
|
||||||
|
|
||||||
|
$end_time = $date->format( 'U' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow filtering of the Black Friday sale end date, mainly for testing purposes.
|
||||||
|
*
|
||||||
|
* @since 4.12.14
|
||||||
|
*
|
||||||
|
* @param int $bf_end_date Unix time for Dec 1 @ 6am UTC.
|
||||||
|
*/
|
||||||
|
return apply_filters( 'tribe_black_friday_end_time', $end_time );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Whether the Black Friday notice should display.
|
||||||
|
*
|
||||||
|
* Unix times for Monday of Thanksgiving week @ 6am UTC and Dec 1 2020 @ 6am UTC.
|
||||||
|
* 6am UTC is midnight for TheEventsCalendar.com, which uses the America/Los_Angeles time zone.
|
||||||
|
*
|
||||||
|
* @since 4.12.14
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function black_friday_should_display() {
|
||||||
|
// If upsells have been manually hidden, respect that.
|
||||||
|
if ( tec_should_hide_upsell() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = Dates::build_date_object( 'now', 'UTC' )->format( 'U' );
|
||||||
|
$bf_sale_start = $this->get_black_friday_start_time();
|
||||||
|
$bf_sale_end = $this->get_black_friday_end_time();
|
||||||
|
|
||||||
|
$current_screen = get_current_screen();
|
||||||
|
|
||||||
|
$screens = [
|
||||||
|
'tribe_events_page_tribe-app-shop', // App shop.
|
||||||
|
'events_page_tribe-app-shop', // App shop.
|
||||||
|
'tribe_events_page_tribe-common', // Settings & Welcome.
|
||||||
|
'tribe_events_page_tec-events-settings', // New Settings & Welcome.
|
||||||
|
'events_page_tribe-common', // Settings & Welcome.
|
||||||
|
'toplevel_page_tribe-common', // Settings & Welcome.
|
||||||
|
];
|
||||||
|
|
||||||
|
// If not a valid screen, don't display.
|
||||||
|
if ( empty( $current_screen->id ) || ! in_array( $current_screen->id, $screens, true ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bf_sale_start <= $now && $now < $bf_sale_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTML for the Black Friday notice.
|
||||||
|
*
|
||||||
|
* @since 4.12.14
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function black_friday_display_notice() {
|
||||||
|
Tribe__Assets::instance()->enqueue( [ 'tribe-common-admin' ] );
|
||||||
|
|
||||||
|
$current_screen = get_current_screen();
|
||||||
|
|
||||||
|
$icon_url = Tribe__Main::instance()->plugin_url . 'src/resources/images/icons/sale-burst.svg';
|
||||||
|
$cta_url = 'https://evnt.is/bf' . date( 'Y' );
|
||||||
|
$screens = [
|
||||||
|
'tribe_events_page_tribe-common',
|
||||||
|
'tribe_events_page_tec-events-settings',
|
||||||
|
'events_page_tribe-common',
|
||||||
|
'toplevel_page_tribe-common',
|
||||||
|
];
|
||||||
|
|
||||||
|
// If we are on the settings page or a welcome page, change the Black Friday URL.
|
||||||
|
if (
|
||||||
|
! empty( $current_screen->id )
|
||||||
|
&& in_array( $current_screen->id, $screens )
|
||||||
|
) {
|
||||||
|
if ( isset( $_GET['welcome-message-the-events-calendar'] ) || isset( $_GET['welcome-message-event-tickets' ] ) ) {
|
||||||
|
$cta_url .= 'welcome';
|
||||||
|
} else {
|
||||||
|
$cta_url .= 'settings';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
|
||||||
|
include Tribe__Main::instance()->plugin_path . 'src/admin-views/notices/tribe-bf-general.php';
|
||||||
|
|
||||||
|
return ob_get_clean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Notice for the Black Friday Sale
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tribe\Admin\Notice\Marketing;
|
||||||
|
|
||||||
|
use Tribe__Date_Utils as Dates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Black_Friday
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @package Tribe\Admin\Notice\Marketing
|
||||||
|
*/
|
||||||
|
class Black_Friday extends \Tribe\Admin\Notice\Date_Based {
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public $slug = 'black-friday';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public $start_date = 'fourth Thursday of November';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public $end_date = 'November 29';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public $end_time = 23;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function display_notice() {
|
||||||
|
\Tribe__Assets::instance()->enqueue( [ 'tribe-common-admin' ] );
|
||||||
|
|
||||||
|
// Set up template variables.
|
||||||
|
$template_args = [
|
||||||
|
'icon_url' => \Tribe__Main::instance()->plugin_url . 'src/resources/images/icons/sale-burst.svg',
|
||||||
|
'cta_url' => 'https://evnt.is/1aqi',
|
||||||
|
'end_date' => $this->get_end_time()->format_i18n( 'F jS' ),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Get the Black Friday notice content.
|
||||||
|
$content = $this->get_template()->template( 'notices/tribe-bf-general', $template_args, false );
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unix time for notice start.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @return \Tribe\Utils\Date_I18n - Date Object
|
||||||
|
*/
|
||||||
|
public function get_start_time() {
|
||||||
|
$date = parent::get_start_time();
|
||||||
|
$date = $date->modify( '-3 days' );
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Notice for the end of year Sale
|
||||||
|
*
|
||||||
|
* @since 4.14.9
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tribe\Admin\Notice\Marketing;
|
||||||
|
|
||||||
|
use Tribe__Date_Utils as Dates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class End_Of_Year_Sale
|
||||||
|
*
|
||||||
|
* @since 4.14.9
|
||||||
|
*
|
||||||
|
* @package Tribe\Admin\Notice\Marketing
|
||||||
|
*/
|
||||||
|
class End_Of_Year_Sale extends \Tribe\Admin\Notice\Date_Based {
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public $slug = 'end-of-year-sale';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public $start_date = 'December 23';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public $end_date = 'December 31';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function display_notice() {
|
||||||
|
tribe_asset_enqueue( [ 'tribe-common-admin' ] );
|
||||||
|
|
||||||
|
// Set up template variables.
|
||||||
|
$template_args = [
|
||||||
|
'icon_url' => \Tribe__Main::instance()->plugin_url . 'src/resources/images/marketing/eoy-sale-2021.svg',
|
||||||
|
'cta_url' => 'https://evnt.is/1a-x',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Get the sale notice content.
|
||||||
|
$content = $this->get_template()->template( 'notices/end-of-year-sale', $template_args, false );
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unix time for notice end.
|
||||||
|
*
|
||||||
|
* @since 4.14.9
|
||||||
|
*
|
||||||
|
* @return \Tribe\Utils\Date_I18n - Date Object
|
||||||
|
*/
|
||||||
|
public function get_end_time() {
|
||||||
|
$date = parent::get_end_time();
|
||||||
|
$date = $date->setTime( 23, 59 );
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Notice for the Stellar Sale
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tribe\Admin\Notice\Marketing;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Stellar_Sale
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @package Tribe\Admin\Notice\Marketing
|
||||||
|
*/
|
||||||
|
class Stellar_Sale extends \Tribe\Admin\Notice\Date_Based {
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public $slug = 'stellar-sale';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public $start_date = 'July 24th, 2023';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* 7am UTC is midnight PDT (-7) and 3am EDT (-4)
|
||||||
|
*/
|
||||||
|
public $start_time = 19;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public $end_date = 'July 31st, 2023';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* 7am UTC is midnight PDT (-7) and 3am EDT (-4)
|
||||||
|
*/
|
||||||
|
public $end_time = 19;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public $extension_date = 'August 2nd, 2023';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* 7am UTC is midnight PDT (-7) and 3am EDT (-4)
|
||||||
|
*/
|
||||||
|
public $extension_time = 19;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function display_notice() {
|
||||||
|
\Tribe__Assets::instance()->enqueue( [ 'tribe-common-admin' ] );
|
||||||
|
|
||||||
|
// Used in the template.
|
||||||
|
$cta_url = 'https://evnt.is/1bcv';
|
||||||
|
$stellar_url = 'https://evnt.is/1bcu';
|
||||||
|
$end_date = $this->get_end_time();
|
||||||
|
$template_args = [
|
||||||
|
'cta_url' => 'https://evnt.is/1bcv',
|
||||||
|
'stellar_url' => 'https://evnt.is/1bcu',
|
||||||
|
'end_date' => $this->get_end_time(),
|
||||||
|
];
|
||||||
|
$dependency = tribe( \Tribe__Dependency::class );
|
||||||
|
|
||||||
|
if ( $dependency->has_active_premium_plugin() ) {
|
||||||
|
return $this->get_template()->template( 'notices/tribe-stellar-sale-premium', $template_args, false );
|
||||||
|
} else {
|
||||||
|
return $this->get_template()->template( 'notices/tribe-stellar-sale', $template_args, false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Shows an admin notice for Php_Version
|
||||||
|
*/
|
||||||
|
class Tribe__Admin__Notice__Php_Version {
|
||||||
|
|
||||||
|
public function hook() {
|
||||||
|
|
||||||
|
// display the PHP version notice
|
||||||
|
tribe_notice(
|
||||||
|
'php-deprecated-74',
|
||||||
|
[ $this, 'display_notice' ],
|
||||||
|
[
|
||||||
|
'type' => 'warning',
|
||||||
|
'dismiss' => 1,
|
||||||
|
'wrap' => 'p',
|
||||||
|
],
|
||||||
|
[ $this, 'should_display' ]
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the list of the Tribe active plugins
|
||||||
|
*
|
||||||
|
* @since 4.7.16
|
||||||
|
*
|
||||||
|
* @return string String of items
|
||||||
|
*/
|
||||||
|
public function get_active_plugins() {
|
||||||
|
|
||||||
|
$active_plugins = Tribe__Dependency::instance()->get_active_plugins();
|
||||||
|
|
||||||
|
foreach ( $active_plugins as $active_plugin ) {
|
||||||
|
|
||||||
|
if ( ! $active_plugin['path'] ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$plugin_data = get_plugin_data( $active_plugin['path'] );
|
||||||
|
$plugins[] = $plugin_data['Name'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->implode_with_grammar( $plugins );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implodes a list items using 'and' as the final separator and a comma everywhere else
|
||||||
|
*
|
||||||
|
* @param array $items List of items to implode
|
||||||
|
* @since 4.7.16
|
||||||
|
*
|
||||||
|
* @return string String of items
|
||||||
|
*/
|
||||||
|
public function implode_with_grammar( $items ) {
|
||||||
|
|
||||||
|
$separator = _x( ', ', 'separator used in a list of items', 'tribe-common' );
|
||||||
|
$conjunction = _x( ' and ', 'the final separator in a list of two or more items', 'tribe-common' );
|
||||||
|
$output = $last_item = array_pop( $items );
|
||||||
|
|
||||||
|
if ( $items ) {
|
||||||
|
$output = implode( $separator, $items ) . $conjunction . $last_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We only want to display notices for users
|
||||||
|
* who are in PHP < 5.6
|
||||||
|
*
|
||||||
|
* @since 4.7.16
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function should_display() {
|
||||||
|
// Bail if the user is not admin or can manage plugins
|
||||||
|
if ( ! current_user_can( 'activate_plugins' ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return version_compare( PHP_VERSION, '7.4.0' ) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTML for the PHP notice
|
||||||
|
*
|
||||||
|
* @since 4.7.16
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function display_notice() {
|
||||||
|
/* Translators: %1$s list of plugins, %2$s current PHP version, %3$s open anchor html link for read more, %4$s open anchor html link for read more */
|
||||||
|
$text = _x(
|
||||||
|
'Starting February 2023, %1$s will require PHP 7.4 or later. Currently, your site is using PHP version %2$s. Please update to a newer version. %3$sRead more%4$s.',
|
||||||
|
'Message notifying users they need to upgrade PHP',
|
||||||
|
'tribe-common'
|
||||||
|
);
|
||||||
|
|
||||||
|
$plugins = $this->get_active_plugins();
|
||||||
|
|
||||||
|
return sprintf( $text, $plugins, PHP_VERSION, '<a href="https://wordpress.org/support/update-php/" target="_blank">', '</a>' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows an admin notice telling users which requisite plugins they need to download
|
||||||
|
*/
|
||||||
|
class Tribe__Admin__Notice__Plugin_Download {
|
||||||
|
|
||||||
|
private $plugin_path;
|
||||||
|
|
||||||
|
private $plugins_required = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $plugin_path Path to the plugin file we're showing a notice for
|
||||||
|
*/
|
||||||
|
public function __construct( $plugin_path ) {
|
||||||
|
$this->plugin_path = $plugin_path;
|
||||||
|
|
||||||
|
tribe_notice(
|
||||||
|
plugin_basename( $plugin_path ),
|
||||||
|
[ $this, 'show_inactive_plugins_alert' ]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a required plugin to the notice
|
||||||
|
*
|
||||||
|
* @since 4.8.3 Method introduced.
|
||||||
|
* @since 4.9 Added $version and $addon parameters.
|
||||||
|
* @since 4.9.12 Add $has_pue_notice param
|
||||||
|
* @since 4.9.17 Appended "+" to all version numbers to indicate "or any later version".
|
||||||
|
*
|
||||||
|
* @param string $name Name of the required plugin
|
||||||
|
* @param null $thickbox_url Download or purchase URL for plugin from within /wp-admin/ thickbox
|
||||||
|
* @param bool $is_active Indicates if the plugin is installed and active or not
|
||||||
|
* @param string $version Optional version number of the required plugin
|
||||||
|
* @param bool $addon Indicates if the plugin is an add-on for The Events Calendar or Event Tickets
|
||||||
|
* @param bool $has_pue_notice Indicates that we need to change the messaging due to expired key.
|
||||||
|
*/
|
||||||
|
public function add_required_plugin( $name, $thickbox_url = null, $is_active = null, $version = null, $addon = false, $has_pue_notice = false ) {
|
||||||
|
$this->plugins_required[ $name ] = [
|
||||||
|
'name' => $name,
|
||||||
|
'thickbox_url' => $thickbox_url,
|
||||||
|
'is_active' => $is_active,
|
||||||
|
'version' => $version ? $version . '+' : null,
|
||||||
|
'addon' => $addon,
|
||||||
|
'has_pue_notice' => $has_pue_notice,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Echoes the admin notice, attach to admin_notices
|
||||||
|
*
|
||||||
|
* @see \Tribe__Admin__Notice__Plugin_Download::add_required_plugin()
|
||||||
|
*
|
||||||
|
* @since 4.9.17 Altered the notice to remove "latest version" verbiage since "+" is now added to the version numbers.
|
||||||
|
*/
|
||||||
|
public function show_inactive_plugins_alert() {
|
||||||
|
if ( ! current_user_can( 'activate_plugins' ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$plugin_data = get_plugin_data( $this->plugin_path );
|
||||||
|
$req_plugins = [];
|
||||||
|
|
||||||
|
if ( empty( $this->plugins_required ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure Thickbox is available and consistent appearance regardless of which admin page we're on
|
||||||
|
add_thickbox();
|
||||||
|
|
||||||
|
$has_pue_notices = false;
|
||||||
|
|
||||||
|
foreach ( $this->plugins_required as $req_plugin ) {
|
||||||
|
$item = $req_plugin['name'];
|
||||||
|
$version = empty( $req_plugin['version'] ) ? '' : ' (' . str_replace( '-dev', '', $req_plugin['version'] ) . ')';
|
||||||
|
|
||||||
|
if ( ! empty( $req_plugin['thickbox_url'] ) ) {
|
||||||
|
$item = sprintf(
|
||||||
|
'<a href="%1$s" class="thickbox" title="%2$s">%3$s%4$s</a>',
|
||||||
|
esc_attr( $req_plugin['thickbox_url'] ),
|
||||||
|
esc_attr( $req_plugin['name'] ),
|
||||||
|
esc_html( $item ),
|
||||||
|
esc_html( $version )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( false === $req_plugin['is_active'] ) {
|
||||||
|
$item = sprintf(
|
||||||
|
'<strong class="tribe-inactive-plugin">%1$s</strong>',
|
||||||
|
$item
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $req_plugin['addon'] ) ) {
|
||||||
|
$plugin_name[] = $req_plugin['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$req_plugins[] = $item;
|
||||||
|
|
||||||
|
// If any of the items has PUE notice we will warn the user.
|
||||||
|
if ( $req_plugin['has_pue_notice'] ) {
|
||||||
|
$has_pue_notices = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If empty then add in the default name.
|
||||||
|
if ( empty( $plugin_name[0] ) ) {
|
||||||
|
$plugin_name[] = $plugin_data['Name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowed_html = [
|
||||||
|
'strong' => [],
|
||||||
|
'a' => [ 'href' => [] ],
|
||||||
|
];
|
||||||
|
|
||||||
|
$plugin_names_clean_text = wp_kses( $this->implode_with_grammar( $plugin_name ), $allowed_html );
|
||||||
|
$req_plugin_names_clean_text = wp_kses( $this->implode_with_grammar( $req_plugins ), $allowed_html );
|
||||||
|
|
||||||
|
$notice_html_content = '<p>' . esc_html__( 'To begin using %2$s, please install (or upgrade) and activate %3$s.', 'tribe-common' ) . '</p>';
|
||||||
|
|
||||||
|
$read_more_link = '<a href="http://evnt.is/1aev" target="_blank">' . esc_html__( 'Read more', 'tribe-common' ) . '.</a>';
|
||||||
|
$pue_notice_text = esc_html__( 'There’s a new version of %1$s available, but your license is expired. You’ll need to renew your license to get access to the latest version. If you plan to continue using your current version of the plugin(s), be sure to use a compatible version of The Events Calendar. %2$s', 'tribe-common' );
|
||||||
|
$pue_notice_html = '<p>' . sprintf( $pue_notice_text, $plugin_names_clean_text, $read_more_link ) . '</p>';
|
||||||
|
|
||||||
|
printf(
|
||||||
|
'<div class="error tribe-notice tribe-dependency-error" data-plugin="%1$s">'
|
||||||
|
. $notice_html_content
|
||||||
|
. ( $has_pue_notices ? $pue_notice_html : '' )
|
||||||
|
. '</div>',
|
||||||
|
esc_attr( sanitize_title( $plugin_data['Name'] ) ),
|
||||||
|
$plugin_names_clean_text,
|
||||||
|
$req_plugin_names_clean_text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implodes a list of items with proper grammar.
|
||||||
|
*
|
||||||
|
* If only 1 item, no grammar. If 2 items, just conjunction. If 3+ items, commas with conjunction.
|
||||||
|
*
|
||||||
|
* @param array $items List of items to implode
|
||||||
|
*
|
||||||
|
* @return string String of items
|
||||||
|
*/
|
||||||
|
public function implode_with_grammar( $items ) {
|
||||||
|
$separator = _x( ', ', 'separator used in a list of items', 'tribe-common' );
|
||||||
|
$conjunction = _x( ' and ', 'the final separator in a list of two or more items', 'tribe-common' );
|
||||||
|
$output = $last_item = array_pop( $items );
|
||||||
|
|
||||||
|
if ( $items ) {
|
||||||
|
$output = implode( $separator, $items );
|
||||||
|
|
||||||
|
if ( 1 < count( $items ) ) {
|
||||||
|
$output .= $separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
$output .= $conjunction . $last_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,239 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* When appropriate, displays a plugin upgrade message "inline" within the plugin
|
||||||
|
* admin screen.
|
||||||
|
*
|
||||||
|
* This is drawn from the Upgrade Notice section of the plugin readme.txt file (ie,
|
||||||
|
* the one belonging to the current stable accessible via WP SVN - at least by
|
||||||
|
* default).
|
||||||
|
*/
|
||||||
|
class Tribe__Admin__Notice__Plugin_Upgrade_Notice {
|
||||||
|
/**
|
||||||
|
* Currently installed version of the plugin
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $current_version = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The plugin path as it is within the plugins directory, ie
|
||||||
|
* "some-plugin/main-file.php".
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $plugin_path = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the plugin upgrade notice (empty if none are available).
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $upgrade_notice = '';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for and display any plugin upgrade messages (if any are available) inline
|
||||||
|
* beside the plugin listing itself.
|
||||||
|
*
|
||||||
|
* The optional third param is the object which actually checks to see if there
|
||||||
|
* are any upgrade notices worth displaying. If not provided, an object of the
|
||||||
|
* default type will be created (which connects to WP SVN).
|
||||||
|
*
|
||||||
|
* @param string $current_version
|
||||||
|
* @param string $plugin_path (ie "plugin-dir/main-file.php")
|
||||||
|
*/
|
||||||
|
public function __construct( $current_version, $plugin_path ) {
|
||||||
|
$this->current_version = $current_version;
|
||||||
|
$this->plugin_path = $plugin_path;
|
||||||
|
|
||||||
|
add_action( "in_plugin_update_message-$plugin_path", [ $this, 'maybe_run' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if there is a plugin upgrade notice and displays it if so.
|
||||||
|
*
|
||||||
|
* Expects to fire during "in_plugin_update_message-{plugin_path}", therefore
|
||||||
|
* this should only run if WordPress has detected that an upgrade is indeed
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
public function maybe_run() {
|
||||||
|
$this->test_for_upgrade_notice();
|
||||||
|
|
||||||
|
if ( $this->upgrade_notice ) {
|
||||||
|
$this->display_message();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests to see if an upgrade notice is available.
|
||||||
|
*/
|
||||||
|
protected function test_for_upgrade_notice() {
|
||||||
|
$cache_key = $this->cache_key();
|
||||||
|
$this->upgrade_notice = get_transient( $cache_key );
|
||||||
|
|
||||||
|
if ( false === $this->upgrade_notice ) {
|
||||||
|
$this->discover_upgrade_notice();
|
||||||
|
}
|
||||||
|
|
||||||
|
set_transient( $cache_key, $this->upgrade_notice, $this->cache_expiration() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a cache key unique to the current plugin path and version, that
|
||||||
|
* still fits within the 45-char limit of regular WP transient keys.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function cache_key() {
|
||||||
|
return 'tribe_plugin_upgrade_notice-' . hash( 'crc32b', $this->plugin_path . $this->current_version );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the period of time (in seconds) for which to cache plugin upgrade messages.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function cache_expiration() {
|
||||||
|
/**
|
||||||
|
* Number of seconds to cache plugin upgrade messages for.
|
||||||
|
*
|
||||||
|
* Defaults to one day, which provides a decent balance between efficiency savings
|
||||||
|
* and allowing for the possibility that some upgrade messages may be changed or
|
||||||
|
* rescinded.
|
||||||
|
*
|
||||||
|
* @var int $cache_expiration
|
||||||
|
*/
|
||||||
|
return (int) apply_filters( 'tribe_plugin_upgrade_notice_expiration', DAY_IN_SECONDS, $this->plugin_path );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks at the current stable plugin readme.txt and parses to try and find the first
|
||||||
|
* available upgrade notice relating to a plugin version higher than this one.
|
||||||
|
*
|
||||||
|
* By default, WP SVN is the source.
|
||||||
|
*/
|
||||||
|
protected function discover_upgrade_notice() {
|
||||||
|
/**
|
||||||
|
* The URL for the current plugin readme.txt file.
|
||||||
|
*
|
||||||
|
* @var string $url
|
||||||
|
* @var string $plugin_path
|
||||||
|
*/
|
||||||
|
$readme_url = apply_filters( 'tribe_plugin_upgrade_readme_url',
|
||||||
|
$this->form_wp_svn_readme_url(),
|
||||||
|
$this->plugin_path
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( ! empty( $readme_url ) ) {
|
||||||
|
$response = wp_safe_remote_get( $readme_url );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $response ) && ! is_wp_error( $response ) ) {
|
||||||
|
$readme = $response['body'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $readme ) ) {
|
||||||
|
$this->parse_for_upgrade_notice( $readme );
|
||||||
|
$this->format_upgrade_notice();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The upgrade notice for the current plugin (may be empty).
|
||||||
|
*
|
||||||
|
* @var string $upgrade_notice
|
||||||
|
* @var string $plugin_path
|
||||||
|
*/
|
||||||
|
return apply_filters( 'tribe_plugin_upgrade_notice',
|
||||||
|
$this->upgrade_notice,
|
||||||
|
$this->plugin_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forms the expected URL to the trunk readme.txt file as it is on WP SVN
|
||||||
|
* or an empty string if for any reason it cannot be determined.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function form_wp_svn_readme_url() {
|
||||||
|
$parts = explode( '/', $this->plugin_path );
|
||||||
|
$slug = empty( $parts[0] ) ? '' : $parts[0];
|
||||||
|
return esc_url( "https://plugins.svn.wordpress.org/$slug/trunk/readme.txt" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a standard Markdown-format WP readme.txt file, finds the first upgrade
|
||||||
|
* notice (if any) for a version higher than $this->current_version.
|
||||||
|
*
|
||||||
|
* @param string $readme
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function parse_for_upgrade_notice( $readme ) {
|
||||||
|
$in_upgrade_notice = false;
|
||||||
|
$in_version_notice = false;
|
||||||
|
$readme_lines = explode( "\n", $readme );
|
||||||
|
|
||||||
|
foreach ( $readme_lines as $line ) {
|
||||||
|
// Once we leave the Upgrade Notice section (ie, we encounter a new section header), bail
|
||||||
|
if ( $in_upgrade_notice && 0 === strpos( $line, '==' ) ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look out for the start of the Upgrade Notice section
|
||||||
|
if ( ! $in_upgrade_notice && preg_match( '/^==\s*Upgrade\s+Notice\s*==/i', $line ) ) {
|
||||||
|
$in_upgrade_notice = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also test to see if we have left the version specific note (ie, we encounter a new sub heading or header)
|
||||||
|
if ( $in_upgrade_notice && $in_version_notice && 0 === strpos( $line, '=' ) ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look out for the first applicable version-specific note within the Upgrade Notice section
|
||||||
|
if ( $in_upgrade_notice && ! $in_version_notice && preg_match( '/^=\s*\[?([0-9\.]{3,})\]?\s*=/', $line, $matches ) ) {
|
||||||
|
// Is this a higher version than currently installed?
|
||||||
|
if ( version_compare( $matches[1], $this->current_version, '>' ) ) {
|
||||||
|
$in_version_notice = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the details of the upgrade notice for the first higher version we find
|
||||||
|
if ( $in_upgrade_notice && $in_version_notice ) {
|
||||||
|
$this->upgrade_notice .= $line . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the plugin version header and any links from Markdown to HTML.
|
||||||
|
*/
|
||||||
|
protected function format_upgrade_notice() {
|
||||||
|
// Convert [links](http://...) to <a href="..."> tags
|
||||||
|
$this->upgrade_notice = preg_replace(
|
||||||
|
'/\[([^\]]*)\]\(([^\)]*)\)/',
|
||||||
|
'<a href="${2}">${1}</a>',
|
||||||
|
$this->upgrade_notice
|
||||||
|
);
|
||||||
|
|
||||||
|
// Convert =4.0= headings to <h4 class="version">4.0</h4> tags
|
||||||
|
$this->upgrade_notice = preg_replace(
|
||||||
|
'/=\s*([a-zA-Z0-9\.]{3,})\s*=/',
|
||||||
|
'<h4 class="version">${1}</h4>',
|
||||||
|
$this->upgrade_notice
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the actual upgrade notice.
|
||||||
|
*
|
||||||
|
* Please note if plugin-specific styling is required for the message, you can
|
||||||
|
* use an ID generated by WordPress for one of the message's parent elements
|
||||||
|
* which takes the form "{plugin_name}-update". Example:
|
||||||
|
*
|
||||||
|
* #the-events-calendar-update .tribe-plugin-update-message { ... }
|
||||||
|
*/
|
||||||
|
public function display_message() {
|
||||||
|
$notice = wp_kses_post( $this->upgrade_notice );
|
||||||
|
echo "<div class='tribe-plugin-update-message'> $notice </div>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handles admin notice functions.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @package Tribe\Admin\Notice;
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tribe\Admin\Notice;
|
||||||
|
|
||||||
|
use TEC\Common\Contracts\Service_Provider as Provider_Contract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Notice
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @package Tribe\Admin\Notice
|
||||||
|
*/
|
||||||
|
class Service_Provider extends Provider_Contract {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the objects and filters required by the provider to manage admin notices.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*/
|
||||||
|
public function register() {
|
||||||
|
tribe_singleton( 'pue.notices', 'Tribe__PUE__Notices' );
|
||||||
|
tribe_singleton( WP_Version::class, WP_Version::class, [ 'hook' ] );
|
||||||
|
tribe_singleton( 'admin.notice.php.version', \Tribe__Admin__Notice__Php_Version::class, [ 'hook' ] );
|
||||||
|
tribe_singleton( Marketing\Stellar_Sale::class, Marketing\Stellar_Sale::class, [ 'hook' ] );
|
||||||
|
|
||||||
|
$this->hooks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up hooks for classes.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*/
|
||||||
|
private function hooks() {
|
||||||
|
add_action( 'tribe_plugins_loaded', [ $this, 'plugins_loaded'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup for things that require plugins loaded first.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*/
|
||||||
|
public function plugins_loaded() {
|
||||||
|
tribe( 'pue.notices' );
|
||||||
|
tribe( 'admin.notice.php.version' );
|
||||||
|
tribe( WP_Version::class );
|
||||||
|
|
||||||
|
if ( defined( 'TRIBE_HIDE_MARKETING_NOTICES' ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tribe( Marketing\Stellar_Sale::class );
|
||||||
|
tribe( Marketing\Black_Friday::class );
|
||||||
|
// EOY Sale disabled for 2022
|
||||||
|
// tribe( Marketing\End_Of_Year_Sale::class );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
<?php
|
||||||
|
namespace Tribe\Admin\Notice;
|
||||||
|
|
||||||
|
use Tribe__Main as Common;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various WordPress version notices.
|
||||||
|
*
|
||||||
|
* @since 4.12.17
|
||||||
|
*/
|
||||||
|
class WP_Version {
|
||||||
|
/**
|
||||||
|
* Register the various WordPress version notices.
|
||||||
|
*
|
||||||
|
* @since 4.12.17
|
||||||
|
*/
|
||||||
|
public function hook() {
|
||||||
|
tribe_notice(
|
||||||
|
'wp_version_57',
|
||||||
|
[ $this, 'wp_version_57_display_notice' ],
|
||||||
|
[
|
||||||
|
'type' => 'warning',
|
||||||
|
'dismiss' => 1,
|
||||||
|
'priority' => -1,
|
||||||
|
'wrap' => 'p',
|
||||||
|
],
|
||||||
|
[ $this, 'wp_version_57_should_display' ]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the WordPress 5.7 notice should display.
|
||||||
|
*
|
||||||
|
* @since 4.12.17
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function wp_version_57_should_display() {
|
||||||
|
global $wp_version, $current_screen;
|
||||||
|
|
||||||
|
$screens = [
|
||||||
|
'tribe_events_page_tribe-app-shop', // App shop.
|
||||||
|
'events_page_tribe-app-shop', // App shop.
|
||||||
|
'tribe_events_page_tribe-common', // Settings & Welcome.
|
||||||
|
'tribe_events_page_tec-events-settings', // New Settings & Welcome.
|
||||||
|
'events_page_tribe-common', // Settings & Welcome.
|
||||||
|
'toplevel_page_tribe-common', // Settings & Welcome.
|
||||||
|
];
|
||||||
|
|
||||||
|
// If not a valid screen, don't display.
|
||||||
|
if ( empty( $current_screen->id ) || ! in_array( $current_screen->id, $screens, true ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$wp_version_min_version_required = '5.8';
|
||||||
|
$common_version_required = '4.12.18-dev';
|
||||||
|
|
||||||
|
return
|
||||||
|
version_compare( Common::VERSION, $common_version_required, '<' )
|
||||||
|
&& version_compare( $wp_version, $wp_version_min_version_required, '<' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTML for the WordPress 5.7 notice.
|
||||||
|
*
|
||||||
|
* @since 4.12.17
|
||||||
|
*
|
||||||
|
* @see https://evnt.is/wp5-7
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function wp_version_57_display_notice() {
|
||||||
|
global $wp_version;
|
||||||
|
$is_wp_57 = version_compare( $wp_version, '5.7-beta', '>=' );
|
||||||
|
$html = '';
|
||||||
|
|
||||||
|
if ( $is_wp_57 ) {
|
||||||
|
$html .= esc_html__( 'You are using WordPress 5.7 which included a major jQuery update that may cause compatibility issues with past versions of The Events Calendar, Event Tickets and other plugins.', 'tribe-common' );
|
||||||
|
} else {
|
||||||
|
$html .= esc_html__( 'WordPress 5.7 includes a major jQuery update that may cause compatibility issues with past versions of The Events Calendar, Event Tickets and other plugins.', 'tribe-common' );
|
||||||
|
}
|
||||||
|
$html .= ' <a target="_blank" href="https://evnt.is/wp5-7">' . esc_html__( 'Read more.', 'tribe-common' ) . '</a>';
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,821 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Tribe__Date_Utils as Dates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 4.3
|
||||||
|
*/
|
||||||
|
class Tribe__Admin__Notices {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the transient that will store transient notices.
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public static $transient_notices_name = '_tribe_admin_notices';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether, in this request, transient notices have been pruned already or not.
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $did_prune_transients = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static singleton variable
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @var self
|
||||||
|
*/
|
||||||
|
private static $instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static Singleton Factory Method
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public static function instance() {
|
||||||
|
if ( ! isset( self::$instance ) ) {
|
||||||
|
self::$instance = new self;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Meta Key that stores which notices have been dismissed.
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public static $meta_key = 'tribe-dismiss-notice';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Meta Key prefix that stores when notices have been dismissed.
|
||||||
|
*
|
||||||
|
* @since 4.13.0
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public static $meta_key_time_prefix = 'tribe-dismiss-notice-time-';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores all the Notices and it's configurations
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $notices = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the Methods in the correct places
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function __construct() {
|
||||||
|
// Not in the admin we don't even care
|
||||||
|
if ( ! is_admin() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before we bail on the
|
||||||
|
add_action( 'wp_ajax_tribe_notice_dismiss', [ $this, 'maybe_dismiss' ] );
|
||||||
|
|
||||||
|
// Doing AJAX? bail.
|
||||||
|
if ( tribe( 'context' )->doing_ajax() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hook the actual rendering of notices
|
||||||
|
add_action( 'current_screen', [ $this, 'hook' ], 20 );
|
||||||
|
|
||||||
|
// Add our notice dismissal script
|
||||||
|
tribe_asset(
|
||||||
|
Tribe__Main::instance(),
|
||||||
|
'tribe-notice-dismiss',
|
||||||
|
'notice-dismiss.js',
|
||||||
|
[ 'jquery' ],
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
'groups' => 'tec-admin-notices',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will happen on the `current_screen` and will hook to the correct actions and display the notices
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function hook() {
|
||||||
|
$transients = $this->get_transients();
|
||||||
|
|
||||||
|
foreach ( $transients as $slug => $transient ) {
|
||||||
|
if ( $this->transient_notice_expired( $slug ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
list( $html, $args, $expire ) = $transients[ $slug ];
|
||||||
|
$this->register( $slug, $html, $args );
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ( $this->notices as $notice ) {
|
||||||
|
if ( ! $this->showing_notice( $notice->slug ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_action( $notice->action, $notice->callback, $notice->priority );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will allow the user to Dismiss the Notice using JS.
|
||||||
|
*
|
||||||
|
* We will dismiss the notice without checking to see if the slug was already
|
||||||
|
* registered (via a call to exists()) for the reason that, during dismissal
|
||||||
|
* ajax request, some valid notices may not have been registered yet.
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function maybe_dismiss() {
|
||||||
|
if ( empty( $_GET[ self::$meta_key ] ) ) {
|
||||||
|
wp_send_json( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
$slug = sanitize_key( $_GET[ self::$meta_key ] );
|
||||||
|
|
||||||
|
// Send a JSON answer with the status of dismissal
|
||||||
|
wp_send_json( $this->dismiss( $slug ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows a Magic to remove the Requirement of creating a callback
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @param string $name Name of the method used to create the slug of the notice.
|
||||||
|
* @param array $arguments Which arguments were used, normally empty.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __call( $name, $arguments ) {
|
||||||
|
// Transform from Method name to Notice number
|
||||||
|
$slug = preg_replace( '/render_/', '', $name, 1 );
|
||||||
|
|
||||||
|
if ( ! $this->exists( $slug ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notice = $this->get( $slug );
|
||||||
|
|
||||||
|
if (
|
||||||
|
empty( $notice->active_callback )
|
||||||
|
|| (
|
||||||
|
is_callable( $notice->active_callback )
|
||||||
|
&& true == call_user_func( $notice->active_callback )
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$content = $notice->content;
|
||||||
|
$wrap = isset( $notice->wrap ) ? $notice->wrap : false;
|
||||||
|
|
||||||
|
if ( is_array( $content ) && isset( $content[0] ) && $content[0] instanceof __PHP_Incomplete_Class ) {
|
||||||
|
// From a class that no longer exists (e.g. the plugin is not active), clean and bail.
|
||||||
|
$this->remove( $slug );
|
||||||
|
$this->remove_transient( $slug );
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_callable( $content ) ) {
|
||||||
|
$content = call_user_func_array( $content, [ $notice ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty( $content ) ) {
|
||||||
|
// There is nothing to render, let's avoid the empty notice frame.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tribe_asset_enqueue_group( 'tec-admin-notices' );
|
||||||
|
|
||||||
|
// Return the rendered HTML.
|
||||||
|
$html = $this->render( $slug, $content, false, $wrap );
|
||||||
|
|
||||||
|
// Remove the notice and the transient (if any) since it's been rendered.
|
||||||
|
$this->remove( $slug );
|
||||||
|
$this->remove_transient( $slug );
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a helper to actually print the Message
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @param string $slug The name of the notice.
|
||||||
|
* @param string $content The content of the notice.
|
||||||
|
* @param boolean $return Echo or return the content.
|
||||||
|
* @param string|bool $wrap An optional HTML tag to wrap the content.
|
||||||
|
*
|
||||||
|
* @return bool|string
|
||||||
|
*/
|
||||||
|
public function render( $slug, $content = null, $return = true, $wrap = false ) {
|
||||||
|
if ( ! $this->exists( $slug ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bail if we already rendered
|
||||||
|
if ( $this->is_rendered( $slug ) ) {
|
||||||
|
if ( $this->is_rendered_html( $slug, $content ) && ! $return ) {
|
||||||
|
echo $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notice = $this->get( $slug );
|
||||||
|
$this->notices[ $slug ]->is_rendered = true;
|
||||||
|
|
||||||
|
$classes = [ 'tribe-dismiss-notice', 'notice' ];
|
||||||
|
$classes[] = sanitize_html_class( 'notice-' . $notice->type );
|
||||||
|
$classes[] = sanitize_html_class( 'tribe-notice-' . $notice->slug );
|
||||||
|
|
||||||
|
if ( $notice->dismiss ) {
|
||||||
|
$classes[] = 'is-dismissible';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $notice->inline ) {
|
||||||
|
$classes[] = 'inline';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevents Empty Notices
|
||||||
|
if ( empty( $content ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_string( $wrap ) ) {
|
||||||
|
$content = sprintf( '<%1$s>' . $content . '</%1$s>', $wrap );
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = sprintf( '<div class="%s" data-ref="%s">%s</div>', implode( ' ', $classes ), $notice->slug, $content );
|
||||||
|
tribe_asset_enqueue_group( 'tec-admin-notices' );
|
||||||
|
|
||||||
|
if ( ! $return ) {
|
||||||
|
echo $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a helper to print the message surrounded by `p` tags.
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @param string $slug The name of the notice.
|
||||||
|
* @param string $content The content of the notice.
|
||||||
|
* @param boolean $return Echo or return the content.
|
||||||
|
*
|
||||||
|
* @return boolean|string
|
||||||
|
*/
|
||||||
|
public function render_paragraph( $slug, $content = null, $return = true ) {
|
||||||
|
return $this->render( $slug, $content, $return, 'p' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a given notice is rendered
|
||||||
|
*
|
||||||
|
* @since 4.7.10
|
||||||
|
*
|
||||||
|
* @param string $slug Which notice to check.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_rendered( $slug ) {
|
||||||
|
if ( ! $this->exists( $slug ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notice = $this->get( $slug );
|
||||||
|
|
||||||
|
return isset( $notice->is_rendered ) ? $notice->is_rendered : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a given string is a notice rendered
|
||||||
|
*
|
||||||
|
* @since 4.7.10
|
||||||
|
*
|
||||||
|
* @param string $slug Which notice to check.
|
||||||
|
* @param string $html Which html string we are check.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function is_rendered_html( $slug, $html ) {
|
||||||
|
if ( ! $this->exists( $slug ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$search = sprintf( 'data-ref="%s"', $slug );
|
||||||
|
|
||||||
|
return false !== strpos( $html, $search );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a given user has dismissed a given notice.
|
||||||
|
*
|
||||||
|
* @since 4.13.0
|
||||||
|
*
|
||||||
|
* @param string $slug The name of the notice.
|
||||||
|
* @param int|null $user_id The user ID.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function has_user_dismissed( $slug, $user_id = null ) {
|
||||||
|
|
||||||
|
if ( is_null( $user_id ) ) {
|
||||||
|
$user_id = get_current_user_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
$dismissed_notices = get_user_meta( $user_id, self::$meta_key );
|
||||||
|
|
||||||
|
if ( ! is_array( $dismissed_notices ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! in_array( $slug, $dismissed_notices ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notice = $this->get( $slug );
|
||||||
|
if (
|
||||||
|
is_object( $notice )
|
||||||
|
&& $notice->recurring
|
||||||
|
&& $this->should_recurring_notice_show( $slug, $user_id )
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a given user has dismissed a given notice.
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
* @deprecated 4.13.0 Deprecated in favor of correcting the typo.
|
||||||
|
*
|
||||||
|
* @param string $slug The Name of the Notice
|
||||||
|
* @param int|null $user_id The user ID
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function has_user_dimissed( $slug, $user_id = null ) {
|
||||||
|
return $this->has_user_dismissed( $slug, $user_id );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the last Dismissal for a given notice slug and user.
|
||||||
|
*
|
||||||
|
* @since 4.13.0
|
||||||
|
*
|
||||||
|
* @param string $slug Slug of the notice to look for.
|
||||||
|
* @param int|null $user_id Which user? If null will default to current user.
|
||||||
|
*
|
||||||
|
* @return false|\Tribe\Utils\Date_I18n
|
||||||
|
*/
|
||||||
|
public function get_last_dismissal( $slug, $user_id = null ) {
|
||||||
|
if ( is_null( $user_id ) ) {
|
||||||
|
$user_id = get_current_user_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
$dismissed_time = get_user_meta( $user_id, static::$meta_key_time_prefix . $slug, true );
|
||||||
|
|
||||||
|
if ( ! is_numeric( $dismissed_time ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Dates::build_date_object( $dismissed_time );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a given notice needs to be re-displayed in case of recurring notice.
|
||||||
|
*
|
||||||
|
* @since 4.13.0
|
||||||
|
*
|
||||||
|
* @param string $slug Slug of the notice to look for.
|
||||||
|
* @param int|null $user_id Which user? If null will default to current user.
|
||||||
|
*
|
||||||
|
* @return false|\Tribe\Utils\Date_I18n
|
||||||
|
*/
|
||||||
|
public function should_recurring_notice_show( $slug, $user_id = null ) {
|
||||||
|
$notice = $this->get( $slug );
|
||||||
|
if ( ! is_object( $notice ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! $notice->recurring || ! $notice->recurring_interval ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_null( $user_id ) ) {
|
||||||
|
$user_id = get_current_user_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
$interval = Dates::interval( $notice->recurring_interval );
|
||||||
|
$last_dismissal = $this->get_last_dismissal( $slug, $user_id );
|
||||||
|
if ( ! $last_dismissal ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$next_dismissal = $last_dismissal->add( $interval );
|
||||||
|
$now = Dates::build_date_object( 'now' );
|
||||||
|
|
||||||
|
if ( $now >= $next_dismissal ) {
|
||||||
|
delete_user_meta( $user_id, self::$meta_key, $slug );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Method to actually add the Meta value telling that this notice has been dismissed
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @param string $slug The Name of the Notice
|
||||||
|
* @param int|null $user_id The user ID
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function dismiss( $slug, $user_id = null ) {
|
||||||
|
if ( is_null( $user_id ) ) {
|
||||||
|
$user_id = get_current_user_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this user has dismissed we don't care either
|
||||||
|
if ( $this->has_user_dismissed( $slug, $user_id ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_user_meta( $user_id, static::$meta_key_time_prefix . $slug, time() );
|
||||||
|
|
||||||
|
return add_user_meta( $user_id, self::$meta_key, $slug, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the User meta holding if a notice was dismissed
|
||||||
|
*
|
||||||
|
* @param string $slug The Name of the Notice
|
||||||
|
* @param int|null $user_id The user ID
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function undismiss( $slug, $user_id = null ) {
|
||||||
|
if ( is_null( $user_id ) ) {
|
||||||
|
$user_id = get_current_user_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this user has dismissed we don't care either
|
||||||
|
if ( ! $this->has_user_dismissed( $slug, $user_id ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return delete_user_meta( $user_id, self::$meta_key, $slug );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undismisses the specified notice for all users.
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @param string $slug
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function undismiss_for_all( $slug ) {
|
||||||
|
$user_query = new WP_User_Query( [
|
||||||
|
'meta_key' => self::$meta_key,
|
||||||
|
'meta_value' => $slug,
|
||||||
|
] );
|
||||||
|
|
||||||
|
$affected = 0;
|
||||||
|
|
||||||
|
foreach ( $user_query->get_results() as $user ) {
|
||||||
|
if ( $this->undismiss( $slug, $user->ID ) ) {
|
||||||
|
$affected ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $affected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a Notice and attach a callback to the required action to display it correctly
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @param string $slug Slug to save the notice
|
||||||
|
* @param callable|string $callback A callable Method/Function to actually display the notice
|
||||||
|
* @param array $arguments Arguments to Setup a notice
|
||||||
|
* @param callable|null $active_callback An optional callback that should return bool values
|
||||||
|
* to indicate whether the notice should display or not.
|
||||||
|
*
|
||||||
|
* @return stdClass
|
||||||
|
*/
|
||||||
|
public function register( $slug, $callback, $arguments = [], $active_callback = null ) {
|
||||||
|
// Prevent weird stuff here
|
||||||
|
$slug = sanitize_key( $slug );
|
||||||
|
|
||||||
|
$defaults = [
|
||||||
|
'callback' => null,
|
||||||
|
'content' => null,
|
||||||
|
'action' => 'admin_notices',
|
||||||
|
'priority' => 10,
|
||||||
|
'expire' => false,
|
||||||
|
'dismiss' => false,
|
||||||
|
'inline' => false,
|
||||||
|
'recurring' => false,
|
||||||
|
'recurring_interval' => null,
|
||||||
|
'type' => 'error',
|
||||||
|
'is_rendered' => false,
|
||||||
|
'wrap' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
$defaults['callback'] = [ $this, 'render_' . $slug ];
|
||||||
|
$defaults['content'] = $callback;
|
||||||
|
|
||||||
|
if ( is_callable( $active_callback ) ) {
|
||||||
|
$defaults['active_callback'] = $active_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge Arguments
|
||||||
|
$notice = (object) wp_parse_args( $arguments, $defaults );
|
||||||
|
|
||||||
|
// Enforce this one
|
||||||
|
$notice->slug = $slug;
|
||||||
|
|
||||||
|
// Clean these
|
||||||
|
$notice->priority = absint( $notice->priority );
|
||||||
|
$notice->expire = (bool) $notice->expire;
|
||||||
|
$notice->recurring = (bool) $notice->recurring;
|
||||||
|
|
||||||
|
if ( ! is_callable( $notice->dismiss ) ) {
|
||||||
|
$notice->dismiss = (bool) $notice->dismiss;
|
||||||
|
}
|
||||||
|
if ( ! is_callable( $notice->inline ) ) {
|
||||||
|
$notice->inline = (bool) $notice->inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the Notice on the array of notices
|
||||||
|
$this->notices[ $slug ] = $notice;
|
||||||
|
|
||||||
|
// Return the notice Object because it might be modified
|
||||||
|
return $notice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a transient Admin Notice easily.
|
||||||
|
*
|
||||||
|
* A transient admin notice is a "fire-and-forget" admin notice that will display once registered and
|
||||||
|
* until dismissed (if dismissible) without need, on the side of the source code, to register it on each request.
|
||||||
|
*
|
||||||
|
* @since 4.7.7
|
||||||
|
*
|
||||||
|
* @param string $slug Slug to save the notice
|
||||||
|
* @param string $html The notice output HTML code
|
||||||
|
* @param array $arguments Arguments to Setup a notice
|
||||||
|
* @param int $expire After how much time (in seconds) the notice will stop showing.
|
||||||
|
*
|
||||||
|
* @return stdClass Which notice was registered
|
||||||
|
*/
|
||||||
|
public function register_transient( $slug, $html, $arguments = [], $expire = null ) {
|
||||||
|
$notices = $this->get_transients();
|
||||||
|
$notices[ $slug ] = [ $html, $arguments, time() + $expire ];
|
||||||
|
$this->set_transients( $notices );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a transient notice based on its slug.
|
||||||
|
*
|
||||||
|
* @since 4.7.7
|
||||||
|
*
|
||||||
|
* @param string $slug
|
||||||
|
*/
|
||||||
|
public function remove_transient( $slug ) {
|
||||||
|
$notices = $this->get_transients();
|
||||||
|
unset( $notices[ $slug ] );
|
||||||
|
$this->set_transients( $notices );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a notice based on its slug.
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @param string $slug
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function remove( $slug ) {
|
||||||
|
if ( ! $this->exists( $slug ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unset( $this->notices[ $slug ] );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the configuration for the Notices
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @param string $slug
|
||||||
|
*
|
||||||
|
* @return object|array|null
|
||||||
|
*/
|
||||||
|
public function get( $slug = null ) {
|
||||||
|
if ( is_null( $slug ) ) {
|
||||||
|
return $this->notices;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent weird stuff here
|
||||||
|
$slug = sanitize_key( $slug );
|
||||||
|
|
||||||
|
if ( ! empty( $this->notices[ $slug ] ) ) {
|
||||||
|
// I want to avoid modifying the registered value.
|
||||||
|
$notice = $this->notices[ $slug ];
|
||||||
|
|
||||||
|
if ( is_callable( $notice->inline ) ) {
|
||||||
|
$notice->inline = call_user_func( $notice->inline, $notice );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_callable( $notice->dismiss ) ) {
|
||||||
|
$notice->dismiss = call_user_func( $notice->dismiss, $notice );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $notice;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a given notice exists
|
||||||
|
*
|
||||||
|
* @since 4.3
|
||||||
|
*
|
||||||
|
* @param string $slug
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function exists( $slug ) {
|
||||||
|
return is_object( $this->get( $slug ) ) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of registered transient notices.
|
||||||
|
*
|
||||||
|
* @since 4.7.7
|
||||||
|
*
|
||||||
|
* @return array An associative array in the shape [ <slug> => [ <html>, <args>, <expire timestamp> ] ]
|
||||||
|
*/
|
||||||
|
protected function get_transients() {
|
||||||
|
$cached = tribe( 'cache' )['transient_admin_notices'];
|
||||||
|
|
||||||
|
if ( false !== $cached ) {
|
||||||
|
return $cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
$transient = self::$transient_notices_name;
|
||||||
|
$notices = get_transient( $transient );
|
||||||
|
$notices = is_array( $notices ) ? $notices : [];
|
||||||
|
|
||||||
|
if ( $this->did_prune_transients ) {
|
||||||
|
$this->did_prune_transients = true;
|
||||||
|
foreach ( $notices as $key => $notice ) {
|
||||||
|
list( $html, $args, $expire_at ) = $notice;
|
||||||
|
|
||||||
|
if ( $expire_at < time() ) {
|
||||||
|
unset( $notices[ $key ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tribe( 'cache' )['transient_admin_notices'] = $notices;
|
||||||
|
|
||||||
|
return $notices;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates/sets the transient notices transient.
|
||||||
|
*
|
||||||
|
* @since 4.7.7
|
||||||
|
*
|
||||||
|
* @param array $notices An associative array in the shape [ <slug> => [ <html>, <args>, <expire timestamp> ] ]
|
||||||
|
*/
|
||||||
|
protected function set_transients( $notices ) {
|
||||||
|
$transient = self::$transient_notices_name;
|
||||||
|
set_transient( $transient, $notices, MONTH_IN_SECONDS );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a specific transient admin notices is being shown or not, depending on its expiration and
|
||||||
|
* dismissible status.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @since 4.11.1
|
||||||
|
*
|
||||||
|
* @param string|array $slug The slug, or slugs, of the transient notices to check. This is the same slug used
|
||||||
|
* to register the transient notice in the `tribe_transient_notice` function or the
|
||||||
|
* `Tribe__Admin__Notices::register_transient()` method.
|
||||||
|
*
|
||||||
|
* @return bool Whether the transient notice is showing or not.
|
||||||
|
*/
|
||||||
|
public function showing_transient_notice( $slug ) {
|
||||||
|
$transient_notices = (array) $this->get_transients();
|
||||||
|
|
||||||
|
return isset( $transient_notices[ $slug ] )
|
||||||
|
&& ! $this->has_user_dismissed( $slug )
|
||||||
|
&& ! $this->transient_notice_expired( $slug );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a transient notice expired or not.
|
||||||
|
*
|
||||||
|
* @since 4.11.1
|
||||||
|
*
|
||||||
|
* @param string|array $slug The slug, or slugs, of the transient notices to check. This is the same slug used
|
||||||
|
* to register the transient notice in the `tribe_transient_notice` function or the
|
||||||
|
* `Tribe__Admin__Notices::register_transient()` method.
|
||||||
|
*
|
||||||
|
* @return bool Whether the transient notice is expired or not.
|
||||||
|
*/
|
||||||
|
protected function transient_notice_expired( $slug ) {
|
||||||
|
$transients = (array) $this->get_transients();
|
||||||
|
|
||||||
|
if ( ! isset( $transients[ $slug ] ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
list( $html, $args, $expire ) = $transients[ $slug ];
|
||||||
|
if ( $expire < time() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a notice is being shown or not; the result takes the notice callback and dismissible status into
|
||||||
|
* account.
|
||||||
|
*
|
||||||
|
* @since 4.11.1
|
||||||
|
*
|
||||||
|
* @param string|array $slug The slug, or slugs, of the transient notices to check. This is the same slug used
|
||||||
|
* to register the transient notice in the `tribe_transient_notice` function or the
|
||||||
|
* `Tribe__Admin__Notices::register_transient()` method.
|
||||||
|
*
|
||||||
|
* @return bool Whether the notice is showing or not.
|
||||||
|
*/
|
||||||
|
public function showing_notice( $slug ) {
|
||||||
|
if ( ! isset( $this->notices[ $slug ] ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notice = $this->notices[ $slug ];
|
||||||
|
if ( $notice->dismiss && $this->has_user_dismissed( $notice->slug ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
! empty( $notice->active_callback )
|
||||||
|
&& is_callable( $notice->active_callback )
|
||||||
|
&& false == call_user_func( $notice->active_callback )
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,309 @@
|
||||||
|
<?php
|
||||||
|
namespace Tribe\Admin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Pages.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*/
|
||||||
|
class Pages {
|
||||||
|
/**
|
||||||
|
* Current page ID (or false if not registered with this controller).
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
private $current_page = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registered pages
|
||||||
|
* Contains information (breadcrumbs, menu info) about TEC admin pages.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*
|
||||||
|
* @var array<string,mixed>
|
||||||
|
*/
|
||||||
|
private $pages = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get registered pages.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*
|
||||||
|
* @return array $pages {
|
||||||
|
* Array containing the registered pages.
|
||||||
|
*
|
||||||
|
* @type array $page_id {
|
||||||
|
* @type string id Id to reference the page.
|
||||||
|
* @type array title Page title. Used in menus and breadcrumbs.
|
||||||
|
* @type string|null parent Parent ID. Null for new top level page.
|
||||||
|
* @type string path Path for this page, full path in app context; ex /analytics/report
|
||||||
|
* @type string capability Capability needed to access the page.
|
||||||
|
* @type string icon Icon. Dashicons helper class, base64-encoded SVG, or 'none'.
|
||||||
|
* @type int position Menu item position.
|
||||||
|
* @type int order Navigation item order.
|
||||||
|
* @type callable callback The function to be called to output the content for the page.
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
public function get_pages() {
|
||||||
|
/**
|
||||||
|
* Filters the list of registered TEC admin pages.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*
|
||||||
|
* @param array $pages {
|
||||||
|
* Array containing the registered pages to be filtered
|
||||||
|
*
|
||||||
|
* @type array $page_id {
|
||||||
|
* @type string id Id to reference the page.
|
||||||
|
* @type array title Page title. Used in menus and breadcrumbs.
|
||||||
|
* @type string|null parent Parent ID. Null for new top level page.
|
||||||
|
* @type string path Path for this page, full path in app context; ex /analytics/report
|
||||||
|
* @type string capability Capability needed to access the page.
|
||||||
|
* @type string icon Icon. Dashicons helper class, base64-encoded SVG, or 'none'.
|
||||||
|
* @type int position Menu item position.
|
||||||
|
* @type int order Navigation item order.
|
||||||
|
* @type callable callback The function to be called to output the content for the page.
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
$pages = apply_filters( 'tec_admin_pages', $this->pages );
|
||||||
|
|
||||||
|
return $pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a page to `tec-admin`.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*
|
||||||
|
* @param array $options {
|
||||||
|
* Array describing the page.
|
||||||
|
*
|
||||||
|
* @type string id Id to reference the page.
|
||||||
|
* @type string title Page title. Used in menus and breadcrumbs.
|
||||||
|
* @type string|null parent Parent ID. Null for new top level page.
|
||||||
|
* @type string path Path for this page, full path in app context; ex /analytics/report
|
||||||
|
* @type string capability Capability needed to access the page.
|
||||||
|
* @type string icon Icon. Dashicons helper class, base64-encoded SVG, or 'none'.
|
||||||
|
* @type int position Menu item position.
|
||||||
|
* @type int order Navigation item order.
|
||||||
|
* @type callable callback The function to be called to output the content for the page.
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @return string $page The resulting page's hook_suffix.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function register_page( $options = [] ) {
|
||||||
|
$defaults = [
|
||||||
|
'id' => null,
|
||||||
|
'parent' => null,
|
||||||
|
'title' => '',
|
||||||
|
'capability' => self::get_capability(),
|
||||||
|
'path' => '',
|
||||||
|
'icon' => '',
|
||||||
|
'position' => null,
|
||||||
|
'callback' => [ __CLASS__, 'render_page' ],
|
||||||
|
];
|
||||||
|
|
||||||
|
$options = wp_parse_args( $options, $defaults );
|
||||||
|
|
||||||
|
if ( is_null( $options['parent'] ) ) {
|
||||||
|
$page = add_menu_page(
|
||||||
|
$options['title'],
|
||||||
|
$options['title'],
|
||||||
|
$options['capability'],
|
||||||
|
$options['path'],
|
||||||
|
$options['callback'],
|
||||||
|
$options['icon'],
|
||||||
|
$options['position']
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$page = add_submenu_page(
|
||||||
|
$options['parent'],
|
||||||
|
$options['title'],
|
||||||
|
$options['title'],
|
||||||
|
$options['capability'],
|
||||||
|
$options['path'],
|
||||||
|
$options['callback']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->connect_page( $options );
|
||||||
|
|
||||||
|
return $page;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current page.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*
|
||||||
|
* @return string|boolean Current page or false if not registered with this controller.
|
||||||
|
*/
|
||||||
|
public function get_current_page() {
|
||||||
|
if ( is_null( $this->current_page ) ) {
|
||||||
|
$this->determine_current_page();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->current_page;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the current page.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*
|
||||||
|
* @return string|boolean Current page or false if not registered with this controller.
|
||||||
|
*/
|
||||||
|
public function determine_current_page() {
|
||||||
|
$current_screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
|
||||||
|
|
||||||
|
if ( is_null( $current_screen ) ) {
|
||||||
|
$this->current_page = tribe_get_request_var( 'page' );
|
||||||
|
return $this->current_page;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->current_page = $current_screen->id;
|
||||||
|
|
||||||
|
return $this->current_page;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect an existing page to wp-admin.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*
|
||||||
|
* @param array $options {
|
||||||
|
* Array describing the page.
|
||||||
|
*
|
||||||
|
* @type string id Id to reference the page.
|
||||||
|
* @type string|array title Page title. Used in menus and breadcrumbs.
|
||||||
|
* @type string|null parent Parent ID. Null for new top level page.
|
||||||
|
* @type string path Path for this page. E.g. admin.php?page=wc-settings&tab=checkout
|
||||||
|
* @type string capability Capability needed to access the page.
|
||||||
|
* @type string icon Icon. Dashicons helper class, base64-encoded SVG, or 'none'.
|
||||||
|
* @type int position Menu item position.
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
public function connect_page( $options = [] ) {
|
||||||
|
if ( ! is_array( $options['title'] ) ) {
|
||||||
|
$options['title'] = array( $options['title'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter the options when connecting or registering a page.
|
||||||
|
*
|
||||||
|
* @param array $options {
|
||||||
|
* Array describing the page.
|
||||||
|
*
|
||||||
|
* @type string id Id to reference the page.
|
||||||
|
* @type string|array title Page title. Used in menus and breadcrumbs.
|
||||||
|
* @type string|null parent Parent ID. Null for new top level page.
|
||||||
|
* @type string screen_id The screen ID that represents the connected page. (Not required for registering).
|
||||||
|
* @type string path Path for this page. E.g. admin.php?page=wc-settings&tab=checkout
|
||||||
|
* @type string capability Capability needed to access the page.
|
||||||
|
* @type string icon Icon. Dashicons helper class, base64-encoded SVG, or 'none'.
|
||||||
|
* @type int position Menu item position.
|
||||||
|
* @type boolean js_page If this is a JS-powered page.
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
$options = apply_filters( 'tec_admin_pages_connect_page_options', $options );
|
||||||
|
|
||||||
|
$this->pages[ $options['id'] ] = $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the capability.
|
||||||
|
*
|
||||||
|
* @param string $capability The capability required for a TEC page to be displayed to the user.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*
|
||||||
|
* @return string The capability required for a TEC page to be displayed to the user.
|
||||||
|
*/
|
||||||
|
public static function get_capability( $capability = 'manage_options' ) {
|
||||||
|
/**
|
||||||
|
* Filters the default capability for Tribe admin pages.
|
||||||
|
*
|
||||||
|
* @param string $capability The capability required for a TEC page to be displayed to the user.
|
||||||
|
*
|
||||||
|
* @todo: We'll need to deprecate this one in favor of the one below.
|
||||||
|
*/
|
||||||
|
$capability = apply_filters( 'tribe_common_event_page_capability', $capability );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the default capability for TEC admin pages.
|
||||||
|
*
|
||||||
|
* @param string $capability The capability required for a TEC page to be displayed to the user.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*/
|
||||||
|
$capability = apply_filters( 'tec_admin_pages_capability', $capability );
|
||||||
|
|
||||||
|
return $capability;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define if is a `tec` admin page (registered).
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*
|
||||||
|
* @param string $page_id The ID of the page to check if is a `tec` admin page.
|
||||||
|
*
|
||||||
|
* @return boolean True if is a `tec` admin page, false otherwise.
|
||||||
|
*/
|
||||||
|
public function is_tec_page( $page_id = '' ) {
|
||||||
|
return in_array( $page_id, array_keys( $this->pages ), true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get pages with tabs.
|
||||||
|
* @since 4.15.0
|
||||||
|
*
|
||||||
|
* @param array $pages The list of pages with tabs.
|
||||||
|
* @return array $pages The list of pages with tabs, filtered.
|
||||||
|
*/
|
||||||
|
public function get_pages_with_tabs( $pages = [] ) {
|
||||||
|
/**
|
||||||
|
* Filters the pages with tabs.
|
||||||
|
*
|
||||||
|
* @param array $pages Pages with tabs.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*/
|
||||||
|
return apply_filters(
|
||||||
|
'tec_admin_pages_with_tabs',
|
||||||
|
$pages
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the current page has tabs.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*
|
||||||
|
* @param string $page The page slug.
|
||||||
|
* @return boolean True if the page has tabs, false otherwise.
|
||||||
|
*/
|
||||||
|
public function has_tabs( $page = '' ) {
|
||||||
|
if ( empty( $page ) ) {
|
||||||
|
$page = $this->get_current_page();
|
||||||
|
}
|
||||||
|
|
||||||
|
return in_array( $page, $this->get_pages_with_tabs() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic page.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*/
|
||||||
|
public static function render_page() {
|
||||||
|
?>
|
||||||
|
<div class="wrap"></div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tribe\Admin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Admin Settings class.
|
||||||
|
*
|
||||||
|
* @since 5.0.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Settings {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loaded image field assets if not already loaded.
|
||||||
|
*
|
||||||
|
* @since 5.0.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function maybe_load_image_field_assets() {
|
||||||
|
if ( has_filter( 'tec_admin_load_image_fields_assets', '__return_true' ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
add_filter( 'tec_admin_load_image_fields_assets', '__return_true' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logic to load image field assets.
|
||||||
|
*
|
||||||
|
* @since 5.0.0
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function should_load_image_field_assets() {
|
||||||
|
/**
|
||||||
|
* Filters whether or not we should load the image field assets on the settings page.
|
||||||
|
*
|
||||||
|
* @since 5.0.0
|
||||||
|
*
|
||||||
|
* @param boolean $return True or false whether to load image field assets.
|
||||||
|
*/
|
||||||
|
$load_assets = apply_filters( 'tec_admin_load_image_fields_assets', false );
|
||||||
|
if ( $load_assets ) {
|
||||||
|
wp_enqueue_media();
|
||||||
|
}
|
||||||
|
return $load_assets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load color field assets if not already loaded.
|
||||||
|
*
|
||||||
|
* @since 5.0.0
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function maybe_load_color_field_assets() {
|
||||||
|
if ( has_filter( 'tec_admin_load_color_field_assets', '__return_true' ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
add_filter( 'tec_admin_load_color_field_assets', '__return_true' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logic to load color field assets.
|
||||||
|
*
|
||||||
|
* @since 5.0.0
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function should_load_color_field_assets() {
|
||||||
|
/**
|
||||||
|
* Filters whether or not we should load the color field assets on the settings page.
|
||||||
|
*
|
||||||
|
* @since 5.0.0
|
||||||
|
*
|
||||||
|
* @param boolean $return True or false whether to load color field assets.
|
||||||
|
*/
|
||||||
|
$load_assets = apply_filters( 'tec_admin_load_color_field_assets', false );
|
||||||
|
return $load_assets;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,382 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Admin Troubleshooting for TEC plugins.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @package Tribe\Admin
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tribe\Admin;
|
||||||
|
use \Tribe__Settings;
|
||||||
|
use \Tribe__Main;
|
||||||
|
use \Tribe__Admin__Helpers;
|
||||||
|
use \Tribe__Timezones as Timezones;
|
||||||
|
use \Tribe__Events__Google__Maps_API_Key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Admin Troubleshooting.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @package Tribe\Admin
|
||||||
|
*/
|
||||||
|
class Troubleshooting {
|
||||||
|
/**
|
||||||
|
* Defines the slug of the troubleshooting page in the WP admin menu item.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @var string the troubleshooting menu slug.
|
||||||
|
*/
|
||||||
|
const MENU_SLUG = 'tec-troubleshooting';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The slug for the new admin page.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private $admin_page = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function hook() {
|
||||||
|
add_action( 'admin_menu', [ $this, 'add_menu_page' ], 90 );
|
||||||
|
add_filter( 'admin_body_class', [ $this, 'admin_body_class' ] );
|
||||||
|
add_action( 'wp_before_admin_bar_render', [ $this, 'add_toolbar_item' ], 20 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method created the troubleshooting page and adds it to TEC menu.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function add_menu_page() {
|
||||||
|
if ( ! Tribe__Settings::instance()->should_setup_pages() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$page_title = esc_html__( 'Troubleshooting', 'tribe-common' );
|
||||||
|
$menu_title = esc_html__( 'Troubleshooting', 'tribe-common' );
|
||||||
|
|
||||||
|
$capability = $this->get_required_capability();
|
||||||
|
|
||||||
|
$where = Tribe__Settings::instance()->get_parent_slug();
|
||||||
|
|
||||||
|
$this->admin_page = add_submenu_page(
|
||||||
|
$where,
|
||||||
|
$page_title,
|
||||||
|
$menu_title,
|
||||||
|
$capability,
|
||||||
|
static::MENU_SLUG,
|
||||||
|
[
|
||||||
|
$this,
|
||||||
|
'do_menu_page',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the required capability for the troubleshooting page.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @return string Which capability we required for the troubleshooting page.
|
||||||
|
*/
|
||||||
|
public function get_required_capability() {
|
||||||
|
/**
|
||||||
|
* Allows third party filtering of capability required to see the Troubleshooting page.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @param string $capability Which capability we are using as the one required for the
|
||||||
|
* troubleshooting page.
|
||||||
|
* @param static $troubleshooting The current instance of the class that handles this page.
|
||||||
|
*/
|
||||||
|
$capability = apply_filters( 'tec_troubleshooting_capability', 'install_plugins', $this );
|
||||||
|
return $capability;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hooked to admin_body_class to add a class for troubleshooting page.
|
||||||
|
*
|
||||||
|
* @since 4.15.0
|
||||||
|
*
|
||||||
|
* @param string $classes a space separated string of classes to be added to body.
|
||||||
|
*
|
||||||
|
* @return string $classes a space separated string of classes to be added to body.
|
||||||
|
*/
|
||||||
|
public function admin_body_class( $classes ) {
|
||||||
|
if ( ! $this->is_current_page() ) {
|
||||||
|
return $classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
$classes .= ' tec-troubleshooting';
|
||||||
|
return $classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the troubleshooting menu to the the WP admin bar under events.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function add_toolbar_item() {
|
||||||
|
$capability = $this->get_required_capability();
|
||||||
|
|
||||||
|
if ( ! current_user_can( $capability ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
global $wp_admin_bar;
|
||||||
|
|
||||||
|
$wp_admin_bar->add_menu( [
|
||||||
|
'id' => 'tec-troubleshooting',
|
||||||
|
'title' => esc_html__( 'Troubleshooting', 'tribe-common' ),
|
||||||
|
'href' => Tribe__Settings::instance()->get_url( [ 'page' => static::MENU_SLUG ] ),
|
||||||
|
'parent' => 'tribe-events-settings-group',
|
||||||
|
] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the current page is the troubleshooting page.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @return boolean returns true if the current page is the troubleshooting page.
|
||||||
|
*/
|
||||||
|
public function is_current_page() {
|
||||||
|
if ( ! Tribe__Settings::instance()->should_setup_pages() || ! did_action( 'admin_menu' ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_null( $this->admin_page ) ) {
|
||||||
|
_doing_it_wrong(
|
||||||
|
__FUNCTION__,
|
||||||
|
'Function was called before it is possible to accurately determine what the current page is.',
|
||||||
|
'4.5.6'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
global $current_screen;
|
||||||
|
|
||||||
|
$troubleshooting_pages = [
|
||||||
|
'tribe_events_page_tec-troubleshooting',
|
||||||
|
'tickets_page_tec-tickets-troubleshooting',
|
||||||
|
];
|
||||||
|
|
||||||
|
return in_array( $current_screen->id, $troubleshooting_pages );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the Troubleshooting page.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function do_menu_page() {
|
||||||
|
tribe_asset_enqueue( 'tribe-admin-help-page' );
|
||||||
|
$main = Tribe__Main::instance();
|
||||||
|
include_once Tribe__Main::instance()->plugin_path . 'src/admin-views/troubleshooting.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks if there are any active issues that need to be flagged.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @return boolean returns true if there are any active issues.
|
||||||
|
*/
|
||||||
|
public function is_any_issue_active() {
|
||||||
|
$issues = $this->get_issues_found();
|
||||||
|
$active_issues = wp_list_pluck( $issues, 'active' );
|
||||||
|
return in_array( true, $active_issues );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if any active TEC plugins require an update.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @return boolean returns true is any of the plugins requires an update.
|
||||||
|
*/
|
||||||
|
public function is_any_tec_plugin_out_of_date() {
|
||||||
|
$current = get_site_transient( 'update_plugins' );
|
||||||
|
$plugins = [];
|
||||||
|
if ( defined( 'TRIBE_EVENTS_FILE' ) ) {
|
||||||
|
$plugins[] = TRIBE_EVENTS_FILE;
|
||||||
|
}
|
||||||
|
if ( defined( 'EVENTS_CALENDAR_PRO_FILE' ) ) {
|
||||||
|
$plugins[] = EVENTS_CALENDAR_PRO_FILE;
|
||||||
|
}
|
||||||
|
if ( defined( 'EVENT_TICKETS_PLUS_FILE' ) ) {
|
||||||
|
$plugins[] = EVENT_TICKETS_PLUS_FILE;
|
||||||
|
}
|
||||||
|
if ( defined( 'EVENTS_VIRTUAL_FILE' ) ) {
|
||||||
|
$plugins[] = EVENTS_VIRTUAL_FILE;
|
||||||
|
}
|
||||||
|
if ( defined( 'EVENT_TICKETS_MAIN_PLUGIN_FILE' ) ) {
|
||||||
|
$plugins[] = EVENT_TICKETS_MAIN_PLUGIN_FILE;
|
||||||
|
}
|
||||||
|
if ( defined( 'TRIBE_EVENTS_FILTERBAR_FILE' ) ) {
|
||||||
|
$plugins[] = TRIBE_EVENTS_FILTERBAR_FILE;
|
||||||
|
}
|
||||||
|
if ( defined( 'EVENTS_COMMUNITY_TICKETS_FILE' ) ) {
|
||||||
|
$plugins[] = EVENTS_COMMUNITY_TICKETS_FILE;
|
||||||
|
}
|
||||||
|
if ( defined( 'EVENTS_COMMUNITY_FILE' ) ) {
|
||||||
|
$plugins[] = EVENTS_COMMUNITY_FILE;
|
||||||
|
}
|
||||||
|
if ( defined( 'EVENTBRITE_PLUGIN_FILE' ) ) {
|
||||||
|
$plugins[] = EVENTBRITE_PLUGIN_FILE;
|
||||||
|
}
|
||||||
|
if ( defined( 'TRIBE_APM_FILE' ) ) {
|
||||||
|
$plugins[] = TRIBE_APM_FILE;
|
||||||
|
}
|
||||||
|
if ( defined( 'IMAGE_WIDGET_PLUS_DIR' ) ) {
|
||||||
|
$plugins[] = IMAGE_WIDGET_PLUS_DIR;
|
||||||
|
}
|
||||||
|
$plugins = array_map( static function( $file ) {
|
||||||
|
$file = \str_replace( WP_PLUGIN_DIR . '/', '', $file );
|
||||||
|
return $file;
|
||||||
|
}, $plugins );
|
||||||
|
|
||||||
|
foreach ( $plugins as $file ) {
|
||||||
|
if ( ! isset( $current->response[ $file ] ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$response = $current->response[ $file ];
|
||||||
|
if ( ! empty( $response->new_version ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if any of the issues defined are active.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @param string $slug the slug of active issue.
|
||||||
|
*
|
||||||
|
* @return boolean returns a boolean value for each individual issue depending on whether it is active or not.
|
||||||
|
*/
|
||||||
|
public function is_active_issue( $slug ) {
|
||||||
|
if ( 'timezone' === $slug ) {
|
||||||
|
return Timezones::is_utc_offset( Timezones::wp_timezone_string() );
|
||||||
|
}
|
||||||
|
if ( 'geolocation' === $slug && class_exists( 'Tribe__Events__Google__Maps_API_Key' ) ) {
|
||||||
|
$key = \tribe_get_option( 'google_maps_js_api_key', false );
|
||||||
|
return empty( $key ) || Tribe__Events__Google__Maps_API_Key::$default_api_key === $key ;
|
||||||
|
}
|
||||||
|
if ( 'out-of-date' === $slug ) {
|
||||||
|
return $this->is_any_tec_plugin_out_of_date();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays issues found in the UI.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @return array of issues which are displayed on the troubleshooting page.
|
||||||
|
*/
|
||||||
|
public function get_issues_found() {
|
||||||
|
$issues_found = apply_filters( 'tec_help_troubleshooting_issues_found', [
|
||||||
|
[
|
||||||
|
'title' => __( 'Site time zone uses UTC', 'tribe-common' ),
|
||||||
|
'description' => __( 'When using The Events Calendar, we highly recommend that you use a geographic timezone such as "America/Los_Angeles" and avoid using a UTC timezone offset such as “UTC+9”. Choosing a UTC timezone for your site or individual events may cause problems when importing events or with Daylight Saving Time. Go to your the General WordPress settings to adjust your site timezone.', 'tribe-common' ),
|
||||||
|
'more_info' => 'http://evnt.is/1ad3',
|
||||||
|
'resolve_text' => __( 'Adjust your timezone', 'tribe-common' ),
|
||||||
|
'fix' => '/wp-admin/options-general.php',
|
||||||
|
'active' => $this->is_active_issue( 'timezone' ),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => __( 'Install max has been reached', 'tribe-common' ),
|
||||||
|
'description' => __( 'License keys can only be used on a limited number of sites, which varies depending on your license level. You\'ll need to remove the license from one or more other site\'s in order to use it on this one.', 'tribe-common' ),
|
||||||
|
'more_info' => 'https://evnt.is/1aqz',
|
||||||
|
'resolve_text' => __( 'Manage your licenses', 'tribe-common' ),
|
||||||
|
'fix' => 'https://evnt.is/1aq-',
|
||||||
|
'active' => $this->is_active_issue( 'install-max' ),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => __( 'Default Google Maps API key', 'tribe-common' ),
|
||||||
|
'description' => __( 'The Events Calendar comes with an API key for basic maps functionality. If you’d like to use more advanced features like custom map pins, dynamic map loads, or Events Calendar Pro\'s Location Search and advanced Map View, you’ll need to get your own Google Maps API key and add it to Events > Settings > Integrations', 'tribe-common' ),
|
||||||
|
'more_info' => 'https://evnt.is/1aqx',
|
||||||
|
'resolve_text' => __( 'Enter a custom API key', 'tribe-common' ),
|
||||||
|
'fix' => '/wp-admin/edit.php?page=tec-events-settings&tab=addons&post_type=tribe_events#tribe-field-google_maps_js_api_key',
|
||||||
|
'active' => $this->is_active_issue( 'geolocation' ),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => __( 'Plugin(s) are out of date', 'tribe-common' ),
|
||||||
|
'description' => __( 'It\'s important to use the most recent versions of our plugins so that you have access to the latest features, bug fixes, and security updates. Plugin functionality can be comprimised if your site is running outdated or mis-matched versions.', 'tribe-common' ),
|
||||||
|
'more_info' => 'https://evnt.is/1aqy',
|
||||||
|
'resolve_text' => __( 'Check for updates', 'tribe-common' ),
|
||||||
|
'fix' => '/wp-admin/update-core.php',
|
||||||
|
'active' => $this->is_active_issue( 'out-of-date' ),
|
||||||
|
],
|
||||||
|
] );
|
||||||
|
|
||||||
|
return $issues_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines common troubleshooting issues and displays them in the UI.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @return array of common issues which are displayed on the troubleshooting page.
|
||||||
|
*/
|
||||||
|
public function get_common_issues() {
|
||||||
|
$common_issues = apply_filters( 'tec_help_troubleshooting_issues', [
|
||||||
|
[
|
||||||
|
'issue' => __( 'Common Error Messages', 'tribe-common' ),
|
||||||
|
'solution' => __( 'Here’s an overview of %s and what they mean.', 'tribe-common' ),
|
||||||
|
'link' => 'https://evnt.is/1as0',
|
||||||
|
'link_label' => 'common error messages',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'issue' => __( 'My calendar doesn’t look right.', 'tribe-common' ),
|
||||||
|
'solution' => __( 'This can happen when other plugins try to improve performance. %s.' ),
|
||||||
|
'link' => 'https://theeventscalendar.com/knowledgebase/k/troubleshooting-the-most-common-installation-issues/#layout-issue',
|
||||||
|
'link_label' => 'More info',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'issue' => __( 'I installed the calendar and it crashed my site.', 'tribe-common' ),
|
||||||
|
'solution' => __( '%s and other common installation issues.', 'tribe-common' ),
|
||||||
|
'link' => 'https://theeventscalendar.com/knowledgebase/k/troubleshooting-the-most-common-installation-issues/#fatal-errors',
|
||||||
|
'link_label' => 'Find solutions to this',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'issue' => __( 'I keep getting “Page Not Found” on events.', 'tribe-common' ),
|
||||||
|
'solution' => __( 'There are a few %s to resolve and prevent 404 errors.', 'tribe-common' ),
|
||||||
|
'link' => 'https://evnt.is/1as2',
|
||||||
|
'link_label' => 'things you can do',
|
||||||
|
],
|
||||||
|
] );
|
||||||
|
|
||||||
|
return $common_issues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired to display notices in the admin pages where the method is called.
|
||||||
|
*
|
||||||
|
* @since 4.14.2
|
||||||
|
*
|
||||||
|
* @param string $page the page which the action is being applied.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function admin_notice( $page ) {
|
||||||
|
do_action( 'tec_admin_notice_area', $page );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upsell notice class.
|
||||||
|
*
|
||||||
|
* @since 4.14.17
|
||||||
|
*
|
||||||
|
* @package Tribe\Admin\Upsell_Notice
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tribe\Admin\Upsell_Notice;
|
||||||
|
|
||||||
|
class Main {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the instance of the template engine that we will use for rendering the page.
|
||||||
|
*
|
||||||
|
* @since 4.14.17
|
||||||
|
*
|
||||||
|
* @var Tribe__Template
|
||||||
|
*/
|
||||||
|
protected $template;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get template object.
|
||||||
|
*
|
||||||
|
* @since 4.14.17
|
||||||
|
*
|
||||||
|
* @return \Tribe__Template
|
||||||
|
*/
|
||||||
|
private function get_template() {
|
||||||
|
if ( empty( self::$template ) ) {
|
||||||
|
$this->template = new \Tribe__Template();
|
||||||
|
$this->template->set_template_origin( \Tribe__Main::instance() );
|
||||||
|
$this->template->set_template_folder( 'src/admin-views/notices/upsell' );
|
||||||
|
$this->template->set_template_context_extract( true );
|
||||||
|
$this->template->set_template_folder_lookup( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->template;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if upsell should be rendered.
|
||||||
|
*
|
||||||
|
* @since 4.14.17
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
private function should_render() {
|
||||||
|
if ( function_exists( 'tec_should_hide_upsell' ) ) {
|
||||||
|
return ! tec_should_hide_upsell();
|
||||||
|
}
|
||||||
|
if ( defined( 'TRIBE_HIDE_UPSELL' ) ) {
|
||||||
|
return ! tribe_is_truthy( TRIBE_HIDE_UPSELL );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render upsell notice.
|
||||||
|
*
|
||||||
|
* @since 4.14.17
|
||||||
|
*
|
||||||
|
* @param array $args Array of arguments that will ultimately be sent to the template.
|
||||||
|
* @param bool $echo Whether or not to echo the HTML. Defaults to true.
|
||||||
|
*
|
||||||
|
* @return string HTML of upsell notice.
|
||||||
|
*/
|
||||||
|
public function render( $args, $echo = true ) {
|
||||||
|
// Check if upsell should be rendered.
|
||||||
|
if ( ! $this->should_render() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default args for the container.
|
||||||
|
$args = wp_parse_args( $args, [
|
||||||
|
'classes' => [],
|
||||||
|
'text' => '',
|
||||||
|
'link_target' => '_blank',
|
||||||
|
'icon_url' => tribe_resource_url( 'images/icons/circle-bolt.svg', false, null, \Tribe__Main::instance() ),
|
||||||
|
'link' => [],
|
||||||
|
] );
|
||||||
|
|
||||||
|
// Default args for the link.
|
||||||
|
$args['link'] = wp_parse_args( $args['link'], [
|
||||||
|
'classes' => [],
|
||||||
|
'text' => '',
|
||||||
|
'url' => '',
|
||||||
|
'target' => '_blank',
|
||||||
|
'rel' => 'noopener noreferrer',
|
||||||
|
] );
|
||||||
|
|
||||||
|
$template = $this->get_template();
|
||||||
|
return $template->template( 'main', $args, $echo );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
# Upsell Notices
|
||||||
|
|
||||||
|
To add an upsell notice, use the following code:
|
||||||
|
|
||||||
|
```
|
||||||
|
tribe( \Tribe\Admin\Upsell_Notice\Main::class )->render( [
|
||||||
|
'text' => 'Text to explain what you are promoting.',
|
||||||
|
'link' => [
|
||||||
|
'text' => 'Text for the link.',
|
||||||
|
'url' => 'https://url.com/to/more/info',
|
||||||
|
],
|
||||||
|
] );
|
||||||
|
```
|
||||||
|
|
||||||
|
## Customizing the notice container
|
||||||
|
|
||||||
|
There are a couple of classes you can add that will display the upsell notice with different styles.
|
||||||
|
|
||||||
|
- `.tec-admin__upsell--rounded-corners` - Adds a rounded-corner, light gray background around the entire notice.
|
||||||
|
- `.tec-admin__upsell--rounded-corners-text` - Adds a rounded-corner, light gray background around the notice text, only.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
tribe( \Tribe\Admin\Upsell_Notice\Main::class )->render( [
|
||||||
|
'classes' => [
|
||||||
|
'tec-admin__upsell--rounded-corners'
|
||||||
|
],
|
||||||
|
'text' => 'Text to explain what you are promoting.',
|
||||||
|
'link' => [
|
||||||
|
'text' => 'Text for the link.',
|
||||||
|
'url' => 'https://url.com/to/more/info',
|
||||||
|
],
|
||||||
|
] );
|
||||||
|
```
|
||||||
|
|
||||||
|
## Customizing the notice link
|
||||||
|
|
||||||
|
Likewise, you can also add these classes to the link array to change the appearance.
|
||||||
|
|
||||||
|
- `.tec-admin__upsell-link--dark` - Changes the color to a dark color, instead of the default blue.
|
||||||
|
- `.tec-admin__upsell-link--underlined` - Adds an underline to the link text.
|
||||||
|
|
||||||
|
You can also change the following attributes of the link:
|
||||||
|
|
||||||
|
- `target` - Default is '_blank'.
|
||||||
|
- `rel` - Default is 'nofollow noreferrer'.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
tribe( \Tribe\Admin\Upsell_Notice\Main::class )->render( [
|
||||||
|
'classes' => [
|
||||||
|
'tec-admin__upsell--rounded-corners-text'
|
||||||
|
],
|
||||||
|
'text' => 'Text to explain what you are promoting.',
|
||||||
|
'link' => [
|
||||||
|
'classes' => [
|
||||||
|
'tec-admin__upsell-link--dark',
|
||||||
|
'tec-admin__upsell-link--underlined',
|
||||||
|
],
|
||||||
|
'text' => 'Text for the link.',
|
||||||
|
'url' => 'https://url.com/to/more/info',
|
||||||
|
'target' => '_parent'
|
||||||
|
],
|
||||||
|
] );
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tribe\Admin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Admin Wysiwyg class.
|
||||||
|
*
|
||||||
|
* @since 5.0.12
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Wysiwyg {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique name given to editor in case more than one is being used on the same page.
|
||||||
|
*
|
||||||
|
* @since 5.0.12
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $name = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial HTML of the editor.
|
||||||
|
*
|
||||||
|
* @since 5.0.12
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $value = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings to pass into the editor.
|
||||||
|
*
|
||||||
|
* @since 5.0.12
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $args = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Wysiwyg object.
|
||||||
|
*
|
||||||
|
* @since 5.0.12
|
||||||
|
*
|
||||||
|
* @param string $name Unique name given to editor.
|
||||||
|
* @param string $value Initial value/HTML.
|
||||||
|
* @param array $args Array of settings.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function __construct( $name, $value = '', $args = [] ) {
|
||||||
|
$this->name = $name;
|
||||||
|
$this->value = $value;
|
||||||
|
$default_args = [
|
||||||
|
'teeny' => true,
|
||||||
|
'wpautop' => true,
|
||||||
|
'textarea_name' => $name,
|
||||||
|
];
|
||||||
|
$this->args = wp_parse_args( $args, $default_args );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters editor buttons.
|
||||||
|
*
|
||||||
|
* @since 5.0.12
|
||||||
|
*
|
||||||
|
* @param array $buttons Array of buttons to include.
|
||||||
|
*
|
||||||
|
* @return array Filtered array of buttons.
|
||||||
|
*/
|
||||||
|
public function filter_buttons( $buttons ) {
|
||||||
|
if (
|
||||||
|
empty( $this->args )
|
||||||
|
|| ! isset( $this->args['buttons'] )
|
||||||
|
|| empty( $this->args['buttons'] )
|
||||||
|
) {
|
||||||
|
return $buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->args['buttons'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter 2nd row of buttons.
|
||||||
|
*
|
||||||
|
* @since 5.0.12
|
||||||
|
*
|
||||||
|
* @param array $buttons Array of buttons to include.
|
||||||
|
*
|
||||||
|
* @return array Filtered array of buttons.
|
||||||
|
*/
|
||||||
|
public function maybe_filter_buttons_2( $buttons ) {
|
||||||
|
if (
|
||||||
|
empty( $this->args ) ||
|
||||||
|
! isset( $this->args['buttons_2'] ) ||
|
||||||
|
empty( $this->args['buttons_2'] )
|
||||||
|
) {
|
||||||
|
return $buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->args['buttons_2'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get HTML of editor.
|
||||||
|
*
|
||||||
|
* @since 5.0.12
|
||||||
|
*
|
||||||
|
* @return string HTML of editor
|
||||||
|
*/
|
||||||
|
public function get_html() {
|
||||||
|
// Add button filters.
|
||||||
|
add_filter( 'teeny_mce_buttons', [ $this, 'filter_buttons' ] );
|
||||||
|
add_filter( 'tiny_mce_buttons', [ $this, 'filter_buttons' ] );
|
||||||
|
add_filter( 'mce_buttons', [ $this, 'filter_buttons' ] );
|
||||||
|
add_filter( 'mce_buttons_2', [ $this, 'maybe_filter_buttons_2' ] );
|
||||||
|
|
||||||
|
// Get HTML of editor.
|
||||||
|
ob_start();
|
||||||
|
wp_editor( html_entity_decode( ( $this->value ) ), sanitize_html_class( $this->name ), $this->args );
|
||||||
|
$html = ob_get_clean();
|
||||||
|
|
||||||
|
// Remove button filters.
|
||||||
|
remove_filter( 'teeny_mce_buttons', [ $this, 'filter_buttons' ] );
|
||||||
|
remove_filter( 'tiny_mce_buttons', [ $this, 'filter_buttons' ] );
|
||||||
|
remove_filter( 'mce_buttons', [ $this, 'filter_buttons' ] );
|
||||||
|
remove_filter( 'mce_buttons_2', [ $this, 'maybe_filter_buttons_2' ] );
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders editor HTML.
|
||||||
|
*
|
||||||
|
* @since 5.0.12
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function render_html() {
|
||||||
|
echo $this->get_html();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue