feat: initial ACRIB WordPress deployment
- WordPress 6.9.4 (es_ES) with Kadence theme - Homepage: Hero, La Asociación, Pilares, Beneficios, Eventos, Miembros, Hazte Miembro, Contacto - Brand identity: #13294b navy, #a12932 burgundy, #c69c48 gold - Fonts: Raleway (headings) + Source Sans 3 (body) + Lato (UI) - Plugins: Kadence Blocks, Polylang, Contact Form 7 - Custom CSS with full brand styling and responsive layout - HTTPS enforced via wp-config.php proxy detection
This commit is contained in:
86
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/telemetry/CLAUDE.md
vendored
Normal file
86
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/telemetry/CLAUDE.md
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is the StellarWP Telemetry Library - a PHP library for WordPress plugins that provides opt-in telemetry data collection. The library is designed to be included via Composer (preferably with Strauss for namespace isolation) and provides a complete telemetry solution with user privacy controls.
|
||||
|
||||
## Common Development Commands
|
||||
|
||||
### Testing
|
||||
```bash
|
||||
# Run unit tests using slic (StellarWP's testing framework)
|
||||
slic run wpunit
|
||||
|
||||
# Run static analysis
|
||||
composer test:analysis
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
```bash
|
||||
# Check coding standards
|
||||
phpcs ./src
|
||||
|
||||
# Auto-fix coding standard issues
|
||||
phpcbf ./src
|
||||
|
||||
# Check PHP compatibility for all supported versions (7.1-8.3)
|
||||
composer compatibility
|
||||
|
||||
# Check specific PHP version compatibility
|
||||
composer compatibility:php-8.0
|
||||
```
|
||||
|
||||
### Local Development
|
||||
```bash
|
||||
# Start local development environment
|
||||
lando start
|
||||
|
||||
# Install dependencies via Lando
|
||||
lando composer install
|
||||
|
||||
# Local site will be available at: https://telemetry-library.lndo.site/
|
||||
```
|
||||
|
||||
## High-Level Architecture
|
||||
|
||||
### Core Components
|
||||
|
||||
1. **Dependency Injection Container**: The library requires a DI container compatible with `stellarwp/container-contract`. The container must be configured before initializing the library.
|
||||
|
||||
2. **Opt-In System**:
|
||||
- `Opt_In/` - Manages user consent through modal interfaces
|
||||
- `Exit_Interview/` - Collects feedback when plugins are deactivated
|
||||
- Privacy-first approach with explicit user consent required
|
||||
|
||||
3. **Data Collection**:
|
||||
- `Data_Providers/` - Abstract data collection with providers like `Debug_Data` for Site Health integration
|
||||
- `Events/` - Event tracking system for capturing user actions
|
||||
- `Telemetry/` - Core functionality for sending telemetry data to the server
|
||||
|
||||
4. **Integration Points**:
|
||||
- `Admin/` - WordPress admin integration and resource management
|
||||
- `Last_Send/` - Tracks when telemetry was last sent
|
||||
- Uses subscriber pattern (`Abstract_Subscriber`) for WordPress hooks
|
||||
|
||||
### Key Design Patterns
|
||||
|
||||
- **Subscriber Pattern**: All WordPress hook integrations use the subscriber pattern through `Abstract_Subscriber`
|
||||
- **Template System**: UI components use template interfaces for rendering
|
||||
- **Modular Design**: Clear separation between opt-in, telemetry, events, and exit interview functionality
|
||||
- **Multi-Plugin Support**: Designed to be shared across multiple plugins using `Config::add_stellar_slug()`
|
||||
|
||||
### Integration Requirements
|
||||
|
||||
1. Initialize with a compatible DI container
|
||||
2. Configure server URL and hook prefix
|
||||
3. Set a unique stellar slug for plugin identification
|
||||
4. Call `Telemetry::instance()->init(__FILE__)` to start
|
||||
|
||||
### Testing Approach
|
||||
|
||||
- Uses Codeception with WordPress browser testing
|
||||
- Tests run via `slic` command in CI/CD
|
||||
- PHPStan level 5 for static analysis
|
||||
- PHPCS with WordPress VIP Go and TEC standards
|
||||
339
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/telemetry/LICENSE
vendored
Normal file
339
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/telemetry/LICENSE
vendored
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
327
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/telemetry/README.md
vendored
Normal file
327
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/telemetry/README.md
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
# Telemetry Library
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
A library for Opt-in and Telemetry data to be sent to the StellarWP Telemetry server.
|
||||
|
||||
## Table of Contents
|
||||
- [Telemetry Library](#telemetry-library)
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Installation](#installation)
|
||||
- [Usage Prerequisites](#usage-prerequisites)
|
||||
- [Filters \& Actions](#filters--actions)
|
||||
- [Integration](#integration)
|
||||
- [Uninstall Hook](#uninstall-hook)
|
||||
- [Opt-In Modal Usage](#opt-in-modal-usage)
|
||||
- [Prompting Users on a Settings Page](#prompting-users-on-a-settings-page)
|
||||
- [Saving Opt-In Status on a Settings Page](#saving-opt-in-status-on-a-settings-page)
|
||||
- [How to Migrate Users Who Have Already Opted In](#how-to-migrate-users-who-have-already-opted-in)
|
||||
- [Utilizing a Shared Telemetry Instance](#utilizing-a-shared-telemetry-instance)
|
||||
- [Adding Plugin Data to Site Health](#adding-plugin-data-to-site-health)
|
||||
- [Capturing User Events](#capturing-user-events)
|
||||
- [Contribution](#contribution)
|
||||
## Installation
|
||||
|
||||
It's recommended that you install Telemetry as a project dependency via [Composer](https://getcomposer.org/):
|
||||
|
||||
```bash
|
||||
composer require stellarwp/telemetry
|
||||
```
|
||||
|
||||
|
||||
> We _actually_ recommend that this library gets included in your project using [Strauss](https://github.com/BrianHenryIE/strauss).
|
||||
>
|
||||
> Luckily, adding Strauss to your `composer.json` is only slightly more complicated than adding a typical dependency, so checkout our [strauss docs](https://github.com/stellarwp/global-docs/blob/main/docs/strauss-setup.md).
|
||||
|
||||
## Usage Prerequisites
|
||||
To actually _use_ the telemetry library, you must have a Dependency Injection Container (DI Container) that is compatible with the [StellarWP Container Contract](https://github.com/stellarwp/container-contract).
|
||||
|
||||
In order to keep this library as light as possible, a container is not included in the library itself, however we do recommend [di52](https://github.com/lucatume/di52). To avoid version compatibility issues, it is also not included as a Composer dependency. Instead, you must include it in your project. We recommend including it via composer [using Strauss](https://github.com/stellarwp/global-docs/blob/main/docs/strauss-setup.md), just like you have done with this library.
|
||||
|
||||
## Filters & Actions
|
||||
If you'd like to take a look at the existing filters & actions available through the library, [view that documentation here](docs/filters.md).
|
||||
## Integration
|
||||
Initialize the library within your main plugin file after plugins are loaded (or anywhere else you see fit). You can configure a unique prefix (we suggest you use your plugin slug) so that hooks can be uniquely called for your specific instance of the library.
|
||||
|
||||
```php
|
||||
use StellarWP\Telemetry\Core as Telemetry;
|
||||
|
||||
add_action( 'plugins_loaded', 'initialize_telemetry' );
|
||||
|
||||
function initialize_telemetry() {
|
||||
/**
|
||||
* 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 = new Container();
|
||||
Config::set_container( $container );
|
||||
|
||||
// Set the full URL for the Telemetry Server API.
|
||||
Config::set_server_url( 'https://telemetry.example.com/api/v1' );
|
||||
|
||||
// Set a unique prefix for actions & filters.
|
||||
Config::set_hook_prefix( 'my-custom-prefix' );
|
||||
|
||||
// Set a unique plugin slug.
|
||||
Config::set_stellar_slug( 'my-custom-stellar-slug' );
|
||||
|
||||
// Initialize the library.
|
||||
Telemetry::instance()->init( __FILE__ );
|
||||
}
|
||||
```
|
||||
|
||||
Using a custom hook prefix provides the ability to uniquely filter functionality of your plugin's specific instance of the library.
|
||||
|
||||
The unique plugin slug is used by the telemetry server to identify the plugin regardless of the plugin's directory structure or slug.
|
||||
|
||||
If you need to hook into an existing instance of the library, you can add your plugin's stellar slug with:
|
||||
```php
|
||||
add_action( 'plugins_loaded', 'hook_into_existing_telemetry' );
|
||||
|
||||
function hook_into_existing_telemetry() {
|
||||
// Check to make sure that the Telemetry library is already instantiated.
|
||||
if ( ! class_exists( Telemetry::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register the current plugin with an already instantiated library.
|
||||
Config::add_stellar_slug( 'my-custom-stellar-slug', 'custom-plugin/custom-plugin.php' );
|
||||
}
|
||||
```
|
||||
|
||||
## Uninstall Hook
|
||||
|
||||
This library provides everything necessary to uninstall itself. Depending on when your plugin uninstalls itself and cleans up the database, you can include this static method to have the library purge the options table of the necessary rows:
|
||||
```php
|
||||
<?php// uninstall.php
|
||||
|
||||
use YOUR_STRAUSS_PREFIX\StellarWP\Telemetry\Uninstall;
|
||||
|
||||
require_once 'vendor/strauss/autoload.php';
|
||||
|
||||
Uninstall::run( 'my-custom-stellar-slug' );
|
||||
```
|
||||
When a user deletes the plugin, WordPress runs the method from `Uninstall` and cleans up the options table. The last plugin utilizing the library will remove all options.
|
||||
|
||||
## Opt-In Modal Usage
|
||||
|
||||

|
||||
|
||||
### Prompting Users on a Settings Page
|
||||
|
||||
On each settings page you'd like to prompt the user to opt-in, add a `do_action()`. _Be sure to include your defined stellar\_slug_.
|
||||
```php
|
||||
do_action( 'stellarwp/telemetry/optin', '{stellar_slug}' );
|
||||
```
|
||||
|
||||
Or, if you're implementing the library prior to version 3.0.0:
|
||||
```php
|
||||
/**
|
||||
* Planned Deprecation: 3.0.0
|
||||
*
|
||||
* Please use 'stellarwp/telemetry/optin' action instead.
|
||||
*/
|
||||
do_action( 'stellarwp/telemetry/{stellar_slug}/optin' );
|
||||
```
|
||||
The library calls this action to handle registering the required resources needed to render the modal. It will only display the modal for users who haven't yet opted in.
|
||||
|
||||
To show the modal on a settings page, add the `do_action()` to the top of your rendered page content:
|
||||
```php
|
||||
function my_options_page() {
|
||||
do_action( 'stellarwp/telemetry/optin', '{stellar_slug}' );
|
||||
?>
|
||||
<div>
|
||||
<h2>My Plugin Settings Page</h2>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
```
|
||||
_Note: When adding the `do_action`, you may pass additional arguments to the library with an array. There is no functionality at the moment, but we expect to expand the library to accept configuration through the passed array._
|
||||
```php
|
||||
do_action( 'stellarwp/telemetry/optin', '{stellar_slug}', [ 'plugin_slug' => 'the-events-calendar' ] );
|
||||
```
|
||||
|
||||
## Saving Opt-In Status on a Settings Page
|
||||
When implementing the library, settings should be available for site administrators to change their opt-in status at any time. The value passed to `set_status()` should be a boolean.
|
||||
|
||||
```php
|
||||
add_action( 'admin_init', 'save_opt_in_setting_field' );
|
||||
|
||||
/**
|
||||
* Saves the "Opt In Status" setting.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save_opt_in_setting_field() {
|
||||
// Return early if not saving the Opt In Status field.
|
||||
if ( ! isset( $_POST[ 'opt-in-status' ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get an instance of the Status class.
|
||||
$Status = Config::get_container()->get( Status::class );
|
||||
|
||||
// Get the value submitted on the settings page as a boolean.
|
||||
$value = filter_input( INPUT_POST, 'opt-in-status', FILTER_VALIDATE_BOOL );
|
||||
|
||||
$Status->set_status( $value );
|
||||
}
|
||||
```
|
||||
|
||||
## How to Migrate Users Who Have Already Opted In
|
||||
If you have a system that users have already opted in to and you'd prefer not to have them opt in again, here's how you might go about it. The `opt_in()` method will set their opt-in status to `true` and send their telemetry data and user data to the telemetry server.
|
||||
|
||||
```php
|
||||
/**
|
||||
* The library attempts to set the opt-in status for a site during 'admin_init'. Use the hook with a priority higher
|
||||
* than 10 to make sure you're setting the status after it initializes the option in the options table.
|
||||
*/
|
||||
add_action( 'admin_init', 'migrate_existing_opt_in', 11 );
|
||||
|
||||
function migrate_existing_opt_in() {
|
||||
|
||||
if ( $user_has_opted_in_already ) {
|
||||
|
||||
// Get the Opt_In_Subscriber object.
|
||||
$Opt_In_Subscriber = Config::get_container()->get( Opt_In_Subscriber::class );
|
||||
$Opt_In_Subscriber->opt_in();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Utilizing a Shared Telemetry Instance
|
||||
|
||||
There are cases where a plugin may want to use a shared instance of the library.
|
||||
|
||||
The best example of this would be an add-on plugin connecting and using the Telemetry instance of its parent plugin.
|
||||
|
||||
In this case, all that the plugin needs to do to implement the parent Telemetry instance is use `Config::add_stellar_slug()`.
|
||||
```php
|
||||
use STRAUSS_PREFIX\StellarWP\Telemetry\Config;
|
||||
|
||||
add_action( 'plugins_loaded', 'add_plugin_to_telemetry' );
|
||||
|
||||
function add_plugin_to_telemetry() {
|
||||
|
||||
// Verify that Telemetry is available.
|
||||
if ( ! class_exists( Config::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set a unique plugin slug and include the plugin basename.
|
||||
Config::add_stellar_slug( 'my-custom-stellar-slug', 'my-custom-stellar-slug/my-custom-stellar-slug.php' );
|
||||
}
|
||||
```
|
||||
|
||||
## Adding Plugin Data to Site Health
|
||||
|
||||
We collect the Site Health data as json on the server. In order to pass additional plugin specific items that can be reported on, you will need to add a section to the Site Health Data. The process for adding a section is documented on [developer.wordpress.org](https://developer.wordpress.org/reference/hooks/debug_information/).
|
||||
|
||||
We do have some requirements so that we can grab the correct data from Site Health. When setting the key to the plugins site health section, use the plugin slug. Do not nest your settings in a single line, use one line per option. Do not translate the debug value. This will help make sure that the data is reportable on the Telemetry Server.
|
||||
|
||||
``` php
|
||||
function add_summary_to_telemtry( $info ) {
|
||||
$info[ 'stellarwp' ] = [
|
||||
'label' => esc_html__( 'StellarWP Plugin Section', 'text-domain' ),
|
||||
'description' => esc_html__( 'There are some key things here... Everything should be output in key value pairs. Follow the translation instructions in the codex (do not translate debug). Plugin Slug should be the main key.', 'text-domain' ),
|
||||
'fields' => [
|
||||
'field_key_one' => [
|
||||
'label' => esc_html__( 'This is the field text', 'text-domain' ),
|
||||
'value' => esc_html__( 'value', 'text-domain' ),
|
||||
'debug' => 'value'
|
||||
],
|
||||
'field_key_two' => [
|
||||
'label' => esc_html__( 'Field Two', 'text-domain' ),
|
||||
'value' => esc_html__( 'yes', 'text-domain' ),
|
||||
'debug' => true,
|
||||
],
|
||||
'field_key_three' => [
|
||||
'label' => esc_html__( 'Three', 'text-domain' ),
|
||||
'value' => esc_html__( 'Tempus pellentesque id hac', 'text-domain' ),
|
||||
'debug' => 'Tempus pellentesque id hac',
|
||||
],
|
||||
'field_key_four' => [
|
||||
'label' => esc_html__( 'Option Four', 'text-domain' ),
|
||||
'value' => esc_html__( 'on', 'text-domain' ),
|
||||
'debug' => true,
|
||||
],
|
||||
],
|
||||
];
|
||||
return $info;
|
||||
}
|
||||
|
||||
add_filter( 'debug_information', 'add_summary_to_telemetry', 10, 1) ;
|
||||
```
|
||||
|
||||
## Capturing User Events
|
||||
|
||||
When a user completes an action, an event can be captured with the telemetry server for a specific site. These events take `name` and `data` (array) parameters to capture any specific information necessary for the event.
|
||||
|
||||
Some examples of actions you may want to capture:
|
||||
- User creates their first post
|
||||
- A plugin feature is used for the first time (but not completed or utilized)
|
||||
- X days have passed and a feature has not yet been utilized
|
||||
|
||||
**NOTE: All plugins should trigger an event when a user opts out of telemetry for a site.**
|
||||
|
||||
To create an event, set up a do_action with the necessary details wherever you'd like to capture it:
|
||||
```php
|
||||
// Event data is sent to the telemetry server as JSON.
|
||||
$data = [
|
||||
'one' => 1,
|
||||
'two' => 2,
|
||||
'three' => 3,
|
||||
];
|
||||
do_action( 'stellarwp/telemetry/{hook-prefix}/event', 'your-event-name', $data );
|
||||
```
|
||||
|
||||
Here is how you might log events when a user creates a new post:
|
||||
```php
|
||||
/**
|
||||
* Log event when a user creates a new post.
|
||||
*
|
||||
* @action save_post
|
||||
*
|
||||
* @param int $post_id The ID of the post being saved.
|
||||
* @param WP_Post $post The post object being saved.
|
||||
* @param bool $update If this is an update to a pre-existing post.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function user_creates_post( $post_id, $post, $update ) {
|
||||
// Only send events for new posts.
|
||||
if ( $update ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only send event for posts, avoid everything else.
|
||||
if ( $post->post_type !== 'post' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add any data to the event that needs to be captured.
|
||||
$event_data = [
|
||||
'title' => $post->post_title,
|
||||
'content' => $post->post_content,
|
||||
'some-other-data' => 'use the array to capture anything else that might be necessary for context'
|
||||
];
|
||||
|
||||
// Log the event with the telemetry server.
|
||||
do_action( 'stellarwp/telemetry/{hook-prefix}/event', 'new_post', $event_data );
|
||||
}
|
||||
```
|
||||
|
||||
## Contribution
|
||||
|
||||
There are more detailed docs that provide guidance on contributing to the library:
|
||||
- [Automated testing](/docs/automated-testing.md)
|
||||
- [Local Environment Configuration](/docs/local-environment.md)
|
||||
- [Quality Assurance](/docs/quality-assurance.md)
|
||||
3
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/telemetry/index.php
vendored
Normal file
3
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/telemetry/index.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
// Silence is golden.
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles all hooks/filters related to the admin screens.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Admin;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Config;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts\Abstract_Subscriber;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Opt_In\Opt_In_Template;
|
||||
/**
|
||||
* Handles all hooks/filters related to the admin screens.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Admin_Subscriber extends Abstract_Subscriber
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
add_action('admin_init', [$this, 'maybe_enqueue_admin_assets']);
|
||||
}
|
||||
/**
|
||||
* Registers required hooks to set up the admin assets.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Adjust to output assets if any stellar slug should render its modal.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_enqueue_admin_assets()
|
||||
{
|
||||
global $pagenow;
|
||||
$should_render = false;
|
||||
foreach (Config::get_all_stellar_slugs() as $stellar_slug => $wp_slug) {
|
||||
$should_render = $this->container->get(Opt_In_Template::class)->should_render($stellar_slug);
|
||||
if ($should_render) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ('plugins.php' === $pagenow || $should_render) {
|
||||
$this->container->get(Resources::class)->enqueue_admin_assets();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A collection of methods to enqueue and localize admin assets.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Admin;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Config;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Exit_Interview\Exit_Interview_Subscriber;
|
||||
/**
|
||||
* A class that enqueues and localizes admin assets.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Resources
|
||||
{
|
||||
const SCRIPT_HANDLE = 'stellarwp-telemetry-admin';
|
||||
const SCRIPT_VERSION = '1.0.0';
|
||||
/**
|
||||
* Enqueues the admin resources.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_admin_assets()
|
||||
{
|
||||
add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts']);
|
||||
add_action('admin_enqueue_scripts', [$this, 'localize_script']);
|
||||
add_action('admin_enqueue_scripts', [$this, 'enqueue_styles']);
|
||||
}
|
||||
/**
|
||||
* Enqueues the admin JS script.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_scripts()
|
||||
{
|
||||
/**
|
||||
* Filters the path to the admin JS script.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $path The path to the admin JS script.
|
||||
*/
|
||||
$script_path = apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'script_path', $this->get_asset_path() . 'resources/js/scripts.js');
|
||||
wp_enqueue_script(self::SCRIPT_HANDLE, $script_path, ['jquery'], self::SCRIPT_VERSION, true);
|
||||
}
|
||||
/**
|
||||
* Localizes the admin JS script.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function localize_script()
|
||||
{
|
||||
/**
|
||||
* Filters the data that is passed to the admin JS script.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array $data The data to pass to the script.
|
||||
*/
|
||||
$script_data = apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'script_data', ['exit_interview' => ['action' => Exit_Interview_Subscriber::AJAX_ACTION, 'nonce' => wp_create_nonce(Exit_Interview_Subscriber::AJAX_ACTION)]]);
|
||||
wp_localize_script(self::SCRIPT_HANDLE, 'stellarwpTelemetry', $script_data);
|
||||
}
|
||||
/**
|
||||
* Enqueues the admin CSS styles.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_styles()
|
||||
{
|
||||
/**
|
||||
* Filters the path to the admin CSS styles.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $path The path to the CSS file.
|
||||
*/
|
||||
$style_path = apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'style_path', $this->get_asset_path() . 'resources/css/styles.css');
|
||||
wp_enqueue_style(self::SCRIPT_HANDLE, $style_path, [], self::SCRIPT_VERSION);
|
||||
}
|
||||
/**
|
||||
* Gets the path to the assets folder.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_asset_path(): string
|
||||
{
|
||||
return plugin_dir_url(dirname(__DIR__));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A helper class to provide configuration options for the library.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\ContainerContract\ContainerInterface;
|
||||
/**
|
||||
* A configuration class to help set up the library.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Config
|
||||
{
|
||||
/**
|
||||
* Container object.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @var ?\KadenceWP\KadenceBlocks\StellarWP\ContainerContract\ContainerInterface
|
||||
*/
|
||||
protected static $container;
|
||||
/**
|
||||
* Prefix for hook names.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $hook_prefix = '';
|
||||
/**
|
||||
* Unique ID for the stellarwp slug.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $stellar_slug = '';
|
||||
/**
|
||||
* Unique IDs and optional plugin slugs for StellarWP slugs.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $stellar_slugs = [];
|
||||
/**
|
||||
* The url of the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $server_url = 'https://telemetry.stellarwp.com/api/v1';
|
||||
/**
|
||||
* Get the container.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @throws \RuntimeException Throws exception if container is not set.
|
||||
*
|
||||
* @return \KadenceWP\KadenceBlocks\StellarWP\ContainerContract\ContainerInterface
|
||||
*/
|
||||
public static function get_container()
|
||||
{
|
||||
if (null === self::$container) {
|
||||
throw new \RuntimeException('You must provide a container via StellarWP\Telemetry\Config::set_container() before attempting to fetch it.');
|
||||
}
|
||||
return self::$container;
|
||||
}
|
||||
/**
|
||||
* Gets the hook prefix.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_hook_prefix()
|
||||
{
|
||||
return static::$hook_prefix;
|
||||
}
|
||||
/**
|
||||
* Gets the telemetry server url.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_server_url()
|
||||
{
|
||||
return static::$server_url;
|
||||
}
|
||||
/**
|
||||
* Gets the stellar slug.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_stellar_slug()
|
||||
{
|
||||
return static::$stellar_slug;
|
||||
}
|
||||
/**
|
||||
* Gets the registered stellar slugs.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @return array<string,string>
|
||||
*/
|
||||
public static function get_all_stellar_slugs()
|
||||
{
|
||||
return static::$stellar_slugs;
|
||||
}
|
||||
/**
|
||||
* Returns whether the container has been set.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_container()
|
||||
{
|
||||
return null !== self::$container;
|
||||
}
|
||||
/**
|
||||
* Resets this class back to the defaults.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function reset()
|
||||
{
|
||||
static::$hook_prefix = '';
|
||||
static::$server_url = 'https://telemetry.stellarwp.com/api/v1';
|
||||
static::$stellar_slug = '';
|
||||
static::$container = null;
|
||||
}
|
||||
/**
|
||||
* Set the container object.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param \KadenceWP\KadenceBlocks\StellarWP\ContainerContract\ContainerInterface $container Container object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function set_container(ContainerInterface $container)
|
||||
{
|
||||
self::$container = $container;
|
||||
}
|
||||
/**
|
||||
* Sets the hook prefix.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $prefix The prefix to use for hooks.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function set_hook_prefix(string $prefix)
|
||||
{
|
||||
// Make sure the prefix always ends with a separator.
|
||||
if (substr($prefix, -1) !== '/') {
|
||||
$prefix = $prefix . '/';
|
||||
}
|
||||
static::$hook_prefix = $prefix;
|
||||
}
|
||||
/**
|
||||
* Sets the stellar slug.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $stellar_slug The unique slug to identify the plugin with the server.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function set_stellar_slug(string $stellar_slug)
|
||||
{
|
||||
static::$stellar_slug = $stellar_slug;
|
||||
// Also add the stellar slug to the array of all registered stellar slugs.
|
||||
static::$stellar_slugs[$stellar_slug] = '';
|
||||
}
|
||||
/**
|
||||
* Adds a new stellar slug to the stellar slugs array.
|
||||
*
|
||||
* Utilizing an array of stellar slugs, the library can be tailored for use in a single plugin
|
||||
* or use within a shared library for several plugins. Each stellar slug registered will
|
||||
* generate unique filters and hooks that give further customization for each slug
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param string $stellar_slug A unique slug to add to the config.
|
||||
* @param string $wp_slug The plugin's basename (used for capturing deactivation "Exit Interview" info).
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function add_stellar_slug(string $stellar_slug, string $wp_slug = '')
|
||||
{
|
||||
static::$stellar_slugs[$stellar_slug] = $wp_slug;
|
||||
}
|
||||
/**
|
||||
* Sets the telemetry server url.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $url The url of the telemetry server.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function set_server_url(string $url)
|
||||
{
|
||||
static::$server_url = $url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles setting up a base for all subscribers.
|
||||
*
|
||||
* @package KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\ContainerContract\ContainerInterface;
|
||||
/**
|
||||
* Class Abstract_Subscriber
|
||||
*
|
||||
* @package \KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts
|
||||
*/
|
||||
abstract class Abstract_Subscriber implements Subscriber_Interface
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
/**
|
||||
* Constructor for the class.
|
||||
*
|
||||
* @param ContainerInterface $container The container.
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* An interface that provides the API for all data providers.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts;
|
||||
|
||||
/**
|
||||
* An interface that provides the API for all data providers.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts
|
||||
*/
|
||||
interface Data_Provider
|
||||
{
|
||||
/**
|
||||
* Gets the data that should be sent to the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_data(): array;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Provides an API for all classes that are runnable.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts;
|
||||
|
||||
/**
|
||||
* Provides an API for all classes that are runnable.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts
|
||||
*/
|
||||
interface Runnable
|
||||
{
|
||||
/**
|
||||
* Run the intended action.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The API implemented by all subscribers.
|
||||
*
|
||||
* @package KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts;
|
||||
|
||||
/**
|
||||
* Interface Subscriber_Interface
|
||||
*
|
||||
* @package \KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts
|
||||
*/
|
||||
interface Subscriber_Interface
|
||||
{
|
||||
/**
|
||||
* Register action/filter listeners to hook into WordPress
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* Provides an API for rendering templates.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts
|
||||
*/
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts;
|
||||
|
||||
/**
|
||||
* Interface that provides an API for rendering templates.
|
||||
*/
|
||||
interface Template_Interface {
|
||||
/**
|
||||
* Renders the template.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Update to handle passed in stellar slug.
|
||||
*
|
||||
* @param string $stellar_slug The stellar slug to be referenced when the modal is rendered.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render( string $stellar_slug );
|
||||
|
||||
/**
|
||||
* Determines if the template should be rendered.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Update to handle passed in stellar slug.
|
||||
*
|
||||
* @param string $stellar_slug The stellar slug for which the modal should be rendered.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function should_render( string $stellar_slug );
|
||||
}
|
||||
150
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/telemetry/src/Telemetry/Core.php
vendored
Normal file
150
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/telemetry/src/Telemetry/Core.php
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles setting up the library.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\ContainerContract\ContainerInterface;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Admin\Admin_Subscriber;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Admin\Resources;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts\Data_Provider;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Data_Providers\Debug_Data;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Events\Event_Subscriber;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Exit_Interview\Exit_Interview_Subscriber;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Exit_Interview\Template;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Last_Send\Last_Send;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Last_Send\Last_Send_Subscriber;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Opt_In\Opt_In_Subscriber;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Opt_In\Opt_In_Template;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Opt_In\Status;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Telemetry\Telemetry;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Telemetry\Telemetry_Subscriber;
|
||||
/**
|
||||
* The core class of the library.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Core
|
||||
{
|
||||
const PLUGIN_BASENAME = 'plugin.basename';
|
||||
const PLUGIN_FILE = 'plugin.file';
|
||||
const SITE_PLUGIN_DIR = 'site.plugin_dir';
|
||||
/**
|
||||
* The subscriber class names that should be registered in the container.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $subscribers = [Admin_Subscriber::class, Exit_Interview_Subscriber::class, Event_Subscriber::class, Last_Send_Subscriber::class, Opt_In_Subscriber::class, Telemetry_Subscriber::class];
|
||||
/**
|
||||
* The container that should be used for loading library resources.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
private $container;
|
||||
/**
|
||||
* The current instance of the library.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @var self
|
||||
*/
|
||||
private static $instance = null;
|
||||
/**
|
||||
* Returns the current instance or creates one to return.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
if (null === self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
/**
|
||||
* Initializes the library.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $plugin_path The path to the main plugin file.
|
||||
*
|
||||
* @throws \RuntimeException Throws exception if container is not set.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init(string $plugin_path)
|
||||
{
|
||||
if (!Config::has_container()) {
|
||||
throw new \RuntimeException('You must call StellarWP\Telemetry\Config::set_container() before calling StellarWP\Telemetry::init().');
|
||||
}
|
||||
$this->init_container($plugin_path);
|
||||
}
|
||||
/**
|
||||
* Gets the container.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return \KadenceWP\KadenceBlocks\StellarWP\ContainerContract\ContainerInterface
|
||||
*/
|
||||
public function container()
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
/**
|
||||
* Initializes the container with library resources.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $plugin_path The path of the plugin.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function init_container(string $plugin_path)
|
||||
{
|
||||
$container = Config::get_container();
|
||||
// For all registered stellar slugs, use the plugin basename for those that do not have a wp_slug set.
|
||||
foreach (Config::get_all_stellar_slugs() as $stellar_slug => $wp_slug) {
|
||||
if ('' !== $wp_slug) {
|
||||
continue;
|
||||
}
|
||||
Config::add_stellar_slug($stellar_slug, plugin_basename($plugin_path));
|
||||
}
|
||||
$container->bind(self::PLUGIN_BASENAME, plugin_basename($plugin_path));
|
||||
$container->bind(self::PLUGIN_FILE, $plugin_path);
|
||||
$container->bind(self::SITE_PLUGIN_DIR, dirname(plugin_dir_path($plugin_path)));
|
||||
$container->bind(Data_Provider::class, Debug_Data::class);
|
||||
$container->bind(Status::class, Status::class);
|
||||
$container->bind(Last_Send::class, Last_Send::class);
|
||||
$container->bind(Opt_In_Template::class, static function () use ($container) {
|
||||
return new Opt_In_Template($container->get(Status::class));
|
||||
});
|
||||
$container->bind(Template::class, static function () use ($container) {
|
||||
return new Template($container);
|
||||
});
|
||||
$container->bind(Telemetry::class, static function () use ($container) {
|
||||
return new Telemetry($container->get(Data_Provider::class), $container->get(Status::class));
|
||||
});
|
||||
$container->bind(Resources::class, static function () {
|
||||
return new Resources();
|
||||
});
|
||||
// Store the container for later use.
|
||||
$this->container = $container;
|
||||
foreach ($this->subscribers as $subscriber_class) {
|
||||
$this->container->bind($subscriber_class, new $subscriber_class($this->container));
|
||||
$this->container->get($subscriber_class)->register();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A helper class for getting site health data.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Data_Providers;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts\Data_Provider;
|
||||
use WP_Debug_Data;
|
||||
/**
|
||||
* Provides methods for retrieving site health data.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Debug_Data implements Data_Provider
|
||||
{
|
||||
/**
|
||||
* Gets the current site health data
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @see https://developer.wordpress.org/reference/classes/wp_debug_data/
|
||||
*
|
||||
* @return array Site health data
|
||||
*/
|
||||
public function get_data(): array
|
||||
{
|
||||
if (!class_exists('WP_Debug_Data')) {
|
||||
require_once ABSPATH . 'wp-admin/includes/class-wp-debug-data.php';
|
||||
}
|
||||
$info = WP_Debug_Data::debug_data();
|
||||
$active_plugins = get_option('active_plugins');
|
||||
$plugins = get_plugins();
|
||||
$active = [];
|
||||
foreach ($active_plugins as $active_plugin) {
|
||||
if (isset($plugins[$active_plugin])) {
|
||||
$active[$active_plugin] = $plugins[$active_plugin];
|
||||
unset($plugins[$active_plugin]);
|
||||
}
|
||||
}
|
||||
$info['telemetry-active-plugins']['fields'] = $active;
|
||||
$info['telemetry-inactive-plugins']['fields'] = $plugins;
|
||||
return $info;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A data provider that provides no data, used for testing.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @package KadenceWP\KadenceBlocks\StellarWP\Telemetry\Data_Providers;
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Data_Providers;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts\Data_Provider;
|
||||
/**
|
||||
* Class Null_Data_Provider.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @package \KadenceWP\KadenceBlocks\StellarWP\Telemetry\Data_Providers;
|
||||
*/
|
||||
class Null_Data_Provider implements Data_Provider
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public function get_data(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Contains all event related functionality.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Events;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Config;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Telemetry\Telemetry;
|
||||
/**
|
||||
* The class that handles user triggered events.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Event
|
||||
{
|
||||
/**
|
||||
* The hook name for sending events asyncronously.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public const AJAX_ACTION = 'stellarwp_telemetry_send_event';
|
||||
/**
|
||||
* An instance of the Telemetry class.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @var \KadenceWP\KadenceBlocks\StellarWP\Telemetry\Telemetry\Telemetry
|
||||
*/
|
||||
private $telemetry;
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @param Telemetry $telemetry An instance of the Telemetry class.
|
||||
*/
|
||||
public function __construct(Telemetry $telemetry)
|
||||
{
|
||||
$this->telemetry = $telemetry;
|
||||
}
|
||||
/**
|
||||
* Sends an event to the telemetry server.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @param string $name The name of the event.
|
||||
* @param array $data Additional information to include with the event.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function send(string $name, array $data = [])
|
||||
{
|
||||
$data = ['token' => $this->telemetry->get_token(), 'stellar_slug' => Config::get_stellar_slug(), 'event' => $name, 'event_data' => wp_json_encode($data)];
|
||||
/**
|
||||
* Provides the ability to filter event data before it is sent to the telemetry server.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @param array $data The data about to be sent.
|
||||
*/
|
||||
$data = apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'event_data', $data);
|
||||
$response = $this->telemetry->send($data, $this->get_url());
|
||||
if (!isset($response['status'])) {
|
||||
return false;
|
||||
}
|
||||
return boolval($response['status']);
|
||||
}
|
||||
/**
|
||||
* Send batched events.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @param array $events An array of stored events to send to the telemetry server.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function send_batch(array $events)
|
||||
{
|
||||
$data = ['token' => $this->telemetry->get_token(), 'events' => $events];
|
||||
$response = $this->telemetry->send($data, $this->get_url());
|
||||
if (!isset($response['status'])) {
|
||||
return false;
|
||||
}
|
||||
return boolval($response['status']);
|
||||
}
|
||||
/**
|
||||
* Gets the url used for sending events.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_url()
|
||||
{
|
||||
$events_url = Config::get_server_url() . '/events';
|
||||
/**
|
||||
* Filters the url used to send events to the telemetry server.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @param string $event_url The events endpoint url.
|
||||
*/
|
||||
return apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'events_url', $events_url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles all actions and filters related to telemetry events.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Events;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Config;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts\Abstract_Subscriber;
|
||||
/**
|
||||
* Handles all actions and filters related to telemetry events.
|
||||
*
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Event_Subscriber extends Abstract_Subscriber
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $events = [];
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
add_action('shutdown', [$this, 'send_cached_events']);
|
||||
add_action('stellarwp/telemetry/' . Config::get_hook_prefix() . 'event', [$this, 'cache_event'], 10, 2);
|
||||
add_action('wp_ajax_' . Event::AJAX_ACTION, [$this, 'send_events'], 10, 1);
|
||||
add_action('wp_ajax_nopriv_' . Event::AJAX_ACTION, [$this, 'send_events'], 10, 1);
|
||||
}
|
||||
/**
|
||||
* Caches an event to be sent during shutdown.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @param string $name The name of the event.
|
||||
* @param array $data The data sent along with the event.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cache_event($name, $data)
|
||||
{
|
||||
self::$events[] = ['name' => $name, 'data' => wp_json_encode($data), 'stellar_slug' => Config::get_stellar_slug()];
|
||||
}
|
||||
/**
|
||||
* Sends the events that have been stored for the current request.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function send_cached_events()
|
||||
{
|
||||
if (empty(self::$events)) {
|
||||
return;
|
||||
}
|
||||
$url = admin_url('admin-ajax.php');
|
||||
wp_remote_post($url, ['blocking' => false, 'sslverify' => false, 'body' => ['action' => Event::AJAX_ACTION, 'events' => self::$events]]);
|
||||
self::$events = [];
|
||||
}
|
||||
/**
|
||||
* Send the event to the telemetry server.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function send_events()
|
||||
{
|
||||
// Get the passed event array.
|
||||
$events = filter_input(INPUT_POST, 'events', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
|
||||
// phpcs:ignore WordPressVIPMinimum.Security.PHPFilterFunctions.RestrictedFilter
|
||||
if (empty($events)) {
|
||||
return;
|
||||
}
|
||||
$this->container->get(Event::class)->send_batch((array) $events);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A class that handles displaying an "Exit Interview" for users deactivating the plugin.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Exit_Interview;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts\Abstract_Subscriber;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Config;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Opt_In\Status;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Telemetry\Telemetry;
|
||||
/**
|
||||
* A class that handles displaying an "Exit Interview" for users deactivating the plugin.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Exit_Interview_Subscriber extends Abstract_Subscriber
|
||||
{
|
||||
const AJAX_ACTION = 'exit-interview';
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
// If the site is not opted in, don't enqueue the Exit Interview modal.
|
||||
if (!$this->container->get(Status::class)->is_active()) {
|
||||
return;
|
||||
}
|
||||
add_action('admin_footer', [$this, 'render_exit_interview']);
|
||||
add_action('wp_ajax_' . self::AJAX_ACTION, [$this, 'ajax_exit_interview']);
|
||||
// Implement the exit interview trigger for each registerred plugin.
|
||||
foreach (Config::get_all_stellar_slugs() as $basename) {
|
||||
add_filter('network_admin_plugin_action_links_' . $basename, [$this, 'plugin_action_links'], 10, 2);
|
||||
add_filter('plugin_action_links_' . $basename, [$this, 'plugin_action_links'], 10, 2);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Possibly renders the exit interview if the user is on the plugins list page.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render_exit_interview()
|
||||
{
|
||||
global $pagenow;
|
||||
if ('plugins.php' === $pagenow) {
|
||||
// Swap key/values since we need to map stellar slugs by plugin basename.
|
||||
$stellar_slugs = array_flip(Config::get_all_stellar_slugs());
|
||||
$plugins = get_plugins();
|
||||
foreach ($plugins as $slug => $data) {
|
||||
if (key_exists($slug, $stellar_slugs)) {
|
||||
$this->container->get(Template::class)->maybe_render($stellar_slugs[$slug]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Handles the ajax request for submitting "Exit Interivew" form data.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.3.4 - Added user capability check.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_exit_interview()
|
||||
{
|
||||
// Check sent data before we do any database checks for faster failures.
|
||||
$uninstall_reason_id = filter_input(INPUT_POST, 'uninstall_reason_id', FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
$uninstall_reason_id = !empty($uninstall_reason_id) ? $uninstall_reason_id : false;
|
||||
if (!$uninstall_reason_id) {
|
||||
wp_send_json_error('No reason id provided');
|
||||
}
|
||||
$uninstall_reason = filter_input(INPUT_POST, 'uninstall_reason', FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
$uninstall_reason = !empty($uninstall_reason) ? $uninstall_reason : false;
|
||||
if (!$uninstall_reason) {
|
||||
wp_send_json_error('No reason provided');
|
||||
}
|
||||
$plugin_slug = filter_input(INPUT_POST, 'plugin_slug', FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
$comment = filter_input(INPUT_POST, 'comment', FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
$comment = !empty($comment) ? $comment : '';
|
||||
// Validate nonce.
|
||||
$nonce = filter_input(INPUT_POST, 'nonce', FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
$nonce = !empty($nonce) ? $nonce : '';
|
||||
if (!wp_verify_nonce($nonce, self::AJAX_ACTION)) {
|
||||
wp_send_json_error('Invalid nonce');
|
||||
}
|
||||
// Sent data validated, check if the user has the necessary permissions.
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_send_json_error('User does not have proper permissions to modify plugins');
|
||||
}
|
||||
$telemetry = $this->container->get(Telemetry::class);
|
||||
$telemetry->send_uninstall($plugin_slug, $uninstall_reason_id, $uninstall_reason, $comment);
|
||||
wp_send_json_success();
|
||||
}
|
||||
/**
|
||||
* Adds an <i> element after the "deactivate" link on the plugin list table so that it can be targeted by JS to trigger the interview modal.
|
||||
*
|
||||
* The deactivation is deferred to the modal displayed.
|
||||
*
|
||||
* @param array $links The links of the plugin in the plugin list.
|
||||
* @param string $plugin_file The plugin file of the current plugin in the list.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function plugin_action_links($links, $plugin_file)
|
||||
{
|
||||
$stellar_slug = '';
|
||||
foreach (Config::get_all_stellar_slugs() as $slug => $basename) {
|
||||
if (plugin_basename($plugin_file) === $basename) {
|
||||
$stellar_slug = $slug;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$passed_deactivate = false;
|
||||
$deactivate_link = '';
|
||||
$before_deactivate = [];
|
||||
$after_deactivate = [];
|
||||
foreach ($links as $key => $link) {
|
||||
if ('deactivate' === $key) {
|
||||
$deactivate_link = $link;
|
||||
$passed_deactivate = true;
|
||||
continue;
|
||||
}
|
||||
if (!$passed_deactivate) {
|
||||
$before_deactivate[$key] = $link;
|
||||
} else {
|
||||
$after_deactivate[$key] = $link;
|
||||
}
|
||||
}
|
||||
if (!empty($deactivate_link)) {
|
||||
$deactivate_link .= '<i class="telemetry-plugin-slug" data-plugin-slug="' . $stellar_slug . '"></i>';
|
||||
// Append deactivation link.
|
||||
$before_deactivate['deactivate'] = $deactivate_link;
|
||||
}
|
||||
return array_merge($before_deactivate, $after_deactivate);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles the methods for rendering the "Exit Interview" modal on plugin deactivation.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Exit_Interview;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\ContainerContract\ContainerInterface;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Admin\Resources;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Config;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts\Template_Interface;
|
||||
/**
|
||||
* The primary class for rendering the "Exit Interview" modal on plugin deactivation.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Template implements Template_Interface
|
||||
{
|
||||
/**
|
||||
* The plugin container.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @var \KadenceWP\KadenceBlocks\StellarWP\ContainerContract\ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param \KadenceWP\KadenceBlocks\StellarWP\ContainerContract\ContainerInterface $container The container.
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
/**
|
||||
* Gets the arguments for configuring the "Exit Interview" modal.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Updated to accept a passed stellar slug.
|
||||
*
|
||||
* @param string $stellar_slug The stellar slug used when outputting the modal.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_args(string $stellar_slug)
|
||||
{
|
||||
$args = ['plugin_slug' => $stellar_slug, 'plugin_logo' => Resources::get_asset_path() . 'resources/images/liquid-web-logo.svg', 'plugin_logo_width' => 148, 'plugin_logo_height' => 32, 'plugin_logo_alt' => 'Liquid Web Logo', 'heading' => __('We’re sorry to see you go.', 'stellarwp-telemetry'), 'intro' => __('We’d love to know why you’re leaving so we can improve our plugin.', 'stellarwp-telemetry'), 'uninstall_reasons' => [['uninstall_reason_id' => 'confusing', 'uninstall_reason' => __('I couldn’t understand how to make it work.', 'stellarwp-telemetry')], ['uninstall_reason_id' => 'better-plugin', 'uninstall_reason' => __('I found a better plugin.', 'stellarwp-telemetry')], ['uninstall_reason_id' => 'no-feature', 'uninstall_reason' => __('I need a specific feature it doesn’t provide.', 'stellarwp-telemetry')], ['uninstall_reason_id' => 'broken', 'uninstall_reason' => __('The plugin doesn’t work.', 'stellarwp-telemetry')], ['uninstall_reason_id' => 'other', 'uninstall_reason' => __('Other', 'stellarwp-telemetry'), 'show_comment' => true]]];
|
||||
/**
|
||||
* Filters the "Exit Interview" modal arguments.
|
||||
*
|
||||
* Planned deprecation: 3.0.0
|
||||
* Use stellarwp/telemetry/exit_interview_args filter instead.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Added the current stellar slug.
|
||||
*
|
||||
* @param array $args The arguments used to configure the modal.
|
||||
* @param string $stellar_slug The current stellar slug for the plugin outputting the modal.
|
||||
*/
|
||||
$args = apply_filters('stellarwp/telemetry/' . $stellar_slug . '/exit_interview_args', $args, $stellar_slug);
|
||||
/**
|
||||
* Filters the "Exit Interview" modal arguments.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param array $args The arguments used to configure the modal.
|
||||
* @param string $stellar_slug The current stellar slug for the plugin outputting the modal.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
$args = apply_filters('stellarwp/telemetry/exit_interview_args', $args, $stellar_slug);
|
||||
return $args;
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $stellar_slug The stellar slug to be referenced when the modal is rendered.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render(string $stellar_slug)
|
||||
{
|
||||
load_template(dirname(dirname(__DIR__)) . '/views/exit-interview.php', false, $this->get_args($stellar_slug));
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $stellar_slug The stellar slug for which the modal should be rendered.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function should_render(string $stellar_slug)
|
||||
{
|
||||
/**
|
||||
* Filters whether the "Exit Interview" modal should render.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Update to include current stellar slug.
|
||||
*
|
||||
* @param bool $should_render Whether the modal should render.
|
||||
* @param string $stellar_slug The current stellar slug of the plugin for which the modal is shown.
|
||||
*/
|
||||
return apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'exit_interview_should_render', true, $stellar_slug);
|
||||
}
|
||||
/**
|
||||
* Renders the template if it should be rendered.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $stellar_slug The stellar slug that could be rendered.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_render(string $stellar_slug)
|
||||
{
|
||||
if ($this->should_render($stellar_slug)) {
|
||||
$this->render($stellar_slug);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles all methods for determining when to send telemetry data.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Last_Send;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Config;
|
||||
/**
|
||||
* Handles all methods for determining when to send telemetry data.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Last_Send
|
||||
{
|
||||
public const OPTION_NAME = 'stellarwp_telemetry_last_send';
|
||||
/**
|
||||
* Initially sets the _last_send option in the options table.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize_option()
|
||||
{
|
||||
if (get_option(self::OPTION_NAME) === false) {
|
||||
update_option(self::OPTION_NAME, '');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Checks whether the last send timestamp is expired or not.
|
||||
*
|
||||
* If the timestamp is >= 1 week, the last send is expired.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_expired()
|
||||
{
|
||||
$last_send = $this->get_timestamp();
|
||||
// No timestamp exists, we'll assume that telemetry data needs to be sent.
|
||||
if ('' === $last_send) {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Filters the amount of seconds the last send timestamp is valid before it expires.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param integer $expire_seconds
|
||||
*/
|
||||
$expire_seconds = apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'last_send_expire_seconds', 7 * DAY_IN_SECONDS);
|
||||
$last_run_time = new DateTimeImmutable($last_send);
|
||||
$next_run_time = $last_run_time->add(new \DateInterval("PT{$expire_seconds}S"));
|
||||
return $next_run_time <= new DateTimeImmutable();
|
||||
}
|
||||
/**
|
||||
* Sets a new timestamp for the last_send option.
|
||||
*
|
||||
* @param DateTimeImmutable $time The time to use for the timestamp.
|
||||
*
|
||||
* @return int Number of rows affected.
|
||||
*/
|
||||
public function set_new_timestamp(DateTimeImmutable $time)
|
||||
{
|
||||
global $wpdb;
|
||||
$timestamp = $time->format('Y-m-d H:i:s');
|
||||
$option_name = self::OPTION_NAME;
|
||||
$current_timestamp = $this->get_timestamp();
|
||||
/**
|
||||
* Update the timestamp and use the current timestamp to make sure it
|
||||
* is only updated a single time.
|
||||
*/
|
||||
$result = $wpdb->update(
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
$wpdb->options,
|
||||
['option_name' => $option_name, 'option_value' => $timestamp],
|
||||
['option_name' => $option_name, 'option_value' => $current_timestamp]
|
||||
);
|
||||
if (false === $result) {
|
||||
return 0;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* Queries the database directly to get the timestamp.
|
||||
*
|
||||
* This avoids any filters being applied than are necessary.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string The timestamp of the last send.
|
||||
*/
|
||||
public function get_timestamp()
|
||||
{
|
||||
global $wpdb;
|
||||
$result = $wpdb->get_var(
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
$wpdb->prepare("SELECT option_value FROM {$wpdb->options} WHERE option_name = %s", self::OPTION_NAME)
|
||||
);
|
||||
if (is_null($result)) {
|
||||
return '';
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles all methods related to the Last Send option in the database.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Last_Send;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts\Abstract_Subscriber;
|
||||
/**
|
||||
* The subscriber for the Last_Send option.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Last_Send_Subscriber extends Abstract_Subscriber
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
add_action('init', [$this, 'initialize_last_send_option']);
|
||||
}
|
||||
/**
|
||||
* Initializes the option in the options table to track the last time data was sent to the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize_last_send_option()
|
||||
{
|
||||
$this->container->get(Last_Send::class)->initialize_option();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles all actions/filters related to the opt-in.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Opt_In;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Config;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts\Abstract_Subscriber;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Telemetry\Telemetry;
|
||||
/**
|
||||
* Class to handle all actions/filters related to the opt-in.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Opt_In_Subscriber extends Abstract_Subscriber
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
/**
|
||||
* Planned deprecation: 3.0.0
|
||||
*
|
||||
* Use stellarwp/telemetry/optin filter instead.
|
||||
*/
|
||||
add_action('stellarwp/telemetry/' . Config::get_stellar_slug() . '/optin', [$this, 'maybe_render_optin'], 10, 1);
|
||||
add_action('stellarwp/telemetry/optin', [$this, 'maybe_render_optin'], 10, 1);
|
||||
add_action('admin_init', [$this, 'set_optin_status']);
|
||||
add_action('init', [$this, 'initialize_optin_option']);
|
||||
}
|
||||
/**
|
||||
* Sets the opt-in status for the site.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.3.4 - Added user capability check.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_optin_status()
|
||||
{
|
||||
// We're not attempting an action.
|
||||
if (empty($_POST['_wpnonce'])) {
|
||||
return;
|
||||
}
|
||||
$nonce = sanitize_text_field($_POST['_wpnonce']);
|
||||
if (!wp_verify_nonce($nonce, 'stellarwp-telemetry')) {
|
||||
return;
|
||||
}
|
||||
// Check sent data before we do any database checks for faster failures.
|
||||
// We're not attempting a telemetry action.
|
||||
if (isset($_POST['action']) && 'stellarwp-telemetry' !== $_POST['action']) {
|
||||
return;
|
||||
}
|
||||
// The user did not respond to the opt-in modal.
|
||||
if (!isset($_POST['optin-agreed'])) {
|
||||
return;
|
||||
}
|
||||
// Sent data validated, check if the user has the necessary permissions.
|
||||
if (!current_user_can('manage_options')) {
|
||||
return;
|
||||
}
|
||||
$stellar_slug = Config::get_stellar_slug();
|
||||
if (isset($_POST['stellar_slug'])) {
|
||||
$stellar_slug = sanitize_text_field($_POST['stellar_slug']);
|
||||
}
|
||||
$opt_in_text = '';
|
||||
if (isset($_POST['opt_in_text'])) {
|
||||
$opt_in_text = sanitize_text_field($_POST['opt_in_text']);
|
||||
}
|
||||
// User agreed to opt-in to Telemetry.
|
||||
if ('true' === $_POST['optin-agreed']) {
|
||||
$this->opt_in($stellar_slug, $opt_in_text);
|
||||
}
|
||||
// Don't show the opt-in modal again.
|
||||
update_option($this->container->get(Opt_In_Template::class)->get_option_name($stellar_slug), '0');
|
||||
}
|
||||
/**
|
||||
* Renders the opt-in modal if it should be rendered.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Update to handle rendering multiple modals.
|
||||
*
|
||||
* @param string $stellar_slug The stellar slug to use in determining when and how the modal is displayed.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_render_optin(string $stellar_slug = '')
|
||||
{
|
||||
if ('' === $stellar_slug) {
|
||||
$stellar_slug = Config::get_stellar_slug();
|
||||
}
|
||||
$this->container->get(Opt_In_Template::class)->maybe_render($stellar_slug);
|
||||
}
|
||||
/**
|
||||
* Sets the initial value when the plugin is loaded.
|
||||
*
|
||||
* If the plugin doesn't already have the opt-in option set, we need to set it
|
||||
* so that the opt-in should be shown to the user when the do_action is run.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize_optin_option()
|
||||
{
|
||||
$opt_in_template = $this->container->get(Opt_In_Template::class);
|
||||
$opt_in_status = $this->container->get(Status::class);
|
||||
// Loop through all registered stellar slugs and add them to the optin option.
|
||||
foreach (Config::get_all_stellar_slugs() as $stellar_slug => $wp_slug) {
|
||||
// Check if plugin slug exists within array.
|
||||
if (!$opt_in_status->plugin_exists($stellar_slug)) {
|
||||
$opt_in_status->add_plugin($stellar_slug, false, $wp_slug);
|
||||
update_option($opt_in_template->get_option_name($stellar_slug), '1');
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Registers the site/user with the telemetry server and sets the opt-in status.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Updated to allow specifying the stellar slug.
|
||||
* @since 2.2.0 - Updated to add opt-in text.
|
||||
*
|
||||
* @param string $stellar_slug The slug to use when opting in.
|
||||
* @param string $opt_in_text The text displayed to the user when they agreed to opt-in.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function opt_in(string $stellar_slug, string $opt_in_text = '')
|
||||
{
|
||||
$this->container->get(Status::class)->set_status(true, $stellar_slug);
|
||||
try {
|
||||
$this->container->get(Telemetry::class)->register_site();
|
||||
$this->container->get(Telemetry::class)->register_user($stellar_slug, $opt_in_text);
|
||||
} catch (\Error $e) {
|
||||
// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
// We don't want to throw errors if the server cannot be reached.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles all methods related to rendering the Opt-In template.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Opt_In;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Admin\Resources;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Config;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts\Template_Interface;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Core;
|
||||
/**
|
||||
* Handles all methods related to rendering the Opt-In template.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Opt_In_Template implements Template_Interface
|
||||
{
|
||||
protected const YES = '1';
|
||||
protected const NO = '-1';
|
||||
/**
|
||||
* The opt-in status object.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @var Status
|
||||
*/
|
||||
protected $opt_in_status;
|
||||
/**
|
||||
* The Telemetry constructor
|
||||
*
|
||||
* @param Status $opt_in_status The opt-in status object.
|
||||
*/
|
||||
public function __construct(Status $opt_in_status)
|
||||
{
|
||||
$this->opt_in_status = $opt_in_status;
|
||||
}
|
||||
/**
|
||||
* Gets the arguments for configuring how the Opt-In modal is rendered.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Updated to handle passed in stellar slug
|
||||
*
|
||||
* @param string $stellar_slug The slug to use when configuring the modal args.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_args(string $stellar_slug)
|
||||
{
|
||||
$optin_args = ['plugin_logo' => Resources::get_asset_path() . 'resources/images/liquid-web-logo.svg', 'plugin_logo_width' => 148, 'plugin_logo_height' => 32, 'plugin_logo_alt' => 'Liquid Web Logo', 'plugin_name' => 'Liquid Web', 'plugin_slug' => $stellar_slug, 'user_name' => wp_get_current_user()->display_name, 'permissions_url' => '#', 'tos_url' => '#', 'privacy_url' => 'https://stellarwp.com/privacy-policy/', 'opted_in_plugins_text' => __('See which plugins you have opted in to tracking for', 'stellarwp-telemetry')];
|
||||
$optin_args['opted_in_plugins'] = $this->get_opted_in_plugin_names();
|
||||
$optin_args['heading'] = sprintf(
|
||||
// Translators: The plugin name.
|
||||
__('We hope you love %s.', 'stellarwp-telemetry'),
|
||||
$optin_args['plugin_name']
|
||||
);
|
||||
$optin_args['intro'] = $this->get_intro($optin_args['user_name'], $optin_args['plugin_name']);
|
||||
/**
|
||||
* Filters the arguments for rendering the Opt-In modal.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param array $optin_args
|
||||
* @param string $stellar_slug
|
||||
*/
|
||||
$optin_args = apply_filters('stellarwp/telemetry/optin_args', $optin_args, $stellar_slug);
|
||||
/**
|
||||
* Filters the arguments for rendering the Opt-In modal.
|
||||
*
|
||||
* Planned Deprecation: 3.0.0
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array $optin_args
|
||||
*/
|
||||
$optin_args = apply_filters('stellarwp/telemetry/' . $stellar_slug . '/optin_args', $optin_args);
|
||||
return $optin_args;
|
||||
}
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Update to handle passed in stellar slug.
|
||||
*
|
||||
* @param string $stellar_slug The slug to render the modal with.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render(string $stellar_slug)
|
||||
{
|
||||
load_template(dirname(dirname(__DIR__)) . '/views/optin.php', false, $this->get_args($stellar_slug));
|
||||
}
|
||||
/**
|
||||
* Gets the option that determines if the modal should be rendered.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Update to handle passed in stellar_slug.
|
||||
*
|
||||
* @param string $stellar_slug The current stellar slug to be used in the option name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_option_name(string $stellar_slug)
|
||||
{
|
||||
$option_name = sprintf('stellarwp_telemetry_%s_show_optin', $stellar_slug);
|
||||
/**
|
||||
* Filters the name of the option stored in the options table.
|
||||
* This filter can be used to apply a generic option name.
|
||||
* Usage of this filter is highly discouraged.
|
||||
*
|
||||
* @since 2.3
|
||||
*
|
||||
* @param string $option_name
|
||||
* @param string $stellar_slug The current stellar slug.
|
||||
*/
|
||||
$option_name = apply_filters('stellarwp/telemetry/show_optin_option_name', $option_name, $stellar_slug);
|
||||
/**
|
||||
* Filters the name of the option stored in the options table.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Update to pass stellar slug for checking the current filter context.
|
||||
*
|
||||
* @param string $option_name
|
||||
* @param string $stellar_slug The current stellar slug.
|
||||
*/
|
||||
return apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'show_optin_option_name', $option_name, $stellar_slug);
|
||||
}
|
||||
/**
|
||||
* Helper function to determine if the modal should be rendered.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - update to handle passed in stellar_slug.
|
||||
*
|
||||
* @param string $stellar_slug The stellar slug to get the option name for.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function should_render(string $stellar_slug)
|
||||
{
|
||||
return (bool) get_option($this->get_option_name($stellar_slug), false);
|
||||
}
|
||||
/**
|
||||
* Renders the modal if it should be rendered.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Add ability to render multiple modals.
|
||||
*
|
||||
* @param string $stellar_slug The stellar slug for which the modal should be rendered.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_render(string $stellar_slug)
|
||||
{
|
||||
if ($this->should_render($stellar_slug)) {
|
||||
$this->render($stellar_slug);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gets an array of opted-in plugin names.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_opted_in_plugin_names()
|
||||
{
|
||||
$option = Config::get_container()->get(Status::class)->get_option();
|
||||
$site_plugins_dir = Config::get_container()->get(Core::SITE_PLUGIN_DIR);
|
||||
$opted_in_plugins = [];
|
||||
foreach ($option['plugins'] as $plugin) {
|
||||
if (true !== $plugin['optin']) {
|
||||
continue;
|
||||
}
|
||||
$plugin_path = trailingslashit($site_plugins_dir) . $plugin['wp_slug'];
|
||||
if (!file_exists($plugin_path)) {
|
||||
continue;
|
||||
}
|
||||
$plugin_data = get_plugin_data($plugin_path);
|
||||
if (empty($plugin_data['Name'])) {
|
||||
continue;
|
||||
}
|
||||
$opted_in_plugins[] = $plugin_data['Name'];
|
||||
}
|
||||
return $opted_in_plugins;
|
||||
}
|
||||
/**
|
||||
* Gets the primary message displayed on the opt-in modal.
|
||||
*
|
||||
* @param string $user_name The display name of the user.
|
||||
* @param string $plugin_name The name of the plugin.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_intro($user_name, $plugin_name)
|
||||
{
|
||||
return sprintf(
|
||||
// Translators: The user name and the plugin name.
|
||||
esc_html__('Want to help shape the future of Liquid Web by Nexcess software products? Opting in shares anonymous usage data with our team at Liquid Web, giving us the insights we need to keep improving the tools you rely on.', 'stellarwp-telemetry'),
|
||||
$user_name,
|
||||
$plugin_name
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles the Opt-in status for the site.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Opt_In;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Config;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Core;
|
||||
/**
|
||||
* Class for handling the Opt-in status for the site.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Status
|
||||
{
|
||||
public const OPTION_NAME = 'stellarwp_telemetry';
|
||||
public const OPTION_NAME_USER_INFO = 'stellarwp_telemetry_user_info';
|
||||
public const STATUS_ACTIVE = 1;
|
||||
public const STATUS_INACTIVE = 2;
|
||||
/**
|
||||
* Gets the option name used to store the opt-in status.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_option_name()
|
||||
{
|
||||
/**
|
||||
* Filters the option name used to store the opt-in status.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $option_name
|
||||
*/
|
||||
return apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'option_name', self::OPTION_NAME);
|
||||
}
|
||||
/**
|
||||
* Gets the current opt-in status.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_option()
|
||||
{
|
||||
$option = get_option($this->get_option_name(), []);
|
||||
return is_array($option) ? $option : [];
|
||||
}
|
||||
/**
|
||||
* Gets the current Opt-in status.
|
||||
*
|
||||
* The status is stored as an integer because there are multiple possible statuses:
|
||||
* 1 = Active
|
||||
* 2 = Inactive
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.1 Correct logic so it is not subject to the order of the plugins.
|
||||
* @since 2.2.0 Update to remove unnecessary "mixed" status.
|
||||
*
|
||||
* @return integer The status value.
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$status = self::STATUS_INACTIVE;
|
||||
$option = $this->get_option();
|
||||
$plugins = $option['plugins'] ?? [];
|
||||
if (count($plugins) === 0) {
|
||||
$status = self::STATUS_INACTIVE;
|
||||
}
|
||||
foreach ($plugins as $plugin) {
|
||||
// If any plugins are missing an optin status or at least one is false, set status to false.
|
||||
if (!isset($plugin['optin']) || false === $plugin['optin']) {
|
||||
$status = self::STATUS_INACTIVE;
|
||||
break;
|
||||
}
|
||||
$status = self::STATUS_ACTIVE;
|
||||
}
|
||||
/**
|
||||
* Filters the opt-in status value.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param integer $status The opt-in status value.
|
||||
*/
|
||||
return apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'optin_status', $status);
|
||||
}
|
||||
/**
|
||||
* Gets the site auth token.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_token()
|
||||
{
|
||||
$option = $this->get_option();
|
||||
/**
|
||||
* Filters the site auth token.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $token The site's auth token.
|
||||
*/
|
||||
return apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'token', $option['token'] ?? '');
|
||||
}
|
||||
/**
|
||||
* Determines if the plugin slug exists in the opt-in option array.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $stellar_slug The plugin's unique slug.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function plugin_exists(string $stellar_slug)
|
||||
{
|
||||
$option = $this->get_option();
|
||||
$plugins = $option['plugins'] ?? [];
|
||||
return array_key_exists($stellar_slug, $plugins);
|
||||
}
|
||||
/**
|
||||
* Adds a plugin slug to the opt-in option array.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $stellar_slug The unique slug identifier for the plugin.
|
||||
* @param boolean $status The opt-in status for the plugin.
|
||||
* @param string $plugin_basename The specific basename for the plugin.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function add_plugin(string $stellar_slug, bool $status = false, string $plugin_basename = '')
|
||||
{
|
||||
$option = $this->get_option();
|
||||
if ('' === $plugin_basename) {
|
||||
$plugin_basename = Config::get_container()->get(Core::PLUGIN_BASENAME);
|
||||
}
|
||||
$option['plugins'][$stellar_slug] = ['wp_slug' => $plugin_basename, 'optin' => $status];
|
||||
return update_option($this->get_option_name(), $option);
|
||||
}
|
||||
/**
|
||||
* Removes a plugin slug from the opt-in option array.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $stellar_slug The slug to remove from the option.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove_plugin(string $stellar_slug)
|
||||
{
|
||||
$option = $this->get_option();
|
||||
// Bail early if the slug does not exist in the option.
|
||||
if (!isset($option['plugins'][$stellar_slug])) {
|
||||
return false;
|
||||
}
|
||||
unset($option['plugins'][$stellar_slug]);
|
||||
return update_option($this->get_option_name(), $option);
|
||||
}
|
||||
/**
|
||||
* Get an array of opted-in plugins.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return array<int, array<string, string>>
|
||||
*/
|
||||
public function get_opted_in_plugins()
|
||||
{
|
||||
$option = $this->get_option();
|
||||
$site_plugins_dir = Config::get_container()->get(Core::SITE_PLUGIN_DIR);
|
||||
$opted_in_plugins = [];
|
||||
// If the status option is not an option, return early.
|
||||
if (!isset($option['plugins'])) {
|
||||
return $opted_in_plugins;
|
||||
}
|
||||
foreach ($option['plugins'] as $stellar_slug => $plugin) {
|
||||
if (!isset($plugin['wp_slug'])) {
|
||||
continue;
|
||||
}
|
||||
$plugin_data = get_plugin_data(trailingslashit($site_plugins_dir) . $plugin['wp_slug']);
|
||||
if (isset($plugin['optin']) && true === $plugin['optin']) {
|
||||
$opted_in_plugins[] = ['slug' => $stellar_slug, 'version' => $plugin_data['Version']];
|
||||
}
|
||||
}
|
||||
return $opted_in_plugins;
|
||||
}
|
||||
/**
|
||||
* Sets the opt-in status option for the site.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Updated to allow defined stellar_slug.
|
||||
*
|
||||
* @param boolean $status The status to set.
|
||||
* @param string $stellar_slug The stellar_slug to set the status of.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function set_status(bool $status, string $stellar_slug = '')
|
||||
{
|
||||
// If no stellar slug is passed, use the singular value.
|
||||
if ('' === $stellar_slug) {
|
||||
$stellar_slug = Config::get_stellar_slug();
|
||||
}
|
||||
$option = $this->get_option();
|
||||
$option['plugins'][$stellar_slug]['optin'] = $status;
|
||||
return update_option($this->get_option_name(), $option);
|
||||
}
|
||||
/**
|
||||
* Gets the site's opt-in status label.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_status()
|
||||
{
|
||||
$optin_label = '';
|
||||
switch ($this->get()) {
|
||||
case 1:
|
||||
$optin_label = esc_html__('Active', 'stellarwp-telemetry');
|
||||
break;
|
||||
case 2:
|
||||
$optin_label = esc_html__('Inactive', 'stellarwp-telemetry');
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* Filters the opt-in status label.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $optin-Label
|
||||
*/
|
||||
return apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'optin_status_label', $optin_label);
|
||||
}
|
||||
/**
|
||||
* Determines if the opt-in status is active.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active(): bool
|
||||
{
|
||||
return $this->get() === self::STATUS_ACTIVE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,366 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles all methods required for sending data to the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Telemetry;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Config;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts\Data_Provider;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Opt_In\Opt_In_Template;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Opt_In\Status;
|
||||
/**
|
||||
* Handles all methods required for sending data to the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Telemetry
|
||||
{
|
||||
public const AJAX_ACTION = 'stellarwp_telemetry_send_data';
|
||||
/**
|
||||
* A data provider for gathering the data.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @var Data_Provider
|
||||
*/
|
||||
protected $provider;
|
||||
/**
|
||||
* The opt-in status object.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @var Status
|
||||
*/
|
||||
protected $opt_in_status;
|
||||
/**
|
||||
* The Telemetry constructor
|
||||
*
|
||||
* @param Data_Provider $provider The provider that collects the site data.
|
||||
* @param Status $opt_in_status The opt-in status object.
|
||||
*/
|
||||
public function __construct(Data_Provider $provider, Status $opt_in_status)
|
||||
{
|
||||
$this->provider = $provider;
|
||||
$this->opt_in_status = $opt_in_status;
|
||||
}
|
||||
/**
|
||||
* Registers the site with the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param bool $force Force the creation of the site on the server.
|
||||
*
|
||||
* @return bool True if the site was registered, false otherwise.
|
||||
*/
|
||||
public function register_site(bool $force = false)
|
||||
{
|
||||
// If site is already registered and we're not forcing a new registration, bail.
|
||||
if ($this->is_registered()) {
|
||||
if (false === $force) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$response = $this->send($this->get_register_site_data(), $this->get_register_site_url());
|
||||
return $this->save_token($response['token'] ?? '');
|
||||
}
|
||||
/**
|
||||
* Registers the user with the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Add support for setting the stellar slug.
|
||||
*
|
||||
* @param string $stellar_slug The slug to pass to the server when registering the site user.
|
||||
* @param string $opt_in_text The opt-in text displayed to the user when they agreed to share their data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_user(string $stellar_slug = '', string $opt_in_text = '')
|
||||
{
|
||||
if ('' === $stellar_slug) {
|
||||
$stellar_slug = Config::get_stellar_slug();
|
||||
}
|
||||
$user_details = $this->get_user_details($stellar_slug, $opt_in_text);
|
||||
try {
|
||||
// Store the user info in the options table.
|
||||
update_option(Status::OPTION_NAME_USER_INFO, $user_details, false);
|
||||
$this->send($user_details, Config::get_server_url() . '/opt-in', false);
|
||||
} catch (\Error $e) {
|
||||
// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
// We don't want to throw errors if the server fails.
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sends the uninstall message to the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $plugin_slug The plugin slug.
|
||||
* @param string $uninstall_reason_id The ID for the reason the plugin was deactivated.
|
||||
* @param string $uninstall_reason Why the user deactivated the plugin.
|
||||
* @param string $comment The additional comment from the text field shown with the uninstall reason.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function send_uninstall(string $plugin_slug, string $uninstall_reason_id, string $uninstall_reason, string $comment = '')
|
||||
{
|
||||
$this->send(['access_token' => $this->get_token(), 'plugin_slug' => $plugin_slug, 'uninstall_reason_id' => $uninstall_reason_id, 'uninstall_reason' => $uninstall_reason, 'comment' => $comment], $this->get_uninstall_url(), false);
|
||||
}
|
||||
/**
|
||||
* Saves the telemetry server's auth token for the site.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $token The site token to authenticate the request with.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save_token(string $token)
|
||||
{
|
||||
$option = array_merge($this->get_option(), ['token' => $token]);
|
||||
return update_option($this->opt_in_status->get_option_name(), $option);
|
||||
}
|
||||
/**
|
||||
* Determines if the current site is registered on the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_registered()
|
||||
{
|
||||
// Check if the site is registered by checking if the token is set.
|
||||
$option = $this->get_option();
|
||||
return !empty($option['token']);
|
||||
}
|
||||
/**
|
||||
* Sends data to the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function send_data()
|
||||
{
|
||||
if (!$this->is_registered()) {
|
||||
return false;
|
||||
}
|
||||
if (!$this->opt_in_status->is_active()) {
|
||||
return false;
|
||||
}
|
||||
$response = $this->send($this->get_send_data_args(), $this->get_send_data_url());
|
||||
return isset($response['status']);
|
||||
}
|
||||
/**
|
||||
* Gets the stored auth token for the current site.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_token()
|
||||
{
|
||||
$option = $this->get_option();
|
||||
return $option['token'] ?? '';
|
||||
}
|
||||
/**
|
||||
* Sends requests to the telemetry server and parses the response.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array $data The array of data to send.
|
||||
* @param string $url The url of the telemetry server.
|
||||
* @param bool $blocking Whether the request should be blocking or not.
|
||||
* @param float $timeout The timeout for the request, `0` for no timeout.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function send(array $data, string $url, bool $blocking = true, float $timeout = 5.0)
|
||||
{
|
||||
if (!$this->opt_in_status->is_active()) {
|
||||
return null;
|
||||
}
|
||||
$response = $this->request($url, $data, $blocking, $timeout);
|
||||
if (is_wp_error($response)) {
|
||||
return null;
|
||||
}
|
||||
$response = $this->parse_response($response);
|
||||
if (empty($response['status'])) {
|
||||
return null;
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
/**
|
||||
* Actually sends the request to the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $url The url of the telemetry server.
|
||||
* @param array $data The data to send.
|
||||
* @param bool $blocking Whether the request should be blocking or not.
|
||||
* @param float $timeout The timeout for the request, `0` for no timeout.
|
||||
*
|
||||
* @return array|\WP_Error
|
||||
*/
|
||||
protected function request(string $url, array $data, bool $blocking = true, float $timeout = 5.0)
|
||||
{
|
||||
return wp_remote_post($url, ['blocking' => $blocking, 'timeout' => $timeout, 'body' => $data]);
|
||||
}
|
||||
/**
|
||||
* Parses responses from wp_remote_requests.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array $response The response from a request.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
protected function parse_response(array $response)
|
||||
{
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
$data = json_decode($body, true);
|
||||
// If status is false, return null.
|
||||
if (false === ($data['status'] ?? false)) {
|
||||
return null;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
/**
|
||||
* Gets the registered site url.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_register_site_url()
|
||||
{
|
||||
/**
|
||||
* Filters the registered site url.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $site_url
|
||||
*/
|
||||
return apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'register_site_url', Config::get_server_url() . '/register-site');
|
||||
}
|
||||
/**
|
||||
* Gets the uninstall url.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_uninstall_url()
|
||||
{
|
||||
/**
|
||||
* Filters the uninstall url.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $uninstall_url
|
||||
*/
|
||||
return apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'uninstall_url', Config::get_server_url() . '/uninstall');
|
||||
}
|
||||
/**
|
||||
* Gets the registered site data.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_register_site_data()
|
||||
{
|
||||
/**
|
||||
* Filters the register site data.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array $register_site_data
|
||||
*/
|
||||
return apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'register_site_data', ['telemetry' => wp_json_encode($this->provider->get_data()), 'stellar_slugs' => wp_json_encode($this->opt_in_status->get_opted_in_plugins())]);
|
||||
}
|
||||
/**
|
||||
* Gets the current user's details.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Add support for passing stellar_slug directly.
|
||||
*
|
||||
* @param string $stellar_slug The plugin slug to pass to the server when registering a site user.
|
||||
* @param string $opt_in_text The opt-in text displayed to the user when they agreed to share their data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_user_details(string $stellar_slug = '', string $opt_in_text = '')
|
||||
{
|
||||
if ('' == $stellar_slug) {
|
||||
$stellar_slug = Config::get_stellar_slug();
|
||||
}
|
||||
$user = wp_get_current_user();
|
||||
$template = Config::get_container()->get(Opt_In_Template::class);
|
||||
$args = ['name' => $user->display_name, 'email' => $user->user_email, 'plugin_slug' => $stellar_slug, 'opt_in_text' => $opt_in_text];
|
||||
/**
|
||||
* Filters the site user details.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.0.0 - Add parameter for the current stellar_slug.
|
||||
*
|
||||
* @param array $site_user_details The details passed to the telemetry server for registering a new site user.
|
||||
* @param string $stellar_slug The current stellar slug passed with the user.
|
||||
*/
|
||||
$user_info = apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'register_site_user_details', $args, $stellar_slug);
|
||||
return ['user' => wp_json_encode($user_info)];
|
||||
}
|
||||
/**
|
||||
* Gets the telemetry option.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_option()
|
||||
{
|
||||
return get_option($this->opt_in_status->get_option_name(), []);
|
||||
}
|
||||
/**
|
||||
* Gets the args for sending data to the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 2.3.0 - Updated to include the opted in user with the telemetry json.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_send_data_args()
|
||||
{
|
||||
$opt_in_user = get_option(Status::OPTION_NAME_USER_INFO, []);
|
||||
$telemetry = $this->provider->get_data();
|
||||
if (count($opt_in_user) > 0) {
|
||||
$telemetry['opt_in_user'] = json_decode($opt_in_user['user'], true);
|
||||
}
|
||||
$args = ['token' => $this->get_token(), 'telemetry' => wp_json_encode($telemetry), 'stellar_slugs' => wp_json_encode($this->opt_in_status->get_opted_in_plugins())];
|
||||
return apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'send_data_args', $args);
|
||||
}
|
||||
/**
|
||||
* Gets the URL for sending data to the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_send_data_url()
|
||||
{
|
||||
/**
|
||||
* Filter the url for sending data to the telemetry server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $data_url
|
||||
*/
|
||||
return apply_filters('stellarwp/telemetry/' . Config::get_hook_prefix() . 'send_data_url', Config::get_server_url() . '/telemetry');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles hooking into the WordPress request lifecycle.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry\Telemetry;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Contracts\Abstract_Subscriber;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Last_Send\Last_Send;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Opt_In\Status;
|
||||
/**
|
||||
* Class Telemetry_Subscriber
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Telemetry_Subscriber extends Abstract_Subscriber
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
add_action('shutdown', [$this, 'send_async_request']);
|
||||
add_action('wp_ajax_' . Telemetry::AJAX_ACTION, [$this, 'send_telemetry_data'], 10, 1);
|
||||
add_action('wp_ajax_nopriv_' . Telemetry::AJAX_ACTION, [$this, 'send_telemetry_data'], 10, 1);
|
||||
}
|
||||
/**
|
||||
* Sends an async request during the 'shutdown' action.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function send_async_request()
|
||||
{
|
||||
if (!$this->container->get(Status::class)->is_active()) {
|
||||
return;
|
||||
}
|
||||
$last_send = $this->container->get(Last_Send::class);
|
||||
// Bail if last send timestamp is not expired.
|
||||
if (!$last_send->is_expired()) {
|
||||
return;
|
||||
}
|
||||
// The last send is expired, set a new timestamp.
|
||||
$timestamp = new DateTimeImmutable();
|
||||
$rows_affected = $last_send->set_new_timestamp($timestamp);
|
||||
// We weren't able to update the timestamp, another process may have updated it first.
|
||||
if (0 === $rows_affected) {
|
||||
return;
|
||||
}
|
||||
$url = admin_url('admin-ajax.php');
|
||||
wp_remote_post($url, ['blocking' => false, 'sslverify' => false, 'body' => ['action' => Telemetry::AJAX_ACTION]]);
|
||||
}
|
||||
/**
|
||||
* Sends telemetry data to the server.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function send_telemetry_data()
|
||||
{
|
||||
$this->container->get(Telemetry::class)->send_data();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Registers methods used for uninstalling the current instance of the library.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package StellarWP\Telemetry
|
||||
*/
|
||||
namespace KadenceWP\KadenceBlocks\StellarWP\Telemetry;
|
||||
|
||||
use KadenceWP\KadenceBlocks\StellarWP\Telemetry\Opt_In\Status;
|
||||
/**
|
||||
* Uninstall class used for uninstalling the current instance of the library.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @package \StellarWP\Telemetry
|
||||
*/
|
||||
class Uninstall
|
||||
{
|
||||
/**
|
||||
* Removes necessary items from the options table.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $stellar_slug The slug for the plugin being deleted.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function run($stellar_slug)
|
||||
{
|
||||
$opt_in_status = new Status();
|
||||
if ($opt_in_status->plugin_exists($stellar_slug)) {
|
||||
$opt_in_status->remove_plugin($stellar_slug);
|
||||
}
|
||||
$optin_option_name = 'stellarwp_telemetry_' . $stellar_slug . '_show_optin';
|
||||
if (get_option($optin_option_name) !== false) {
|
||||
delete_option($optin_option_name);
|
||||
}
|
||||
// If this is the last plugin in the optin option, let's remove the option entirely.
|
||||
self::maybe_remove_optin_option();
|
||||
}
|
||||
/**
|
||||
* Removes the main telemetry option if the current plugin is the last one to use it.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function maybe_remove_optin_option()
|
||||
{
|
||||
$optin = get_option('stellarwp_telemetry');
|
||||
// Bail if option is not set or has more than 'token' in the array.
|
||||
if (false === $optin || count($optin) > 1) {
|
||||
return;
|
||||
}
|
||||
// All plugins have been removed, the token should be the only item in the array.
|
||||
if (array_key_exists('token', $optin)) {
|
||||
delete_option('stellarwp_telemetry');
|
||||
delete_option('stellarwp_telemetry_last_send');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
.stellarwp-telemetry {
|
||||
font-family: 'SF Pro Text', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 18px;
|
||||
color: #4E4E4E;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry__title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
letter-spacing: -0.02em;
|
||||
color: #000;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry__intro {
|
||||
font-size: 12px;
|
||||
letter-spacing: -0.01em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-uninstall-reasons {
|
||||
text-align: left;
|
||||
width: 85%;
|
||||
margin: 1rem auto;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-uninstall-reasons__item {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 18px;
|
||||
letter-spacing: -0.01em;
|
||||
text-align: left;
|
||||
margin-bottom: 0.85rem;
|
||||
display: flex;
|
||||
padding: 0 1rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-uninstall-reasons__item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-uninstall-reasons__item input[type="radio"] {
|
||||
margin-top: 1px;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-uninstall-reasons__item label {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-uninstall-reasons__item textarea {
|
||||
width: 100%;
|
||||
height: 55px;
|
||||
border: 1px solid #DFDFDF;
|
||||
border-radius: 4px;
|
||||
padding: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-uninstall-reasons__item--active {
|
||||
background: rgb(238 238 238 / 45%);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-uninstall-reasons__item--active textarea {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-btn-primary,
|
||||
.stellarwp-telemetry-btn-grey,
|
||||
.stellarwp-telemetry-btn-text {
|
||||
padding: 8px 12px;
|
||||
background: #1145C9;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
border: 0;
|
||||
outline: none;
|
||||
transition: all 0.1s ease-in-out;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-btn-primary:hover {
|
||||
background: #0E38A3;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-btn-primary:disabled,
|
||||
.stellarwp-telemetry-btn-primary.disabled {
|
||||
background: rgba(17, 69, 201, 0.5);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-btn-grey {
|
||||
background: #eee;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-btn-grey:hover {
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-btn-text {
|
||||
background: transparent;
|
||||
color: #1145C9;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-btn-text--skip {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-btn-text:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-modal {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 999999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
transition: all 0.3s ease-in-out;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-modal--exit-interview {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-modal--active {
|
||||
visibility: visible;
|
||||
pointer-events: all;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-modal__inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 32px;
|
||||
width: 90%;
|
||||
margin-top: 47px;
|
||||
background: #fff;
|
||||
box-shadow: 0 0 32px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-modal--exit-interview .stellarwp-telemetry-modal__inner {
|
||||
max-width: 585px;
|
||||
text-align: center;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-plugin-logo {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-links {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-links__link {
|
||||
color: #1145C9;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-links__link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-error-message {
|
||||
display: none;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-other-plugins {
|
||||
margin-bottom: 22px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-other-plugins .stellarwp-telemetry-btn-text:after {
|
||||
content: "\f347";
|
||||
font-family: "dashicons";
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-other-plugins__list {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.stellarwp-telemetry-other-plugins__list ul {
|
||||
list-style: disc inside;
|
||||
flex-direction: column;
|
||||
margin: 0.5rem 0 0;
|
||||
display: flex;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<svg width="768" height="166" viewBox="0 0 768 166" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M147.905 29.7388C159.78 28.0154 170.485 31.0174 178.996 39.5397C179.073 37.7808 178.446 32.8691 179.585 31.725C182.327 30.6024 193.623 30.2733 195.614 32.6148C196.219 36.3272 196.015 43.8606 196.014 47.9237L196.002 114.996C196.012 121.081 196.679 136.203 195.26 141.341C189.822 141.366 183.995 141.49 178.597 141.234C178.271 137.963 178.437 131.841 178.442 128.341C178.384 120.164 178.401 111.987 178.492 103.81C172.444 109.275 166.192 112.032 158.116 112.839C135.2 115.128 119.63 101.446 117.249 78.8933C114.913 56.7606 122.945 32.4655 147.905 29.7388ZM158.513 98.3558C174.437 96.936 179.874 82.183 178.718 68.0329C177.559 53.83 169.85 43.3634 154.68 44.3399C148.414 45.1451 144.14 46.8355 140.123 51.9298C128.117 67.1542 134.332 101.327 158.513 98.3558Z" fill="#1A1D20"/>
|
||||
<path d="M637.93 29.3902C661.749 28.7742 675.811 43.5098 675.864 67.0724C675.871 69.4253 676.43 73.9013 674.833 75.7445C670.773 76.8871 624.412 76.1897 617.671 75.9431C618.159 80.2835 619.103 84.2398 620.933 88.2354C625.952 99.1948 639.909 101.302 649.993 96.4747C655.95 93.6223 657.06 89.3393 659.047 83.5589C661.27 83.3993 664.426 83.4791 666.72 83.4716C668.872 83.4484 671.23 83.3431 673.341 83.6784C673.952 84.3454 674.154 84.7157 674.139 85.6926C673.746 116.781 624.018 121.663 608.742 99.6096C603.471 92.714 601.165 84.9319 600.749 76.2028C599.445 49.0538 609.476 31.2848 637.93 29.3902ZM639.354 62.3866L659.11 62.3889C658.102 56.3199 656.794 51.1638 651.512 47.1955C648.329 44.8026 642.147 43.1628 638.26 43.5986C625.274 44.963 621.304 50.3428 618.226 62.3173C625.27 62.3963 632.31 62.4192 639.354 62.3866Z" fill="#1A1D20"/>
|
||||
<path d="M269.439 30.8958C271.584 31.0549 273.729 30.9866 275.878 30.9981C277.558 31.0071 281.539 30.8441 282.747 32.1224C283.565 32.9873 283.277 103.895 283.058 111.17C279.332 111.45 270.096 111.33 266.406 111.159C266.104 108.698 266.195 105.629 266.203 103.1C256.773 116.267 231.003 116.052 219.947 105.095C210.548 95.7804 212.767 79.8612 212.805 67.6368C212.801 58.8673 212.454 41.5385 213.202 32.2878C213.238 31.9005 214.504 31.3614 214.799 31.3222C216.637 31.0785 229.008 30.3263 229.662 32.2795C230.076 33.5172 229.937 39.6199 229.932 41.456L229.889 67.6773C229.88 74.4739 229.341 83.4709 230.925 89.9352C232.949 98.1936 244.513 99.8041 251.445 97.7705C267.951 92.9276 265.929 77.5706 265.952 63.9174L265.98 40.2734C265.969 38.4864 265.495 33.2966 266.245 31.9676C267.192 31.1405 268.195 31.0961 269.439 30.8958Z" fill="#1A1D20"/>
|
||||
<path d="M99.6171 31.291C100.87 31.2972 102.021 31.1951 103.129 31.7734C104.882 34.1215 103.225 99.9745 103.808 107.848C103.834 108.208 103.721 110.504 103.694 111.068C100.556 111.433 94.0536 111.28 90.6399 111.282C89.0077 111.332 87.7481 111.505 86.5912 110.456C86.0627 107.228 86.2527 99.8831 86.2523 96.3049L86.2681 46.0219C86.2707 42.2886 86.0627 34.8555 86.6628 31.5379C90.2096 31.1885 95.9332 31.3039 99.6171 31.291Z" fill="#1A1D20"/>
|
||||
<path d="M304.241 30.8419C309.224 31.2487 313.49 30.6099 318.381 31.7946C318.865 48.0911 318.417 66.7929 318.421 83.2591L318.426 100.347C318.431 103.174 318.604 107.981 318.173 110.63C317.162 111.405 316.882 111.165 315.367 111.274L305.71 111.289C304.496 111.28 302.025 111.357 301.181 110.5C300.762 107.461 300.951 102.949 300.953 99.7504L301.006 45.1701C301.016 42.5059 300.532 33.8863 301.415 32.0955C302.28 31.1196 302.96 31.0931 304.241 30.8419Z" fill="#1A1D20"/>
|
||||
<path d="M708.096 138.136C708.047 139.572 708.104 141.291 708.111 142.752C702.758 142.694 697.405 142.693 692.051 142.749C692.036 144.826 692.104 147.023 692.134 149.112C696.722 148.886 701.318 148.81 705.911 148.886L706.195 153.742L693.806 153.71C693.06 153.661 692.94 153.644 692.25 153.918C691.583 155.426 692.002 158.782 692.111 160.573C697.491 160.635 702.87 160.65 708.25 160.619L708.137 165.755C701.671 165.162 692.411 165.479 685.72 165.606C685.427 157.018 685.678 146.919 685.738 138.238C692.674 137.979 701.052 138.158 708.096 138.136Z" fill="#1A1D20"/>
|
||||
<path d="M645.895 138.114L651.822 138.192C649.547 142.442 645.715 147.169 643.005 151.439C644.703 154.81 651.852 162.461 651.755 165.427L651.196 165.507C649.404 165.577 647.691 165.499 645.903 165.435C644.291 163.463 640.01 156.344 637.873 156.12C635.942 156.668 631.894 163.482 630.098 165.73C628.074 165.547 625.974 165.621 623.939 165.648C626.694 160.36 630.233 156.38 633.599 151.464C630.248 146.668 627.474 143.335 624.16 138.243C626.342 138.138 628.741 138.186 630.945 138.19C633.569 141.222 635.343 144.705 638.342 147.785C640.688 145.248 643.852 140.927 645.895 138.114Z" fill="#1A1D20"/>
|
||||
<path d="M303.508 1.63389C308.099 1.65205 313.988 1.5316 318.429 2.05881C318.693 5.21812 319.114 17.7862 318.093 20.9829C317.953 21.4208 317.065 21.444 316.489 21.5443C311.548 21.4913 305.539 21.7163 300.719 21.3349C300.612 17.8016 300.489 5.30599 301.154 2.55348C302.06 1.63565 302.022 1.88457 303.508 1.63389Z" fill="#1A1D20"/>
|
||||
<path d="M89.0135 1.66479C91.7089 1.64869 101.236 1.32171 103.121 2.23826C104.497 4.86862 103.775 12.7488 103.919 16.0036C104.003 17.9045 104.325 21.3456 102.025 21.4806C96.7757 21.4938 91.5263 21.4765 86.2769 21.4285C86.2289 17.7544 85.8656 5.43745 86.4321 2.61346C87.5057 1.64686 87.3588 1.92519 89.0135 1.66479Z" fill="#1A1D20"/>
|
||||
<path d="M460.892 0H477.601C479.359 4.5439 481.856 17.6537 483.119 23.1073L493.289 65.7828C494.384 70.5747 496.521 81.8166 498.433 85.5586L513.986 28.7132C515.4 23.4655 520.449 3.31865 522.245 0H539.688C541.716 5.44057 542.976 12.1433 544.734 17.7895C549.997 34.7048 553.862 52.1266 559.159 69.0369C560.692 73.9247 562.053 81.289 563.661 85.7471C564.726 82.5807 565.206 79.4488 565.952 76.2187C570.349 57.1598 575.137 38.1875 579.331 19.071C580.737 12.6608 582.705 6.40063 584.055 0H600.471C600.936 2.29068 600.876 4.00195 600.418 6.27075C597.524 20.5493 593.487 34.701 590.083 48.828L579.549 91.6758C577.941 98.1562 576.617 104.87 574.747 111.259C571.272 111.277 557.322 111.579 554.814 110.94C553.442 109.653 540.959 63.7848 539.324 57.9153C537.428 51.1066 532.329 33.8955 530.781 26.734C528.071 34.5791 526.376 43.9836 523.891 52.0936C517.874 71.7375 513.087 91.6672 506.92 111.279L487.014 111.271C485.076 105.987 483.595 99.0499 482.257 93.4977L475.119 63.5076L464.611 20.7065C463.13 14.4613 460.15 6.21095 460.892 0Z" fill="#1A1D20"/>
|
||||
<path d="M689.569 0H706.056C706.589 4.07899 706.413 11.9197 706.379 16.3151C706.323 23.8653 706.48 31.8369 706.27 39.3521C716.894 26.4472 742.086 27.0218 754.532 37.32C760.103 41.9099 764.05 48.1719 765.786 55.1783C766.307 57.2048 767.06 61.0546 767.75 62.8214V79.7036C766.813 82.4477 766.326 85.5578 765.508 88.3345C760.106 106.727 744.504 115.156 725.932 112.772C717.243 111.655 711.578 109.788 706.049 102.884C706.158 105.999 706.199 108.073 705.959 111.167C703.26 111.38 691.552 111.677 689.607 110.629C688.512 104.925 688.456 4.60348 689.569 0ZM729.977 98.4537C735.556 97.8553 741.006 95.945 744.429 91.3109C756.504 74.9709 751.582 43.2556 726.735 44.3422C721.408 44.9875 714.619 47.3606 711.627 52.0007C700.613 69.0882 704.898 99.5835 729.977 98.4537Z" fill="#1A1D20"/>
|
||||
<path d="M393.583 0H409.954C410.419 3.00719 410.235 10.997 410.228 14.419L410.205 41.2141L410.232 86.1956C410.235 93.7533 410.528 103.791 410.059 111.197C405.523 111.498 398.224 111.483 393.696 111.203C393.46 108.323 393.546 105.824 393.621 102.953C393.111 103.597 392.575 104.215 392.005 104.806C386.637 110.352 376.523 112.953 369.06 113.046C344.105 113.354 332.071 96.4363 331.551 72.9272C331.042 49.9255 341.77 30.0805 366.817 29.4508C377.336 29.1948 385.415 31.5472 393.227 39.1187C393.126 32.6397 392.076 4.97745 393.583 0ZM374.004 98.2817C401.512 95.0655 400.691 41.7608 368.987 44.3464C339.686 47.7023 342.721 102.128 373.846 98.302L374.004 98.2817Z" fill="#1A1D20"/>
|
||||
<path d="M0 0H17.1678C18.1063 8.0015 17.4711 22.9476 17.5483 31.6547C17.7376 53.0252 17.3254 74.5752 17.6126 95.9562C24.5968 95.9952 73.6429 95.3237 75.0239 96.6922C76.4687 98.1236 76.2007 101.486 76.1868 103.394C76.1707 105.63 76.5778 109.296 75.0577 111.03C71.8982 111.447 65.1796 111.26 61.646 111.261L13.0714 111.264C9.84002 111.262 2.85971 111.425 0 110.998V0Z" fill="#1A1D20"/>
|
||||
<path d="M510.877 137.687C517.153 137.611 524.032 136.737 529.231 140.464C531.608 145.762 531.503 147.775 527.001 151.627C531.068 153.087 533.021 156.024 531.574 160.467C530.404 164.053 528.08 165.029 524.748 166H510.783C510.476 162.674 510.528 140.744 510.877 137.687ZM515.143 161.507C518.806 161.56 522.682 161.946 526.056 160.355C531.263 152.841 519.016 153.602 515.121 153.672L515.143 161.507ZM515.139 149.516C518.645 149.6 522.42 150.122 525.302 148.1C529.745 141.626 518.525 142.26 515.124 142.302L515.139 149.516Z" fill="#1A1D20"/>
|
||||
<path d="M588.296 138.211L594.054 138.053C594.133 142.489 594.759 163.069 593.458 166H593.155C590.635 165.459 588.585 165.613 586.024 165.686C581.129 158.113 577.721 151.59 573.256 144.258C573.136 148.447 573.751 162.972 572.937 166H572.364C570.774 165.456 569.421 165.576 567.76 165.611C567.517 157.161 567.468 146.655 567.734 138.211C570.257 138.177 573.361 138.052 575.839 138.174C577.32 140.542 587.205 157.198 588.364 157.58C588.806 154.926 588.337 141.643 588.296 138.211Z" fill="#1A1D20"/>
|
||||
<path d="M745.265 138.578C753.962 136.408 765.463 135.943 765.25 148.011L759.578 147.981C759.372 145.689 759.668 145.609 758.119 143.779C755.735 140.962 746.509 141.919 746.937 145.845C748.856 148.809 758.854 150.025 763.968 152.583C768.642 160.08 764.714 163.776 757.46 166H748.882C746.3 165.109 745.029 164.726 742.738 163.164C740.834 159.715 740.748 159.06 740.751 155.103L745.816 155.023C746.333 156.71 746.847 158.453 747.387 160.127C750.881 161.099 758.262 162.561 759.956 158.187C759.139 152.815 741.681 155.31 740.886 147.388C740.481 143.381 742.802 140.898 745.265 138.578Z" fill="#1A1D20"/>
|
||||
<path d="M717.415 155.352C718.018 160.668 720.965 161.629 726.322 161.37C728.309 161.274 730.925 160.173 731.308 157.947C729.876 152.788 714.191 155.62 712.425 148.169C711.192 142.966 714.419 139.521 719.094 138.122C725.186 135.97 737.77 138.537 736.597 146.916C735.375 148.726 733.148 148.059 731.026 147.958L730.412 143.958C726.595 142.473 720.89 141.008 718.119 145.091C717.25 151.117 744.286 147.228 735.101 163.303C732.646 164.72 731.727 165.092 729.032 166H720.219C716.2 164.601 715.285 164.505 712.455 161.404C712.088 159.003 711.859 157.606 711.885 155.187L717.415 155.352Z" fill="#1A1D20"/>
|
||||
<path d="M663.29 166C652.599 162.185 654.203 157.107 654.263 147.251C654.338 135.143 676.25 134.658 680.25 144.06C680.864 145.502 680.928 147.412 680.999 149.008C679.114 148.973 676.887 148.984 675.031 148.871C674.619 146.742 674.458 145.144 672.456 143.932C668.362 141.452 663.732 142.531 660.467 145.69C658.495 155.665 659.35 162.217 671.369 160.248C673.787 158.258 674.255 157.768 675.125 154.646L681.033 154.724C680.291 162.366 678.356 163.653 671.342 166H663.29Z" fill="#1A1D20"/>
|
||||
<path d="M621.228 138.16L621.269 142.746L604.669 142.684L604.621 149.093C609.629 148.869 614.296 148.844 619.312 148.855L619.428 153.839C614.51 153.698 609.592 153.653 604.669 153.706L604.643 160.622L621.52 160.664C621.487 162.313 621.629 164.639 620.827 166H620.508C617.981 165.013 602.735 165.474 599.181 165.668C598.975 156.507 599.2 147.348 599.091 138.209L621.228 138.16Z" fill="#1A1D20"/>
|
||||
<path d="M531.491 137.924C533.181 137.794 535.157 137.591 536.829 137.596C538.568 140.576 542.036 147.15 543.746 149.562C546.205 146.007 548.645 141.464 550.808 137.637L555.779 137.777C549.987 152.158 545.894 147.509 546.208 166H541.665C541.579 161.255 541.972 155.96 539.641 151.656C537.129 147.026 534.362 142.344 531.491 137.924Z" fill="#1A1D20"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,122 @@
|
||||
(function ( $ ) {
|
||||
|
||||
let $body = $('body');
|
||||
|
||||
/**
|
||||
* jQuery code to handle the opt-in modal.
|
||||
*/
|
||||
$body.find('[data-js="optin-modal"]').each(function () {
|
||||
let $optin = $(this);
|
||||
let $other_plugins = $optin.find('[data-js="other-plugins-toggle"]');
|
||||
|
||||
if ( $other_plugins.length ) {
|
||||
$other_plugins.click(function (e) {
|
||||
let $this = $(this).closest('.stellarwp-telemetry-other-plugins');
|
||||
$this.find('.stellarwp-telemetry-other-plugins__list').slideToggle();
|
||||
});
|
||||
}
|
||||
|
||||
// Disabling the submit button to prevent multiple submissions.
|
||||
$optin.find('[data-js="optin-form"]').submit(function () {
|
||||
$(this).find('[data-js="form-submit"]').addClass('disabled');
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* jQuery code to handle the exit interview modal.
|
||||
*/
|
||||
$body.find('[data-js="exit-interview-modal"]').each( function () {
|
||||
let $exitInterview = $(this);
|
||||
let pluginSlug = $exitInterview.data('plugin-slug');
|
||||
let redirectLink = null;
|
||||
|
||||
// Deactivate Button
|
||||
$body.on( 'click', '#the-list .deactivate > a', function ( e ) {
|
||||
if ( 0 === $( this ).next( '[data-plugin-slug].telemetry-plugin-slug' ).length ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( $( this ).next( '[data-plugin-slug].telemetry-plugin-slug' ).data( 'plugin-slug' ) !== pluginSlug ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
redirectLink = $(this).attr('href');
|
||||
$exitInterview.addClass('stellarwp-telemetry-modal--active');
|
||||
|
||||
// Skip Button
|
||||
$exitInterview.on( 'click', '[data-js="skip-interview"]', function ( e ) {
|
||||
e.preventDefault();
|
||||
$exitInterview.removeClass('stellarwp-telemetry-modal--active');
|
||||
window.location.href = redirectLink;
|
||||
});
|
||||
|
||||
// Answer Click
|
||||
$exitInterview.on( 'change', '[name="uninstall_reason"]', function () {
|
||||
let $this = $(this);
|
||||
let $wrapper = $this.closest('li');
|
||||
let $reason = $wrapper.find('[name="comment"]');
|
||||
|
||||
$exitInterview.find('.stellarwp-telemetry-uninstall-reasons__item--active').removeClass('stellarwp-telemetry-uninstall-reasons__item--active');
|
||||
$exitInterview.find('.stellarwp-telemetry-uninstall-reasons__item [name="comment"]').val('');
|
||||
$exitInterview.find('.stellarwp-telemetry-error-message').hide();
|
||||
|
||||
if ( ! $reason.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wrapper.addClass('stellarwp-telemetry-uninstall-reasons__item--active');
|
||||
});
|
||||
|
||||
// Submit Button
|
||||
$exitInterview.on( 'click', '[data-js="submit-telemetry"]', function ( e ) {
|
||||
e.preventDefault();
|
||||
this.disabled = true;
|
||||
|
||||
let $form = $('[data-js="exit-interview-form"]');
|
||||
|
||||
let data = {
|
||||
action: stellarwpTelemetry.exit_interview.action,
|
||||
nonce: stellarwpTelemetry.exit_interview.nonce,
|
||||
plugin_slug: pluginSlug,
|
||||
};
|
||||
|
||||
// Get uninstall_reason value
|
||||
let $reason = $form.find('[name="uninstall_reason"]:checked');
|
||||
|
||||
if ( ! $reason.length ) {
|
||||
$exitInterview.find('.stellarwp-telemetry-error-message').show();
|
||||
this.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
data['uninstall_reason_id'] = $reason.data('uninstall-reason-id');
|
||||
data['uninstall_reason'] = $reason.val();
|
||||
|
||||
// Get comment value if exists
|
||||
let $comment = $reason.closest('li').find('[name="comment"]');
|
||||
|
||||
if ( $comment.length ) {
|
||||
if ( ! $comment.val() ) {
|
||||
$exitInterview.find('.stellarwp-telemetry-error-message').show();
|
||||
this.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
data['comment'] = $comment.val();
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: data,
|
||||
}).done(function () {
|
||||
// Redirect to the plugin page.
|
||||
window.location.href = redirectLink;
|
||||
});
|
||||
} );
|
||||
});
|
||||
});
|
||||
|
||||
}( jQuery ));
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* $args comes from load_template() in OptinTemplate.php
|
||||
*
|
||||
* @var array $args
|
||||
*/
|
||||
|
||||
?>
|
||||
<div id="exit-interview-<?php echo esc_attr( $args['plugin_slug'] ); ?>" class="stellarwp-telemetry stellarwp-telemetry-modal stellarwp-telemetry-modal--exit-interview" data-js="exit-interview-modal" data-plugin-slug="<?php echo esc_attr( $args['plugin_slug'] ); ?>">
|
||||
<div class="stellarwp-telemetry-modal__inner">
|
||||
<img src="<?php echo esc_url( $args['plugin_logo'] ); ?>" width="<?php echo esc_attr( $args['plugin_logo_width'] ); ?>" height="<?php echo esc_attr( $args['plugin_logo_height'] ); ?>" alt="<?php echo esc_attr( $args['plugin_logo_alt'] ); ?>" class="stellarwp-telemetry-plugin-logo">
|
||||
<h1 class="stellarwp-telemetry__title">
|
||||
<?php echo esc_attr( $args['heading'] ); ?>
|
||||
</h1>
|
||||
<div class="stellarwp-telemetry__intro">
|
||||
<?php echo esc_attr( $args['intro'] ); ?>
|
||||
</div>
|
||||
<form method="get" data-js="exit-interview-form">
|
||||
<ul class="stellarwp-telemetry-uninstall-reasons">
|
||||
<?php foreach ( $args['uninstall_reasons'] as $key => $item ) : ?>
|
||||
<li class="stellarwp-telemetry-uninstall-reasons__item">
|
||||
<input type="radio" name="uninstall_reason" id="reason-<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $item['uninstall_reason'] ); ?>" data-uninstall-reason-id="<?php echo esc_attr( $item['uninstall_reason_id'] ); ?>">
|
||||
<label for="reason-<?php echo esc_attr( $key ); ?>">
|
||||
<?php echo esc_attr( $item['uninstall_reason'] ); ?>
|
||||
<?php if ( isset( $item['show_comment'] ) && $item['show_comment'] ) { ?>
|
||||
<textarea name="comment" placeholder="<?php echo esc_attr__( 'Tell us more...', 'stellarwp-telemetry' ); ?>"></textarea>
|
||||
<?php } ?>
|
||||
</label>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<div class="error-message stellarwp-telemetry-error-message">
|
||||
<?php echo esc_html__( 'Please select a reason', 'stellarwp-telemetry' ); ?>
|
||||
</div>
|
||||
<footer>
|
||||
<button data-js="skip-interview" class="stellarwp-telemetry-btn-grey" type="button">
|
||||
<?php echo esc_html__( 'Skip', 'stellarwp-telemetry' ); ?>
|
||||
</button>
|
||||
<button data-js="submit-telemetry" class="stellarwp-telemetry-btn-primary" type="submit" name="deactivate" value="true">
|
||||
<?php echo esc_html__( 'Deactivate', 'stellarwp-telemetry' ); ?>
|
||||
</button>
|
||||
</footer>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
70
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/telemetry/src/views/optin.php
vendored
Normal file
70
wp-content/plugins/kadence-blocks/vendor/vendor-prefixed/stellarwp/telemetry/src/views/optin.php
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* $args comes from load_template() in OptinTemplate.php
|
||||
*
|
||||
* @var array $args
|
||||
*/
|
||||
|
||||
?>
|
||||
<div id="optin-modal-<?php echo esc_attr( $args['plugin_slug'] ); ?>" class="stellarwp-telemetry stellarwp-telemetry-modal stellarwp-telemetry-modal--active" data-js="optin-modal">
|
||||
<section class="stellarwp-telemetry-modal__inner">
|
||||
<header>
|
||||
<img src="<?php echo esc_url( $args['plugin_logo'] ); ?>" width="<?php echo esc_attr( $args['plugin_logo_width'] ); ?>" height="<?php echo esc_attr( $args['plugin_logo_height'] ); ?>" alt="<?php echo esc_attr( $args['plugin_logo_alt'] ); ?>"/>
|
||||
<h1 class="stellarwp-telemetry__title">
|
||||
<?php echo esc_attr( $args['heading'] ); ?>
|
||||
</h1>
|
||||
</header>
|
||||
<main>
|
||||
<p>
|
||||
<?php echo esc_attr( $args['intro'] ); ?>
|
||||
</p>
|
||||
<ul class="stellarwp-telemetry-links">
|
||||
<li>
|
||||
<a href="<?php echo esc_url( $args['permissions_url'] ); ?>" target="_blank" class="stellarwp-telemetry-links__link">
|
||||
<?php echo esc_html__( 'What permissions are being granted?', 'stellarwp-telemetry' ); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="<?php echo esc_url( $args['tos_url'] ); ?>" target="_blank" class="stellarwp-telemetry-links__link">
|
||||
<?php echo esc_html__( 'Terms of Service', 'stellarwp-telemetry' ); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="<?php echo esc_url( $args['privacy_url'] ); ?>" target="_blank" class="stellarwp-telemetry-links__link">
|
||||
<?php echo esc_html__( 'Privacy Policy', 'stellarwp-telemetry' ); ?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<?php if ( $args['opted_in_plugins'] ) { ?>
|
||||
<div class="stellarwp-telemetry-other-plugins">
|
||||
<button class="stellarwp-telemetry-btn-text" data-js="other-plugins-toggle">
|
||||
<?php echo esc_html__( 'Other plugins you have opted in:', 'stellarwp-telemetry' ); ?>
|
||||
</button>
|
||||
<div class="stellarwp-telemetry-other-plugins__list">
|
||||
<ul>
|
||||
<?php foreach ( $args['opted_in_plugins'] as $opted_in_plugin ) { ?>
|
||||
<li>
|
||||
<?php echo esc_attr( $opted_in_plugin ); ?>
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</main>
|
||||
<footer>
|
||||
<form method="post" action="" data-js="optin-form">
|
||||
<input type="hidden" name="action" value="stellarwp-telemetry">
|
||||
<input type="hidden" name="stellar_slug" value="<?php echo esc_attr( $args['plugin_slug'] ); ?>">
|
||||
<input type="hidden" name="opt_in_text" value="<?php echo esc_attr( $args['intro'] ); ?>">
|
||||
<?php wp_nonce_field( 'stellarwp-telemetry' ); ?>
|
||||
<button class="stellarwp-telemetry-btn-primary" data-js="form-submit" type="submit" name="optin-agreed" value="true">
|
||||
<?php echo esc_html__( 'Allow & Continue', 'stellarwp-telemetry' ); ?>
|
||||
</button>
|
||||
<button data-js="close-modal" class="stellarwp-telemetry-btn-text stellarwp-telemetry-btn-text--skip" type="submit" name="optin-agreed" value="false">
|
||||
<?php echo esc_html__( 'Skip', 'stellarwp-telemetry' ); ?>
|
||||
</button>
|
||||
</form>
|
||||
</footer>
|
||||
</section>
|
||||
</div>
|
||||
Reference in New Issue
Block a user