Initial commit.
80
.gitignore
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
|
||||
# Ignore Git files
|
||||
git-filter-repo/
|
||||
|
||||
# Ignore compiled files
|
||||
*.class
|
||||
*.o
|
||||
*.pyc
|
||||
.VSCodeCounter/
|
||||
__pycache__/
|
||||
|
||||
# Ignore logs and databases
|
||||
*.log
|
||||
*.log.*
|
||||
|
||||
# Ignore logs and databases
|
||||
# *.sql
|
||||
# *.sqlite
|
||||
|
||||
# Ignore OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# Ignore IDE and editor files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*.sublime-workspace
|
||||
|
||||
# Ignore package management directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
bower_components/
|
||||
|
||||
# Ignore build directories
|
||||
build/
|
||||
dist/
|
||||
out/
|
||||
|
||||
# Ignore environment and config files
|
||||
.env
|
||||
config.js
|
||||
secrets.yaml
|
||||
|
||||
# Ignore dependency lock files (uncomment if you want to ignore)
|
||||
# package-lock.json
|
||||
# yarn.lock
|
||||
|
||||
# Ignore personal TODO lists
|
||||
TODO.md
|
||||
|
||||
# Ignore all files in a directory
|
||||
tmp/
|
||||
|
||||
# Ignore all .txt files in the doc/ directory
|
||||
doc/*.txt
|
||||
|
||||
# But don't ignore doc/important.txt, even though we're ignoring .txt files above
|
||||
!doc/important.txt
|
||||
|
||||
# Ignore all .pdf files in the doc/ directory and any of its subdirectories
|
||||
doc/**/*.pdf
|
||||
|
||||
# Ignore deprecated files
|
||||
DEPRECATED/
|
||||
|
||||
# Ignore virtual environments
|
||||
bot_env/
|
||||
bot_web/
|
||||
env_test/
|
||||
env_web/
|
||||
|
||||
# Ignore database
|
||||
mysql
|
||||
7
README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
Wordpress plugins:
|
||||
- WP Booking System - calendar for customer time slots
|
||||
- (Not in use) WPForms - form builder, can be used for quotes, customer contact / service request forms
|
||||
- Easy Invoice - invoicing + quoting
|
||||
|
||||
- Amelia - can replace all of the above and take payments and offer customer portal
|
||||
64
docker-compose.yml
Normal file
@@ -0,0 +1,64 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
db:
|
||||
image: mysql:8.0
|
||||
container_name: suffle_and_skirmish_wordpress_db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||||
MYSQL_DATABASE: ${DB_NAME}
|
||||
MYSQL_USER: ${DB_USER}
|
||||
MYSQL_PASSWORD: ${DB_PASSWORD}
|
||||
volumes:
|
||||
- ./mysql/data:/var/lib/mysql
|
||||
- ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
networks:
|
||||
- suffle_and_skirmish_wordpress_network
|
||||
|
||||
wordpress:
|
||||
image: wordpress:6.4-php8.2
|
||||
container_name: suffle_and_skirmish_wordpress_app
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8000:80"
|
||||
environment:
|
||||
WORDPRESS_DB_HOST: db:3306
|
||||
WORDPRESS_DB_USER: ${DB_USER}
|
||||
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
|
||||
WORDPRESS_DB_NAME: ${DB_NAME}
|
||||
WORDPRESS_DEBUG: 1
|
||||
WORDPRESS_CONFIG_EXTRA: |
|
||||
define('WP_HOME', 'http://localhost:8000');
|
||||
define('WP_SITEURL', 'http://localhost:8000');
|
||||
define('WP_DEBUG_LOG', '/var/www/html/wp-content/debug.log');
|
||||
volumes:
|
||||
- ./wp-content/themes:/var/www/html/wp-content/themes
|
||||
- ./wp-content/plugins:/var/www/html/wp-content/plugins
|
||||
- ./wp-content/uploads:/var/www/html/wp-content/uploads
|
||||
depends_on:
|
||||
- db
|
||||
networks:
|
||||
- suffle_and_skirmish_wordpress_network
|
||||
|
||||
phpmyadmin:
|
||||
image: phpmyadmin:latest
|
||||
container_name: suffle_and_skirmish_wordpress_phpmyadmin
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:80"
|
||||
environment:
|
||||
PMA_HOST: db
|
||||
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||||
depends_on:
|
||||
- db
|
||||
networks:
|
||||
- suffle_and_skirmish_wordpress_network
|
||||
|
||||
networks:
|
||||
suffle_and_skirmish_wordpress_network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
suffle_and_skirmish_wordpress_data:
|
||||
54
setup.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Setting up WordPress development environment..."
|
||||
|
||||
# Create directories with proper permissions
|
||||
mkdir -p wp-content/themes wp-content/plugins wp-content/uploads mysql/data
|
||||
|
||||
# Set ownership of current directory to current user
|
||||
sudo chown -R $USER:$USER .
|
||||
|
||||
# Set directory permissions
|
||||
chmod -R 755 wp-content/
|
||||
chmod -R 755 mysql/
|
||||
chmod 644 .env
|
||||
|
||||
# Check if Docker is running
|
||||
if ! docker info > /dev/null 2>&1; then
|
||||
echo "Docker is not running. Please start Docker first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if user is in docker group
|
||||
if groups $USER | grep -q '\bdocker\b'; then
|
||||
echo "User is in docker group, proceeding without sudo..."
|
||||
DOCKER_COMPOSE_CMD="docker-compose"
|
||||
else
|
||||
echo "User not in docker group, using sudo..."
|
||||
DOCKER_COMPOSE_CMD="sudo docker-compose"
|
||||
fi
|
||||
|
||||
echo "Building and starting containers..."
|
||||
$DOCKER_COMPOSE_CMD up -d
|
||||
|
||||
echo "Waiting for containers to initialize..."
|
||||
sleep 15
|
||||
|
||||
# Check if containers are running
|
||||
if $DOCKER_COMPOSE_CMD ps | grep -q "Up"; then
|
||||
echo "✅ WordPress development environment is ready!"
|
||||
echo ""
|
||||
echo "🌐 WordPress: http://localhost:8000"
|
||||
echo "📊 phpMyAdmin: http://localhost:8080"
|
||||
echo ""
|
||||
echo "Default credentials:"
|
||||
echo "WordPress Admin: admin / admin (you'll set this during installation)"
|
||||
echo "MySQL: root / root_password"
|
||||
echo ""
|
||||
echo "Useful commands:"
|
||||
echo " View logs: $DOCKER_COMPOSE_CMD logs -f"
|
||||
echo " Stop: $DOCKER_COMPOSE_CMD stop"
|
||||
echo " Remove: $DOCKER_COMPOSE_CMD down"
|
||||
else
|
||||
echo "❌ Some containers failed to start. Check logs with: $DOCKER_COMPOSE_CMD logs"
|
||||
fi
|
||||
17
wp-config-dev.ph
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
// Enable WordPress debug mode
|
||||
define('WP_DEBUG', true);
|
||||
define('WP_DEBUG_LOG', true);
|
||||
define('WP_DEBUG_DISPLAY', false);
|
||||
|
||||
// Development environment
|
||||
define('WP_ENVIRONMENT_TYPE', 'development');
|
||||
|
||||
// Disable file edits from WordPress admin (security)
|
||||
define('DISALLOW_FILE_EDIT', false);
|
||||
|
||||
// Allow file modifications (for theme/plugin development)
|
||||
define('DISALLOW_FILE_MODS', false);
|
||||
|
||||
// Increase memory limit
|
||||
define('WP_MEMORY_LIMIT', '256M');
|
||||
34
wp-content/plugins/akismet/.htaccess
Normal file
@@ -0,0 +1,34 @@
|
||||
# Only allow direct access to specific Web-available files.
|
||||
|
||||
# Apache 2.2
|
||||
<IfModule !mod_authz_core.c>
|
||||
Order Deny,Allow
|
||||
Deny from all
|
||||
</IfModule>
|
||||
|
||||
# Apache 2.4
|
||||
<IfModule mod_authz_core.c>
|
||||
Require all denied
|
||||
</IfModule>
|
||||
|
||||
# Akismet CSS and JS
|
||||
<FilesMatch "^(form\.js|akismet(-frontend|-admin)?\.js|akismet(-admin)?(-rtl)?\.css|inter\.css)$">
|
||||
<IfModule !mod_authz_core.c>
|
||||
Allow from all
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_authz_core.c>
|
||||
Require all granted
|
||||
</IfModule>
|
||||
</FilesMatch>
|
||||
|
||||
# Akismet images
|
||||
<FilesMatch "^(logo-(a|full)-2x\.png|akismet-refresh-logo\.svg|akismet-refresh-logo@2x\.png|arrow-left\.svg|icon-external\.svg)$">
|
||||
<IfModule !mod_authz_core.c>
|
||||
Allow from all
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_authz_core.c>
|
||||
Require all granted
|
||||
</IfModule>
|
||||
</FilesMatch>
|
||||
339
wp-content/plugins/akismet/LICENSE.txt
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.
|
||||
378
wp-content/plugins/akismet/_inc/akismet-admin.css
Normal file
@@ -0,0 +1,378 @@
|
||||
#akismet-plugin-container {
|
||||
background-color: var(--akismet-color-light-grey);
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen-Sans', 'Ubuntu', 'Cantarell', 'Helvetica Neue', sans-serif;
|
||||
--akismet-color-charcoal: #272635;
|
||||
--akismet-color-light-grey: #f6f7f7;
|
||||
--akismet-color-mid-grey: #a7aaad;
|
||||
--akismet-color-dark-grey: #646970;
|
||||
--akismet-color-grey-80: #2c3338;
|
||||
--akismet-color-grey-100: #101517;
|
||||
--akismet-color-white: #fff;
|
||||
--akismet-color-mid-green: #357b49;
|
||||
--akismet-color-mid-red: #e82c3f;
|
||||
--akismet-color-light-blue: #256eff;
|
||||
--akismet-color-notice-light-green: #dbf0e1;
|
||||
--akismet-color-notice-dark-green: #69bf82;
|
||||
--akismet-color-notice-light-red: #ffdbde;
|
||||
--akismet-color-notice-dark-red: #ff6676;
|
||||
}
|
||||
|
||||
#akismet-plugin-container a {
|
||||
color: var(--akismet-color-mid-green);
|
||||
}
|
||||
|
||||
#akismet-plugin-container button:focus-visible,
|
||||
#akismet-plugin-container input:focus-visible {
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
outline: 2px solid var(--akismet-color-light-blue);
|
||||
}
|
||||
|
||||
.akismet-masthead {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.akismet-masthead__logo {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.akismet-section-header {
|
||||
box-shadow: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.akismet-section-header__label {
|
||||
color: var(--akismet-color-charcoal);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.akismet-button, .akismet-button:hover {
|
||||
background-color: var(--akismet-color-mid-green);
|
||||
border: 0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Need this specificity to override the existing header rule */
|
||||
.akismet-new-snapshot h3.akismet-new-snapshot__header {
|
||||
background: none;
|
||||
font-size: 13px;
|
||||
color: var(--akismet-color-charcoal);
|
||||
text-align: left;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot .akismet-new-snapshot__number {
|
||||
color: var(--akismet-color-charcoal);
|
||||
letter-spacing: -1px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot li.akismet-new-snapshot__item {
|
||||
color: var(--akismet-color-dark-grey);
|
||||
font-size: 13px;
|
||||
text-align: left;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.akismet-masthead__logo-link {
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.akismet-masthead__back-link-container {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
/* Need this specificity to override the existing link rule */
|
||||
#akismet-plugin-container a.akismet-masthead__back-link {
|
||||
background-image: url(img/arrow-left.svg);
|
||||
background-position: left;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px;
|
||||
color: var(--akismet-color-charcoal);
|
||||
font-weight: 400;
|
||||
padding-left: 20px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#akismet-plugin-container a.akismet-masthead__back-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__item {
|
||||
border-top: 1px solid var(--akismet-color-light-grey);
|
||||
border-left: 1px solid var(--akismet-color-light-grey);
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot li:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__list {
|
||||
display: flex;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__item {
|
||||
flex: 1 0 33.33%;
|
||||
margin-bottom: 0;
|
||||
padding-left: 1.5em;
|
||||
padding-right: 1.5em;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__chart {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.akismet-box {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.akismet-box,
|
||||
.akismet-card {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06), 0 0 2px rgba(0, 0, 0, 0.16);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.akismet-card {
|
||||
margin: 32px auto 0 auto;
|
||||
}
|
||||
|
||||
.akismet-lower {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.akismet-lower .inside {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.akismet-section-header__label {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet-settings__row {
|
||||
border-bottom: 1px solid var(--akismet-color-light-grey);
|
||||
display: block;
|
||||
padding: 1em 1.5em;
|
||||
}
|
||||
|
||||
.akismet-settings__row-input {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.akismet-settings__row-title {
|
||||
font-weight: 500;
|
||||
font-size: 1em;
|
||||
margin: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.akismet-settings__row-description {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.akismet-card-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.akismet-card-actions__secondary-action {
|
||||
align-self: center;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.akismet-card-actions__secondary-action a[target="_blank"]::after {
|
||||
background: url('img/icon-external.svg') no-repeat;
|
||||
background-size: contain;
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
margin-left: 5px;
|
||||
vertical-align: middle;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.akismet-settings__row label {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.akismet-settings__row-note {
|
||||
font-size: 0.9em;
|
||||
margin-top: 0.4em;
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="checkbox"],
|
||||
.akismet-settings__row input[type="radio"] {
|
||||
accent-color: var(--akismet-color-mid-green);
|
||||
box-shadow: none;
|
||||
flex-shrink: 0;
|
||||
margin: 2px 0 0 0;
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="checkbox"] {
|
||||
margin-top: 1px;
|
||||
vertical-align: top;
|
||||
-webkit-appearance: checkbox;
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="radio"] {
|
||||
-webkit-appearance: radio;
|
||||
}
|
||||
|
||||
/* Fix up misbehaving wp-admin styles in Chrome (from forms and colors stylesheets) */
|
||||
.akismet-settings__row input[type="checkbox"]:checked:before {
|
||||
content: '';
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="radio"]:checked:before {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="checkbox"]:checked:hover,
|
||||
.akismet-settings__row input[type="radio"]:checked:hover {
|
||||
accent-color: var(--akismet-color-mid-green);
|
||||
}
|
||||
|
||||
.akismet-button:disabled {
|
||||
background-color: var(--akismet-color-mid-grey);
|
||||
color: var(--akismet-color-white);
|
||||
cursor: arrow;
|
||||
}
|
||||
|
||||
.akismet-awaiting-stats,
|
||||
.akismet-account {
|
||||
padding: 0 1rem 1rem 1rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet-account {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.akismet-account th {
|
||||
font-weight: 500;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.akismet-account th, .akismet-account td {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.akismet-settings__row-input-label {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.akismet-settings__row-label-text {
|
||||
padding-left: 0.5em;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.akismet-alert {
|
||||
border-left: 8px solid;
|
||||
border-radius: 8px;
|
||||
margin: 20px 0;
|
||||
padding: 0.2em 1em;
|
||||
}
|
||||
|
||||
.akismet-alert__heading {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.akismet-alert.is-good {
|
||||
background-color: var(--akismet-color-notice-light-green);
|
||||
border-left-color: var(--akismet-color-notice-dark-green);
|
||||
}
|
||||
|
||||
.akismet-alert.is-neutral {
|
||||
background-color: var(--akismet-color-white);
|
||||
border-left-color: var(--akismet-color-dark-grey);
|
||||
}
|
||||
|
||||
.akismet-alert.is-bad {
|
||||
background-color: var(--akismet-color-notice-light-red);
|
||||
border-left-color: var(--akismet-color-notice-dark-red);
|
||||
}
|
||||
|
||||
#akismet-plugin-container .akismet-alert.is-good a,
|
||||
#akismet-plugin-container .akismet-alert.is-bad a {
|
||||
/* For better contrast - green isn't great */
|
||||
color: var(--akismet-color-grey-80);
|
||||
}
|
||||
|
||||
/* Setup - API key input */
|
||||
.akismet-enter-api-key-box {
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
.akismet-enter-api-key-box__reveal {
|
||||
background: none;
|
||||
border: 0;
|
||||
color: var(--akismet-color-mid-green);
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.akismet-enter-api-key-box__form-wrapper {
|
||||
display: none;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.akismet-enter-api-key-box__input-wrapper {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
padding: 0 1.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.akismet-enter-api-key-box__key-input {
|
||||
flex-grow: 1;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
h3.akismet-enter-api-key-box__header {
|
||||
padding-top: 0;
|
||||
padding-bottom: 1em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 782px) {
|
||||
.akismet-new-snapshot__list {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__number {
|
||||
float: right;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
margin-top: -16px;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__header {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__text {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="checkbox"],
|
||||
.akismet-settings__row input[type="radio"] {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.akismet-settings__row-label-text {
|
||||
padding-left: 0.8em;
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="checkbox"],
|
||||
.akismet-settings__row input[type="radio"] {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
7
wp-content/plugins/akismet/_inc/akismet-admin.js
Normal file
@@ -0,0 +1,7 @@
|
||||
document.addEventListener( 'DOMContentLoaded', function() {
|
||||
// Prevent aggressive iframe caching in Firefox
|
||||
var statsIframe = document.getElementById( 'stats-iframe' );
|
||||
if ( statsIframe ) {
|
||||
statsIframe.contentWindow.location.href = statsIframe.src;
|
||||
}
|
||||
} );
|
||||
376
wp-content/plugins/akismet/_inc/akismet-frontend.js
Normal file
@@ -0,0 +1,376 @@
|
||||
/**
|
||||
* Observe how the user enters content into the comment form in order to determine whether it's a bot or not.
|
||||
*
|
||||
* Note that no actual input is being saved here, only counts and timings between events.
|
||||
*/
|
||||
|
||||
( function() {
|
||||
// Passive event listeners are guaranteed to never call e.preventDefault(),
|
||||
// but they're not supported in all browsers. Use this feature detection
|
||||
// to determine whether they're available for use.
|
||||
var supportsPassive = false;
|
||||
|
||||
try {
|
||||
var opts = Object.defineProperty( {}, 'passive', {
|
||||
get : function() {
|
||||
supportsPassive = true;
|
||||
}
|
||||
} );
|
||||
|
||||
window.addEventListener( 'testPassive', null, opts );
|
||||
window.removeEventListener( 'testPassive', null, opts );
|
||||
} catch ( e ) {}
|
||||
|
||||
function init() {
|
||||
var input_begin = '';
|
||||
|
||||
var keydowns = {};
|
||||
var lastKeyup = null;
|
||||
var lastKeydown = null;
|
||||
var keypresses = [];
|
||||
|
||||
var modifierKeys = [];
|
||||
var correctionKeys = [];
|
||||
|
||||
var lastMouseup = null;
|
||||
var lastMousedown = null;
|
||||
var mouseclicks = [];
|
||||
|
||||
var mousemoveTimer = null;
|
||||
var lastMousemoveX = null;
|
||||
var lastMousemoveY = null;
|
||||
var mousemoveStart = null;
|
||||
var mousemoves = [];
|
||||
|
||||
var touchmoveCountTimer = null;
|
||||
var touchmoveCount = 0;
|
||||
|
||||
var lastTouchEnd = null;
|
||||
var lastTouchStart = null;
|
||||
var touchEvents = [];
|
||||
|
||||
var scrollCountTimer = null;
|
||||
var scrollCount = 0;
|
||||
|
||||
var correctionKeyCodes = [ 'Backspace', 'Delete', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End', 'PageUp', 'PageDown' ];
|
||||
var modifierKeyCodes = [ 'Shift', 'CapsLock' ];
|
||||
|
||||
var forms = document.querySelectorAll( 'form[method=post]' );
|
||||
|
||||
for ( var i = 0; i < forms.length; i++ ) {
|
||||
var form = forms[i];
|
||||
|
||||
var formAction = form.getAttribute( 'action' );
|
||||
|
||||
// Ignore forms that POST directly to other domains; these could be things like payment forms.
|
||||
if ( formAction ) {
|
||||
// Check that the form is posting to an external URL, not a path.
|
||||
if ( formAction.indexOf( 'http://' ) == 0 || formAction.indexOf( 'https://' ) == 0 ) {
|
||||
if ( formAction.indexOf( 'http://' + window.location.hostname + '/' ) != 0 && formAction.indexOf( 'https://' + window.location.hostname + '/' ) != 0 ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
form.addEventListener( 'submit', function () {
|
||||
var ak_bkp = prepare_timestamp_array_for_request( keypresses );
|
||||
var ak_bmc = prepare_timestamp_array_for_request( mouseclicks );
|
||||
var ak_bte = prepare_timestamp_array_for_request( touchEvents );
|
||||
var ak_bmm = prepare_timestamp_array_for_request( mousemoves );
|
||||
|
||||
var input_fields = {
|
||||
// When did the user begin entering any input?
|
||||
'bib': input_begin,
|
||||
|
||||
// When was the form submitted?
|
||||
'bfs': Date.now(),
|
||||
|
||||
// How many keypresses did they make?
|
||||
'bkpc': keypresses.length,
|
||||
|
||||
// How quickly did they press a sample of keys, and how long between them?
|
||||
'bkp': ak_bkp,
|
||||
|
||||
// How quickly did they click the mouse, and how long between clicks?
|
||||
'bmc': ak_bmc,
|
||||
|
||||
// How many mouseclicks did they make?
|
||||
'bmcc': mouseclicks.length,
|
||||
|
||||
// When did they press modifier keys (like Shift or Capslock)?
|
||||
'bmk': modifierKeys.join( ';' ),
|
||||
|
||||
// When did they correct themselves? e.g., press Backspace, or use the arrow keys to move the cursor back
|
||||
'bck': correctionKeys.join( ';' ),
|
||||
|
||||
// How many times did they move the mouse?
|
||||
'bmmc': mousemoves.length,
|
||||
|
||||
// How many times did they move around using a touchscreen?
|
||||
'btmc': touchmoveCount,
|
||||
|
||||
// How many times did they scroll?
|
||||
'bsc': scrollCount,
|
||||
|
||||
// How quickly did they perform touch events, and how long between them?
|
||||
'bte': ak_bte,
|
||||
|
||||
// How many touch events were there?
|
||||
'btec' : touchEvents.length,
|
||||
|
||||
// How quickly did they move the mouse, and how long between moves?
|
||||
'bmm' : ak_bmm
|
||||
};
|
||||
|
||||
var akismet_field_prefix = 'ak_';
|
||||
|
||||
if ( this.getElementsByClassName ) {
|
||||
// Check to see if we've used an alternate field name prefix. We store this as an attribute of the container around some of the Akismet fields.
|
||||
var possible_akismet_containers = this.getElementsByClassName( 'akismet-fields-container' );
|
||||
|
||||
for ( var containerIndex = 0; containerIndex < possible_akismet_containers.length; containerIndex++ ) {
|
||||
var container = possible_akismet_containers.item( containerIndex );
|
||||
|
||||
if ( container.getAttribute( 'data-prefix' ) ) {
|
||||
akismet_field_prefix = container.getAttribute( 'data-prefix' );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( var field_name in input_fields ) {
|
||||
var field = document.createElement( 'input' );
|
||||
field.setAttribute( 'type', 'hidden' );
|
||||
field.setAttribute( 'name', akismet_field_prefix + field_name );
|
||||
field.setAttribute( 'value', input_fields[ field_name ] );
|
||||
this.appendChild( field );
|
||||
}
|
||||
}, supportsPassive ? { passive: true } : false );
|
||||
|
||||
form.addEventListener( 'keydown', function ( e ) {
|
||||
// If you hold a key down, some browsers send multiple keydown events in a row.
|
||||
// Ignore any keydown events for a key that hasn't come back up yet.
|
||||
if ( e.key in keydowns ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var keydownTime = ( new Date() ).getTime();
|
||||
keydowns[ e.key ] = [ keydownTime ];
|
||||
|
||||
if ( ! input_begin ) {
|
||||
input_begin = keydownTime;
|
||||
}
|
||||
|
||||
// In some situations, we don't want to record an interval since the last keypress -- for example,
|
||||
// on the first keypress, or on a keypress after focus has changed to another element. Normally,
|
||||
// we want to record the time between the last keyup and this keydown. But if they press a
|
||||
// key while already pressing a key, we want to record the time between the two keydowns.
|
||||
|
||||
var lastKeyEvent = Math.max( lastKeydown, lastKeyup );
|
||||
|
||||
if ( lastKeyEvent ) {
|
||||
keydowns[ e.key ].push( keydownTime - lastKeyEvent );
|
||||
}
|
||||
|
||||
lastKeydown = keydownTime;
|
||||
}, supportsPassive ? { passive: true } : false );
|
||||
|
||||
form.addEventListener( 'keyup', function ( e ) {
|
||||
if ( ! ( e.key in keydowns ) ) {
|
||||
// This key was pressed before this script was loaded, or a mouseclick happened during the keypress, or...
|
||||
return;
|
||||
}
|
||||
|
||||
var keyupTime = ( new Date() ).getTime();
|
||||
|
||||
if ( 'TEXTAREA' === e.target.nodeName || 'INPUT' === e.target.nodeName ) {
|
||||
if ( -1 !== modifierKeyCodes.indexOf( e.key ) ) {
|
||||
modifierKeys.push( keypresses.length - 1 );
|
||||
} else if ( -1 !== correctionKeyCodes.indexOf( e.key ) ) {
|
||||
correctionKeys.push( keypresses.length - 1 );
|
||||
} else {
|
||||
// ^ Don't record timings for keys like Shift or backspace, since they
|
||||
// typically get held down for longer than regular typing.
|
||||
|
||||
var keydownTime = keydowns[ e.key ][0];
|
||||
|
||||
var keypress = [];
|
||||
|
||||
// Keypress duration.
|
||||
keypress.push( keyupTime - keydownTime );
|
||||
|
||||
// Amount of time between this keypress and the previous keypress.
|
||||
if ( keydowns[ e.key ].length > 1 ) {
|
||||
keypress.push( keydowns[ e.key ][1] );
|
||||
}
|
||||
|
||||
keypresses.push( keypress );
|
||||
}
|
||||
}
|
||||
|
||||
delete keydowns[ e.key ];
|
||||
|
||||
lastKeyup = keyupTime;
|
||||
}, supportsPassive ? { passive: true } : false );
|
||||
|
||||
form.addEventListener( "focusin", function ( e ) {
|
||||
lastKeydown = null;
|
||||
lastKeyup = null;
|
||||
keydowns = {};
|
||||
}, supportsPassive ? { passive: true } : false );
|
||||
|
||||
form.addEventListener( "focusout", function ( e ) {
|
||||
lastKeydown = null;
|
||||
lastKeyup = null;
|
||||
keydowns = {};
|
||||
}, supportsPassive ? { passive: true } : false );
|
||||
}
|
||||
|
||||
document.addEventListener( 'mousedown', function ( e ) {
|
||||
lastMousedown = ( new Date() ).getTime();
|
||||
}, supportsPassive ? { passive: true } : false );
|
||||
|
||||
document.addEventListener( 'mouseup', function ( e ) {
|
||||
if ( ! lastMousedown ) {
|
||||
// If the mousedown happened before this script was loaded, but the mouseup happened after...
|
||||
return;
|
||||
}
|
||||
|
||||
var now = ( new Date() ).getTime();
|
||||
|
||||
var mouseclick = [];
|
||||
mouseclick.push( now - lastMousedown );
|
||||
|
||||
if ( lastMouseup ) {
|
||||
mouseclick.push( lastMousedown - lastMouseup );
|
||||
}
|
||||
|
||||
mouseclicks.push( mouseclick );
|
||||
|
||||
lastMouseup = now;
|
||||
|
||||
// If the mouse has been clicked, don't record this time as an interval between keypresses.
|
||||
lastKeydown = null;
|
||||
lastKeyup = null;
|
||||
keydowns = {};
|
||||
}, supportsPassive ? { passive: true } : false );
|
||||
|
||||
document.addEventListener( 'mousemove', function ( e ) {
|
||||
if ( mousemoveTimer ) {
|
||||
clearTimeout( mousemoveTimer );
|
||||
mousemoveTimer = null;
|
||||
}
|
||||
else {
|
||||
mousemoveStart = ( new Date() ).getTime();
|
||||
lastMousemoveX = e.offsetX;
|
||||
lastMousemoveY = e.offsetY;
|
||||
}
|
||||
|
||||
mousemoveTimer = setTimeout( function ( theEvent, originalMousemoveStart ) {
|
||||
var now = ( new Date() ).getTime() - 500; // To account for the timer delay.
|
||||
|
||||
var mousemove = [];
|
||||
mousemove.push( now - originalMousemoveStart );
|
||||
mousemove.push(
|
||||
Math.round(
|
||||
Math.sqrt(
|
||||
Math.pow( theEvent.offsetX - lastMousemoveX, 2 ) +
|
||||
Math.pow( theEvent.offsetY - lastMousemoveY, 2 )
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ( mousemove[1] > 0 ) {
|
||||
// If there was no measurable distance, then it wasn't really a move.
|
||||
mousemoves.push( mousemove );
|
||||
}
|
||||
|
||||
mousemoveStart = null;
|
||||
mousemoveTimer = null;
|
||||
}, 500, e, mousemoveStart );
|
||||
}, supportsPassive ? { passive: true } : false );
|
||||
|
||||
document.addEventListener( 'touchmove', function ( e ) {
|
||||
if ( touchmoveCountTimer ) {
|
||||
clearTimeout( touchmoveCountTimer );
|
||||
}
|
||||
|
||||
touchmoveCountTimer = setTimeout( function () {
|
||||
touchmoveCount++;
|
||||
}, 500 );
|
||||
}, supportsPassive ? { passive: true } : false );
|
||||
|
||||
document.addEventListener( 'touchstart', function ( e ) {
|
||||
lastTouchStart = ( new Date() ).getTime();
|
||||
}, supportsPassive ? { passive: true } : false );
|
||||
|
||||
document.addEventListener( 'touchend', function ( e ) {
|
||||
if ( ! lastTouchStart ) {
|
||||
// If the touchstart happened before this script was loaded, but the touchend happened after...
|
||||
return;
|
||||
}
|
||||
|
||||
var now = ( new Date() ).getTime();
|
||||
|
||||
var touchEvent = [];
|
||||
touchEvent.push( now - lastTouchStart );
|
||||
|
||||
if ( lastTouchEnd ) {
|
||||
touchEvent.push( lastTouchStart - lastTouchEnd );
|
||||
}
|
||||
|
||||
touchEvents.push( touchEvent );
|
||||
|
||||
lastTouchEnd = now;
|
||||
|
||||
// Don't record this time as an interval between keypresses.
|
||||
lastKeydown = null;
|
||||
lastKeyup = null;
|
||||
keydowns = {};
|
||||
}, supportsPassive ? { passive: true } : false );
|
||||
|
||||
document.addEventListener( 'scroll', function ( e ) {
|
||||
if ( scrollCountTimer ) {
|
||||
clearTimeout( scrollCountTimer );
|
||||
}
|
||||
|
||||
scrollCountTimer = setTimeout( function () {
|
||||
scrollCount++;
|
||||
}, 500 );
|
||||
}, supportsPassive ? { passive: true } : false );
|
||||
}
|
||||
|
||||
/**
|
||||
* For the timestamp data that is collected, don't send more than `limit` data points in the request.
|
||||
* Choose a random slice and send those.
|
||||
*/
|
||||
function prepare_timestamp_array_for_request( a, limit ) {
|
||||
if ( ! limit ) {
|
||||
limit = 100;
|
||||
}
|
||||
|
||||
var rv = '';
|
||||
|
||||
if ( a.length > 0 ) {
|
||||
var random_starting_point = Math.max( 0, Math.floor( Math.random() * a.length - limit ) );
|
||||
|
||||
for ( var i = 0; i < limit && i < a.length; i++ ) {
|
||||
rv += a[ random_starting_point + i ][0];
|
||||
|
||||
if ( a[ random_starting_point + i ].length >= 2 ) {
|
||||
rv += "," + a[ random_starting_point + i ][1];
|
||||
}
|
||||
|
||||
rv += ";";
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
if ( document.readyState !== 'loading' ) {
|
||||
init();
|
||||
} else {
|
||||
document.addEventListener( 'DOMContentLoaded', init );
|
||||
}
|
||||
})();
|
||||
648
wp-content/plugins/akismet/_inc/akismet.css
Normal file
@@ -0,0 +1,648 @@
|
||||
.wp-admin.jetpack_page_akismet-key-config, .wp-admin.settings_page_akismet-key-config {
|
||||
background-color:#f3f6f8;
|
||||
}
|
||||
|
||||
#submitted-on {
|
||||
position: relative;
|
||||
}
|
||||
#the-comment-list .author .akismet-user-comment-count {
|
||||
display: inline;
|
||||
}
|
||||
#the-comment-list .author a span {
|
||||
text-decoration: none;
|
||||
color: #999;
|
||||
}
|
||||
#the-comment-list .author a span.akismet-span-link {
|
||||
text-decoration: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
#the-comment-list .akismet_remove_url {
|
||||
margin-left: 3px;
|
||||
color: #999;
|
||||
padding: 2px 3px 2px 0;
|
||||
}
|
||||
#the-comment-list .akismet_remove_url:hover {
|
||||
color: #A7301F;
|
||||
font-weight: bold;
|
||||
padding: 2px 2px 2px 0;
|
||||
}
|
||||
#dashboard_recent_comments .akismet-status {
|
||||
display: none;
|
||||
}
|
||||
.akismet-status {
|
||||
float: right;
|
||||
}
|
||||
.akismet-status a {
|
||||
color: #AAA;
|
||||
font-style: italic;
|
||||
}
|
||||
table.comments td.comment p a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
table.comments td.comment p a:after {
|
||||
content: attr(href);
|
||||
color: #aaa;
|
||||
display: inline-block; /* Show the URL without the link's underline extending under it. */
|
||||
padding: 0 1ex; /* Because it's inline block, we can't just use spaces in the content: attribute to separate it from the link text. */
|
||||
}
|
||||
.mshot-arrow {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 10px solid transparent;
|
||||
border-bottom: 10px solid transparent;
|
||||
border-right: 10px solid #5C5C5C;
|
||||
position: absolute;
|
||||
left: -6px;
|
||||
top: 91px;
|
||||
}
|
||||
.mshot-container {
|
||||
background: #5C5C5C;
|
||||
position: absolute;
|
||||
top: -94px;
|
||||
padding: 7px;
|
||||
width: 450px;
|
||||
height: 338px;
|
||||
z-index: 20000;
|
||||
-moz-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
-webkit-border-radius: 6px;
|
||||
}
|
||||
.akismet-mshot {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
}
|
||||
.akismet-mshot .mshot-image {
|
||||
margin: 0;
|
||||
height: 338px;
|
||||
width: 450px;
|
||||
}
|
||||
.checkforspam {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
.checkforspam-spinner {
|
||||
display: inline-block;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.akismet-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.akismet-card .akismet-right {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.akismet-alert-text {
|
||||
color: #dd3d36;
|
||||
font-weight: bold;
|
||||
font-size: 120%;
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot {
|
||||
margin-top: 1em;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot h3 {
|
||||
background: #f5f5f5;
|
||||
color: #888;
|
||||
font-size: 11px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot ul li {
|
||||
color: #999;
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__number {
|
||||
display: block;
|
||||
font-size: 32px;
|
||||
font-weight: lighter;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
.akismet-settings th:first-child {
|
||||
vertical-align: top;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.akismet-settings th.akismet-api-key {
|
||||
vertical-align: middle;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.akismet-settings span.akismet-note{
|
||||
float: left;
|
||||
padding-left: 23px;
|
||||
font-size: 75%;
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
/**
|
||||
* For the activation notice on the plugins page.
|
||||
*/
|
||||
|
||||
#akismet_setup_prompt {
|
||||
background: none;
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.akismet_activate {
|
||||
border: 1px solid #4F800D;
|
||||
padding: 5px;
|
||||
margin: 15px 0;
|
||||
background: #83AF24;
|
||||
background-image: -webkit-gradient(linear, 0% 0, 80% 100%, from(#83AF24), to(#4F800D));
|
||||
background-image: -moz-linear-gradient(80% 100% 120deg, #4F800D, #83AF24);
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_a {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
right: 10px;
|
||||
font-size: 140px;
|
||||
color: #769F33;
|
||||
font-family: Georgia, "Times New Roman", Times, serif;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_button {
|
||||
font-weight: bold;
|
||||
border: 1px solid #029DD6;
|
||||
border-top: 1px solid #06B9FD;
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
padding: 9px 0 8px 0;
|
||||
color: #FFF;
|
||||
background: #029DD6;
|
||||
background-image: -webkit-gradient(linear, 0% 0, 0% 100%, from(#029DD6), to(#0079B1));
|
||||
background-image: -moz-linear-gradient(0% 100% 90deg, #0079B1, #029DD6);
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_button:hover {
|
||||
text-decoration: none !important;
|
||||
border: 1px solid #029DD6;
|
||||
border-bottom: 1px solid #00A8EF;
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
padding: 9px 0 8px 0;
|
||||
color: #F0F8FB;
|
||||
background: #0079B1;
|
||||
background-image: -webkit-gradient(linear, 0% 0, 0% 100%, from(#0079B1), to(#0092BF));
|
||||
background-image: -moz-linear-gradient(0% 100% 90deg, #0092BF, #0079B1);
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_button_border {
|
||||
border: 1px solid #006699;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
background: #029DD6;
|
||||
background-image: -webkit-gradient(linear, 0% 0, 0% 100%, from(#029DD6), to(#0079B1));
|
||||
background-image: -moz-linear-gradient(0% 100% 90deg, #0079B1, #029DD6);
|
||||
}
|
||||
|
||||
.akismet_activate .aa_button_container {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
background: #DEF1B8;
|
||||
padding: 5px;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
width: 266px;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_description {
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
left: 285px;
|
||||
margin-left: 25px;
|
||||
color: #E5F2B1;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_description strong {
|
||||
color: #FFF;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
@media (max-width: 550px) {
|
||||
.akismet_activate .aa_a {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_button_container {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 782px) {
|
||||
.akismet_activate {
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 850px) {
|
||||
#akismet_setup_prompt .aa_description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.akismet_activate {
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.jetpack_page_akismet-key-config #wpcontent, .settings_page_akismet-key-config #wpcontent {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.akismet-masthead {
|
||||
background-color:#fff;
|
||||
text-align:center;
|
||||
box-shadow:0 1px 0 rgba(200,215,225,0.5),0 1px 2px #e9eff3
|
||||
}
|
||||
@media (max-width: 45rem) {
|
||||
.akismet-masthead {
|
||||
padding:0 1.25rem
|
||||
}
|
||||
}
|
||||
|
||||
.akismet-masthead__inside-container {
|
||||
padding:.375rem 0;
|
||||
margin:0 auto;
|
||||
width:100%;
|
||||
max-width:45rem;
|
||||
text-align: left;
|
||||
}
|
||||
.akismet-masthead__logo-container {
|
||||
padding:.3125rem 0 0
|
||||
}
|
||||
.akismet-masthead__logo-link {
|
||||
display:inline-block;
|
||||
outline:none;
|
||||
vertical-align:middle
|
||||
}
|
||||
.akismet-masthead__logo-link:focus {
|
||||
line-height:0;
|
||||
box-shadow:0 0 0 2px #78dcfa
|
||||
}
|
||||
.akismet-masthead__logo-link+code {
|
||||
margin:0 10px;
|
||||
padding:5px 9px;
|
||||
border-radius:2px;
|
||||
background:#e6ecf1;
|
||||
color:#647a88
|
||||
}
|
||||
.akismet-masthead__links {
|
||||
display:-ms-flexbox;
|
||||
display:flex;
|
||||
-ms-flex-flow:row wrap;
|
||||
flex-flow:row wrap;
|
||||
-ms-flex:2 50%;
|
||||
flex:2 50%;
|
||||
-ms-flex-pack:end;
|
||||
justify-content:flex-end;
|
||||
margin:0
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.akismet-masthead__links {
|
||||
padding-right:.625rem
|
||||
}
|
||||
}
|
||||
.akismet-masthead__link-li {
|
||||
margin:0;
|
||||
padding:0
|
||||
}
|
||||
.akismet-masthead__link {
|
||||
font-style:normal;
|
||||
color:#0087be;
|
||||
padding:.625rem;
|
||||
display:inline-block
|
||||
}
|
||||
.akismet-masthead__link:visited {
|
||||
color:#0087be
|
||||
}
|
||||
.akismet-masthead__link:active,.akismet-masthead__link:hover {
|
||||
color:#00aadc
|
||||
}
|
||||
.akismet-masthead__link:hover {
|
||||
text-decoration:underline
|
||||
}
|
||||
.akismet-masthead__link .dashicons {
|
||||
display:none
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.akismet-masthead__link:hover,.akismet-masthead__link:active {
|
||||
text-decoration:none
|
||||
}
|
||||
.akismet-masthead__link .dashicons {
|
||||
display:block;
|
||||
font-size:1.75rem
|
||||
}
|
||||
.akismet-masthead__link span+span {
|
||||
display:none
|
||||
}
|
||||
}
|
||||
.akismet-masthead__link-li:last-of-type .akismet-masthead__link {
|
||||
padding-right:0
|
||||
}
|
||||
|
||||
.akismet-lower {
|
||||
margin: 0 auto;
|
||||
text-align: left;
|
||||
max-width: 45rem;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.akismet-lower .notice {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.akismet-card {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 0;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.akismet-card:after, .akismet-card .inside:after, .akismet-masthead__logo-container:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.akismet-card .inside {
|
||||
padding: 1.5rem;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.akismet-card .akismet-card-actions {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.jetpack_page_akismet-key-config .update-nag, .settings_page_akismet-key-config .update-nag {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.akismet-masthead .akismet-right {
|
||||
line-height: 2.125rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.akismet-box {
|
||||
box-sizing: border-box;
|
||||
background: white;
|
||||
border: 1px solid rgba(200, 215, 225, 0.5);
|
||||
}
|
||||
|
||||
.akismet-box h2, .akismet-box h3 {
|
||||
padding: 1.5rem 1.5rem .5rem 1.5rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet-box p {
|
||||
padding: 0 1.5rem 1.5rem 1.5rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet-jetpack-email {
|
||||
font-style: oblique;
|
||||
}
|
||||
|
||||
.akismet-jetpack-gravatar {
|
||||
padding: 0 0 0 1.5rem;
|
||||
float: left;
|
||||
margin-right: 1rem;
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
}
|
||||
|
||||
.akismet-box p:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.akismet-box .akismet-right {
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
|
||||
.akismet-boxes .akismet-box {
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.akismet-boxes .akismet-box:last-child {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.akismet-boxes .akismet-box:first-child {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.akismet-box-header {
|
||||
max-width: 700px;
|
||||
margin: 0 auto 40px auto;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.akismet-box-header h2 {
|
||||
margin: 1.5rem 10% 0;
|
||||
font-size: 1.375rem;
|
||||
font-weight: 700;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.akismet-box .centered {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.akismet-box .akismet-toggles {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
.akismet-box .akismet-ak-connect, .akismet-box .toggle-jp-connect {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.akismet-button, .akismet-button:hover, .akismet-button:visited {
|
||||
background: white;
|
||||
border-color: #c8d7e1;
|
||||
border-style: solid;
|
||||
border-width: 1px 1px 2px;
|
||||
color: #2e4453;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
overflow: hidden;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
text-overflow: ellipsis;
|
||||
text-decoration: none;
|
||||
vertical-align: top;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
border-radius: 4px;
|
||||
padding: 7px 14px 9px;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.akismet-button:hover {
|
||||
border-color: #a8bece;
|
||||
}
|
||||
|
||||
.akismet-button:active {
|
||||
border-width: 2px 1px 1px;
|
||||
}
|
||||
|
||||
.akismet-is-primary, .akismet-is-primary:hover, .akismet-is-primary:visited {
|
||||
background: #00aadc;
|
||||
border-color: #0087be;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.akismet-is-primary:hover, .akismet-is-primary:focus {
|
||||
border-color: #005082;
|
||||
}
|
||||
|
||||
.akismet-is-primary:hover {
|
||||
border-color: #005082;
|
||||
}
|
||||
|
||||
.akismet-section-header {
|
||||
position: relative;
|
||||
margin: 0 auto 0.625rem auto;
|
||||
padding: 1rem;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 0 0 1px rgba(200, 215, 225, 0.5), 0 1px 2px #e9eff3;
|
||||
background: #ffffff;
|
||||
width: 100%;
|
||||
padding-top: 0.6875rem;
|
||||
padding-bottom: 0.6875rem;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.akismet-section-header__label {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-ms-flex-positive: 1;
|
||||
flex-grow: 1;
|
||||
line-height: 1.75rem;
|
||||
position: relative;
|
||||
font-size: 0.875rem;
|
||||
color: #4f748e;
|
||||
}
|
||||
|
||||
.akismet-section-header__actions {
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.akismet-setup-instructions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.akismet-setup-instructions form {
|
||||
padding-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
div.error.akismet-usage-limit-alert {
|
||||
padding: 25px 45px 25px 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#akismet-plugin-container .akismet-usage-limit-alert {
|
||||
margin: 0 auto 0.625rem auto;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 0 0 1px rgba(200, 215, 225, 0.5), 0 1px 2px #e9eff3;
|
||||
border: none;
|
||||
border-left: 4px solid #d63638;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-logo {
|
||||
width: 38px;
|
||||
min-width: 38px;
|
||||
height: 38px;
|
||||
border-radius: 20px;
|
||||
margin-right: 18px;
|
||||
background: black;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-logo img {
|
||||
position: absolute;
|
||||
width: 22px;
|
||||
left: 8px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-text {
|
||||
flex-grow: 1;
|
||||
margin-right: 18px;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-cta {
|
||||
border-color: none;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#akismet-plugin-container .akismet-usage-limit-cta a {
|
||||
color: #d63638;
|
||||
}
|
||||
|
||||
@media (max-width: 550px) {
|
||||
div.error.akismet-usage-limit-alert {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-logo,
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-text {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-cta {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
421
wp-content/plugins/akismet/_inc/akismet.js
Normal file
@@ -0,0 +1,421 @@
|
||||
jQuery( function ( $ ) {
|
||||
var mshotRemovalTimer = null;
|
||||
var mshotRetryTimer = null;
|
||||
var mshotTries = 0;
|
||||
var mshotRetryInterval = 1000;
|
||||
var mshotEnabledLinkSelector = 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a';
|
||||
|
||||
var preloadedMshotURLs = [];
|
||||
|
||||
$('.akismet-status').each(function () {
|
||||
var thisId = $(this).attr('commentid');
|
||||
$(this).prependTo('#comment-' + thisId + ' .column-comment');
|
||||
});
|
||||
$('.akismet-user-comment-count').each(function () {
|
||||
var thisId = $(this).attr('commentid');
|
||||
$(this).insertAfter('#comment-' + thisId + ' .author strong:first').show();
|
||||
});
|
||||
|
||||
akismet_enable_comment_author_url_removal();
|
||||
|
||||
$( '#the-comment-list' ).on( 'click', '.akismet_remove_url', function () {
|
||||
var thisId = $(this).attr('commentid');
|
||||
var data = {
|
||||
action: 'comment_author_deurl',
|
||||
_wpnonce: WPAkismet.comment_author_url_nonce,
|
||||
id: thisId
|
||||
};
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: data,
|
||||
beforeSend: function () {
|
||||
// Removes "x" link
|
||||
$("a[commentid='"+ thisId +"']").hide();
|
||||
// Show temp status
|
||||
$("#author_comment_url_"+ thisId).html( $( '<span/>' ).text( WPAkismet.strings['Removing...'] ) );
|
||||
},
|
||||
success: function (response) {
|
||||
if (response) {
|
||||
// Show status/undo link
|
||||
$("#author_comment_url_"+ thisId)
|
||||
.attr('cid', thisId)
|
||||
.addClass('akismet_undo_link_removal')
|
||||
.html(
|
||||
$( '<span/>' ).text( WPAkismet.strings['URL removed'] )
|
||||
)
|
||||
.append( ' ' )
|
||||
.append(
|
||||
$( '<span/>' )
|
||||
.text( WPAkismet.strings['(undo)'] )
|
||||
.addClass( 'akismet-span-link' )
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}).on( 'click', '.akismet_undo_link_removal', function () {
|
||||
var thisId = $(this).attr('cid');
|
||||
var thisUrl = $(this).attr('href');
|
||||
var data = {
|
||||
action: 'comment_author_reurl',
|
||||
_wpnonce: WPAkismet.comment_author_url_nonce,
|
||||
id: thisId,
|
||||
url: thisUrl
|
||||
};
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: data,
|
||||
beforeSend: function () {
|
||||
// Show temp status
|
||||
$("#author_comment_url_"+ thisId).html( $( '<span/>' ).text( WPAkismet.strings['Re-adding...'] ) );
|
||||
},
|
||||
success: function (response) {
|
||||
if (response) {
|
||||
// Add "x" link
|
||||
$("a[commentid='"+ thisId +"']").show();
|
||||
// Show link. Core strips leading http://, so let's do that too.
|
||||
$("#author_comment_url_"+ thisId).removeClass('akismet_undo_link_removal').text( thisUrl.replace( /^http:\/\/(www\.)?/ig, '' ) );
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// Show a preview image of the hovered URL. Applies to author URLs and URLs inside the comments.
|
||||
if ( "enable_mshots" in WPAkismet && WPAkismet.enable_mshots ) {
|
||||
$( '#the-comment-list' ).on( 'mouseover', mshotEnabledLinkSelector, function () {
|
||||
clearTimeout( mshotRemovalTimer );
|
||||
|
||||
if ( $( '.akismet-mshot' ).length > 0 ) {
|
||||
if ( $( '.akismet-mshot:first' ).data( 'link' ) == this ) {
|
||||
// The preview is already showing for this link.
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// A new link is being hovered, so remove the old preview.
|
||||
$( '.akismet-mshot' ).remove();
|
||||
}
|
||||
}
|
||||
|
||||
clearTimeout( mshotRetryTimer );
|
||||
|
||||
var linkUrl = $( this ).attr( 'href' );
|
||||
|
||||
if ( preloadedMshotURLs.indexOf( linkUrl ) !== -1 ) {
|
||||
// This preview image was already preloaded, so begin with a retry URL so the user doesn't see the placeholder image for the first second.
|
||||
mshotTries = 2;
|
||||
}
|
||||
else {
|
||||
mshotTries = 1;
|
||||
}
|
||||
|
||||
var mShot = $( '<div class="akismet-mshot mshot-container"><div class="mshot-arrow"></div><img src="' + akismet_mshot_url( linkUrl, mshotTries ) + '" width="450" height="338" class="mshot-image" /></div>' );
|
||||
mShot.data( 'link', this );
|
||||
mShot.data( 'url', linkUrl );
|
||||
|
||||
mShot.find( 'img' ).on( 'load', function () {
|
||||
$( '.akismet-mshot' ).data( 'pending-request', false );
|
||||
} );
|
||||
|
||||
var offset = $( this ).offset();
|
||||
|
||||
mShot.offset( {
|
||||
left : Math.min( $( window ).width() - 475, offset.left + $( this ).width() + 10 ), // Keep it on the screen if the link is near the edge of the window.
|
||||
top: offset.top + ( $( this ).height() / 2 ) - 101 // 101 = top offset of the arrow plus the top border thickness
|
||||
} );
|
||||
|
||||
$( 'body' ).append( mShot );
|
||||
|
||||
mshotRetryTimer = setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
|
||||
} ).on( 'mouseout', 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a', function () {
|
||||
mshotRemovalTimer = setTimeout( function () {
|
||||
clearTimeout( mshotRetryTimer );
|
||||
|
||||
$( '.akismet-mshot' ).remove();
|
||||
}, 200 );
|
||||
} );
|
||||
|
||||
var preloadDelayTimer = null;
|
||||
|
||||
$( window ).on( 'scroll resize', function () {
|
||||
clearTimeout( preloadDelayTimer );
|
||||
|
||||
preloadDelayTimer = setTimeout( preloadMshotsInViewport, 500 );
|
||||
} );
|
||||
|
||||
preloadMshotsInViewport();
|
||||
}
|
||||
|
||||
/**
|
||||
* The way mShots works is if there was no screenshot already recently generated for the URL,
|
||||
* it returns a "loading..." image for the first request. Then, some subsequent request will
|
||||
* receive the actual screenshot, but it's unknown how long it will take. So, what we do here
|
||||
* is continually re-request the mShot, waiting a second after every response until we get the
|
||||
* actual screenshot.
|
||||
*/
|
||||
function retryMshotUntilLoaded() {
|
||||
clearTimeout( mshotRetryTimer );
|
||||
|
||||
var imageWidth = $( '.akismet-mshot img' ).get(0).naturalWidth;
|
||||
|
||||
if ( imageWidth == 0 ) {
|
||||
// It hasn't finished loading yet the first time. Check again shortly.
|
||||
setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
|
||||
}
|
||||
else if ( imageWidth == 400 ) {
|
||||
// It loaded the preview image.
|
||||
|
||||
if ( mshotTries == 20 ) {
|
||||
// Give up if we've requested the mShot 20 times already.
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $( '.akismet-mshot' ).data( 'pending-request' ) ) {
|
||||
$( '.akismet-mshot' ).data( 'pending-request', true );
|
||||
|
||||
mshotTries++;
|
||||
|
||||
$( '.akismet-mshot .mshot-image' ).attr( 'src', akismet_mshot_url( $( '.akismet-mshot' ).data( 'url' ), mshotTries ) );
|
||||
}
|
||||
|
||||
mshotRetryTimer = setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
|
||||
}
|
||||
else {
|
||||
// All done.
|
||||
}
|
||||
}
|
||||
|
||||
function preloadMshotsInViewport() {
|
||||
var windowWidth = $( window ).width();
|
||||
var windowHeight = $( window ).height();
|
||||
|
||||
$( '#the-comment-list' ).find( mshotEnabledLinkSelector ).each( function ( index, element ) {
|
||||
var linkUrl = $( this ).attr( 'href' );
|
||||
|
||||
// Don't attempt to preload an mshot for a single link twice.
|
||||
if ( preloadedMshotURLs.indexOf( linkUrl ) !== -1 ) {
|
||||
// The URL is already preloaded.
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( typeof element.getBoundingClientRect !== 'function' ) {
|
||||
// The browser is too old. Return false to stop this preloading entirely.
|
||||
return false;
|
||||
}
|
||||
|
||||
var rect = element.getBoundingClientRect();
|
||||
|
||||
if ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= windowHeight && rect.right <= windowWidth ) {
|
||||
akismet_preload_mshot( linkUrl );
|
||||
$( this ).data( 'akismet-mshot-preloaded', true );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
$( '.checkforspam.enable-on-load' ).on( 'click', function( e ) {
|
||||
if ( $( this ).hasClass( 'ajax-disabled' ) ) {
|
||||
// Akismet hasn't been configured yet. Allow the user to proceed to the button's link.
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
if ( $( this ).hasClass( 'button-disabled' ) ) {
|
||||
window.location.href = $( this ).data( 'success-url' ).replace( '__recheck_count__', 0 ).replace( '__spam_count__', 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
$('.checkforspam').addClass('button-disabled').addClass( 'checking' );
|
||||
$('.checkforspam-spinner').addClass( 'spinner' ).addClass( 'is-active' );
|
||||
|
||||
akismet_check_for_spam(0, 100);
|
||||
}).removeClass( 'button-disabled' );
|
||||
|
||||
var spam_count = 0;
|
||||
var recheck_count = 0;
|
||||
|
||||
function akismet_check_for_spam(offset, limit) {
|
||||
var check_for_spam_buttons = $( '.checkforspam' );
|
||||
|
||||
var nonce = check_for_spam_buttons.data( 'nonce' );
|
||||
|
||||
// We show the percentage complete down to one decimal point so even queues with 100k
|
||||
// pending comments will show some progress pretty quickly.
|
||||
var percentage_complete = Math.round( ( recheck_count / check_for_spam_buttons.data( 'pending-comment-count' ) ) * 1000 ) / 10;
|
||||
|
||||
// Update the progress counter on the "Check for Spam" button.
|
||||
$( '.checkforspam' ).text( check_for_spam_buttons.data( 'progress-label' ).replace( '%1$s', percentage_complete ) );
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
{
|
||||
'action': 'akismet_recheck_queue',
|
||||
'offset': offset,
|
||||
'limit': limit,
|
||||
'nonce': nonce
|
||||
},
|
||||
function(result) {
|
||||
if ( 'error' in result ) {
|
||||
// An error is only returned in the case of a missing nonce, so we don't need the actual error message.
|
||||
window.location.href = check_for_spam_buttons.data( 'failure-url' );
|
||||
return;
|
||||
}
|
||||
|
||||
recheck_count += result.counts.processed;
|
||||
spam_count += result.counts.spam;
|
||||
|
||||
if (result.counts.processed < limit) {
|
||||
window.location.href = check_for_spam_buttons.data( 'success-url' ).replace( '__recheck_count__', recheck_count ).replace( '__spam_count__', spam_count );
|
||||
}
|
||||
else {
|
||||
// Account for comments that were caught as spam and moved out of the queue.
|
||||
akismet_check_for_spam(offset + limit - result.counts.spam, limit);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if ( "start_recheck" in WPAkismet && WPAkismet.start_recheck ) {
|
||||
$( '.checkforspam' ).click();
|
||||
}
|
||||
|
||||
if ( typeof MutationObserver !== 'undefined' ) {
|
||||
// Dynamically add the "X" next the the author URL links when a comment is quick-edited.
|
||||
var comment_list_container = document.getElementById( 'the-comment-list' );
|
||||
|
||||
if ( comment_list_container ) {
|
||||
var observer = new MutationObserver( function ( mutations ) {
|
||||
for ( var i = 0, _len = mutations.length; i < _len; i++ ) {
|
||||
if ( mutations[i].addedNodes.length > 0 ) {
|
||||
akismet_enable_comment_author_url_removal();
|
||||
|
||||
// Once we know that we'll have to check for new author links, skip the rest of the mutations.
|
||||
break;
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
observer.observe( comment_list_container, { attributes: true, childList: true, characterData: true } );
|
||||
}
|
||||
}
|
||||
|
||||
function akismet_enable_comment_author_url_removal() {
|
||||
$( '#the-comment-list' )
|
||||
.find( 'tr.comment, tr[id ^= "comment-"]' )
|
||||
.find( '.column-author a[href^="http"]:first' ) // Ignore mailto: links, which would be the comment author's email.
|
||||
.each(function () {
|
||||
if ( $( this ).parent().find( '.akismet_remove_url' ).length > 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var linkHref = $(this).attr( 'href' );
|
||||
|
||||
// Ignore any links to the current domain, which are diagnostic tools, like the IP address link
|
||||
// or any other links another plugin might add.
|
||||
var currentHostParts = document.location.href.split( '/' );
|
||||
var currentHost = currentHostParts[0] + '//' + currentHostParts[2] + '/';
|
||||
|
||||
if ( linkHref.indexOf( currentHost ) != 0 ) {
|
||||
var thisCommentId = $(this).parents('tr:first').attr('id').split("-");
|
||||
|
||||
$(this)
|
||||
.attr("id", "author_comment_url_"+ thisCommentId[1])
|
||||
.after(
|
||||
$( '<a href="#" class="akismet_remove_url">x</a>' )
|
||||
.attr( 'commentid', thisCommentId[1] )
|
||||
.attr( 'title', WPAkismet.strings['Remove this URL'] )
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an mShot URL if given a link URL.
|
||||
*
|
||||
* @param string linkUrl
|
||||
* @param int retry If retrying a request, the number of the retry.
|
||||
* @return string The mShot URL;
|
||||
*/
|
||||
function akismet_mshot_url( linkUrl, retry ) {
|
||||
var mshotUrl = '//s0.wp.com/mshots/v1/' + encodeURIComponent( linkUrl ) + '?w=900';
|
||||
|
||||
if ( retry > 1 ) {
|
||||
mshotUrl += '&r=' + encodeURIComponent( retry );
|
||||
}
|
||||
|
||||
mshotUrl += '&source=akismet';
|
||||
|
||||
return mshotUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin loading an mShot preview of a link.
|
||||
*
|
||||
* @param string linkUrl
|
||||
*/
|
||||
function akismet_preload_mshot( linkUrl ) {
|
||||
var img = new Image();
|
||||
img.src = akismet_mshot_url( linkUrl );
|
||||
|
||||
preloadedMshotURLs.push( linkUrl );
|
||||
}
|
||||
|
||||
$( '.akismet-could-be-primary' ).each( function () {
|
||||
var form = $( this ).closest( 'form' );
|
||||
|
||||
form.data( 'initial-state', form.serialize() );
|
||||
|
||||
form.on( 'change keyup', function () {
|
||||
var self = $( this );
|
||||
var submit_button = self.find( '.akismet-could-be-primary' );
|
||||
|
||||
if ( self.serialize() != self.data( 'initial-state' ) ) {
|
||||
submit_button.addClass( 'akismet-is-primary' );
|
||||
}
|
||||
else {
|
||||
submit_button.removeClass( 'akismet-is-primary' );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
/**
|
||||
* Shows the Enter API key form
|
||||
*/
|
||||
$( '.akismet-enter-api-key-box__reveal' ).on( 'click', function ( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
var div = $( '.akismet-enter-api-key-box__form-wrapper' );
|
||||
div.show( 500 );
|
||||
div.find( 'input[name=key]' ).focus();
|
||||
|
||||
$( this ).hide();
|
||||
} );
|
||||
|
||||
/**
|
||||
* Hides the Connect with Jetpack form | Shows the Activate Akismet Account form
|
||||
*/
|
||||
$( 'a.toggle-ak-connect' ).on( 'click', function ( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
$( '.akismet-ak-connect' ).slideToggle('slow');
|
||||
$( 'a.toggle-ak-connect' ).hide();
|
||||
$( '.akismet-jp-connect' ).hide();
|
||||
$( 'a.toggle-jp-connect' ).show();
|
||||
} );
|
||||
|
||||
/**
|
||||
* Shows the Connect with Jetpack form | Hides the Activate Akismet Account form
|
||||
*/
|
||||
$( 'a.toggle-jp-connect' ).on( 'click', function ( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
$( '.akismet-jp-connect' ).slideToggle('slow');
|
||||
$( 'a.toggle-jp-connect' ).hide();
|
||||
$( '.akismet-ak-connect' ).hide();
|
||||
$( 'a.toggle-ak-connect' ).show();
|
||||
} );
|
||||
});
|
||||
67
wp-content/plugins/akismet/_inc/fonts/inter.css
Normal file
@@ -0,0 +1,67 @@
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("https://s0.wp.com/i/fonts/inter/Inter-Regular.woff2?v=3.19") format("woff2"),
|
||||
url("https://s0.wp.com/i/fonts/inter/Inter-Regular.woff?v=3.19") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("https://s0.wp.com/i/fonts/inter/Inter-Italic.woff2?v=3.19") format("woff2"),
|
||||
url("https://s0.wp.com/i/fonts/inter/Inter-Italic.woff?v=3.19") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("https://s0.wp.com/i/fonts/inter/Inter-Medium.woff2?v=3.19") format("woff2"),
|
||||
url("https://s0.wp.com/i/fonts/inter/Inter-Medium.woff?v=3.19") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("https://s0.wp.com/i/fonts/inter/Inter-MediumItalic.woff2?v=3.19") format("woff2"),
|
||||
url("https://s0.wp.com/i/fonts/inter/Inter-MediumItalic.woff?v=3.19") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("https://s0.wp.com/i/fonts/inter/Inter-SemiBold.woff2?v=3.19") format("woff2"),
|
||||
url("https://s0.wp.com/i/fonts/inter/Inter-SemiBold.woff?v=3.19") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("https://s0.wp.com/i/fonts/inter/Inter-SemiBoldItalic.woff2?v=3.19") format("woff2"),
|
||||
url("https://s0.wp.com/i/fonts/inter/Inter-SemiBoldItalic.woff?v=3.19") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("https://s0.wp.com/i/fonts/inter/Inter-Bold.woff2?v=3.19") format("woff2"),
|
||||
url("https://s0.wp.com/i/fonts/inter/Inter-Bold.woff?v=3.19") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("https://s0.wp.com/i/fonts/inter/Inter-BoldItalic.woff2?v=3.19") format("woff2"),
|
||||
url("https://s0.wp.com/i/fonts/inter/Inter-BoldItalic.woff?v=3.19") format("woff");
|
||||
}
|
||||
|
After Width: | Height: | Size: 8.4 KiB |
BIN
wp-content/plugins/akismet/_inc/img/akismet-refresh-logo@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
1
wp-content/plugins/akismet/_inc/img/arrow-left.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false"><path d="M20 11.2H6.8l3.7-3.7-1-1L3.9 12l5.6 5.5 1-1-3.7-3.7H20z"></path></svg>
|
||||
|
After Width: | Height: | Size: 199 B |
1
wp-content/plugins/akismet/_inc/img/icon-external.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false"><path fill="#357b49" d="M19.5 4.5h-7V6h4.44l-5.97 5.97 1.06 1.06L18 7.06v4.44h1.5v-7Zm-13 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-3H17v3a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h3V5.5h-3Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 350 B |
BIN
wp-content/plugins/akismet/_inc/img/logo-a-2x.png
Normal file
|
After Width: | Height: | Size: 904 B |
BIN
wp-content/plugins/akismet/_inc/img/logo-full-2x.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
380
wp-content/plugins/akismet/_inc/rtl/akismet-admin-rtl.css
Normal file
@@ -0,0 +1,380 @@
|
||||
/* This file was automatically generated on Nov 20 2023 03:10:42 */
|
||||
|
||||
#akismet-plugin-container {
|
||||
background-color: var(--akismet-color-light-grey);
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen-Sans', 'Ubuntu', 'Cantarell', 'Helvetica Neue', sans-serif;
|
||||
--akismet-color-charcoal: #272635;
|
||||
--akismet-color-light-grey: #f6f7f7;
|
||||
--akismet-color-mid-grey: #a7aaad;
|
||||
--akismet-color-dark-grey: #646970;
|
||||
--akismet-color-grey-80: #2c3338;
|
||||
--akismet-color-grey-100: #101517;
|
||||
--akismet-color-white: #fff;
|
||||
--akismet-color-mid-green: #357b49;
|
||||
--akismet-color-mid-red: #e82c3f;
|
||||
--akismet-color-light-blue: #256eff;
|
||||
--akismet-color-notice-light-green: #dbf0e1;
|
||||
--akismet-color-notice-dark-green: #69bf82;
|
||||
--akismet-color-notice-light-red: #ffdbde;
|
||||
--akismet-color-notice-dark-red: #ff6676;
|
||||
}
|
||||
|
||||
#akismet-plugin-container a {
|
||||
color: var(--akismet-color-mid-green);
|
||||
}
|
||||
|
||||
#akismet-plugin-container button:focus-visible,
|
||||
#akismet-plugin-container input:focus-visible {
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
outline: 2px solid var(--akismet-color-light-blue);
|
||||
}
|
||||
|
||||
.akismet-masthead {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.akismet-masthead__logo {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.akismet-section-header {
|
||||
box-shadow: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.akismet-section-header__label {
|
||||
color: var(--akismet-color-charcoal);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.akismet-button, .akismet-button:hover {
|
||||
background-color: var(--akismet-color-mid-green);
|
||||
border: 0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Need this specificity to override the existing header rule */
|
||||
.akismet-new-snapshot h3.akismet-new-snapshot__header {
|
||||
background: none;
|
||||
font-size: 13px;
|
||||
color: var(--akismet-color-charcoal);
|
||||
text-align: right;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot .akismet-new-snapshot__number {
|
||||
color: var(--akismet-color-charcoal);
|
||||
letter-spacing: -1px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot li.akismet-new-snapshot__item {
|
||||
color: var(--akismet-color-dark-grey);
|
||||
font-size: 13px;
|
||||
text-align: right;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.akismet-masthead__logo-link {
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.akismet-masthead__back-link-container {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
/* Need this specificity to override the existing link rule */
|
||||
#akismet-plugin-container a.akismet-masthead__back-link {
|
||||
background-image: url(../img/arrow-left.svg);
|
||||
background-position: right;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px;
|
||||
color: var(--akismet-color-charcoal);
|
||||
font-weight: 400;
|
||||
padding-right: 20px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#akismet-plugin-container a.akismet-masthead__back-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__item {
|
||||
border-top: 1px solid var(--akismet-color-light-grey);
|
||||
border-right: 1px solid var(--akismet-color-light-grey);
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot li:first-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__list {
|
||||
display: flex;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__item {
|
||||
flex: 1 0 33.33%;
|
||||
margin-bottom: 0;
|
||||
padding-right: 1.5em;
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__chart {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.akismet-box {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.akismet-box,
|
||||
.akismet-card {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06), 0 0 2px rgba(0, 0, 0, 0.16);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.akismet-card {
|
||||
margin: 32px auto 0 auto;
|
||||
}
|
||||
|
||||
.akismet-lower {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.akismet-lower .inside {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.akismet-section-header__label {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet-settings__row {
|
||||
border-bottom: 1px solid var(--akismet-color-light-grey);
|
||||
display: block;
|
||||
padding: 1em 1.5em;
|
||||
}
|
||||
|
||||
.akismet-settings__row-input {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.akismet-settings__row-title {
|
||||
font-weight: 500;
|
||||
font-size: 1em;
|
||||
margin: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.akismet-settings__row-description {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.akismet-card-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.akismet-card-actions__secondary-action {
|
||||
align-self: center;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.akismet-card-actions__secondary-action a[target="_blank"]::after {
|
||||
background: url('../img/icon-external.svg') no-repeat;
|
||||
background-size: contain;
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
margin-right: 5px;
|
||||
vertical-align: middle;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.akismet-settings__row label {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.akismet-settings__row-note {
|
||||
font-size: 0.9em;
|
||||
margin-top: 0.4em;
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="checkbox"],
|
||||
.akismet-settings__row input[type="radio"] {
|
||||
accent-color: var(--akismet-color-mid-green);
|
||||
box-shadow: none;
|
||||
flex-shrink: 0;
|
||||
margin: 2px 0 0 0;
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="checkbox"] {
|
||||
margin-top: 1px;
|
||||
vertical-align: top;
|
||||
-webkit-appearance: checkbox;
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="radio"] {
|
||||
-webkit-appearance: radio;
|
||||
}
|
||||
|
||||
/* Fix up misbehaving wp-admin styles in Chrome (from forms and colors stylesheets) */
|
||||
.akismet-settings__row input[type="checkbox"]:checked:before {
|
||||
content: '';
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="radio"]:checked:before {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="checkbox"]:checked:hover,
|
||||
.akismet-settings__row input[type="radio"]:checked:hover {
|
||||
accent-color: var(--akismet-color-mid-green);
|
||||
}
|
||||
|
||||
.akismet-button:disabled {
|
||||
background-color: var(--akismet-color-mid-grey);
|
||||
color: var(--akismet-color-white);
|
||||
cursor: arrow;
|
||||
}
|
||||
|
||||
.akismet-awaiting-stats,
|
||||
.akismet-account {
|
||||
padding: 0 1rem 1rem 1rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet-account {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.akismet-account th {
|
||||
font-weight: 500;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.akismet-account th, .akismet-account td {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.akismet-settings__row-input-label {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.akismet-settings__row-label-text {
|
||||
padding-right: 0.5em;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.akismet-alert {
|
||||
border-right: 8px solid;
|
||||
border-radius: 8px;
|
||||
margin: 20px 0;
|
||||
padding: 0.2em 1em;
|
||||
}
|
||||
|
||||
.akismet-alert__heading {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.akismet-alert.is-good {
|
||||
background-color: var(--akismet-color-notice-light-green);
|
||||
border-right-color: var(--akismet-color-notice-dark-green);
|
||||
}
|
||||
|
||||
.akismet-alert.is-neutral {
|
||||
background-color: var(--akismet-color-white);
|
||||
border-right-color: var(--akismet-color-dark-grey);
|
||||
}
|
||||
|
||||
.akismet-alert.is-bad {
|
||||
background-color: var(--akismet-color-notice-light-red);
|
||||
border-right-color: var(--akismet-color-notice-dark-red);
|
||||
}
|
||||
|
||||
#akismet-plugin-container .akismet-alert.is-good a,
|
||||
#akismet-plugin-container .akismet-alert.is-bad a {
|
||||
/* For better contrast - green isn't great */
|
||||
color: var(--akismet-color-grey-80);
|
||||
}
|
||||
|
||||
/* Setup - API key input */
|
||||
.akismet-enter-api-key-box {
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
.akismet-enter-api-key-box__reveal {
|
||||
background: none;
|
||||
border: 0;
|
||||
color: var(--akismet-color-mid-green);
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.akismet-enter-api-key-box__form-wrapper {
|
||||
display: none;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.akismet-enter-api-key-box__input-wrapper {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
padding: 0 1.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.akismet-enter-api-key-box__key-input {
|
||||
flex-grow: 1;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
h3.akismet-enter-api-key-box__header {
|
||||
padding-top: 0;
|
||||
padding-bottom: 1em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 782px) {
|
||||
.akismet-new-snapshot__list {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__number {
|
||||
float: left;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
margin-top: -16px;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__header {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__text {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="checkbox"],
|
||||
.akismet-settings__row input[type="radio"] {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.akismet-settings__row-label-text {
|
||||
padding-right: 0.8em;
|
||||
}
|
||||
|
||||
.akismet-settings__row input[type="checkbox"],
|
||||
.akismet-settings__row input[type="radio"] {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
649
wp-content/plugins/akismet/_inc/rtl/akismet-rtl.css
Normal file
@@ -0,0 +1,649 @@
|
||||
/* This file was automatically generated on Aug 25 2023 03:41:43 */
|
||||
|
||||
.wp-admin.jetpack_page_akismet-key-config, .wp-admin.settings_page_akismet-key-config {
|
||||
background-color:#f3f6f8;
|
||||
}
|
||||
|
||||
#submitted-on {
|
||||
position: relative;
|
||||
}
|
||||
#the-comment-list .author .akismet-user-comment-count {
|
||||
display: inline;
|
||||
}
|
||||
#the-comment-list .author a span {
|
||||
text-decoration: none;
|
||||
color: #999;
|
||||
}
|
||||
#the-comment-list .author a span.akismet-span-link {
|
||||
text-decoration: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
#the-comment-list .akismet_remove_url {
|
||||
margin-right: 3px;
|
||||
color: #999;
|
||||
padding: 2px 0 2px 3px;
|
||||
}
|
||||
#the-comment-list .akismet_remove_url:hover {
|
||||
color: #A7301F;
|
||||
font-weight: bold;
|
||||
padding: 2px 0 2px 2px;
|
||||
}
|
||||
#dashboard_recent_comments .akismet-status {
|
||||
display: none;
|
||||
}
|
||||
.akismet-status {
|
||||
float: left;
|
||||
}
|
||||
.akismet-status a {
|
||||
color: #AAA;
|
||||
font-style: italic;
|
||||
}
|
||||
table.comments td.comment p a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
table.comments td.comment p a:after {
|
||||
content: attr(href);
|
||||
color: #aaa;
|
||||
display: inline-block; /* Show the URL without the link's underline extending under it. */
|
||||
padding: 0 1ex; /* Because it's inline block, we can't just use spaces in the content: attribute to separate it from the link text. */
|
||||
}
|
||||
.mshot-arrow {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 10px solid transparent;
|
||||
border-bottom: 10px solid transparent;
|
||||
border-left: 10px solid #5C5C5C;
|
||||
position: absolute;
|
||||
right: -6px;
|
||||
top: 91px;
|
||||
}
|
||||
.mshot-container {
|
||||
background: #5C5C5C;
|
||||
position: absolute;
|
||||
top: -94px;
|
||||
padding: 7px;
|
||||
width: 450px;
|
||||
height: 338px;
|
||||
z-index: 20000;
|
||||
-moz-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
-webkit-border-radius: 6px;
|
||||
}
|
||||
.akismet-mshot {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
}
|
||||
.akismet-mshot .mshot-image {
|
||||
margin: 0;
|
||||
height: 338px;
|
||||
width: 450px;
|
||||
}
|
||||
.checkforspam {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
.checkforspam-spinner {
|
||||
display: inline-block;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.akismet-right {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.akismet-card .akismet-right {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.akismet-alert-text {
|
||||
color: #dd3d36;
|
||||
font-weight: bold;
|
||||
font-size: 120%;
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot {
|
||||
margin-top: 1em;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot h3 {
|
||||
background: #f5f5f5;
|
||||
color: #888;
|
||||
font-size: 11px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot ul li {
|
||||
color: #999;
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
}
|
||||
|
||||
.akismet-new-snapshot__number {
|
||||
display: block;
|
||||
font-size: 32px;
|
||||
font-weight: lighter;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
.akismet-settings th:first-child {
|
||||
vertical-align: top;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.akismet-settings th.akismet-api-key {
|
||||
vertical-align: middle;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.akismet-settings span.akismet-note{
|
||||
float: right;
|
||||
padding-right: 23px;
|
||||
font-size: 75%;
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
/**
|
||||
* For the activation notice on the plugins page.
|
||||
*/
|
||||
|
||||
#akismet_setup_prompt {
|
||||
background: none;
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.akismet_activate {
|
||||
border: 1px solid #4F800D;
|
||||
padding: 5px;
|
||||
margin: 15px 0;
|
||||
background: #83AF24;
|
||||
background-image: -webkit-gradient(linear, 0% 0, 80% 100%, from(#83AF24), to(#4F800D));
|
||||
background-image: -moz-linear-gradient(-80% 100% 120deg, #4F800D, #83AF24);
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_a {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: 10px;
|
||||
font-size: 140px;
|
||||
color: #769F33;
|
||||
font-family: Georgia, "Times New Roman", Times, serif;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_button {
|
||||
font-weight: bold;
|
||||
border: 1px solid #029DD6;
|
||||
border-top: 1px solid #06B9FD;
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
padding: 9px 0 8px 0;
|
||||
color: #FFF;
|
||||
background: #029DD6;
|
||||
background-image: -webkit-gradient(linear, 0% 0, 0% 100%, from(#029DD6), to(#0079B1));
|
||||
background-image: -moz-linear-gradient(0% 100% 90deg, #0079B1, #029DD6);
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_button:hover {
|
||||
text-decoration: none !important;
|
||||
border: 1px solid #029DD6;
|
||||
border-bottom: 1px solid #00A8EF;
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
padding: 9px 0 8px 0;
|
||||
color: #F0F8FB;
|
||||
background: #0079B1;
|
||||
background-image: -webkit-gradient(linear, 0% 0, 0% 100%, from(#0079B1), to(#0092BF));
|
||||
background-image: -moz-linear-gradient(0% 100% 90deg, #0092BF, #0079B1);
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_button_border {
|
||||
border: 1px solid #006699;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
background: #029DD6;
|
||||
background-image: -webkit-gradient(linear, 0% 0, 0% 100%, from(#029DD6), to(#0079B1));
|
||||
background-image: -moz-linear-gradient(0% 100% 90deg, #0079B1, #029DD6);
|
||||
}
|
||||
|
||||
.akismet_activate .aa_button_container {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
background: #DEF1B8;
|
||||
padding: 5px;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
width: 266px;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_description {
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
right: 285px;
|
||||
margin-right: 25px;
|
||||
color: #E5F2B1;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_description strong {
|
||||
color: #FFF;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
@media (max-width: 550px) {
|
||||
.akismet_activate .aa_a {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.akismet_activate .aa_button_container {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 782px) {
|
||||
.akismet_activate {
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 850px) {
|
||||
#akismet_setup_prompt .aa_description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.akismet_activate {
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.jetpack_page_akismet-key-config #wpcontent, .settings_page_akismet-key-config #wpcontent {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.akismet-masthead {
|
||||
background-color:#fff;
|
||||
text-align:center;
|
||||
box-shadow:0 1px 0 rgba(200,215,225,0.5),0 1px 2px #e9eff3
|
||||
}
|
||||
@media (max-width: 45rem) {
|
||||
.akismet-masthead {
|
||||
padding:0 1.25rem
|
||||
}
|
||||
}
|
||||
|
||||
.akismet-masthead__inside-container {
|
||||
padding:.375rem 0;
|
||||
margin:0 auto;
|
||||
width:100%;
|
||||
max-width:45rem;
|
||||
text-align: right;
|
||||
}
|
||||
.akismet-masthead__logo-container {
|
||||
padding:.3125rem 0 0
|
||||
}
|
||||
.akismet-masthead__logo-link {
|
||||
display:inline-block;
|
||||
outline:none;
|
||||
vertical-align:middle
|
||||
}
|
||||
.akismet-masthead__logo-link:focus {
|
||||
line-height:0;
|
||||
box-shadow:0 0 0 2px #78dcfa
|
||||
}
|
||||
.akismet-masthead__logo-link+code {
|
||||
margin:0 10px;
|
||||
padding:5px 9px;
|
||||
border-radius:2px;
|
||||
background:#e6ecf1;
|
||||
color:#647a88
|
||||
}
|
||||
.akismet-masthead__links {
|
||||
display:-ms-flexbox;
|
||||
display:flex;
|
||||
-ms-flex-flow:row wrap;
|
||||
flex-flow:row wrap;
|
||||
-ms-flex:2 50%;
|
||||
flex:2 50%;
|
||||
-ms-flex-pack:end;
|
||||
justify-content:flex-end;
|
||||
margin:0
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.akismet-masthead__links {
|
||||
padding-left:.625rem
|
||||
}
|
||||
}
|
||||
.akismet-masthead__link-li {
|
||||
margin:0;
|
||||
padding:0
|
||||
}
|
||||
.akismet-masthead__link {
|
||||
font-style:normal;
|
||||
color:#0087be;
|
||||
padding:.625rem;
|
||||
display:inline-block
|
||||
}
|
||||
.akismet-masthead__link:visited {
|
||||
color:#0087be
|
||||
}
|
||||
.akismet-masthead__link:active,.akismet-masthead__link:hover {
|
||||
color:#00aadc
|
||||
}
|
||||
.akismet-masthead__link:hover {
|
||||
text-decoration:underline
|
||||
}
|
||||
.akismet-masthead__link .dashicons {
|
||||
display:none
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.akismet-masthead__link:hover,.akismet-masthead__link:active {
|
||||
text-decoration:none
|
||||
}
|
||||
.akismet-masthead__link .dashicons {
|
||||
display:block;
|
||||
font-size:1.75rem
|
||||
}
|
||||
.akismet-masthead__link span+span {
|
||||
display:none
|
||||
}
|
||||
}
|
||||
.akismet-masthead__link-li:last-of-type .akismet-masthead__link {
|
||||
padding-left:0
|
||||
}
|
||||
|
||||
.akismet-lower {
|
||||
margin: 0 auto;
|
||||
text-align: right;
|
||||
max-width: 45rem;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.akismet-lower .notice {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.akismet-card {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 0;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.akismet-card:after, .akismet-card .inside:after, .akismet-masthead__logo-container:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.akismet-card .inside {
|
||||
padding: 1.5rem;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.akismet-card .akismet-card-actions {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.jetpack_page_akismet-key-config .update-nag, .settings_page_akismet-key-config .update-nag {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.akismet-masthead .akismet-right {
|
||||
line-height: 2.125rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.akismet-box {
|
||||
box-sizing: border-box;
|
||||
background: white;
|
||||
border: 1px solid rgba(200, 215, 225, 0.5);
|
||||
}
|
||||
|
||||
.akismet-box h2, .akismet-box h3 {
|
||||
padding: 1.5rem 1.5rem .5rem 1.5rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet-box p {
|
||||
padding: 0 1.5rem 1.5rem 1.5rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet-jetpack-email {
|
||||
font-style: oblique;
|
||||
}
|
||||
|
||||
.akismet-jetpack-gravatar {
|
||||
padding: 0 1.5rem 0 0;
|
||||
float: right;
|
||||
margin-left: 1rem;
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
}
|
||||
|
||||
.akismet-box p:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.akismet-box .akismet-right {
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
||||
.akismet-boxes .akismet-box {
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.akismet-boxes .akismet-box:last-child {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.akismet-boxes .akismet-box:first-child {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.akismet-box-header {
|
||||
max-width: 700px;
|
||||
margin: 0 auto 40px auto;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.akismet-box-header h2 {
|
||||
margin: 1.5rem 10% 0;
|
||||
font-size: 1.375rem;
|
||||
font-weight: 700;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.akismet-box .centered {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.akismet-box .akismet-toggles {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
.akismet-box .akismet-ak-connect, .akismet-box .toggle-jp-connect {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.akismet-button, .akismet-button:hover, .akismet-button:visited {
|
||||
background: white;
|
||||
border-color: #c8d7e1;
|
||||
border-style: solid;
|
||||
border-width: 1px 1px 2px;
|
||||
color: #2e4453;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
overflow: hidden;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
text-overflow: ellipsis;
|
||||
text-decoration: none;
|
||||
vertical-align: top;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
border-radius: 4px;
|
||||
padding: 7px 14px 9px;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.akismet-button:hover {
|
||||
border-color: #a8bece;
|
||||
}
|
||||
|
||||
.akismet-button:active {
|
||||
border-width: 2px 1px 1px;
|
||||
}
|
||||
|
||||
.akismet-is-primary, .akismet-is-primary:hover, .akismet-is-primary:visited {
|
||||
background: #00aadc;
|
||||
border-color: #0087be;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.akismet-is-primary:hover, .akismet-is-primary:focus {
|
||||
border-color: #005082;
|
||||
}
|
||||
|
||||
.akismet-is-primary:hover {
|
||||
border-color: #005082;
|
||||
}
|
||||
|
||||
.akismet-section-header {
|
||||
position: relative;
|
||||
margin: 0 auto 0.625rem auto;
|
||||
padding: 1rem;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 0 0 1px rgba(200, 215, 225, 0.5), 0 1px 2px #e9eff3;
|
||||
background: #ffffff;
|
||||
width: 100%;
|
||||
padding-top: 0.6875rem;
|
||||
padding-bottom: 0.6875rem;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.akismet-section-header__label {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-ms-flex-positive: 1;
|
||||
flex-grow: 1;
|
||||
line-height: 1.75rem;
|
||||
position: relative;
|
||||
font-size: 0.875rem;
|
||||
color: #4f748e;
|
||||
}
|
||||
|
||||
.akismet-section-header__actions {
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.akismet-setup-instructions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.akismet-setup-instructions form {
|
||||
padding-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
div.error.akismet-usage-limit-alert {
|
||||
padding: 25px 15px 25px 45px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#akismet-plugin-container .akismet-usage-limit-alert {
|
||||
margin: 0 auto 0.625rem auto;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 0 0 1px rgba(200, 215, 225, 0.5), 0 1px 2px #e9eff3;
|
||||
border: none;
|
||||
border-right: 4px solid #d63638;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-logo {
|
||||
width: 38px;
|
||||
min-width: 38px;
|
||||
height: 38px;
|
||||
border-radius: 20px;
|
||||
margin-left: 18px;
|
||||
background: black;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-logo img {
|
||||
position: absolute;
|
||||
width: 22px;
|
||||
right: 8px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-text {
|
||||
flex-grow: 1;
|
||||
margin-left: 18px;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-cta {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#akismet-plugin-container .akismet-usage-limit-cta a {
|
||||
color: #d63638;
|
||||
}
|
||||
|
||||
@media (max-width: 550px) {
|
||||
div.error.akismet-usage-limit-alert {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-logo,
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-text {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.akismet-usage-limit-alert .akismet-usage-limit-cta {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
68
wp-content/plugins/akismet/akismet.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Akismet
|
||||
*/
|
||||
/*
|
||||
Plugin Name: Akismet Anti-spam: Spam Protection
|
||||
Plugin URI: https://akismet.com/
|
||||
Description: Used by millions, Akismet is quite possibly the best way in the world to <strong>protect your blog from spam</strong>. Akismet Anti-spam keeps your site protected even while you sleep. To get started: activate the Akismet plugin and then go to your Akismet Settings page to set up your API key.
|
||||
Version: 5.3.1
|
||||
Requires at least: 5.8
|
||||
Requires PHP: 5.6.20
|
||||
Author: Automattic - Anti-spam Team
|
||||
Author URI: https://automattic.com/wordpress-plugins/
|
||||
License: GPLv2 or later
|
||||
Text Domain: akismet
|
||||
*/
|
||||
|
||||
/*
|
||||
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.
|
||||
|
||||
Copyright 2005-2023 Automattic, Inc.
|
||||
*/
|
||||
|
||||
// Make sure we don't expose any info if called directly
|
||||
if ( !function_exists( 'add_action' ) ) {
|
||||
echo 'Hi there! I\'m just a plugin, not much I can do when called directly.';
|
||||
exit;
|
||||
}
|
||||
|
||||
define( 'AKISMET_VERSION', '5.3.1' );
|
||||
define( 'AKISMET__MINIMUM_WP_VERSION', '5.8' );
|
||||
define( 'AKISMET__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
|
||||
define( 'AKISMET_DELETE_LIMIT', 10000 );
|
||||
|
||||
register_activation_hook( __FILE__, array( 'Akismet', 'plugin_activation' ) );
|
||||
register_deactivation_hook( __FILE__, array( 'Akismet', 'plugin_deactivation' ) );
|
||||
|
||||
require_once( AKISMET__PLUGIN_DIR . 'class.akismet.php' );
|
||||
require_once( AKISMET__PLUGIN_DIR . 'class.akismet-widget.php' );
|
||||
require_once( AKISMET__PLUGIN_DIR . 'class.akismet-rest-api.php' );
|
||||
|
||||
add_action( 'init', array( 'Akismet', 'init' ) );
|
||||
|
||||
add_action( 'rest_api_init', array( 'Akismet_REST_API', 'init' ) );
|
||||
|
||||
if ( is_admin() || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
|
||||
require_once( AKISMET__PLUGIN_DIR . 'class.akismet-admin.php' );
|
||||
add_action( 'init', array( 'Akismet_Admin', 'init' ) );
|
||||
}
|
||||
|
||||
//add wrapper class around deprecated akismet functions that are referenced elsewhere
|
||||
require_once( AKISMET__PLUGIN_DIR . 'wrapper.php' );
|
||||
|
||||
if ( defined( 'WP_CLI' ) && WP_CLI ) {
|
||||
require_once( AKISMET__PLUGIN_DIR . 'class.akismet-cli.php' );
|
||||
}
|
||||
509
wp-content/plugins/akismet/changelog.txt
Normal file
@@ -0,0 +1,509 @@
|
||||
=== Akismet Anti-spam ===
|
||||
|
||||
== Archived Changelog Entries ==
|
||||
|
||||
This file contains older changelog entries, so we can keep the size of the standard WordPress readme.txt file reasonable.
|
||||
For the latest changes, please see the "Changelog" section of the [readme.txt file](https://plugins.svn.wordpress.org/akismet/trunk/readme.txt).
|
||||
|
||||
= 4.1.12 =
|
||||
*Release Date - 3 September 2021*
|
||||
|
||||
* Fixed "Use of undefined constant" notice.
|
||||
* Improved styling of alert notices.
|
||||
|
||||
= 4.1.11 =
|
||||
*Release Date - 23 August 2021*
|
||||
|
||||
* Added support for Akismet API usage notifications on Akismet settings and edit-comments admin pages.
|
||||
* Added support for the deleted_comment action when bulk-deleting comments from Spam.
|
||||
|
||||
= 4.1.10 =
|
||||
*Release Date - 6 July 2021*
|
||||
|
||||
* Simplified the code around checking comments in REST API and XML-RPC requests.
|
||||
* Updated Plus plan terminology in notices to match current subscription names.
|
||||
* Added `rel="noopener"` to the widget link to avoid warnings in Google Lighthouse.
|
||||
* Set the Akismet JavaScript as deferred instead of async to improve responsiveness.
|
||||
* Improved the preloading of screenshot popups on the edit comments admin page.
|
||||
|
||||
= 4.1.9 =
|
||||
*Release Date - 2 March 2021*
|
||||
|
||||
* Improved handling of pingbacks in XML-RPC multicalls
|
||||
|
||||
= 4.1.8 =
|
||||
*Release Date - 6 January 2021*
|
||||
|
||||
* Fixed missing fields in submit-spam and submit-ham calls that could lead to reduced accuracy.
|
||||
* Fixed usage of deprecated jQuery function.
|
||||
|
||||
= 4.1.7 =
|
||||
*Release Date - 22 October 2020*
|
||||
|
||||
* Show the "Set up your Akismet account" banner on the comments admin screen, where it's relevant to mention if Akismet hasn't been configured.
|
||||
* Don't use wp_blacklist_check when the new wp_check_comment_disallowed_list function is available.
|
||||
|
||||
= 4.1.6 =
|
||||
*Release Date - 4 June 2020*
|
||||
|
||||
* Disable "Check for Spam" button until the page is loaded to avoid errors with clicking through to queue recheck endpoint directly.
|
||||
* Added filter "akismet_enable_mshots" to allow disabling screenshot popups on the edit comments admin page.
|
||||
|
||||
= 4.1.5 =
|
||||
*Release Date - 29 April 2020*
|
||||
|
||||
* Based on user feedback, we have dropped the in-admin notice explaining the availability of the "privacy notice" option in the AKismet settings screen. The option itself is available, but after displaying the notice for the last 2 years, it is now considered a known fact.
|
||||
* Updated the "Requires at least" to WP 4.6, based on recommendations from https://wp-info.org/tools/checkplugini18n.php?slug=akismet
|
||||
* Moved older changelog entries to a separate file to keep the size of this readme reasonable, also based on recommendations from https://wp-info.org/tools/checkplugini18n.php?slug=akismet
|
||||
|
||||
= 4.1.4 =
|
||||
*Release Date - 17 March 2020*
|
||||
|
||||
* Only redirect to the Akismet setup screen upon plugin activation if the plugin was activated manually from within the plugin-related screens, to help users with non-standard install workflows, like WP-CLI.
|
||||
* Update the layout of the initial setup screen to be more readable on small screens.
|
||||
* If no API key has been entered, don't run code that expects an API key.
|
||||
* Improve the readability of the comment history entries.
|
||||
* Don't modify the comment form HTML if no API key has been set.
|
||||
|
||||
= 4.1.3 =
|
||||
*Release Date - 31 October 2019*
|
||||
|
||||
* Prevented an attacker from being able to cause a user to unknowingly recheck their Pending comments for spam.
|
||||
* Improved compatibility with Jetpack 7.7+.
|
||||
* Updated the plugin activation page to use consistent language and markup.
|
||||
* Redirecting users to the Akismet connnection/settings screen upon plugin activation, in an effort to make it easier for people to get setup.
|
||||
|
||||
= 4.1.2 =
|
||||
*Release Date - 14 May 2019*
|
||||
|
||||
* Fixed a conflict between the Akismet setup banner and other plugin notices.
|
||||
* Reduced the number of API requests made by the plugin when attempting to verify the API key.
|
||||
* Include additional data in the pingback pre-check API request to help make the stats more accurate.
|
||||
* Fixed a bug that was enabling the "Check for Spam" button when no comments were eligible to be checked.
|
||||
* Improved Akismet's AMP compatibility.
|
||||
|
||||
= 4.1.1 =
|
||||
*Release Date - 31 January 2019*
|
||||
|
||||
* Fixed the "Setup Akismet" notice so it resizes responsively.
|
||||
* Only highlight the "Save Changes" button in the Akismet config when changes have been made.
|
||||
* The count of comments in your spam queue shown on the dashboard show now always be up-to-date.
|
||||
|
||||
= 4.1 =
|
||||
*Release Date - 12 November 2018*
|
||||
|
||||
* Added a WP-CLI method for retrieving stats.
|
||||
* Hooked into the new "Personal Data Eraser" functionality from WordPress 4.9.6.
|
||||
* Added functionality to clear outdated alerts from Akismet.com.
|
||||
|
||||
= 4.0.8 =
|
||||
*Release Date - 19 June 2018*
|
||||
|
||||
* Improved the grammar and consistency of the in-admin privacy related notes (notice and config).
|
||||
* Revised in-admin explanation of the comment form privacy notice to make its usage clearer.
|
||||
* Added `rel="nofollow noopener"` to the comment form privacy notice to improve SEO and security.
|
||||
|
||||
= 4.0.7 =
|
||||
*Release Date - 28 May 2018*
|
||||
|
||||
* Based on user feedback, the link on "Learn how your comment data is processed." in the optional privacy notice now has a `target` of `_blank` and opens in a new tab/window.
|
||||
* Updated the in-admin privacy notice to use the term "comment" instead of "contact" in "Akismet can display a notice to your users under your comment forms."
|
||||
* Only show in-admin privacy notice if Akismet has an API Key configured
|
||||
|
||||
= 4.0.6 =
|
||||
*Release Date - 26 May 2018*
|
||||
|
||||
* Moved away from using `empty( get_option() )` to instantiating a variable to be compatible with older versions of PHP (5.3, 5.4, etc).
|
||||
|
||||
= 4.0.5 =
|
||||
*Release Date - 26 May 2018*
|
||||
|
||||
* Corrected version number after tagging. Sorry...
|
||||
|
||||
= 4.0.4 =
|
||||
*Release Date - 26 May 2018*
|
||||
|
||||
* Added a hook to provide Akismet-specific privacy information for a site's privacy policy.
|
||||
* Added tools to control the display of a privacy related notice under comment forms.
|
||||
* Fixed HTML in activation failure message to close META and HEAD tag properly.
|
||||
* Fixed a bug that would sometimes prevent Akismet from being correctly auto-configured.
|
||||
|
||||
= 4.0.3 =
|
||||
*Release Date - 19 February 2018*
|
||||
|
||||
* Added a scheduled task to remove entries in wp_commentmeta that no longer have corresponding comments in wp_comments.
|
||||
* Added a new `akismet_batch_delete_count` action to the batch delete methods for people who'd like to keep track of the numbers of records being processed by those methods.
|
||||
|
||||
= 4.0.2 =
|
||||
*Release Date - 18 December 2017*
|
||||
|
||||
* Fixed a bug that could cause Akismet to recheck a comment that has already been manually approved or marked as spam.
|
||||
* Fixed a bug that could cause Akismet to claim that some comments are still waiting to be checked when no comments are waiting to be checked.
|
||||
|
||||
= 4.0.1 =
|
||||
*Release Date - 6 November 2017*
|
||||
|
||||
* Fixed a bug that could prevent some users from connecting Akismet via their Jetpack connection.
|
||||
* Ensured that any pending Akismet-related events are unscheduled if the plugin is deactivated.
|
||||
* Allow some JavaScript to be run asynchronously to avoid affecting page render speeds.
|
||||
|
||||
= 4.0 =
|
||||
*Release Date - 19 September 2017*
|
||||
|
||||
* Added REST API endpoints for configuring Akismet and retrieving stats.
|
||||
* Increased the minimum supported WordPress version to 4.0.
|
||||
* Added compatibility with comments submitted via the REST API.
|
||||
* Improved the progress indicator on the "Check for Spam" button.
|
||||
|
||||
= 3.3.4 =
|
||||
*Release Date - 3 August 2017*
|
||||
|
||||
* Disabled Akismet's debug log output by default unless AKISMET_DEBUG is defined.
|
||||
* URL previews now begin preloading when the mouse moves near them in the comments section of wp-admin.
|
||||
* When a comment is caught by the Comment Blacklist, Akismet will always allow it to stay in the trash even if it is spam as well.
|
||||
* Fixed a bug that was preventing an error from being shown when a site can't reach Akismet's servers.
|
||||
|
||||
= 3.3.3 =
|
||||
*Release Date - 13 July 2017*
|
||||
|
||||
* Reduced amount of bandwidth used by the URL Preview feature.
|
||||
* Improved the admin UI when the API key is manually pre-defined for the site.
|
||||
* Removed a workaround for WordPress installations older than 3.3 that will improve Akismet's compatibility with other plugins.
|
||||
* The number of spam blocked that is displayed on the WordPress dashboard will now be more accurate and updated more frequently.
|
||||
* Fixed a bug in the Akismet widget that could cause PHP warnings.
|
||||
|
||||
= 3.3.2 =
|
||||
*Release Date - 10 May 2017*
|
||||
|
||||
* Fixed a bug causing JavaScript errors in some browsers.
|
||||
|
||||
= 3.3.1 =
|
||||
*Release Date - 2 May 2017*
|
||||
|
||||
* Improve performance by only requesting the akismet_comment_nonce option when absolutely necessary.
|
||||
* Fixed two bugs that could cause PHP warnings.
|
||||
* Fixed a bug that was preventing the "Remove author URL" feature from working after a comment was edited using "Quick Edit."
|
||||
* Fixed a bug that was preventing the URL preview feature from working after a comment was edited using "Quick Edit."
|
||||
|
||||
= 3.3 =
|
||||
*Release Date - 23 February 2017*
|
||||
|
||||
* Updated the Akismet admin pages with a new clean design.
|
||||
* Fixed bugs preventing the `akismet_add_comment_nonce` and `akismet_update_alert` wrapper functions from working properly.
|
||||
* Fixed bug preventing the loading indicator from appearing when re-checking all comments for spam.
|
||||
* Added a progress indicator to the "Check for Spam" button.
|
||||
* Added a success message after manually rechecking the Pending queue for spam.
|
||||
|
||||
= 3.2 =
|
||||
*Release Date - 6 September 2016*
|
||||
|
||||
* Added a WP-CLI module. You can now check comments and recheck the moderation queue from the command line.
|
||||
* Stopped using the deprecated jQuery function `.live()`.
|
||||
* Fixed a bug in `remove_comment_author_url()` and `add_comment_author_url()` that could generate PHP notices.
|
||||
* Fixed a bug that could cause an infinite loop for sites with very very very large comment IDs.
|
||||
* Fixed a bug that could cause the Akismet widget title to be blank.
|
||||
|
||||
= 3.1.11 =
|
||||
*Release Date - 12 May 2016*
|
||||
|
||||
* Fixed a bug that could cause the "Check for Spam" button to skip some comments.
|
||||
* Fixed a bug that could prevent some spam submissions from being sent to Akismet.
|
||||
* Updated all links to use https:// when possible.
|
||||
* Disabled Akismet debug logging unless WP_DEBUG and WP_DEBUG_LOG are both enabled.
|
||||
|
||||
= 3.1.10 =
|
||||
*Release Date - 1 April 2016*
|
||||
|
||||
* Fixed a bug that could cause comments caught as spam to be placed in the Pending queue.
|
||||
* Fixed a bug that could have resulted in comments that were caught by the core WordPress comment blacklist not to have a corresponding History entry.
|
||||
* Fixed a bug that could have caused avoidable PHP warnings in the error log.
|
||||
|
||||
= 3.1.9 =
|
||||
*Release Date - 28 March 2016*
|
||||
|
||||
* Add compatibility with Jetpack so that Jetpack can automatically configure Akismet settings when appropriate.
|
||||
* Fixed a bug preventing some comment data from being sent to Akismet.
|
||||
|
||||
= 3.1.8 =
|
||||
*Release Date - 4 March 2016*
|
||||
|
||||
* Fixed a bug preventing Akismet from being used with some plugins that rewrite admin URLs.
|
||||
* Reduced the amount of bandwidth used on Akismet API calls
|
||||
* Reduced the amount of space Akismet uses in the database
|
||||
* Fixed a bug that could cause comments caught as spam to be placed in the Pending queue.
|
||||
|
||||
= 3.1.7 =
|
||||
*Release Date - 4 January 2016*
|
||||
|
||||
* Added documentation for the 'akismet_comment_nonce' filter.
|
||||
* The post-install activation button is now accessible to screen readers and keyboard-only users.
|
||||
* Fixed a bug that was preventing the "Remove author URL" feature from working in WordPress 4.4
|
||||
|
||||
= 3.1.6 =
|
||||
*Release Date - 14 December 2015*
|
||||
|
||||
* Improve the notices shown after activating Akismet.
|
||||
* Update some strings to allow for the proper plural forms in all languages.
|
||||
|
||||
= 3.1.5 =
|
||||
*Release Date - 13 October 2015*
|
||||
|
||||
* Closes a potential XSS vulnerability.
|
||||
|
||||
= 3.1.4 =
|
||||
*Release Date - 24 September 2015*
|
||||
|
||||
* Fixed a bug that was preventing some users from automatically connecting using Jetpack if they didn't have a current Akismet subscription.
|
||||
* Fixed a bug that could cause comments caught as spam to be placed in the Pending queue.
|
||||
* Error messages and instructions have been simplified to be more understandable.
|
||||
* Link previews are enabled for all links inside comments, not just the author's website link.
|
||||
|
||||
= 3.1.3 =
|
||||
*Release Date - 6 July 2015*
|
||||
|
||||
* Notify users when their account status changes after previously being successfully set up. This should help any users who are seeing blank Akismet settings screens.
|
||||
|
||||
= 3.1.2 =
|
||||
*Release Date - 7 June 2015*
|
||||
|
||||
* Reduced the amount of space Akismet uses in the commentmeta table.
|
||||
* Fixed a bug where some comments with quotes in the author name weren't getting history entries
|
||||
* Pre-emptive security improvements to ensure that the Akismet plugin can't be used by attackers to compromise a WordPress installation.
|
||||
* Better UI for the key entry field: allow whitespace to be included at the beginning or end of the key and strip it out automatically when the form is submitted.
|
||||
* When deactivating the plugin, notify the Akismet API so the site can be marked as inactive.
|
||||
* Clearer error messages.
|
||||
|
||||
= 3.1.1 =
|
||||
*Release Date - 17th March, 2015*
|
||||
|
||||
* Improvements to the "Remove comment author URL" JavaScript
|
||||
* Include the pingback pre-check from the 2.6 branch.
|
||||
|
||||
= 3.1 =
|
||||
*Release Date - 11th March, 2015*
|
||||
|
||||
* Use HTTPS by default for all requests to Akismet.
|
||||
* Fix for a situation where Akismet might strip HTML from a comment.
|
||||
|
||||
= 3.0.4 =
|
||||
*Release Date - 11th December, 2014*
|
||||
|
||||
* Fix to make .htaccess compatible with Apache 2.4.
|
||||
* Fix to allow removal of https author URLs.
|
||||
* Fix to avoid stripping part of the author URL when removing and re-adding.
|
||||
* Removed the "Check for Spam" button from the "Trash" and "Approved" queues, where it would have no effect.
|
||||
* Allow automatic API key configuration when Jetpack is installed and connected to a WordPress.com account
|
||||
|
||||
= 3.0.3 =
|
||||
*Release Date - 3rd November, 2014*
|
||||
|
||||
* Fix for sending the wrong data to delete_comment action that could have prevented old spam comments from being deleted.
|
||||
* Added a filter to disable logging of Akismet debugging information.
|
||||
* Added a filter for the maximum comment age when deleting old spam comments.
|
||||
* Added a filter for the number per batch when deleting old spam comments.
|
||||
* Removed the "Check for Spam" button from the Spam folder.
|
||||
|
||||
= 3.0.2 =
|
||||
*Release Date - 18th August, 2014*
|
||||
|
||||
* Performance improvements.
|
||||
* Fixed a bug that could truncate the comment data being sent to Akismet for checking.
|
||||
|
||||
= 3.0.1 =
|
||||
*Release Date - 9th July, 2014*
|
||||
|
||||
* Removed dependency on PHP's fsockopen function
|
||||
* Fix spam/ham reports to work when reported outside of the WP dashboard, e.g., from Notifications or the WP app
|
||||
* Remove jQuery dependency for comment form JavaScript
|
||||
* Remove unnecessary data from some Akismet comment meta
|
||||
* Suspended keys will now result in all comments being put in moderation, not spam.
|
||||
|
||||
= 3.0.0 =
|
||||
*Release Date - 15th April, 2014*
|
||||
|
||||
* Move Akismet to Settings menu
|
||||
* Drop Akismet Stats menu
|
||||
* Add stats snapshot to Akismet settings
|
||||
* Add Akismet subscription details and status to Akismet settings
|
||||
* Add contextual help for each page
|
||||
* Improve Akismet setup to use Jetpack to automate plugin setup
|
||||
* Fix "Check for Spam" to use AJAX to avoid page timing out
|
||||
* Fix Akismet settings page to be responsive
|
||||
* Drop legacy code
|
||||
* Tidy up CSS and Javascript
|
||||
* Replace the old discard setting with a new "discard pervasive spam" feature.
|
||||
|
||||
= 2.6.0 =
|
||||
*Release Date - 18th March, 2014*
|
||||
|
||||
* Add ajax paging to the check for spam button to handle large volumes of comments
|
||||
* Optimize javascript and add localization support
|
||||
* Fix bug in link to spam comments from right now dashboard widget
|
||||
* Fix bug with deleting old comments to avoid timeouts dealing with large volumes of comments
|
||||
* Include X-Pingback-Forwarded-For header in outbound WordPress pingback verifications
|
||||
* Add pre-check for pingbacks, to stop spam before an outbound verification request is made
|
||||
|
||||
= 2.5.9 =
|
||||
*Release Date - 1st August, 2013*
|
||||
|
||||
* Update 'Already have a key' link to redirect page rather than depend on javascript
|
||||
* Fix some non-translatable strings to be translatable
|
||||
* Update Activation banner in plugins page to redirect user to Akismet config page
|
||||
|
||||
= 2.5.8 =
|
||||
*Release Date - 20th January, 2013*
|
||||
|
||||
* Simplify the activation process for new users
|
||||
* Remove the reporter_ip parameter
|
||||
* Minor preventative security improvements
|
||||
|
||||
= 2.5.7 =
|
||||
*Release Date - 13th December, 2012*
|
||||
|
||||
* FireFox Stats iframe preview bug
|
||||
* Fix mshots preview when using https
|
||||
* Add .htaccess to block direct access to files
|
||||
* Prevent some PHP notices
|
||||
* Fix Check For Spam return location when referrer is empty
|
||||
* Fix Settings links for network admins
|
||||
* Fix prepare() warnings in WP 3.5
|
||||
|
||||
= 2.5.6 =
|
||||
*Release Date - 26th April, 2012*
|
||||
|
||||
* Prevent retry scheduling problems on sites where wp_cron is misbehaving
|
||||
* Preload mshot previews
|
||||
* Modernize the widget code
|
||||
* Fix a bug where comments were not held for moderation during an error condition
|
||||
* Improve the UX and display when comments are temporarily held due to an error
|
||||
* Make the Check For Spam button force a retry when comments are held due to an error
|
||||
* Handle errors caused by an invalid key
|
||||
* Don't retry comments that are too old
|
||||
* Improve error messages when verifying an API key
|
||||
|
||||
= 2.5.5 =
|
||||
*Release Date - 11th January, 2012*
|
||||
|
||||
* Add nonce check for comment author URL remove action
|
||||
* Fix the settings link
|
||||
|
||||
= 2.5.4 =
|
||||
*Release Date - 5th January, 2012*
|
||||
|
||||
* Limit Akismet CSS and Javascript loading in wp-admin to just the pages that need it
|
||||
* Added author URL quick removal functionality
|
||||
* Added mShot preview on Author URL hover
|
||||
* Added empty index.php to prevent directory listing
|
||||
* Move wp-admin menu items under Jetpack, if it is installed
|
||||
* Purge old Akismet comment meta data, default of 15 days
|
||||
|
||||
= 2.5.3 =
|
||||
*Release Date - 8th Febuary, 2011*
|
||||
|
||||
* Specify the license is GPL v2 or later
|
||||
* Fix a bug that could result in orphaned commentmeta entries
|
||||
* Include hotfix for WordPress 3.0.5 filter issue
|
||||
|
||||
= 2.5.2 =
|
||||
*Release Date - 14th January, 2011*
|
||||
|
||||
* Properly format the comment count for author counts
|
||||
* Look for super admins on multisite installs when looking up user roles
|
||||
* Increase the HTTP request timeout
|
||||
* Removed padding for author approved count
|
||||
* Fix typo in function name
|
||||
* Set Akismet stats iframe height to fixed 2500px. Better to have one tall scroll bar than two side by side.
|
||||
|
||||
= 2.5.1 =
|
||||
*Release Date - 17th December, 2010*
|
||||
|
||||
* Fix a bug that caused the "Auto delete" option to fail to discard comments correctly
|
||||
* Remove the comment nonce form field from the 'Akismet Configuration' page in favor of using a filter, akismet_comment_nonce
|
||||
* Fixed padding bug in "author" column of posts screen
|
||||
* Added margin-top to "cleared by ..." badges on dashboard
|
||||
* Fix possible error when calling akismet_cron_recheck()
|
||||
* Fix more PHP warnings
|
||||
* Clean up XHTML warnings for comment nonce
|
||||
* Fix for possible condition where scheduled comment re-checks could get stuck
|
||||
* Clean up the comment meta details after deleting a comment
|
||||
* Only show the status badge if the comment status has been changed by someone/something other than Akismet
|
||||
* Show a 'History' link in the row-actions
|
||||
* Translation fixes
|
||||
* Reduced font-size on author name
|
||||
* Moved "flagged by..." notification to top right corner of comment container and removed heavy styling
|
||||
* Hid "flagged by..." notification while on dashboard
|
||||
|
||||
= 2.5.0 =
|
||||
*Release Date - 7th December, 2010*
|
||||
|
||||
* Track comment actions under 'Akismet Status' on the edit comment screen
|
||||
* Fix a few remaining deprecated function calls ( props Mike Glendinning )
|
||||
* Use HTTPS for the stats IFRAME when wp-admin is using HTTPS
|
||||
* Use the WordPress HTTP class if available
|
||||
* Move the admin UI code to a separate file, only loaded when needed
|
||||
* Add cron retry feature, to replace the old connectivity check
|
||||
* Display Akismet status badge beside each comment
|
||||
* Record history for each comment, and display it on the edit page
|
||||
* Record the complete comment as originally submitted in comment_meta, to use when reporting spam and ham
|
||||
* Highlight links in comment content
|
||||
* New option, "Show the number of comments you've approved beside each comment author."
|
||||
* New option, "Use a nonce on the comment form."
|
||||
|
||||
= 2.4.0 =
|
||||
*Release Date - 23rd August, 2010*
|
||||
|
||||
* Spell out that the license is GPLv2
|
||||
* Fix PHP warnings
|
||||
* Fix WordPress deprecated function calls
|
||||
* Fire the delete_comment action when deleting comments
|
||||
* Move code specific for older WP versions to legacy.php
|
||||
* General code clean up
|
||||
|
||||
= 2.3.0 =
|
||||
*Release Date - 5th June, 2010*
|
||||
|
||||
* Fix "Are you sure" nonce message on config screen in WPMU
|
||||
* Fix XHTML compliance issue in sidebar widget
|
||||
* Change author link; remove some old references to WordPress.com accounts
|
||||
* Localize the widget title (core ticket #13879)
|
||||
|
||||
= 2.2.9 =
|
||||
*Release Date - 2nd June, 2010*
|
||||
|
||||
* Eliminate a potential conflict with some plugins that may cause spurious reports
|
||||
|
||||
= 2.2.8 =
|
||||
*Release Date - 27th May, 2010*
|
||||
|
||||
* Fix bug in initial comment check for ipv6 addresses
|
||||
* Report comments as ham when they are moved from spam to moderation
|
||||
* Report comments as ham when clicking undo after spam
|
||||
* Use transition_comment_status action when available instead of older actions for spam/ham submissions
|
||||
* Better diagnostic messages when PHP network functions are unavailable
|
||||
* Better handling of comments by logged-in users
|
||||
|
||||
= 2.2.7 =
|
||||
*Release Date - 17th December, 2009*
|
||||
|
||||
* Add a new AKISMET_VERSION constant
|
||||
* Reduce the possibility of over-counting spam when another spam filter plugin is in use
|
||||
* Disable the connectivity check when the API key is hard-coded for WPMU
|
||||
|
||||
= 2.2.6 =
|
||||
*Release Date - 20th July, 2009*
|
||||
|
||||
* Fix a global warning introduced in 2.2.5
|
||||
* Add changelog and additional readme.txt tags
|
||||
* Fix an array conversion warning in some versions of PHP
|
||||
* Support a new WPCOM_API_KEY constant for easier use with WordPress MU
|
||||
|
||||
= 2.2.5 =
|
||||
*Release Date - 13th July, 2009*
|
||||
|
||||
* Include a new Server Connectivity diagnostic check, to detect problems caused by firewalls
|
||||
|
||||
= 2.2.4 =
|
||||
*Release Date - 3rd June, 2009*
|
||||
|
||||
* Fixed a key problem affecting the stats feature in WordPress MU
|
||||
* Provide additional blog information in Akismet API calls
|
||||
1377
wp-content/plugins/akismet/class.akismet-admin.php
Normal file
186
wp-content/plugins/akismet/class.akismet-cli.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
WP_CLI::add_command( 'akismet', 'Akismet_CLI' );
|
||||
|
||||
/**
|
||||
* Filter spam comments.
|
||||
*/
|
||||
class Akismet_CLI extends WP_CLI_Command {
|
||||
/**
|
||||
* Checks one or more comments against the Akismet API.
|
||||
*
|
||||
* ## OPTIONS
|
||||
* <comment_id>...
|
||||
* : The ID(s) of the comment(s) to check.
|
||||
*
|
||||
* [--noaction]
|
||||
* : Don't change the status of the comment. Just report what Akismet thinks it is.
|
||||
*
|
||||
* ## EXAMPLES
|
||||
*
|
||||
* wp akismet check 12345
|
||||
*
|
||||
* @alias comment-check
|
||||
*/
|
||||
public function check( $args, $assoc_args ) {
|
||||
foreach ( $args as $comment_id ) {
|
||||
if ( isset( $assoc_args['noaction'] ) ) {
|
||||
// Check the comment, but don't reclassify it.
|
||||
$api_response = Akismet::check_db_comment( $comment_id, 'wp-cli' );
|
||||
}
|
||||
else {
|
||||
$api_response = Akismet::recheck_comment( $comment_id, 'wp-cli' );
|
||||
}
|
||||
|
||||
if ( 'true' === $api_response ) {
|
||||
WP_CLI::line( sprintf( __( "Comment #%d is spam.", 'akismet' ), $comment_id ) );
|
||||
}
|
||||
else if ( 'false' === $api_response ) {
|
||||
WP_CLI::line( sprintf( __( "Comment #%d is not spam.", 'akismet' ), $comment_id ) );
|
||||
}
|
||||
else {
|
||||
if ( false === $api_response ) {
|
||||
WP_CLI::error( __( "Failed to connect to Akismet.", 'akismet' ) );
|
||||
}
|
||||
else if ( is_wp_error( $api_response ) ) {
|
||||
WP_CLI::warning( sprintf( __( "Comment #%d could not be checked.", 'akismet' ), $comment_id ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recheck all comments in the Pending queue.
|
||||
*
|
||||
* ## EXAMPLES
|
||||
*
|
||||
* wp akismet recheck_queue
|
||||
*
|
||||
* @alias recheck-queue
|
||||
*/
|
||||
public function recheck_queue() {
|
||||
$batch_size = 100;
|
||||
$start = 0;
|
||||
|
||||
$total_counts = array();
|
||||
|
||||
do {
|
||||
$result_counts = Akismet_Admin::recheck_queue_portion( $start, $batch_size );
|
||||
|
||||
if ( $result_counts['processed'] > 0 ) {
|
||||
foreach ( $result_counts as $key => $count ) {
|
||||
if ( ! isset( $total_counts[ $key ] ) ) {
|
||||
$total_counts[ $key ] = $count;
|
||||
}
|
||||
else {
|
||||
$total_counts[ $key ] += $count;
|
||||
}
|
||||
}
|
||||
$start += $batch_size;
|
||||
$start -= $result_counts['spam']; // These comments will have been removed from the queue.
|
||||
}
|
||||
} while ( $result_counts['processed'] > 0 );
|
||||
|
||||
WP_CLI::line( sprintf( _n( "Processed %d comment.", "Processed %d comments.", $total_counts['processed'], 'akismet' ), number_format( $total_counts['processed'] ) ) );
|
||||
WP_CLI::line( sprintf( _n( "%d comment moved to Spam.", "%d comments moved to Spam.", $total_counts['spam'], 'akismet' ), number_format( $total_counts['spam'] ) ) );
|
||||
|
||||
if ( $total_counts['error'] ) {
|
||||
WP_CLI::line( sprintf( _n( "%d comment could not be checked.", "%d comments could not be checked.", $total_counts['error'], 'akismet' ), number_format( $total_counts['error'] ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches stats from the Akismet API.
|
||||
*
|
||||
* ## OPTIONS
|
||||
*
|
||||
* [<interval>]
|
||||
* : The time period for which to retrieve stats.
|
||||
* ---
|
||||
* default: all
|
||||
* options:
|
||||
* - days
|
||||
* - months
|
||||
* - all
|
||||
* ---
|
||||
*
|
||||
* [--format=<format>]
|
||||
* : Allows overriding the output of the command when listing connections.
|
||||
* ---
|
||||
* default: table
|
||||
* options:
|
||||
* - table
|
||||
* - json
|
||||
* - csv
|
||||
* - yaml
|
||||
* - count
|
||||
* ---
|
||||
*
|
||||
* [--summary]
|
||||
* : When set, will display a summary of the stats.
|
||||
*
|
||||
* ## EXAMPLES
|
||||
*
|
||||
* wp akismet stats
|
||||
* wp akismet stats all
|
||||
* wp akismet stats days
|
||||
* wp akismet stats months
|
||||
* wp akismet stats all --summary
|
||||
*/
|
||||
public function stats( $args, $assoc_args ) {
|
||||
$api_key = Akismet::get_api_key();
|
||||
|
||||
if ( empty( $api_key ) ) {
|
||||
WP_CLI::error( __( 'API key must be set to fetch stats.', 'akismet' ) );
|
||||
}
|
||||
|
||||
switch ( $args[0] ) {
|
||||
case 'days':
|
||||
$interval = '60-days';
|
||||
break;
|
||||
case 'months':
|
||||
$interval = '6-months';
|
||||
break;
|
||||
default:
|
||||
$interval = 'all';
|
||||
break;
|
||||
}
|
||||
|
||||
$request_args = array(
|
||||
'blog' => get_option( 'home' ),
|
||||
'key' => $api_key,
|
||||
'from' => $interval,
|
||||
);
|
||||
|
||||
$request_args = apply_filters( 'akismet_request_args', $request_args, 'get-stats' );
|
||||
|
||||
$response = Akismet::http_post( Akismet::build_query( $request_args ), 'get-stats' );
|
||||
|
||||
if ( empty( $response[1] ) ) {
|
||||
WP_CLI::error( __( 'Currently unable to fetch stats. Please try again.', 'akismet' ) );
|
||||
}
|
||||
|
||||
$response_body = json_decode( $response[1], true );
|
||||
|
||||
if ( is_null( $response_body ) ) {
|
||||
WP_CLI::error( __( 'Stats response could not be decoded.', 'akismet' ) );
|
||||
}
|
||||
|
||||
if ( isset( $assoc_args['summary'] ) ) {
|
||||
$keys = array(
|
||||
'spam',
|
||||
'ham',
|
||||
'missed_spam',
|
||||
'false_positives',
|
||||
'accuracy',
|
||||
'time_saved',
|
||||
);
|
||||
|
||||
WP_CLI\Utils\format_items( $assoc_args['format'], array( $response_body ), $keys );
|
||||
}
|
||||
else {
|
||||
$stats = $response_body['breakdown'];
|
||||
WP_CLI\Utils\format_items( $assoc_args['format'], $stats, array_keys( end( $stats ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
373
wp-content/plugins/akismet/class.akismet-rest-api.php
Normal file
@@ -0,0 +1,373 @@
|
||||
<?php
|
||||
|
||||
class Akismet_REST_API {
|
||||
/**
|
||||
* Register the REST API routes.
|
||||
*/
|
||||
public static function init() {
|
||||
if ( ! function_exists( 'register_rest_route' ) ) {
|
||||
// The REST API wasn't integrated into core until 4.4, and we support 4.0+ (for now).
|
||||
return false;
|
||||
}
|
||||
|
||||
register_rest_route( 'akismet/v1', '/key', array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
|
||||
'callback' => array( 'Akismet_REST_API', 'get_key' ),
|
||||
), array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
|
||||
'callback' => array( 'Akismet_REST_API', 'set_key' ),
|
||||
'args' => array(
|
||||
'key' => array(
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ),
|
||||
'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ),
|
||||
),
|
||||
),
|
||||
), array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
|
||||
'callback' => array( 'Akismet_REST_API', 'delete_key' ),
|
||||
)
|
||||
) );
|
||||
|
||||
register_rest_route( 'akismet/v1', '/settings/', array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
|
||||
'callback' => array( 'Akismet_REST_API', 'get_settings' ),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
|
||||
'callback' => array( 'Akismet_REST_API', 'set_boolean_settings' ),
|
||||
'args' => array(
|
||||
'akismet_strictness' => array(
|
||||
'required' => false,
|
||||
'type' => 'boolean',
|
||||
'description' => __( 'If true, Akismet will automatically discard the worst spam automatically rather than putting it in the spam folder.', 'akismet' ),
|
||||
),
|
||||
'akismet_show_user_comments_approved' => array(
|
||||
'required' => false,
|
||||
'type' => 'boolean',
|
||||
'description' => __( 'If true, show the number of approved comments beside each comment author in the comments list page.', 'akismet' ),
|
||||
),
|
||||
),
|
||||
)
|
||||
) );
|
||||
|
||||
register_rest_route( 'akismet/v1', '/stats', array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
|
||||
'callback' => array( 'Akismet_REST_API', 'get_stats' ),
|
||||
'args' => array(
|
||||
'interval' => array(
|
||||
'required' => false,
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_interval' ),
|
||||
'description' => __( 'The time period for which to retrieve stats. Options: 60-days, 6-months, all', 'akismet' ),
|
||||
'default' => 'all',
|
||||
),
|
||||
),
|
||||
) );
|
||||
|
||||
register_rest_route( 'akismet/v1', '/stats/(?P<interval>[\w+])', array(
|
||||
'args' => array(
|
||||
'interval' => array(
|
||||
'description' => __( 'The time period for which to retrieve stats. Options: 60-days, 6-months, all', 'akismet' ),
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
|
||||
'callback' => array( 'Akismet_REST_API', 'get_stats' ),
|
||||
)
|
||||
) );
|
||||
|
||||
register_rest_route( 'akismet/v1', '/alert', array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ),
|
||||
'callback' => array( 'Akismet_REST_API', 'get_alert' ),
|
||||
'args' => array(
|
||||
'key' => array(
|
||||
'required' => false,
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ),
|
||||
'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ),
|
||||
'callback' => array( 'Akismet_REST_API', 'set_alert' ),
|
||||
'args' => array(
|
||||
'key' => array(
|
||||
'required' => false,
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ),
|
||||
'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ),
|
||||
'callback' => array( 'Akismet_REST_API', 'delete_alert' ),
|
||||
'args' => array(
|
||||
'key' => array(
|
||||
'required' => false,
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ),
|
||||
'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ),
|
||||
),
|
||||
),
|
||||
)
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current Akismet API key.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public static function get_key( $request = null ) {
|
||||
return rest_ensure_response( Akismet::get_api_key() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the API key, if possible.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public static function set_key( $request ) {
|
||||
if ( defined( 'WPCOM_API_KEY' ) ) {
|
||||
return rest_ensure_response( new WP_Error( 'hardcoded_key', __( 'This site\'s API key is hardcoded and cannot be changed via the API.', 'akismet' ), array( 'status'=> 409 ) ) );
|
||||
}
|
||||
|
||||
$new_api_key = $request->get_param( 'key' );
|
||||
|
||||
if ( ! self::key_is_valid( $new_api_key ) ) {
|
||||
return rest_ensure_response( new WP_Error( 'invalid_key', __( 'The value provided is not a valid and registered API key.', 'akismet' ), array( 'status' => 400 ) ) );
|
||||
}
|
||||
|
||||
update_option( 'wordpress_api_key', $new_api_key );
|
||||
|
||||
return self::get_key();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset the API key, if possible.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public static function delete_key( $request ) {
|
||||
if ( defined( 'WPCOM_API_KEY' ) ) {
|
||||
return rest_ensure_response( new WP_Error( 'hardcoded_key', __( 'This site\'s API key is hardcoded and cannot be deleted.', 'akismet' ), array( 'status'=> 409 ) ) );
|
||||
}
|
||||
|
||||
delete_option( 'wordpress_api_key' );
|
||||
|
||||
return rest_ensure_response( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Akismet settings.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public static function get_settings( $request = null ) {
|
||||
return rest_ensure_response( array(
|
||||
'akismet_strictness' => ( get_option( 'akismet_strictness', '1' ) === '1' ),
|
||||
'akismet_show_user_comments_approved' => ( get_option( 'akismet_show_user_comments_approved', '1' ) === '1' ),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the Akismet settings.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public static function set_boolean_settings( $request ) {
|
||||
foreach ( array(
|
||||
'akismet_strictness',
|
||||
'akismet_show_user_comments_approved',
|
||||
) as $setting_key ) {
|
||||
|
||||
$setting_value = $request->get_param( $setting_key );
|
||||
if ( is_null( $setting_value ) ) {
|
||||
// This setting was not specified.
|
||||
continue;
|
||||
}
|
||||
|
||||
// From 4.7+, WP core will ensure that these are always boolean
|
||||
// values because they are registered with 'type' => 'boolean',
|
||||
// but we need to do this ourselves for prior versions.
|
||||
$setting_value = Akismet_REST_API::parse_boolean( $setting_value );
|
||||
|
||||
update_option( $setting_key, $setting_value ? '1' : '0' );
|
||||
}
|
||||
|
||||
return self::get_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a numeric or string boolean value into a boolean.
|
||||
*
|
||||
* @param mixed $value The value to convert into a boolean.
|
||||
* @return bool The converted value.
|
||||
*/
|
||||
public static function parse_boolean( $value ) {
|
||||
switch ( $value ) {
|
||||
case true:
|
||||
case 'true':
|
||||
case '1':
|
||||
case 1:
|
||||
return true;
|
||||
|
||||
case false:
|
||||
case 'false':
|
||||
case '0':
|
||||
case 0:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return (bool) $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Akismet stats for a given time period.
|
||||
*
|
||||
* Possible `interval` values:
|
||||
* - all
|
||||
* - 60-days
|
||||
* - 6-months
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public static function get_stats( $request ) {
|
||||
$api_key = Akismet::get_api_key();
|
||||
|
||||
$interval = $request->get_param( 'interval' );
|
||||
|
||||
$stat_totals = array();
|
||||
|
||||
$request_args = array(
|
||||
'blog' => get_option( 'home' ),
|
||||
'key' => $api_key,
|
||||
'from' => $interval,
|
||||
);
|
||||
|
||||
$request_args = apply_filters( 'akismet_request_args', $request_args, 'get-stats' );
|
||||
|
||||
$response = Akismet::http_post( Akismet::build_query( $request_args ), 'get-stats' );
|
||||
|
||||
if ( ! empty( $response[1] ) ) {
|
||||
$stat_totals[$interval] = json_decode( $response[1] );
|
||||
}
|
||||
|
||||
return rest_ensure_response( $stat_totals );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current alert code and message. Alert codes are used to notify the site owner
|
||||
* if there's a problem, like a connection issue between their site and the Akismet API,
|
||||
* invalid requests being sent, etc.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public static function get_alert( $request ) {
|
||||
return rest_ensure_response( array(
|
||||
'code' => get_option( 'akismet_alert_code' ),
|
||||
'message' => get_option( 'akismet_alert_msg' ),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the current alert code and message by triggering a call to the Akismet server.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public static function set_alert( $request ) {
|
||||
delete_option( 'akismet_alert_code' );
|
||||
delete_option( 'akismet_alert_msg' );
|
||||
|
||||
// Make a request so the most recent alert code and message are retrieved.
|
||||
Akismet::verify_key( Akismet::get_api_key() );
|
||||
|
||||
return self::get_alert( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the current alert code and message.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public static function delete_alert( $request ) {
|
||||
delete_option( 'akismet_alert_code' );
|
||||
delete_option( 'akismet_alert_msg' );
|
||||
|
||||
return self::get_alert( $request );
|
||||
}
|
||||
|
||||
private static function key_is_valid( $key ) {
|
||||
$request_args = array(
|
||||
'key' => $key,
|
||||
'blog' => get_option( 'home' ),
|
||||
);
|
||||
|
||||
$request_args = apply_filters( 'akismet_request_args', $request_args, 'verify-key' );
|
||||
|
||||
$response = Akismet::http_post( Akismet::build_query( $request_args ), 'verify-key' );
|
||||
|
||||
if ( $response[1] == 'valid' ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function privileged_permission_callback() {
|
||||
return current_user_can( 'manage_options' );
|
||||
}
|
||||
|
||||
/**
|
||||
* For calls that Akismet.com makes to the site to clear outdated alert codes, use the API key for authorization.
|
||||
*/
|
||||
public static function remote_call_permission_callback( $request ) {
|
||||
$local_key = Akismet::get_api_key();
|
||||
|
||||
return $local_key && ( strtolower( $request->get_param( 'key' ) ) === strtolower( $local_key ) );
|
||||
}
|
||||
|
||||
public static function sanitize_interval( $interval, $request, $param ) {
|
||||
$interval = trim( $interval );
|
||||
|
||||
$valid_intervals = array( '60-days', '6-months', 'all', );
|
||||
|
||||
if ( ! in_array( $interval, $valid_intervals ) ) {
|
||||
$interval = 'all';
|
||||
}
|
||||
|
||||
return $interval;
|
||||
}
|
||||
|
||||
public static function sanitize_key( $key, $request, $param ) {
|
||||
return trim( $key );
|
||||
}
|
||||
}
|
||||
137
wp-content/plugins/akismet/class.akismet-widget.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Akismet
|
||||
*/
|
||||
class Akismet_Widget extends WP_Widget {
|
||||
|
||||
function __construct() {
|
||||
load_plugin_textdomain( 'akismet' );
|
||||
|
||||
parent::__construct(
|
||||
'akismet_widget',
|
||||
__( 'Akismet Widget' , 'akismet'),
|
||||
array( 'description' => __( 'Display the number of spam comments Akismet has caught' , 'akismet') )
|
||||
);
|
||||
|
||||
if ( is_active_widget( false, false, $this->id_base ) ) {
|
||||
add_action( 'wp_head', array( $this, 'css' ) );
|
||||
}
|
||||
}
|
||||
|
||||
function css() {
|
||||
?>
|
||||
|
||||
<style type="text/css">
|
||||
.a-stats {
|
||||
width: auto;
|
||||
}
|
||||
.a-stats a {
|
||||
background: #7CA821;
|
||||
background-image:-moz-linear-gradient(0% 100% 90deg,#5F8E14,#7CA821);
|
||||
background-image:-webkit-gradient(linear,0% 0,0% 100%,from(#7CA821),to(#5F8E14));
|
||||
border: 1px solid #5F8E14;
|
||||
border-radius:3px;
|
||||
color: #CFEA93;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
font-weight: normal;
|
||||
height: 100%;
|
||||
-moz-border-radius:3px;
|
||||
padding: 7px 0 8px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
-webkit-border-radius:3px;
|
||||
width: 100%;
|
||||
}
|
||||
.a-stats a:hover {
|
||||
text-decoration: none;
|
||||
background-image:-moz-linear-gradient(0% 100% 90deg,#6F9C1B,#659417);
|
||||
background-image:-webkit-gradient(linear,0% 0,0% 100%,from(#659417),to(#6F9C1B));
|
||||
}
|
||||
.a-stats .count {
|
||||
color: #FFF;
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
line-height: 16px;
|
||||
padding: 0 13px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
||||
function form( $instance ) {
|
||||
if ( $instance && isset( $instance['title'] ) ) {
|
||||
$title = $instance['title'];
|
||||
}
|
||||
else {
|
||||
$title = __( 'Spam Blocked' , 'akismet' );
|
||||
}
|
||||
?>
|
||||
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php esc_html_e( 'Title:' , 'akismet'); ?></label>
|
||||
<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
|
||||
</p>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
||||
function update( $new_instance, $old_instance ) {
|
||||
$instance = array();
|
||||
$instance['title'] = strip_tags( $new_instance['title'] );
|
||||
return $instance;
|
||||
}
|
||||
|
||||
function widget( $args, $instance ) {
|
||||
$count = get_option( 'akismet_spam_count' );
|
||||
|
||||
if ( ! isset( $instance['title'] ) ) {
|
||||
$instance['title'] = __( 'Spam Blocked' , 'akismet' );
|
||||
}
|
||||
|
||||
echo $args['before_widget'];
|
||||
if ( ! empty( $instance['title'] ) ) {
|
||||
echo $args['before_title'];
|
||||
echo esc_html( $instance['title'] );
|
||||
echo $args['after_title'];
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="a-stats">
|
||||
<a href="https://akismet.com" target="_blank" rel="noopener" title="">
|
||||
<?php
|
||||
|
||||
echo wp_kses(
|
||||
sprintf(
|
||||
/* translators: The placeholder is the number of pieces of spam blocked by Akismet. */
|
||||
_n(
|
||||
'<strong class="count">%1$s spam</strong> blocked by <strong>Akismet</strong>',
|
||||
'<strong class="count">%1$s spam</strong> blocked by <strong>Akismet</strong>',
|
||||
$count,
|
||||
'akismet'
|
||||
),
|
||||
number_format_i18n( $count )
|
||||
),
|
||||
array(
|
||||
'strong' => array(
|
||||
'class' => true,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
echo $args['after_widget'];
|
||||
}
|
||||
}
|
||||
|
||||
function akismet_register_widgets() {
|
||||
register_widget( 'Akismet_Widget' );
|
||||
}
|
||||
|
||||
add_action( 'widgets_init', 'akismet_register_widgets' );
|
||||
1874
wp-content/plugins/akismet/class.akismet.php
Normal file
2
wp-content/plugins/akismet/index.php
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
# Silence is golden.
|
||||
130
wp-content/plugins/akismet/readme.txt
Normal file
@@ -0,0 +1,130 @@
|
||||
=== Akismet Anti-spam: Spam Protection ===
|
||||
Contributors: matt, ryan, andy, mdawaffe, tellyworth, josephscott, lessbloat, eoigal, cfinke, automattic, jgs, procifer, stephdau, kbrownkd, bluefuton, akismetantispam
|
||||
Tags: comments, spam, antispam, anti-spam, contact form, anti spam, comment moderation, comment spam, contact form spam, spam comments
|
||||
Requires at least: 5.8
|
||||
Tested up to: 6.4
|
||||
Stable tag: 5.3.1
|
||||
License: GPLv2 or later
|
||||
|
||||
The best anti-spam protection to block spam comments and spam in a contact form. The most trusted antispam solution for WordPress and WooCommerce.
|
||||
|
||||
== Description ==
|
||||
|
||||
The best anti-spam protection to block spam comments and spam in a contact form. The most trusted antispam solution for WordPress and WooCommerce.
|
||||
|
||||
Akismet checks your comments and contact form submissions against our global database of spam to prevent your site from publishing malicious content. You can review the comment spam it catches on your blog's "Comments" admin screen.
|
||||
|
||||
Major features in Akismet include:
|
||||
|
||||
* Automatically checks all comments and filters out the ones that look like spam.
|
||||
* Each comment has a status history, so you can easily see which comments were caught or cleared by Akismet and which were spammed or unspammed by a moderator.
|
||||
* URLs are shown in the comment body to reveal hidden or misleading links.
|
||||
* Moderators can see the number of approved comments for each user.
|
||||
* A discard feature that outright blocks the worst spam, saving you disk space and speeding up your site.
|
||||
|
||||
PS: You'll be prompted to get an Akismet.com API key to use it, once activated. Keys are free for personal blogs; paid subscriptions are available for businesses and commercial sites.
|
||||
|
||||
== Installation ==
|
||||
|
||||
Upload the Akismet plugin to your blog, activate it, and then enter your Akismet.com API key.
|
||||
|
||||
1, 2, 3: You're done!
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 5.3.1 =
|
||||
*Release Date - 17 January 2024*
|
||||
|
||||
* Make the plugin more resilient when asset files are missing (as seen in WordPress Playground).
|
||||
* Add a link to the 'Account overview' page on akismet.com.
|
||||
* Fix a minor error that occurs when another plugin removes all comment actions from the dashboard.
|
||||
* Add the akismet_request_args filter to allow request args in Akismet API requests to be filtered.
|
||||
* Fix a bug that causes some contact forms to include unnecessary data in the comment_content parameter.
|
||||
|
||||
= 5.3 =
|
||||
*Release Date - 14 September 2023*
|
||||
|
||||
* Improve display of user notices.
|
||||
* Add stylesheets for RTL languages.
|
||||
* Remove initial disabled state from 'Save changes' button.
|
||||
* Improve accessibility of API key entry form.
|
||||
* Add new filter hooks for Fluent Forms.
|
||||
* Fix issue with PHP 8.1 compatibility.
|
||||
|
||||
= 5.2 =
|
||||
*Release Date - 21 June 2023*
|
||||
|
||||
* Visual refresh of Akismet stats.
|
||||
* Improve PHP 8.1 compatibility.
|
||||
* Improve appearance of plugin to match updated stats.
|
||||
* Change minimum supported PHP version to 5.6 to match WordPress.
|
||||
* Drop IE11 support and update minimum WordPress version to 5.8 (where IE11 support was removed from WP Core).
|
||||
|
||||
= 5.1 =
|
||||
*Release Date - 20 March 2023*
|
||||
|
||||
* Removed unnecessary limit notices from admin page.
|
||||
* Improved spam detection by including post taxonomies in the comment-check call.
|
||||
* Removed API keys from stats iframes to avoid possible inadvertent exposure.
|
||||
|
||||
= 5.0.2 =
|
||||
*Release Date - 1 December 2022*
|
||||
|
||||
* Improved compatibility with themes that hide or show UI elements based on mouse movements.
|
||||
* Increased security of API keys by sending them in request bodies instead of subdomains.
|
||||
|
||||
= 5.0.1 =
|
||||
*Release Date - 28 September 2022*
|
||||
|
||||
* Added an empty state for the Statistics section on the admin page.
|
||||
* Fixed a bug that broke some admin page links when Jetpack plugins are active.
|
||||
* Marked some event listeners as passive to improve performance in newer browsers.
|
||||
* Disabled interaction observation on forms that post to other domains.
|
||||
|
||||
= 5.0 =
|
||||
*Release Date - 26 July 2022*
|
||||
|
||||
* Added a new feature to catch spammers by observing how they interact with the page.
|
||||
|
||||
= 4.2.5 =
|
||||
*Release Date - 11 July 2022*
|
||||
|
||||
* Fixed a bug that added unnecessary comment history entries after comment rechecks.
|
||||
* Added a notice that displays when WP-Cron is disabled and might be affecting comment rechecks.
|
||||
|
||||
= 4.2.4 =
|
||||
*Release Date - 20 May 2022*
|
||||
|
||||
* Improved translator instructions for comment history.
|
||||
* Bumped the "Tested up to" tag to WP 6.0.
|
||||
|
||||
= 4.2.3 =
|
||||
*Release Date - 25 April 2022*
|
||||
|
||||
* Improved compatibility with Fluent Forms
|
||||
* Fixed missing translation domains
|
||||
* Updated stats URL.
|
||||
* Improved accessibility of elements on the config page.
|
||||
|
||||
= 4.2.2 =
|
||||
*Release Date - 24 January 2022*
|
||||
|
||||
* Improved compatibility with Formidable Forms
|
||||
* Fixed a bug that could cause issues when multiple contact forms appear on one page.
|
||||
* Updated delete_comment and deleted_comment actions to pass two arguments to match WordPress core since 4.9.0.
|
||||
* Added a filter that allows comment types to be excluded when counting users' approved comments.
|
||||
|
||||
= 4.2.1 =
|
||||
*Release Date - 1 October 2021*
|
||||
|
||||
* Fixed a bug causing AMP validation to fail on certain pages with forms.
|
||||
|
||||
= 4.2 =
|
||||
*Release Date - 30 September 2021*
|
||||
|
||||
* Added links to additional information on API usage notifications.
|
||||
* Reduced the number of network requests required for a comment page when running Akismet.
|
||||
* Improved compatibility with the most popular contact form plugins.
|
||||
* Improved API usage buttons for clarity on what upgrade is needed.
|
||||
|
||||
For older changelog entries, please see the [additional changelog.txt file](https://plugins.svn.wordpress.org/akismet/trunk/changelog.txt) delivered with the plugin.
|
||||
8
wp-content/plugins/akismet/views/activate.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<div class="akismet-box">
|
||||
<?php Akismet::view( 'title' ); ?>
|
||||
<?php Akismet::view( 'setup' );?>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="akismet-box">
|
||||
<?php Akismet::view( 'enter' );?>
|
||||
</div>
|
||||
326
wp-content/plugins/akismet/views/config.php
Normal file
@@ -0,0 +1,326 @@
|
||||
<?php
|
||||
|
||||
//phpcs:disable VariableAnalysis
|
||||
// There are "undefined" variables here because they're defined in the code that includes this file as a template.
|
||||
$kses_allow_link_href = array(
|
||||
'a' => array(
|
||||
'href' => true,
|
||||
),
|
||||
);
|
||||
?>
|
||||
<div id="akismet-plugin-container">
|
||||
<div class="akismet-masthead">
|
||||
<div class="akismet-masthead__inside-container">
|
||||
<?php Akismet::view( 'logo' ); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="akismet-lower">
|
||||
<?php if ( Akismet::get_api_key() ) { ?>
|
||||
<?php Akismet_Admin::display_status(); ?>
|
||||
<?php } ?>
|
||||
<?php if ( ! empty( $notices ) ) { ?>
|
||||
<?php foreach ( $notices as $notice ) { ?>
|
||||
<?php Akismet::view( 'notice', $notice ); ?>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
|
||||
<div class="akismet-card">
|
||||
<div class="akismet-section-header">
|
||||
<h2 class="akismet-section-header__label">
|
||||
<span><?php esc_html_e( 'Statistics', 'akismet' ); ?></span>
|
||||
</h2>
|
||||
|
||||
<?php if ( $stat_totals && isset( $stat_totals['all'] ) && (int) $stat_totals['all']->spam > 0 ) : ?>
|
||||
<div class="akismet-section-header__actions">
|
||||
<a href="<?php echo esc_url( Akismet_Admin::get_page_url( 'stats' ) ); ?>">
|
||||
<?php esc_html_e( 'Detailed stats', 'akismet' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div> <!-- close akismet-section-header -->
|
||||
|
||||
<div class="akismet-new-snapshot">
|
||||
<?php /* name attribute on iframe is used as a cache-buster here to force Firefox to load the new style charts: https://bugzilla.mozilla.org/show_bug.cgi?id=356558 */ ?>
|
||||
<div class="akismet-new-snapshot__chart">
|
||||
<iframe id="stats-iframe" allowtransparency="true" scrolling="no" frameborder="0" style="width: 100%; height: 220px; overflow: hidden;" src="<?php echo esc_url( sprintf( 'https://tools.akismet.com/1.0/snapshot.php?blog=%s&token=%s&height=200&locale=%s&is_redecorated=1', rawurlencode( get_option( 'home' ) ), rawurlencode( Akismet::get_access_token() ), get_locale() ) ); ?>" name="<?php echo esc_attr( 'snapshot-' . filemtime( __FILE__ ) ); ?>" title="<?php echo esc_attr__( 'Akismet stats' ); ?>"></iframe>
|
||||
</div>
|
||||
<ul class="akismet-new-snapshot__list">
|
||||
<li class="akismet-new-snapshot__item">
|
||||
<h3 class="akismet-new-snapshot__header"><?php esc_html_e( 'Past six months', 'akismet' ); ?></h3>
|
||||
<span class="akismet-new-snapshot__number"><?php echo number_format( $stat_totals['6-months']->spam ); ?></span>
|
||||
<span class="akismet-new-snapshot__text"><?php echo esc_html( _n( 'Spam blocked', 'Spam blocked', $stat_totals['6-months']->spam, 'akismet' ) ); ?></span>
|
||||
</li>
|
||||
<li class="akismet-new-snapshot__item">
|
||||
<h3 class="akismet-new-snapshot__header"><?php esc_html_e( 'All time', 'akismet' ); ?></h3>
|
||||
<span class="akismet-new-snapshot__number"><?php echo number_format( $stat_totals['all']->spam ); ?></span>
|
||||
<span class="akismet-new-snapshot__text"><?php echo esc_html( _n( 'Spam blocked', 'Spam blocked', $stat_totals['all']->spam, 'akismet' ) ); ?></span>
|
||||
</li>
|
||||
<li class="akismet-new-snapshot__item">
|
||||
<h3 class="akismet-new-snapshot__header"><?php esc_html_e( 'Accuracy', 'akismet' ); ?></h3>
|
||||
<span class="akismet-new-snapshot__number"><?php echo floatval( $stat_totals['all']->accuracy ); ?>%</span>
|
||||
<span class="akismet-new-snapshot__text">
|
||||
<?php
|
||||
/* translators: %s: number of spam missed by Akismet */
|
||||
echo esc_html( sprintf( _n( '%s missed spam', '%s missed spam', $stat_totals['all']->missed_spam, 'akismet' ), number_format( $stat_totals['all']->missed_spam ) ) ) . ', ';
|
||||
/* translators: %s: number of false positive spam flagged by Akismet */
|
||||
echo esc_html( sprintf( _n( '%s false positive', '%s false positives', $stat_totals['all']->false_positives, 'akismet' ), number_format( $stat_totals['all']->false_positives ) ) );
|
||||
?>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div> <!-- close akismet-new-snapshot -->
|
||||
|
||||
<?php else : ?>
|
||||
</div> <!-- close akismet-section-header -->
|
||||
<div class="inside">
|
||||
<p class="akismet-awaiting-stats"><?php esc_html_e( 'Akismet is active and ready to stop spam. Your site’s spam statistics will be displayed here.', 'akismet' ); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
</div> <!-- close akismet-card -->
|
||||
|
||||
<?php if ( $akismet_user ) : ?>
|
||||
<div class="akismet-card">
|
||||
<div class="akismet-section-header">
|
||||
<h2 class="akismet-section-header__label">
|
||||
<span><?php esc_html_e( 'Settings', 'akismet' ); ?></span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="inside">
|
||||
<form action="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>" autocomplete="off" method="POST" id="akismet-settings-form">
|
||||
|
||||
<div class="akismet-settings">
|
||||
<?php if ( ! Akismet::predefined_api_key() ) : ?>
|
||||
<div class="akismet-settings__row">
|
||||
<h3 class="akismet-settings__row-title">
|
||||
<label class="akismet-settings__row-label" for="key"><?php esc_html_e( 'API key', 'akismet' ); ?></label>
|
||||
</h3>
|
||||
<div class="akismet-settings__row-input">
|
||||
<span class="api-key"><input id="key" name="key" type="text" size="15" value="<?php echo esc_attr( get_option( 'wordpress_api_key' ) ); ?>" class="<?php echo esc_attr( 'regular-text code ' . $akismet_user->status ); ?>"></span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
//phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_GET['ssl_status'] ) ) :
|
||||
?>
|
||||
<div class="akismet-settings__row">
|
||||
<div class="akismet-settings__row-text">
|
||||
<h3 class="akismet-settings__row-title"><?php esc_html_e( 'SSL status', 'akismet' ); ?></h3>
|
||||
<div class="akismet-settings__row-description">
|
||||
<?php if ( ! wp_http_supports( array( 'ssl' ) ) ) : ?>
|
||||
<strong><?php esc_html_e( 'Disabled.', 'akismet' ); ?></strong>
|
||||
<?php esc_html_e( 'Your Web server cannot make SSL requests; contact your Web host and ask them to add support for SSL requests.', 'akismet' ); ?>
|
||||
<?php else : ?>
|
||||
<?php $ssl_disabled = get_option( 'akismet_ssl_disabled' ); ?>
|
||||
|
||||
<?php if ( $ssl_disabled ) : ?>
|
||||
<strong><?php esc_html_e( 'Temporarily disabled.', 'akismet' ); ?></strong>
|
||||
<?php esc_html_e( 'Akismet encountered a problem with a previous SSL request and disabled it temporarily. It will begin using SSL for requests again shortly.', 'akismet' ); ?>
|
||||
<?php else : ?>
|
||||
<strong><?php esc_html_e( 'Enabled.', 'akismet' ); ?></strong>
|
||||
<?php esc_html_e( 'All systems functional.', 'akismet' ); ?>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="akismet-settings__row">
|
||||
<div class="akismet-settings__row-text">
|
||||
<h3 class="akismet-settings__row-title"><?php esc_html_e( 'Comments', 'akismet' ); ?></h3>
|
||||
</div>
|
||||
<div class="akismet-settings__row-input">
|
||||
<label class="akismet-settings__row-input-label" for="akismet_show_user_comments_approved">
|
||||
<input
|
||||
name="akismet_show_user_comments_approved"
|
||||
id="akismet_show_user_comments_approved"
|
||||
value="1"
|
||||
type="checkbox"
|
||||
<?php
|
||||
// If the option isn't set, or if it's enabled ('1'), or if it was enabled a long time ago ('true'), check the checkbox.
|
||||
checked( true, ( in_array( get_option( 'akismet_show_user_comments_approved' ), array( false, '1', 'true' ), true ) ) );
|
||||
?>
|
||||
/>
|
||||
<span class="akismet-settings__row-label-text">
|
||||
<?php esc_html_e( 'Show the number of approved comments beside each comment author.', 'akismet' ); ?>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="akismet-settings__row is-radio">
|
||||
<div class="akismet-settings__row-text">
|
||||
<h3 class="akismet-settings__row-title"><?php esc_html_e( 'Spam filtering', 'akismet' ); ?></h3>
|
||||
</div>
|
||||
<div class="akismet-settings__row-input">
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text">
|
||||
<span><?php esc_html_e( 'Akismet Anti-spam strictness', 'akismet' ); ?></span>
|
||||
</legend>
|
||||
<div>
|
||||
<label class="akismet-settings__row-input-label" for="akismet_strictness_1">
|
||||
<input type="radio" name="akismet_strictness" id="akismet_strictness_1" value="1" <?php checked( '1', get_option( 'akismet_strictness' ) ); ?> />
|
||||
<span class="akismet-settings__row-label-text">
|
||||
<?php esc_html_e( 'Silently discard the worst and most pervasive spam so I never see it.', 'akismet' ); ?>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="akismet-settings__row-input-label" for="akismet_strictness_0">
|
||||
<input type="radio" name="akismet_strictness" id="akismet_strictness_0" value="0" <?php checked( '0', get_option( 'akismet_strictness' ) ); ?> />
|
||||
<span class="akismet-settings__row-label-text">
|
||||
<?php esc_html_e( 'Always put spam in the Spam folder for review.', 'akismet' ); ?>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="akismet-settings__row-note">
|
||||
<strong><?php esc_html_e( 'Note:', 'akismet' ); ?></strong>
|
||||
<?php
|
||||
$delete_interval = max( 1, intval( apply_filters( 'akismet_delete_comment_interval', 15 ) ) );
|
||||
|
||||
$spam_folder_link = sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
esc_url( admin_url( 'edit-comments.php?comment_status=spam' ) ),
|
||||
esc_html__( 'spam folder', 'akismet' )
|
||||
);
|
||||
|
||||
// The _n() needs to be on one line so the i18n tooling can extract the translator comment.
|
||||
/* translators: %1$s: spam folder link, %2$d: delete interval in days */
|
||||
$delete_message = _n( 'Spam in the %1$s older than %2$d day is deleted automatically.', 'Spam in the %1$s older than %2$d days is deleted automatically.', $delete_interval, 'akismet' );
|
||||
|
||||
printf(
|
||||
wp_kses( $delete_message, $kses_allow_link_href ),
|
||||
wp_kses( $spam_folder_link, $kses_allow_link_href ),
|
||||
esc_html( $delete_interval )
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="akismet-settings__row is-radio">
|
||||
<div class="akismet-settings__row-text">
|
||||
<h3 class="akismet-settings__row-title"><?php esc_html_e( 'Privacy', 'akismet' ); ?></h3>
|
||||
</div>
|
||||
<div class="akismet-settings__row-input">
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text">
|
||||
<span><?php esc_html_e( 'Akismet privacy notice', 'akismet' ); ?></span>
|
||||
</legend>
|
||||
<div>
|
||||
<label class="akismet-settings__row-input-label" for="akismet_comment_form_privacy_notice_display">
|
||||
<input type="radio" name="akismet_comment_form_privacy_notice" id="akismet_comment_form_privacy_notice_display" value="display" <?php checked( 'display', get_option( 'akismet_comment_form_privacy_notice' ) ); ?> />
|
||||
<span class="akismet-settings__row-label-text">
|
||||
<?php esc_html_e( 'Display a privacy notice under your comment forms.', 'akismet' ); ?>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="akismet-settings__row-input-label" for="akismet_comment_form_privacy_notice_hide">
|
||||
<input type="radio" name="akismet_comment_form_privacy_notice" id="akismet_comment_form_privacy_notice_hide" value="hide" <?php echo in_array( get_option( 'akismet_comment_form_privacy_notice' ), array( 'display', 'hide' ), true ) ? checked( 'hide', get_option( 'akismet_comment_form_privacy_notice' ), false ) : 'checked="checked"'; ?> />
|
||||
<span class="akismet-settings__row-label-text">
|
||||
<?php esc_html_e( 'Do not display privacy notice.', 'akismet' ); ?>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="akismet-settings__row-note">
|
||||
<?php esc_html_e( 'To help your site with transparency under privacy laws like the GDPR, Akismet can display a notice to your users under your comment forms.', 'akismet' ); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="akismet-card-actions">
|
||||
<?php if ( ! Akismet::predefined_api_key() ) : ?>
|
||||
<div id="delete-action" class="akismet-card-actions__secondary-action">
|
||||
<a class="submitdelete deletion" href="<?php echo esc_url( Akismet_Admin::get_page_url( 'delete_key' ) ); ?>"><?php esc_html_e( 'Disconnect this account', 'akismet' ); ?></a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php wp_nonce_field( Akismet_Admin::NONCE ); ?>
|
||||
|
||||
<div id="publishing-action">
|
||||
<input type="hidden" name="action" value="enter-key">
|
||||
<input type="submit" name="submit" id="submit" class="akismet-button akismet-could-be-primary" value="<?php esc_attr_e( 'Save changes', 'akismet' ); ?>">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ( ! Akismet::predefined_api_key() ) : ?>
|
||||
<div class="akismet-card">
|
||||
<div class="akismet-section-header">
|
||||
<h2 class="akismet-section-header__label">
|
||||
<span><?php esc_html_e( 'Account', 'akismet' ); ?></span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="inside">
|
||||
<table class="akismet-account">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Subscription type', 'akismet' ); ?></th>
|
||||
<td>
|
||||
<?php echo esc_html( $akismet_user->account_name ); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Status', 'akismet' ); ?></th>
|
||||
<td>
|
||||
<?php
|
||||
if ( 'cancelled' === $akismet_user->status ) :
|
||||
esc_html_e( 'Cancelled', 'akismet' );
|
||||
elseif ( 'suspended' === $akismet_user->status ) :
|
||||
esc_html_e( 'Suspended', 'akismet' );
|
||||
elseif ( 'missing' === $akismet_user->status ) :
|
||||
esc_html_e( 'Missing', 'akismet' );
|
||||
elseif ( 'no-sub' === $akismet_user->status ) :
|
||||
esc_html_e( 'No subscription found', 'akismet' );
|
||||
else :
|
||||
esc_html_e( 'Active', 'akismet' );
|
||||
endif;
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if ( $akismet_user->next_billing_date ) : ?>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Next billing date', 'akismet' ); ?></th>
|
||||
<td>
|
||||
<?php echo esc_html( gmdate( 'F j, Y', $akismet_user->next_billing_date ) ); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="akismet-card-actions">
|
||||
<?php if ( $akismet_user->status === 'active' ) : ?>
|
||||
<div class="akismet-card-actions__secondary-action">
|
||||
<a href="https://akismet.com/account" target="_blank" rel="noopener noreferrer" aria-label="Account overview on akismet.com (opens in a new window)"><?php esc_html_e( 'Account overview', 'akismet' ); ?></a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div id="publishing-action">
|
||||
<?php
|
||||
Akismet::view(
|
||||
'get',
|
||||
array(
|
||||
'text' => ( $akismet_user->account_type === 'free-api-key' && $akismet_user->status === 'active' ? __( 'Upgrade', 'akismet' ) : __( 'Change', 'akismet' ) ),
|
||||
'redirect' => 'upgrade',
|
||||
)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
98
wp-content/plugins/akismet/views/connect-jp.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
//phpcs:disable VariableAnalysis
|
||||
// There are "undefined" variables here because they're defined in the code that includes this file as a template.
|
||||
|
||||
?>
|
||||
<div class="akismet-box">
|
||||
<?php Akismet::view( 'title' ); ?>
|
||||
<div class="akismet-jp-connect">
|
||||
<h3><?php esc_html_e( 'Connect with Jetpack', 'akismet' ); ?></h3>
|
||||
<?php if ( in_array( $akismet_user->status, array( 'no-sub', 'missing' ) ) ) { ?>
|
||||
<p><?php esc_html_e( 'Use your Jetpack connection to set up Akismet.', 'akismet' ); ?></p>
|
||||
<form name="akismet_activate" id="akismet_activate" action="https://akismet.com/get/" method="post" class="akismet-right" target="_blank">
|
||||
<input type="hidden" name="passback_url" value="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>"/>
|
||||
<input type="hidden" name="blog" value="<?php echo esc_url( get_option( 'home' ) ); ?>"/>
|
||||
<input type="hidden" name="auto-connect" value="<?php echo esc_attr( $akismet_user->ID ); ?>"/>
|
||||
<input type="hidden" name="redirect" value="plugin-signup"/>
|
||||
<input type="submit" class="akismet-button akismet-is-primary" value="<?php esc_attr_e( 'Connect with Jetpack', 'akismet' ); ?>"/>
|
||||
</form>
|
||||
<?php echo get_avatar( $akismet_user->user_email, null, null, null, array( 'class' => 'akismet-jetpack-gravatar' ) ); ?>
|
||||
<p>
|
||||
<?php
|
||||
|
||||
/* translators: %s is the WordPress.com username */
|
||||
echo sprintf( esc_html( __( 'You are connected as %s.', 'akismet' ) ), '<b>' . esc_html( $akismet_user->user_login ) . '</b>' );
|
||||
|
||||
?>
|
||||
<br />
|
||||
<span class="akismet-jetpack-email"><?php echo esc_html( $akismet_user->user_email ); ?></span>
|
||||
</p>
|
||||
<?php } elseif ( $akismet_user->status == 'cancelled' ) { ?>
|
||||
<p><?php esc_html_e( 'Use your Jetpack connection to set up Akismet.', 'akismet' ); ?></p>
|
||||
<form name="akismet_activate" id="akismet_activate" action="https://akismet.com/get/" method="post" class="akismet-right" target="_blank">
|
||||
<input type="hidden" name="passback_url" value="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>"/>
|
||||
<input type="hidden" name="blog" value="<?php echo esc_url( get_option( 'home' ) ); ?>"/>
|
||||
<input type="hidden" name="user_id" value="<?php echo esc_attr( $akismet_user->ID ); ?>"/>
|
||||
<input type="hidden" name="redirect" value="upgrade"/>
|
||||
<input type="submit" class="akismet-button akismet-is-primary" value="<?php esc_attr_e( 'Connect with Jetpack', 'akismet' ); ?>"/>
|
||||
</form>
|
||||
<?php echo get_avatar( $akismet_user->user_email, null, null, null, array( 'class' => 'akismet-jetpack-gravatar' ) ); ?>
|
||||
<p>
|
||||
<?php
|
||||
|
||||
/* translators: %s is the WordPress.com email address */
|
||||
echo esc_html( sprintf( __( 'Your subscription for %s is cancelled.', 'akismet' ), $akismet_user->user_email ) );
|
||||
|
||||
?>
|
||||
<br />
|
||||
<span class="akismet-jetpack-email"><?php echo esc_html( $akismet_user->user_email ); ?></span>
|
||||
</p>
|
||||
<?php } elseif ( $akismet_user->status == 'suspended' ) { ?>
|
||||
<div class="akismet-right">
|
||||
<p><a href="https://akismet.com/contact" class="akismet-button akismet-is-primary"><?php esc_html_e( 'Contact Akismet support', 'akismet' ); ?></a></p>
|
||||
</div>
|
||||
<p>
|
||||
<span class="akismet-alert-text">
|
||||
<?php
|
||||
|
||||
/* translators: %s is the WordPress.com email address */
|
||||
echo esc_html( sprintf( __( 'Your subscription for %s is suspended.', 'akismet' ), $akismet_user->user_email ) );
|
||||
|
||||
?>
|
||||
</span>
|
||||
<?php esc_html_e( 'No worries! Get in touch and we’ll sort this out.', 'akismet' ); ?>
|
||||
</p>
|
||||
<?php } else { // ask do they want to use akismet account found using jetpack wpcom connection ?>
|
||||
<p><?php esc_html_e( 'Use your Jetpack connection to set up Akismet.', 'akismet' ); ?></p>
|
||||
<form name="akismet_use_wpcom_key" action="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>" method="post" id="akismet-activate" class="akismet-right">
|
||||
<input type="hidden" name="key" value="<?php echo esc_attr( $akismet_user->api_key ); ?>"/>
|
||||
<input type="hidden" name="action" value="enter-key">
|
||||
<?php wp_nonce_field( Akismet_Admin::NONCE ); ?>
|
||||
<input type="submit" class="akismet-button akismet-is-primary" value="<?php esc_attr_e( 'Connect with Jetpack', 'akismet' ); ?>"/>
|
||||
</form>
|
||||
<?php echo get_avatar( $akismet_user->user_email, null, null, null, array( 'class' => 'akismet-jetpack-gravatar' ) ); ?>
|
||||
<p>
|
||||
<?php
|
||||
|
||||
/* translators: %s is the WordPress.com username */
|
||||
echo sprintf( esc_html( __( 'You are connected as %s.', 'akismet' ) ), '<b>' . esc_html( $akismet_user->user_login ) . '</b>' );
|
||||
|
||||
?>
|
||||
<br />
|
||||
<span class="akismet-jetpack-email"><?php echo esc_html( $akismet_user->user_email ); ?></span>
|
||||
</p>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<div class="akismet-ak-connect">
|
||||
<?php Akismet::view( 'setup' ); ?>
|
||||
</div>
|
||||
<div class="centered akismet-toggles">
|
||||
<a href="#" class="toggle-jp-connect"><?php esc_html_e( 'Connect with Jetpack', 'akismet' ); ?></a>
|
||||
<a href="#" class="toggle-ak-connect"><?php esc_html_e( 'Set up a different account', 'akismet' ); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="akismet-box">
|
||||
<?php Akismet::view( 'enter' ); ?>
|
||||
</div>
|
||||
14
wp-content/plugins/akismet/views/enter.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<div class="akismet-enter-api-key-box centered">
|
||||
<button class="akismet-enter-api-key-box__reveal"><?php esc_html_e( 'Manually enter an API key', 'akismet' ); ?></button>
|
||||
<div class="akismet-enter-api-key-box__form-wrapper">
|
||||
<form action="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>" method="post">
|
||||
<?php wp_nonce_field( Akismet_Admin::NONCE ); ?>
|
||||
<input type="hidden" name="action" value="enter-key">
|
||||
<h3 class="akismet-enter-api-key-box__header" id="akismet-enter-api-key-box__header"><?php esc_html_e( 'Enter your API key', 'akismet' ); ?></h3>
|
||||
<div class="akismet-enter-api-key-box__input-wrapper">
|
||||
<input id="key" name="key" type="text" size="15" value="" placeholder="<?php esc_attr_e( 'API key', 'akismet' ); ?>" class="akismet-enter-api-key-box__key-input regular-text code" aria-labelledby="akismet-enter-api-key-box__header">
|
||||
<input type="submit" name="submit" id="submit" class="akismet-button" value="<?php esc_attr_e( 'Connect with API key', 'akismet' ); ?>">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
18
wp-content/plugins/akismet/views/get.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
//phpcs:disable VariableAnalysis
|
||||
// There are "undefined" variables here because they're defined in the code that includes this file as a template.
|
||||
|
||||
$submit_classes_attr = 'akismet-button';
|
||||
|
||||
if ( isset( $classes ) && ( is_countable( $classes ) ? count( $classes ) : 0 ) > 0 ) {
|
||||
$submit_classes_attr = implode( ' ', $classes );
|
||||
}
|
||||
?>
|
||||
|
||||
<form name="akismet_activate" action="https://akismet.com/get/" method="POST" target="_blank">
|
||||
<input type="hidden" name="passback_url" value="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>"/>
|
||||
<input type="hidden" name="blog" value="<?php echo esc_url( get_option( 'home' ) ); ?>"/>
|
||||
<input type="hidden" name="redirect" value="<?php echo isset( $redirect ) ? $redirect : 'plugin-signup'; ?>"/>
|
||||
<button type="submit" class="<?php echo esc_attr( $submit_classes_attr ); ?>" value="<?php echo esc_attr( $text ); ?>"><?php echo esc_attr( $text ) . '<span class="screen-reader-text">' . esc_html__( '(opens in a new tab)', 'akismet' ) . '</span>'; ?></button>
|
||||
</form>
|
||||
13
wp-content/plugins/akismet/views/logo.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
//phpcs:disable VariableAnalysis
|
||||
// There are "undefined" variables here because they're defined in the code that includes this file as a template.
|
||||
?>
|
||||
<div class="akismet-masthead__logo-container">
|
||||
<?php if ( isset( $include_logo_link ) && $include_logo_link === true ) : ?>
|
||||
<a href="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>" class="akismet-masthead__logo-link">
|
||||
<?php endif; ?>
|
||||
<img class="akismet-masthead__logo" src="<?php echo esc_url( plugins_url( '../_inc/img/akismet-refresh-logo@2x.png', __FILE__ ) ); ?>" srcset="<?php echo esc_url( plugins_url( '../_inc/img/akismet-refresh-logo.svg', __FILE__ ) ); ?>" alt="Akismet logo" />
|
||||
<?php if ( isset( $include_logo_link ) && $include_logo_link === true ) : ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
330
wp-content/plugins/akismet/views/notice.php
Normal file
@@ -0,0 +1,330 @@
|
||||
<?php
|
||||
//phpcs:disable VariableAnalysis
|
||||
// There are "undefined" variables here because they're defined in the code that includes this file as a template.
|
||||
$kses_allow_link = array(
|
||||
'a' => array(
|
||||
'href' => true,
|
||||
'target' => true,
|
||||
),
|
||||
);
|
||||
$kses_allow_strong = array( 'strong' => true );
|
||||
|
||||
/*
|
||||
* Some notices (plugin, spam-check, spam-check-cron-disabled, alert and usage-limit) are shown elsewhere in wp-admin,
|
||||
* so look different to the standard notices.
|
||||
*/
|
||||
?>
|
||||
<?php if ( $type === 'plugin' ) : ?>
|
||||
<div class="updated" id="akismet_setup_prompt">
|
||||
<form name="akismet_activate" action="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>" method="POST">
|
||||
<div class="akismet_activate">
|
||||
<div class="aa_a">A</div>
|
||||
<div class="aa_button_container">
|
||||
<div class="aa_button_border">
|
||||
<input type="submit" class="aa_button" value="<?php esc_attr_e( 'Set up your Akismet account', 'akismet' ); ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="aa_description">
|
||||
<?php
|
||||
echo wp_kses(
|
||||
__( '<strong>Almost done</strong> - configure Akismet and say goodbye to spam', 'akismet' ),
|
||||
$kses_allow_strong
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'spam-check' ) : ?>
|
||||
<div class="notice notice-warning">
|
||||
<p><strong><?php esc_html_e( 'Akismet has detected a problem.', 'akismet' ); ?></strong></p>
|
||||
<p><?php esc_html_e( 'Some comments have not yet been checked for spam by Akismet. They have been temporarily held for moderation and will automatically be rechecked later.', 'akismet' ); ?></p>
|
||||
<?php if ( $link_text ) : ?>
|
||||
<p><?php echo wp_kses( $link_text, $kses_allow_link ); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'spam-check-cron-disabled' ) : ?>
|
||||
<div class="notice notice-warning">
|
||||
<p><strong><?php esc_html_e( 'Akismet has detected a problem.', 'akismet' ); ?></strong></p>
|
||||
<p><?php esc_html_e( 'WP-Cron has been disabled using the DISABLE_WP_CRON constant. Comment rechecks may not work properly.', 'akismet' ); ?></p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'alert' ) : ?>
|
||||
<div class="error">
|
||||
<?php /* translators: The placeholder is an error code returned by Akismet. */ ?>
|
||||
<p><strong><?php printf( esc_html__( 'Akismet error code: %s', 'akismet' ), esc_html( $code ) ); ?></strong></p>
|
||||
<p><?php echo esc_html( $msg ); ?></p>
|
||||
<p>
|
||||
<?php
|
||||
/* translators: the placeholder is a clickable URL that leads to more information regarding an error code. */
|
||||
printf( esc_html__( 'For more information: %s', 'akismet' ), '<a href="https://akismet.com/errors/' . esc_attr( $code ) . '">https://akismet.com/errors/' . esc_attr( $code ) . '</a>' );
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'notice' ) : ?>
|
||||
<div class="akismet-alert is-bad">
|
||||
<h3 class="akismet-alert__heading"><?php echo wp_kses( $notice_header, Akismet_Admin::get_notice_kses_allowed_elements() ); ?></h3>
|
||||
<p>
|
||||
<?php echo wp_kses( $notice_text, Akismet_Admin::get_notice_kses_allowed_elements() ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'missing-functions' ) : ?>
|
||||
<div class="akismet-alert is-bad">
|
||||
<h3 class="akismet-alert__heading"><?php esc_html_e( 'Network functions are disabled.', 'akismet' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
/* translators: The placeholder is a URL. */
|
||||
echo wp_kses( sprintf( __( 'Your web host or server administrator has disabled PHP’s <code>gethostbynamel</code> function. <strong>Akismet cannot work correctly until this is fixed.</strong> Please contact your web host or firewall administrator and give them <a href="%s" target="_blank">this information about Akismet’s system requirements</a>.', 'akismet' ), esc_url( 'https://akismet.com/akismet-hosting-faq/' ) ), array_merge( $kses_allow_link, $kses_allow_strong, array( 'code' => true ) ) );
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'servers-be-down' ) : ?>
|
||||
<div class="akismet-alert is-bad">
|
||||
<h3 class="akismet-alert__heading"><?php esc_html_e( 'Your site can’t connect to the Akismet servers.', 'akismet' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
/* translators: The placeholder is a URL. */
|
||||
echo wp_kses( sprintf( __( 'Your firewall may be blocking Akismet from connecting to its API. Please contact your host and refer to <a href="%s" target="_blank">our guide about firewalls</a>.', 'akismet' ), esc_url( 'https://akismet.com/akismet-hosting-faq/' ) ), $kses_allow_link );
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'active-dunning' ) : ?>
|
||||
<div class="akismet-alert is-bad">
|
||||
<h3 class="akismet-alert__heading"><?php esc_html_e( 'Please update your payment information.', 'akismet' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
/* translators: The placeholder is a URL. */
|
||||
echo wp_kses( sprintf( __( 'We cannot process your payment. Please <a href="%s" target="_blank">update your payment details</a>.', 'akismet' ), esc_url( 'https://akismet.com/account/' ) ), $kses_allow_link );
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'cancelled' ) : ?>
|
||||
<div class="akismet-alert is-bad">
|
||||
<h3 class="akismet-alert__heading"><?php esc_html_e( 'Your Akismet plan has been cancelled.', 'akismet' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
/* translators: The placeholder is a URL. */
|
||||
echo wp_kses( sprintf( __( 'Please visit your <a href="%s" target="_blank">Akismet account page</a> to reactivate your subscription.', 'akismet' ), esc_url( 'https://akismet.com/account/' ) ), $kses_allow_link );
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'suspended' ) : ?>
|
||||
<div class="akismet-alert is-bad">
|
||||
<h3 class="akismet-alert__heading"><?php esc_html_e( 'Your Akismet subscription is suspended.', 'akismet' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
/* translators: The placeholder is a URL. */
|
||||
echo wp_kses( sprintf( __( 'Please contact <a href="%s" target="_blank">Akismet support</a> for assistance.', 'akismet' ), esc_url( 'https://akismet.com/contact/' ) ), $kses_allow_link );
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'active-notice' && $time_saved ) : ?>
|
||||
<div class="akismet-alert is-neutral">
|
||||
<h3 class="akismet-alert__heading"><?php echo esc_html( $time_saved ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
/* translators: the placeholder is a clickable URL to the Akismet account upgrade page. */
|
||||
echo wp_kses( sprintf( __( 'You can help us fight spam and upgrade your account by <a href="%s" target="_blank">contributing a token amount</a>.', 'akismet' ), esc_url( 'https://akismet.com/pricing' ) ), $kses_allow_link );
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'missing' ) : ?>
|
||||
<div class="akismet-alert is-bad">
|
||||
<h3 class="akismet-alert__heading"><?php esc_html_e( 'There is a problem with your API key.', 'akismet' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
/* translators: The placeholder is a URL to the Akismet contact form. */
|
||||
echo wp_kses( sprintf( __( 'Please contact <a href="%s" target="_blank">Akismet support</a> for assistance.', 'akismet' ), esc_url( 'https://akismet.com/contact/' ) ), $kses_allow_link );
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'no-sub' ) : ?>
|
||||
<div class="akismet-alert is-bad">
|
||||
<h3 class="akismet-alert__heading"><?php esc_html_e( 'You don’t have an Akismet plan.', 'akismet' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
/* translators: the placeholder is a clickable URL to the Akismet account upgrade page. */
|
||||
echo wp_kses( sprintf( __( 'In 2012, Akismet began using subscription plans for all accounts (even free ones). A plan has not been assigned to your account, and we’d appreciate it if you’d <a href="%s" target="_blank">sign into your account</a> and choose one.', 'akismet' ), esc_url( 'https://akismet.com/pricing' ) ), $kses_allow_link );
|
||||
?>
|
||||
<br /><br />
|
||||
<?php
|
||||
/* translators: The placeholder is a URL to the Akismet contact form. */
|
||||
echo wp_kses( sprintf( __( 'Please <a href="%s" target="_blank">contact our support team</a> with any questions.', 'akismet' ), esc_url( 'https://akismet.com/contact/' ) ), $kses_allow_link );
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'new-key-valid' ) : ?>
|
||||
<?php
|
||||
global $wpdb;
|
||||
|
||||
$check_pending_link = false;
|
||||
|
||||
$at_least_one_comment_in_moderation = ! ! $wpdb->get_var( "SELECT comment_ID FROM {$wpdb->comments} WHERE comment_approved = '0' LIMIT 1" );
|
||||
|
||||
if ( $at_least_one_comment_in_moderation ) {
|
||||
$check_pending_link = 'edit-comments.php?akismet_recheck=' . wp_create_nonce( 'akismet_recheck' );
|
||||
}
|
||||
?>
|
||||
<div class="akismet-alert is-good">
|
||||
<p><?php esc_html_e( 'Akismet is now protecting your site from spam.', 'akismet' ); ?></p>
|
||||
<?php if ( $check_pending_link ) : ?>
|
||||
<p>
|
||||
<?php
|
||||
echo wp_kses(
|
||||
sprintf(
|
||||
/* translators: The placeholder is a URL for checking pending comments. */
|
||||
__( 'Would you like to <a href="%s">check pending comments</a>?', 'akismet' ),
|
||||
esc_url( $check_pending_link )
|
||||
),
|
||||
$kses_allow_link
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'new-key-invalid' ) : ?>
|
||||
<div class="akismet-alert is-bad">
|
||||
<p><?php esc_html_e( 'The key you entered is invalid. Please double-check it.', 'akismet' ); ?></p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'existing-key-invalid' ) : ?>
|
||||
<div class="akismet-alert is-bad">
|
||||
<h3 class="akismet-alert__heading"><?php echo esc_html( __( 'Your API key is no longer valid.', 'akismet' ) ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
echo wp_kses(
|
||||
sprintf(
|
||||
/* translators: The placeholder is a URL to the Akismet contact form. */
|
||||
__( 'Please enter a new key or <a href="%s" target="_blank">contact Akismet support</a>.', 'akismet' ),
|
||||
'https://akismet.com/contact/'
|
||||
),
|
||||
$kses_allow_link
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'new-key-failed' ) : ?>
|
||||
<div class="akismet-alert is-bad">
|
||||
<h3 class="akismet-alert__heading"><?php esc_html_e( 'The API key you entered could not be verified.', 'akismet' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
echo wp_kses(
|
||||
sprintf(
|
||||
/* translators: The placeholder is a URL. */
|
||||
__( 'The connection to akismet.com could not be established. Please refer to <a href="%s" target="_blank">our guide about firewalls</a> and check your server configuration.', 'akismet' ),
|
||||
'https://blog.akismet.com/akismet-hosting-faq/'
|
||||
),
|
||||
$kses_allow_link
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php elseif ( $type === 'usage-limit' && isset( Akismet::$limit_notices[ $code ] ) ) : ?>
|
||||
<div class="error akismet-usage-limit-alert">
|
||||
<div class="akismet-usage-limit-logo">
|
||||
<img src="<?php echo esc_url( plugins_url( '../_inc/img/logo-a-2x.png', __FILE__ ) ); ?>" alt="Akismet logo" />
|
||||
</div>
|
||||
<div class="akismet-usage-limit-text">
|
||||
<h3>
|
||||
<?php
|
||||
switch ( Akismet::$limit_notices[ $code ] ) {
|
||||
case 'FIRST_MONTH_OVER_LIMIT':
|
||||
case 'SECOND_MONTH_OVER_LIMIT':
|
||||
esc_html_e( 'Your Akismet account usage is over your plan’s limit', 'akismet' );
|
||||
break;
|
||||
case 'THIRD_MONTH_APPROACHING_LIMIT':
|
||||
esc_html_e( 'Your Akismet account usage is approaching your plan’s limit', 'akismet' );
|
||||
break;
|
||||
case 'THIRD_MONTH_OVER_LIMIT':
|
||||
case 'FOUR_PLUS_MONTHS_OVER_LIMIT':
|
||||
esc_html_e( 'Your account has been restricted', 'akismet' );
|
||||
break;
|
||||
default:
|
||||
}
|
||||
?>
|
||||
</h3>
|
||||
<p>
|
||||
<?php
|
||||
switch ( Akismet::$limit_notices[ $code ] ) {
|
||||
case 'FIRST_MONTH_OVER_LIMIT':
|
||||
echo esc_html(
|
||||
sprintf(
|
||||
/* translators: The first placeholder is a date, the second is a (formatted) number, the third is another formatted number. */
|
||||
__( 'Since %1$s, your account made %2$s API calls, compared to your plan’s limit of %3$s.', 'akismet' ),
|
||||
esc_html( gmdate( 'F' ) . ' 1' ),
|
||||
number_format( $api_calls ),
|
||||
number_format( $usage_limit )
|
||||
)
|
||||
);
|
||||
echo ' ';
|
||||
echo '<a href="https://docs.akismet.com/akismet-api-usage-limits/" target="_blank">';
|
||||
echo esc_html( __( 'Learn more about usage limits.', 'akismet' ) );
|
||||
echo '</a>';
|
||||
|
||||
break;
|
||||
case 'SECOND_MONTH_OVER_LIMIT':
|
||||
echo esc_html( __( 'Your Akismet usage has been over your plan’s limit for two consecutive months. Next month, we will restrict your account after you reach the limit. Please consider upgrading your plan.', 'akismet' ) );
|
||||
echo ' ';
|
||||
echo '<a href="https://docs.akismet.com/akismet-api-usage-limits/" target="_blank">';
|
||||
echo esc_html( __( 'Learn more about usage limits.', 'akismet' ) );
|
||||
echo '</a>';
|
||||
|
||||
break;
|
||||
case 'THIRD_MONTH_APPROACHING_LIMIT':
|
||||
echo esc_html( __( 'Your Akismet usage is nearing your plan’s limit for the third consecutive month. We will restrict your account after you reach the limit. Upgrade your plan so Akismet can continue blocking spam.', 'akismet' ) );
|
||||
echo ' ';
|
||||
echo '<a href="https://docs.akismet.com/akismet-api-usage-limits/" target="_blank">';
|
||||
echo esc_html( __( 'Learn more about usage limits.', 'akismet' ) );
|
||||
echo '</a>';
|
||||
|
||||
break;
|
||||
case 'THIRD_MONTH_OVER_LIMIT':
|
||||
case 'FOUR_PLUS_MONTHS_OVER_LIMIT':
|
||||
echo esc_html( __( 'Your Akismet usage has been over your plan’s limit for three consecutive months. We have restricted your account for the rest of the month. Upgrade your plan so Akismet can continue blocking spam.', 'akismet' ) );
|
||||
echo ' ';
|
||||
echo '<a href="https://docs.akismet.com/akismet-api-usage-limits/" target="_blank">';
|
||||
echo esc_html( __( 'Learn more about usage limits.', 'akismet' ) );
|
||||
echo '</a>';
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<div class="akismet-usage-limit-cta">
|
||||
<a href="<?php echo esc_attr( $upgrade_url ); ?>" class="button" target="_blank">
|
||||
<?php
|
||||
// If only a qty upgrade is required, show a more generic message.
|
||||
if ( ! empty( $upgrade_type ) && 'qty' === $upgrade_type ) {
|
||||
esc_html_e( 'Upgrade your subscription level', 'akismet' );
|
||||
} else {
|
||||
echo esc_html(
|
||||
sprintf(
|
||||
/* translators: The placeholder is the name of a subscription level, like "Plus" or "Enterprise" . */
|
||||
__( 'Upgrade to %s', 'akismet' ),
|
||||
$upgrade_plan
|
||||
)
|
||||
);
|
||||
}
|
||||
?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
11
wp-content/plugins/akismet/views/predefined.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="akismet-box">
|
||||
<h2><?php esc_html_e( 'Manual Configuration', 'akismet' ); ?></h2>
|
||||
<p>
|
||||
<?php
|
||||
|
||||
/* translators: %s is the wp-config.php file */
|
||||
echo sprintf( esc_html__( 'An Akismet API key has been defined in the %s file for this site.', 'akismet' ), '<code>wp-config.php</code>' );
|
||||
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
4
wp-content/plugins/akismet/views/setup.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<div class="akismet-setup-instructions">
|
||||
<p><?php esc_html_e( 'Set up your Akismet account to enable spam filtering on this site.', 'akismet' ); ?></p>
|
||||
<?php Akismet::view( 'get', array( 'text' => __( 'Set up your Akismet account' , 'akismet' ), 'classes' => array( 'akismet-button', 'akismet-is-primary' ) ) ); ?>
|
||||
</div>
|
||||
29
wp-content/plugins/akismet/views/start.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
//phpcs:disable VariableAnalysis
|
||||
// There are "undefined" variables here because they're defined in the code that includes this file as a template.
|
||||
|
||||
?>
|
||||
<div id="akismet-plugin-container">
|
||||
<div class="akismet-masthead">
|
||||
<div class="akismet-masthead__inside-container">
|
||||
<?php Akismet::view( 'logo' ); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="akismet-lower">
|
||||
<?php Akismet_Admin::display_status();?>
|
||||
<div class="akismet-boxes">
|
||||
<?php
|
||||
|
||||
if ( Akismet::predefined_api_key() ) {
|
||||
Akismet::view( 'predefined' );
|
||||
} elseif ( $akismet_user && in_array( $akismet_user->status, array( 'active', 'active-dunning', 'no-sub', 'missing', 'cancelled', 'suspended' ) ) ) {
|
||||
Akismet::view( 'connect-jp', compact( 'akismet_user' ) );
|
||||
} else {
|
||||
Akismet::view( 'activate' );
|
||||
}
|
||||
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
12
wp-content/plugins/akismet/views/stats.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<div id="akismet-plugin-container">
|
||||
<div class="akismet-masthead">
|
||||
<div class="akismet-masthead__inside-container">
|
||||
<?php Akismet::view( 'logo', array( 'include_logo_link' => true ) ); ?>
|
||||
<div class="akismet-masthead__back-link-container">
|
||||
<a class="akismet-masthead__back-link" href="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>"><?php esc_html_e( 'Back to settings', 'akismet' ); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php /* name attribute on iframe is used as a cache-buster here to force Firefox to load the new style charts: https://bugzilla.mozilla.org/show_bug.cgi?id=356558 */ ?>
|
||||
<iframe id="stats-iframe" src="<?php echo esc_url( sprintf( 'https://tools.akismet.com/1.0/user-stats.php?blog=%s&token=%s&locale=%s&is_redecorated=1', urlencode( get_option( 'home' ) ), urlencode( Akismet::get_access_token() ), esc_attr( get_locale() ) ) ); ?>" name="<?php echo esc_attr( 'user-stats- ' . filemtime( __FILE__ ) ); ?>" width="100%" height="2500px" frameborder="0" title="<?php echo esc_attr__( 'Akismet detailed stats' ); ?>"></iframe>
|
||||
</div>
|
||||
3
wp-content/plugins/akismet/views/title.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<div class="centered akismet-box-header">
|
||||
<h2><?php esc_html_e( 'Eliminate spam from your site', 'akismet' ); ?></h2>
|
||||
</div>
|
||||
214
wp-content/plugins/akismet/wrapper.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
global $wpcom_api_key, $akismet_api_host, $akismet_api_port;
|
||||
|
||||
$wpcom_api_key = defined( 'WPCOM_API_KEY' ) ? constant( 'WPCOM_API_KEY' ) : '';
|
||||
$akismet_api_host = Akismet::get_api_key() . '.rest.akismet.com';
|
||||
$akismet_api_port = 80;
|
||||
|
||||
function akismet_test_mode() {
|
||||
return Akismet::is_test_mode();
|
||||
}
|
||||
|
||||
function akismet_http_post( $request, $host, $path, $port = 80, $ip = null ) {
|
||||
$path = str_replace( '/1.1/', '', $path );
|
||||
|
||||
return Akismet::http_post( $request, $path, $ip );
|
||||
}
|
||||
|
||||
function akismet_microtime() {
|
||||
return Akismet::_get_microtime();
|
||||
}
|
||||
|
||||
function akismet_delete_old() {
|
||||
return Akismet::delete_old_comments();
|
||||
}
|
||||
|
||||
function akismet_delete_old_metadata() {
|
||||
return Akismet::delete_old_comments_meta();
|
||||
}
|
||||
|
||||
function akismet_check_db_comment( $id, $recheck_reason = 'recheck_queue' ) {
|
||||
return Akismet::check_db_comment( $id, $recheck_reason );
|
||||
}
|
||||
|
||||
function akismet_rightnow() {
|
||||
if ( !class_exists( 'Akismet_Admin' ) )
|
||||
return false;
|
||||
|
||||
return Akismet_Admin::rightnow_stats();
|
||||
}
|
||||
|
||||
function akismet_admin_init() {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
}
|
||||
function akismet_version_warning() {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
}
|
||||
function akismet_load_js_and_css() {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
}
|
||||
function akismet_nonce_field( $action = -1 ) {
|
||||
return wp_nonce_field( $action );
|
||||
}
|
||||
function akismet_plugin_action_links( $links, $file ) {
|
||||
return Akismet_Admin::plugin_action_links( $links, $file );
|
||||
}
|
||||
function akismet_conf() {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
}
|
||||
function akismet_stats_display() {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
}
|
||||
function akismet_stats() {
|
||||
return Akismet_Admin::dashboard_stats();
|
||||
}
|
||||
function akismet_admin_warnings() {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
}
|
||||
function akismet_comment_row_action( $a, $comment ) {
|
||||
return Akismet_Admin::comment_row_actions( $a, $comment );
|
||||
}
|
||||
function akismet_comment_status_meta_box( $comment ) {
|
||||
return Akismet_Admin::comment_status_meta_box( $comment );
|
||||
}
|
||||
function akismet_comments_columns( $columns ) {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
|
||||
return $columns;
|
||||
}
|
||||
function akismet_comment_column_row( $column, $comment_id ) {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
}
|
||||
function akismet_text_add_link_callback( $m ) {
|
||||
return Akismet_Admin::text_add_link_callback( $m );
|
||||
}
|
||||
function akismet_text_add_link_class( $comment_text ) {
|
||||
return Akismet_Admin::text_add_link_class( $comment_text );
|
||||
}
|
||||
function akismet_check_for_spam_button( $comment_status ) {
|
||||
return Akismet_Admin::check_for_spam_button( $comment_status );
|
||||
}
|
||||
function akismet_submit_nonspam_comment( $comment_id ) {
|
||||
return Akismet::submit_nonspam_comment( $comment_id );
|
||||
}
|
||||
function akismet_submit_spam_comment( $comment_id ) {
|
||||
return Akismet::submit_spam_comment( $comment_id );
|
||||
}
|
||||
function akismet_transition_comment_status( $new_status, $old_status, $comment ) {
|
||||
return Akismet::transition_comment_status( $new_status, $old_status, $comment );
|
||||
}
|
||||
function akismet_spam_count( $type = false ) {
|
||||
return Akismet_Admin::get_spam_count( $type );
|
||||
}
|
||||
function akismet_recheck_queue() {
|
||||
return Akismet_Admin::recheck_queue();
|
||||
}
|
||||
function akismet_remove_comment_author_url() {
|
||||
return Akismet_Admin::remove_comment_author_url();
|
||||
}
|
||||
function akismet_add_comment_author_url() {
|
||||
return Akismet_Admin::add_comment_author_url();
|
||||
}
|
||||
function akismet_check_server_connectivity() {
|
||||
return Akismet_Admin::check_server_connectivity();
|
||||
}
|
||||
function akismet_get_server_connectivity( $cache_timeout = 86400 ) {
|
||||
return Akismet_Admin::get_server_connectivity( $cache_timeout );
|
||||
}
|
||||
function akismet_server_connectivity_ok() {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
|
||||
return true;
|
||||
}
|
||||
function akismet_admin_menu() {
|
||||
return Akismet_Admin::admin_menu();
|
||||
}
|
||||
function akismet_load_menu() {
|
||||
return Akismet_Admin::load_menu();
|
||||
}
|
||||
function akismet_init() {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
}
|
||||
function akismet_get_key() {
|
||||
return Akismet::get_api_key();
|
||||
}
|
||||
function akismet_check_key_status( $key, $ip = null ) {
|
||||
return Akismet::check_key_status( $key, $ip );
|
||||
}
|
||||
function akismet_update_alert( $response ) {
|
||||
return Akismet::update_alert( $response );
|
||||
}
|
||||
function akismet_verify_key( $key, $ip = null ) {
|
||||
return Akismet::verify_key( $key, $ip );
|
||||
}
|
||||
function akismet_get_user_roles( $user_id ) {
|
||||
return Akismet::get_user_roles( $user_id );
|
||||
}
|
||||
function akismet_result_spam( $approved ) {
|
||||
return Akismet::comment_is_spam( $approved );
|
||||
}
|
||||
function akismet_result_hold( $approved ) {
|
||||
return Akismet::comment_needs_moderation( $approved );
|
||||
}
|
||||
function akismet_get_user_comments_approved( $user_id, $comment_author_email, $comment_author, $comment_author_url ) {
|
||||
return Akismet::get_user_comments_approved( $user_id, $comment_author_email, $comment_author, $comment_author_url );
|
||||
}
|
||||
function akismet_update_comment_history( $comment_id, $message, $event = null ) {
|
||||
return Akismet::update_comment_history( $comment_id, $message, $event );
|
||||
}
|
||||
function akismet_get_comment_history( $comment_id ) {
|
||||
return Akismet::get_comment_history( $comment_id );
|
||||
}
|
||||
function akismet_cmp_time( $a, $b ) {
|
||||
return Akismet::_cmp_time( $a, $b );
|
||||
}
|
||||
function akismet_auto_check_update_meta( $id, $comment ) {
|
||||
return Akismet::auto_check_update_meta( $id, $comment );
|
||||
}
|
||||
function akismet_auto_check_comment( $commentdata ) {
|
||||
return Akismet::auto_check_comment( $commentdata );
|
||||
}
|
||||
function akismet_get_ip_address() {
|
||||
return Akismet::get_ip_address();
|
||||
}
|
||||
function akismet_cron_recheck() {
|
||||
return Akismet::cron_recheck();
|
||||
}
|
||||
function akismet_add_comment_nonce( $post_id ) {
|
||||
return Akismet::add_comment_nonce( $post_id );
|
||||
}
|
||||
function akismet_fix_scheduled_recheck() {
|
||||
return Akismet::fix_scheduled_recheck();
|
||||
}
|
||||
function akismet_spam_comments() {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
|
||||
return array();
|
||||
}
|
||||
function akismet_spam_totals() {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
|
||||
return array();
|
||||
}
|
||||
function akismet_manage_page() {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
}
|
||||
function akismet_caught() {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
}
|
||||
function redirect_old_akismet_urls() {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
}
|
||||
function akismet_kill_proxy_check( $option ) {
|
||||
_deprecated_function( __FUNCTION__, '3.0' );
|
||||
|
||||
return 0;
|
||||
}
|
||||
function akismet_pingback_forwarded_for( $r, $url ) {
|
||||
// This functionality is now in core.
|
||||
return false;
|
||||
}
|
||||
function akismet_pre_check_pingback( $method ) {
|
||||
return Akismet::pre_check_pingback( $method );
|
||||
}
|
||||
100
wp-content/plugins/hello.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Hello_Dolly
|
||||
* @version 1.7.2
|
||||
*/
|
||||
/*
|
||||
Plugin Name: Hello Dolly
|
||||
Plugin URI: http://wordpress.org/plugins/hello-dolly/
|
||||
Description: This is not just a plugin, it symbolizes the hope and enthusiasm of an entire generation summed up in two words sung most famously by Louis Armstrong: Hello, Dolly. When activated you will randomly see a lyric from <cite>Hello, Dolly</cite> in the upper right of your admin screen on every page.
|
||||
Author: Matt Mullenweg
|
||||
Version: 1.7.2
|
||||
Author URI: http://ma.tt/
|
||||
*/
|
||||
|
||||
function hello_dolly_get_lyric() {
|
||||
/** These are the lyrics to Hello Dolly */
|
||||
$lyrics = "Hello, Dolly
|
||||
Well, hello, Dolly
|
||||
It's so nice to have you back where you belong
|
||||
You're lookin' swell, Dolly
|
||||
I can tell, Dolly
|
||||
You're still glowin', you're still crowin'
|
||||
You're still goin' strong
|
||||
I feel the room swayin'
|
||||
While the band's playin'
|
||||
One of our old favorite songs from way back when
|
||||
So, take her wrap, fellas
|
||||
Dolly, never go away again
|
||||
Hello, Dolly
|
||||
Well, hello, Dolly
|
||||
It's so nice to have you back where you belong
|
||||
You're lookin' swell, Dolly
|
||||
I can tell, Dolly
|
||||
You're still glowin', you're still crowin'
|
||||
You're still goin' strong
|
||||
I feel the room swayin'
|
||||
While the band's playin'
|
||||
One of our old favorite songs from way back when
|
||||
So, golly, gee, fellas
|
||||
Have a little faith in me, fellas
|
||||
Dolly, never go away
|
||||
Promise, you'll never go away
|
||||
Dolly'll never go away again";
|
||||
|
||||
// Here we split it into lines.
|
||||
$lyrics = explode( "\n", $lyrics );
|
||||
|
||||
// And then randomly choose a line.
|
||||
return wptexturize( $lyrics[ mt_rand( 0, count( $lyrics ) - 1 ) ] );
|
||||
}
|
||||
|
||||
// This just echoes the chosen line, we'll position it later.
|
||||
function hello_dolly() {
|
||||
$chosen = hello_dolly_get_lyric();
|
||||
$lang = '';
|
||||
if ( 'en_' !== substr( get_user_locale(), 0, 3 ) ) {
|
||||
$lang = ' lang="en"';
|
||||
}
|
||||
|
||||
printf(
|
||||
'<p id="dolly"><span class="screen-reader-text">%s </span><span dir="ltr"%s>%s</span></p>',
|
||||
__( 'Quote from Hello Dolly song, by Jerry Herman:' ),
|
||||
$lang,
|
||||
$chosen
|
||||
);
|
||||
}
|
||||
|
||||
// Now we set that function up to execute when the admin_notices action is called.
|
||||
add_action( 'admin_notices', 'hello_dolly' );
|
||||
|
||||
// We need some CSS to position the paragraph.
|
||||
function dolly_css() {
|
||||
echo "
|
||||
<style type='text/css'>
|
||||
#dolly {
|
||||
float: right;
|
||||
padding: 5px 10px;
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
line-height: 1.6666;
|
||||
}
|
||||
.rtl #dolly {
|
||||
float: left;
|
||||
}
|
||||
.block-editor-page #dolly {
|
||||
display: none;
|
||||
}
|
||||
@media screen and (max-width: 782px) {
|
||||
#dolly,
|
||||
.rtl #dolly {
|
||||
float: none;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
";
|
||||
}
|
||||
|
||||
add_action( 'admin_head', 'dolly_css' );
|
||||
2
wp-content/plugins/index.php
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// Silence is golden.
|
||||
674
wp-content/plugins/pinterest-for-woocommerce/LICENSE
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. 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
|
||||
them 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 prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. 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.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey 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;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If 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 convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU 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 that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
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.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
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.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
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
|
||||
state 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program 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, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU 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. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
131
wp-content/plugins/pinterest-for-woocommerce/README.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# Pinterest for WooCommerce
|
||||
|
||||
[](https://github.com/woocommerce/pinterest-for-woocommerce/actions/workflows/php-unit-tests.yml)
|
||||
[](https://github.com/woocommerce/pinterest-for-woocommerce/actions/workflows/js-unit-tests.yml)
|
||||
[](https://github.com/woocommerce/pinterest-for-woocommerce/actions/workflows/php-cs-on-changes.yml)
|
||||
[](https://github.com/woocommerce/pinterest-for-woocommerce/actions/workflows/js-css-linting.yml)
|
||||
|
||||
A native integration which allows you to market your store on Pinterest, including:
|
||||
|
||||
- [Sync your WooCommerce products to Pinterest.](https://help.pinterest.com/en/business/article/before-you-get-started-with-catalogs)
|
||||
- Allow your visitors to [save products to their Pinterest boards](https://help.pinterest.com/en/business/article/save-button).
|
||||
- Make your products and posts show up as [Rich Pins](https://help.pinterest.com/en/business/article/rich-pins) on Pinterest.
|
||||
- Track conversions with [Pinterest tag](https://help.pinterest.com/en/business/article/track-conversions-with-pinterest-tag).
|
||||
|
||||
## Status - _in development_
|
||||
|
||||
Pinterest for WooCommerce is under development. To find out more about availability and release, refer to WooCommerce.com.
|
||||
|
||||
## Support
|
||||
|
||||
This repository is not suitable for support. Please don't use our issue tracker for support requests.
|
||||
|
||||
### Requirements
|
||||
|
||||
Pinterest for WooCommerce requires recent versions of PHP (7.3 or newer), and WordPress and WooCommerce (we recommend the latest, and support the last two versions, a.k.a. L-2).
|
||||
|
||||
See [pinterest-for-woocommerce.php](https://github.com/woocommerce/pinterest-for-woocommerce/blob/develop/pinterest-for-woocommerce.php) for current required versions.
|
||||
|
||||
### Supported browsers
|
||||
|
||||
As per [WordPress Core Handbook](https://make.wordpress.org/core/handbook/best-practices/browser-support/) we currently support:
|
||||
|
||||
> - Last 1 Android versions.
|
||||
> - Last 1 ChromeAndroid versions.
|
||||
> - Last 2 Chrome versions.
|
||||
> - Last 2 Firefox versions.
|
||||
> - Last 2 Safari versions.
|
||||
> - Last 2 iOS versions.
|
||||
> - Last 2 Edge versions.
|
||||
> - Last 2 Opera versions.
|
||||
> - Browsers with > 1% usage based on [can I use browser usage table](https://caniuse.com/usage-table)
|
||||
|
||||
:warning: We do not support Internet Explorer.
|
||||
|
||||
## Development
|
||||
|
||||
After cloning the repo. Remember to use the appropriate node version
|
||||
|
||||
- `nvm use` to autoselect the node version based on `.nvmrc` file.
|
||||
|
||||
Then, install dependencies:
|
||||
|
||||
- `npm install` to install JavaScript dependencies.
|
||||
- `composer install` to gather PHP dependencies.
|
||||
|
||||
Now you can build the plugin using one of these commands:
|
||||
|
||||
- `npm start`: Build a development version and watch files for changes.
|
||||
- `npm build`: Build a production version.
|
||||
- `npm build:zip`: Build and production version and package as a zip file.
|
||||
|
||||
### Branches
|
||||
|
||||
- `develop` branch is the most up-to-date code.
|
||||
|
||||
### Development tools
|
||||
|
||||
There are a number of development tools available as npm scripts. Check the [`package.json`](https://github.com/woocommerce/pinterest-for-woocommerce/blob/develop/package.json) file for more.
|
||||
|
||||
- `npm run lint:js`: Run [`eslint`](https://eslint.org/) to validate JavaScript code style.
|
||||
- `npm run lint:css`: Run [`stylelint`](https://stylelint.io/) to validate CSS code style.
|
||||
- `npm run lint:php`: Run [`phpcs`](https://github.com/squizlabs/PHP_CodeSniffer) to validate PHP code style.
|
||||
|
||||
Please use these tools to ensure your code changes are consistent with the rest of the code base. This code follows WooCommerce and WordPress standards.
|
||||
|
||||
This repository includes an [`EditorConfig`](https://editorconfig.org/) to automate basic code formatting. Please install the appropriate plugin for your editor.
|
||||
|
||||
|
||||
## PHPUnit
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Install [`composer`](https://getcomposer.org/), `git`, `svn`, and either `wget` or `curl`.
|
||||
|
||||
Change to the plugin root directory and type:
|
||||
|
||||
```bash
|
||||
$ composer install
|
||||
```
|
||||
|
||||
|
||||
### Install Test Dependencies
|
||||
|
||||
To run the unit tests you need WordPress, [WooCommerce](https://github.com/woocommerce/woocommerce), and the WordPress Unit Test lib (included in the [core development repository](https://make.wordpress.org/core/handbook/testing/automated-testing/phpunit/)).
|
||||
|
||||
Install them using the `install-wp-tests.sh` script:
|
||||
|
||||
```bash
|
||||
$ ./bin/install-wp-tests.sh <db-name> <db-user> <db-pass> <db-host>
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
$ ./bin/install-wp-tests.sh wordpress_tests root root localhost
|
||||
```
|
||||
|
||||
This script installs the test dependencies into your system's temporary directory and also creates a test database.
|
||||
|
||||
You can also specify the path to their directories by setting the following environment variables:
|
||||
|
||||
- `WP_TESTS_DIR`: WordPress Unit Test lib directory
|
||||
- `WP_CORE_DIR`: WordPress core directory
|
||||
- `WC_DIR`: WooCommerce directory
|
||||
|
||||
### Running Tests
|
||||
|
||||
Change to the plugin root directory and type:
|
||||
|
||||
```bash
|
||||
$ vendor/bin/phpunit
|
||||
```
|
||||
|
||||
The tests will execute, and you'll be presented with a summary.
|
||||
|
||||
<p align="center">
|
||||
<br/><br/>
|
||||
Made with 💜 by <a href="https://woocommerce.com/">WooCommerce</a>.<br/>
|
||||
<a href="https://woocommerce.com/careers/">We're hiring</a>! Come work with us!
|
||||
</p>
|
||||
|
||||
198
wp-content/plugins/pinterest-for-woocommerce/TRACKING.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# Usage Tracking
|
||||
|
||||
_Pinterest for WooCommerce_ implements usage tracking, based on the native [WooCommerce Usage Tracking](https://woocommerce.com/usage-tracking/), and is only enabled when WooCommerce Tracking is enabled.
|
||||
|
||||
When a store opts in to WooCommerce usage tracking and uses _Pinterest for WooCommerce_, they will also be opted in to the tracking added by _Pinterest for WooCommerce_.
|
||||
|
||||
## What is tracked
|
||||
|
||||
As in WooCommerce core, only non-sensitive data about how a store is set up and managed is tracked. We **do not track or store personal data** from your clients.
|
||||
|
||||
<woocommerce-grow-tracking-jsdoc>
|
||||
<!---
|
||||
Everything below will be automatically generated by `woocommerce-grow-tracking-jsdoc`.
|
||||
Do not edit it manually!
|
||||
-->
|
||||
|
||||
### [`wcadmin_pfw_account_connect_button_click`](assets/source/setup-guide/app/components/Account/Connection.js#L37)
|
||||
Clicking on "Connect" Pinterest account button.
|
||||
#### Emitters
|
||||
- [`AccountConnection`](assets/source/setup-guide/app/components/Account/Connection.js#L82)
|
||||
|
||||
### [`wcadmin_pfw_account_convert_button_click`](assets/source/setup-guide/app/steps/SetupAccount.js#L32)
|
||||
Clicking on "… convert your personal account" button.
|
||||
#### Emitters
|
||||
- [`SetupAccount`](assets/source/setup-guide/app/steps/SetupAccount.js#L54)
|
||||
|
||||
### [`wcadmin_pfw_account_create_button_click`](assets/source/setup-guide/app/steps/SetupAccount.js#L27)
|
||||
Clicking on "… create a new Pinterest account" button.
|
||||
#### Emitters
|
||||
- [`SetupAccount`](assets/source/setup-guide/app/steps/SetupAccount.js#L54)
|
||||
|
||||
### [`wcadmin_pfw_account_disconnect_button_click`](assets/source/setup-guide/app/components/Account/Connection.js#L42)
|
||||
Clicking on "Disconnect" Pinterest account button.
|
||||
#### Properties
|
||||
| name | type | description |
|
||||
| ---- | ---- | ----------- |
|
||||
`context` | `string` | `'settings' \| 'wizard'` In which context it was used?
|
||||
#### Emitters
|
||||
- [`AccountConnection`](assets/source/setup-guide/app/components/Account/Connection.js#L82) with the given `{ context }`
|
||||
|
||||
### [`wcadmin_pfw_ads_manager_link_click`](assets/source/catalog-sync/sections/SyncState.js#L25)
|
||||
Clicking on the "Pinterest ads manager" link.
|
||||
#### Emitters
|
||||
- [`SyncState`](assets/source/catalog-sync/sections/SyncState.js#L41)
|
||||
|
||||
### [`wcadmin_pfw_ads_credits_success_notice`](assets/source/catalog-sync/sections/AdCreditsNotice.js#L20)
|
||||
Closing the Ads Credits notice on Catalog Page.
|
||||
#### Emitters
|
||||
- [`AdCreditsNotice`](assets/source/catalog-sync/sections/AdCreditsNotice.js#L38)
|
||||
|
||||
### [`wcadmin_pfw_ads_billing_details_link_click`](assets/source/catalog-sync/sections/AdCreditsNotice.js#L25)
|
||||
Clicking on the "add your billing details" link.
|
||||
#### Emitters
|
||||
- [`AdCreditsNotice`](assets/source/catalog-sync/sections/AdCreditsNotice.js#L38)
|
||||
|
||||
### [`wcadmin_pfw_business_account_connect_button_click`](assets/source/setup-guide/app/components/Account/BusinessAccountSelection.js#L24)
|
||||
Clicking on "Connect" business account button.
|
||||
#### Emitters
|
||||
- [`BusinessAccountSelection`](assets/source/setup-guide/app/components/Account/BusinessAccountSelection.js#L40)
|
||||
|
||||
### [`wcadmin_pfw_business_account_create_button_click`](assets/source/setup-guide/app/components/Account/BusinessAccountSelection.js#L19)
|
||||
Clicking on "Create business account" button.
|
||||
#### Emitters
|
||||
- [`BusinessAccountSelection`](assets/source/setup-guide/app/components/Account/BusinessAccountSelection.js#L40)
|
||||
|
||||
### [`wcadmin_pfw_documentation_link_click`](assets/source/setup-guide/app/helpers/documentation-link-props.js#L6)
|
||||
Clicking on an external documentation link.
|
||||
#### Properties
|
||||
| name | type | description |
|
||||
| ---- | ---- | ----------- |
|
||||
`link_id` | `string` | Identifier of the link.
|
||||
`context` | `string` | `'settings' \| 'welcome-section' \| 'wizard' \| 'ads-credits-terms-and-conditions'` In which context the link was placed?
|
||||
`href` | `string` | Href to which the user was navigated to.
|
||||
#### Emitters
|
||||
- [`documentationLinkProps`](assets/source/setup-guide/app/helpers/documentation-link-props.js#L49) on click, with given `linkId` and `context`.
|
||||
- [`ClaimWebsite`](assets/source/setup-guide/app/steps/ClaimWebsite.js#L99) with `{ link_id: 'claim-website', context: props.view }`
|
||||
- [`SetupAccount`](assets/source/setup-guide/app/steps/SetupAccount.js#L56)
|
||||
- with `{ link_id: 'ad-guidelines', context: props.view }`
|
||||
- with `{ link_id: 'merchant-guidelines', context: props.view }`
|
||||
- [`SetupTracking`](assets/source/setup-guide/app/steps/SetupTracking.js#L57)
|
||||
- with `{ link_id: 'ad-guidelines', context: 'wizard'|'settings' }`
|
||||
- with `{ link_id: 'ad-data-terms', context: 'wizard'|'settings' }`
|
||||
- with `{ link_id: 'ad-terms-of-service', context: 'wizard'|'settings' }`
|
||||
- with `{ link_id: 'install-tag', context: 'wizard'|'settings' }`
|
||||
- with `{ link_id: 'automatic-enhanced-match', context: 'wizard'|'settings' }`
|
||||
- [`SetupPins`](assets/source/setup-guide/app/steps/SetupPins.js#L48)
|
||||
- with `{ link_id: 'ads-manager', context: 'settings' }`
|
||||
- with `{ link_id: 'enhanced-match', context: 'settings' }`
|
||||
- [`WelcomeSection`](assets/source/setup-guide/app/views/LandingPageApp.js#L48) with `{ link_id: 'terms-of-service', context: 'welcome-section' }`
|
||||
- [TermsAndConditionsModal]( assets/source/setup-guide/app/components/TermsAndConditionsModal.js#L24)
|
||||
- with `{ link_id: 'terms-of-service', context: 'ads-credits-terms-and-conditions' }`
|
||||
- with `{ link_id: 'privacy-policy', context: 'ads-credits-terms-and-conditions' }`
|
||||
- with `{ link_id: 'advertising-services-agreement', context: 'ads-credits-terms-and-conditions' }`
|
||||
- [FormattedReasons]( assets/source/setup-guide/app/components/HealthCheck/index.js#L29)
|
||||
- with `{ link_id: 'merchant-guidelines', context: 'merchant-disapproval-reasons' }`
|
||||
### [`wcadmin_pfw_domain_verify_failure`](assets/source/setup-guide/app/steps/ClaimWebsite.js#L69)
|
||||
Triggered when domain verification fails.
|
||||
#### Properties
|
||||
| name | type | description |
|
||||
| ---- | ---- | ----------- |
|
||||
`step` | `string` | Identifier of the step when verification failed.
|
||||
#### Emitters
|
||||
- [`ClaimWebsite`](assets/source/setup-guide/app/steps/ClaimWebsite.js#L99)
|
||||
|
||||
### [`wcadmin_pfw_domain_verify_success`](assets/source/setup-guide/app/steps/ClaimWebsite.js#L77)
|
||||
Triggered when a site is successfully verified.
|
||||
#### Emitters
|
||||
- [`ClaimWebsite`](assets/source/setup-guide/app/steps/ClaimWebsite.js#L99)
|
||||
|
||||
### [`wcadmin_pfw_get_started_faq`](assets/source/setup-guide/app/views/LandingPageApp.js#L310)
|
||||
Clicking on getting started page faq item to collapse or expand it.
|
||||
#### Properties
|
||||
| name | type | description |
|
||||
| ---- | ---- | ----------- |
|
||||
`action` | `string` | `'expand' \| 'collapse'` What action was initiated.
|
||||
`question_id` | `string` | Identifier of the clicked question.
|
||||
#### Emitters
|
||||
- [`FaqQuestion`](assets/source/setup-guide/app/views/LandingPageApp.js#326) whenever the FAQ is toggled.
|
||||
|
||||
### [`wcadmin_pfw_get_started_notice_link_click`](assets/source/setup-guide/app/helpers/documentation-link-props.js#L16)
|
||||
Clicking on the link inside the notice.
|
||||
#### Properties
|
||||
| name | type | description |
|
||||
| ---- | ---- | ----------- |
|
||||
`link_id` | `string` | Identifier of the link.
|
||||
`context` | `string` | What action was initiated.
|
||||
`href` | `string` | Href to which the user was navigated to.
|
||||
#### Emitters
|
||||
- [`PrelaunchNotice`](assets/source/components/prelaunch-notice/index.js#L18) `{ context: 'pinterest-landing', link_id: 'prelaunch-notice' }`
|
||||
- [`UnsupportedCountryNotice`](assets/source/setup-guide/app/components/UnsupportedCountryNotice/index.js#L31) with `{ context: 'pinterest-landing', linkId: 'ads-availability' | 'unsupported-country-link' }`
|
||||
|
||||
### [`wcadmin_pfw_modal_closed`](assets/source/setup-guide/app/components/Account/Connection.js#L55)
|
||||
Closing a modal.
|
||||
#### Properties
|
||||
| name | type | description |
|
||||
| ---- | ---- | ----------- |
|
||||
`name` | `string` | Which modal is it?
|
||||
`context` | `string` | `'settings' \| 'wizard' \| 'landing-page' \| 'catalog-sync'` In which context it was used?
|
||||
`action` | `string` | `confirm` - When the final "Yes, I'm sure" button is clicked. <br> `dismiss` - When the modal is dismissed by clicking on "x", "cancel", overlay, or by pressing a keystroke.
|
||||
#### Emitters
|
||||
- [`AccountConnection`](assets/source/setup-guide/app/components/Account/Connection.js#L82) with `{ name: 'account-disconnection', … }`
|
||||
- [`LandingPageApp.AdsCreditSection`](assets/source/setup-guide/app/views/LandingPageApp.js#L140) with `{ name: 'ads-credits-terms-and-conditions', … } `
|
||||
- [`CatalogSync`](assets/source/catalog-sync/App.js#L37) with `{ name: 'ads-credits-onboarding', … } `
|
||||
- [`SetupAccount`](assets/source/setup-guide/app/steps/SetupAccount.js#L60 ) with `{ name: 'ads-credits-terms-and-conditions', … } `
|
||||
|
||||
### [`wcadmin_pfw_modal_open`](assets/source/setup-guide/app/components/Account/Connection.js#L39)
|
||||
Opening a modal.
|
||||
#### Properties
|
||||
| name | type | description |
|
||||
| ---- | ---- | ----------- |
|
||||
`name` | `string` | Which modal is it?
|
||||
`context` | `string` | `'settings' \| 'wizard' \| 'landing-page' \| 'catalog-sync'` In which context it was used?
|
||||
#### Emitters
|
||||
- [`AccountConnection`](assets/source/setup-guide/app/components/Account/Connection.js#L82) with `{ name: 'account-disconnection', … }`
|
||||
- [`LandingPageApp.AdsCreditSection`](assets/source/setup-guide/app/views/LandingPageApp.js#L140) with `{ name: 'ads-credits-terms-and-conditions', … } `
|
||||
- [`CatalogSync`](assets/source/catalog-sync/App.js#L38) with `{ name: 'ads-credits-onboarding', … } `
|
||||
- [`SetupAccount`](assets/source/setup-guide/app/steps/SetupAccount.js#L59 ) with `{ name: 'ads-credits-terms-and-conditions', … } `
|
||||
|
||||
### [`wcadmin_pfw_save_changes_button_click`](assets/source/setup-guide/app/components/SaveSettingsButton.js#L19)
|
||||
Clicking on "… Save changes" button.
|
||||
#### Properties
|
||||
| name | type | description |
|
||||
| ---- | ---- | ----------- |
|
||||
`enable_debug_logging` | `boolean` | Indicates if Enable debug logging option is checked
|
||||
`enhanced_match_support` | `boolean` | Indicates if Enhanced Match Support option is checked
|
||||
`automatic_enhanced_match_support` | `boolean` | Indicates if Automatic Enhanced Match Support option is checked
|
||||
`erase_plugin_data` | `boolean` | Indicates if Erase Plugin Data option is checked
|
||||
`product_sync_enabled` | `boolean` | Indicates if Enable Product Sync option is checked
|
||||
`rich_pins_on_posts` | `boolean` | Indicates if Add Rich Pins for Posts option is checked
|
||||
`rich_pins_on_products` | `boolean` | Indicates if Add Rich Pins for Products option is checked
|
||||
`save_to_pinterest` | `boolean` | Indicates if Save to Pinterest option is checked
|
||||
`track_conversions` | `boolean` | Indicates if Track Conversion option is checked
|
||||
`context` | `string` | The context in which the event is recorded
|
||||
#### Emitters
|
||||
- [`SaveSettingsButton`](assets/source/setup-guide/app/components/SaveSettingsButton.js#L42) with `{ context: view, … }`
|
||||
|
||||
### [`wcadmin_pfw_setup`](assets/source/setup-guide/app/views/LandingPageApp.js#L38)
|
||||
Triggered on events during setup,
|
||||
like starting, ending, or navigating between steps.
|
||||
#### Properties
|
||||
| name | type | description |
|
||||
| ---- | ---- | ----------- |
|
||||
`target` | `string` | Setup phase that the user navigates to.
|
||||
`trigger` | `string` | UI element that triggered the action, e.g. `wizard-stepper` or `get-started` button.
|
||||
#### Emitters
|
||||
- [`SetupTracking`](assets/source/setup-guide/app/steps/SetupTracking.js#L54)
|
||||
- with `{ target: 'complete', trigger: 'setup-tracking-complete' }` when "Complete setup" button is clicked.
|
||||
- with `{ target: 'fetch-tags' | 'fetch-advertisers', trigger: 'setup-tracking-try-again' }` when "Try again" button is clicked.
|
||||
- [`WelcomeSection`](assets/source/setup-guide/app/views/LandingPageApp.js#L53) with `{ target: 'onboarding', trigger: 'get-started' }` when "Get started" button is clicked for incomplete setup.
|
||||
- [`WizardApp`](assets/source/setup-guide/app/views/WizardApp.js#L37)
|
||||
- with `{ target: 'setup-account' | 'claim-website' | 'setup-tracking', trigger: 'wizard-stepper' }` when wizard's header step is clicked.
|
||||
- with `{ target: 'claim-website' , trigger: 'setup-account-continue' }` when continue button is clicked.
|
||||
- with `{ target: 'setup-tracking', trigger: 'claim-website-continue' }` when continue button is clicked.
|
||||
|
||||
<!---
|
||||
End of `woocommerce-grow-tracking-jsdoc`-generated content.
|
||||
-->
|
||||
</woocommerce-grow-tracking-jsdoc>
|
||||
@@ -0,0 +1,24 @@
|
||||
.pinterest-for-woocommerce-image-wrapper {
|
||||
left: 10px;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
z-index: 50;
|
||||
opacity: 0;
|
||||
visibility: hidden; }
|
||||
@media (hover: none) {
|
||||
.pinterest-for-woocommerce-image-wrapper {
|
||||
opacity: 1;
|
||||
visibility: visible; } }
|
||||
.product:hover > .pinterest-for-woocommerce-image-wrapper,
|
||||
.wc-block-grid__product:hover > .pinterest-for-woocommerce-image-wrapper {
|
||||
opacity: 1;
|
||||
visibility: visible; }
|
||||
.product:hover > .pinterest-for-woocommerce-image-wrapper a,
|
||||
.wc-block-grid__product:hover > .pinterest-for-woocommerce-image-wrapper a {
|
||||
text-decoration: none; }
|
||||
|
||||
.wp-block-post.product,
|
||||
.wc-block-product.product {
|
||||
position: relative; }
|
||||
|
||||
/*# sourceMappingURL=../../source/_maps/css/frontend/pinterest-for-woocommerce-pins.css.map */
|
||||
@@ -0,0 +1,2 @@
|
||||
.pinterest-for-woocommerce-image-wrapper{left:10px;position:absolute;top:10px;z-index:50;opacity:0;visibility:hidden}@media (hover:none){.pinterest-for-woocommerce-image-wrapper{opacity:1;visibility:visible}}.product:hover>.pinterest-for-woocommerce-image-wrapper,.wc-block-grid__product:hover>.pinterest-for-woocommerce-image-wrapper{opacity:1;visibility:visible}.product:hover>.pinterest-for-woocommerce-image-wrapper a,.wc-block-grid__product:hover>.pinterest-for-woocommerce-image-wrapper a{text-decoration:none}.wc-block-product.product,.wp-block-post.product{position:relative}
|
||||
/*# sourceMappingURL=../../source/_maps/css/frontend/pinterest-for-woocommerce-pins.min.css.map */
|
||||
@@ -0,0 +1,29 @@
|
||||
<svg width="517" height="160" viewBox="0 0 517 160" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="517" height="160" fill="#F7EDF7"/>
|
||||
<g clip-path="url(#clip0_3682_60429)">
|
||||
<path d="M170.925 81.0513C173.197 80.6136 175.21 79.6822 176.842 78.0041C177.009 77.83 177.159 77.6454 177.245 77.4128C177.479 76.783 177.245 76.0701 176.683 75.7051C176.104 75.3241 175.373 75.385 174.866 75.902C174.182 76.599 173.42 77.1646 172.529 77.5673C170.84 78.3356 169.069 78.5363 167.239 78.3867C163.895 78.1094 161.78 76.4712 160.605 73.0522C160.493 72.7264 160.521 72.5966 160.916 72.5315C163.273 72.1409 165.292 71.0806 166.956 69.3566C167.727 68.5612 168.263 67.6348 168.507 66.5515C169.048 64.1144 167.817 62.0234 165.455 61.4071C163.857 60.9915 162.429 61.4088 161.209 62.4559C159.139 64.2343 157.96 66.5219 157.541 69.2007C157.477 69.6003 157.356 69.6552 157.006 69.5564C153.574 68.5886 151.244 66.4438 150.038 63.082C149.907 62.7232 149.947 62.5763 150.363 62.4991C152.063 62.1724 153.585 61.4496 154.956 60.3967C155.88 59.6851 156.712 58.8875 157.271 57.8427C158.693 55.1767 157.404 51.997 154.574 51.2584C152.642 50.7547 151.002 51.3532 149.657 52.7632C148.047 54.446 147.127 56.4721 146.8 58.7726C146.755 59.0875 146.896 59.5522 146.616 59.6914C146.347 59.8246 145.953 59.61 145.624 59.4992C143.419 58.7316 141.545 57.5375 140.813 55.1873C139.757 51.7863 140.022 48.5539 142.359 45.6913C142.883 45.0507 142.812 44.1918 142.21 43.6661C141.615 43.1458 140.755 43.1948 140.185 43.798C140.039 43.9489 139.9 44.1108 139.777 44.2776C136.898 48.3522 136.598 52.7328 138.578 57.1901C140.039 60.4864 142.976 61.993 146.401 62.6198C146.784 62.6893 146.967 62.7944 147.089 63.1982C148.536 68.2126 151.818 71.3119 156.902 72.4583C157.415 72.5733 157.569 72.7857 157.698 73.2564C158.692 76.9227 160.736 79.6657 164.543 80.7872C165.941 81.1991 167.377 81.3243 168.892 81.2954C169.529 81.2547 170.231 81.1892 170.925 81.0513ZM149.634 59.4551C149.819 57.546 150.557 55.8903 151.951 54.5569C152.329 54.1959 152.791 53.9827 153.327 53.9682C154.244 53.9394 154.94 54.6014 154.957 55.5183C154.972 56.0604 154.76 56.5215 154.428 56.92C153.223 58.347 151.684 59.2271 149.882 59.664C149.682 59.7106 149.609 59.691 149.634 59.4551ZM160.419 69.4284C160.793 67.473 161.665 65.8011 163.229 64.5341C163.766 64.0999 164.389 64.0038 165.05 64.3091C165.528 64.5317 165.754 64.8925 165.748 65.1892C165.746 66.0229 165.531 66.5624 165.146 67.0244C163.962 68.4339 162.445 69.2853 160.646 69.6492C160.418 69.6969 160.382 69.6312 160.419 69.4284Z" fill="#E5CFE8"/>
|
||||
</g>
|
||||
<path d="M288.311 55.275C287.858 52.216 286.234 49.5346 283.779 47.7218C281.286 45.9091 278.265 45.1537 275.206 45.6069C271.127 46.2112 263.801 51.9516 259.458 55.5771C258.211 50.0255 255.87 40.9995 253 38.0537C250.847 35.8633 247.977 34.617 244.918 34.5415C244.842 34.5415 244.767 34.5415 244.691 34.5415C241.708 34.5415 238.875 35.6745 236.722 37.7894C232.153 42.208 232.039 49.5346 236.496 54.0665C240.084 57.7676 253.151 60.9777 257.154 61.8841C259.609 63.017 271.656 68.4176 277.547 68.4176C277.963 68.4176 278.34 68.3798 278.643 68.342C281.702 67.8888 284.383 66.2649 286.196 63.8101C288.009 61.3553 288.764 58.2963 288.311 55.275ZM282.835 61.3553C281.664 62.9415 279.964 63.9612 278.001 64.2633C275.281 64.6787 267.539 61.9218 261.497 59.316C266.482 55.0484 273.091 50.1388 275.81 49.7234C277.736 49.4213 279.7 49.9122 281.286 51.083C282.872 52.2537 283.892 53.9532 284.194 55.917C284.496 57.8431 284.005 59.7692 282.835 61.3553ZM244.729 38.6958H244.842C246.806 38.7335 248.656 39.5266 250.016 40.924C251.942 42.9255 254.208 50.8564 255.605 57.2766C249.223 55.6904 241.405 53.1979 239.479 51.2341C236.647 48.3261 236.722 43.6431 239.63 40.8107C240.99 39.4511 242.803 38.6958 244.729 38.6958Z" fill="#533582"/>
|
||||
<path d="M322.451 98.0259V160H275.659L275.357 98.0259H322.451Z" fill="#784DAD"/>
|
||||
<path d="M275.659 160H185.852V98.0259H275.357L275.659 160Z" fill="#9A69C7"/>
|
||||
<path d="M230.114 98.0259H226.337V160H230.114V98.0259Z" fill="#533582"/>
|
||||
<path d="M301.642 98.0259H297.865V160H301.642V98.0259Z" fill="#533582"/>
|
||||
<path d="M314.105 80.3514L311.121 89.6796L307.534 88.5089L310.517 79.1807L314.105 80.3514Z" fill="#260206"/>
|
||||
<path d="M236.949 54.8597L233.928 64.4145L230.34 63.2438L233.361 53.689L236.949 54.8597Z" fill="#260206"/>
|
||||
<path d="M335.593 87.4516L332.723 96.742L311.121 89.6798L314.105 80.3516L335.593 87.4516Z" fill="#9A69C7"/>
|
||||
<path d="M310.517 79.181L307.533 88.5091L281.173 79.8985L284.496 70.5703L310.517 79.181Z" fill="#9A69C7"/>
|
||||
<path d="M284.496 70.57L281.173 79.8982L233.928 64.4142L236.949 54.8594L284.496 70.57Z" fill="#C792E0"/>
|
||||
<path d="M233.361 53.6888L230.34 63.2436L190.119 50.101L193.367 40.4707L233.361 53.6888Z" fill="#C792E0"/>
|
||||
<path d="M236.949 54.8597L233.928 64.4145L230.34 63.2438L233.361 53.689L236.949 54.8597Z" fill="#7B4EB1"/>
|
||||
<path d="M314.105 80.3514L311.121 89.6796L307.534 88.5089L310.517 79.1807L314.105 80.3514Z" fill="#623F8D"/>
|
||||
<path d="M315.5 35C317.985 35 320 32.9853 320 30.5C320 28.0147 317.985 26 315.5 26C313.015 26 311 28.0147 311 30.5C311 32.9853 313.015 35 315.5 35Z" fill="white"/>
|
||||
<path d="M199 79C200.657 79 202 77.6569 202 76C202 74.3431 200.657 73 199 73C197.343 73 196 74.3431 196 76C196 77.6569 197.343 79 199 79Z" fill="#9A69C7"/>
|
||||
<path d="M343.569 57.5554C344.168 58.2783 344.097 59.3523 343.389 60.0017C343.048 60.3107 342.694 60.6134 342.323 60.8855C342.041 61.0928 341.982 61.2576 342.248 61.5356C342.532 61.825 342.775 62.1494 343.027 62.4651C343.708 63.3075 343.641 64.3868 342.875 65.0308C342.088 65.6923 341.006 65.5572 340.282 64.7059C340.006 64.3831 339.724 64.0647 339.474 63.7201C339.292 63.4792 339.155 63.4859 338.942 63.6802C338.601 63.9892 338.244 64.277 337.876 64.564C337.067 65.1991 335.977 65.0876 335.358 64.3191C334.756 63.5717 334.866 62.5013 335.619 61.8414C335.963 61.5377 336.322 61.2402 336.684 60.9576C336.909 60.7888 336.947 60.6511 336.744 60.4277C336.456 60.1137 336.196 59.7778 335.924 59.4507C335.236 58.5881 335.309 57.4948 336.099 56.8482C336.879 56.2103 337.947 56.349 338.649 57.1739C338.925 57.4966 339.207 57.815 339.457 58.1596C339.647 58.4208 339.799 58.4106 340.028 58.2032C340.384 57.8811 340.753 57.5748 341.136 57.2844C341.901 56.7036 342.965 56.8273 343.569 57.5554Z" fill="#9A69C7"/>
|
||||
<path d="M149.962 120.578C150.646 120.268 151.459 120.549 151.811 121.232C151.978 121.559 152.137 121.896 152.269 122.24C152.369 122.501 152.484 122.582 152.754 122.435C153.037 122.276 153.338 122.158 153.635 122.029C154.428 121.681 155.247 121.96 155.582 122.686C155.927 123.432 155.595 124.239 154.786 124.618C154.479 124.763 154.174 124.914 153.855 125.034C153.631 125.124 153.607 125.231 153.713 125.436C153.879 125.763 154.026 126.1 154.17 126.444C154.49 127.202 154.174 128.019 153.451 128.335C152.748 128.642 151.945 128.332 151.595 127.612C151.433 127.282 151.279 126.943 151.138 126.604C151.055 126.395 150.956 126.337 150.741 126.447C150.439 126.602 150.125 126.733 149.815 126.873C149.005 127.223 148.177 126.936 147.845 126.191C147.517 125.455 147.849 124.66 148.633 124.293C148.94 124.147 149.245 123.997 149.563 123.877C149.804 123.785 149.829 123.666 149.717 123.446C149.543 123.103 149.385 122.754 149.241 122.398C148.954 121.686 149.274 120.891 149.962 120.578Z" fill="#9A69C7"/>
|
||||
<path d="M152.5 102C154.985 102 157 99.9853 157 97.5C157 95.0147 154.985 93 152.5 93C150.015 93 148 95.0147 148 97.5C148 99.9853 150.015 102 152.5 102Z" fill="white"/>
|
||||
<defs>
|
||||
<clipPath id="clip0_3682_60429">
|
||||
<rect width="39" height="39.0559" fill="white" transform="translate(176.028 42) rotate(87.8517)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.4 KiB |
@@ -0,0 +1,11 @@
|
||||
<svg width="101" height="100" viewBox="0 0 101 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="51.0001" cy="50" r="50" fill="#F6F7F7"/>
|
||||
<path d="M43.3355 44H11.998C10.8496 43.9985 9.74874 43.4673 8.93676 42.523C8.12478 41.5787 7.66804 40.2984 7.66675 38.963V9.03704C7.66804 7.70159 8.12478 6.42128 8.93676 5.47698C9.74874 4.53268 10.8496 4.0015 11.998 4H43.3355C44.4838 4.0015 45.5848 4.53268 46.3967 5.47698C47.2087 6.42128 47.6655 7.70159 47.6667 9.03704V38.963C47.6655 40.2984 47.2087 41.5787 46.3967 42.523C45.5848 43.4673 44.4838 43.9985 43.3355 44Z" fill="#E6E6E6"/>
|
||||
<path d="M19.9742 36.8172C19.9685 36.8172 19.9628 36.8171 19.9572 36.8168L16.3928 36.6633C16.2816 36.6594 16.1755 36.6088 16.0939 36.521C16.0123 36.4332 15.9607 36.314 15.9488 36.1854C15.7035 33.6398 14.6939 20.668 18.9233 15.2765C19.522 14.4981 20.2621 13.8843 21.09 13.4799C21.918 13.0754 22.8129 12.8903 23.71 12.9381C23.7465 12.9408 23.7829 12.9319 23.8153 12.9122C23.8476 12.8926 23.8748 12.863 23.8938 12.8267L24.7566 11.2498C24.8039 11.1643 24.8707 11.096 24.9497 11.0525C25.0286 11.0089 25.1164 10.992 25.2032 11.0035C25.895 11.1007 29.4214 11.5597 30.9042 11.0604C30.9916 11.0304 31.0848 11.031 31.1719 11.0622C31.2591 11.0934 31.3364 11.1537 31.3942 11.2357L32.5273 12.8463C32.5468 12.8754 32.5719 12.8987 32.6007 12.9142C32.6295 12.9297 32.661 12.937 32.6927 12.9354C33.269 12.9219 35.2898 13.0517 37.0583 15.3522C38.9734 17.8432 40.9498 23.4636 39.4898 36.0918C39.4745 36.2215 39.4195 36.3404 39.3348 36.4267C39.2501 36.513 39.1415 36.5608 39.0289 36.5613H36.2216C36.1102 36.5607 36.0026 36.5137 35.9183 36.4289C35.834 36.3441 35.7786 36.227 35.7621 36.0989L34.8451 28.7401C34.8376 28.6796 34.8107 28.6246 34.77 28.586C34.7292 28.5475 34.6774 28.5281 34.625 28.5319C34.5725 28.5356 34.5232 28.5622 34.4868 28.6063C34.4503 28.6504 34.4295 28.7088 34.4284 28.7699L34.3652 32.2249C34.3632 32.3274 34.3363 32.4271 34.2874 32.5125C34.2386 32.5978 34.1699 32.6653 34.0893 32.7069C33.0885 33.2187 27.8007 35.6187 21.9563 32.6128C21.8772 32.5714 21.8096 32.5054 21.7609 32.4221C21.7122 32.3387 21.6843 32.2412 21.6804 32.1405L21.5655 29.0014C21.5633 28.9401 21.5412 28.882 21.5038 28.8388C21.4663 28.7956 21.4163 28.7704 21.3635 28.7683C21.3108 28.7661 21.2594 28.7872 21.2194 28.8273C21.1795 28.8674 21.154 28.9235 21.1481 28.9844L20.4356 36.3377C20.4224 36.4694 20.3681 36.5909 20.2831 36.6793C20.1981 36.7676 20.0882 36.8167 19.9742 36.8172Z" fill="#7F54B3"/>
|
||||
<path d="M43.3355 90H11.998C10.8496 89.9985 9.74874 89.4673 8.93676 88.523C8.12478 87.5787 7.66804 86.2984 7.66675 84.963V55.037C7.66804 53.7016 8.12478 52.4213 8.93676 51.477C9.74874 50.5327 10.8496 50.0015 11.998 50H43.3355C44.4838 50.0015 45.5848 50.5327 46.3967 51.477C47.2087 52.4213 47.6655 53.7016 47.6667 55.037V84.963C47.6655 86.2984 47.2087 87.5787 46.3967 88.523C45.5848 89.4673 44.4838 89.9985 43.3355 90Z" fill="#E6E6E6"/>
|
||||
<path d="M34.3275 80.5397H34.3248L20.2396 80.4505C20.1372 80.4498 20.0385 80.4116 19.9622 80.3434C19.8859 80.2751 19.8371 80.1813 19.825 80.0796L18.4082 68.0364C18.3995 67.9587 18.3631 67.8868 18.3056 67.8338C18.2481 67.7808 18.1734 67.7504 18.0953 67.7482C16.9771 67.7117 14.3167 67.4568 13.7654 65.882C13.2744 64.4796 14.6174 62.411 17.7569 59.7334C17.8103 59.6878 17.8743 59.6562 17.9431 59.6416C18.0118 59.627 18.0831 59.6299 18.1505 59.65C18.2178 59.67 18.279 59.7067 18.3286 59.7565C18.3781 59.8063 18.4144 59.8678 18.4341 59.9353L20.0639 65.5582C20.0838 65.6257 20.1248 65.685 20.1809 65.7274C20.237 65.7699 20.3052 65.7932 20.3755 65.794L33.7304 65.8836C33.8004 65.8844 33.8687 65.8625 33.9253 65.8213C33.9818 65.78 34.0236 65.7217 34.0443 65.6548L35.8578 59.8847C35.878 59.8203 35.9134 59.7617 35.961 59.7139C36.0086 59.6661 36.0671 59.6304 36.1314 59.61C36.1957 59.5896 36.264 59.585 36.3305 59.5966C36.3969 59.6081 36.4596 59.6356 36.5133 59.6765C37.7507 60.6216 41.7371 63.8664 41.081 65.9415C40.7373 67.0284 39.1874 67.6342 36.4741 67.7422C36.3962 67.7449 36.3219 67.7755 36.2646 67.8284C36.2074 67.8813 36.1711 67.953 36.1623 68.0305L34.7447 80.1683C34.7329 80.2706 34.6838 80.365 34.6069 80.4335C34.5299 80.502 34.4305 80.5398 34.3275 80.5397Z" fill="#7F54B3"/>
|
||||
<path d="M89.5377 10H57.7958C55.5154 10 53.6667 12.1544 53.6667 14.812V45.188C53.6667 47.8456 55.5154 50 57.7958 50H89.5377C91.8181 50 93.6667 47.8456 93.6667 45.188V14.812C93.6667 12.1544 91.8181 10 89.5377 10Z" fill="#E5CFE8"/>
|
||||
<path d="M87.7129 33.7761C83.2869 34.6282 79.1129 36.4767 75.5075 39.1816C75.325 38.6963 74.9815 38.2883 74.5343 38.0258C74.2289 37.8364 73.8956 37.6963 73.5465 37.6108C73.2291 37.5299 72.924 37.7228 72.6439 38.0009C72.3216 38.3575 72.0513 38.7578 71.8409 39.1899C67.0039 35.8698 59.6665 33.7512 59.6665 33.7512V33.0872C59.6724 32.9307 59.6884 32.7747 59.7142 32.6203C59.7391 32.4418 59.7703 32.2841 59.8097 32.0912C60.4322 28.9246 62.8932 21.6889 62.8932 21.6889H65.6759L71.071 22.8094L77.1405 22.438L83.2536 21.166L84.0463 21C85.3681 22.0375 86.8684 29.3002 87.4577 32.392C87.5324 32.7842 87.5905 33.1079 87.6341 33.3466C87.686 33.6163 87.7129 33.7761 87.7129 33.7761Z" fill="white"/>
|
||||
<path d="M89.5377 55.9546H57.7958C55.5154 55.9546 53.6667 58.109 53.6667 60.7666V91.1426C53.6667 93.8002 55.5154 95.9546 57.7958 95.9546H89.5377C91.8181 95.9546 93.6667 93.8002 93.6667 91.1426V60.7666C93.6667 58.109 91.8181 55.9546 89.5377 55.9546Z" fill="#E5CFE8"/>
|
||||
<path d="M70.0823 65.0562C70.0823 65.0562 68.7898 65.3793 66.7853 70.8086C64.7808 76.2378 64.0707 83.2526 64.0707 83.2526C64.0707 83.2526 62.9435 85.1613 67.7547 85.2891C67.7547 85.2891 67.3677 86.5496 70.0823 86.3561C72.7969 86.1626 72.4061 86.1645 72.4061 86.1645C72.4061 86.1645 74.1514 85.0655 74.9273 85.259C75.7031 85.4525 76.1878 85.5183 77.0276 86.2284C77.8673 86.9385 80.5519 86.6492 80.5838 86.1006C80.6054 85.8312 80.6054 85.5604 80.5838 85.291C80.5838 85.291 84.6886 85.5502 83.9127 82.5763C83.1369 79.6025 82.4906 74.7218 82.4906 74.7218C82.4906 74.7218 80.3903 65.1877 77.997 65.0581C75.6036 64.9285 70.0823 65.0562 70.0823 65.0562Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.9 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="117" height="100" viewBox="0 0 117 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="57.8334" cy="50" r="50" fill="#F6F7F7"/>
|
||||
<path d="M49.7407 41.9682C50.563 42.1762 51.3181 42.5155 51.9886 42.959C52.6593 43.4025 53.681 43.1392 53.8762 42.3592L57.5083 27.8462C57.6421 27.3114 57.3179 26.7691 56.7833 26.6339L42.4122 23.0004C41.6378 22.8046 41.3744 21.7947 41.813 21.1271C42.2628 20.4424 42.6072 19.6698 42.8181 18.8278C43.8196 14.8394 41.421 10.7951 37.4716 9.79313C33.5222 8.79115 29.5099 11.2213 28.5083 15.2098C28.2977 16.0508 28.2378 16.8952 28.3118 17.7123C28.3841 18.5093 27.6715 19.2758 26.8957 19.0796L14.1274 15.8504C12.7111 15.4919 11.2763 16.3612 10.9179 17.7916L0.541534 59.2507C0.183124 60.681 1.0412 62.1272 2.45752 62.4857L43.5253 72.8676C44.9416 73.2262 46.3764 72.3569 46.7348 70.9265L49.9641 58.0265C50.1589 57.248 49.385 56.5352 48.5857 56.608C47.7839 56.681 46.9563 56.6214 46.1323 56.4129C42.1829 55.411 39.7842 51.3667 40.7858 47.3782C41.7799 43.3889 45.7913 40.9662 49.7407 41.9682Z" fill="#7F54B3"/>
|
||||
<path d="M109.354 37.6466L96.0928 38.8676C95.2966 38.9409 94.713 38.0751 94.9088 37.2999C95.1101 36.5032 95.1826 35.6583 95.1038 34.7893C94.7224 30.6951 91.1001 27.6739 86.9989 28.0551C82.8979 28.4289 79.8842 32.0594 80.2657 36.1536C80.3446 37.0181 80.5698 37.8342 80.9134 38.5806C81.2479 39.3072 80.832 40.2656 80.0354 40.3387L65.1164 41.7078C64.5664 41.7583 64.1615 42.2451 64.212 42.795L65.5811 57.7184C65.6541 58.5145 64.7884 59.0978 64.0133 58.902C63.2165 58.7007 62.3717 58.6281 61.5027 58.7069C57.4087 59.0959 54.3878 62.7186 54.769 66.8204C55.1426 70.9219 58.7727 73.9359 62.8664 73.5543C63.7309 73.4754 64.547 73.2501 65.2933 72.9064C66.0198 72.5719 66.9782 72.9875 67.0515 73.784L68.2721 87.0453C68.406 88.5134 69.7068 89.5889 71.1747 89.4549L113.76 85.5417C115.227 85.4077 116.303 84.1068 116.169 82.6387L112.256 40.0487C112.115 38.5879 110.822 37.5127 109.354 37.6466Z" fill="#C498D9"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,20 @@
|
||||
<svg width="63" height="56" viewBox="0 0 63 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_3655_60366)">
|
||||
<path d="M26.9949 55.4499C38.1366 55.4499 47.1687 54.7317 47.1687 53.8458C47.1687 52.9599 38.1366 52.2417 26.9949 52.2417C15.8532 52.2417 6.82104 52.9599 6.82104 53.8458C6.82104 54.7317 15.8532 55.4499 26.9949 55.4499Z" fill="#E6E6E6"/>
|
||||
<path d="M4.19092 33.4118C6.30079 32.6459 8.42511 31.8655 10.5205 31.0996C12.3703 33.195 14.9859 33.5419 17.1536 32.2702C17.0091 32.8771 16.879 33.4262 16.7345 33.9898C16.5178 34.8858 16.301 35.7818 16.0842 36.6778C15.853 37.6604 16.3588 38.5275 17.2548 38.7298C18.1507 38.9466 18.9889 38.4119 19.2346 37.4292C19.6826 35.6373 20.1017 33.8598 20.5352 32.0678C20.5785 31.8944 20.6219 31.721 20.6942 31.4609C22.8618 37.4148 25.0151 43.2964 27.1827 49.2503C27.0238 49.3081 26.8504 49.3803 26.6625 49.4381C23.411 50.6231 20.1595 51.8081 16.9079 52.9931C14.3067 53.9325 12.2113 53.2677 10.665 50.9844C10.6217 50.9266 10.5639 50.8833 10.5205 50.8255C8.42511 45.0161 6.31524 39.2212 4.19092 33.4118Z" fill="#7F54B3"/>
|
||||
<path d="M0.0722335 22.1109C0.0577823 21.8363 0.0288799 21.5762 0.0144288 21.3017C-0.101181 19.2496 1.11272 17.2698 3.02027 16.5472C6.54636 15.2177 10.1013 13.946 13.6274 12.6599C13.6852 12.631 13.7575 12.631 13.8442 12.6021C15.1593 16.2004 16.4599 19.7698 17.7894 23.426C17.2691 23.3104 16.7922 23.2092 16.3153 23.0791C15.1448 22.7612 13.9743 22.6312 12.8182 23.0936C10.795 23.874 9.68226 25.3624 9.46549 27.5301C9.45104 27.6746 9.45104 27.8191 9.43659 27.9636C9.43659 27.9781 9.42214 27.9925 9.40769 28.0504C7.31227 28.8163 5.2024 29.5822 3.07808 30.3625C2.08095 27.6024 1.06936 24.8566 0.0722335 22.1109Z" fill="#7F54B3"/>
|
||||
<path d="M16.9513 11.446C17.1681 11.3593 17.3559 11.3015 17.5438 11.2293C26.9371 7.80434 36.3303 4.36496 45.738 0.940034C48.7439 -0.158255 51.3595 1.05564 52.4578 4.06149C53.3393 6.47483 54.2209 8.87373 55.1168 11.3593C54.929 11.4316 54.77 11.4894 54.611 11.5472C46.6484 14.4519 38.7003 17.3566 30.7377 20.2612C30.3909 20.3913 30.1886 20.3624 29.914 20.0734C27.7319 17.8046 24.148 18.0213 22.2404 20.5069C21.8069 21.0705 21.3878 21.663 20.9254 22.2989C19.5814 18.6716 18.2808 15.0877 16.9513 11.446Z" fill="#7F54B3"/>
|
||||
<path d="M17.6304 26.808C17.0379 27.6028 16.5177 28.3542 15.9541 29.0768C15.3616 29.8138 14.3789 29.9872 13.5841 29.5103C12.8037 29.0479 12.4713 28.1086 12.7893 27.2704C13.1072 26.4322 13.9598 25.9264 14.8558 26.1143C15.694 26.2877 16.5321 26.5045 17.3703 26.7213C17.4425 26.7213 17.5003 26.7502 17.6304 26.808Z" fill="#7F54B3"/>
|
||||
<path d="M23.1509 24.7555C23.7867 23.9029 24.3214 23.1225 24.9284 22.3855C25.492 21.6919 26.4746 21.5763 27.2406 22.0387C27.9776 22.4867 28.3244 23.3682 28.0498 24.1919C27.7753 25.0301 26.966 25.5648 26.0845 25.4636C25.9255 25.4492 25.7665 25.4058 25.6076 25.3625C24.8128 25.1746 24.0324 24.9723 23.1509 24.7555Z" fill="#7F54B3"/>
|
||||
<path d="M31.388 23.5129C31.0267 26.591 29.9718 27.8627 27.1104 28.672C27.2694 28.8021 27.4139 28.9032 27.544 29.0188C28.5844 29.7847 29.6394 30.5507 30.6799 31.331C31.518 31.9524 31.6914 32.9496 31.1278 33.701C30.5642 34.438 29.596 34.5536 28.7723 33.9611C27.5006 33.0363 26.2433 32.0969 24.9716 31.1721C24.6104 30.9119 24.2491 30.6518 23.8156 30.3339C25.9977 36.3311 28.1509 42.2128 30.3041 48.1377C30.5209 48.051 30.7088 47.9932 30.8966 47.921C40.2899 44.496 49.6976 41.0567 59.0909 37.6317C62.0967 36.5334 63.3106 33.9178 62.2123 30.9119C60.2903 25.6373 58.3683 20.3626 56.4318 15.0879C56.3596 14.9 56.3018 14.7122 56.2151 14.481C47.9057 17.4868 39.6396 20.4926 31.388 23.5129Z" fill="#7F54B3"/>
|
||||
<path d="M37.1684 40.1459L37.0383 39.7846C36.1568 40.0592 35.3909 39.8569 34.9429 39.221C34.8706 39.1199 34.8995 39.0187 35.0007 38.9609L35.5787 38.5852C35.6799 38.5274 35.7666 38.5418 35.8533 38.643C36.0556 38.8598 36.3447 38.9465 36.6915 38.8598L36.3591 37.9349L36.0845 37.9204C35.6799 37.9349 34.6539 37.9204 34.3504 37.0967C34.0614 36.3019 34.5094 35.536 35.3475 35.1603L35.203 34.7701C35.1741 34.6834 35.203 34.6256 35.2897 34.5967L35.4053 34.5533C35.492 34.5244 35.5498 34.5533 35.5787 34.64L35.7233 35.0302C36.388 34.8568 36.9516 35.0447 37.3851 35.5071C37.4718 35.6083 37.4574 35.7094 37.3562 35.7817L36.7926 36.1863C36.6915 36.2586 36.6192 36.2441 36.5181 36.1574C36.388 36.0418 36.229 35.9695 36.0556 35.984L36.3591 36.8222H36.6337C37.6886 36.8077 38.18 37.1256 38.4112 37.7181C38.7146 38.5563 38.2089 39.2644 37.3707 39.6401L37.5007 40.0159C37.5297 40.1026 37.5007 40.1604 37.414 40.1893L37.2984 40.2326C37.2551 40.2615 37.1973 40.2326 37.1684 40.1459ZM35.6944 36.0996C35.5209 36.2152 35.4198 36.3742 35.4776 36.562C35.5209 36.6921 35.6076 36.7932 35.8967 36.8077H35.94L35.6944 36.0996ZM37.284 38.1806C37.2262 38.036 37.0961 37.9349 36.8215 37.9204H36.7782L37.0528 38.6864C37.2695 38.5563 37.3562 38.3829 37.284 38.1806Z" fill="#7F54B3"/>
|
||||
<path d="M42.3997 40.1607L40.5933 35.2039L39.7551 35.9843C39.4516 36.2733 39.1193 36.23 38.8736 35.912L38.6135 35.5797C38.3678 35.2617 38.3967 34.9583 38.6713 34.6981L40.3765 33.0796C40.6077 32.8484 40.81 32.7472 41.2291 32.6027C41.6049 32.4727 41.8794 32.6027 42.0095 32.9784L44.365 39.4526C44.5095 39.8283 44.3795 40.1173 43.9893 40.2618L43.2089 40.5509C42.8188 40.6809 42.5297 40.5509 42.3997 40.1607Z" fill="#7F54B3"/>
|
||||
<path d="M44.2929 35.7963C43.498 33.6142 44.1483 31.3743 46.3016 30.5939C48.4403 29.8135 50.4346 31.0852 51.2294 33.2674C52.0242 35.435 51.3306 37.7039 49.1773 38.4842C47.0386 39.2646 45.0877 37.9785 44.2929 35.7963ZM49.3074 33.9755C48.8161 32.6315 47.8478 31.8367 46.8796 32.1835C45.9258 32.5304 45.7235 33.7587 46.2149 35.1027C46.7062 36.4322 47.66 37.2559 48.5993 36.9091C49.5675 36.5478 49.7988 35.305 49.3074 33.9755Z" fill="#7F54B3"/>
|
||||
<path d="M52.0964 32.9638C51.3016 30.7817 51.9519 28.5418 54.1052 27.7614C56.2439 26.981 58.2382 28.2527 59.033 30.4349C59.8278 32.6025 59.1342 34.8714 56.9809 35.6517C54.8277 36.4321 52.8913 35.1315 52.0964 32.9638ZM57.111 31.1285C56.6197 29.7846 55.6514 28.9897 54.6832 29.3366C53.7294 29.6834 53.5271 30.9117 54.0184 32.2557C54.5098 33.5852 55.4636 34.4089 56.4029 34.0621C57.3711 33.7008 57.5879 32.458 57.111 31.1285Z" fill="#7F54B3"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_3655_60366">
|
||||
<rect width="62.6314" height="54.9" fill="white" transform="translate(0 0.549805)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.2 KiB |
@@ -0,0 +1,12 @@
|
||||
<svg width="104" height="100" viewBox="0 0 104 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="53.1409" cy="50" r="50" fill="#F6F7F7"/>
|
||||
<path d="M29.3335 75.4242C29.3335 74.6312 28.444 74 27.3265 74H18.3405C17.223 74 16.3335 74.6312 16.3335 75.4242V93H29.3335V75.4242Z" fill="#E5CFE8"/>
|
||||
<path d="M49.3335 51.4098C49.3335 50.6248 48.444 50 47.3265 50H38.3405C37.223 50 36.3335 50.6248 36.3335 51.4098V93H49.3335V51.4098Z" fill="#7F54B3"/>
|
||||
<path d="M69.3335 63.4403C69.3335 62.6383 68.444 62 67.3265 62H58.3405C57.223 62 56.3335 62.6383 56.3335 63.4403V93H69.3335V63.4403Z" fill="#C498D9"/>
|
||||
<path d="M90.3335 27.4262C90.3335 26.6321 89.444 26 88.3265 26H79.3405C78.223 26 77.3335 26.6321 77.3335 27.4262V93H90.3335V27.4262Z" fill="#7F54B3"/>
|
||||
<path d="M9.7113 61.1378L34.2418 33.7769L58.7724 47.5517L83.3029 5.28369" stroke="#E5CFE8" stroke-width="1.32088" stroke-miterlimit="10" stroke-linecap="round"/>
|
||||
<path d="M9.617 66.421C12.535 66.421 14.9005 64.0555 14.9005 61.1375C14.9005 58.2195 12.535 55.854 9.617 55.854C6.699 55.854 4.3335 58.2195 4.3335 61.1375C4.3335 64.0555 6.699 66.421 9.617 66.421Z" fill="#7F54B3"/>
|
||||
<path d="M34.1475 39.0602C37.0655 39.0602 39.431 36.6947 39.431 33.7767C39.431 30.8587 37.0655 28.4932 34.1475 28.4932C31.2295 28.4932 28.864 30.8587 28.864 33.7767C28.864 36.6947 31.2295 39.0602 34.1475 39.0602Z" fill="#7F54B3"/>
|
||||
<path d="M58.678 52.8351C61.596 52.8351 63.9615 50.4696 63.9615 47.5516C63.9615 44.6336 61.596 42.2681 58.678 42.2681C55.76 42.2681 53.3945 44.6336 53.3945 47.5516C53.3945 50.4696 55.76 52.8351 58.678 52.8351Z" fill="#7F54B3"/>
|
||||
<path d="M83.2085 10.567C86.1265 10.567 88.4921 8.2015 88.4921 5.2835C88.4921 2.3655 86.1265 0 83.2085 0C80.2906 0 77.925 2.3655 77.925 5.2835C77.925 8.2015 80.2906 10.567 83.2085 10.567Z" fill="#7F54B3"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 220 KiB |
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><path d="M0 12c0 4.914 2.955 9.135 7.183 10.991-.034-.838-.006-1.843.209-2.755l1.544-6.54s-.383-.765-.383-1.898c0-1.778 1.03-3.106 2.314-3.106 1.091 0 1.619.82 1.619 1.801 0 1.098-.7 2.739-1.06 4.259-.3 1.273.638 2.311 1.894 2.311 2.274 0 3.805-2.92 3.805-6.38 0-2.63-1.771-4.599-4.993-4.599-3.64 0-5.908 2.715-5.908 5.747 0 1.046.308 1.783.79 2.354.223.262.254.368.173.669-.057.22-.19.752-.244.963-.08.304-.326.412-.6.3-1.678-.684-2.458-2.52-2.458-4.584 0-3.41 2.875-7.497 8.576-7.497 4.582 0 7.597 3.316 7.597 6.875 0 4.707-2.617 8.224-6.475 8.224-1.295 0-2.514-.7-2.931-1.496 0 0-.697 2.765-.845 3.299-.254.925-.752 1.85-1.207 2.57 1.079.32 2.219.493 3.4.493 6.627 0 12-5.373 12-12C24 5.372 18.627 0 12 0S0 5.373 0 12Z" fill="#CB1F27"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h24v24H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 925 B |
@@ -0,0 +1 @@
|
||||
<?php // Silence is golden
|
||||
@@ -0,0 +1,19 @@
|
||||
/* global jQuery */
|
||||
|
||||
( function ( $ ) {
|
||||
'use strict';
|
||||
|
||||
function hideTabs( event, productType ) {
|
||||
$( '.hide_if_' + productType ).hide();
|
||||
}
|
||||
|
||||
$( document ).on( 'woocommerce-product-type-change', 'body', hideTabs );
|
||||
|
||||
$( document ).ready( function () {
|
||||
if ( $( '#product-type' ).length > 0 ) {
|
||||
hideTabs( false, $( '#product-type' ).val() );
|
||||
}
|
||||
} );
|
||||
} )( jQuery );
|
||||
|
||||
//# sourceMappingURL=../../source/_maps/js/admin/pinterest-for-woocommerce-admin.js.map
|
||||
@@ -0,0 +1,2 @@
|
||||
!function(o){"use strict";function e(e,t){o(".hide_if_"+t).hide()}o(document).on("woocommerce-product-type-change","body",e),o(document).ready(function(){0<o("#product-type").length&&e(0,o("#product-type").val())})}(jQuery);
|
||||
//# sourceMappingURL=../../source/_maps/js/admin/pinterest-for-woocommerce-admin.min.js.map
|
||||
@@ -0,0 +1,27 @@
|
||||
/*global fetch*/
|
||||
|
||||
/**
|
||||
* Disable the Save to Pinterest button if the Chrome extension is detected.
|
||||
*/
|
||||
// eslint-disable-next-line @wordpress/no-global-event-listener
|
||||
window.addEventListener( 'load', function () {
|
||||
const disableSaveButton = () => {
|
||||
document
|
||||
.querySelectorAll( '.pinterest-for-woocommerce-image-wrapper' )
|
||||
.forEach( function ( button ) {
|
||||
button.style.display = 'none';
|
||||
} );
|
||||
};
|
||||
|
||||
const isChromeExtensionDetected = () => {
|
||||
fetch(
|
||||
`chrome-extension://gpdjojdkbbmdfjfahjcgigfpmkopogic/html/save.html`
|
||||
)
|
||||
.then( () => disableSaveButton() )
|
||||
.catch( () => false );
|
||||
};
|
||||
|
||||
isChromeExtensionDetected();
|
||||
} );
|
||||
|
||||
//# sourceMappingURL=../source/_maps/js/pinterest-for-woocommerce-save-button.js.map
|
||||
@@ -0,0 +1,2 @@
|
||||
window.addEventListener("load",function(){fetch("chrome-extension://gpdjojdkbbmdfjfahjcgigfpmkopogic/html/save.html").then(()=>(()=>{document.querySelectorAll(".pinterest-for-woocommerce-image-wrapper").forEach(function(e){e.style.display="none"})})()).catch(()=>!1)});
|
||||
//# sourceMappingURL=../source/_maps/js/pinterest-for-woocommerce-save-button.min.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["frontend/pinterest-for-woocommerce-pins.scss"],"names":[],"mappings":"AAAA;EACC,UAAU;EACV,kBAAkB;EAClB,SAAS;EACT,WAAW;EACX,UAAU;EACV,kBAAkB,EAAA;EAElB;IARD;MASE,UAAU;MACV,mBAAmB,EAAA,EAYpB;EATA;;IAEC,UAAU;IACV,mBAAmB,EAAA;IAHpB;;MAME,qBAAqB,EAAA;;AAOxB;;EAIE,kBAAkB,EAAA","file":"../../../../sass/frontend/pinterest-for-woocommerce-pins.css","sourcesContent":[".pinterest-for-woocommerce-image-wrapper {\n\tleft: 10px;\n\tposition: absolute;\n\ttop: 10px;\n\tz-index: 50;\n\topacity: 0;\n\tvisibility: hidden;\n\n\t@media (hover: none) {\n\t\topacity: 1;\n\t\tvisibility: visible;\n\t}\n\n\t.product:hover > &,\n\t.wc-block-grid__product:hover > & {\n\t\topacity: 1;\n\t\tvisibility: visible;\n\n\t\ta {\n\t\t\ttext-decoration: none;\n\t\t}\n\t}\n}\n\n\n// Twenty Twenty-Four compatibility.\n.wp-block-post,\n.wc-block-product {\n\n\t&.product {\n\t\tposition: relative;\n\t}\n}\n"]}
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../../../../source/_maps/css/frontend/frontend/pinterest-for-woocommerce-pins.scss","frontend/pinterest-for-woocommerce-pins.css"],"names":[],"mappings":"AAAA,yCACC,KAAA,KACA,SAAA,SACA,IAAA,KACA,QAAA,GACA,QAAA,EACA,WAAA,OAEA,oBARD,yCASE,QAAA,EACA,WAAA,SAGD,wDCDC,uEDGA,QAAA,EACA,WAAA,QAHD,0DCGG,yEDGD,gBAAA,KCCH,0BDMA,uBAIE,SAAA","file":"../../../../css/frontend/pinterest-for-woocommerce-pins.min.css","sourcesContent":[null,".pinterest-for-woocommerce-image-wrapper {\n left: 10px;\n position: absolute;\n top: 10px;\n z-index: 50;\n opacity: 0;\n visibility: hidden; }\n @media (hover: none) {\n .pinterest-for-woocommerce-image-wrapper {\n opacity: 1;\n visibility: visible; } }\n .product:hover > .pinterest-for-woocommerce-image-wrapper,\n .wc-block-grid__product:hover > .pinterest-for-woocommerce-image-wrapper {\n opacity: 1;\n visibility: visible; }\n .product:hover > .pinterest-for-woocommerce-image-wrapper a,\n .wc-block-grid__product:hover > .pinterest-for-woocommerce-image-wrapper a {\n text-decoration: none; }\n\n.wp-block-post.product,\n.wc-block-product.product {\n position: relative; }\n\n/*# sourceMappingURL=../../source/_maps/css/frontend/pinterest-for-woocommerce-pins.css.map */\n"]}
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"names":[],"mappings":"","sources":["admin/pinterest-for-woocommerce-admin.js"],"sourcesContent":["/* global jQuery */\n\n( function ( $ ) {\n\t'use strict';\n\n\tfunction hideTabs( event, productType ) {\n\t\t$( '.hide_if_' + productType ).hide();\n\t}\n\n\t$( document ).on( 'woocommerce-product-type-change', 'body', hideTabs );\n\n\t$( document ).ready( function () {\n\t\tif ( $( '#product-type' ).length > 0 ) {\n\t\t\thideTabs( false, $( '#product-type' ).val() );\n\t\t}\n\t} );\n} )( jQuery );\n"],"file":"../../../../js/admin/pinterest-for-woocommerce-admin.js"}
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"../../../../js/admin/pinterest-for-woocommerce-admin.min.js","sources":["admin/pinterest-for-woocommerce-admin.js"],"sourcesContent":["/* global jQuery */\n\n( function ( $ ) {\n\t'use strict';\n\n\tfunction hideTabs( event, productType ) {\n\t\t$( '.hide_if_' + productType ).hide();\n\t}\n\n\t$( document ).on( 'woocommerce-product-type-change', 'body', hideTabs );\n\n\t$( document ).ready( function () {\n\t\tif ( $( '#product-type' ).length > 0 ) {\n\t\t\thideTabs( false, $( '#product-type' ).val() );\n\t\t}\n\t} );\n} )( jQuery );\n\n//# sourceMappingURL=../../source/_maps/js/admin/pinterest-for-woocommerce-admin.js.map\n"],"names":["$","hideTabs","event","productType","hide","document","on","ready","length","val","jQuery"],"mappings":"CAEA,SAAaA,gBAGZ,SAASC,EAAUC,EAAOC,GACzBH,EAAG,YAAcG,GAAcC,OAGhCJ,EAAGK,UAAWC,GAAI,kCAAmC,OAAQL,GAE7DD,EAAGK,UAAWE,MAAO,WACe,EAA9BP,EAAG,iBAAkBQ,QACzBP,EAAU,EAAOD,EAAG,iBAAkBS,SAXzC,CAcKC"}
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"names":[],"mappings":"","sources":["pinterest-for-woocommerce-save-button.js"],"sourcesContent":["/*global fetch*/\n\n/**\n * Disable the Save to Pinterest button if the Chrome extension is detected.\n */\n// eslint-disable-next-line @wordpress/no-global-event-listener\nwindow.addEventListener( 'load', function () {\n\tconst disableSaveButton = () => {\n\t\tdocument\n\t\t\t.querySelectorAll( '.pinterest-for-woocommerce-image-wrapper' )\n\t\t\t.forEach( function ( button ) {\n\t\t\t\tbutton.style.display = 'none';\n\t\t\t} );\n\t};\n\n\tconst isChromeExtensionDetected = () => {\n\t\tfetch(\n\t\t\t`chrome-extension://gpdjojdkbbmdfjfahjcgigfpmkopogic/html/save.html`\n\t\t)\n\t\t\t.then( () => disableSaveButton() )\n\t\t\t.catch( () => false );\n\t};\n\n\tisChromeExtensionDetected();\n} );\n"],"file":"../../../js/pinterest-for-woocommerce-save-button.js"}
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"../../../js/pinterest-for-woocommerce-save-button.min.js","sources":["pinterest-for-woocommerce-save-button.js"],"sourcesContent":["/*global fetch*/\n\n/**\n * Disable the Save to Pinterest button if the Chrome extension is detected.\n */\n// eslint-disable-next-line @wordpress/no-global-event-listener\nwindow.addEventListener( 'load', function () {\n\tconst disableSaveButton = () => {\n\t\tdocument\n\t\t\t.querySelectorAll( '.pinterest-for-woocommerce-image-wrapper' )\n\t\t\t.forEach( function ( button ) {\n\t\t\t\tbutton.style.display = 'none';\n\t\t\t} );\n\t};\n\n\tconst isChromeExtensionDetected = () => {\n\t\tfetch(\n\t\t\t`chrome-extension://gpdjojdkbbmdfjfahjcgigfpmkopogic/html/save.html`\n\t\t)\n\t\t\t.then( () => disableSaveButton() )\n\t\t\t.catch( () => false );\n\t};\n\n\tisChromeExtensionDetected();\n} );\n\n//# sourceMappingURL=../source/_maps/js/pinterest-for-woocommerce-save-button.js.map\n"],"names":["window","addEventListener","fetch","then","document","querySelectorAll","forEach","button","style","display","disableSaveButton","catch"],"mappings":"AAMAA,OAAOC,iBAAkB,OAAQ,WAU/BC,MACC,sEAECC,KAAM,KAZiB,KACzBC,SACEC,iBAAkB,4CAClBC,QAAS,SAAWC,GACpBA,EAAOC,MAAMC,QAAU,UAQXC,IACZC,MAAO,KAAM"}
|
||||
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import '@wordpress/notices';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
import { useCallback, useEffect, useState } from '@wordpress/element';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import SyncState from './sections/SyncState';
|
||||
import AdCreditsNotice from './sections/AdCreditsNotice';
|
||||
import SyncIssues from './sections/SyncIssues';
|
||||
import HealthCheck from '../setup-guide/app/components/HealthCheck';
|
||||
import CapiEnablementModal from '../setup-guide/app/components/CapiEnablementModal';
|
||||
import {
|
||||
useCreateNotice,
|
||||
useDismissAdsModalDispatch,
|
||||
useDismissCapiModalDispatch,
|
||||
} from './helpers/effects';
|
||||
import NavigationClassic from '../components/navigation-classic';
|
||||
import OnboardingModals from './components/OnboardingModals';
|
||||
import { USER_INTERACTION_STORE_NAME } from './data';
|
||||
import { useSettingsSelect } from '../setup-guide/app/helpers/effects';
|
||||
|
||||
/**
|
||||
* Opening a modal.
|
||||
*
|
||||
* @event wcadmin_pfw_modal_open
|
||||
* @property {string} name Ads Onboarding Modal.
|
||||
* @property {string} context catalog-sync
|
||||
*/
|
||||
/**
|
||||
* Closing a modal.
|
||||
*
|
||||
* @event wcadmin_pfw_modal_closed
|
||||
* @property {string} name Ads Onboarding Modal.
|
||||
* @property {string} context catalog-sync
|
||||
*/
|
||||
|
||||
/**
|
||||
* Catalog Sync Tab.
|
||||
*
|
||||
* @fires wcadmin_pfw_modal_open with `{ name: 'ads-credits-onboarding' }`
|
||||
* @fires wcadmin_pfw_modal_close with `{ name: 'ads-credits-onboarding' }`
|
||||
*
|
||||
* @return {JSX.Element} rendered component
|
||||
*/
|
||||
const CatalogSyncApp = () => {
|
||||
const appSettings = useSettingsSelect();
|
||||
const adsCampaignIsActive = appSettings?.ads_campaign_is_active;
|
||||
|
||||
const couponRedeemErrorID =
|
||||
appSettings?.account_data?.coupon_redeem_info?.error_id;
|
||||
|
||||
useCreateNotice( wcSettings.pinterest_for_woocommerce.error );
|
||||
const [ isOnboardingModalOpen, setIsOnboardingModalOpen ] =
|
||||
useState( false );
|
||||
const [ isAdCreditsNoticeOpen, setIsAdCreditsNoticeOpen ] =
|
||||
useState( false );
|
||||
const [ isCapiModalOpen, setIsCapiModalOpen ] = useState( false );
|
||||
|
||||
const userInteractions = useSelect( ( select ) =>
|
||||
select( USER_INTERACTION_STORE_NAME ).getUserInteractions()
|
||||
);
|
||||
|
||||
const userInteractionsLoaded = useSelect( ( select ) =>
|
||||
select( USER_INTERACTION_STORE_NAME ).areInteractionsLoaded()
|
||||
);
|
||||
|
||||
const openOnboardingModal = useCallback( () => {
|
||||
if (
|
||||
userInteractionsLoaded === false ||
|
||||
userInteractions?.ads_modal_dismissed
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsOnboardingModalOpen( true );
|
||||
recordEvent( 'pfw_modal_open', {
|
||||
context: 'catalog-sync',
|
||||
name: 'ads-credits-onboarding',
|
||||
} );
|
||||
}, [ userInteractions?.ads_modal_dismissed, userInteractionsLoaded ] );
|
||||
|
||||
const openAdsCreditsNotice = useCallback( () => {
|
||||
if (
|
||||
userInteractionsLoaded === false ||
|
||||
userInteractions?.ads_notice_dismissed
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
couponRedeemErrorID !== undefined &&
|
||||
couponRedeemErrorID !== 2322
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsAdCreditsNoticeOpen( true );
|
||||
}, [
|
||||
userInteractions?.ads_notice_dismissed,
|
||||
userInteractionsLoaded,
|
||||
couponRedeemErrorID,
|
||||
] );
|
||||
|
||||
const openCapiModal = useCallback( () => {
|
||||
if (
|
||||
userInteractionsLoaded === false ||
|
||||
userInteractions?.capi_modal_dismissed
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const trackConversions = appSettings?.track_conversions;
|
||||
const trackConversionsCapi = appSettings?.track_conversions_capi;
|
||||
|
||||
// Only show if track_conversions is enabled but CAPI is not enabled
|
||||
if ( ! trackConversions || trackConversionsCapi ) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsCapiModalOpen( true );
|
||||
}, [
|
||||
userInteractionsLoaded,
|
||||
userInteractions?.capi_modal_dismissed,
|
||||
appSettings?.track_conversions,
|
||||
appSettings?.track_conversions_capi,
|
||||
] );
|
||||
|
||||
const closeOnboardingModal = () => {
|
||||
setIsOnboardingModalOpen( false );
|
||||
handleSetDismissAdsModal();
|
||||
recordEvent( 'pfw_modal_closed', {
|
||||
context: 'catalog-sync',
|
||||
name: 'ads-credits-onboarding',
|
||||
} );
|
||||
};
|
||||
|
||||
const setDismissCapiModal = useDismissCapiModalDispatch();
|
||||
const handleSetDismissCapiModal = useCallback( async () => {
|
||||
try {
|
||||
await setDismissCapiModal();
|
||||
} catch ( error ) {}
|
||||
}, [ setDismissCapiModal ] );
|
||||
|
||||
const setDismissAdsModal = useDismissAdsModalDispatch();
|
||||
const handleSetDismissAdsModal = useCallback( async () => {
|
||||
try {
|
||||
await setDismissAdsModal();
|
||||
} catch ( error ) {}
|
||||
}, [ setDismissAdsModal ] );
|
||||
|
||||
useEffect( () => {
|
||||
openOnboardingModal();
|
||||
openAdsCreditsNotice();
|
||||
openCapiModal();
|
||||
}, [ openOnboardingModal, openAdsCreditsNotice, openCapiModal ] );
|
||||
|
||||
return (
|
||||
<div className="pinterest-for-woocommerce-catalog-sync">
|
||||
<HealthCheck />
|
||||
<NavigationClassic />
|
||||
|
||||
<div className="pinterest-for-woocommerce-catalog-sync__container">
|
||||
<SyncState />
|
||||
{ isAdCreditsNoticeOpen && adsCampaignIsActive && (
|
||||
<AdCreditsNotice />
|
||||
) }
|
||||
<SyncIssues />
|
||||
</div>
|
||||
{ isOnboardingModalOpen && (
|
||||
<OnboardingModals onCloseModal={ closeOnboardingModal } />
|
||||
) }
|
||||
{ isCapiModalOpen && (
|
||||
<CapiEnablementModal
|
||||
onCloseModal={ () => setIsCapiModalOpen( false ) }
|
||||
onDismiss={ handleSetDismissCapiModal }
|
||||
/>
|
||||
) }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CatalogSyncApp;
|
||||
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import { createInterpolateElement } from '@wordpress/element';
|
||||
import { Icon, external as externalIcon } from '@wordpress/icons';
|
||||
import {
|
||||
Button,
|
||||
Flex,
|
||||
Modal,
|
||||
__experimentalText as Text, // eslint-disable-line @wordpress/no-unsafe-wp-apis --- _experimentalText unlikely to change/disappear and also used by WC Core
|
||||
} from '@wordpress/components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useSettingsSelect } from '../../../setup-guide/app/helpers/effects';
|
||||
import { useBillingSetupFlowEntered } from '../../helpers/effects';
|
||||
|
||||
const OnboardingModalText = ( { isBillingSetup } ) => {
|
||||
const appSettings = useSettingsSelect();
|
||||
const currencyCreditInfo = appSettings?.account_data?.currency_credit_info;
|
||||
|
||||
if ( ! isBillingSetup ) {
|
||||
return (
|
||||
<Text variant="body">
|
||||
{ createInterpolateElement(
|
||||
sprintf(
|
||||
// translators: %1$s: Amount of ad credit given with currency. %2$s: Amount of money required to spend to claim ad credits with currency.
|
||||
__(
|
||||
'You are eligible for %1$s of Pinterest ad credits. To claim the credits, <strong>you would need to add your billing details and spend %2$s on Pinterest ads.</strong>',
|
||||
'pinterest-for-woocommerce'
|
||||
),
|
||||
currencyCreditInfo.creditsGiven,
|
||||
currencyCreditInfo.spendRequire
|
||||
),
|
||||
{
|
||||
strong: <strong />,
|
||||
}
|
||||
) }
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Text variant="body">
|
||||
{ sprintf(
|
||||
// translators: %s: Amount of ad credit given with currency.
|
||||
__(
|
||||
'You are eligible for %s of Pinterest ad credits. To claim the credits, head over to the Pinterest ads manager and ',
|
||||
'pinterest-for-woocommerce'
|
||||
),
|
||||
currencyCreditInfo.creditsGiven
|
||||
) }
|
||||
<strong>
|
||||
{ sprintf(
|
||||
// translators: %s: Amount of money required to spend to claim ad credits with currency.
|
||||
__(
|
||||
'spend %s on Pinterest ads.',
|
||||
'pinterest-for-woocommerce'
|
||||
),
|
||||
currencyCreditInfo.spendRequire
|
||||
) }
|
||||
</strong>
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Ads Onboarding Modal.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {Function} options.onCloseModal Action to call when the modal gets closed.
|
||||
*
|
||||
* @return {JSX.Element} rendered component
|
||||
*/
|
||||
const OnboardingAdsModal = ( { onCloseModal } ) => {
|
||||
const appSettings = useSettingsSelect();
|
||||
const isBillingSetup = appSettings?.account_data?.is_billing_setup;
|
||||
const currencyCreditInfo = appSettings?.account_data?.currency_credit_info;
|
||||
const billingSetupFlowEntered = useBillingSetupFlowEntered();
|
||||
|
||||
const onClickBilling = () => {
|
||||
onCloseModal();
|
||||
billingSetupFlowEntered();
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
icon={
|
||||
<img
|
||||
src={
|
||||
wcSettings.pinterest_for_woocommerce.pluginUrl +
|
||||
'/assets/images/gift_banner.svg'
|
||||
}
|
||||
alt="Gift banner"
|
||||
/>
|
||||
}
|
||||
onRequestClose={ onCloseModal }
|
||||
className="pinterest-for-woocommerce-catalog-sync__onboarding-modal"
|
||||
>
|
||||
<Text variant="title.small">
|
||||
{ sprintf(
|
||||
// translators: %s: Amount of ad credit given with currency.
|
||||
__(
|
||||
'You are one step away from claiming %s of Pinterest ad credits.',
|
||||
'pinterest-for-woocommerce'
|
||||
),
|
||||
currencyCreditInfo.creditsGiven
|
||||
) }
|
||||
</Text>
|
||||
<Text variant="body">
|
||||
{ __(
|
||||
'You have successfully set up your Pinterest integration! Your product catalog is being synced and reviewed. This could take up to 2 days.',
|
||||
'pinterest-for-woocommerce'
|
||||
) }
|
||||
</Text>
|
||||
<OnboardingModalText isBillingSetup={ isBillingSetup } />
|
||||
<Text variant="caption">
|
||||
{ __(
|
||||
'*Ad credits may take up to 24 hours to be credited to account.',
|
||||
'pinterest-for-woocommerce'
|
||||
) }
|
||||
</Text>
|
||||
<Flex direction="row" justify="flex-end">
|
||||
{ isBillingSetup ? (
|
||||
<Button isPrimary onClick={ onCloseModal }>
|
||||
{ __( 'Got it', 'pinterest-for-woocommerce' ) }
|
||||
</Button>
|
||||
) : (
|
||||
<>
|
||||
<Button onClick={ onCloseModal }>
|
||||
{ __(
|
||||
'Do this later',
|
||||
'pinterest-for-woocommerce'
|
||||
) }
|
||||
</Button>
|
||||
{
|
||||
// Empty tracking_advertiser should not happen.
|
||||
appSettings.tracking_advertiser ? (
|
||||
<Button
|
||||
isPrimary
|
||||
href={ `https://ads.pinterest.com/advertiser/${ appSettings.tracking_advertiser }/billing/` }
|
||||
target="_blank"
|
||||
onClick={ onClickBilling }
|
||||
>
|
||||
{ __(
|
||||
'Add billing details',
|
||||
'pinterest-for-woocommerce'
|
||||
) }
|
||||
<Icon icon={ externalIcon } />
|
||||
</Button>
|
||||
) : (
|
||||
''
|
||||
)
|
||||
}
|
||||
</>
|
||||
) }
|
||||
</Flex>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default OnboardingAdsModal;
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import {
|
||||
Flex,
|
||||
Dashicon,
|
||||
__experimentalText as Text, // eslint-disable-line @wordpress/no-unsafe-wp-apis --- _experimentalText unlikely to change/disappear and also used by WC Core
|
||||
} from '@wordpress/components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import OnboardingModal from './OnboardingModal';
|
||||
import { useSettingsSelect } from '../../../setup-guide/app/helpers/effects';
|
||||
|
||||
/**
|
||||
* Ads Onboarding Modal.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {Function} options.onCloseModal Action to call when the modal gets closed.
|
||||
*
|
||||
* @return {JSX.Element} rendered component
|
||||
*/
|
||||
const OnboardingErrorModal = ( { onCloseModal } ) => {
|
||||
const ALREADY_REDEEMED_ERROR = 2322;
|
||||
const DIFFERENT_ADVERTISER_ALREADY_REDEEMED_ERROR = 2318;
|
||||
const OFFER_EXPIRED_ERROR = 2319;
|
||||
const NOT_AVAILABLE_IN_COUNTRY_OR_CURRENCY_ERROR = 2327;
|
||||
const WRONG_BILLING_PROFILE_ERROR = 2006;
|
||||
|
||||
const couponRedeemInfo =
|
||||
useSettingsSelect()?.account_data?.coupon_redeem_info;
|
||||
|
||||
let errorMessageText = '';
|
||||
switch ( couponRedeemInfo?.error_id ) {
|
||||
case ALREADY_REDEEMED_ERROR:
|
||||
errorMessageText = __(
|
||||
'Advertiser already has a redeemed offer.',
|
||||
'pinterest-for-woocommerce'
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case DIFFERENT_ADVERTISER_ALREADY_REDEEMED_ERROR:
|
||||
errorMessageText = __(
|
||||
'The merchant already redeemed the offer on another advertiser.',
|
||||
'pinterest-for-woocommerce'
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case OFFER_EXPIRED_ERROR:
|
||||
errorMessageText = __(
|
||||
'Unable to claim Pinterest ads credits as the offer has expired.',
|
||||
'pinterest-for-woocommerce'
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case NOT_AVAILABLE_IN_COUNTRY_OR_CURRENCY_ERROR:
|
||||
errorMessageText = __(
|
||||
'Unable to claim Pinterest ads credits as the offer code is not available for your country.',
|
||||
'pinterest-for-woocommerce'
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case WRONG_BILLING_PROFILE_ERROR:
|
||||
errorMessageText = __(
|
||||
'Offer code can only be redeemed by an advertiser with a credit card billing profile.',
|
||||
'pinterest-for-woocommerce'
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
errorMessageText = couponRedeemInfo?.error_message;
|
||||
break;
|
||||
}
|
||||
return (
|
||||
<OnboardingModal onCloseModal={ onCloseModal }>
|
||||
<Flex
|
||||
direction="row"
|
||||
className="pinterest-for-woocommerce-catalog-sync__onboarding-generic-modal__error"
|
||||
>
|
||||
<Dashicon icon="info" />
|
||||
<Text variant="body.large">{ errorMessageText }</Text>
|
||||
</Flex>
|
||||
</OnboardingModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default OnboardingErrorModal;
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import {
|
||||
Button,
|
||||
Flex,
|
||||
Modal,
|
||||
__experimentalText as Text, // eslint-disable-line @wordpress/no-unsafe-wp-apis --- _experimentalText unlikely to change/disappear and also used by WC Core
|
||||
} from '@wordpress/components';
|
||||
|
||||
/**
|
||||
* Ads Onboarding Modal.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {Function} options.onCloseModal Action to call when the modal gets closed.
|
||||
* @param {Object} options.children Children of the component.
|
||||
*
|
||||
* @return {JSX.Element} rendered component
|
||||
*/
|
||||
const OnboardingModal = ( { onCloseModal, children } ) => {
|
||||
return (
|
||||
<Modal
|
||||
icon={
|
||||
<img
|
||||
src={
|
||||
wcSettings.pinterest_for_woocommerce.pluginUrl +
|
||||
'/assets/images/onboarding_success_modal_header.svg'
|
||||
}
|
||||
alt="Gift banner"
|
||||
/>
|
||||
}
|
||||
onRequestClose={ onCloseModal }
|
||||
className="pinterest-for-woocommerce-catalog-sync__onboarding-generic-modal"
|
||||
>
|
||||
<Text variant="title.small">
|
||||
{ __(
|
||||
'You have successfully set up your Pinterest integration.',
|
||||
'pinterest-for-woocommerce'
|
||||
) }
|
||||
</Text>
|
||||
<Text variant="body.large">
|
||||
{ __(
|
||||
'You have successfully set up your Pinterest integration! Your product catalog is being synced and reviewed. This could take up to 2 days.',
|
||||
'pinterest-for-woocommerce'
|
||||
) }
|
||||
</Text>
|
||||
{ children }
|
||||
<Flex direction="row" justify="flex-end">
|
||||
<Button isPrimary onClick={ onCloseModal }>
|
||||
{ __( 'View catalog', 'pinterest-for-woocommerce' ) }
|
||||
</Button>
|
||||
</Flex>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default OnboardingModal;
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useSettingsSelect } from '../../../setup-guide/app/helpers/effects';
|
||||
import OnboardingAdsModal from './OnboardingAdsModal';
|
||||
import OnboardingModal from './OnboardingModal';
|
||||
import OnboardingErrorModal from './OnboardingErrorModal';
|
||||
|
||||
/**
|
||||
* Ads Onboarding Modal.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {Function} options.onCloseModal Action to call when the modal gets closed.
|
||||
*
|
||||
* @return {JSX.Element} rendered component
|
||||
*/
|
||||
const OnboardingModals = ( { onCloseModal } ) => {
|
||||
const adsCampaignIsActive = useSettingsSelect()?.ads_campaign_is_active;
|
||||
const couponRedeemInfo =
|
||||
useSettingsSelect()?.account_data?.coupon_redeem_info;
|
||||
|
||||
// Generic modal when there is no campaign.
|
||||
if ( ! adsCampaignIsActive ) {
|
||||
return <OnboardingModal onCloseModal={ onCloseModal } />;
|
||||
}
|
||||
|
||||
// Ads campaign modal no error.
|
||||
if ( ! couponRedeemInfo?.error_id ) {
|
||||
return <OnboardingAdsModal onCloseModal={ onCloseModal } />;
|
||||
}
|
||||
|
||||
// Ads campaign redeem error modal.
|
||||
return <OnboardingErrorModal onCloseModal={ onCloseModal } />;
|
||||
};
|
||||
|
||||
export default OnboardingModals;
|
||||
@@ -0,0 +1,2 @@
|
||||
export { REPORTS_STORE_NAME } from './reports';
|
||||
export { USER_INTERACTION_STORE_NAME } from './userInteraction';
|
||||
@@ -0,0 +1,9 @@
|
||||
const TYPES = {
|
||||
RECEIVE_FEEDISSUES: 'RECEIVE_FEEDISSUES',
|
||||
RECEIVE_FEEDSTATE: 'RECEIVE_FEEDSTATE',
|
||||
SET_IS_REQUESTING: 'SET_IS_REQUESTING',
|
||||
SET_REQUESTING_ERROR: 'SET_REQUESTING_ERROR',
|
||||
RESET_FEED: 'RESET_FEED',
|
||||
};
|
||||
|
||||
export default TYPES;
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import TYPES from './action-types';
|
||||
|
||||
export function receiveFeedIssues( feedIssues ) {
|
||||
return {
|
||||
type: TYPES.RECEIVE_FEEDISSUES,
|
||||
feedIssues,
|
||||
};
|
||||
}
|
||||
|
||||
export function receiveFeedState( feedState ) {
|
||||
return {
|
||||
type: TYPES.RECEIVE_FEEDSTATE,
|
||||
feedState,
|
||||
};
|
||||
}
|
||||
|
||||
export function setIsRequesting( isRequesting ) {
|
||||
return {
|
||||
type: TYPES.SET_IS_REQUESTING,
|
||||
isRequesting,
|
||||
};
|
||||
}
|
||||
|
||||
export function setRequestingError( error, name ) {
|
||||
return {
|
||||
type: TYPES.SET_REQUESTING_ERROR,
|
||||
error,
|
||||
name,
|
||||
};
|
||||
}
|
||||
|
||||
export function resetFeed() {
|
||||
return {
|
||||
type: TYPES.RESET_FEED,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export const STORE_NAME = 'pinterest_for_woocommerce/admin/reports';
|
||||
export const API_ROUTE = wcSettings.pinterest_for_woocommerce.apiRoute;
|
||||
28
wp-content/plugins/pinterest-for-woocommerce/assets/source/catalog-sync/data/reports/controls.js
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import apiFetch from '@wordpress/api-fetch';
|
||||
import { addQueryArgs } from '@wordpress/url';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { API_ROUTE } from './constants';
|
||||
|
||||
export const fetch = ( endpoint, data = {} ) => {
|
||||
return {
|
||||
type: 'FETCH',
|
||||
endpoint,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
export const controls = {
|
||||
FETCH( { endpoint, data = {} } ) {
|
||||
return new Promise( ( resolve ) => {
|
||||
const url = addQueryArgs( `${ API_ROUTE }/${ endpoint }`, data );
|
||||
|
||||
apiFetch( { path: url } ).then( ( result ) => resolve( result ) );
|
||||
} );
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
|
||||
import { registerStore } from '@wordpress/data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { STORE_NAME } from './constants';
|
||||
import * as selectors from './selectors';
|
||||
import * as actions from './actions';
|
||||
import * as resolvers from './resolvers';
|
||||
import { controls } from './controls';
|
||||
import reducer from './reducer';
|
||||
|
||||
registerStore( STORE_NAME, {
|
||||
reducer,
|
||||
actions,
|
||||
controls,
|
||||
selectors,
|
||||
resolvers,
|
||||
} );
|
||||
|
||||
export const REPORTS_STORE_NAME = STORE_NAME;
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import TYPES from './action-types';
|
||||
|
||||
const reportsReducer = (
|
||||
state = {
|
||||
feedIssues: {},
|
||||
feedState: {},
|
||||
isRequesting: false,
|
||||
requestingErrors: {},
|
||||
},
|
||||
action
|
||||
) => {
|
||||
switch ( action.type ) {
|
||||
case TYPES.RECEIVE_FEEDISSUES:
|
||||
state = {
|
||||
...state,
|
||||
feedIssues: action.feedIssues,
|
||||
};
|
||||
break;
|
||||
case TYPES.RECEIVE_FEEDSTATE:
|
||||
state = {
|
||||
...state,
|
||||
feedState: action.feedState,
|
||||
};
|
||||
break;
|
||||
case TYPES.RESET_FEED:
|
||||
state = {
|
||||
...state,
|
||||
feedIssues: {},
|
||||
feedState: {},
|
||||
};
|
||||
break;
|
||||
case TYPES.SET_IS_REQUESTING:
|
||||
state = {
|
||||
...state,
|
||||
isRequesting: action.isRequesting,
|
||||
};
|
||||
break;
|
||||
case TYPES.SET_REQUESTING_ERROR:
|
||||
state = {
|
||||
...state,
|
||||
requestingErrors: {
|
||||
[ action.name ]: action.error,
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
export default reportsReducer;
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
receiveFeedIssues,
|
||||
receiveFeedState,
|
||||
setRequestingError,
|
||||
setIsRequesting,
|
||||
} from './actions';
|
||||
import { fetch } from './controls';
|
||||
|
||||
/**
|
||||
* Request current feed issues.
|
||||
*
|
||||
* @param {Object} query
|
||||
*/
|
||||
export function* getFeedIssues( query = {} ) {
|
||||
try {
|
||||
const data = {
|
||||
paged: query.paged || 1,
|
||||
per_page: query.per_page || 25,
|
||||
};
|
||||
yield setIsRequesting( true );
|
||||
|
||||
const result = yield fetch( 'feed_issues', data );
|
||||
yield receiveFeedIssues( result );
|
||||
|
||||
yield setIsRequesting( false );
|
||||
} catch ( error ) {
|
||||
yield setRequestingError( error, 'feed_issues' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request current feed state.
|
||||
*/
|
||||
export function* getFeedState() {
|
||||
try {
|
||||
const result = yield fetch( 'feed_state' );
|
||||
yield receiveFeedState( result );
|
||||
} catch ( error ) {
|
||||
yield setRequestingError( error, 'feed_state' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Get settings from state tree.
|
||||
*
|
||||
* @param {Object} state - Reducer state
|
||||
*/
|
||||
export const getFeedIssues = ( state ) => {
|
||||
return state.feedIssues;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get setting from state tree.
|
||||
*
|
||||
* @param {Object} state - Reducer state
|
||||
*/
|
||||
export const getFeedState = ( state ) => {
|
||||
return state.feedState;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine if an options request resulted in an error.
|
||||
*
|
||||
* @param {Object} state - Reducer state
|
||||
* @param {string} name - Report name
|
||||
*/
|
||||
export const getReportsRequestingError = ( state, name ) => {
|
||||
return state.requestingErrors[ name ] || false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine if options are being updated.
|
||||
*
|
||||
* @param {Object} state - Reducer state
|
||||
*/
|
||||
export const isRequesting = ( state ) => {
|
||||
return state.isRequesting || false;
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
const TYPES = {
|
||||
RECEIVE_INTERACTIONS: 'RECEIVE_INTERACTIONS',
|
||||
SET_ADS_MODAL_DISMISSED: 'SET_ADS_MODAL_DISMISSED',
|
||||
SET_ADS_NOTICE_DISMISSED: 'SET_ADS_NOTICE_DISMISSED',
|
||||
SET_CAPI_MODAL_DISMISSED: 'SET_CAPI_MODAL_DISMISSED',
|
||||
SET_IS_REQUESTING: 'SET_IS_REQUESTING',
|
||||
SET_REQUESTING_ERROR: 'SET_REQUESTING_ERROR',
|
||||
SET_BILLING_SETUP_FLOW_ENTERED: 'SET_BILLING_SETUP_FLOW_ENTERED',
|
||||
};
|
||||
|
||||
export default TYPES;
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import apiFetch from '@wordpress/api-fetch';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import TYPES from './action-types';
|
||||
import { API_ROUTE } from './constants';
|
||||
|
||||
export function receiveUserInteractions( userInteractions ) {
|
||||
return {
|
||||
type: TYPES.RECEIVE_INTERACTIONS,
|
||||
userInteractions,
|
||||
};
|
||||
}
|
||||
|
||||
export function setAdsModalDismissed( modalDismissed ) {
|
||||
return {
|
||||
type: TYPES.SET_ADS_MODAL_DISMISSED,
|
||||
modalDismissed,
|
||||
};
|
||||
}
|
||||
|
||||
export function setIsRequesting( isRequesting ) {
|
||||
return {
|
||||
type: TYPES.SET_IS_REQUESTING,
|
||||
isRequesting,
|
||||
};
|
||||
}
|
||||
|
||||
export function setRequestingError( error, name ) {
|
||||
return {
|
||||
type: TYPES.SET_REQUESTING_ERROR,
|
||||
error,
|
||||
name,
|
||||
};
|
||||
}
|
||||
|
||||
export function* adsModalDismissed() {
|
||||
yield setAdsModalDismissed( true );
|
||||
|
||||
try {
|
||||
const results = yield apiFetch( {
|
||||
path: API_ROUTE,
|
||||
method: 'POST',
|
||||
data: {
|
||||
ads_modal_dismissed: true,
|
||||
},
|
||||
} );
|
||||
|
||||
return { success: results.ads_modal_dismissed };
|
||||
} catch ( error ) {}
|
||||
}
|
||||
|
||||
export function setAdsNoticeDismissed( noticeDismissed ) {
|
||||
return {
|
||||
type: TYPES.SET_ADS_NOTICE_DISMISSED,
|
||||
noticeDismissed,
|
||||
};
|
||||
}
|
||||
|
||||
export function* adsNoticeDismissed() {
|
||||
yield setAdsNoticeDismissed( true );
|
||||
|
||||
try {
|
||||
const results = yield apiFetch( {
|
||||
path: API_ROUTE,
|
||||
method: 'POST',
|
||||
data: {
|
||||
ads_notice_dismissed: true,
|
||||
},
|
||||
} );
|
||||
|
||||
return { success: results.ads_notice_dismissed };
|
||||
} catch ( error ) {}
|
||||
}
|
||||
|
||||
export function setCapiModalDismissed( modalDismissed ) {
|
||||
return {
|
||||
type: TYPES.SET_CAPI_MODAL_DISMISSED,
|
||||
modalDismissed,
|
||||
};
|
||||
}
|
||||
|
||||
export function* capiModalDismissed() {
|
||||
yield setCapiModalDismissed( true );
|
||||
|
||||
try {
|
||||
const results = yield apiFetch( {
|
||||
path: API_ROUTE,
|
||||
method: 'POST',
|
||||
data: {
|
||||
capi_modal_dismissed: true,
|
||||
},
|
||||
} );
|
||||
|
||||
return { success: results.capi_modal_dismissed };
|
||||
} catch ( error ) {}
|
||||
}
|
||||
|
||||
export function setBillingSetupFlowEntered() {
|
||||
return {
|
||||
type: TYPES.SET_BILLING_SETUP_FLOW_ENTERED,
|
||||
};
|
||||
}
|
||||
|
||||
export function* billingSetupFlowEntered() {
|
||||
yield setBillingSetupFlowEntered();
|
||||
|
||||
try {
|
||||
const results = yield apiFetch( {
|
||||
path: API_ROUTE,
|
||||
method: 'POST',
|
||||
data: {
|
||||
billing_setup_flow_entered: true,
|
||||
},
|
||||
} );
|
||||
|
||||
return { success: results.billing_setup_flow_entered };
|
||||
} catch ( error ) {}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export const STORE_NAME = 'pinterest_for_woocommerce/admin/userInteraction';
|
||||
export const API_ROUTE =
|
||||
wcSettings.pinterest_for_woocommerce.apiRoute + '/user_interaction';
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import apiFetch from '@wordpress/api-fetch';
|
||||
import { controls as dataControls } from '@wordpress/data-controls';
|
||||
import { addQueryArgs } from '@wordpress/url';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { API_ROUTE } from './constants';
|
||||
|
||||
export const fetch = ( endpoint, data = {} ) => {
|
||||
return {
|
||||
type: 'FETCH',
|
||||
endpoint,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
export const controls = {
|
||||
...dataControls,
|
||||
FETCH( { data = {}, method = 'GET' } ) {
|
||||
return new Promise( ( resolve ) => {
|
||||
const url = addQueryArgs( `${ API_ROUTE }`, data );
|
||||
|
||||
apiFetch( { path: url, method } ).then( ( result ) =>
|
||||
resolve( result )
|
||||
);
|
||||
} );
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
|
||||
import { registerStore } from '@wordpress/data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { STORE_NAME } from './constants';
|
||||
import * as selectors from './selectors';
|
||||
import * as actions from './actions';
|
||||
import * as resolvers from './resolvers';
|
||||
import { controls } from './controls';
|
||||
import reducer from './reducer';
|
||||
|
||||
registerStore( STORE_NAME, {
|
||||
reducer,
|
||||
actions,
|
||||
controls,
|
||||
selectors,
|
||||
resolvers,
|
||||
} );
|
||||
|
||||
export const USER_INTERACTION_STORE_NAME = STORE_NAME;
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import TYPES from './action-types';
|
||||
|
||||
const userInteractionsReducer = (
|
||||
state = {
|
||||
userInteractions: {
|
||||
ads_modal_dismissed: false,
|
||||
ads_notice_dismissed: false,
|
||||
capi_modal_dismissed: false,
|
||||
billingSetupFlowEntered: false,
|
||||
},
|
||||
isRequesting: false,
|
||||
interactionsLoaded: false,
|
||||
requestingErrors: {},
|
||||
},
|
||||
action
|
||||
) => {
|
||||
switch ( action.type ) {
|
||||
case TYPES.RECEIVE_INTERACTIONS:
|
||||
state = {
|
||||
...state,
|
||||
userInteractions: action.userInteractions,
|
||||
interactionsLoaded: true,
|
||||
};
|
||||
break;
|
||||
case TYPES.SET_IS_REQUESTING:
|
||||
state = {
|
||||
...state,
|
||||
isRequesting: action.isRequesting,
|
||||
};
|
||||
break;
|
||||
case TYPES.SET_ADS_MODAL_DISMISSED:
|
||||
state = {
|
||||
...state,
|
||||
userInteractions: {
|
||||
...state.userInteractions,
|
||||
ads_modal_dismissed: action.modalDismissed,
|
||||
},
|
||||
};
|
||||
break;
|
||||
case TYPES.SET_ADS_NOTICE_DISMISSED:
|
||||
state = {
|
||||
...state,
|
||||
userInteractions: {
|
||||
...state.userInteractions,
|
||||
ads_notice_dismissed: action.noticeDismissed,
|
||||
},
|
||||
};
|
||||
break;
|
||||
case TYPES.SET_CAPI_MODAL_DISMISSED:
|
||||
state = {
|
||||
...state,
|
||||
userInteractions: {
|
||||
...state.userInteractions,
|
||||
capi_modal_dismissed: action.modalDismissed,
|
||||
},
|
||||
};
|
||||
break;
|
||||
case TYPES.SET_BILLING_SETUP_FLOW_ENTERED:
|
||||
state = {
|
||||
...state,
|
||||
userInteractions: {
|
||||
...state.userInteractions,
|
||||
billingSetupFlowEntered: true,
|
||||
},
|
||||
};
|
||||
break;
|
||||
case TYPES.SET_REQUESTING_ERROR:
|
||||
state = {
|
||||
...state,
|
||||
requestingErrors: {
|
||||
[ action.name ]: action.error,
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
export default userInteractionsReducer;
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
receiveUserInteractions,
|
||||
setRequestingError,
|
||||
setIsRequesting,
|
||||
} from './actions';
|
||||
import { fetch } from './controls';
|
||||
|
||||
/**
|
||||
* Request current feed state.
|
||||
*/
|
||||
export function* getUserInteractions() {
|
||||
try {
|
||||
yield setIsRequesting( true );
|
||||
const result = yield fetch( 'user_interaction' );
|
||||
yield receiveUserInteractions( result );
|
||||
yield setIsRequesting( false );
|
||||
} catch ( error ) {
|
||||
yield setRequestingError( error, 'user_interaction' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Has user dismissed ads modal.
|
||||
*
|
||||
* @param {Object} state - Reducer state
|
||||
*/
|
||||
export const getUserInteractions = ( state ) => {
|
||||
return state.userInteractions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine if interactions options have been loaded.
|
||||
*
|
||||
* @param {Object} state - Reducer state
|
||||
*/
|
||||
export const areInteractionsLoaded = ( state ) => {
|
||||
return state.interactionsLoaded;
|
||||
};
|
||||
49
wp-content/plugins/pinterest-for-woocommerce/assets/source/catalog-sync/helpers/effects.js
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useDispatch } from '@wordpress/data';
|
||||
import { useEffect } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { USER_INTERACTION_STORE_NAME } from '../data';
|
||||
|
||||
export const useCreateNotice = ( error ) => {
|
||||
const { createNotice } = useDispatch( 'core/notices' );
|
||||
|
||||
useEffect( () => {
|
||||
if ( error ) {
|
||||
createNotice( 'error', error );
|
||||
}
|
||||
}, [ error, createNotice ] );
|
||||
};
|
||||
|
||||
export const useDismissAdsModalDispatch = () => {
|
||||
const { adsModalDismissed } = useDispatch( USER_INTERACTION_STORE_NAME );
|
||||
return () => adsModalDismissed();
|
||||
};
|
||||
|
||||
export const useDismissAdsNoticeDispatch = () => {
|
||||
const { adsNoticeDismissed } = useDispatch( USER_INTERACTION_STORE_NAME );
|
||||
return () => adsNoticeDismissed();
|
||||
};
|
||||
|
||||
export const useDismissCapiModalDispatch = () => {
|
||||
const { capiModalDismissed } = useDispatch( USER_INTERACTION_STORE_NAME );
|
||||
return () => capiModalDismissed();
|
||||
};
|
||||
|
||||
export const useBillingSetupFlowEntered = () => {
|
||||
const { billingSetupFlowEntered } = useDispatch(
|
||||
USER_INTERACTION_STORE_NAME
|
||||
);
|
||||
return () => billingSetupFlowEntered();
|
||||
};
|
||||
|
||||
export const useResetUserInteractions = () => {
|
||||
const { invalidateResolutionForStore } = useDispatch(
|
||||
USER_INTERACTION_STORE_NAME
|
||||
);
|
||||
return () => invalidateResolutionForStore();
|
||||
};
|
||||
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import {
|
||||
createInterpolateElement,
|
||||
useCallback,
|
||||
useState,
|
||||
} from '@wordpress/element';
|
||||
import {
|
||||
ExternalLink,
|
||||
Icon,
|
||||
Notice,
|
||||
__experimentalText as Text, // eslint-disable-line @wordpress/no-unsafe-wp-apis --- _experimentalText unlikely to change/disappear and also used by WC Core
|
||||
} from '@wordpress/components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useSettingsSelect } from '../../setup-guide/app/helpers/effects';
|
||||
import GiftIcon from '../../setup-guide/app/components/GiftIcon';
|
||||
import {
|
||||
useBillingSetupFlowEntered,
|
||||
useDismissAdsNoticeDispatch,
|
||||
} from '../helpers/effects';
|
||||
|
||||
/**
|
||||
* Closing the Ad Credits notice.
|
||||
*
|
||||
* @event wcadmin_pfw_ads_credits_success_notice
|
||||
*/
|
||||
/**
|
||||
* Clicking the "Add billing details" link.
|
||||
*
|
||||
* @event wcadmin_pfw_ads_billing_details_link_click
|
||||
*/
|
||||
|
||||
/**
|
||||
* Catalog ad credits notice.
|
||||
*
|
||||
* @fires wcadmin_pfw_ads_credits_success_notice
|
||||
* @fires wcadmin_pfw_ads_billing_details_link_click
|
||||
* @return {JSX.Element} Rendered component.
|
||||
*/
|
||||
const AdCreditsNotice = () => {
|
||||
const [ isNoticeDisplayed, setIsNoticeDisplayed ] = useState( true );
|
||||
|
||||
const appSettings = useSettingsSelect();
|
||||
const isBillingSetup = appSettings?.account_data?.is_billing_setup;
|
||||
const trackingAdvertiser = appSettings?.tracking_advertiser;
|
||||
const currencyCreditInfo = appSettings?.account_data?.currency_credit_info;
|
||||
|
||||
const closeAdCreditsNotice = () => {
|
||||
setIsNoticeDisplayed( false );
|
||||
handleSetDismissAdsNotice();
|
||||
recordEvent( 'pfw_ads_credits_success_notice' );
|
||||
};
|
||||
|
||||
const setDismissAdsNotice = useDismissAdsNoticeDispatch();
|
||||
const handleSetDismissAdsNotice = useCallback( async () => {
|
||||
try {
|
||||
await setDismissAdsNotice();
|
||||
} catch ( error ) {}
|
||||
}, [ setDismissAdsNotice ] );
|
||||
|
||||
const billingSetupFlowEntered = useBillingSetupFlowEntered();
|
||||
|
||||
return (
|
||||
isNoticeDisplayed && (
|
||||
<Notice
|
||||
isDismissible={ true }
|
||||
onRemove={ closeAdCreditsNotice }
|
||||
className="pinterest-for-woocommerce-catalog-sync__ad-credits"
|
||||
status="success"
|
||||
>
|
||||
<Icon
|
||||
icon={ GiftIcon }
|
||||
className="pinterest-for-woocommerce-catalog-sync__ad-credits__icon"
|
||||
/>
|
||||
{ isBillingSetup ? (
|
||||
<Text>
|
||||
{ sprintf(
|
||||
// translators: %1$s: Amount of money required to spend to claim ad credits with currency. %2$s: Amount of ad credits given with currency.
|
||||
__(
|
||||
'Spend %1$s to claim %2$s in Pinterest ad credits. (Ad credits may take up to 24 hours to be credited to account).',
|
||||
'pinterest-for-woocommerce'
|
||||
),
|
||||
currencyCreditInfo.spendRequire,
|
||||
currencyCreditInfo.creditsGiven
|
||||
) }
|
||||
</Text>
|
||||
) : (
|
||||
<Text>
|
||||
{ createInterpolateElement(
|
||||
sprintf(
|
||||
// translators: %1$s: Amount of money required to spend to claim ad credits with currency. %2$s: Amount of ad credits given with currency.
|
||||
__(
|
||||
'Spend %1$s to claim %2$s in Pinterest ad credits. To claim the credits, <adsBillingDetails>add your billing details.</adsBillingDetails>',
|
||||
'pinterest-for-woocommerce'
|
||||
),
|
||||
currencyCreditInfo.spendRequire,
|
||||
currencyCreditInfo.creditsGiven
|
||||
),
|
||||
{
|
||||
adsBillingDetails: trackingAdvertiser ? (
|
||||
<ExternalLink
|
||||
href={ `https://ads.pinterest.com/advertiser/${ trackingAdvertiser }/billing/` }
|
||||
onClick={ () => {
|
||||
recordEvent(
|
||||
'wcadmin_pfw_ads_credits_success_notice'
|
||||
);
|
||||
billingSetupFlowEntered();
|
||||
} }
|
||||
/>
|
||||
) : (
|
||||
<strong />
|
||||
),
|
||||
}
|
||||
) }
|
||||
</Text>
|
||||
) }
|
||||
</Notice>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default AdCreditsNotice;
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
import { createInterpolateElement, useState } from '@wordpress/element';
|
||||
import { getHistory, getQuery, onQueryChange } from '@woocommerce/navigation';
|
||||
import {
|
||||
ExternalLink,
|
||||
__experimentalText as Text, // eslint-disable-line @wordpress/no-unsafe-wp-apis --- _experimentalText unlikely to change/disappear and also used by WC Core
|
||||
} from '@wordpress/components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { REPORTS_STORE_NAME } from '../data';
|
||||
import SyncIssuesTable from './SyncIssuesTable';
|
||||
import { useSettingsSelect } from '../../setup-guide/app/helpers/effects';
|
||||
|
||||
const SyncIssues = () => {
|
||||
const itemsLimit = 250;
|
||||
const [ query, setQuery ] = useState( getQuery() );
|
||||
const feedIssues = useSelect( ( select ) =>
|
||||
select( REPORTS_STORE_NAME ).getFeedIssues( query )
|
||||
);
|
||||
const isRequesting = useSelect( ( select ) =>
|
||||
select( REPORTS_STORE_NAME ).isRequesting()
|
||||
);
|
||||
|
||||
const appSettings = useSettingsSelect();
|
||||
const trackingAdvertiser = appSettings?.tracking_advertiser;
|
||||
|
||||
const total = feedIssues?.total_rows ?? 0;
|
||||
|
||||
const messageStyles = {
|
||||
marginTop: '40px',
|
||||
textAlign: 'right',
|
||||
};
|
||||
|
||||
if ( ! feedIssues?.lines?.length ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
getHistory().listen( () => {
|
||||
setQuery( getQuery() );
|
||||
} );
|
||||
|
||||
if ( ! query.paged ) {
|
||||
query.paged = 1;
|
||||
}
|
||||
|
||||
if ( ! query.per_page ) {
|
||||
query.per_page = 25;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{ itemsLimit === total && (
|
||||
<Text style={ messageStyles }>
|
||||
{ createInterpolateElement(
|
||||
sprintf(
|
||||
// translators: %1$s: Total number of issues in the table.
|
||||
__(
|
||||
'Only the first %1$s Errors and Warnings are displayed below. To see more, please, visit <feedDiagnostics>Pinterest Feed Diagnostics</feedDiagnostics> page.',
|
||||
'pinterest-for-woocommerce'
|
||||
),
|
||||
total
|
||||
),
|
||||
{
|
||||
feedDiagnostics: (
|
||||
<ExternalLink
|
||||
href={ `https://pinterest.com/business/catalogs/diagnosticsv2/?advertiserId=${ trackingAdvertiser }` }
|
||||
/>
|
||||
),
|
||||
}
|
||||
) }
|
||||
</Text>
|
||||
) }
|
||||
<SyncIssuesTable
|
||||
issues={ feedIssues?.lines }
|
||||
query={ query }
|
||||
totalRows={ total }
|
||||
isRequesting={ isRequesting }
|
||||
onQueryChange={ onQueryChange }
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SyncIssues;
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { Icon } from '@wordpress/components';
|
||||
import { TableCard } from '@woocommerce/components';
|
||||
|
||||
const SyncIssuesTable = ( {
|
||||
issues,
|
||||
totalRows,
|
||||
query,
|
||||
isRequesting,
|
||||
onQueryChange,
|
||||
} ) => {
|
||||
const defaultHeaderAttributes = {
|
||||
isLeftAligned: true,
|
||||
isSortable: false,
|
||||
};
|
||||
|
||||
const headers = [
|
||||
{
|
||||
key: 'type',
|
||||
label: __( 'Type', 'pinterest-for-woocommerce' ),
|
||||
...defaultHeaderAttributes,
|
||||
},
|
||||
{
|
||||
key: 'affected-product',
|
||||
label: __( 'Affected Product', 'pinterest-for-woocommerce' ),
|
||||
...defaultHeaderAttributes,
|
||||
},
|
||||
{
|
||||
key: 'issue',
|
||||
label: __( 'Issue', 'pinterest-for-woocommerce' ),
|
||||
...defaultHeaderAttributes,
|
||||
},
|
||||
{ key: 'edit', ...defaultHeaderAttributes },
|
||||
];
|
||||
|
||||
const getRows = ( data ) => {
|
||||
const statuses = {
|
||||
success: 'success',
|
||||
warning: 'warning',
|
||||
error: 'error',
|
||||
};
|
||||
|
||||
const icons = {
|
||||
success: 'yes-alt',
|
||||
warning: 'warning',
|
||||
error: 'warning',
|
||||
};
|
||||
|
||||
return data.map( ( row ) => {
|
||||
return [
|
||||
{
|
||||
display: (
|
||||
<Icon
|
||||
icon={ icons[ row.status ] }
|
||||
className={ `${ statuses[ row.status ] }-text` }
|
||||
/>
|
||||
),
|
||||
},
|
||||
{ display: row.product_name },
|
||||
{ display: row.issue_description },
|
||||
{
|
||||
display: (
|
||||
<a
|
||||
href={ row.product_edit_link }
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{ __( 'Edit', 'pinterest-for-woocommerce' ) }
|
||||
</a>
|
||||
),
|
||||
},
|
||||
];
|
||||
} );
|
||||
};
|
||||
|
||||
return (
|
||||
<TableCard
|
||||
className="pinterest-for-woocommerce-catalog-sync__issues"
|
||||
title={ __( 'Issues', 'pinterest-for-woocommerce' ) }
|
||||
rows={ issues && getRows( issues ) }
|
||||
headers={ headers }
|
||||
showMenu={ false }
|
||||
query={ query }
|
||||
rowsPerPage={ query.per_page }
|
||||
totalRows={ totalRows }
|
||||
isLoading={ ! issues || isRequesting }
|
||||
onQueryChange={ onQueryChange }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SyncIssuesTable;
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
import { createInterpolateElement } from '@wordpress/element';
|
||||
import { Icon, trendingUp as trendingUpIcon } from '@wordpress/icons';
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
ExternalLink,
|
||||
Flex,
|
||||
FlexItem,
|
||||
__experimentalText as Text, // eslint-disable-line @wordpress/no-unsafe-wp-apis --- _experimentalText unlikely to change/disappear and also used by WC Core
|
||||
} from '@wordpress/components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { REPORTS_STORE_NAME } from '../data';
|
||||
import SyncStateSummary from './SyncStateSummary';
|
||||
import SyncStateTable from './SyncStateTable';
|
||||
import { useSettingsSelect } from '../../setup-guide/app/helpers/effects';
|
||||
|
||||
/**
|
||||
* Clicking on the "Pinterest ads manager" link.
|
||||
*
|
||||
* @event wcadmin_pfw_ads_manager_link_click
|
||||
*/
|
||||
|
||||
/**
|
||||
* Catalog sync state overview component.
|
||||
*
|
||||
* @fires wcadmin_pfw_ads_manager_link_click
|
||||
* @return {JSX.Element} Rendered component.
|
||||
*/
|
||||
const SyncState = () => {
|
||||
const feedState = useSelect( ( select ) =>
|
||||
select( REPORTS_STORE_NAME ).getFeedState()
|
||||
);
|
||||
|
||||
const hasAvailableCredits =
|
||||
useSettingsSelect()?.account_data?.available_discounts?.marketing_offer
|
||||
?.remaining_discount;
|
||||
|
||||
const availableCredits = sprintf(
|
||||
/* translators: %s credits value with currency formatted using wc_price */
|
||||
__(
|
||||
'You have %s of free ad credits left to use',
|
||||
'pinterest-for-woocommerce'
|
||||
),
|
||||
hasAvailableCredits
|
||||
);
|
||||
|
||||
return (
|
||||
<Card className="woocommerce-table pinterest-for-woocommerce-catalog-sync__state">
|
||||
<CardHeader>
|
||||
<Text variant="title.small" as="h2">
|
||||
{ __( 'Overview', 'pinterest-for-woocommerce' ) }
|
||||
</Text>
|
||||
</CardHeader>
|
||||
<SyncStateSummary overview={ feedState?.overview } />
|
||||
<SyncStateTable workflow={ feedState?.workflow } />
|
||||
<CardFooter justify="flex-start">
|
||||
<Icon icon={ trendingUpIcon } />
|
||||
<Flex
|
||||
direction={ 'column' }
|
||||
className="pinterest-for-woocommerce-catalog-sync__state-footer"
|
||||
>
|
||||
<FlexItem>
|
||||
<Text>
|
||||
{ createInterpolateElement(
|
||||
__(
|
||||
'Create ads to increase your reach with the <adsManagerLink>Pinterest ads manager</adsManagerLink>',
|
||||
'pinterest-for-woocommerce'
|
||||
),
|
||||
{
|
||||
adsManagerLink: (
|
||||
<ExternalLink
|
||||
href={
|
||||
wcSettings
|
||||
.pinterest_for_woocommerce
|
||||
.pinterestLinks.adsManager
|
||||
}
|
||||
onClick={ () => {
|
||||
recordEvent(
|
||||
'pfw_ads_manager_link_click'
|
||||
);
|
||||
} }
|
||||
/>
|
||||
),
|
||||
}
|
||||
) }
|
||||
</Text>
|
||||
</FlexItem>
|
||||
{ hasAvailableCredits && (
|
||||
<FlexItem>
|
||||
<Text
|
||||
className="pinterest-for-woocommerce-catalog-sync__state-footer-credits"
|
||||
dangerouslySetInnerHTML={ {
|
||||
__html: availableCredits,
|
||||
} }
|
||||
/>
|
||||
</FlexItem>
|
||||
) }
|
||||
</Flex>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default SyncState;
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import SyncState from './SyncState';
|
||||
|
||||
describe( 'SyncState component', () => {
|
||||
test( 'should render header and footer correctly', () => {
|
||||
const { getByRole } = render( <SyncState /> );
|
||||
|
||||
expect( getByRole( 'heading' ) ).toHaveTextContent( 'Overview' );
|
||||
expect( getByRole( 'link' ) ).toHaveTextContent(
|
||||
'Pinterest ads manager(opens in a new tab)'
|
||||
);
|
||||
} );
|
||||
|
||||
test( 'should render SyncStateSummary', () => {
|
||||
const { getAllByTestId } = render( <SyncState /> );
|
||||
|
||||
expect( getAllByTestId( 'summary-placeholder' ) ).toBeTruthy();
|
||||
} );
|
||||
|
||||
test( 'should render SyncStateTable', () => {
|
||||
const { getByText } = render( <SyncState /> );
|
||||
|
||||
expect( getByText( 'Property' ) ).toBeTruthy();
|
||||
} );
|
||||
|
||||
test( 'should fire `pfw_ads_manager_link_click` when "Pinterest ads manager" is clicked', () => {
|
||||
const { getByText } = render( <SyncState /> );
|
||||
|
||||
fireEvent.click( getByText( 'Pinterest ads manager' ) );
|
||||
|
||||
expect( recordEvent ).toHaveBeenCalledWith(
|
||||
'pfw_ads_manager_link_click'
|
||||
);
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import {
|
||||
SummaryList,
|
||||
SummaryNumber,
|
||||
SummaryListPlaceholder,
|
||||
} from '@woocommerce/components';
|
||||
|
||||
const SyncStateSummary = ( { overview } ) => {
|
||||
const getItems = ( data ) => {
|
||||
const defaultValue = __( 'N/A', 'pinterest-for-woocommerce' );
|
||||
|
||||
return [
|
||||
<SummaryNumber
|
||||
key="active"
|
||||
value={ data?.total ?? defaultValue }
|
||||
label={ __( 'Active', 'pinterest-for-woocommerce' ) }
|
||||
/>,
|
||||
<SummaryNumber
|
||||
key="not-synced"
|
||||
value={ data?.not_synced ?? defaultValue }
|
||||
label={ __( 'Not synced', 'pinterest-for-woocommerce' ) }
|
||||
/>,
|
||||
<SummaryNumber
|
||||
key="with-warnings"
|
||||
value={ data?.warnings ?? defaultValue }
|
||||
label={ __( 'Warnings', 'pinterest-for-woocommerce' ) }
|
||||
/>,
|
||||
<SummaryNumber
|
||||
key="with-errors"
|
||||
value={ data?.errors ?? defaultValue }
|
||||
label={ __( 'Errors', 'pinterest-for-woocommerce' ) }
|
||||
/>,
|
||||
];
|
||||
};
|
||||
|
||||
return overview ? (
|
||||
<SummaryList>{ () => getItems( overview ) }</SummaryList>
|
||||
) : (
|
||||
<SummaryListPlaceholder numberOfItems={ 4 } />
|
||||
);
|
||||
};
|
||||
|
||||
export default SyncStateSummary;
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { Icon } from '@wordpress/components';
|
||||
import { Table, TablePlaceholder } from '@woocommerce/components';
|
||||
|
||||
const SyncStateTable = ( { workflow } ) => {
|
||||
const defaultHeaderAttributes = {
|
||||
isLeftAligned: true,
|
||||
isSortable: false,
|
||||
};
|
||||
|
||||
const headers = [
|
||||
{
|
||||
key: 'property',
|
||||
label: __( 'Property', 'pinterest-for-woocommerce' ),
|
||||
...defaultHeaderAttributes,
|
||||
},
|
||||
{
|
||||
key: 'state',
|
||||
label: __( 'State', 'pinterest-for-woocommerce' ),
|
||||
...defaultHeaderAttributes,
|
||||
},
|
||||
];
|
||||
|
||||
const getRows = ( data ) => {
|
||||
const statuses = {
|
||||
success: 'success',
|
||||
pending: 'warning',
|
||||
warning: 'warning',
|
||||
error: 'error',
|
||||
};
|
||||
|
||||
const icons = {
|
||||
success: 'yes-alt',
|
||||
pending: 'clock',
|
||||
warning: 'warning',
|
||||
error: 'warning',
|
||||
};
|
||||
|
||||
return data.map( ( row ) => {
|
||||
return [
|
||||
{ display: `${ row.label }:` },
|
||||
{
|
||||
display: (
|
||||
<>
|
||||
<span
|
||||
className={ `${ statuses[ row.status ] }-text` }
|
||||
>
|
||||
<Icon icon={ icons[ row.status ] } />{ ' ' }
|
||||
{ row.status_label }
|
||||
</span>
|
||||
{ row.extra_info ? (
|
||||
<>
|
||||
{ ` \xa0 • \xa0 ` }
|
||||
<span
|
||||
dangerouslySetInnerHTML={ {
|
||||
__html: row.extra_info,
|
||||
} }
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
''
|
||||
) }
|
||||
</>
|
||||
),
|
||||
},
|
||||
];
|
||||
} );
|
||||
};
|
||||
|
||||
return workflow ? (
|
||||
<Table
|
||||
rows={ getRows( workflow ) }
|
||||
headers={ headers }
|
||||
showMenu={ false }
|
||||
/>
|
||||
) : (
|
||||
<TablePlaceholder headers={ headers } numberOfRows={ 3 } caption="" />
|
||||
);
|
||||
};
|
||||
|
||||
export default SyncStateTable;
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { NavigableMenu } from '@wordpress/components';
|
||||
import { Link } from '@woocommerce/components';
|
||||
import classnames from 'classnames';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
const TabLink = ( { tabId, href, children, selected, ...rest } ) => {
|
||||
return (
|
||||
<Link
|
||||
role="tab"
|
||||
tabIndex={ selected ? null : -1 }
|
||||
aria-selected={ selected }
|
||||
id={ tabId }
|
||||
href={ href }
|
||||
{ ...rest }
|
||||
>
|
||||
{ children }
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const AppTabNav = ( props ) => {
|
||||
const { selectedKey, tabs } = props;
|
||||
|
||||
return (
|
||||
<div className="app-tab-nav">
|
||||
<NavigableMenu
|
||||
role="tablist"
|
||||
orientation="horizontal"
|
||||
className="app-tab-nav__tabs"
|
||||
>
|
||||
{ tabs.map( ( tab ) => (
|
||||
<TabLink
|
||||
className={ classnames(
|
||||
'components-button',
|
||||
'app-tab-nav__tabs-item',
|
||||
{
|
||||
'is-active': tab.key === selectedKey,
|
||||
}
|
||||
) }
|
||||
tabId={ `${ tab.key }` }
|
||||
aria-controls={ `${ tab.key }-view` }
|
||||
selected={ tab.key === selectedKey }
|
||||
key={ tab.key }
|
||||
href={ tab.href }
|
||||
>
|
||||
{ tab.title }
|
||||
</TabLink>
|
||||
) ) }
|
||||
</NavigableMenu>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppTabNav;
|
||||