@@ -1,339 +0,0 @@
|
||||
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.
|
||||
|
||||
All-in-One Event Calendar 2.0
|
||||
Copyright (C) 2013 Timely Network Inc.
|
||||
|
||||
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.
|
||||
@@ -1,4 +0,0 @@
|
||||
all-in-one-event-calendar
|
||||
=========================
|
||||
|
||||
All-in-One Event Calendar 2.0
|
||||
@@ -1,88 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: All-in-One Event Calendar by Time.ly
|
||||
* Plugin URI: https://wordpress.org/plugins/all-in-one-event-calendar/
|
||||
* Description: A calendar system with month, week, day, agenda views, upcoming events widget, color-coded categories, recurrence, and import/export of .ics feeds.
|
||||
* Author: Time.ly Network Inc.
|
||||
* Author URI: https://time.ly/
|
||||
* Version: 2.5.44
|
||||
* Text Domain: all-in-one-event-calendar
|
||||
* Domain Path: /language
|
||||
*/
|
||||
$ai1ec_base_dir = dirname( __FILE__ );
|
||||
$ai1ec_base_url = plugins_url( '', __FILE__ );
|
||||
|
||||
$ai1ec_config_path = $ai1ec_base_dir . DIRECTORY_SEPARATOR . 'app' .
|
||||
DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR;
|
||||
|
||||
// Include configuration files and initiate global constants as they are used
|
||||
// By the error/exception handler too.
|
||||
foreach ( array( 'constants-local.php', 'constants.php' ) as $file ) {
|
||||
if ( is_file( $ai1ec_config_path . $file ) ) {
|
||||
require_once $ai1ec_config_path . $file;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'ai1ec_initiate_constants' ) ) {
|
||||
throw new Ai1ec_Exception(
|
||||
'No constant file was found.'
|
||||
);
|
||||
}
|
||||
ai1ec_initiate_constants( $ai1ec_base_dir, $ai1ec_base_url );
|
||||
|
||||
require $ai1ec_base_dir . DIRECTORY_SEPARATOR . 'lib' .
|
||||
DIRECTORY_SEPARATOR . 'exception' . DIRECTORY_SEPARATOR . 'ai1ec.php';
|
||||
require $ai1ec_base_dir . DIRECTORY_SEPARATOR . 'lib' .
|
||||
DIRECTORY_SEPARATOR . 'exception' . DIRECTORY_SEPARATOR . 'error.php';
|
||||
require $ai1ec_base_dir . DIRECTORY_SEPARATOR . 'lib' .
|
||||
DIRECTORY_SEPARATOR . 'exception' . DIRECTORY_SEPARATOR . 'handler.php';
|
||||
require $ai1ec_base_dir . DIRECTORY_SEPARATOR . 'lib' .
|
||||
DIRECTORY_SEPARATOR . 'http' . DIRECTORY_SEPARATOR . 'response' .
|
||||
DIRECTORY_SEPARATOR . 'helper.php';
|
||||
$ai1ec_exception_handler = new Ai1ec_Exception_Handler(
|
||||
'Ai1ec_Exception',
|
||||
'Ai1ec_Error_Exception'
|
||||
);
|
||||
|
||||
|
||||
// if the user clicked the link to reactivate the plugin
|
||||
if ( isset( $_GET[Ai1ec_Exception_Handler::DB_REACTIVATE_PLUGIN] ) ) {
|
||||
$ai1ec_exception_handler->reactivate_plugin();
|
||||
}
|
||||
$soft_disable_message = $ai1ec_exception_handler->get_disabled_message();
|
||||
if ( false !== $soft_disable_message ) {
|
||||
return $ai1ec_exception_handler->show_notices( $soft_disable_message );
|
||||
}
|
||||
|
||||
$prev_er_handler = set_error_handler(
|
||||
array( $ai1ec_exception_handler, 'handle_error' )
|
||||
);
|
||||
$prev_ex_handler = set_exception_handler(
|
||||
array( $ai1ec_exception_handler, 'handle_exception' )
|
||||
);
|
||||
$ai1ec_exception_handler->set_prev_er_handler( $prev_er_handler );
|
||||
$ai1ec_exception_handler->set_prev_ex_handler( $prev_ex_handler );
|
||||
|
||||
// Regular startup sequence starts here
|
||||
|
||||
require $ai1ec_base_dir . DIRECTORY_SEPARATOR . 'lib' .
|
||||
DIRECTORY_SEPARATOR . 'bootstrap' . DIRECTORY_SEPARATOR . 'loader.php';
|
||||
|
||||
require $ai1ec_base_dir . DIRECTORY_SEPARATOR . 'lib' .
|
||||
DIRECTORY_SEPARATOR . 'global-functions.php';
|
||||
|
||||
require $ai1ec_base_dir . DIRECTORY_SEPARATOR . 'lib' .
|
||||
DIRECTORY_SEPARATOR . 'iCal' . DIRECTORY_SEPARATOR . 'iCalcreator-2.26.9' . DIRECTORY_SEPARATOR . 'autoload.php';
|
||||
|
||||
require $ai1ec_base_dir . DIRECTORY_SEPARATOR . 'app' .
|
||||
DIRECTORY_SEPARATOR . 'controller' . DIRECTORY_SEPARATOR . 'extension.php';
|
||||
|
||||
require $ai1ec_base_dir . DIRECTORY_SEPARATOR . 'app' .
|
||||
DIRECTORY_SEPARATOR . 'controller' . DIRECTORY_SEPARATOR . 'extension-license.php';
|
||||
|
||||
$ai1ec_loader = new Ai1ec_Loader( $ai1ec_base_dir );
|
||||
@ini_set( 'unserialize_callback_func', 'spl_autoload_call' );
|
||||
spl_autoload_register( array( $ai1ec_loader, 'load' ) );
|
||||
|
||||
$ai1ec_front_controller = new Ai1ec_Front_Controller();
|
||||
$ai1ec_front_controller->initialize( $ai1ec_loader );
|
||||
@@ -1,493 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Define required constants, if these have not been defined already.
|
||||
*
|
||||
* @param string $ai1ec_base_dir Sanitized, absolute, path to Ai1EC base dir
|
||||
*
|
||||
* @uses plugin_basename To determine plug-in folder+file name
|
||||
* @uses plugins_url To determine absolute URI to plug-ins' folder
|
||||
* @uses get_option To fetch 'home' URI value
|
||||
*
|
||||
* @return void Method does not return
|
||||
*/
|
||||
function ai1ec_initiate_constants( $ai1ec_base_dir, $ai1ec_base_url ) {
|
||||
|
||||
// ===============
|
||||
// = Plugin Path =
|
||||
// ===============
|
||||
if ( ! defined( 'AI1EC_PATH' ) ) {
|
||||
define( 'AI1EC_PATH', $ai1ec_base_dir );
|
||||
}
|
||||
|
||||
// =======================
|
||||
// = Extensions base dir =
|
||||
// =======================
|
||||
if ( ! defined( 'AI1EC_EXTENSIONS_BASEDIR' ) ) {
|
||||
define(
|
||||
'AI1EC_EXTENSIONS_BASEDIR',
|
||||
dirname( $ai1ec_base_dir ) . DIRECTORY_SEPARATOR
|
||||
);
|
||||
}
|
||||
|
||||
// ===============
|
||||
// = Plugin Name =
|
||||
// ===============
|
||||
if ( ! defined( 'AI1EC_PLUGIN_NAME' ) ) {
|
||||
define( 'AI1EC_PLUGIN_NAME', 'all-in-one-event-calendar' );
|
||||
}
|
||||
|
||||
// ===================
|
||||
// = Plugin Basename =
|
||||
// ===================
|
||||
if ( ! defined( 'AI1EC_PLUGIN_BASENAME' ) ) {
|
||||
$plugin = AI1EC_PATH . DIRECTORY_SEPARATOR . AI1EC_PLUGIN_NAME . '.php';
|
||||
define( 'AI1EC_PLUGIN_BASENAME', plugin_basename( $plugin ) );
|
||||
unset( $plugin );
|
||||
}
|
||||
|
||||
// ==================
|
||||
// = Plugin Version =
|
||||
// ==================
|
||||
if ( ! defined( 'AI1EC_VERSION' ) ) {
|
||||
define( 'AI1EC_VERSION', '2.5.44' );
|
||||
}
|
||||
|
||||
// ================
|
||||
// = RSS FEED URL =
|
||||
// ================
|
||||
if ( ! defined( 'AI1EC_RSS_FEED' ) ) {
|
||||
define( 'AI1EC_RSS_FEED', 'https://time.ly/blog/feed/' );
|
||||
}
|
||||
|
||||
// =================
|
||||
// = Language Path =
|
||||
// =================
|
||||
if ( ! defined( 'AI1EC_LANGUAGE_PATH' ) ) {
|
||||
define(
|
||||
'AI1EC_LANGUAGE_PATH',
|
||||
AI1EC_PLUGIN_NAME . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR
|
||||
);
|
||||
}
|
||||
// ================
|
||||
// = Cron Version =
|
||||
// ================
|
||||
if ( ! defined( 'AI1EC_CRON_VERSION' ) ) {
|
||||
define( 'AI1EC_CRON_VERSION', AI1EC_VERSION );
|
||||
}
|
||||
if ( ! defined( 'AI1EC_U_CRON_VERSION' ) ) {
|
||||
define( 'AI1EC_U_CRON_VERSION', AI1EC_VERSION );
|
||||
}
|
||||
if ( ! defined( 'AI1EC_U_CRON_FREQ' ) ) {
|
||||
define( 'AI1EC_U_CRON_FREQ', 'hourly' );
|
||||
}
|
||||
|
||||
// ==============
|
||||
// = Plugin Url =
|
||||
// ==============
|
||||
if ( ! defined( 'AI1EC_URL' ) ) {
|
||||
define( 'AI1EC_URL', $ai1ec_base_url );
|
||||
}
|
||||
// ===============
|
||||
// = VENDOR PATH =
|
||||
// ===============
|
||||
if ( ! defined( 'AI1EC_VENDOR_PATH' ) ) {
|
||||
define(
|
||||
'AI1EC_VENDOR_PATH',
|
||||
AI1EC_PATH . DIRECTORY_SEPARATOR . 'vendor' .
|
||||
DIRECTORY_SEPARATOR
|
||||
);
|
||||
}
|
||||
|
||||
// ===============
|
||||
// = ADMIN PATH =
|
||||
// ===============
|
||||
if ( ! defined( 'AI1EC_ADMIN_PATH' ) ) {
|
||||
define(
|
||||
'AI1EC_ADMIN_PATH',
|
||||
AI1EC_PATH . DIRECTORY_SEPARATOR . 'public' .
|
||||
DIRECTORY_SEPARATOR . 'admin' . DIRECTORY_SEPARATOR
|
||||
);
|
||||
}
|
||||
|
||||
// ===============
|
||||
// = ADMIN URL =
|
||||
// ===============
|
||||
if ( ! defined( 'AI1EC_ADMIN_URL' ) ) {
|
||||
define(
|
||||
'AI1EC_ADMIN_URL',
|
||||
AI1EC_URL . '/public/admin/'
|
||||
);
|
||||
}
|
||||
|
||||
// ==============
|
||||
// = CACHE PATH =
|
||||
// ==============
|
||||
if ( ! defined( 'AI1EC_CACHE_PATH' ) ) {
|
||||
define(
|
||||
'AI1EC_CACHE_PATH',
|
||||
AI1EC_PATH . DIRECTORY_SEPARATOR . 'cache' .
|
||||
DIRECTORY_SEPARATOR
|
||||
);
|
||||
}
|
||||
|
||||
// ==============
|
||||
// = CACHE URL =
|
||||
// ==============
|
||||
if ( ! defined( 'AI1EC_CACHE_URL' ) ) {
|
||||
define(
|
||||
'AI1EC_CACHE_URL',
|
||||
AI1EC_URL . '/cache/'
|
||||
);
|
||||
}
|
||||
|
||||
// ==============
|
||||
// = TWIG CACHE PATH =
|
||||
// ==============
|
||||
if ( ! defined( 'AI1EC_TWIG_CACHE_PATH' ) ) {
|
||||
define(
|
||||
'AI1EC_TWIG_CACHE_PATH',
|
||||
AI1EC_CACHE_PATH . 'twig' .
|
||||
DIRECTORY_SEPARATOR
|
||||
);
|
||||
}
|
||||
|
||||
// ======================
|
||||
// = Default theme name =
|
||||
// ======================
|
||||
if ( ! defined( 'AI1EC_DEFAULT_THEME_NAME' ) ) {
|
||||
define( 'AI1EC_DEFAULT_THEME_NAME', 'vortex' );
|
||||
}
|
||||
// ================
|
||||
// = THEME FOLDER =
|
||||
// ================
|
||||
if ( ! defined( 'AI1EC_THEME_FOLDER' ) ) {
|
||||
define( 'AI1EC_THEME_FOLDER', 'themes-ai1ec' );
|
||||
}
|
||||
|
||||
// =======================
|
||||
// = DEFAULT THEME PATH =
|
||||
// =======================
|
||||
if ( ! defined( 'AI1EC_DEFAULT_THEME_ROOT' ) ) {
|
||||
define(
|
||||
'AI1EC_DEFAULT_THEME_ROOT',
|
||||
AI1EC_PATH . DIRECTORY_SEPARATOR . 'public' .
|
||||
DIRECTORY_SEPARATOR . AI1EC_THEME_FOLDER
|
||||
);
|
||||
}
|
||||
|
||||
// =======================
|
||||
// = DEFAULT THEME PATH =
|
||||
// =======================
|
||||
if ( ! defined( 'AI1EC_DEFAULT_THEME_PATH' ) ) {
|
||||
define(
|
||||
'AI1EC_DEFAULT_THEME_PATH',
|
||||
AI1EC_DEFAULT_THEME_ROOT . DIRECTORY_SEPARATOR .
|
||||
AI1EC_DEFAULT_THEME_NAME
|
||||
);
|
||||
}
|
||||
|
||||
// ===================
|
||||
// = AI1EC Theme URL =
|
||||
// ===================
|
||||
if ( ! defined( 'AI1EC_THEMES_URL' ) ) {
|
||||
define(
|
||||
'AI1EC_THEMES_URL',
|
||||
AI1EC_URL . '/public/' . AI1EC_THEME_FOLDER
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// =====================
|
||||
// = AI1EC Core themes =
|
||||
// =====================
|
||||
if ( ! defined( 'AI1EC_CORE_THEMES' ) ) {
|
||||
define( 'AI1EC_CORE_THEMES', 'vortex,umbra,gamma,plana' );
|
||||
}
|
||||
|
||||
// ===================
|
||||
// = AI1EC Theme URL =
|
||||
// ===================
|
||||
if ( ! defined( 'AI1EC_THEMES_URL' ) ) {
|
||||
define( 'AI1EC_THEMES_URL', AI1EC_URL . '/public/' . AI1EC_THEME_FOLDER . '/' );
|
||||
}
|
||||
|
||||
// =================
|
||||
// = Admin CSS URL =
|
||||
// =================
|
||||
if ( ! defined( 'AI1EC_ADMIN_THEME_CSS_URL' ) ) {
|
||||
define( 'AI1EC_ADMIN_THEME_CSS_URL', AI1EC_URL .'/public/admin/css/' );
|
||||
}
|
||||
|
||||
// =================
|
||||
// = Admin Font URL =
|
||||
// =================
|
||||
if ( ! defined( 'AI1EC_ADMIN_THEME_FONT_URL' ) ) {
|
||||
define( 'AI1EC_ADMIN_THEME_FONT_URL', AI1EC_URL .'/public/admin/font/' );
|
||||
}
|
||||
|
||||
// =================
|
||||
// = Admin Js URL =
|
||||
// =================
|
||||
if ( ! defined( 'AI1EC_ADMIN_THEME_JS_URL' ) ) {
|
||||
define( 'AI1EC_ADMIN_THEME_JS_URL', AI1EC_URL .'/public/js/' );
|
||||
}
|
||||
|
||||
// =============
|
||||
// = POST TYPE =
|
||||
// =============
|
||||
if ( ! defined( 'AI1EC_POST_TYPE' ) ) {
|
||||
define( 'AI1EC_POST_TYPE', 'ai1ec_event' );
|
||||
}
|
||||
|
||||
// ==============
|
||||
// = SCRIPT URL =
|
||||
// ==============
|
||||
if ( ! defined( 'AI1EC_SCRIPT_URL' ) ) {
|
||||
define(
|
||||
'AI1EC_SCRIPT_URL',
|
||||
get_option( 'home' ) . '/?plugin=' . AI1EC_PLUGIN_NAME
|
||||
);
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// = BASE URL FOR ALL CALENDAR ADMIN PAGES =
|
||||
// =========================================
|
||||
if ( ! defined( 'AI1EC_ADMIN_BASE_URL' ) ) {
|
||||
define( 'AI1EC_ADMIN_BASE_URL', 'edit.php?post_type=' . AI1EC_POST_TYPE );
|
||||
}
|
||||
|
||||
|
||||
// =====================================================
|
||||
// = THEME OPTIONS PAGE BASE URL (wrap in admin_url()) =
|
||||
// =====================================================
|
||||
if ( ! defined( 'AI1EC_THEME_OPTIONS_BASE_URL' ) ) {
|
||||
define( 'AI1EC_THEME_OPTIONS_BASE_URL', AI1EC_ADMIN_BASE_URL . '&page=' . AI1EC_PLUGIN_NAME . '-edit-css' );
|
||||
}
|
||||
|
||||
// =======================================================
|
||||
// = THEME SELECTION PAGE BASE URL (wrap in admin_url()) =
|
||||
// =======================================================
|
||||
if ( ! defined( 'AI1EC_THEME_SELECTION_BASE_URL' ) ) {
|
||||
define(
|
||||
'AI1EC_THEME_SELECTION_BASE_URL',
|
||||
AI1EC_ADMIN_BASE_URL . '&page=' . AI1EC_PLUGIN_NAME . '-themes'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// =====================================================
|
||||
// = FEED SETTINGS PAGE BASE URL (wrap in admin_url()) =
|
||||
// =====================================================
|
||||
if ( ! defined( 'AI1EC_FEED_SETTINGS_BASE_URL' ) ) {
|
||||
define( 'AI1EC_FEED_SETTINGS_BASE_URL', AI1EC_ADMIN_BASE_URL . '&page=' . AI1EC_PLUGIN_NAME . '-feeds' );
|
||||
}
|
||||
|
||||
// ================================================
|
||||
// = SETTINGS PAGE BASE URL (wrap in admin_url()) =
|
||||
// ================================================
|
||||
if ( ! defined( 'AI1EC_SETTINGS_BASE_URL' ) ) {
|
||||
define(
|
||||
'AI1EC_SETTINGS_BASE_URL',
|
||||
AI1EC_ADMIN_BASE_URL . '&page=' . AI1EC_PLUGIN_NAME . '-settings'
|
||||
);
|
||||
}
|
||||
|
||||
// ==============
|
||||
// = EXPORT URL =
|
||||
// ==============
|
||||
if ( ! defined( 'AI1EC_EXPORT_URL' ) ) {
|
||||
// ====================================================
|
||||
// = Convert http:// to webcal:// in AI1EC_SCRIPT_URL =
|
||||
// = (webcal:// protocol does not support https://) =
|
||||
// ====================================================
|
||||
$webcal_url = preg_replace( '/^https?:\/\//', 'webcal://', AI1EC_SCRIPT_URL );
|
||||
define(
|
||||
'AI1EC_EXPORT_URL',
|
||||
$webcal_url . '&controller=ai1ec_exporter_controller' .
|
||||
'&action=export_events'
|
||||
);
|
||||
unset( $webcal_url );
|
||||
}
|
||||
|
||||
if ( ! defined( 'AI1EC_CA_ROOT_PEM' ) ) {
|
||||
define(
|
||||
'AI1EC_CA_ROOT_PEM',
|
||||
AI1EC_PATH . DIRECTORY_SEPARATOR . 'ca_cert' .
|
||||
DIRECTORY_SEPARATOR . 'ca_cert.pem'
|
||||
);
|
||||
}
|
||||
|
||||
// ====================
|
||||
// = SPECIAL SETTINGS =
|
||||
// ====================
|
||||
|
||||
// Set AI1EC_EVENT_PLATFORM to TRUE to turn WordPress into an events-only
|
||||
// platform. For a multi-site install, setting this to TRUE is equivalent to a
|
||||
// super-administrator selecting the
|
||||
// "Turn this blog into an events-only platform" checkbox
|
||||
// on the Calendar Settings page of every blog on the network.
|
||||
// This mode, when enabled on blogs where this plugin is active, hides all
|
||||
// administrative functions unrelated to events and the calendar (except to
|
||||
// super-administrators), and sets default WordPress settings appropriate for
|
||||
// pure event management.
|
||||
if ( ! defined( 'AI1EC_EVENT_PLATFORM' ) ) {
|
||||
define( 'AI1EC_EVENT_PLATFORM', false );
|
||||
}
|
||||
|
||||
// If i choose to use the calendar url as the base for events permalinks,
|
||||
// i must specify another name for the events archive.
|
||||
if ( ! defined( 'AI1EC_ALTERNATIVE_ARCHIVE_URL' ) ) {
|
||||
define( 'AI1EC_ALTERNATIVE_ARCHIVE_URL', 'ai1ec_events_archive' );
|
||||
}
|
||||
|
||||
// ===================
|
||||
// = AI1EC Theme URL =
|
||||
// ===================
|
||||
if ( ! defined( 'AI1EC_THEMES_URL_LEGACY' ) ) {
|
||||
define( 'AI1EC_THEMES_URL_LEGACY', WP_CONTENT_URL . '/' . AI1EC_THEME_FOLDER );
|
||||
}
|
||||
|
||||
// =====================
|
||||
// = Default theme url legacy=
|
||||
// =====================
|
||||
if ( ! defined( 'AI1EC_DEFAULT_THEME_URL_LEGACY' ) ) {
|
||||
define( 'AI1EC_DEFAULT_THEME_URL_LEGACY', AI1EC_THEMES_URL . '/' . AI1EC_DEFAULT_THEME_NAME . '/' );
|
||||
}
|
||||
|
||||
// =====================
|
||||
// = Default theme url =
|
||||
// =====================
|
||||
if ( ! defined( 'AI1EC_DEFAULT_THEME_URL' ) ) {
|
||||
define( 'AI1EC_DEFAULT_THEME_URL', AI1EC_THEMES_URL . '/' . AI1EC_DEFAULT_THEME_NAME . '/' );
|
||||
}
|
||||
|
||||
// ===================
|
||||
// = CSS Folder name =
|
||||
// ===================
|
||||
if ( ! defined( 'AI1EC_CSS_FOLDER' ) ) {
|
||||
define( 'AI1EC_CSS_FOLDER', 'css' );
|
||||
}
|
||||
|
||||
// ==================
|
||||
// = JS Folder name =
|
||||
// ==================
|
||||
if ( ! defined( 'AI1EC_JS_FOLDER' ) ) {
|
||||
define( 'AI1EC_JS_FOLDER', 'js' );
|
||||
}
|
||||
|
||||
// =====================
|
||||
// = Image folder name =
|
||||
// =====================
|
||||
if ( ! defined( 'AI1EC_IMG_FOLDER' ) ) {
|
||||
define( 'AI1EC_IMG_FOLDER', 'img' );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ========================
|
||||
// = Admin theme CSS path =
|
||||
// ========================
|
||||
if ( ! defined( 'AI1EC_ADMIN_THEME_CSS_PATH' ) ) {
|
||||
define( 'AI1EC_ADMIN_THEME_CSS_PATH', AI1EC_ADMIN_PATH . AI1EC_CSS_FOLDER );
|
||||
}
|
||||
|
||||
// =======================
|
||||
// = Admin theme JS path =
|
||||
// =======================
|
||||
if ( ! defined( 'AI1EC_ADMIN_THEME_JS_PATH' ) ) {
|
||||
define( 'AI1EC_ADMIN_THEME_JS_PATH', AI1EC_PATH . DIRECTORY_SEPARATOR . 'public' .
|
||||
DIRECTORY_SEPARATOR . AI1EC_JS_FOLDER );
|
||||
}
|
||||
|
||||
// =================
|
||||
// = Admin IMG URL =
|
||||
// =================
|
||||
if ( ! defined( 'AI1EC_ADMIN_THEME_IMG_URL' ) ) {
|
||||
define( 'AI1EC_ADMIN_THEME_IMG_URL', AI1EC_URL . '/public/admin/' . AI1EC_IMG_FOLDER );
|
||||
}
|
||||
|
||||
// ====================
|
||||
// = Add-ons list URL =
|
||||
// ====================
|
||||
if ( ! defined( 'AI1EC_TIMELY_ADDONS_URI' ) ) {
|
||||
define( 'AI1EC_TIMELY_ADDONS_URI', 'https://time.ly/?action=addons_list' );
|
||||
}
|
||||
|
||||
// Enable All-in-One-Event-Calendar to work in debug mode, which means,
|
||||
// that cache is ignored, extra output may appear at places, etc.
|
||||
// Do not set this to any other value than `false` on production even if
|
||||
// you know what you are doing, because you will waste valuable
|
||||
// resources - save the Earth, at least.
|
||||
if ( ! defined( 'AI1EC_DEBUG' ) ) {
|
||||
define( 'AI1EC_DEBUG', false );
|
||||
}
|
||||
|
||||
// Enable Ai1EC cache functionality. If you set this to false, only cache
|
||||
// that is based on request, will remain active.
|
||||
// This is pointless in any case other than development, where literary
|
||||
// every second refresh needs to take fresh copy of everything.
|
||||
if ( ! defined( 'AI1EC_CACHE' ) ) {
|
||||
define( 'AI1EC_CACHE', true );
|
||||
}
|
||||
|
||||
if ( ! defined( 'AI1EC_DISABLE_FILE_CACHE' ) ) {
|
||||
define( 'AI1EC_DISABLE_FILE_CACHE', false );
|
||||
}
|
||||
|
||||
// A value identifying that cache is not available.
|
||||
// Used in place of actual path for cache to use.
|
||||
// Named constant allows reuse of a single typed variable.
|
||||
if ( ! defined( 'AI1EC_CACHE_UNAVAILABLE' ) ) {
|
||||
define( 'AI1EC_CACHE_UNAVAILABLE', 'AI1EC_CACHE_UNAVAILABLE' );
|
||||
}
|
||||
|
||||
// Defines if backward (<= 2.1.5) theme compatibility is enabled or not.
|
||||
if ( ! defined( 'AI1EC_THEME_COMPATIBILITY_FER' ) ) {
|
||||
define( 'AI1EC_THEME_COMPATIBILITY_FER', true );
|
||||
}
|
||||
|
||||
// Defines amount of needed free memory to compile LESS files.
|
||||
if ( ! defined( 'AI1EC_LESS_MIN_AVAIL_MEMORY' ) ) {
|
||||
define( 'AI1EC_LESS_MIN_AVAIL_MEMORY', '24M' );
|
||||
}
|
||||
|
||||
// Defines if LESS files are parsed at every request
|
||||
if ( ! defined( 'AI1EC_PARSE_LESS_FILES_AT_EVERY_REQUEST' ) ) {
|
||||
define( 'AI1EC_PARSE_LESS_FILES_AT_EVERY_REQUEST', false );
|
||||
}
|
||||
|
||||
// Defines a list of FER-enabled templates.
|
||||
if ( ! defined( 'AI1EC_FER_ENABLED_TEMPLATES_LIST' ) ) {
|
||||
define(
|
||||
'AI1EC_FER_ENABLED_TEMPLATES_LIST',
|
||||
'agenda,oneday,week,month,posterboard,stream'
|
||||
);
|
||||
}
|
||||
|
||||
// Defines API URL.
|
||||
if ( ! defined( 'AI1EC_API_URL' ) ) {
|
||||
define(
|
||||
'AI1EC_API_URL',
|
||||
'https://api.time.ly/api/'
|
||||
);
|
||||
}
|
||||
|
||||
// Defines Tickets checkout URL.
|
||||
if ( ! defined( 'AI1EC_TICKETS_CHECKOUT_URL' ) ) {
|
||||
define(
|
||||
'AI1EC_TICKETS_CHECKOUT_URL',
|
||||
'https://api.time.ly/events/{event_id}/checkout'
|
||||
);
|
||||
}
|
||||
|
||||
// ================================================
|
||||
// = Force WordPress updates command link =
|
||||
// ================================================
|
||||
if ( ! defined( 'AI1EC_FORCE_UPDATES_URL' ) ) {
|
||||
define(
|
||||
'AI1EC_FORCE_UPDATES_URL',
|
||||
AI1EC_ADMIN_BASE_URL . '&ai1ec_force_updates=true'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* This exception is thrown when no constant function is found.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Config
|
||||
*/
|
||||
class Ai1ec_Constants_Not_Set_Exception extends Ai1ec_Exception {
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Feeds (import and export streams) mediator.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Controller
|
||||
*/
|
||||
class Ai1ec_Controller_Calendar_Feeds extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* @var array Holds the instances of registered plugins.
|
||||
*/
|
||||
protected $_plugins = array();
|
||||
|
||||
/**
|
||||
* Add plugin to the internal array.
|
||||
*
|
||||
* This assure us that the plugins extends our base abstract class.
|
||||
*
|
||||
* @param Ai1ec_Connector_Plugin $plugin Plugin to add.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_plugin( Ai1ec_Connector_Plugin $plugin ) {
|
||||
$plugin->initialize_settings_if_not_set();
|
||||
$this->_plugins[] = $plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of a plugin class
|
||||
*
|
||||
* @param string $class
|
||||
* @throws Exception
|
||||
* @return Ai1ec_Connector_Plugin
|
||||
*/
|
||||
public function get_plugin_instance( $class ) {
|
||||
foreach ( $this->_plugins as $plugin ) {
|
||||
if( get_class( $plugin ) === $class ) {
|
||||
return $plugin;
|
||||
}
|
||||
}
|
||||
throw new Exception( "Class not found" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the plugins the possibility to handle data posted in the calendar feeds page
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle_feeds_page_post() {
|
||||
// Iterate over the plugins and call the methods
|
||||
foreach ( $this->_plugins as $plugin ) {
|
||||
$plugin->handle_feeds_page_post();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the tab header for each plugin
|
||||
*
|
||||
* @param $active_feed
|
||||
* The tab that should be visualized
|
||||
*/
|
||||
public function render_tab_headers() {
|
||||
foreach ( $this->_plugins as $plugin ) {
|
||||
$plugin->render_tab_header();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Render the tab body for each plugin
|
||||
*
|
||||
* @param $active_feed
|
||||
* The tab that should be visualized
|
||||
*/
|
||||
public function render_tab_contents() {
|
||||
foreach ( $this->_plugins as $plugin ) {
|
||||
$plugin->render_tab_content();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles strict_compatibility_content_filtering.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.1
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Controller
|
||||
*/
|
||||
class Ai1ec_Controller_Content_Filter extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Content filters lib.
|
||||
* @var Ai1ec_Content_Filters
|
||||
*/
|
||||
protected $_content_filter;
|
||||
|
||||
/**
|
||||
* Setting _strict_compatibility_content_filtering.
|
||||
* @var bool
|
||||
*/
|
||||
protected $_strict_compatibility_content_filtering;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry Registry object.
|
||||
*
|
||||
* @return void Method does not return.
|
||||
*/
|
||||
public function __construct( Ai1ec_Registry_Object $registry ) {
|
||||
parent::__construct( $registry );
|
||||
$this->_content_filter = $registry->get( 'content.filter' );
|
||||
$this->_strict_compatibility_content_filtering =
|
||||
$registry->get( 'model.settings' )
|
||||
->get( 'strict_compatibility_content_filtering' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all the_content filters excluding few defaults.
|
||||
*
|
||||
* @return void Method does not return.
|
||||
*/
|
||||
public function clear_the_content_filters() {
|
||||
if ( $this->_strict_compatibility_content_filtering ) {
|
||||
$this->_content_filter->clear_the_content_filters();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the_content filters.
|
||||
*
|
||||
* @return void Method does not return.
|
||||
*/
|
||||
public function restore_the_content_filters() {
|
||||
if ( $this->_strict_compatibility_content_filtering ) {
|
||||
$this->_content_filter->restore_the_content_filters();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The exception thrown when an engine is not set..
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Controller.Exception
|
||||
*/
|
||||
class Ai1ec_Engine_Not_Set_Exception extends Ai1ec_Exception {
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The exception thrown when an engine is not set..
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Controller.Exception
|
||||
*/
|
||||
class Ai1ec_File_Not_Found_Exception extends Ai1ec_Exception {
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Abstract class for extensions which are sold.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Controller
|
||||
*/
|
||||
abstract class Ai1ec_Base_License_Controller extends Ai1ec_Base_Extension_Controller {
|
||||
|
||||
/**
|
||||
* @var string Settings entry name for license key.
|
||||
*/
|
||||
protected $_licence;
|
||||
|
||||
/**
|
||||
* @var string Settings entry name for license status output.
|
||||
*/
|
||||
protected $_licence_status;
|
||||
|
||||
/**
|
||||
* @var string Licensing API endpoint URI.
|
||||
*/
|
||||
protected $_store = 'https://time.ly/';
|
||||
|
||||
/**
|
||||
* Get label to be used for license input field.
|
||||
*
|
||||
* @return string Localized label field.
|
||||
*/
|
||||
abstract public function get_license_label();
|
||||
|
||||
/**
|
||||
* @param Ai1ec_Registry_Object $registry
|
||||
*/
|
||||
public function initialize_licence_actions() {
|
||||
$this->_register_licence_actions();
|
||||
$this->_register_licence_fields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the extension tab if not present
|
||||
*
|
||||
* @param array $tabs
|
||||
* @return array
|
||||
*/
|
||||
public function add_tabs( array $tabs ) {
|
||||
if ( ! isset( $tabs['extensions'] ) ) {
|
||||
$tabs['extensions'] = array(
|
||||
'name' => Ai1ec_I18n::__( 'Add-ons' ),
|
||||
'items' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register action for licences.
|
||||
*/
|
||||
protected function _register_licence_actions() {
|
||||
$dispatcher = $this->_registry->get( 'event.dispatcher' );
|
||||
// we need the super class so we use get_class()
|
||||
$class = explode( '_', get_class( $this ) );
|
||||
$controller = strtolower( end( $class ) );
|
||||
$dispatcher->register_filter(
|
||||
'ai1ec_add_setting_tabs',
|
||||
array( 'controller.' . $controller, 'add_tabs' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register fields for licence
|
||||
*/
|
||||
protected function _register_licence_fields() {
|
||||
$plugin_id = $this->get_machine_name();
|
||||
$this->_licence = 'ai1ec_licence_' . $plugin_id;
|
||||
$this->_licence_status = 'ai1ec_licence_status_' . $plugin_id;
|
||||
$options = array(
|
||||
$this->_licence => array(
|
||||
'type' => 'string',
|
||||
'version' => $this->get_version(),
|
||||
'renderer' => array(
|
||||
'class' => 'input',
|
||||
'group-class' => 'ai1ec-col-sm-7',
|
||||
'tab' => 'extensions',
|
||||
'item' => 'licenses',
|
||||
'type' => 'normal',
|
||||
'label' => $this->get_license_label(),
|
||||
'status' => $this->_licence_status,
|
||||
),
|
||||
'default' => '',
|
||||
),
|
||||
$this->_licence_status => array(
|
||||
'type' => 'string',
|
||||
'version' => $this->get_version(),
|
||||
'default' => 'invalid',
|
||||
),
|
||||
);
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
foreach ( $options as $key => $option ) {
|
||||
$renderer = null;
|
||||
if ( isset( $option['renderer'] ) ) {
|
||||
$renderer = $option['renderer'];
|
||||
}
|
||||
$settings->register(
|
||||
$key,
|
||||
$option['default'],
|
||||
$option['type'],
|
||||
$renderer,
|
||||
$option['version']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,291 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Basic extension controller.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Controller
|
||||
*/
|
||||
abstract class Ai1ec_Base_Extension_Controller {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Registry_Object
|
||||
*/
|
||||
protected $_registry;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $_settings;
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Registry_Object
|
||||
*/
|
||||
protected static $_registry_static;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $_settings_static;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $_schema;
|
||||
|
||||
/**
|
||||
* Get the long name of the extension
|
||||
*/
|
||||
abstract public function get_name();
|
||||
|
||||
/**
|
||||
* Get the machine name of the extension
|
||||
*/
|
||||
abstract public function get_machine_name();
|
||||
|
||||
/**
|
||||
* Get the version of the extension
|
||||
*/
|
||||
abstract public function get_version();
|
||||
|
||||
/**
|
||||
* Get the name of the main plugin file
|
||||
*/
|
||||
abstract public function get_file();
|
||||
|
||||
/**
|
||||
* Add extension specific settings
|
||||
*/
|
||||
abstract protected function _get_settings();
|
||||
|
||||
/**
|
||||
* Register action/filters/shortcodes for the extension
|
||||
*
|
||||
* @param Ai1ec_Event_Dispatcher $dispatcher
|
||||
*/
|
||||
abstract protected function _register_actions(
|
||||
Ai1ec_Event_Dispatcher $dispatcher
|
||||
);
|
||||
|
||||
/**
|
||||
* Perform the basic compatibility check.
|
||||
*
|
||||
* @param string $ai1ec_version
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function check_compatibility( $ai1ec_version ) {
|
||||
return version_compare(
|
||||
$ai1ec_version,
|
||||
$this->minimum_core_required(),
|
||||
'>='
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function minimum_core_required() {
|
||||
return '2.0.7';
|
||||
}
|
||||
/**
|
||||
* Removes options when uninstalling the plugin.
|
||||
*/
|
||||
public static function on_uninstall() {
|
||||
global $wpdb;
|
||||
if ( ! current_user_can( 'activate_plugins' ) ) {
|
||||
return;
|
||||
}
|
||||
$settings = self::$_registry_static->get( 'model.settings' );
|
||||
foreach ( self::$_settings_static as $name => $params ) {
|
||||
$settings->remove_option( $name );
|
||||
}
|
||||
$schema = self::$_schema;
|
||||
foreach ( $schema['tables'] as $table_name ) {
|
||||
// Delete table events
|
||||
$wpdb->query( 'DROP TABLE IF EXISTS ' . $table_name );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
global $wpdb;
|
||||
self::$_schema = $this->_get_schema( $wpdb->prefix );
|
||||
$settings = $this->_get_settings();
|
||||
$this->_settings = $settings;
|
||||
self::$_settings_static = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize the extension.
|
||||
*/
|
||||
public function init( Ai1ec_Registry_Object $registry ) {
|
||||
$this->_registry = $registry;
|
||||
// static properties are needed as uninstall hook must be static
|
||||
// http://wpseek.com/register_uninstall_hook/
|
||||
self::$_registry_static = $registry;
|
||||
register_deactivation_hook(
|
||||
$this->get_file(),
|
||||
array( $this, 'on_deactivation' )
|
||||
);
|
||||
|
||||
$this->_install_schema( $registry );
|
||||
$this->_register_actions( $registry->get( 'event.dispatcher' ) );
|
||||
$this->_add_settings( $registry->get( 'model.settings' ) );
|
||||
$this->_perform_upgrade( $registry );
|
||||
if ( method_exists( $this, 'initialize_licence_actions' ) ) {
|
||||
$this->initialize_licence_actions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides settings on deactivation.
|
||||
*/
|
||||
public function on_deactivation() {
|
||||
if ( ! current_user_can( 'activate_plugins' ) ) {
|
||||
return;
|
||||
}
|
||||
$plugin = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : '';
|
||||
$referer = 'deactivate-plugin_' . $plugin;
|
||||
// if we are disabling the plugin in the exception handler, this can't be done.
|
||||
// but i want to disable options
|
||||
if ( function_exists( '_get_list_table' ) ) {
|
||||
$wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
|
||||
$action = $wp_list_table->current_action();
|
||||
if ( 'deactivate-selected' === $action ) {
|
||||
$referer = 'bulk-plugins';
|
||||
}
|
||||
check_admin_referer( $referer );
|
||||
}
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
foreach ( $this->_settings as $name => $params ) {
|
||||
$settings->hide_option( $name );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the settings
|
||||
*/
|
||||
public function show_settings( Ai1ec_Registry_Object $registry ) {
|
||||
$settings = $registry->get( 'model.settings' );
|
||||
foreach ( $this->_settings as $name => $params ) {
|
||||
if ( isset( $params['renderer'] ) ) {
|
||||
$settings->show_option( $name, $params['renderer'] );
|
||||
}
|
||||
}
|
||||
$settings->set( 'allow_statistics', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* If extensions need to add tables, they will need to override the function to add a schema.
|
||||
*
|
||||
* @param string $prefix Database prefix to use for table names.
|
||||
*
|
||||
* @return array An array with two keys, schema and tables which are used
|
||||
* for installing and dropping the table.
|
||||
*/
|
||||
protected static function _get_schema( $prefix ) {
|
||||
return array(
|
||||
'tables' => array(),
|
||||
'schema' => '',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performe upgarde actions based on extension version
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry
|
||||
*/
|
||||
protected function _perform_upgrade( Ai1ec_Registry_Object $registry ) {
|
||||
$version_variable = 'ai1ec_' . $this->get_machine_name() .
|
||||
'_version';
|
||||
$option = $registry->get( 'model.option' );
|
||||
$version = $option->get( $version_variable );
|
||||
if ( $version !== $this->get_version() ) {
|
||||
$registry->get( 'model.settings' )->perform_upgrade_actions();
|
||||
$this->_perform_upgrade_actions();
|
||||
$option->set( $version_variable, $this->get_version(), true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called on add on upgrade.
|
||||
* Can be overridden by add ons for extra behaviour
|
||||
*/
|
||||
protected function _perform_upgrade_actions() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Since the call the to the uninstall hook it's static, if a different behaviour
|
||||
* is needed also this call must be overridden.
|
||||
*/
|
||||
protected function _register_uninstall_hook() {
|
||||
register_uninstall_hook(
|
||||
$this->get_file(),
|
||||
array( get_class( $this ), 'on_uninstall' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds extension settings
|
||||
*
|
||||
* @param Ai1ec_Settings $settings
|
||||
*/
|
||||
protected function _add_settings( Ai1ec_Settings $settings ) {
|
||||
foreach ( $this->_settings as $name => $params ) {
|
||||
$renderer = null;
|
||||
if ( isset( $params['renderer'] ) ) {
|
||||
$renderer = $params['renderer'];
|
||||
}
|
||||
$settings->register(
|
||||
$name,
|
||||
$params['value'],
|
||||
$params['type'],
|
||||
$renderer,
|
||||
$this->get_version()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the schema needs to be updated
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry
|
||||
* @throws Ai1ec_Database_Update_Exception
|
||||
*/
|
||||
protected function _install_schema( Ai1ec_Registry_Object $registry ) {
|
||||
$option = $registry->get( 'model.option' );
|
||||
$schema = self::$_schema;
|
||||
if (
|
||||
is_admin() &&
|
||||
! empty( $schema['schema'] )
|
||||
) {
|
||||
$db_version_variable = 'ai1ec_' . $this->get_machine_name() .
|
||||
'_db_version';
|
||||
$version = sha1( $schema['schema'] );
|
||||
if (
|
||||
$option->get( $db_version_variable ) !== $version
|
||||
) {
|
||||
if (
|
||||
$registry->get( 'database.helper' )->apply_delta(
|
||||
$schema['schema']
|
||||
)
|
||||
) {
|
||||
$option->set( $db_version_variable, $version );
|
||||
} else {
|
||||
throw new Ai1ec_Database_Update_Exception(
|
||||
'Database upgrade for ' . $this->get_name() .
|
||||
' failed'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,112 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The controller which handles import/export.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Controller
|
||||
*/
|
||||
class Ai1ec_Import_Export_Controller {
|
||||
|
||||
/**
|
||||
* @var array The registered engines.
|
||||
*/
|
||||
protected $_engines = array();
|
||||
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Registry_Object
|
||||
*/
|
||||
protected $_registry;
|
||||
|
||||
/**
|
||||
* @var array Import / export params.
|
||||
*/
|
||||
protected $_params;
|
||||
|
||||
/**
|
||||
* This controller is instanciated only if we need to import/export something.
|
||||
*
|
||||
* When it is instanciated it allows other engines to be injected through a
|
||||
* filter. If we do not plan to ship core engines, let's skip the
|
||||
* $core_engines param.
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry
|
||||
* @param array $core_engines
|
||||
* @param array $params
|
||||
*/
|
||||
public function __construct(
|
||||
Ai1ec_Registry_Object $registry,
|
||||
array $core_engines = array( 'ics', 'api-ics' ),
|
||||
array $params = array()
|
||||
) {
|
||||
$this->_registry = $registry;
|
||||
$known_engines = apply_filters(
|
||||
'ai1ec_register_import_export_engines',
|
||||
$core_engines
|
||||
);
|
||||
$this->_params = $params;
|
||||
foreach ( $known_engines as $engine ) {
|
||||
$this->register( $engine );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an import-export engine.
|
||||
*
|
||||
* @param string $engine
|
||||
*/
|
||||
public function register( $engine ) {
|
||||
$this->_engines[$engine] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import events into the calendar.
|
||||
*
|
||||
* @param string $engine
|
||||
* @param array $args
|
||||
*
|
||||
* @throws Ai1ec_Engine_Not_Set_Exception If the engine is not set.
|
||||
* @throws Ai1ec_Parse_Exception If an error happens during parse.
|
||||
*
|
||||
* @return int The number of imported events
|
||||
*/
|
||||
public function import_events( $engine, array $args ) {
|
||||
if ( ! isset( $this->_engines[$engine] ) ) {
|
||||
throw new Ai1ec_Engine_Not_Set_Exception(
|
||||
'The engine ' . $engine . 'is not registered.'
|
||||
);
|
||||
}
|
||||
// external engines must register themselves into the registry.
|
||||
$engine = $this->_registry->get( 'import-export.' . $engine );
|
||||
$exception = null;
|
||||
try {
|
||||
return $engine->import( $args );
|
||||
} catch ( Ai1ec_Parse_Exception $parse_exception ) {
|
||||
$exception = $parse_exception;
|
||||
}
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the events using the specified engine.
|
||||
*
|
||||
* @param string $engine
|
||||
* @param array $args
|
||||
*
|
||||
* @throws Ai1ec_Engine_Not_Set_Exception
|
||||
*/
|
||||
public function export_events( $engine, array $args ) {
|
||||
if ( ! isset( $this->_engines[$engine] ) ) {
|
||||
throw new Ai1ec_Engine_Not_Set_Exception(
|
||||
'The engine ' . $engine . 'is not registered.'
|
||||
);
|
||||
}
|
||||
// external engines must register themselves into the registry.
|
||||
$engine = $this->_registry->get( 'import-export.' . $engine );
|
||||
return $engine->export( $args, $this->_params );
|
||||
}
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles Super Widget.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Javascript
|
||||
*/
|
||||
class Ai1ec_Controller_Javascript_Widget extends Ai1ec_Base {
|
||||
|
||||
const WIDGET_PARAMETER = 'ai1ec_js_widget';
|
||||
const LEGACY_WIDGET_PARAMETER = 'ai1ec_super_widget';
|
||||
const WIDGET_JS_CACHE_FILE = '/public/js_cache/ai1ec_js_widget.js';
|
||||
|
||||
protected $_widgets = array();
|
||||
|
||||
|
||||
public function add_widget( $widget_id, $widget_class ) {
|
||||
$this->_widgets[$widget_id] = $widget_class;
|
||||
}
|
||||
|
||||
public function get_widgets() {
|
||||
return $this->_widgets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds Super Widget JS to admin screen.
|
||||
*
|
||||
* @param array $files
|
||||
* @param string $page_to_load
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_js( array $files, $page_to_load ) {
|
||||
if ( 'admin_settings.js' === $page_to_load ) {
|
||||
$files[] = AI1ECSW_PATH . '/public/js/pages/admin_settings.js';
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function add_js_translation( array $data ) {
|
||||
$data['set_calendar_page'] = __(
|
||||
'You must choose the Calendar page before using the Super Widget',
|
||||
AI1EC_PLUGIN_NAME
|
||||
);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag to revalidate cached js files on next render.
|
||||
*/
|
||||
public function revalidate_cache() {
|
||||
$this->_registry->get( 'model.option' )->set( 'jswidgetupdated', '0' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders everything that's needed for the embedded widget.
|
||||
*/
|
||||
public function render_js_widget() {
|
||||
|
||||
if ( isset( $_GET['render'] ) && 'true' === $_GET['render'] ) {
|
||||
if ( isset( $_GET[self::WIDGET_PARAMETER] ) ){
|
||||
$widget = $_GET[self::WIDGET_PARAMETER];
|
||||
} else if ( isset( $_GET[self::LEGACY_WIDGET_PARAMETER] ) ) {
|
||||
$widget = $_GET[self::LEGACY_WIDGET_PARAMETER];
|
||||
}
|
||||
$widget_class = null;
|
||||
if ( isset( $this->_widgets[$widget] ) ) {
|
||||
$widget_class = $this->_widgets[$widget];
|
||||
}
|
||||
if ( null === $widget_class ) {
|
||||
return;
|
||||
}
|
||||
$widget_instance = $this->_registry->get( $widget_class );
|
||||
$this->render_content( $widget_instance );
|
||||
} else {
|
||||
if (
|
||||
! $this->_registry->get( 'model.settings' )->get( 'cache_dynamic_js' ) ||
|
||||
'1' != $this->_registry->get( 'model.option' )->get( 'jswidgetupdated' ) ||
|
||||
! $this->_registry->get( 'filesystem.checker' )->check_file_exists(
|
||||
AI1EC_PATH . self::WIDGET_JS_CACHE_FILE,
|
||||
true
|
||||
)
|
||||
) {
|
||||
$this->render_javascript();
|
||||
} else {
|
||||
header(
|
||||
'Location: '
|
||||
. plugin_dir_url( 'all-in-one-event-calendar/public/js_cache/.' )
|
||||
. 'ai1ec_js_widget.js'
|
||||
);
|
||||
exit( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function render_javascript() {
|
||||
|
||||
header( 'Content-Type: application/javascript' );
|
||||
header(
|
||||
'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 31536000 ) . ' GMT'
|
||||
);
|
||||
header( 'Cache-Control: public, max-age=31536000' );
|
||||
|
||||
$jscontroller = $this->_registry->get( 'controller.javascript' );
|
||||
$css_controller = $this->_registry->get( 'css.frontend' );
|
||||
$require_main = AI1EC_ADMIN_THEME_JS_PATH . DIRECTORY_SEPARATOR . 'require.js';
|
||||
$widget_file = AI1EC_PATH . '/public/js/widget/common_widget.js';
|
||||
$translation = $jscontroller->get_frontend_translation_data();
|
||||
$page_id = $this->_registry->get(
|
||||
'model.settings'
|
||||
)->get( 'calendar_page_id' );
|
||||
$permalink = get_permalink(
|
||||
$page_id
|
||||
);
|
||||
$full_permalink = $this->_registry->get(
|
||||
'template.link.helper'
|
||||
)->get_full_permalink( $page_id );
|
||||
// load the css to hardcode, saving a call
|
||||
$css_rules = $css_controller->get_compiled_css();
|
||||
$css_rules = addslashes( $css_rules );
|
||||
$translation['permalinks_structure'] = $this->
|
||||
_registry->get( 'model.option' )->get( 'permalink_structure' );
|
||||
$translation['calendar_url'] = preg_replace( '/^https?:/', '', $permalink );
|
||||
$translation['full_calendar_url'] = preg_replace( '/^https?:/', '', $full_permalink );
|
||||
// Let extensions add their scripts.
|
||||
// look at Extended Views or Super Widget for examples
|
||||
$extension_urls = array();
|
||||
$extension_urls = apply_filters(
|
||||
'ai1ec_render_js',
|
||||
$extension_urls,
|
||||
'ai1ec_widget.js'
|
||||
);
|
||||
// Removing http:// or https:// from extension URLs
|
||||
foreach ( $extension_urls as &$extension_url ) {
|
||||
$extension_url = preg_replace( '/https?:/', '', $extension_url );
|
||||
}
|
||||
|
||||
$translation['extension_urls'] = $extension_urls;
|
||||
// the single event page js is loaded dinamically.
|
||||
$translation['event_page'] = array(
|
||||
'id' => 'ai1ec_event',
|
||||
'url' => preg_replace( '/^https?:/', '', AI1EC_URL ) . '/public/js/pages/event.js',
|
||||
);
|
||||
$translation_module = $jscontroller->create_require_js_module(
|
||||
Ai1ec_Javascript_Controller::FRONTEND_CONFIG_MODULE,
|
||||
$translation
|
||||
);
|
||||
// get requirejs
|
||||
$require = file_get_contents( $require_main );
|
||||
$main_widget = file_get_contents( $widget_file );
|
||||
$require_config = $jscontroller->create_require_js_config_object();
|
||||
$config = $jscontroller->create_require_js_module(
|
||||
'ai1ec_config',
|
||||
$jscontroller->get_translation_data()
|
||||
);
|
||||
// get jquery
|
||||
$jquery = $jscontroller->get_jquery_version_based_on_browser(
|
||||
isset( $_SERVER['HTTP_USER_AGENT'] )
|
||||
? $_SERVER['HTTP_USER_AGENT']
|
||||
: ''
|
||||
);
|
||||
|
||||
$domready = $jscontroller->get_module(
|
||||
'domReady.js'
|
||||
);
|
||||
$frontend = $jscontroller->get_module(
|
||||
'scripts/common_scripts/frontend/common_frontend.js'
|
||||
);
|
||||
|
||||
// compress data if possible
|
||||
$compatibility_ob = $this->_registry->get( 'compatibility.ob' );
|
||||
$js = <<<JS
|
||||
/******** Called once Require.js has loaded ******/
|
||||
|
||||
(function() {
|
||||
|
||||
var timely_css = document.createElement( 'style' );
|
||||
timely_css.innerHTML = '$css_rules';
|
||||
( document.getElementsByTagName( "head" )[0] || document.documentElement ).appendChild( timely_css );
|
||||
// bring in requires
|
||||
$require
|
||||
// make timely global
|
||||
window.timely = timely;
|
||||
$require_config
|
||||
// Load other modules
|
||||
$translation_module
|
||||
$config
|
||||
$jquery
|
||||
$frontend
|
||||
|
||||
// start up the widget
|
||||
$main_widget
|
||||
})(); // We call our anonymous function immediately
|
||||
JS;
|
||||
$compatibility_ob->gzip_if_possible( $js );
|
||||
|
||||
if (
|
||||
$this->_registry->get( 'model.settings' )->get( 'cache_dynamic_js' ) &&
|
||||
(
|
||||
'0' === $this->_registry->get( 'model.option' )->get( 'jswidgetupdated' ) ||
|
||||
! $this->_registry->get( 'filesystem.checker' )->check_file_exists(
|
||||
AI1EC_PATH . self::WIDGET_JS_CACHE_FILE,
|
||||
true
|
||||
)
|
||||
)
|
||||
) {
|
||||
try {
|
||||
$js_path = AI1EC_ADMIN_THEME_JS_PATH . DIRECTORY_SEPARATOR;
|
||||
$js_saved = file_put_contents(
|
||||
$js_path . '../js_cache/ai1ec_js_widget.js',
|
||||
$js
|
||||
);
|
||||
if ( $js_saved ) {
|
||||
$this->_registry->get( 'model.option' )->set( 'jswidgetupdated', '1' );
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
$this->_registry->get( 'model.settings' )->set( 'cache_dynamic_js', false );
|
||||
}
|
||||
}
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
public function render_content( Ai1ec_Embeddable $widget_instance ) {
|
||||
$args = array();
|
||||
$defaults = $widget_instance->get_js_widget_configurable_defaults();
|
||||
foreach ( $defaults as $id => $value ) {
|
||||
if ( isset( $_GET[$id] ) ) {
|
||||
$args[$id] = $_GET[$id];
|
||||
}
|
||||
}
|
||||
$html = $widget_instance->javascript_widget( $args );
|
||||
$jsonp = $this->_registry->get( 'http.response.render.strategy.jsonp' );
|
||||
$jsonp->render(
|
||||
array(
|
||||
'data' => array( 'html' => $html )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,917 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Controller that handles javascript related functions.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Controller
|
||||
*/
|
||||
class Ai1ec_Javascript_Controller {
|
||||
|
||||
// The js handle used when enqueueing
|
||||
const JS_HANDLE = 'ai1ec_requirejs';
|
||||
|
||||
// The namespace for require.js functions
|
||||
const REQUIRE_NAMESPACE = 'timely';
|
||||
|
||||
// the name of the configuration module for the frontend
|
||||
const FRONTEND_CONFIG_MODULE = 'ai1ec_calendar';
|
||||
|
||||
//the name of the get parameter we use for loading js
|
||||
const LOAD_JS_PARAMETER = 'ai1ec_render_js';
|
||||
|
||||
// just load backend scripts
|
||||
const LOAD_ONLY_BACKEND_SCRIPTS = 'common_backend';
|
||||
|
||||
// just load backend scripts
|
||||
const LOAD_ONLY_FRONTEND_SCRIPTS = 'common_frontend';
|
||||
|
||||
// Are we in the backend
|
||||
const IS_BACKEND_PARAMETER = 'is_backend';
|
||||
|
||||
// Are we on the calendar page
|
||||
const IS_CALENDAR_PAGE = 'is_calendar_page';
|
||||
|
||||
// this is the value of IS_BACKEND_PARAMETER which triggers loading of backend script
|
||||
const TRUE_PARAM = 'true';
|
||||
|
||||
// the javascript file for event page
|
||||
const EVENT_PAGE_JS = 'event.js';
|
||||
|
||||
// the javascript file for calendar page
|
||||
const CALENDAR_PAGE_JS = 'calendar.js';
|
||||
|
||||
// the file for the calendar feedsa page
|
||||
const CALENDAR_FEEDS_PAGE = 'calendar_feeds.js';
|
||||
|
||||
// add new event page js
|
||||
const ADD_NEW_EVENT_PAGE = 'add_new_event.js';
|
||||
|
||||
// event category page js
|
||||
const EVENT_CATEGORY_PAGE = 'event_category.js';
|
||||
|
||||
// less variable editing page
|
||||
const LESS_VARIBALES_PAGE = 'less_variables_editing.js';
|
||||
|
||||
// settings page
|
||||
const SETTINGS_PAGE = 'admin_settings.js';
|
||||
|
||||
//widget creator page
|
||||
const WIDGET_CREATOR = 'widget-creator.js';
|
||||
|
||||
//ticketing page
|
||||
const TICKETING = 'ticketing.js';
|
||||
|
||||
//cache file
|
||||
const CALENDAR_JS_CACHE_FILE = '/public/js_cache/calendar.js';
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Registry_Object
|
||||
*/
|
||||
private $_registry;
|
||||
|
||||
/**
|
||||
* The core js pages to load.
|
||||
* Used to avoid errors when extensions add pages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_core_pages = array(
|
||||
self::CALENDAR_FEEDS_PAGE => true,
|
||||
self::ADD_NEW_EVENT_PAGE => true,
|
||||
self::EVENT_CATEGORY_PAGE => true,
|
||||
self::LESS_VARIBALES_PAGE => true,
|
||||
self::SETTINGS_PAGE => true,
|
||||
self::EVENT_PAGE_JS => true,
|
||||
self::CALENDAR_PAGE_JS => true,
|
||||
self::WIDGET_CREATOR => true,
|
||||
self::TICKETING => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds an instance of the settings object
|
||||
*
|
||||
* @var Ai1ec_Settings
|
||||
*/
|
||||
private $_settings;
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Locale
|
||||
*/
|
||||
private $_locale;
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Scripts
|
||||
*/
|
||||
private $_scripts_helper;
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Acl_Aco
|
||||
*/
|
||||
private $_aco;
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Template_Link_Helper
|
||||
*/
|
||||
private $_template_link_helper;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $_frontend_scripts_loaded = false;
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( Ai1ec_Registry_Object $registry ) {
|
||||
$this->_registry = $registry;
|
||||
$this->_settings = $registry->get( 'model.settings' );
|
||||
$this->_locale = $registry->get( 'p28n.wpml' );
|
||||
$this->_aco = $registry->get( 'acl.aco' );
|
||||
$this->_template_link_helper = $registry->get( 'template.link.helper' );
|
||||
// this will need to be modified
|
||||
$this->_scripts_helper = $registry->get( 'script.helper' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Load javascript files for frontend pages.
|
||||
*
|
||||
* @wp-hook ai1ec_load_frontend_js
|
||||
*
|
||||
* @param $is_calendar_page boolean Whether we are displaying the main
|
||||
* calendar page or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load_frontend_js( $is_calendar_page, $is_shortcode = false ) {
|
||||
$page = null;
|
||||
|
||||
// ======
|
||||
// = JS =
|
||||
// ======
|
||||
if( $this->_are_we_accessing_the_single_event_page() === true ) {
|
||||
$page = self::EVENT_PAGE_JS;
|
||||
}
|
||||
if( $is_calendar_page === true ) {
|
||||
$page = self::CALENDAR_PAGE_JS;
|
||||
}
|
||||
if( null !== $page ) {
|
||||
$this->add_link_to_render_js( $page, false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the javascript for the appropriate page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render_js() {
|
||||
$js_path = AI1EC_ADMIN_THEME_JS_PATH . DIRECTORY_SEPARATOR;
|
||||
$common_js = '';
|
||||
$js_cache = $this->_settings->get( 'cache_dynamic_js' );
|
||||
|
||||
if ( ! isset( $_GET[self::LOAD_JS_PARAMETER] ) ) {
|
||||
return null;
|
||||
}
|
||||
$page_to_load = $_GET[self::LOAD_JS_PARAMETER];
|
||||
$scripts_updated = $this->_registry->get( 'model.option' )->get( 'calendarjsupdated' );
|
||||
|
||||
if (
|
||||
$js_cache &&
|
||||
$page_to_load === self::CALENDAR_PAGE_JS &&
|
||||
'1' === $scripts_updated &&
|
||||
$this->_registry->get( 'filesystem.checker' )->check_file_exists(
|
||||
AI1EC_PATH . self::CALENDAR_JS_CACHE_FILE,
|
||||
true
|
||||
)
|
||||
) {
|
||||
Ai1ec_Http_Response_Helper::stop( 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
isset( $_GET[self::IS_BACKEND_PARAMETER] ) &&
|
||||
$_GET[self::IS_BACKEND_PARAMETER] === self::TRUE_PARAM
|
||||
) {
|
||||
$common_js = file_get_contents( $js_path . 'pages/common_backend.js' );
|
||||
} else if (
|
||||
$page_to_load === self::EVENT_PAGE_JS ||
|
||||
$page_to_load === self::CALENDAR_PAGE_JS ||
|
||||
$page_to_load === self::LOAD_ONLY_FRONTEND_SCRIPTS
|
||||
) {
|
||||
if (
|
||||
$page_to_load === self::LOAD_ONLY_FRONTEND_SCRIPTS &&
|
||||
true === $this->_frontend_scripts_loaded
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if ( false === $this->_frontend_scripts_loaded ) {
|
||||
$common_js = file_get_contents(
|
||||
$js_path . 'pages/common_frontend.js'
|
||||
);
|
||||
$this->_frontend_scripts_loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the config object for Require.js.
|
||||
$require_config = $this->create_require_js_config_object();
|
||||
|
||||
// Load Require.js script.
|
||||
$require = file_get_contents( $js_path . 'require.js' );
|
||||
|
||||
// Load appropriate jQuery script based on browser.
|
||||
$jquery = $this->get_jquery_version_based_on_browser(
|
||||
isset( $_SERVER['HTTP_USER_AGENT'] )
|
||||
? $_SERVER['HTTP_USER_AGENT']
|
||||
: ''
|
||||
);
|
||||
|
||||
// Load the main script for the page.
|
||||
$page_js = '';
|
||||
if ( isset( $this->_core_pages[$page_to_load] ) ) {
|
||||
$page_js = file_get_contents( $js_path . 'pages/' . $page_to_load );
|
||||
}
|
||||
|
||||
// Load translation module.
|
||||
$translation = $this->get_frontend_translation_data();
|
||||
$permalink = $this->_template_link_helper
|
||||
->get_permalink( $this->_settings->get( 'calendar_page_id' ) );
|
||||
$full_permalink = $this->_template_link_helper
|
||||
->get_full_permalink( $this->_settings->get( 'calendar_page_id' ) );
|
||||
$translation['calendar_url'] = $permalink;
|
||||
$translation['full_calendar_url'] = $full_permalink;
|
||||
$translation_module = $this->create_require_js_module(
|
||||
self::FRONTEND_CONFIG_MODULE,
|
||||
$translation
|
||||
);
|
||||
|
||||
// Load Ai1ec config script.
|
||||
$config = $this->create_require_js_module(
|
||||
'ai1ec_config',
|
||||
$this->get_translation_data()
|
||||
);
|
||||
|
||||
// Let extensions add their scripts.
|
||||
$extension_files = array();
|
||||
$extension_files = apply_filters(
|
||||
'ai1ec_render_js',
|
||||
$extension_files,
|
||||
$page_to_load
|
||||
);
|
||||
$ext_js = '';
|
||||
|
||||
foreach ( $extension_files as $file ) {
|
||||
$ext_js .= file_get_contents( $file );
|
||||
}
|
||||
|
||||
// Finally, load the page_ready script to execute code that must run after
|
||||
// all scripts have been loaded.
|
||||
$page_ready = file_get_contents(
|
||||
$js_path . 'scripts/common_scripts/page_ready.js'
|
||||
);
|
||||
|
||||
$javascript = $require . $require_config . $translation_module .
|
||||
$config . $jquery . $common_js . $ext_js . $page_js . $page_ready;
|
||||
// add to blank spaces to fix issues with js
|
||||
// being truncated onn some installs
|
||||
$javascript .= ' ';
|
||||
|
||||
if (
|
||||
$js_cache &&
|
||||
$page_to_load === self::CALENDAR_PAGE_JS &&
|
||||
(
|
||||
'0' === $scripts_updated ||
|
||||
! $this->_registry->get( 'filesystem.checker' )->check_file_exists(
|
||||
AI1EC_PATH . self::CALENDAR_JS_CACHE_FILE,
|
||||
true
|
||||
)
|
||||
)
|
||||
) {
|
||||
$js_saved = false;
|
||||
try {
|
||||
$js_saved = file_put_contents(
|
||||
$js_path . '../js_cache/' . self::CALENDAR_PAGE_JS,
|
||||
$javascript
|
||||
);
|
||||
if ( $js_saved ) {
|
||||
$this->_registry->get( 'model.option' )->set( 'calendarjsupdated', '1' );
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
$this->_settings->set( 'cache_dynamic_js', false );
|
||||
}
|
||||
}
|
||||
|
||||
$this->_echo_javascript( $javascript );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the flag to revalidate cached js files on next render.
|
||||
*/
|
||||
public function revalidate_cache() {
|
||||
$this->_registry->get( 'model.option' )->set( 'calendarjsupdated', '0' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a compiled javascript file ( used by extensions )
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_module( $name ) {
|
||||
$js_path = AI1EC_ADMIN_THEME_JS_PATH . DIRECTORY_SEPARATOR;
|
||||
return file_get_contents( $js_path . $name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check what file needs to be loaded and add the correct link.
|
||||
*
|
||||
* @wp-hook init
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load_admin_js() {
|
||||
// Initialize dashboard view
|
||||
|
||||
$script_to_load = FALSE;
|
||||
if ( $this->are_we_on_calendar_feeds_page() === TRUE ) {
|
||||
// Load script for the importer plugins
|
||||
$script_to_load[] = self::CALENDAR_FEEDS_PAGE;
|
||||
}
|
||||
// Start the scripts for the event category page
|
||||
if ( $this->_are_we_editing_event_categories() === TRUE ) {
|
||||
// Load script required when editing categories
|
||||
$script_to_load[] = self::EVENT_CATEGORY_PAGE;
|
||||
}
|
||||
if ( $this->_are_we_editing_less_variables() === TRUE ) {
|
||||
// Load script required when editing categories
|
||||
$script_to_load[] = self::LESS_VARIBALES_PAGE;
|
||||
}
|
||||
// Load the js needed when you edit an event / add a new event
|
||||
if (
|
||||
true === $this->_are_we_creating_a_new_event() ||
|
||||
true === $this->_are_we_editing_an_event()
|
||||
) {
|
||||
// Load script for adding / modifying events
|
||||
$script_to_load[] = self::ADD_NEW_EVENT_PAGE;
|
||||
}
|
||||
if ( true === $this->_are_we_accessing_the_calendar_settings_page() ) {
|
||||
$script_to_load[] = self::SETTINGS_PAGE;
|
||||
}
|
||||
if ( true === $this->_are_we_creating_widgets() ) {
|
||||
$script_to_load[] = self::WIDGET_CREATOR;
|
||||
}
|
||||
if (
|
||||
true === $this->_are_we_managing_tickets() ||
|
||||
true === $this->_are_we_managing_events_list()
|
||||
) {
|
||||
$script_to_load[] = self::TICKETING;
|
||||
}
|
||||
if ( false === $script_to_load ) {
|
||||
$script_to_load[] = apply_filters( 'ai1ec_backend_js', self::LOAD_ONLY_BACKEND_SCRIPTS );
|
||||
}
|
||||
foreach ($script_to_load as $value) {
|
||||
$this->add_link_to_render_js( $value, true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads version 1.9 or 2.0 of jQuery based on user agent.
|
||||
* If $user_agent is null (due to lack of HTTP header) we always serve
|
||||
* jQuery 2.0.
|
||||
*
|
||||
* @param string $user_agent
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_jquery_version_based_on_browser( $user_agent ) {
|
||||
$js_path = AI1EC_ADMIN_THEME_JS_PATH . DIRECTORY_SEPARATOR;
|
||||
$jquery = 'jquery_timely20.js';
|
||||
|
||||
preg_match( '/MSIE (.*?);/', $user_agent, $matches );
|
||||
if ( count( $matches ) > 1 ) {
|
||||
//Then we're using IE
|
||||
$version = (int) $matches[1];
|
||||
if ( $version <= 8 ) {
|
||||
//IE 8 or under!
|
||||
$jquery = 'jquery_timely19.js';
|
||||
}
|
||||
}
|
||||
return file_get_contents( $js_path . $jquery );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a requirejs module that can be used for translations
|
||||
*
|
||||
* @param string $object_name
|
||||
* @param array $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function create_require_js_module( $object_name, array $data ) {
|
||||
foreach ( (array) $data as $key => $value ) {
|
||||
if ( ! is_scalar( $value ) )
|
||||
continue;
|
||||
$data[$key] = html_entity_decode( (string) $value, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
$json_data = json_encode( $data );
|
||||
$prefix = self::REQUIRE_NAMESPACE;
|
||||
$script = "$prefix.define( '$object_name', $json_data );";
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the array needed for translation and passing other settings to JS.
|
||||
*
|
||||
* @return $data array the dynamic data array
|
||||
*/
|
||||
public function get_translation_data() {
|
||||
|
||||
$force_ssl_admin = force_ssl_admin();
|
||||
if ( $force_ssl_admin && ! is_ssl() ) {
|
||||
force_ssl_admin( false );
|
||||
}
|
||||
$ajax_url = ai1ec_admin_url( 'admin-ajax.php' );
|
||||
force_ssl_admin( $force_ssl_admin );
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$locale = $this->_registry->get( 'p28n.wpml' );
|
||||
$blog_timezone = $this->_registry->get( 'model.option' )
|
||||
->get( 'gmt_offset' );
|
||||
$application = $this->_registry->get( 'bootstrap.registry.application' );
|
||||
$data = array(
|
||||
'calendar_feeds_nonce' => wp_create_nonce( 'ai1ec_ics_feed_nonce'),
|
||||
// ICS feed error messages
|
||||
'duplicate_feed_message' => esc_html(
|
||||
Ai1ec_I18n::__( 'This feed is already being imported.' )
|
||||
),
|
||||
'invalid_url_message' => esc_html(
|
||||
Ai1ec_I18n::__( 'Please enter a valid iCalendar URL.' )
|
||||
),
|
||||
'invalid_website_message' => esc_html(
|
||||
Ai1ec_I18n::__( 'Please enter a valid Website URL.' )
|
||||
),
|
||||
'invalid_registration_message' => esc_html(
|
||||
Ai1ec_I18n::__( 'Please enter a valid Registration URL, starting with https:// or http://.' )
|
||||
),
|
||||
'invalid_email_message' => esc_html(
|
||||
Ai1ec_I18n::__( 'Please enter a valid email address.' )
|
||||
),
|
||||
'choose_image_message' => Ai1ec_I18n::__( 'Choose Image' ),
|
||||
'now' => $this->_registry->get( 'date.system' )
|
||||
->current_time(),
|
||||
'size_less_variable_not_ok' => Ai1ec_I18n::__(
|
||||
'The value you have entered is not a valid CSS length.'
|
||||
),
|
||||
'confirm_reset_theme' => Ai1ec_I18n::__(
|
||||
'Are you sure you want to reset your theme options to their default values?'
|
||||
),
|
||||
'error_message_not_valid_lat' => Ai1ec_I18n::__(
|
||||
'Please enter a valid latitude. A valid latitude is comprised between +90 and -90.'
|
||||
),
|
||||
'error_message_not_valid_long' => Ai1ec_I18n::__(
|
||||
'Please enter a valid longitude. A valid longitude is comprised between +180 and -180.'
|
||||
),
|
||||
'error_message_not_entered_lat' => Ai1ec_I18n::__(
|
||||
'When the "Input coordinates" checkbox is checked, "Latitude" is a required field.'
|
||||
),
|
||||
'error_message_not_entered_long' => Ai1ec_I18n::__(
|
||||
'When the "Input coordinates" checkbox is checked, "Longitude" is a required field.'
|
||||
),
|
||||
'ai1ec_contact_url_not_valid' => Ai1ec_I18n::__(
|
||||
'The URL you have entered in the <b>Organizer Contact Info</b> > <b>Website URL</b> seems to be invalid.'
|
||||
),
|
||||
'ai1ec_ticket_ext_url_not_valid' => Ai1ec_I18n::__(
|
||||
'The URL you have entered in the <b>Event Cost and Tickets</b> > <b>Tickets or Registration URL</b> seems to be invalid.'
|
||||
),
|
||||
'ai1ec_contact_email_not_valid' => Ai1ec_I18n::__(
|
||||
'The Email you have entered in the <b>Organizer Contact Info</b> > <b>E-mail</b> seems to be invalid.'
|
||||
),
|
||||
'general_url_not_valid' => Ai1ec_I18n::__(
|
||||
'Please remember that URLs must start with either "http://" or "https://".'
|
||||
),
|
||||
'calendar_loading' => Ai1ec_I18n::__(
|
||||
'Loading…'
|
||||
),
|
||||
'ticketing_required_fields' => Ai1ec_I18n::__(
|
||||
'<b>Required or incorrect fields for Ticketing are outlined red.</b>'
|
||||
),
|
||||
'ticketing_repeat_not_supported' => Ai1ec_I18n::__( '<b>The Repeat option was selected but recurrence is not supported by Event with Tickets.</b>'
|
||||
),
|
||||
'ticketing_no_tickets_included' => Ai1ec_I18n::__( '<b>
|
||||
The Event has the cost option Tickets selected but no ticket was included.</b>'
|
||||
),
|
||||
'discovery_event_success' => Ai1ec_I18n::__(
|
||||
'Event was imported successfully.'
|
||||
),
|
||||
'discovery_event_error' => Ai1ec_I18n::__(
|
||||
'An error occurred when importing event. Please, try later.'
|
||||
),
|
||||
'language' => $this->_registry->get( 'p28n.wpml' )->get_lang(),
|
||||
'ajax_url' => $ajax_url,
|
||||
// 24h time format for time pickers
|
||||
'twentyfour_hour' => $settings->get( 'input_24h_time' ),
|
||||
// Date format for date pickers
|
||||
'date_format' => $settings->get( 'input_date_format' ),
|
||||
// Names for months in date picker header (escaping is done in wp_localize_script)
|
||||
'month_names' => $locale->get_localized_month_names(),
|
||||
// Names for days in date picker header (escaping is done in wp_localize_script)
|
||||
'day_names' => $locale->get_localized_week_names(),
|
||||
// Start the week on this day in the date picker
|
||||
'week_start_day' => $settings->get( 'week_start_day' ),
|
||||
'week_view_starts_at' => $settings->get( 'week_view_starts_at' ),
|
||||
'week_view_ends_at' => $settings->get( 'week_view_ends_at' ),
|
||||
'google_maps_api_key' => $settings->get( 'google_maps_api_key' ),
|
||||
'blog_timezone' => $blog_timezone,
|
||||
'affix_filter_menu' => $settings->get( 'affix_filter_menu' ),
|
||||
'affix_vertical_offset_md' => $settings->get( 'affix_vertical_offset_md' ),
|
||||
'affix_vertical_offset_lg' => $settings->get( 'affix_vertical_offset_lg' ),
|
||||
'affix_vertical_offset_sm' => $settings->get( 'affix_vertical_offset_sm' ),
|
||||
'affix_vertical_offset_xs' => $settings->get( 'affix_vertical_offset_xs' ),
|
||||
'calendar_page_id' => $settings->get( 'calendar_page_id' ),
|
||||
'region' => ( $settings->get( 'geo_region_biasing' ) ) ? $locale->get_region() : '',
|
||||
'site_url' => trailingslashit(
|
||||
ai1ec_get_site_url()
|
||||
),
|
||||
'javascript_widgets' => array(),
|
||||
'widget_creator' => array(
|
||||
'preview' => Ai1ec_I18n::__( 'Preview:' ),
|
||||
'preview_loading' => Ai1ec_I18n::__(
|
||||
'Loading preview <i class="ai1ec-fa ai1ec-fa-spin ai1ec-fa-spinner"></i>'
|
||||
)
|
||||
),
|
||||
'ticketing' => array(
|
||||
'details' => Ai1ec_I18n::__( 'Ticketing Details' ),
|
||||
'hide_details' => Ai1ec_I18n::__( 'Hide Ticketing Details' ),
|
||||
'loading_details' => Ai1ec_I18n::__( 'Loading tickets details...' ),
|
||||
'type_and_price' => Ai1ec_I18n::__( 'Type and price' ),
|
||||
'info' => Ai1ec_I18n::__( 'Info' ),
|
||||
'information' => Ai1ec_I18n::__( 'Information' ),
|
||||
'report' => Ai1ec_I18n::__( 'Report' ),
|
||||
'sale_dates' => Ai1ec_I18n::__( 'Sale dates' ),
|
||||
'limits' => Ai1ec_I18n::__( 'Limits' ),
|
||||
'actions' => Ai1ec_I18n::__( 'Actions' ),
|
||||
'sold' => Ai1ec_I18n::__( 'Sold:' ),
|
||||
'left' => Ai1ec_I18n::__( 'Left:' ),
|
||||
'start' => Ai1ec_I18n::__( 'Start:' ),
|
||||
'end' => Ai1ec_I18n::__( 'End:' ),
|
||||
'min' => Ai1ec_I18n::__( 'Min:' ),
|
||||
'max' => Ai1ec_I18n::__( 'Max:' ),
|
||||
'attendees' => Ai1ec_I18n::__( 'Attendees' ),
|
||||
'hide_attendees' => Ai1ec_I18n::__( 'Hide Attendees' ),
|
||||
'attendees_list' => Ai1ec_I18n::__( 'Attendees List' ),
|
||||
'guest_name' => Ai1ec_I18n::__( 'Guest Name' ),
|
||||
'status' => Ai1ec_I18n::__( 'Status' ),
|
||||
'email' => Ai1ec_I18n::__( 'Email' ),
|
||||
'no_attendees' => Ai1ec_I18n::__( 'No attendees for this ticket type.' ),
|
||||
'edit' => Ai1ec_I18n::__( 'Edit' ),
|
||||
'code' => Ai1ec_I18n::__( 'Code' ),
|
||||
'unlimited' => Ai1ec_I18n::__( 'Unlimited' ),
|
||||
'open_for_sale' => Ai1ec_I18n::__( 'Open for sale' ),
|
||||
'no_delete_text' => Ai1ec_I18n::__( 'You have sold tickets for this ticket type. Please change it\'s status to "Canceled" and make refunds to all users that purchased tickets.' ),
|
||||
'cancel_message' => Ai1ec_I18n::__( 'You have sold tickets for this ticket type. Please make refunds to all users that purchased tickets' )
|
||||
),
|
||||
'review' => array(
|
||||
'message_sent' => Ai1ec_I18n::__( 'Your message has been sent. Thank you for your feedback.' ),
|
||||
'message_error' => Ai1ec_I18n::__( 'Your message has not been sent. Please try again or contact us.' )
|
||||
),
|
||||
'load_views_error' => Ai1ec_I18n::__(
|
||||
'Something went wrong while fetching events.<br>The request status is: %STATUS% <br>The error thrown was: %ERROR%'
|
||||
),
|
||||
'load_views_error_popup_title' => Ai1ec_I18n::__( 'Response text received from server' ),
|
||||
'load_views_error_link_popup' => Ai1ec_I18n::__( 'Click here for technical details' ),
|
||||
'cookie_path' => $this->_registry->get(
|
||||
'cookie.utility'
|
||||
)->get_path_for_cookie(),
|
||||
'disable_autocompletion' => $settings->get( 'disable_autocompletion' ),
|
||||
'end_must_be_after_start' => __( 'The end date can\'t be earlier than the start date.', AI1EC_PLUGIN_NAME ),
|
||||
'show_at_least_six_hours' => __( 'For week and day view, you must select an interval of at least 6 hours.', AI1EC_PLUGIN_NAME ),
|
||||
'ai1ec_permalinks_enabled' => $application->get( 'permalinks_enabled' ),
|
||||
);
|
||||
return apply_filters( 'ai1ec_js_translations', $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array with translated data for the frontend
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_frontend_translation_data() {
|
||||
$data = array(
|
||||
'export_url' => AI1EC_EXPORT_URL,
|
||||
);
|
||||
|
||||
// Replace desired CSS selector with calendar, if selector has been set
|
||||
$calendar_selector = $this->_settings->get( 'calendar_css_selector' );
|
||||
if( $calendar_selector ) {
|
||||
$page = get_post(
|
||||
$this->_settings->get( 'calendar_page_id' )
|
||||
);
|
||||
$data['selector'] = $calendar_selector;
|
||||
$data['title'] = $page->post_title;
|
||||
}
|
||||
|
||||
// DEPRECATED: Only still here for backwards compatibility with Ai1ec 1.x.
|
||||
$data['fonts'] = array();
|
||||
$fonts_dir = AI1EC_DEFAULT_THEME_URL . 'font_css/';
|
||||
$data['fonts'][] = array(
|
||||
'name' => 'League Gothic',
|
||||
'url' => $fonts_dir . 'font-league-gothic.css',
|
||||
);
|
||||
$data['fonts'][] = array(
|
||||
'name' => 'fontawesome',
|
||||
'url' => $fonts_dir . 'font-awesome.css',
|
||||
);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Echoes the Javascript if not cached.
|
||||
*
|
||||
* Echoes the javascript with the correct content.
|
||||
* Since the content is dinamic, i use the hash function.
|
||||
*
|
||||
* @param string $javascript
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _echo_javascript( $javascript ) {
|
||||
$conditional_get = new HTTP_ConditionalGet( array(
|
||||
'contentHash' => md5( $javascript )
|
||||
)
|
||||
);
|
||||
$conditional_get->sendHeaders();
|
||||
if ( ! $conditional_get->cacheIsValid ) {
|
||||
$http_encoder = $this->_registry->get(
|
||||
'http.encoder',
|
||||
array(
|
||||
'content' => $javascript,
|
||||
'type' => 'text/javascript'
|
||||
)
|
||||
);
|
||||
$compression_level = null;
|
||||
if ( $this->_registry->get( 'model.settings' )->get( 'disable_gzip_compression' ) ) {
|
||||
// set the compression level to 0 to disable it.
|
||||
$compression_level = 0;
|
||||
}
|
||||
$http_encoder->encode( $compression_level );
|
||||
$http_encoder->sendAll();
|
||||
}
|
||||
Ai1ec_Http_Response_Helper::stop( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the config object for requirejs.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function create_require_js_config_object() {
|
||||
$js_url = AI1EC_ADMIN_THEME_JS_URL;
|
||||
$version = AI1EC_VERSION;
|
||||
$namespace = self::REQUIRE_NAMESPACE;
|
||||
$config = <<<JSC
|
||||
$namespace.require.config( {
|
||||
waitSeconds : 15,
|
||||
urlArgs : 'ver=$version',
|
||||
baseUrl : '$js_url'
|
||||
} );
|
||||
JSC;
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are in the calendar feeds page
|
||||
*
|
||||
* @return boolean TRUE if we are in the calendar feeds page FALSE otherwise
|
||||
*/
|
||||
public function are_we_on_calendar_feeds_page() {
|
||||
if ( !isset( $_SERVER['SCRIPT_NAME'] ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$path_details = pathinfo( $_SERVER['SCRIPT_NAME'] );
|
||||
$post_type = isset( $_GET['post_type'] ) ? $_GET['post_type'] : FALSE;
|
||||
$page = isset( $_GET['page'] ) ? $_GET['page'] : FALSE;
|
||||
if( $post_type === FALSE || $page === FALSE ) {
|
||||
return FALSE;
|
||||
}
|
||||
$is_calendar_feed_page = $path_details['basename'] === 'edit.php' &&
|
||||
$post_type === 'ai1ec_event' &&
|
||||
$page === 'all-in-one-event-calendar-feeds';
|
||||
return $is_calendar_feed_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the link to render the javascript
|
||||
*
|
||||
* @param string $page
|
||||
* @param boolean $backend
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_link_to_render_js( $page, $backend ) {
|
||||
$load_backend_script = 'false';
|
||||
if ( true === $backend ) {
|
||||
$load_backend_script = self::TRUE_PARAM;
|
||||
}
|
||||
$is_calendar_page = false;
|
||||
if(
|
||||
true === is_page( $this->_settings->get( 'calendar_page_id' ) ) ||
|
||||
self::CALENDAR_PAGE_JS === $page
|
||||
) {
|
||||
$is_calendar_page = self::TRUE_PARAM;
|
||||
}
|
||||
|
||||
$url = add_query_arg(
|
||||
array(
|
||||
// Add the page to load
|
||||
self::LOAD_JS_PARAMETER => $page,
|
||||
// If we are in the backend, we must load the common scripts
|
||||
self::IS_BACKEND_PARAMETER => $load_backend_script,
|
||||
// If we are on the calendar page we must load the correct option
|
||||
self::IS_CALENDAR_PAGE => $is_calendar_page,
|
||||
),
|
||||
trailingslashit( ai1ec_get_site_url() )
|
||||
);
|
||||
if (
|
||||
$this->_settings->get( 'cache_dynamic_js' ) &&
|
||||
$is_calendar_page &&
|
||||
'1' === $this->_registry->get( 'model.option' )->get( 'calendarjsupdated' ) &&
|
||||
$this->_registry->get( 'filesystem.checker' )->check_file_exists(
|
||||
AI1EC_PATH . self::CALENDAR_JS_CACHE_FILE,
|
||||
true
|
||||
)
|
||||
) {
|
||||
$url = plugin_dir_url( 'all-in-one-event-calendar/public/js_cache/.' ) . $page;
|
||||
}
|
||||
|
||||
if ( true === $backend ) {
|
||||
$this->_scripts_helper->enqueue_script(
|
||||
self::JS_HANDLE,
|
||||
$url,
|
||||
array( 'postbox' ),
|
||||
true
|
||||
);
|
||||
} else {
|
||||
$this->_scripts_helper->enqueue_script(
|
||||
self::JS_HANDLE,
|
||||
$url,
|
||||
array(),
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if we are editing an event
|
||||
*
|
||||
* @return boolean TRUE if we are editing an event FALSE otherwise
|
||||
*/
|
||||
private function _are_we_editing_an_event() {
|
||||
if ( !isset( $_SERVER['SCRIPT_NAME'] ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$path_details = pathinfo( $_SERVER['SCRIPT_NAME'] );
|
||||
$post_id = isset( $_GET['post'] ) ? $_GET['post'] : FALSE;
|
||||
$action = isset( $_GET['action'] ) ? $_GET['action'] : FALSE;
|
||||
if( $post_id === FALSE || $action === FALSE ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$editing = (
|
||||
'post.php' === $path_details['basename'] &&
|
||||
'edit' === $action &&
|
||||
$this->_aco->is_our_post_type( $post_id )
|
||||
);
|
||||
return $editing;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if we are viewing events list
|
||||
*
|
||||
* @return boolean TRUE if we are on the events list FALSE otherwise
|
||||
*/
|
||||
private function _are_we_managing_events_list() {
|
||||
if ( !isset( $_SERVER['SCRIPT_NAME'] ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$path_details = pathinfo( $_SERVER['SCRIPT_NAME'] );
|
||||
$post_type = isset( $_GET['post_type'] ) ? $_GET['post_type'] : FALSE;
|
||||
if ( FALSE === $post_type ) {
|
||||
return FALSE;
|
||||
}
|
||||
$page = isset( $_GET['page'] ) ? $_GET['page'] : '';
|
||||
$events_list = (
|
||||
'edit.php' === $path_details['basename'] &&
|
||||
'ai1ec_event' === $post_type &&
|
||||
ai1ec_is_blank( $page )
|
||||
);
|
||||
return $events_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if we are creating a new event
|
||||
*
|
||||
* @return boolean TRUE if we are creating a new event FALSE otherwise
|
||||
*/
|
||||
private function _are_we_creating_a_new_event() {
|
||||
if ( !isset( $_SERVER['SCRIPT_NAME'] ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$path_details = pathinfo( $_SERVER['SCRIPT_NAME'] );
|
||||
$post_type = isset( $_GET['post_type'] ) ? $_GET['post_type'] : '';
|
||||
return $path_details['basename'] === 'post-new.php' &&
|
||||
$post_type === AI1EC_POST_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are accessing the settings page
|
||||
*
|
||||
* @return boolean TRUE if we are accessing the settings page FALSE otherwise
|
||||
*/
|
||||
private function _are_we_accessing_the_calendar_settings_page() {
|
||||
if ( !isset( $_SERVER['SCRIPT_NAME'] ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$path_details = pathinfo( $_SERVER['SCRIPT_NAME'] );
|
||||
$page = isset( $_GET['page'] ) ? $_GET['page'] : '';
|
||||
return $path_details['basename'] === 'edit.php' &&
|
||||
$page === AI1EC_PLUGIN_NAME . '-settings';
|
||||
}
|
||||
|
||||
protected function _are_we_creating_widgets() {
|
||||
if ( !isset( $_SERVER['SCRIPT_NAME'] ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$path_details = pathinfo( $_SERVER['SCRIPT_NAME'] );
|
||||
$page = isset( $_GET['page'] ) ? $_GET['page'] : '';
|
||||
return $path_details['basename'] === 'edit.php' &&
|
||||
$page === AI1EC_PLUGIN_NAME . '-widget-creator';
|
||||
}
|
||||
|
||||
protected function _are_we_managing_tickets() {
|
||||
if ( !isset( $_SERVER['SCRIPT_NAME'] ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$path_details = pathinfo( $_SERVER['SCRIPT_NAME'] );
|
||||
$page = isset( $_GET['page'] ) ? $_GET['page'] : '';
|
||||
return $path_details['basename'] === 'edit.php' &&
|
||||
$page === AI1EC_PLUGIN_NAME . '-tickets';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are editing less variables
|
||||
*
|
||||
* @return boolean TRUE if we are accessing a single event page FALSE otherwise
|
||||
*/
|
||||
private function _are_we_editing_less_variables() {
|
||||
if ( !isset( $_SERVER['SCRIPT_NAME'] ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$path_details = pathinfo( $_SERVER['SCRIPT_NAME'] );
|
||||
$page = isset( $_GET['page'] ) ? $_GET['page'] : '';
|
||||
return $path_details['basename'] === 'edit.php' && $page === AI1EC_PLUGIN_NAME . '-edit-css';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are accessing the events category page
|
||||
*
|
||||
* @return boolean TRUE if we are accessing the events category page FALSE otherwise
|
||||
*/
|
||||
private function _are_we_editing_event_categories() {
|
||||
if ( !isset( $_SERVER['SCRIPT_NAME'] ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$path_details = pathinfo( $_SERVER['SCRIPT_NAME'] );
|
||||
$post_type = isset( $_GET['post_type'] ) ? $_GET['post_type'] : '';
|
||||
return (
|
||||
$path_details['basename'] === 'edit-tags.php' ||
|
||||
$path_details['basename'] === 'term.php'
|
||||
) && $post_type === AI1EC_POST_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are accessing a single event page
|
||||
*
|
||||
* @return boolean TRUE if we are accessing a single event page FALSE otherwise
|
||||
*/
|
||||
private function _are_we_accessing_the_single_event_page() {
|
||||
return $this->_aco->is_our_post_type();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Controller that handles shutdown functions.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Controller
|
||||
*/
|
||||
class Ai1ec_Shutdown_Controller {
|
||||
|
||||
/**
|
||||
* @var array Map of object names and class names they represent to preserve
|
||||
*/
|
||||
protected $_preserve = array(
|
||||
'wpdb' => 'wpdb',
|
||||
'wp_object_cache' => 'WP_Object_Cache',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array Map of object names and their representation from global scope
|
||||
*/
|
||||
protected $_restorables = array();
|
||||
|
||||
/**
|
||||
* @var array List of callbacks to be executed during shutdown sequence
|
||||
*/
|
||||
protected $_callbacks = array();
|
||||
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
* Here processing of globals is made - values are replaced, callbacks
|
||||
* are executed and globals are restored to the previous state.
|
||||
*
|
||||
* @return void Destructor does not return
|
||||
*/
|
||||
public function __destruct() {
|
||||
// replace globals from our internal store
|
||||
$restore = array();
|
||||
foreach ( $this->_preserve as $name => $class ) {
|
||||
if (
|
||||
! isset( $GLOBALS[$name] ) ||
|
||||
! ( $GLOBALS[$name] instanceof $class )
|
||||
) {
|
||||
$restore[$name] = NULL;
|
||||
if ( isset( $GLOBALS[$name] ) ) {
|
||||
$restore[$name] = $GLOBALS[$name];
|
||||
}
|
||||
$GLOBALS[$name] = $this->_restorables[$name];
|
||||
}
|
||||
}
|
||||
// execute callbacks
|
||||
foreach ( $this->_callbacks as $callback ) {
|
||||
call_user_func( $callback );
|
||||
}
|
||||
// restore globals to previous state
|
||||
foreach ( $restore as $name => $object ) {
|
||||
if ( NULL === $object ) {
|
||||
unset( $GLOBALS[$name] );
|
||||
} else {
|
||||
$GLOBALS[$name] = $object;
|
||||
}
|
||||
}
|
||||
// destroy local references
|
||||
foreach ( $this->_restorables as $name => $object ) {
|
||||
unset( $object, $this->_restorables[$name] );
|
||||
}
|
||||
if ( AI1EC_DEBUG ) {
|
||||
// __destruct is called twice if facebook extension is installed
|
||||
// still can't find the reason, this fixes it but prevent other plugins
|
||||
// __destruct() so let's just use it in dev until we fix this.
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be executed during shutdown sequence
|
||||
*
|
||||
* @param callback $callback Valid PHP callback
|
||||
*
|
||||
* @return Ai1ec_Shutdown_Utility Self instance for chaining
|
||||
*/
|
||||
public function register( $callback ) {
|
||||
$this->_callbacks[] = $callback;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Here global variables are referenced locally to ensure their preservation
|
||||
*
|
||||
* @return void Constructor does not return
|
||||
*/
|
||||
public function __construct() {
|
||||
foreach ( $this->_preserve as $name => $class ) {
|
||||
$this->_restorables[$name] = $GLOBALS[$name];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,622 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Common class for Timely API communication.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.4
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
abstract class Ai1ec_Api_Abstract extends Ai1ec_App {
|
||||
|
||||
const WP_OPTION_KEY = 'ai1ec_api_settings';
|
||||
const DEFAULT_TIMEOUT = 30;
|
||||
|
||||
protected $_settings;
|
||||
|
||||
/**
|
||||
* Post construction routine.
|
||||
*
|
||||
* Override this method to perform post-construction tasks.
|
||||
*
|
||||
* @return void Return from this method is ignored.
|
||||
*/
|
||||
protected function _initialize() {
|
||||
$this->_settings = $this->_registry->get( 'model.settings' );
|
||||
}
|
||||
|
||||
protected function get_ticketing_settings( $find_attribute = null, $default_value_attribute = null ) {
|
||||
$api_settings = get_option( self::WP_OPTION_KEY, null );
|
||||
if ( ! is_array( $api_settings ) ) {
|
||||
$api_settings = array(
|
||||
'enabled' => $this->_settings->get( 'ticketing_enabled' ),
|
||||
'message' => $this->_settings->get( 'ticketing_message' ),
|
||||
'token' => $this->_settings->get( 'ticketing_token' ),
|
||||
'calendar_id' => $this->_settings->get( 'ticketing_calendar_id' )
|
||||
);
|
||||
update_option( self::WP_OPTION_KEY, $api_settings );
|
||||
$this->_settings->set( 'ticketing_message' , '' );
|
||||
$this->_settings->set( 'ticketing_enabled' , false );
|
||||
$this->_settings->set( 'ticketing_token' , '' );
|
||||
$this->_settings->set( 'ticketing_calendar_id', null );
|
||||
}
|
||||
if ( is_null( $find_attribute ) ) {
|
||||
return $api_settings;
|
||||
} else {
|
||||
if ( isset( $api_settings[$find_attribute] ) ) {
|
||||
return $api_settings[$find_attribute];
|
||||
} else {
|
||||
return $default_value_attribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $message last message received from the Sign up or Sign in process
|
||||
* @param bool $enabled true or false is ticket is enabled
|
||||
* @param string $token autenthication token
|
||||
* @param int @calendar_id remote id of the calendar
|
||||
* @param string $account Email used to create the account
|
||||
*/
|
||||
protected function save_ticketing_settings( $message, $enabled, $token, $calendar_id, $account ) {
|
||||
$api_settings = $this->get_ticketing_settings();
|
||||
$api_settings['message'] = $message;
|
||||
$api_settings['enabled'] = $enabled;
|
||||
$api_settings['token'] = $token;
|
||||
$api_settings['calendar_id'] = $calendar_id;
|
||||
$api_settings['account'] = $account;
|
||||
return update_option( self::WP_OPTION_KEY, $api_settings );
|
||||
}
|
||||
|
||||
protected function clear_ticketing_settings() {
|
||||
delete_option( self::WP_OPTION_KEY );
|
||||
|
||||
// Clear transient API data
|
||||
delete_transient( 'ai1ec_api_feeds_subscriptions' );
|
||||
delete_transient( 'ai1ec_api_subscriptions' );
|
||||
delete_transient( 'ai1ec_api_features' );
|
||||
delete_transient( 'ai1ec_api_checked' );
|
||||
|
||||
$this->check_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the Payment settings localy (same saved on the API)
|
||||
* @param array Preferences to save
|
||||
*/
|
||||
public function save_payment_settings( array $values ) {
|
||||
$api_settings = $this->get_ticketing_settings();
|
||||
if ( null !== $values ) {
|
||||
$api_settings['payment_settings'] = $values;
|
||||
} else {
|
||||
unset( $api_settings['payment_settings'] );
|
||||
}
|
||||
return update_option( self::WP_OPTION_KEY, $api_settings );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the saved payments settings (the same saved on the API)
|
||||
*/
|
||||
public function get_payment_settings() {
|
||||
return $this->get_ticketing_settings( 'payment_settings' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current WP instance has payments settings configured
|
||||
*/
|
||||
public function has_payment_settings() {
|
||||
$payment_settings = $this->get_payment_settings();
|
||||
if ( null === $payment_settings ) {
|
||||
//code to migrate the settings save on ticketing api and
|
||||
//bring them to the core side
|
||||
$payment_settings = $this->get_payment_preferences();
|
||||
if ( is_object( $payment_settings ) ) {
|
||||
$payment_settings = (array) $payment_settings;
|
||||
}
|
||||
$this->save_payment_settings( (array) $payment_settings );
|
||||
}
|
||||
return ( null !== $payment_settings &&
|
||||
'paypal' === $payment_settings['payment_method'] &&
|
||||
false === ai1ec_is_blank( $payment_settings['paypal_email'] ) ) ;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return object Response from API, or empty defaults
|
||||
*/
|
||||
public function get_payment_preferences() {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
$settings = null;
|
||||
if ( 0 < $calendar_id ) {
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . "calendars/$calendar_id/payment",
|
||||
null, //no body
|
||||
true //decode response body
|
||||
);
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$settings = $response->body;
|
||||
}
|
||||
}
|
||||
if ( is_null( $settings ) ) {
|
||||
return (object) array( 'payment_method'=>'paypal', 'paypal_email'=> '', 'first_name'=>'', 'last_name'=>'', 'currency'=> 'USD' );
|
||||
} else {
|
||||
if ( ! isset( $settings->currency ) ) {
|
||||
$settings->currency = 'USD';
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function get_timely_token() {
|
||||
return $this->get_ticketing_settings( 'token' );
|
||||
}
|
||||
|
||||
protected function save_calendar_id ( $calendar_id ) {
|
||||
$api_settings = $this->get_ticketing_settings();
|
||||
$api_settings['calendar_id'] = $calendar_id;
|
||||
return update_option( self::WP_OPTION_KEY, $api_settings );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the header array with authorization token
|
||||
*/
|
||||
protected function _get_headers( $custom_headers = null ) {
|
||||
$headers = array(
|
||||
'Content-Type' => 'application/x-www-form-urlencoded'
|
||||
);
|
||||
$headers['Authorization'] = 'Basic ' . $this->get_ticketing_settings( 'token', '' );
|
||||
if ( null !== $custom_headers ) {
|
||||
foreach ( $custom_headers as $key => $value ) {
|
||||
if ( null === $value ) {
|
||||
unset( $headers[$key] );
|
||||
} else {
|
||||
$headers[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a standarized message to return
|
||||
* 1) If the API respond with http code 400 and with a JSON body, so, we will consider the API message to append in the base message.
|
||||
* 2) If the API does not responde with http code 400 or does not have a valid a JSON body, we will show the API URL and the http message error.
|
||||
*/
|
||||
protected function _transform_error_message( $base_message, $response, $url, $ask_for_reload = false ) {
|
||||
$api_error = $this->get_api_error_msg( $response );
|
||||
$result = null;
|
||||
if ( false === ai1ec_is_blank( $api_error ) ) {
|
||||
$result = sprintf(
|
||||
__( '%s.<br/>Detail: %s.', AI1EC_PLUGIN_NAME ),
|
||||
$base_message, $api_error
|
||||
);
|
||||
} else {
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$error_message = sprintf(
|
||||
__( 'API URL: %s.<br/>Detail: %s', AI1EC_PLUGIN_NAME ),
|
||||
$url,
|
||||
$response->get_error_message()
|
||||
);
|
||||
} else {
|
||||
$error_message = sprintf(
|
||||
__( 'API URL: %s.<br/>Detail: %s - %s', AI1EC_PLUGIN_NAME ),
|
||||
$url,
|
||||
wp_remote_retrieve_response_code( $response ),
|
||||
wp_remote_retrieve_response_message( $response )
|
||||
);
|
||||
$mailto = '<a href="mailto:labs@time.ly" target="_top">labs@time.ly</a>';
|
||||
if ( true === $ask_for_reload ) {
|
||||
$result = sprintf(
|
||||
__( '%s. Please reload this page to try again. If this error persists, please contact us at %s. In your report please include the information below.<br/>%s.', AI1EC_PLUGIN_NAME ),
|
||||
$base_message,
|
||||
$mailto,
|
||||
$error_message
|
||||
);
|
||||
} else {
|
||||
$result = sprintf(
|
||||
__( '%s. Please try again. If this error persists, please contact us at %s. In your report please include the information below.<br/>%s.', AI1EC_PLUGIN_NAME ),
|
||||
$base_message,
|
||||
$mailto,
|
||||
$error_message
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
$result = trim( $result );
|
||||
$result = str_replace( '..', '.', $result );
|
||||
$result = str_replace( '.,', '.', $result );
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search for the API message error
|
||||
*/
|
||||
public function get_api_error_msg( $response ) {
|
||||
if ( isset( $response ) && false === is_wp_error( $response ) ) {
|
||||
$response_body = json_decode( $response['body'], true );
|
||||
if ( is_array( $response_body ) &&
|
||||
isset( $response_body['errors'] ) ) {
|
||||
$errors = $response_body['errors'];
|
||||
if ( false === is_array( $errors )) {
|
||||
$errors = array( $errors );
|
||||
}
|
||||
$messages = null;
|
||||
foreach ($errors as $key => $value) {
|
||||
if ( false === ai1ec_is_blank( $value ) ) {
|
||||
if ( is_array( $value ) ) {
|
||||
$value = implode ( ', ', $value );
|
||||
}
|
||||
$messages[] = $value;
|
||||
}
|
||||
}
|
||||
if ( null !== $messages && false === empty( $messages ) ) {
|
||||
return implode ( ', ', $messages);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ticket calendar from settings, if the calendar does not exists in
|
||||
* settings, then we will try to find on the API
|
||||
* @return string JSON.
|
||||
*/
|
||||
protected function _get_ticket_calendar( $createIfNotExists = true ) {
|
||||
$ticketing_calendar_id = $this->get_ticketing_settings( 'calendar_id', 0 );
|
||||
if ( 0 < $ticketing_calendar_id ) {
|
||||
return $ticketing_calendar_id;
|
||||
} else {
|
||||
if ( ! $createIfNotExists ) {
|
||||
return 0;
|
||||
}
|
||||
// Try to find the calendar in the API
|
||||
$ticketing_calendar_id = $this->_find_user_calendar();
|
||||
if ( 0 < $ticketing_calendar_id ) {
|
||||
$this->save_calendar_id( $ticketing_calendar_id );
|
||||
|
||||
return $ticketing_calendar_id;
|
||||
} else {
|
||||
// If the calendar doesn't exist in the API, create a new one
|
||||
$ticketing_calendar_id = $this->_create_calendar();
|
||||
if ( 0 < $ticketing_calendar_id ) {
|
||||
$this->save_calendar_id( $ticketing_calendar_id );
|
||||
|
||||
return $ticketing_calendar_id;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the existent calendar when the user is signing in
|
||||
*/
|
||||
protected function _find_user_calendar() {
|
||||
$body = array(
|
||||
'title' => get_bloginfo( 'name' ),
|
||||
'url' => ai1ec_site_url()
|
||||
);
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'calendars', $body );
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
if ( is_array( $response->body ) ) {
|
||||
return $response->body[0]->id;
|
||||
} else {
|
||||
return $response->body->id;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a calendar when the user is signup
|
||||
*/
|
||||
protected function _create_calendar() {
|
||||
$body = array(
|
||||
'title' => get_bloginfo( 'name' ),
|
||||
'url' => ai1ec_site_url(),
|
||||
'timezone' => $this->_settings->get( 'timezone_string' )
|
||||
);
|
||||
$response = $this->request_api( 'POST', AI1EC_API_URL . 'calendars', $body );
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
return $response->body->id;
|
||||
} else {
|
||||
$this->log_error( $response, 'Created calendar' );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current WP instance is signed into the API
|
||||
*/
|
||||
public function is_signed() {
|
||||
return ( true === $this->get_ticketing_settings( 'enabled', false ) );
|
||||
}
|
||||
|
||||
public function check_settings( $force = false ) {
|
||||
$checked = get_transient( 'ai1ec_api_checked' );
|
||||
|
||||
if ( false === $checked || $force ) {
|
||||
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
||||
|
||||
$failList = array();
|
||||
foreach ( Ai1ec_Api_Features::$features as $key => $value ) {
|
||||
if ( empty( $value ) ) {
|
||||
continue;
|
||||
}
|
||||
if ( ( ! $this->is_signed() || ! $this->has_subscription_active( $key ) ) && call_user_func( 'is'.'_'.'pl'.'ug'.'in'.'_'.'ac'.'ti'.'ve', $value ) ) {
|
||||
$failList[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $failList ) > 0 ) {
|
||||
call_user_func( 'de'.'act'.'iv'.'ate'.'_'.'pl'.'ug'.'ins', $failList );
|
||||
|
||||
$message = 'Your ' .
|
||||
'All-in-One Event Calendar ' .
|
||||
'has the ' .
|
||||
'following ' .
|
||||
'plugins ' .
|
||||
'installed ' .
|
||||
'but they are ' .
|
||||
'disabled. '.
|
||||
'To keep ' .
|
||||
'them ' .
|
||||
'enabled'.
|
||||
', simply '.
|
||||
'keep ' .
|
||||
'your calendar ' .
|
||||
'logged in ' .
|
||||
'to your '.
|
||||
'Timely account.' .
|
||||
'<br /><br />';
|
||||
|
||||
foreach ( $failList as $failed ) {
|
||||
$pieces = explode( '/', $failed );
|
||||
$message .= '- ' . $pieces[0] . '<br />';
|
||||
}
|
||||
|
||||
$this->show_error( $message );
|
||||
}
|
||||
|
||||
set_transient( 'ai1ec_api_checked', true, 5 * 60 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current email account
|
||||
*/
|
||||
public function get_current_account() {
|
||||
return $this->get_ticketing_settings( 'account', '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current calendar id
|
||||
*/
|
||||
public function get_current_calendar() {
|
||||
return $this->get_ticketing_settings( 'calendar_id', 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last message return by Signup or Signup process
|
||||
*/
|
||||
public function get_sign_message() {
|
||||
return $this->get_ticketing_settings( 'message', '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the last message return by Signup or Signup process
|
||||
*/
|
||||
public function clear_sign_message() {
|
||||
$api_settings = $this->get_ticketing_settings();
|
||||
$api_settings['message'] = '';
|
||||
return update_option( self::WP_OPTION_KEY, $api_settings );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array List of subscriptions and limits
|
||||
*/
|
||||
protected function get_subscriptions( $force_refresh = false ) {
|
||||
$subscriptions = get_transient( 'ai1ec_api_subscriptions' );
|
||||
|
||||
if ( false === $subscriptions || $force_refresh || ( defined( 'AI1EC_DEBUG' ) && AI1EC_DEBUG ) ) {
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'calendars/' . $this->_get_ticket_calendar() . '/subscriptions',
|
||||
null,
|
||||
true
|
||||
);
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$subscriptions = (array) $response->body;
|
||||
} else {
|
||||
$subscriptions = array();
|
||||
}
|
||||
|
||||
// Save for 5 minutes
|
||||
$minutes = 5;
|
||||
set_transient( 'ai1ec_api_subscriptions', $subscriptions, $minutes * 60 );
|
||||
}
|
||||
|
||||
return $subscriptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if calendar should have a specific feature enabled
|
||||
*/
|
||||
public function has_subscription_active( $feature ) {
|
||||
$subscriptions = $this->get_subscriptions();
|
||||
|
||||
return array_key_exists( $feature, $subscriptions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if feature has reached its limit
|
||||
*/
|
||||
public function subscription_has_reached_limit( $feature ) {
|
||||
$has_reached_limit = true;
|
||||
|
||||
$provided = $this->subscription_get_quantity_limit( $feature );
|
||||
$used = $this->subscription_get_used_quantity( $feature );
|
||||
|
||||
if ( $provided - $used > 0 ) {
|
||||
$has_reached_limit = false;
|
||||
}
|
||||
|
||||
return $has_reached_limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get feature quantity limit
|
||||
*/
|
||||
public function subscription_get_quantity_limit( $feature ) {
|
||||
$provided = 0;
|
||||
|
||||
$subscriptions = $this->get_subscriptions();
|
||||
|
||||
if ( array_key_exists( $feature, $subscriptions ) ) {
|
||||
$quantity = (array) $subscriptions[$feature];
|
||||
|
||||
$provided = $quantity['provided'];
|
||||
}
|
||||
|
||||
return $provided;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get feature used quantity
|
||||
*/
|
||||
public function subscription_get_used_quantity( $feature ) {
|
||||
$used = 0;
|
||||
|
||||
$subscriptions = $this->get_subscriptions();
|
||||
|
||||
if ( array_key_exists( $feature, $subscriptions ) ) {
|
||||
$quantity = (array) $subscriptions[$feature];
|
||||
|
||||
$used = $quantity['used'];
|
||||
}
|
||||
|
||||
return $used;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the request to the API endpons
|
||||
* @param $url The end part of the url to make the request.
|
||||
* $body The body to send the message
|
||||
* $method POST | GET | PUT, etc
|
||||
* or send a customized message to be showed in case of error
|
||||
* $decode_response_body TRUE (default) to decode the body response
|
||||
* @return stdClass with the the fields:
|
||||
* is_error TRUE or FALSE
|
||||
* error in case of is_error be true
|
||||
* body in case of is_error be false
|
||||
*/
|
||||
protected function request_api( $method, $url, $body = null, $decode_response_body = true, $custom_headers = null ) {
|
||||
$request = array(
|
||||
'method' => $method,
|
||||
'accept' => 'application/json',
|
||||
'headers' => $this->_get_headers( $custom_headers ),
|
||||
'timeout' => self::DEFAULT_TIMEOUT
|
||||
);
|
||||
if ( ! is_null( $body ) ) {
|
||||
$request['body'] = $body;
|
||||
}
|
||||
$response = wp_remote_request( $url, $request );
|
||||
$result = new stdClass();
|
||||
$result->url = $url;
|
||||
$result->raw = $response;
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$result->is_error = true;
|
||||
$result->error = $response->get_error_message();
|
||||
} else {
|
||||
$result->response_code = wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 === $result->response_code ) {
|
||||
if ( true === $decode_response_body ) {
|
||||
$result->body = json_decode( $response['body'] );
|
||||
if ( false === is_null( $result->body ) ) {
|
||||
$result->is_error = false;
|
||||
} else {
|
||||
$result->is_error = true;
|
||||
$result->error = __( 'Error decoding the response', AI1EC_PLUGIN_NAME );
|
||||
unset( $result->body );
|
||||
}
|
||||
} else {
|
||||
$result->is_error = false;
|
||||
$result->body = $response['body'];
|
||||
}
|
||||
} else {
|
||||
$result->is_error = true;
|
||||
$result->error = wp_remote_retrieve_response_message( $response );
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a post request to the api
|
||||
* @param rest_endpoint Partial URL that can include {calendar_id} that will be replaced by the current calendar signed
|
||||
*/
|
||||
public function call_api( $method, $endpoint, $body = null, $decode_response_body = true, $custom_headers = null ) {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( 0 >= $calendar_id ) {
|
||||
return false;
|
||||
}
|
||||
$url = AI1EC_API_URL . str_replace( '{calendar_id}', $calendar_id, $endpoint );
|
||||
return $this->request_api( $method, $url, $body, $decode_response_body, $custom_headers );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an error notification to be showed to the user on WP header of the page
|
||||
* @param $response The response got from request_api method.
|
||||
* $custom_error_message The custom message to show before the detailed message
|
||||
* @return full error message
|
||||
*/
|
||||
protected function save_error_notification( $response, $custom_error_response ) {
|
||||
$error_message = $this->_transform_error_message(
|
||||
$custom_error_response,
|
||||
$response->raw,
|
||||
$response->url,
|
||||
true
|
||||
);
|
||||
$response->error_message = $error_message;
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store( $error_message, 'error', 0, array( Ai1ec_Notification_Admin::RCPT_ADMIN ), false );
|
||||
error_log( $custom_error_response . ': ' . $error_message . ' - raw error: ' . print_r( $response->raw, true ) );
|
||||
return $error_message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an error notification to be showed to the user on WP header of the page
|
||||
* @param $response The response got from request_api method.
|
||||
* $custom_error_message The custom message to show before the detailed message
|
||||
* @return full error message
|
||||
*/
|
||||
protected function log_error( $response, $custom_error_response ) {
|
||||
$error_message = $this->_transform_error_message(
|
||||
$custom_error_response,
|
||||
$response->raw,
|
||||
$response->url,
|
||||
true
|
||||
);
|
||||
error_log( $custom_error_response . ': ' . $error_message . ' - raw error: ' . print_r( $response->raw, true ) );
|
||||
return $error_message;
|
||||
}
|
||||
|
||||
protected function show_error( $error_message ) {
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store( $error_message, 'error', 0, array( Ai1ec_Notification_Admin::RCPT_ADMIN ), false );
|
||||
error_log( $error_message);
|
||||
return $error_message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful method to check if the response of request_api is a successful message
|
||||
*/
|
||||
public function is_response_success( $response ) {
|
||||
return $response != null &&
|
||||
( !isset( $response->is_error ) || ( isset( $response->is_error ) && false === $response->is_error ) );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
class Ai1ec_Api_Features {
|
||||
|
||||
const CODE_API_ACCESS = 'api-access';
|
||||
const CODE_TICKETING = 'ticketing';
|
||||
const CODE_TWITTER = 'twitter';
|
||||
const CODE_FRONTEND_SUBMISSIONS = 'frontend-submissions';
|
||||
const CODE_CSV_IMPORT = 'csv-import';
|
||||
const CODE_SUPER_WIDGET = 'super-widget';
|
||||
const CODE_EXTENDED_VIEWS = 'extended-views';
|
||||
const CODE_BIG_FILTERING = 'big-filtering';
|
||||
const CODE_CUSTOM_FILTERS = 'custom-filter-groups';
|
||||
const CODE_DISCOVER_EVENTS = 'discover-events';
|
||||
const CODE_EVENT_PROMOTE = 'event-promote';
|
||||
const CODE_FACEBOOK_INTEGRATION = 'facebook-integration';
|
||||
const CODE_FEATURED_EVENTS = 'featured-events';
|
||||
const CODE_MAILCHIMP = 'mailchimp';
|
||||
const CODE_PHRASE_OVERRIDE = 'phrase-override';
|
||||
const CODE_POPOVERS = 'popovers';
|
||||
const CODE_SAVE_AND_SHARE = 'save-and-share';
|
||||
const CODE_VENUES = 'venues';
|
||||
const CODE_IMPORT_FEEDS = 'import-feeds';
|
||||
|
||||
public static $features = array(
|
||||
self::CODE_API_ACCESS => '',
|
||||
self::CODE_TICKETING => '',
|
||||
self::CODE_TWITTER => 'all-in-one-event-calendar-twitter-integration/all-in-one-event-calendar-twitter-integration.php',
|
||||
self::CODE_FRONTEND_SUBMISSIONS => 'all-in-one-event-calendar-frontend-submissions/all-in-one-event-calendar-frontend-submissions.php',
|
||||
self::CODE_CSV_IMPORT => 'all-in-one-event-calendar-csv-feed/all-in-one-event-calendar-csv-feed.php',
|
||||
self::CODE_SUPER_WIDGET => 'all-in-one-event-calendar-super-widget/all-in-one-event-calendar-super-widget.php',
|
||||
self::CODE_EXTENDED_VIEWS => 'all-in-one-event-calendar-extended-views/all-in-one-event-calendar-extended-views.php',
|
||||
self::CODE_BIG_FILTERING => 'all-in-one-event-calendar-big-filtering/all-in-one-event-calendar-big-filtering.php',
|
||||
self::CODE_CUSTOM_FILTERS => 'all-in-one-event-calendar-custom-filter-groups/all-in-one-event-calendar-custom-filter-groups.php',
|
||||
self::CODE_DISCOVER_EVENTS => '',
|
||||
self::CODE_EVENT_PROMOTE => 'all-in-one-event-calendar-event-promote/all-in-one-event-calendar-event-promote.php',
|
||||
self::CODE_FACEBOOK_INTEGRATION => 'all-in-one-event-calendar-facebook-integration/all-in-one-event-calendar-facebook-integration.php',
|
||||
self::CODE_FEATURED_EVENTS => 'all-in-one-event-calendar-featured-events/all-in-one-event-calendar-featured-events.php',
|
||||
self::CODE_MAILCHIMP => 'all-in-one-event-calendar-mailchimp/all-in-one-event-calendar-mailchimp.php',
|
||||
self::CODE_PHRASE_OVERRIDE => 'all-in-one-event-calendar-phrase-override/all-in-one-event-calendar-phrase-override.php',
|
||||
self::CODE_POPOVERS => 'all-in-one-event-calendar-popovers/all-in-one-event-calendar-popovers.php',
|
||||
self::CODE_SAVE_AND_SHARE => 'all-in-one-event-calendar-save-and-share/all-in-one-event-calendar-save-and-share.php',
|
||||
self::CODE_VENUES => 'all-in-one-event-calendar-venue/all-in-one-event-calendar-venue.php',
|
||||
self::CODE_IMPORT_FEEDS => '',
|
||||
);
|
||||
}
|
||||
@@ -1,321 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class for Timely API communication related to Discover Events and Feeds.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.4
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Api_Feeds extends Ai1ec_Api_Abstract {
|
||||
|
||||
// Feed status
|
||||
// c = Feed not migrated yet to API
|
||||
// a = Feed migrated to API (all events)
|
||||
// b = Feed migrated to API (individual events were selected)
|
||||
public static $FEED_NOT_MIGRATED_CODE = 'c';
|
||||
public static $FEED_API_ALL_EVENTS_CODE = 'a';
|
||||
public static $FEED_API_SOME_EVENTS_CODE = 'b';
|
||||
|
||||
/**
|
||||
* Post construction routine.
|
||||
*
|
||||
* Override this method to perform post-construction tasks.
|
||||
*
|
||||
* @return void Return from this method is ignored.
|
||||
*/
|
||||
protected function _initialize() {
|
||||
parent::_initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get static var (for PHP 5.2 compatibility)
|
||||
*
|
||||
* @param String $var
|
||||
*/
|
||||
public function getStaticVar($var) {
|
||||
return self::$$var;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getting a suggested events list.
|
||||
* @return stClass Response using the following format:
|
||||
* [total] => 10
|
||||
* [per_page] => 8
|
||||
* [current_page] => 1
|
||||
* [last_page] => 2
|
||||
* [next_page_url] =>
|
||||
* [prev_page_url] =>
|
||||
* [from] => 1
|
||||
* [to] => 8
|
||||
* [data] => Array list of suggested events
|
||||
*/
|
||||
public function get_suggested_events() {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( 0 >= $calendar_id ) {
|
||||
throw new Exception( 'Calendar ID not found' );
|
||||
}
|
||||
|
||||
$body = null;
|
||||
if (
|
||||
isset( $_POST[ 'lat' ] ) &&
|
||||
isset( $_POST[ 'lng' ] ) &&
|
||||
isset( $_POST[ 'radius' ] )
|
||||
) {
|
||||
$body = array(
|
||||
'lat' => $_POST[ 'lat' ],
|
||||
'lng' => $_POST[ 'lng' ],
|
||||
'radius' => $_POST[ 'radius' ]
|
||||
);
|
||||
}
|
||||
|
||||
$page = isset( $_POST[ 'page' ] ) ? $_POST[ 'page' ] : 1;
|
||||
$max = isset( $_POST[ 'max' ] ) ? $_POST[ 'max' ] : 8;
|
||||
$term = isset( $_POST[ 'term' ] ) && $_POST[ 'term' ]
|
||||
? urlencode( $_POST[ 'term' ] )
|
||||
: '*';
|
||||
$location = isset( $_POST[ 'location' ] ) && $_POST[ 'location' ]
|
||||
? '&location=' . urlencode( $_POST[ 'location' ] )
|
||||
: '';
|
||||
|
||||
$url = AI1EC_API_URL .
|
||||
"calendars/$calendar_id/discover/events?page=$page&max=$max&term=$term" .
|
||||
$location;
|
||||
|
||||
$response = $this->request_api( 'GET', $url,
|
||||
$body,
|
||||
true //decode body response
|
||||
);
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
return $response->body;
|
||||
} else {
|
||||
$this->save_error_notification(
|
||||
$response,
|
||||
__( 'We were unable to get the Suggested Events from Time.ly Network', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
throw new Exception( 'We were unable to get the Suggested Events from Time.ly Network' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the API to Process and Import the Feed
|
||||
*/
|
||||
public function import_feed( $entry ) {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( 0 >= $calendar_id ) {
|
||||
throw new Exception( 'Calendar ID not found' );
|
||||
}
|
||||
$response = $this->request_api( 'POST', AI1EC_API_URL . 'calendars/' . $calendar_id . '/feeds/import',
|
||||
array(
|
||||
'url' => $entry['feed_url'],
|
||||
'categories' => $entry['feed_category'],
|
||||
'tags' => $entry['feed_tags'],
|
||||
'allow_comments' => $entry['comments_enabled'],
|
||||
'show_maps' => $entry['map_display_enabled'],
|
||||
'import_any_tag_and_categories' => $entry['keep_tags_categories'],
|
||||
'preserve_imported_events' => $entry['keep_old_events'],
|
||||
'assign_default_utc' => $entry['import_timezone']
|
||||
)
|
||||
);
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
// Refresh list of subscriptions and limits
|
||||
$this->get_subscriptions( true );
|
||||
|
||||
return $response->body;
|
||||
} else {
|
||||
$this->save_error_notification(
|
||||
$response,
|
||||
__( 'We were unable to import feed', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
throw new Exception( $this->get_api_error_msg( $response->raw ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the API to get the feed
|
||||
*/
|
||||
public function get_feed( $feed_id ) {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( 0 >= $calendar_id ) {
|
||||
throw new Exception( 'Calendar ID not found' );
|
||||
}
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'calendars/' . $calendar_id . '/feeds/get/' . $feed_id,
|
||||
array( 'max' => '9999' )
|
||||
);
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
return $response->body;
|
||||
} else {
|
||||
$this->save_error_notification(
|
||||
$response,
|
||||
__( 'We were unable to get feed data', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
throw new Exception( $this->get_api_error_msg( $response->raw ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the API to get list of feed subscriptions
|
||||
*/
|
||||
public function get_feed_subscriptions( $force_refresh = false ) {
|
||||
$feeds_subscriptions = get_transient( 'ai1ec_api_feeds_subscriptions' );
|
||||
|
||||
if ( $force_refresh || false === $feeds_subscriptions ) {
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'calendars/' . $this->_get_ticket_calendar() . '/feeds/list',
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$feeds_subscriptions = (array) $response->body;
|
||||
} else {
|
||||
$feeds_subscriptions = array();
|
||||
}
|
||||
|
||||
// Save for 5 minutes
|
||||
$minutes = 5;
|
||||
set_transient( 'ai1ec_api_feeds_subscriptions', $feeds_subscriptions, $minutes * 60 );
|
||||
}
|
||||
|
||||
return $feeds_subscriptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync feed subscriptions
|
||||
*/
|
||||
public function get_and_sync_feed_subscriptions() {
|
||||
$feeds_subscriptions = $this->get_feed_subscriptions();
|
||||
|
||||
$db = $this->_registry->get( 'dbi.dbi' );
|
||||
$table_name = $db->get_table_name( 'ai1ec_event_feeds' );
|
||||
|
||||
// Select all feeds
|
||||
$rows = $db->select(
|
||||
$table_name,
|
||||
array(
|
||||
'feed_id',
|
||||
'feed_url',
|
||||
'feed_name',
|
||||
'feed_category',
|
||||
'feed_tags',
|
||||
'comments_enabled',
|
||||
'map_display_enabled',
|
||||
'keep_tags_categories',
|
||||
'keep_old_events',
|
||||
'import_timezone'
|
||||
)
|
||||
);
|
||||
|
||||
// Iterate over API response
|
||||
foreach( $feeds_subscriptions as $api_feed ) {
|
||||
$found = false;
|
||||
|
||||
foreach ( $rows as $row ) {
|
||||
// Check if URL is the same
|
||||
if ( trim( $row->feed_url ) === trim( $api_feed->url ) ) {
|
||||
$found = true;
|
||||
|
||||
// Update feed
|
||||
$db->update(
|
||||
$table_name,
|
||||
array(
|
||||
'comments_enabled' => $api_feed->allow_comments,
|
||||
'map_display_enabled' => $api_feed->show_maps,
|
||||
'keep_tags_categories' => $api_feed->import_any_tag_and_categories,
|
||||
'keep_old_events' => $api_feed->preserve_imported_events,
|
||||
'import_timezone' => $api_feed->assign_default_utc,
|
||||
'feed_name' => $api_feed->feed_id
|
||||
),
|
||||
array(
|
||||
'feed_id' => $row->feed_id
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Not found in local database.. Insert
|
||||
if ( ! $found ) {
|
||||
$entry = array(
|
||||
'feed_url' => $api_feed->url,
|
||||
'feed_name' => $api_feed->feed_id,
|
||||
'feed_category' => $api_feed->categories,
|
||||
'feed_tags' => $api_feed->tags,
|
||||
'comments_enabled' => $api_feed->allow_comments,
|
||||
'map_display_enabled' => $api_feed->show_maps,
|
||||
'keep_tags_categories' => $api_feed->import_any_tag_and_categories,
|
||||
'keep_old_events' => $api_feed->preserve_imported_events,
|
||||
'import_timezone' => $api_feed->assign_default_utc
|
||||
);
|
||||
$format = array( '%s', '%s', '%s', '%s', '%d', '%d', '%d', '%d', '%d' );
|
||||
$db->insert(
|
||||
$table_name,
|
||||
$entry,
|
||||
$format
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the API to subscribe feed
|
||||
*/
|
||||
public function subscribe_feed( $feed_id, $feed_event_uid = '' ) {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( 0 >= $calendar_id ) {
|
||||
throw new Exception( 'Calendar ID not found' );
|
||||
}
|
||||
|
||||
$response = $this->request_api( 'POST', AI1EC_API_URL . 'calendars/' . $calendar_id . '/feeds/subscribe',
|
||||
array(
|
||||
'feed_id' => $feed_id,
|
||||
'feed_event_uid' => $feed_event_uid
|
||||
)
|
||||
);
|
||||
|
||||
// Refresh list of subscriptions and limits
|
||||
$this->get_subscriptions( true );
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
return $response->body;
|
||||
} else {
|
||||
$this->save_error_notification(
|
||||
$response,
|
||||
__( 'We were unable to subscribe feed', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
throw new Exception( $this->get_api_error_msg( $response->raw ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the API to unsubscribe feed
|
||||
*/
|
||||
public function unsubscribe_feed( $feed_id, $feed_event_uid = '' ) {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( 0 >= $calendar_id ) {
|
||||
throw new Exception( 'Calendar ID not found' );
|
||||
}
|
||||
|
||||
$response = $this->request_api( 'POST', AI1EC_API_URL . 'calendars/' . $calendar_id . '/feeds/unsubscribe',
|
||||
array(
|
||||
'feed_id' => $feed_id,
|
||||
'feed_event_uid' => $feed_event_uid
|
||||
)
|
||||
);
|
||||
|
||||
// Refresh list of subscriptions and limits
|
||||
$this->get_subscriptions( true );
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
return $response->body;
|
||||
} else {
|
||||
$this->save_error_notification(
|
||||
$response,
|
||||
__( 'We were unable to unsubscribe feed', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
throw new Exception( $this->get_api_error_msg( $response->raw ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class for Timely API communication for Registration.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.4
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Api_Registration extends Ai1ec_Api_Abstract {
|
||||
|
||||
/**
|
||||
* Post construction routine.
|
||||
*
|
||||
* Override this method to perform post-construction tasks.
|
||||
*
|
||||
* @return void Return from this method is ignored.
|
||||
*/
|
||||
protected function _initialize() {
|
||||
parent::_initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
public function signin() {
|
||||
$body['email'] = $_POST['ai1ec_email'];
|
||||
$body['password'] = $_POST['ai1ec_password'];
|
||||
$body['calendar_type'] = $_POST['ai1ec_calendar_type'];
|
||||
$response = $this->request_api( 'POST', AI1EC_API_URL . 'auth/authenticate', $body, true, array( 'Authorization' => null ) );
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$response_body = (array) $response->body;
|
||||
// Save calendar ID as 0 first, otherwise the auth data won't be saved in the database before creating/finding the calendar
|
||||
$this->save_ticketing_settings( $response_body['message'], true, $response_body['auth_token'], 0, $body['email'] );
|
||||
// Now save the calendar ID
|
||||
$this->save_calendar_id( $this->_get_ticket_calendar() );
|
||||
$this->has_payment_settings();
|
||||
$this->get_subscriptions( true );
|
||||
$this->sync_api_settings();
|
||||
} else {
|
||||
$error_message = $this->save_error_notification( $response, __( 'We were unable to Sign you In for Time.ly Network', AI1EC_PLUGIN_NAME ) );
|
||||
$this->save_ticketing_settings( $error_message, false, '', 0, null );
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
public function signup() {
|
||||
$body['name'] = $_POST['ai1ec_name'];
|
||||
$body['email'] = $_POST['ai1ec_email'];
|
||||
$body['password'] = $_POST['ai1ec_password'];
|
||||
$body['password_confirmation'] = $_POST['ai1ec_password_confirmation'];
|
||||
$body['phone'] = $_POST['ai1ec_phone'];
|
||||
$body['calendar_type'] = $_POST['ai1ec_calendar_type'];
|
||||
$body['terms'] = $_POST['ai1ec_terms'];
|
||||
$response = $this->request_api( 'POST', AI1EC_API_URL . 'auth/register', $body, true );
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$response_body = (array) $response->body;
|
||||
// Save calendar ID as 0 first, otherwise the auth data won't be saved in the database before creating the calendar
|
||||
$this->save_ticketing_settings( $response_body['Registration'], true, $response_body['auth_token'] , 0, $body['email'] );
|
||||
// Now save the calendar ID
|
||||
$this->save_calendar_id( $this->_create_calendar() );
|
||||
$this->has_payment_settings();
|
||||
$this->get_subscriptions( true );
|
||||
$this->sync_api_settings();
|
||||
} else {
|
||||
$error_message = $this->save_error_notification( $response, __( 'We were unable to Sign you Up for Time.ly Network', AI1EC_PLUGIN_NAME ) );
|
||||
$this->save_ticketing_settings( $error_message, false, '', 0, null );
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
protected function availability() {
|
||||
$api_features = get_transient( 'ai1ec_api_features' );
|
||||
|
||||
if ( false === $api_features || ( defined( 'AI1EC_DEBUG' ) && AI1EC_DEBUG ) ) {
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'feature/availability', null, true );
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$api_features = (array) $response->body;
|
||||
} else {
|
||||
$api_features = array();
|
||||
}
|
||||
|
||||
// Save for 5 minutes
|
||||
$minutes = 5;
|
||||
set_transient( 'ai1ec_api_features', $api_features, $minutes * 60 );
|
||||
}
|
||||
|
||||
return $api_features;
|
||||
}
|
||||
|
||||
protected function is_feature_available( $feature_code ) {
|
||||
$availability = $this->availability();
|
||||
|
||||
if ( ! is_null( $availability ) ) {
|
||||
foreach ( $availability as $value ) {
|
||||
if ( isset( $value->code ) && $feature_code === $value->code
|
||||
&& isset( $value->available ) && true === $value->available ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
protected function settings() {
|
||||
$calendar_settings = get_transient( 'ai1ec_calendar_settings' );
|
||||
|
||||
if ( false === $calendar_settings || ( defined( 'AI1EC_DEBUG' ) && AI1EC_DEBUG ) ) {
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'calendars/' . $this->_get_ticket_calendar() . '/settings', null, true );
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$calendar_settings = (array) $response->body;
|
||||
} else {
|
||||
$calendar_settings = array();
|
||||
}
|
||||
|
||||
// Save for 5 minutes
|
||||
$minutes = 5;
|
||||
set_transient( 'ai1ec_calendar_settings', $calendar_settings, $minutes * 60 );
|
||||
}
|
||||
|
||||
return $calendar_settings;
|
||||
}
|
||||
|
||||
public function is_api_sign_up_available() {
|
||||
return $this->is_feature_available( Ai1ec_Api_Features::CODE_API_ACCESS );
|
||||
}
|
||||
|
||||
public function is_ticket_available() {
|
||||
return $this->is_feature_available( Ai1ec_Api_Features::CODE_TICKETING );
|
||||
}
|
||||
|
||||
public function is_ticket_enabled() {
|
||||
return $this->has_subscription_active( Ai1ec_Api_Features::CODE_TICKETING );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the ticketing settings on WP database only
|
||||
*/
|
||||
public function signout() {
|
||||
$calendar_id = $this->_get_ticket_calendar( false );
|
||||
if ( 0 >= $calendar_id ) {
|
||||
$this->clear_ticketing_settings();
|
||||
return false;
|
||||
}
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'calendars/' . $calendar_id . '/signout', null, true );
|
||||
// Consider "Unauthorized" status (401) a valid response
|
||||
if ( $this->is_response_success( $response ) || 401 === wp_remote_retrieve_response_code( $response->raw ) ) {
|
||||
$this->clear_ticketing_settings();
|
||||
return array( 'message' => '' );
|
||||
} else {
|
||||
$error_message = $this->save_error_notification( $response, __( 'We were unable to Sign you Out of Time.ly Network', AI1EC_PLUGIN_NAME ) );
|
||||
return array( 'message' => $error_message );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body from API.
|
||||
*/
|
||||
public function save_payment_preferences() {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( 0 >= $calendar_id ) {
|
||||
return false;
|
||||
}
|
||||
$settings = array(
|
||||
'payment_method' => $_POST['ai1ec_payment_method'],
|
||||
'paypal_email' => $_POST['ai1ec_paypal_email'],
|
||||
'first_name' => $_POST['ai1ec_first_name'],
|
||||
'last_name' => $_POST['ai1ec_last_name'],
|
||||
'currency' => $_POST['ai1ec_currency']
|
||||
);
|
||||
$custom_headers['content-type'] = 'application/x-www-form-urlencoded';
|
||||
$response = $this->request_api( 'PUT', AI1EC_API_URL . 'calendars/' . $calendar_id . '/payment',
|
||||
$settings,
|
||||
true, //decode response body
|
||||
$custom_headers
|
||||
);
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$this->save_payment_settings( $settings );
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store(
|
||||
__( 'Payment preferences were saved.', AI1EC_PLUGIN_NAME ),
|
||||
'updated',
|
||||
0,
|
||||
array( Ai1ec_Notification_Admin::RCPT_ADMIN ),
|
||||
false
|
||||
);
|
||||
return $response->body;
|
||||
} else {
|
||||
$this->save_error_notification( $response,
|
||||
__( 'Payment preferences were not saved.', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function _order_comparator( $order1, $order2 ) {
|
||||
return strcmp( $order1->created_at, $order2->created_at ) * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
public function get_purchases() {
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'calendars/' . $this->_get_ticket_calendar() . '/sales',
|
||||
null, //body
|
||||
true //decode response body
|
||||
);
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$result = $response->body;
|
||||
if ( isset( $result->orders ) ) {
|
||||
usort( $result->orders, array( "Ai1ec_Api_Registration", "_order_comparator" ) );
|
||||
return $result->orders;
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
} else {
|
||||
$this->save_error_notification( $response,
|
||||
__( 'We were unable to get the Sales information from Time.ly Network', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync settings from API after signing in
|
||||
*/
|
||||
public function sync_api_settings() {
|
||||
// Sync feeds subscriptions
|
||||
try {
|
||||
$api_feed = $this->_registry->get( 'model.api.api-feeds' );
|
||||
$api_feed->get_and_sync_feed_subscriptions();
|
||||
} catch ( Exception $e ) {
|
||||
$error_message = 'Some feeds were not imported to Time.ly Network. Error: ' . $e->getMessage();
|
||||
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store( $error_message, 'error', 0, array( Ai1ec_Notification_Admin::RCPT_ADMIN ), false );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
<?php
|
||||
class Ai1ec_Api_Settings {
|
||||
const FACEBOOK_API_KEY = 'facebook_api_key';
|
||||
}
|
||||
@@ -1,901 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class for Timely API communication for Ticketing.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.4
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Api_Ticketing extends Ai1ec_Api_Abstract {
|
||||
|
||||
const API_EVENT_DATA = '_ai1ec_api_event_id';
|
||||
|
||||
const ATTR_EVENT_ID = 'api_event_id';
|
||||
const ATTR_THUMBNAIL_ID = 'thumbnail_id';
|
||||
const ATTR_ICS_CHECKOUT_URL = 'ics_checkout_url';
|
||||
const ATTR_ICS_API_URL = 'ics_api_url';
|
||||
const ATTR_ACCOUNT = 'account';
|
||||
const ATTR_CALENDAR_ID = 'calendar_id';
|
||||
const ATTR_CURRENCY = 'currency';
|
||||
|
||||
const MAX_TICKET_TO_BUY_DEFAULT = 25;
|
||||
|
||||
/**
|
||||
* Post construction routine.
|
||||
*
|
||||
* Override this method to perform post-construction tasks.
|
||||
*
|
||||
* @return void Return from this method is ignored.
|
||||
*/
|
||||
protected function _initialize() {
|
||||
parent::_initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the valid Tickets Types (not removed) included inside the Ticket Event
|
||||
*/
|
||||
private function _count_valid_tickets( $post_ticket_types ) {
|
||||
if (false === isset( $post_ticket_types ) || 0 === count( $post_ticket_types ) ) {
|
||||
return 0;
|
||||
} else {
|
||||
$count = 0;
|
||||
foreach ( $post_ticket_types as $ticket_type_ite ) {
|
||||
if ( !isset( $ticket_type_ite['remove'] ) ) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an error if the Ticket Event is not owned by the Current account
|
||||
*/
|
||||
private function _prevent_update_ticket_event( Ai1ec_Event $event, $ajax_action = false ) {
|
||||
if ( $this->is_ticket_event_imported( $event->get( 'post_id' ) ) ) {
|
||||
//prevent changes on Ticket Events that were imported
|
||||
$error = __( 'This Event was replicated from another site. Changes are not allowed.', AI1EC_PLUGIN_NAME );
|
||||
if ( ! $ajax_action ) {
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store(
|
||||
$error,
|
||||
'error',
|
||||
0,
|
||||
array( Ai1ec_Notification_Admin::RCPT_ADMIN ),
|
||||
false
|
||||
);
|
||||
}
|
||||
return $error;
|
||||
}
|
||||
if ( $this->is_ticket_event_from_another_account( $event->get( 'post_id' ) ) ) {
|
||||
//prevent changes on Ticket Events that were imported
|
||||
$error = sprintf(
|
||||
__( 'This Event was created using a different account %s. Changes are not allowed.', AI1EC_PLUGIN_NAME ),
|
||||
$this->get_api_event_account( $event->get( 'post_id' ) )
|
||||
);
|
||||
if ( ! $ajax_action ) {
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store(
|
||||
$error,
|
||||
'error',
|
||||
0,
|
||||
array( Ai1ec_Notification_Admin::RCPT_ADMIN ),
|
||||
false
|
||||
);
|
||||
}
|
||||
return $error;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run some validations inside the _POST request to check if the Event
|
||||
* submmited is a valid event for Tickets
|
||||
* @return NULL in case of success or a Message in case of error
|
||||
*/
|
||||
private function _is_valid_post( Ai1ec_Event $event, $updating ) {
|
||||
$message = null;
|
||||
if ( ( isset( $_POST['ai1ec_rdate'] ) && ! empty( $_POST['ai1ec_rdate'] ) ) ||
|
||||
( isset( $_POST['ai1ec_repeat'] ) && ! empty( $_POST['ai1ec_repeat'] ) )
|
||||
) {
|
||||
$message = __( 'The Repeat option was selected but recurrence is not supported by Event with Tickets.', AI1EC_PLUGIN_NAME );
|
||||
} else if ( isset( $_POST['ai1ec_tickets_loading_error'] ) ) {
|
||||
//do not update tickets because is unsafe. There was a problem to load the tickets,
|
||||
//the customer received the same message when the event was loaded.
|
||||
$message = $_POST['ai1ec_tickets_loading_error'];
|
||||
} else if ( false === ai1ec_is_blank( $event->get( 'ical_feed_url' ) ) ) {
|
||||
//prevent ticket creating inside Regular Events Imported events
|
||||
$message = __( 'This Event was replicated from another site. Any changes on Tickets were discarded.', AI1EC_PLUGIN_NAME );
|
||||
} else {
|
||||
$error = $this->_prevent_update_ticket_event( $event );
|
||||
if ( null !== $error ) {
|
||||
$message = $error;
|
||||
} else if ( ! isset( $_POST['ai1ec_tickets'] ) || 0 === $this->_count_valid_tickets( $_POST['ai1ec_tickets'] ) ) {
|
||||
$message = __( 'The Event has the cost option Ticket selected but no ticket was included.', AI1EC_PLUGIN_NAME );
|
||||
} else if ( false === $this->has_payment_settings() ) {
|
||||
$message = __( 'You need to save the payments settings to create ticket events.', AI1EC_PLUGIN_NAME );
|
||||
} else if ( ! isset( $_POST['tax_options'] ) && ! $updating ) {
|
||||
$message = __( 'Tax and Invoice options are required.', AI1EC_PLUGIN_NAME );
|
||||
}
|
||||
}
|
||||
if ( null !== $message ) {
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store( $message, 'error', 0, array( Ai1ec_Notification_Admin::RCPT_ADMIN ), false );
|
||||
return $message;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or update a Ticket Event on API server
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
public function store_event( Ai1ec_Event $event, WP_Post $post, $updating ) {
|
||||
|
||||
$error = $this->_is_valid_post( $event, $updating );
|
||||
if ( null !== $error ) {
|
||||
return $error;
|
||||
}
|
||||
$api_event_id = $this->get_api_event_id( $event->get( 'post_id' ) );
|
||||
$is_new = ! $api_event_id;
|
||||
$fields = array( 'visibility' => $_POST['visibility'] );
|
||||
if ( isset( $_POST['tax_options'] ) ) {
|
||||
$fields['tax_options'] = $_POST['tax_options'];
|
||||
}
|
||||
$body_data = $this->parse_event_fields_to_api_structure(
|
||||
$event,
|
||||
$post,
|
||||
$_POST['ai1ec_tickets'],
|
||||
$fields
|
||||
);
|
||||
$url = AI1EC_API_URL . 'events';
|
||||
if ( $api_event_id ) {
|
||||
$url = $url . '/' . $api_event_id;
|
||||
}
|
||||
|
||||
//get the thumbnail id saved previously
|
||||
$api_data = $this->get_api_event_data( $event->get( 'post_id' ) );
|
||||
if ( isset( $api_data[self::ATTR_THUMBNAIL_ID] ) ) {
|
||||
$event_thumbnail_id = $api_data[self::ATTR_THUMBNAIL_ID];
|
||||
} else {
|
||||
$event_thumbnail_id = 0;
|
||||
}
|
||||
//get the current thumbnail id
|
||||
$post_thumbnail_id = get_post_thumbnail_id( $event->get( 'post_id' ) );
|
||||
if ( false === isset( $post_thumbnail_id ) ) {
|
||||
$post_thumbnail_id = 0;
|
||||
}
|
||||
$update_image = ( $event_thumbnail_id !== $post_thumbnail_id );
|
||||
$payload = '';
|
||||
$custom_headers = null;
|
||||
|
||||
if ( true === $update_image && 0 < $post_thumbnail_id ) {
|
||||
$boundary = wp_generate_password( 24 );
|
||||
$custom_headers['Content-Type'] = 'multipart/form-data; boundary=' . $boundary;
|
||||
$body_data['update_image'] = '1';
|
||||
foreach ($body_data as $key => $value) {
|
||||
if ( is_array( $value ) ) {
|
||||
$index = 0;
|
||||
foreach ( $value as $arr_key => $arr_value ) {
|
||||
if ( is_array( $arr_value ) ) {
|
||||
foreach ( $arr_value as $child_key => $child_value ) {
|
||||
$payload .= '--' . $boundary;
|
||||
$payload .= "\r\n";
|
||||
$payload .= 'Content-Disposition: form-data; name="' . $key . '[' . $index . '][' . $child_key . ']"' . "\r\n";
|
||||
$payload .= "\r\n";
|
||||
$payload .= $child_value;
|
||||
$payload .= "\r\n";
|
||||
}
|
||||
} else {
|
||||
$payload .= '--' . $boundary;
|
||||
$payload .= "\r\n";
|
||||
$payload .= 'Content-Disposition: form-data; name="tax_options[' . $arr_key . ']"' . "\r\n";
|
||||
$payload .= "\r\n";
|
||||
$payload .= $arr_value;
|
||||
$payload .= "\r\n";
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
} else {
|
||||
$payload .= '--' . $boundary;
|
||||
$payload .= "\r\n";
|
||||
$payload .= 'Content-Disposition: form-data; name="' . $key . '"' . "\r\n";
|
||||
$payload .= "\r\n";
|
||||
$payload .= $value;
|
||||
$payload .= "\r\n";
|
||||
}
|
||||
}
|
||||
$file_path = get_attached_file ( $post_thumbnail_id );
|
||||
$file_type = wp_check_filetype ( $file_path );
|
||||
$payload .= '--' . $boundary;
|
||||
$payload .= "\r\n";
|
||||
$payload .= 'Content-Disposition: form-data; name="image_id"; filename="' . basename( $file_path ) . '"' . "\r\n";
|
||||
$payload .= 'Content-Type: ' . $file_type['type'] . "\r\n";
|
||||
$payload .= "\r\n";
|
||||
$payload .= file_get_contents( $file_path );
|
||||
$payload .= "\r\n";
|
||||
$payload .= '--' . $boundary . '--';
|
||||
} else {
|
||||
$body_data['update_image'] = (true === $update_image) ? '1' : '0';
|
||||
$payload = $body_data;
|
||||
}
|
||||
$response = $this->request_api( 'POST', $url, $payload,
|
||||
true, //true to decode response body
|
||||
$custom_headers
|
||||
);
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$api_event_id = $response->body->id;
|
||||
if ( isset( $response->body->currency ) ) {
|
||||
$currency = $response->body->currency;
|
||||
} else {
|
||||
$currency = 'USD';
|
||||
}
|
||||
$currency = $response->body->currency;
|
||||
if ( $post_thumbnail_id <= 0 ) {
|
||||
$post_thumbnail_id = null;
|
||||
}
|
||||
$this->save_api_event_data( $event->get( 'post_id') , $api_event_id, null, null, $currency, $post_thumbnail_id );
|
||||
return true;
|
||||
} else {
|
||||
$error_message = '';
|
||||
if ( $is_new ) {
|
||||
$error_message = __( 'We were unable to create the Event on Time.ly Ticketing', AI1EC_PLUGIN_NAME );
|
||||
} else {
|
||||
$error_message = __( 'We were unable to update the Event on Time.ly Ticketing', AI1EC_PLUGIN_NAME );
|
||||
}
|
||||
return $this->save_error_notification( $response, $error_message );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the fields of an Event to the structure used by API
|
||||
*/
|
||||
public function parse_event_fields_to_api_structure( Ai1ec_Event $event , WP_Post $post, $post_ticket_types, $api_fields_values ) {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( $calendar_id <= 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//fields of ai1ec events table used by API
|
||||
$body['latitude'] = $event->get( 'latitude' );
|
||||
$body['longitude'] = $event->get( 'longitude' );
|
||||
$body['post_id'] = $event->get( 'post_id' );
|
||||
$body['calendar_id'] = $calendar_id;
|
||||
$body['dtstart'] = $event->get( 'start' )->format_to_javascript();
|
||||
$body['dtend'] = $event->getenddate()->format_to_javascript();
|
||||
$body['timezone'] = $event->get( 'timezone_name' );
|
||||
$body['venue_name'] = $event->get( 'venue' );
|
||||
$body['address'] = $event->get( 'address' );
|
||||
$body['city'] = $event->get( 'city' );
|
||||
$body['province'] = $event->get( 'province' );
|
||||
$body['postal_code'] = $event->get( 'postal_code' );
|
||||
$body['country'] = $event->get( 'country' );
|
||||
$body['contact_name'] = $event->get( 'contact_name' );
|
||||
$body['contact_phone'] = $event->get( 'contact_phone' );
|
||||
$body['contact_email'] = $event->get( 'contact_email' );
|
||||
$body['contact_website'] = $event->get( 'contact_url' );
|
||||
$body['uid'] = $event->get_uid();
|
||||
$body['title'] = $post->post_title;
|
||||
$body['description'] = $post->post_content;
|
||||
$body['url'] = get_permalink( $post->ID );
|
||||
$body['status'] = $post->post_status;
|
||||
|
||||
$utc_current_time = $this->_registry->get( 'date.time')->format_to_javascript();
|
||||
$body['created_at'] = $utc_current_time;
|
||||
$body['updated_at'] = $utc_current_time;
|
||||
|
||||
//removing blank values
|
||||
foreach ($body as $key => $value) {
|
||||
if ( ai1ec_is_blank( $value ) ) {
|
||||
unset( $body[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_null( $api_fields_values ) || 0 == count( $api_fields_values ) ) {
|
||||
$api_fields_values = array( 'status' => 'closed', 'ai1ec_version' => AI1EC_VERSION );
|
||||
} else {
|
||||
if ( ! isset( $api_fields_values['ai1ec_version'] ) ) {
|
||||
$api_fields_values['ai1ec_version'] = AI1EC_VERSION;
|
||||
}
|
||||
foreach ( $api_fields_values as $key => $value ) {
|
||||
$body[$key] = $api_fields_values[$key];
|
||||
if ( 'visibility' === $key ) {
|
||||
if ( 0 === strcasecmp( 'private', $value ) ) {
|
||||
$body['status'] = 'private';
|
||||
} else if ( 0 === strcasecmp( 'password', $value ) ) {
|
||||
$body['status'] = 'password';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tickets_types = array();
|
||||
if ( ! is_null( $post_ticket_types ) ) {
|
||||
$index = 0;
|
||||
foreach ( $post_ticket_types as $ticket_type_ite ) {
|
||||
if ( false === isset( $ticket_type_ite['id'] ) &&
|
||||
isset( $ticket_type_ite['remove'] ) ) {
|
||||
//ignoring new tickets that didn't go to api yet
|
||||
continue;
|
||||
}
|
||||
$tickets_types[$index++] = $this->_parse_tickets_type_post_to_api_structure(
|
||||
$ticket_type_ite,
|
||||
$event
|
||||
);
|
||||
}
|
||||
}
|
||||
$body['ticket_types'] = $tickets_types;
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the fields of a Ticket Type to the structure used by API
|
||||
*/
|
||||
protected function _parse_tickets_type_post_to_api_structure( $ticket_type_ite, $event ) {
|
||||
$utc_current_time = $this->_registry->get( 'date.time' )->format_to_javascript();
|
||||
if ( isset( $ticket_type_ite['id'] ) ) {
|
||||
$ticket_type['id'] = $ticket_type_ite['id'];
|
||||
$ticket_type['created_at'] = $ticket_type_ite['created_at'];
|
||||
} else {
|
||||
$ticket_type['created_at'] = $utc_current_time;
|
||||
}
|
||||
if ( isset( $ticket_type_ite['remove'] ) ) {
|
||||
$ticket_type['deleted_at'] = $utc_current_time;
|
||||
}
|
||||
$ticket_type['name'] = $ticket_type_ite['ticket_name'];
|
||||
$ticket_type['description'] = $ticket_type_ite['description'];
|
||||
$ticket_type['price'] = $ticket_type_ite['ticket_price'];
|
||||
if ( 0 === strcasecmp( 'on', $ticket_type_ite['unlimited'] ) ) {
|
||||
$ticket_type['quantity'] = null;
|
||||
} else {
|
||||
$ticket_type['quantity'] = $ticket_type_ite['quantity'];
|
||||
}
|
||||
$ticket_type['buy_min_qty'] = $ticket_type_ite['buy_min_limit'];
|
||||
if ( ai1ec_is_blank( $ticket_type_ite['buy_max_limit'] ) ) {
|
||||
$ticket_type['buy_max_qty'] = null;
|
||||
} else {
|
||||
$ticket_type['buy_max_qty'] = $ticket_type_ite['buy_max_limit'];
|
||||
}
|
||||
if ( 0 === strcasecmp( 'on', $ticket_type_ite['availibility'] ) ) {
|
||||
//immediate availability
|
||||
$timezone_start_time = $this->_registry->get( 'date.time' );
|
||||
$timezone_start_time->set_timezone( $event->get('timezone_name') );
|
||||
$ticket_type['immediately'] = true;
|
||||
$ticket_type['sale_start_date'] = $timezone_start_time->format_to_javascript( $event->get('timezone_name') );
|
||||
$ticket_type['sale_end_date'] = $event->get( 'end' )->format_to_javascript();
|
||||
} else {
|
||||
$ticket_type['immediately'] = false;
|
||||
$ticket_type['sale_start_date'] = $ticket_type_ite['ticket_sale_start_date'];
|
||||
$ticket_type['sale_end_date'] = $ticket_type_ite['ticket_sale_end_date'];
|
||||
}
|
||||
$ticket_type['updated_at'] = $utc_current_time;
|
||||
$ticket_type['status'] = $ticket_type_ite['ticket_status'];
|
||||
return $ticket_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unparse the fields of API structure to the Ticket Type
|
||||
*/
|
||||
protected function _unparse_tickets_type_from_api_structure( $ticket_type_api ) {
|
||||
$ticket_type = $ticket_type_api;
|
||||
$ticket_type->ticket_name = $ticket_type_api->name;
|
||||
$ticket_type->ticket_price = $ticket_type_api->price;
|
||||
$ticket_type->buy_min_limit = $ticket_type_api->buy_min_qty;
|
||||
if ( null === $ticket_type_api->buy_max_qty ) {
|
||||
$ticket_type->buy_max_limit = self::MAX_TICKET_TO_BUY_DEFAULT;
|
||||
} else {
|
||||
$ticket_type->buy_max_limit = $ticket_type_api->buy_max_qty;
|
||||
}
|
||||
if ( true === ( ( bool ) $ticket_type_api->immediately ) ) {
|
||||
$ticket_type->availibility = 'on';
|
||||
} else {
|
||||
$ticket_type->availibility = 'off';
|
||||
}
|
||||
$ticket_type->ticket_sale_start_date = $ticket_type_api->sale_start_date; //YYYY-MM-YY HH:NN:SS
|
||||
$ticket_type->ticket_sale_end_date = $ticket_type_api->sale_end_date; //YYYY-MM-YY HH:NN:SS
|
||||
$ticket_type->ticket_status = $ticket_type_api->status;
|
||||
if ( 'open' === $ticket_type_api->status ) {
|
||||
$ticket_type->ticket_status_label = __( 'Open for sale', AI1EC_PLUGIN_NAME );
|
||||
} else if ( 'closed' === $ticket_type_api->status ) {
|
||||
$ticket_type->ticket_status_label = __( 'Sale ended', AI1EC_PLUGIN_NAME );
|
||||
} else if ( 'canceled' === $ticket_type_api->status ) {
|
||||
$ticket_type->ticket_status_label = __( 'Canceled', AI1EC_PLUGIN_NAME );
|
||||
} else {
|
||||
$ticket_type->ticket_status_label = $ticket_type_api->status;
|
||||
}
|
||||
if ( false === isset( $ticket_type_api->quantity ) ||
|
||||
null === $ticket_type_api->quantity ) {
|
||||
$ticket_type->unlimited = 'on';
|
||||
} else {
|
||||
$ticket_type->unlimited = 'off';
|
||||
}
|
||||
$ticket_type->ticket_type_id = $ticket_type_api->id;
|
||||
$ticket_type->available = $ticket_type_api->available;
|
||||
$ticket_type->availability = $this->_parse_availability_message( $ticket_type_api->availability );
|
||||
|
||||
//derived property to set the max quantity of dropdown
|
||||
if ( $ticket_type->available !== null ) {
|
||||
if ( $ticket_type->available > $ticket_type->buy_max_limit ) {
|
||||
$ticket_type->buy_max_available = $ticket_type->buy_max_limit;
|
||||
} else {
|
||||
$ticket_type->buy_max_available = $ticket_type->available;
|
||||
}
|
||||
} else {
|
||||
$ticket_type->buy_max_available = $ticket_type->buy_max_limit;
|
||||
}
|
||||
return $ticket_type;
|
||||
}
|
||||
|
||||
public function _parse_availability_message( $availability ){
|
||||
if ( ai1ec_is_blank ( $availability ) ) {
|
||||
return null;
|
||||
} else {
|
||||
switch ($availability) {
|
||||
case 'past_event':
|
||||
return __( 'Past Event' );
|
||||
case 'event_closed':
|
||||
return __( 'Event closed' );
|
||||
case 'not_available_yet':
|
||||
return __( 'Not available yet' );
|
||||
case 'sale_closed':
|
||||
return __( 'Sale closed' );
|
||||
case 'sold_out':
|
||||
return __( 'Sold out' );
|
||||
default:
|
||||
return __( 'Not available' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function get_event( $post_id ) {
|
||||
$api_event_id = $this->get_api_event_id( $post_id );
|
||||
if ( ! $api_event_id ) {
|
||||
return (object) array( 'data' => array() );
|
||||
}
|
||||
$response = $this->request_api( 'GET', $this->get_api_event_url( $post_id ) . 'events/' . $api_event_id . '/edit' );
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
if ( isset( $response->body->ticket_types ) ) {
|
||||
foreach ( $response->body->ticket_types as $ticket_api ) {
|
||||
$this->_unparse_tickets_type_from_api_structure( $ticket_api );
|
||||
}
|
||||
}
|
||||
return (object) array( 'data' => $response->body );
|
||||
} else {
|
||||
$error_message = $this->_transform_error_message(
|
||||
__( 'We were unable to get the Event Details from Time.ly Ticketing', AI1EC_PLUGIN_NAME ),
|
||||
$response->raw, $response->url,
|
||||
true
|
||||
);
|
||||
return (object) array( 'data' => array(), 'error' => $error_message );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string JSON.
|
||||
*/
|
||||
public function get_ticket_types( $post_id, $get_canceled = true ) {
|
||||
$api_event_id = $this->get_api_event_id( $post_id );
|
||||
if ( ! $api_event_id ) {
|
||||
return json_encode( array( 'data' => array() ) );
|
||||
}
|
||||
$response = $this->request_api( 'GET', $this->get_api_event_url( $post_id ) . 'events/' . $api_event_id . '/ticket_types',
|
||||
array( 'get_canceled' => ( true === $get_canceled ? 1 : 0 ) )
|
||||
);
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
if ( isset( $response->body->ticket_types ) ) {
|
||||
foreach ( $response->body->ticket_types as $ticket_api ) {
|
||||
$this->_unparse_tickets_type_from_api_structure( $ticket_api );
|
||||
}
|
||||
return json_encode( array( 'data' => $response->body->ticket_types ) );
|
||||
} else {
|
||||
return json_encode( array( 'data' => array() ) );
|
||||
}
|
||||
} else {
|
||||
$error_message = $this->_transform_error_message(
|
||||
__( 'We were unable to get the Tickets Details from Time.ly Ticketing', AI1EC_PLUGIN_NAME ),
|
||||
$response->raw, $response->url,
|
||||
true
|
||||
);
|
||||
return json_encode( array( 'data' => array(), 'error' => $error_message ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
public function get_tickets( $post_id ) {
|
||||
$api_event_id = $this->get_api_event_id( $post_id );
|
||||
if ( ! $api_event_id ) {
|
||||
return json_encode( array( 'data' => array() ) );
|
||||
}
|
||||
$request = array(
|
||||
'headers' => $this->_get_headers(),
|
||||
'timeout' => parent::DEFAULT_TIMEOUT
|
||||
);
|
||||
$url = $this->get_api_event_url( $post_id ) . 'events/' . $api_event_id . '/tickets';
|
||||
$response = wp_remote_get( $url, $request );
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 === $response_code ) {
|
||||
return $response['body'];
|
||||
} else {
|
||||
$error_message = $this->_transform_error_message(
|
||||
__( 'We were unable to get the Tickets Attendees from Time.ly Ticketing', AI1EC_PLUGIN_NAME ),
|
||||
$response, $url,
|
||||
true
|
||||
);
|
||||
return json_encode( array( 'data' => array(), 'error' => $error_message ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a Ticket Event was imported from an ICS Feed
|
||||
*/
|
||||
public function is_ticket_event_imported( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) && isset( $data[self::ATTR_ICS_API_URL] ) ) {
|
||||
return ( ! ai1ec_is_blank ( $data[self::ATTR_ICS_API_URL] ) );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Ticket Event was created using a different account
|
||||
* The user probably created the event from one account, signed out and
|
||||
* is currently signed in with a new account
|
||||
*/
|
||||
public function is_ticket_event_from_another_account( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
if ( isset( $data[self::ATTR_ACCOUNT] ) ) {
|
||||
return ( $this->get_current_account() != $data[self::ATTR_ACCOUNT] );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API account where the event was created
|
||||
* @param int $post_id Post ID
|
||||
* @param bool $default_null True to return NULL if the value does not exist, false to return the configured API URL
|
||||
*/
|
||||
public function get_api_event_account( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
if ( isset( $data[self::ATTR_ACCOUNT] ) ) {
|
||||
return $data[self::ATTR_ACCOUNT];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the response that came from the API is the event not found
|
||||
*/
|
||||
private function _is_event_notfound_error( $response ) {
|
||||
if ( isset( $response->response_code ) && 404 === $response->response_code ) {
|
||||
if ( isset( $response->body ) ) {
|
||||
if ( is_array( $response->body ) &&
|
||||
isset( $response->body['message'] ) ) {
|
||||
if ( false !== stripos( $response->body['message'], 'event not found') ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return NULL in case of success or an error string in case of error
|
||||
*/
|
||||
public function update_api_event_fields( WP_Post $post, $api_fields_values, $post_action = 'trash', $ajax_action = false ) {
|
||||
$post_id = $post->ID;
|
||||
$api_event_id = $this->get_api_event_id( $post_id );
|
||||
if ( ! $api_event_id ) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
$event = $this->_registry->get( 'model.event', $post_id );
|
||||
} catch ( Ai1ec_Event_Not_Found_Exception $excpt ) {
|
||||
$message = __( 'Event not found inside the database.', AI1EC_PLUGIN_NAME );
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store( $message, 'error', 0, array( Ai1ec_Notification_Admin::RCPT_ADMIN ), false );
|
||||
return $message;
|
||||
}
|
||||
if ( 'update' === $post_action ) {
|
||||
$error = $this->_prevent_update_ticket_event( $event, $ajax_action );
|
||||
if ( null !== $error ) {
|
||||
return $error;
|
||||
}
|
||||
} else {
|
||||
if ( $this->is_ticket_event_imported( $post_id ) ) {
|
||||
return null;
|
||||
}
|
||||
if ( $this->is_ticket_event_from_another_account( $post_id ) ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$headers = $this->_get_headers();
|
||||
$body_data = $this->parse_event_fields_to_api_structure(
|
||||
$event,
|
||||
$post,
|
||||
null, //does not update ticket types, just chaging the api fields specified
|
||||
$api_fields_values
|
||||
);
|
||||
$response = $this->request_api( 'POST',
|
||||
AI1EC_API_URL . 'events/' . $api_event_id,
|
||||
$body_data,
|
||||
true //true to decode response body
|
||||
);
|
||||
if ( ! $this->is_response_success( $response ) ) {
|
||||
if ( $this->_is_event_notfound_error( $response ) ) {
|
||||
if ( isset( $api_fields_values['status'] ) &&
|
||||
'trash' === $api_fields_values['status'] ) {
|
||||
//this is an exception, the event was deleted on API server, but for some reason
|
||||
//the metada was not unset, in this case leave the event be
|
||||
//move to trash
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$message = $this->save_error_notification( $response, __( 'We were unable to Update the Event on Time.ly Network', AI1EC_PLUGIN_NAME ) );
|
||||
return $message;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the API event
|
||||
* @return NULL in case of success or an error string in case of error
|
||||
*/
|
||||
public function delete_api_event( $post_id, $post_action = 'delete', $ajax_action = false ) {
|
||||
$api_event_id = $this->get_api_event_id( $post_id );
|
||||
if ( ! $api_event_id ) {
|
||||
return null;
|
||||
}
|
||||
if ( 'update' === $post_action ) {
|
||||
try {
|
||||
$event = $this->_registry->get( 'model.event', $post_id );
|
||||
} catch ( Ai1ec_Event_Not_Found_Exception $excpt ) {
|
||||
$message = __( 'Event not found inside the database.', AI1EC_PLUGIN_NAME );
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store( $message, 'error', 0, array( Ai1ec_Notification_Admin::RCPT_ADMIN ), false );
|
||||
return $message;
|
||||
}
|
||||
$error = $this->_prevent_update_ticket_event( $event, $ajax_action );
|
||||
if ( null !== $error ) {
|
||||
return $error;
|
||||
}
|
||||
} else {
|
||||
if ( $this->is_ticket_event_imported( $post_id ) ) {
|
||||
$this->clear_event_metadata( $post_id );
|
||||
return null;
|
||||
}
|
||||
if ( $this->is_ticket_event_from_another_account( $post_id ) ) {
|
||||
$this->clear_event_metadata( $post_id );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$response = $this->request_api( 'DELETE',
|
||||
AI1EC_API_URL . 'events/' . $api_event_id,
|
||||
true //true to decode response body
|
||||
);
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$this->clear_event_metadata( $post_id );
|
||||
return null;
|
||||
} else {
|
||||
if ( $this->_is_event_notfound_error( $response ) ) {
|
||||
$this->clear_event_metadata( $post_id );
|
||||
return null;
|
||||
}
|
||||
$message = $this->save_error_notification( $response, __( 'We were unable to remove the Event on Time.ly Network', AI1EC_PLUGIN_NAME ) );
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the event metadata used by Event from the post id
|
||||
* @param int $post_id Post ID
|
||||
*/
|
||||
public function clear_event_metadata( $post_id ) {
|
||||
delete_post_meta( $post_id, self::API_EVENT_DATA );
|
||||
}
|
||||
|
||||
public function get_api_event_data( $post_id ) {
|
||||
$data = get_post_meta(
|
||||
$post_id,
|
||||
self::API_EVENT_DATA,
|
||||
true
|
||||
);
|
||||
if ( ai1ec_is_blank ( $data ) ) {
|
||||
return null;
|
||||
} else if ( is_numeric( $data ) ) {
|
||||
//migrate the old metadata into one
|
||||
$new_data[self::ATTR_EVENT_ID] = $data;
|
||||
$value = get_post_meta( $post_id, '_ai1ec_thumbnail_id', true );
|
||||
if ( false === ai1ec_is_blank( $value ) ) {
|
||||
$new_data[self::ATTR_THUMBNAIL_ID] = $value;
|
||||
}
|
||||
$value = get_post_meta( $post_id, '_ai1ec_ics_checkout_url', true );
|
||||
if ( false === ai1ec_is_blank( $value ) ) {
|
||||
$new_data[self::ATTR_ICS_CHECKOUT_URL] = $value;
|
||||
}
|
||||
$value = get_post_meta( $post_id, '_ai1ec_ics_api_url' , true );
|
||||
if ( ai1ec_is_blank( $value ) ) {
|
||||
//not imported ticket event
|
||||
$new_data[self::ATTR_ACCOUNT] = $this->get_current_account();
|
||||
$new_data[self::ATTR_CALENDAR_ID] = $this->get_current_calendar();
|
||||
} else {
|
||||
$new_data[self::ATTR_ICS_API_URL] = $value;
|
||||
}
|
||||
$new_data[self::ATTR_CURRENCY] = 'USD';
|
||||
update_post_meta( $post_id, self::API_EVENT_DATA, $new_data );
|
||||
return $new_data;
|
||||
} else if ( is_array( $data ) ) {
|
||||
return $data;
|
||||
} else {
|
||||
wp_die( 'Error geting the api data' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the event on the API
|
||||
* @param int $post_id Post ID
|
||||
*/
|
||||
public function get_api_event_id( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
return $data[self::ATTR_EVENT_ID];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API URL of the event
|
||||
* @param int $post_id Post ID
|
||||
* @param bool $default_null True to return NULL if the value does not exist, false to return the configured API URL
|
||||
*/
|
||||
public function get_api_event_url ( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
if ( isset( $data[self::ATTR_ICS_API_URL] ) ) {
|
||||
return $data[self::ATTR_ICS_API_URL];
|
||||
} else {
|
||||
return AI1EC_API_URL;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Currency of the event
|
||||
* @param int $post_id Post ID
|
||||
*/
|
||||
public function get_api_event_currency ( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
if ( isset( $data[self::ATTR_CURRENCY] ) ) {
|
||||
return $data[self::ATTR_CURRENCY];
|
||||
} else {
|
||||
return 'USD';
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Checkout url of the event
|
||||
* @param int $post_id Post ID
|
||||
*/
|
||||
public function get_api_event_checkout_url ( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
if ( isset( $data[self::ATTR_ICS_CHECKOUT_URL] ) ) {
|
||||
return $data[self::ATTR_ICS_CHECKOUT_URL];
|
||||
} else {
|
||||
return AI1EC_TICKETS_CHECKOUT_URL;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Buy Ticket URL of the event
|
||||
* @param int $post_id Post ID
|
||||
*/
|
||||
public function get_api_event_buy_ticket_url ( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
$api_event_id = $data[self::ATTR_EVENT_ID];
|
||||
if ( isset( $data[self::ATTR_ICS_CHECKOUT_URL] ) ) {
|
||||
$checkout_url = $data[self::ATTR_ICS_CHECKOUT_URL];
|
||||
} else {
|
||||
$checkout_url = AI1EC_TICKETS_CHECKOUT_URL;
|
||||
}
|
||||
return str_replace( '{event_id}', $api_event_id, $checkout_url );
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tax options modal
|
||||
* @param int $event_id Event ID (optional)
|
||||
*/
|
||||
public function get_tax_options_modal( $post_id = null ) {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
$event_id = $this->get_api_event_id( $post_id );
|
||||
$response = $this->request_api( 'GET',
|
||||
AI1EC_API_URL . 'calendars/' . $calendar_id . '/tax_options' .
|
||||
( is_null( $event_id ) ? '' : '?event_id=' . $event_id )
|
||||
);
|
||||
return (object) array( 'data' => $response->raw, 'error' => false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tax options modal
|
||||
* @param int $event_id Event ID (optional)
|
||||
*/
|
||||
public function get_tax_options_modal_ep() {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
$response = $this->request_api( 'GET',
|
||||
AI1EC_API_URL . 'eventpromote/' . $calendar_id . '/tax_options'
|
||||
);
|
||||
return (object) array( 'data' => $response->raw, 'error' => false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the API event data
|
||||
* @param int $post_id Post ID
|
||||
* @param int $api_event_id (optional) Id of the event on the API
|
||||
* @param string $ics_api_url (optional) API URL of the event on the API (used when importing an ICS feed)
|
||||
* @param string $ics_checkout_url (optional) API CHECKOUT URL of the event on the API (used when importing an ICS feed)
|
||||
* @param string $currency (optional) Currency code of the event
|
||||
* @param string $thumbnail_id (optional) Id of the Thumbnail (Featured Image id)
|
||||
*/
|
||||
public function save_api_event_data( $post_id, $api_event_id, $ics_api_url = null, $ics_checkout_url = null, $currency = null, $thumbnail_id = null ) {
|
||||
if ( ai1ec_is_blank( $api_event_id ) ) {
|
||||
throw new Error( 'Api event id should never be null' );
|
||||
}
|
||||
$api_data[self::ATTR_EVENT_ID] = $api_event_id;
|
||||
$api_data[self::ATTR_ICS_API_URL] = $ics_api_url;
|
||||
$api_data[self::ATTR_ICS_CHECKOUT_URL] = $ics_checkout_url;
|
||||
$api_data[self::ATTR_CURRENCY] = $currency;
|
||||
$api_data[self::ATTR_THUMBNAIL_ID] = $thumbnail_id;
|
||||
if ( ai1ec_is_blank( $ics_api_url ) ) {
|
||||
$api_data[self::ATTR_ACCOUNT] = $this->get_current_account();
|
||||
$api_data[self::ATTR_CALENDAR_ID] = $this->get_current_calendar();
|
||||
}
|
||||
$previous_data = $this->get_api_event_data( $post_id );
|
||||
$new_data = array();
|
||||
if ( is_array( $previous_data ) ) {
|
||||
foreach ( $previous_data as $key => $value) {
|
||||
$new_data[$key] = $value;
|
||||
}
|
||||
}
|
||||
foreach ( $api_data as $key => $value ) {
|
||||
if ( ai1ec_is_blank( $value ) ) {
|
||||
unset( $new_data[$key] );
|
||||
} else {
|
||||
$new_data[$key] = $api_data[$key];
|
||||
}
|
||||
}
|
||||
return update_post_meta( $post_id, self::API_EVENT_DATA, $new_data, $previous_data );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Base application model.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_App extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Initiate base objects.
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry
|
||||
* @internal param \Ai1ec_Registry_Object $system Injectable system object.
|
||||
*/
|
||||
public function __construct( Ai1ec_Registry_Object $registry ) {
|
||||
parent::__construct( $registry );
|
||||
$this->_initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Post construction routine.
|
||||
*
|
||||
* Override this method to perform post-construction tasks.
|
||||
*
|
||||
* @return void Return from this method is ignored.
|
||||
*/
|
||||
protected function _initialize() {}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Model representing an event or an event instance.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.1
|
||||
* @instantiator Ai1ec_Factory_Event.create_event_instance
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Event_Compatibility extends Ai1ec_Event {
|
||||
|
||||
/**
|
||||
* Getter.
|
||||
*
|
||||
* @param string $name Property name.
|
||||
*
|
||||
* @return mixed Property value.
|
||||
*/
|
||||
public function __get( $name ) {
|
||||
$value = $this->get( $name );
|
||||
if ( null !== $value ) {
|
||||
return $value;
|
||||
}
|
||||
return $this->get_runtime( $name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Isset magic function.
|
||||
*
|
||||
* @param string $name Property name.
|
||||
*
|
||||
* @return bool True of false.
|
||||
*/
|
||||
public function __isset( $name ) {
|
||||
$method_name = 'get' . $name;
|
||||
if ( method_exists( $this, $method_name ) ) {
|
||||
return false;
|
||||
}
|
||||
return ( null !== $this->$name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Twig timespan short method.
|
||||
*
|
||||
* @return string Value.
|
||||
*/
|
||||
public function gettimespan_short() {
|
||||
return $this->_registry->get( 'view.event.time' )
|
||||
->get_timespan_html( $this, 'short' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Twig is_allday method.
|
||||
*
|
||||
* @return bool Value.
|
||||
*/
|
||||
public function getis_allday() {
|
||||
return $this->is_allday();
|
||||
}
|
||||
|
||||
/**
|
||||
* Twig is_multiday method.
|
||||
*
|
||||
* @return bool Value.
|
||||
*/
|
||||
public function getis_multiday() {
|
||||
return $this->is_multiday();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Event instance permalink for FER compatibility.
|
||||
*
|
||||
* @return string Event instance permalink.
|
||||
*/
|
||||
public function getpermalink() {
|
||||
return $this->get_runtime( 'instance_permalink' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Event timespan for popup.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getpopup_timespan() {
|
||||
return $this->_registry->get( 'twig.ai1ec-extension' )
|
||||
->timespan( $this, 'short' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Avatar not wrapped in <a> tag.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getavatar_not_wrapped() {
|
||||
return $this->getavatar( false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Event avatar URL.
|
||||
*
|
||||
* @return string Event avatar URL.
|
||||
* @throws Ai1ec_Bootstrap_Exception
|
||||
*/
|
||||
public function getavatar_url() {
|
||||
return $this->_registry->get(
|
||||
'view.event.avatar'
|
||||
)->get_event_avatar_url( $this );
|
||||
}
|
||||
}
|
||||
@@ -1,895 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Model representing an event or an event instance.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @instantiator Ai1ec_Factory_Event.create_event_instance
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Event extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Event_Entity Data store object reference.
|
||||
*/
|
||||
protected $_entity = null;
|
||||
|
||||
/**
|
||||
* @var array Map of fields that require special care during set/get
|
||||
* operations. Values have following meanings:
|
||||
* [0] - both way care required;
|
||||
* [1] - only `set` operations require care;
|
||||
* [-1] - only `get` (for storage) operations require care.
|
||||
*/
|
||||
protected $_swizzable = array(
|
||||
'cost' => 0,
|
||||
'start' => -1,
|
||||
'end' => -1,
|
||||
'timezone_name' => -1,
|
||||
'recurrence_dates' => 1,
|
||||
'exception_dates' => 1,
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array Runtime properties
|
||||
*/
|
||||
protected $_runtime_props = array();
|
||||
|
||||
/**
|
||||
* @var bool|null Boolean cache-definition indicating if event is multiday.
|
||||
*/
|
||||
protected $_is_multiday = null;
|
||||
|
||||
/**
|
||||
* Wrapper to get property value.
|
||||
*
|
||||
* @param string $property Name of property to get.
|
||||
* @param mixed $default Default value to return.
|
||||
*
|
||||
* @return mixed Actual property.
|
||||
*/
|
||||
public function get( $property, $default = null ) {
|
||||
return $this->_entity->get( $property, $default );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properties generated at runtime
|
||||
*
|
||||
* @param string $property
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_runtime( $property, $default = '' ) {
|
||||
return isset( $this->_runtime_props[$property] ) ?
|
||||
$this->_runtime_props[$property] :
|
||||
$default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set properties generated at runtime
|
||||
*
|
||||
* @param string $property
|
||||
* @param string $value
|
||||
*/
|
||||
public function set_runtime( $property, $value ) {
|
||||
$this->_runtime_props[$property] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle property initiation.
|
||||
*
|
||||
* Decides, how to extract value stored in permanent storage.
|
||||
*
|
||||
* @param string $property Name of property to handle
|
||||
* @param mixed $value Value, read from permanent storage
|
||||
*
|
||||
* @return bool Success
|
||||
*/
|
||||
public function set( $property, $value ) {
|
||||
if (
|
||||
isset( $this->_swizzable[$property] ) &&
|
||||
$this->_swizzable[$property] >= 0
|
||||
) {
|
||||
$method = '_handle_property_construct_' . $property;
|
||||
$value = $this->{$method}( $value );
|
||||
}
|
||||
$this->_entity->set( $property, $value );
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the event is all day, during the specified number of days
|
||||
*
|
||||
* @param number $length
|
||||
*/
|
||||
public function set_all_day( $length = 1 ) {
|
||||
// set allday as true
|
||||
$this->set( 'allday', true );
|
||||
$start = $this->get( 'start' );
|
||||
// reset time component
|
||||
$start->set_time( 0, 0, 0 );
|
||||
$end = $this->_registry->get( 'date.time', $start );
|
||||
// set the correct length
|
||||
$end->adjust_day( $length );
|
||||
$this->set( 'end', $end );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the event as if it has no end time
|
||||
*/
|
||||
public function set_no_end_time() {
|
||||
$this->set( 'instant_event', true );
|
||||
$start = $this->get( 'start' );
|
||||
$end = $this->_registry->get( 'date.time', $start );
|
||||
$end->set_time(
|
||||
$start->format( 'H' ),
|
||||
$start->format( 'i' ) + 15,
|
||||
$start->format( 's' )
|
||||
);
|
||||
$this->set( 'end', $end );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set object fields from arbitrary array.
|
||||
*
|
||||
* @param array $data Supposedly map of fields to initiate.
|
||||
*
|
||||
* @return Ai1ec_Event Instance of self for chaining.
|
||||
*/
|
||||
public function initialize_from_array( array $data ) {
|
||||
|
||||
// =======================================================
|
||||
// = Assign each event field the value from the database =
|
||||
// =======================================================
|
||||
foreach ( $this->_entity->list_properties() as $property ) {
|
||||
if ( 'post' !== $property && isset( $data[$property] ) ) {
|
||||
$this->set( $property, $data[$property] );
|
||||
unset( $data[$property] );
|
||||
}
|
||||
}
|
||||
if ( isset( $data['post'] ) ) {
|
||||
$this->set( 'post', (object)$data['post'] );
|
||||
} else {
|
||||
// ========================================
|
||||
// = Remaining fields are the post fields =
|
||||
// ========================================
|
||||
$this->set( 'post', (object)$data );
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the events from all tables
|
||||
*/
|
||||
public function delete() {
|
||||
// delete post (this will trigger deletion of cached events, and
|
||||
// remove the event from events table)
|
||||
wp_delete_post( $this->get( 'post_id' ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize object from ID.
|
||||
*
|
||||
* Attempts to retrieve entity from database and if succeeds - uses
|
||||
* {@see self::initialize_from_array} to initiate actual values.
|
||||
*
|
||||
* @param int $post_id ID of post (event) to initiate.
|
||||
* @param int|bool $instance ID of event instance, false for base event.
|
||||
*
|
||||
* @return Ai1ec_Event Instance of self for chaining.
|
||||
*
|
||||
* @throws Ai1ec_Event_Not_Found_Exception If entity is not locatable.
|
||||
*/
|
||||
public function initialize_from_id( $post_id, $instance = false ) {
|
||||
$post = get_post( $post_id );
|
||||
if ( ! $post || $post->post_status == 'auto-draft' ) {
|
||||
throw new Ai1ec_Event_Not_Found_Exception(
|
||||
'Post with ID \'' . $post_id .
|
||||
'\' could not be retrieved from the database.'
|
||||
);
|
||||
}
|
||||
$post_id = (int)$post_id;
|
||||
$dbi = $this->_registry->get( 'dbi.dbi' );
|
||||
|
||||
$left_join = '';
|
||||
$select_sql = '
|
||||
e.post_id,
|
||||
e.timezone_name,
|
||||
e.recurrence_rules,
|
||||
e.exception_rules,
|
||||
e.allday,
|
||||
e.instant_event,
|
||||
e.recurrence_dates,
|
||||
e.exception_dates,
|
||||
e.venue,
|
||||
e.country,
|
||||
e.address,
|
||||
e.city,
|
||||
e.province,
|
||||
e.postal_code,
|
||||
e.show_map,
|
||||
e.contact_name,
|
||||
e.contact_phone,
|
||||
e.contact_email,
|
||||
e.contact_url,
|
||||
e.cost,
|
||||
e.ticket_url,
|
||||
e.ical_feed_url,
|
||||
e.ical_source_url,
|
||||
e.ical_organizer,
|
||||
e.ical_contact,
|
||||
e.ical_uid,
|
||||
e.longitude,
|
||||
e.latitude,
|
||||
e.show_coordinates,
|
||||
GROUP_CONCAT( ttc.term_id ) AS categories,
|
||||
GROUP_CONCAT( ttt.term_id ) AS tags
|
||||
';
|
||||
|
||||
if (
|
||||
false !== $instance &&
|
||||
is_numeric( $instance ) &&
|
||||
$instance > 0
|
||||
) {
|
||||
$select_sql .= ', IF( aei.start IS NOT NULL, aei.start, e.start ) as start,' .
|
||||
' IF( aei.start IS NOT NULL, aei.end, e.end ) as end ';
|
||||
|
||||
$instance = (int)$instance;
|
||||
$this->set( 'instance_id', $instance );
|
||||
$left_join = 'LEFT JOIN ' . $dbi->get_table_name( 'ai1ec_event_instances' ) .
|
||||
' aei ON aei.id = ' . $instance . ' AND e.post_id = aei.post_id ';
|
||||
} else {
|
||||
$select_sql .= ', e.start as start, e.end as end, e.allday ';
|
||||
if ( -1 === (int)$instance ) {
|
||||
$select_sql .= ', aei.id as instance_id ';
|
||||
$left_join = 'LEFT JOIN ' .
|
||||
$dbi->get_table_name( 'ai1ec_event_instances' ) .
|
||||
' aei ON e.post_id = aei.post_id ' .
|
||||
'AND e.start = aei.start AND e.end = aei.end ';
|
||||
}
|
||||
}
|
||||
|
||||
// =============================
|
||||
// = Fetch event from database =
|
||||
// =============================
|
||||
$query = 'SELECT ' . $select_sql . '
|
||||
FROM ' . $dbi->get_table_name( 'ai1ec_events' ) . ' e
|
||||
LEFT JOIN ' .
|
||||
$dbi->get_table_name( 'term_relationships' ) . ' tr
|
||||
ON ( e.post_id = tr.object_id )
|
||||
LEFT JOIN ' . $dbi->get_table_name( 'term_taxonomy' ) . ' ttc
|
||||
ON (
|
||||
tr.term_taxonomy_id = ttc.term_taxonomy_id AND
|
||||
ttc.taxonomy = \'events_categories\'
|
||||
)
|
||||
LEFT JOIN ' . $dbi->get_table_name( 'term_taxonomy' ) . ' ttt
|
||||
ON (
|
||||
tr.term_taxonomy_id = ttt.term_taxonomy_id AND
|
||||
ttt.taxonomy = \'events_tags\'
|
||||
)
|
||||
' . $left_join . '
|
||||
WHERE e.post_id = ' . $post_id . '
|
||||
GROUP BY e.post_id';
|
||||
|
||||
$event = $dbi->get_row( $query, ARRAY_A );
|
||||
if ( null === $event || null === $event['post_id'] ) {
|
||||
throw new Ai1ec_Event_Not_Found_Exception(
|
||||
'Event with ID \'' . $post_id .
|
||||
'\' could not be retrieved from the database.'
|
||||
);
|
||||
}
|
||||
|
||||
$event['post'] = $post;
|
||||
return $this->initialize_from_array( $event );
|
||||
}
|
||||
|
||||
public function getenddate() {
|
||||
$end = $this->get( 'end' );
|
||||
if ( $this->is_allday() ) {
|
||||
$end->set_time(
|
||||
$end->format( 'H' ),
|
||||
$end->format( 'i' ),
|
||||
$end->format( 's' ) - 1
|
||||
);
|
||||
}
|
||||
return $end;
|
||||
}
|
||||
/**
|
||||
* Returns enddate specific info.
|
||||
*
|
||||
* @return array Date info structure.
|
||||
*/
|
||||
public function getenddate_info() {
|
||||
$end = $this->getenddate();
|
||||
return array(
|
||||
'month' => $this->get( 'end' )->format_i18n( 'M' ),
|
||||
'day' => $this->get( 'end' )->format_i18n( 'j' ),
|
||||
'weekday' => $this->get( 'end' )->format_i18n( 'D' ),
|
||||
'year' => $this->get( 'end' )->format_i18n( 'Y' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new event object, using provided data for initialization.
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry Injected object registry.
|
||||
* @param int|array|null $data Look up post with id $data, or
|
||||
* initialize fields with associative
|
||||
* array $data containing both post
|
||||
* and event fields.
|
||||
* @param int|bool $instance Optionally instance ID. When ID
|
||||
* value is -1 then it is
|
||||
* retrieved from db.
|
||||
*
|
||||
* @throws Ai1ec_Invalid_Argument_Exception When $data is not one
|
||||
* of int|array|null.
|
||||
* @throws Ai1ec_Event_Not_Found_Exception When $data relates to
|
||||
* non-existent ID.
|
||||
*
|
||||
*/
|
||||
function __construct(
|
||||
Ai1ec_Registry_Object $registry,
|
||||
$data = null,
|
||||
$instance = false
|
||||
) {
|
||||
parent::__construct( $registry );
|
||||
$this->_entity = $this->_registry->get( 'model.event.entity' );
|
||||
if ( null === $data ) {
|
||||
return; // empty object
|
||||
} else if ( is_numeric( $data ) ) {
|
||||
$this->initialize_from_id( $data, $instance );
|
||||
} else if ( is_array( $data ) ) {
|
||||
$this->initialize_from_array( $data );
|
||||
} else {
|
||||
throw new Ai1ec_Invalid_Argument_Exception(
|
||||
'Argument to constructor must be integer, array or null' .
|
||||
', not ' . var_export( $data, true )
|
||||
);
|
||||
}
|
||||
|
||||
if ( $this->is_allday() ) {
|
||||
try {
|
||||
$timezone = $this->_registry->get( 'date.timezone' )
|
||||
->get( $this->get( 'timezone_name' ) );
|
||||
$this->_entity->set_preferred_timezone( $timezone );
|
||||
} catch ( Exception $excpt ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Twig method for retrieving avatar.
|
||||
*
|
||||
* @param bool $wrap_permalink Whether to wrap avatar in <a> element or not
|
||||
*
|
||||
* @return string Avatar markup
|
||||
*/
|
||||
public function getavatar( $wrap_permalink = true ) {
|
||||
return $this->_registry->
|
||||
get( 'view.event.avatar' )->get_event_avatar(
|
||||
$this,
|
||||
$this->_registry->get( 'view.calendar.fallbacks' )->get_all(),
|
||||
'',
|
||||
$wrap_permalink
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether Event has geo information.
|
||||
*
|
||||
* @return bool True or false.
|
||||
*/
|
||||
public function has_geoinformation() {
|
||||
$latitude = floatval( $this->get( 'latitude') );
|
||||
$longitude = floatval( $this->get( 'longitude' ) );
|
||||
return (
|
||||
(
|
||||
$latitude >= 0.000000000000001 ||
|
||||
$latitude <= -0.000000000000001
|
||||
) &&
|
||||
(
|
||||
$longitude >= 0.000000000000001 ||
|
||||
$longitude <= -0.000000000000001
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function _handle_property_construct_recurrence_dates( $value ) {
|
||||
if ( $value ) {
|
||||
$this->_entity->set( 'recurrence_rules', 'RDATE=' . $value );
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
protected function _handle_property_construct_exception_dates( $value ) {
|
||||
if ( $value ) {
|
||||
$this->_entity->set( 'exception_rules', 'EXDATE=' . $value );
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle `cost` value reading from permanent storage.
|
||||
*
|
||||
* @param string $value Value stored in permanent storage
|
||||
*
|
||||
* @return bool Success: true, always
|
||||
*/
|
||||
protected function _handle_property_construct_cost( $value ) {
|
||||
$test_value = false;
|
||||
if (
|
||||
isset( $value{1} ) && (
|
||||
':' === $value{1} || ';' === $value{1}
|
||||
)
|
||||
) {
|
||||
$test_value = unserialize( $value );
|
||||
}
|
||||
$cost = $is_free = NULL;
|
||||
if ( false === $test_value ) {
|
||||
$cost = trim( $value );
|
||||
$is_free = false;
|
||||
} else {
|
||||
extract( $test_value, EXTR_IF_EXISTS );
|
||||
}
|
||||
$this->_entity->set( 'is_free', (bool)$is_free );
|
||||
return (string)$cost;
|
||||
}
|
||||
|
||||
public function get_uid_pattern() {
|
||||
static $format = null;
|
||||
if ( null === $format ) {
|
||||
$site_url = parse_url( ai1ec_get_site_url() );
|
||||
$format = 'ai1ec-%d@' . $site_url['host'];
|
||||
if ( isset( $site_url['path'] ) ) {
|
||||
$format .= $site_url['path'];
|
||||
}
|
||||
}
|
||||
return $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get UID to be used for current event.
|
||||
*
|
||||
* The generated format is cached in static variable within this function
|
||||
* to re-use when generating UIDs for different entries.
|
||||
*
|
||||
* @return string Generated UID.
|
||||
*
|
||||
* @staticvar string $format Cached format.
|
||||
*/
|
||||
public function get_uid() {
|
||||
$ical_uid = $this->get( 'ical_uid' );
|
||||
if ( ! empty( $ical_uid ) ) {
|
||||
return $ical_uid;
|
||||
}
|
||||
return sprintf( $this->get_uid_pattern(), $this->get( 'post_id' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if event is free.
|
||||
*
|
||||
* @return bool Free status.
|
||||
*/
|
||||
public function is_free() {
|
||||
return (bool)$this->get( 'is_free' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if event is taking all day.
|
||||
*
|
||||
* @return bool True for all-day long events.
|
||||
*/
|
||||
public function is_allday() {
|
||||
return (bool)$this->get( 'allday' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if event has virtually no time.
|
||||
*
|
||||
* @return bool True for instant events.
|
||||
*/
|
||||
public function is_instant() {
|
||||
return (bool)$this->get( 'instant_event' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if event is taking multiple days.
|
||||
*
|
||||
* Uses object-wide variable {@see self::$_is_multiday} to store
|
||||
* calculated value after first call.
|
||||
*
|
||||
* @return bool True for multiday events.
|
||||
*/
|
||||
public function is_multiday() {
|
||||
if ( null === $this->_is_multiday ) {
|
||||
$start = $this->get( 'start' );
|
||||
$end = $this->get( 'end' );
|
||||
$diff = $end->diff_sec( $start );
|
||||
$this->_is_multiday = $diff > 86400 &&
|
||||
$start->format( 'Y-m-d' ) !== $end->format( 'Y-m-d' );
|
||||
}
|
||||
return $this->_is_multiday;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the duration of the event
|
||||
*
|
||||
* @return number
|
||||
*/
|
||||
public function get_duration() {
|
||||
$duration = $this->get_runtime( 'duration', null );
|
||||
if ( null === $duration ) {
|
||||
$duration = $this->get( 'end' )->format() -
|
||||
$this->get( 'start' )->format();
|
||||
$this->set_runtime( 'duration', $duration );
|
||||
}
|
||||
return $duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create/update entity representation.
|
||||
*
|
||||
* Saves the current event data to the database. If $this->post_id exists,
|
||||
* but $update is false, creates a new record in the ai1ec_events table of
|
||||
* this event data, but does not try to create a new post. Else if $update
|
||||
* is true, updates existing event record. If $this->post_id is empty,
|
||||
* creates a new post AND record in the ai1ec_events table for this event.
|
||||
*
|
||||
* @param bool $update Whether to update an existing event or create a
|
||||
* new one
|
||||
* @param bool $backward_compatibility The (wpdb) ofr the new wordpress 4.4
|
||||
* now inserts NULL as null values. The previous version, if you insert a NULL
|
||||
* value in an int value, the values saved would be 0 instead of null.
|
||||
* @return int The post_id of the new or existing event.
|
||||
*/
|
||||
function save( $update = false, $backward_compatibility = true ) {
|
||||
do_action( 'ai1ec_pre_save_event', $this, $update );
|
||||
if ( ! $update ) {
|
||||
$response = apply_filters( 'ai1ec_event_save_new', $this );
|
||||
if ( is_wp_error( $response ) ) {
|
||||
throw new Ai1ec_Event_Create_Exception(
|
||||
'Failed to create event: ' . $response->get_error_message()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$dbi = $this->_registry->get( 'dbi.dbi' );
|
||||
$columns = $this->prepare_store_entity();
|
||||
$format = $this->prepare_store_format( $columns, $backward_compatibility );
|
||||
$table_name = $dbi->get_table_name( 'ai1ec_events' );
|
||||
$post_id = $columns['post_id'];
|
||||
|
||||
if ( $this->get( 'end' )->is_empty() ) {
|
||||
$this->set_no_end_time();
|
||||
}
|
||||
if ( $post_id ) {
|
||||
$success = false;
|
||||
if ( ! $update ) {
|
||||
$success = $dbi->insert(
|
||||
$table_name,
|
||||
$columns,
|
||||
$format
|
||||
);
|
||||
} else {
|
||||
$success = $dbi->update(
|
||||
$table_name,
|
||||
$columns,
|
||||
array( 'post_id' => $columns['post_id'] ),
|
||||
$format,
|
||||
array( '%d' )
|
||||
);
|
||||
}
|
||||
if ( false === $success ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// ===================
|
||||
// = Insert new post =
|
||||
// ===================
|
||||
$post_id = wp_insert_post( $this->get( 'post' ), false );
|
||||
if ( 0 === $post_id ) {
|
||||
return false;
|
||||
}
|
||||
$this->set( 'post_id', $post_id );
|
||||
$columns['post_id'] = $post_id;
|
||||
|
||||
// =========================
|
||||
// = Insert new event data =
|
||||
// =========================
|
||||
if ( false === $dbi->insert( $table_name, $columns, $format ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$taxonomy = $this->_registry->get(
|
||||
'model.event.taxonomy',
|
||||
$post_id
|
||||
);
|
||||
$cats = $this->get( 'categories' );
|
||||
if (
|
||||
is_array( $cats ) &&
|
||||
! empty( $cats )
|
||||
) {
|
||||
$taxonomy->set_categories( $cats );
|
||||
}
|
||||
$tags = $this->get( 'tags' );
|
||||
if (
|
||||
is_array( $tags ) &&
|
||||
! empty( $tags )
|
||||
) {
|
||||
$taxonomy->set_tags( $tags );
|
||||
}
|
||||
|
||||
if (
|
||||
$feed = $this->get( 'feed' ) &&
|
||||
isset( $feed->feed_id )
|
||||
) {
|
||||
$taxonomy->set_feed( $feed );
|
||||
}
|
||||
|
||||
// give other plugins / extensions the ability to do things
|
||||
// when saving, like fetching authors which i removed as it's not core.
|
||||
do_action( 'ai1ec_save_event' );
|
||||
|
||||
$instance_model = $this->_registry->get( 'model.event.instance' );
|
||||
$instance_model->recreate( $this );
|
||||
|
||||
do_action( 'ai1ec_event_saved', $post_id, $this, $update );
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare fields format flags to use in database operations.
|
||||
*
|
||||
* @param array $columns Array of columns with data to insert.
|
||||
*
|
||||
* @return array List of format flags to use in integrations with DBI.
|
||||
*/
|
||||
public function prepare_store_format( array &$columns, $backward_compatibility = true ) {
|
||||
$format = array(
|
||||
'%d', // post_id
|
||||
'%d', // start
|
||||
'%d', // end
|
||||
'%s', // timezone_name
|
||||
'%d', // allday
|
||||
'%d', // instant_event
|
||||
'%s', // recurrence_rules
|
||||
'%s', // exception_rules
|
||||
'%s', // recurrence_dates
|
||||
'%s', // exception_dates
|
||||
'%s', // venue
|
||||
'%s', // country
|
||||
'%s', // address
|
||||
'%s', // city
|
||||
'%s', // province
|
||||
'%s', // postal_code
|
||||
'%d', // show_map
|
||||
'%s', // contact_name
|
||||
'%s', // contact_phone
|
||||
'%s', // contact_email
|
||||
'%s', // contact_url
|
||||
'%s', // cost
|
||||
'%s', // ticket_url
|
||||
'%s', // ical_feed_url
|
||||
'%s', // ical_source_url
|
||||
'%s', // ical_uid
|
||||
'%d', // show_coordinates
|
||||
'%f', // latitude
|
||||
'%f', // longitude
|
||||
);
|
||||
|
||||
if ( $backward_compatibility ) {
|
||||
$columns_count = count( $columns );
|
||||
if ( count( $format ) !== $columns_count ) {
|
||||
throw new Ai1ec_Event_Not_Found_Exception(
|
||||
'Data columns count differs from format columns count'
|
||||
);
|
||||
}
|
||||
$index = 0;
|
||||
foreach ( $columns as $key => $value ) {
|
||||
if ( '%d' === $format[ $index ] ) {
|
||||
if ( is_null( $value ) ) {
|
||||
$columns[ $key ] = 0;
|
||||
}
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
|
||||
return $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare event entity {@see self::$_entity} for persistent storage.
|
||||
*
|
||||
* Creates an array of database fields and corresponding values.
|
||||
*
|
||||
* @return array Map of fields to store.
|
||||
*/
|
||||
public function prepare_store_entity() {
|
||||
$entity = array(
|
||||
'post_id' => $this->storage_format( 'post_id' ),
|
||||
'start' => $this->storage_format( 'start' ),
|
||||
'end' => $this->storage_format( 'end' ),
|
||||
'timezone_name' => $this->storage_format( 'timezone_name' ),
|
||||
'allday' => $this->storage_format( 'allday' ),
|
||||
'instant_event' => $this->storage_format( 'instant_event' ),
|
||||
'recurrence_rules' => $this->storage_format( 'recurrence_rules' ),
|
||||
'exception_rules' => $this->storage_format( 'exception_rules' ),
|
||||
'recurrence_dates' => $this->storage_format( 'recurrence_dates' ),
|
||||
'exception_dates' => $this->storage_format( 'exception_dates' ),
|
||||
'venue' => $this->storage_format( 'venue' ),
|
||||
'country' => $this->storage_format( 'country' ),
|
||||
'address' => $this->storage_format( 'address' ),
|
||||
'city' => $this->storage_format( 'city' ),
|
||||
'province' => $this->storage_format( 'province' ),
|
||||
'postal_code' => $this->storage_format( 'postal_code' ),
|
||||
'show_map' => $this->storage_format( 'show_map' ),
|
||||
'contact_name' => $this->storage_format( 'contact_name' ),
|
||||
'contact_phone' => $this->storage_format( 'contact_phone' ),
|
||||
'contact_email' => $this->storage_format( 'contact_email' ),
|
||||
'contact_url' => $this->storage_format( 'contact_url' ),
|
||||
'cost' => $this->storage_format( 'cost' ),
|
||||
'ticket_url' => $this->storage_format( 'ticket_url' ),
|
||||
'ical_feed_url' => $this->storage_format( 'ical_feed_url' ),
|
||||
'ical_source_url' => $this->storage_format( 'ical_source_url' ),
|
||||
'ical_uid' => $this->storage_format( 'ical_uid' ),
|
||||
'show_coordinates' => $this->storage_format( 'show_coordinates' ),
|
||||
'latitude' => $this->storage_format( 'latitude', '' ),
|
||||
'longitude' => $this->storage_format( 'longitude', '' ),
|
||||
);
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact field for writing to persistent storage.
|
||||
*
|
||||
* @param string $field Name of field to compact.
|
||||
* @param mixed $default Default value to use for undescribed fields.
|
||||
*
|
||||
* @return mixed Value or $default.
|
||||
*/
|
||||
public function storage_format( $field, $default = null ) {
|
||||
$value = $this->_entity->get( $field, $default );
|
||||
if (
|
||||
isset( $this->_swizzable[$field] ) &&
|
||||
$this->_swizzable[$field] <= 0
|
||||
) {
|
||||
$value = $this->{ '_handle_property_destruct_' . $field }( $value );
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow properties to be modified after cloning.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __clone() {
|
||||
$this->_entity = clone $this->_entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode timezone to use for event.
|
||||
*
|
||||
* Following algorythm is used to detect a value:
|
||||
* - take value provided in input;
|
||||
* - if empty - take value associated with start time;
|
||||
* - if empty - take current environment timezone.
|
||||
*
|
||||
* @param string $timezone_name Timezone provided in input.
|
||||
*
|
||||
* @return string Timezone name to use for event in future.
|
||||
*/
|
||||
protected function _handle_property_destruct_timezone_name(
|
||||
$timezone_name
|
||||
) {
|
||||
if ( empty( $timezone_name ) ) {
|
||||
$timezone_name = $this->get( 'start' )->get_timezone();
|
||||
if ( empty( $timezone_name ) ) {
|
||||
$timezone_name = $this->_registry->get( 'date.timezone' )
|
||||
->get_default_timezone();
|
||||
}
|
||||
}
|
||||
return $timezone_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format datetime to UNIX timestamp for storage.
|
||||
*
|
||||
* @param Ai1ec_Date_Time $start Datetime object to compact.
|
||||
*
|
||||
* @return int UNIX timestamp.
|
||||
*/
|
||||
protected function _handle_property_destruct_start( Ai1ec_Date_Time $start ) {
|
||||
return $start->format_to_gmt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format datetime to UNIX timestamp for storage.
|
||||
*
|
||||
* @param Ai1ec_Date_Time $end Datetime object to compact.
|
||||
*
|
||||
* @return int UNIX timestamp.
|
||||
*/
|
||||
protected function _handle_property_destruct_end( Ai1ec_Date_Time $end ) {
|
||||
return $end->format_to_gmt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle `cost` writing to permanent storage.
|
||||
*
|
||||
* @param string $cost Value of cost.
|
||||
*
|
||||
* @return string Serialized value to store.
|
||||
*/
|
||||
protected function _handle_property_destruct_cost( $cost ) {
|
||||
$cost = array(
|
||||
'cost' => $cost,
|
||||
'is_free' => false,
|
||||
);
|
||||
if ( $this->get( 'is_free' ) ) {
|
||||
$cost['is_free'] = true;
|
||||
}
|
||||
return serialize( $cost );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the submitter information array
|
||||
* @return array (
|
||||
* is_organizer => 1 if the organizer is the submitter,
|
||||
* email => if is_organizer is 0, them this property has the email of the submitter,
|
||||
* name => if is_organizer is 0, them this property has the name of the submitter
|
||||
* )
|
||||
*/
|
||||
public function get_submitter_info() {
|
||||
$post_id = $this->get( 'post_id' );
|
||||
if ( empty( $post_id ) ) {
|
||||
return null;
|
||||
}
|
||||
$submitter_info = get_post_meta(
|
||||
$post_id,
|
||||
'_submitter_info',
|
||||
true
|
||||
);
|
||||
if ( false == ai1ec_is_blank( $submitter_info ) ) {
|
||||
$submitter_info = json_decode( $submitter_info, true );
|
||||
if ( is_array( $submitter_info ) ) {
|
||||
return $submitter_info;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the submitter information into post metadata
|
||||
*/
|
||||
public function save_submitter_info( $is_submitter, $submitter_email, $submitter_name ) {
|
||||
$post_id = $this->get( 'post_id' );
|
||||
if ( empty( $post_id ) ) {
|
||||
throw new Exception( 'Post id empty' );
|
||||
}
|
||||
$save = false;
|
||||
if ( 1 === intval( $is_submitter ) ) {
|
||||
$submitter_info['is_organizer'] = 1;
|
||||
if ( false === ai1ec_is_blank( $this->get( 'contact_email' ) ) ) {
|
||||
$save = true;
|
||||
}
|
||||
} else {
|
||||
$submitter_info['is_organizer'] = 0;
|
||||
if ( false === ai1ec_is_blank( $submitter_email ) ) {
|
||||
$submitter_info['email'] = trim( $submitter_email );
|
||||
$submitter_info['name'] = trim( $submitter_name );
|
||||
$save = true;
|
||||
}
|
||||
}
|
||||
if ( $save ) {
|
||||
update_post_meta( $post_id, '_submitter_info', json_encode( $submitter_info ) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,512 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles create/update operations.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Model
|
||||
*/
|
||||
class Ai1ec_Event_Creating extends Ai1ec_Base {
|
||||
|
||||
protected function is_valid_event( $post ) {
|
||||
// verify this came from the our screen and with proper authorization,
|
||||
// because save_post can be triggered at other times
|
||||
if (
|
||||
! isset( $_POST[AI1EC_POST_TYPE] ) ||
|
||||
! wp_verify_nonce( $_POST[AI1EC_POST_TYPE], 'ai1ec' )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
isset( $post->post_status ) &&
|
||||
'auto-draft' === $post->post_status
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// verify if this is not inline-editing
|
||||
if (
|
||||
isset( $_REQUEST['action'] ) &&
|
||||
'inline-save' === $_REQUEST['action']
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// verify that the post_type is that of an event
|
||||
if ( $post->post_type !== AI1EC_POST_TYPE ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function _parse_post_to_event( $post_id ) {
|
||||
|
||||
/**
|
||||
* =====================================================================
|
||||
*
|
||||
* CHANGE CODE BELOW TO HAVE FOLLOWING PROPERTIES:
|
||||
* - be initializiable from model;
|
||||
* - have sane defaults;
|
||||
* - avoid that cluster of isset and ternary operator.
|
||||
*
|
||||
* =====================================================================
|
||||
*/
|
||||
|
||||
$all_day = isset( $_POST['ai1ec_all_day_event'] ) ? 1 : 0;
|
||||
$instant_event = isset( $_POST['ai1ec_instant_event'] ) ? 1 : 0;
|
||||
$timezone_name = isset( $_POST['ai1ec_timezone_name'] ) ? sanitize_text_field( $_POST['ai1ec_timezone_name'] ) : 'sys.default';
|
||||
$start_time = isset( $_POST['ai1ec_start_time'] ) ? sanitize_text_field( $_POST['ai1ec_start_time'] ) : '';
|
||||
$end_time = isset( $_POST['ai1ec_end_time'] ) ? sanitize_text_field( $_POST['ai1ec_end_time'] ) : '';
|
||||
$venue = isset( $_POST['ai1ec_venue'] ) ? sanitize_text_field( $_POST['ai1ec_venue'] ) : '';
|
||||
$address = isset( $_POST['ai1ec_address'] ) ? sanitize_text_field( $_POST['ai1ec_address'] ) : '';
|
||||
$city = isset( $_POST['ai1ec_city'] ) ? sanitize_text_field( $_POST['ai1ec_city'] ) : '';
|
||||
$province = isset( $_POST['ai1ec_province'] ) ? sanitize_text_field( $_POST['ai1ec_province'] ) : '';
|
||||
$postal_code = isset( $_POST['ai1ec_postal_code'] ) ? sanitize_text_field( $_POST['ai1ec_postal_code'] ) : '';
|
||||
$country = isset( $_POST['ai1ec_country'] ) ? sanitize_text_field( $_POST['ai1ec_country'] ) : '';
|
||||
$google_map = isset( $_POST['ai1ec_google_map'] ) ? 1 : 0;
|
||||
$cost = isset( $_POST['ai1ec_cost'] ) ? sanitize_text_field( $_POST['ai1ec_cost'] ) : '';
|
||||
$is_free = isset( $_POST['ai1ec_is_free'] ) ? (bool)$_POST['ai1ec_is_free'] : false;
|
||||
$ticket_url = isset( $_POST['ai1ec_ticket_url'] ) ? sanitize_text_field( $_POST['ai1ec_ticket_url'] ) : '';
|
||||
$contact_name = isset( $_POST['ai1ec_contact_name'] ) ? sanitize_text_field( $_POST['ai1ec_contact_name'] ) : '';
|
||||
$contact_phone = isset( $_POST['ai1ec_contact_phone'] ) ? sanitize_text_field( $_POST['ai1ec_contact_phone'] ) : '';
|
||||
$contact_email = isset( $_POST['ai1ec_contact_email'] ) ? sanitize_text_field( $_POST['ai1ec_contact_email'] ) : '';
|
||||
$contact_url = isset( $_POST['ai1ec_contact_url'] ) ? sanitize_text_field( $_POST['ai1ec_contact_url'] ) : '';
|
||||
$show_coordinates = isset( $_POST['ai1ec_input_coordinates'] )? 1 : 0;
|
||||
$longitude = isset( $_POST['ai1ec_longitude'] ) ? sanitize_text_field( $_POST['ai1ec_longitude'] ) : '';
|
||||
$latitude = isset( $_POST['ai1ec_latitude'] ) ? sanitize_text_field( $_POST['ai1ec_latitude'] ) : '';
|
||||
$cost_type = isset( $_POST['ai1ec_cost_type'] ) ? sanitize_text_field( $_POST['ai1ec_cost_type'] ) : '';
|
||||
$rrule = null;
|
||||
$exrule = null;
|
||||
$exdate = null;
|
||||
$rdate = null;
|
||||
|
||||
if ( 'external' !== $cost_type ) {
|
||||
$ticket_url = '';
|
||||
}
|
||||
|
||||
$this->_remap_recurrence_dates();
|
||||
// if rrule is set, convert it from local to UTC time
|
||||
if (
|
||||
isset( $_POST['ai1ec_repeat'] ) &&
|
||||
! empty( $_POST['ai1ec_repeat'] )
|
||||
) {
|
||||
$rrule = $_POST['ai1ec_rrule'];
|
||||
}
|
||||
|
||||
// add manual dates
|
||||
if (
|
||||
isset( $_POST['ai1ec_exdate'] ) &&
|
||||
! empty( $_POST['ai1ec_exdate'] )
|
||||
) {
|
||||
$exdate = $_POST['ai1ec_exdate'];
|
||||
}
|
||||
if (
|
||||
isset( $_POST['ai1ec_rdate'] ) &&
|
||||
! empty( $_POST['ai1ec_rdate'] )
|
||||
) {
|
||||
$rdate = $_POST['ai1ec_rdate'];
|
||||
}
|
||||
|
||||
// if exrule is set, convert it from local to UTC time
|
||||
if (
|
||||
isset( $_POST['ai1ec_exclude'] ) &&
|
||||
! empty( $_POST['ai1ec_exclude'] ) &&
|
||||
( null !== $rrule || null !== $rdate ) // no point for exclusion, if repetition is not set
|
||||
) {
|
||||
$exrule = $this->_registry->get( 'recurrence.rule' )->merge_exrule(
|
||||
$_POST['ai1ec_exrule'],
|
||||
$rrule
|
||||
);
|
||||
}
|
||||
|
||||
$is_new = false;
|
||||
try {
|
||||
$event = $this->_registry->get(
|
||||
'model.event',
|
||||
$post_id ? $post_id : null
|
||||
);
|
||||
} catch ( Ai1ec_Event_Not_Found_Exception $excpt ) {
|
||||
// Post exists, but event data hasn't been saved yet. Create new event
|
||||
// object.
|
||||
$is_new = true;
|
||||
$event = $this->_registry->get( 'model.event' );
|
||||
}
|
||||
$formatted_timezone = $this->_registry->get( 'date.timezone' )
|
||||
->get_name( $timezone_name );
|
||||
if ( empty( $timezone_name ) || ! $formatted_timezone ) {
|
||||
$timezone_name = 'sys.default';
|
||||
}
|
||||
|
||||
unset( $formatted_timezone );
|
||||
$start_time_entry = $this->_registry
|
||||
->get( 'date.time', $start_time, $timezone_name );
|
||||
$end_time_entry = $this->_registry
|
||||
->get( 'date.time', $end_time, $timezone_name );
|
||||
|
||||
$timezone_name = $start_time_entry->get_timezone();
|
||||
if ( null === $timezone_name ) {
|
||||
$timezone_name = $start_time_entry->get_default_format_timezone();
|
||||
}
|
||||
|
||||
$event->set( 'post_id', $post_id );
|
||||
$event->set( 'start', $start_time_entry );
|
||||
if ( $instant_event ) {
|
||||
$event->set_no_end_time();
|
||||
} else {
|
||||
$event->set( 'end', $end_time_entry );
|
||||
$event->set( 'instant_event', false );
|
||||
}
|
||||
$event->set( 'timezone_name', $timezone_name );
|
||||
$event->set( 'allday', $all_day );
|
||||
$event->set( 'venue', $venue );
|
||||
$event->set( 'address', $address );
|
||||
$event->set( 'city', $city );
|
||||
$event->set( 'province', $province );
|
||||
$event->set( 'postal_code', $postal_code );
|
||||
$event->set( 'country', $country );
|
||||
$event->set( 'show_map', $google_map );
|
||||
$event->set( 'cost', $cost );
|
||||
$event->set( 'is_free', $is_free );
|
||||
$event->set( 'ticket_url', $ticket_url );
|
||||
$event->set( 'contact_name', $contact_name );
|
||||
$event->set( 'contact_phone', $contact_phone );
|
||||
$event->set( 'contact_email', $contact_email );
|
||||
$event->set( 'contact_url', $contact_url );
|
||||
$event->set( 'recurrence_rules', $rrule );
|
||||
$event->set( 'exception_rules', $exrule );
|
||||
$event->set( 'exception_dates', $exdate );
|
||||
$event->set( 'recurrence_dates', $rdate );
|
||||
$event->set( 'show_coordinates', $show_coordinates );
|
||||
$event->set( 'longitude', trim( $longitude ) );
|
||||
$event->set( 'latitude', trim( $latitude ) );
|
||||
$event->set( 'ical_uid', $event->get_uid() );
|
||||
|
||||
return array(
|
||||
'event' => $event,
|
||||
'is_new' => $is_new
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves meta post data.
|
||||
*
|
||||
* @wp_hook save_post
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param object $post Post object.
|
||||
* @param update
|
||||
*
|
||||
* @return object|null Saved Ai1ec_Event object if successful or null.
|
||||
*/
|
||||
public function save_post( $post_id, $post, $update ) {
|
||||
|
||||
if ( false === $this->is_valid_event( $post ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// LABEL:magicquotes
|
||||
// remove WordPress `magical` slashes - we work around it ourselves
|
||||
$_POST = stripslashes_deep( $_POST );
|
||||
|
||||
$data = $this->_parse_post_to_event( $post_id );
|
||||
if ( ! $data ) {
|
||||
return null;
|
||||
}
|
||||
$event = $data['event'];
|
||||
$is_new = $data['is_new'];
|
||||
|
||||
$banner_image = isset( $_POST['ai1ec_banner_image'] ) ? sanitize_text_field( $_POST['ai1ec_banner_image'] ) : '';
|
||||
$cost_type = isset( $_POST['ai1ec_cost_type'] ) ? sanitize_text_field( $_POST['ai1ec_cost_type'] ) : '';
|
||||
|
||||
update_post_meta( $post_id, 'ai1ec_banner_image', $banner_image );
|
||||
if ( $cost_type ) {
|
||||
update_post_meta( $post_id, '_ai1ec_cost_type', $cost_type );
|
||||
}
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
if ( $update === false ) {
|
||||
//this method just creates the API event, the update action
|
||||
//is treated by another hook (pre_update_event inside api )
|
||||
if ( 'tickets' === $cost_type ) {
|
||||
$result = $api->store_event( $event, $post, false );
|
||||
if ( true !== $result ) {
|
||||
$_POST['_ticket_store_event_error'] = $result;
|
||||
} else {
|
||||
update_post_meta(
|
||||
$post_id,
|
||||
'_ai1ec_timely_tickets_url',
|
||||
$api->get_api_event_buy_ticket_url( $event->get( 'post_id' ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( 'tickets' === $cost_type ) {
|
||||
update_post_meta(
|
||||
$post_id,
|
||||
'_ai1ec_timely_tickets_url',
|
||||
$api->get_api_event_buy_ticket_url( $event->get( 'post_id' ) )
|
||||
);
|
||||
} else {
|
||||
delete_post_meta(
|
||||
$post_id,
|
||||
'_ai1ec_timely_tickets_url'
|
||||
);
|
||||
}
|
||||
|
||||
// let other extensions save their fields.
|
||||
do_action( 'ai1ec_save_post', $event );
|
||||
|
||||
$event->save( ! $is_new );
|
||||
|
||||
// LABEL:magicquotes
|
||||
// restore `magic` WordPress quotes to maintain compatibility
|
||||
$_POST = add_magic_quotes( $_POST );
|
||||
|
||||
$api = $this->_registry->get( 'model.api.api-registration' );
|
||||
$api->check_settings();
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
private function get_sendback_page( $post_id ) {
|
||||
$sendback = wp_get_referer();
|
||||
$page_base = Ai1ec_Wp_Uri_Helper::get_pagebase( $sendback ); //$_SERVER['REQUEST_URI'] );
|
||||
if ( 'post.php' === $page_base ) {
|
||||
return get_edit_post_link( $post_id, 'url' );
|
||||
} else {
|
||||
return admin_url( 'edit.php?post_type=ai1ec_event' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle PRE (ticket event) update.
|
||||
* Just handle the Ticket Events, other kind of post are ignored
|
||||
* @wp_hook pre_post_update
|
||||
*
|
||||
*/
|
||||
public function pre_post_update ( $post_id, $new_post_data ) {
|
||||
|
||||
// LABEL:magicquotes
|
||||
// remove WordPress `magical` slashes - we work around it ourselves
|
||||
$_POST = stripslashes_deep( $_POST );
|
||||
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
$action = $this->current_action();
|
||||
switch( $action ) {
|
||||
case 'inline-save': //quick edit from edit page
|
||||
$fields = array();
|
||||
if ( false === ai1ec_is_blank( $_REQUEST['post_title'] ) ) {
|
||||
$fields['title'] = sanitize_text_field( $_REQUEST['post_title'] );
|
||||
}
|
||||
if ( false === ai1ec_is_blank( $_REQUEST['_status'] ) ) {
|
||||
$fields['status'] = $_REQUEST['_status'];
|
||||
}
|
||||
if ( isset( $_REQUEST['keep_private'] ) && 'private' === $_REQUEST['keep_private'] ) {
|
||||
$fields['visibility'] = 'private';
|
||||
} else if ( isset( $_REQUEST['post_password'] ) && false === ai1ec_is_blank( $_REQUEST['post_password'] ) ) {
|
||||
$fields['visibility'] = 'password';
|
||||
}
|
||||
if ( 0 < count( $fields ) ) {
|
||||
$post = get_post( $post_id );
|
||||
$ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
|
||||
$message = $api->update_api_event_fields( $post, $fields, 'update', $ajax );
|
||||
if ( null !== $message ) {
|
||||
if ( $ajax ) {
|
||||
wp_die( $message );
|
||||
} else {
|
||||
wp_redirect( $this->get_sendback_page( $post_id ) );
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
case 'edit': //bulk edition from edit page
|
||||
$fields = array();
|
||||
if ( false === ai1ec_is_blank( $_REQUEST['_status'] ) ) {
|
||||
$fields['status'] = $_REQUEST['_status'];
|
||||
}
|
||||
if ( 0 < count( $fields ) ) {
|
||||
$post = get_post( $post_id );
|
||||
$ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
|
||||
$message = $api->update_api_event_fields( $post, $fields, 'update', $ajax );
|
||||
if ( null !== $message ) {
|
||||
if ( $ajax ) {
|
||||
wp_die( $message );
|
||||
} else {
|
||||
wp_redirect( $this->get_sendback_page( $post_id ) );
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
case 'editpost': //edition from post page
|
||||
$new_post_data['ID'] = $post_id;
|
||||
$post = new WP_Post( (object) $new_post_data );
|
||||
if ( false === $this->is_valid_event( $post ) ) {
|
||||
break;
|
||||
}
|
||||
$data = $this->_parse_post_to_event( $post_id );
|
||||
if ( ! $data ) {
|
||||
break;
|
||||
}
|
||||
$event = $data['event'];
|
||||
$cost_type = isset( $_REQUEST['ai1ec_cost_type'] ) ? $_REQUEST['ai1ec_cost_type'] : '';
|
||||
if ( 'tickets' === $cost_type ) {
|
||||
$result = $api->store_event( $event, $post, true );
|
||||
if ( true !== $result ) {
|
||||
wp_redirect( $this->get_sendback_page( $post_id ) );
|
||||
exit();
|
||||
}
|
||||
} else {
|
||||
$message = $api->delete_api_event( $post_id, 'update', false );
|
||||
if ( null !== $message ) {
|
||||
wp_redirect( $this->get_sendback_page( $post_id ) );
|
||||
exit();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// LABEL:magicquotes
|
||||
// restore `magic` WordPress quotes to maintain compatibility
|
||||
$_POST = add_magic_quotes( $_POST );
|
||||
}
|
||||
|
||||
protected function current_action() {
|
||||
$action = '';
|
||||
if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) ) {
|
||||
$action = 'delete';
|
||||
} else {
|
||||
if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] ) {
|
||||
$action = $_REQUEST['action'];
|
||||
}
|
||||
if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] ) {
|
||||
$action = $_REQUEST['action2'];
|
||||
}
|
||||
}
|
||||
return $action;
|
||||
}
|
||||
|
||||
/**
|
||||
* _create_duplicate_post method
|
||||
*
|
||||
* Create copy of event by calling {@uses wp_insert_post} function.
|
||||
* Using 'post_parent' to add hierarchy.
|
||||
*
|
||||
* @param array $data Event instance data to copy
|
||||
*
|
||||
* @return int|bool New post ID or false on failure
|
||||
**/
|
||||
public function create_duplicate_post() {
|
||||
if ( ! isset( $_POST['post_ID'] ) ) {
|
||||
return false;
|
||||
}
|
||||
$clean_fields = array(
|
||||
'ai1ec_repeat' => NULL,
|
||||
'ai1ec_rrule' => '',
|
||||
'ai1ec_exrule' => '',
|
||||
'ai1ec_exdate' => '',
|
||||
'post_ID' => NULL,
|
||||
'post_name' => NULL,
|
||||
'ai1ec_instance_id' => NULL,
|
||||
);
|
||||
$old_post_id = $_POST['post_ID'];
|
||||
$instance_id = $_POST['ai1ec_instance_id'];
|
||||
foreach ( $clean_fields as $field => $to_value ) {
|
||||
if ( NULL === $to_value ) {
|
||||
unset( $_POST[$field] );
|
||||
} else {
|
||||
$_POST[$field] = $to_value;
|
||||
}
|
||||
}
|
||||
$_POST = _wp_translate_postdata( false, $_POST );
|
||||
$_POST['post_parent'] = $old_post_id;
|
||||
if ( isset( $_POST['post_title'] ) ) {
|
||||
$_POST['post_title'] = sanitize_text_field( $_POST['post_title'] );
|
||||
}
|
||||
$post_id = wp_insert_post( $_POST );
|
||||
$this->_registry->get( 'model.event.parent' )->event_parent(
|
||||
$post_id,
|
||||
$old_post_id,
|
||||
$instance_id
|
||||
);
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans calendar shortcodes from event content.
|
||||
*
|
||||
* @param array $data An array of slashed post data.
|
||||
* @param array $postarr An array of sanitized, but otherwise unmodified post data.
|
||||
*
|
||||
* @return array An array of slashed post data.
|
||||
*/
|
||||
public function wp_insert_post_data( $data ) {
|
||||
global $shortcode_tags;
|
||||
if (
|
||||
! isset( $data['post_type'] ) ||
|
||||
! isset( $data['post_content'] ) ||
|
||||
AI1EC_POST_TYPE !== $data['post_type'] ||
|
||||
empty( $shortcode_tags ) ||
|
||||
! is_array( $shortcode_tags ) ||
|
||||
false === strpos( $data['post_content'], '[' )
|
||||
) {
|
||||
return $data;
|
||||
}
|
||||
$pattern = get_shortcode_regex();
|
||||
$data['post_content'] = preg_replace_callback(
|
||||
"/$pattern/s",
|
||||
array( $this, 'strip_shortcode_tag' ),
|
||||
$data['post_content']
|
||||
);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reutrns shortcode or stripped content for given shortcode.
|
||||
* Currently regex callback function passes as $tag argument 7-element long
|
||||
* array.
|
||||
* First element ($tag[0]) is not modified full shortcode text.
|
||||
* Third element ($tag[2]) is pure shortcode identifier.
|
||||
* Sixth element ($tag[5]) contains shortcode content if any
|
||||
* [ai1ec_test]content[/ai1ec].
|
||||
*
|
||||
* @param array $tag Incoming data.
|
||||
*
|
||||
* @return string Shortcode replace tag.
|
||||
*/
|
||||
public function strip_shortcode_tag( $tag ) {
|
||||
if (
|
||||
count( $tag ) < 7 ||
|
||||
'ai1ec' !== substr( $tag[2], 0, 5 ) ||
|
||||
! apply_filters( 'ai1ec_content_remove_shortcode_' . $tag[2], false )
|
||||
) {
|
||||
return $tag[0];
|
||||
}
|
||||
return $tag[5];
|
||||
}
|
||||
|
||||
protected function _remap_recurrence_dates() {
|
||||
if (
|
||||
isset( $_POST['ai1ec_exclude'] ) &&
|
||||
'EXDATE' === substr( $_POST['ai1ec_exrule'], 0, 6 )
|
||||
) {
|
||||
$_POST['ai1ec_exdate'] = substr( $_POST['ai1ec_exrule'], 7 );
|
||||
unset( $_POST['ai1ec_exclude'], $_POST['ai1ec_exrule'] );
|
||||
}
|
||||
if (
|
||||
isset( $_POST['ai1ec_repeat'] ) &&
|
||||
'RDATE' === substr( $_POST['ai1ec_rrule'], 0, 5 )
|
||||
) {
|
||||
$_POST['ai1ec_rdate'] = substr( $_POST['ai1ec_rrule'], 6 );
|
||||
unset( $_POST['ai1ec_repeat'], $_POST['ai1ec_rrule'] );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,371 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Event internal structure representation. Plain value object.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @instantiator new
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Event_Entity extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Get list of object properties.
|
||||
*
|
||||
* Special value `registry` ({@see Ai1ec_Registry_Object}) is excluded.
|
||||
*
|
||||
* @return array List of accessible properties.
|
||||
*
|
||||
* @staticvar array $known List of properties.
|
||||
*/
|
||||
public function list_properties() {
|
||||
static $known = null;
|
||||
if ( null === $known ) {
|
||||
$known = array();
|
||||
foreach ( $this as $name => $value ) {
|
||||
$name = substr( $name, 1 );
|
||||
if ( 'registry' === $name ) {
|
||||
continue;
|
||||
}
|
||||
$known[] = $name;
|
||||
}
|
||||
}
|
||||
return $known;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle cloning properly to resist property changes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __clone() {
|
||||
$this->_start = $this->_registry->get( 'date.time', $this->_start );
|
||||
$this->_end = $this->_registry->get( 'date.time', $this->_end );
|
||||
$this->_post = clone $this->_post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change stored property.
|
||||
*
|
||||
* @param string $name Name of property to change.
|
||||
* @param mixed $value Arbitrary value to use.
|
||||
*
|
||||
* @return Ai1ec_Event_Entity Instance of self for chaining.
|
||||
*
|
||||
* @staticvar array $time_fields Map of fields holding a value of
|
||||
* {@see Ai1ec_Date_Time}, which
|
||||
* require modification instead of
|
||||
* replacement.
|
||||
*/
|
||||
public function set( $name, $value ) {
|
||||
static $time_fields = array(
|
||||
'start' => true,
|
||||
'end' => true,
|
||||
);
|
||||
if ( 'registry' === $name ) {
|
||||
return $this; // short-circuit: protection mean.
|
||||
}
|
||||
if ( 'timezone_name' === $name && empty( $value ) ) {
|
||||
return $this; // protection against invalid TZ values.
|
||||
}
|
||||
$field = '_' . $name;
|
||||
if ( isset( $time_fields[$name] ) ) {
|
||||
// object of Ai1ec_Date_Time type is now handled in it itself
|
||||
$this->{$field}->set_date_time(
|
||||
$value,
|
||||
( null === $this->_timezone_name )
|
||||
? 'UTC'
|
||||
: $this->_timezone_name
|
||||
);
|
||||
$this->adjust_preferred_timezone();
|
||||
} else {
|
||||
$this->{$field} = $value;
|
||||
}
|
||||
if ( 'timezone_name' === $name ) {
|
||||
$this->_start->set_timezone( $value );
|
||||
$this->_end ->set_timezone( $value );
|
||||
$this->adjust_preferred_timezone();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally adjust preferred (display) timezone.
|
||||
*
|
||||
* @return bool|DateTimeZone False or new timezone.
|
||||
*
|
||||
* @staticvar bool $do_adjust True when adjustment should be performed.
|
||||
*/
|
||||
public function adjust_preferred_timezone() {
|
||||
static $do_adjust = null;
|
||||
if ( null === $do_adjust ) {
|
||||
$do_adjust = !$this->_registry
|
||||
->get( 'model.settings' )
|
||||
->get( 'always_use_calendar_timezone', false );
|
||||
}
|
||||
if ( ! $do_adjust ) {
|
||||
return false;
|
||||
}
|
||||
$timezone = $this->_registry->get( 'date.timezone' )->get(
|
||||
$this->_timezone_name
|
||||
);
|
||||
$this->set_preferred_timezone( $timezone );
|
||||
return $timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set preferred timezone to datetime fields.
|
||||
*
|
||||
* @param DateTimeZone $timezone Preferred timezone instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_preferred_timezone( DateTimeZone $timezone ) {
|
||||
$this->_start->set_preferred_timezone( $timezone );
|
||||
$this->_end ->set_preferred_timezone( $timezone );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value of some property.
|
||||
*
|
||||
* @param string $name Name of property to get.
|
||||
* @param mixed $default Value to return if property is not defined.
|
||||
*
|
||||
* @return mixed Found value or $default.
|
||||
*/
|
||||
public function get( $name, $default = null ) {
|
||||
if ( ! isset( $this->{ '_' . $name } ) ) {
|
||||
return $default;
|
||||
}
|
||||
return $this->{ '_' . $name };
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize values to some sane defaults.
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry Injected registry.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( Ai1ec_Registry_Object $registry ) {
|
||||
parent::__construct( $registry );
|
||||
$this->_start = $this->_registry->get( 'date.time' );
|
||||
$this->_end = $this->_registry->get( 'date.time', '+1 hour' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @var object Instance of WP_Post object.
|
||||
*/
|
||||
private $_post;
|
||||
|
||||
/**
|
||||
* @var int Post ID.
|
||||
*/
|
||||
private $_post_id;
|
||||
|
||||
/**
|
||||
* @var int|null Uniquely identifies the recurrence instance of this event
|
||||
* object. Value may be null.
|
||||
*/
|
||||
private $_instance_id;
|
||||
|
||||
/**
|
||||
* @var string Name of timezone to use for event times.
|
||||
*/
|
||||
private $_timezone_name;
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Date_Time Start date-time specifier
|
||||
*/
|
||||
private $_start;
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Date_Time End date-time specifier
|
||||
*/
|
||||
private $_end;
|
||||
|
||||
/**
|
||||
* @var bool Whether this copy of the event was broken up for rendering and
|
||||
* the start time is not its "real" start time.
|
||||
*/
|
||||
private $_start_truncated;
|
||||
|
||||
/**
|
||||
* @var bool Whether this copy of the event was broken up for rendering and
|
||||
* the end time is not its "real" end time.
|
||||
*/
|
||||
private $_end_truncated;
|
||||
|
||||
/**
|
||||
* @var int If event is all-day long
|
||||
*/
|
||||
private $_allday;
|
||||
|
||||
/**
|
||||
* @var int If event has no duration
|
||||
*/
|
||||
private $_instant_event;
|
||||
|
||||
/**
|
||||
* ==========================
|
||||
* = Recurrence information =
|
||||
* ==========================
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var string Recurrence rules
|
||||
*/
|
||||
private $_recurrence_rules;
|
||||
|
||||
/**
|
||||
* @var string Exception rules
|
||||
*/
|
||||
private $_exception_rules;
|
||||
|
||||
/**
|
||||
* @var string Recurrence dates
|
||||
*/
|
||||
private $_recurrence_dates;
|
||||
|
||||
/**
|
||||
* @var string Exception dates
|
||||
*/
|
||||
private $_exception_dates;
|
||||
|
||||
/**
|
||||
* @var string Venue name - free text
|
||||
*/
|
||||
private $_venue;
|
||||
|
||||
/**
|
||||
* @var string Country name - free text
|
||||
*/
|
||||
private $_country;
|
||||
|
||||
/**
|
||||
* @var string Address information - free text
|
||||
*/
|
||||
private $_address;
|
||||
|
||||
/**
|
||||
* @var string City name - free text
|
||||
*/
|
||||
private $_city;
|
||||
|
||||
/**
|
||||
* @var string Province free text definition
|
||||
*/
|
||||
private $_province;
|
||||
|
||||
/**
|
||||
* @var int Postal code
|
||||
*/
|
||||
private $_postal_code;
|
||||
|
||||
/**
|
||||
* @var int Set to true to display map
|
||||
*/
|
||||
private $_show_map;
|
||||
|
||||
/**
|
||||
* @var int Set to true to show coordinates in description
|
||||
*/
|
||||
private $_show_coordinates;
|
||||
|
||||
/**
|
||||
* @var float GEO information - longitude
|
||||
*/
|
||||
private $_longitude;
|
||||
|
||||
/**
|
||||
* @var float GEO information - latitude
|
||||
*/
|
||||
private $_latitude;
|
||||
|
||||
/**
|
||||
* @var string Event contact information - contact person
|
||||
*/
|
||||
private $_contact_name;
|
||||
|
||||
/**
|
||||
* @var string Event contact information - phone number
|
||||
*/
|
||||
private $_contact_phone;
|
||||
|
||||
/**
|
||||
* @var string Event contact information - email address
|
||||
*/
|
||||
private $_contact_email;
|
||||
|
||||
/**
|
||||
* @var string Event contact information - external URL.
|
||||
*/
|
||||
private $_contact_url;
|
||||
|
||||
/**
|
||||
* @var string Defines event cost.
|
||||
*/
|
||||
private $_cost;
|
||||
|
||||
/**
|
||||
* @var bool Indicates, whereas event is free.
|
||||
*/
|
||||
private $_is_free;
|
||||
|
||||
/**
|
||||
* @var string Link to buy tickets
|
||||
*/
|
||||
private $_ticket_url;
|
||||
|
||||
// ====================================
|
||||
// = iCalendar feed (.ics) properties =
|
||||
// ====================================
|
||||
|
||||
/**
|
||||
* @var string URI of source ICAL feed.
|
||||
*/
|
||||
private $_ical_feed_url;
|
||||
|
||||
/**
|
||||
* @var string|null URI of source ICAL entity.
|
||||
*/
|
||||
private $_ical_source_url;
|
||||
|
||||
/**
|
||||
* @var string Organiser details
|
||||
*/
|
||||
private $_ical_organizer;
|
||||
|
||||
/**
|
||||
* @var string Contact details
|
||||
*/
|
||||
private $_ical_contact;
|
||||
|
||||
/**
|
||||
* @var string|int UID of ICAL feed
|
||||
*/
|
||||
private $_ical_uid;
|
||||
|
||||
// ===============================
|
||||
// = taxonomy-related properties =
|
||||
// ===============================
|
||||
|
||||
/**
|
||||
* @var string Associated event tag names (*not* IDs), joined by commas.
|
||||
*/
|
||||
private $_tags;
|
||||
|
||||
/**
|
||||
* @var string Associated event category IDs, joined by commas.
|
||||
*/
|
||||
private $_categories;
|
||||
|
||||
/**
|
||||
* @var string Associated event feed object
|
||||
*/
|
||||
private $_feed;
|
||||
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Indicates a failure that happens during event save operation.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.1
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Model
|
||||
*/
|
||||
class Ai1ec_Event_Create_Exception extends Exception {
|
||||
|
||||
}
|
||||
@@ -1,440 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Kigkonsult\Icalcreator\Util\UtilRecur;
|
||||
|
||||
/**
|
||||
* Event instance management model.
|
||||
*
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Event_Instance extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Dbi Instance of database abstraction.
|
||||
*/
|
||||
protected $_dbi = null;
|
||||
|
||||
/**
|
||||
* DBI utils.
|
||||
*
|
||||
* @var Ai1ec_Dbi_Utils
|
||||
*/
|
||||
protected $_dbi_utils;
|
||||
|
||||
/**
|
||||
* Store locally instance of Ai1ec_Dbi.
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry Injected object registry.
|
||||
*
|
||||
*/
|
||||
public function __construct( Ai1ec_Registry_Object $registry ) {
|
||||
parent::__construct( $registry );
|
||||
$this->_dbi = $this->_registry->get( 'dbi.dbi' );
|
||||
$this->_dbi_utils = $this->_registry->get( 'dbi.dbi-utils' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove entries for given post. Optionally delete particular instance.
|
||||
*
|
||||
* @param int $post_id Event ID to remove instances for.
|
||||
* @param int|null $instance_id Instance ID, or null for all.
|
||||
*
|
||||
* @return int|bool Number of entries removed, or false on failure.
|
||||
*/
|
||||
public function clean( $post_id, $instance_id = null ) {
|
||||
$where = array( 'post_id' => $post_id );
|
||||
$format = array( '%d' );
|
||||
if ( null !== $instance_id ) {
|
||||
$where['id'] = $instance_id;
|
||||
$format[] = '%d';
|
||||
}
|
||||
return $this->_dbi->delete( 'ai1ec_event_instances', $where, $format );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and then create instance entries for given event.
|
||||
*
|
||||
* @param Ai1ec_Event $event Instance of event to recreate entries for.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function recreate( Ai1ec_Event $event ) {
|
||||
$old_instances = $this->_load_instances( $event->get( 'post_id' ) );
|
||||
$instances = $this->_create_instances_collection( $event );
|
||||
$insert = array();
|
||||
foreach ( $instances as $instance ) {
|
||||
if ( ! isset( $old_instances[$instance['start'] . ':' . $instance['end']] ) ) {
|
||||
$insert[] = $instance;
|
||||
continue;
|
||||
}
|
||||
unset( $old_instances[$instance['start'] . ':' . $instance['end']] );
|
||||
}
|
||||
$this->_remove_instances_by_ids( array_values( $old_instances ) );
|
||||
$this->_add_instances( $insert );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create list of recurrent instances.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event to generate instances for.
|
||||
* @param array $event_instance First instance contents.
|
||||
* @param int $_start Timestamp of first occurence.
|
||||
* @param int $duration Event duration in seconds.
|
||||
* @param string $timezone Target timezone.
|
||||
*
|
||||
* @return array List of event instances.
|
||||
*/
|
||||
public function create_instances_by_recurrence(
|
||||
Ai1ec_Event $event,
|
||||
array $event_instance,
|
||||
$_start,
|
||||
$duration,
|
||||
$timezone
|
||||
) {
|
||||
$restore_timezone = date_default_timezone_get();
|
||||
$recurrence_parser = $this->_registry->get( 'recurrence.rule' );
|
||||
$events = array();
|
||||
|
||||
$start = $event_instance['start'];
|
||||
$wdate = $startdate = $enddate
|
||||
= $this->_parsed_date_array( $_start, $timezone );
|
||||
$enddate['year'] = $enddate['year'] + 10;
|
||||
$exclude_dates = array();
|
||||
$exception_rules = $event->get( 'exception_dates' );
|
||||
$recurrence_dates = array();
|
||||
$recurrence_rules = $event->get( 'recurrence_dates' );
|
||||
if ( $recurrence_rules ) {
|
||||
$recurrence_dates = $this->_populate_recurring_dates(
|
||||
$recurrence_rules,
|
||||
$startdate,
|
||||
$timezone
|
||||
);
|
||||
}
|
||||
if ( $exception_rules ) {
|
||||
$exclude_dates = $this->_populate_recurring_dates(
|
||||
$exception_rules,
|
||||
$startdate,
|
||||
$timezone
|
||||
);
|
||||
}
|
||||
if ( $event->get( 'exception_rules' ) ) {
|
||||
// creat an array for the rules
|
||||
$exception_rules = $recurrence_parser
|
||||
->build_recurrence_rules_array(
|
||||
$event->get( 'exception_rules' )
|
||||
);
|
||||
unset($exception_rules['EXDATE']);
|
||||
if ( ! empty( $exception_rules ) ) {
|
||||
$exception_rules = UtilRecur::setRexrule(
|
||||
$exception_rules
|
||||
);
|
||||
$result = array();
|
||||
date_default_timezone_set( $timezone );
|
||||
// The first array is the result and it is passed by reference
|
||||
UtilRecur::recur2date(
|
||||
$exclude_dates,
|
||||
$exception_rules,
|
||||
$wdate,
|
||||
$startdate,
|
||||
$enddate
|
||||
);
|
||||
// Get start date time
|
||||
$startHour = isset( $startdate['hour'] ) ? sprintf( "%02d", $startdate['hour'] ) : '00';
|
||||
$startMinute = isset( $startdate['min'] ) ? sprintf( "%02d", $startdate['min'] ) : '00';
|
||||
$startSecond = isset( $startdate['sec'] ) ? sprintf( "%02d", $startdate['sec'] ) : '00';
|
||||
$startTime = $startHour . $startMinute . $startSecond;
|
||||
// Convert to timestamp
|
||||
if ( is_array( $exclude_dates ) ) {
|
||||
$new_exclude_dates = array();
|
||||
foreach ( $exclude_dates as $key => $value ) {
|
||||
$timestamp = strtotime( $key . 'T' . $startTime );
|
||||
$new_exclude_dates[$timestamp] = $value;
|
||||
}
|
||||
$exclude_dates = $new_exclude_dates;
|
||||
}
|
||||
date_default_timezone_set( $restore_timezone );
|
||||
}
|
||||
}
|
||||
$recurrence_rules = $recurrence_parser
|
||||
->build_recurrence_rules_array(
|
||||
$event->get( 'recurrence_rules' )
|
||||
);
|
||||
|
||||
$recurrence_rules = UtilRecur::setRexrule( $recurrence_rules );
|
||||
if ( $recurrence_rules ) {
|
||||
date_default_timezone_set( $timezone );
|
||||
UtilRecur::recur2date(
|
||||
$recurrence_dates,
|
||||
$recurrence_rules,
|
||||
$wdate,
|
||||
$startdate,
|
||||
$enddate
|
||||
);
|
||||
|
||||
// Get start date time
|
||||
$startHour = isset( $startdate['hour'] ) ? sprintf( "%02d", $startdate['hour'] ) : '00';
|
||||
$startMinute = isset( $startdate['min'] ) ? sprintf( "%02d", $startdate['min'] ) : '00';
|
||||
$startSecond = isset( $startdate['sec'] ) ? sprintf( "%02d", $startdate['sec'] ) : '00';
|
||||
$startTime = $startHour . $startMinute . $startSecond;
|
||||
// Convert to timestamp
|
||||
if ( is_array( $recurrence_dates ) ) {
|
||||
$new_recurrence_dates = array();
|
||||
foreach ( $recurrence_dates as $key => $value ) {
|
||||
$timestamp = strtotime( $key . 'T' . $startTime );
|
||||
$new_recurrence_dates[$timestamp] = $value;
|
||||
}
|
||||
$recurrence_dates = $new_recurrence_dates;
|
||||
}
|
||||
date_default_timezone_set( $restore_timezone );
|
||||
}
|
||||
|
||||
if ( ! is_array( $recurrence_dates ) ) {
|
||||
$recurrence_dates = array();
|
||||
}
|
||||
$recurrence_dates = array_keys( $recurrence_dates );
|
||||
// Add the instances
|
||||
foreach ( $recurrence_dates as $timestamp ) {
|
||||
// The arrays are in the form timestamp => true so an isset call is what we need
|
||||
if ( ! isset( $exclude_dates[$timestamp] ) ) {
|
||||
$event_instance['start'] = $timestamp;
|
||||
$event_instance['end'] = $timestamp + $duration;
|
||||
$events[$timestamp] = $event_instance;
|
||||
}
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and store instance entries in database for given event.
|
||||
*
|
||||
* @param Ai1ec_Event $event Instance of event to create entries for.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function create( Ai1ec_Event $event ) {
|
||||
$instances = $this->_create_instances_collection( $event );
|
||||
$this->_add_instances( $instances );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given date match dates in EXDATES rule.
|
||||
*
|
||||
* @param string $date Date to check.
|
||||
* @param string $ics_rule ICS EXDATES rule.
|
||||
* @param string $timezone Timezone to evaluate value in.
|
||||
*
|
||||
* @return bool True if given date is in rule.
|
||||
*/
|
||||
public function date_match_exdates( $date, $ics_rule, $timezone ) {
|
||||
$ranges = $this->_get_date_ranges( $ics_rule, $timezone );
|
||||
foreach ( $ranges as $interval ) {
|
||||
if ( $date >= $interval[0] && $date <= $interval[1] ) {
|
||||
return true;
|
||||
}
|
||||
if ( $date <= $interval[0] ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare date range list for fast exdate search.
|
||||
*
|
||||
* NOTICE: timezone is relevant in only first run.
|
||||
*
|
||||
* @param string $date_list ICS list provided from data model.
|
||||
* @param string $timezone Timezone in which to evaluate.
|
||||
*
|
||||
* @return array List of date ranges, sorted in increasing order.
|
||||
*/
|
||||
protected function _get_date_ranges( $date_list, $timezone ) {
|
||||
static $ranges = array();
|
||||
if ( ! isset( $ranges[$date_list] ) ) {
|
||||
$ranges[$date_list] = array();
|
||||
$exploded = explode( ',', $date_list );
|
||||
sort( $exploded );
|
||||
foreach ( $exploded as $date ) {
|
||||
// COMMENT on `rtrim( $date, 'Z' )`:
|
||||
// user selects exclusion date in event timezone thus it
|
||||
// must be parsed as such as opposed to UTC which happen
|
||||
// when 'Z' is preserved.
|
||||
$date = $this->_registry
|
||||
->get( 'date.time', rtrim( $date, 'Z' ), $timezone )
|
||||
->format_to_gmt();
|
||||
$ranges[$date_list][] = array(
|
||||
$date,
|
||||
$date + (24 * 60 * 60) - 1
|
||||
);
|
||||
}
|
||||
}
|
||||
return $ranges[$date_list];
|
||||
}
|
||||
|
||||
protected function _populate_recurring_dates( $rule, array $start_struct, $timezone ) {
|
||||
$start = clone $start_struct['_dt'];
|
||||
$dates = array();
|
||||
foreach ( explode( ',', $rule ) as $date ) {
|
||||
$i_date = clone $start;
|
||||
$spec = sscanf( $date, '%04d%02d%02d' );
|
||||
$i_date->set_date(
|
||||
$spec[0],
|
||||
$spec[1],
|
||||
$spec[2]
|
||||
);
|
||||
$dates[$i_date->format_to_gmt()] = $i_date;
|
||||
}
|
||||
return $dates;
|
||||
}
|
||||
|
||||
protected function _parsed_date_array( $startdate, $timezone ) {
|
||||
$datetime = $this->_registry->get( 'date.time', $startdate, $timezone );
|
||||
$parsed = array(
|
||||
'year' => intval( $datetime->format( 'Y' ) ),
|
||||
'month' => intval( $datetime->format( 'm' ) ),
|
||||
'day' => intval( $datetime->format( 'd' ) ),
|
||||
'hour' => intval( $datetime->format( 'H' ) ),
|
||||
'min' => intval( $datetime->format( 'i' ) ),
|
||||
'sec' => intval( $datetime->format( 's' ) ),
|
||||
'tz' => $datetime->get_timezone(),
|
||||
'_dt' => $datetime,
|
||||
);
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current instances map.
|
||||
*
|
||||
* @param int post_id Post ID.
|
||||
*
|
||||
* @return array Array of data.
|
||||
*/
|
||||
protected function _load_instances( $post_id ) {
|
||||
$query = $this->_dbi->prepare(
|
||||
'SELECT `id`, `start`, `end` FROM ' .
|
||||
$this->_dbi->get_table_name( 'ai1ec_event_instances' ) .
|
||||
' WHERE post_id = %d',
|
||||
$post_id
|
||||
);
|
||||
$results = $this->_dbi->get_results( $query );
|
||||
$instances = array();
|
||||
foreach ( $results as $result ) {
|
||||
$instances[(int)$result->start . ':' . (int)$result->end] = (int)$result->id;
|
||||
}
|
||||
return $instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and store instance entries in database for given event.
|
||||
*
|
||||
* @param Ai1ec_Event $event Instance of event to create entries for.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
protected function _create_instances_collection( Ai1ec_Event $event ) {
|
||||
$events = array();
|
||||
$event_item = array(
|
||||
'post_id' => $event->get( 'post_id' ),
|
||||
'start' => $event->get( 'start' )->format_to_gmt(),
|
||||
'end' => $event->get( 'end' )->format_to_gmt(),
|
||||
);
|
||||
$duration = $event->get( 'end' )->diff_sec( $event->get( 'start' ) );
|
||||
|
||||
$_start = $event->get( 'start' )->format_to_gmt();
|
||||
$_end = $event->get( 'end' )->format_to_gmt();
|
||||
|
||||
// Always cache initial instance
|
||||
$events[$_start] = $event_item;
|
||||
|
||||
if ( $event->get( 'recurrence_rules' ) || $event->get( 'recurrence_dates' ) ) {
|
||||
$start_timezone = $this->_registry->get( 'model.option' )
|
||||
->get( 'timezone_string' );
|
||||
if ( empty( $start_timezone ) ) {
|
||||
$start_timezone = $this->_registry->get( 'date.timezone' )->get_default_timezone();
|
||||
}
|
||||
|
||||
$events += $this->create_instances_by_recurrence(
|
||||
$event,
|
||||
$event_item,
|
||||
$_start,
|
||||
$duration,
|
||||
$start_timezone
|
||||
);
|
||||
}
|
||||
|
||||
$search_helper = $this->_registry->get( 'model.search' );
|
||||
foreach ( $events as &$event_item ) {
|
||||
// Find out if this event instance is already accounted for by an
|
||||
// overriding 'RECURRENCE-ID' of the same iCalendar feed (by comparing the
|
||||
// UID, start date, recurrence). If so, then do not create duplicate
|
||||
// instance of event.
|
||||
$start = $event_item['start'];
|
||||
$matching_event_id = null;
|
||||
if ( $event->get( 'ical_uid' ) ) {
|
||||
$matching_event_id = $search_helper->get_matching_event_id(
|
||||
$event->get( 'ical_uid' ),
|
||||
$event->get( 'ical_feed_url' ),
|
||||
$event->get( 'start' ),
|
||||
false,
|
||||
$event->get( 'post_id' )
|
||||
);
|
||||
}
|
||||
|
||||
// If no other instance was found
|
||||
if ( null !== $matching_event_id ) {
|
||||
$event_item = false;
|
||||
}
|
||||
}
|
||||
|
||||
return array_filter( $events );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes ai1ec_event_instances entries using their IDS.
|
||||
*
|
||||
* @param array $ids Collection of IDS.
|
||||
*
|
||||
* @return bool Result.
|
||||
*/
|
||||
protected function _remove_instances_by_ids( array $ids ) {
|
||||
if ( empty( $ids ) ) {
|
||||
return false;
|
||||
}
|
||||
$query = 'DELETE FROM ' . $this->_dbi->get_table_name(
|
||||
'ai1ec_event_instances'
|
||||
) . ' WHERE id IN (';
|
||||
$ids = array_filter( array_map( 'intval', $ids ) );
|
||||
$query .= implode( ',', $ids ) . ')';
|
||||
$this->_dbi->query( $query );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new instances collection.
|
||||
*
|
||||
* @param array $instances Collection of instances.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _add_instances( array $instances ) {
|
||||
$chunks = array_chunk( $instances, 50 );
|
||||
foreach ( $chunks as $chunk ) {
|
||||
$query = 'INSERT INTO ' . $this->_dbi->get_table_name(
|
||||
'ai1ec_event_instances'
|
||||
) . '(`post_id`, `start`, `end`) VALUES';
|
||||
$chunk = array_map(
|
||||
array( $this->_dbi_utils, 'array_value_to_sql_value' ),
|
||||
$chunk
|
||||
);
|
||||
$query .= implode( ',', $chunk );
|
||||
$this->_dbi->query( $query );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Some argument was of invalid type.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Model
|
||||
*/
|
||||
class Ai1ec_Invalid_Argument_Exception extends Ai1ec_Exception {
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Model representing a legacy event.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @instantiator new
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Event_Legacy extends Ai1ec_Event {
|
||||
|
||||
/**
|
||||
* @var array map of method => class for legacy code.
|
||||
*/
|
||||
protected static $_classes = array(
|
||||
'get_category_colors' => 'taxonomy',
|
||||
'get_color_style' => 'taxonomy',
|
||||
'get_categories_html' => 'taxonomy',
|
||||
'get_tags_html' => 'taxonomy',
|
||||
'get_category_text_color' => 'taxonomy',
|
||||
'get_category_bg_color' => 'taxonomy',
|
||||
'get_faded_color' => 'color',
|
||||
'get_rgba_color' => 'color',
|
||||
'get_event_avatar' => 'avatar',
|
||||
'get_event_avatar_url' => 'avatar',
|
||||
'get_post_thumbnail_url' => 'avatar',
|
||||
'get_content_img_url' => 'avatar',
|
||||
'get_short_location' => 'location',
|
||||
'get_location' => 'location',
|
||||
'get_map_view' => 'location',
|
||||
'get_latlng' => 'location',
|
||||
'get_gmap_url' => 'location',
|
||||
'get_tickets_url_label' => 'ticket',
|
||||
'get_contact_html' => 'ticket',
|
||||
'get_timespan_html' => 'time',
|
||||
'get_exclude_html' => 'time',
|
||||
'get_back_to_calendar_button_html' => 'content',
|
||||
'get_post_excerpt' => 'content',
|
||||
);
|
||||
|
||||
public function get_long_end_date( $adjust = 0 ) {
|
||||
$time = $this->_registry->get( 'view.event.time' );
|
||||
$end = $this->_registry->get( 'date.time', $this->get( 'end' ) );
|
||||
if ( ! empty( $adjust ) ) {
|
||||
$end->set_time(
|
||||
$end->format( 'H' ),
|
||||
$end->format( 'i' ),
|
||||
$adjust
|
||||
);
|
||||
}
|
||||
return $time->get_long_date( $end );
|
||||
}
|
||||
|
||||
public function get_long_start_date() {
|
||||
$time = $this->_registry->get( 'view.event.time' );
|
||||
return $time->get_long_date( $this->get( 'start' ) );
|
||||
}
|
||||
|
||||
public function get_multiday() {
|
||||
return $this->is_multiday();
|
||||
}
|
||||
|
||||
public function get_recurrence_html() {
|
||||
$rrule = $this->_registry->get( 'recurrence.rule' );
|
||||
return $rrule->rrule_to_text( $this->get( 'recurrence_rules' ) );
|
||||
}
|
||||
|
||||
public function get_short_end_date() {
|
||||
$time = $this->_registry->get( 'view.event.time' );
|
||||
$end = $this->_registry->get( 'date.time', $this->get( 'end' ) );
|
||||
$end->set_time(
|
||||
$end->format( 'H' ),
|
||||
$end->format( 'i' ),
|
||||
-1
|
||||
);
|
||||
return $time->get_short_date( $end );
|
||||
}
|
||||
|
||||
public function get_short_end_time() {
|
||||
$time = $this->_registry->get( 'view.event.time' );
|
||||
return $time->get_short_time( $this->get( 'end' ) );
|
||||
}
|
||||
|
||||
public function get_short_start_date() {
|
||||
$time = $this->_registry->get( 'view.event.time' );
|
||||
return $time->get_short_date( $this->get( 'start' ) );
|
||||
}
|
||||
|
||||
public function get_short_start_time() {
|
||||
$time = $this->_registry->get( 'view.event.time' );
|
||||
return $time->get_short_time( $this->get( 'start' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles legacy property setters.
|
||||
*
|
||||
* @param string $property Name of property being set.
|
||||
* @param mixed $value Value attempted to set.
|
||||
*
|
||||
* @return Ai1ec_Event Instance of self for chaining.
|
||||
*/
|
||||
public function __set( $property, $value ) {
|
||||
return $this->set( $property, $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle property accessors.
|
||||
*
|
||||
* @param string $name Property name
|
||||
*
|
||||
* @return mixed Property value
|
||||
*/
|
||||
public function __get( $name ) {
|
||||
$method = 'get_' . $name;
|
||||
if ( method_exists( $this, $name ) ) {
|
||||
return $this->{$method}();
|
||||
}
|
||||
return $this->get( $name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle legacy methods calls.
|
||||
*
|
||||
* @param string $method Legacy method name.
|
||||
* @param array $arguments Arguments passed to method.
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws Ai1ec_Invalid_Argument_Exception If there is no method handler.
|
||||
*/
|
||||
public function __call( $method, $arguments ) {
|
||||
if ( ! isset( self::$_classes[$method] ) ) {
|
||||
throw new Ai1ec_Invalid_Argument_Exception(
|
||||
'Requested method \'' . $method . '\' is unknown'
|
||||
);
|
||||
}
|
||||
array_unshift( $arguments, $this );
|
||||
$class = 'view.event.' . self::$_classes[$method];
|
||||
return $this->_registry->dispatch(
|
||||
$class,
|
||||
$method,
|
||||
$arguments
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Event not found.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Model
|
||||
*/
|
||||
class Ai1ec_Event_Not_Found_Exception extends Exception {
|
||||
|
||||
}
|
||||
@@ -1,366 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Class which represnt event parent/child relationship.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Event_Parent extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* event_parent method
|
||||
*
|
||||
* Get/set event parent
|
||||
*
|
||||
* @param int $event_id ID of checked event
|
||||
* @param int $parent_id ID of new parent [optional=NULL, acts as getter]
|
||||
* @param int $instance_id ID of old instance id
|
||||
*
|
||||
* @return int|bool Value depends on mode:
|
||||
* Getter: {@see self::get_parent_event()} for details
|
||||
* Setter: true on success.
|
||||
*/
|
||||
public function event_parent(
|
||||
$event_id,
|
||||
$parent_id = null,
|
||||
$instance_id = null
|
||||
) {
|
||||
$meta_key = '_ai1ec_event_parent';
|
||||
if ( null === $parent_id ) {
|
||||
return $this->get_parent_event( $event_id );
|
||||
}
|
||||
$meta_value = json_encode( array(
|
||||
'created' => $this->_registry->get( 'date.system' )->current_time(),
|
||||
'instance' => $instance_id,
|
||||
) );
|
||||
return add_post_meta( $event_id, $meta_key, $meta_value, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parent ID for given event
|
||||
*
|
||||
* @param int $current_id Current event ID
|
||||
*
|
||||
* @return int|bool ID of parent event or bool(false)
|
||||
*/
|
||||
public function get_parent_event( $current_id ) {
|
||||
static $parents = null;
|
||||
if ( null === $parents ) {
|
||||
$parents = $this->_registry->get( 'cache.memory' );
|
||||
}
|
||||
$current_id = (int)$current_id;
|
||||
if ( null === ( $parent_id = $parents->get( $current_id ) ) ) {
|
||||
$db = $this->_registry->get( 'dbi.dbi' );
|
||||
/* @var $db Ai1ec_Dbi */
|
||||
$query = '
|
||||
SELECT parent.ID, parent.post_status
|
||||
FROM
|
||||
' . $db->get_table_name( 'posts' ) . ' AS child
|
||||
INNER JOIN ' . $db->get_table_name( 'posts' ) . ' AS parent
|
||||
ON ( parent.ID = child.post_parent )
|
||||
WHERE child.ID = ' . $current_id;
|
||||
$parent = $db->get_row( $query );
|
||||
if (
|
||||
empty( $parent ) ||
|
||||
'trash' === $parent->post_status
|
||||
) {
|
||||
$parent_id = false;
|
||||
} else {
|
||||
$parent_id = $parent->ID;
|
||||
}
|
||||
$parents->set( $current_id, $parent_id );
|
||||
unset( $query );
|
||||
}
|
||||
return $parent_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of modified (children) event objects
|
||||
*
|
||||
* @param int $parent_id ID of parent event
|
||||
* @param bool $include_trash Includes trashed when `true` [optional=false]
|
||||
*
|
||||
* @return array List (might be empty) of Ai1ec_Event objects
|
||||
*/
|
||||
public function get_child_event_objects(
|
||||
$parent_id,
|
||||
$include_trash = false
|
||||
) {
|
||||
$db = $this->_registry->get( 'dbi.dbi' );
|
||||
/* @var $db Ai1ec_Dbi */
|
||||
$parent_id = (int)$parent_id;
|
||||
$sql_query = 'SELECT ID FROM ' . $db->get_table_name( 'posts' ) .
|
||||
' WHERE post_parent = ' . $parent_id;
|
||||
$children = (array)$db->get_col( $sql_query );
|
||||
$objects = array();
|
||||
foreach ( $children as $child_id ) {
|
||||
try {
|
||||
$instance = $this->_registry->get( 'model.event', $child_id );
|
||||
if (
|
||||
$include_trash ||
|
||||
'trash' !== $instance->get( 'post' )->post_status
|
||||
) {
|
||||
$objects[$child_id] = $instance;
|
||||
}
|
||||
} catch ( Ai1ec_Event_Not_Found_Exception $exception ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return $objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* admin_init_post method
|
||||
*
|
||||
* Bind to admin_action_editpost action to override default save
|
||||
* method when user is editing single instance.
|
||||
* New post is created with some fields unset.
|
||||
*/
|
||||
public function admin_init_post( ) {
|
||||
if (
|
||||
isset( $_POST['ai1ec_instance_id'] ) &&
|
||||
isset( $_POST['action'] ) &&
|
||||
'editpost' === $_POST['action']
|
||||
) {
|
||||
$old_post_id = $_POST['post_ID'];
|
||||
$instance_id = $_POST['ai1ec_instance_id'];
|
||||
$post_id = $this->_registry->get( 'model.event.creating' )
|
||||
->create_duplicate_post();
|
||||
if ( false !== $post_id ) {
|
||||
$this->_handle_instances(
|
||||
$this->_registry->get( 'model.event', $post_id ),
|
||||
$this->_registry->get( 'model.event', $old_post_id ),
|
||||
$instance_id
|
||||
);
|
||||
$this->_registry->get( 'model.event.instance' )->clean(
|
||||
$old_post_id,
|
||||
$instance_id
|
||||
);
|
||||
$location = add_query_arg(
|
||||
'message',
|
||||
1,
|
||||
get_edit_post_link( $post_id, 'url' )
|
||||
);
|
||||
wp_redirect(
|
||||
apply_filters(
|
||||
'redirect_post_location',
|
||||
$location,
|
||||
$post_id
|
||||
)
|
||||
);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject base event edit link for modified instances
|
||||
*
|
||||
* Modified instances are events, belonging to some parent having recurrence
|
||||
* rule, and having some of it's properties altered.
|
||||
*
|
||||
* @param array $actions List of defined actions
|
||||
* @param stdClass $post Instance being rendered (WP_Post class instance in WP 3.5+)
|
||||
*
|
||||
* @return array Optionally modified $actions list
|
||||
*/
|
||||
public function post_row_actions( $actions, $post ) {
|
||||
if ( $this->_registry->get( 'acl.aco' )->is_our_post_type( $post ) ) {
|
||||
$parent_post_id = $this->event_parent( $post->ID );
|
||||
if (
|
||||
$parent_post_id &&
|
||||
NULL !== ( $parent_post = get_post( $parent_post_id ) ) &&
|
||||
isset( $parent_post->post_status ) &&
|
||||
'trash' !== $parent_post->post_status
|
||||
) {
|
||||
$parent_link = get_edit_post_link(
|
||||
$parent_post_id,
|
||||
'display'
|
||||
);
|
||||
$actions['ai1ec_parent'] = sprintf(
|
||||
'<a href="%s" title="%s">%s</a>',
|
||||
wp_nonce_url( $parent_link ),
|
||||
sprintf(
|
||||
__( 'Edit “%s”', AI1EC_PLUGIN_NAME ),
|
||||
apply_filters(
|
||||
'the_title',
|
||||
$parent_post->post_title,
|
||||
$parent_post->ID
|
||||
)
|
||||
),
|
||||
__( 'Base Event', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
}
|
||||
}
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* add_exception_date method
|
||||
*
|
||||
* Add exception (date) to event.
|
||||
*
|
||||
* @param int $post_id Event edited post ID
|
||||
* @param mixed $date Parseable date representation to exclude
|
||||
*
|
||||
* @return bool Success
|
||||
*/
|
||||
public function add_exception_date( $post_id, Ai1ec_Date_Time $date ) {
|
||||
$event = $this->_registry->get( 'model.event', $post_id );
|
||||
$dates_list = explode( ',', $event->get( 'exception_dates' ) );
|
||||
if ( empty( $dates_list[0] ) ) {
|
||||
unset( $dates_list[0] );
|
||||
}
|
||||
$date->set_time( 0, 0, 0 );
|
||||
$dates_list[] = $date->format(
|
||||
'Ymd\THis\Z'
|
||||
);
|
||||
$event->set( 'exception_dates', implode( ',', $dates_list ) );
|
||||
return $event->save( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles instances saving and switching if needed. If original event
|
||||
* and created event have different start dates proceed in old style
|
||||
* otherwise find next instance, switch original start date to next
|
||||
* instance start date. If there are no next instances mark event as
|
||||
* non recurring. Filter also exception dates if are past.
|
||||
*
|
||||
* @param Ai1ec_Event $created_event Created event object.
|
||||
* @param Ai1ec_Event $original_event Original event object.
|
||||
*
|
||||
* @return void Method does not return.
|
||||
*/
|
||||
protected function _handle_instances(
|
||||
Ai1ec_Event $created_event,
|
||||
Ai1ec_Event $original_event,
|
||||
$instance_id
|
||||
) {
|
||||
$ce_start = $created_event->get( 'start' );
|
||||
$oe_start = $original_event->get( 'start' );
|
||||
if (
|
||||
$ce_start->format() !== $oe_start->format()
|
||||
) {
|
||||
$this->add_exception_date(
|
||||
$original_event->get( 'post_id' ),
|
||||
$ce_start
|
||||
);
|
||||
return;
|
||||
}
|
||||
$next_instance = $this->_find_next_instance(
|
||||
$original_event->get( 'post_id' ),
|
||||
$instance_id
|
||||
);
|
||||
if ( ! $next_instance ) {
|
||||
$original_event->set( 'recurrence_rules', null );
|
||||
$original_event->save( true );
|
||||
return;
|
||||
}
|
||||
$original_event->set(
|
||||
'start',
|
||||
$this->_registry->get( 'date.time', $next_instance->get( 'start' ) )
|
||||
);
|
||||
$original_event->set(
|
||||
'end',
|
||||
$this->_registry->get( 'date.time', $next_instance->get( 'end' ) )
|
||||
);
|
||||
$edates = $this->_filter_exception_dates( $original_event );
|
||||
$original_event->set( 'exception_dates', implode( ',', $edates ) );
|
||||
$recurrence_rules = $original_event->get( 'recurrence_rules' );
|
||||
$rules_info = $this->_registry->get( 'recurrence.rule' )
|
||||
->build_recurrence_rules_array( $recurrence_rules );
|
||||
if ( isset( $rules_info['COUNT'] ) ) {
|
||||
$next_instances_count = $this->_count_next_instances(
|
||||
$original_event->get( 'post_id' ),
|
||||
$instance_id
|
||||
);
|
||||
$rules_info['COUNT'] = (int)$next_instances_count + count( $edates );
|
||||
$rules = '';
|
||||
if ( $rules_info['COUNT'] <= 1 ) {
|
||||
$rules_info = array();
|
||||
}
|
||||
foreach ( $rules_info as $key => $value ) {
|
||||
$rules .= $key . '=' . $value . ';';
|
||||
}
|
||||
$original_event->set(
|
||||
'recurrence_rules',
|
||||
$rules
|
||||
);
|
||||
}
|
||||
$original_event->save( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns next instance.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param int $instance_id Instance ID.
|
||||
*
|
||||
* @return null|Ai1ec_Event Result.
|
||||
*/
|
||||
protected function _find_next_instance( $post_id, $instance_id ) {
|
||||
$dbi = $this->_registry->get( 'dbi.dbi' );
|
||||
$table_instances = $dbi->get_table_name( 'ai1ec_event_instances' );
|
||||
$table_posts = $dbi->get_table_name( 'posts' );
|
||||
$query = $dbi->prepare(
|
||||
'SELECT i.id FROM ' . $table_instances . ' i JOIN ' .
|
||||
$table_posts . ' p ON (p.ID = i.post_id) ' .
|
||||
'WHERE i.post_id = %d AND i.id > %d ' .
|
||||
'AND p.post_status = \'publish\' ' .
|
||||
'ORDER BY id ASC LIMIT 1',
|
||||
$post_id,
|
||||
$instance_id
|
||||
);
|
||||
$next_instance_id = $dbi->get_var( $query );
|
||||
if ( ! $next_instance_id ) {
|
||||
return null;
|
||||
}
|
||||
return $this->_registry->get( 'model.search' )
|
||||
->get_event( $post_id, $next_instance_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts future instances.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param int $instance_id Instance ID.
|
||||
*
|
||||
* @return int Result.
|
||||
*/
|
||||
protected function _count_next_instances( $post_id, $instance_id ) {
|
||||
$dbi = $this->_registry->get( 'dbi.dbi' );
|
||||
$table_instances = $dbi->get_table_name( 'ai1ec_event_instances' );
|
||||
$table_posts = $dbi->get_table_name( 'posts' );
|
||||
$query = $dbi->prepare(
|
||||
'SELECT COUNT(i.id) FROM ' . $table_instances . ' i JOIN ' .
|
||||
$table_posts . ' p ON (p.ID = i.post_id) ' .
|
||||
'WHERE i.post_id = %d AND i.id > %d ' .
|
||||
'AND p.post_status = \'publish\'',
|
||||
$post_id,
|
||||
$instance_id
|
||||
);
|
||||
return (int)$dbi->get_var( $query );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters past or out of range exception dates.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event.
|
||||
*
|
||||
* @return array Filtered exception dates.
|
||||
*/
|
||||
protected function _filter_exception_dates( Ai1ec_Event $event ) {
|
||||
$start = (int)$event->get( 'start' )->format();
|
||||
$exception_dates = explode( ',', $event->get( 'exception_dates' ) );
|
||||
$dates = array();
|
||||
foreach ( $exception_dates as $date ) {
|
||||
$ex_date = (int)$this->_registry->get( 'date.time', $date )->format();
|
||||
if ( $ex_date > $start ) {
|
||||
$dates[] = $date;
|
||||
}
|
||||
}
|
||||
return $dates;
|
||||
}
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Modal class representing an event or an event instance.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @instantiator new
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
|
||||
class Ai1ec_Event_Taxonomy extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* @var string Name of categories taxonomy.
|
||||
*/
|
||||
const CATEGORIES = 'events_categories';
|
||||
|
||||
/**
|
||||
* @var string Name of tags taxonomy.
|
||||
*/
|
||||
const TAGS = 'events_tags';
|
||||
|
||||
/**
|
||||
* @var string Name of feeds taxonomy.
|
||||
*/
|
||||
const FEEDS = 'events_feeds';
|
||||
|
||||
/**
|
||||
* @var int ID of related post object
|
||||
*/
|
||||
protected $_post_id = 0;
|
||||
|
||||
/**
|
||||
* Store event ID in local variable.
|
||||
*
|
||||
* @param int $post_id ID of post being managed.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( Ai1ec_Registry_Object $registry, $post_id = 0 ) {
|
||||
parent::__construct( $registry );
|
||||
$this->_post_id = (int)$post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ID of term. Optionally create it if it doesn't exist.
|
||||
*
|
||||
* @param string $term Name of term to create.
|
||||
* @param string $taxonomy Name of taxonomy to contain term within.
|
||||
* @param bool $is_id Set to true if $term is ID.
|
||||
* @param array $attrs Attributes to creatable entity.
|
||||
*
|
||||
* @return array|bool Associative array with term_id
|
||||
* and taxonomy keys or false on error
|
||||
*/
|
||||
public function initiate_term(
|
||||
$term,
|
||||
$taxonomy,
|
||||
$is_id = false,
|
||||
array $attrs = array()
|
||||
) {
|
||||
// cast to int to have it working with term_exists
|
||||
$term = ( $is_id ) ? (int) $term : $term;
|
||||
$term_to_check = term_exists( $term, $taxonomy );
|
||||
$to_return = array(
|
||||
'taxonomy' => $taxonomy
|
||||
);
|
||||
// if term doesn't exist, create it.
|
||||
if ( 0 === $term_to_check || null === $term_to_check ) {
|
||||
$alias_to_use = apply_filters( 'ai1ec_ics_import_alias', $term );
|
||||
// the filter will either return null, the term_id to use or the original $term
|
||||
// if the filter is not run. Thus in need to check that $term !== $alias_to_use
|
||||
if ( $alias_to_use && $alias_to_use !== $term ) {
|
||||
$to_return['term_id'] = (int) $alias_to_use;
|
||||
// check that the term matches the taxonomy
|
||||
$tax = $this->get_taxonomy_for_term_id( term_exists( (int) $alias_to_use ) );
|
||||
$to_return['taxonomy'] = $tax->taxonomy;
|
||||
} else {
|
||||
$term_to_check = wp_insert_term( $term, $taxonomy, $attrs );
|
||||
if ( is_wp_error( $term_to_check ) ) {
|
||||
return false;
|
||||
}
|
||||
$term_to_check = (object)$term_to_check;
|
||||
$to_return['term_id'] = (int)$term_to_check->term_id;
|
||||
}
|
||||
} else {
|
||||
$term_id = is_array( $term_to_check )
|
||||
? $term_to_check['term_id']
|
||||
: $term_to_check;
|
||||
$to_return['term_id'] = (int)$term_id;
|
||||
// when importing categories, use the mapping of the current site
|
||||
// so place the term in the current taxonomy
|
||||
if ( self::CATEGORIES === $taxonomy ) {
|
||||
// check that the term matches the taxonomy
|
||||
$tax = $this->get_taxonomy_for_term_id( $term_id );
|
||||
$to_return['taxonomy'] = $tax->taxonomy;
|
||||
}
|
||||
|
||||
}
|
||||
return $to_return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for terms setting to post.
|
||||
*
|
||||
* @param array $terms List of terms to set.
|
||||
* @param string $taxonomy Name of taxonomy to set terms to.
|
||||
* @param bool $append When true post may have multiple same instances.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function set_terms( array $terms, $taxonomy, $append = false ) {
|
||||
$result = wp_set_post_terms(
|
||||
$this->_post_id,
|
||||
$terms,
|
||||
$taxonomy,
|
||||
$append
|
||||
);
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return false;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update event categories.
|
||||
*
|
||||
* @param array $categories List of category IDs.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function set_categories( array $categories ) {
|
||||
return $this->set_terms( $categories, self::CATEGORIES );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update event tags.
|
||||
*
|
||||
* @param array $tags List of tag IDs.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function set_tags( array $tags ) {
|
||||
return $this->set_terms( $tags, self::TAGS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update event feed description.
|
||||
*
|
||||
* @param object $feed Feed object.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function set_feed( $feed ) {
|
||||
$feed_name = $feed->feed_url;
|
||||
// If the feed is not from an imported file, parse the url.
|
||||
if ( ! isset( $feed->feed_imported_file ) ) {
|
||||
$url_components = parse_url( $feed->feed_url );
|
||||
$feed_name = $url_components['host'];
|
||||
}
|
||||
$term = $this->initiate_term(
|
||||
$feed_name,
|
||||
self::FEEDS,
|
||||
false,
|
||||
array(
|
||||
'description' => $feed->feed_url,
|
||||
)
|
||||
);
|
||||
if ( false === $term ) {
|
||||
return false;
|
||||
}
|
||||
$term_id = $term['term_id'];
|
||||
return $this->set_terms( array( $term_id ), self::FEEDS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the taxonomy name from term id
|
||||
*
|
||||
* @param int $term
|
||||
*
|
||||
* @return stdClass The taxonomy nane
|
||||
*/
|
||||
public function get_taxonomy_for_term_id( $term_id ) {
|
||||
$db = $this->_registry->get( 'dbi.dbi' );
|
||||
return $db->get_row(
|
||||
$db->prepare(
|
||||
'SELECT terms_taxonomy.taxonomy FROM ' . $db->get_table_name( 'terms' ) .
|
||||
' AS terms INNER JOIN ' .
|
||||
$db->get_table_name( 'term_taxonomy' ) .
|
||||
' AS terms_taxonomy USING(term_id) '.
|
||||
'WHERE terms.term_id = %d LIMIT 1', $term_id )
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Handles trash/delete operations.
|
||||
*
|
||||
* NOTICE: only operations on events entries themselve is handled.
|
||||
* If plugins need some extra handling - they must bind to appropriate
|
||||
* actions on their will.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Model
|
||||
*/
|
||||
class Ai1ec_Event_Trashing extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Trash/untrash/deletes child posts
|
||||
*
|
||||
* @param id $post_id
|
||||
* @param string $action
|
||||
*/
|
||||
protected function _manage_children( $post_id, $action ) {
|
||||
try {
|
||||
$ai1ec_event = $this->_registry->get( 'model.event', $post_id );
|
||||
if (
|
||||
$ai1ec_event->get( 'post' ) &&
|
||||
$ai1ec_event->get( 'recurrence_rules' )
|
||||
) {
|
||||
// when untrashing also get trashed object
|
||||
$children = $this->_registry->get( 'model.event.parent' )
|
||||
->get_child_event_objects( $ai1ec_event->get( 'post_id' ), $action === 'untrash' );
|
||||
$function = 'wp_' . $action . '_post';
|
||||
foreach ( $children as $child ) {
|
||||
$function( $child->get( 'post_id' ) );
|
||||
}
|
||||
}
|
||||
} catch ( Ai1ec_Event_Not_Found_Exception $exception ) {
|
||||
// ignore - not an event
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trashes child posts
|
||||
*
|
||||
* @param int $post_id
|
||||
*/
|
||||
public function trash_children( $post_id ) {
|
||||
$this->_manage_children( $post_id, 'trash' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete child posts
|
||||
*
|
||||
* @param int $post_id
|
||||
*/
|
||||
public function delete_children( $post_id ) {
|
||||
$this->_manage_children( $post_id, 'delete' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Untrashes child posts
|
||||
*
|
||||
* @param int $post_id
|
||||
*/
|
||||
public function untrash_children( $post_id ) {
|
||||
$this->_manage_children( $post_id, 'untrash' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle PRE (event) trashing.
|
||||
*
|
||||
* @wp_hook trash_post
|
||||
*
|
||||
* @param int $post_id ID of post, which was trashed.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function trash_post( $post_id ) {
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
$post = get_post( $post_id );
|
||||
$restored_status = get_post_meta( $post_id, '_wp_trash_meta_status', true );
|
||||
$fields = array(
|
||||
'status' => 'trash'
|
||||
);
|
||||
$ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
|
||||
$message = $api->update_api_event_fields( $post, $fields, 'trash', $ajax );
|
||||
if ( null !== $message ) {
|
||||
if ( $ajax ) {
|
||||
wp_die( $message );
|
||||
} else {
|
||||
wp_redirect( $this->get_sendback_page( $post_id ) );
|
||||
exit();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle POST (event) trashing.
|
||||
*
|
||||
* @wp_hook trashed_post
|
||||
*
|
||||
* @param int $post_id ID of post, which was trashed.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function trashed_post( $post_id ) {
|
||||
return $this->trash_children( $post_id );
|
||||
}
|
||||
|
||||
private function get_sendback_page( $post_id ) {
|
||||
$sendback = wp_get_referer();
|
||||
$page_base = Ai1ec_Wp_Uri_Helper::get_pagebase( $sendback ); //$_SERVER['REQUEST_URI'] );
|
||||
if ( 'post.php' === $page_base ) {
|
||||
return get_edit_post_link( $post_id, 'url' );
|
||||
} else {
|
||||
return admin_url( 'edit.php?post_type=ai1ec_event' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle PRE (event) untrashing.
|
||||
*
|
||||
* @wp_hook untrash_post
|
||||
*
|
||||
* @param int $post_id ID of post, which was untrashed.
|
||||
*
|
||||
* @return bool Success. Interrupt the action with exit is
|
||||
* the integration with API fails
|
||||
*/
|
||||
public function untrash_post ( $post_id ) {
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
$post = get_post( $post_id );
|
||||
$restored_status = get_post_meta( $post_id, '_wp_trash_meta_status', true );
|
||||
$fields = array(
|
||||
'status' => $restored_status
|
||||
);
|
||||
$ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
|
||||
$message = $api->update_api_event_fields( $post, $fields, 'untrash', $ajax );
|
||||
if ( null !== $message ) {
|
||||
if ( $ajax ) {
|
||||
wp_die( $message );
|
||||
} else {
|
||||
wp_redirect( $this->get_sendback_page( $post_id ) );
|
||||
exit();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle POST (event) untrashing.
|
||||
*
|
||||
* @wp_hook untrashed_post
|
||||
*
|
||||
* @param int $post_id ID of post, which was untrashed.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function untrashed_post( $post_id ) {
|
||||
return $this->untrash_children( $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle PRE (event) deletion.
|
||||
*
|
||||
* Executed before post is deleted, but after meta is removed.
|
||||
*
|
||||
* @wp_hook delete_post
|
||||
*
|
||||
* @param int $post_id ID of post, which was trashed.
|
||||
*
|
||||
* @return bool Success. Interrupt the action with exit is
|
||||
* the integration with API fails
|
||||
*/
|
||||
public function before_delete_post( $post_id ) {
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
$ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
|
||||
$message = $api->delete_api_event( $post_id, 'delete', $ajax );
|
||||
if ( null !== $message ) {
|
||||
if ( $ajax ) {
|
||||
wp_die( $message );
|
||||
} else {
|
||||
wp_redirect( $this->get_sendback_page( $post_id ) );
|
||||
exit();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle POST (event) deletion.
|
||||
*
|
||||
* Executed before post is deleted, but after meta is removed.
|
||||
*
|
||||
* @wp_hook delete_post
|
||||
*
|
||||
* @param int $post_id ID of post, which was trashed.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function delete( $post_id ) {
|
||||
$post_id = (int)$post_id;
|
||||
$where = array( 'post_id' => (int)$post_id );
|
||||
$format = array( '%d' );
|
||||
$dbi = $this->_registry->get( 'dbi.dbi' );
|
||||
$success = $this->delete_children( $post_id );
|
||||
$success = $dbi->delete( 'ai1ec_events', $where, $format );
|
||||
$success = $this->_registry->get( 'model.event.instance' )->clean( $post_id );
|
||||
unset( $where, $dbi );
|
||||
return $success;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Authors filtering implementation.
|
||||
*
|
||||
* @instantiator new
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Filter
|
||||
*/
|
||||
class Ai1ec_Filter_Authors extends Ai1ec_Filter_Int {
|
||||
|
||||
public function get_field() {
|
||||
return 'p.post_author';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Categories filtering implementation.
|
||||
*
|
||||
* @instantiator new
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Filter
|
||||
*/
|
||||
class Ai1ec_Filter_Categories extends Ai1ec_Filter_Taxonomy {
|
||||
|
||||
public function get_taxonomy() {
|
||||
return 'events_categories';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Posts (events) filtering implementation.
|
||||
*
|
||||
* @instantiator new
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Filter
|
||||
*/
|
||||
class Ai1ec_Filter_Posts_By_Instance extends Ai1ec_Filter_Int {
|
||||
|
||||
public function get_field() {
|
||||
return 'i.id';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Base class for integers-based filters.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Filter
|
||||
*/
|
||||
abstract class Ai1ec_Filter_Int implements Ai1ec_Filter_Interface {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Registry_Object Injected object registry.
|
||||
*/
|
||||
protected $_registry = null;
|
||||
|
||||
/**
|
||||
* @var array Sanitized input values with only positive integers kept.
|
||||
*/
|
||||
protected $_values = array();
|
||||
|
||||
/**
|
||||
* Sanitize input values upon construction.
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry Injected registry.
|
||||
* @param array $filter_values Values to sanitize.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
Ai1ec_Registry_Object $registry,
|
||||
array $filter_values = array()
|
||||
) {
|
||||
$this->_registry = $registry;
|
||||
$this->_values = array_filter(
|
||||
array_map(
|
||||
array( $this->_registry->get( 'primitive.int' ), 'positive' ),
|
||||
$filter_values
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* These simple filters does not require new joins.
|
||||
*
|
||||
* @return string Empty string is returned.
|
||||
*/
|
||||
public function get_join() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get condition part of query for single field.
|
||||
*
|
||||
* @param string $inner_operator Inner logics to use. It is ignored.
|
||||
*
|
||||
* @return string Conditional snippet for query.
|
||||
*/
|
||||
public function get_where( $inner_operator = null ) {
|
||||
if ( empty( $this->_values ) ) {
|
||||
return '';
|
||||
}
|
||||
return $this->get_field() . ' IN ( ' . join( ',', $this->_values ) . ' )';
|
||||
}
|
||||
|
||||
/**
|
||||
* Require ancestors to override this to build correct conditional snippet.
|
||||
*
|
||||
* @return string Column alias to use in condition.
|
||||
*/
|
||||
abstract public function get_field();
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Filter provider interface.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Filter
|
||||
*/
|
||||
interface Ai1ec_Filter_Interface {
|
||||
|
||||
/**
|
||||
* Store user-input locally.
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry Injected registry.
|
||||
* @param array $filter_values User provided input.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
Ai1ec_Registry_Object $registry,
|
||||
array $filter_values = array()
|
||||
);
|
||||
|
||||
/**
|
||||
* Return SQL snippet for `FROM` part.
|
||||
*
|
||||
* @return string Valid SQL snippet for `FROM` part.
|
||||
*/
|
||||
public function get_join();
|
||||
|
||||
/**
|
||||
* Return SQL snippet for `WHERE` part.
|
||||
*
|
||||
* Snippet should not be put in brackets - this will be performed
|
||||
* in upper level.
|
||||
*
|
||||
* @return string Valid SQL snippet.
|
||||
*/
|
||||
public function get_where();
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Posts (events) filtering implementation.
|
||||
*
|
||||
* @instantiator new
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Filter
|
||||
*/
|
||||
class Ai1ec_Filter_Posts extends Ai1ec_Filter_Int {
|
||||
|
||||
public function get_field() {
|
||||
return 'e.post_id';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Tags filtering implementation.
|
||||
*
|
||||
* @instantiator new
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Filter
|
||||
*/
|
||||
class Ai1ec_Filter_Tags extends Ai1ec_Filter_Taxonomy {
|
||||
|
||||
public function get_taxonomy() {
|
||||
return 'events_tags';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Base class for taxonomies filtering.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Filter
|
||||
*/
|
||||
abstract class Ai1ec_Filter_Taxonomy extends Ai1ec_Filter_Int {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Dbi Instance of database interface.
|
||||
*/
|
||||
protected $_dbi = null;
|
||||
|
||||
/**
|
||||
* Sanitize input values upon construction.
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry Injected registry.
|
||||
* @param array $filter_values Values to sanitize.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
Ai1ec_Registry_Object $registry,
|
||||
array $filter_values = array()
|
||||
) {
|
||||
parent::__construct( $registry, $filter_values );
|
||||
$this->_dbi = $this->_registry->get( 'dbi.dbi' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Build SQL snippet for `FROM` particle.
|
||||
*
|
||||
* @return string Valid SQL snippet.
|
||||
*/
|
||||
public function get_join() {
|
||||
if ( empty( $this->_values ) ) {
|
||||
return '';
|
||||
}
|
||||
$sql_query =
|
||||
'LEFT JOIN `{{RELATIONSHIPS_TABLE}}` AS `{{RELATIONSHIP_ALIAS}}` ' .
|
||||
'ON ( `e` . `post_id` = `{{RELATIONSHIP_ALIAS}}` . `object_id` ) ' .
|
||||
'LEFT JOIN `{{TAXONOMY_TABLE}}` AS `{{TAXONOMY_ALIAS}}` ' .
|
||||
'ON (' .
|
||||
'`{{RELATIONSHIP_ALIAS}}` . `term_taxonomy_id` = ' .
|
||||
'`{{TAXONOMY_ALIAS}}` . `term_taxonomy_id` ' .
|
||||
'AND `{{TAXONOMY_ALIAS}}` . taxonomy = {{TAXONOMY}} ' .
|
||||
')';
|
||||
return str_replace(
|
||||
array(
|
||||
'{{RELATIONSHIPS_TABLE}}',
|
||||
'{{RELATIONSHIP_ALIAS}}',
|
||||
'{{TAXONOMY_TABLE}}',
|
||||
'{{TAXONOMY_ALIAS}}',
|
||||
'{{TAXONOMY}}',
|
||||
),
|
||||
array(
|
||||
$this->_dbi->get_table_name( 'term_relationships' ),
|
||||
$this->_table_alias( 'term_relationships' ),
|
||||
$this->_dbi->get_table_name( 'term_taxonomy' ),
|
||||
$this->_table_alias( 'term_taxonomy' ),
|
||||
'\'' . addslashes( $this->get_taxonomy() ) . '\'',
|
||||
),
|
||||
$sql_query
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Required by parent class. Using internal abstractions.
|
||||
*
|
||||
* @return string Field name to use in `WHERE` particle.
|
||||
*/
|
||||
public function get_field() {
|
||||
return $this->_table_alias( 'term_taxonomy' ) . '.term_id';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the qualified name for the taxonomy.
|
||||
*
|
||||
* @return string Valid taxonomy name (see `term_taxonomy` table).
|
||||
*/
|
||||
abstract public function get_taxonomy();
|
||||
|
||||
/**
|
||||
* Generate table alias given taxonomy.
|
||||
*
|
||||
* @param string $table Table to generate alias for.
|
||||
*
|
||||
* @return string Table alias.
|
||||
*/
|
||||
protected function _table_alias( $table ) {
|
||||
return $table . '_' . $this->get_taxonomy();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Post meta entries management.
|
||||
*
|
||||
* Meta entries management based on {@see Ai1ec_Meta} class.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Meta_Post extends Ai1ec_Meta {
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* User meta entries management.
|
||||
*
|
||||
* Meta entries management based on {@see Ai1ec_Meta} class.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Meta_User extends Ai1ec_Meta {
|
||||
|
||||
/**
|
||||
* Get meta value for current user.
|
||||
*
|
||||
* @param string $meta_key Name of meta entry to get for current user.
|
||||
* @param mixed $default Value to return if no entry found.
|
||||
*
|
||||
* @return mixed Current user's option or $default if none found.
|
||||
*/
|
||||
public function get_current( $meta_key, $default = null ) {
|
||||
$user_id = 0;
|
||||
if ( is_callable( 'wp_get_current_user' ) ) {
|
||||
$user = wp_get_current_user();
|
||||
$user_id = (int)$user->ID;
|
||||
unset( $user );
|
||||
}
|
||||
if ( $user_id <= 0 ) {
|
||||
return $default;
|
||||
}
|
||||
return $this->get( $user_id, $meta_key, $default );
|
||||
}
|
||||
|
||||
/**
|
||||
* user_selected_tz method
|
||||
*
|
||||
* Get/set user selected (preferred) timezone.
|
||||
* If only {@see $user_id} is provided - method acts as getter.
|
||||
* Otherwise it acts as setter.
|
||||
*
|
||||
* @param int $user_id ID of user whose timezone is being checked/changed
|
||||
* @param string $new_value New timezone string value to set user preferrence
|
||||
* @param bool $force_update Set to true to force value update instead of add
|
||||
*
|
||||
* @return mixed Return value depends on activity:
|
||||
* - [getter] string User preferred timezone name (might be empty string)
|
||||
* - [setter] bool Success of preferrence change
|
||||
*/
|
||||
public function user_selected_tz(
|
||||
$user_id,
|
||||
$new_value = NULL,
|
||||
$force_update = false
|
||||
) {
|
||||
$meta_key = 'ai1ec_timezone';
|
||||
$user_id = (int)$user_id;
|
||||
$old_value = $this->get(
|
||||
$user_id,
|
||||
$meta_key,
|
||||
NULL,
|
||||
true
|
||||
);
|
||||
if ( NULL !== $new_value ) {
|
||||
if ( ! in_array( $new_value, timezone_identifiers_list() ) ) {
|
||||
return false;
|
||||
}
|
||||
$success = false;
|
||||
if ( true === $force_update || ! empty( $old_value ) ) {
|
||||
$success = update_user_meta(
|
||||
$user_id,
|
||||
$meta_key,
|
||||
$new_value,
|
||||
$old_value
|
||||
);
|
||||
} else {
|
||||
$success = add_user_meta(
|
||||
$user_id,
|
||||
$meta_key,
|
||||
$new_value,
|
||||
true
|
||||
);
|
||||
if ( false === $success ) {
|
||||
return $this->user_selected_tz(
|
||||
$user_id,
|
||||
$new_value,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
return $old_value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Abstract class for meta entries management.
|
||||
*
|
||||
* Via use of cache allows object-based access to meta entries.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
abstract class Ai1ec_Meta extends Ai1ec_App {
|
||||
|
||||
/**
|
||||
* @var string Name of base object for storage.
|
||||
*/
|
||||
protected $_object = '';
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Cache_Memory In-memory cache operator.
|
||||
*/
|
||||
protected $_cache = null;
|
||||
|
||||
/**
|
||||
* Initialize instance-specific in-memory cache storage.
|
||||
*
|
||||
* @return void Method does not return.
|
||||
*/
|
||||
protected function _initialize() {
|
||||
$class = get_class( $this );
|
||||
$this->_object = strtolower(
|
||||
substr( $class, strlen( __CLASS__ ) + 1 )
|
||||
);
|
||||
$this->_cache = $this->_registry->get( 'cache.memory' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new entry if it does not exist and cache provided value.
|
||||
*
|
||||
* @param string $object_id ID of object to store.
|
||||
* @param string $key Key particle for ID to store.
|
||||
* @param mixed $value Serializable value to store.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
final public function add( $object_id, $key, $value ) {
|
||||
if ( ! $this->_add( $object_id, $key, $value ) ) {
|
||||
return false;
|
||||
}
|
||||
$this->_cache->set( $this->_cache_key( $object_id, $key ), $value );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update existing entry and cache it's value.
|
||||
*
|
||||
* @param string $object_id ID of object to store.
|
||||
* @param string $key Key particle for ID to store.
|
||||
* @param mixed $value Serializable value to store.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
final public function update( $object_id, $key, $value ) {
|
||||
if ( ! $this->_update( $object_id, $key, $value ) ) {
|
||||
return false;
|
||||
}
|
||||
$this->_cache->set( $this->_cache_key( $object_id, $key ), $value );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object value - from cache or actual store.
|
||||
*
|
||||
* @param string $object_id ID of object to get.
|
||||
* @param string $key Key particle for ID to get.
|
||||
* @param mixed $default Value to return if nothing found.
|
||||
*
|
||||
* @return mixed Value stored or {$default}.
|
||||
*/
|
||||
final public function get( $object_id, $key, $default = null ) {
|
||||
$cache_key = $this->_cache_key( $object_id, $key );
|
||||
$value = $this->_cache->get( $cache_key, $default );
|
||||
if ( $default === $value ) {
|
||||
$value = $this->_get( $object_id, $key );
|
||||
$this->_cache->set( $cache_key, $value );
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or update an entry cache new value.
|
||||
*
|
||||
* @param string $object_id ID of object to store.
|
||||
* @param string $key Key particle for ID to store.
|
||||
* @param mixed $value Serializable value to store.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
final public function set( $object_id, $key, $value ) {
|
||||
if ( ! $this->get( $object_id, $key ) ) {
|
||||
if ( ! $this->_add( $object_id, $key, $value ) ) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ( ! $this->_update( $object_id, $key, $value ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$this->_cache->set( $this->_cache_key( $object_id, $key ), $value );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove object entry based on ID and key.
|
||||
*
|
||||
* @param string $object_id ID of object to remove.
|
||||
* @param string $key Key particle for ID to remove.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
final public function delete( $object_id, $key ) {
|
||||
$this->_cache->delete( $this->_cache_key( $object_id, $key ) );
|
||||
return $this->_delete( $object_id, $key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object value from actual store.
|
||||
*
|
||||
* @param string $object_id ID of object to get.
|
||||
* @param string $key Key particle for ID to get.
|
||||
*
|
||||
* @return mixed Value as found.
|
||||
*/
|
||||
protected function _get( $object_id, $key ) {
|
||||
$function = 'get_' . $this->_object . '_meta';
|
||||
return $function( $object_id, $key, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new entry if it does not exist.
|
||||
*
|
||||
* @param string $object_id ID of object to store.
|
||||
* @param string $key Key particle for ID to store.
|
||||
* @param mixed $value Serializable value to store.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
protected function _add( $object_id, $key, $value ) {
|
||||
$function = 'add_' . $this->_object . '_meta';
|
||||
return $function( $object_id, $key, $value, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update existing entry.
|
||||
*
|
||||
* @param string $object_id ID of object to store.
|
||||
* @param string $key Key particle for ID to store.
|
||||
* @param mixed $value Serializable value to store.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
protected function _update( $object_id, $key, $value ) {
|
||||
$function = 'update_' . $this->_object . '_meta';
|
||||
return $function( $object_id, $key, $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove object entry based on ID and key.
|
||||
*
|
||||
* @param string $object_id ID of object to remove.
|
||||
* @param string $key Key particle for ID to remove.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
protected function _delete( $object_id, $key ) {
|
||||
$function = 'delete_' . $this->_object . '_meta';
|
||||
return $function( $object_id, $key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate key for use with cache engine.
|
||||
*
|
||||
* @param string $object_id ID of object.
|
||||
* @param string $key Key particle for ID.
|
||||
*
|
||||
* @return string Single identifier for given keys.
|
||||
*/
|
||||
protected function _cache_key( $object_id, $key ) {
|
||||
static $separator = "\0";
|
||||
return $object_id . $separator . $key;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Options management class.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Option extends Ai1ec_App {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Cache_Memory In-memory cache storage engine for fast access.
|
||||
*/
|
||||
protected $_cache = null;
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Registry_Object instance of the registry object.
|
||||
*/
|
||||
protected $_registry;
|
||||
|
||||
/**
|
||||
* Add cache instance to object scope.
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry Registry object.
|
||||
*
|
||||
* @return Ai1ec_Option
|
||||
*/
|
||||
public function __construct( Ai1ec_Registry_Object $registry ) {
|
||||
$this->_registry = $registry;
|
||||
$this->_cache = $registry->get( 'cache.memory' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an option if it does not exist.
|
||||
*
|
||||
* @param string $name Key to put value under.
|
||||
* @param mixed $value Value to put to storage.
|
||||
* @param bool $autoload Set to true to load on start.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function add( $name, $value, $autoload = false ) {
|
||||
$autoload = $this->_parse_autoload( $autoload );
|
||||
if ( ! add_option( $name, $value, '', $autoload ) ) {
|
||||
return false;
|
||||
}
|
||||
$this->_cache->set( $name, $value );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an option if it does not exist, or update existing.
|
||||
*
|
||||
* @param string $name Key to put value under.
|
||||
* @param mixed $value Value to put to storage.
|
||||
* @param bool $autoload Set to true to load on start.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function set( $name, $value, $autoload = false ) {
|
||||
$comparator = "\0t\0";
|
||||
if ( $this->get( $name, $comparator ) === $comparator ) {
|
||||
return $this->add( $name, $value, $autoload );
|
||||
}
|
||||
if ( ! update_option( $name, $value ) ) {
|
||||
return false;
|
||||
}
|
||||
$this->_cache->set( $name, $value );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from storage.
|
||||
*
|
||||
* @param string $name Key to retrieve.
|
||||
* @param mixed $default Value to return if key was not set previously.
|
||||
*
|
||||
* @return mixed Value from storage or {$default}.
|
||||
*/
|
||||
public function get( $name, $default = null ) {
|
||||
$value = $this->_cache->get( $name, $default );
|
||||
if ( $default === $value ) {
|
||||
$value = get_option( $name, $default );
|
||||
$this->_cache->set( $name, $value );
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete value from storage.
|
||||
*
|
||||
* @param string $name Key to delete.
|
||||
*
|
||||
* @wp_hook deleted_option Fire after deletion.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
public function delete( $name ) {
|
||||
$this->_cache->delete( $name );
|
||||
if ( 'deleted_option' === current_filter() ) {
|
||||
return true; // avoid loops
|
||||
}
|
||||
return delete_option( $name );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert autoload flag input to value recognized by WordPress.
|
||||
*
|
||||
* @param bool $input Autoload flag value.
|
||||
*
|
||||
* @return string Autoload identifier.
|
||||
*/
|
||||
protected function _parse_autoload( $input ) {
|
||||
return $input ? 'yes' : 'no';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class to manage the review made by the user.
|
||||
* The data are saved inside the wp_option table
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
*
|
||||
* @package AI1ECCFG
|
||||
*/
|
||||
class Ai1ec_Review extends Ai1ec_Base {
|
||||
|
||||
const EMAIL_FEEDBACK_DESTINATION = 'info@time.ly';
|
||||
const OPTION_KEY = '_ai1ec_review';
|
||||
const FEEDBACK_FIELD = 'feedback';
|
||||
const RELEASE_DATE_FIELD = 'release_date';
|
||||
const PUBLISHED_THRESHOLD = 15;
|
||||
const FUTURE_EVENTS_THRESHOLD = 3;
|
||||
const WEEK_OFFSET_SEC_FIELD = 604800; //1 week in seconds (7 * 86400)
|
||||
|
||||
/**
|
||||
* review colletion.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_review_items = array();
|
||||
|
||||
/**
|
||||
* Option class.
|
||||
*
|
||||
* @var Ai1ec_Option
|
||||
*/
|
||||
protected $_option;
|
||||
|
||||
public function __construct( Ai1ec_Registry_Object $registry ) {
|
||||
parent::__construct( $registry );
|
||||
$this->_option = $registry->get( 'model.option' );
|
||||
$this->_review_items = $this->_get_array( self::OPTION_KEY );
|
||||
}
|
||||
|
||||
private function _get_array( $option_key ) {
|
||||
$items = $this->_option->get( $option_key );
|
||||
if ( ! is_array( $items ) ) {
|
||||
$items = array();
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
private function _get_field( $field_name, $default_value ) {
|
||||
if ( isset( $this->_review_items[$field_name] ) ) {
|
||||
$value = $this->_review_items[$field_name];
|
||||
if ( ai1ec_is_blank( $value ) ) {
|
||||
return $default_value;
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
} else {
|
||||
return $default_value;
|
||||
}
|
||||
}
|
||||
|
||||
protected function _save( array $values ) {
|
||||
foreach ($values as $key => $value) {
|
||||
$this->_review_items[$key] = $value;
|
||||
}
|
||||
$this->_option->set( self::OPTION_KEY, $this->_review_items );
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function _is_show_box_review() {
|
||||
//only show for admins
|
||||
if ( false === is_admin() ) {
|
||||
return false;
|
||||
}
|
||||
$user_id = get_current_user_id();
|
||||
if ( empty( $user_id ) ) {
|
||||
return false;
|
||||
}
|
||||
//if the user already gave his feedback does not ask him again
|
||||
if ( $this->_has_feedback( $user_id ) ) {
|
||||
return false;
|
||||
}
|
||||
$release_date_str = $this->_get_field( self::RELEASE_DATE_FIELD, '' );
|
||||
if ( ai1ec_is_blank( $release_date_str ) ) {
|
||||
//the first time this page is loaded is save the moment as the release date
|
||||
//to just ask the user a review after 2 weeks
|
||||
$this->_save( array(
|
||||
self::RELEASE_DATE_FIELD => $this->_registry->get( 'date.time' )->format()
|
||||
) );
|
||||
return false;
|
||||
} else {
|
||||
$current_time = $this->_registry->get( 'date.time' );
|
||||
$release_date = $this->_registry->get( 'date.time', $release_date_str );
|
||||
$diff_sec = $release_date->diff_sec( $current_time );
|
||||
//verify is passed 2 weeks after we release this feature
|
||||
if ( $diff_sec < self::WEEK_OFFSET_SEC_FIELD ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//count the published events
|
||||
$event_count = count_user_posts( $user_id, AI1EC_POST_TYPE, true );
|
||||
if ( $event_count < self::PUBLISHED_THRESHOLD ) {
|
||||
return false;
|
||||
}
|
||||
//count the future events
|
||||
$count_future_events = apply_filters( 'ai1ec_count_future_events', $user_id );
|
||||
if ( $count_future_events < self::FUTURE_EVENTS_THRESHOLD ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_content( $theme_loader ) {
|
||||
if ( $this->_is_show_box_review() ) {
|
||||
$current_user = wp_get_current_user();
|
||||
$review_args = array();
|
||||
if ( $current_user instanceof WP_User ) {
|
||||
$review_args['contact_name'] = $current_user->display_name;
|
||||
$review_args['contact_email'] = $current_user->user_email;
|
||||
} else {
|
||||
$review_args['contact_name'] = '';
|
||||
$review_args['contact_email'] = '';
|
||||
}
|
||||
$review_args['site_url'] = get_option( 'siteurl' );
|
||||
$theme_loader = $this->_registry->get( 'theme.loader' );
|
||||
return $theme_loader->get_file( 'box_ask_customer_review.php', $review_args, true )->get_content();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function save_feedback_review() {
|
||||
$user_id = get_current_user_id();
|
||||
if ( empty( $user_id ) ) {
|
||||
throw new Exception( 'User not identified' );
|
||||
}
|
||||
if ( ai1ec_is_blank( $_POST['feedback'] ) ||
|
||||
!in_array( $_POST['feedback'], array( 'y', 'n' ) ) ) {
|
||||
throw new Exception( 'The field is not filled or invalid' );
|
||||
}
|
||||
$values = $this->_get_field( self::FEEDBACK_FIELD, null );
|
||||
if ( null === $values ) {
|
||||
$values = array();
|
||||
}
|
||||
$values[ $user_id ] = $_POST['feedback'];
|
||||
$this->_save( array(
|
||||
self::FEEDBACK_FIELD => $values
|
||||
) );
|
||||
}
|
||||
|
||||
protected function _has_feedback( $user_id ) {
|
||||
$values = $this->_get_field( self::FEEDBACK_FIELD, null );
|
||||
if ( null === $values ) {
|
||||
return false;
|
||||
}
|
||||
$user = (string) $user_id;
|
||||
$value = isset( $values[$user] ) ? $values[$user] : '';
|
||||
return 0 === strcasecmp( 'y', $value ) || 0 === strcasecmp( 'n', $value );
|
||||
}
|
||||
|
||||
public function send_feedback_message() {
|
||||
if ( ai1ec_is_blank( $_POST['name'] ) ||
|
||||
ai1ec_is_blank( $_POST['email'] ) ||
|
||||
ai1ec_is_blank( $_POST['site'] ) ||
|
||||
ai1ec_is_blank( $_POST['message'] )
|
||||
) {
|
||||
throw new Exception( 'All fields are required' );
|
||||
}
|
||||
$subject = __( 'Feedback provided by user', AI1EC_PLUGIN_NAME );
|
||||
$content = sprintf( '<b>%s:</b><br/>%s<br/><br/><b>%s:</b><br/>%s<br/><br/><b>%s:</b><br/>%s<br/><br/><b>%s:</b><br/>%s',
|
||||
__( 'Name', AI1EC_PLUGIN_NAME ),
|
||||
$_POST['name'],
|
||||
__( 'E-mail', AI1EC_PLUGIN_NAME ),
|
||||
$_POST['email'],
|
||||
__( 'Site URL', AI1EC_PLUGIN_NAME ),
|
||||
$_POST['site'],
|
||||
__( 'Message', AI1EC_PLUGIN_NAME ),
|
||||
nl2br( $_POST['message'] )
|
||||
);
|
||||
$dispatcher = $this->_registry->get(
|
||||
'notification.email',
|
||||
$content,
|
||||
explode( ',', self::EMAIL_FEEDBACK_DESTINATION ),
|
||||
$subject
|
||||
);
|
||||
$headers = array(
|
||||
'Content-type: text/html',
|
||||
sprintf( 'From: %s <%s>', $_POST['name'], $_POST['email'])
|
||||
);
|
||||
if ( $dispatcher->send( $headers ) ) {
|
||||
$_POST['feedback'] = 'n';
|
||||
$this->save_feedback_review();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,879 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Search Event.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.search
|
||||
*/
|
||||
class Ai1ec_Event_Search extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Dbi instance
|
||||
*/
|
||||
private $_dbi = null;
|
||||
|
||||
/**
|
||||
* Caches the ids of the last 'between' query
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_ids_between_cache = array();
|
||||
|
||||
/**
|
||||
* Creates local DBI instance.
|
||||
*/
|
||||
public function __construct( Ai1ec_Registry_Object $registry ){
|
||||
parent::__construct( $registry );
|
||||
$this->_dbi = $this->_registry->get( 'dbi.dbi' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_cached_between_ids() {
|
||||
return $this->_ids_between_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the event object with the given post ID.
|
||||
*
|
||||
* Uses the WP cache to make this more efficient if possible.
|
||||
*
|
||||
* @param int $post_id The ID of the post associated.
|
||||
* @param bool|int $instance_id Instance ID, to fetch post details for.
|
||||
*
|
||||
* @return Ai1ec_Event The associated event object.
|
||||
*/
|
||||
public function get_event( $post_id, $instance_id = false ) {
|
||||
$post_id = (int)$post_id;
|
||||
$instance_id = (int)$instance_id;
|
||||
if ( $instance_id < 1 ) {
|
||||
$instance_id = false;
|
||||
}
|
||||
return $this->_registry->get( 'model.event', $post_id, $instance_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return events falling within some time range.
|
||||
*
|
||||
* Return all events starting after the given start time and before the
|
||||
* given end time that the currently logged in user has permission to view.
|
||||
* If $spanning is true, then also include events that span this
|
||||
* period. All-day events are returned first.
|
||||
*
|
||||
* @param Ai1ec_Date_Time $start Limit to events starting after this.
|
||||
* @param Ai1ec_Date_Time $end Limit to events starting before this.
|
||||
* @param array $filter Array of filters for the events returned:
|
||||
* ['cat_ids'] => list of category IDs;
|
||||
* ['tag_ids'] => list of tag IDs;
|
||||
* ['post_ids'] => list of post IDs;
|
||||
* ['auth_ids'] => list of author IDs;
|
||||
* ['instance_ids'] => list of events
|
||||
* instance ids;
|
||||
* @param bool $spanning Also include events that span this period.
|
||||
* @param bool $single_day This parameter is added for oneday view.
|
||||
* Query should find events lasting in
|
||||
* particular day instead of checking dates
|
||||
* range. If you need to call this method
|
||||
* with $single_day set to true consider
|
||||
* using method get_events_for_day. This
|
||||
* parameter matters only if $spanning is set
|
||||
* to false.
|
||||
*
|
||||
* @return array List of matching event objects.
|
||||
*/
|
||||
public function get_events_between(
|
||||
Ai1ec_Date_Time $start,
|
||||
Ai1ec_Date_Time $end,
|
||||
array $filter = array(),
|
||||
$spanning = false,
|
||||
$single_day = false
|
||||
) {
|
||||
// Query arguments
|
||||
$args = array(
|
||||
$start->format_to_gmt(),
|
||||
$end->format_to_gmt(),
|
||||
);
|
||||
|
||||
// Get post status Where snippet and associated SQL arguments
|
||||
$where_parameters = $this->_get_post_status_sql();
|
||||
$post_status_where = $where_parameters['post_status_where'];
|
||||
$args = array_merge( $args, $where_parameters['args'] );
|
||||
|
||||
// Get the Join (filter_join) and Where (filter_where) statements based
|
||||
// on $filter elements specified
|
||||
$filter = $this->_get_filter_sql( $filter );
|
||||
|
||||
$ai1ec_localization_helper = $this->_registry->get( 'p28n.wpml' );
|
||||
|
||||
$wpml_join_particle = $ai1ec_localization_helper
|
||||
->get_wpml_table_join( 'p.ID' );
|
||||
|
||||
$wpml_where_particle = $ai1ec_localization_helper
|
||||
->get_wpml_table_where();
|
||||
|
||||
if ( $spanning ) {
|
||||
$spanning_string = 'i.end > %d AND i.start < %d ';
|
||||
} elseif ( $single_day ) {
|
||||
$spanning_string = 'i.end >= %d AND i.start <= %d ';
|
||||
} else {
|
||||
$spanning_string = 'i.start BETWEEN %d AND %d ';
|
||||
}
|
||||
|
||||
$sql = '
|
||||
SELECT
|
||||
`p`.*,
|
||||
`e`.`post_id`,
|
||||
`i`.`id` AS `instance_id`,
|
||||
`i`.`start` AS `start`,
|
||||
`i`.`end` AS `end`,
|
||||
`e`.`timezone_name` AS `timezone_name`,
|
||||
`e`.`allday` AS `event_allday`,
|
||||
`e`.`recurrence_rules`,
|
||||
`e`.`exception_rules`,
|
||||
`e`.`recurrence_dates`,
|
||||
`e`.`exception_dates`,
|
||||
`e`.`venue`,
|
||||
`e`.`country`,
|
||||
`e`.`address`,
|
||||
`e`.`city`,
|
||||
`e`.`province`,
|
||||
`e`.`postal_code`,
|
||||
`e`.`instant_event`,
|
||||
`e`.`show_map`,
|
||||
`e`.`contact_name`,
|
||||
`e`.`contact_phone`,
|
||||
`e`.`contact_email`,
|
||||
`e`.`contact_url`,
|
||||
`e`.`cost`,
|
||||
`e`.`ticket_url`,
|
||||
`e`.`ical_feed_url`,
|
||||
`e`.`ical_source_url`,
|
||||
`e`.`ical_organizer`,
|
||||
`e`.`ical_contact`,
|
||||
`e`.`ical_uid`,
|
||||
`e`.`longitude`,
|
||||
`e`.`latitude`
|
||||
FROM
|
||||
' . $this->_dbi->get_table_name( 'ai1ec_events' ) . ' e
|
||||
INNER JOIN
|
||||
' . $this->_dbi->get_table_name( 'posts' ) . ' p
|
||||
ON ( `p`.`ID` = `e`.`post_id` )
|
||||
' . $wpml_join_particle . '
|
||||
INNER JOIN
|
||||
' . $this->_dbi->get_table_name( 'ai1ec_event_instances' ) . ' i
|
||||
ON ( `e`.`post_id` = `i`.`post_id` )
|
||||
' . $filter['filter_join'] . '
|
||||
WHERE
|
||||
post_type = \'' . AI1EC_POST_TYPE . '\'
|
||||
' . $wpml_where_particle . '
|
||||
AND
|
||||
' . $spanning_string . '
|
||||
' . $filter['filter_where'] . '
|
||||
' . $post_status_where . '
|
||||
GROUP BY
|
||||
`i`.`id`
|
||||
ORDER BY
|
||||
`e` . `allday` DESC,
|
||||
`i` . `start` ASC,
|
||||
`p` . `post_title` ASC';
|
||||
|
||||
$query = $this->_dbi->prepare( $sql, $args );
|
||||
$events = $this->_dbi->get_results( $query, ARRAY_A );
|
||||
|
||||
$id_list = array();
|
||||
$id_instance_list = array();
|
||||
foreach ( $events as $event ) {
|
||||
|
||||
if ( ! in_array( $event['post_id'], $id_list, true ) ) {
|
||||
$id_list[] = $event['post_id'];
|
||||
}
|
||||
|
||||
$id_instance_list[] = array(
|
||||
'id' => $event['post_id'],
|
||||
'instance_id' => $event['instance_id'],
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $id_list ) ) {
|
||||
update_meta_cache( 'post', $id_list );
|
||||
$this->_ids_between_cache = $id_instance_list;
|
||||
}
|
||||
|
||||
foreach ( $events as &$event ) {
|
||||
$event['allday'] = $this->_is_all_day( $event );
|
||||
$event = $this->_registry->get( 'model.event', $event );
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_events_relative_to function
|
||||
*
|
||||
* Return all events starting after the given reference time, limiting the
|
||||
* result set to a maximum of $limit items, offset by $page_offset. A
|
||||
* negative $page_offset can be provided, which will return events *before*
|
||||
* the reference time, as expected.
|
||||
*
|
||||
* @param int $time limit to events starting after this (local) UNIX time
|
||||
* @param int $limit return a maximum of this number of items
|
||||
* @param int $page_offset offset the result set by $limit times this number
|
||||
* @param array $filter Array of filters for the events returned.
|
||||
* ['cat_ids'] => non-associatative array of category IDs
|
||||
* ['tag_ids'] => non-associatative array of tag IDs
|
||||
* ['post_ids'] => non-associatative array of post IDs
|
||||
* ['auth_ids'] => non-associatative array of author IDs
|
||||
* ['instance_ids'] => non-associatative array of author IDs
|
||||
* @param int $last_day Last day (time), that was displayed.
|
||||
* NOTE FROM NICOLA: be careful, if you want a query with events
|
||||
* that have a start date which is greater than today, pass 0 as
|
||||
* this parameter. If you pass false ( or pass nothing ) you end up with a query
|
||||
* with events that finish before today. I don't know the rationale
|
||||
* behind this but that's how it works
|
||||
* @param bool $unique Whether display only unique events and don't
|
||||
* duplicate results with other instances or not.
|
||||
*
|
||||
* @return array five-element array:
|
||||
* ['events'] an array of matching event objects
|
||||
* ['prev'] true if more previous events
|
||||
* ['next'] true if more next events
|
||||
* ['date_first'] UNIX timestamp (date part) of first event
|
||||
* ['date_last'] UNIX timestamp (date part) of last event
|
||||
*/
|
||||
public function get_events_relative_to(
|
||||
$time,
|
||||
$limit = 0,
|
||||
$page_offset = 0,
|
||||
$filter = array(),
|
||||
$last_day = false,
|
||||
$unique = false
|
||||
) {
|
||||
$localization_helper = $this->_registry->get( 'p28n.wpml' );
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
|
||||
|
||||
// Even if there ARE more than 5 times the limit results - we shall not
|
||||
// try to fetch and display these, as it would crash system
|
||||
$limit = preg_replace('/\D/', '', $limit);
|
||||
$upper_boundary = $limit;
|
||||
if (
|
||||
$settings->get( 'agenda_include_entire_last_day' ) &&
|
||||
( false !== $last_day )
|
||||
) {
|
||||
$upper_boundary *= 5;
|
||||
}
|
||||
|
||||
// Convert timestamp to GMT time
|
||||
$time = $this->_registry->get(
|
||||
'date.system'
|
||||
)->get_current_rounded_time();
|
||||
// Get post status Where snippet and associated SQL arguments
|
||||
$where_parameters = $this->_get_post_status_sql();
|
||||
$post_status_where = $where_parameters['post_status_where'];
|
||||
|
||||
// Get the Join (filter_join) and Where (filter_where) statements based
|
||||
// on $filter elements specified
|
||||
$filter = $this->_get_filter_sql( $filter );
|
||||
|
||||
// Query arguments
|
||||
$args = array( $time );
|
||||
$args = array_merge( $args, $where_parameters['args'] );
|
||||
|
||||
if( $page_offset >= 0 ) {
|
||||
$first_record = $page_offset * $limit;
|
||||
} else {
|
||||
$first_record = ( -$page_offset - 1 ) * $limit;
|
||||
}
|
||||
|
||||
|
||||
$wpml_join_particle = $localization_helper
|
||||
->get_wpml_table_join( 'p.ID' );
|
||||
|
||||
$wpml_where_particle = $localization_helper
|
||||
->get_wpml_table_where();
|
||||
|
||||
$filter_date_clause = ( $page_offset >= 0 )
|
||||
? 'i.end >= %d '
|
||||
: 'i.start < %d ';
|
||||
$order_direction = ( $page_offset >= 0 ) ? 'ASC' : 'DESC';
|
||||
if ( false !== $last_day ) {
|
||||
if ( 0 == $last_day ) {
|
||||
$last_day = $time;
|
||||
}
|
||||
$filter_date_clause = ' i.end ';
|
||||
if ( $page_offset < 0 ) {
|
||||
$filter_date_clause .= '<';
|
||||
$order_direction = 'DESC';
|
||||
} else {
|
||||
$filter_date_clause .= '>';
|
||||
$order_direction = 'ASC';
|
||||
}
|
||||
$filter_date_clause .= ' %d ';
|
||||
$args[0] = $last_day;
|
||||
$first_record = 0;
|
||||
}
|
||||
$query = $this->_dbi->prepare(
|
||||
'SELECT DISTINCT p.*, e.post_id, i.id AS instance_id, ' .
|
||||
'i.start AS start, ' .
|
||||
'i.end AS end, ' .
|
||||
'e.allday AS event_allday, ' .
|
||||
'e.recurrence_rules, e.exception_rules, e.ticket_url, e.instant_event, e.recurrence_dates, e.exception_dates, ' .
|
||||
'e.venue, e.country, e.address, e.city, e.province, e.postal_code, ' .
|
||||
'e.show_map, e.contact_name, e.contact_phone, e.contact_email, e.cost, ' .
|
||||
'e.ical_feed_url, e.ical_source_url, e.ical_organizer, e.ical_contact, e.ical_uid, e.timezone_name, e.longitude, e.latitude ' .
|
||||
'FROM ' . $this->_dbi->get_table_name( 'ai1ec_events' ) . ' e ' .
|
||||
'INNER JOIN ' . $this->_dbi->get_table_name( 'posts' ) . ' p ON e.post_id = p.ID ' .
|
||||
$wpml_join_particle .
|
||||
' INNER JOIN ' . $this->_dbi->get_table_name( 'ai1ec_event_instances' ) . ' i ON e.post_id = i.post_id ' .
|
||||
$filter['filter_join'] .
|
||||
" WHERE post_type = '" . AI1EC_POST_TYPE . "' " .
|
||||
' AND ' . $filter_date_clause .
|
||||
$wpml_where_particle .
|
||||
$filter['filter_where'] .
|
||||
$post_status_where .
|
||||
( $unique ? ' GROUP BY e.post_id' : '' ) .
|
||||
// Reverse order when viewing negative pages, to get correct set of
|
||||
// records. Then reverse results later to order them properly.
|
||||
' ORDER BY i.start ' . $order_direction .
|
||||
', post_title ' . $order_direction .
|
||||
' LIMIT ' . $first_record . ', ' . $upper_boundary,
|
||||
$args
|
||||
);
|
||||
|
||||
$events = $this->_dbi->get_results( $query, ARRAY_A );
|
||||
|
||||
// Limit the number of records to convert to data-object
|
||||
$events = $this->_limit_result_set(
|
||||
$events,
|
||||
$limit,
|
||||
( false !== $last_day )
|
||||
);
|
||||
|
||||
// Reorder records if in negative page offset
|
||||
if( $page_offset < 0 ) {
|
||||
$events = array_reverse( $events );
|
||||
}
|
||||
|
||||
$date_first = $date_last = NULL;
|
||||
|
||||
foreach ( $events as &$event ) {
|
||||
$event['allday'] = $this->_is_all_day( $event );
|
||||
$event = $this->_registry->get( 'model.event', $event );
|
||||
if ( null === $date_first ) {
|
||||
$date_first = $event->get( 'start' );
|
||||
}
|
||||
$date_last = $event->get( 'start' );
|
||||
}
|
||||
$date_first = $this->_registry->get( 'date.time', $date_first );
|
||||
$date_last = $this->_registry->get( 'date.time', $date_last );
|
||||
// jus show next/prev links, in case no event found is shown.
|
||||
$next = true;
|
||||
$prev = true;
|
||||
|
||||
return array(
|
||||
'events' => $events,
|
||||
'prev' => $prev,
|
||||
'next' => $next,
|
||||
'date_first' => $date_first,
|
||||
'date_last' => $date_last,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_events_relative_to_reference function
|
||||
*
|
||||
* Return all events starting after the given date reference, limiting the
|
||||
* result set to a maximum of $limit items, offset by $page_offset. A
|
||||
* negative $page_offset can be provided, which will return events *before*
|
||||
* the reference time, as expected.
|
||||
*
|
||||
* @param int $date_reference if page_offset is greater than or equal to zero, events with start date greater than the date_reference will be returned
|
||||
* otherwise events with start date less than the date_reference will be returned.
|
||||
* @param int $limit return a maximum of this number of items
|
||||
* @param int $page_offset offset the result set by $limit times this number
|
||||
* @param array $filter Array of filters for the events returned.
|
||||
* ['cat_ids'] => non-associatative array of category IDs
|
||||
* ['tag_ids'] => non-associatative array of tag IDs
|
||||
* ['post_ids'] => non-associatative array of post IDs
|
||||
* ['auth_ids'] => non-associatative array of author IDs
|
||||
* ['instance_ids'] => non-associatative array of author IDs
|
||||
* @param bool $unique Whether display only unique events and don't
|
||||
* duplicate results with other instances or not.
|
||||
*
|
||||
* @return array five-element array:
|
||||
* ['events'] an array of matching event objects
|
||||
* ['prev'] true if more previous events
|
||||
* ['next'] true if more next events
|
||||
* ['date_first'] UNIX timestamp (date part) of first event
|
||||
* ['date_last'] UNIX timestamp (date part) of last event
|
||||
*/
|
||||
public function get_events_relative_to_reference( $date_reference, $limit = 0, $page_offset = 0, $filter = array(), $unique = false ) {
|
||||
$localization_helper = $this->_registry->get( 'p28n.wpml' );
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
|
||||
// Even if there ARE more than 5 times the limit results - we shall not
|
||||
// try to fetch and display these, as it would crash system
|
||||
$limit = preg_replace( '/\D/', '', $limit );
|
||||
|
||||
// Convert timestamp to GMT time
|
||||
if ( 0 == $date_reference ) {
|
||||
$timezone = $this->_registry->get( 'date.timezone' )->get( $settings->get( 'timezone_string' ) );
|
||||
$current_time = new DateTime( 'now' );
|
||||
$current_time->setTimezone( $timezone );
|
||||
$time = $current_time->format( 'U' );
|
||||
} else {
|
||||
$time = $date_reference;
|
||||
}
|
||||
|
||||
// Get post status Where snippet and associated SQL arguments
|
||||
$where_parameters = $this->_get_post_status_sql();
|
||||
$post_status_where = $where_parameters['post_status_where'];
|
||||
|
||||
// Get the Join (filter_join) and Where (filter_where) statements based
|
||||
// on $filter elements specified
|
||||
$filter = $this->_get_filter_sql( $filter );
|
||||
|
||||
// Query arguments
|
||||
$args = array( $time );
|
||||
$args = array_merge( $args, $where_parameters['args'] );
|
||||
|
||||
if ( 0 == $date_reference ) {
|
||||
if ( $page_offset >= 0 ) {
|
||||
$filter_date_clause = 'i.end >= %d ';
|
||||
$order_direction = 'ASC';
|
||||
} else {
|
||||
$filter_date_clause = 'i.start < %d ';
|
||||
$order_direction = 'DESC';
|
||||
}
|
||||
} else {
|
||||
if ( $page_offset < 0 ) {
|
||||
$filter_date_clause = 'i.end < %d ';
|
||||
$order_direction = 'DESC';
|
||||
} else {
|
||||
$filter_date_clause = 'i.end >= %d ';
|
||||
$order_direction = 'ASC';
|
||||
}
|
||||
}
|
||||
if ( $page_offset >= 0 ) {
|
||||
$first_record = $page_offset * $limit;
|
||||
} else {
|
||||
$first_record = ( - $page_offset - 1 ) * $limit;
|
||||
}
|
||||
$wpml_join_particle = $localization_helper->get_wpml_table_join( 'p.ID' );
|
||||
$wpml_where_particle = $localization_helper->get_wpml_table_where();
|
||||
|
||||
$query = $this->_dbi->prepare(
|
||||
'SELECT DISTINCT p.*, e.post_id, i.id AS instance_id, ' . 'i.start AS start, ' . 'i.end AS end, ' .
|
||||
'e.allday AS event_allday, ' .
|
||||
'e.recurrence_rules, e.exception_rules, e.ticket_url, e.instant_event, e.recurrence_dates, e.exception_dates, ' .
|
||||
'e.venue, e.country, e.address, e.city, e.province, e.postal_code, ' .
|
||||
'e.show_map, e.contact_name, e.contact_phone, e.contact_email, e.cost, ' .
|
||||
'e.ical_feed_url, e.ical_source_url, e.ical_organizer, e.ical_contact, e.ical_uid, e.timezone_name, e.longitude, e.latitude ' .
|
||||
'FROM ' . $this->_dbi->get_table_name( 'ai1ec_events' ) . ' e ' . 'INNER JOIN ' .
|
||||
$this->_dbi->get_table_name( 'posts' ) . ' p ON e.post_id = p.ID ' . $wpml_join_particle .
|
||||
' INNER JOIN ' . $this->_dbi->get_table_name( 'ai1ec_event_instances' ) . ' i ON e.post_id = i.post_id ' .
|
||||
$filter['filter_join'] . " WHERE post_type = '" . AI1EC_POST_TYPE . "' " . ' AND ' . $filter_date_clause .
|
||||
$wpml_where_particle . $filter['filter_where'] . $post_status_where .
|
||||
( $unique ? ' GROUP BY e.post_id' : '' ) .
|
||||
// Reverse order when viewing negative pages, to get correct set of
|
||||
// records. Then reverse results later to order them properly.
|
||||
' ORDER BY i.start ' . $order_direction . ', post_title ' . $order_direction . ' LIMIT ' . $first_record .
|
||||
', ' . ( $limit + 1 ),
|
||||
$args );
|
||||
|
||||
$events = $this->_dbi->get_results( $query, ARRAY_A );
|
||||
|
||||
if ( $page_offset >= 0 ) {
|
||||
$prev = true;
|
||||
$next = ( count( $events ) > $limit );
|
||||
if ( $next ) {
|
||||
array_pop( $events );
|
||||
}
|
||||
} else {
|
||||
$prev = ( count( $events ) > $limit );
|
||||
if ( $prev ) {
|
||||
array_pop( $events );
|
||||
}
|
||||
$next = true;
|
||||
}
|
||||
|
||||
// Reorder records if in negative page offset
|
||||
if ( $page_offset < 0 ) {
|
||||
$events = array_reverse( $events );
|
||||
}
|
||||
|
||||
$date_first = $date_last = NULL;
|
||||
|
||||
foreach ( $events as &$event ) {
|
||||
$event['allday'] = $this->_is_all_day( $event );
|
||||
$event = $this->_registry->get( 'model.event', $event );
|
||||
if ( null === $date_first ) {
|
||||
$date_first = $event->get( 'start' );
|
||||
}
|
||||
$date_last = $event->get( 'start' );
|
||||
}
|
||||
$date_first = $this->_registry->get( 'date.time', $date_first );
|
||||
$date_last = $this->_registry->get( 'date.time', $date_last );
|
||||
|
||||
return array(
|
||||
'events' => $events,
|
||||
'prev' => $prev,
|
||||
'next' => $next,
|
||||
'date_first' => $date_first,
|
||||
'date_last' => $date_last );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns events for given day. Event must start before end of day and must
|
||||
* ends after beginning of day.
|
||||
*
|
||||
* @param Ai1ec_Date_Time $day Date object.
|
||||
* @param array $filter Search filters;
|
||||
*
|
||||
* @return array List of events.
|
||||
*/
|
||||
public function get_events_for_day(
|
||||
Ai1ec_Date_Time $day,
|
||||
array $filter = array()
|
||||
) {
|
||||
$end_of_day = $this->_registry->get( 'date.time', $day )
|
||||
->set_time( 23, 59, 59 );
|
||||
$start_of_day = $this->_registry->get( 'date.time', $day )
|
||||
->set_time( 0, 0, 0 );
|
||||
return $this->get_events_between(
|
||||
$start_of_day,
|
||||
$end_of_day,
|
||||
$filter,
|
||||
false,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ID of event in database, matching imported one.
|
||||
*
|
||||
* Return event ID by iCalendar UID, feed url, start time and whether the
|
||||
* event has recurrence rules (to differentiate between an event with a UID
|
||||
* defining the recurrence pattern, and other events with with the same UID,
|
||||
* which are just RECURRENCE-IDs).
|
||||
*
|
||||
* @param int $uid iCalendar UID property
|
||||
* @param string $feed Feed URL
|
||||
* @param int $start Start timestamp (GMT)
|
||||
* @param bool $has_recurrence Whether the event has recurrence rules
|
||||
* @param int|null $exclude_post_id Do not match against this post ID
|
||||
*
|
||||
* @return object|null ID of matching event post, or NULL if no match
|
||||
*/
|
||||
public function get_matching_event_id(
|
||||
$uid,
|
||||
$feed,
|
||||
$start,
|
||||
$has_recurrence = false,
|
||||
$exclude_post_id = null
|
||||
) {
|
||||
$dbi = $this->_registry->get( 'dbi.dbi' );
|
||||
$table_name = $dbi->get_table_name( 'ai1ec_events' );
|
||||
$query = 'SELECT `post_id` FROM ' . $table_name . '
|
||||
WHERE
|
||||
ical_feed_url = %s
|
||||
AND ical_uid = %s
|
||||
AND start = %d ' .
|
||||
( $has_recurrence ? 'AND NOT ' : 'AND ' ) .
|
||||
' ( recurrence_rules IS NULL OR recurrence_rules = \'\' )';
|
||||
$args = array( $feed, $uid );
|
||||
if ( $start instanceof Ai1ec_Date_Time ) {
|
||||
$args[] = $start->format();
|
||||
} else {
|
||||
$args[] = (int)$start;
|
||||
}
|
||||
if ( null !== $exclude_post_id ) {
|
||||
$query .= ' AND post_id <> %d';
|
||||
$args[] = $exclude_post_id;
|
||||
}
|
||||
|
||||
return $dbi->get_var( $dbi->prepare( $query, $args ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get event by UID. UID must be unique.
|
||||
*
|
||||
* NOTICE: deletes events with that UID if they have different URLs.
|
||||
*
|
||||
* @param string $uid UID from feed.
|
||||
* @param string $uid Feed URL.
|
||||
*
|
||||
* @return int|null Matching Event ID or NULL if none found.
|
||||
*/
|
||||
public function get_matching_event_by_uid_and_url( $uid, $url ) {
|
||||
if ( ! isset( $uid{1} ) ) {
|
||||
return null;
|
||||
}
|
||||
$dbi = $this->_registry->get( 'dbi.dbi' );
|
||||
$table_name = $dbi->get_table_name( 'ai1ec_events' );
|
||||
$argv = array( $url, $uid, $url );
|
||||
// fix issue where invalid feed URLs were assigned
|
||||
$update = 'UPDATE ' . $table_name . ' SET `ical_feed_url` = %s' .
|
||||
' WHERE `ical_uid` = %s AND `ical_feed_url` != %s';
|
||||
$query = $dbi->prepare( $update, $argv);
|
||||
$success = $dbi->query( $query );
|
||||
|
||||
// retrieve actual feed ID if any
|
||||
$select = 'SELECT `post_id` FROM `' . $table_name .
|
||||
'` WHERE `ical_uid` = %s';
|
||||
return $dbi->get_var( $dbi->prepare( $select, array( $uid ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get event ids for the passed feed url
|
||||
*
|
||||
* @param string $feed_url
|
||||
*/
|
||||
public function get_event_ids_for_feed( $feed_url ) {
|
||||
$dbi = $this->_registry->get( 'dbi.dbi' );
|
||||
$table_name = $dbi->get_table_name( 'ai1ec_events' );
|
||||
$query = 'SELECT `post_id` FROM ' . $table_name .
|
||||
' WHERE ical_feed_url = %s';
|
||||
return $dbi->get_col( $dbi->prepare( $query, array( $feed_url ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns events instances closest to today.
|
||||
*
|
||||
* @param array $events_ids Events ids filter.
|
||||
*
|
||||
* @return array Events collection.
|
||||
* @throws Ai1ec_Bootstrap_Exception
|
||||
*/
|
||||
public function get_instances_closest_to_today( array $events_ids = array() ) {
|
||||
$where_events_ids = '';
|
||||
if ( ! empty( $events_ids ) ) {
|
||||
$where_events_ids = 'i.post_id IN ('
|
||||
. implode( ',', $events_ids ) . ') AND ';
|
||||
}
|
||||
$query = 'SELECT i.id, i.post_id FROM ' .
|
||||
$this->_dbi->get_table_name( 'ai1ec_event_instances' ) .
|
||||
' i WHERE ' .
|
||||
$where_events_ids .
|
||||
' i.start > %d ' .
|
||||
' GROUP BY i.post_id';
|
||||
/** @var $today Ai1ec_Date_Time */
|
||||
$today = $this->_registry->get( 'date.time', 'now', 'sys.default' );
|
||||
$today->set_time( 0, 0, 0 );
|
||||
$query = $this->_dbi->prepare( $query, $today->format( 'U' ) );
|
||||
$results = $this->_dbi->get_results( $query );
|
||||
$events = array();
|
||||
foreach ( $results as $result ) {
|
||||
$events[] = $this->get_event(
|
||||
$result->post_id,
|
||||
$result->id
|
||||
);
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given event must be treated as all-day event.
|
||||
*
|
||||
* Event instances that span 24 hours are treated as all-day.
|
||||
* NOTICE: event is passed in before being transformed into
|
||||
* Ai1ec_Event object, with Ai1ec_Date_Time fields.
|
||||
*
|
||||
* @param array $event Event data returned from database.
|
||||
*
|
||||
* @return bool True if event is all-day event.
|
||||
*/
|
||||
protected function _is_all_day( array $event ) {
|
||||
if ( isset( $event['event_allday'] ) && $event['event_allday'] ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! isset( $event['start'] ) || ! isset( $event['end'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ( 86400 === $event['end'] - $event['start'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* _limit_result_set function
|
||||
*
|
||||
* Slice given number of events from list, with exception when all
|
||||
* events from last day shall be included.
|
||||
*
|
||||
* @param array $events List of events to slice
|
||||
* @param int $limit Number of events to slice-off
|
||||
* @param bool $last_day Set to true to include all events from last day ignoring {$limit}
|
||||
*
|
||||
* @return array Sliced events list
|
||||
*/
|
||||
protected function _limit_result_set(
|
||||
array $events,
|
||||
$limit,
|
||||
$last_day
|
||||
) {
|
||||
$limited_events = array();
|
||||
$start_day_previous = 0;
|
||||
foreach ( $events as $event ) {
|
||||
$start_day = date(
|
||||
'Y-m-d',
|
||||
$event['start']
|
||||
);
|
||||
--$limit; // $limit = $limit - 1;
|
||||
if ( $limit < 0 ) {
|
||||
if ( true === $last_day ) {
|
||||
if ( $start_day != $start_day_previous ) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$limited_events[] = $event;
|
||||
$start_day_previous = $start_day;
|
||||
}
|
||||
return $limited_events;
|
||||
}
|
||||
|
||||
/**
|
||||
* _get_post_status_sql function
|
||||
*
|
||||
* Returns SQL snippet for properly matching event posts, as well as array
|
||||
* of arguments to pass to $this_dbi->prepare, in function argument
|
||||
* references.
|
||||
* Nothing is returned by the function.
|
||||
*
|
||||
* @return array An array containing post_status_where: the sql string,
|
||||
* args: the arguments for prepare()
|
||||
*/
|
||||
protected function _get_post_status_sql() {
|
||||
$args = array();
|
||||
|
||||
// Query the correct post status
|
||||
if (
|
||||
current_user_can( 'administrator' ) ||
|
||||
current_user_can( 'editor' ) ||
|
||||
current_user_can( 'read_private_ai1ec_events' )
|
||||
) {
|
||||
// User has privilege of seeing all published and private
|
||||
$post_status_where = 'AND post_status IN ( %s, %s ) ';
|
||||
$args[] = 'publish';
|
||||
$args[] = 'private';
|
||||
} elseif ( is_user_logged_in() ) {
|
||||
// User has privilege of seeing all published and only their own
|
||||
// private posts.
|
||||
|
||||
// Get user ID
|
||||
$user_id = 0;
|
||||
if ( is_callable( 'wp_get_current_user' ) ) {
|
||||
$user = wp_get_current_user();
|
||||
$user_id = (int)$user->ID;
|
||||
unset( $user );
|
||||
}
|
||||
|
||||
// include post_status = published
|
||||
// OR
|
||||
// post_status = private AND post_author = userID
|
||||
$post_status_where =
|
||||
'AND ( ' .
|
||||
'post_status = %s ' .
|
||||
'OR ( post_status = %s AND post_author = %d ) ' .
|
||||
') ';
|
||||
|
||||
$args[] = 'publish';
|
||||
$args[] = 'private';
|
||||
$args[] = $user_id;
|
||||
} else {
|
||||
// User can only see published posts.
|
||||
$post_status_where = 'AND post_status = %s ';
|
||||
$args[] = 'publish';
|
||||
}
|
||||
|
||||
return array(
|
||||
'post_status_where' => $post_status_where,
|
||||
'args' => $args
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take filter and return SQL options.
|
||||
*
|
||||
* Takes an array of filtering options and turns it into JOIN and WHERE
|
||||
* statements for running an SQL query limited to the specified options.
|
||||
*
|
||||
* @param array $filter Array of filters for the events returned:
|
||||
* ['cat_ids'] => list of category IDs
|
||||
* ['tag_ids'] => list of tag IDs
|
||||
* ['post_ids'] => list of event post IDs
|
||||
* ['auth_ids'] => list of event author IDs
|
||||
* ['instance_ids'] => list of event instance IDs
|
||||
*
|
||||
* @return array The modified filter array to having:
|
||||
* ['filter_join'] the Join statements for the SQL
|
||||
* ['filter_where'] the Where statements for the SQL
|
||||
*/
|
||||
protected function _get_filter_sql( $filter ) {
|
||||
$filter_join = $filter_where = array();
|
||||
foreach ( $filter as $filter_type => $filter_ids ) {
|
||||
$filter_object = null;
|
||||
try {
|
||||
if ( empty( $filter_ids ) ) {
|
||||
$filter_ids = array();
|
||||
}
|
||||
$filter_object = $this->_registry->get(
|
||||
'model.filter.' . $filter_type,
|
||||
$filter_ids
|
||||
);
|
||||
if ( ! ( $filter_object instanceof Ai1ec_Filter_Interface ) ) {
|
||||
throw new Ai1ec_Bootstrap_Exception(
|
||||
'Filter \'' . get_class( $filter_object ) .
|
||||
'\' is not instance of Ai1ec_Filter_Interface'
|
||||
);
|
||||
}
|
||||
} catch ( Ai1ec_Bootstrap_Exception $exception ) {
|
||||
continue;
|
||||
}
|
||||
$filter_join[] = $filter_object->get_join();
|
||||
$filter_where[] = $filter_object->get_where();
|
||||
}
|
||||
|
||||
$filter_join = array_filter( $filter_join );
|
||||
$filter_where = array_filter( $filter_where );
|
||||
$filter_join = join( ' ', $filter_join );
|
||||
if ( count( $filter_where ) > 0 ) {
|
||||
$operator = $this->get_distinct_types_operator();
|
||||
$filter_where = $operator . '( ' .
|
||||
implode( ' ) ' . $operator . ' ( ', $filter_where ) .
|
||||
' ) ';
|
||||
} else {
|
||||
$filter_where = '';
|
||||
}
|
||||
|
||||
return $filter + compact( 'filter_where', 'filter_join' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get operator for joining distinct filters in WHERE.
|
||||
*
|
||||
* @return string SQL operator.
|
||||
*/
|
||||
public function get_distinct_types_operator() {
|
||||
static $operators = array( 'AND' => 1, 'OR' => 2 );
|
||||
$default = 'AND';
|
||||
$where_operator = strtoupper( trim( (string)apply_filters(
|
||||
'ai1ec_filter_distinct_types_logic',
|
||||
$default
|
||||
) ) );
|
||||
if ( ! isset( $operators[$where_operator] ) ) {
|
||||
$where_operator = $default;
|
||||
}
|
||||
return $where_operator;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Settings extension for managing view-related settings.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Settings_View extends Ai1ec_App {
|
||||
|
||||
/**
|
||||
* @var string Name of settings option to use for views map.
|
||||
*/
|
||||
const SETTING_VIEWS_MAP = 'enabled_views';
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Settings Instance
|
||||
*/
|
||||
protected $_settings = null;
|
||||
|
||||
/**
|
||||
* Acquire Settings model instance for future reference.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _initialize() {
|
||||
$this->_settings = $this->_registry->get( 'model.settings' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a view if not set.
|
||||
*
|
||||
* @param array $view
|
||||
*/
|
||||
public function add( array $view ) {
|
||||
$enabled_views = $this->_get();
|
||||
if ( isset( $enabled_views[$view['name']] ) ) {
|
||||
if ( $enabled_views[$view['name']]['longname'] === $view['longname'] ) {
|
||||
return;
|
||||
}
|
||||
$enabled_views[$view['name']]['longname'] = $view['longname'];
|
||||
} else {
|
||||
// Copy relevant settings to local view array; account for possible missing
|
||||
// mobile settings during upgrade (assign defaults).
|
||||
$enabled_views[$view['name']] = array(
|
||||
'enabled' => $view['enabled'],
|
||||
'default' => $view['default'],
|
||||
'enabled_mobile' => isset( $view['enabled_mobile'] ) ?
|
||||
$view['enabled_mobile'] : $view['enabled'],
|
||||
'default_mobile' => isset( $view['default_mobile'] ) ?
|
||||
$view['default_mobile'] : $view['default'],
|
||||
'longname' => $view['longname'],
|
||||
);
|
||||
}
|
||||
$this->_set( $enabled_views );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a view.
|
||||
*
|
||||
* @param string $view
|
||||
*/
|
||||
public function remove( $view ) {
|
||||
$enabled_views = $this->_get();
|
||||
if ( isset( $enabled_views[$view] ) ) {
|
||||
unset( $enabled_views[$view] );
|
||||
$this->_set( $enabled_views );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all configured views.
|
||||
*
|
||||
* @return array Map of configured view aliases and their details.
|
||||
*/
|
||||
public function get_all() {
|
||||
return $this->_get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name of view to be rendered for requested alias.
|
||||
*
|
||||
* @param string $view Name of view requested.
|
||||
*
|
||||
* @return string Name of view to be rendered.
|
||||
*
|
||||
* @throws Ai1ec_Settings_Exception If no views are configured.
|
||||
*/
|
||||
public function get_configured( $view ) {
|
||||
$enabled_views = $this->_get();
|
||||
if ( empty( $enabled_views ) ) {
|
||||
throw new Ai1ec_Settings_Exception( 'No view is enabled' );
|
||||
}
|
||||
if (
|
||||
isset( $enabled_views[$view] ) &&
|
||||
isset( $enabled_views[$view]['enabled' . ( wp_is_mobile() ? '_mobile' : '' ) ] ) &&
|
||||
$enabled_views[$view]['enabled' . ( wp_is_mobile() ? '_mobile' : '' ) ]
|
||||
) {
|
||||
return $view;
|
||||
}
|
||||
return $this->get_default();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default view to render.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public function get_default() {
|
||||
$enabled_views = $this->_get();
|
||||
$default = null;
|
||||
// Check mobile settings first, if in mobile mode.
|
||||
if (
|
||||
! $this->_registry->get( 'compatibility.cli' )->is_cli() &&
|
||||
wp_is_mobile()
|
||||
) {
|
||||
foreach ( $enabled_views as $view => $details ) {
|
||||
if (
|
||||
isset( $details['default_mobile'] ) &&
|
||||
$details['default_mobile'] &&
|
||||
$details['enabled_mobile']
|
||||
) {
|
||||
$default = $view;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Either not in mobile mode or no mobile settings available; look up
|
||||
// desktop settings.
|
||||
if ( null === $default ) {
|
||||
foreach ( $enabled_views as $view => $details ) {
|
||||
if ( $details['default'] && $details['enabled'] ) {
|
||||
$default = $view;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// No enabled view found, but we need to pick one, so pick the first view.
|
||||
if ( null === $default ) {
|
||||
$default = (string)current( array_keys( $enabled_views ) );
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve views maps from storage.
|
||||
*
|
||||
* @return array Current views map.
|
||||
*/
|
||||
protected function _get() {
|
||||
return (array)$this->_settings->get( self::SETTING_VIEWS_MAP, array() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update views map.
|
||||
*
|
||||
* @param array $enabled_views Map of enabled views.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
protected function _set( array $enabled_views ) {
|
||||
return $this->_settings->set( self::SETTING_VIEWS_MAP, $enabled_views );
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Exception occuring during settings modification.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Html
|
||||
*/
|
||||
class Ai1ec_Settings_Exception extends Ai1ec_Exception {
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Model used for storing/retrieving taxonomy.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Html
|
||||
*/
|
||||
class Ai1ec_Taxonomy extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* @var array Map of taxonomy values.
|
||||
*/
|
||||
protected $_taxonomy_map = array(
|
||||
'events_categories' => array(),
|
||||
'events_tags' => array(),
|
||||
);
|
||||
|
||||
/**
|
||||
* Callback to pre-populate taxonomies before exporting ics.
|
||||
* All taxonomies which are not tags are exported as event_categories
|
||||
*
|
||||
* @param array $post_ids List of Post IDs to inspect.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function prepare_meta_for_ics( array $post_ids ) {
|
||||
$taxonomies = get_object_taxonomies( AI1EC_POST_TYPE );
|
||||
$categories = array();
|
||||
$excluded_categories = array(
|
||||
'events_tags' => true,
|
||||
'events_feeds' => true
|
||||
);
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
if ( isset( $excluded_categories[$taxonomy] ) ) {
|
||||
continue;
|
||||
}
|
||||
$categories[] = $taxonomy;
|
||||
}
|
||||
foreach ( $post_ids as $post_id ) {
|
||||
$post_id = (int)$post_id;
|
||||
$this->_taxonomy_map['events_categories'][$post_id] = array();
|
||||
$this->_taxonomy_map['events_tags'][$post_id] = array();
|
||||
}
|
||||
$tags = wp_get_object_terms(
|
||||
$post_ids,
|
||||
array( 'events_tags' ),
|
||||
array( 'fields' => 'all_with_object_id' )
|
||||
);
|
||||
foreach ( $tags as $term ) {
|
||||
$this->_taxonomy_map[$term->taxonomy][$term->object_id][] = $term;
|
||||
}
|
||||
$category_terms = wp_get_object_terms(
|
||||
$post_ids,
|
||||
$categories,
|
||||
array( 'fields' => 'all_with_object_id' )
|
||||
);
|
||||
foreach ( $category_terms as $term ) {
|
||||
$this->_taxonomy_map['events_categories'][$term->object_id][] = $term;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to pre-populate taxonomies before processing.
|
||||
*
|
||||
* @param array $post_ids List of Post IDs to inspect.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function update_meta( array $post_ids ) {
|
||||
foreach ( $post_ids as $post_id ) {
|
||||
$post_id = (int)$post_id;
|
||||
$this->_taxonomy_map['events_categories'][$post_id] = array();
|
||||
$this->_taxonomy_map['events_tags'][$post_id] = array();
|
||||
}
|
||||
$terms = wp_get_object_terms(
|
||||
$post_ids,
|
||||
array( 'events_categories', 'events_tags' ),
|
||||
array( 'fields' => 'all_with_object_id' )
|
||||
);
|
||||
foreach ( $terms as $term ) {
|
||||
$this->_taxonomy_map[$term->taxonomy][$term->object_id][] = $term;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-fetch category entries map from database.
|
||||
*
|
||||
* @return array Map of category entries.
|
||||
*/
|
||||
public function fetch_category_map() {
|
||||
$category_map = array();
|
||||
$records = (array)$this->_registry->get( 'dbi.dbi' )->select(
|
||||
'ai1ec_event_category_meta',
|
||||
array( 'term_id', 'term_image', 'term_color' )
|
||||
);
|
||||
foreach ( $records as $row ) {
|
||||
$image = $color = null;
|
||||
if ( $row->term_image ) {
|
||||
$image = $row->term_image;
|
||||
}
|
||||
if ( $row->term_color ) {
|
||||
$color = $row->term_color;
|
||||
}
|
||||
$category_map[(int)$row->term_id] = compact( 'image', 'color' );
|
||||
}
|
||||
return $category_map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get taxonomy values for specified post.
|
||||
*
|
||||
* @param int $post_id Actual Post ID to check.
|
||||
* @param string $taxonomy Name of taxonomy to retrieve values for.
|
||||
*
|
||||
* @return array List of terms (stdClass'es) associated with post.
|
||||
*/
|
||||
public function get_post_taxonomy( $post_id, $taxonomy ) {
|
||||
$post_id = (int)$post_id;
|
||||
if ( ! isset( $this->_taxonomy_map[$taxonomy][$post_id] ) ) {
|
||||
$definition = wp_get_post_terms( $post_id, $taxonomy );
|
||||
if ( empty( $definition ) || is_wp_error( $definition ) ) {
|
||||
$definition = array();
|
||||
}
|
||||
$this->_taxonomy_map[$taxonomy][$post_id] = $definition;
|
||||
}
|
||||
return $this->_taxonomy_map[$taxonomy][$post_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get post (event) categories taxonomy.
|
||||
*
|
||||
* @param int $post_id Checked post ID.
|
||||
*
|
||||
* @return array List of categories (stdClass'es) associated with event.
|
||||
*/
|
||||
public function get_post_categories( $post_id ) {
|
||||
return $this->get_post_taxonomy( $post_id, 'events_categories' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get post (event) tags taxonomy.
|
||||
*
|
||||
* @param int $post_id Checked post ID.
|
||||
*
|
||||
* @return array List of tags (stdClass'es) associated with event.
|
||||
*/
|
||||
public function get_post_tags( $post_id ) {
|
||||
return $this->get_post_taxonomy( $post_id, 'events_tags' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached category description field.
|
||||
*
|
||||
* @param int $term_id Category ID.
|
||||
* @param string $field Name of field, one of 'image', 'color'.
|
||||
*
|
||||
* @return string|null Field value or null if entry is not found.
|
||||
*/
|
||||
public function get_category_field( $term_id, $field ) {
|
||||
static $category_meta = null;
|
||||
if ( null === $category_meta ) {
|
||||
$category_meta = $this->fetch_category_map();
|
||||
}
|
||||
$term_id = (int)$term_id;
|
||||
if ( ! isset( $category_meta[$term_id] ) ) {
|
||||
return null;
|
||||
}
|
||||
return $category_meta[$term_id][$field];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color of the Event Category having the given term ID.
|
||||
*
|
||||
* @param int $term_id The ID of the Event Category.
|
||||
*
|
||||
* @return string|null Color to use
|
||||
*/
|
||||
public function get_category_color( $term_id ) {
|
||||
return $this->get_category_field( $term_id, 'color' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image of the Event Category having the given term ID.
|
||||
*
|
||||
* @param int $term_id The ID of the Event Category.
|
||||
*
|
||||
* @return string|null Image url to use.
|
||||
*/
|
||||
public function get_category_image( $term_id ) {
|
||||
return $this->get_category_field( $term_id, 'image' );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The abstract class for a admin page.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
abstract class Ai1ec_View_Admin_Abstract extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $_page_id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $_page_suffix;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $_api_registration;
|
||||
|
||||
/**
|
||||
* Standard constructor
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry
|
||||
*/
|
||||
public function __construct( Ai1ec_Registry_Object $registry ) {
|
||||
parent::__construct( $registry );
|
||||
$exploded_class = explode( '_', get_class( $this ) );
|
||||
$this->_page_suffix = strtolower( end( $exploded_class ) );
|
||||
$this->_api_registration = $this->_registry->get( 'model.api.api-registration' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url of the page
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_url() {
|
||||
return add_query_arg(
|
||||
array(
|
||||
'post_type' => AI1EC_POST_TYPE,
|
||||
'page' => AI1EC_PLUGIN_NAME . '-' . $this->_page_suffix,
|
||||
),
|
||||
ai1ec_admin_url( 'edit.php' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the page to the correct menu.
|
||||
*/
|
||||
abstract public function add_page();
|
||||
|
||||
/**
|
||||
* Adds the page to the correct menu.
|
||||
*/
|
||||
abstract public function add_meta_box();
|
||||
|
||||
/**
|
||||
* Display the page html
|
||||
*/
|
||||
abstract public function display_page();
|
||||
|
||||
/**
|
||||
* Handle post, likely to be deprecated to use commands.
|
||||
*/
|
||||
abstract public function handle_post();
|
||||
|
||||
}
|
||||
@@ -1,576 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Event create/update form backend view layer.
|
||||
*
|
||||
* Manage creation of boxes (containers) for our control elements
|
||||
* and instantiating, as well as updating them.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Add_New_Event extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Create hook to display event meta box when creating or editing an event.
|
||||
*
|
||||
* @wp_hook add_meta_boxes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function event_meta_box_container() {
|
||||
add_meta_box(
|
||||
AI1EC_POST_TYPE,
|
||||
Ai1ec_I18n::__( 'Event Details' ),
|
||||
array( $this, 'meta_box_view' ),
|
||||
AI1EC_POST_TYPE,
|
||||
'normal',
|
||||
'high'
|
||||
);
|
||||
|
||||
add_meta_box(
|
||||
AI1EC_POST_TYPE . '_features',
|
||||
Ai1ec_I18n::__( 'Empower your calendar, build your community' ),
|
||||
array( $this, 'features_info' ),
|
||||
AI1EC_POST_TYPE,
|
||||
'side',
|
||||
'low'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Event Details meta box to the Add/Edit Event screen in the dashboard.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function features_info( $post ) {
|
||||
$message = __(
|
||||
'<ul class="ai1ec-features-list"><li><a href="https://time.ly/hub" target="_blank">Pull events from other calendars</a></li><li><a href="https://time.ly/hub" target="_blank">Pull events from Facebook</a></li><li><a href="https://time.ly/hub" target="_blank">Add a Newsletter</a></li><li><a href="https://time.ly/hub" target="_blank">Get public event submissions</a></li><li><a href="https://time.ly/hub" target="_blank">Charge people to post events</a></li><li><a href="https://time.ly/hub" target="_blank">Add social sharing</a></li><li><a href="https://time.ly/hub" target="_blank">And more</a></li></ul>',
|
||||
AI1EC_PLUGIN_NAME
|
||||
);
|
||||
|
||||
echo $message;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add Event Details meta box to the Add/Edit Event screen in the dashboard.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function meta_box_view( $post ) {
|
||||
|
||||
$theme_loader = $this->_registry->get( 'theme.loader' );
|
||||
$empty_event = $this->_registry->get( 'model.event' );
|
||||
|
||||
// ==================
|
||||
// = Default values =
|
||||
// ==================
|
||||
// ATTENTION - When adding new fields to the event remember that you must
|
||||
// also set up the duplicate-controller.
|
||||
// TODO: Fix this duplication.
|
||||
$all_day_event = '';
|
||||
$instant_event = '';
|
||||
$start = $this->_registry->get( 'date.time' );
|
||||
$end = $this->_registry->get( 'date.time', '+1 hour' );
|
||||
$timezone_name = null;
|
||||
$timezones_list = $this->_registry->get( 'date.timezone' )->get_timezones( true );
|
||||
$show_map = false;
|
||||
$google_map = '';
|
||||
$venue = '';
|
||||
$country = '';
|
||||
$address = '';
|
||||
$city = '';
|
||||
$province = '';
|
||||
$postal_code = '';
|
||||
$contact_name = '';
|
||||
$contact_phone = '';
|
||||
$contact_email = '';
|
||||
$contact_url = '';
|
||||
$cost = '';
|
||||
$is_free = '';
|
||||
$cost_type = 'free';
|
||||
$rrule = '';
|
||||
$rrule_text = '';
|
||||
$repeating_event = false;
|
||||
$exrule = '';
|
||||
$exrule_text = '';
|
||||
$exclude_event = false;
|
||||
$exdate = '';
|
||||
$show_coordinates = false;
|
||||
$longitude = '';
|
||||
$latitude = '';
|
||||
$coordinates = '';
|
||||
$ticket_url = '';
|
||||
|
||||
$instance_id = false;
|
||||
if ( isset( $_REQUEST['instance'] ) ) {
|
||||
$instance_id = absint( $_REQUEST['instance'] );
|
||||
}
|
||||
if ( $instance_id ) {
|
||||
add_filter(
|
||||
'print_scripts_array',
|
||||
array( $this, 'disable_autosave' )
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// on some php version, nested try catch blocks fail and the exception would never be caught.
|
||||
// this is why we use this approach.
|
||||
$excpt = null;
|
||||
$event = null;
|
||||
try {
|
||||
$event = $this->_registry->get(
|
||||
'model.event',
|
||||
get_the_ID(),
|
||||
$instance_id
|
||||
);
|
||||
} catch ( Ai1ec_Event_Not_Found_Exception $excpt ) {
|
||||
$ai1ec_localization_helper = $this->_registry
|
||||
->get( 'p28n.wpml' );
|
||||
$translatable_id = $ai1ec_localization_helper
|
||||
->get_translatable_id();
|
||||
if ( false !== $translatable_id ) {
|
||||
$event = $this->_registry->get(
|
||||
'model.event',
|
||||
$translatable_id,
|
||||
$instance_id
|
||||
);
|
||||
}
|
||||
}
|
||||
if ( null !== $excpt ) {
|
||||
throw $excpt;
|
||||
}
|
||||
|
||||
// Existing event was found. Initialize form values with values from
|
||||
// event object.
|
||||
$all_day_event = $event->is_allday() ? 'checked' : '';
|
||||
$instant_event = $event->is_instant() ? 'checked' : '';
|
||||
|
||||
$start = $event->get( 'start' );
|
||||
$end = $event->get( 'end' );
|
||||
$timezone_name = $event->get( 'timezone_name' );
|
||||
|
||||
$multi_day = $event->is_multiday();
|
||||
|
||||
$show_map = $event->get( 'show_map' );
|
||||
$google_map = $show_map ? 'checked="checked"' : '';
|
||||
|
||||
$show_coordinates = $event->get( 'show_coordinates' );
|
||||
$coordinates = $show_coordinates ? 'checked="checked"' : '';
|
||||
$longitude = (float)$event->get( 'longitude', 0 );
|
||||
$latitude = (float)$event->get( 'latitude', 0 );
|
||||
// There is a known bug in Wordpress (https://core.trac.wordpress.org/ticket/15158) that saves 0 to the DB instead of null.
|
||||
// We handle a special case here to avoid having the fields with a value of 0 when the user never inputted any coordinates
|
||||
if ( ! $show_coordinates ) {
|
||||
$longitude = '';
|
||||
$latitude = '';
|
||||
}
|
||||
|
||||
$venue = $event->get( 'venue' );
|
||||
$country = $event->get( 'country' );
|
||||
$address = $event->get( 'address' );
|
||||
$city = $event->get( 'city' );
|
||||
$province = $event->get( 'province' );
|
||||
$postal_code = $event->get( 'postal_code' );
|
||||
$contact_name = $event->get( 'contact_name' );
|
||||
$contact_phone = $event->get( 'contact_phone' );
|
||||
$contact_email = $event->get( 'contact_email' );
|
||||
$contact_url = $event->get( 'contact_url' );
|
||||
$cost = $event->get( 'cost' );
|
||||
$ticket_url = $event->get( 'ticket_url' );
|
||||
$rrule = $event->get( 'recurrence_rules' );
|
||||
$exrule = $event->get( 'exception_rules' );
|
||||
$exdate = $event->get( 'exception_dates' );
|
||||
$repeating_event = ! empty( $rrule );
|
||||
$exclude_event = ! empty( $exrule );
|
||||
|
||||
$is_free = '';
|
||||
$free = $event->is_free();
|
||||
if ( ! empty( $free ) ) {
|
||||
$is_free = 'checked="checked" ';
|
||||
$cost = '';
|
||||
}
|
||||
|
||||
if ( $repeating_event ) {
|
||||
$rrule_text = ucfirst(
|
||||
$this->_registry->get( 'recurrence.rule' )
|
||||
->rrule_to_text( $rrule )
|
||||
);
|
||||
}
|
||||
|
||||
if ( $exclude_event ) {
|
||||
$exrule_text = ucfirst(
|
||||
$this->_registry->get( 'recurrence.rule' )
|
||||
->rrule_to_text( $exrule )
|
||||
);
|
||||
}
|
||||
} catch ( Ai1ec_Event_Not_Found_Exception $excpt ) {
|
||||
// Event does not exist.
|
||||
// Leave form fields undefined (= zero-length strings)
|
||||
$event = null;
|
||||
}
|
||||
|
||||
// Time zone; display if set.
|
||||
$timezone = '';
|
||||
$timezone_string = null;
|
||||
$date_timezone = $this->_registry->get( 'date.timezone' );
|
||||
|
||||
if (
|
||||
! empty( $timezone_name ) &&
|
||||
$local_name = $date_timezone->get_name( $timezone_name )
|
||||
) {
|
||||
$timezone_string = $local_name;
|
||||
}
|
||||
if ( null === $timezone_string ) {
|
||||
$timezone_string = $date_timezone->get_default_timezone();
|
||||
}
|
||||
|
||||
if ( $timezone_string ) {
|
||||
$timezone = $this->_registry->get( 'date.system' )
|
||||
->get_gmt_offset_expr( $timezone_string );
|
||||
}
|
||||
|
||||
if ( empty( $timezone_name ) ) {
|
||||
/**
|
||||
* Actual Olsen timezone name is used when value is to be directly
|
||||
* exposed to user in some mean. It's possible to use named const.
|
||||
* `'sys.default'` only when passing value to date.time library.
|
||||
*/
|
||||
$timezone_name = $date_timezone->get_default_timezone();
|
||||
}
|
||||
|
||||
// This will store each of the accordion tabs' markup, and passed as an
|
||||
// argument to the final view.
|
||||
$boxes = array();
|
||||
$parent_event_id = null;
|
||||
if ( $event ) {
|
||||
$parent_event_id = $this->_registry->get( 'model.event.parent' )
|
||||
->event_parent( $event->get( 'post_id' ) );
|
||||
}
|
||||
// ===============================
|
||||
// = Display event time and date =
|
||||
// ===============================
|
||||
$args = array(
|
||||
'all_day_event' => $all_day_event,
|
||||
'instant_event' => $instant_event,
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'repeating_event' => $repeating_event,
|
||||
'rrule' => $rrule,
|
||||
'rrule_text' => $rrule_text,
|
||||
'exclude_event' => $exclude_event,
|
||||
'exrule' => $exrule,
|
||||
'exrule_text' => $exrule_text,
|
||||
'timezone' => $timezone,
|
||||
'timezone_string' => $timezone_string,
|
||||
'timezone_name' => $timezone_name,
|
||||
'exdate' => $exdate,
|
||||
'parent_event_id' => $parent_event_id,
|
||||
'instance_id' => $instance_id,
|
||||
'timezones_list' => $timezones_list,
|
||||
);
|
||||
|
||||
$boxes[] = $theme_loader
|
||||
->get_file( 'box_time_and_date.php', $args, true )
|
||||
->get_content();
|
||||
|
||||
// =================================================
|
||||
// = Display event location details and Google map =
|
||||
// =================================================
|
||||
$args = array(
|
||||
'select_venue' => apply_filters( 'ai1ec_admin_pre_venue_html', '' ),
|
||||
'save_venue' => apply_filters( 'ai1ec_admin_post_venue_html', '' ),
|
||||
'venue' => $venue,
|
||||
'country' => $country,
|
||||
'address' => $address,
|
||||
'city' => $city,
|
||||
'province' => $province,
|
||||
'postal_code' => $postal_code,
|
||||
'google_map' => $google_map,
|
||||
'show_map' => $show_map,
|
||||
'show_coordinates' => $show_coordinates,
|
||||
'longitude' => $longitude,
|
||||
'latitude' => $latitude,
|
||||
'coordinates' => $coordinates,
|
||||
);
|
||||
$boxes[] = $theme_loader
|
||||
->get_file( 'box_event_location.php', $args, true )
|
||||
->get_content();
|
||||
|
||||
// ===================================
|
||||
// = Display event ticketing options =
|
||||
// ===================================
|
||||
if ( $event ) {
|
||||
$cost_type = get_post_meta(
|
||||
$event->get( 'post_id' ),
|
||||
'_ai1ec_cost_type',
|
||||
true
|
||||
);
|
||||
if ( ! $cost_type ) {
|
||||
if ( $ticket_url || $cost ) {
|
||||
$cost_type = 'external';
|
||||
} else {
|
||||
$cost_type = 'free';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
$api_reg = $this->_registry->get( 'model.api.api-registration' );
|
||||
$ticketing = $api_reg->is_signed() && $api_reg->is_ticket_available() && $api_reg->is_ticket_enabled();
|
||||
$message = $api->get_sign_message();
|
||||
$ticket_error = null;
|
||||
$ticket_event_imported = false;
|
||||
$tickets = array( null );
|
||||
$tax_options = null;
|
||||
|
||||
if ( ! $api_reg->is_ticket_available() ) {
|
||||
$message = __(
|
||||
'Ticketing is currently not available for this website. Please, try again later.',
|
||||
AI1EC_PLUGIN_NAME
|
||||
);
|
||||
} else if ( ! $api_reg->is_ticket_enabled() ) {
|
||||
$message = __(
|
||||
'Timely Ticketing saves time & money. Create ticketing/registration right here and now. You do not pay any ticketing fees (other than regular PayPal transaction costs). Create as many ticketing/registration as you\'d like.<br /><br />Ticketing feature is not enabled for this website. Please sign up for Ticketing plan <a href="https://time.ly/tickets-existing-users/" target="_blank">here</a>.',
|
||||
AI1EC_PLUGIN_NAME
|
||||
);
|
||||
}
|
||||
|
||||
if ( $event ) {
|
||||
$is_ticket_event = ! is_null( $api->get_api_event_id( $event->get( 'post_id' ) ) );
|
||||
$ticket_event_account = $api->get_api_event_account( $event->get( 'post_id' ) );
|
||||
$ticket_event_imported = $api->is_ticket_event_imported( $event->get( 'post_id' ) );
|
||||
if ( $ticketing || $ticket_event_imported ) {
|
||||
if ( 'tickets' === $cost_type ) {
|
||||
if ( $ticket_event_imported ) {
|
||||
$response = json_decode( $api->get_ticket_types( $event->get( 'post_id' ) ) );
|
||||
if ( isset( $response->data ) && 0 < count( $response->data ) ) {
|
||||
$tickets = array_merge( $tickets, $response->data );
|
||||
}
|
||||
if ( isset( $response->error ) ) {
|
||||
$ticket_error = $response->error;
|
||||
}
|
||||
} else {
|
||||
$response = $api->get_event( $event->get( 'post_id' ) );
|
||||
if ( isset( $response->data ) && 0 < count( $response->data ) ) {
|
||||
$tickets = array_merge( $tickets, $response->data->ticket_types );
|
||||
$tax_options = $response->data->tax_options;
|
||||
}
|
||||
if ( isset( $response->error ) ) {
|
||||
$ticket_error = $response->error;
|
||||
}
|
||||
}
|
||||
}
|
||||
$uid = $event->get_uid();
|
||||
} else {
|
||||
$uid = $empty_event->get_uid();
|
||||
}
|
||||
$uid = $event->get_uid();
|
||||
} else {
|
||||
$is_ticket_event = false;
|
||||
$ticket_event_account = '';
|
||||
$uid = $empty_event->get_uid();
|
||||
}
|
||||
|
||||
if ( $ticketing ) {
|
||||
if ( $event ) {
|
||||
$ticket_currency = $api->get_api_event_currency( $event->get( 'post_id' ) );
|
||||
if ( $api->is_ticket_event_from_another_account( $event->get( 'post_id' ) ) ) {
|
||||
$ticket_error = sprintf(
|
||||
__( 'This Event was created using a different account %s. Changes are not allowed.', AI1EC_PLUGIN_NAME ),
|
||||
$api->get_api_event_account( $event->get( 'post_id' ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
if ( ! isset( $ticket_currency ) || is_null( $ticket_currency ) ) {
|
||||
//for new ticket events get the currency from the payments settings
|
||||
$payments_settings = $api->get_payment_settings();
|
||||
if ( null !== $payments_settings ) {
|
||||
$ticket_currency = $payments_settings['currency'];
|
||||
} else {
|
||||
$ticket_currency = 'USD';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$ticket_currency = '';
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'cost' => $cost,
|
||||
'cost_type' => $cost_type,
|
||||
'ticket_url' => $ticket_url,
|
||||
'event' => $empty_event,
|
||||
'uid' => $uid,
|
||||
'tickets' => $tickets,
|
||||
'ticketing' => $ticketing,
|
||||
'valid_payout_details' => $api->has_payment_settings(),
|
||||
'tickets_message' => $message,
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'tickets_loading_error' => $ticket_error,
|
||||
'ticket_event_imported' => $ticket_event_imported,
|
||||
'is_free' => $is_free,
|
||||
'ticket_currency' => $ticket_currency,
|
||||
'is_ticket_event' => $is_ticket_event,
|
||||
'ticket_event_account' => $ticket_event_account,
|
||||
'tax_options' => $tax_options
|
||||
);
|
||||
|
||||
$boxes[] = $theme_loader
|
||||
->get_file( 'box_event_cost.php', $args, true )
|
||||
->get_content();
|
||||
|
||||
|
||||
|
||||
// =========================================
|
||||
// = Display organizer contact information =
|
||||
// =========================================
|
||||
$submitter_html = null;
|
||||
if ( $event ) {
|
||||
$submitter_info = $event->get_submitter_info();
|
||||
if ( null !== $submitter_info ) {
|
||||
if ( 1 === $submitter_info['is_organizer'] ) {
|
||||
$submitter_html = Ai1ec_I18n::__( '<span class="ai1ec-info-text">The event was submitted by this Organizer.</span>' );
|
||||
} else if ( isset( $submitter_info['email'] ) ||
|
||||
isset( $submitter_info['name'] ) ) {
|
||||
$submitted_by = '';
|
||||
if ( false === ai1ec_is_blank ( $submitter_info['name'] ) ) {
|
||||
$submitted_by = sprintf( '<strong>%s</strong>', htmlspecialchars( $submitter_info['name'] ) );
|
||||
}
|
||||
if ( false === ai1ec_is_blank( $submitter_info['email'] ) ) {
|
||||
if ( '' !== $submitted_by ) {
|
||||
$submitted_by .= Ai1ec_I18n::__( ', email: ' );
|
||||
}
|
||||
$submitted_by .= sprintf( '<a href="mailto:%s" target="_top">%s</a>', $submitter_info['email'], $submitter_info['email'] ) ;
|
||||
}
|
||||
$submitter_html = sprintf( Ai1ec_I18n::__( '<span class="ai1ec-info-text">The event was submitted by %s.</span>' ),
|
||||
$submitted_by
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
$args = array(
|
||||
'contact_name' => $contact_name,
|
||||
'contact_phone' => $contact_phone,
|
||||
'contact_email' => $contact_email,
|
||||
'contact_url' => $contact_url,
|
||||
'event' => $empty_event,
|
||||
'submitter_html' => $submitter_html
|
||||
);
|
||||
$boxes[] = $theme_loader
|
||||
->get_file( 'box_event_contact.php', $args, true )
|
||||
->get_content();
|
||||
|
||||
// ==========================
|
||||
// = Parent/Child relations =
|
||||
// ==========================
|
||||
if ( $event ) {
|
||||
$parent = $this->_registry->get( 'model.event.parent' )
|
||||
->get_parent_event( $event->get( 'post_id' ) );
|
||||
if ( $parent ) {
|
||||
try {
|
||||
$parent = $this->_registry->get( 'model.event', $parent );
|
||||
} catch ( Ai1ec_Event_Not_Found_Exception $exception ) { // ignore
|
||||
$parent = null;
|
||||
}
|
||||
}
|
||||
if ( $parent ) {
|
||||
$children = $this->_registry->get( 'model.event.parent' )
|
||||
->get_child_event_objects( $event->get( 'post_id' ) );
|
||||
$args = compact( 'parent', 'children' );
|
||||
$args['registry'] = $this->_registry;
|
||||
|
||||
$boxes[] = $theme_loader->get_file(
|
||||
'box_event_children.php',
|
||||
$args,
|
||||
true
|
||||
)->get_content();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$boxes = apply_filters( 'ai1ec_add_new_event_boxes', $boxes, $event );
|
||||
// Display the final view of the meta box.
|
||||
$args = array(
|
||||
'boxes' => $boxes,
|
||||
);
|
||||
|
||||
if ( $this->_is_post_event( $post ) ) {
|
||||
// ======================
|
||||
// = Display Box Review =
|
||||
// ======================
|
||||
$review = $this->_registry->get( 'model.review' );
|
||||
$review_content = $review->get_content( $theme_loader );
|
||||
|
||||
if ( false === ai1ec_is_blank( $review_content ) ) {
|
||||
$args['review_box'] = $review_content;
|
||||
}
|
||||
}
|
||||
|
||||
echo $theme_loader
|
||||
->get_file( 'add_new_event_meta_box.php', $args, true )
|
||||
->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Banner Image meta box to the Add/Edit Event.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function banner_meta_box_view( $post ) {
|
||||
$banner_image_meta = get_post_meta( $post->ID, 'ai1ec_banner_image' );
|
||||
$theme_loader = $this->_registry->get( 'theme.loader' );
|
||||
$args = array(
|
||||
'src' => $banner_image_meta && $banner_image_meta[0]
|
||||
? $banner_image_meta[0] : false,
|
||||
'set_text' => Ai1ec_I18n::__( 'Set banner image' ),
|
||||
'remove_text' => Ai1ec_I18n::__( 'Remove banner image' ),
|
||||
|
||||
);
|
||||
echo $theme_loader
|
||||
->get_file( 'banner-image.twig', $args, true )
|
||||
->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* disable_autosave method
|
||||
*
|
||||
* Callback to disable autosave script
|
||||
*
|
||||
* @param array $input List of scripts registered
|
||||
*
|
||||
* @return array Modified scripts list
|
||||
*/
|
||||
public function disable_autosave( array $input ) {
|
||||
wp_deregister_script( 'autosave' );
|
||||
$autosave_key = array_search( 'autosave', $input );
|
||||
if ( false === $autosave_key || ! is_scalar( $autosave_key ) ) {
|
||||
unset( $input[$autosave_key] );
|
||||
}
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders Bootstrap inline alert.
|
||||
*
|
||||
* @param WP_Post $post Post object.
|
||||
*
|
||||
* @return void Method does not return.
|
||||
*/
|
||||
public function event_inline_alert( $post ) {
|
||||
if ( $this->_is_post_event( $post ) ) {
|
||||
$theme_loader = $this->_registry->get( 'theme.loader' );
|
||||
echo $theme_loader->get_file( 'box_inline_warning.php', null, true )
|
||||
->get_content();
|
||||
}
|
||||
}
|
||||
|
||||
private function _is_post_event( $post ) {
|
||||
return isset( $post->post_type ) && AI1EC_POST_TYPE === $post->post_type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The Calendar Add-ons page.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.1
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Add_Ons extends Ai1ec_View_Admin_Abstract {
|
||||
/**
|
||||
* Adds page to the menu.
|
||||
*
|
||||
* @wp_hook admin_menu
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_page() {
|
||||
// =======================
|
||||
// = Calendar Add Ons Page =
|
||||
// =======================
|
||||
add_submenu_page(
|
||||
AI1EC_ADMIN_BASE_URL,
|
||||
Ai1ec_I18n::__( 'Add-ons' ),
|
||||
Ai1ec_I18n::__( 'Add-ons' ),
|
||||
'manage_ai1ec_feeds',
|
||||
AI1EC_PLUGIN_NAME . '-add-ons',
|
||||
array( $this, 'display_page' )
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Display Add Ons list page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_page() {
|
||||
wp_enqueue_style(
|
||||
'ai1ec_addons.css',
|
||||
AI1EC_ADMIN_THEME_CSS_URL . 'addons.css',
|
||||
array(),
|
||||
AI1EC_VERSION
|
||||
);
|
||||
$content = get_site_transient( 'ai1ec_timely_addons' );
|
||||
$is_error = false;
|
||||
if (
|
||||
false === $content ||
|
||||
(
|
||||
defined( 'AI1EC_DEBUG' ) &&
|
||||
AI1EC_DEBUG
|
||||
)
|
||||
) {
|
||||
$is_error = true;
|
||||
$feed = wp_remote_get( AI1EC_TIMELY_ADDONS_URI );
|
||||
if ( ! is_wp_error( $feed ) ) {
|
||||
$content = json_decode( wp_remote_retrieve_body( $feed ) );
|
||||
if ( null !== $content ) {
|
||||
set_site_transient( 'ai1ec_timely_addons', $content, 3600 );
|
||||
$is_error = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->_registry->get( 'theme.loader' )->get_file(
|
||||
'add-ons-list/page.twig',
|
||||
array(
|
||||
'labels' => array(
|
||||
'title' => Ai1ec_I18n::__(
|
||||
'Add-ons for All In One Event Calendar'
|
||||
),
|
||||
'button_title' => Ai1ec_I18n::__(
|
||||
'Browse All Add-ons'
|
||||
),
|
||||
'paragraph_content' => Ai1ec_I18n::__(
|
||||
'These add-ons extend the functionality of the All-in-One Event Calendar.'
|
||||
),
|
||||
'error' => Ai1ec_I18n::__(
|
||||
'There was an error retrieving the extensions list from the server. Please try again later.'
|
||||
),
|
||||
),
|
||||
'content' => $content,
|
||||
'is_error' => $is_error,
|
||||
),
|
||||
true
|
||||
)->render();
|
||||
}
|
||||
|
||||
public function add_meta_box() {
|
||||
}
|
||||
|
||||
public function display_meta_box( $object, $box ) {
|
||||
}
|
||||
|
||||
public function handle_post() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,260 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Ai1ec_View_Admin_All_Events extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* change_columns function
|
||||
*
|
||||
* Adds Event date/time column to our custom post type
|
||||
* and renames Date column to Post Date
|
||||
*
|
||||
* @param array $columns Existing columns
|
||||
*
|
||||
* @return array Updated columns array
|
||||
*/
|
||||
public function change_columns( array $columns = array() ) {
|
||||
$columns['author'] = __( 'Author', AI1EC_PLUGIN_NAME );
|
||||
$columns['date'] = __( 'Post Date', AI1EC_PLUGIN_NAME );
|
||||
$columns['ai1ec_event_date'] = __( 'Event date/time', AI1EC_PLUGIN_NAME );
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
if ( $api->is_signed() ) {
|
||||
$columns['tickets'] = __( 'Ticket Types', AI1EC_PLUGIN_NAME );
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* orderby function
|
||||
*
|
||||
* Orders events by event date
|
||||
*
|
||||
* @param string $orderby Orderby sql
|
||||
* @param object $wp_query
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
public function orderby( $orderby, $wp_query ) {
|
||||
|
||||
$db = $this->_registry->get( 'dbi.dbi' );
|
||||
$aco = $this->_registry->get( 'acl.aco' );
|
||||
|
||||
if( true === $aco->is_all_events_page() ) {
|
||||
$wp_query->query = wp_parse_args( $wp_query->query );
|
||||
$table_name = $db->get_table_name( 'ai1ec_events' );
|
||||
$posts = $db->get_table_name( 'posts' );
|
||||
if( isset( $wp_query->query['orderby'] ) && 'ai1ec_event_date' === @$wp_query->query['orderby'] ) {
|
||||
$orderby = "(SELECT start FROM {$table_name} WHERE post_id = {$posts}.ID) " . $wp_query->get('order');
|
||||
} else if( empty( $wp_query->query['orderby'] ) || $wp_query->query['orderby'] === 'menu_order title' ) {
|
||||
$orderby = "(SELECT start FROM {$table_name} WHERE post_id = {$posts}.ID) " . 'desc';
|
||||
}
|
||||
}
|
||||
return $orderby;
|
||||
}
|
||||
|
||||
/**
|
||||
* custom_columns function
|
||||
*
|
||||
* Adds content for custom columns
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
public function custom_columns( $column, $post_id ) {
|
||||
if ( 'ai1ec_event_date' === $column ) {
|
||||
try {
|
||||
$event = $this->_registry->get( 'model.event', $post_id );
|
||||
$time = $this->_registry->get( 'view.event.time' );
|
||||
echo $time->get_timespan_html( $event );
|
||||
} catch ( Exception $e ) {
|
||||
// event wasn't found, output empty string
|
||||
echo '';
|
||||
}
|
||||
} else if ( 'tickets' === $column ) {
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
if ( $api->is_ticket_event_imported( $post_id ) ) {
|
||||
echo '';
|
||||
} else {
|
||||
try {
|
||||
$event = $this->_registry->get( 'model.event', $post_id );
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
$api_event_id = $api->get_api_event_id( $post_id );
|
||||
if ( $api_event_id ) {
|
||||
echo '<a href="#" class="ai1ec-has-tickets" data-post-id="'
|
||||
. $post_id . '">'
|
||||
. __( 'Ticketing Details', AI1EC_PLUGIN_NAME ) . '</a>';
|
||||
}
|
||||
|
||||
} catch ( Exception $e ) {
|
||||
// event wasn't found, output empty string
|
||||
echo '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sortable_columns function
|
||||
*
|
||||
* Enable sorting of columns
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
public function sortable_columns( $columns ) {
|
||||
$columns['ai1ec_event_date'] = 'ai1ec_event_date';
|
||||
$columns['author'] = 'author';
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* taxonomy_filter_restrict_manage_posts function
|
||||
*
|
||||
* Adds filter dropdowns for event categories and event tags.
|
||||
* Adds filter dropdowns for event authors.
|
||||
*
|
||||
* @uses wp_dropdown_users To create a dropdown with current user selected.
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
function taxonomy_filter_restrict_manage_posts() {
|
||||
global $typenow;
|
||||
|
||||
// =============================================
|
||||
// = add the dropdowns only on the events page =
|
||||
// =============================================
|
||||
if( $typenow === AI1EC_POST_TYPE ) {
|
||||
$filters = get_object_taxonomies( $typenow );
|
||||
foreach( $filters as $tax_slug ) {
|
||||
$tax_obj = get_taxonomy( $tax_slug );
|
||||
wp_dropdown_categories( array(
|
||||
'show_option_all' => __( 'Show All ', AI1EC_PLUGIN_NAME ) . $tax_obj->label,
|
||||
'taxonomy' => $tax_slug,
|
||||
'name' => $tax_obj->name,
|
||||
'orderby' => 'name',
|
||||
'selected' => isset( $_GET[$tax_slug] ) ? $_GET[$tax_slug] : '',
|
||||
'hierarchical' => $tax_obj->hierarchical,
|
||||
'show_count' => true,
|
||||
'hide_if_empty' => true,
|
||||
'value_field' => 'slug',
|
||||
));
|
||||
}
|
||||
$args = array(
|
||||
'name' => 'author',
|
||||
'show_option_all' => __( 'Show All Authors', AI1EC_PLUGIN_NAME ),
|
||||
);
|
||||
if ( isset( $_GET['user'] ) ) {
|
||||
$args['selected'] = (int)$_GET['user'];
|
||||
}
|
||||
wp_dropdown_users($args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* taxonomy_filter_post_type_request function
|
||||
*
|
||||
* Adds filtering of events list by event tags and event categories
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
public function taxonomy_filter_post_type_request( $query ) {
|
||||
global $pagenow, $typenow;
|
||||
if( 'edit.php' === $pagenow ) {
|
||||
$filters = get_object_taxonomies( $typenow );
|
||||
foreach( $filters as $tax_slug ) {
|
||||
$var = &$query->query_vars[$tax_slug];
|
||||
if( isset( $var ) ) {
|
||||
$term = null;
|
||||
|
||||
if( is_numeric( $var ) ) {
|
||||
$term = get_term_by( 'id', $var, $tax_slug );
|
||||
} else {
|
||||
$term = get_term_by( 'slug', $var, $tax_slug );
|
||||
}
|
||||
|
||||
if( isset( $term->slug ) ) {
|
||||
$var = $term->slug;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ===========================
|
||||
// = Order by Event date ASC =
|
||||
// ===========================
|
||||
if( 'ai1ec_event' === $typenow ) {
|
||||
if ( ! array_key_exists( 'orderby', $query->query_vars ) ) {
|
||||
$query->query_vars['orderby'] = 'ai1ec_event_date';
|
||||
$query->query_vars['order'] = 'desc';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CSS and templates files needed for ticketing.
|
||||
*/
|
||||
public function add_ticketing_styling() {
|
||||
// Add CSS
|
||||
$this->_registry->get( 'css.admin' )->admin_enqueue_scripts(
|
||||
'ai1ec_event_page_all-in-one-event-calendar-settings'
|
||||
);
|
||||
$this->_registry->get( 'css.admin' )->process_enqueue(
|
||||
array(
|
||||
array( 'style', 'ticketing.css', ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ticket details by Event id.
|
||||
*/
|
||||
public function show_ticket_details() {
|
||||
$post_id = $_POST['ai1ec_event_id'];
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
if ( $api->is_ticket_event_from_another_account( $post_id ) ) {
|
||||
$tickets = json_encode(
|
||||
array( 'data' => array(), 'error' =>
|
||||
sprintf(
|
||||
__( 'This Event was created using a different account %s. Changes are not allowed.', AI1EC_PLUGIN_NAME ),
|
||||
$api->get_api_event_account( $post_id )
|
||||
)
|
||||
) );
|
||||
} else {
|
||||
$tickets = $api->get_ticket_types( $post_id );
|
||||
}
|
||||
echo $tickets;
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attendees list.
|
||||
*/
|
||||
public function show_attendees() {
|
||||
$post_id = $_POST['ai1ec_event_id'];
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
$tickets = $api->get_tickets( $post_id );
|
||||
echo $tickets;
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* count_future_events function
|
||||
*
|
||||
* @return Count future events
|
||||
**/
|
||||
public function count_future_events( $user_id = null ) {
|
||||
if ( is_admin() ) {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$current_time = $this->_registry->get( 'date.time' );
|
||||
$current_time->set_timezone( $settings->get( 'timezone_string' ) );
|
||||
$current_time = $current_time->format_to_gmt();
|
||||
$user_id = get_current_user_id();
|
||||
$where = get_posts_by_author_sql( AI1EC_POST_TYPE, true, $user_id );
|
||||
$db = $this->_registry->get( 'dbi.dbi' );
|
||||
$posts = $db->get_table_name( 'posts' );
|
||||
$table_name = $db->get_table_name( 'ai1ec_events' );
|
||||
$sql = "SELECT COUNT(*) FROM $table_name INNER JOIN $posts on $table_name.post_id = {$posts}.ID"
|
||||
. " $where AND $table_name.start > $current_time"; //future event
|
||||
return $db->get_var( $sql );
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The Calendar Feeds page.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Calendar_Feeds extends Ai1ec_View_Admin_Abstract {
|
||||
|
||||
/**
|
||||
* Adds page to the menu.
|
||||
*
|
||||
* @wp_hook admin_menu
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_page() {
|
||||
// =======================
|
||||
// = Calendar Feeds Page =
|
||||
// =======================
|
||||
$calendar_feeds = add_submenu_page(
|
||||
AI1EC_ADMIN_BASE_URL,
|
||||
Ai1ec_I18n::__( 'Import Feeds' ),
|
||||
Ai1ec_I18n::__( 'Import Feeds' ),
|
||||
'manage_ai1ec_feeds',
|
||||
AI1EC_PLUGIN_NAME . '-feeds',
|
||||
array( $this, 'display_page' )
|
||||
);
|
||||
$this->_registry->get( 'model.settings' )
|
||||
->set( 'feeds_page', $calendar_feeds );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds metabox to the page.
|
||||
*
|
||||
* @wp_hook admin_init
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_meta_box() {
|
||||
// Add the 'ICS Import Settings' meta box.
|
||||
add_meta_box(
|
||||
'ai1ec-feeds',
|
||||
Ai1ec_I18n::_x( 'Feed Subscriptions', 'meta box' ),
|
||||
array( $this, 'display_meta_box' ),
|
||||
$this->_registry->get( 'model.settings' )->get( 'feeds_page' ),
|
||||
'left',
|
||||
'default'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display this plugin's feeds page in the admin.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_page() {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$args = array(
|
||||
'title' => __(
|
||||
'All-in-One Event Calendar: Import Feeds',
|
||||
AI1EC_PLUGIN_NAME
|
||||
),
|
||||
'settings_page' => $settings->get( 'feeds_page' ),
|
||||
'calendar_settings' => false,
|
||||
);
|
||||
$file = $loader->get_file( 'feeds_settings.php', $args, true );
|
||||
wp_enqueue_style(
|
||||
'ai1ec_samples.css',
|
||||
AI1EC_ADMIN_THEME_CSS_URL . 'samples.css',
|
||||
array(),
|
||||
AI1EC_VERSION
|
||||
);
|
||||
$file->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the contents of the Calendar Feeds meta box.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_meta_box( $object, $box ) {
|
||||
// register the calendar feeds page.
|
||||
$calendar_feeds = $this->_registry->get( 'controller.calendar-feeds' );
|
||||
$feeds = array();
|
||||
|
||||
array_push( $feeds, $this->_registry->get( 'calendar-feed.import' ) );
|
||||
// Check for user subscription - Discover events
|
||||
if ($this->_api_registration->has_subscription_active( 'discover-events' ) ) {
|
||||
array_push( $feeds, $this->_registry->get( 'calendar-feed.suggested' ) );
|
||||
}
|
||||
|
||||
// Add ICS
|
||||
array_push( $feeds, $this->_registry->get( 'calendar-feed.ics' ) );
|
||||
|
||||
$feeds = apply_filters( 'ai1ec_calendar_feeds', $feeds );
|
||||
foreach ( $feeds as $feed ) {
|
||||
$calendar_feeds->add_plugin( $feed );
|
||||
}
|
||||
$calendar_feeds->handle_feeds_page_post();
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$file = $loader->get_file(
|
||||
'box_feeds.php',
|
||||
array( 'calendar_feeds' => $calendar_feeds ),
|
||||
true
|
||||
);
|
||||
$file->render();
|
||||
}
|
||||
|
||||
public function handle_post() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Event category admin view snippets renderer.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Admin
|
||||
*/
|
||||
class Ai1ec_View_Admin_EventCategory extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Inserts Color element at index 2 of columns array
|
||||
*
|
||||
* @param array $columns Array with event_category columns
|
||||
*
|
||||
* @return array Array with event_category columns where Color is inserted
|
||||
* at index 2
|
||||
*/
|
||||
public function manage_event_categories_columns( $columns ) {
|
||||
wp_enqueue_media();
|
||||
$this->_registry->get( 'css.admin' )
|
||||
->process_enqueue( array(
|
||||
array( 'style', 'bootstrap.min.css' )
|
||||
) );
|
||||
return array_splice( $columns, 0, 3 ) + // get only first element
|
||||
// insert at index 2
|
||||
array( 'cat_color' => __( 'Color', AI1EC_PLUGIN_NAME ) ) +
|
||||
// insert at index 3
|
||||
array( 'cat_image' => __( 'Image', AI1EC_PLUGIN_NAME ) ) +
|
||||
// insert rest of elements at the back
|
||||
array_splice( $columns, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color or image of the event category.
|
||||
*
|
||||
* That will be displayed on event category lists page in the backend.
|
||||
*
|
||||
* @param $not_set
|
||||
* @param $column_name
|
||||
* @param $term_id
|
||||
* @internal param array $columns Array with event_category columns
|
||||
*
|
||||
* @return array Array with event_category columns where Color is inserted
|
||||
* at index 2
|
||||
*/
|
||||
public function manage_events_categories_custom_column(
|
||||
$not_set,
|
||||
$column_name,
|
||||
$term_id
|
||||
) {
|
||||
switch ( $column_name ) {
|
||||
case 'cat_color':
|
||||
return $this->_registry->get( 'view.event.taxonomy' )
|
||||
->get_category_color_square( $term_id );
|
||||
case 'cat_image':
|
||||
return $this->_registry->get( 'view.event.taxonomy' )
|
||||
->get_category_image_square( $term_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to process event categories creation
|
||||
*
|
||||
* @param $term_id
|
||||
*
|
||||
* @return void Method does not return.
|
||||
*/
|
||||
public function created_events_categories( $term_id ) {
|
||||
$this->edited_events_categories( $term_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback method, triggered when `event_categories' are being edited.
|
||||
*
|
||||
* @param int $term_id ID of term (category) being edited.
|
||||
*
|
||||
* @return void Method does not return.
|
||||
*/
|
||||
public function edited_events_categories( $term_id ) {
|
||||
if ( isset( $_POST['_inline_edit'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tag_color_value = '';
|
||||
if ( ! empty( $_POST['tag-color-value'] ) ) {
|
||||
$tag_color_value = (string)$_POST['tag-color-value'];
|
||||
}
|
||||
$tag_image_value = '';
|
||||
if ( ! empty( $_POST['ai1ec_category_image_url'] ) ) {
|
||||
$tag_image_value = (string)$_POST['ai1ec_category_image_url'];
|
||||
}
|
||||
if ( isset( $_POST['ai1ec_category_image_url_remove'] ) ) {
|
||||
$tag_image_value = null;
|
||||
}
|
||||
|
||||
$db = $this->_registry->get( 'dbi.dbi' );
|
||||
$table_name = $db->get_table_name( 'ai1ec_event_category_meta' );
|
||||
$term = $db->get_row( $db->prepare(
|
||||
'SELECT term_id FROM ' . $table_name .
|
||||
' WHERE term_id = %d',
|
||||
$term_id
|
||||
) );
|
||||
|
||||
if ( null === $term ) { // term does not exist, create it
|
||||
$db->insert(
|
||||
$table_name,
|
||||
array(
|
||||
'term_id' => $term_id,
|
||||
'term_color' => $tag_color_value,
|
||||
'term_image' => $tag_image_value,
|
||||
),
|
||||
array(
|
||||
'%d',
|
||||
'%s',
|
||||
'%s',
|
||||
)
|
||||
);
|
||||
} else { // term exist, update it
|
||||
$db->update(
|
||||
$table_name,
|
||||
array(
|
||||
'term_color' => $tag_color_value,
|
||||
'term_image' => $tag_image_value
|
||||
),
|
||||
array( 'term_id' => $term_id ),
|
||||
array( '%s', '%s' ),
|
||||
array( '%d' )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function show_color( $term = null ) {
|
||||
|
||||
$taxonomy = $this->_registry->get( 'model.taxonomy' );
|
||||
$color = '';
|
||||
if ( null !== $term ) {
|
||||
$color = $taxonomy->get_category_color( $term->term_id );
|
||||
}
|
||||
|
||||
$style = '';
|
||||
$clr = '';
|
||||
|
||||
if ( $color ) {
|
||||
$style = 'style="background-color: ' . $color . '"';
|
||||
$clr = $color;
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'style' => $style,
|
||||
'color' => $clr,
|
||||
'label' => Ai1ec_I18n::__( 'Category Color' ),
|
||||
'description' => Ai1ec_I18n::__(
|
||||
'Events in this category will be identified by this color'
|
||||
),
|
||||
'edit' => true,
|
||||
);
|
||||
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$loader->get_file(
|
||||
'setting/categories-color-picker.twig',
|
||||
$args,
|
||||
true
|
||||
)->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit category form
|
||||
*
|
||||
* @param $term
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function events_categories_edit_form_fields( $term ) {
|
||||
$this->show_color( $term );
|
||||
$taxonomy = $this->_registry->get( 'model.taxonomy' );
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$image = $taxonomy->get_category_image( $term->term_id );
|
||||
|
||||
$style = 'style="display:none"';
|
||||
|
||||
if ( null !== $image ) {
|
||||
$style = '';
|
||||
}
|
||||
|
||||
// Category image
|
||||
$args = array(
|
||||
'image_src' => $image,
|
||||
'image_style' => $style,
|
||||
'section_name' => __( 'Category Image', AI1EC_PLUGIN_NAME ),
|
||||
'label' => __( 'Add Image', AI1EC_PLUGIN_NAME ),
|
||||
'remove_label' => __( 'Remove Image', AI1EC_PLUGIN_NAME ),
|
||||
'description' => __(
|
||||
'Assign an optional image to the category. Recommended size: square, minimum 400×400 pixels.',
|
||||
AI1EC_PLUGIN_NAME
|
||||
),
|
||||
'edit' => true,
|
||||
);
|
||||
|
||||
$loader->get_file(
|
||||
'setting/categories-image.twig',
|
||||
$args,
|
||||
true
|
||||
)->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add category form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function events_categories_add_form_fields() {
|
||||
|
||||
$this->show_color();
|
||||
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
|
||||
// Category image
|
||||
$args = array(
|
||||
'image_src' => '',
|
||||
'image_style' => 'style="display:none"',
|
||||
'section_name' => __( 'Category Image', AI1EC_PLUGIN_NAME ),
|
||||
'label' => __( 'Add Image', AI1EC_PLUGIN_NAME),
|
||||
'description' => __( 'Assign an optional image to the category. Recommended size: square, minimum 400×400 pixels.', AI1EC_PLUGIN_NAME ),
|
||||
'edit' => false,
|
||||
);
|
||||
|
||||
$file = $loader->get_file(
|
||||
'setting/categories-image.twig',
|
||||
$args,
|
||||
true
|
||||
);
|
||||
|
||||
$file->render();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,670 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The get repeat box snippet.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Admin_Get_repeat_Box extends Ai1ec_Base {
|
||||
/**
|
||||
* get_repeat_box function
|
||||
*
|
||||
* @return string
|
||||
**/
|
||||
public function get_repeat_box() {
|
||||
$time_system = $this->_registry->get( 'date.system' );
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$repeat = (int) $_REQUEST["repeat"];
|
||||
$repeat = $repeat == 1 ? 1 : 0;
|
||||
$post_id = (int) $_REQUEST["post_id"];
|
||||
$count = 100;
|
||||
$end = 0;
|
||||
$until = $time_system->current_time( true );
|
||||
|
||||
// try getting the event
|
||||
try {
|
||||
$event = $this->_registry->get( 'model.event', $post_id );
|
||||
$rule = '';
|
||||
|
||||
if ( $repeat ) {
|
||||
$rule = $event->get( 'recurrence_rules' )
|
||||
? $event->get( 'recurrence_rules' )
|
||||
: '';
|
||||
} else {
|
||||
$rule = $event->get( 'exception_rules' ) ?
|
||||
$event->get( 'exception_rules' )
|
||||
: '';
|
||||
}
|
||||
|
||||
$rule = $this->_registry->get( 'recurrence.rule' )->filter_rule( $rule );
|
||||
|
||||
$rc = new SG_iCal_Recurrence(
|
||||
new SG_iCal_Line( 'RRULE:' . $rule )
|
||||
);
|
||||
|
||||
if ( $until = $rc->getUntil() ) {
|
||||
$until = ( is_numeric( $until ) )
|
||||
? $until
|
||||
: strtotime( $until );
|
||||
$end = 2;
|
||||
} elseif ( $count = $rc->getCount() ) {
|
||||
$count = ( is_numeric( $count ) ) ? $count : 100;
|
||||
$end = 1;
|
||||
}
|
||||
} catch( Ai1ec_Event_Not_Found_Exception $e ) {
|
||||
$rule = '';
|
||||
$rc = new SG_iCal_Recurrence(
|
||||
new SG_iCal_Line( 'RRULE:' )
|
||||
);
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'row_daily' => $this->row_daily(
|
||||
false,
|
||||
$rc->getInterval() ? $rc->getInterval() : 1
|
||||
),
|
||||
'row_weekly' => $this->row_weekly(
|
||||
false,
|
||||
$rc->getInterval() ? $rc->getInterval() : 1,
|
||||
is_array( $rc->getByDay() ) ? $rc->getByDay() : array()
|
||||
),
|
||||
'row_monthly' => $this->row_monthly(
|
||||
false,
|
||||
$rc->getInterval() ? $rc->getInterval() : 1,
|
||||
! $this->_is_monthday_empty( $rc ),
|
||||
$rc->getByMonthDay() ? $rc->getByMonthDay() : array(),
|
||||
$rc->getByDay() ? $rc->getByDay() : array()
|
||||
),
|
||||
'row_yearly' => $this->row_yearly(
|
||||
false,
|
||||
$rc->getInterval() ? $rc->getInterval() : 1,
|
||||
is_array( $rc->getByMonth() ) ? $rc->getByMonth() : array()
|
||||
),
|
||||
'row_custom' => $this->row_custom(
|
||||
false,
|
||||
$this->get_date_array_from_rule( $rule )
|
||||
),
|
||||
'count' => $this->create_count_input(
|
||||
'ai1ec_count',
|
||||
$count
|
||||
) . Ai1ec_I18n::__( 'times' ),
|
||||
'end' => $this->create_end_dropdown( $end ),
|
||||
'until' => $until,
|
||||
'repeat' => $repeat,
|
||||
'ending_type' => $end,
|
||||
'selected_tab' => $rc->getFreq()
|
||||
? strtolower( $rc->getFreq() )
|
||||
: 'custom',
|
||||
);
|
||||
$output = array(
|
||||
'error' => false,
|
||||
'message' => $loader->get_file(
|
||||
'box_repeat.php',
|
||||
$args,
|
||||
true
|
||||
)->get_content(),
|
||||
'repeat' => $repeat,
|
||||
);
|
||||
$json_strategy = $this->_registry->get( 'http.response.render.strategy.json' );
|
||||
$json_strategy->render( array( 'data' => $output ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* get_weekday_by_id function
|
||||
*
|
||||
* Returns weekday name in English
|
||||
*
|
||||
* @param int $day_id Day ID
|
||||
*
|
||||
* @return string
|
||||
**/
|
||||
public function get_weekday_by_id( $day_id, $by_value = false ) {
|
||||
// do not translate this !!!
|
||||
$week_days = array(
|
||||
0 => 'SU',
|
||||
1 => 'MO',
|
||||
2 => 'TU',
|
||||
3 => 'WE',
|
||||
4 => 'TH',
|
||||
5 => 'FR',
|
||||
6 => 'SA',
|
||||
);
|
||||
|
||||
if ( $by_value ) {
|
||||
while ( $_name = current( $week_days ) ) {
|
||||
if ( $_name == $day_id ) {
|
||||
return key( $week_days );
|
||||
}
|
||||
next( $week_days );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return $week_days[$day_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* convert_rrule_to_text method
|
||||
*
|
||||
* Convert a `recurrence rule' to text to display it on screen
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
public function convert_rrule_to_text() {
|
||||
$error = false;
|
||||
$message = '';
|
||||
// check to see if RRULE is set
|
||||
if ( isset( $_REQUEST['rrule'] ) ) {
|
||||
// check to see if rrule is empty
|
||||
if ( empty( $_REQUEST['rrule'] ) ) {
|
||||
$error = true;
|
||||
$message = Ai1ec_I18n::__(
|
||||
'Recurrence rule cannot be empty.'
|
||||
);
|
||||
} else {
|
||||
//list( $rule, $value ) = explode( '=', $_REQUEST['rrule'], 2 );
|
||||
//if ( in_array( array(), $rule ) ) {
|
||||
// $message = $this->_registry->get( 'recurrence.date' );
|
||||
//
|
||||
//} else {
|
||||
$rrule = $this->_registry->get( 'recurrence.rule' );
|
||||
// convert rrule to text
|
||||
$message = ucfirst(
|
||||
$rrule->rrule_to_text( $_REQUEST['rrule'] )
|
||||
);
|
||||
//}
|
||||
}
|
||||
} else {
|
||||
$error = true;
|
||||
$message = Ai1ec_I18n::__(
|
||||
'Recurrence rule was not provided.'
|
||||
);
|
||||
}
|
||||
$output = array(
|
||||
'error' => $error,
|
||||
'message' => get_magic_quotes_gpc()
|
||||
? stripslashes( $message )
|
||||
: $message,
|
||||
);
|
||||
|
||||
$json_strategy = $this->_registry->get( 'http.response.render.strategy.json' );
|
||||
$json_strategy->render( array( 'data' => $output ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* create_end_dropdown function
|
||||
*
|
||||
* Outputs the dropdown list for the recurrence end option.
|
||||
*
|
||||
* @param int $selected The index of the selected option, if any
|
||||
* @return void
|
||||
**/
|
||||
protected function create_end_dropdown( $selected = NULL ) {
|
||||
ob_start();
|
||||
|
||||
$options = array(
|
||||
0 => Ai1ec_I18n::__( 'Never' ),
|
||||
1 => Ai1ec_I18n::__( 'After' ),
|
||||
2 => Ai1ec_I18n::__( 'On date' ),
|
||||
);
|
||||
|
||||
?>
|
||||
<select name="ai1ec_end" id="ai1ec_end">
|
||||
<?php foreach( $options as $key => $val ): ?>
|
||||
<option value="<?php echo $key ?>"
|
||||
<?php if( $key === $selected ) echo 'selected="selected"' ?>>
|
||||
<?php echo $val ?>
|
||||
</option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
<?php
|
||||
|
||||
$output = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* row_daily function
|
||||
*
|
||||
* Returns daily selector
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
protected function row_daily( $visible = false, $selected = 1 ) {
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
|
||||
$args = array(
|
||||
'visible' => $visible,
|
||||
'count' => $this->create_count_input(
|
||||
'ai1ec_daily_count',
|
||||
$selected,
|
||||
365
|
||||
) . Ai1ec_I18n::__( 'day(s)' ),
|
||||
);
|
||||
return $loader->get_file( 'row_daily.php', $args, true )
|
||||
->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* row_custom function
|
||||
*
|
||||
* Returns custom dates selector
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
protected function row_custom( $visible = false, $dates = array() ) {
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
|
||||
$args = array(
|
||||
'visible' => $visible,
|
||||
'selected_dates' => implode( ',', $dates )
|
||||
);
|
||||
return $loader->get_file( 'row_custom.php', $args, true )
|
||||
->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and returns "End after X times" input
|
||||
*
|
||||
* @param Integer|NULL $count Initial value of range input
|
||||
*
|
||||
* @return String Repeat dropdown
|
||||
*/
|
||||
protected function create_count_input( $name, $count = 100, $max = 365 ) {
|
||||
ob_start();
|
||||
|
||||
if ( ! $count ) {
|
||||
$count = 100;
|
||||
}
|
||||
?>
|
||||
<input type="range" name="<?php echo $name ?>" id="<?php echo $name ?>"
|
||||
min="1" max="<?php echo $max ?>"
|
||||
<?php if ( $count ) echo 'value="' . $count . '"' ?> />
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* row_weekly function
|
||||
*
|
||||
* Returns weekly selector
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
protected function row_weekly(
|
||||
$visible = false,
|
||||
$count = 1,
|
||||
array $selected = array()
|
||||
) {
|
||||
global $wp_locale;
|
||||
$start_of_week = $this->_registry->get( 'model.option' )
|
||||
->get( 'start_of_week', 1 );
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
|
||||
$options = array();
|
||||
// get days from start_of_week until the last day
|
||||
for ( $i = $start_of_week; $i <= 6; ++$i ) {
|
||||
$options[$this->get_weekday_by_id( $i )] = $wp_locale
|
||||
->weekday_initial[$wp_locale->weekday[$i]];
|
||||
}
|
||||
|
||||
// get days from 0 until start_of_week
|
||||
if ( $start_of_week > 0 ) {
|
||||
for ( $i = 0; $i < $start_of_week; $i++ ) {
|
||||
$options[$this->get_weekday_by_id( $i )] = $wp_locale
|
||||
->weekday_initial[$wp_locale->weekday[$i]];
|
||||
}
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'visible' => $visible,
|
||||
'count' => $this->create_count_input(
|
||||
'ai1ec_weekly_count',
|
||||
$count,
|
||||
52
|
||||
) . Ai1ec_I18n::__( 'week(s)' ),
|
||||
'week_days' => $this->create_list_element(
|
||||
'ai1ec_weekly_date_select',
|
||||
$options,
|
||||
$selected
|
||||
)
|
||||
);
|
||||
return $loader->get_file( 'row_weekly.php', $args, true )
|
||||
->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a grid of weekday, day, or month selection buttons.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function create_list_element(
|
||||
$name,
|
||||
array $options = array(),
|
||||
array $selected = array()
|
||||
) {
|
||||
ob_start();
|
||||
?>
|
||||
<div class="ai1ec-btn-group-grid" id="<?php echo $name; ?>">
|
||||
<?php foreach ( $options as $key => $val ) : ?>
|
||||
<div class="ai1ec-pull-left">
|
||||
<a class="ai1ec-btn ai1ec-btn-default ai1ec-btn-block
|
||||
<?php echo in_array( $key, $selected ) ? 'ai1ec-active' : ''; ?>">
|
||||
<?php echo $val; ?>
|
||||
</a>
|
||||
<input type="hidden" name="<?php echo $name . '_' . $key; ?>"
|
||||
value="<?php echo $key; ?>">
|
||||
</div class="ai1ec-pull-left">
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<input type="hidden" name="<?php echo $name; ?>"
|
||||
value="<?php echo implode( ',', $selected ) ?>">
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* row_monthly function
|
||||
*
|
||||
* Returns monthly selector
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
protected function row_monthly(
|
||||
$visible = false,
|
||||
$count = 1,
|
||||
$bymonthday = true,
|
||||
$month = array(),
|
||||
$day = array()
|
||||
) {
|
||||
global $wp_locale;
|
||||
$start_of_week = $this->_registry->get( 'model.option' )
|
||||
->get( 'start_of_week', 1 );
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
|
||||
$options_wd = array();
|
||||
// get days from start_of_week until the last day
|
||||
for ( $i = $start_of_week; $i <= 6; ++$i ) {
|
||||
$options_wd[$this->get_weekday_by_id( $i )] = $wp_locale
|
||||
->weekday[$i];
|
||||
}
|
||||
|
||||
// get days from 0 until start_of_week
|
||||
if ( $start_of_week > 0 ) {
|
||||
for ( $i = 0; $i < $start_of_week; $i++ ) {
|
||||
$options_wd[$this->get_weekday_by_id( $i )] = $wp_locale
|
||||
->weekday[$i];
|
||||
}
|
||||
}
|
||||
|
||||
// get options like 1st/2nd/3rd for "day number"
|
||||
$options_dn = array( 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5 );
|
||||
foreach ( $options_dn as $_dn ) {
|
||||
$options_dn[$_dn] = $this->_registry->get(
|
||||
'date.time',
|
||||
strtotime( $_dn . '-01-1998 12:00:00' )
|
||||
)->format_i18n( 'jS' );
|
||||
}
|
||||
$options_dn['-1'] = Ai1ec_I18n::__( 'last' );
|
||||
|
||||
$byday_checked = $bymonthday ? '' : 'checked';
|
||||
$byday_expanded = $bymonthday ? 'ai1ec-collapse' : 'ai1ec-in';
|
||||
$bymonthday_checked = $bymonthday ? 'checked' : '';
|
||||
$bymonthday_expanded = $bymonthday ? 'ai1ec-in' : 'ai1ec-collapse';
|
||||
|
||||
$args = array(
|
||||
'visible' => $visible,
|
||||
'count' => $this->create_count_input(
|
||||
'ai1ec_monthly_count',
|
||||
$count,
|
||||
12
|
||||
) . Ai1ec_I18n::__( 'month(s)' ),
|
||||
'month' => $this->create_monthly_date_select(
|
||||
$month
|
||||
),
|
||||
'day_nums' => $this->create_select_element(
|
||||
'ai1ec_monthly_byday_num',
|
||||
$options_dn,
|
||||
$this->_get_day_number_from_byday( $day )
|
||||
),
|
||||
'week_days' => $this->create_select_element(
|
||||
'ai1ec_monthly_byday_weekday',
|
||||
$options_wd,
|
||||
$this->_get_day_shortname_from_byday( $day )
|
||||
),
|
||||
'bymonthday_checked' => $bymonthday_checked,
|
||||
'byday_checked' => $byday_checked,
|
||||
'bymonthday_expanded' => $bymonthday_expanded,
|
||||
'byday_expanded' => $byday_expanded,
|
||||
);
|
||||
return $loader->get_file( 'row_monthly.php', $args, true )
|
||||
->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates selector for dates in monthly repeat tab.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function create_monthly_date_select( $selected = array() ) {
|
||||
$options = array();
|
||||
for ( $i = 1; $i <= 31; ++$i ) {
|
||||
$options[$i] = $i;
|
||||
}
|
||||
return $this->create_list_element(
|
||||
'ai1ec_montly_date_select',
|
||||
$options,
|
||||
$selected
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* create_on_the_select function
|
||||
*
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
**/
|
||||
protected function create_on_the_select(
|
||||
$f_selected = false,
|
||||
$s_selected = false
|
||||
) {
|
||||
$ret = '';
|
||||
|
||||
$first_options = array(
|
||||
'0' => Ai1ec_I18n::__( 'first' ),
|
||||
'1' => Ai1ec_I18n::__( 'second' ),
|
||||
'2' => Ai1ec_I18n::__( 'third' ),
|
||||
'3' => Ai1ec_I18n::__( 'fourth' ),
|
||||
'4' => '------',
|
||||
'5' => Ai1ec_I18n::__( 'last' )
|
||||
);
|
||||
$ret = $this->create_select_element(
|
||||
'ai1ec_monthly_each_select',
|
||||
$first_options,
|
||||
$f_selected,
|
||||
array( 4 )
|
||||
);
|
||||
|
||||
$second_options = array(
|
||||
'0' => Ai1ec_I18n::__( 'Sunday' ),
|
||||
'1' => Ai1ec_I18n::__( 'Monday' ),
|
||||
'2' => Ai1ec_I18n::__( 'Tuesday' ),
|
||||
'3' => Ai1ec_I18n::__( 'Wednesday' ),
|
||||
'4' => Ai1ec_I18n::__( 'Thursday' ),
|
||||
'5' => Ai1ec_I18n::__( 'Friday' ),
|
||||
'6' => Ai1ec_I18n::__( 'Saturday' ),
|
||||
'7' => '--------',
|
||||
'8' => Ai1ec_I18n::__( 'day' ),
|
||||
'9' => Ai1ec_I18n::__( 'weekday' ),
|
||||
'10' => Ai1ec_I18n::__( 'weekend day' )
|
||||
);
|
||||
|
||||
return $ret . $this->create_select_element(
|
||||
'ai1ec_monthly_on_the_select',
|
||||
$second_options,
|
||||
$s_selected,
|
||||
array( 7 )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* create_select_element function
|
||||
*
|
||||
* Render HTML <select> element
|
||||
*
|
||||
* @param string $name Name of element to be rendered
|
||||
* @param array $options Select <option> values as key=>value pairs
|
||||
* @param string $selected Key to be marked as selected [optional=false]
|
||||
* @param array $disabled_keys List of options to disable [optional=array]
|
||||
*
|
||||
* @return string Rendered <select> HTML element
|
||||
**/
|
||||
protected function create_select_element(
|
||||
$name,
|
||||
array $options = array(),
|
||||
$selected = false,
|
||||
array $disabled_keys = array()
|
||||
) {
|
||||
ob_start();
|
||||
?>
|
||||
<select name="<?php echo $name ?>" id="<?php echo $name ?>">
|
||||
<?php foreach( $options as $key => $val ): ?>
|
||||
<option value="<?php echo $key ?>"
|
||||
<?php echo $key === $selected ? 'selected="selected"' : '' ?>
|
||||
<?php echo in_array( $key, $disabled_keys ) ? 'disabled' : '' ?>>
|
||||
<?php echo $val ?>
|
||||
</option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* row_yearly function
|
||||
*
|
||||
* Returns yearly selector
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
protected function row_yearly(
|
||||
$visible = false,
|
||||
$count = 1,
|
||||
$year = array(),
|
||||
$first = false,
|
||||
$second = false
|
||||
) {
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
|
||||
$args = array(
|
||||
'visible' => $visible,
|
||||
'count' => $this->create_count_input(
|
||||
'ai1ec_yearly_count',
|
||||
$count,
|
||||
10
|
||||
) . Ai1ec_I18n::__( 'year(s)' ),
|
||||
'year' => $this->create_yearly_date_select( $year ),
|
||||
'on_the_select' => $this->create_on_the_select(
|
||||
$first,
|
||||
$second
|
||||
),
|
||||
);
|
||||
return $loader->get_file( 'row_yearly.php', $args, true )
|
||||
->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* create_yearly_date_select function
|
||||
*
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
protected function create_yearly_date_select( $selected = array() ) {
|
||||
global $wp_locale;
|
||||
$options = array();
|
||||
for ( $i = 1; $i <= 12; ++$i ) {
|
||||
$options[$i] = $wp_locale->month_abbrev[
|
||||
$wp_locale->month[sprintf( '%02d', $i )]
|
||||
];
|
||||
}
|
||||
return $this->create_list_element(
|
||||
'ai1ec_yearly_date_select',
|
||||
$options,
|
||||
$selected
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts recurrence rule to array of string of dates.
|
||||
*
|
||||
* @param string $rule RUle.
|
||||
*
|
||||
* @return array Array of dates or empty array.
|
||||
* @throws Ai1ec_Bootstrap_Exception
|
||||
*/
|
||||
protected function get_date_array_from_rule( $rule ) {
|
||||
if (
|
||||
'RDATE' !== substr( $rule, 0, 5 ) &&
|
||||
'EXDATE' !== substr( $rule, 0, 6 )
|
||||
) {
|
||||
return array();
|
||||
}
|
||||
$line = new SG_iCal_Line( 'RRULE:' . $rule );
|
||||
$dates = $line->getDataAsArray();
|
||||
$dates_as_strings = array();
|
||||
foreach ( $dates as $date ) {
|
||||
$date = str_replace( array( 'RDATE=', 'EXDATE=' ), '', $date );
|
||||
$date = $this->_registry->get( 'date.time', $date )->set_preferred_timezone( 'UTC' );
|
||||
$dates_as_strings[] = $date->format( 'm/d/Y' );
|
||||
}
|
||||
return $dates_as_strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether recurrence rule has non null ByMonthDay.
|
||||
*
|
||||
* @param SG_iCal_Recurrence $rc iCal class.
|
||||
*
|
||||
* @return bool True or false.
|
||||
*/
|
||||
protected function _is_monthday_empty( SG_iCal_Recurrence $rc ) {
|
||||
return false === $rc->getByMonthDay();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns day number from by day array.
|
||||
*
|
||||
* @param array $day
|
||||
*
|
||||
* @return bool|int Day of false if empty array.
|
||||
*/
|
||||
protected function _get_day_number_from_byday( array $day ) {
|
||||
return isset( $day[0] ) ? (int) $day[0] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns string part from "ByDay" recurrence rule.
|
||||
*
|
||||
* @param array $day Element to parse.
|
||||
*
|
||||
* @return bool|string False if empty or not matched, otherwise short day
|
||||
* name.
|
||||
*/
|
||||
protected function _get_day_shortname_from_byday( $day ) {
|
||||
if ( empty( $day ) ) {
|
||||
return false;
|
||||
}
|
||||
$value = $day[0];
|
||||
if ( preg_match('/[-]?\d([A-Z]+)/', $value, $matches ) ) {
|
||||
return $matches[1];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The get tax options box.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.4
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Admin_Get_Tax_Box extends Ai1ec_Base {
|
||||
/**
|
||||
* get_tax_box function
|
||||
*
|
||||
* @return string
|
||||
**/
|
||||
public function get_tax_box() {
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
$post_id = $_POST['ai1ec_event_id'];
|
||||
$modal = $api->get_tax_options_modal( $post_id );
|
||||
$output = array(
|
||||
'error' => $modal->error,
|
||||
'message' => $modal->data
|
||||
);
|
||||
$json_strategy = $this->_registry->get( 'http.response.render.strategy.json' );
|
||||
$json_strategy->render( array( 'data' => $output ) );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Admin-side navigation elements rendering.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.0
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Admin_Navigation extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Adds a link to Settings page in plugin list page.
|
||||
*
|
||||
* @param array $links List of available links.
|
||||
*
|
||||
* @return array Modified links list.
|
||||
*/
|
||||
public function plugin_action_links( $links ) {
|
||||
$settings_link = sprintf(
|
||||
Ai1ec_I18n::__( '<a href="%s">Settings</a>' ),
|
||||
ai1ec_admin_url( AI1EC_SETTINGS_BASE_URL )
|
||||
);
|
||||
array_unshift( $links, $settings_link );
|
||||
if ( current_user_can( 'activate_plugins' ) ) {
|
||||
$updates_link = sprintf(
|
||||
Ai1ec_I18n::__( '<a href="%s">Check for updates</a>' ),
|
||||
ai1ec_admin_url( AI1EC_FORCE_UPDATES_URL )
|
||||
);
|
||||
array_push( $links, $updates_link );
|
||||
}
|
||||
return $links;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The page to manage taxonomies.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Organize extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* @var array The taxonomies for events
|
||||
*/
|
||||
protected $_taxonomies = array();
|
||||
|
||||
/**
|
||||
* Register actions to draw the headers
|
||||
*/
|
||||
public function add_taxonomy_actions() {
|
||||
$taxonomies = get_object_taxonomies( AI1EC_POST_TYPE, 'object' );
|
||||
$dispatcher = $this->_registry->get( 'event.dispatcher' );
|
||||
$taxonomy_metadata = array(
|
||||
'events_categories' => array(
|
||||
'icon' => 'ai1ec-fa ai1ec-fa-folder-open'
|
||||
),
|
||||
'events_tags' => array(
|
||||
'icon' => 'ai1ec-fa ai1ec-fa-tags'
|
||||
)
|
||||
);
|
||||
$taxonomy_metadata = apply_filters(
|
||||
'ai1ec_add_custom_groups',
|
||||
$taxonomy_metadata
|
||||
);
|
||||
do_action( 'ai1ec_taxonomy_management_css' );
|
||||
foreach ( $taxonomies as $taxonomy => $data ) {
|
||||
if ( true === $data->public ) {
|
||||
$active_taxonomy =
|
||||
isset( $_GET['taxonomy'] ) &&
|
||||
$taxonomy === $_GET['taxonomy'];
|
||||
$edit_url = $edit_label = '';
|
||||
if ( isset( $taxonomy_metadata[$taxonomy]['url'] ) ) {
|
||||
$edit_url = $taxonomy_metadata[$taxonomy]['url'];
|
||||
$edit_label = $taxonomy_metadata[$taxonomy]['edit_label'];
|
||||
}
|
||||
$this->_taxonomies[] = array(
|
||||
'taxonomy_name' => $taxonomy,
|
||||
'url' => add_query_arg(
|
||||
array(
|
||||
'post_type' => AI1EC_POST_TYPE,
|
||||
'taxonomy' => $taxonomy
|
||||
),
|
||||
admin_url( 'edit-tags.php' )
|
||||
),
|
||||
'name' => $data->labels->name,
|
||||
'active' => $active_taxonomy,
|
||||
'icon' => isset( $taxonomy_metadata[$taxonomy] ) ?
|
||||
$taxonomy_metadata[$taxonomy]['icon'] :
|
||||
'',
|
||||
'edit_url' => $edit_url,
|
||||
'edit_label' => $edit_label,
|
||||
);
|
||||
|
||||
if ( $active_taxonomy ) {
|
||||
$dispatcher->register_action(
|
||||
$taxonomy . '_pre_add_form',
|
||||
array( 'view.admin.organize', 'render_header' )
|
||||
);
|
||||
$dispatcher->register_action(
|
||||
$taxonomy . '_pre_edit_form',
|
||||
array( 'view.admin.organize', 'render_header' )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render tabbed header to manage taxonomies.
|
||||
*/
|
||||
public function render_header() {
|
||||
echo $this->get_header();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and return tabbed header to manage taxonomies.
|
||||
*
|
||||
* @return string HTML markup for tabbed header
|
||||
*/
|
||||
public function get_header() {
|
||||
return $this->_registry->get( 'theme.loader' )->get_file(
|
||||
'organize/header.twig',
|
||||
array(
|
||||
'taxonomies' => apply_filters(
|
||||
'ai1ec_custom_taxonomies',
|
||||
$this->_taxonomies
|
||||
),
|
||||
'text_title' => Ai1ec_I18n::__( 'Organize Events' ),
|
||||
),
|
||||
true
|
||||
)->get_content();
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The Calendar Samples page.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.1
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Samples extends Ai1ec_View_Admin_Abstract {
|
||||
/**
|
||||
* Adds page to the menu.
|
||||
*
|
||||
* @wp_hook admin_menu
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_page() {
|
||||
// =======================
|
||||
// = Calendar Add Ons Page =
|
||||
// =======================
|
||||
}
|
||||
/**
|
||||
* Display Add Ons list page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_page() {
|
||||
wp_enqueue_style(
|
||||
'ai1ec_samples.css',
|
||||
AI1EC_ADMIN_THEME_CSS_URL . 'samples.css',
|
||||
array(),
|
||||
AI1EC_VERSION
|
||||
);
|
||||
|
||||
$this->_registry->get( 'theme.loader' )->get_file(
|
||||
'samples.twig',
|
||||
array(),
|
||||
true
|
||||
)->render();
|
||||
}
|
||||
|
||||
public function add_meta_box() {
|
||||
}
|
||||
|
||||
public function display_meta_box( $object, $box ) {
|
||||
}
|
||||
|
||||
public function handle_post() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,349 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The Settings page.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Admin_Settings extends Ai1ec_View_Admin_Abstract {
|
||||
|
||||
/**
|
||||
* @var string The nonce action
|
||||
*/
|
||||
CONST NONCE_ACTION = 'ai1ec_settings_save';
|
||||
|
||||
/**
|
||||
* @var string The nonce name
|
||||
*/
|
||||
CONST NONCE_NAME = 'ai1ec_settings_nonce';
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_View_Admin_Abstract::display_page()
|
||||
*/
|
||||
public function display_page() {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$args = array(
|
||||
'title' => Ai1ec_I18n::__(
|
||||
'All-in-One Event Calendar: Settings'
|
||||
),
|
||||
'nonce' => array(
|
||||
'action' => self::NONCE_ACTION,
|
||||
'name' => self::NONCE_NAME,
|
||||
'referrer' => false,
|
||||
),
|
||||
'metabox' => array(
|
||||
'screen' => $settings->get( 'settings_page' ),
|
||||
'action' => 'left',
|
||||
'object' => null
|
||||
),
|
||||
'support' => array(
|
||||
'screen' => $settings->get( 'settings_page' ),
|
||||
'action' => 'right',
|
||||
'object' => null
|
||||
),
|
||||
'action' =>
|
||||
ai1ec_admin_url(
|
||||
'?controller=front&action=ai1ec_save_settings&plugin=' .
|
||||
AI1EC_PLUGIN_NAME
|
||||
),
|
||||
);
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$file = $loader->get_file( 'setting/page.twig', $args, true );
|
||||
$file->render();
|
||||
if ( apply_filters( 'ai1ec_robots_install', true ) ) {
|
||||
$this->_registry->get( 'robots.helper' )->install();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_View_Admin_Abstract::add_page()
|
||||
*/
|
||||
public function add_page() {
|
||||
$settings_page = add_submenu_page(
|
||||
AI1EC_ADMIN_BASE_URL,
|
||||
Ai1ec_I18n::__( 'Settings' ),
|
||||
Ai1ec_I18n::__( 'Settings' ),
|
||||
'manage_ai1ec_options',
|
||||
AI1EC_PLUGIN_NAME . '-settings',
|
||||
array( $this, 'display_page' )
|
||||
);
|
||||
$this->_registry->get( 'model.settings' )
|
||||
->set( 'settings_page', $settings_page );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds metabox to the page.
|
||||
*
|
||||
* @wp_hook admin_init
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_meta_box() {
|
||||
// Add the 'General Settings' meta box.
|
||||
add_meta_box(
|
||||
'ai1ec-general-settings',
|
||||
Ai1ec_I18n::_x( 'General Settings', 'meta box' ),
|
||||
array( $this, 'display_meta_box' ),
|
||||
$this->_registry->get( 'model.settings' )->get( 'settings_page' ),
|
||||
'left',
|
||||
'default'
|
||||
);
|
||||
// Add the 'Timely' meta box.
|
||||
add_meta_box(
|
||||
'ai1ec-support',
|
||||
Ai1ec_I18n::_x( 'Timely', 'meta box', AI1EC_PLUGIN_NAME ),
|
||||
array( $this, 'support_meta_box' ),
|
||||
$this->_registry->get( 'model.settings' )->get( 'settings_page' ),
|
||||
'right',
|
||||
'default'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Timely blog meta box
|
||||
*
|
||||
* @param mixed $object
|
||||
* @param mixed $box
|
||||
*/
|
||||
public function support_meta_box( $object, $box ) {
|
||||
$newsItems = $this->_registry->get( 'news.feed' )->import_feed();
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$file = $loader->get_file(
|
||||
'box_support.php',
|
||||
array(
|
||||
'news' => $newsItems,
|
||||
),
|
||||
true
|
||||
);
|
||||
$file->render();
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_View_Admin_Abstract::handle_post()
|
||||
*/
|
||||
public function handle_post() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the meta box for the settings page.
|
||||
*
|
||||
* @param mixed $object
|
||||
* @param mixed $box
|
||||
*/
|
||||
public function display_meta_box( $object, $box ) {
|
||||
$tabs = array(
|
||||
'viewing-events' => array(
|
||||
'name' => Ai1ec_I18n::__( 'Viewing Events' ),
|
||||
),
|
||||
'editing-events' => array(
|
||||
'name' => Ai1ec_I18n::__( 'Adding/Editing Events' ),
|
||||
),
|
||||
'advanced' => array(
|
||||
'name' => Ai1ec_I18n::__( 'Advanced' ),
|
||||
'items' => array(
|
||||
'advanced' => Ai1ec_I18n::__( 'Advanced Settings' ),
|
||||
'embedded-views' => Ai1ec_I18n::__( 'Shortcodes' ),
|
||||
'email' => Ai1ec_I18n::__( 'Email Templates' ),
|
||||
'apis' => Ai1ec_I18n::__( 'External Services' ),
|
||||
'cache' => Ai1ec_I18n::__( 'Cache Report' ),
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// let other extensions add tabs.
|
||||
$tabs = apply_filters( 'ai1ec_add_setting_tabs', $tabs );
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$plugin_settings = $settings->get_options();
|
||||
$tabs = $this->_get_tabs_to_show( $plugin_settings, $tabs );
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$api = $this->_registry->get( 'model.api.api-registration' );
|
||||
$signup_available = $api->is_api_sign_up_available();
|
||||
$signed_to_api = $api->is_signed();
|
||||
$ticketing_message = $api->get_sign_message();
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$account = $api->get_current_account();
|
||||
$signup_args = array(
|
||||
'api_signed' => $signed_to_api,
|
||||
'signup_available' => $signup_available,
|
||||
'title' => Ai1ec_I18n::__(
|
||||
'Please, Sign In to Timely Network.'
|
||||
),
|
||||
'nonce' => array(
|
||||
'action' => 'ai1ec_api_ticketing_signup',
|
||||
'name' => 'ai1ec_api_ticketing_nonce',
|
||||
'referrer' => false,
|
||||
),
|
||||
'api_action' =>
|
||||
'?controller=front&action=ai1ec_api_ticketing_signup&plugin=' .
|
||||
AI1EC_PLUGIN_NAME,
|
||||
'required_text' => Ai1ec_I18n::__( 'This field is required.' ),
|
||||
'register_text' => Ai1ec_I18n::__( 'Register' ),
|
||||
'sign_in_text' => Ai1ec_I18n::__( 'Sign in' ),
|
||||
'signed_in_text' => Ai1ec_I18n::__(
|
||||
'You are signed in to <b>Timely Network</b> as ' . $account
|
||||
),
|
||||
'sign_out_text' => Ai1ec_I18n::__( 'Sign out' ),
|
||||
'can_sign_out' => apply_filters( 'ai1ec_api_can_sign_out', true ),
|
||||
'full_name_text' => Ai1ec_I18n::__( 'Full Name:' ),
|
||||
'hide_form_text' => Ai1ec_I18n::__( 'Hide form' ),
|
||||
'show_form_text' => Ai1ec_I18n::__( 'Show form' ),
|
||||
'email_text' => Ai1ec_I18n::__( 'Email:' ),
|
||||
'password_text' => Ai1ec_I18n::__( 'Password:' ),
|
||||
'confirm_password_text' => Ai1ec_I18n::__( 'Confirm Password:' ),
|
||||
'phone_number_text' => Ai1ec_I18n::__( 'Phone Number:' ),
|
||||
'terms_text' => Ai1ec_I18n::__(
|
||||
'I confirm that I have read, understand and agree with the <a href="https://time.ly/tos">terms of service</a>.'
|
||||
),
|
||||
'sign_out_warning' => Ai1ec_I18n::__(
|
||||
'<h4>Attention Required:</h4>If you choose to sign-out of the API Timely Network this will close all the created tickets and remove user access to them. In this case, on the event page, users will see the status “Event closed”.'
|
||||
),
|
||||
'sign_out_cancel' => Ai1ec_I18n::__( 'Cancel' ),
|
||||
'sign_out_confirm' => Ai1ec_I18n::__( 'Sign Out' ),
|
||||
'sign_up_button_text' => Ai1ec_I18n::__( 'Sign Up' ),
|
||||
'sign_in_button_text' => Ai1ec_I18n::__( 'Sign In' ),
|
||||
'calendar_type_text' => Ai1ec_I18n::__( 'Calendar Type:' ),
|
||||
'calendar_types' => array(
|
||||
'tourism' => Ai1ec_I18n::__( 'Tourism' ),
|
||||
'media' => Ai1ec_I18n::__( 'Media' ),
|
||||
'community_hubs' => Ai1ec_I18n::__( 'Community Hubs' ),
|
||||
'education' => Ai1ec_I18n::__( 'Education' ),
|
||||
'venue_business' => Ai1ec_I18n::__( 'Venue/Business' ),
|
||||
'artist_performer' => Ai1ec_I18n::__( 'Artist/Performer' ),
|
||||
'church_spiritual' => Ai1ec_I18n::__( 'Church/Spiritual' ),
|
||||
'association_group' => Ai1ec_I18n::__( 'Association/Group' ),
|
||||
'other' => Ai1ec_I18n::__( 'Other' )
|
||||
),
|
||||
);
|
||||
$loader->get_file( 'setting/api-signup.twig', $signup_args, true )->render();
|
||||
|
||||
|
||||
$args = array(
|
||||
'tabs' => $tabs,
|
||||
'content_class' => 'ai1ec-form-horizontal',
|
||||
'submit' => array(
|
||||
'id' => 'ai1ec_save_settings',
|
||||
'value' => '<i class="ai1ec-fa ai1ec-fa-save ai1ec-fa-fw"></i> ' .
|
||||
Ai1ec_I18n::__( 'Save Settings' ),
|
||||
'args' => array(
|
||||
'class' => 'ai1ec-btn ai1ec-btn-primary ai1ec-btn-lg',
|
||||
),
|
||||
),
|
||||
'pre_tabs_markup' => sprintf(
|
||||
'<div class="ai1ec-gzip-causes-js-failure">' .
|
||||
Ai1ec_I18n::__(
|
||||
'If the form below is not working please follow <a href="%s">this link</a>.'
|
||||
) .
|
||||
'</div>',
|
||||
wp_nonce_url(
|
||||
add_query_arg( 'ai1ec_disable_gzip_compression', '1' ),
|
||||
'ai1ec_disable_gzip_compression'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
$file = $loader->get_file( 'setting/bootstrap_tabs.twig', $args, true );
|
||||
$file->render();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the plugin options, decides what tabs to render.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param array $plugin_settings
|
||||
* @param array $tabs
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _get_tabs_to_show( array $plugin_settings, array $tabs ) {
|
||||
$index = 0;
|
||||
$renderer = $this->_registry->get( 'html.element.setting-renderer' );
|
||||
foreach ( $plugin_settings as $id => $setting ) {
|
||||
// if the setting is shown
|
||||
if ( isset ( $setting['renderer'] ) ) {
|
||||
$tab_to_use = isset( $setting['renderer']['item'] ) ?
|
||||
$setting['renderer']['item'] :
|
||||
$setting['renderer']['tab'];
|
||||
// check if it's the first one
|
||||
if (
|
||||
! isset ( $tabs[$tab_to_use]['elements'] )
|
||||
) {
|
||||
$tabs[$tab_to_use]['elements'] = array();
|
||||
}
|
||||
$setting['id'] = $id;
|
||||
// render the settings
|
||||
$weight = 10;
|
||||
if ( isset( $setting['renderer']['weight'] ) ) {
|
||||
$weight = (int)$setting['renderer']['weight'];
|
||||
}
|
||||
// NOTICE: do NOT change order of two first
|
||||
// elements {weight,index}, otherwise sorting will fail.
|
||||
$tabs[$tab_to_use]['elements'][] = array(
|
||||
'weight' => $weight,
|
||||
'index' => ++$index,
|
||||
'html' => $renderer->render( $setting ),
|
||||
);
|
||||
// if the settings has an item tab, set the item as active.
|
||||
if ( isset( $setting['renderer']['item'] ) ) {
|
||||
if ( ! isset( $tabs[$setting['renderer']['tab']]['items_active'][$setting['renderer']['item']] ) ) {
|
||||
$tabs[$setting['renderer']['tab']]['items_active'][$setting['renderer']['item']] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$tabs_to_display = array();
|
||||
// now let's see what tabs to display.
|
||||
foreach ( $tabs as $name => $tab ) {
|
||||
// sort by weights
|
||||
if ( isset( $tab['elements'] ) ) {
|
||||
asort( $tab['elements'] );
|
||||
}
|
||||
// if a tab has more than one item.
|
||||
if ( isset( $tab['items'] ) ) {
|
||||
// if no item is active, nothing is shown
|
||||
if ( empty( $tab['items_active'] ) ) {
|
||||
continue;
|
||||
}
|
||||
// if only one item is active, do not use the dropdown
|
||||
if ( count( $tab['items_active'] ) === 0 ) {
|
||||
$name = key($tab['items_active']);
|
||||
$tab['name'] = $tab['items'][$name];
|
||||
unset ( $tab['items'] );
|
||||
} else {
|
||||
// check active items for the dropdown
|
||||
foreach ( $tab['items'] as $item => $longname ) {
|
||||
if ( ! isset( $tab['items_active'][$item] ) ) {
|
||||
unset( $tab['items'][$item] );
|
||||
}
|
||||
}
|
||||
}
|
||||
// lets make a check to avoid overriding tabs
|
||||
if ( ! isset( $tabs_to_display[$name] ) ) {
|
||||
$tabs_to_display[$name] = $tab;
|
||||
} else {
|
||||
$tabs_to_display[$name]['elements'] = $tab['elements'];
|
||||
}
|
||||
|
||||
} else {
|
||||
// no items, just check for any element to display.
|
||||
if ( isset( $tab['elements'] ) ) {
|
||||
// lets make a check to avoid overriding tabs
|
||||
if ( ! isset( $tabs_to_display[$name] ) ) {
|
||||
$tabs_to_display[$name] = $tab;
|
||||
} else {
|
||||
$tabs_to_display[$name]['elements'] = $tab['elements'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tabs_to_display;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The Theme options page.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Theme_Options extends Ai1ec_View_Admin_Abstract {
|
||||
|
||||
/**
|
||||
* @var string The nonce action
|
||||
*/
|
||||
const NONCE_ACTION = 'ai1ec_theme_options_save';
|
||||
|
||||
/**
|
||||
* @var string The nonce name
|
||||
*/
|
||||
const NONCE_NAME = 'ai1ec_theme_options_nonce';
|
||||
|
||||
/**
|
||||
* @var string The id/name of the submit button.
|
||||
*/
|
||||
const SUBMIT_ID = 'ai1ec_save_themes_options';
|
||||
|
||||
/**
|
||||
* @var string The id/name of the Reset button.
|
||||
*/
|
||||
const RESET_ID = 'ai1ec_reset_themes_options';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $title;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $meta_box_id;
|
||||
|
||||
/**
|
||||
* Adds the page to the correct menu.
|
||||
*/
|
||||
public function add_page() {
|
||||
$theme_options_page = add_submenu_page(
|
||||
AI1EC_ADMIN_BASE_URL,
|
||||
Ai1ec_I18n::__( 'Theme Options' ),
|
||||
Ai1ec_I18n::__( 'Theme Options' ),
|
||||
'manage_ai1ec_options',
|
||||
AI1EC_PLUGIN_NAME . '-edit-css',
|
||||
array( $this, 'display_page' )
|
||||
);
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
if ( false !== $settings->get( 'less_variables_page' ) ) {
|
||||
// Make copy of Theme Options page at its old location.
|
||||
$submenu['themes.php'][] = array(
|
||||
Ai1ec_I18n::__( 'Calendar Theme Options' ),
|
||||
'manage_ai1ec_options',
|
||||
AI1EC_THEME_OPTIONS_BASE_URL,
|
||||
);
|
||||
};
|
||||
$settings->set( 'less_variables_page', $theme_options_page );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add meta box for page.
|
||||
*
|
||||
* @wp_hook admin_init
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_meta_box() {
|
||||
// Add the 'General Settings' meta box.
|
||||
add_meta_box(
|
||||
'ai1ec-less-variables-tabs',
|
||||
Ai1ec_I18n::_x( 'Calendar Theme Options', 'meta box' ),
|
||||
array( $this, 'display_meta_box' ),
|
||||
$this->_registry->get( 'model.settings' )
|
||||
->get( 'less_variables_page' ),
|
||||
'left',
|
||||
'default'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the page html
|
||||
*/
|
||||
public function display_page() {
|
||||
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
|
||||
$args = array(
|
||||
'title' => Ai1ec_I18n::__(
|
||||
'Calendar Theme Options'
|
||||
),
|
||||
'nonce' => array(
|
||||
'action' => self::NONCE_ACTION,
|
||||
'name' => self::NONCE_NAME,
|
||||
'referrer' => false,
|
||||
),
|
||||
'metabox' => array(
|
||||
'screen' => $settings->get( 'themes_option_page' ),
|
||||
'action' => 'left',
|
||||
'object' => null
|
||||
),
|
||||
'action' =>
|
||||
'?controller=front&action=ai1ec_save_theme_options&plugin=' . AI1EC_PLUGIN_NAME
|
||||
);
|
||||
|
||||
$frontend = $this->_registry->get( 'css.frontend' );
|
||||
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
|
||||
$file = $loader->get_file( 'theme-options/page.twig', $args, true );
|
||||
|
||||
return $file->render();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the meta box for the settings page.
|
||||
*
|
||||
* @param mixed $object
|
||||
* @param mixed $box
|
||||
*/
|
||||
public function display_meta_box( $object, $box ) {
|
||||
|
||||
$tabs = array(
|
||||
'general' => array(
|
||||
'name' => Ai1ec_I18n::__( 'General' ),
|
||||
),
|
||||
'table' => array(
|
||||
'name' => Ai1ec_I18n::__( 'Tables' ),
|
||||
),
|
||||
'buttons' => array(
|
||||
'name' => Ai1ec_I18n::__( 'Buttons' ),
|
||||
),
|
||||
'forms' => array(
|
||||
'name' => Ai1ec_I18n::__( 'Forms' ),
|
||||
),
|
||||
'calendar' => array(
|
||||
'name' => Ai1ec_I18n::__( 'Calendar general' ),
|
||||
),
|
||||
'month' => array(
|
||||
'name' => Ai1ec_I18n::__( 'Month/week/day view' ),
|
||||
),
|
||||
'agenda' => array(
|
||||
'name' => Ai1ec_I18n::__( 'Agenda view' ),
|
||||
),
|
||||
);
|
||||
|
||||
$tabs = apply_filters( 'ai1ec_less_variables_tabs', $tabs );
|
||||
|
||||
$less_variables = $this->_registry
|
||||
->get( 'less.lessphp' )->get_saved_variables();
|
||||
$tabs = $this->_get_tabs_to_show( $less_variables, $tabs );
|
||||
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$args = array(
|
||||
'stacked' => true,
|
||||
'content_class' => 'ai1ec-form-horizontal',
|
||||
'tabs' => $tabs,
|
||||
'submit' => array(
|
||||
'id' => self::SUBMIT_ID,
|
||||
'value' => '<i class="ai1ec-fa ai1ec-fa-save ai1ec-fa-fw"></i> ' .
|
||||
Ai1ec_I18n::__( 'Save Options' ),
|
||||
'args' => array(
|
||||
'class' => 'ai1ec-btn ai1ec-btn-primary ai1ec-btn-lg',
|
||||
),
|
||||
),
|
||||
'reset' => array(
|
||||
'id' => self::RESET_ID,
|
||||
'value' => '<i class="ai1ec-fa ai1ec-fa-undo ai1ec-fa-fw"></i> ' .
|
||||
Ai1ec_I18n::__( 'Reset to Defaults' ),
|
||||
'args' => array(
|
||||
'class' => 'ai1ec-btn ai1ec-btn-danger ai1ec-btn-lg',
|
||||
),
|
||||
),
|
||||
);
|
||||
$file = $loader->get_file( 'theme-options/bootstrap_tabs.twig', $args, true );
|
||||
$file->render();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the theme options tabs
|
||||
*
|
||||
* @param array $less_variables
|
||||
* @param array $tabs list of tabs
|
||||
*
|
||||
* @return array the array of tabs to display
|
||||
*/
|
||||
protected function _get_tabs_to_show( array $less_variables, array $tabs) {
|
||||
|
||||
// Inizialize the array of tabs that will be added to the layout
|
||||
$bootstrap_tabs_to_add = array();
|
||||
|
||||
foreach( $tabs as $id => $tab ){
|
||||
$tab['elements'] = array();
|
||||
$bootstrap_tabs_to_add[$id] = $tab;
|
||||
}
|
||||
foreach ( $less_variables as $variable_id => $variable_attributes ) {
|
||||
$variable_attributes['id'] = $variable_id;
|
||||
$renderable = $this->_registry->get(
|
||||
'less.variable.' . $variable_attributes['type'],
|
||||
$variable_attributes
|
||||
);
|
||||
$bootstrap_tabs_to_add[$variable_attributes['tab']]['elements'][] = array(
|
||||
'html' => $renderable->render()
|
||||
);
|
||||
}
|
||||
return $bootstrap_tabs_to_add;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle post, likely to be deprecated to use commands.
|
||||
*/
|
||||
public function handle_post() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The Theme selection page.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Admin_Theme_Switching extends Ai1ec_View_Admin_Abstract {
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_View_Admin_Abstract::display_page()
|
||||
*/
|
||||
public function display_page() {
|
||||
global $ct;
|
||||
// defaults
|
||||
$activated = isset( $_GET['activated'] ) ? true : false;
|
||||
$deleted = false;
|
||||
|
||||
$_list_table = $this->_registry->get( 'theme.list' );
|
||||
$_list_table->prepare_items();
|
||||
|
||||
$args = array(
|
||||
'activated' => $activated,
|
||||
'deleted' => $deleted,
|
||||
'ct' => $ct,
|
||||
'wp_list_table' => $_list_table,
|
||||
'page_title' => Ai1ec_I18n::__(
|
||||
'All-in-One Event Calendar: Themes'
|
||||
),
|
||||
);
|
||||
|
||||
add_thickbox();
|
||||
wp_enqueue_script( 'theme-preview' );
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
|
||||
$file = $loader->get_file( 'themes.php', $args, true );
|
||||
return $file->render();
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_View_Admin_Abstract::add_page()
|
||||
*/
|
||||
public function add_page() {
|
||||
global $submenu;
|
||||
// ===============
|
||||
// = Themes Page =
|
||||
// ===============
|
||||
$themes_page = add_submenu_page(
|
||||
AI1EC_ADMIN_BASE_URL,
|
||||
Ai1ec_I18n::__( 'Calendar Themes' ),
|
||||
Ai1ec_I18n::__( 'Calendar Themes' ),
|
||||
'switch_ai1ec_themes',
|
||||
AI1EC_PLUGIN_NAME . '-themes',
|
||||
array( $this, 'display_page' )
|
||||
);
|
||||
}
|
||||
|
||||
public function add_meta_box() {
|
||||
}
|
||||
|
||||
public function handle_post() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Tickets page.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.4
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Tickets extends Ai1ec_View_Admin_Abstract {
|
||||
|
||||
/**
|
||||
* @var string The nonce action
|
||||
*/
|
||||
const NONCE_ACTION = 'ai1ec_api_ticketing_signup';
|
||||
|
||||
/**
|
||||
* @var string The nonce name
|
||||
*/
|
||||
const NONCE_NAME = 'ai1ec_api_ticketing_nonce';
|
||||
|
||||
/**
|
||||
* @var string The id/name of the submit button.
|
||||
*/
|
||||
const SUBMIT_ID = 'ai1ec_api_ticketing_signup';
|
||||
|
||||
/**
|
||||
* Adds the page to the correct menu.
|
||||
*/
|
||||
public function add_page() {
|
||||
add_submenu_page(
|
||||
AI1EC_ADMIN_BASE_URL,
|
||||
__( 'Ticketing', AI1EC_PLUGIN_NAME ),
|
||||
__( 'Ticketing', AI1EC_PLUGIN_NAME ),
|
||||
'manage_ai1ec_feeds',
|
||||
AI1EC_PLUGIN_NAME . '-tickets',
|
||||
array( $this, 'display_page' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add meta box for page.
|
||||
*
|
||||
* @wp_hook admin_init
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_meta_box() {}
|
||||
|
||||
/**
|
||||
* Display the page html
|
||||
*/
|
||||
public function display_page() {
|
||||
|
||||
$signed_to_api = $this->_api_registration->is_signed();
|
||||
$signup_available = $this->_api_registration->is_api_sign_up_available();
|
||||
$ticketing_available = $this->_api_registration->is_ticket_available();
|
||||
$ticketing_enabled = $this->_api_registration->has_subscription_active( Ai1ec_Api_Features::CODE_TICKETING );
|
||||
$ticketing_message = $this->_api_registration->get_sign_message();
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
wp_enqueue_style(
|
||||
'ai1ec_samples.css',
|
||||
AI1EC_ADMIN_THEME_CSS_URL . 'samples.css',
|
||||
array(),
|
||||
AI1EC_VERSION
|
||||
);
|
||||
|
||||
if ( ! $signed_to_api ) {
|
||||
|
||||
if ( false === ai1ec_is_blank( $ticketing_message ) ) {
|
||||
$this->_api_registration->clear_sign_message();
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'title' => Ai1ec_I18n::__(
|
||||
'Timely Ticketing'
|
||||
),
|
||||
'sign_up_text' => 'Please, <a href="edit.php?post_type=ai1ec_event&page=all-in-one-event-calendar-settings">Sign Up for a Timely Network account</a> to use Ticketing.',
|
||||
'signup_form' => Ai1ec_I18n::__( 'You need to sign up for a Timely Network account in order to use Ticketing.<br /><br />' ) .
|
||||
(
|
||||
$signup_available
|
||||
? Ai1ec_I18n::__( '<a href="edit.php?post_type=ai1ec_event&page=all-in-one-event-calendar-settings" class="ai1ec-btn ai1ec-btn-primary ai1ec-btn-lg">Sign In to Timely Network</a>' )
|
||||
: Ai1ec_I18n::__( '<b>Signing up for a Timely Network account is currently unavailable. Please, try again later.</b>' )
|
||||
),
|
||||
'show_info' => true
|
||||
|
||||
);
|
||||
$file = $loader->get_file( 'ticketing/signup.twig', $args, true );
|
||||
} elseif ( ! $ticketing_available ) {
|
||||
$args = array(
|
||||
'title' => Ai1ec_I18n::__(
|
||||
'Timely Ticketing'
|
||||
),
|
||||
'sign_up_text' => '',
|
||||
'signup_form' => 'Ticketing is currently not available for this website. Please, try again later.',
|
||||
'show_info' => true
|
||||
|
||||
);
|
||||
$file = $loader->get_file( 'ticketing/signup.twig', $args, true );
|
||||
} elseif ( ! $ticketing_enabled ) {
|
||||
$args = array(
|
||||
'title' => Ai1ec_I18n::__(
|
||||
'Timely Ticketing'
|
||||
),
|
||||
'sign_up_text' => '',
|
||||
'signup_form' => '',
|
||||
'show_info' => true
|
||||
);
|
||||
$file = $loader->get_file( 'ticketing/signup.twig', $args, true );
|
||||
} else {
|
||||
$response = $this->_api_registration->get_payment_preferences();
|
||||
$purchases = $this->_api_registration->get_purchases();
|
||||
$args = array(
|
||||
'title' => Ai1ec_I18n::__(
|
||||
'Timely Ticketing'
|
||||
),
|
||||
'settings_text' => Ai1ec_I18n::__( 'Settings' ),
|
||||
'sales_text' => Ai1ec_I18n::__( 'Sales' ),
|
||||
'select_payment_text' => Ai1ec_I18n::__( 'Please provide your PayPal details.' ),
|
||||
'cheque_text' => Ai1ec_I18n::__( 'Cheque' ),
|
||||
'paypal_text' => Ai1ec_I18n::__( 'PayPal' ),
|
||||
'currency_text' => Ai1ec_I18n::__( 'Preferred currency for tickets:' ),
|
||||
'required_text' => Ai1ec_I18n::__( 'This field is required.' ),
|
||||
'save_changes_text' => Ai1ec_I18n::__( 'Save Changes' ),
|
||||
'date_text' => Ai1ec_I18n::__( 'Date' ),
|
||||
'event_text' => Ai1ec_I18n::__( 'Event' ),
|
||||
'purchaser_text' => Ai1ec_I18n::__( 'Purchaser' ),
|
||||
'tickets_text' => Ai1ec_I18n::__( 'Tickets' ),
|
||||
'email_text' => Ai1ec_I18n::__( 'Email' ),
|
||||
'status_text' => Ai1ec_I18n::__( 'Status' ),
|
||||
'total_text' => Ai1ec_I18n::__( 'Total' ),
|
||||
'sign_out_button_text' => Ai1ec_I18n::__( 'Sign Out' ),
|
||||
'payment_method' => $response->payment_method,
|
||||
'paypal_email' => $response->paypal_email,
|
||||
'first_name' => $response->first_name,
|
||||
'last_name' => $response->last_name,
|
||||
'currency' => $response->currency,
|
||||
'nonce' => array(
|
||||
'action' => self::NONCE_ACTION,
|
||||
'name' => self::NONCE_NAME,
|
||||
'referrer' => false,
|
||||
),
|
||||
'action' =>
|
||||
'?controller=front&action=ai1ec_api_ticketing_signup&plugin=' .
|
||||
AI1EC_PLUGIN_NAME,
|
||||
'purchases' => $purchases,
|
||||
'paypal_currencies' => array (
|
||||
array( 'description' => Ai1ec_I18n::__( 'United States Dollar' ), 'code' => 'USD' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Canadian Dollar' ), 'code' => 'CAD' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Australian Dollar' ), 'code' => 'AUD' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Brazilian Real' ), 'code' => 'BRL', 'note' => Ai1ec_I18n::__( 'Note: This currency is supported as a payment currency and a currency balance for in-country PayPal accounts only.' ) ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Czech Koruna' ), 'code' => 'CZK' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Danish Krone' ), 'code' => 'DKK' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Euro' ), 'code' => 'EUR' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Hong Kong Dollar' ), 'code' => 'HKD' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Hungarian Forint' ), 'code' => 'HUF', 'note' => Ai1ec_I18n::__( 'Note: Decimal amounts are not supported for this currency. Passing a decimal amount will throw an error.' ) ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Israeli New Sheqel' ), 'code' => 'ILS' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Japanese Yen' ), 'code' => 'JPY', 'note' => Ai1ec_I18n::__( 'Note: This currency does not support decimals. Passing a decimal amount will throw an error. 1,000,000' ) ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Malaysian Ringgit' ), 'code' => 'MYR', 'note' => Ai1ec_I18n::__( 'Note: This currency is supported as a payment currency and a currency balance for in-country PayPal accounts only.' ) ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Mexican Peso' ), 'code' => 'MXN' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Norwegian Krone' ), 'code' => 'NOK' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'New Zealand Dollar' ), 'code' => 'NZD' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Philippine Peso' ), 'code' => 'PHP' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Polish Zloty' ), 'code' => 'PLN' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Pound Sterling' ), 'code' => 'GBP' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Russian Ruble' ), 'code' => 'RUB', 'note' => Ai1ec_I18n::__( 'For in-border payments (payments made within Russia), the Russian Ruble is the only accepted currency. If you use another currency for in-border payments, the transaction will fail' ) ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Singapore Dollar' ), 'code' => 'SGD' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Swedish Krona' ), 'code' => 'SEK' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Swiss Franc' ), 'code' => 'CHF' ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Taiwan New Dollar' ), 'code' => 'TWD', 'note' => Ai1ec_I18n::__( 'Note: Decimal amounts are not supported for this currency. Passing a decimal amount will throw an error.' ) ),
|
||||
array( 'description' => Ai1ec_I18n::__( 'Thai Baht' ), 'code' => 'THB' ),
|
||||
)
|
||||
);
|
||||
$file = $loader->get_file( 'ticketing/manage.twig', $args, true );
|
||||
}
|
||||
|
||||
$this->_registry->get( 'css.admin' )->admin_enqueue_scripts(
|
||||
'ai1ec_event_page_all-in-one-event-calendar-settings'
|
||||
);
|
||||
$this->_registry->get( 'css.admin' )->process_enqueue(
|
||||
array(
|
||||
array( 'style', 'ticketing.css', ),
|
||||
)
|
||||
);
|
||||
if ( isset( $_POST['ai1ec_save_settings'] ) ) {
|
||||
$response = $this->_api_registration->save_payment_preferences();
|
||||
|
||||
// this redirect makes sure that the error messages appear on the screen
|
||||
if ( isset( $_SERVER['HTTP_REFERER'] ) ) {
|
||||
header( "Location: " . $_SERVER['HTTP_REFERER'] );
|
||||
}
|
||||
}
|
||||
return $file->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle post, likely to be deprecated to use commands.
|
||||
*/
|
||||
public function handle_post(){}
|
||||
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The SuperWidget creator page.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.1
|
||||
*
|
||||
* @package AI1ECSW
|
||||
* @subpackage AI1ECSW.View
|
||||
*/
|
||||
class Ai1ec_View_Widget_Creator extends Ai1ec_View_Admin_Abstract {
|
||||
|
||||
/**
|
||||
* Adds page to the menu.
|
||||
*
|
||||
* @wp_hook admin_menu
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_page() {
|
||||
add_submenu_page(
|
||||
AI1EC_ADMIN_BASE_URL,
|
||||
__( 'Widget Creator', AI1EC_PLUGIN_NAME ),
|
||||
__( 'Widget Creator', AI1EC_PLUGIN_NAME ),
|
||||
'manage_ai1ec_feeds',
|
||||
AI1EC_PLUGIN_NAME . '-widget-creator',
|
||||
array( $this, 'display_page' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display this plugin's feeds page in the admin.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_page() {
|
||||
$this->_registry->get( 'css.admin' )->admin_enqueue_scripts(
|
||||
'ai1ec_event_page_all-in-one-event-calendar-settings'
|
||||
);
|
||||
$this->_registry->get( 'css.admin' )->process_enqueue(
|
||||
array(
|
||||
array( 'style', 'super-widget.css', ),
|
||||
)
|
||||
);
|
||||
$args = array(
|
||||
'title' => __(
|
||||
'Widget Creator',
|
||||
AI1EC_PLUGIN_NAME
|
||||
),
|
||||
'metabox' => array(
|
||||
'screen' => 'ai1ec-super-widget',
|
||||
'action' => 'left',
|
||||
'object' => null
|
||||
),
|
||||
);
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$file = $loader->get_file( 'widget-creator/page.twig', $args, true );
|
||||
$file->render();
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_View_Admin_Settings::handle_post()
|
||||
*/
|
||||
public function handle_post() {
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_View_Admin_Settings::add_meta_box()
|
||||
*/
|
||||
public function add_meta_box() {
|
||||
add_meta_box(
|
||||
'ai1ec-widget-creator',
|
||||
_x( 'Widget Creator', 'meta box', AI1EC_PLUGIN_NAME ),
|
||||
array( $this, 'display_meta_box' ),
|
||||
'ai1ec-super-widget',
|
||||
'left',
|
||||
'default'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the settings
|
||||
*
|
||||
* @param array $settings
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_html_from_settings( array $settings ) {
|
||||
$named_elements = array();
|
||||
foreach ( $settings as $id => $setting ) {
|
||||
$named_elements[$id] = $this->_registry->get(
|
||||
'html.element.setting.' . $setting['renderer']['class'],
|
||||
array(
|
||||
'id' => $id,
|
||||
'value' => $setting['value'],
|
||||
'renderer' => $setting['renderer'],
|
||||
)
|
||||
)->render();
|
||||
}
|
||||
return $named_elements;
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_View_Admin_Settings::display_meta_box()
|
||||
*/
|
||||
public function display_meta_box( $object, $box ) {
|
||||
$widgets = $this->_registry->get( 'controller.javascript-widget' )
|
||||
->get_widgets();
|
||||
// this is just for the Super Widget which doesn't fully implement Ai1ec_Embeddable
|
||||
$widgets = apply_filters( 'ai1ec_widget_creators_widgets', $widgets );
|
||||
$tabs = array();
|
||||
foreach ( $widgets as $widget_id => $widget_class ) {
|
||||
$widget = $this->_registry->get( $widget_class );
|
||||
$tabs[$widget_id] = array(
|
||||
'name' => $widget->get_name(),
|
||||
'icon' => $widget->get_icon(),
|
||||
'requirements' => $widget->check_requirements(),
|
||||
'elements' => $this->get_html_from_settings(
|
||||
$widget->get_configurable_for_widget_creation()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$file = $loader->get_file(
|
||||
'widget-creator/super-widget-contents.twig',
|
||||
array(
|
||||
'tabs' => $tabs,
|
||||
'siteurl' => trailingslashit( preg_replace( '/^.*?:/', '', ai1ec_get_site_url() ) ),
|
||||
'text_common_info' => Ai1ec_I18n::__( 'Use this tool to generate code snippets you can add to <strong>an external website</strong> to embed new calendars and widgets.' ),
|
||||
'text_alert' => Ai1ec_I18n::__( '<h4>Attention!</h4><p>These widgets are designed to be embedded in <strong>external sites only</strong> and may cause conflicts if used within the same WordPress site.</p>' ),
|
||||
'text_alternatives' => sprintf(
|
||||
Ai1ec_I18n::__( '<p>Use <a href="%s"><strong>Appearance</strong> > <strong>Widgets</strong></a> to add event widgets to your WordPress site as you would any other widget, or use <a href="%s" target="_blank">shortcodes</a> to embed the full calendar.</strong></p>' ),
|
||||
admin_url( 'widgets.php' ),
|
||||
'https://time.ly/document/user-guide/using-calendar/display-multiple-calendars-site/'
|
||||
),
|
||||
'display_alert' => apply_filters( 'ai1ec_display_widget_creator_warning', true ),
|
||||
'text_preview' => Ai1ec_I18n::__( 'Preview:' ),
|
||||
'text_paste' => Ai1ec_I18n::__( 'Paste this code onto your site:' ),
|
||||
'text_updated_code' => Ai1ec_I18n::__( 'This code will update to reflect changes made to the settings. Changing settings will not affect previously embedded widgets.' ),
|
||||
),
|
||||
true
|
||||
);
|
||||
$file->render();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The concrete class for the calendar page.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.1
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_Calendar_Avatar_Fallbacks extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Default avatar fallbacks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_fallbacks = array(
|
||||
'post_thumbnail',
|
||||
'content_img',
|
||||
'category_avatar',
|
||||
);
|
||||
|
||||
/**
|
||||
* Get registered fallbacks.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_all() {
|
||||
return apply_filters( 'ai1ec_avatar_fallbacks', $this->_fallbacks );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register new avatar fallbacks.
|
||||
*
|
||||
* @param array $fallbacks Fallbacks.
|
||||
*
|
||||
* @return void Method does not return.
|
||||
*/
|
||||
public function set( array $fallbacks ) {
|
||||
$this->_fallbacks = $fallbacks;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,522 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The concrete class for the calendar page.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_Calendar_Page extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Memory_Utility Instance of memory to hold exact dates
|
||||
*/
|
||||
protected $_exact_dates = NULL;
|
||||
|
||||
/**
|
||||
* Public constructor
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry The registry object
|
||||
*/
|
||||
public function __construct( Ai1ec_Registry_Object $registry ) {
|
||||
parent::__construct( $registry );
|
||||
$this->_exact_dates = $registry->get( 'cache.memory' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content if the calendar page
|
||||
*
|
||||
* @param Ai1ec_Request_Parser $request Request object.
|
||||
* @param string $caller Method caller, expected one of
|
||||
* ['shortcode', 'render-command']
|
||||
* Defaults to 'render-command'.
|
||||
*
|
||||
* @return string Content.
|
||||
*/
|
||||
public function get_content(
|
||||
Ai1ec_Request_Parser $request,
|
||||
$caller = 'render-command'
|
||||
) {
|
||||
// Get args for the current view; required to generate HTML for views
|
||||
// dropdown list, categories, tags, subscribe buttons, and of course the
|
||||
// view itself.
|
||||
$view_args = $this->get_view_args_for_view( $request );
|
||||
|
||||
try {
|
||||
$action = $this->_registry->get( 'model.settings-view' )
|
||||
->get_configured( $view_args['action'] );
|
||||
} catch ( Ai1ec_Settings_Exception $exception ) {
|
||||
// short-circuit and return error message
|
||||
return '<div id="ai1ec-container"><div class="timely"><p>' .
|
||||
Ai1ec_I18n::__(
|
||||
'There was an error loading calendar. Please contact site administrator and inform him to configure calendar views.'
|
||||
) .
|
||||
'</p></div></div>';
|
||||
}
|
||||
$type = $request->get( 'request_type' );
|
||||
$is_json = $this->_registry->get( 'http.request' )->is_json_required(
|
||||
$view_args['request_format'], $action
|
||||
);
|
||||
|
||||
// Add view-specific args to the current view args.
|
||||
$exact_date = $this->get_exact_date( $request );
|
||||
try {
|
||||
$view_obj = $this->_registry->get(
|
||||
'view.calendar.view.' . $action,
|
||||
$request
|
||||
);
|
||||
} catch ( Ai1ec_Bootstrap_Exception $exc ) {
|
||||
$this->_registry->get( 'notification.admin' )->store(
|
||||
sprintf(
|
||||
Ai1ec_I18n::__( 'Calendar was unable to initialize %s view and has reverted to Agenda view. Please check if you have installed the latest versions of calendar add-ons.' ),
|
||||
ucfirst( $action )
|
||||
),
|
||||
'error',
|
||||
0,
|
||||
array( Ai1ec_Notification_Admin::RCPT_ADMIN ),
|
||||
true
|
||||
);
|
||||
// don't disable calendar - just switch to agenda which should
|
||||
// always exists
|
||||
$action = 'agenda';
|
||||
$view_obj = $this->_registry->get(
|
||||
'view.calendar.view.' . $action,
|
||||
$request
|
||||
);
|
||||
}
|
||||
$view_args = $view_obj->get_extra_arguments( $view_args, $exact_date );
|
||||
|
||||
// Get HTML for views dropdown list.
|
||||
$dropdown_args = $view_args;
|
||||
if (
|
||||
isset( $dropdown_args['time_limit'] ) &&
|
||||
false !== $exact_date
|
||||
) {
|
||||
$dropdown_args['exact_date'] = $exact_date;
|
||||
}
|
||||
$views_dropdown =
|
||||
$this->get_html_for_views_dropdown( $dropdown_args, $view_obj );
|
||||
// Add views dropdown markup to view args.
|
||||
$view_args['views_dropdown'] = $views_dropdown;
|
||||
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
if ( $settings->get( 'ai1ec_use_frontend_rendering' ) ) {
|
||||
$view_args['request_format'] = 'json';
|
||||
}
|
||||
|
||||
// Get HTML for subscribe buttons.
|
||||
$subscribe_buttons = $this->get_html_for_subscribe_buttons( $view_args );
|
||||
|
||||
// Get HTML for view itself.
|
||||
$view = $view_obj->get_content( $view_args );
|
||||
|
||||
$router = $this->_registry->get( 'routing.router' );
|
||||
$are_filters_set = $router->is_at_least_one_filter_set_in_request(
|
||||
$view_args
|
||||
);
|
||||
|
||||
if (
|
||||
$is_json &&
|
||||
( $view_args['no_navigation'] || $type !== 'html' )
|
||||
) {
|
||||
// send data both for json and jsonp as shortcodes are jsonp
|
||||
return array(
|
||||
'html' => $view,
|
||||
'views_dropdown' => $views_dropdown,
|
||||
'subscribe_buttons' => $subscribe_buttons,
|
||||
'are_filters_set' => $are_filters_set,
|
||||
'is_json' => $is_json,
|
||||
);
|
||||
|
||||
} else {
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$empty = $loader->get_file( 'empty.twig', array(), false );
|
||||
// Get HTML for categories and for tags
|
||||
$taxonomy = $this->_registry->get( 'view.calendar.taxonomy' );
|
||||
$categories = $taxonomy->get_html_for_categories(
|
||||
$view_args
|
||||
);
|
||||
$tags = $taxonomy->get_html_for_tags(
|
||||
$view_args,
|
||||
true
|
||||
);
|
||||
|
||||
// option to show filters in the super widget
|
||||
// Define new arguments for overall calendar view
|
||||
$filter_args = array(
|
||||
'views_dropdown' => $views_dropdown,
|
||||
'categories' => $categories,
|
||||
'tags' => $tags,
|
||||
'contribution_buttons' => apply_filters(
|
||||
'ai1ec_contribution_buttons',
|
||||
'',
|
||||
$type,
|
||||
$caller
|
||||
),
|
||||
'additional_buttons' => apply_filters(
|
||||
'ai1ec_additional_buttons',
|
||||
'',
|
||||
$view_args
|
||||
),
|
||||
'show_dropdowns' => apply_filters(
|
||||
'ai1ec_show_dropdowns',
|
||||
true
|
||||
),
|
||||
'show_select2' => apply_filters(
|
||||
'ai1ec_show_select2',
|
||||
false
|
||||
),
|
||||
'span_for_select2' => apply_filters(
|
||||
'ai1ec_span_for_select2',
|
||||
''
|
||||
),
|
||||
'authors' => apply_filters(
|
||||
'ai1ec_authors',
|
||||
''
|
||||
),
|
||||
'save_view_btngroup' => apply_filters(
|
||||
'ai1ec_save_view_btngroup',
|
||||
$empty
|
||||
),
|
||||
'view_args' => $view_args,
|
||||
'request' => $request,
|
||||
);
|
||||
|
||||
$filter_menu = $loader->get_file(
|
||||
'filter-menu.twig',
|
||||
$filter_args,
|
||||
false
|
||||
)->get_content();
|
||||
// hide filters in the SW
|
||||
if ( 'true' !== $request->get( 'display_filters' ) && 'jsonp' === $type ) {
|
||||
$filter_menu = '';
|
||||
}
|
||||
|
||||
$calendar_args = array(
|
||||
'version' => AI1EC_VERSION,
|
||||
'filter_menu' => $filter_menu,
|
||||
'view' => $view,
|
||||
'subscribe_buttons' => $subscribe_buttons,
|
||||
'disable_standard_filter_menu' => apply_filters(
|
||||
'ai1ec_disable_standard_filter_menu',
|
||||
false
|
||||
),
|
||||
'inline_js_calendar' => apply_filters(
|
||||
'ai1ec_inline_js_calendar',
|
||||
''
|
||||
),
|
||||
'after_view' => apply_filters(
|
||||
'ai1ec_after_view',
|
||||
''
|
||||
),
|
||||
'ai1ec_above_calendar' => apply_filters(
|
||||
'ai1ec_above_calendar',
|
||||
''
|
||||
),
|
||||
);
|
||||
|
||||
if ( is_array( $calendar_args['view'] ) ) {
|
||||
$view_args['request_format'] = 'html';
|
||||
$calendar_args['view'] = $view_obj->get_content( $view_args );
|
||||
}
|
||||
$calendar = $loader->get_file( 'calendar.twig', $calendar_args, false );
|
||||
// if it's just html, only the calendar html must be returned.
|
||||
if ( 'html' === $type ) {
|
||||
return $calendar->get_content();
|
||||
}
|
||||
// send data both for json and jsonp as shortcodes are jsonp
|
||||
return array(
|
||||
'html' => $calendar->get_content(),
|
||||
'views_dropdown' => $views_dropdown,
|
||||
'subscribe_buttons' => $subscribe_buttons,
|
||||
'are_filters_set' => $are_filters_set,
|
||||
'is_json' => $is_json
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the HTML for the `subscribe' buttons.
|
||||
*
|
||||
* @param array $view_args Args to pass.
|
||||
*
|
||||
* @return string Rendered HTML to include in output.
|
||||
*/
|
||||
public function get_html_for_subscribe_buttons( array $view_args ) {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$turn_off_subscribe = $settings->get( 'turn_off_subscription_buttons' );
|
||||
if ( $turn_off_subscribe ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'url_args' => '',
|
||||
'is_filtered' => false,
|
||||
'export_url' => AI1EC_EXPORT_URL,
|
||||
'export_url_no_html' => AI1EC_EXPORT_URL . '&no_html=true',
|
||||
'text_filtered' => Ai1ec_I18n::__( 'Subscribe to filtered calendar' ),
|
||||
'text_subscribe' => Ai1ec_I18n::__( 'Subscribe' ),
|
||||
'text_get_calendar' => Ai1ec_I18n::__( 'Get a Timely Calendar' ),
|
||||
'show_get_calendar' => ! $settings->get( 'disable_get_calendar_button' ),
|
||||
'text' => $this->_registry
|
||||
->get( 'view.calendar.subscribe-button' )
|
||||
->get_labels(),
|
||||
'placement' => 'up',
|
||||
);
|
||||
if ( ! empty( $view_args['cat_ids'] ) ) {
|
||||
$args['url_args'] .= '&ai1ec_cat_ids=' .
|
||||
implode( ',', $view_args['cat_ids'] );
|
||||
$args['is_filtered'] = true;
|
||||
}
|
||||
if ( ! empty( $view_args['tag_ids'] ) ) {
|
||||
$args['url_args'] .= '&ai1ec_tag_ids=' .
|
||||
implode( ',', $view_args['tag_ids'] );
|
||||
$args['is_filtered'] = true;
|
||||
}
|
||||
if ( ! empty( $view_args['post_ids'] ) ) {
|
||||
$args['url_args'] .= '&ai1ec_post_ids=' .
|
||||
implode( ',', $view_args['post_ids'] );
|
||||
$args['is_filtered'] = true;
|
||||
}
|
||||
$args = apply_filters(
|
||||
'ai1ec_subscribe_buttons_arguments',
|
||||
$args,
|
||||
$view_args
|
||||
);
|
||||
$localization = $this->_registry->get( 'p28n.wpml' );
|
||||
if (
|
||||
NULL !== ( $use_lang = $localization->get_language() )
|
||||
) {
|
||||
$args['url_args'] .= '&lang=' . $use_lang;
|
||||
}
|
||||
$subscribe = $this->_registry->get( 'theme.loader' )
|
||||
->get_file( 'subscribe-buttons.twig', $args, false );
|
||||
return $subscribe->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function generates the html for the view dropdowns.
|
||||
*
|
||||
* @param array $view_args Args passed to view
|
||||
* @param Ai1ec_Calendar_View_Abstract $view View object
|
||||
*/
|
||||
protected function get_html_for_views_dropdown(
|
||||
array $view_args,
|
||||
Ai1ec_Calendar_View_Abstract $view
|
||||
) {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$available_views = array();
|
||||
$enabled_views = (array)$settings->get( 'enabled_views', array() );
|
||||
$view_names = array();
|
||||
$mode = wp_is_mobile() ? '_mobile' : '';
|
||||
foreach ( $enabled_views as $key => $val ) {
|
||||
$view_names[$key] = translate_nooped_plural(
|
||||
$val['longname'],
|
||||
1
|
||||
);
|
||||
// Find out if view is enabled in requested mode (mobile or desktop). If
|
||||
// no mode-specific setting is available, fall back to desktop setting.
|
||||
$view_enabled = isset( $enabled_views[$key]['enabled' . $mode] ) ?
|
||||
$enabled_views[$key]['enabled' . $mode] :
|
||||
$enabled_views[$key]['enabled'];
|
||||
$values = array();
|
||||
$options = $view_args;
|
||||
if ( $view_enabled ) {
|
||||
if ( $view instanceof Ai1ec_Calendar_View_Agenda ) {
|
||||
if (
|
||||
isset( $options['exact_date'] ) &&
|
||||
! isset( $options['time_limit'] )
|
||||
) {
|
||||
$options['time_limit'] = $options['exact_date'];
|
||||
}
|
||||
unset( $options['exact_date'] );
|
||||
} else {
|
||||
unset( $options['time_limit'] );
|
||||
}
|
||||
unset( $options['month_offset'] );
|
||||
unset( $options['week_offset'] );
|
||||
unset( $options['oneday_offset'] );
|
||||
$options['action'] = $key;
|
||||
$values['desc'] = translate_nooped_plural(
|
||||
$val['longname'],
|
||||
1
|
||||
);
|
||||
if ( $settings->get( 'ai1ec_use_frontend_rendering' ) ) {
|
||||
$options['request_format'] = 'json';
|
||||
}
|
||||
$href = $this->_registry->get( 'html.element.href', $options );
|
||||
$values['href'] = $href->generate_href();
|
||||
$available_views[$key] = $values;
|
||||
}
|
||||
};
|
||||
$args = array(
|
||||
'view_names' => $view_names,
|
||||
'available_views' => $available_views,
|
||||
'current_view' => $view_args['action'],
|
||||
'data_type' => $view_args['data_type'],
|
||||
);
|
||||
|
||||
$views_dropdown = $this->_registry->get( 'theme.loader' )
|
||||
->get_file( 'views_dropdown.twig', $args, false );
|
||||
return $views_dropdown->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the exact date from request if available, or else from settings.
|
||||
*
|
||||
* @param Ai1ec_Abstract_Query settings
|
||||
*
|
||||
* @return boolean|int
|
||||
*/
|
||||
private function get_exact_date( Ai1ec_Abstract_Query $request ) {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
|
||||
// Preprocess exact_date.
|
||||
// Check to see if a date has been specified.
|
||||
$exact_date = $request->get( 'exact_date' );
|
||||
$use_key = $exact_date;
|
||||
if ( null === ( $exact_date = $this->_exact_dates->get( $use_key ) ) ) {
|
||||
$exact_date = $use_key;
|
||||
// Let's check if we have a date
|
||||
if ( false !== $exact_date ) {
|
||||
// If it's not a timestamp
|
||||
if ( ! Ai1ec_Validation_Utility::is_valid_time_stamp( $exact_date ) ) {
|
||||
// Try to parse it
|
||||
$exact_date = $this->return_gmtime_from_exact_date( $exact_date );
|
||||
if ( false === $exact_date ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Last try, let's see if an exact date is set in settings.
|
||||
if ( false === $exact_date && $settings->get( 'exact_date' ) !== '' ) {
|
||||
$exact_date = $this->return_gmtime_from_exact_date(
|
||||
$settings->get( 'exact_date' )
|
||||
);
|
||||
}
|
||||
$this->_exact_dates->set( $use_key, $exact_date );
|
||||
}
|
||||
return $exact_date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decomposes an 'exact_date' parameter into month, day, year components based
|
||||
* on date pattern defined in settings (assumed to be in local time zone),
|
||||
* then returns a timestamp in GMT.
|
||||
*
|
||||
* @param string $exact_date 'exact_date' parameter passed to a view
|
||||
* @return bool|int false if argument not provided or invalid,
|
||||
* else UNIX timestamp in GMT
|
||||
*/
|
||||
private function return_gmtime_from_exact_date( $exact_date ) {
|
||||
$input_format = $this->_registry->get( 'model.settings' )
|
||||
->get( 'input_date_format' );
|
||||
|
||||
$date = Ai1ec_Validation_Utility::format_as_iso(
|
||||
$exact_date,
|
||||
$input_format
|
||||
);
|
||||
if ( false === $date ) {
|
||||
$exact_date = false;
|
||||
} else {
|
||||
$exact_date = $this->_registry->get(
|
||||
'date.time',
|
||||
$date,
|
||||
'sys.default'
|
||||
)->format_to_gmt();
|
||||
if ( $exact_date < 0 ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return $exact_date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the correct data attribute to use in views
|
||||
*
|
||||
* @param string $type
|
||||
*/
|
||||
private function return_data_type_for_request_type( $type ) {
|
||||
$data_type = 'data-type="json"';
|
||||
if ( $type === 'jsonp' ) {
|
||||
$data_type = 'data-type="jsonp"';
|
||||
}
|
||||
return $data_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parameters for the view from the request object
|
||||
*
|
||||
* @param Ai1ec_Abstract_Query $request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_view_args_for_view( Ai1ec_Abstract_Query $request ) {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
// Define arguments for specific calendar sub-view (month, agenda, etc.)
|
||||
// Preprocess action.
|
||||
// Allow action w/ or w/o ai1ec_ prefix. Remove ai1ec_ if provided.
|
||||
$action = $request->get( 'action' );
|
||||
|
||||
if ( 0 === strncmp( $action, 'ai1ec_', 6 ) ) {
|
||||
$action = substr( $action, 6 );
|
||||
}
|
||||
$view_args = $request->get_dict(
|
||||
apply_filters(
|
||||
'ai1ec_view_args_for_view',
|
||||
array(
|
||||
'post_ids',
|
||||
'auth_ids',
|
||||
'cat_ids',
|
||||
'tag_ids',
|
||||
'events_limit',
|
||||
'instance_ids',
|
||||
)
|
||||
)
|
||||
);
|
||||
$type = $request->get( 'request_type' );
|
||||
if ( 'html' === $type ) {
|
||||
$add_defaults = array(
|
||||
'cat_ids' => 'categories',
|
||||
'tag_ids' => 'tags',
|
||||
);
|
||||
foreach ( $add_defaults as $query => $default ) {
|
||||
if ( empty( $view_args[$query] ) ) {
|
||||
$setting = $settings->get( 'default_tags_categories' );
|
||||
if ( isset( $setting[$default] ) ) {
|
||||
$view_args[$query] = $setting[$default];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$view_args['data_type'] = $this->return_data_type_for_request_type(
|
||||
$type
|
||||
);
|
||||
|
||||
$view_args['request_format'] = $request->get( 'request_format' );
|
||||
$exact_date = $this->get_exact_date( $request );
|
||||
|
||||
$view_args['no_navigation'] = $request->get( 'no_navigation' ) == true;
|
||||
|
||||
// Find out which view of the calendar page was requested, and render it
|
||||
// accordingly.
|
||||
$view_args['action'] = $action;
|
||||
|
||||
$view_args['request'] = $request;
|
||||
$view_args = apply_filters(
|
||||
'ai1ec_view_args_array',
|
||||
$view_args
|
||||
);
|
||||
if ( null === $exact_date ) {
|
||||
$href = $this->_registry->get( 'html.element.href', $view_args )
|
||||
->generate_href();
|
||||
return Ai1ec_Http_Response_Helper::redirect( $href, 307 );
|
||||
|
||||
}
|
||||
return $view_args;
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The class that handles rendering the shortcode.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Calendar_Shortcode extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Generate replacement content for [ai1ec] shortcode.
|
||||
*
|
||||
* @param array $atts Attributes provided on shortcode
|
||||
* @param string $content Tag internal content (shall be empty)
|
||||
* @param string $tag Used tag name (must be 'ai1ec' always)
|
||||
*
|
||||
* @staticvar $call_count Used to restrict to single calendar per page
|
||||
*
|
||||
* @return string Replacement for shortcode entry
|
||||
*/
|
||||
public function shortcode( $atts, $content = '', $tag = 'ai1ec' ) {
|
||||
$settings_view = $this->_registry->get( 'model.settings-view' );
|
||||
$view_names_list = array_keys( $settings_view->get_all() );
|
||||
$default_view = $settings_view->get_default();
|
||||
|
||||
$view_names = array();
|
||||
foreach ( $view_names_list as $view_name ) {
|
||||
$view_names[$view_name] = true;
|
||||
}
|
||||
|
||||
$view = $default_view;
|
||||
$_events_categories = $_events_tags = $post_ids = array();
|
||||
|
||||
if ( isset( $atts['view'] ) ) {
|
||||
if ( 'ly' === substr( $atts['view'], -2 ) ) {
|
||||
$atts['view'] = substr( $atts['view'], 0, -2 );
|
||||
}
|
||||
if ( ! isset( $view_names[$atts['view']] ) ) {
|
||||
return false;
|
||||
}
|
||||
$view = $atts['view'];
|
||||
}
|
||||
|
||||
$mappings = array(
|
||||
'cat_name' => 'events_categories',
|
||||
'cat_id' => 'events_categories',
|
||||
'tag_name' => 'events_tags',
|
||||
'tag_id' => 'events_tags',
|
||||
'post_id' => 'post_ids',
|
||||
'events_limit' => 'events_limit',
|
||||
);
|
||||
$matches = array();
|
||||
$custom_taxonomies = array();
|
||||
if ( ! empty( $atts ) ) {
|
||||
foreach ( $atts as $att => $value ) {
|
||||
if (
|
||||
! preg_match( '/([a-z0-9\_]+)_(id|name)/', $att, $matches ) ||
|
||||
isset( $mappings[$matches[1] . '_id'] )
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
${'_' . $matches[1] . '_ids'} = array();
|
||||
$custom_taxonomies[] = $matches[1];
|
||||
|
||||
if ( ! isset( $mappings[$matches[1] . '_id'] ) ) {
|
||||
$mappings[$matches[1] . '_id'] = $matches[1];
|
||||
}
|
||||
if ( ! isset( $mappings[$matches[1] . '_name'] ) ) {
|
||||
$mappings[$matches[1] . '_name'] = $matches[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $mappings as $att_name => $type ) {
|
||||
if ( ! isset( $atts[$att_name] ) ) {
|
||||
continue;
|
||||
}
|
||||
$raw_values = explode( ',', $atts[$att_name] );
|
||||
foreach ( $raw_values as $argument ) {
|
||||
if ( 'post_id' === $att_name ) {
|
||||
if ( ( $argument = (int)$argument ) > 0 ) {
|
||||
$post_ids[] = $argument;
|
||||
}
|
||||
} else {
|
||||
if ( ! is_numeric( $argument ) ) {
|
||||
$search_val = trim( $argument );
|
||||
$argument = false;
|
||||
foreach ( array( 'name', 'slug' ) as $field ) {
|
||||
$record = get_term_by(
|
||||
$field,
|
||||
$search_val,
|
||||
$type
|
||||
);
|
||||
if ( false !== $record ) {
|
||||
$argument = $record;
|
||||
break;
|
||||
}
|
||||
}
|
||||
unset( $search_val, $record, $field );
|
||||
if ( false === $argument ) {
|
||||
continue;
|
||||
}
|
||||
$argument = (int)$argument->term_id;
|
||||
} else {
|
||||
if ( ( $argument = (int)$argument ) <= 0 ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
${'_' . $type}[] = $argument;
|
||||
}
|
||||
}
|
||||
}
|
||||
$query = array(
|
||||
'ai1ec_cat_ids' => implode( ',', $_events_categories ),
|
||||
'ai1ec_tag_ids' => implode( ',', $_events_tags ),
|
||||
'ai1ec_post_ids' => implode( ',', $post_ids ),
|
||||
'action' => $view,
|
||||
'request_type' => 'jsonp',
|
||||
'events_limit' => isset( $atts['events_limit'] )
|
||||
// definition above casts values as array, so we take first element,
|
||||
// as there won't be others
|
||||
? (int) $atts['events_limit']
|
||||
: null,
|
||||
);
|
||||
// this is the opposite of how the SuperWidget works.
|
||||
if ( ! isset( $atts['display_filters'] ) ) {
|
||||
$query['display_filters'] = 'true';
|
||||
} else {
|
||||
$query['display_filters'] = $atts['display_filters'];
|
||||
}
|
||||
|
||||
foreach ( $custom_taxonomies as $taxonomy ) {
|
||||
$query['ai1ec_' . $taxonomy . '_ids'] = implode( ',', ${'_' . $taxonomy} );
|
||||
}
|
||||
if ( isset( $atts['exact_date'] ) ) {
|
||||
$query['exact_date'] = $atts['exact_date'];
|
||||
}
|
||||
$request = $this->_registry->get(
|
||||
'http.request.parser',
|
||||
$query,
|
||||
$default_view
|
||||
);
|
||||
$request->parse();
|
||||
$page_content = $this->_registry->get( 'view.calendar.page' )
|
||||
->get_content( $request, 'shortcode' );
|
||||
$this->_registry->get( 'css.frontend' )
|
||||
->add_link_to_html_for_frontend();
|
||||
$this->_registry->get( 'controller.javascript' )
|
||||
->load_frontend_js( true );
|
||||
$page_content['html'] = preg_replace( '/\s+/', ' ', $page_content['html'] );
|
||||
return $page_content['html'];
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Generate translation entities for subscription buttons.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Calendar_SubscribeButton {
|
||||
|
||||
/**
|
||||
* Get a list of texts for subscribtion buttons.
|
||||
*
|
||||
* @return array Map of labels.
|
||||
*/
|
||||
public function get_labels() {
|
||||
return array(
|
||||
'label' => array(
|
||||
'timely' => Ai1ec_I18n::__( 'Add to Timely Calendar' ),
|
||||
'google' => Ai1ec_I18n::__( 'Add to Google' ),
|
||||
'outlook' => Ai1ec_I18n::__( 'Add to Outlook' ),
|
||||
'apple' => Ai1ec_I18n::__( 'Add to Apple Calendar' ),
|
||||
'plaintext' => Ai1ec_I18n::__( 'Add to other calendar' ),
|
||||
'xml' => Ai1ec_I18n::__( 'Export to XML' ),
|
||||
),
|
||||
'title' => array(
|
||||
'timely' => Ai1ec_I18n::__( 'Copy this URL for your own Timely calendar or click to add to your rich-text calendar' ),
|
||||
'google' => Ai1ec_I18n::__( 'Subscribe to this calendar in your Google Calendar' ),
|
||||
'outlook' => Ai1ec_I18n::__( 'Subscribe to this calendar in MS Outlook' ),
|
||||
'apple' => Ai1ec_I18n::__( 'Subscribe to this calendar in Apple Calendar/iCal' ),
|
||||
'plaintext' => Ai1ec_I18n::__( 'Subscribe to this calendar in another plain-text calendar' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The class that handles html generation for taxonomies.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_View_Calendar_Taxonomy extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Returns a link to a calendar page without the given arguments; does not
|
||||
* otherwise disturb current page state.
|
||||
*
|
||||
* @param array $args Current arguments to the calendar
|
||||
* @param array $args_to_remove Names of arguments to remove from current args
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generate_href_without_arguments(
|
||||
array $args,
|
||||
array $args_to_remove
|
||||
) {
|
||||
$args_to_remove = array_flip( $args_to_remove );
|
||||
$args = array_diff_key( $args, $args_to_remove );
|
||||
$href = $this->_registry->get( 'html.element.href', $args );
|
||||
return $href->generate_href();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the html for tags filter
|
||||
*
|
||||
* @param array $view_args
|
||||
* @return string
|
||||
*/
|
||||
public function get_html_for_tags( array $view_args ) {
|
||||
return $this->_get_html_for_taxonomy( $view_args, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the html for categories filter
|
||||
*
|
||||
* @param array $view_args
|
||||
* @return string
|
||||
*/
|
||||
public function get_html_for_categories( array $view_args ) {
|
||||
return $this->_get_html_for_taxonomy( $view_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the HTML for a taxonomy selector.
|
||||
*
|
||||
* @param array $view_args Arguments to the parent view
|
||||
* @param bool $tag whether it's tags or categories.
|
||||
*
|
||||
* @return string Markup for categories selector
|
||||
*/
|
||||
protected function _get_html_for_taxonomy( $view_args, $tag = false ) {
|
||||
$taxonomy_name = 'events_categories';
|
||||
$type = 'category';
|
||||
$type_for_filter = 'cat_ids';
|
||||
$type_for_view_args = 'categories';
|
||||
if ( true === $tag ) {
|
||||
$taxonomy_name = 'events_tags';
|
||||
$type = 'tag';
|
||||
$type_for_filter = 'tag_ids';
|
||||
$type_for_view_args = 'tags';
|
||||
}
|
||||
|
||||
|
||||
$terms = get_terms( $taxonomy_name, array( 'orderby' => 'name' ) );
|
||||
if( empty( $terms ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
foreach( $terms as &$term ) {
|
||||
$href = $this->_registry->get( 'html.element.href', $view_args, $type );
|
||||
$href->set_term_id( $term->term_id );
|
||||
$term->href = $href->generate_href();
|
||||
if ( false === $tag ) {
|
||||
$taxonomy = $this->_registry->get( 'view.event.taxonomy' );
|
||||
$term->color = $taxonomy->get_category_color_square( $term->term_id );
|
||||
}
|
||||
}
|
||||
|
||||
$href_for_clearing_filter =
|
||||
$this->generate_href_without_arguments( $view_args, array( $type_for_filter ) );
|
||||
|
||||
$args = array(
|
||||
$type_for_view_args => $terms,
|
||||
'selected_' . $type_for_filter => $view_args[$type_for_filter],
|
||||
'data_type' => $view_args['data_type'],
|
||||
'clear_filter' => $href_for_clearing_filter,
|
||||
'text_clear_category_filter' => __( 'Clear category filter', AI1EC_PLUGIN_NAME ),
|
||||
'text_categories' => __( 'Categories', AI1EC_PLUGIN_NAME ),
|
||||
'text_clear_tag_filter' => __( 'Clear tag filter', AI1EC_PLUGIN_NAME ),
|
||||
'text_tags' => __( 'Tags', AI1EC_PLUGIN_NAME ),
|
||||
);
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
return $loader->get_file( $type_for_view_args . '.twig', $args, false )
|
||||
->get_content();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,330 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The abstract class for a view.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
abstract class Ai1ec_Calendar_View_Abstract extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Request_Parser The request object
|
||||
*/
|
||||
protected $_request;
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Compatibility_Check Theme compatibility check object.
|
||||
*/
|
||||
protected $_compatibility;
|
||||
|
||||
/**
|
||||
* Public constructor
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry
|
||||
* @param Ai1ec_Request_Parser $request
|
||||
*/
|
||||
public function __construct( Ai1ec_Registry_Object $registry, Ai1ec_Request_Parser $request ) {
|
||||
parent::__construct( $registry );
|
||||
$this->_request = $request;
|
||||
$this->_compatibility = $registry->get( 'compatibility.check' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the machine name for the view
|
||||
*
|
||||
* @return string The machine name of the view.
|
||||
*/
|
||||
abstract public function get_name();
|
||||
|
||||
/**
|
||||
* Get extra arguments specific for the view
|
||||
*
|
||||
* @param array $view_args
|
||||
* @param int|bool $exact_date the exact date used to display the view.
|
||||
*
|
||||
* @return array The view arguments with the extra parameters added.
|
||||
*/
|
||||
public function get_extra_arguments( array $view_args, $exact_date ) {
|
||||
$offset = $this->get_name() . '_offset';
|
||||
$view_args[$offset] = $this->_request->get( $offset );
|
||||
if( false !== $exact_date ) {
|
||||
$view_args['exact_date'] = $exact_date;
|
||||
}
|
||||
return $view_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extra arguments specific for the view's template
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return array The template arguments with the extra parameters added.
|
||||
*/
|
||||
public function get_extra_template_arguments( array $args ) {
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$args['action_buttons'] = apply_filters(
|
||||
'ai1ec_add_action_buttons',
|
||||
$this->_action_buttons()
|
||||
);
|
||||
if (
|
||||
true === apply_filters(
|
||||
'ai1ec_buy_button_product',
|
||||
false
|
||||
)
|
||||
) {
|
||||
$args['has_product_buy_button'] = true;
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the view and return the content
|
||||
*
|
||||
* @param array $view_args
|
||||
*
|
||||
* @return string the html of the view
|
||||
*/
|
||||
abstract public function get_content( array $view_args );
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string HTML of action buttons
|
||||
*/
|
||||
protected function _action_buttons() {
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$action_buttons = $loader->get_file(
|
||||
'buttons.twig',
|
||||
array(
|
||||
'action_buttons' => apply_filters(
|
||||
'ai1ec_action_buttons',
|
||||
''
|
||||
),
|
||||
'tickets_button' => true,
|
||||
'text_tickets' => __( 'Tickets', AI1EC_PLUGIN_NAME ),
|
||||
'has_buy_tickets_product' => apply_filters(
|
||||
'ai1ec_buy_button_product',
|
||||
false
|
||||
)
|
||||
),
|
||||
false
|
||||
)->get_content();
|
||||
return $action_buttons;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $exact_date
|
||||
*/
|
||||
protected function _create_link_for_day_view( $exact_date ) {
|
||||
$href = $this->_registry->get(
|
||||
'html.element.href',
|
||||
array(
|
||||
'action' => 'oneday',
|
||||
'exact_date' => $exact_date,
|
||||
)
|
||||
);
|
||||
return $href->generate_href();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view html
|
||||
*
|
||||
* @param array $view_args
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _get_view( array $view_args ) {
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$view = $this->get_name();
|
||||
$file = $loader->get_file( $view . '.twig', $view_args, false );
|
||||
|
||||
return apply_filters(
|
||||
'ai1ec_get_' . $view . '_view',
|
||||
$file->get_content(),
|
||||
$view_args
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies filters to view args for front end rendering
|
||||
*
|
||||
* @param array $args
|
||||
*/
|
||||
protected function _apply_filters_to_args( array $args ) {
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$view = $this->get_name();
|
||||
return $loader->apply_filters_to_args( $args, $view . '.twig', false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare week specific event start/end timestamps.
|
||||
*
|
||||
* @param Ai1ec_Event $event Instance of event.
|
||||
*
|
||||
* @return array Start and end respectively in 0 and 1 positions.
|
||||
*/
|
||||
protected function _get_view_specific_timestamps( Ai1ec_Event $event ) {
|
||||
if ( $event->is_allday() ) {
|
||||
// reset to be day-contained with respect to current timezone
|
||||
$event_start = $this->_registry
|
||||
->get( 'date.time', $event->get( 'start' ), 'sys.default' )
|
||||
->set_time( 0, 0, 0 )
|
||||
->format();
|
||||
$event_end = $this->_registry
|
||||
->get( 'date.time', $event->get( 'end' ), 'sys.default' )
|
||||
->set_time( 0, 0, 0 )
|
||||
->format();
|
||||
} else {
|
||||
$event_start = $event->get( 'start' )->format();
|
||||
$event_end = $event->get( 'end' )->format();
|
||||
}
|
||||
return array( $event_start, $event_end );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update metadata for retrieved events.
|
||||
*
|
||||
* This speeds up further meta data requests.
|
||||
*
|
||||
* @param array $events List of events retrieved.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _update_meta( array $events ) {
|
||||
$post_ids = array();
|
||||
foreach ( $events as $event ) {
|
||||
$post_ids[] = (int)$event->get( 'post_id' );
|
||||
}
|
||||
update_meta_cache( 'post', $post_ids );
|
||||
$this->_registry->get( 'model.taxonomy' )
|
||||
->update_meta( $post_ids );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the navigation bar HTML.
|
||||
*
|
||||
* @param array $nav_args Args for the navigation bar template, including
|
||||
* 'no_navigation' which determines whether to show it
|
||||
* @return string
|
||||
*/
|
||||
protected function _get_navigation( array $nav_args ) {
|
||||
$navigation = '';
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$nav_args['contribution_buttons'] = apply_filters(
|
||||
'ai1ec_contribution_buttons',
|
||||
'',
|
||||
'html',
|
||||
'render-command'
|
||||
);
|
||||
if ( true !== $nav_args['no_navigation'] ) {
|
||||
$navigation = $loader->get_file(
|
||||
'navigation.twig',
|
||||
$nav_args,
|
||||
false
|
||||
)->get_content();
|
||||
}
|
||||
return $navigation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the get_*_pagination_links method for the current view type and
|
||||
* renders its result, returning the rendered pagination links.
|
||||
*
|
||||
* @param array $args Current request arguments
|
||||
* @param string $title Title to display in datepicker button
|
||||
* @return string
|
||||
*/
|
||||
protected function _get_pagination( array $args, $title ) {
|
||||
$method = 'get_' . $this->get_name() . '_pagination_links';
|
||||
$pagination_links = $this->$method( $args, $title );
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$pagination_links = $loader->get_file(
|
||||
'pagination.twig',
|
||||
array(
|
||||
'links' => $pagination_links,
|
||||
'data_type' => $args['data_type'],
|
||||
),
|
||||
false
|
||||
)->get_content();
|
||||
return $pagination_links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds runtime properties to the event.
|
||||
*
|
||||
* @param Ai1ec_Event $event
|
||||
*/
|
||||
protected function _add_runtime_properties( Ai1ec_Event $event ) {
|
||||
global $post;
|
||||
$original_post = $post;
|
||||
$post = $event->get( 'post' );
|
||||
$instance_permalink = get_permalink(
|
||||
$event->get( 'post_id' )
|
||||
);
|
||||
$instance_permalink = add_query_arg(
|
||||
'instance_id',
|
||||
$event->get( 'instance_id' ),
|
||||
$instance_permalink
|
||||
);
|
||||
$event->set_runtime( 'instance_permalink', $instance_permalink );
|
||||
|
||||
$event->set_runtime(
|
||||
'filtered_title',
|
||||
apply_filters(
|
||||
'the_title',
|
||||
$event->get( 'post' )->post_title,
|
||||
$event->get( 'post_id' ),
|
||||
true
|
||||
)
|
||||
);
|
||||
$calendar_state = $this->_registry->get( 'calendar.state' );
|
||||
$calendar_state->set_append_content( false );
|
||||
$event->set_runtime(
|
||||
'filtered_content',
|
||||
apply_filters(
|
||||
'ai1ec_the_content',
|
||||
apply_filters(
|
||||
'the_content',
|
||||
$event->get( 'post' )->post_content
|
||||
)
|
||||
)
|
||||
);
|
||||
$calendar_state->set_append_content( true );
|
||||
|
||||
$taxonomy = $this->_registry->get( 'view.event.taxonomy' );
|
||||
$ticket = $this->_registry->get( 'view.event.ticket' );
|
||||
$event->set_runtime(
|
||||
'color_style',
|
||||
$taxonomy->get_color_style( $event )
|
||||
);
|
||||
$event->set_runtime( 'category_colors', $taxonomy->get_category_colors( $event ) );
|
||||
$event->set_runtime( 'ticket_url_label', $ticket->get_tickets_url_label( $event, false ) );
|
||||
$event->set_runtime( 'edit_post_link', get_edit_post_link( $event->get( 'post_id' ) ) );
|
||||
$event_post = $this->_registry->get( 'view.event.post' );
|
||||
$event->set_runtime( 'post_excerpt', $event_post->trim_excerpt( $event ) );
|
||||
$color = $this->_registry->get( 'view.event.color' );
|
||||
$event->set_runtime( 'faded_color', $color->get_faded_color( $event ) );
|
||||
$event->set_runtime( 'rgba_color', $color->get_rgba_color( $event ) );
|
||||
$event->set_runtime(
|
||||
'short_start_time',
|
||||
$this->_registry->get( 'view.event.time' )
|
||||
->get_short_time( $event->get( 'start' ) )
|
||||
);
|
||||
$this->_add_view_specific_runtime_properties( $event );
|
||||
$post = $original_post;
|
||||
}
|
||||
|
||||
/**
|
||||
* If some views have specific runtime properties they must extend this method
|
||||
*
|
||||
* @param Ai1ec_Event $event
|
||||
*/
|
||||
protected function _add_view_specific_runtime_properties( Ai1ec_Event $event ) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,582 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The concrete class for agenda view.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_Calendar_View_Agenda extends Ai1ec_Calendar_View_Abstract {
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Calendar_View_Abstract::get_name()
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'agenda';
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Calendar_View_Abstract::get_content()
|
||||
*/
|
||||
public function get_content( array $view_args ) {
|
||||
|
||||
$type = $this->get_name();
|
||||
$time = $this->_registry->get( 'date.system' );
|
||||
// Get localized time
|
||||
$timestamp = $time->current_time();
|
||||
|
||||
// Get events, then classify into date array
|
||||
$per_page_setting = $type . '_events_per_page';
|
||||
$search = $this->_registry->get( 'model.search' );
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$events_limit = is_numeric( $view_args['events_limit'] )
|
||||
? $view_args['events_limit']
|
||||
: $settings->get( $per_page_setting );
|
||||
$events_limit = apply_filters(
|
||||
'ai1ec_events_limit',
|
||||
$events_limit
|
||||
);
|
||||
$relative_to_reference = in_array( $this->get_name(), array( 'agenda', 'posterboard', 'stream' ) );
|
||||
if ( $relative_to_reference ) {
|
||||
$results = $search->get_events_relative_to_reference(
|
||||
$view_args['time_limit'],
|
||||
$events_limit,
|
||||
$view_args['page_offset'],
|
||||
apply_filters(
|
||||
'ai1ec_get_events_relative_to_filter',
|
||||
array(
|
||||
'post_ids' => $view_args['post_ids'],
|
||||
'auth_ids' => $view_args['auth_ids'],
|
||||
'cat_ids' => $view_args['cat_ids'],
|
||||
'tag_ids' => $view_args['tag_ids'],
|
||||
'instance_ids' => $view_args['instance_ids'],
|
||||
),
|
||||
$view_args
|
||||
),
|
||||
apply_filters(
|
||||
'ai1ec_show_unique_events',
|
||||
false
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$results = $search->get_events_relative_to(
|
||||
$timestamp,
|
||||
$events_limit,
|
||||
$view_args['page_offset'],
|
||||
apply_filters(
|
||||
'ai1ec_get_events_relative_to_filter',
|
||||
array(
|
||||
'post_ids' => $view_args['post_ids'],
|
||||
'auth_ids' => $view_args['auth_ids'],
|
||||
'cat_ids' => $view_args['cat_ids'],
|
||||
'tag_ids' => $view_args['tag_ids'],
|
||||
'instance_ids' => $view_args['instance_ids'],
|
||||
),
|
||||
$view_args
|
||||
),
|
||||
$view_args['time_limit'],
|
||||
apply_filters(
|
||||
'ai1ec_show_unique_events',
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
$this->_update_meta( $results['events'] );
|
||||
$dates = $this->get_agenda_like_date_array(
|
||||
$results['events'],
|
||||
$view_args['request']
|
||||
);
|
||||
|
||||
|
||||
// Generate title of view based on date range month & year.
|
||||
$range_start = $results['date_first'] &&
|
||||
false === $results['date_first']->is_empty() ?
|
||||
$results['date_first'] :
|
||||
$this->_registry->get( 'date.time', $timestamp );
|
||||
$range_end = $results['date_last'] &&
|
||||
false === $results['date_last']->is_empty() ?
|
||||
$results['date_last'] :
|
||||
$this->_registry->get( 'date.time', $timestamp );
|
||||
$range_start = $this->_registry->get( 'date.time', $range_start );
|
||||
$range_end = $this->_registry->get( 'date.time', $range_end );
|
||||
$start_year = $range_start->format_i18n( 'Y' );
|
||||
$end_year = $range_end->format_i18n( 'Y' );
|
||||
$start_month = $range_start->format_i18n( 'F' );
|
||||
$start_month_short = $range_start->format_i18n( 'M' );
|
||||
$end_month = $range_end->format_i18n( 'F' );
|
||||
$end_month_short = $range_end->format_i18n( 'M' );
|
||||
if ( $start_year === $end_year && $start_month === $end_month ) {
|
||||
$title = "$start_month $start_year";
|
||||
$title_short = "$start_month_short $start_year";
|
||||
} elseif ( $start_year === $end_year ) {
|
||||
$title = "$start_month – $end_month $end_year";
|
||||
$title_short = "$start_month_short – $end_month_short $end_year";
|
||||
} else {
|
||||
$title = "$start_month $start_year – $end_month $end_year";
|
||||
$title_short = "$start_month_short $start_year – $end_month_short $end_year";
|
||||
}
|
||||
|
||||
// Create navigation bar if requested.
|
||||
$navigation = '';
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$pagination_links = '';
|
||||
if ( ! $view_args['no_navigation'] ) {
|
||||
|
||||
if ( $relative_to_reference ) {
|
||||
$pagination_links = $this->_get_pagination_links(
|
||||
$view_args,
|
||||
$results['prev'],
|
||||
$results['next'],
|
||||
$results['date_first'],
|
||||
$results['date_last'],
|
||||
$title,
|
||||
$title_short,
|
||||
$view_args['page_offset'] + -1,
|
||||
$view_args['page_offset'] + 1
|
||||
);
|
||||
} else {
|
||||
$pagination_links = $this->_get_agenda_like_pagination_links(
|
||||
$view_args,
|
||||
$results['prev'],
|
||||
$results['next'],
|
||||
$results['date_first'],
|
||||
$results['date_last'],
|
||||
$title,
|
||||
$title_short,
|
||||
null === $view_args['time_limit'] ||
|
||||
0 === $view_args['time_limit'] ?
|
||||
$timestamp :
|
||||
$view_args['time_limit']
|
||||
);
|
||||
}
|
||||
|
||||
$pagination_links = $loader->get_file(
|
||||
'pagination.twig',
|
||||
array(
|
||||
'links' => $pagination_links,
|
||||
'data_type' => $view_args['data_type'],
|
||||
),
|
||||
false
|
||||
)->get_content();
|
||||
|
||||
// Get HTML for navigation bar.
|
||||
$nav_args = array(
|
||||
'no_navigation' => $view_args['no_navigation'],
|
||||
'pagination_links' => $pagination_links,
|
||||
'views_dropdown' => $view_args['views_dropdown'],
|
||||
'below_toolbar' => apply_filters(
|
||||
'ai1ec_below_toolbar',
|
||||
'',
|
||||
$type,
|
||||
$view_args
|
||||
),
|
||||
);
|
||||
// Add extra buttons to Agenda view's nav bar if events were returned.
|
||||
if ( $type === 'agenda' && $dates ) {
|
||||
$button_args = array(
|
||||
'text_collapse_all' => __( 'Collapse All', AI1EC_PLUGIN_NAME ),
|
||||
'text_expand_all' => __( 'Expand All', AI1EC_PLUGIN_NAME ),
|
||||
);
|
||||
$nav_args['after_pagination'] = $loader
|
||||
->get_file( 'agenda-buttons.twig', $button_args, false )
|
||||
->get_content();
|
||||
}
|
||||
$navigation = $this->_get_navigation( $nav_args );
|
||||
}
|
||||
|
||||
$is_ticket_button_enabled = apply_filters( 'ai1ec_' . $type . '_ticket_button', false );
|
||||
$args = array(
|
||||
'title' => $title,
|
||||
'dates' => $dates,
|
||||
'type' => $type,
|
||||
'show_year_in_agenda_dates' => $settings->get( 'show_year_in_agenda_dates' ),
|
||||
'expanded' => $settings->get( 'agenda_events_expanded' ),
|
||||
'show_location_in_title' => $settings->get( 'show_location_in_title' ),
|
||||
'page_offset' => $view_args['page_offset'],
|
||||
'navigation' => $navigation,
|
||||
'pagination_links' => $pagination_links,
|
||||
'post_ids' => join( ',', $view_args['post_ids'] ),
|
||||
'data_type' => $view_args['data_type'],
|
||||
'is_ticket_button_enabled' => $is_ticket_button_enabled,
|
||||
'text_upcoming_events' => __( 'There are no upcoming events to display at this time.', AI1EC_PLUGIN_NAME ),
|
||||
'text_edit' => __( 'Edit', AI1EC_PLUGIN_NAME ),
|
||||
'text_read_more' => __( 'Read more', AI1EC_PLUGIN_NAME ),
|
||||
'text_categories' => __( 'Categories:', AI1EC_PLUGIN_NAME ),
|
||||
'text_tags' => __( 'Tags:', AI1EC_PLUGIN_NAME ),
|
||||
'text_venue_separator' => __( '@ %s', AI1EC_PLUGIN_NAME ),
|
||||
);
|
||||
|
||||
// Allow child views to modify arguments passed to template.
|
||||
$args = $this->get_extra_template_arguments( $args );
|
||||
|
||||
return
|
||||
$this->_registry->get( 'http.request' )->is_json_required(
|
||||
$view_args['request_format'], $type
|
||||
)
|
||||
? $loader->apply_filters_to_args( $args, $type . '.twig', false )
|
||||
: $this->_get_view( $args );
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Calendar_View_Abstract::get_extra_arguments()
|
||||
*/
|
||||
public function get_extra_arguments( array $view_args, $exact_date ) {
|
||||
$view_args += $this->_request->get_dict( array(
|
||||
'page_offset',
|
||||
'time_limit',
|
||||
) );
|
||||
if( false !== $exact_date ) {
|
||||
$view_args['time_limit'] = $exact_date;
|
||||
}
|
||||
return $view_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Breaks down the given ordered array of event objects into dates, and
|
||||
* outputs an ordered array of two-element associative arrays in the
|
||||
* following format:
|
||||
* key: localized UNIX timestamp of date
|
||||
* value:
|
||||
* ['events'] => two-element associatative array broken down thus:
|
||||
* ['allday'] => all-day events occurring on this day
|
||||
* ['notallday'] => all other events occurring on this day
|
||||
* ['today'] => whether or not this date is today
|
||||
*
|
||||
* @param array $events Event results
|
||||
* @param Ai1ec_Abstract_Query|null $query Current calendar page request, if
|
||||
* any (null for widget)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_agenda_like_date_array(
|
||||
$events,
|
||||
Ai1ec_Abstract_Query $query = null
|
||||
) {
|
||||
$dates = array();
|
||||
$time = $this->_registry->get( 'date.system' );
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$this->_registry->get( 'controller.content-filter' )
|
||||
->clear_the_content_filters();
|
||||
// Classify each event into a date/allday category
|
||||
foreach ( $events as $event ) {
|
||||
$start_time = $this->_registry
|
||||
->get(
|
||||
'date.time',
|
||||
$event->get( 'start' )->format( 'Y-m-d\T00:00:00' ),
|
||||
'sys.default'
|
||||
);
|
||||
$exact_date = $time->format_datetime_for_url(
|
||||
$start_time,
|
||||
$settings->get( 'input_date_format' )
|
||||
);
|
||||
$href_for_date = $this->_create_link_for_day_view( $exact_date );
|
||||
// timestamp is used to have correctly sorted array as UNIX
|
||||
// timestamp never goes in decreasing order for increasing dates.
|
||||
$timestamp = $start_time->format();
|
||||
// Ensure all-day & non all-day categories are created in correct
|
||||
// order: "allday" preceding "notallday".
|
||||
if ( ! isset( $dates[$timestamp]['events'] ) ) {
|
||||
$dates[$timestamp]['events'] = array(
|
||||
'allday' => array(),
|
||||
'notallday' => array(),
|
||||
);
|
||||
}
|
||||
$this->_add_runtime_properties( $event );
|
||||
// Add the event.
|
||||
$category = $event->is_allday()
|
||||
? 'allday'
|
||||
: 'notallday';
|
||||
$event_props = array();
|
||||
$event_props['post_id'] = $event->get( 'post_id' );
|
||||
$event_props['instance_id'] = $event->get( 'instance_id' );
|
||||
$event_props['venue'] = $event->get( 'venue' );
|
||||
$event_props['ticket_url'] = $event->get( 'ticket_url' );
|
||||
$event_props['filtered_title'] = $event->get_runtime( 'filtered_title' );
|
||||
$event_props['edit_post_link'] = $event->get_runtime( 'edit_post_link' );
|
||||
$event_props['content_img_url'] = $event->get_runtime( 'content_img_url' );
|
||||
$event_props['filtered_content'] = $event->get_runtime( 'filtered_content' );
|
||||
$event_props['ticket_url_label'] = $event->get_runtime( 'ticket_url_label' );
|
||||
$event_props['permalink'] = $event->get_runtime( 'instance_permalink' );
|
||||
$event_props['categories_html'] = $event->get_runtime( 'categories_html' );
|
||||
$event_props['category_bg_color'] = $event->get_runtime( 'category_bg_color' );
|
||||
$event_props['category_text_color'] = $event->get_runtime( 'category_text_color' );
|
||||
$event_props['tags_html'] = $event->get_runtime( 'tags_html' );
|
||||
$event_props['post_excerpt'] = $event->get_runtime( 'post_excerpt' );
|
||||
$event_props['short_start_time'] = $event->get_runtime( 'short_start_time' );
|
||||
$event_props['is_allday'] = $event->is_allday();
|
||||
$event_props['is_multiday'] = $event->is_multiday();
|
||||
$event_props['enddate_info'] = $event->getenddate_info();
|
||||
$event_props['timespan_short'] = $event->_registry->
|
||||
get( 'view.event.time' )->get_timespan_html( $event, 'short' );
|
||||
$event_props['avatar'] = $event->getavatar();
|
||||
$event_props['avatar_not_wrapped'] = $event->getavatar( false );
|
||||
$event_props['avatar_url'] = $this->_registry
|
||||
->get( 'view.event.avatar' )->get_event_avatar_url( $event );
|
||||
$event_props['category_divider_color'] = $event->get_runtime(
|
||||
'category_divider_color'
|
||||
);
|
||||
|
||||
$meta = $this->_registry->get( 'model.meta-post' );
|
||||
if ( ! $event_props['ticket_url'] ) {
|
||||
$timely_tickets = $meta->get(
|
||||
$event->get( 'post_id' ),
|
||||
'_ai1ec_timely_tickets_url',
|
||||
null
|
||||
);
|
||||
if ( $timely_tickets ) {
|
||||
$event_props['ticket_url'] = $timely_tickets;
|
||||
$event->set( 'ticket_url', $event_props['ticket_url'] );
|
||||
}
|
||||
}
|
||||
if (
|
||||
true === apply_filters(
|
||||
'ai1ec_buy_button_product',
|
||||
false
|
||||
)
|
||||
) {
|
||||
$full_details = $meta->get(
|
||||
$event->get( 'post_id' ),
|
||||
'_ai1ec_ep_product_details',
|
||||
null
|
||||
);
|
||||
if (
|
||||
is_array( $full_details ) &&
|
||||
isset( $full_details['show_buy_button'] ) &&
|
||||
true === $full_details['show_buy_button']
|
||||
&& $event_props['ticket_url']
|
||||
) {
|
||||
// Tickets button is shown by default in this case.
|
||||
} else {
|
||||
// Otherwise not.
|
||||
$event_props['ticket_url'] = false;
|
||||
}
|
||||
$event->set( 'ticket_url', $event_props['ticket_url'] );
|
||||
}
|
||||
|
||||
$event_object = $event_props;
|
||||
if (
|
||||
$this->_compatibility->use_backward_compatibility()
|
||||
) {
|
||||
$event_object = $event;
|
||||
}
|
||||
|
||||
$months = apply_filters( 'ai1ec_i18n_months', array() );
|
||||
$weekdays = apply_filters( 'ai1ec_i18n_weekdays', array() );
|
||||
|
||||
$dates[$timestamp]['events'][$category][] = $event_object;
|
||||
$dates[$timestamp]['href'] = $href_for_date;
|
||||
$dates[$timestamp]['day'] = $this->_registry->
|
||||
get( 'date.time', $timestamp )->format_i18n( 'j' );
|
||||
|
||||
$w = $this->
|
||||
_registry->get( 'date.time', $timestamp )->format_i18n( 'D' );
|
||||
$dates[$timestamp]['weekday'] = array_key_exists( $w, $weekdays ) ? $weekdays[$w] : $w;
|
||||
|
||||
$m = $this->
|
||||
_registry->get( 'date.time', $timestamp )->format_i18n( 'M' );
|
||||
$dates[$timestamp]['month'] = array_key_exists( $m, $months ) ? $months[$m] : $m;
|
||||
|
||||
$this->_registry->
|
||||
get( 'date.time', $timestamp )->format_i18n( 'M' );
|
||||
|
||||
$dates[$timestamp]['full_month'] = $this->_registry->
|
||||
get( 'date.time', $timestamp )->format_i18n( 'F' );
|
||||
$dates[$timestamp]['full_weekday'] = $this->_registry->
|
||||
get( 'date.time', $timestamp )->format_i18n( 'l' );
|
||||
$dates[$timestamp]['year'] = $this->_registry->
|
||||
get( 'date.time', $timestamp )->format_i18n( 'Y' );
|
||||
}
|
||||
$this->_registry->get( 'controller.content-filter' )
|
||||
->restore_the_content_filters();
|
||||
// Flag today
|
||||
$today = $this->_registry->get( 'date.time', 'now', 'sys.default' )
|
||||
->set_time( 0, 0, 0 )
|
||||
->format();
|
||||
if ( isset( $dates[$today] ) ) {
|
||||
$dates[$today]['today'] = true;
|
||||
}
|
||||
return $dates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an associative array of two links for any agenda-like view of the
|
||||
* calendar:
|
||||
* previous page (if previous events exist),
|
||||
* next page (if next events exist).
|
||||
* Each element is an associative array containing the link's enabled status
|
||||
* ['enabled'], CSS class ['class'], text ['text'] and value to assign to
|
||||
* link's href ['href'].
|
||||
*
|
||||
* @param array $args Current request arguments
|
||||
*
|
||||
* @param bool $prev Whether there are more events before
|
||||
* the current page
|
||||
* @param bool $next Whether there are more events after
|
||||
* the current page
|
||||
* @param Ai1ec_Date_Time|null $date_first
|
||||
* @param Ai1ec_Date_Time|null $date_last
|
||||
* @param string $title Title to display in datepicker button
|
||||
* @param string $title_short Short month names.
|
||||
* @param int|null $default_time_limit The default time limit in the case of pagination ends.
|
||||
* @return array Array of links
|
||||
*/
|
||||
protected function _get_agenda_like_pagination_links(
|
||||
$args,
|
||||
$prev = false,
|
||||
$next = false,
|
||||
$date_first = null,
|
||||
$date_last = null,
|
||||
$title = '',
|
||||
$title_short = '',
|
||||
$default_time_limit = 0
|
||||
) {
|
||||
$links = array();
|
||||
|
||||
if (
|
||||
$this->_registry->get(
|
||||
'model.settings'
|
||||
)->get( 'ai1ec_use_frontend_rendering' )
|
||||
) {
|
||||
$args['request_format'] = 'json';
|
||||
}
|
||||
$args['page_offset'] = -1;
|
||||
if ( null === $date_first || $date_first->is_empty() ) {
|
||||
$args['time_limit'] = $default_time_limit;
|
||||
} else {
|
||||
$args['time_limit'] = $this->_registry
|
||||
->get( 'date.time', $date_first )->set_time(
|
||||
$date_first->format( 'H' ),
|
||||
$date_first->format( 'i' ),
|
||||
$date_first->format( 's' ) - 1
|
||||
)->format_to_gmt();
|
||||
}
|
||||
$href = $this->_registry->get(
|
||||
'html.element.href',
|
||||
$args
|
||||
);
|
||||
$links[] = array(
|
||||
'class' => 'ai1ec-prev-page',
|
||||
'text' => '<i class="ai1ec-fa ai1ec-fa-chevron-left"></i>',
|
||||
'href' => $href->generate_href(),
|
||||
'enabled' => $prev,
|
||||
);
|
||||
|
||||
// Minical datepicker.
|
||||
$factory = $this->_registry->get( 'factory.html' );
|
||||
$links[] = $factory->create_datepicker_link(
|
||||
$args,
|
||||
$date_first->format_to_gmt(),
|
||||
$title,
|
||||
$title_short
|
||||
);
|
||||
|
||||
$args['page_offset'] = 1;
|
||||
if ( null === $date_last || $date_last->is_empty() ) {
|
||||
$args['time_limit'] = $default_time_limit;
|
||||
} else {
|
||||
$args['time_limit'] = $this->_registry
|
||||
->get( 'date.time', $date_last )->set_time(
|
||||
$date_last->format( 'H' ),
|
||||
$date_last->format( 'i' ),
|
||||
$date_last->format( 's' ) + 1
|
||||
)->format_to_gmt();
|
||||
}
|
||||
$href = $this->_registry->get(
|
||||
'html.element.href',
|
||||
$args
|
||||
);
|
||||
$links[] = array(
|
||||
'class' => 'ai1ec-next-page',
|
||||
'text' => '<i class="ai1ec-fa ai1ec-fa-chevron-right"></i>',
|
||||
'href' => $href->generate_href(),
|
||||
'enabled' => $next,
|
||||
);
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an associative array of two links for any agenda-like view of the
|
||||
* calendar:
|
||||
* previous page (if previous events exist),
|
||||
* next page (if next events exist).
|
||||
* Each element is an associative array containing the link's enabled status
|
||||
* ['enabled'], CSS class ['class'], text ['text'] and value to assign to
|
||||
* link's href ['href'].
|
||||
*
|
||||
* @param array $args Current request arguments
|
||||
*
|
||||
* @param bool $prev Whether there are more events before
|
||||
* the current page
|
||||
* @param bool $next Whether there are more events after
|
||||
* the current page
|
||||
* @param Ai1ec_Date_Time|null $date_first
|
||||
* @param Ai1ec_Date_Time|null $date_last
|
||||
* @param string $title Title to display in datepicker button
|
||||
* @param string $title_short Short month names.
|
||||
* @param int|null $default_time_limit The default time limit in the case of pagination ends.
|
||||
* @return array Array of links
|
||||
*/
|
||||
protected function _get_pagination_links(
|
||||
$args,
|
||||
$prev = false,
|
||||
$next = false,
|
||||
$date_first = null,
|
||||
$date_last = null,
|
||||
$title = '',
|
||||
$title_short = '',
|
||||
$prev_offset = -1,
|
||||
$next_offset = 1) {
|
||||
|
||||
$links = array();
|
||||
|
||||
if ( $this->_registry->get( 'model.settings' )->get( 'ai1ec_use_frontend_rendering' ) ) {
|
||||
$args['request_format'] = 'json';
|
||||
}
|
||||
$args['page_offset'] = $prev_offset;
|
||||
|
||||
$href = $this->_registry->get( 'html.element.href', $args );
|
||||
$links[] = array(
|
||||
'class' => 'ai1ec-prev-page',
|
||||
'text' => '<i class="ai1ec-fa ai1ec-fa-chevron-left"></i>',
|
||||
'href' => $href->generate_href(),
|
||||
'enabled' => $prev );
|
||||
|
||||
// Minical datepicker.
|
||||
$factory = $this->_registry->get( 'factory.html' );
|
||||
$links[] = $factory->create_datepicker_link( $args, $date_first->format_to_gmt(), $title, $title_short );
|
||||
|
||||
$args['page_offset'] = $next_offset;
|
||||
$href = $this->_registry->get( 'html.element.href', $args );
|
||||
$links[] = array(
|
||||
'class' => 'ai1ec-next-page',
|
||||
'text' => '<i class="ai1ec-fa ai1ec-fa-chevron-right"></i>',
|
||||
'href' => $href->generate_href(),
|
||||
'enabled' => $next );
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Calendar_View_Abstract::_add_view_specific_runtime_properties()
|
||||
*/
|
||||
protected function _add_view_specific_runtime_properties( Ai1ec_Event $event ) {
|
||||
$taxonomy = $this->_registry->get( 'view.event.taxonomy' );
|
||||
$avatar = $this->_registry->get( 'view.event.avatar' );
|
||||
$event->set_runtime(
|
||||
'categories_html',
|
||||
$taxonomy->get_categories_html( $event )
|
||||
);
|
||||
$event->set_runtime(
|
||||
'tags_html',
|
||||
$taxonomy->get_tags_html( $event )
|
||||
);
|
||||
$event->set_runtime(
|
||||
'content_img_url',
|
||||
$avatar->get_content_img_url( $event )
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,573 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The concrete class for month view.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_Calendar_View_Month extends Ai1ec_Calendar_View_Abstract {
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Calendar_View_Abstract::get_name()
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'month';
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Calendar_View_Abstract::get_content()
|
||||
*/
|
||||
public function get_content( array $view_args ) {
|
||||
$date_system = $this->_registry->get( 'date.system' );
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$defaults = array(
|
||||
'month_offset' => 0,
|
||||
'cat_ids' => array(),
|
||||
'auth_ids' => array(),
|
||||
'tag_ids' => array(),
|
||||
'post_ids' => array(),
|
||||
'instance_ids' => array(),
|
||||
'exact_date' => $date_system->current_time(),
|
||||
);
|
||||
$args = wp_parse_args( $view_args, $defaults );
|
||||
$local_date = $this->_registry
|
||||
->get( 'date.time', $args['exact_date'], 'sys.default' );
|
||||
$local_date->set_date(
|
||||
$local_date->format( 'Y' ),
|
||||
$local_date->format( 'm' ) + $args['month_offset'],
|
||||
1
|
||||
)
|
||||
->set_time( 0, 0, 0 );
|
||||
|
||||
$days_events = $this->get_events_for_month(
|
||||
$local_date,
|
||||
apply_filters(
|
||||
'ai1ec_get_events_relative_to_filter',
|
||||
array(
|
||||
'cat_ids' => $args['cat_ids'],
|
||||
'tag_ids' => $args['tag_ids'],
|
||||
'post_ids' => $args['post_ids'],
|
||||
'auth_ids' => $args['auth_ids'],
|
||||
'instance_ids' => $args['instance_ids'],
|
||||
),
|
||||
$view_args,
|
||||
apply_filters(
|
||||
'ai1ec_show_unique_events',
|
||||
false
|
||||
)
|
||||
)
|
||||
);
|
||||
$cell_array = $this->get_month_cell_array(
|
||||
$local_date,
|
||||
$days_events
|
||||
);
|
||||
// Create pagination links.
|
||||
$title = $local_date->format_i18n( 'F Y' );
|
||||
$pagination_links = $this->_get_pagination( $args, $title );
|
||||
|
||||
$is_ticket_button_enabled = apply_filters(
|
||||
'ai1ec_month_ticket_button',
|
||||
false
|
||||
);
|
||||
|
||||
$view_args = array(
|
||||
'title' => $title,
|
||||
'type' => 'month',
|
||||
'weekdays' => $this->get_weekdays(),
|
||||
'cell_array' => $cell_array,
|
||||
'show_location_in_title' => $settings->get( 'show_location_in_title' ),
|
||||
'month_word_wrap' => $settings->get( 'month_word_wrap' ),
|
||||
'post_ids' => join( ',', $args['post_ids'] ),
|
||||
'data_type' => $args['data_type'],
|
||||
'is_ticket_button_enabled' => $is_ticket_button_enabled,
|
||||
'text_venue_separator' => __( '@ %s', AI1EC_PLUGIN_NAME ),
|
||||
'pagination_links' => $pagination_links,
|
||||
);
|
||||
|
||||
// Add navigation if requested.
|
||||
$view_args['navigation'] = $this->_get_navigation(
|
||||
array(
|
||||
'no_navigation' => $args['no_navigation'],
|
||||
'pagination_links' => $pagination_links,
|
||||
'views_dropdown' => $args['views_dropdown'],
|
||||
'below_toolbar' => apply_filters(
|
||||
'ai1ec_below_toolbar',
|
||||
'',
|
||||
$this->get_name(),
|
||||
$args
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$view_args = $this->get_extra_template_arguments( $view_args );
|
||||
|
||||
return
|
||||
$this->_registry->get( 'http.request' )->is_json_required(
|
||||
$args['request_format'], 'month'
|
||||
)
|
||||
? $this->_apply_filters_to_args( $view_args )
|
||||
: $this->_get_view( $view_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a non-associative array of four links for the month view of the
|
||||
* calendar:
|
||||
* previous year, previous month, next month, and next year.
|
||||
* Each element is an associative array containing the link's enabled status
|
||||
* ['enabled'], CSS class ['class'], text ['text'] and value to assign to
|
||||
* link's href ['href'].
|
||||
*
|
||||
* @param array $args Current request arguments
|
||||
* @param string $title Title to display in datepicker button
|
||||
*
|
||||
* @return array Array of links
|
||||
*/
|
||||
function get_month_pagination_links( $args, $title ) {
|
||||
$links = array();
|
||||
|
||||
$local_date = $this->_registry
|
||||
->get( 'date.time', $args['exact_date'], 'sys.default' );
|
||||
$orig_date = $this->_registry->get( 'date.time', $local_date );
|
||||
$default_tz = $this->_registry->get( 'date.timezone' )->get_default_timezone();
|
||||
// =================
|
||||
// = Previous year =
|
||||
// =================
|
||||
// Align date to first of month, month offset applied, 1 year behind.
|
||||
$local_date
|
||||
->set_timezone( $default_tz )
|
||||
->set_date(
|
||||
$local_date->format( 'Y' ) -1,
|
||||
$local_date->format( 'm' ) + $args['month_offset'],
|
||||
1
|
||||
)
|
||||
->set_time( 0, 0, 0 );
|
||||
|
||||
$args['exact_date'] = $local_date->format();
|
||||
$href = $this->_registry->get( 'html.element.href', $args );
|
||||
$links[] = array(
|
||||
'enabled' => true,
|
||||
'class'=> 'ai1ec-prev-year',
|
||||
'text' => '<i class="ai1ec-fa ai1ec-fa-angle-double-left"></i> ' .
|
||||
$local_date->format_i18n( 'Y' ),
|
||||
'href' => $href->generate_href(),
|
||||
);
|
||||
|
||||
// ==================
|
||||
// = Previous month =
|
||||
// ==================
|
||||
// Align date to first of month, month offset applied, 1 month behind.
|
||||
$local_date
|
||||
->set_date(
|
||||
$local_date->format( 'Y' ) + 1,
|
||||
$local_date->format( 'm' ) - 1,
|
||||
1
|
||||
);
|
||||
$args['exact_date'] = $local_date->format();
|
||||
$href = $this->_registry->get( 'html.element.href', $args );
|
||||
$months = apply_filters( 'ai1ec_i18n_months', array() );
|
||||
$m = $local_date->format_i18n( 'M' );
|
||||
$month_text = array_key_exists( $m, $months ) ? $months[$m] : $m;
|
||||
$links[] = array(
|
||||
'enabled' => true,
|
||||
'class'=> 'ai1ec-prev-month',
|
||||
'text' => '<i class="ai1ec-fa ai1ec-fa-angle-left"></i> ' . $month_text,
|
||||
'href' => $href->generate_href(),
|
||||
);
|
||||
|
||||
// ======================
|
||||
// = Minical datepicker =
|
||||
// ======================
|
||||
// Align date to first of month, month offset applied.
|
||||
|
||||
$orig_date
|
||||
->set_timezone('UTC')
|
||||
->set_date(
|
||||
$orig_date->format( 'Y' ),
|
||||
$orig_date->format( 'm' ) + $args['month_offset'],
|
||||
1
|
||||
);
|
||||
$args['exact_date'] = $orig_date->format();
|
||||
$factory = $this->_registry->get( 'factory.html' );
|
||||
$links[] = $factory->create_datepicker_link(
|
||||
$args,
|
||||
$args['exact_date'],
|
||||
$title
|
||||
);
|
||||
|
||||
// ==============
|
||||
// = Next month =
|
||||
// ==============
|
||||
// Align date to first of month, month offset applied, 1 month ahead.
|
||||
$orig_date
|
||||
->set_timezone( $default_tz )
|
||||
->set_date(
|
||||
$orig_date->format( 'Y' ),
|
||||
$orig_date->format( 'm' ) + 1,
|
||||
1
|
||||
)
|
||||
->set_time( 0, 0, 0 );
|
||||
$args['exact_date'] = $orig_date->format();
|
||||
$href = $this->_registry->get( 'html.element.href', $args );
|
||||
$m = $orig_date->format_i18n( 'M' );
|
||||
$links[] = array(
|
||||
'enabled' => true,
|
||||
'class'=> 'ai1ec-next-month',
|
||||
'text' => ( array_key_exists( $m, $months ) ? $months[$m] : $m ) .
|
||||
' <i class="ai1ec-fa ai1ec-fa-angle-right"></i>',
|
||||
'href' => $href->generate_href(),
|
||||
);
|
||||
|
||||
// =============
|
||||
// = Next year =
|
||||
// =============
|
||||
// Align date to first of month, month offset applied, 1 year ahead.
|
||||
$orig_date
|
||||
->set_date(
|
||||
$orig_date->format( 'Y' ) + 1,
|
||||
$orig_date->format( 'm' ) - 1,
|
||||
1
|
||||
);
|
||||
$args['exact_date'] = $orig_date->format();
|
||||
$href = $this->_registry->get( 'html.element.href', $args );
|
||||
$links[] = array(
|
||||
'enabled' => true,
|
||||
'class'=> 'ai1ec-next-year',
|
||||
'text' => $orig_date->format_i18n( 'Y' ) .
|
||||
' <i class="ai1ec-fa ai1ec-fa-angle-double-right"></i>',
|
||||
'href' => $href->generate_href(),
|
||||
);
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_weekdays function
|
||||
*
|
||||
* Returns a list of abbreviated weekday names starting on the configured
|
||||
* week start day setting.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_weekdays() {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
static $weekdays;
|
||||
|
||||
if ( ! isset( $weekdays ) ) {
|
||||
$time = $this->_registry->get(
|
||||
'date.time',
|
||||
'next Sunday',
|
||||
'sys.default'
|
||||
);
|
||||
$time->adjust_day( $settings->get( 'week_start_day' ) );
|
||||
|
||||
$weekdays = array();
|
||||
for( $i = 0; $i < 7; $i++ ) {
|
||||
$weekdays[] = $time->format_i18n( 'D' );
|
||||
$time->adjust_day( 1 );// Add a day
|
||||
}
|
||||
}
|
||||
return $weekdays;
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Calendar_View_Abstract::_add_view_specific_runtime_properties()
|
||||
*/
|
||||
protected function _add_view_specific_runtime_properties(
|
||||
Ai1ec_Event $event
|
||||
) {
|
||||
$end_day = $this->_registry->get( 'date.time', $event->get( 'end' ) )
|
||||
->adjust( -1, 'second' )
|
||||
->format_i18n( 'd' );
|
||||
$event->set_runtime( 'multiday_end_day', $end_day );
|
||||
$event->set_runtime(
|
||||
'start_day',
|
||||
$event->get( 'start' )->format( 'j' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_month_cell_array function
|
||||
*
|
||||
* Return an array of weeks, each containing an array of days, each
|
||||
* containing the date for the day ['date'] (if inside the month) and
|
||||
* the events ['events'] (if any) for the day, and a boolean ['today']
|
||||
* indicating whether that day is today.
|
||||
*
|
||||
* @param int $timestamp UNIX timestamp of the 1st day of the desired
|
||||
* month to display
|
||||
* @param array $days_events list of events for each day of the month in
|
||||
* the format returned by get_events_for_month()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function get_month_cell_array( Ai1ec_Date_Time $timestamp, $days_events ) {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$date_system = $this->_registry->get( 'date.system' );
|
||||
$today = $this->_registry->get( 'date.time' );// Used to flag today's cell
|
||||
|
||||
// Figure out index of first table cell
|
||||
$first_cell_index = $timestamp->format( 'w' );
|
||||
// Modify weekday based on start of week setting
|
||||
$first_cell_index = ( 7 + $first_cell_index - $settings->get( 'week_start_day' ) ) % 7;
|
||||
|
||||
// Get the last day of the month
|
||||
$last_day = $timestamp->format( 't' );
|
||||
$last_timestamp = $this->_registry->get( 'date.time', $timestamp );
|
||||
$last_timestamp->set_date(
|
||||
$timestamp->format( 'Y' ),
|
||||
$timestamp->format( 'm' ),
|
||||
$last_day
|
||||
)->set_time( 0, 0, 0 );
|
||||
// Figure out index of last table cell
|
||||
$last_cell_index = $last_timestamp->format( 'w' );
|
||||
// Modify weekday based on start of week setting
|
||||
$last_cell_index = ( 7 + $last_cell_index - $settings->get( 'week_start_day' ) ) % 7;
|
||||
|
||||
$weeks = array();
|
||||
$week = 0;
|
||||
$weeks[$week] = array();
|
||||
|
||||
// Insert any needed blank cells into first week
|
||||
for( $i = 0; $i < $first_cell_index; $i++ ) {
|
||||
$weeks[$week][] = array(
|
||||
'date' => null,
|
||||
'events' => array(),
|
||||
'date_link' => null
|
||||
);
|
||||
}
|
||||
|
||||
// Insert each month's day and associated events
|
||||
for( $i = 1; $i <= $last_day; $i++ ) {
|
||||
$day = $this->_registry->get( 'date.time' )
|
||||
->set_date(
|
||||
$timestamp->format( 'Y' ),
|
||||
$timestamp->format( 'm' ),
|
||||
$i
|
||||
)
|
||||
->set_time( 0, 0, 0 )
|
||||
->format();
|
||||
$exact_date = $date_system->format_date_for_url(
|
||||
$day,
|
||||
$settings->get( 'input_date_format' )
|
||||
);
|
||||
$events = array();
|
||||
foreach ( $days_events[$i] as $evt ){
|
||||
$event_data = array(
|
||||
'filtered_title' => $evt->get_runtime( 'filtered_title' ),
|
||||
'post_excerpt' => $evt->get_runtime( 'post_excerpt' ),
|
||||
'color_style' => $evt->get_runtime( 'color_style' ),
|
||||
'category_colors' => $evt->get_runtime( 'category_colors' ),
|
||||
'permalink' => $evt->get_runtime( 'instance_permalink' ),
|
||||
'ticket_url_label' => $evt->get_runtime( 'ticket_url_label' ),
|
||||
'edit_post_link' => $evt->get_runtime( 'edit_post_link' ),
|
||||
'short_start_time' => $evt->get_runtime( 'short_start_time' ),
|
||||
'multiday_end_day' => $evt->get_runtime( 'multiday_end_day' ),
|
||||
'start_day' => $evt->get_runtime( 'start_day' ),
|
||||
'short_start_time' => $evt->get_runtime( 'short_start_time' ),
|
||||
'instance_id' => $evt->get( 'instance_id' ),
|
||||
'post_id' => $evt->get( 'post_id' ),
|
||||
'is_allday' => $evt->is_allday(),
|
||||
'is_multiday' => $evt->is_multiday(),
|
||||
'venue' => $evt->get( 'venue' ),
|
||||
'ticket_url' => $evt->get( 'ticket_url' ),
|
||||
'start_truncated' => $evt->get( 'start_truncated' ),
|
||||
'end_truncated' => $evt->get( 'end_truncated' ),
|
||||
'popup_timespan' => $this->_registry
|
||||
->get( 'twig.ai1ec-extension')->timespan( $evt, 'short' ),
|
||||
'avatar_not_wrapped' => $evt->getavatar( false ),
|
||||
'avatar' => $this->_registry
|
||||
->get( 'twig.ai1ec-extension')->avatar(
|
||||
$evt,
|
||||
array(
|
||||
'post_thumbnail',
|
||||
'content_img',
|
||||
'location_avatar',
|
||||
'category_avatar',
|
||||
),
|
||||
'',
|
||||
false ),
|
||||
);
|
||||
$meta = $this->_registry->get( 'model.meta-post' );
|
||||
if ( ! $event_data['ticket_url'] ) {
|
||||
$timely_tickets = $meta->get(
|
||||
$evt->get( 'post_id' ),
|
||||
'_ai1ec_timely_tickets_url',
|
||||
null
|
||||
);
|
||||
if ( $timely_tickets ) {
|
||||
$event_data['ticket_url'] = $timely_tickets;
|
||||
$evt->set( 'ticket_url', $event_data['ticket_url'] );
|
||||
}
|
||||
}
|
||||
if (
|
||||
true === apply_filters(
|
||||
'ai1ec_buy_button_product',
|
||||
false
|
||||
)
|
||||
) {
|
||||
$full_details = $meta->get(
|
||||
$evt->get( 'post_id' ),
|
||||
'_ai1ec_ep_product_details',
|
||||
null
|
||||
);
|
||||
if (
|
||||
is_array( $full_details ) &&
|
||||
isset( $full_details['show_buy_button'] ) &&
|
||||
true === $full_details['show_buy_button']
|
||||
&& $event_data['ticket_url']
|
||||
) {
|
||||
// Tickets button is shown by default in this case.
|
||||
} else {
|
||||
// Otherwise not.
|
||||
$event_data['ticket_url'] = false;
|
||||
}
|
||||
$evt->set( 'ticket_url', $event_data['ticket_url'] );
|
||||
}
|
||||
|
||||
if (
|
||||
$this->_compatibility->use_backward_compatibility()
|
||||
) {
|
||||
$event_data = $evt;
|
||||
}
|
||||
$events[] = $event_data;
|
||||
}
|
||||
$weeks[$week][] = array(
|
||||
'date' => $i,
|
||||
'date_link' => $this->_create_link_for_day_view( $exact_date ),
|
||||
'today' =>
|
||||
$timestamp->format( 'Y' ) == $today->format( 'Y' ) &&
|
||||
$timestamp->format( 'm' ) == $today->format( 'm' ) &&
|
||||
$i == $today->format( 'j' ),
|
||||
'events' => $events,
|
||||
|
||||
);
|
||||
// If reached the end of the week, increment week
|
||||
if( count( $weeks[$week] ) == 7 )
|
||||
$week++;
|
||||
}
|
||||
|
||||
// Insert any needed blank cells into last week
|
||||
for( $i = $last_cell_index + 1; $i < 7; $i++ ) {
|
||||
$weeks[$week][] = array( 'date' => null, 'events' => array() );
|
||||
}
|
||||
|
||||
return $weeks;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_events_for_month function
|
||||
*
|
||||
* Return an array of all dates for the given month as an associative
|
||||
* array, with each element's value being another array of event objects
|
||||
* representing the events occuring on that date.
|
||||
*
|
||||
* @param int $time the UNIX timestamp of a date within the desired month
|
||||
* @param array $filter Array of filters for the events returned:
|
||||
* ['cat_ids'] => non-associatative array of category IDs
|
||||
* ['tag_ids'] => non-associatative array of tag IDs
|
||||
* ['post_ids'] => non-associatative array of post IDs
|
||||
* ['auth_ids'] => non-associatative array of author IDs
|
||||
*
|
||||
* @return array array of arrays as per function's description
|
||||
*/
|
||||
protected function get_events_for_month(
|
||||
Ai1ec_Date_Time $time,
|
||||
$filter = array()
|
||||
) {
|
||||
$last_day = $time->format( 't' );
|
||||
|
||||
$day_entry = array(
|
||||
'multi' => array(),
|
||||
'allday' => array(),
|
||||
'other' => array(),
|
||||
);
|
||||
$days_events = array_fill(
|
||||
1,
|
||||
$last_day,
|
||||
$day_entry
|
||||
);
|
||||
unset( $day_entry );
|
||||
$start_time = $this->_registry->get( 'date.time', $time );
|
||||
$start_time->set_date(
|
||||
$time->format( 'Y' ),
|
||||
$time->format( 'm' ),
|
||||
1
|
||||
)->set_time( 0, 0, 0 );
|
||||
$end_time = $this->_registry->get( 'date.time', $start_time );
|
||||
|
||||
$end_time->adjust_month( 1 );
|
||||
|
||||
$search = $this->_registry->get( 'model.search' );
|
||||
$month_events = $search->get_events_between(
|
||||
$start_time,
|
||||
$end_time,
|
||||
$filter,
|
||||
true
|
||||
);
|
||||
$start_time = $start_time->format();
|
||||
$end_time = $end_time->format();
|
||||
$this->_update_meta( $month_events );
|
||||
$this->_registry->get( 'controller.content-filter' )
|
||||
->clear_the_content_filters();
|
||||
foreach ( $month_events as $event ) {
|
||||
$event_start = $event->get( 'start' )->format();
|
||||
$event_end = $event->get( 'end' )->format();
|
||||
|
||||
/**
|
||||
* REASONING: we assume, that event spans multiple periods, one of
|
||||
* which happens to be current (month). Thus we mark, that current
|
||||
* event starts at the very first day of current month and further
|
||||
* we will mark it as having truncated beginning (unless it is not
|
||||
* overlapping period boundaries).
|
||||
* Although, if event starts after the first second of this period
|
||||
* it's start day will be decoded as time 'j' format (`int`-casted
|
||||
* to increase map access time), of it's actual start time.
|
||||
*/
|
||||
$day = 1;
|
||||
if ( $event_start > $start_time ) {
|
||||
$day = (int)$event->get( 'start' )->format( 'j' );
|
||||
}
|
||||
|
||||
// Set multiday properties. TODO: Should these be made event object
|
||||
// properties? They probably shouldn't be saved to the DB, so I'm
|
||||
// not sure. Just creating properties dynamically for now.
|
||||
if ( $event_start < $start_time ) {
|
||||
$event->set( 'start_truncated', true );
|
||||
}
|
||||
if ( $event_end >= $end_time ) {
|
||||
$event->set( 'end_truncated', true );
|
||||
}
|
||||
|
||||
// Categorize event.
|
||||
$priority = 'other';
|
||||
if ( $event->is_allday() ) {
|
||||
$priority = 'allday';
|
||||
} elseif ( $event->is_multiday() ) {
|
||||
$priority = 'multi';
|
||||
}
|
||||
$this->_add_runtime_properties( $event );
|
||||
$days_events[$day][$priority][] = $event;
|
||||
}
|
||||
$this->_registry->get( 'controller.content-filter' )
|
||||
->restore_the_content_filters();
|
||||
for ( $day = 1; $day <= $last_day; $day++ ) {
|
||||
$days_events[$day] = array_merge(
|
||||
$days_events[$day]['multi'],
|
||||
$days_events[$day]['allday'],
|
||||
$days_events[$day]['other']
|
||||
);
|
||||
}
|
||||
|
||||
return apply_filters(
|
||||
'ai1ec_get_events_for_month',
|
||||
$days_events,
|
||||
$time,
|
||||
$filter
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,437 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The concrete class for day view.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_Calendar_View_Oneday extends Ai1ec_Calendar_View_Abstract {
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Calendar_View_Abstract::get_name()
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'oneday';
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Calendar_View_Abstract::get_content()
|
||||
*/
|
||||
public function get_content( array $view_args ) {
|
||||
$date_system = $this->_registry->get( 'date.system' );
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$defaults = array(
|
||||
'oneday_offset' => 0,
|
||||
'cat_ids' => array(),
|
||||
'tag_ids' => array(),
|
||||
'auth_ids' => array(),
|
||||
'post_ids' => array(),
|
||||
'instance_ids' => array(),
|
||||
'exact_date' => $date_system->current_time(),
|
||||
);
|
||||
$args = wp_parse_args( $view_args, $defaults );
|
||||
$local_date = $this->_registry
|
||||
->get( 'date.time', $args['exact_date'], 'sys.default' )
|
||||
->adjust_day( 0 + $args['oneday_offset'] )
|
||||
->set_time( 0, 0, 0 );
|
||||
|
||||
$cell_array = $this->get_oneday_cell_array(
|
||||
$local_date,
|
||||
apply_filters(
|
||||
'ai1ec_get_events_relative_to_filter',
|
||||
array(
|
||||
'cat_ids' => $args['cat_ids'],
|
||||
'tag_ids' => $args['tag_ids'],
|
||||
'post_ids' => $args['post_ids'],
|
||||
'auth_ids' => $args['auth_ids'],
|
||||
'instance_ids' => $args['instance_ids'],
|
||||
),
|
||||
$view_args,
|
||||
apply_filters(
|
||||
'ai1ec_show_unique_events',
|
||||
false
|
||||
)
|
||||
)
|
||||
);
|
||||
// Create pagination links.
|
||||
$title = $local_date->format_i18n(
|
||||
$this->_registry->get( 'model.option' )
|
||||
->get( 'date_format', 'l, M j, Y' )
|
||||
);
|
||||
$pagination_links = $this->_get_pagination( $args, $title );
|
||||
|
||||
// Calculate today marker's position.
|
||||
$midnight = $this->_registry->get( 'date.time', 'now', 'sys.default' )
|
||||
->set_time( 0, 0, 0 );
|
||||
$now = $this->_registry->get( 'date.time', 'now', 'sys.default' );
|
||||
$now_text = $this->_registry->get( 'view.event.time' )
|
||||
->get_short_time( $now );
|
||||
$now = (int) ( $now->diff_sec( $midnight ) / 60 );
|
||||
|
||||
$is_ticket_button_enabled = apply_filters( 'ai1ec_oneday_ticket_button', false );
|
||||
$show_reveal_button = apply_filters( 'ai1ec_oneday_reveal_button', false );
|
||||
|
||||
$time_format = $this->_registry->get( 'model.option' )
|
||||
->get( 'time_format', Ai1ec_I18n::__( 'g a' ) );
|
||||
|
||||
$hours = array();
|
||||
$today = $this->_registry->get( 'date.time', 'now', 'sys.default' );
|
||||
for ( $hour = 0; $hour < 24; $hour++ ) {
|
||||
$hours[] = $today
|
||||
->set_time( $hour, 0, 0 )
|
||||
->format_i18n( $time_format );
|
||||
}
|
||||
|
||||
$view_args = array(
|
||||
'title' => $title,
|
||||
'type' => 'oneday',
|
||||
'cell_array' => $cell_array,
|
||||
'show_location_in_title' => $settings->get( 'show_location_in_title' ),
|
||||
'now_top' => $now,
|
||||
'now_text' => $now_text,
|
||||
'time_format' => $time_format,
|
||||
'done_allday_label' => false,// legacy
|
||||
'done_grid' => false,// legacy
|
||||
'data_type' => $args['data_type'],
|
||||
'is_ticket_button_enabled' => $is_ticket_button_enabled,
|
||||
'show_reveal_button' => $show_reveal_button,
|
||||
'text_full_day' => __( 'Reveal full day', AI1EC_PLUGIN_NAME ),
|
||||
'text_all_day' => __( 'All-day', AI1EC_PLUGIN_NAME ),
|
||||
'text_now_label' => __( 'Now:', AI1EC_PLUGIN_NAME ),
|
||||
'text_venue_separator' => __( '@ %s', AI1EC_PLUGIN_NAME ),
|
||||
'hours' => $hours,
|
||||
'indent_multiplier' => 16,
|
||||
'indent_offset' => 54,
|
||||
'pagination_links' => $pagination_links,
|
||||
);
|
||||
|
||||
$view_args = $this->get_extra_template_arguments( $view_args );
|
||||
|
||||
// Add navigation if requested.
|
||||
$view_args['navigation'] = $this->_get_navigation(
|
||||
array(
|
||||
'no_navigation' => $args['no_navigation'],
|
||||
'pagination_links' => $pagination_links,
|
||||
'views_dropdown' => $args['views_dropdown'],
|
||||
'below_toolbar' => apply_filters(
|
||||
'ai1ec_below_toolbar',
|
||||
'',
|
||||
$this->get_name(),
|
||||
$args
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
return
|
||||
$this->_registry->get( 'http.request' )->is_json_required(
|
||||
$args['request_format'], 'oneday'
|
||||
)
|
||||
? $this->_apply_filters_to_args( $view_args )
|
||||
: $this->_get_view( $view_args );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce an array of three links for the day view of the calendar.
|
||||
*
|
||||
* Each element is an associative array containing the link's enabled status
|
||||
* ['enabled'], CSS class ['class'], text ['text'] and value to assign to
|
||||
* link's href ['href'].
|
||||
*
|
||||
* @param array $args Current request arguments.
|
||||
* @param string $title Title to display in datepicker button
|
||||
*
|
||||
* @return array Array of links.
|
||||
*/
|
||||
function get_oneday_pagination_links( $args, $title ) {
|
||||
$links = array();
|
||||
$orig_date = $args['exact_date'];
|
||||
|
||||
// ================
|
||||
// = Previous day =
|
||||
// ================
|
||||
$local_date = $this->_registry
|
||||
->get( 'date.time', $args['exact_date'], 'sys.default' )
|
||||
->adjust_day( $args['oneday_offset'] - 1 )
|
||||
->set_time( 0, 0, 0 );
|
||||
$args['exact_date'] = $local_date->format();
|
||||
$href = $this->_registry->get( 'html.element.href', $args );
|
||||
$links[] = array(
|
||||
'enabled' => true,
|
||||
'class'=> 'ai1ec-prev-day',
|
||||
'text' => '<i class="ai1ec-fa ai1ec-fa-chevron-left"></i>',
|
||||
'href' => $href->generate_href(),
|
||||
);
|
||||
|
||||
// ======================
|
||||
// = Minical datepicker =
|
||||
// ======================
|
||||
$args['exact_date'] = $orig_date;
|
||||
$factory = $this->_registry->get( 'factory.html' );
|
||||
$links[] = $factory->create_datepicker_link(
|
||||
$args,
|
||||
$args['exact_date'],
|
||||
$title
|
||||
);
|
||||
|
||||
// ============
|
||||
// = Next day =
|
||||
// ============
|
||||
$local_date->adjust_day( +2 ); // above was (-1), (+2) is to counteract
|
||||
$args['exact_date'] = $local_date->format();
|
||||
$href = $this->_registry->get( 'html.element.href', $args );
|
||||
$links[] = array(
|
||||
'enabled' => true,
|
||||
'class' => 'ai1ec-next-day',
|
||||
'text' => '<i class="ai1ec-fa ai1ec-fa-chevron-right"></i>',
|
||||
'href' => $href->generate_href(),
|
||||
);
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_oneday_cell_array function
|
||||
*
|
||||
* Return an associative array of weekdays, indexed by the day's date,
|
||||
* starting the day given by $timestamp, each element an associative array
|
||||
* containing three elements:
|
||||
* ['today'] => whether the day is today
|
||||
* ['allday'] => non-associative ordered array of events that are all-day
|
||||
* ['notallday'] => non-associative ordered array of non-all-day events to
|
||||
* display for that day, each element another associative
|
||||
* array like so:
|
||||
* ['top'] => how many minutes offset from the start of the day
|
||||
* ['height'] => how many minutes this event spans
|
||||
* ['indent'] => how much to indent this event to accommodate multiple
|
||||
* events occurring at the same time (0, 1, 2, etc., to
|
||||
* be multiplied by whatever desired px/em amount)
|
||||
* ['event'] => event data object
|
||||
*
|
||||
* @param int $timestamp the UNIX timestamp of the first day of the week
|
||||
* @param array $filter Array of filters for the events returned:
|
||||
* ['cat_ids'] => non-associatative array of category IDs
|
||||
* ['tag_ids'] => non-associatative array of tag IDs
|
||||
* ['post_ids'] => non-associatative array of post IDs
|
||||
* ['auth_ids'] => non-associatative array of author IDs
|
||||
* ['instance_ids'] => non-associatative array of event instance IDs
|
||||
*
|
||||
* @return array array of arrays as per function description
|
||||
*/
|
||||
function get_oneday_cell_array(
|
||||
Ai1ec_Date_Time $start_time,
|
||||
array $filter = array(),
|
||||
$legacy = false
|
||||
) {
|
||||
$search = $this->_registry->get( 'model.search' );
|
||||
|
||||
$loc_start_time = $this->_registry
|
||||
->get( 'date.time', $start_time, 'sys.default' )
|
||||
->set_time( 0, 0, 0 );
|
||||
$loc_end_time = $this->_registry
|
||||
->get( 'date.time', $start_time, 'sys.default' )
|
||||
->adjust_day( +1 )
|
||||
->set_time( 0, 0, 0 );
|
||||
|
||||
$day_events = $search->get_events_for_day( $loc_start_time, $filter );
|
||||
$this->_update_meta( $day_events );
|
||||
// Split up events on a per-day basis
|
||||
$all_events = array();
|
||||
|
||||
$day_start_ts = $loc_start_time->format();
|
||||
$day_end_ts = $loc_end_time->format();
|
||||
$this->_registry->get( 'controller.content-filter' )
|
||||
->clear_the_content_filters();
|
||||
foreach ( $day_events as $evt ) {
|
||||
list( $evt_start, $evt_end ) = $this->
|
||||
_get_view_specific_timestamps( $evt );
|
||||
|
||||
// If event falls on this day, make a copy.
|
||||
if ( $evt_end > $day_start_ts && $evt_start < $day_end_ts ) {
|
||||
$_evt = clone $evt;
|
||||
if ( $evt_start < $day_start_ts ) {
|
||||
// If event starts before this day, adjust copy's start time
|
||||
$_evt->set( 'start', $day_start_ts );
|
||||
$_evt->set( 'start_truncated', true );
|
||||
}
|
||||
if ( $evt_end > $day_end_ts ) {
|
||||
// If event ends after this day, adjust copy's end time
|
||||
$_evt->set( 'end', $day_end_ts );
|
||||
$_evt->set( 'end_truncated', true );
|
||||
}
|
||||
|
||||
// Store reference to original, unmodified event, required by view.
|
||||
$_evt->set( '_orig', $evt );
|
||||
$this->_add_runtime_properties( $_evt );
|
||||
// Place copy of event in appropriate category
|
||||
if ( $_evt->is_allday() ) {
|
||||
$all_events[$day_start_ts]['allday'][] = $_evt;
|
||||
} else {
|
||||
$all_events[$day_start_ts]['notallday'][] = $_evt;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
$this->_registry->get( 'controller.content-filter' )
|
||||
->restore_the_content_filters();
|
||||
|
||||
// This will store the returned array
|
||||
$days = array();
|
||||
|
||||
// Initialize empty arrays for this day if no events to minimize warnings
|
||||
if ( ! isset( $all_events[$day_start_ts]['allday'] ) ) {
|
||||
$all_events[$day_start_ts]['allday'] = array();
|
||||
}
|
||||
if ( ! isset( $all_events[$day_start_ts]['notallday'] ) ) {
|
||||
$all_events[$day_start_ts]['notallday'] = array();
|
||||
}
|
||||
|
||||
$today_ymd = $this->_registry->get(
|
||||
'date.time',
|
||||
$this->_registry->get( 'date.system' )->current_time()
|
||||
)->format( 'Y-m-d' );
|
||||
|
||||
$evt_stack = array( 0 ); // Stack to keep track of indentation
|
||||
|
||||
foreach ( $all_events[$day_start_ts] as $event_type => &$events ) {
|
||||
foreach ( $events as &$evt ) {
|
||||
$event = array(
|
||||
'filtered_title' => $evt->get_runtime( 'filtered_title' ),
|
||||
'post_excerpt' => $evt->get_runtime( 'post_excerpt' ),
|
||||
'color_style' => $evt->get_runtime( 'color_style' ),
|
||||
'category_colors' => $evt->get_runtime( 'category_colors' ),
|
||||
'permalink' => $evt->get_runtime( 'instance_permalink' ),
|
||||
'ticket_url_label' => $evt->get_runtime( 'ticket_url_label' ),
|
||||
'edit_post_link' => $evt->get_runtime( 'edit_post_link' ),
|
||||
'faded_color' => $evt->get_runtime( 'faded_color' ),
|
||||
'rgba_color' => $evt->get_runtime( 'rgba_color' ),
|
||||
'short_start_time' => $evt->get_runtime( 'short_start_time' ),
|
||||
'instance_id' => $evt->get( 'instance_id' ),
|
||||
'post_id' => $evt->get( 'post_id' ),
|
||||
'is_multiday' => $evt->get( 'is_multiday' ),
|
||||
'venue' => $evt->get( 'venue' ),
|
||||
'ticket_url' => $evt->get( 'ticket_url' ),
|
||||
'start_truncated' => $evt->get( 'start_truncated' ),
|
||||
'end_truncated' => $evt->get( 'end_truncated' ),
|
||||
'popup_timespan' => $this->_registry
|
||||
->get( 'twig.ai1ec-extension')->timespan( $evt, 'short' ),
|
||||
'avatar_not_wrapped' => $evt->getavatar( false ),
|
||||
'avatar' => $this->_registry
|
||||
->get( 'twig.ai1ec-extension')->avatar(
|
||||
$evt,
|
||||
array(
|
||||
'post_thumbnail',
|
||||
'content_img',
|
||||
'location_avatar',
|
||||
'category_avatar',
|
||||
),
|
||||
'',
|
||||
false ),
|
||||
);
|
||||
$meta = $this->_registry->get( 'model.meta-post' );
|
||||
if ( ! $event['ticket_url'] ) {
|
||||
$timely_tickets = $meta->get(
|
||||
$evt->get( 'post_id' ),
|
||||
'_ai1ec_timely_tickets_url',
|
||||
null
|
||||
);
|
||||
if ( $timely_tickets ) {
|
||||
$event['ticket_url'] = $timely_tickets;
|
||||
$evt->set( 'ticket_url', $event['ticket_url'] );
|
||||
}
|
||||
}
|
||||
if (
|
||||
true === apply_filters(
|
||||
'ai1ec_buy_button_product',
|
||||
false
|
||||
)
|
||||
) {
|
||||
$full_details = $meta->get(
|
||||
$evt->get( 'post_id' ),
|
||||
'_ai1ec_ep_product_details',
|
||||
null
|
||||
);
|
||||
if (
|
||||
is_array( $full_details ) &&
|
||||
isset( $full_details['show_buy_button'] ) &&
|
||||
true === $full_details['show_buy_button']
|
||||
&& $event['ticket_url']
|
||||
) {
|
||||
// Tickets button is shown by default in this case.
|
||||
} else {
|
||||
// Otherwise not.
|
||||
$event['ticket_url'] = false;
|
||||
}
|
||||
$evt->set( 'ticket_url', $event['ticket_url'] );
|
||||
}
|
||||
|
||||
if (
|
||||
$this->_compatibility->use_backward_compatibility()
|
||||
) {
|
||||
$event = $evt;
|
||||
}
|
||||
if ( 'notallday' === $event_type) {
|
||||
// Calculate top and bottom edges of current event
|
||||
$top = (int)(
|
||||
$evt->get( 'start' )->diff_sec( $loc_start_time ) / 60
|
||||
);
|
||||
$bottom = min(
|
||||
$top + ( $evt->get_duration() / 60 ),
|
||||
1440
|
||||
);
|
||||
// While there's more than one event in the stack and this event's
|
||||
// top position is beyond the last event's bottom, pop the stack
|
||||
while ( count( $evt_stack ) > 1 && $top >= end( $evt_stack ) ) {
|
||||
array_pop( $evt_stack );
|
||||
}
|
||||
// Indentation is number of stacked events minus 1
|
||||
$indent = count( $evt_stack ) - 1;
|
||||
// Push this event onto the top of the stack
|
||||
array_push( $evt_stack, $bottom );
|
||||
$evt = array(
|
||||
'top' => $top,
|
||||
'height' => $bottom - $top,
|
||||
'indent' => $indent,
|
||||
'event' => $event,
|
||||
);
|
||||
} else {
|
||||
$evt = $event;
|
||||
}
|
||||
}
|
||||
}
|
||||
$days[$day_start_ts] = array(
|
||||
'today' => 0 === strcmp(
|
||||
$today_ymd,
|
||||
$start_time->format( 'Y-m-d' )
|
||||
),
|
||||
'allday' => $all_events[$day_start_ts]['allday'],
|
||||
'notallday' => $all_events[$day_start_ts]['notallday'],
|
||||
'day' => $this->_registry->
|
||||
get( 'date.time', $day_start_ts )->format_i18n( 'j' ),
|
||||
'weekday' => $this->_registry->
|
||||
get( 'date.time', $day_start_ts )->format_i18n( 'D' ),
|
||||
);
|
||||
|
||||
return apply_filters(
|
||||
'ai1ec_get_oneday_cell_array',
|
||||
$days,
|
||||
$start_time->format(),
|
||||
$filter
|
||||
);
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Calendar_View_Abstract::_add_view_specific_runtime_properties()
|
||||
*/
|
||||
protected function _add_view_specific_runtime_properties( Ai1ec_Event $event ) {
|
||||
$event->set_runtime(
|
||||
'multiday',
|
||||
$event->get( '_orig' )->is_multiday()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,513 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The concrete class for day view.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View
|
||||
*/
|
||||
class Ai1ec_Calendar_View_Week extends Ai1ec_Calendar_View_Abstract {
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Calendar_View_Abstract::get_name()
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'week';
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Calendar_View_Abstract::get_content()
|
||||
*/
|
||||
public function get_content( array $view_args ) {
|
||||
$date_system = $this->_registry->get( 'date.system' );
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$defaults = array(
|
||||
'week_offset' => 0,
|
||||
'cat_ids' => array(),
|
||||
'tag_ids' => array(),
|
||||
'auth_ids' => array(),
|
||||
'post_ids' => array(),
|
||||
'instance_ids' => array(),
|
||||
'exact_date' => $date_system->current_time(),
|
||||
);
|
||||
$args = wp_parse_args( $view_args, $defaults );
|
||||
|
||||
// Localize requested date and get components.
|
||||
$local_date = $this->_registry
|
||||
->get( 'date.time', $args['exact_date'], 'sys.default' );
|
||||
$start_day_offset = $this->get_week_start_day_offset( $local_date->format( 'w' ) );
|
||||
// get the first day of week
|
||||
$local_date->adjust_day( 0 + $start_day_offset + ( $args['week_offset'] * 7 ) )
|
||||
->set_time( 0, 0, 0 );
|
||||
|
||||
$cell_array = $this->get_week_cell_array(
|
||||
$local_date,
|
||||
apply_filters(
|
||||
'ai1ec_get_events_relative_to_filter',
|
||||
array(
|
||||
'cat_ids' => $args['cat_ids'],
|
||||
'tag_ids' => $args['tag_ids'],
|
||||
'post_ids' => $args['post_ids'],
|
||||
'auth_ids' => $args['auth_ids'],
|
||||
'instance_ids' => $args['instance_ids'],
|
||||
),
|
||||
$view_args,
|
||||
apply_filters(
|
||||
'ai1ec_show_unique_events',
|
||||
false
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Create pagination links. (Translators: '%s' = week's start date.)
|
||||
$title = sprintf(
|
||||
__( 'Week of %s', AI1EC_PLUGIN_NAME ),
|
||||
$local_date->format_i18n( 'F j' )
|
||||
);
|
||||
$pagination_links = $this->_get_pagination( $args, $title );
|
||||
|
||||
$time_format = $this->_registry->get( 'model.option' )
|
||||
->get( 'time_format', Ai1ec_I18n::__( 'g a' ) );
|
||||
|
||||
// Calculate today marker's position.
|
||||
$now = $this->_registry->get( 'date.time', 'now', 'sys.default' );
|
||||
$now_text = $now->format_i18n( 'M j h:i a' );
|
||||
$now = $now->format( 'G' ) * 60 + $now->format( 'i' );
|
||||
// Find out if the current week view contains "now" and thus should display
|
||||
// the "now" marker.
|
||||
$show_now = false;
|
||||
foreach ( $cell_array as $day ) {
|
||||
if ( $day['today'] ) {
|
||||
$show_now = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$is_ticket_button_enabled = apply_filters( 'ai1ec_week_ticket_button', false );
|
||||
$show_reveal_button = apply_filters( 'ai1ec_week_reveal_button', false );
|
||||
|
||||
$hours = array();
|
||||
$today = $this->_registry->get( 'date.time', 'now', 'sys.default' );
|
||||
for ( $hour = 0; $hour < 24; $hour++ ) {
|
||||
$hours[] = $today
|
||||
->set_time( $hour, 0, 0 )
|
||||
->format_i18n( $time_format );
|
||||
}
|
||||
|
||||
$view_args = array(
|
||||
'title' => $title,
|
||||
'type' => 'week',
|
||||
'cell_array' => $cell_array,
|
||||
'show_location_in_title' => $settings->get( 'show_location_in_title' ),
|
||||
'now_top' => $now,
|
||||
'now_text' => $now_text,
|
||||
'show_now' => $show_now,
|
||||
'post_ids' => join( ',', $args['post_ids'] ),
|
||||
'time_format' => $time_format,
|
||||
'done_allday_label' => false,
|
||||
'done_grid' => false,
|
||||
'data_type' => $args['data_type'],
|
||||
'is_ticket_button_enabled' => $is_ticket_button_enabled,
|
||||
'show_reveal_button' => $show_reveal_button,
|
||||
'text_full_day' => __( 'Reveal full day', AI1EC_PLUGIN_NAME ),
|
||||
'text_all_day' => __( 'All-day', AI1EC_PLUGIN_NAME ),
|
||||
'text_now_label' => __( 'Now:', AI1EC_PLUGIN_NAME ),
|
||||
'text_venue_separator' => __( '@ %s', AI1EC_PLUGIN_NAME ),
|
||||
'hours' => $hours,
|
||||
'indent_multiplier' => 8,
|
||||
'indent_offset' => 0,
|
||||
'pagination_links' => $pagination_links,
|
||||
);
|
||||
|
||||
// Add navigation if requested.
|
||||
$view_args['navigation'] = $this->_get_navigation(
|
||||
array(
|
||||
'no_navigation' => $args['no_navigation'],
|
||||
'pagination_links' => $pagination_links,
|
||||
'views_dropdown' => $args['views_dropdown'],
|
||||
'below_toolbar' => apply_filters(
|
||||
'ai1ec_below_toolbar',
|
||||
'',
|
||||
$this->get_name(),
|
||||
$args
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$view_args = $this->get_extra_template_arguments( $view_args );
|
||||
|
||||
return
|
||||
$this->_registry->get( 'http.request' )->is_json_required(
|
||||
$args['request_format'], 'week'
|
||||
)
|
||||
? $this->_apply_filters_to_args( $view_args )
|
||||
: $this->_get_view( $view_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a non-associative array of two links for the week view of the
|
||||
* calendar:
|
||||
* previous week, and next week.
|
||||
* Each element is an associative array containing the link's enabled status
|
||||
* ['enabled'], CSS class ['class'], text ['text'] and value to assign to
|
||||
* link's href ['href'].
|
||||
*
|
||||
* @param array $args Current request arguments
|
||||
* @param string $title Title to display in datepicker button
|
||||
*
|
||||
* @return array Array of links
|
||||
*/
|
||||
protected function get_week_pagination_links( $args, $title ) {
|
||||
$links = array();
|
||||
|
||||
$orig_date = $args['exact_date'];
|
||||
|
||||
$negative_offset = $args['week_offset'] * 7 - 7;
|
||||
$positive_offset = $args['week_offset'] * 7 + 7;
|
||||
// =================
|
||||
// = Previous week =
|
||||
// =================
|
||||
$local_date = $this->_registry
|
||||
->get( 'date.time', $args['exact_date'], 'sys.default' )
|
||||
->adjust_day( $negative_offset )
|
||||
->set_time( 0, 0, 0 );
|
||||
$args['exact_date'] = $local_date->format();
|
||||
$href = $this->_registry->get( 'html.element.href', $args );
|
||||
$links[] = array(
|
||||
'enabled' => true,
|
||||
'class'=> 'ai1ec-prev-week',
|
||||
'text' => '<i class="ai1ec-fa ai1ec-fa-chevron-left"></i>',
|
||||
'href' => $href->generate_href(),
|
||||
);
|
||||
// ======================
|
||||
// = Minical datepicker =
|
||||
// ======================
|
||||
$args['exact_date'] = $orig_date;
|
||||
$factory = $this->_registry->get( 'factory.html' );
|
||||
$links[] = $factory->create_datepicker_link(
|
||||
$args,
|
||||
$args['exact_date'],
|
||||
$title
|
||||
);
|
||||
|
||||
// =============
|
||||
// = Next week =
|
||||
// =============
|
||||
$local_date->adjust_day( $positive_offset * 2 ); // above was (-1), (+2) is to counteract
|
||||
$args['exact_date'] = $local_date->format();
|
||||
$href = $this->_registry->get( 'html.element.href', $args );
|
||||
$links[] = array(
|
||||
'enabled' => true,
|
||||
'class'=> 'ai1ec-next-week',
|
||||
'text' => '<i class="ai1ec-fa ai1ec-fa-chevron-right"></i>',
|
||||
'href' => $href->generate_href(),
|
||||
);
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_week_cell_array function
|
||||
*
|
||||
* Return an associative array of weekdays, indexed by the day's date,
|
||||
* starting the day given by $timestamp, each element an associative array
|
||||
* containing three elements:
|
||||
* ['today'] => whether the day is today
|
||||
* ['allday'] => non-associative ordered array of events that are all-day
|
||||
* ['notallday'] => non-associative ordered array of non-all-day events to
|
||||
* display for that day, each element another associative
|
||||
* array like so:
|
||||
* ['top'] => how many minutes offset from the start of the day
|
||||
* ['height'] => how many minutes this event spans
|
||||
* ['indent'] => how much to indent this event to accommodate multiple
|
||||
* events occurring at the same time (0, 1, 2, etc., to
|
||||
* be multiplied by whatever desired px/em amount)
|
||||
* ['event'] => event data object
|
||||
*
|
||||
* @param int $start_of_week the UNIX timestamp of the first day of the week
|
||||
* @param array $filter Array of filters for the events returned:
|
||||
* ['cat_ids'] => non-associatative array of category IDs
|
||||
* ['tag_ids'] => non-associatative array of tag IDs
|
||||
* ['post_ids'] => non-associatative array of post IDs
|
||||
* ['auth_ids'] => non-associatative array of author IDs
|
||||
*
|
||||
* @return array array of arrays as per function description
|
||||
*/
|
||||
protected function get_week_cell_array( Ai1ec_Date_Time $start_of_week, $filter = array() ) {
|
||||
$search = $this->_registry->get( 'model.search' );
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$date_system = $this->_registry->get( 'date.system' );
|
||||
$end_of_week = $this->_registry->get( 'date.time', $start_of_week );
|
||||
$end_of_week->adjust_day( 7 );
|
||||
// Do one SQL query to find all events for the week, including spanning
|
||||
$week_events = $search->get_events_between(
|
||||
$start_of_week,
|
||||
$end_of_week,
|
||||
$filter,
|
||||
true
|
||||
);
|
||||
$this->_update_meta( $week_events );
|
||||
// Split up events on a per-day basis
|
||||
$all_events = array();
|
||||
$this->_days_cache = $this->_registry->get( 'cache.memory' );
|
||||
$this->_registry->get( 'controller.content-filter' )
|
||||
->clear_the_content_filters();
|
||||
foreach ( $week_events as $evt ) {
|
||||
list( $evt_start, $evt_end ) = $this->
|
||||
_get_view_specific_timestamps( $evt );
|
||||
|
||||
// Iterate through each day of the week and generate new event object
|
||||
// based on this one for each day that it spans
|
||||
for (
|
||||
$day = $start_of_week->format( 'j' ),
|
||||
$last_week_day_index = $start_of_week->format( 'j' ) + 7;
|
||||
$day < $last_week_day_index;
|
||||
$day++
|
||||
) {
|
||||
list( $day_start, $day_end ) = $this->
|
||||
_get_wkday_start_end( $day, $start_of_week );
|
||||
|
||||
if ( $evt_end < $day_start ) {
|
||||
break; // save cycles
|
||||
}
|
||||
|
||||
// If event falls on this day, make a copy.
|
||||
if ( $evt_end > $day_start && $evt_start < $day_end ) {
|
||||
$_evt = clone $evt;
|
||||
if ( $evt_start < $day_start ) {
|
||||
// If event starts before this day, adjust copy's start time
|
||||
$_evt->set( 'start', $day_start );
|
||||
$_evt->set( 'start_truncated', true );
|
||||
}
|
||||
if ( $evt_end > $day_end ) {
|
||||
// If event ends after this day, adjust copy's end time
|
||||
$_evt->set( 'end', $day_end );
|
||||
$_evt->set( 'end_truncated', true );
|
||||
}
|
||||
|
||||
// Store reference to original, unmodified event, required by view.
|
||||
$_evt->set( '_orig', $evt );
|
||||
$this->_add_runtime_properties( $_evt );
|
||||
|
||||
// Place copy of event in appropriate category
|
||||
if ( $_evt->is_allday() ) {
|
||||
$all_events[$day_start]['allday'][] = $_evt;
|
||||
} else {
|
||||
$all_events[$day_start]['notallday'][] = $_evt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->_registry->get( 'controller.content-filter' )
|
||||
->restore_the_content_filters();
|
||||
// This will store the returned array
|
||||
$days = array();
|
||||
$now = $this->_registry->get(
|
||||
'date.time',
|
||||
'now',
|
||||
$start_of_week->get_timezone()
|
||||
);
|
||||
// =========================================
|
||||
// = Iterate through each date of the week =
|
||||
// =========================================
|
||||
for (
|
||||
$day = $start_of_week->format( 'j' ),
|
||||
$last_week_day_index = $start_of_week->format( 'j' ) + 7;
|
||||
$day < $last_week_day_index;
|
||||
$day++
|
||||
) {
|
||||
list( $day_date, , $day_date_ob ) = $this->
|
||||
_get_wkday_start_end( $day, $start_of_week );
|
||||
|
||||
$exact_date = $date_system->format_datetime_for_url(
|
||||
$day_date_ob,
|
||||
$settings->get( 'input_date_format' )
|
||||
);
|
||||
$href_for_date = $this->_create_link_for_day_view( $exact_date );
|
||||
|
||||
// Initialize empty arrays for this day if no events to minimize warnings
|
||||
if ( ! isset( $all_events[$day_date]['allday'] ) ) {
|
||||
$all_events[$day_date]['allday'] = array();
|
||||
}
|
||||
if ( ! isset( $all_events[$day_date]['notallday'] ) ) {
|
||||
$all_events[$day_date]['notallday'] = array();
|
||||
}
|
||||
|
||||
$evt_stack = array( 0 ); // Stack to keep track of indentation
|
||||
|
||||
foreach ( $all_events[$day_date] as $event_type => &$events ) {
|
||||
foreach ( $events as &$evt ) {
|
||||
$event = array(
|
||||
'filtered_title' => $evt->get_runtime( 'filtered_title' ),
|
||||
'post_excerpt' => $evt->get_runtime( 'post_excerpt' ),
|
||||
'color_style' => $evt->get_runtime( 'color_style' ),
|
||||
'category_colors' => $evt->get_runtime( 'category_colors' ),
|
||||
'permalink' => $evt->get_runtime( 'instance_permalink' ),
|
||||
'ticket_url_label' => $evt->get_runtime( 'ticket_url_label' ),
|
||||
'edit_post_link' => $evt->get_runtime( 'edit_post_link' ),
|
||||
'faded_color' => $evt->get_runtime( 'faded_color' ),
|
||||
'rgba_color' => $evt->get_runtime( 'rgba_color' ),
|
||||
'short_start_time' => $evt->get_runtime( 'short_start_time' ),
|
||||
'instance_id' => $evt->get( 'instance_id' ),
|
||||
'post_id' => $evt->get( 'post_id' ),
|
||||
'is_multiday' => $evt->get( 'is_multiday' ),
|
||||
'venue' => $evt->get( 'venue' ),
|
||||
'ticket_url' => $evt->get( 'ticket_url' ),
|
||||
'start_truncated' => $evt->get( 'start_truncated' ),
|
||||
'end_truncated' => $evt->get( 'end_truncated' ),
|
||||
'popup_timespan' => $this->_registry
|
||||
->get( 'twig.ai1ec-extension')->timespan( $evt, 'short' ),
|
||||
'avatar_not_wrapped' => $evt->getavatar( false ),
|
||||
'avatar' => $this->_registry
|
||||
->get( 'twig.ai1ec-extension')->avatar(
|
||||
$evt,
|
||||
array(
|
||||
'post_thumbnail',
|
||||
'content_img',
|
||||
'location_avatar',
|
||||
'category_avatar',
|
||||
),
|
||||
'',
|
||||
false ),
|
||||
);
|
||||
$meta = $this->_registry->get( 'model.meta-post' );
|
||||
if ( ! $event['ticket_url'] ) {
|
||||
$timely_tickets = $meta->get(
|
||||
$evt->get( 'post_id' ),
|
||||
'_ai1ec_timely_tickets_url',
|
||||
null
|
||||
);
|
||||
if ( $timely_tickets ) {
|
||||
$event['ticket_url'] = $timely_tickets;
|
||||
$evt->set( 'ticket_url', $event['ticket_url'] );
|
||||
}
|
||||
}
|
||||
if (
|
||||
true === apply_filters(
|
||||
'ai1ec_buy_button_product',
|
||||
false
|
||||
)
|
||||
) {
|
||||
$full_details = $meta->get(
|
||||
$evt->get( 'post_id' ),
|
||||
'_ai1ec_ep_product_details',
|
||||
null
|
||||
);
|
||||
if (
|
||||
is_array( $full_details ) &&
|
||||
isset( $full_details['show_buy_button'] ) &&
|
||||
true === $full_details['show_buy_button']
|
||||
&& $event['ticket_url']
|
||||
) {
|
||||
// Tickets button is shown by default in this case.
|
||||
} else {
|
||||
// Otherwise not.
|
||||
$event['ticket_url'] = false;
|
||||
}
|
||||
$evt->set( 'ticket_url', $event['ticket_url'] );
|
||||
}
|
||||
|
||||
if (
|
||||
$this->_compatibility->use_backward_compatibility()
|
||||
) {
|
||||
$event = $evt;
|
||||
}
|
||||
if ( 'notallday' === $event_type) {
|
||||
$start = $evt->get( 'start' );
|
||||
// Calculate top and bottom edges of current event
|
||||
$top = $start->format( 'G' ) * 60 + $start->format( 'i' );
|
||||
$bottom = min( $top + $evt->get_duration() / 60, 1440 );
|
||||
// While there's more than one event in the stack and this event's top
|
||||
// position is beyond the last event's bottom, pop the stack
|
||||
while ( count( $evt_stack ) > 1 && $top >= end( $evt_stack ) ) {
|
||||
array_pop( $evt_stack );
|
||||
}
|
||||
// Indentation is number of stacked events minus 1
|
||||
$indent = count( $evt_stack ) - 1;
|
||||
// Push this event onto the top of the stack
|
||||
array_push( $evt_stack, $bottom );
|
||||
$evt = array(
|
||||
'top' => $top,
|
||||
'height' => $bottom - $top,
|
||||
'indent' => $indent,
|
||||
'event' => $event,
|
||||
);
|
||||
} else {
|
||||
$evt = $event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$days[$day_date] = array(
|
||||
'today' =>
|
||||
$day_date_ob->format( 'Y' ) == $now->format( 'Y' ) &&
|
||||
$day_date_ob->format( 'm' ) == $now->format( 'm' ) &&
|
||||
$day_date_ob->format( 'j' ) == $now->format( 'j' ),
|
||||
'allday' => $all_events[$day_date]['allday'],
|
||||
'notallday' => $all_events[$day_date]['notallday'],
|
||||
'href' => $href_for_date,
|
||||
'day' => $this->_registry->
|
||||
get( 'date.time', $day_date )->format_i18n( 'j' ),
|
||||
'weekday' => $this->_registry->
|
||||
get( 'date.time', $day_date )->format_i18n( 'D' ),
|
||||
);
|
||||
}
|
||||
|
||||
return apply_filters( 'ai1ec_get_week_cell_array', $days, $start_of_week, $filter );
|
||||
}
|
||||
|
||||
/**
|
||||
* get_week_start_day_offset function
|
||||
*
|
||||
* Returns the day offset of the first day of the week given a weekday in
|
||||
* question.
|
||||
*
|
||||
* @param int $wday The weekday to get information about
|
||||
* @return int A value between -6 and 0 indicating the week start
|
||||
* day relative to the given weekday.
|
||||
*/
|
||||
protected function get_week_start_day_offset( $wday ) {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
return - ( 7 - ( $settings->get( 'week_start_day' ) - $wday ) ) % 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get start/end timestamps for a given weekday and week start identifier.
|
||||
*
|
||||
* @param int $day Week day number.
|
||||
* @param Ai1ec_Date_Time $week_start Date/Time information for week start.
|
||||
*
|
||||
* @return array List of start and and timestamps, 0-indexed array.
|
||||
*/
|
||||
protected function _get_wkday_start_end(
|
||||
$day,
|
||||
Ai1ec_Date_Time $week_start
|
||||
) {
|
||||
$entry = null;
|
||||
$day = (int)$day;
|
||||
if ( null === ( $entry = $this->_days_cache->get( $day ) ) ) {
|
||||
$day_start = $this->_registry
|
||||
->get( 'date.time', $week_start )
|
||||
->set_date(
|
||||
$week_start->format( 'Y' ),
|
||||
$week_start->format( 'm' ),
|
||||
$day
|
||||
)
|
||||
->set_time( 0, 0, 0 );
|
||||
$day_end = $this->_registry->get( 'date.time', $day_start );
|
||||
$day_end->adjust_day( 1 );
|
||||
$entry = array(
|
||||
$day_start->format(),
|
||||
$day_end->format(),
|
||||
$day_start
|
||||
);
|
||||
unset( $day_end ); // discard and free memory
|
||||
$this->_days_cache->set( $day, $entry );
|
||||
}
|
||||
return $entry;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,428 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Calendar Widget class
|
||||
*
|
||||
* A widget that displays the next X upcoming events (similar to Agenda view).
|
||||
*/
|
||||
class Ai1ec_View_Admin_Widget extends Ai1ec_Embeddable {
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $_css_loaded = false;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_id() {
|
||||
return 'ai1ec_agenda_widget';
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the widget class.
|
||||
*/
|
||||
public static function register_widget() {
|
||||
register_widget( 'Ai1ec_View_Admin_Widget' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for widget.
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
parent::__construct(
|
||||
$this->get_id(),
|
||||
__( 'Upcoming Events', AI1EC_PLUGIN_NAME ),
|
||||
array(
|
||||
'description' => __( 'All-in-One Event Calendar: Lists upcoming events in Agenda view', AI1EC_PLUGIN_NAME ),
|
||||
'class' => 'ai1ec-agenda-widget',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Embeddable::register_javascript_widget()
|
||||
*/
|
||||
public function register_javascript_widget( $id_base ) {
|
||||
$this->_registry->get( 'controller.javascript-widget' )
|
||||
->add_widget( $id_base, 'view.calendar.widget' );
|
||||
}
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Embeddable::get_defaults()
|
||||
*/
|
||||
public function get_defaults() {
|
||||
return array(
|
||||
'title' => __( 'Upcoming Events', AI1EC_PLUGIN_NAME ),
|
||||
'events_seek_type' => 'events',
|
||||
'events_per_page' => 10,
|
||||
'days_per_page' => 10,
|
||||
'show_subscribe_buttons' => true,
|
||||
'show_calendar_button' => true,
|
||||
'hide_on_calendar_page' => true,
|
||||
'limit_by_cat' => false,
|
||||
'limit_by_tag' => false,
|
||||
'cat_ids' => array(),
|
||||
'tag_ids' => array(),
|
||||
'link_for_days' => true,
|
||||
);
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Embeddable::get_configurable_for_widget_creation()
|
||||
*/
|
||||
public function get_configurable_for_widget_creation() {
|
||||
$defaults = $this->get_js_widget_configurable_defaults();
|
||||
return array(
|
||||
'events_seek_type' => array(
|
||||
'renderer' => array(
|
||||
'class' => 'select',
|
||||
'label' => __(
|
||||
'Choose how to limit the upcoming events',
|
||||
AI1EC_PLUGIN_NAME
|
||||
),
|
||||
'options' => array(
|
||||
array(
|
||||
'text' => __(
|
||||
'Events',
|
||||
AI1EC_PLUGIN_NAME
|
||||
),
|
||||
'value' => 'events'
|
||||
),
|
||||
array(
|
||||
'text' => __(
|
||||
'Days',
|
||||
AI1EC_PLUGIN_NAME
|
||||
),
|
||||
'value' => 'days'
|
||||
),
|
||||
),
|
||||
),
|
||||
'value' => $defaults['events_seek_type']
|
||||
),
|
||||
'events_per_page' => array(
|
||||
'renderer' => array(
|
||||
'class' => 'input',
|
||||
'label' => Ai1ec_I18n::__( 'Number of events to show' ),
|
||||
'type' => 'append',
|
||||
'append' => 'events',
|
||||
),
|
||||
'value' => $defaults['events_per_page'],
|
||||
),
|
||||
'days_per_page' => array(
|
||||
'renderer' => array(
|
||||
'class' => 'input',
|
||||
'label' => Ai1ec_I18n::__( 'Number of days to show' ),
|
||||
'type' => 'append',
|
||||
'append' => 'days',
|
||||
),
|
||||
'value' => $defaults['days_per_page'],
|
||||
),
|
||||
'upcoming_widgets_default_tags_categories' => array(
|
||||
'renderer' => array(
|
||||
'class' => 'tags-categories',
|
||||
'label' => __(
|
||||
'Show events filtered for the following tags/categories',
|
||||
AI1EC_PLUGIN_NAME
|
||||
),
|
||||
'help' => __(
|
||||
'To clear, hold ⌘/<abbr class="initialism">CTRL</abbr> and click selection.',
|
||||
AI1EC_PLUGIN_NAME
|
||||
)
|
||||
),
|
||||
'value' => array(
|
||||
'categories' => array(),
|
||||
'tags' => array(),
|
||||
),
|
||||
),
|
||||
'show_subscribe_buttons' => array(
|
||||
'renderer' => array(
|
||||
'class' => 'checkbox',
|
||||
'label' => Ai1ec_I18n::__( 'Show the subscribe button in the widget' ),
|
||||
),
|
||||
'value' => $defaults['show_subscribe_buttons'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Calendar_View_Abstract::get_name()
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'Upcoming Events';
|
||||
}
|
||||
|
||||
/**
|
||||
* The icon class associated with the widget.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_icon() {
|
||||
return 'ai1ec-fa ai1ec-fa-clock-o';
|
||||
}
|
||||
|
||||
/**
|
||||
* Form function.
|
||||
*
|
||||
* Renders the widget's configuration form for the Manage Widgets page.
|
||||
*
|
||||
* @param array $instance The data array for the widget instance being configured.
|
||||
* @return void
|
||||
*/
|
||||
public function form( $instance ) {
|
||||
$default = $this->get_defaults();
|
||||
$instance = wp_parse_args( (array) $instance, $default );
|
||||
|
||||
// Get available cats, tags, events to allow user to limit widget to certain categories
|
||||
$events_categories = get_terms( 'events_categories', array( 'orderby' => 'name', "hide_empty" => false ) );
|
||||
$events_tags = get_terms( 'events_tags', array( 'orderby' => 'name', "hide_empty" => false ) );
|
||||
|
||||
// Generate unique IDs and NAMEs of all needed form fields
|
||||
$fields = array(
|
||||
'title' => array('value' => $instance['title']),
|
||||
'events_seek_type' => array('value' => $instance['events_seek_type']),
|
||||
'events_per_page' => array('value' => $instance['events_per_page']),
|
||||
'days_per_page' => array('value' => $instance['days_per_page']),
|
||||
'show_subscribe_buttons' => array('value' => $instance['show_subscribe_buttons']),
|
||||
'show_calendar_button' => array('value' => $instance['show_calendar_button']),
|
||||
'hide_on_calendar_page' => array('value' => $instance['hide_on_calendar_page']),
|
||||
'limit_by_cat' => array('value' => $instance['limit_by_cat']),
|
||||
'limit_by_tag' => array('value' => $instance['limit_by_tag']),
|
||||
'cat_ids' => array(
|
||||
'value' => (array)$instance['cat_ids'],
|
||||
'options' => $events_categories
|
||||
),
|
||||
'tag_ids' => array(
|
||||
'value' => (array)$instance['tag_ids'],
|
||||
'options' => $events_tags
|
||||
),
|
||||
);
|
||||
foreach ( $fields as $field => $data ) {
|
||||
$fields[$field]['id'] = $this->get_field_id( $field );
|
||||
$fields[$field]['name'] = $this->get_field_name( $field );
|
||||
$fields[$field]['value'] = $data['value'];
|
||||
if ( isset($data['options']) ) {
|
||||
$fields[$field]['options'] = $data['options'];
|
||||
}
|
||||
}
|
||||
|
||||
// Display theme
|
||||
$this->_registry->get( 'theme.loader' )->get_file(
|
||||
'agenda-widget-form.php',
|
||||
$fields,
|
||||
true
|
||||
)->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update function.
|
||||
*
|
||||
* Called when a user submits the widget configuration form.
|
||||
* The data should be validated and returned.
|
||||
*
|
||||
* @param array $new_instance The new data that was submitted.
|
||||
* @param array $old_instance The widget's old data.
|
||||
* @return array The new data to save for this widget instance.
|
||||
*/
|
||||
public function update( $new_instance, $old_instance ) {
|
||||
// Save existing data as a base to modify with new data
|
||||
$instance = $old_instance;
|
||||
$instance['title'] = strip_tags( $new_instance['title'] );
|
||||
$instance['events_per_page'] = Ai1ec_Primitive_Int::index(
|
||||
$new_instance['events_per_page'],
|
||||
1,
|
||||
1
|
||||
);
|
||||
$instance['days_per_page'] = Ai1ec_Primitive_Int::index(
|
||||
$new_instance['days_per_page'],
|
||||
1,
|
||||
1
|
||||
);
|
||||
$instance['events_seek_type'] = $this->_valid_seek_type(
|
||||
$new_instance['events_seek_type']
|
||||
);
|
||||
$instance['show_subscribe_buttons'] = isset( $new_instance['show_subscribe_buttons'] ) ? true : false;
|
||||
$instance['show_calendar_button'] = isset( $new_instance['show_calendar_button'] ) ? true : false;
|
||||
$instance['hide_on_calendar_page'] = isset( $new_instance['hide_on_calendar_page'] ) ? true : false;
|
||||
|
||||
// For limits, set the limit to False if no IDs were selected, or set the respective IDs to empty if "limit by" was unchecked
|
||||
$instance['limit_by_cat'] = false;
|
||||
$instance['cat_ids'] = array();
|
||||
if ( isset( $new_instance['cat_ids'] ) && $new_instance['cat_ids'] != false ) {
|
||||
$instance['limit_by_cat'] = true;
|
||||
}
|
||||
if ( isset( $new_instance['limit_by_cat'] ) && $new_instance['limit_by_cat'] != false ) {
|
||||
$instance['limit_by_cat'] = true;
|
||||
}
|
||||
if ( isset( $new_instance['cat_ids'] ) && $instance['limit_by_cat'] === true ) {
|
||||
$instance['cat_ids'] = $new_instance['cat_ids'];
|
||||
}
|
||||
|
||||
$instance['limit_by_tag'] = false;
|
||||
$instance['tag_ids'] = array();
|
||||
if ( isset( $new_instance['tag_ids'] ) && $new_instance['tag_ids'] != false ) {
|
||||
$instance['limit_by_tag'] = true;
|
||||
}
|
||||
if ( isset( $new_instance['limit_by_tag'] ) && $new_instance['limit_by_tag'] != false ) {
|
||||
$instance['limit_by_tag'] = true;
|
||||
}
|
||||
if ( isset( $new_instance['tag_ids'] ) && $instance['limit_by_tag'] === true ) {
|
||||
$instance['tag_ids'] = $new_instance['tag_ids'];
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Embeddable::add_js()
|
||||
*/
|
||||
public function add_js() {
|
||||
$this->_registry->get( 'controller.javascript' )->add_link_to_render_js(
|
||||
Ai1ec_Javascript_Controller::LOAD_ONLY_FRONTEND_SCRIPTS,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Embeddable::get_content()
|
||||
*/
|
||||
public function get_content( array $args_for_widget, $remote = false ) {
|
||||
$agenda = $this->_registry->get(
|
||||
'view.calendar.view.agenda',
|
||||
$this->_registry->get( 'http.request.parser' )
|
||||
);
|
||||
$time = $this->_registry->get( 'date.time' );
|
||||
$search = $this->_registry->get( 'model.search' );
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$html = $this->_registry->get( 'factory.html' );
|
||||
|
||||
$is_calendar_page = is_page( $settings->get( 'calendar_page_id' ) );
|
||||
if ( $args_for_widget['hide_on_calendar_page'] &&
|
||||
$is_calendar_page ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add params to the subscribe_url for filtering by Limits (category, tag)
|
||||
$subscribe_filter = '';
|
||||
if ( ! is_array( $args_for_widget['cat_ids'] ) ) {
|
||||
$args_for_widget['cat_ids'] = explode( ',', $args_for_widget['cat_ids'] );
|
||||
}
|
||||
|
||||
if ( ! is_array( $args_for_widget['tag_ids'] ) ) {
|
||||
$args_for_widget['tag_ids'] = explode( ',', $args_for_widget['tag_ids'] );
|
||||
}
|
||||
$subscribe_filter .= $args_for_widget['cat_ids'] ? '&ai1ec_cat_ids=' . join( ',', $args_for_widget['cat_ids'] ) : '';
|
||||
$subscribe_filter .= $args_for_widget['tag_ids'] ? '&ai1ec_tag_ids=' . join( ',', $args_for_widget['tag_ids'] ) : '';
|
||||
|
||||
// Get localized time
|
||||
$timestamp = $time->format_to_gmt();
|
||||
|
||||
// Set $limit to the specified category/tag
|
||||
$limit = array(
|
||||
'cat_ids' => $args_for_widget['cat_ids'],
|
||||
'tag_ids' => $args_for_widget['tag_ids'],
|
||||
);
|
||||
$limit = apply_filters( 'ai1ec_add_filters_upcoming_widget', $limit );
|
||||
|
||||
// Get events, then classify into date array
|
||||
// JB: apply seek check here
|
||||
$seek_days = ( 'days' === $args_for_widget['events_seek_type'] );
|
||||
$seek_count = $args_for_widget['events_per_page'];
|
||||
$last_day = false;
|
||||
if ( $seek_days ) {
|
||||
$seek_count = $args_for_widget['days_per_page'] * 5;
|
||||
$last_day = strtotime(
|
||||
'+' . $args_for_widget['days_per_page'] . ' days'
|
||||
);
|
||||
}
|
||||
|
||||
$event_results = $search->get_events_relative_to(
|
||||
$timestamp,
|
||||
$seek_count,
|
||||
0,
|
||||
$limit
|
||||
);
|
||||
if ( $seek_days ) {
|
||||
foreach ( $event_results['events'] as $ek => $event ) {
|
||||
if ( $event->get( 'start' )->format() >= $last_day ) {
|
||||
unset( $event_results['events'][$ek] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dates = $agenda->get_agenda_like_date_array( $event_results['events'] );
|
||||
|
||||
|
||||
$args_for_widget['dates'] = $dates;
|
||||
// load CSS just once for all widgets.
|
||||
// Do not load it on the calendar page as it's already loaded.
|
||||
if ( false === $this->_css_loaded && ! $is_calendar_page ) {
|
||||
if ( true === $remote ) {
|
||||
$args_for_widget['css'] = $this->_registry->get( 'css.frontend' )->get_compiled_css();
|
||||
}
|
||||
$this->_css_loaded = true;
|
||||
}
|
||||
$args_for_widget['show_location_in_title'] = $settings->get( 'show_location_in_title' );
|
||||
$args_for_widget['show_year_in_agenda_dates'] = $settings->get( 'show_year_in_agenda_dates' );
|
||||
$args_for_widget['calendar_url'] = $html->create_href_helper_instance( $limit )->generate_href();
|
||||
$args_for_widget['subscribe_url'] = AI1EC_EXPORT_URL . $subscribe_filter;
|
||||
$args_for_widget['subscribe_url_no_html'] = AI1EC_EXPORT_URL . '&no_html=true' . $subscribe_filter;
|
||||
$args_for_widget['text_upcoming_events'] = __( 'There are no upcoming events.', AI1EC_PLUGIN_NAME );
|
||||
$args_for_widget['text_all_day'] = __( 'all-day', AI1EC_PLUGIN_NAME );
|
||||
$args_for_widget['text_view_calendar'] = __( 'View Calendar', AI1EC_PLUGIN_NAME );
|
||||
$args_for_widget['text_edit'] = __( 'Edit', AI1EC_PLUGIN_NAME );
|
||||
$args_for_widget['text_venue_separator'] = __( '@ %s', AI1EC_PLUGIN_NAME );
|
||||
$args_for_widget['text_subscribe_label'] = __( 'Add', AI1EC_PLUGIN_NAME );
|
||||
$args_for_widget['subscribe_buttons_text'] = $this->_registry
|
||||
->get( 'view.calendar.subscribe-button' )
|
||||
->get_labels();
|
||||
// Display theme
|
||||
return $this->_registry->get( 'theme.loader' )->get_file(
|
||||
'agenda-widget.twig',
|
||||
$args_for_widget
|
||||
)->get_content();
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Embeddable::get_js_widget_configurable_defaults()
|
||||
*/
|
||||
public function get_js_widget_configurable_defaults() {
|
||||
$def = $this->get_defaults();
|
||||
unset( $def['title'] );
|
||||
unset( $def['link_for_days'] );
|
||||
return $def;
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Embeddable::javascript_widget()
|
||||
*/
|
||||
public function javascript_widget( $args ) {
|
||||
$args['show_calendar_button'] = false;
|
||||
$args['link_for_days'] = false;
|
||||
return parent::javascript_widget( $args );
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Ai1ec_Embeddable::check_requirements()
|
||||
*/
|
||||
public function check_requirements() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* _valid_seek_type method.
|
||||
*
|
||||
* Return valid seek type for given user input (selection).
|
||||
*
|
||||
* @param string $value User selection for seek type
|
||||
* @return string Seek type to use
|
||||
*/
|
||||
protected function _valid_seek_type( $value ) {
|
||||
static $list = array( 'events', 'days' );
|
||||
if ( ! in_array( $value, $list ) ) {
|
||||
return (string)reset( $list );
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
<?php
|
||||
abstract class Ai1ec_Embeddable extends WP_Widget {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Registry_Object
|
||||
*/
|
||||
protected $_registry;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $_id;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $_css_loaded = false;
|
||||
|
||||
/**
|
||||
* Get default values for shortcode or widget.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function get_defaults();
|
||||
|
||||
/**
|
||||
* Get values which are configurable in the Javascript widget.
|
||||
* Some things might not be configurable.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function get_js_widget_configurable_defaults();
|
||||
|
||||
/**
|
||||
* Create the html for the widget. Shared by all versions.
|
||||
*
|
||||
* @param array $args_for_widget
|
||||
* @param bool $remote_request whether the request is for a remote site or not (useful to inline CSS)
|
||||
*/
|
||||
abstract public function get_content( array $args_for_widget, $remote_request = false );
|
||||
|
||||
/**
|
||||
* Add the required javascript for the widget. Needed for shortcode and Wordpress widget
|
||||
*/
|
||||
abstract public function add_js();
|
||||
|
||||
/**
|
||||
* Register the widget to the controller.
|
||||
*
|
||||
* @param string $id_base
|
||||
*/
|
||||
abstract public function register_javascript_widget( $id_base );
|
||||
|
||||
|
||||
/**
|
||||
* Return options needed for thw "Widget creator page
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function get_configurable_for_widget_creation();
|
||||
|
||||
/**
|
||||
* The human-readable name of the widget.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function get_name();
|
||||
|
||||
/**
|
||||
* The icon class associated with the widget. Defaults to calendar.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_icon() {
|
||||
return 'ai1ec-fa ai1ec-fa-calendar';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks and returns widget requirements.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function check_requirements();
|
||||
|
||||
/**
|
||||
* Register widget class with current WP instance.
|
||||
* This must be static as otherwise the class would be instantiated twice,
|
||||
* one to register it and the other from Wordpress.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function register_widget() {
|
||||
throw new Ai1ec_Exception( 'This should be implemented in child class' );
|
||||
}
|
||||
|
||||
public function __construct( $id_base, $name, $widget_options = array(), $control_options = array() ) {
|
||||
$this->_id = $id_base;
|
||||
parent::__construct( $id_base, $name, $widget_options, $control_options );
|
||||
add_shortcode( $id_base, array( $this, 'shortcode' ) );
|
||||
add_filter(
|
||||
'ai1ec_content_remove_shortcode_' . $id_base,
|
||||
array( $this, 'is_this_to_remove_from_event' )
|
||||
);
|
||||
$this->_registry = apply_filters( 'ai1ec_registry', false );
|
||||
$this->register_javascript_widget( $id_base );
|
||||
add_filter( 'ai1ec_js_translations', array( $this, 'add_js_translations' ) );
|
||||
$this->_registry->get( 'css.frontend' )->add_link_to_html_for_frontend();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $translations
|
||||
* @return array
|
||||
*/
|
||||
public function add_js_translations( array $translations ) {
|
||||
$translations['javascript_widgets'][$this->_id] = $this->get_js_widget_configurable_defaults();
|
||||
return $translations;
|
||||
}
|
||||
/**
|
||||
* Widget function.
|
||||
*
|
||||
* Outputs the given instance of the widget to the front-end.
|
||||
*
|
||||
* @param array $args Display arguments passed to the widget
|
||||
* @param array $instance The settings for this widget instance
|
||||
* @return void
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
$defaults = $this->get_defaults();
|
||||
$instance = wp_parse_args( $instance, $defaults );
|
||||
$this->add_js();
|
||||
$args['widget_html'] = $this->get_content( $instance );
|
||||
if ( ! empty( $args['widget_html'] ) ) {
|
||||
$args['title'] = $instance['title'];
|
||||
$args = $this->_filter_widget_args( $args );
|
||||
// Display theme
|
||||
$this->_registry->get( 'theme.loader' )->get_file(
|
||||
'widget.twig',
|
||||
$args
|
||||
)->render();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders shortcode
|
||||
*
|
||||
* @param array $atts
|
||||
* @param string $content
|
||||
*/
|
||||
public function shortcode( $atts, $content = null ) {
|
||||
$defaults = $this->get_defaults();
|
||||
$atts = shortcode_atts( $defaults, $atts );
|
||||
$this->add_js();
|
||||
return $this->get_content( $atts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders js widget
|
||||
*
|
||||
* @param array $args
|
||||
*/
|
||||
public function javascript_widget( $args ) {
|
||||
$defaults = $this->get_defaults();
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
return $this->get_content( $args, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this shortcode should be removed from event content.
|
||||
*
|
||||
* @return bool True.
|
||||
*/
|
||||
public function is_this_to_remove_from_event() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters default widget parameters like classes, html elements before and
|
||||
* after title or widget. Useful for Feature Events widget which has
|
||||
* different title styling.
|
||||
*
|
||||
* @param array $args Widget arguments.
|
||||
*
|
||||
* @return array Filtered arguments.
|
||||
*/
|
||||
protected function _filter_widget_args( $args ) {
|
||||
return $args;
|
||||
}
|
||||
}
|
||||
@@ -1,405 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event avatar.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Avatar extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Get HTML markup for the post's "avatar" image according conditional
|
||||
* fallback model.
|
||||
*
|
||||
* Accepts an ordered array of named avatar $fallbacks. Also accepts a string
|
||||
* of space-separated classes to add to the default classes.
|
||||
* @param Ai1ec_Event $event The event to get the avatar for
|
||||
* @param array|null $fallback_order Order of fallback in searching for
|
||||
* images, or null to use default
|
||||
* @param string $classes A space-separated list of CSS classes
|
||||
* to apply to the outer <div> element.
|
||||
* @param boolean $wrap_permalink Whether to wrap the element in a link
|
||||
* to the event details page.
|
||||
*
|
||||
* @return string String of HTML if image is found
|
||||
*/
|
||||
public function get_event_avatar(
|
||||
Ai1ec_Event $event,
|
||||
$fallback_order = null,
|
||||
$classes = '',
|
||||
$wrap_permalink = true
|
||||
) {
|
||||
$source = $size = null;
|
||||
$url = $this->get_event_avatar_url(
|
||||
$event,
|
||||
$fallback_order,
|
||||
$source,
|
||||
$size
|
||||
);
|
||||
|
||||
if ( empty( $url ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$url = esc_attr( $url );
|
||||
$classes = esc_attr( $classes );
|
||||
|
||||
// Set the alt tag (helpful for SEO).
|
||||
$alt = $event->get( 'post' )->post_title;
|
||||
$location = $this->_registry->get( 'view.event.location' )->get_short_location( $event );
|
||||
if ( ! empty( $location ) ) {
|
||||
$alt .= ' @ ' . $location;
|
||||
}
|
||||
|
||||
$alt = esc_attr( $alt );
|
||||
$size_attr = $size[0] ? "width=\"$size[0]\" height=\"$size[1]\"" : "";
|
||||
$html = '<img src="' . $url . '" alt="' . $alt . '" ' .
|
||||
$size_attr . ' />';
|
||||
|
||||
if ( $wrap_permalink ) {
|
||||
$permalink = add_query_arg(
|
||||
'instance_id',
|
||||
$event->get( 'instance_id' ),
|
||||
get_permalink( $event->get( 'post_id' ) )
|
||||
);
|
||||
$html = '<a href="' . $permalink . '">' . $html . '</a>';
|
||||
}
|
||||
|
||||
$classes .= ' ai1ec-' . $source;
|
||||
$classes .= ( $size[0] > $size[1] )
|
||||
? ' ai1ec-landscape'
|
||||
: ' ai1ec-portrait';
|
||||
$html = '<div class="ai1ec-event-avatar timely ' . $classes . '">' .
|
||||
$html . '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post's "avatar" image url according conditional fallback model.
|
||||
*
|
||||
* Accepts an ordered array of named methods for $fallback order. Returns
|
||||
* image URL or null if no image found. Also returns matching fallback in the
|
||||
* $source reference.
|
||||
*
|
||||
* @param array|null $fallback_order Order of fallbacks in search for images
|
||||
* @param null $source Fallback that returned matching image,
|
||||
* returned format is string
|
||||
* @param null $size (width, height) array of returned image
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_event_avatar_url(
|
||||
Ai1ec_Event $event,
|
||||
$fallback_order = null,
|
||||
&$source = null,
|
||||
&$size = null
|
||||
) {
|
||||
if ( empty( $fallback_order ) ) {
|
||||
$fallback_order = array(
|
||||
'post_thumbnail',
|
||||
'content_img',
|
||||
'category_avatar',
|
||||
'default_avatar',
|
||||
);
|
||||
}
|
||||
|
||||
$valid_fallbacks = $this->_get_valid_fallbacks();
|
||||
|
||||
foreach ( $fallback_order as $fallback ) {
|
||||
if ( ! isset( $valid_fallbacks[$fallback] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$function = $valid_fallbacks[$fallback];
|
||||
$url = null;
|
||||
if (
|
||||
! is_array( $function ) &&
|
||||
method_exists( $this, $function )
|
||||
) {
|
||||
$url = $this->$function( $event, $size );
|
||||
} else if ( is_callable( $function ) ) {
|
||||
$url = call_user_func_array( $function, array( $event, &$size ) );
|
||||
}
|
||||
if ( null !== $url ) {
|
||||
$source = $fallback;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $url ) ) {
|
||||
return null;
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read post meta for post-thumbnail and return its URL as a string.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
* @param null $size (width, height) array of returned image.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_post_thumbnail_url( Ai1ec_Event $event, &$size = null ) {
|
||||
return $this->_get_post_attachment_url(
|
||||
$event,
|
||||
array(
|
||||
'medium',
|
||||
'large',
|
||||
'full',
|
||||
),
|
||||
$size
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read post meta for post-image and return its URL as a string.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
* @param null $size (width, height) array of returned image.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_post_image_url( Ai1ec_Event $event, &$size = null ) {
|
||||
return $this->_get_post_attachment_url(
|
||||
$event,
|
||||
array(
|
||||
'full',
|
||||
'large',
|
||||
'medium'
|
||||
),
|
||||
$size
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read post meta for featured image and return its URL as a string.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
* @param null $size (width, height) array of returned image.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_featured_image_url( Ai1ec_Event $event, &$size = null ) {
|
||||
$featured_image = get_post_meta( $event->get( 'post_id' ) , '_featured_image', true );
|
||||
if ( empty( $featured_image ) ) {
|
||||
return $this->_get_post_attachment_url(
|
||||
$event,
|
||||
array(
|
||||
'full',
|
||||
'large',
|
||||
'medium'
|
||||
),
|
||||
$size
|
||||
);
|
||||
} else {
|
||||
$priority_order = array( 'large', 'full', 'medium', 'thumbnail' );
|
||||
$url = null;
|
||||
foreach ( $priority_order as $priority ) {
|
||||
foreach ( $featured_image as $values_arr ) {
|
||||
if ( $values_arr[0] === $priority ) {
|
||||
$url = $values_arr[1];
|
||||
$size = array( $values_arr[2], $values_arr[3] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( null !== $url ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the avatar url from the event content
|
||||
*/
|
||||
public function remove_avatar_url( $content ) {
|
||||
return preg_replace( '/<div[^<>]+class=[\'"]?ai1ec-event-avatar[^<>]*[\'"]?[^<>]+>.+<\/div>[.\s]*/'
|
||||
, ''
|
||||
, $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple regex-parse of post_content for matches of <img src="foo" />; if
|
||||
* one is found, return its URL.
|
||||
*
|
||||
* @param Ai1ec_Event $event
|
||||
* @param null $size (width, height) array of returned image
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_content_img_url( Ai1ec_Event $event, &$size = null ) {
|
||||
$matches = $this->get_image_from_content(
|
||||
$event->get( 'post' )->post_content
|
||||
);
|
||||
// Check if we have a result, otherwise a notice is issued.
|
||||
if ( empty( $matches ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = $matches[2];
|
||||
$size = array( 0, 0 );
|
||||
|
||||
// Try to detect width and height.
|
||||
$attrs = $matches[1] . $matches[3];
|
||||
$matches = null;
|
||||
preg_match_all(
|
||||
'/(width|height)=["\']?(\d+)/i',
|
||||
$attrs,
|
||||
$matches,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
// Check if we have a result, otherwise a notice is issued.
|
||||
if ( ! empty( $matches ) ) {
|
||||
foreach ( $matches as $match ) {
|
||||
$size[ $match[1] === 'width' ? 0 : 1 ] = $match[2];
|
||||
}
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an image tag from an html string
|
||||
*
|
||||
* @param string $content
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_image_from_content( $content ) {
|
||||
preg_match(
|
||||
'/<img([^>]+)src=["\']?([^"\'\ >]+)([^>]*)>/i',
|
||||
$content,
|
||||
$matches
|
||||
);
|
||||
return $matches;
|
||||
}
|
||||
/**
|
||||
* Returns default avatar image (normally when no other ones are available).
|
||||
*
|
||||
* @param null $size (width, height) array of returned image
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_default_avatar_url( &$size = null ) {
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$file = $loader->get_file( 'default-event-avatar.png', array(), false );
|
||||
$size = array( 256, 256 );
|
||||
return $file->get_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns avatar image for event's deepest category, if any.
|
||||
*
|
||||
* @param Ai1ec_Event $event Avatar requester.
|
||||
* @param void $size Unused argument.
|
||||
*
|
||||
* @return string|null Avatar's HTML or null if none.
|
||||
*/
|
||||
public function get_category_avatar_url( Ai1ec_Event $event, &$size = null ) {
|
||||
$db = $this->_registry->get( 'dbi.dbi' );
|
||||
|
||||
$terms = $this->_registry->get( 'model.taxonomy' )->get_post_categories(
|
||||
$event->get( 'post_id' )
|
||||
);
|
||||
if ( empty( $terms ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$terms_by_id = array();
|
||||
// Key $terms by term_id rather than arbitrary int.
|
||||
foreach ( $terms as $term ) {
|
||||
$terms_by_id[$term->term_id] = $term;
|
||||
}
|
||||
|
||||
// Array to store term depths, sorted later.
|
||||
$term_depths = array();
|
||||
foreach ( $terms_by_id as $term ) {
|
||||
$depth = 0;
|
||||
$ancestor = $term;
|
||||
while ( ! empty( $ancestor->parent ) ) {
|
||||
$depth++;
|
||||
if ( ! isset( $terms_by_id[$ancestor->parent] ) ) {
|
||||
break;
|
||||
}
|
||||
$ancestor = $terms_by_id[$ancestor->parent];
|
||||
}
|
||||
// Store negative depths for asort() to order from deepest to shallowest.
|
||||
$term_depths[$term->term_id] = -$depth;
|
||||
}
|
||||
// Order term IDs by depth.
|
||||
asort( $term_depths );
|
||||
|
||||
$url = '';
|
||||
$model = $this->_registry->get( 'model.taxonomy' );
|
||||
// Starting at deepest depth, find the first category that has an avatar.
|
||||
foreach ( $term_depths as $term_id => $depth ) {
|
||||
$term_image = $model->get_category_image( $term_id );
|
||||
if ( $term_image ) {
|
||||
$url = $term_image;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return empty( $url ) ? null : $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read post meta for post-attachment and return its URL as a string.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
* @param array $ordered_img_sizes Image sizes order.
|
||||
* @param null $size (width, height) array of returned
|
||||
* image.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function _get_post_attachment_url(
|
||||
Ai1ec_Event $event,
|
||||
array $ordered_img_sizes,
|
||||
&$size = null
|
||||
) {
|
||||
// Since WP does will return null if the wrong size is targeted,
|
||||
// we iterate over an array of sizes, breaking if a URL is found.
|
||||
foreach ( $ordered_img_sizes as $size ) {
|
||||
$attributes = wp_get_attachment_image_src(
|
||||
get_post_thumbnail_id( $event->get( 'post_id' ) ), $size
|
||||
);
|
||||
if ( $attributes ) {
|
||||
$url = array_shift( $attributes );
|
||||
$size = $attributes;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return empty( $url ) ? null : $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of valid fallbacks.
|
||||
*
|
||||
* @return array List of valid fallbacks.
|
||||
*/
|
||||
protected function _get_valid_fallbacks() {
|
||||
static $fallbacks;
|
||||
if ( null === $fallbacks ) {
|
||||
$fallbacks = apply_filters(
|
||||
'ai1ec_avatar_valid_callbacks',
|
||||
array(
|
||||
'post_image' => 'get_post_image_url',
|
||||
'post_thumbnail' => 'get_post_thumbnail_url',
|
||||
'content_img' => 'get_content_img_url',
|
||||
'category_avatar' => 'get_category_avatar_url',
|
||||
'default_avatar' => 'get_default_avatar_url',
|
||||
'featured_image' => 'get_featured_image_url'
|
||||
)
|
||||
);
|
||||
}
|
||||
return $fallbacks;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event colors.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Color extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Faded version of event category color
|
||||
*/
|
||||
protected function _get_color( Ai1ec_Event $event, $type ) {
|
||||
static $categories_cache = array(
|
||||
'rgba' => array(),
|
||||
'faded' => array(),
|
||||
);
|
||||
$methods = array(
|
||||
'rgba' => 'get_event_category_rgba_color',
|
||||
'faded' => 'get_event_category_faded_color',
|
||||
);
|
||||
$categories = $this->_registry->get( 'model.taxonomy' )
|
||||
->get_post_categories( $event->get( 'post_id' ) );
|
||||
if ( ! empty( $categories ) ) {
|
||||
if (
|
||||
! isset( $categories_cache[$type][$categories[0]->term_id] )
|
||||
) {
|
||||
$method = $methods[$type];
|
||||
$categories_cache[$type][$categories[0]->term_id] = $this
|
||||
->$method( $categories[0]->term_id );
|
||||
}
|
||||
return $categories_cache[$type][$categories[0]->term_id];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
public function get_faded_color( Ai1ec_Event $event ) {
|
||||
return $this->_get_color( $event, 'faded' );
|
||||
}
|
||||
|
||||
/**
|
||||
* rgba() format of faded category color.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_rgba_color( Ai1ec_Event $event ) {
|
||||
return $this->_get_color( $event, 'rgba' );
|
||||
}
|
||||
/**
|
||||
* Returns a faded version of the event's category color in hex format.
|
||||
*
|
||||
* @param int $term_id The Event Category's term ID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_event_category_faded_color( $term_id ) {
|
||||
$taxonomy = $this->_registry->get( 'model.taxonomy' );
|
||||
$color = $taxonomy->get_category_color( $term_id );
|
||||
if( ! is_null( $color ) && ! empty( $color ) ) {
|
||||
|
||||
$color1 = substr( $color, 1 );
|
||||
$color2 = 'ffffff';
|
||||
|
||||
$c1_p1 = hexdec( substr( $color1, 0, 2 ) );
|
||||
$c1_p2 = hexdec( substr( $color1, 2, 2 ) );
|
||||
$c1_p3 = hexdec( substr( $color1, 4, 2 ) );
|
||||
|
||||
$c2_p1 = hexdec( substr( $color2, 0, 2 ) );
|
||||
$c2_p2 = hexdec( substr( $color2, 2, 2 ) );
|
||||
$c2_p3 = hexdec( substr( $color2, 4, 2 ) );
|
||||
|
||||
$m_p1 = dechex( round( $c1_p1 * 0.5 + $c2_p1 * 0.5 ) );
|
||||
$m_p2 = dechex( round( $c1_p2 * 0.5 + $c2_p2 * 0.5 ) );
|
||||
$m_p3 = dechex( round( $c1_p3 * 0.5 + $c2_p3 * 0.5 ) );
|
||||
|
||||
return '#' . $m_p1 . $m_p2 . $m_p3;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rgba() format of the event's category color, with '%s' in place
|
||||
* of the opacity (to be substituted by sprintf).
|
||||
*
|
||||
* @param int $term_id The Event Category's term ID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_event_category_rgba_color( $term_id ) {
|
||||
$taxonomy = $this->_registry->get( 'model.taxonomy' );
|
||||
$color = $taxonomy->get_category_color( $term_id );
|
||||
if ( ! is_null( $color ) && ! empty( $color ) ) {
|
||||
$p1 = hexdec( substr( $color, 1, 2 ) );
|
||||
$p2 = hexdec( substr( $color, 3, 2 ) );
|
||||
$p3 = hexdec( substr( $color, 5, 2 ) );
|
||||
return "rgba($p1, $p2, $p3, %s)";
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class process event content.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Content extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Render event excerpt header.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event to render excerpt for.
|
||||
*
|
||||
* @return void Content is not returned, just rendered.
|
||||
*/
|
||||
public function excerpt_view( Ai1ec_Event $event ) {
|
||||
$location = $this->_registry->get( 'view.event.location' );
|
||||
$location = esc_html(
|
||||
str_replace(
|
||||
"\n",
|
||||
', ',
|
||||
rtrim( $location->get_location( $event ) )
|
||||
)
|
||||
);
|
||||
$args = array(
|
||||
'event' => $event,
|
||||
'location' => $location,
|
||||
'text_when' => __( 'When:', AI1EC_PLUGIN_NAME ),
|
||||
'text_where' => __( 'Where:', AI1EC_PLUGIN_NAME ),
|
||||
);
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
echo $loader->get_file(
|
||||
'event-excerpt.twig',
|
||||
$args,
|
||||
true
|
||||
)->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format events excerpt view.
|
||||
*
|
||||
* @param string $text Content to excerpt.
|
||||
*
|
||||
* @return string Formatted event excerpt.
|
||||
*/
|
||||
public function event_excerpt( $text ) {
|
||||
if ( ! $this->_registry->get( 'acl.aco' )->is_our_post_type() ) {
|
||||
return $text;
|
||||
}
|
||||
$event = $this->_registry->get( 'model.event', get_the_ID() );
|
||||
$post = $this->_registry->get( 'view.event.post' );
|
||||
$ob = $this->_registry->get( 'compatibility.ob' );
|
||||
$ob->start();
|
||||
$this->excerpt_view( $event );
|
||||
// Re-apply any filters to the post content that normally would have
|
||||
// been applied if it weren't for our interference (below).
|
||||
echo shortcode_unautop( wpautop( $post->trim_excerpt( $event ) ) );
|
||||
return $ob->get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid re-adding `wpautop` for Ai1EC instances.
|
||||
*
|
||||
* @param string $content Processed content.
|
||||
*
|
||||
* @return string Paragraphs enclosed text.
|
||||
*/
|
||||
public function event_excerpt_noautop( $content ) {
|
||||
if ( ! $this->_registry->get( 'acl.aco' )->is_our_post_type() ) {
|
||||
return wpautop( $content );
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function get_post_excerpt( Ai1ec_Event $event ) {
|
||||
$content = strip_tags(
|
||||
strip_shortcodes(
|
||||
preg_replace(
|
||||
'#<\s*script[^>]*>.+<\s*/\s*script\s*>#x',
|
||||
'',
|
||||
apply_filters(
|
||||
'ai1ec_the_content',
|
||||
apply_filters(
|
||||
'the_content',
|
||||
$event->get( 'post' )->post_content
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$content = preg_replace( '/\s+/', ' ', $content );
|
||||
$words = explode( ' ', $content );
|
||||
if ( count( $words ) > 25 ) {
|
||||
return implode(
|
||||
' ',
|
||||
array_slice( $words, 0, 25 )
|
||||
) . ' [...]';
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the html for the "Calendar" button for this event.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_back_to_calendar_button_html() {
|
||||
$class = '';
|
||||
$data_type = '';
|
||||
$href = '';
|
||||
if ( isset( $_COOKIE['ai1ec_calendar_url'] ) ) {
|
||||
$href = json_decode(
|
||||
stripslashes( $_COOKIE['ai1ec_calendar_url'] )
|
||||
);
|
||||
setcookie( 'ai1ec_calendar_url', '', time() - 3600 );
|
||||
} else {
|
||||
$href = $this->_registry->get( 'html.element.href', array() );
|
||||
$href = $href->generate_href();
|
||||
}
|
||||
$text = esc_attr( Ai1ec_I18n::__( 'Calendar' ) );
|
||||
$tooltip = esc_attr( Ai1ec_I18n::__( 'View all events' ) );
|
||||
$html = <<<HTML
|
||||
<a class="ai1ec-calendar-link ai1ec-btn ai1ec-btn-default ai1ec-btn-sm
|
||||
ai1ec-tooltip-trigger $class"
|
||||
href="$href"
|
||||
$data_type
|
||||
data-placement="left"
|
||||
title="$tooltip">
|
||||
<i class="ai1ec-fa ai1ec-fa-calendar ai1ec-fa-fw"></i>
|
||||
<span class="ai1ec-hidden-xs">$text</span>
|
||||
</a>
|
||||
HTML;
|
||||
return apply_filters( 'ai1ec_get_back_to_calendar_html', $html, $href );
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple regex-parse of post_content for matches of <img src="foo" />; if
|
||||
* one is found, return its URL.
|
||||
*
|
||||
* @param null $size (width, height) array of returned image
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_content_img_url( Ai1ec_Event $event, &$size = null ) {
|
||||
preg_match(
|
||||
'/<img([^>]+)src=["\']?([^"\'\ >]+)([^>]*)>/i',
|
||||
$event->get( 'post' )->post_content,
|
||||
$matches
|
||||
);
|
||||
|
||||
// Check if we have a result, otherwise a notice is issued.
|
||||
if ( empty( $matches ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Mark found image.
|
||||
$event->get( 'post' )->post_content = str_replace(
|
||||
'<img' . $matches[1],
|
||||
'<img' . $matches[1] . ' data-ai1ec-hidden ',
|
||||
$event->get( 'post' )->post_content
|
||||
);
|
||||
|
||||
$url = $matches[2];
|
||||
$size = array( 0, 0 );
|
||||
|
||||
// Try to detect width and height.
|
||||
$attrs = $matches[1] . $matches[3];
|
||||
$matches = null;
|
||||
preg_match_all(
|
||||
'/(width|height)=["\']?(\d+)/i',
|
||||
$attrs,
|
||||
$matches,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
// Check if we have a result, otherwise a notice is issued.
|
||||
if ( ! empty( $matches ) ) {
|
||||
foreach ( $matches as $match ) {
|
||||
$size[ $match[1] === 'width' ? 0 : 1 ] = $match[2];
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event location.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Location extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Return location details in brief format, separated by | characters.
|
||||
*
|
||||
* @return $string Short location string
|
||||
*/
|
||||
public function get_short_location( Ai1ec_Event $event ) {
|
||||
$location_items = array();
|
||||
foreach ( array( 'venue', 'city', 'province', 'country' ) as $field ) {
|
||||
if ( $event->get( $field ) !== '' ) {
|
||||
$location_items[] = $event->get( $field );
|
||||
}
|
||||
}
|
||||
return implode( ' | ', $location_items );
|
||||
}
|
||||
|
||||
/*
|
||||
* Return any available location details separated by newlines
|
||||
*/
|
||||
public function get_location( Ai1ec_Event $event ) {
|
||||
$location = '';
|
||||
$venue = $event->get( 'venue' );
|
||||
if ( $venue ) {
|
||||
$location .= $venue . "\n";
|
||||
}
|
||||
$address = $event->get( 'address' );
|
||||
if ( $address ) {
|
||||
$bits = explode( ',', $address );
|
||||
$bits = array_map( 'trim', $bits );
|
||||
|
||||
// If more than three comma-separated values, treat first value as
|
||||
// the street address, last value as the country, and everything
|
||||
// in the middle as the city, state, etc.
|
||||
if ( count( $bits ) >= 3 ) {
|
||||
// Append the street address
|
||||
$street_address = array_shift( $bits ) . "\n";
|
||||
if ( $street_address ) {
|
||||
$location .= $street_address;
|
||||
}
|
||||
// Save the country for the last line
|
||||
$country = array_pop( $bits );
|
||||
// Append the middle bit(s) (filtering out any zero-length strings)
|
||||
$bits = array_filter( $bits, 'strval' );
|
||||
if ( $bits ) {
|
||||
$location .= join( ', ', $bits ) . "\n";
|
||||
}
|
||||
if ( $country ) {
|
||||
$location .= $country . "\n";
|
||||
}
|
||||
} else {
|
||||
// There are two or less comma-separated values, so just append
|
||||
// them each on their own line (filtering out any zero-length strings)
|
||||
$bits = array_filter( $bits, 'strval' );
|
||||
$location .= join( "\n", $bits );
|
||||
}
|
||||
}
|
||||
return $location;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_map_view function
|
||||
*
|
||||
* Returns HTML markup displaying a Google map of the given event, if the event
|
||||
* has show_map set to true. Returns a zero-length string otherwise.
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
function get_map_view( Ai1ec_Event $event ) {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
if( ! $event->get( 'show_map' ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$location = $this->get_latlng( $event );
|
||||
if ( ! $location ) {
|
||||
$location = $event->get( 'address' );
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'address' => $location,
|
||||
'gmap_url_link' => $this->get_gmap_url( $event, false ),
|
||||
'hide_maps_until_clicked' => $settings->get( 'hide_maps_until_clicked' ),
|
||||
'text_view_map' => __( 'Click to view map', AI1EC_PLUGIN_NAME ),
|
||||
'text_full_map' => __( 'View Full-Size Map', AI1EC_PLUGIN_NAME ),
|
||||
);
|
||||
return $loader->get_file( 'event-map.twig', $args, false )->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latitude/longitude coordinates as a textual string
|
||||
* parsable by the Geocoder API.
|
||||
*
|
||||
* @param Ai1ec_Event &$event The event to return data from
|
||||
*
|
||||
* @return string The latitude & longitude string, or null
|
||||
*/
|
||||
public function get_latlng( Ai1ec_Event $event ) {
|
||||
// If the coordinates are set, use those, otherwise use the address.
|
||||
$location = NULL;
|
||||
// If the coordinates are set by hand use them.
|
||||
if ( $event->get( 'show_coordinates' ) ) {
|
||||
$longitude = floatval( $event->get( 'longitude' ) );
|
||||
$latitude = floatval( $event->get( 'latitude' ) );
|
||||
$location = $latitude . ',' . $longitude;
|
||||
}
|
||||
return $location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL to the Google Map for the given event object.
|
||||
*
|
||||
* @param Ai1ec_Event $event The event object to display a map for
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_gmap_url( Ai1ec_Event $event ) {
|
||||
$lang = $this->_registry->get( 'p28n.wpml' )->get_language();
|
||||
$location = $this->get_latlng( $event );
|
||||
if ( ! $location ) {
|
||||
$location = $event->get( 'address' );
|
||||
}
|
||||
return 'https://www.google.com/maps?f=q&hl=' . urlencode( $lang ) .
|
||||
'&source=embed&q=' . urlencode( $location );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event colors.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Post extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Add event-specific messages to be used when one is modified in dashboard.
|
||||
*
|
||||
* @wp_hook post_updated_messages
|
||||
*
|
||||
* @param array $messages List of messages.
|
||||
*
|
||||
* @return array Modified list of messages.
|
||||
*/
|
||||
public function post_updated_messages( $messages ) {
|
||||
global $post, $post_ID;
|
||||
|
||||
$messages[AI1EC_POST_TYPE] = array(
|
||||
0 => '', // Unused. Messages start at index 1.
|
||||
1 => sprintf(
|
||||
Ai1ec_I18n::__( 'Event updated. <a href="%s">View event</a>' ),
|
||||
esc_url( get_permalink( $post_ID ) )
|
||||
),
|
||||
2 => Ai1ec_I18n::__( 'Custom field updated.' ),
|
||||
3 => Ai1ec_I18n::__( 'Custom field deleted.' ),
|
||||
4 => Ai1ec_I18n::__( 'Event updated.' ),
|
||||
/* translators: %s: date and time of the revision */
|
||||
5 => isset( $_GET['revision'] )
|
||||
? sprintf(
|
||||
Ai1ec_I18n::__( 'Event restored to revision from %s' ),
|
||||
wp_post_revision_title( (int) $_GET['revision'], false )
|
||||
)
|
||||
: false,
|
||||
6 => sprintf(
|
||||
Ai1ec_I18n::__( 'Event published. <a href="%s">View event</a>' ),
|
||||
esc_url( get_permalink($post_ID) )
|
||||
),
|
||||
7 => Ai1ec_I18n::__( 'Event saved.' ),
|
||||
8 => sprintf(
|
||||
Ai1ec_I18n::__( 'Event submitted. <a target="_blank" href="%s">Preview event</a>' ),
|
||||
esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) )
|
||||
),
|
||||
9 => sprintf(
|
||||
Ai1ec_I18n::__( 'Event scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview event</a>' ),
|
||||
// translators: Publish box date format, see http://php.net/date
|
||||
$this->_registry->get( 'date.time', $post->post_date )->format_i18n( Ai1ec_I18n::__( 'M j, Y @ G:i' ) ),
|
||||
esc_url( get_permalink($post_ID) )
|
||||
),
|
||||
10 => sprintf(
|
||||
Ai1ec_I18n::__( 'Event draft updated. <a target="_blank" href="%s">Preview event</a>' ),
|
||||
esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) )
|
||||
),
|
||||
);
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an excerpt from the given content string.
|
||||
*
|
||||
* Adapted from WordPress's `wp_trim_excerpt' function that is not useful
|
||||
* for applying to custom content.
|
||||
*
|
||||
* @param string $text The content to trim.
|
||||
*
|
||||
* @return string The excerpt.
|
||||
*/
|
||||
public function trim_excerpt( Ai1ec_Event $event, $length = 35, $more = '[...]' ) {
|
||||
global $post;
|
||||
$original_post = $post;
|
||||
$post = $event->get( 'post' );
|
||||
$raw_excerpt = $event->get( 'post' )->post_content;
|
||||
if ( ! isset( $raw_excerpt{0} ) ) {
|
||||
$raw_excerpt = ' ';
|
||||
}
|
||||
|
||||
$text = preg_replace(
|
||||
'#<\s*script[^>]*>.+<\s*/\s*script\s*>#x',
|
||||
'',
|
||||
apply_filters(
|
||||
'the_excerpt',
|
||||
$raw_excerpt
|
||||
)
|
||||
);
|
||||
$text = strip_shortcodes( $text );
|
||||
$text = str_replace( ']]>', ']]>', $text );
|
||||
$text = strip_tags( $text );
|
||||
|
||||
$excerpt_length = apply_filters( 'excerpt_length', $length );
|
||||
$excerpt_more = apply_filters( 'excerpt_more', $more );
|
||||
$words = preg_split(
|
||||
'/\s+/',
|
||||
$text,
|
||||
$excerpt_length + 1,
|
||||
PREG_SPLIT_NO_EMPTY
|
||||
);
|
||||
if ( count( $words ) > $excerpt_length ) {
|
||||
array_pop( $words );
|
||||
$text = implode( ' ', $words );
|
||||
$text = $text . $excerpt_more;
|
||||
} else {
|
||||
$text = implode( ' ', $words );
|
||||
}
|
||||
$post = $original_post;
|
||||
return apply_filters( 'wp_trim_excerpt', $text, $raw_excerpt );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,283 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the single event page.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Single extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Renders the html of the page and returns it.
|
||||
*
|
||||
* @param Ai1ec_Event $event
|
||||
*
|
||||
* @return string the html of the page
|
||||
*/
|
||||
public function get_content( Ai1ec_Event $event ) {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$rrule = $this->_registry->get( 'recurrence.rule' );
|
||||
$taxonomy = $this->_registry->get( 'view.event.taxonomy' );
|
||||
$location = $this->_registry->get( 'view.event.location' );
|
||||
$ticket = $this->_registry->get( 'view.event.ticket' );
|
||||
$content = $this->_registry->get( 'view.event.content' );
|
||||
$time = $this->_registry->get( 'view.event.time' );
|
||||
|
||||
$subscribe_url = AI1EC_EXPORT_URL . '&ai1ec_post_ids=' .
|
||||
$event->get( 'post_id' );
|
||||
|
||||
$event->set_runtime(
|
||||
'tickets_url_label',
|
||||
$ticket->get_tickets_url_label( $event, false )
|
||||
);
|
||||
$event->set_runtime(
|
||||
'content_img_url',
|
||||
$content->get_content_img_url( $event )
|
||||
);
|
||||
|
||||
$extra_buttons = apply_filters(
|
||||
'ai1ec_rendering_single_event_actions',
|
||||
'',
|
||||
$event
|
||||
);
|
||||
|
||||
$venues_html = apply_filters(
|
||||
'ai1ec_rendering_single_event_venues',
|
||||
nl2br( $location->get_location( $event ) ),
|
||||
$event
|
||||
);
|
||||
$default_tz = $this->_registry->get( 'date.timezone' )->get_default_timezone();
|
||||
$timezone_info = array(
|
||||
'show_timezone' => $this->_registry->get( 'model.settings' )->get( 'always_use_calendar_timezone' ),
|
||||
'using_calendar_tz' => $this->_registry->get( 'model.settings' )->get( 'always_use_calendar_timezone' ),
|
||||
'event_timezone' => str_replace( '_', ' ', $event->get( 'timezone_name' ) ) . ' ' . __( 'Timezone', AI1EC_PLUGIN_NAME ),
|
||||
'calendar_timezone' => str_replace( '_', ' ', $default_tz ) . ' ' . __( 'Timezone', AI1EC_PLUGIN_NAME ),
|
||||
);
|
||||
|
||||
$banner_image_meta = get_post_meta( $event->get( 'post_id' ), 'ai1ec_banner_image' );
|
||||
$banner_image = $banner_image_meta ? $banner_image_meta[0] : '';
|
||||
|
||||
// objects are passed by reference so an action is ok
|
||||
do_action( 'ai1ec_single_event_page_before_render', $event );
|
||||
|
||||
$filter_groups_html = apply_filters( 'ai1ec_get_filter_groups_html', $event );
|
||||
|
||||
$args = array(
|
||||
'event' => $event,
|
||||
'recurrence' => $rrule->rrule_to_text( $event->get( 'recurrence_rules' ) ),
|
||||
'exclude' => $time->get_exclude_html( $event, $rrule ),
|
||||
'categories' => $taxonomy->get_categories_html( $event ),
|
||||
'tags' => $taxonomy->get_tags_html( $event ),
|
||||
'location' => html_entity_decode( $venues_html ),
|
||||
'filter_groups' => $filter_groups_html,
|
||||
'map' => $location->get_map_view( $event ),
|
||||
'contact' => $ticket->get_contact_html( $event ),
|
||||
'back_to_calendar' => $content->get_back_to_calendar_button_html(),
|
||||
'subscribe_url' => $subscribe_url,
|
||||
'subscribe_url_no_html' => $subscribe_url . '&no_html=true',
|
||||
'edit_instance_url' => null,
|
||||
'edit_instance_text' => null,
|
||||
'google_url' => 'https://www.google.com/calendar/render?cid=' . urlencode( $subscribe_url ),
|
||||
'show_subscribe_buttons' => ! $settings->get( 'turn_off_subscription_buttons' ),
|
||||
'hide_featured_image' => $settings->get( 'hide_featured_image' ),
|
||||
'extra_buttons' => $extra_buttons,
|
||||
'show_get_calendar' => ! $settings->get( 'disable_get_calendar_button' ),
|
||||
'text_add_calendar' => __( 'Add to Calendar', AI1EC_PLUGIN_NAME ),
|
||||
'subscribe_buttons_text' => $this->_registry
|
||||
->get( 'view.calendar.subscribe-button' )
|
||||
->get_labels(),
|
||||
'text_get_calendar' => Ai1ec_I18n::__( 'Get a Timely Calendar' ),
|
||||
'text_when' => __( 'When:', AI1EC_PLUGIN_NAME ),
|
||||
'text_where' => __( 'Where:', AI1EC_PLUGIN_NAME ),
|
||||
'text_cost' => __( 'Cost:', AI1EC_PLUGIN_NAME ),
|
||||
'text_contact' => __( 'Contact:', AI1EC_PLUGIN_NAME ),
|
||||
'text_tickets' => __( 'Tickets:', AI1EC_PLUGIN_NAME ),
|
||||
'text_free' => __( 'Free', AI1EC_PLUGIN_NAME ),
|
||||
'text_categories' => __( 'Categories', AI1EC_PLUGIN_NAME ),
|
||||
'text_tags' => __( 'Tags', AI1EC_PLUGIN_NAME ),
|
||||
'buy_tickets_text' => __( 'Buy Tickets', AI1EC_PLUGIN_NAME ),
|
||||
'timezone_info' => $timezone_info,
|
||||
'banner_image' => $banner_image,
|
||||
'content_img_url' => $event->get_runtime( 'content_img_url' ),
|
||||
'post_id' => $event->get( 'post_id' ),
|
||||
'ticket_url' => $event->get( 'ticket_url' ),
|
||||
'tickets_url_label' => $event->get_runtime( 'tickets_url_label' ),
|
||||
'start' => $event->get( 'start' ),
|
||||
'end' => $event->get( 'end' ),
|
||||
'cost' => $event->get( 'cost' ),
|
||||
'instance_id' => $event->get( 'instance_id' ),
|
||||
);
|
||||
|
||||
if (
|
||||
! empty( $args['recurrence'] ) &&
|
||||
$event->get( 'instance_id' ) &&
|
||||
current_user_can( 'edit_ai1ec_events' )
|
||||
) {
|
||||
$args['edit_instance_url'] = ai1ec_admin_url(
|
||||
'post.php?post=' . $event->get( 'post_id' ) .
|
||||
'&action=edit&instance=' . $event->get( 'instance_id' )
|
||||
);
|
||||
$args['edit_instance_text'] = sprintf(
|
||||
Ai1ec_I18n::__( 'Edit this occurrence (%s)' ),
|
||||
$event->get( 'start' )->format_i18n( 'M j' )
|
||||
);
|
||||
}
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
if ( false === ai1ec_is_blank( $event->get( 'ical_feed_url' ) ) ) {
|
||||
$ticket_url = $api->get_api_event_buy_ticket_url( $event->get( 'post_id' ) );
|
||||
if ( ! empty ( $ticket_url ) ) {
|
||||
$args['ticket_url'] = $ticket_url;
|
||||
}
|
||||
} else {
|
||||
$api_event_id = $api->get_api_event_id( $event->get( 'post_id' ) );
|
||||
if ( $api_event_id ) {
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
$ticket_types = json_decode( $api->get_ticket_types( $event->get( 'post_id' ), false ) );
|
||||
$args['has_tickets'] = true;
|
||||
$args['API_URL'] = AI1EC_API_URL;
|
||||
$args['tickets_block'] = $loader->get_file(
|
||||
'tickets.twig',
|
||||
array(
|
||||
'tickets_checkout_url' => $api->get_api_event_buy_ticket_url( $event->get( 'post_id' ) ),
|
||||
'tickets' => $ticket_types->data,
|
||||
'text_tickets' => $args['text_tickets'],
|
||||
'buy_tickets_text' => $args['buy_tickets_text'],
|
||||
'api_event_id' => $api_event_id
|
||||
), false
|
||||
)->get_content();
|
||||
}
|
||||
}
|
||||
|
||||
return $loader->get_file( 'event-single.twig', $args, false )
|
||||
->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add meta OG tags to the event details page
|
||||
*/
|
||||
public function add_meta_tags() {
|
||||
// Add tags only on Event Details page
|
||||
$aco = $this->_registry->get( 'acl.aco' );
|
||||
if ( ! $aco->is_our_post_type() ) return;
|
||||
|
||||
// Get Event and process description
|
||||
$instance_id = ( isset( $_GET[ 'instance_id' ] ) ) ? $_GET[ 'instance_id' ] : null;
|
||||
|
||||
if ( !is_null( $instance_id ) ) {
|
||||
$instance_id = preg_replace( '/\D/', '', $instance_id );
|
||||
}
|
||||
$event = $this->_registry->get( 'model.event', get_the_ID(), $instance_id );
|
||||
$avatar = $this->_registry->get( 'view.event.avatar' );
|
||||
$content = $this->_registry->get( 'view.event.content' );
|
||||
$desc = $event->get( 'post' )->post_content;
|
||||
$desc = apply_filters( 'the_excerpt', $desc );
|
||||
$desc = strip_shortcodes( $desc );
|
||||
$desc = str_replace( ']]>', ']]>', $desc );
|
||||
$desc = strip_tags( $desc );
|
||||
$desc = preg_replace( '/\n+/', ' ', $desc);
|
||||
$desc = substr( $desc, 0, 300 );
|
||||
// Get featured image
|
||||
$image = $avatar->get_post_thumbnail_url( $event );
|
||||
if ( ! $image ) {
|
||||
$image = $content->get_content_img_url( $event );
|
||||
}
|
||||
|
||||
$og = array(
|
||||
'url' => home_url( esc_url( add_query_arg( null, null ) ) ),
|
||||
'title' => htmlspecialchars(
|
||||
$event->get( 'post' )->post_title .
|
||||
' (' . substr( $event->get( 'start' ) , 0, 10 ) . ')'
|
||||
),
|
||||
'type' => 'article',
|
||||
'description' => htmlspecialchars( $desc ),
|
||||
'image' => $image,
|
||||
);
|
||||
foreach ( $og as $key => $val ) {
|
||||
echo "<meta property=\"og:$key\" content=\"$val\" />\n";
|
||||
}
|
||||
// Twitter meta tags
|
||||
$twitter = array(
|
||||
'card' => 'summary',
|
||||
'title' => htmlspecialchars(
|
||||
$event->get( 'post' )->post_title .
|
||||
' (' . substr( $event->get( 'start' ) , 0, 10 ) . ')'
|
||||
),
|
||||
'description' => htmlspecialchars( $desc ),
|
||||
'image' => $image,
|
||||
);
|
||||
foreach ( $twitter as $key => $val ) {
|
||||
if ( empty( $val ) && 'image' !== $key ) {
|
||||
$val = Ai1ec_I18n::__( 'No data' );
|
||||
}
|
||||
echo "<meta name=\"twitter:$key\" content=\"$val\" />\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ai1ec_Event $event
|
||||
*
|
||||
* @return The html of the footer
|
||||
*/
|
||||
public function get_footer( Ai1ec_Event $event ) {
|
||||
|
||||
$text_calendar_feed = null;
|
||||
|
||||
$feed_url = trim( strtolower( $event->get( 'ical_feed_url' ) ) );
|
||||
|
||||
if ( strpos( $feed_url, 'http' ) === 0 ) {
|
||||
$text_calendar_feed = Ai1ec_I18n::__(
|
||||
'This post was replicated from another site\'s <a href="%s" title="iCalendar feed"><i class="ai1ec-fa ai1ec-fa-calendar"></i> calendar feed</a>.'
|
||||
);
|
||||
} else {
|
||||
$text_calendar_feed = Ai1ec_I18n::__(
|
||||
'This post was imported from a CSV/ICS file.'
|
||||
);
|
||||
}
|
||||
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$text_calendar_feed = sprintf(
|
||||
$text_calendar_feed,
|
||||
esc_attr( str_replace( 'http://', 'webcal://', $event->get( 'ical_feed_url' ) ) )
|
||||
);
|
||||
$args = array(
|
||||
'event' => $event,
|
||||
'text_calendar_feed' => $text_calendar_feed,
|
||||
'text_view_post' => Ai1ec_I18n::__( 'View original' ),
|
||||
);
|
||||
return $loader->get_file( 'event-single-footer.twig', $args, false )
|
||||
->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the full article for the event – title, content, and footer.
|
||||
*
|
||||
* @param Ai1ec_Event $event
|
||||
* @param string $footer Footer HTML to append to event
|
||||
*/
|
||||
public function get_full_article( Ai1ec_Event $event, $footer = '' ) {
|
||||
$title = apply_filters(
|
||||
'the_title',
|
||||
$event->get( 'post' )->post_title,
|
||||
$event->get( 'post_id' )
|
||||
);
|
||||
$event_details = $this->get_content( $event );
|
||||
$content = wpautop(
|
||||
apply_filters(
|
||||
'ai1ec_the_content',
|
||||
apply_filters(
|
||||
'the_content',
|
||||
$event->get( 'post' )->post_content
|
||||
)
|
||||
)
|
||||
);
|
||||
$args = compact( 'title', 'event_details', 'content', 'footer' );
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
return $loader->get_file( 'event-single-full.twig', $args, false )
|
||||
->get_content();
|
||||
}
|
||||
}
|
||||
@@ -1,398 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event taxonomy.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Taxonomy extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Taxonomy Taxonomy abstraction layer.
|
||||
*/
|
||||
protected $_taxonomy_model = null;
|
||||
|
||||
/**
|
||||
* @var array Caches the color evaluated for each event.
|
||||
*/
|
||||
protected $_event_color_map = array();
|
||||
|
||||
/**
|
||||
* @var array Caches the color squares HTML evaluated for each event.
|
||||
*/
|
||||
protected $_event_color_squares_map = array();
|
||||
|
||||
/**
|
||||
* Returns style attribute for events rendered in Month, Week, or Day view.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
*
|
||||
* @return string Color style attribute.
|
||||
*/
|
||||
public function get_color_style( Ai1ec_Event $event ) {
|
||||
$color = $this->get_color_for_event( $event );
|
||||
|
||||
// Convert to style attribute.
|
||||
if ( $color ) {
|
||||
$color = $event->is_allday() || $event->is_multiday()
|
||||
? 'background-color: ' . $color . ';'
|
||||
: 'color: ' . $color . ' !important;';
|
||||
} else {
|
||||
$color = '';
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML of category color swatches for this event.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
*
|
||||
* @return string HTML of the event's category color swatches.
|
||||
*/
|
||||
public function get_category_colors( Ai1ec_Event $event ) {
|
||||
$post_id = $event->get( 'post_id' );
|
||||
|
||||
if ( ! isset( $this->_event_color_squares_map[$post_id] ) ) {
|
||||
$squares = '';
|
||||
$categories = $this->_taxonomy_model->get_post_categories( $post_id );
|
||||
|
||||
if ( false !== $categories ) {
|
||||
$squares = $this->get_event_category_colors( $categories );
|
||||
}
|
||||
|
||||
// Allow add-ons to modify/add to category color swatch HTML.
|
||||
$squares = apply_filters(
|
||||
'ai1ec_event_color_squares',
|
||||
$squares,
|
||||
$event
|
||||
);
|
||||
|
||||
$this->_event_color_squares_map[$post_id] = $squares;
|
||||
}
|
||||
|
||||
return $this->_event_color_squares_map[$post_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTML markup for the category color square.
|
||||
*
|
||||
* @param int $term_id The term ID of event category
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_category_color_square( $term_id ) {
|
||||
$color = $this->_taxonomy_model->get_category_color( $term_id );
|
||||
$event_taxonomy = $this->_registry->get( 'model.event.taxonomy' );
|
||||
if ( null !== $color ) {
|
||||
$taxonomy = $event_taxonomy->get_taxonomy_for_term_id( $term_id );
|
||||
$cat = get_term( $term_id, $taxonomy->taxonomy );
|
||||
return '<span class="ai1ec-color-swatch ai1ec-tooltip-trigger" ' .
|
||||
'style="background:' . $color . '" title="' .
|
||||
esc_attr( $cat->name ) . '"></span>';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTML markup for the category image square.
|
||||
*
|
||||
* @param int $term_id The term ID of event category.
|
||||
*
|
||||
* @return string HTML snippet to use for category image.
|
||||
*/
|
||||
public function get_category_image_square( $term_id ) {
|
||||
$image = $this->_taxonomy_model->get_category_image( $term_id );
|
||||
if ( null !== $image ) {
|
||||
return '<img src="' . $image . '" alt="' .
|
||||
Ai1ec_I18n::__( 'Category image' ) .
|
||||
'" class="ai1ec_category_small_image_preview" />';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns category color squares for the list of Event Category objects.
|
||||
*
|
||||
* @param array $cats The Event Category objects as returned by get_terms()
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_event_category_colors( array $cats ) {
|
||||
$sqrs = '';
|
||||
foreach ( $cats as $cat ) {
|
||||
$tmp = $this->get_category_color_square( $cat->term_id );
|
||||
if ( ! empty( $tmp ) ) {
|
||||
$sqrs .= $tmp;
|
||||
}
|
||||
}
|
||||
return $sqrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Style attribute for event background color.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
*
|
||||
* @return string Color to assign to event background.
|
||||
*/
|
||||
public function get_category_bg_color( Ai1ec_Event $event ) {
|
||||
$color = $this->get_color_for_event( $event );
|
||||
|
||||
// Convert to HTML attribute.
|
||||
if ( $color ) {
|
||||
$color = 'style="background-color: ' . $color . ';"';
|
||||
} else {
|
||||
$color = '';
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Style attribute for event multi-date divider color.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
*
|
||||
* @return string Color to assign to event background.
|
||||
*/
|
||||
public function get_category_divider_color( Ai1ec_Event $event ) {
|
||||
$color = $this->get_color_for_event( $event );
|
||||
|
||||
// Convert to HTML attribute.
|
||||
if ( $color ) {
|
||||
$color = 'style="border-color: ' . $color . ' transparent transparent transparent;"';
|
||||
} else {
|
||||
$color = '';
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Style attribute for event text color.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
*
|
||||
* @return string Color to assign to event text (foreground).
|
||||
*/
|
||||
public function get_category_text_color( Ai1ec_Event $event ) {
|
||||
$color = $this->get_color_for_event( $event );
|
||||
|
||||
// Convert to HTML attribute.
|
||||
if ( $color ) {
|
||||
$color = 'style="color: ' . $color . ';"';
|
||||
} else {
|
||||
$color = '';
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches color for event having the given post ID.
|
||||
*
|
||||
* @param int $post_id Event's post ID.
|
||||
*
|
||||
* @return string Color associated with event.
|
||||
*/
|
||||
public function get_color_for_event( $event ) {
|
||||
$post_id = $event->get( 'post_id' );
|
||||
|
||||
// If color for this event is uncached, populate cache.
|
||||
if ( ! isset( $this->_event_color_map[$post_id] ) ) {
|
||||
// Find out if an add-on has provided its own color for the event.
|
||||
$color = apply_filters( 'ai1ec_event_color', '', $event );
|
||||
|
||||
// If none provided, fall back to event categories.
|
||||
if ( empty( $color ) ) {
|
||||
$categories = $this->_taxonomy_model->get_post_categories( $post_id );
|
||||
// Find the first category of this post that defines a color.
|
||||
foreach ( $categories as $category ) {
|
||||
$color = $this->_taxonomy_model->get_category_color(
|
||||
$category->term_id
|
||||
);
|
||||
if ( $color ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->_event_color_map[$post_id] = $color;
|
||||
}
|
||||
|
||||
return $this->_event_color_map[$post_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Categories as HTML, either as blocks or inline.
|
||||
*
|
||||
* @param Ai1ec_Event $event Rendered Event.
|
||||
* @param string $format Return 'blocks' or 'inline' formatted result.
|
||||
*
|
||||
* @return string String of HTML for category blocks.
|
||||
*/
|
||||
public function get_categories_html(
|
||||
Ai1ec_Event $event,
|
||||
$format = 'blocks'
|
||||
) {
|
||||
$categories = $this->_taxonomy_model->get_post_categories(
|
||||
$event->get( 'post_id' )
|
||||
);
|
||||
foreach ( $categories as &$category ) {
|
||||
$href = $this->_registry->get(
|
||||
'html.element.href',
|
||||
array( 'cat_ids' => $category->term_id )
|
||||
);
|
||||
|
||||
$class = $data_type = $title = '';
|
||||
if ( $category->description ) {
|
||||
$title = 'title="' .
|
||||
esc_attr( $category->description ) . '" ';
|
||||
}
|
||||
|
||||
$html = '';
|
||||
$class .= ' ai1ec-category';
|
||||
$color_style = '';
|
||||
if ( $format === 'inline' ) {
|
||||
$taxonomy = $this->_registry->get( 'model.taxonomy' );
|
||||
$color_style = $taxonomy->get_category_color(
|
||||
$category->term_id
|
||||
);
|
||||
if ( $color_style !== '' ) {
|
||||
$color_style = 'style="color: ' . $color_style . ';" ';
|
||||
}
|
||||
$class .= '-inline';
|
||||
}
|
||||
|
||||
$html .= '<a ' . $data_type . ' class="' . $class .
|
||||
' ai1ec-term-id-' . $category->term_id . ' p-category" ' .
|
||||
$title . $color_style . 'href="' . $href->generate_href() . '">';
|
||||
|
||||
if ( $format === 'blocks' ) {
|
||||
$html .= $this->get_category_color_square(
|
||||
$category->term_id
|
||||
) . ' ';
|
||||
} else {
|
||||
$html .=
|
||||
'<i ' . $color_style .
|
||||
'class="ai1ec-fa ai1ec-fa-folder-open"></i>';
|
||||
}
|
||||
|
||||
$html .= esc_html( $category->name ) . '</a>';
|
||||
$category = $html;
|
||||
}
|
||||
return implode( ' ', $categories );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags as HTML
|
||||
*/
|
||||
public function get_tags_html( Ai1ec_Event $event ) {
|
||||
$tags = $this->_taxonomy_model->get_post_tags(
|
||||
$event->get( 'post_id' )
|
||||
);
|
||||
if ( ! $tags ) {
|
||||
$tags = array();
|
||||
}
|
||||
foreach ( $tags as &$tag ) {
|
||||
$href = $this->_registry->get(
|
||||
'html.element.href',
|
||||
array( 'tag_ids' => $tag->term_id )
|
||||
);
|
||||
$class = '';
|
||||
$data_type = '';
|
||||
$title = '';
|
||||
if ( $tag->description ) {
|
||||
$title = 'title="' . esc_attr( $tag->description ) . '" ';
|
||||
}
|
||||
$tag = '<a ' . $data_type . ' class="ai1ec-tag ' . $class .
|
||||
' ai1ec-term-id-' . $tag->term_id . '" ' . $title .
|
||||
'href="' . $href->generate_href() . '">' .
|
||||
'<i class="ai1ec-fa ai1ec-fa-tag"></i>' .
|
||||
esc_html( $tag->name ) . '</a>';
|
||||
}
|
||||
return implode( ' ', $tags );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter Groups as HTML, either as blocks or inline.
|
||||
*
|
||||
* @param Ai1ec_Event $event Rendered Event.
|
||||
* @param array $filter_group Filter Group (Option Model)
|
||||
* @param string $format Return 'blocks' or 'inline' formatted result.
|
||||
*
|
||||
* @return string String of HTML for filter group blocks.
|
||||
*/
|
||||
public function get_filter_group_html(
|
||||
Ai1ec_Event $event,
|
||||
$filter_group,
|
||||
$format = 'blocks'
|
||||
) {
|
||||
|
||||
$filter_groups = $this->_taxonomy_model->get_post_taxonomy(
|
||||
$event->get( 'post_id' ), $filter_group['taxonomy_name']
|
||||
);
|
||||
|
||||
$icon_name = '';
|
||||
if ( 'ai1eccfgi-null' !== $filter_group['icon'] ) {
|
||||
$icon_name = $filter_group['icon'];
|
||||
} else {
|
||||
$icon_name = 'ai1ec-icon-timely';
|
||||
}
|
||||
|
||||
foreach ( $filter_groups as &$group ) {
|
||||
$href = $this->_registry->get(
|
||||
'html.element.href',
|
||||
array( $filter_group['taxonomy_name'] . '_ids' => $group->term_id )
|
||||
);
|
||||
|
||||
$class = $data_type = $title = '';
|
||||
if ( $group->description ) {
|
||||
$title = 'title="' .
|
||||
esc_attr( $group->description ) . '" ';
|
||||
}
|
||||
|
||||
$html = '';
|
||||
$class .= ' ai1ec-category';
|
||||
$color_style = '';
|
||||
if ( 'inline' === $format ) {
|
||||
$taxonomy = $this->_registry->get( 'model.taxonomy' );
|
||||
$color_style = $taxonomy->get_category_color(
|
||||
$group->term_id
|
||||
);
|
||||
if ( $color_style !== '' ) {
|
||||
$color_style = 'style="color: ' . $color_style . ';" ';
|
||||
}
|
||||
$class .= '-inline';
|
||||
}
|
||||
|
||||
$html .= '<a ' . $data_type . ' class="' . $class .
|
||||
' ai1ec-term-id-' . $group->term_id . ' p-category" ' .
|
||||
$title . $color_style . 'href="' . $href->generate_href() . '">';
|
||||
|
||||
if ( 'blocks' === $format ) {
|
||||
$html .= $this->get_category_color_square($group->term_id) . ' ';
|
||||
} else {
|
||||
$html = $html
|
||||
. '<i ' . $color_style . ' class="ai1ec-fa '
|
||||
. $icon_name . '"></i>';
|
||||
}
|
||||
|
||||
$html .= esc_html( $group->name ) . '</a>';
|
||||
$group = $html;
|
||||
}
|
||||
|
||||
return implode( ' ', $filter_groups );
|
||||
}
|
||||
|
||||
public function __construct( Ai1ec_Registry_Object $registry ) {
|
||||
parent::__construct( $registry );
|
||||
$this->_taxonomy_model = $this->_registry->get( 'model.taxonomy' );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event ticket.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Ticket {
|
||||
|
||||
/**
|
||||
* Create readable content for buy tickets/register link
|
||||
*
|
||||
* @param bool $long Set to false to use short message version
|
||||
*
|
||||
* @return string Message to be rendered on buy tickets link
|
||||
*/
|
||||
public function get_tickets_url_label( Ai1ec_Event $event, $long = true ) {
|
||||
if ( $event->is_free() ) {
|
||||
return ( $long )
|
||||
? __( 'Register Now', AI1EC_PLUGIN_NAME )
|
||||
: __( 'Register', AI1EC_PLUGIN_NAME );
|
||||
}
|
||||
$output = '';
|
||||
if ( $long ) {
|
||||
$output = apply_filters(
|
||||
'ai1ec_buy_tickets_url_icon',
|
||||
'<i class="ai1ec-fa ai1ec-fa-shopping-cart"></i>'
|
||||
);
|
||||
if ( ! empty( $output ) ) {
|
||||
$output .= ' ';
|
||||
}
|
||||
}
|
||||
$output .= ( $long )
|
||||
? __( 'Buy Tickets', AI1EC_PLUGIN_NAME )
|
||||
: __( 'Tickets', AI1EC_PLUGIN_NAME );
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contact info as HTML
|
||||
*/
|
||||
public function get_contact_html( Ai1ec_Event $event ) {
|
||||
$contact = '<div class="h-card">';
|
||||
$has_contents = false;
|
||||
if ( $event->get( 'contact_name' ) ) {
|
||||
$contact .=
|
||||
'<div class="ai1ec-contact-name p-name">' .
|
||||
'<i class="ai1ec-fa ai1ec-fa-fw ai1ec-fa-user"></i> ' .
|
||||
esc_html( $event->get( 'contact_name' ) ) .
|
||||
'</div> ';
|
||||
$has_contents = true;
|
||||
}
|
||||
if ( $event->get( 'contact_phone' ) ) {
|
||||
$contact .=
|
||||
'<div class="ai1ec-contact-phone p-tel">' .
|
||||
'<i class="ai1ec-fa ai1ec-fa-fw ai1ec-fa-phone"></i> ' .
|
||||
esc_html( $event->get( 'contact_phone' ) ) .
|
||||
'</div> ';
|
||||
$has_contents = true;
|
||||
}
|
||||
if ( $event->get( 'contact_email' ) ) {
|
||||
$contact .=
|
||||
'<div class="ai1ec-contact-email">' .
|
||||
'<a class="u-email" href="mailto:' .
|
||||
esc_attr( $event->get( 'contact_email' ) ) . '">' .
|
||||
'<i class="ai1ec-fa ai1ec-fa-fw ai1ec-fa-envelope-o"></i> ' .
|
||||
__( 'Email', AI1EC_PLUGIN_NAME ) . '</a></div> ';
|
||||
$has_contents = true;
|
||||
}
|
||||
if ( $event->get( 'contact_url' ) ) {
|
||||
$contact .=
|
||||
'<div class="ai1ec-contact-url">' .
|
||||
'<a class="u-url" target="_blank" href="' .
|
||||
esc_attr( $event->get( 'contact_url' ) ) .
|
||||
'"><i class="ai1ec-fa ai1ec-fa-fw ai1ec-fa-link"></i> ' .
|
||||
apply_filters(
|
||||
'ai1ec_contact_url',
|
||||
__( 'Event website', AI1EC_PLUGIN_NAME )
|
||||
) .
|
||||
' <i class="ai1ec-fa ai1ec-fa-external-link"></i></a></div>';
|
||||
$has_contents = true;
|
||||
}
|
||||
$contact .= '</div>';
|
||||
return $has_contents ? $contact : '';
|
||||
}
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event time.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Time extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Returns timespan expression for the event.
|
||||
*
|
||||
* Properly handles:
|
||||
* - instantaneous events
|
||||
* - all-day events
|
||||
* - multi-day events
|
||||
* Display of start date can be hidden (non-all-day events only) or full
|
||||
* date. All-day status, if any, is enclosed in a span.ai1ec-allday-badge
|
||||
* element.
|
||||
*
|
||||
* @param Ai1ec_Event $event Rendered event.
|
||||
* @param string $start_date_display Can be one of 'hidden', 'short',
|
||||
* or 'long'.
|
||||
*
|
||||
* @return string Formatted timespan HTML element.
|
||||
*/
|
||||
public function get_timespan_html(
|
||||
Ai1ec_Event $event,
|
||||
$start_date_display = 'long'
|
||||
) {
|
||||
// Makes no sense to hide start date for all-day events, so fix argument
|
||||
if ( 'hidden' === $start_date_display && $event->is_allday() ) {
|
||||
$start_date_display = 'short';
|
||||
}
|
||||
|
||||
// Localize time.
|
||||
$start = $this->_registry->get( 'date.time', $event->get( 'start' ) );
|
||||
$end = $this->_registry->get( 'date.time', $event->get( 'end' ) );
|
||||
|
||||
// All-day events need to have their end time shifted by 1 second less
|
||||
// to land on the correct day.
|
||||
$end_offset = 0;
|
||||
if ( $event->is_allday() ) {
|
||||
$end->set_time(
|
||||
$end->format( 'H' ),
|
||||
$end->format( 'i' ),
|
||||
$end->format( 's' ) - 1
|
||||
);
|
||||
}
|
||||
|
||||
// Get timestamps of start & end dates without time component.
|
||||
$start_ts = $this->_registry->get( 'date.time', $start )
|
||||
->set_time( 0, 0, 0 )
|
||||
->format();
|
||||
$end_ts = $this->_registry->get( 'date.time', $end )
|
||||
->set_time( 0, 0, 0 )
|
||||
->format();
|
||||
|
||||
$break_years = $start->format( 'Y' ) !== $end->format( 'Y' );
|
||||
$output = '';
|
||||
|
||||
// Display start date, depending on $start_date_display.
|
||||
switch ( $start_date_display ) {
|
||||
case 'hidden':
|
||||
break;
|
||||
case 'short':
|
||||
case 'long':
|
||||
$property = $start_date_display . '_date';
|
||||
$output .= $this->{'get_' . $property}( $start, $break_years );
|
||||
break;
|
||||
default:
|
||||
$start_date_display = 'long';
|
||||
}
|
||||
|
||||
// Output start time for non-all-day events.
|
||||
if ( ! $event->is_allday() ) {
|
||||
if ( 'hidden' !== $start_date_display ) {
|
||||
$output .= apply_filters(
|
||||
'ai1ec_get_timespan_html_time_separator',
|
||||
Ai1ec_I18n::_x( ' @ ', 'Event time separator' )
|
||||
);
|
||||
}
|
||||
$output .= $this->get_short_time( $start );
|
||||
}
|
||||
|
||||
// Find out if we need to output the end time/date. Do not output it for
|
||||
// instantaneous events and all-day events lasting only one day.
|
||||
if (
|
||||
! (
|
||||
$event->is_instant() ||
|
||||
( $event->is_allday() && $start_ts === $end_ts )
|
||||
)
|
||||
) {
|
||||
$output .= apply_filters(
|
||||
'ai1ec_get_timespan_html_date_separator',
|
||||
Ai1ec_I18n::_x( ' – ', 'Event start/end separator' )
|
||||
);
|
||||
|
||||
// If event ends on a different day, output end date.
|
||||
if ( $start_ts !== $end_ts ) {
|
||||
// for short date, use short display type
|
||||
if ( 'short' === $start_date_display ) {
|
||||
$output .= $this->get_short_date( $end, $break_years );
|
||||
} else {
|
||||
$output .= $this->get_long_date( $end );
|
||||
}
|
||||
}
|
||||
|
||||
// Output end time for non-all-day events.
|
||||
if ( ! $event->is_allday() ) {
|
||||
if ( $start_ts !== $end_ts ) {
|
||||
$output .= apply_filters(
|
||||
'ai1ec_get_timespan_html_time_separator',
|
||||
Ai1ec_I18n::_x( ' @ ', 'Event time separator' )
|
||||
);
|
||||
}
|
||||
$output .= $this->get_short_time( $end );
|
||||
}
|
||||
}
|
||||
|
||||
$output = esc_html( $output );
|
||||
|
||||
// Add all-day label.
|
||||
if ( $event->is_allday() ) {
|
||||
$output .= apply_filters(
|
||||
'ai1ec_get_timespan_html_allday_badge',
|
||||
' <span class="ai1ec-allday-badge">' .
|
||||
Ai1ec_I18n::__( 'all-day' ) .
|
||||
'</span>'
|
||||
);
|
||||
}
|
||||
return apply_filters(
|
||||
'ai1ec_get_timespan_html',
|
||||
$output,
|
||||
$event,
|
||||
$start_date_display
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the html for the exclude dates and exception rules.
|
||||
*
|
||||
* @param Ai1ec_Event $event
|
||||
* @param Ai1ec_Recurrence_Rule $rrule
|
||||
* @return string
|
||||
*/
|
||||
public function get_exclude_html(
|
||||
Ai1ec_Event $event,
|
||||
Ai1ec_Recurrence_Rule $rrule
|
||||
) {
|
||||
$excludes = array();
|
||||
$exception_rules = $event->get( 'exception_rules' );
|
||||
$exception_dates = $event->get( 'exception_dates' );
|
||||
if ( $exception_rules ) {
|
||||
$excludes[] =
|
||||
$rrule->rrule_to_text( $exception_rules );
|
||||
}
|
||||
if ( $exception_dates && 0 !== strpos( $exception_rules, 'EXDATE' ) ) {
|
||||
$excludes[] =
|
||||
$rrule->exdate_to_text( $exception_dates );
|
||||
}
|
||||
return implode( Ai1ec_I18n::__( ', and ' ), $excludes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the short date
|
||||
*
|
||||
* @param Ai1ec_Date_Time $time
|
||||
* @param bool $add_year Whether to add year or not.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_short_date( Ai1ec_Date_Time $time, $add_year = false ) {
|
||||
$months = apply_filters( 'ai1ec_i18n_months', array() );
|
||||
$m = $time->format_i18n( 'M' );
|
||||
$m = array_key_exists( $m, $months ) ? $months[$m] : $m;
|
||||
if ( $add_year ) {
|
||||
return $m . ' ' . $time->format_i18n( 'j Y' );
|
||||
}
|
||||
return $m . ' ' . $time->format_i18n( 'j' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a long-length date for use in other views (e.g., single event).
|
||||
*
|
||||
* @param Ai1ec_Date_Time $time Object to format.
|
||||
*
|
||||
* @return string Formatted date time [default: `l, M j, Y`].
|
||||
*/
|
||||
public function get_long_date( Ai1ec_Date_Time $time ) {
|
||||
$date_format = $this->_registry->get( 'model.option' )->get(
|
||||
'date_format',
|
||||
'l, M j, Y'
|
||||
);
|
||||
return $time->format_i18n( $date_format );
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a short-form time for use in compressed (e.g. month) views.
|
||||
*
|
||||
* @param Ai1ec_Date_Time $time Object to format.
|
||||
*
|
||||
* @return string Formatted date time [default: `g:i a`].
|
||||
*/
|
||||
public function get_short_time( Ai1ec_Date_Time $time ) {
|
||||
$time_format = $this->_registry->get( 'model.option' )->get(
|
||||
'time_format',
|
||||
'g:i a'
|
||||
);
|
||||
return $time->format_i18n( $time_format );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE5TCCA82gAwIBAgIQB28SRoFFnCjVSNaXxA4AGzANBgkqhkiG9w0BAQUFADBv
|
||||
MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
|
||||
ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
|
||||
eHRlcm5hbCBDQSBSb290MB4XDTEyMDIxNjAwMDAwMFoXDTIwMDUzMDEwNDgzOFow
|
||||
czELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxGTAXBgNV
|
||||
BAMTEFBvc2l0aXZlU1NMIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQDo6jnjIqaqucQA0OeqZztDB71Pkuu8vgGjQK3g70QotdA6voBUF4V6a4Rs
|
||||
NjbloyTi/igBkLzX3Q+5K05IdwVpr95XMLHo+xoD9jxbUx6hAUlocnPWMytDqTcy
|
||||
Ug+uJ1YxMGCtyb1zLDnukNh1sCUhYHsqfwL9goUfdE+SNHNcHQCgsMDqmOK+ARRY
|
||||
FygiinddUCXNmmym5QzlqyjDsiCJ8AckHpXCLsDl6ez2PRIHSD3SwyNWQezT3zVL
|
||||
yOf2hgVSEEOajBd8i6q8eODwRTusgFX+KJPhChFo9FJXb/5IC1tdGmpnc5mCtJ5D
|
||||
YD7HWyoSbhruyzmuwzWdqLxdsC/DAgMBAAGjggF3MIIBczAfBgNVHSMEGDAWgBSt
|
||||
vZh6NLQm9/rEJlTvA73gJMtUGjAdBgNVHQ4EFgQUmeRAX2sUXj4F2d3TY1T8Yrj3
|
||||
AKwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEQYDVR0gBAow
|
||||
CDAGBgRVHSAAMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0
|
||||
LmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LmNybDCBswYIKwYBBQUHAQEEgaYw
|
||||
gaMwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9BZGRUcnVz
|
||||
dEV4dGVybmFsQ0FSb290LnA3YzA5BggrBgEFBQcwAoYtaHR0cDovL2NydC51c2Vy
|
||||
dHJ1c3QuY29tL0FkZFRydXN0VVROU0dDQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRw
|
||||
Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQCcNuNOrvGK
|
||||
u2yXjI9LZ9Cf2ISqnyFfNaFbxCtjDei8d12nxDf9Sy2e6B1pocCEzNFti/OBy59L
|
||||
dLBJKjHoN0DrH9mXoxoR1Sanbg+61b4s/bSRZNy+OxlQDXqV8wQTqbtHD4tc0azC
|
||||
e3chUN1bq+70ptjUSlNrTa24yOfmUlhNQ0zCoiNPDsAgOa/fT0JbHtMJ9BgJWSrZ
|
||||
6EoYvzL7+i1ki4fKWyvouAt+vhcSxwOCKa9Yr4WEXT0K3yNRw82vEL+AaXeRCk/l
|
||||
uuGtm87fM04wO+mPZn+C+mv626PAcwDj1hKvTfIPWhRRH224hoFiB85ccsJP81cq
|
||||
cdnUl4XmGFO3
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
|
||||
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
|
||||
IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
|
||||
MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
|
||||
FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
|
||||
bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
|
||||
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
|
||||
H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
|
||||
uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
|
||||
mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
|
||||
a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
|
||||
E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
|
||||
WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
|
||||
VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
|
||||
Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
|
||||
cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
|
||||
IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
|
||||
AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
|
||||
YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
|
||||
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
|
||||
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
|
||||
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
|
||||
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,4 +0,0 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user