├── .gitignore
├── composer.json
├── wp-event-calendar
├── assets
│ ├── js
│ │ └── event.js
│ └── css
│ │ ├── calendar.css
│ │ └── datepicker.css
└── includes
│ ├── events
│ ├── user-dashboard.php
│ ├── post-statuses.php
│ ├── user-alerts.php
│ ├── editor.php
│ ├── cron.php
│ ├── hooks.php
│ ├── post-types.php
│ ├── capabilities.php
│ ├── taxonomies.php
│ ├── admin.php
│ └── metaboxes.php
│ └── common
│ ├── list-table-month.php
│ ├── event.php
│ ├── list-table-day.php
│ ├── list-table-week.php
│ ├── admin.php
│ ├── functions.php
│ └── list-table-base.php
├── README.md
├── wp-event-calendar.php
├── readme.txt
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | .idea
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "stuttter/wp-event-calendar",
3 | "description": "The best way to manage events in WordPress",
4 | "homepage": "https://github.com/stuttter/wp-event-calendar",
5 | "type": "wordpress-plugin",
6 | "require": {
7 | "php": ">=5.2",
8 | "composer/installers": "^1.0"
9 | },
10 | "license": "GPL-2.0-or-later",
11 | "authors": [
12 | {
13 | "name": "John James Jacoby",
14 | "email": "johnjamesjacoby@me.com"
15 | }
16 | ]
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/wp-event-calendar/assets/js/event.js:
--------------------------------------------------------------------------------
1 | jQuery( document ).ready( function( $ ) {
2 | 'use strict';
3 |
4 | if ( $( '.wp_event_calendar_datepicker' ).length > 0 ) {
5 | $( '.wp_event_calendar_datepicker' ).datepicker( {
6 | dateFormat: 'mm/dd/yy'
7 | } );
8 | }
9 |
10 | $( '#wp_event_calendar_all_day' ).click( function( e ) {
11 | var checked = $( this ).prop( 'checked' );
12 |
13 | if ( true === checked ) {
14 | $( '.event-time' ).hide();
15 | } else {
16 | $( '.event-time' ).show();
17 | }
18 | } );
19 |
20 | if ( $( '.ct_rental_datepicker' ).length > 0 ) {
21 | $( '.ct_rental_datepicker' ).datepicker( {
22 | dateFormat: 'mm/dd/yy'
23 | } );
24 | }
25 | } );
26 |
--------------------------------------------------------------------------------
/wp-event-calendar/includes/events/user-dashboard.php:
--------------------------------------------------------------------------------
1 | 'events',
24 | 'slug' => 'events',
25 | 'url' => '',
26 | 'label' => esc_html__( 'Events', 'wp-user-alerts' ),
27 | 'show_in_menu' => true,
28 | 'order' => 20
29 | );
30 |
31 | // Return sections
32 | return $sections;
33 | }
34 |
--------------------------------------------------------------------------------
/wp-event-calendar/includes/events/post-statuses.php:
--------------------------------------------------------------------------------
1 | esc_html_x( 'Past', 'events', 'wp-event-calendar' ),
22 | 'label_count' => _nx_noop( 'Past (%s) ', 'Past (%s) ', 'events', 'wp-event-calendar' ),
23 | 'exclude_from_search' => get_post_type_object( 'event' )->exclude_from_search,
24 | 'public' => get_post_type_object( 'event' )->public,
25 | 'publicly_queryable' => get_post_type_object( 'event' )->publicly_queryable,
26 | 'show_in_admin_status_list' => true,
27 | 'show_in_admin_all_list' => true,
28 | ) );
29 | }
30 |
--------------------------------------------------------------------------------
/wp-event-calendar/includes/events/user-alerts.php:
--------------------------------------------------------------------------------
1 | 'OR',
34 |
35 | // Starts after midnight yesterday
36 | array(
37 | 'key' => 'wp_event_calendar_date_time',
38 | 'value' => $midnight_yesterday,
39 | 'type' => 'DATETIME',
40 | 'compare' => '>',
41 | ),
42 |
43 | // Ends after midnight today
44 | array(
45 | 'key' => 'wp_event_calendar_end_date_time',
46 | 'value' => $midnight_yesterday,
47 | 'type' => 'DATETIME',
48 | 'compare' => '>',
49 | )
50 | );
51 |
52 | return $r;
53 | }
54 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WP Event Calendar
2 |
3 | WP Event Calendar is the best way to keep track of events in WordPress.
4 |
5 | * Seamlessly integrates into WordPress's dashboard interface
6 | * Month, week, and day list-table views
7 | * Organize events by type, category, & tag
8 | * Easily & logically paginate through date ranges
9 | * Safe, secure, & efficient
10 | * Full of developer hooks for integration with other plugins & themes
11 | * Integrates with User Groups, Alerts, Activity, and Profiles
12 |
13 | # Installation
14 |
15 | * Download and install using the built in WordPress plugin installer.
16 | * Activate in the "Plugins" area of your admin by clicking the "Activate" link.
17 | * No further setup or configuration is necessary.
18 |
19 | # FAQ
20 |
21 | ### Does this create new database tables?
22 |
23 | No. It uses WordPress's custom post-type, custom taxonomy, and metadata APIs.
24 |
25 | ### Does this modify existing database tables?
26 |
27 | No. All of WordPress's core database tables remain untouched.
28 |
29 | ### Where can I get support?
30 |
31 | * Basic: https://wordpress.org/support/plugin/wp-event-calendar/
32 | * Priority: https://chat.flox.io/support/channels/wp-event-calendar/
33 |
34 | ### Can I contribute?
35 |
36 | Yes, please! The number of users needing events and calendars in WordPress is always growing. Having an easy-to-use API and powerful set of functions is critical to managing complex WordPress installations. If this is your thing, please help us out!
37 |
--------------------------------------------------------------------------------
/wp-event-calendar/includes/events/editor.php:
--------------------------------------------------------------------------------
1 | 'ids',
51 | 'post_type' => wp_event_calendar_allowed_post_types(),
52 | 'post_status' => 'publish',
53 | 'posts_per_page' => -1,
54 | 'meta_query' => array( array(
55 | 'relation' => 'AND',
56 | array(
57 | 'key' => 'wp_event_calendar_date_time',
58 | 'value' => $eod,
59 | 'type' => 'DATETIME',
60 | 'compare' => '<',
61 | ),
62 | array(
63 | 'key' => 'wp_event_calendar_end_date_time',
64 | 'value' => $eod,
65 | 'type' => 'DATETIME',
66 | 'compare' => '<',
67 | )
68 | ) )
69 | ) );
70 |
71 | // Bail if no posts
72 | if ( empty( $old_events->posts ) ) {
73 | return;
74 | }
75 |
76 | // Loop through posts and update status
77 | foreach ( $old_events->posts as $post_id ) {
78 | wp_update_post( array(
79 | 'ID' => $post_id,
80 | 'post_status' => 'passed'
81 | ) );
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/wp-event-calendar/includes/events/hooks.php:
--------------------------------------------------------------------------------
1 | _x( 'Events', 'post type general name', 'wp-event-calendar' ),
25 | 'singular_name' => _x( 'Event', 'post type singular name', 'wp-event-calendar' ),
26 | 'add_new' => _x( 'Add New', 'event', 'wp-event-calendar' ),
27 | 'add_new_item' => __( 'Add New Event', 'wp-event-calendar' ),
28 | 'edit_item' => __( 'Edit Event', 'wp-event-calendar' ),
29 | 'new_item' => __( 'New Event', 'wp-event-calendar' ),
30 | 'view_item' => __( 'View Event', 'wp-event-calendar' ),
31 | 'search_items' => __( 'Search Events', 'wp-event-calendar' ),
32 | 'not_found' => __( 'No events found.', 'wp-event-calendar' ),
33 | 'not_found_in_trash' => __( 'No events found in trash.', 'wp-event-calendar' ),
34 | 'parent_item_colon' => __( 'Parent Event:', 'wp-event-calendar' ),
35 | 'all_items' => __( 'All Events', 'wp-event-calendar' ),
36 | 'featured_image' => __( 'Featured Image', 'wp-event-calendar' ),
37 | 'set_featured_image' => __( 'Set featured image', 'wp-event-calendar' ),
38 | 'remove_featured_image' => __( 'Remove featured image', 'wp-event-calendar' ),
39 | 'use_featured_image' => __( 'Use as featured image', 'wp-event-calendar' ),
40 | );
41 |
42 | // Supports
43 | $supports = array(
44 | 'title',
45 | 'thumbnail',
46 | 'revisions',
47 | 'events'
48 | );
49 |
50 | // Capability types
51 | $cap_types = array(
52 | 'event',
53 | 'events'
54 | );
55 |
56 | // Capabilities
57 | $caps = array(
58 |
59 | // Meta caps
60 | 'edit_post' => 'edit_event',
61 | 'read_post' => 'read_event',
62 | 'delete_post' => 'delete_event',
63 |
64 | // Primitive/meta caps
65 | 'read' => 'read',
66 | 'create_posts' => 'create_events',
67 |
68 | // Primitive caps (used outside of map_meta_cap)
69 | 'edit_posts' => 'edit_events',
70 | 'edit_others_posts' => 'edit_others_events',
71 | 'publish_posts' => 'publish_events',
72 | 'read_private_posts' => 'read_private_events',
73 |
74 | // Primitive caps (used inside of map_meta_cap)
75 | 'delete_posts' => 'delete_events',
76 | 'delete_private_posts' => 'delete_private_events',
77 | 'delete_published_posts' => 'delete_published_events',
78 | 'delete_others_posts' => 'delete_others_events',
79 | 'edit_private_posts' => 'edit_private_events',
80 | 'edit_published_posts' => 'edit_published_events'
81 | );
82 |
83 | // Rewrite
84 | $rewrite = array(
85 | 'slug' => 'event',
86 | 'with_front' => false
87 | );
88 |
89 | // Post type arguments
90 | $args = array(
91 | 'labels' => $labels,
92 | 'supports' => $supports,
93 | 'description' => '',
94 | 'public' => true,
95 | 'hierarchical' => true,
96 | 'exclude_from_search' => true,
97 | 'publicly_queryable' => false,
98 | 'show_ui' => true,
99 | 'show_in_menu' => true,
100 | 'show_in_nav_menus' => false,
101 | 'archive_in_nav_menus' => false,
102 | 'show_in_admin_bar' => true,
103 | 'menu_position' => 44,
104 | 'menu_icon' => 'dashicons-calendar-alt',
105 | 'capabilities' => $caps,
106 | 'capability_type' => $cap_types,
107 | 'register_meta_box_cb' => null,
108 | 'taxonomies' => array(),
109 | 'has_archive' => false,
110 | 'rewrite' => $rewrite,
111 | 'query_var' => true,
112 | 'can_export' => true,
113 | 'delete_with_user' => false,
114 | );
115 |
116 | // Register the event type
117 | register_post_type( 'event', $args );
118 | }
119 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | === WP Event Calendar ===
2 | Contributors: johnjamesjacoby, stuttter
3 | Tags: event, calendar, session, appointment, month, week, day, category, tag, term, type
4 | Requires at least: 4.7
5 | Tested up to: 4.8
6 | Stable tag: 1.1.0
7 | License: GPLv2 or later
8 | License URI: https://www.gnu.org/licenses/gpl-2.0.html
9 | Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9Q4F4EL5YJ62J
10 |
11 | == Description ==
12 |
13 | WP Event Calendar is the best way to manage events in WordPress!
14 |
15 | > We know you have your choice of calendar & events plugins. We appreciate you giving this one a try, and we hope you really love it!
16 |
17 | = Details =
18 |
19 | * Seamlessly integrates into WordPress's dashboard interface
20 | * Month, week, and day list-table views
21 | * Organize events by type, category, & tag
22 | * Easily & logically paginate through date ranges
23 | * Safe, secure, & efficient
24 | * Full of developer hooks for integration with other plugins & themes
25 | * Integrates with User Groups, Alerts, Activity, and Profiles
26 |
27 | = Works great with =
28 |
29 | * [WP Chosen](https://wordpress.org/plugins/wp-chosen/ "Make long, unwieldy select boxes much more user-friendly.")
30 | * [WP Pretty Filters](https://wordpress.org/plugins/wp-pretty-filters/ "Makes post filters better match what's already in Media & Attachments.")
31 | * [WP Media Categories](https://wordpress.org/plugins/wp-media-categories/ "Add categories to media & attachments.")
32 | * [WP Term Order](https://wordpress.org/plugins/wp-term-order/ "Sort taxonomy terms, your way.")
33 | * [WP Term Authors](https://wordpress.org/plugins/wp-term-authors/ "Authors for categories, tags, and other taxonomy terms.")
34 | * [WP Term Colors](https://wordpress.org/plugins/wp-term-colors/ "Pretty colors for categories, tags, and other taxonomy terms.")
35 | * [WP Term Families](https://wordpress.org/plugins/wp-term-families/ "Families of taxonomies for taxonomy terms.")
36 | * [WP Term Icons](https://wordpress.org/plugins/wp-term-icons/ "Pretty icons for categories, tags, and other taxonomy terms.")
37 | * [WP Term Images](https://wordpress.org/plugins/wp-term-images/ "Pretty images for categories, tags, and other taxonomy terms.")
38 | * [WP Term Visibility](https://wordpress.org/plugins/wp-term-visibility/ "Visibilities for categories, tags, and other taxonomy terms.")
39 | * [WP User Activity](https://wordpress.org/plugins/wp-user-activity/ "The best way to log activity in WordPress.")
40 | * [WP User Alerts](https://wordpress.org/plugins/wp-user-alerts/ "Alert registered users when new content is published.")
41 | * [WP User Avatars](https://wordpress.org/plugins/wp-user-avatars/ "Allow users to upload avatars or choose them from your media library.")
42 | * [WP User Groups](https://wordpress.org/plugins/wp-user-groups/ "Group users together with taxonomies & terms.")
43 | * [WP User Parents](https://wordpress.org/plugins/wp-user-parents/ "Allow parent users to manage their direct decendants.")
44 | * [WP User Profiles](https://wordpress.org/plugins/wp-user-profiles/ "A sophisticated way to edit users in WordPress.")
45 |
46 | == Screenshots ==
47 |
48 | 1. Month View
49 | 2. Week View
50 | 3. Metabox
51 | 4. Date Picker
52 |
53 | == Installation ==
54 |
55 | * Download and install using the built in WordPress plugin installer.
56 | * Activate in the "Plugins" area of your admin by clicking the "Activate" link.
57 | * No further setup or configuration is necessary.
58 |
59 | == Frequently Asked Questions ==
60 |
61 | = Does this create new database tables? =
62 |
63 | No. It uses WordPress's custom post-type, custom taxonomy, and metadata APIs.
64 |
65 | = Does this modify existing database tables? =
66 |
67 | No. All of WordPress's core database tables remain untouched.
68 |
69 | = Where can I get support? =
70 |
71 | * Basic: https://wordpress.org/support/plugin/wp-event-calendar/
72 | * Priority: https://chat.flox.io/support/channels/wp-event-calendar/
73 |
74 | = Where can I find documentation? =
75 |
76 | http://github.com/stuttter/wp-event-calendar/
77 |
78 | == Changelog ==
79 |
80 | = [1.1.0] - 2016-12-09 =
81 | * Improved editor metabox experience
82 | * Fix bug caused when relocating the "Details" metabox
83 |
84 | = [1.0.0] - 2016-09-07 =
85 | * Improved support for mu-plugins location
86 | * Improved performance of all ranged calendar queries
87 | * Updated plugin file organization structure
88 |
89 | = [0.4.0] - 2016-05-12 =
90 | * More improvements to capability mappings
91 | * Support for additional post types
92 | * Helper functions for iCal integration
93 | * Query functions
94 |
95 | = [0.3.1] - 2016-05-03 =
96 | * Fix capability regression in 0.3.1
97 | * Add contextual help to Calendar page
98 |
99 | = [0.3.0] - 2016-03-30 =
100 | * Improve capability mapping
101 | * Improve TinyMCE compatibility
102 | * Update calendar styling
103 |
104 | = [0.2.4] - 2016-02-05 =
105 | * Dropdown select elements for hours & minutes
106 |
107 | = [0.2.3] - 2016-02-01 =
108 | * Rename metabox titles
109 | * Make "Location" optional
110 | * Add revision support to events
111 | * General code & styling clean-up
112 |
113 | = [0.2.2] - 2016-01-10 =
114 | * Improve support for all-day & multi-day events
115 | * Improve month, week, and day views
116 | * Improve contrast of current & active items
117 |
118 | = [0.2.1] - 2015-12-30 =
119 | * Improve taxonomy & status filtering
120 |
121 | = [0.2.0] - 2015-11-30 =
122 | * Add "Day" view
123 | * Improve "Month" view
124 |
125 | = [0.1.10] - 2015-11-30 =
126 | * Filter events by registered taxonomy
127 |
128 | = [0.1.9] - 2015-11-16 =
129 | * Move events to "Passed" status twice daily
130 |
131 | = [0.1.8] - 2015-9-10 =
132 | * Added week view
133 | * Added persistent pagination for mode, status, & search
134 | * Added styling for a few event types
135 | * Added help text
136 | * Added legend in help text area
137 |
138 | = [0.1.7] - 2015-9-8 =
139 | * Updated date-picker styling
140 |
141 | = [0.1.6] - 2015-9-7 =
142 | * Sort by start, end, and repetition
143 |
144 | = [0.1.5] - 2015-9-6 =
145 | * All-day events
146 |
147 | = [0.1.4] - 2015-9-5 =
148 | * More flexible mapped capabilities
149 |
150 | = [0.1.3] - 2015-9-4 =
151 | * Revert role & capability changes
152 |
153 | = [0.1.2] - 2015-9-3 =
154 | * Remove dependency
155 | * Start, end, repeat, & expiring events
156 | * Date picker
157 | * Cleanup
158 |
159 | = [0.1.1] - 2015-9-2 =
160 | * Show pointers on event clicks
161 | * Add flexible methods for pointers output
162 | * Add actions & filters
163 | * Rename main class to be for month-only view
164 | * Use new icon for private posts
165 |
166 | = [0.1.0] - 2015-9-1 =
167 | * Initial release
168 |
--------------------------------------------------------------------------------
/wp-event-calendar/assets/css/calendar.css:
--------------------------------------------------------------------------------
1 | /** Editor ********************************************************************/
2 |
3 | body.post-type-event #post-body-content {
4 | margin-bottom: 0;
5 | }
6 |
7 | .wp-event-calendar-editor #wp-content-editor-tools {
8 | background-color: #fff;
9 | padding-top: 0;
10 | }
11 |
12 | #above_event_editor-sortables {
13 | margin-top: 20px;
14 | }
15 |
16 | .event-time {
17 | display: inline-block;
18 | }
19 | .wp_event_calendar_datepicker {
20 | max-width: 125px;
21 | height: 28px;
22 | margin: 2px 0 3px;
23 | }
24 | .event-time input {
25 | max-width: 50px;
26 | }
27 |
28 | /** Edit & Rows ***************************************************************/
29 |
30 | .widefat .column-start,
31 | .widefat .column-end,
32 | .widefat .column-duration {
33 | width: 15%
34 | }
35 |
36 | .widefat .column-event-types,
37 | .widefat .column-event-categories {
38 | width: 10%;
39 | }
40 |
41 | .widefat .column-repeat {
42 | width: 10%;
43 | }
44 |
45 | /** Common ********************************************************************/
46 |
47 | .view-switch .view-month:before {
48 | content: '\f509';
49 | }
50 |
51 | .view-switch .view-week:before {
52 | content: '\f164';
53 | }
54 |
55 | .view-switch .view-day:before {
56 | content: '\f163';
57 | }
58 |
59 | table.calendar {
60 | table-layout: fixed;
61 | }
62 |
63 | table.calendar thead th,
64 | table.calendar tfoot th {
65 | text-align: center;
66 | }
67 |
68 | table.calendar tbody td {
69 | padding: 0;
70 | position: relative;
71 | text-align: left;
72 | border-bottom: 1px solid #e1e1e1;
73 | border-right: 1px solid #e1e1e1;
74 | }
75 |
76 | table.calendar a {
77 | display: block;
78 | -o-text-overflow: ellipsis;
79 | text-overflow: ellipsis;
80 | overflow-x: hidden;
81 | white-space: nowrap;
82 | margin: 0;
83 | padding: 0 5px;
84 | }
85 |
86 | table.calendar:not(.day) tbody td.saturday,
87 | table.calendar:not(.day) tbody td.sunday {
88 | background-color: #f1f1f1;
89 | }
90 |
91 | table.calendar a:before {
92 | font: normal 15px/20px 'dashicons';
93 | vertical-align: top;
94 | speak: none;
95 | -webkit-font-smoothing: antialiased;
96 | -moz-osx-font-smoothing: grayscale;
97 | width: 20px;
98 | height: 20px;
99 | margin-right: 4px;
100 | }
101 |
102 |
103 | .wp-pointer-content h3.type-event:before,
104 | table.calendar a.type-event:before {
105 | content: '\f145';
106 | }
107 |
108 | .wp-pointer-content h3.type-post:before,
109 | table.calendar a.type-post:before {
110 | content: '\f109';
111 | }
112 |
113 | .wp-pointer-content h3.type-page:before,
114 | table.calendar a.type-page:before {
115 | content: '\f105';
116 | }
117 |
118 | .wp-pointer-content h3.status-trash:before,
119 | table.calendar a.status-trash:before {
120 | content: '\f182';
121 | }
122 |
123 | .wp-pointer-content h3.status-private:before,
124 | table.calendar a.status-private:before {
125 | content: '\f530';
126 | }
127 |
128 | .wp-pointer-content h3.post-password-required:before,
129 | table.calendar a.post-password-required:before {
130 | content: '\f315';
131 | }
132 |
133 | .wp-pointer-content h3.has-location:before,
134 | table.calendar a.has-location:before {
135 | content: "\f230";
136 | }
137 |
138 | .wp-pointer-content h3.all-day:before,
139 | table.calendar a.all-day:before {
140 | content: '\f469';
141 | }
142 |
143 | table.calendar a.status-draft {
144 | opacity: 0.5;
145 | }
146 |
147 | /** Month *********************************************************************/
148 |
149 | table.month tbody td a.day-number {
150 | position: absolute;
151 | top: 0px;
152 | left: 0px;
153 | height: 26px;
154 | width: 26px;
155 | text-align: center;
156 | line-height: 1.9em;
157 | padding: 0;
158 | border-right: 1px solid #e1e1e1;
159 | border-bottom: 1px solid #e1e1e1;
160 | background-color: rgba(255, 255, 255, 1);
161 | color: #aaa;
162 | font-weight: 600;
163 | }
164 |
165 | table.month tbody td.today a.day-number {
166 | background: #ffe;
167 | }
168 | table.month tbody a.add-event-for-day:hover,
169 | table.month tbody td a.day-number:hover {
170 | background: rgba(235, 235, 235, 1);
171 | }
172 |
173 | table.month tbody a.add-event-for-day {
174 | visibility: hidden;
175 | position: absolute;
176 | right: 0;
177 | top: 0;
178 | height: 26px;
179 | width: 26px;
180 | text-align: center;
181 | border-left: 1px solid #e1e1e1;
182 | border-bottom: 1px solid #e1e1e1;
183 | background-color: rgba(255, 255, 255, 1);
184 | padding: 0;
185 | margin: 0;
186 | }
187 |
188 | table.month tbody a i {
189 | line-height: 1.9em;
190 | font-size: 15px;
191 | overflow: hidden;
192 | }
193 |
194 | table.month tbody td:hover a.add-event-for-day {
195 | visibility: visible;
196 | }
197 |
198 | table.month tbody td:hover {
199 | background-color: #ffe;
200 | }
201 |
202 | table.month tbody td {
203 | min-height: 110px;
204 | }
205 |
206 | table.month tbody th {
207 | height: 80px;
208 | background-color: #fff;
209 | border-bottom: 1px solid #e1e1e1;
210 | }
211 |
212 | table.month tbody tr th:last-of-type {
213 | border-right: 1px solid #e1e1e1;
214 | }
215 |
216 | table.month tbody td:last-of-type:not(.position-6) {
217 | border-right: 1px solid #e1e1e1;
218 | }
219 |
220 | table.month tbody tr td:last-of-type {
221 | border-right: none;
222 | }
223 |
224 | table.month div.events-for-cell {
225 | margin: 30px 0 5px;
226 | min-height: 80px
227 | }
228 |
229 | .wp-pointer-content h3 a {
230 | color: #fff;
231 | text-decoration: none;
232 | }
233 |
234 | .wp-pointer-content h3 a:hover {
235 | color: #eee;
236 | }
237 |
238 | input#year {
239 | width: 90px;
240 | }
241 |
242 | /** Week **********************************************************************/
243 |
244 | table.week th,
245 | table.day th {
246 | width: 30px;
247 | background-color: #fff;
248 | color: #333;
249 | border-bottom: 1px solid #e1e1e1;
250 | border-right: 1px solid #e1e1e1;
251 | text-align: center;
252 | cursor: default;
253 | }
254 |
255 | table.week tbody tr.this-hour td,
256 | table.day tbody tr.this-hour td {
257 | background: #ffe;
258 | }
259 |
260 | table.day tr.multi-day,
261 | table.day tr.all-day,
262 | table.week tr.multi-day,
263 | table.week tr.all-day {
264 | background-color: #efe;
265 | }
266 |
267 | table.week tr.multi-day th,
268 | table.week tr.multi-day td,
269 | table.day tr.multi-day th,
270 | table.day tr.multi-day td {
271 | border-bottom: 2px solid #e1e1e1;
272 | }
273 |
274 | table.week th.column-hour,
275 | table.day th.column-hour {
276 | width: 100px;
277 | }
278 |
279 | table.week th.column-monday,
280 | table.week th.column-tuesday,
281 | table.week th.column-wednesday,
282 | table.week th.column-thursday,
283 | table.week th.column-friday,
284 | table.week th.column-saturday,
285 | table.week th.column-sunday,
286 | table.day th.column-monday,
287 | table.day th.column-tuesday,
288 | table.day th.column-wednesday,
289 | table.day th.column-thursday,
290 | table.day th.column-friday,
291 | table.day th.column-saturday,
292 | table.day th.column-sunday {
293 | width: 100%;
294 | }
--------------------------------------------------------------------------------
/wp-event-calendar/includes/common/list-table-month.php:
--------------------------------------------------------------------------------
1 | view_start = "{$this->year}-{$this->month}-01 00:00:00";
41 |
42 | $mon = mysql2date( 'U', $this->view_start );
43 | $eom = strtotime( '+1 month', $mon );
44 |
45 | $this->view_end = date_i18n( 'Y-m-d H:i:s', $eom );
46 | }
47 |
48 | /**
49 | * Setup the list-table's columns
50 | *
51 | * @see WP_List_Table::single_row_columns()
52 | *
53 | * @return array An associative array containing column information
54 | */
55 | public function get_columns() {
56 | return array(
57 | 'sunday' => $GLOBALS['wp_locale']->get_weekday( 0 ),
58 | 'monday' => $GLOBALS['wp_locale']->get_weekday( 1 ),
59 | 'tuesday' => $GLOBALS['wp_locale']->get_weekday( 2 ),
60 | 'wednesday' => $GLOBALS['wp_locale']->get_weekday( 3 ),
61 | 'thursday' => $GLOBALS['wp_locale']->get_weekday( 4 ),
62 | 'friday' => $GLOBALS['wp_locale']->get_weekday( 5 ),
63 | 'saturday' => $GLOBALS['wp_locale']->get_weekday( 6 )
64 | );
65 | }
66 |
67 | /**
68 | * Get a list of CSS classes for the list table table tag.
69 | *
70 | * @since 0.1.0
71 | * @access protected
72 | *
73 | * @return array List of CSS classes for the table tag.
74 | */
75 | protected function get_table_classes() {
76 | return array( 'widefat', 'fixed', 'striped', 'calendar', 'month', $this->_args['plural'] );
77 | }
78 |
79 | /**
80 | * Add a post to the item array, keyed by day
81 | *
82 | * @todo Repeat & expire
83 | *
84 | * @since 0.1.1
85 | *
86 | * @param object $post
87 | * @param int $max
88 | */
89 | protected function setup_item( $post = false, $max = 10 ) {
90 |
91 | // Bail if there is no post
92 | if ( empty( $post ) ) {
93 | return;
94 | }
95 |
96 | // Start day
97 | $time = $this->item_start;
98 | $type = 'items';
99 | $max_int = absint( $max );
100 |
101 | // Loop through days and setup the item
102 | for ( $i = 0, $j = $this->item_days; $i < $j; ++$i ) {
103 | $day = (int) date_i18n( 'j', $time );
104 | $month = (int) date_i18n( 'n', $time );
105 | $year = (int) date_i18n( 'Y', $time );
106 |
107 | // Skip if not this month
108 | if ( ( $month === (int) $this->month ) && ( $year === (int) $this->year ) ) {
109 |
110 | // Setup the pointer for each day
111 | $this->setup_pointer( $post, $day );
112 |
113 | // Get count for day
114 | $count = empty( $this->{$type}[ $day ] )
115 | ? 0
116 | : count( $this->{$type}[ $day ] );
117 |
118 | // Add post to item types for each day in it's duration
119 | if ( $count < $max_int ) {
120 | $this->{$type}[ $day ][ $post->ID ] = $post;
121 | }
122 | }
123 |
124 | // Bump the time 1 day
125 | $time += DAY_IN_SECONDS;
126 | }
127 | }
128 |
129 | /**
130 | * Start the week with a table row
131 | *
132 | * @since 0.1.0
133 | */
134 | protected function get_row_start() {
135 | ?>
136 |
137 |
138 |
139 |
149 |
150 |
151 |
152 |
162 |
163 |
164 |
165 | 'day',
181 | 'cy' => $this->year,
182 | 'cm' => $this->month,
183 | 'cd' => $day_of_month
184 | ), $this->get_base_url() );
185 |
186 | // Link to add new event on this day
187 | $add_event_for_day = add_query_arg( array(
188 | 'post_type' => wp_event_calendar_get_admin_post_type(),
189 | 'start_day' => strtotime( "{$this->month}/{$day_of_month}/{$this->year}" )
190 | ), admin_url( 'post-new.php' ) ); ?>
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 | get_posts_for_cell( $day_of_month ); ?>
203 |
204 |
205 |
206 | month, 1, $this->year );
218 | $max_day = date_i18n( 't', $timestamp );
219 | $this_month = getdate( $timestamp );
220 | $start_day = $this_month['wday'];
221 |
222 | // Loop through days of the month
223 | for ( $i = 0; $i < ( $max_day + $start_day ); $i++ ) {
224 |
225 | // New row
226 | if ( ( $i % 7 ) === 0 ) {
227 | $this->get_row_start();
228 | }
229 |
230 | // Pad day
231 | if ( $i < $start_day ) {
232 | $this->get_row_pad( $i, $start_day );
233 |
234 | // Month day
235 | } else {
236 | $this->get_row_cell( $i, $start_day );
237 | }
238 |
239 | if ( ( $i % 7 ) === 6 ) {
240 | $this->get_row_end();
241 | }
242 | }
243 | }
244 |
245 | /**
246 | * Paginate through months & years
247 | *
248 | * @since 0.1.0
249 | *
250 | * @param array $args
251 | */
252 | protected function pagination( $args = array() ) {
253 |
254 | // Parse args
255 | $r = wp_parse_args( $args, array(
256 | 'small' => '1 month',
257 | 'large' => '1 year',
258 | 'labels' => array(
259 | 'next_small' => esc_html__( 'Next Month', 'wp-event-calendar' ),
260 | 'next_large' => esc_html__( 'Next Year', 'wp-event-calendar' ),
261 | 'prev_small' => esc_html__( 'Previous Month', 'wp-event-calendar' ),
262 | 'prev_large' => esc_html__( 'Previous Year', 'wp-event-calendar' )
263 | )
264 | ) );
265 |
266 | // Return pagination
267 | return parent::pagination( $r );
268 | }
269 | }
270 |
--------------------------------------------------------------------------------
/wp-event-calendar/includes/events/capabilities.php:
--------------------------------------------------------------------------------
1 | post_type ) {
40 | $post = get_post( $post->post_parent );
41 | if ( ! $post ) {
42 | $caps[] = 'do_not_allow';
43 | break;
44 | }
45 | }
46 |
47 | // If the post author is set and the user is the author...
48 | if ( (int) $user_id === $post->post_author ) {
49 |
50 | // If the post is published or scheduled...
51 | if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) {
52 | $caps = array( 'delete_published_posts' );
53 |
54 | } elseif ( 'trash' === $post->post_status ) {
55 | $status = get_post_meta( $post->ID, '_wp_trash_meta_status', true );
56 |
57 | if ( in_array( $status, array( 'publish', 'future' ), true ) ) {
58 | $caps = array( 'delete_published_posts' );
59 | } else {
60 | $caps = array( 'delete_posts' );
61 | }
62 |
63 | // If the post is draft...
64 | } else {
65 | $caps = array( 'delete_posts' );
66 | }
67 |
68 | // The user is trying to edit someone else's post.
69 | } else {
70 | $caps = array( 'delete_others_posts' );
71 |
72 | // The post is published or scheduled, extra cap required.
73 | if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) {
74 | $caps = array( 'delete_published_posts' );
75 | } elseif ( 'private' === $post->post_status ) {
76 | $caps = array( 'delete_private_posts' );
77 | }
78 | }
79 | break;
80 |
81 | // Editing
82 | case 'edit_event' :
83 | $post = get_post( $args[0] );
84 | if ( empty( $post ) ) {
85 | $caps = array( 'do_not_allow' );
86 | break;
87 | }
88 |
89 | if ( 'revision' === $post->post_type ) {
90 | $post = get_post( $post->post_parent );
91 | if ( empty( $post ) ) {
92 | $caps = array( 'do_not_allow' );
93 | break;
94 | }
95 | }
96 |
97 | // If the post author is set and the user is the author...
98 | if ( (int) $user_id === (int) $post->post_author ) {
99 |
100 | // If the post is published or scheduled...
101 | if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) {
102 | $caps = array( 'edit_published_posts' );
103 |
104 | } elseif ( 'trash' === $post->post_status ) {
105 | $status = get_post_meta( $post->ID, '_wp_trash_meta_status', true );
106 |
107 | if ( in_array( $status, array( 'publish', 'future' ), true ) ) {
108 | $caps = array( 'edit_published_posts' );
109 | } else {
110 | $caps = array( 'edit_posts' );
111 | }
112 |
113 | // If the post is draft...
114 | } else {
115 | $caps = array( 'edit_posts' );
116 | }
117 |
118 | // The user is trying to edit someone else's post.
119 | } else {
120 | $caps = array( 'edit_others_posts' );
121 |
122 | // The post is published or scheduled, extra cap required.
123 | if ( in_array( $post->post_status, array( 'publish', 'future' ), true ) ) {
124 | $caps = array( 'edit_published_posts' );
125 | } elseif ( 'private' === $post->post_status ) {
126 | $caps = array( 'edit_private_posts' );
127 | }
128 | }
129 | break;
130 |
131 | // Reading
132 | case 'read_event' :
133 | $post = get_post( $args[0] );
134 | if ( empty( $post ) ) {
135 | $caps = array( 'do_not_allow' );
136 | break;
137 | }
138 |
139 | if ( 'revision' == $post->post_type ) {
140 | $post = get_post( $post->post_parent );
141 | if ( empty( $post ) ) {
142 | $caps = 'do_not_allow';
143 | break;
144 | }
145 | }
146 |
147 | $status_obj = get_post_status_object( $post->post_status );
148 | if ( true === $status_obj->public ) {
149 | $caps = array( 'read' );
150 | break;
151 | }
152 |
153 | if ( (int) $user_id === $post->post_author ) {
154 | $caps = array( 'read' );
155 | } elseif ( true === $status_obj->private ) {
156 | $caps = array( 'read_private_posts' );
157 | } else {
158 | $caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
159 | }
160 |
161 | break;
162 |
163 | // Remap
164 | case 'delete_events' :
165 | $caps = array( 'delete_posts' );
166 | break;
167 |
168 | case 'delete_others_events' :
169 | $caps = array( 'delete_others_events' );
170 | break;
171 |
172 | case 'create_events' :
173 | case 'edit_events' :
174 | case 'read_calendar' :
175 | $caps = array( 'edit_posts' );
176 | break;
177 |
178 | case 'edit_others_events' :
179 | $caps = array( 'edit_others_posts' );
180 | break;
181 |
182 | case 'publish_events' :
183 | $caps = array( 'publish_posts' );
184 | break;
185 | }
186 |
187 | return apply_filters( 'wp_event_calendar_meta_caps', $caps, $cap, $user_id, $args );
188 | }
189 |
190 | /**
191 | * Maps event type capabilities
192 | *
193 | * @since 0.1.4
194 | *
195 | * @param array $caps Capabilities for meta capability
196 | * @param string $cap Capability name
197 | * @param int $user_id User id
198 | * @param array $args Arguments
199 | *
200 | * @return array Actual capabilities for meta capability
201 | */
202 | function wp_event_calendar_type_meta_caps( $caps, $cap, $user_id, $args ) {
203 |
204 | // What capability is being checked?
205 | switch ( $cap ) {
206 | case 'manage_event_types' :
207 | case 'edit_event_types' :
208 | case 'delete_event_types' :
209 | case 'assign_event_types' :
210 | $caps = array( 'list_users' );
211 | break;
212 | }
213 |
214 | return apply_filters( 'wp_event_calendar_type_meta_caps', $caps, $cap, $user_id, $args );
215 | }
216 |
217 | /**
218 | * Maps event category capabilities
219 | *
220 | * @since 0.1.4
221 | *
222 | * @param array $caps Capabilities for meta capability
223 | * @param string $cap Capability name
224 | * @param int $user_id User id
225 | * @param array $args Arguments
226 | *
227 | * @return array Actual capabilities for meta capability
228 | */
229 | function wp_event_calendar_category_meta_caps( $caps, $cap, $user_id, $args ) {
230 |
231 | // What capability is being checked?
232 | switch ( $cap ) {
233 | case 'manage_event_categories' :
234 | case 'edit_event_categories' :
235 | case 'delete_event_categories' :
236 | case 'assign_event_categories' :
237 | $caps = array( 'list_users' );
238 | break;
239 | }
240 |
241 | return apply_filters( 'wp_event_calendar_category_meta_caps', $caps, $cap, $user_id, $args );
242 | }
243 |
244 | /**
245 | * Maps event tag capabilities
246 | *
247 | * @since 0.1.4
248 | *
249 | * @param array $caps Capabilities for meta capability
250 | * @param string $cap Capability name
251 | * @param int $user_id User id
252 | * @param array $args Arguments
253 | *
254 | * @return array Actual capabilities for meta capability
255 | */
256 | function wp_event_calendar_tag_meta_caps( $caps, $cap, $user_id, $args ) {
257 |
258 | // What capability is being checked?
259 | switch ( $cap ) {
260 | case 'manage_event_tags' :
261 | case 'edit_event_tags' :
262 | case 'delete_event_tags' :
263 | case 'assign_event_tags' :
264 | $caps = array( 'list_users' );
265 | break;
266 | }
267 |
268 | return apply_filters( 'wp_event_calendar_tag_meta_caps', $caps, $cap, $user_id, $args );
269 | }
270 |
--------------------------------------------------------------------------------
/wp-event-calendar/assets/css/datepicker.css:
--------------------------------------------------------------------------------
1 | /* Date Picker Default Styles */
2 | .ui-datepicker {
3 | padding: 0;
4 | margin: 0;
5 | -webkit-border-radius: 0;
6 | -moz-border-radius: 0;
7 | border-radius: 0;
8 | background-color: #fff;
9 | border: 1px solid #dfdfdf;
10 | border-top: none;
11 | -webkit-box-shadow: 0 3px 6px rgba(0, 0, 0, 0.075);
12 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.075);
13 | min-width: 17em;
14 | width: auto;
15 | z-index: 1000 !important;
16 | }
17 |
18 | .ui-datepicker * {
19 | padding: 0;
20 | font-family: "Open Sans", sans-serif;
21 | -webkit-border-radius: 0;
22 | -moz-border-radius: 0;
23 | border-radius: 0;
24 | }
25 |
26 | .ui-datepicker table {
27 | font-size: 13px;
28 | margin: 0;
29 | border: none;
30 | border-collapse: collapse;
31 | }
32 |
33 | .ui-datepicker .ui-widget-header,
34 | .ui-datepicker .ui-datepicker-header {
35 | background-image: none;
36 | border: none;
37 | color: #fff;
38 | font-weight: normal;
39 | }
40 |
41 | .ui-datepicker .ui-datepicker-header .ui-state-hover {
42 | background: transparent;
43 | border-color: transparent;
44 | cursor: pointer;
45 | }
46 |
47 | .ui-datepicker .ui-datepicker-title {
48 | margin: 0;
49 | padding: 10px 0;
50 | color: #fff;
51 | font-size: 14px;
52 | line-height: 14px;
53 | text-align: center;
54 | }
55 |
56 | .ui-datepicker .ui-datepicker-prev,
57 | .ui-datepicker .ui-datepicker-next {
58 | position: relative;
59 | top: 0;
60 | height: 34px;
61 | width: 34px;
62 | }
63 |
64 | .ui-datepicker .ui-state-hover.ui-datepicker-prev,
65 | .ui-datepicker .ui-state-hover.ui-datepicker-next {
66 | border: none;
67 | }
68 |
69 | .ui-datepicker .ui-datepicker-prev,
70 | .ui-datepicker .ui-datepicker-prev-hover {
71 | left: 0;
72 | }
73 |
74 | .ui-datepicker .ui-datepicker-next,
75 | .ui-datepicker .ui-datepicker-next-hover {
76 | right: 0;
77 | }
78 |
79 | .ui-datepicker .ui-datepicker-next span,
80 | .ui-datepicker .ui-datepicker-prev span {
81 | display: none;
82 | }
83 |
84 | .ui-datepicker .ui-datepicker-prev {
85 | float: left;
86 | }
87 |
88 | .ui-datepicker .ui-datepicker-next {
89 | float: right;
90 | }
91 |
92 | .ui-datepicker .ui-datepicker-prev:before,
93 | .ui-datepicker .ui-datepicker-next:before {
94 | font: normal 20px/34px 'dashicons';
95 | padding-left: 7px;
96 | color: #fff;
97 | speak: none;
98 | -webkit-font-smoothing: antialiased;
99 | -moz-osx-font-smoothing: grayscale;
100 | width: 34px;
101 | height: 34px;
102 | }
103 |
104 | .ui-datepicker .ui-datepicker-prev:before {
105 | content: '\f341';
106 | }
107 |
108 | .ui-datepicker .ui-datepicker-next:before {
109 | content: '\f345';
110 | }
111 |
112 | .ui-datepicker .ui-datepicker-prev-hover:before,
113 | .ui-datepicker .ui-datepicker-next-hover:before {
114 | opacity: 0.7;
115 | }
116 |
117 | .ui-datepicker select.ui-datepicker-month,
118 | .ui-datepicker select.ui-datepicker-year {
119 | width: 33%;
120 | }
121 |
122 | .ui-datepicker thead {
123 | color: #fff;
124 | font-weight: 600;
125 | }
126 |
127 | .ui-datepicker th {
128 | padding: 10px;
129 | }
130 |
131 | .ui-datepicker td {
132 | padding: 0;
133 | border: 1px solid #f4f4f4;
134 | }
135 |
136 | .ui-datepicker td.ui-datepicker-other-month {
137 | border: transparent;
138 | }
139 |
140 | .ui-datepicker td.ui-datepicker-week-end {
141 | background-color: #f4f4f4;
142 | border: 1px solid #f4f4f4;
143 | }
144 |
145 | .ui-datepicker td.ui-datepicker-today {
146 | background-color: #f0f0c0;
147 | }
148 |
149 | .ui-datepicker td.ui-datepicker-current-day {
150 | background: #bbdd88;
151 | }
152 |
153 | .ui-datepicker td .ui-state-default {
154 | background: transparent;
155 | border: none;
156 | text-align: center;
157 | text-decoration: none;
158 | width: auto;
159 | display: block;
160 | padding: 5px 10px;
161 | font-weight: normal;
162 | color: #444;
163 | }
164 |
165 | .ui-datepicker td.ui-state-disabled .ui-state-default {
166 | opacity: 0.5;
167 | }
168 |
169 | /* Default Color Scheme */
170 | .ui-datepicker .ui-widget-header,
171 | .ui-datepicker .ui-datepicker-header {
172 | background: #00a0d2;
173 | }
174 |
175 | .ui-datepicker thead {
176 | background: #32373c;
177 | }
178 |
179 | .ui-datepicker td .ui-state-hover {
180 | background: #0073aa;
181 | color: #fff;
182 | }
183 |
184 | /* WordPress Color Schemes */
185 |
186 | /* Fresh */
187 | .admin-color-fresh .ui-datepicker .ui-widget-header,
188 | .admin-color-fresh .ui-datepicker .ui-datepicker-header {
189 | background: #00a0d2;
190 | }
191 |
192 | .admin-color-fresh .ui-datepicker thead {
193 | background: #32373c;
194 | }
195 |
196 | .admin-color-fresh .ui-datepicker td .ui-state-hover {
197 | background: #0073aa;
198 | color: #fff;
199 | }
200 |
201 | /* Blue */
202 | .admin-color-blue .ui-datepicker .ui-widget-header,
203 | .admin-color-blue .ui-datepicker .ui-datepicker-header {
204 | background: #52accc;
205 | }
206 |
207 | .admin-color-blue .ui-datepicker thead {
208 | background: #4796b3;
209 | }
210 |
211 | .admin-color-blue .ui-datepicker td .ui-state-hover {
212 | background: #096484;
213 | color: #fff;
214 | }
215 |
216 | /* Coffee */
217 | .admin-color-coffee .ui-datepicker .ui-widget-header,
218 | .admin-color-coffee .ui-datepicker .ui-datepicker-header {
219 | background: #59524c;
220 | }
221 |
222 | .admin-color-coffee .ui-datepicker thead {
223 | background: #46403c;
224 | }
225 |
226 | .admin-color-coffee .ui-datepicker td .ui-state-hover {
227 | background: #c7a589;
228 | color: #fff;
229 | }
230 |
231 | /* Ectoplasm */
232 | .admin-color-ectoplasm .ui-datepicker .ui-widget-header,
233 | .admin-color-ectoplasm .ui-datepicker .ui-datepicker-header {
234 | background: #523f6d;
235 | }
236 |
237 | .admin-color-ectoplasm .ui-datepicker thead {
238 | background: #413256;
239 | }
240 |
241 | .admin-color-ectoplasm .ui-datepicker td .ui-state-hover {
242 | background: #a3b745;
243 | color: #fff;
244 | }
245 |
246 | /* Midnight */
247 | .admin-color-midnight .ui-datepicker .ui-widget-header,
248 | .admin-color-midnight .ui-datepicker .ui-datepicker-header {
249 | background: #363b3f;
250 | }
251 |
252 | .admin-color-midnight .ui-datepicker thead {
253 | background: #26292c;
254 | }
255 |
256 | .admin-color-midnight .ui-datepicker td .ui-state-hover {
257 | background: #e14d43;
258 | color: #fff;
259 | }
260 |
261 | /* Ocean */
262 | .admin-color-ocean .ui-datepicker .ui-widget-header,
263 | .admin-color-ocean .ui-datepicker .ui-datepicker-header {
264 | background: #738e96;
265 | }
266 |
267 | .admin-color-ocean .ui-datepicker thead {
268 | background: #627c83;
269 | }
270 |
271 | .admin-color-ocean .ui-datepicker td .ui-state-hover {
272 | background: #9ebaa0;
273 | color: #fff;
274 | }
275 |
276 | /* Sunrise */
277 | .admin-color-sunrise .ui-datepicker .ui-widget-header,
278 | .admin-color-sunrise .ui-datepicker .ui-datepicker-header,
279 | .admin-color-sunrise .ui-datepicker .ui-datepicker-header .ui-state-hover {
280 | background: #cf4944;
281 | }
282 |
283 | .admin-color-sunrise .ui-datepicker th {
284 | border-color: #be3631;
285 | background: #be3631;
286 | }
287 |
288 | .admin-color-sunrise .ui-datepicker td .ui-state-hover {
289 | background: #dd823b;
290 | color: #fff;
291 | }
292 |
293 | /* Light */
294 | .admin-color-light .ui-datepicker .ui-widget-header,
295 | .admin-color-light .ui-datepicker .ui-datepicker-header {
296 | background: #e5e5e5;
297 | }
298 |
299 | .admin-color-light .ui-datepicker thead {
300 | background: #888;
301 | }
302 |
303 | .admin-color-light .ui-datepicker .ui-datepicker-title,
304 | .admin-color-light .ui-datepicker td .ui-state-default,
305 | .admin-color-light .ui-datepicker .ui-datepicker-prev:before,
306 | .admin-color-light .ui-datepicker .ui-datepicker-next:before {
307 | color: #555;
308 | }
309 |
310 | .admin-color-light .ui-datepicker td .ui-state-hover {
311 | background: #e5e5e5;
312 | }
313 |
314 | /* bbPress Color Schemes */
315 |
316 | /* Evergreen */
317 | .admin-color-bbp-evergreen .ui-datepicker .ui-widget-header,
318 | .admin-color-bbp-evergreen .ui-datepicker .ui-datepicker-header {
319 | background: #56b274;
320 | }
321 |
322 | .admin-color-bbp-evergreen .ui-datepicker thead {
323 | background: #36533f;
324 | }
325 |
326 | .admin-color-bbp-evergreen .ui-datepicker td .ui-state-hover {
327 | background: #446950;
328 | color: #fff;
329 | }
330 |
331 | /* Mint */
332 | .admin-color-bbp-mint .ui-datepicker .ui-widget-header,
333 | .admin-color-bbp-mint .ui-datepicker .ui-datepicker-header {
334 | background: #4ca26a;
335 | }
336 |
337 | .admin-color-bbp-mint .ui-datepicker thead {
338 | background: #4f6d59;
339 | }
340 |
341 | .admin-color-bbp-mint .ui-datepicker td .ui-state-hover {
342 | background: #5fb37c;
343 | color: #fff;
344 | }
--------------------------------------------------------------------------------
/wp-event-calendar/includes/events/taxonomies.php:
--------------------------------------------------------------------------------
1 | __( 'Types', 'wp-event-calendar' ),
22 | 'singular_name' => __( 'Type', 'wp-event-calendar' ),
23 | 'search_items' => __( 'Search Types', 'wp-event-calendar' ),
24 | 'popular_items' => __( 'Popular Types', 'wp-event-calendar' ),
25 | 'all_items' => __( 'All Types', 'wp-event-calendar' ),
26 | 'parent_item' => __( 'Parent Type', 'wp-event-calendar' ),
27 | 'parent_item_colon' => __( 'Parent Type:', 'wp-event-calendar' ),
28 | 'edit_item' => __( 'Edit Type', 'wp-event-calendar' ),
29 | 'view_item' => __( 'View Type', 'wp-event-calendar' ),
30 | 'update_item' => __( 'Update Type', 'wp-event-calendar' ),
31 | 'add_new_item' => __( 'Add New Type', 'wp-event-calendar' ),
32 | 'new_item_name' => __( 'New Type Name', 'wp-event-calendar' ),
33 | 'separate_items_with_commas' => __( 'Separate types with commas', 'wp-event-calendar' ),
34 | 'add_or_remove_items' => __( 'Add or remove types', 'wp-event-calendar' ),
35 | 'choose_from_most_used' => __( 'Choose from the most used types', 'wp-event-calendar' ),
36 | 'no_terms' => __( 'No types', 'wp-event-calendar' ),
37 | 'not_found' => __( 'No types found', 'wp-event-calendar' ),
38 | 'items_list_navigation' => __( 'Types list navigation', 'wp-event-calendar' ),
39 | 'items_list' => __( 'Types list', 'wp-event-calendar' )
40 | );
41 |
42 | // Rewrite rules
43 | $rewrite = array(
44 | 'slug' => 'events/type',
45 | 'with_front' => false
46 | );
47 |
48 | // Capabilities
49 | $caps = array(
50 | 'manage_terms' => 'manage_event_types',
51 | 'edit_terms' => 'edit_event_types',
52 | 'delete_terms' => 'delete_event_types',
53 | 'assign_terms' => 'assign_event_types'
54 | );
55 |
56 | // Arguments
57 | $args = array(
58 | 'labels' => $labels,
59 | 'rewrite' => $rewrite,
60 | 'capabilities' => $caps,
61 | 'update_count_callback' => '_update_post_term_count',
62 | 'query_var' => 'event-type',
63 | 'show_tagcloud' => true,
64 | 'hierarchical' => false,
65 | 'show_in_nav_menus' => false,
66 | 'public' => false,
67 | 'show_ui' => true
68 | );
69 |
70 | // Register
71 | register_taxonomy( 'event-type', 'event', $args );
72 | }
73 |
74 | /**
75 | * Event category taxonomy
76 | *
77 | * @since 0.1.2
78 | */
79 | function wp_event_calendar_register_category_taxonomy() {
80 |
81 | // Labels
82 | $labels = array(
83 | 'name' => __( 'Categories', 'wp-event-calendar' ),
84 | 'singular_name' => __( 'Category', 'wp-event-calendar' ),
85 | 'search_items' => __( 'Search Categories', 'wp-event-calendar' ),
86 | 'popular_items' => __( 'Popular Categories', 'wp-event-calendar' ),
87 | 'all_items' => __( 'All Categories', 'wp-event-calendar' ),
88 | 'parent_item' => __( 'Parent Category', 'wp-event-calendar' ),
89 | 'parent_item_colon' => __( 'Parent Category:', 'wp-event-calendar' ),
90 | 'edit_item' => __( 'Edit Category', 'wp-event-calendar' ),
91 | 'view_item' => __( 'View Category', 'wp-event-calendar' ),
92 | 'update_item' => __( 'Update Category', 'wp-event-calendar' ),
93 | 'add_new_item' => __( 'Add New Category', 'wp-event-calendar' ),
94 | 'new_item_name' => __( 'New Category Name', 'wp-event-calendar' ),
95 | 'separate_items_with_commas' => __( 'Separate categories with commas', 'wp-event-calendar' ),
96 | 'add_or_remove_items' => __( 'Add or remove categories', 'wp-event-calendar' ),
97 | 'choose_from_most_used' => __( 'Choose from the most used categories', 'wp-event-calendar' ),
98 | 'no_terms' => __( 'No categories', 'wp-event-calendar' ),
99 | 'not_found' => __( 'No categories found', 'wp-event-calendar' ),
100 | 'items_list_navigation' => __( 'Categories list navigation', 'wp-event-calendar' ),
101 | 'items_list' => __( 'Categories list', 'wp-event-calendar' )
102 | );
103 |
104 | // Rewrite rules
105 | $rewrite = array(
106 | 'slug' => 'events/category',
107 | 'with_front' => false
108 | );
109 |
110 | // Capabilities
111 | $caps = array(
112 | 'manage_terms' => 'manage_event_categories',
113 | 'edit_terms' => 'edit_event_categories',
114 | 'delete_terms' => 'delete_event_categories',
115 | 'assign_terms' => 'assign_event_categories'
116 | );
117 |
118 | // Arguments
119 | $args = array(
120 | 'labels' => $labels,
121 | 'rewrite' => $rewrite,
122 | 'capabilities' => $caps,
123 | 'update_count_callback' => '_update_post_term_count',
124 | 'query_var' => 'event-category',
125 | 'show_tagcloud' => false,
126 | 'hierarchical' => true,
127 | 'show_in_nav_menus' => false,
128 | 'public' => false,
129 | 'show_ui' => true
130 | );
131 |
132 | // Register
133 | register_taxonomy( 'event-category', 'event', $args );
134 | }
135 |
136 | /**
137 | * Event tag taxonomy
138 | *
139 | * @since 0.1.2
140 | */
141 | function wp_event_calendar_register_tag_taxonomy() {
142 |
143 | // Labels
144 | $labels = array(
145 | 'name' => __( 'Tags', 'wp-event-calendar' ),
146 | 'singular_name' => __( 'Tag', 'wp-event-calendar' ),
147 | 'search_items' => __( 'Search Tags', 'wp-event-calendar' ),
148 | 'popular_items' => __( 'Popular Tags', 'wp-event-calendar' ),
149 | 'all_items' => __( 'All Tags', 'wp-event-calendar' ),
150 | 'parent_item' => __( 'Parent Tag', 'wp-event-calendar' ),
151 | 'parent_item_colon' => __( 'Parent Tag:', 'wp-event-calendar' ),
152 | 'edit_item' => __( 'Edit Tag', 'wp-event-calendar' ),
153 | 'view_item' => __( 'View Tag', 'wp-event-calendar' ),
154 | 'update_item' => __( 'Update Tag', 'wp-event-calendar' ),
155 | 'add_new_item' => __( 'Add New Tag', 'wp-event-calendar' ),
156 | 'new_item_name' => __( 'New Tag Name', 'wp-event-calendar' ),
157 | 'separate_items_with_commas' => __( 'Separate tags with commas', 'wp-event-calendar' ),
158 | 'add_or_remove_items' => __( 'Add or remove tags', 'wp-event-calendar' ),
159 | 'choose_from_most_used' => __( 'Choose from the most used tags', 'wp-event-calendar' ),
160 | 'no_terms' => __( 'No tags', 'wp-event-calendar' ),
161 | 'not_found' => __( 'No tags found', 'wp-event-calendar' ),
162 | 'items_list_navigation' => __( 'Tags list navigation', 'wp-event-calendar' ),
163 | 'items_list' => __( 'Tags list', 'wp-event-calendar' )
164 | );
165 |
166 | // Rewrite rules
167 | $rewrite = array(
168 | 'slug' => 'events/tag',
169 | 'with_front' => false
170 | );
171 |
172 | // Capabilities
173 | $caps = array(
174 | 'manage_terms' => 'manage_event_tags',
175 | 'edit_terms' => 'edit_event_tags',
176 | 'delete_terms' => 'delete_event_tags',
177 | 'assign_terms' => 'assign_event_tags'
178 | );
179 |
180 | // Arguments
181 | $args = array(
182 | 'labels' => $labels,
183 | 'rewrite' => $rewrite,
184 | 'capabilities' => $caps,
185 | 'update_count_callback' => '_update_post_term_count',
186 | 'query_var' => 'event-tag',
187 | 'show_tagcloud' => false,
188 | 'hierarchical' => false,
189 | 'show_in_nav_menus' => false,
190 | 'public' => false,
191 | 'show_ui' => true
192 | );
193 |
194 | // Register
195 | register_taxonomy( 'event-tag', 'event', $args );
196 | }
197 |
--------------------------------------------------------------------------------
/wp-event-calendar/includes/common/event.php:
--------------------------------------------------------------------------------
1 | 'CONFIRMED',
64 | 'EventCancelled' => 'CANCELLED',
65 | 'EventRescheduled' => 'CONFIRMED',
66 | 'EventPostponed' => 'TENTATIVE',
67 | );
68 |
69 | /**
70 | * @var string Where the event is happening
71 | *
72 | * @link http://schema.org/location
73 | */
74 | protected $location;
75 |
76 | /**
77 | * WP_Event_Calendar_Event constructor handles validating the data and
78 | * getting a handle on what the event is doing. This way we can echo the
79 | * object and have it render an ICS file
80 | *
81 | * @todo Can I do PHP primitive type checks here or object checks?
82 | * @todo Use PhysicalLocation to align with Schema.org - check if this is possible
83 | *
84 | * @param DateTime $start_date Start date in ISO-8601 date format
85 | * @param DateTime $end_date End date in ISO-8601 date format. If NULL it will assume an all day event
86 | * @param string $name Name of the event
87 | * @param string $description Description of the event possibly with event details
88 | * @param string $location Simple string of text describing the event location
89 | * @param int $repeat Repetition of the event
90 | * @param string $event_status Defaults to EventScheduled
91 | */
92 | public function __construct( $start_date = null, $end_date = null, $name = '', $description = '', $location = '', $repeat = 0, $event_status = 'EventScheduled' ) {
93 |
94 | // Check if start_date is instance of DateTime object
95 | if ( $start_date instanceof DateTime ) {
96 | $this->start_date = $start_date;
97 |
98 | // Assumes we are at least passing some date through
99 | } elseif ( ! empty( $start_date ) ) {
100 | $this->start_date = new DateTime( $start_date );
101 |
102 | // Bail if event has no start_date
103 | } else {
104 | return;
105 | }
106 |
107 | // If the end_date is null, this is an all_day event
108 | if ( is_null( $end_date ) ) {
109 | $this->start_date->setTime( 0, 0, 0 ); // Set to beginning of day (all day event)
110 | $this->end_date = clone $this->start_date;
111 | $this->end_date->setTime( 23, 59, 59 ); // EOD
112 | $this->all_day = true;
113 |
114 | // End date exists
115 | } elseif ( $end_date instanceof DateTime ) {
116 | $this->end_date = $end_date;
117 |
118 | // End dates are not required - if empty we want to skip added business logic
119 | } elseif ( empty( $end_date ) ) {
120 | $this->end_date = '';
121 |
122 | // Assumes we are passing some date through if getting here
123 | } else {
124 | $this->end_date = new DateTime( $end_date );
125 | }
126 |
127 | // Not doing anything with the rest of the properties for now
128 | $this->name = $name;
129 | $this->description = $description;
130 | $this->event_status = $event_status;
131 | $this->location = $location;
132 | $this->repeat = $repeat;
133 | }
134 |
135 | /**
136 | * This converts the Schema.org enumeration to the RFC spec
137 | *
138 | * @see https://tools.ietf.org/html/rfc5545#section-3.8.1.11
139 | * @see http://schema.org/EventStatusType
140 | *
141 | * @return string Event Status according to RFC5545
142 | */
143 | protected function event_status_to_rfc() {
144 |
145 | // Make sure the EventStatus is to spec
146 | if ( ! empty( $this->event_status_mapping[ $this->event_status ] ) ) {
147 | return $this->event_status_mapping[ $this->event_status ];
148 | }
149 |
150 | // Returning EventScheduled/CONFIRMED if spec does not match
151 | return $this->event_status_mapping[ 'EventScheduled' ];
152 | }
153 |
154 | /**
155 | * Formats the event date according to how the RFC specifies
156 | *
157 | * @see https://tools.ietf.org/html/rfc5545#section-3.3.5
158 | * @param $date DateTime Date to be formatted
159 | *
160 | * @return string date
161 | */
162 | protected function event_date_to_rfc( $date = '' ) {
163 |
164 | // @todo check WordPress UTC functions
165 | // @todo look at moving this conversion towards the constructor
166 | if ( empty( $date ) || ! ( $date instanceof DateTime ) ) {
167 | return '';
168 | }
169 |
170 | // 20160119T070000 - not sure about returning Z
171 | return $date->format( 'Ymd\THis' );
172 | }
173 |
174 | /**
175 | * Returns the event recurrence in accordance with the RFC
176 | *
177 | * @see https://tools.ietf.org/html/rfc5545#section-3.3.10
178 | *
179 | * @return string Frequency of repeated event
180 | */
181 | protected function event_recurrance_to_rfc() {
182 |
183 | // No recurrance by default
184 | $frequency = '';
185 |
186 | // Check how our event repeats
187 | switch ( $this->repeat ) {
188 | case 10:
189 | $frequency = 'FREQ=WEEKLY';
190 | break;
191 | case 100:
192 | $frequency = 'FREQ=MONTHLY';
193 | break;
194 | case 1000:
195 | $frequency = 'FREQ=YEARLY';
196 | break;
197 | }
198 |
199 | // Get the UNTIL portion if the frequency and end_date are not empty
200 | if ( ! empty( $frequency ) && ! empty( $this->end_date ) ) {
201 | $frequency .= ';UNTIL=' . $this->event_date_to_rfc( $this->end_date );
202 | }
203 |
204 | return $frequency;
205 | }
206 |
207 | /**
208 | * All of the array keys are VEVENT properties as part of the RFC. If
209 | * the property is empty() it will just be ignored in the end. They are
210 | * here to be filled in eventually and as a reminder that we can expand
211 | * our implementation of the spec.
212 | *
213 | * Note: Keeping them in the order of the RFC spec for now
214 | *
215 | * @return array Array of key/value pairs to match the RFC spec
216 | */
217 | protected function event_to_rfc() {
218 | return array(
219 |
220 | // Required
221 | 'dtstamp' => '', // required if using 'METHOD' - which we aren't
222 | 'dtstart' => $this->event_date_to_rfc( $this->start_date ), // the only real required property
223 |
224 | // Optional
225 | 'class' => '',
226 | 'created' => '',
227 | 'description' => $this->description,
228 | 'geo' => '',
229 | 'last-mod' => '',
230 | 'location' => $this->location,
231 | 'organizer' => '',
232 | 'priority' => '',
233 | 'seq' => '',
234 | 'status' => $this->event_status_to_rfc(),
235 | 'summary' => $this->name, // title of the event?
236 | 'transp' => '',
237 | 'url' => '',
238 | 'recurid' => '',
239 | 'rrule' => $this->event_recurrance_to_rfc(),
240 | 'dtend' => $this->event_date_to_rfc( $this->end_date ),
241 | 'duration' => '',
242 | 'attach' => '',
243 | 'attendee' => '',
244 | 'categories' => '',
245 | 'comment' => '',
246 | 'contact' => '',
247 | 'exdate' => '',
248 | 'rstatus' => '',
249 | 'related' => '',
250 | 'resources' => '',
251 | 'rdate' => '',
252 | 'x-prop' => '',
253 | 'iana-prop' => ''
254 | );
255 | }
256 |
257 | /**
258 | * The object will return an ICS VEVENT for use in an iCal. This formats the
259 | * object according to RFC5545.
260 | *
261 | * @see https://tools.ietf.org/html/rfc5545#section-3.6.1
262 | *
263 | * @return string ICS Formatted VEVENT
264 | */
265 | public function __toString() {
266 |
267 | // Get the event as an array of keys & values to match the RFC
268 | $vevent = $this->event_to_rfc();
269 |
270 | // Start going through the array and building the event
271 | $event = 'BEGIN:VEVENT' . PHP_EOL;
272 |
273 | foreach ( $vevent as $key => $value ) {
274 | if ( ! empty( $value ) ) {
275 | $event .= strtoupper( $key ) . ':' . $value . PHP_EOL;
276 | }
277 | }
278 |
279 | $event .= 'END:VEVENT' . PHP_EOL;
280 |
281 | return apply_filters( 'wp_event_calendar_event', $event, $vevent );
282 | }
283 | }
284 |
--------------------------------------------------------------------------------
/wp-event-calendar/includes/common/list-table-day.php:
--------------------------------------------------------------------------------
1 | day_start = strtotime( 'midnight', $this->today );
61 | $this->day_end = strtotime( 'tomorrow', $this->day_start );
62 |
63 | // Setup the day ranges
64 | $this->view_start = date_i18n( 'Y-m-d H:i:s', $this->day_start );
65 | $this->view_end = date_i18n( 'Y-m-d H:i:s', $this->day_end );
66 | }
67 |
68 | /**
69 | * Setup the list-table's columns
70 | *
71 | * @see WP_List_Table::single_row_columns()
72 | *
73 | * @return array An associative array containing column information
74 | */
75 | public function get_columns() {
76 |
77 | // Lowercase day, for column key
78 | $day = strtolower( date( 'l', $this->day_start ) );
79 |
80 | // Return Week & Day
81 | return array(
82 | 'hour' => sprintf( esc_html__( 'Wk. %s', 'wp-event-calendar' ), date_i18n( 'W', $this->today ) ),
83 | $day => date_i18n( 'l, F j, Y', $this->day_start ),
84 | );
85 | }
86 |
87 | /**
88 | * Get a list of CSS classes for the list table table tag.
89 | *
90 | * @since 0.1.8
91 | * @access protected
92 | *
93 | * @return array List of CSS classes for the table tag.
94 | */
95 | protected function get_table_classes() {
96 | return array( 'widefat', 'fixed', 'striped', 'calendar', 'day', $this->_args['plural'] );
97 | }
98 |
99 | /**
100 | * Add a post to the items array, keyed by day
101 | *
102 | * @todo Repeat & expire
103 | *
104 | * @since 0.1.8
105 | *
106 | * @param object $post
107 | * @param int $max
108 | */
109 | protected function setup_item( $post = false, $max = 10 ) {
110 |
111 | // Calculate start day
112 | if ( ! empty( $this->item_start ) ) {
113 | $start_day = date_i18n( 'j', $this->item_start );
114 | $start_hour = date_i18n( 'G', $this->item_start );
115 | } else {
116 | $start_day = 0;
117 | $start_hour = 0;
118 | }
119 |
120 | // Calculate end day
121 | if ( ! empty( $this->item_end ) ) {
122 | $end_day = date_i18n( 'j', $this->item_end );
123 | $end_hour = date_i18n( 'G', $this->item_end );
124 | } else {
125 | $end_day = $start_day;
126 | $end_hour = $start_hour;
127 | }
128 |
129 | // All day events (and days that overlap multiple days)
130 | if ( ( true === $this->item_all_day ) || ( $this->item_days > 1 ) || ( $start_day !== $end_day ) ) {
131 |
132 | // What type of item is this?
133 | $type = ( true === $this->item_all_day )
134 | ? 'all_day_items'
135 | : 'multi_day_items';
136 |
137 | // Math the heck out of this
138 | $interval = 1;
139 | $offset = 0;
140 | $cell = $offset;
141 | $end_cell = ( $end_day * $start_day ) + $offset;
142 |
143 | // Regular single-day events
144 | } else {
145 | $type = 'items';
146 | $interval = 1;
147 |
148 | // Calculate the cell offset
149 | $offset = intval( ( $this->item_start - $this->day_start ) / DAY_IN_SECONDS );
150 | $cell = ( $start_hour * $interval ) + $offset;
151 | $end_cell = ( $end_hour * $interval ) + $offset;
152 | }
153 |
154 | // Loop through days
155 | while ( $cell <= $end_cell ) {
156 |
157 | // Setup the pointer for each day
158 | $this->setup_pointer( $post, $cell );
159 |
160 | // Add post to items for each day in it's duration
161 | if ( empty( $this->{$type}[ $cell ] ) || ( $max > count( $this->{$type}[ $cell ] ) ) ) {
162 | $this->{$type}[ $cell ][ $post->ID ] = $post;
163 | }
164 |
165 | // Bump the hour
166 | $cell = intval( $cell + $interval );
167 | }
168 | }
169 |
170 | /**
171 | * Paginate through days & weeks
172 | *
173 | * @since 0.1.8
174 | *
175 | * @param array $args
176 | */
177 | protected function pagination( $args = array() ) {
178 |
179 | // Parse args
180 | $r = wp_parse_args( $args, array(
181 | 'small' => '1 day',
182 | 'large' => '1 week',
183 | 'labels' => array(
184 | 'next_small' => esc_html__( 'Tomorrow', 'wp-event-calendar' ),
185 | 'next_large' => esc_html__( 'Next Week', 'wp-event-calendar' ),
186 | 'prev_small' => esc_html__( 'Yerterday', 'wp-event-calendar' ),
187 | 'prev_large' => esc_html__( 'Previous Week', 'wp-event-calendar' )
188 | )
189 | ) );
190 |
191 | // Return pagination
192 | return parent::pagination( $r );
193 | }
194 |
195 | /**
196 | * Output a special row for "All Day" events
197 | *
198 | * @since 0.1.8
199 | */
200 | protected function get_all_day_row() {
201 |
202 | // Start an output buffer
203 | ob_start(); ?>
204 |
205 |
206 |
207 | get_day_row_cell( 0, 'all_day_items' ); ?>
208 |
209 |
210 |
225 |
226 |
227 |
228 | get_day_row_cell( 0, 'multi_day_items' ); ?>
229 |
230 |
231 |
246 |
247 |
248 | get_posts_for_cell( $iterator, $type ); ?>
249 |
250 |
251 |
279 |
280 |
281 |
282 |
297 |
298 |
299 |
300 |
315 |
316 |
317 |
318 | get_posts_for_cell( $iterator ); ?>
319 |
320 |
321 |
322 | month, $this->day, $this->year );
337 | $this_month = getdate( $timestamp );
338 | $start_day = $this_month['wday'];
339 |
340 | // All day events
341 | echo $this->get_all_day_row();
342 |
343 | // Multi day events
344 | echo $this->get_multi_day_row();
345 |
346 | // Loop through days of the month
347 | for ( $i = 0; $i <= ( 24 - 1 ); $i++ ) {
348 |
349 | // Get timestamp & hour
350 | $timestamp = mktime( $i, 0, 0, $this->month, $this->day, $this->year );
351 |
352 | // New row
353 | echo $this->get_row_start( $timestamp );
354 |
355 | // Get this table cell
356 | echo $this->get_row_cell( $i, $start_day );
357 |
358 | // Close row
359 | echo $this->get_row_end();
360 | }
361 | }
362 | }
363 |
--------------------------------------------------------------------------------
/wp-event-calendar/includes/common/list-table-week.php:
--------------------------------------------------------------------------------
1 | week_start = strtotime( $where_is_thumbkin, $this->today );
66 | $this->week_end = strtotime( 'this Saturday midnight', $this->today );
67 |
68 | // Setup the week ranges
69 | $this->view_start = date_i18n( 'Y-m-d H:i:s', $this->week_start );
70 | $this->view_end = date_i18n( 'Y-m-d H:i:s', $this->week_end );
71 | }
72 |
73 | /**
74 | * Setup the list-table's columns
75 | *
76 | * @see WP_List_Table::single_row_columns()
77 | *
78 | * @return array An associative array containing column information
79 | */
80 | public function get_columns() {
81 | return array(
82 | 'hour' => sprintf( esc_html__( 'Wk. %s', 'wp-event-calendar' ), date_i18n( 'W', $this->today ) ),
83 | 'sunday' => date_i18n( 'D, M. j', $this->week_start ),
84 | 'monday' => date_i18n( 'D, M. j', $this->week_start + ( DAY_IN_SECONDS * 1 ) ),
85 | 'tuesday' => date_i18n( 'D, M. j', $this->week_start + ( DAY_IN_SECONDS * 2 ) ),
86 | 'wednesday' => date_i18n( 'D, M. j', $this->week_start + ( DAY_IN_SECONDS * 3 ) ),
87 | 'thursday' => date_i18n( 'D, M. j', $this->week_start + ( DAY_IN_SECONDS * 4 ) ),
88 | 'friday' => date_i18n( 'D, M. j', $this->week_start + ( DAY_IN_SECONDS * 5 ) ),
89 | 'saturday' => date_i18n( 'D, M. j', $this->week_end )
90 | );
91 | }
92 |
93 | /**
94 | * Get a list of CSS classes for the list table table tag.
95 | *
96 | * @since 0.1.8
97 | * @access protected
98 | *
99 | * @return array List of CSS classes for the table tag.
100 | */
101 | protected function get_table_classes() {
102 | return array( 'widefat', 'fixed', 'striped', 'calendar', 'week', $this->_args['plural'] );
103 | }
104 |
105 | /**
106 | * Add a post to the items array, keyed by day
107 | *
108 | * @todo Repeat & expire
109 | *
110 | * @since 0.1.8
111 | *
112 | * @param object $post
113 | * @param int $max
114 | */
115 | protected function setup_item( $post = false, $max = 10 ) {
116 |
117 | // Calculate start day
118 | if ( ! empty( $this->item_start ) ) {
119 | $start_day = date_i18n( 'j', $this->item_start );
120 | $start_hour = date_i18n( 'G', $this->item_start );
121 | } else {
122 | $start_day = 0;
123 | $start_hour = 0;
124 | }
125 |
126 | // Calculate end day
127 | if ( ! empty( $this->item_end ) ) {
128 | $end_day = date_i18n( 'j', $this->item_end );
129 | $end_hour = date_i18n( 'G', $this->item_end );
130 | } else {
131 | $end_day = $start_day;
132 | $end_hour = $start_hour;
133 | }
134 |
135 | // All day events (and days that overlap multiple days)
136 | if ( ( true === $this->item_all_day ) || ( $this->item_days > 1 ) || ( $start_day !== $end_day ) ) {
137 |
138 | // What type of item is this?
139 | $type = ( true === $this->item_all_day )
140 | ? 'all_day_items'
141 | : 'multi_day_items';
142 |
143 | // Math the heck out of this
144 | $interval = 1;
145 | $offset = - ceil( ( $this->week_start - $this->item_start ) / DAY_IN_SECONDS );
146 | $cell = $offset;
147 | $end_cell = ( $end_day - $start_day ) + $offset;
148 |
149 | // Regular single-day events
150 | } else {
151 | $type = 'items';
152 | $interval = 7;
153 |
154 | // Calculate the cell offset
155 | $offset = intval( ( $this->item_start - $this->week_start ) / DAY_IN_SECONDS );
156 |
157 | // Start the days loop with the start day
158 | $cell = ( $start_hour * $interval ) + $offset;
159 |
160 | // Maybe don't include the end hour
161 | $end_cell = ( $end_hour * $interval ) + $offset;
162 | }
163 |
164 | // Loop through days
165 | while ( $cell <= $end_cell ) {
166 |
167 | // Setup the pointer for each day
168 | $this->setup_pointer( $post, $cell );
169 |
170 | // Add post to items for each day in it's duration
171 | if ( empty( $this->{$type}[ $cell ] ) || ( $max > count( $this->{$type}[ $cell ] ) ) ) {
172 | $this->{$type}[ $cell ][ $post->ID ] = $post;
173 | }
174 |
175 | // Bump the hour
176 | $cell = intval( $cell + $interval );
177 | }
178 | }
179 |
180 | /**
181 | * Paginate through months & years
182 | *
183 | * @since 0.1.8
184 | *
185 | * @param array $args
186 | */
187 | protected function pagination( $args = array() ) {
188 |
189 | // Parse args
190 | $r = wp_parse_args( $args, array(
191 | 'small' => '1 week',
192 | 'large' => '1 month',
193 | 'labels' => array(
194 | 'next_small' => esc_html__( 'Next Week', 'wp-event-calendar' ),
195 | 'next_large' => esc_html__( 'Next Month', 'wp-event-calendar' ),
196 | 'prev_small' => esc_html__( 'Previous Week', 'wp-event-calendar' ),
197 | 'prev_large' => esc_html__( 'Previous Month', 'wp-event-calendar' )
198 | )
199 | ) );
200 |
201 | // Return pagination
202 | return parent::pagination( $r );
203 | }
204 |
205 | /**
206 | * Start the week with a table row, and a th to show the time
207 | *
208 | * @since 0.1.8
209 | */
210 | protected function get_all_day_row() {
211 |
212 | // Items that last an entire day, maybe for multiple
213 | $type = 'all_day_items';
214 |
215 | // Start an output buffer
216 | ob_start(); ?>
217 |
218 |
219 |
220 | get_day_row_cell( 0, $type ); ?>
221 | get_day_row_cell( 1, $type ); ?>
222 | get_day_row_cell( 2, $type ); ?>
223 | get_day_row_cell( 3, $type ); ?>
224 | get_day_row_cell( 4, $type ); ?>
225 | get_day_row_cell( 5, $type ); ?>
226 | get_day_row_cell( 6, $type ); ?>
227 |
228 |
229 |
247 |
248 |
249 |
250 | get_day_row_cell( 0, $type ); ?>
251 | get_day_row_cell( 1, $type ); ?>
252 | get_day_row_cell( 2, $type ); ?>
253 | get_day_row_cell( 3, $type ); ?>
254 | get_day_row_cell( 4, $type ); ?>
255 | get_day_row_cell( 5, $type ); ?>
256 | get_day_row_cell( 6, $type ); ?>
257 |
258 |
259 |
274 |
275 |
276 | get_posts_for_cell( $iterator, $type ); ?>
277 |
278 |
279 |
307 |
308 |
309 |
310 |
325 |
326 |
327 |
328 |
343 |
344 |
345 |
346 | get_posts_for_cell( $iterator ); ?>
347 |
348 |
349 |
350 | month, $this->day, $this->year );
365 | $this_month = getdate( $timestamp );
366 | $start_day = $this_month['wday'];
367 |
368 | // All day events
369 | echo $this->get_all_day_row();
370 |
371 | // Multi day events
372 | echo $this->get_multi_day_row();
373 |
374 | // Loop through hours in days of week
375 | for ( $i = 0; $i <= ( 7 * 24 ) - 1; $i++ ) {
376 |
377 | // Get timestamp & hour
378 | $timestamp = mktime( ( $i / 7 ), 0, 0, $this->month, $this->day, $this->year );
379 |
380 | // New row
381 | if ( ( $i % 7 ) === 0 ) {
382 | echo $this->get_row_start( $timestamp );
383 | }
384 |
385 | // Get this table cell
386 | echo $this->get_row_cell( $i, $start_day );
387 |
388 | // Close row
389 | if ( ( $i % 7 ) === 6 ) {
390 | echo $this->get_row_end();
391 | }
392 | }
393 | }
394 | }
395 |
--------------------------------------------------------------------------------
/wp-event-calendar/includes/events/admin.php:
--------------------------------------------------------------------------------
1 | post_type ) {
26 | $title = esc_html__( 'Name this event', 'wp-event-calendar' );
27 | }
28 |
29 | // Return possibly modified title
30 | return $title;
31 | }
32 |
33 | /**
34 | * Disable months dropdown
35 | *
36 | * @since 0.1.2
37 | */
38 | function wp_event_calendar_disable_months_dropdown( $disabled = false, $post_type = 'post' ) {
39 |
40 | // Disable dropdown for events
41 | if ( 'event' === $post_type ) {
42 | $disabled = true;
43 | }
44 |
45 | // Return maybe modified value
46 | return $disabled;
47 | }
48 |
49 | /**
50 | * Output dropdowns & filters
51 | *
52 | * @since 0.1.2
53 | */
54 | function wp_event_calendar_add_dropdown_filters( $post_type = '' ) {
55 |
56 | // Bail if not the event post type
57 | if ( 'event' !== $post_type ) {
58 | return;
59 | }
60 |
61 | // Bail if event type taxonomy was unregistered
62 | if ( ! is_object_in_taxonomy( 'event', 'event-type' ) ) {
63 | return;
64 | }
65 |
66 | // Get registered taxonomies
67 | $taxonomies = get_object_taxonomies( 'event', 'objects' );
68 |
69 | // Loop through query vars
70 | foreach ( $taxonomies as $taxonomy ) {
71 |
72 | // Is this taxonomy being queried?
73 | $selected = isset( $_GET[ $taxonomy->query_var ] )
74 | ? sanitize_key( $_GET[ $taxonomy->query_var ] )
75 | : '';
76 |
77 | // Output label
78 | echo '' . sprintf( __( 'Filter by %s', 'wp-event-calendar' ), strtolower( $taxonomy->labels->singular_name ) ) . ' ';
79 |
80 | // Output dropdown
81 | wp_dropdown_categories( array(
82 | 'show_option_none' => $taxonomy->labels->all_items,
83 | 'option_none_value' => 0,
84 | 'hide_empty' => false,
85 | 'hierarchical' => false,
86 | 'taxonomy' => $taxonomy->name,
87 | 'show_count' => 0,
88 | 'orderby' => 'name',
89 | 'value_field' => 'slug',
90 | 'name' => $taxonomy->query_var,
91 | 'selected' => $selected
92 | ) );
93 | }
94 | }
95 |
96 | /**
97 | * Filter events posts list-table columns
98 | *
99 | * @since 0.1.2
100 | *
101 | * @param array $old_columns
102 | * @return array
103 | */
104 | function wp_event_calendar_manage_posts_columns( $old_columns = array() ) {
105 |
106 | // New columns
107 | $new_columns = array(
108 | 'cb' => ' ',
109 | 'title' => esc_html__( 'Event', 'wp-event-calendar' ),
110 | 'start' => esc_html__( 'Starts', 'wp-event-calendar' ),
111 | 'end' => esc_html__( 'Ends', 'wp-event-calendar' ),
112 | 'duration' => esc_html__( 'Duration', 'wp-event-calendar' ),
113 | 'repeat' => esc_html__( 'Repeats', 'wp-event-calendar' ),
114 | 'event-categories' => esc_html__( 'Categories', 'wp-event-calendar' ),
115 | 'event-types' => esc_html__( 'Types', 'wp-event-calendar' ),
116 | );
117 |
118 | // Filter & return
119 | return apply_filters( 'wp_event_calendar_manage_posts_columns', $new_columns, $old_columns );
120 | }
121 |
122 | /**
123 | * Sortable event columns
124 | *
125 | * @since 0.1.2
126 | *
127 | * @param array $columns
128 | *
129 | * @return array
130 | */
131 | function wp_event_calendar_sortable_columns( $columns = array() ) {
132 |
133 | // Override columns
134 | $columns = array(
135 | 'title' => 'title',
136 | 'start' => 'start_date',
137 | 'end' => 'end_date',
138 | 'repeat' => 'repeat'
139 | );
140 |
141 | return $columns;
142 | }
143 |
144 | /**
145 | * Set the relevant query vars for sorting posts by our front-end sortables.
146 | *
147 | * @since 0.1.6
148 | *
149 | * @param WP_Query $wp_query The current WP_Query object.
150 | */
151 | function wp_event_calendar_maybe_sort_by_fields( WP_Query $wp_query ) {
152 |
153 | // Bail if no post_type
154 | if ( empty( $wp_query->query['post_type'] ) ) {
155 | return;
156 | }
157 |
158 | // Bail if several post_type's
159 | if ( is_array( $wp_query->query['post_type'] ) ) {
160 | return;
161 | }
162 |
163 | // Bail if any post type
164 | if ( 'any' === $wp_query->query['post_type'] ) {
165 | return;
166 | }
167 |
168 | // Bail if single post type does not support events
169 | if ( ! post_type_supports( $wp_query->query['post_type'], 'events' ) ) {
170 | return;
171 | }
172 |
173 | // Bail in AJAX for now
174 | if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
175 | return;
176 | }
177 |
178 | // Some default order values
179 | $order = ! empty( $wp_query->query['order'] )
180 | ? strtoupper( $wp_query->query['order'] )
181 | : 'DESC';
182 |
183 | // Bail if no orderby
184 | if ( empty( $wp_query->query['orderby'] ) ) {
185 | return;
186 | }
187 |
188 | // Set by 'orderby'
189 | switch ( $wp_query->query['orderby'] ) {
190 |
191 | // Skip if title
192 | case 'title' :
193 | break;
194 |
195 | // End
196 | case 'repeat' :
197 | $wp_query->set( 'order', $order );
198 | $wp_query->set( 'orderby', 'meta_value' );
199 | $wp_query->set( 'meta_key', 'wp_event_calendar_repeat' );
200 | $wp_query->set( 'meta_type', 'NUMERIC' );
201 | break;
202 |
203 | // End
204 | case 'end_date' :
205 | $wp_query->set( 'order', $order );
206 | $wp_query->set( 'orderby', 'meta_value' );
207 | //$wp_query->set( 'meta_key', 'wp_event_calendar_end_date_time' );
208 | //$wp_query->set( 'meta_type', 'DATETIME' );
209 | break;
210 |
211 | // Start (default)
212 | case 'start_date' :
213 | default :
214 | $_GET['orderby'] = 'start_date';
215 | $wp_query->set( 'order', $order );
216 | $wp_query->set( 'orderby', 'meta_value' );
217 | //$wp_query->set( 'meta_key', 'wp_event_calendar_date_time' );
218 | //$wp_query->set( 'meta_type', 'DATETIME' );
219 | break;
220 | }
221 | }
222 |
223 | /**
224 | * Set the relevant query vars for filtering posts by our front-end filters.
225 | *
226 | * @since 0.1.0
227 | *
228 | * @param WP_Query $wp_query The current WP_Query object.
229 | */
230 | function wp_event_calendar_maybe_filter_by_fields( WP_Query $wp_query ) {
231 |
232 | // Bail if not 'event' post type
233 | if ( empty( $wp_query->query['post_type'] ) || ! in_array( 'event', (array) $wp_query->query['post_type'], true ) ) {
234 | return;
235 | }
236 |
237 | // Event statuses
238 | if ( ! empty( $_GET['post_status'] ) ) {
239 | $wp_query->post_status = sanitize_key( $_GET['post_status'] );
240 | }
241 |
242 | // Get taxonomies
243 | $taxonomies = get_object_taxonomies( 'event', 'objects' );
244 | $tax_query = array();
245 |
246 | // Loop through query vars
247 | foreach ( $taxonomies as $taxonomy ) {
248 |
249 | // Skip if not set
250 | if ( empty( $_GET[ $taxonomy->query_var ] ) ) {
251 | continue;
252 | }
253 |
254 | // Add to taxonomy query
255 | $tax_query[] = array(
256 | 'taxonomy' => $taxonomy->name,
257 | 'field' => 'slug',
258 | 'terms' => sanitize_key( $_GET[ $taxonomy->query_var ] )
259 | );
260 | }
261 |
262 | // Maybe set tax_query
263 | if ( ! empty( $tax_query ) ) {
264 | $wp_query->set( 'tax_query', $tax_query );
265 | }
266 | }
267 |
268 | /**
269 | * Output content for each event column
270 | *
271 | * @since 0.1.2
272 | *
273 | * @param string $column
274 | * @param int $post_id
275 | */
276 | function wp_event_calendar_manage_custom_column_data( $column = '', $post_id = 0 ) {
277 |
278 | // Get post & metadata
279 | $post = get_post( $post_id );
280 |
281 | // Custom column IDs
282 | switch ( $column ) {
283 |
284 | // Type
285 | case 'event-types' :
286 | echo wp_get_event_taxonomy_column_data( $post, 'event-type' );
287 | break;
288 |
289 | // Category
290 | case 'event-categories' :
291 | echo wp_get_event_taxonomy_column_data( $post, 'event-category' );
292 | break;
293 |
294 | // Starts
295 | case 'start' :
296 | echo wp_get_event_start_date_time( $post );
297 | break;
298 |
299 | // Ends
300 | case 'end' :
301 | echo wp_get_event_end_date_time( $post );
302 | break;
303 |
304 | // Duration
305 | case 'duration' :
306 | echo wp_get_event_duration( $post );
307 | break;
308 |
309 | // Repeat
310 | case 'repeat' :
311 | $repeat = get_post_meta( $post->ID, 'wp_event_calendar_repeat', true );
312 | switch( $repeat ) {
313 | case '1000' :
314 | esc_html_e( 'Yearly', 'wp-event-calendar' );
315 | break;
316 | case '100' :
317 | esc_html_e( 'Monthly', 'wp-event-calendar' );
318 | break;
319 | case '10' :
320 | esc_html_e( 'Weekly', 'wp-event-calendar' );
321 | break;
322 | case '0' :
323 | default :
324 | esc_html_e( 'Never', 'wp-event-calendar' );
325 | break;
326 | }
327 | break;
328 | }
329 | }
330 |
331 | /**
332 | * Helper function for getting column data for event taxonomies
333 | *
334 | * @since 0.1.5
335 | *
336 | * @param int $post
337 | * @param string $taxonomy
338 | * @return string
339 | */
340 | function wp_get_event_taxonomy_column_data( $post = false, $taxonomy = '' ) {
341 |
342 | // Get post & taxonomy
343 | $post = get_post( $post );
344 | $taxonomy_object = get_taxonomy( $taxonomy );
345 | $terms = get_the_terms( $post->ID, $taxonomy );
346 |
347 | // Event statuses
348 | $post_status = ! empty( $_GET['post_status'] )
349 | ? array( 'post_status' => sanitize_key( $_GET['post_status'] ) )
350 | : array( 'post_status' => 'all' );
351 |
352 | // Has terms
353 | if ( is_array( $terms ) ) {
354 | $out = array();
355 |
356 | // Loop through terms and create links
357 | foreach ( $terms as $t ) {
358 |
359 | // Reset default query variables
360 | $posts_in_term_qv = $post_status;
361 |
362 | // Set the post type
363 | if ( 'post' !== $post->post_type ) {
364 | $posts_in_term_qv['post_type'] = $post->post_type;
365 | }
366 |
367 | // Set the query variables
368 | if ( $taxonomy_object->query_var ) {
369 | $posts_in_term_qv[ $taxonomy_object->query_var ] = $t->slug;
370 | } else {
371 | $posts_in_term_qv['taxonomy'] = $taxonomy;
372 | $posts_in_term_qv['term'] = $t->slug;
373 | }
374 |
375 | // Add the term to array of links
376 | $out[] = sprintf( '%s ',
377 | esc_url( add_query_arg( $posts_in_term_qv, 'edit.php' ) ),
378 | esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) )
379 | );
380 | }
381 |
382 | /* translators: used between list items, there is a space after the comma */
383 | $retval = join( __( ', ', 'wp-event-calendar' ), $out );
384 |
385 | // No terms
386 | } else {
387 | $retval = '— ' . esc_html( $taxonomy_object->labels->no_terms ) . ' ';
388 | }
389 |
390 | return apply_filters( 'wp_event_calendar_taxonomy_column_data', $retval, $post, $taxonomy );
391 | }
392 |
393 | /**
394 | * Enqueue scripts
395 | *
396 | * @since 0.1.0
397 | */
398 | function wp_event_calendar_admin_event_assets() {
399 |
400 | // Bail if not an event post type
401 | if ( ! post_type_supports( get_post_type(), 'events' ) ) {
402 | return;
403 | }
404 |
405 | // Enqueue the date picker
406 | wp_enqueue_script( 'jquery-ui-datepicker' );
407 |
408 | $url = wp_event_calendar_get_plugin_url();
409 | $ver = wp_event_calendar_get_asset_version();
410 |
411 | // Date picker CSS (for jQuery UI calendar)
412 | wp_enqueue_style( 'wp_event_calendar_datepicker', $url . 'assets/css/datepicker.css', false, $ver, false );
413 |
414 | // Datepicker & event JS
415 | wp_enqueue_script( 'wp_event_calendar_all_event', $url . 'assets/js/event.js', array( 'jquery' ), $ver, true );
416 | }
417 |
418 | /**
419 | * Hides the inline-edit-group from the admin form
420 | *
421 | * @since 0.4.1
422 | */
423 | function wp_event_calendar_hide_quick_bulk_edit() {
424 |
425 | // Bail if not an event post type
426 | if ( ! post_type_supports( get_post_type(), 'events' ) ) {
427 | return;
428 | }
429 |
430 | ?>
431 |
439 | esc_html__( 'Close', 'wp-event-calendar' ),
59 | ) );
60 | }
61 |
62 | /**
63 | * This tells WordPress to highlight the Events > Calendar submenu.
64 | *
65 | * @since 0.1.0
66 | *
67 | * @global string $plugin_page
68 | * @global array $submenu
69 | */
70 | function wp_event_calendar_admin_submenu_highlight() {
71 | global $plugin_page, $submenu_file;
72 |
73 | // Highlight both, since they're the same thing.
74 | if ( in_array( $plugin_page, array( 'event-calendar', 'event_page_calendar' ) ) ) {
75 | $submenu_file = $plugin_page;
76 | }
77 | }
78 |
79 | /**
80 | * Admin screen options
81 | *
82 | * @since 0.1.0
83 | */
84 | function wp_event_calendar_admin_add_screen_options() {
85 |
86 | // columns screen option
87 | add_screen_option( 'layout_type', array(
88 | 'label' => _x( 'Layout', 'Month, Week, or Day (screen options)', 'wp-event-calendar' ),
89 | 'default' => 'month',
90 | 'option' => 'calendar_layout'
91 | ) );
92 |
93 | // Events per day
94 | add_screen_option( 'per_page', array(
95 | 'label' => _x( 'Events per day', 'Events per day (screen options)', 'wp-event-calendar' ),
96 | 'default' => 10,
97 | 'option' => 'edit_calendar_per_day'
98 | ) );
99 | }
100 |
101 | /**
102 | * Admin help tabs
103 | *
104 | * @since 0.1.0
105 | */
106 | function wp_event_calendar_admin_add_help_tabs() {
107 |
108 | // Bail if not an Event type screen
109 | if ( 'event' !== get_current_screen()->post_type ) {
110 | return;
111 | }
112 |
113 | // Bail if viewing a taxonomy
114 | if ( get_current_screen()->taxonomy ) {
115 | return;
116 | }
117 |
118 | // Calendar
119 | get_current_screen()->add_help_tab( array(
120 | 'id' => 'calendar',
121 | 'title' => esc_html__( 'Calendar', 'wp-event-calendar' ),
122 | 'content' =>
123 | '' . esc_html__( 'This is a calendar that lays out your content chronologically.', 'wp-event-calendar' ) . '
' .
124 | '' . esc_html__( 'You can view events in month and week modes.', 'wp-event-calendar' ) . ' ' .
125 | '' . esc_html__( 'Clicking an event shows a snapshot of the event for that period.', 'wp-event-calendar' ) . ' ' .
126 | '' . esc_html__( 'Events may have icons and styling to differentiate them.', 'wp-event-calendar' ) . ' ' .
127 |
128 | '' . esc_html__( 'Events', 'wp-event-calendar' ) . '
' .
129 | '' . esc_html__( 'Most events are single-day, for a few hours.', 'wp-event-calendar' ) . ' ' .
130 | '' . esc_html__( 'Location data can be attached.', 'wp-event-calendar' ) . ' ' .
131 | '' . esc_html__( 'Some events span multiple days, or have intervals.', 'wp-event-calendar' ) . ' ' .
132 | '' . esc_html__( 'Organize events with types, categories, & tags.', 'wp-event-calendar' ) . ' ' ) );
133 |
134 | // Month View
135 | get_current_screen()->add_help_tab( array(
136 | 'id' => 'month',
137 | 'title' => esc_html__( '— Month', 'wp-event-calendar' ),
138 | 'content' =>
139 | '' . esc_html__( 'This is a traditional monthly calendar view.', 'wp-event-calendar' ) . '
' .
140 | '' . esc_html__( 'Events are listed chronologically in each day.', 'wp-event-calendar' ) . ' ' .
141 | '' . esc_html__( 'Events may happen over several days.', 'wp-event-calendar' ) . ' ' .
142 | '' . esc_html__( 'Events may repeat in daily, weekly, or yearly intervals.', 'wp-event-calendar' ) . ' ' .
143 |
144 | '' . esc_html__( 'Navigation', 'wp-event-calendar' ) . '
' .
145 | '' . esc_html__( 'View specific months & years via the dropdown on the left.', 'wp-event-calendar' ) . ' ' .
146 | '' . esc_html__( 'Paginate through years with double-arrow buttons.', 'wp-event-calendar' ) . ' ' .
147 | '' . esc_html__( 'Paginate through months with single-arrow buttons.', 'wp-event-calendar' ) . ' ' .
148 | '' . esc_html__( 'Return to today with the double-colon button.', 'wp-event-calendar' ) . ' '
149 | ) );
150 |
151 | // Month View
152 | get_current_screen()->add_help_tab( array(
153 | 'id' => 'week',
154 | 'title' => __( '— Week', 'wp-event-calendar' ),
155 | 'content' =>
156 | '' . esc_html__( 'This is a traditional weekly calendar view.', 'wp-event-calendar' ) . '
' .
157 | '' . esc_html__( 'Events are listed chronologically in each day.', 'wp-event-calendar' ) . ' ' .
158 | '' . esc_html__( 'Events spanning more than 1 day are omitted.', 'wp-event-calendar' ) . ' ' .
159 | '' . esc_html__( 'All-day events appear in the top row.', 'wp-event-calendar' ) . ' ' .
160 |
161 | '' . esc_html__( 'Navigation', 'wp-event-calendar' ) . '
' .
162 | '' . esc_html__( 'View specific months & years via the dropdown on the left.', 'wp-event-calendar' ) . ' ' .
163 | '' . esc_html__( 'Paginate through months with double-arrow buttons.', 'wp-event-calendar' ) . ' ' .
164 | '' . esc_html__( 'Paginate through weeks with single-arrow buttons.', 'wp-event-calendar' ) . ' ' .
165 | '' . esc_html__( 'Return to today with the double-colon button.', 'wp-event-calendar' ) . ' '
166 | ) );
167 |
168 | // Month View
169 | get_current_screen()->add_help_tab( array(
170 | 'id' => 'day',
171 | 'title' => __( '— Day', 'wp-event-calendar' ),
172 | 'content' =>
173 | '' . esc_html__( 'This is a traditional daily calendar view.', 'wp-event-calendar' ) . '
' .
174 | '' . esc_html__( 'Events are listed chronologically for the day.', 'wp-event-calendar' ) . ' ' .
175 | '' . esc_html__( 'Events spanning more than 1 day are shown.', 'wp-event-calendar' ) . ' ' .
176 | '' . esc_html__( 'All-day events appear in the top row.', 'wp-event-calendar' ) . ' ' .
177 |
178 | '' . esc_html__( 'Navigation', 'wp-event-calendar' ) . '
' .
179 | '' . esc_html__( 'View specific months & years via the dropdown on the left.', 'wp-event-calendar' ) . ' ' .
180 | '' . esc_html__( 'Paginate through weeks with double-arrow buttons.', 'wp-event-calendar' ) . ' ' .
181 | '' . esc_html__( 'Paginate through days with single-arrow buttons.', 'wp-event-calendar' ) . ' ' .
182 | '' . esc_html__( 'Return to today with the double-colon button.', 'wp-event-calendar' ) . ' '
183 | ) );
184 |
185 | // Help Sidebar
186 | get_current_screen()->set_help_sidebar(
187 | ' ' . esc_html__( 'Regular Event', 'wp-event-calendar' ) . '
' .
188 | ' ' . esc_html__( 'Has Location', 'wp-event-calendar' ) . '
' .
189 | ' ' . esc_html__( 'All Day', 'wp-event-calendar' ) . '
' .
190 | ' ' . esc_html__( 'Recurring', 'wp-event-calendar' ) . '
' .
191 | ' ' . esc_html__( 'Trashed', 'wp-event-calendar' ) . '
' .
192 | ' ' . esc_html__( 'Private', 'wp-event-calendar' ) . '
' .
193 | ' ' . esc_html__( 'Protected', 'wp-event-calendar' ) . '
'
194 | );
195 | }
196 |
197 | /**
198 | * Reorder "Events" submenu items to reprioritize "Calendar"
199 | *
200 | * @since 0.1.0
201 | *
202 | * @param array $menu_order
203 | *
204 | * @return array
205 | */
206 | function wp_event_calendar_change_menu_order( $menu_order = array() ) {
207 | global $submenu;
208 |
209 | // Setup a bunch of empty arrays
210 | $neighbors = $calendar_menus = $calendar_submenus = array();
211 |
212 | // Get allowed post types
213 | $allowed_types = wp_event_calendar_allowed_post_types();
214 |
215 | // Loop through allowed types
216 | foreach ( $allowed_types as $type ) {
217 |
218 | // Find "All" links
219 | if ( 'post' === $type ) {
220 | $pt = 'edit.php';
221 | } else {
222 | $pt = 'edit.php?post_type=' . $type;
223 | }
224 |
225 | $neighbors[] = $pt;
226 |
227 | // Custom menus
228 | $calendar_menus[] = $type . '-calendar';
229 |
230 | // The calendar submenu arrays
231 | $calendar_submenus[ $pt ] = array(
232 | esc_html__( 'Calendar', 'wp-event-calendar' ),
233 | 'read_calendar',
234 | $type . '-calendar',
235 | esc_html__( 'Calendar', 'wp-event-calendar' ),
236 | );
237 | }
238 |
239 | // Loop through menu order and do some rearranging
240 | foreach ( $submenu as $parent => $children ) {
241 |
242 | // Skip if no neighborly match
243 | if ( in_array( $parent, $neighbors ) ) {
244 | foreach ( $children as $child => $menu ) {
245 |
246 | // Found a neighbor
247 | if ( in_array( $menu[2], $neighbors ) ) {
248 | unset( $submenu[ $parent ][ $child ] );
249 |
250 | $submenu[ $parent ][ $child ] = $menu;
251 | $submenu[ $parent ][9] = $calendar_submenus[ $parent ];
252 | } elseif ( in_array( $menu[2], $calendar_menus ) ) {
253 | unset( $submenu[ $parent ][ $child ] );
254 | }
255 | }
256 |
257 | ksort( $submenu[ $parent ] );
258 | }
259 | }
260 |
261 | // Always return the menu order
262 | return $menu_order;
263 | }
264 |
265 | /**
266 | * Output the admin calendar
267 | *
268 | * @since 0.1.0
269 | */
270 | function wp_event_calendar_show_admin_calendar() {
271 |
272 | // Get the post type for easy caps checking
273 | $post_type = wp_event_calendar_get_admin_post_type();
274 | $post_type_object = get_post_type_object( $post_type );
275 | $user_id = get_current_user_id();
276 |
277 | // Check for new mode
278 | if ( ! empty( $_REQUEST['mode'] ) ) {
279 | if ( in_array( $_REQUEST['mode'], array( 'month', 'week', 'day' ) ) ) {
280 | $mode = $_REQUEST['mode'];
281 | }
282 | update_user_option( $user_id, 'event_calendar_mode', $mode );
283 |
284 | // Use existing mode
285 | } else {
286 | $mode = get_user_option( 'event_calendar_mode', $user_id );
287 | }
288 |
289 | // Load the list table based on the mode
290 | switch ( $mode ) {
291 | case 'day' :
292 | $wp_list_table = new WP_Event_Calendar_Day_Table();
293 | break;
294 | case 'week' :
295 | $wp_list_table = new WP_Event_Calendar_Week_Table();
296 | break;
297 | case 'month' :
298 | default :
299 | $wp_list_table = new WP_Event_Calendar_Month_Table();
300 | break;
301 | }
302 |
303 | // Query for calendar content
304 | $wp_list_table->prepare_items();
305 |
306 | // Set the help tabs
307 | $wp_list_table->set_help_tabs(); ?>
308 |
309 |
310 |
311 | cap->create_posts ) ) : ?>
312 |
313 |
314 |
315 |
316 | views(); ?>
317 |
318 |
328 |
329 |
330 |
331 |
332 |
333 | true ) );
27 | $types = array_keys( $supports );
28 |
29 | // Filter & return
30 | return apply_filters( 'wp_event_calendar_allowed_post_types', $types, $supports );
31 | }
32 |
33 | /**
34 | * Get the current admin post type
35 | *
36 | * @since 0.1.0
37 | *
38 | * @return string
39 | */
40 | function wp_event_calendar_get_admin_post_type() {
41 |
42 | // Use $typenow global if it's not empty
43 | if ( ! empty( $GLOBALS['typenow'] ) ) {
44 | return $GLOBALS['typenow'];
45 | }
46 |
47 | // Use $GET post_type if it's not empty
48 | if ( ! empty( $_GET['post_type'] ) ) {
49 | return wp_unslash( $_GET['post_type'] );
50 | }
51 |
52 | // Use get parameter
53 | return 'post';
54 | }
55 |
56 |
57 | /**
58 | * Get a human readable representation of the time elapsed since a given date.
59 | *
60 | * Based on function created by Dunstan Orchard - http://1976design.com
61 | *
62 | * This function will return a read representation of the time elapsed
63 | * since a given date.
64 | * eg: 2 hours and 50 minutes
65 | * eg: 4 days
66 | * eg: 4 weeks and 6 days
67 | *
68 | * Note that fractions of minutes are not represented in the return string. So
69 | * an interval of 3 minutes will be represented by "3 minutes", as will an
70 | * interval of 3 minutes 59 seconds.
71 | *
72 | * @param int|string $older_date The earlier time from which you're calculating
73 | * the time elapsed. Enter either as an integer Unix timestamp,
74 | * or as a date string of the format 'Y-m-d h:i:s'.
75 | * @param int|bool $newer_date Optional. Unix timestamp of date to compare older
76 | * date to. Default: false (current time).
77 | *
78 | * @return string String representing the time since the older date, eg
79 | * "2 hours and 50 minutes".
80 | */
81 | function wp_event_calendar_human_diff_time( $older_date, $newer_date = false ) {
82 |
83 | // Format
84 | if ( ! is_numeric( $older_date ) ) {
85 | $older_date = strtotime( $older_date );
86 | }
87 |
88 | if ( ! is_numeric( $newer_date ) ) {
89 | $newer_date = strtotime( $newer_date );
90 | }
91 |
92 | // Catch issues with flipped old vs. new dates
93 | $flipped = false;
94 |
95 | // array of time period chunks
96 | $chunks = array(
97 | YEAR_IN_SECONDS,
98 | 30 * DAY_IN_SECONDS,
99 | WEEK_IN_SECONDS,
100 | DAY_IN_SECONDS,
101 | HOUR_IN_SECONDS,
102 | MINUTE_IN_SECONDS,
103 | 1
104 | );
105 |
106 | if ( ! empty( $older_date ) && ! is_numeric( $older_date ) ) {
107 | $time_chunks = explode( ':', str_replace( ' ', ':', $older_date ) );
108 | $date_chunks = explode( '-', str_replace( ' ', '-', $older_date ) );
109 | $older_date = gmmktime( (int) $time_chunks[1], (int) $time_chunks[2], (int) $time_chunks[3], (int) $date_chunks[1], (int) $date_chunks[2], (int) $date_chunks[0] );
110 | }
111 |
112 | /**
113 | * $newer_date will equal false if we want to know the time elapsed between
114 | * a date and the current time. $newer_date will have a value if we want to
115 | * work out time elapsed between two known dates.
116 | */
117 | $newer_date = empty( $newer_date )
118 | ? current_time( 'timestamp' )
119 | : $newer_date;
120 |
121 | // Difference in seconds
122 | $since = $newer_date - $older_date;
123 |
124 | // Flipped
125 | if ( $since < 0 ) {
126 | $flipped = true;
127 | $since = $older_date - $newer_date;
128 | }
129 |
130 | // Step one: the first chunk
131 | for ( $i = 0, $j = count( $chunks ); $i < $j; ++$i ) {
132 | $seconds = $chunks[$i];
133 |
134 | // Finding the biggest chunk (if the chunk fits, break)
135 | $count = floor( $since / $seconds );
136 | if ( 0 != $count ) {
137 | break;
138 | }
139 | }
140 |
141 | // Set output var
142 | switch ( $seconds ) {
143 | case YEAR_IN_SECONDS :
144 | $output = sprintf( _n( '%s year', '%s years', $count, 'wp-event-calendar' ), $count );
145 | break;
146 | case 30 * DAY_IN_SECONDS :
147 | $output = sprintf( _n( '%s month', '%s months', $count, 'wp-event-calendar' ), $count );
148 | break;
149 | case WEEK_IN_SECONDS :
150 | $output = sprintf( _n( '%s week', '%s weeks', $count, 'wp-event-calendar' ), $count );
151 | break;
152 | case DAY_IN_SECONDS :
153 | $output = sprintf( _n( '%s day', '%s days', $count, 'wp-event-calendar' ), $count );
154 | break;
155 | case HOUR_IN_SECONDS :
156 | $output = sprintf( _n( '%s hour', '%s hours', $count, 'wp-event-calendar' ), $count );
157 | break;
158 | case MINUTE_IN_SECONDS :
159 | $output = sprintf( _n( '%s minute', '%s minutes', $count, 'wp-event-calendar' ), $count );
160 | break;
161 | default:
162 | $output = sprintf( _n( '%s second', '%s seconds', $count, 'wp-event-calendar' ), $count );
163 | }
164 |
165 | // Step two: the second chunk
166 | // A quirk in the implementation means that this
167 | // condition fails in the case of minutes and seconds.
168 | // We've left the quirk in place, since fractions of a
169 | // minute are not a useful piece of information for our
170 | // purposes
171 | if ( $i + 2 < $j ) {
172 | $seconds2 = $chunks[$i + 1];
173 | $count2 = floor( ( $since - ( $seconds * $count ) ) / $seconds2 );
174 |
175 | // Add to output var
176 | if ( 0 != $count2 ) {
177 | $output .= _x( ',', 'Separator in time since', 'wp-event-calendar' ) . ' ';
178 |
179 | switch ( $seconds2 ) {
180 | case 30 * DAY_IN_SECONDS :
181 | $output .= sprintf( _n( '%s month', '%s months', $count2, 'wp-event-calendar' ), $count2 );
182 | break;
183 | case WEEK_IN_SECONDS :
184 | $output .= sprintf( _n( '%s week', '%s weeks', $count2, 'wp-event-calendar' ), $count2 );
185 | break;
186 | case DAY_IN_SECONDS :
187 | $output .= sprintf( _n( '%s day', '%s days', $count2, 'wp-event-calendar' ), $count2 );
188 | break;
189 | case HOUR_IN_SECONDS :
190 | $output .= sprintf( _n( '%s hour', '%s hours', $count2, 'wp-event-calendar' ), $count2 );
191 | break;
192 | case MINUTE_IN_SECONDS :
193 | $output .= sprintf( _n( '%s minute', '%s minutes', $count2, 'wp-event-calendar' ), $count2 );
194 | break;
195 | default:
196 | $output .= sprintf( _n( '%s second', '%s seconds', $count2, 'wp-event-calendar' ), $count2 );
197 | }
198 | }
199 | }
200 |
201 | if ( true === $flipped ) {
202 | $output = '-' . $output;
203 | }
204 |
205 | /**
206 | * Filters the human readable representation of the time elapsed since a
207 | * given date.
208 | *
209 | * @since 0.1.2
210 | *
211 | * @param string $output Final string
212 | * @param string $older_date Earlier time from which we're calculating time elapsed
213 | * @param string $newer_date Unix timestamp of date to compare older time to
214 | */
215 | return apply_filters( 'wp_event_calendar_human_diff_time', $output, $older_date, $newer_date );
216 | }
217 |
218 | /**
219 | * Return the start date & time of an event
220 | *
221 | * @since 0.1.5
222 | *
223 | * @param mixed $post
224 | *
225 | * @return string
226 | */
227 | function wp_get_event_start_date_time( $post = false ) {
228 |
229 | // Get the post object & start date
230 | $post = get_post( $post );
231 | $date = get_post_meta( $post->ID, 'wp_event_calendar_date_time', true );
232 | $all_day = get_post_meta( $post->ID, 'wp_event_calendar_all_day', true );
233 |
234 | // Start an output buffer
235 | ob_start();
236 |
237 | if ( ! empty( $date ) ) {
238 | $date = strtotime( $date );
239 | $df = get_option( 'date_format' );
240 | $tf = get_option( 'time_format' );
241 |
242 | echo date_i18n( $df, $date );
243 |
244 | // Time
245 | if ( empty( $all_day ) ) {
246 | echo ' '. date_i18n( $tf, $date );
247 | }
248 |
249 | // No start date
250 | } else {
251 | echo '—';
252 | }
253 |
254 | // Get the output buffer
255 | $retval = ob_get_clean();
256 |
257 | // Filter & return
258 | return apply_filters( 'wp_get_event_start_date_time', $retval, $post, $date );
259 | }
260 |
261 | /**
262 | * Return the end date & time of an event
263 | *
264 | * @since 0.1.5
265 | *
266 | * @param mixed $post
267 | *
268 | * @return string
269 | */
270 | function wp_get_event_end_date_time( $post = false ) {
271 |
272 | // Get the post object & start date
273 | $post = get_post( $post );
274 | $date = get_post_meta( $post->ID, 'wp_event_calendar_end_date_time', true );
275 | $all_day = get_post_meta( $post->ID, 'wp_event_calendar_all_day', true );
276 |
277 | // Start an output buffer
278 | ob_start();
279 |
280 | if ( ! empty( $date ) ) {
281 | $date = strtotime( $date );
282 | $df = get_option( 'date_format' );
283 | $tf = get_option( 'time_format' );
284 |
285 | echo date_i18n( $df, $date );
286 |
287 | // Time
288 | if ( empty( $all_day ) ) {
289 | echo ' '. date_i18n( $tf, $date );
290 | }
291 |
292 | } else {
293 | echo '—';
294 | }
295 |
296 | // Get the output buffer
297 | $retval = ob_get_clean();
298 |
299 | // Filter & return
300 | return apply_filters( 'wp_get_event_end_date_time', $retval, $post, $date );
301 | }
302 |
303 | /**
304 | * Return the duration of an event
305 | *
306 | * @since 0.1.5
307 | *
308 | * @param mixed $post
309 | *
310 | * @return string
311 | */
312 | function wp_get_event_duration( $post = false ) {
313 |
314 | // Get the post object & start date
315 | $post = get_post( $post );
316 | $all_day = (bool) get_post_meta( $post->ID, 'wp_event_calendar_all_day', true );
317 | $start_date = strtotime( get_post_meta( $post->ID, 'wp_event_calendar_date_time', true ) );
318 | $end_date = strtotime( get_post_meta( $post->ID, 'wp_event_calendar_end_date_time', true ) );
319 |
320 | // Start an output buffer
321 | ob_start();
322 |
323 | // All day event
324 | if ( true === $all_day ) {
325 |
326 | // 1 day
327 | if ( date( 'd', $start_date ) === date( 'd', $end_date ) ) {
328 | esc_html_e( 'All Day', 'wp-event-calendar' );
329 |
330 | // More than 1 day
331 | } else {
332 | echo wp_event_calendar_human_diff_time(
333 | strtotime( 'midnight', $start_date ),
334 | strtotime( 'midnight', $end_date )
335 | );
336 | }
337 |
338 | // Specific times
339 | } else {
340 | echo wp_event_calendar_human_diff_time( $start_date, $end_date );
341 | }
342 |
343 | // Get the output buffer
344 | $retval = ob_get_clean();
345 |
346 | // Filter & return
347 | return apply_filters( 'wp_get_event_end_date_time', $retval, $post, $all_day, $start_date, $end_date );
348 | }
349 |
350 | /**
351 | * Return array of hours
352 | *
353 | * @since 0.2.4
354 | *
355 | * @return array
356 | */
357 | function wp_event_calendar_get_hours() {
358 | return apply_filters( 'wp_event_calendar_get_hours', array(
359 | '01',
360 | '02',
361 | '03',
362 | '04',
363 | '05',
364 | '06',
365 | '07',
366 | '08',
367 | '09',
368 | '10',
369 | '11',
370 | '12'
371 | ) );
372 | }
373 |
374 | /**
375 | * Return array of minutes
376 | *
377 | * @since 0.2.4
378 | *
379 | * @return array
380 | */
381 | function wp_event_calendar_get_minutes() {
382 | return apply_filters( 'wp_event_calendar_get_minutes', array(
383 | '00',
384 | '05',
385 | '10',
386 | '15',
387 | '20',
388 | '25',
389 | '30',
390 | '35',
391 | '40',
392 | '45',
393 | '50',
394 | '55'
395 | ) );
396 | }
397 |
398 | /**
399 | * Output a select dropdown for hours & minutes
400 | *
401 | * @since 0.2.4
402 | *
403 | * @param array $args
404 | */
405 | function wp_event_calendar_time_dropdown( $args = array() ) {
406 |
407 | // Parse the arguments
408 | $r = wp_parse_args( $args, array(
409 | 'first' => esc_html( 'Select One', 'wp-event-calendar' ),
410 | 'placeholder' => ' ',
411 | 'id' => '',
412 | 'name' => '',
413 | 'class' => '',
414 | 'items' => array(),
415 | 'selected' => '',
416 | 'multi' => false,
417 | 'echo' => true,
418 | 'width' => 55
419 | ) );
420 |
421 | // Is multi?
422 | $multi = ( true === $r['multi'] )
423 | ? 'multi'
424 | : '';
425 |
426 | // Start an output buffer
427 | ob_start();
428 |
429 | // Start the select wrapper
430 | ?> style="width: px;" >>
439 |
440 | wp_event_calendar_allowed_post_types(),
466 | 'post_status' => array( 'publish', 'future' ),
467 | 'posts_per_page' => -1,
468 | 'orderby' => 'meta_value',
469 | 'order' => 'ASC',
470 | 'hierarchical' => false,
471 | 'ignore_sticky_posts' => true,
472 | 'suppress_filters' => true,
473 | 'no_found_rows' => true,
474 | 'meta_query' => wp_event_calendar_get_meta_query()
475 | ) );
476 |
477 | // Query for events
478 | $query = new WP_Query( $r );
479 |
480 | // Return posts
481 | return $query->posts;
482 | }
483 |
484 | /**
485 | * Get meta_query argument for a WP_Query
486 | *
487 | * Okay; let's talk this out here in regular English, because otherwise it
488 | * barely makes any sense at all and you just get lost trying to remember:
489 | *
490 | * - Ranges are: day, week, month, custom
491 | * - Look for:
492 | * - Events starting & ending within the current range
493 | * - Events starting before and ending anytime after current range
494 | * - Events starting before and ending within the current range
495 | * - Events starting within and ending anytime after the current range
496 | *
497 | * @since 0.4.0
498 | *
499 | * @param array $args {
500 | * @type string $mode month|week|day
501 | * @type string $start Start time in mysql format
502 | * @type string $end End time in mysql format
503 | * }
504 | *
505 | * @return array 'meta_query' used for WP_Query
506 | */
507 | function wp_event_calendar_get_meta_query( $args = array() ) {
508 |
509 | // Parse arguments
510 | $r = wp_parse_args( $args, array(
511 | 'mode' => 'month',
512 | 'start' => '',
513 | 'end' => ''
514 | ) );
515 |
516 | // They're all the same now!
517 | $retval = array(
518 | 'wp_event_calendar_clause' => array(
519 | 'relation' => 'AND',
520 | 'within_range_clause' => array(
521 | 'relation' => 'AND',
522 | 'start_between_clause' => array(
523 | 'key' => 'wp_event_calendar_date_time',
524 | 'value' => $r['end'],
525 | 'type' => 'DATETIME',
526 | 'compare' => '<'
527 | ),
528 | 'end_between_clause' => array(
529 | 'key' => 'wp_event_calendar_end_date_time',
530 | 'value' => $r['start'],
531 | 'type' => 'DATETIME',
532 | 'compare' => '>'
533 | )
534 | )
535 | )
536 | );
537 |
538 | return apply_filters( 'wp_event_calendar_get_meta_query', $retval, $r, $args );
539 | }
540 |
541 | /**
542 | * Get an array of WP_Event_Calendar_Event objects
543 | *
544 | * @since 0.4.0
545 | *
546 | * @param array $args
547 | */
548 | function wp_event_calendar_get_events( $args = array() ) {
549 |
550 | // Get posts & define default
551 | $posts = wp_get_events( $args );
552 | $events = array();
553 |
554 | // Loop through events and create the object
555 | foreach ( $posts as $post ) {
556 | $events[] = wp_event_calendar_post_to_event( $post );
557 | }
558 |
559 | return apply_filters( 'wp_event_calendar_get_events', $events, $posts, $args );
560 | }
561 |
562 | /**
563 | * Convert a WP_Post object to a WP_Event_Calendar_Event object
564 | *
565 | * @since 0.4.0
566 | *
567 | * @param WP_Post $post
568 | *
569 | * @return \WP_Event_Calendar_Event
570 | */
571 | function wp_event_calendar_post_to_event( WP_Post $post ) {
572 |
573 | // Core
574 | $title = $post->post_title;
575 | $content = $post->post_content;
576 |
577 | // Meta
578 | $start = get_post_meta( $post->ID, 'wp_event_calendar_date_time', true );
579 | $end = get_post_meta( $post->ID, 'wp_event_calendar_end_date_time', true );
580 | $location = get_post_meta( $post->ID, 'wp_event_calendar_location', true );
581 | $repeat = get_post_meta( $post->ID, 'wp_event_calendar_repeat', true );
582 |
583 | // Return object
584 | return new WP_Event_Calendar_Event( $start, $end, $title, $content, $location, $repeat );
585 | }
586 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
341 |
--------------------------------------------------------------------------------
/wp-event-calendar/includes/events/metaboxes.php:
--------------------------------------------------------------------------------
1 | term_id, $args['popular_cats'] )
49 | ? ' class="popular-category"'
50 | : '';
51 |
52 | // Maybe use already selected categories
53 | $args['selected_cats'] = empty( $args['selected_cats'] )
54 | ? array()
55 | : $args['selected_cats'];
56 |
57 | /** This filter is documented in wp-includes/category-template.php */
58 | $output .= "\n" .
59 | ' term_id, $args['selected_cats'] ), true, false ) .
61 | disabled( empty( $args['disabled'] ), false, false ) . ' /> ' .
62 | esc_html( apply_filters( 'the_category', $category->name ) ) . ' ';
63 | }
64 | }
65 |
66 | /**
67 | * Event Types Metabox
68 | * Output radio buttons instead of the default WordPress mechanism
69 | *
70 | * @since 0.4.1
71 | *
72 | * @param array $args
73 | * @param string $taxonomy
74 | *
75 | * @return array
76 | */
77 | function wp_event_calendar_taxonomy_args( $args = array(), $taxonomy = '' ) {
78 | if ( 'event-type' === $taxonomy ) {
79 |
80 | $r = apply_filters( 'wp_event_calendar_taxonomy_args', array(
81 | 'meta_box_cb' => 'post_categories_meta_box'
82 | ), $args );
83 |
84 | $args = wp_parse_args( $args, $r );
85 | }
86 |
87 | return $args;
88 | }
89 |
90 | /**
91 | * Use the custom walker for radio buttons
92 | *
93 | * @since 0.4.1
94 | *
95 | * @param array $args
96 | *
97 | * @return array
98 | */
99 | function wp_event_calendar_checklist_args( $args = array() ) {
100 | if ( 'event-type' === $args['taxonomy'] ) {
101 |
102 | $r = apply_filters( 'wp_event_calendar_checklist_args', array(
103 | 'walker' => new WP_Event_Calendar_Walker_Category_Radio(),
104 | ), $args );
105 |
106 | $args = wp_parse_args( $args, $r );
107 | }
108 |
109 | return $args;
110 | }
111 |
112 | /**
113 | * Event Metabox
114 | *
115 | * @since 0.1.1
116 | */
117 | function wp_event_calendar_add_metabox() {
118 | add_meta_box(
119 | 'wp_event_calendar_duration',
120 | __( 'Duration', 'wp-event-calendar' ),
121 | 'wp_event_calendar_duration_metabox',
122 | wp_event_calendar_allowed_post_types(),
123 | 'above_event_editor',
124 | 'default'
125 | );
126 |
127 | add_meta_box(
128 | 'wp_event_calendar_details',
129 | __( 'Details', 'wp-event-calendar' ),
130 | 'wp_event_calendar_details_metabox',
131 | wp_event_calendar_allowed_post_types(),
132 | 'above_event_editor',
133 | 'default'
134 | );
135 | }
136 |
137 | /**
138 | * Output the event duration metabox
139 | *
140 | * @since 0.2.3
141 | *
142 | * @param WP_Post $post The post
143 | */
144 | function wp_event_calendar_duration_metabox( $post = null ) {
145 | $meta = get_post_custom( $post->ID );
146 | $date = $hour = $minute = $am_pm = '';
147 | $end_date = $end_hour = $end_minute = $end_am_pm = '';
148 |
149 | /** All Day ***************************************************************/
150 |
151 | $all_day = ! empty( $meta['wp_event_calendar_all_day'][0] )
152 | ? (bool) $meta['wp_event_calendar_all_day'][0]
153 | : false;
154 | $hidden = ( true === $all_day )
155 | ? ' style="display: none;"'
156 | : '';
157 |
158 | /** Location **************************************************************/
159 |
160 | $location = ! empty( $meta['wp_event_calendar_location'][0] )
161 | ? $meta['wp_event_calendar_location'][0]
162 | : '';
163 |
164 | /** Ends ******************************************************************/
165 |
166 | // Get date_time
167 | $end_date_time = ! empty( $meta['wp_event_calendar_end_date_time'][0] )
168 | ? strtotime( $meta['wp_event_calendar_end_date_time'][0] )
169 | : null;
170 |
171 | // Only if end isn't empty
172 | if ( ! empty( $end_date_time ) ) {
173 |
174 | // Date
175 | $end_date = date( 'm/d/Y', $end_date_time );
176 |
177 | // Only if not all-day
178 | if ( empty( $all_day ) ) {
179 |
180 | // Hour
181 | $end_hour = date( 'h', $end_date_time );
182 | if ( empty( $end_hour ) ) {
183 | $end_hour = '';
184 | }
185 |
186 | // Minute
187 | $end_minute = date( 'i', $end_date_time );
188 | if ( empty( $end_hour ) ) {
189 | $end_minute = '';
190 | }
191 |
192 | // Day/night
193 | $end_am_pm = date( 'a', $end_date_time );
194 | }
195 | }
196 |
197 | /** Starts ****************************************************************/
198 |
199 | // Get date_time
200 | if ( ! empty( $_GET['start_day'] ) ) {
201 | $date_time = (int) $_GET['start_day'];
202 | } else {
203 | $date_time = ! empty( $meta['wp_event_calendar_date_time'][0] )
204 | ? strtotime( $meta['wp_event_calendar_date_time'][0] )
205 | : null;
206 | }
207 |
208 | // Date
209 | if ( ! empty( $date_time ) ) {
210 | $date = date( 'm/d/Y', $date_time );
211 |
212 | // Only if not all-day
213 | if ( empty( $all_day ) ) {
214 |
215 | // Hour
216 | $hour = date( 'h', $date_time );
217 | if ( empty( $end_hour ) || empty( $hour ) ) {
218 | $hour = '';
219 | }
220 |
221 | // Minute
222 | $minute = date( 'i', $date_time );
223 | if ( empty( $hour ) && empty( $end_minute ) ) {
224 | $minute = '';
225 | }
226 |
227 | // Day/night
228 | $am_pm = date( 'a', $date_time );
229 | }
230 | }
231 |
232 | /** Repeat ****************************************************************/
233 |
234 | // Interval
235 | $interval = ! empty( $meta['wp_event_calendar_repeat'][0] )
236 | ? $meta['wp_event_calendar_repeat'][0]
237 | : '';
238 |
239 | // Filter the intervals
240 | $options = apply_filters( 'wp_event_calendar_intervals', array(
241 | '0' => __( 'Never', 'wp-event-calendar' ),
242 | '10' => __( 'Weekly', 'wp-event-calendar' ),
243 | '100' => __( 'Monthly', 'wp-event-calendar' ),
244 | '1000' => __( 'Yearly', 'wp-event-calendar' )
245 | ) );
246 |
247 | /** Let's Go! *************************************************************/
248 |
249 | // Start an output buffer
250 | ob_start(); ?>
251 |
252 |
253 |
374 |
375 | post_content, 'post_content' );
390 | }
391 |
392 | /**
393 | * Offset hour based on meridem
394 | *
395 | * @since 0.2.2
396 | *
397 | * @param int $hour
398 | * @param string $meridiem
399 | *
400 | * @return int
401 | */
402 | function wp_event_calendar_adjust_hour_for_meridiem( $hour = 0, $meridiem = 'am' ) {
403 |
404 | // Store new hour
405 | $new_hour = $hour;
406 |
407 | // Bump by 12 hours
408 | if ( 'pm' === $meridiem && ( $new_hour < 12 ) ) {
409 | $new_hour += 12;
410 |
411 | // Decrease by 12 hours
412 | } elseif ( 'am' === $meridiem && ( $new_hour >= 12 ) ) {
413 | $new_hour -= 12;
414 | }
415 |
416 | // Filter & return
417 | return (int) apply_filters( 'wp_event_calendar_adjust_hour_for_meridiem', $new_hour, $hour, $meridiem );
418 | }
419 |
420 | /**
421 | * Metabox save
422 | *
423 | * @since 0.1.1
424 | *
425 | * @return int|void
426 | */
427 | function wp_event_calendar_metabox_save( $post_id = 0 ) {
428 |
429 | // Bail if no nonce or nonce check fails
430 | if ( empty( $_POST['wp_event_calendar_metabox_nonce'] ) || ! wp_verify_nonce( $_POST['wp_event_calendar_metabox_nonce'], 'wp_event_calendar' ) ) {
431 | return $post_id;
432 | }
433 |
434 | // Bail on autosave, ajax, or bulk
435 | if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || ( defined( 'DOING_AJAX') && DOING_AJAX ) || isset( $_REQUEST['bulk_edit'] ) ) {
436 | return $post_id;
437 | }
438 |
439 | // Get the post type
440 | $post_type = get_post_type( $post_id );
441 |
442 | // Only save event metadata to supported post types
443 | if ( ! post_type_supports( $post_type, 'events' ) ) {
444 | return $post_id;
445 | }
446 |
447 | // Bail if revision
448 | if ( wp_is_post_revision( $post_id ) ) {
449 | return $post_id;
450 | }
451 |
452 | // Get post type object
453 | $post_type_object = get_post_type_object( $post_type );
454 |
455 | // Bail if user cannot edit this event
456 | if ( ! current_user_can( $post_type_object->cap->edit_post, $post_id ) ) {
457 | return $post_id;
458 | }
459 |
460 | /** Location **************************************************************/
461 |
462 | // Get event location
463 | $location = ! empty( $_POST['wp_event_calendar_location'] )
464 | ? wp_kses( $_POST['wp_event_calendar_location'], array() )
465 | : '';
466 |
467 | /** Starts ****************************************************************/
468 |
469 | // Get calendar date
470 | $date = ! empty( $_POST['wp_event_calendar_date'] )
471 | ? strtotime( sanitize_text_field( $_POST['wp_event_calendar_date'] ) )
472 | : current_time( 'timestamp' );
473 |
474 | // Hour
475 | $hour = ! empty( $_POST['wp_event_calendar_time_hour'] )
476 | ? sanitize_text_field( $_POST['wp_event_calendar_time_hour'] )
477 | : 0;
478 |
479 | // Minutes
480 | $minutes = ! empty( $_POST['wp_event_calendar_time_minute'] )
481 | ? sanitize_text_field( $_POST['wp_event_calendar_time_minute'] )
482 | : 0;
483 |
484 | // Day/night
485 | $am_pm = ! empty( $_POST['wp_event_calendar_time_am_pm'] )
486 | ? sanitize_text_field( $_POST['wp_event_calendar_time_am_pm'] )
487 | : 'am';
488 |
489 | /** Ends ******************************************************************/
490 |
491 | // Calendar date is set
492 | $end_date = ! empty( $_POST['wp_event_calendar_end_date'] )
493 | ? strtotime( sanitize_text_field( $_POST['wp_event_calendar_end_date'] ) )
494 | : null;
495 |
496 | // Hour
497 | $end_hour = ! empty( $_POST['wp_event_calendar_end_time_hour'] )
498 | ? sanitize_text_field( $_POST['wp_event_calendar_end_time_hour'] )
499 | : 0;
500 |
501 | // Minutes
502 | $end_minutes = ! empty( $_POST['wp_event_calendar_end_time_minute'] )
503 | ? sanitize_text_field( $_POST['wp_event_calendar_end_time_minute'] )
504 | : 0;
505 |
506 | // Day/night
507 | $end_am_pm = ! empty( $_POST['wp_event_calendar_end_time_am_pm'] )
508 | ? sanitize_text_field( $_POST['wp_event_calendar_end_time_am_pm'] )
509 | : 'am';
510 |
511 | /** Repeat ****************************************************************/
512 |
513 | // Repeat
514 | $repeat = ! empty( $_POST['wp_event_calendar_repeat'] )
515 | ? sanitize_key( $_POST['wp_event_calendar_repeat'] )
516 | : '';
517 |
518 | // Expire
519 | $expire = ! empty( $_POST['wp_event_calendar_expire'] )
520 | ? sanitize_text_field( $_POST['wp_event_calendar_expire'] )
521 | : '';
522 |
523 | /** All Day ***************************************************************/
524 |
525 | // Get all-day status
526 | $all_day = ! empty( $_POST['wp_event_calendar_all_day'] )
527 | ? (bool) $_POST['wp_event_calendar_all_day']
528 | : false;
529 |
530 | // Set all day if no end date
531 | if ( ( false === $all_day ) && ( empty( $minutes ) && empty( $hour ) && empty( $end_minutes ) && empty( $end_hour ) ) ) {
532 | if ( empty( $end_date ) || ( $date === $end_date ) ) {
533 |
534 | // Make all-day event
535 | $all_day = true;
536 |
537 | // Make single-day event
538 | if ( empty( $end_date ) ) {
539 | $end_date = $date;
540 | }
541 | }
542 | }
543 |
544 | /** Combine ***************************************************************/
545 |
546 | // Maybe tweak hours
547 | $hour = wp_event_calendar_adjust_hour_for_meridiem( $hour, $am_pm );
548 | $end_hour = wp_event_calendar_adjust_hour_for_meridiem( $end_hour, $end_am_pm );
549 |
550 | // Make timestamps from pieces
551 | $date = mktime( intval( $hour ), intval( $minutes ), 0, date( 'm', $date ), date( 'd', $date ), date( 'Y', $date ) );
552 | $end_date = mktime( intval( $end_hour ), intval( $end_minutes ), 0, date( 'm', $end_date ), date( 'd', $end_date ), date( 'Y', $end_date ) );
553 |
554 | // End dates can't be before start dates
555 | if ( $end_date <= $date ) {
556 | $end_date = strtotime( '+30 minutes', $date );
557 | }
558 |
559 | /** Save ******************************************************************/
560 |
561 | // Save the start date & time
562 | ! empty( $date )
563 | ? update_post_meta( $post_id, 'wp_event_calendar_date_time', gmdate( 'Y-m-d H:i:s', $date ) )
564 | : delete_post_meta( $post_id, 'wp_event_calendar_date_time' );
565 |
566 | // Save the end date & time
567 | ! empty( $end_date )
568 | ? update_post_meta( $post_id, 'wp_event_calendar_end_date_time', gmdate( 'Y-m-d H:i:s', $end_date ) )
569 | : delete_post_meta( $post_id, 'wp_event_calendar_end_date_time' );
570 |
571 | // Save location
572 | ! empty( $location )
573 | ? update_post_meta( $post_id, 'wp_event_calendar_location', $location )
574 | : delete_post_meta( $post_id, 'wp_event_calendar_location' );
575 |
576 | // Save all-day
577 | ! empty( $all_day )
578 | ? update_post_meta( $post_id, 'wp_event_calendar_all_day', 1 )
579 | : delete_post_meta( $post_id, 'wp_event_calendar_all_day' );
580 |
581 | // Save if repeating
582 | ! empty( $repeat )
583 | ? update_post_meta( $post_id, 'wp_event_calendar_repeat', $repeat )
584 | : delete_post_meta( $post_id, 'wp_event_calendar_repeat' );
585 |
586 | // Save only if repeating
587 | ! empty( $expire ) && ( 'never' !== $repeat )
588 | ? update_post_meta( $post_id, 'wp_event_calendar_expire', strtotime( $expire ) )
589 | : delete_post_meta( $post_id, 'wp_event_calendar_expire' );
590 | }
591 |
--------------------------------------------------------------------------------
/wp-event-calendar/includes/common/list-table-base.php:
--------------------------------------------------------------------------------
1 | year = $this->get_year();
183 | $this->month = $this->get_month();
184 | $this->day = $this->get_day();
185 |
186 | // Set "today" based on current request
187 | $this->today = strtotime( "{$this->year}/{$this->month}/{$this->day}" );
188 |
189 | // Set modes
190 | $this->modes = $this->get_modes();
191 |
192 | // Setup arguments
193 | $r = wp_parse_args( $args, array(
194 | 'singular' => esc_html__( 'Event', 'wp-event-calendar' ),
195 | 'plural' => esc_html__( 'Events', 'wp-event-calendar' )
196 | ) );
197 |
198 | // Pass arguments into parent
199 | parent::__construct( $r );
200 | }
201 |
202 | /**
203 | * Get the possible list table modes
204 | *
205 | * @since 0.1.8
206 | *
207 | * @return array
208 | */
209 | protected function get_modes() {
210 | return apply_filters( 'wp_event_calendar_list_table_modes', array(
211 | 'month' => __( 'Month', 'wp-event-calendar' ),
212 | 'week' => __( 'Week', 'wp-event-calendar' ),
213 | 'day' => __( 'Day', 'wp-event-calendar' )
214 | ) );
215 | }
216 |
217 | /**
218 | * Return the post type of the current screen
219 | *
220 | * @since 0.1.0
221 | *
222 | * @return string
223 | */
224 | protected function get_screen_post_type() {
225 |
226 | // Special handling for "post" post type
227 | if ( ! empty( $this->screen->post_type ) ) {
228 | $post_type = $this->screen->post_type;
229 | } else {
230 | $post_type = 'post';
231 | }
232 |
233 | return $post_type;
234 | }
235 |
236 | /**
237 | * Return the base URL
238 | *
239 | * @since 0.1.0
240 | *
241 | * @return string
242 | */
243 | protected function get_base_url() {
244 |
245 | // Define local variables
246 | $args = array();
247 | $post_type = $this->get_screen_post_type();
248 |
249 | // "post" post type needs special handling
250 | if ( 'post' !== $post_type ) {
251 | $args['post_type'] = $post_type;
252 | }
253 |
254 | // Persistent `post_status`
255 | if ( isset( $_GET['post_status'] ) ) {
256 | $args['post_status'] = sanitize_key( $_GET['post_status'] );
257 | }
258 |
259 | // Persistent searches
260 | if ( isset( $_GET['s'] ) ) {
261 | $args['s'] = urlencode( $_GET['s'] );
262 | }
263 |
264 | // Setup `page` & `mode` arguments
265 | $args['page'] = $post_type . '-calendar';
266 | $args['mode'] = $this->mode;
267 |
268 | // Add args & return
269 | return add_query_arg( $args, admin_url( 'edit.php' ) );
270 | }
271 |
272 | /**
273 | * Setup the list-table's columns
274 | *
275 | * @see WP_List_Table::single_row_columns()
276 | *
277 | * @return array An associative array containing column information
278 | */
279 | public function get_columns() {
280 | return array(
281 | 'sunday' => $GLOBALS['wp_locale']->get_weekday( 0 ),
282 | 'monday' => $GLOBALS['wp_locale']->get_weekday( 1 ),
283 | 'tuesday' => $GLOBALS['wp_locale']->get_weekday( 2 ),
284 | 'wednesday' => $GLOBALS['wp_locale']->get_weekday( 3 ),
285 | 'thursday' => $GLOBALS['wp_locale']->get_weekday( 4 ),
286 | 'friday' => $GLOBALS['wp_locale']->get_weekday( 5 ),
287 | 'saturday' => $GLOBALS['wp_locale']->get_weekday( 6 )
288 | );
289 | }
290 |
291 | /**
292 | * Allow columns to be sortable
293 | *
294 | * @return array An associative array containing the sortable columns
295 | */
296 | protected function get_sortable_columns() {
297 | return array();
298 | }
299 |
300 | /**
301 | * Setup the bulk actions
302 | *
303 | * @return array An associative array containing all the bulk actions
304 | */
305 | public function get_bulk_actions() {
306 | return array();
307 | }
308 |
309 | /**
310 | * Get the current month
311 | *
312 | * @since 0.1.0
313 | *
314 | * @access public
315 | *
316 | * @return int
317 | */
318 | protected function get_month() {
319 | return (int) isset( $_REQUEST['cm'] )
320 | ? (int) $_REQUEST['cm']
321 | : date_i18n( 'n' );
322 | }
323 |
324 | /**
325 | * Get the current day
326 | *
327 | * @since 0.1.0
328 | *
329 | * @access public
330 | *
331 | * @return int
332 | */
333 | protected function get_day() {
334 | return (int) isset( $_REQUEST['cd'] )
335 | ? (int) $_REQUEST['cd']
336 | : date_i18n( 'j' );
337 | }
338 |
339 | /**
340 | * Get the current year
341 | *
342 | * @since 0.1.0
343 | *
344 | * @access public
345 | *
346 | * @return int
347 | */
348 | protected function get_year() {
349 | return (int) isset( $_REQUEST['cy'] )
350 | ? (int) $_REQUEST['cy']
351 | : date_i18n( 'Y' );
352 | }
353 |
354 | /**
355 | * Get the current page number
356 | *
357 | * @since 0.1.0
358 | *
359 | * @access public
360 | *
361 | * @return int
362 | */
363 | protected function get_post_status() {
364 | return isset( $_REQUEST['post_status'] )
365 | ? sanitize_key( $_REQUEST['post_status'] )
366 | : $this->get_available_post_stati();
367 | }
368 |
369 | /**
370 | * Get the current page number
371 | *
372 | * @since 0.1.0
373 | *
374 | * @access public
375 | *
376 | * @return int
377 | */
378 | protected function get_available_post_stati() {
379 | return array(
380 | 'publish',
381 | 'future',
382 | 'draft',
383 | 'pending',
384 | 'private',
385 | 'hidden',
386 | 'passed'
387 | );
388 | }
389 |
390 | /**
391 | * Get the current page number
392 | *
393 | * @since 0.1.0
394 | *
395 | * @access public
396 | *
397 | * @return int
398 | */
399 | protected function get_orderby() {
400 | return isset( $_REQUEST['orderby'] )
401 | ? sanitize_key( $_REQUEST['orderby'] )
402 | : 'date';
403 | }
404 |
405 | /**
406 | * Get the current page number
407 | *
408 | * @since 0.1.0
409 | *
410 | * @access public
411 | *
412 | * @return int
413 | */
414 | protected function get_order() {
415 | return isset( $_REQUEST['order'] )
416 | ? ucwords( $_REQUEST['order'] )
417 | : 'ASC';
418 | }
419 |
420 | /**
421 | * Get the current page number
422 | *
423 | * @since 0.1.0
424 | *
425 | * @access public
426 | *
427 | * @return int
428 | */
429 | protected function get_search() {
430 | return isset( $_REQUEST['s'] )
431 | ? wp_unslash( $_REQUEST['s'] )
432 | : '';
433 | }
434 |
435 | /**
436 | * Get the meta_query for the current mode
437 | *
438 | * @since 0.3.2
439 | *
440 | * @return array
441 | */
442 | protected function get_meta_query() {
443 | return wp_event_calendar_get_meta_query( array(
444 | 'mode' => $this->mode,
445 | 'start' => $this->view_start,
446 | 'end' => $this->view_end
447 | ) );
448 | }
449 |
450 | /**
451 | * Get the current page number
452 | *
453 | * @since 0.1.0
454 | *
455 | * @access public
456 | *
457 | * @return int
458 | */
459 | protected function get_max() {
460 | $user_option = get_user_option( get_current_screen()->base . 'per_day' );
461 |
462 | if ( empty( $user_option ) ) {
463 | $user_option = 10;
464 | }
465 |
466 | return (int) $user_option;
467 | }
468 |
469 | /**
470 | * Get a list of CSS classes for the list table table tag.
471 | *
472 | * @since 0.1.0
473 | *
474 | * @return array List of CSS classes for the table tag.
475 | */
476 | protected function get_table_classes() {
477 | return array( 'widefat', 'fixed', 'striped', 'calendar', $this->_args['plural'] );
478 | }
479 |
480 | /**
481 | * Determine if the current view is the "All" view.
482 | *
483 | * @since 0.1.0
484 | *
485 | * @return bool Whether the current view is the "All" view.
486 | */
487 | protected function is_base_request() {
488 | if ( empty( $_GET ) ) {
489 | return true;
490 | } elseif ( empty( $_GET['post_status'] ) ) {
491 | return true;
492 | } elseif ( 2 === count( $_GET ) && ! empty( $_GET['post_type'] ) ) {
493 | return ( $this->screen->post_type === $_GET['post_type'] );
494 | }
495 | return false;
496 | }
497 |
498 | /**
499 | * Get the calendar views
500 | *
501 | * @since 0.1.0
502 | *
503 | * @access public
504 | *
505 | * @return int
506 | */
507 | protected function get_views() {
508 |
509 | // Screen
510 | $base_url = $this->get_base_url();
511 |
512 | // Posts
513 | $post_type = $this->get_screen_post_type();
514 | $num_posts = wp_count_posts( $post_type, 'readable' );
515 | $total_posts = array_sum( (array) $num_posts );
516 | $class = $allposts = '';
517 |
518 | // Post type statuses
519 | $avail_post_stati = $this->get_available_post_stati();
520 | $status_links = array();
521 | $post_statuses = get_post_stati( array( 'show_in_admin_all_list' => false ) );
522 |
523 | // Subtract post statuses that are not included in the admin all list.
524 | foreach ( $post_statuses as $state ) {
525 | $total_posts -= $num_posts->$state;
526 | }
527 |
528 | // "All" link
529 | if ( empty( $class ) && ( $this->is_base_request() || isset( $_REQUEST['all_posts'] ) ) ) {
530 | $class = 'current';
531 | }
532 |
533 | $all_inner_html = sprintf(
534 | _nx(
535 | 'All (%s) ',
536 | 'All (%s) ',
537 | $total_posts,
538 | 'posts'
539 | ),
540 | number_format_i18n( $total_posts )
541 | );
542 |
543 | $status_links['all'] = '' . $all_inner_html . ' ';
544 |
545 | // Other links
546 | $post_statuses = get_post_stati( array( 'show_in_admin_status_list' => true ), 'objects' );
547 |
548 | // Loop through statuses and compile array of available ones
549 | foreach ( $post_statuses as $status ) {
550 |
551 | // Set variable to trick PHP
552 | $status_name = $status->name;
553 |
554 | // "Passed" status is irrelevant in calendar view
555 | if ( 'passed' === $status_name ) {
556 | continue;
557 | }
558 |
559 | // Skip if not available status
560 | if ( ! in_array( $status_name, $avail_post_stati ) ) {
561 | continue;
562 | }
563 |
564 | // Skip if no post count
565 | if ( empty( $num_posts->$status_name ) ) {
566 | continue;
567 | }
568 |
569 | // Set the class value
570 | if ( isset( $_REQUEST['post_status'] ) && ( $status_name === $_REQUEST['post_status'] ) ) {
571 | $class = 'current';
572 | } else {
573 | $class = '';
574 | }
575 |
576 | // Calculate the status text
577 | $status_text = sprintf( translate_nooped_plural( $status->label_count, $num_posts->$status_name ), number_format_i18n( $num_posts->$status_name ) );
578 | $status_url = add_query_arg( array( 'post_status' => $status_name ), $base_url );
579 |
580 | // Add link to array
581 | $status_links[ $status_name ] = '' . $status_text . ' ';
582 | }
583 |
584 | return $status_links;
585 | }
586 |
587 | /**
588 | * Prepare items for list-table display
589 | *
590 | * @since 0.1.0
591 | *
592 | * @uses $this->_column_headers
593 | * @uses $this->get_columns()
594 | * @uses $this->get_orderby()
595 | * @uses $this->get_order()
596 | */
597 | public function prepare_items() {
598 |
599 | // Set the mode
600 | $this->set_mode();
601 |
602 | // Set column headers
603 | $this->_column_headers = array(
604 | $this->get_columns(),
605 | array(),
606 | array()
607 | );
608 |
609 | // Query for posts for this month only
610 | $this->query = new WP_Query( $this->main_query_args() );
611 |
612 | // Max per day
613 | $max_per = $this->get_max();
614 |
615 | // Rearrange posts into an array keyed by day of the month
616 | foreach ( $this->query->posts as $post ) {
617 |
618 | // Get start & end
619 | $this->item_all_day = (bool) get_post_meta( $post->ID, 'wp_event_calendar_all_day', true );
620 | $this->item_start = get_post_meta( $post->ID, 'wp_event_calendar_date_time', true );
621 | $this->item_end = get_post_meta( $post->ID, 'wp_event_calendar_end_date_time', true );
622 |
623 | // Format start
624 | if ( ! empty( $this->item_start ) ) {
625 | $this->item_start = strtotime( $this->item_start );
626 | }
627 |
628 | // Format end
629 | if ( ! empty( $this->item_end ) ) {
630 | $this->item_end = strtotime( $this->item_end );
631 | }
632 |
633 | if ( empty( $this->item_start ) ) {
634 | continue;
635 | }
636 |
637 | // Convert dates to timestamps that exclude the timestamp
638 | $start_date_timestamp = strtotime( date( 'F j, Y', $this->item_start ) );
639 | $end_date_timestamp = strtotime( date( 'F j, Y', $this->item_end ) );
640 |
641 | // Get the number of seconds between each timestamp's date
642 | $diff = abs( $end_date_timestamp - $start_date_timestamp );
643 |
644 | // Calculate full days spanned
645 | $this->item_days = ceil( $diff / DAY_IN_SECONDS ) + 1;
646 |
647 | // Prepare pointer & item
648 | $this->setup_item( $post, $max_per );
649 | }
650 | }
651 |
652 | /**
653 | *
654 | * @return type
655 | */
656 | protected function main_query_args( $args = array() ) {
657 |
658 | // Events
659 | if ( post_type_supports( $this->screen->post_type, 'events' ) ) {
660 | $defaults = array(
661 | 'post_type' => $this->screen->post_type,
662 | 'post_status' => $this->get_post_status(),
663 | 'posts_per_page' => -1,
664 | 'orderby' => 'meta_value',
665 | 'order' => $this->get_order(),
666 | 'hierarchical' => false,
667 | 'ignore_sticky_posts' => true,
668 | 's' => $this->get_search(),
669 | 'meta_query' => $this->get_meta_query()
670 | );
671 |
672 | // All others
673 | } else {
674 | $defaults = array(
675 | 'post_type' => $this->screen->post_type,
676 | 'post_status' => $this->get_post_status(),
677 | 'monthnum' => $this->month,
678 | 'year' => $this->year,
679 | 'day' => null,
680 | 'posts_per_page' => -1,
681 | 'orderby' => $this->get_orderby(),
682 | 'order' => $this->get_order(),
683 | 'hierarchical' => false,
684 | 'ignore_sticky_posts' => true,
685 | 's' => $this->get_search()
686 | );
687 | }
688 |
689 | // Parse the arguments
690 | $r = wp_parse_args( $args, $defaults );
691 |
692 | return apply_filters( 'wp_event_calendar_month_query', $r, $args, $defaults );
693 | }
694 |
695 | /**
696 | * Handle bulk action requests
697 | */
698 | public function process_bulk_action() {
699 | // No bulk actions
700 | }
701 |
702 | /**
703 | * Always have items
704 | *
705 | * This method forces WordPress to always show our calendar, and never to
706 | * trigger the `no_items()` method.
707 | *
708 | * @since 0.1.0
709 | *
710 | * @return boolean
711 | */
712 | public function has_items() {
713 | return true;
714 | }
715 |
716 | /**
717 | * Add a post to the item array, keyed by day
718 | *
719 | * @todo Repeat & expire
720 | *
721 | * @since 0.1.1
722 | *
723 | * @param object $post
724 | * @param int $max
725 | */
726 | protected function setup_item( $post = false, $max = 10 ) {
727 |
728 | // Calculate start day
729 | if ( ! empty( $this->item_start ) ) {
730 | $start_day = date_i18n( 'j', $this->item_start );
731 | } else {
732 | $start_day = 0;
733 | }
734 |
735 | // Calculate end day
736 | if ( ! empty( $this->item_end ) ) {
737 | $end_day = date_i18n( 'j', $this->item_end );
738 | } else {
739 | $end_day = $start_day;
740 | }
741 |
742 | // Start the days loop with the start day
743 | $day = (int) $start_day;
744 | $type = 'items';
745 |
746 | // Loop through days
747 | while ( $day <= $end_day ) {
748 |
749 | // Setup the pointer for each day
750 | $this->setup_pointer( $post, $day );
751 |
752 | // Add post to item types for each day in it's duration
753 | if ( empty( $this->{$type}[ $day ] ) || ( $max > count( $this->{$type}[ $day ] ) ) ) {
754 | $this->{$type}[ $day ][ $post->ID ] = $post;
755 | }
756 |
757 | // Bump the day
758 | ++$day;
759 | }
760 | }
761 |
762 | /**
763 | * Get the already queried posts for a given day
764 | *
765 | * @since 0.1.8
766 | *
767 | * @param int $iterator
768 | *
769 | * @return array
770 | */
771 | protected function get_queried_items( $iterator = 1, $type = 'items' ) {
772 | return isset( $this->{$type}[ $iterator ] )
773 | ? $this->{$type}[ $iterator ]
774 | : array();
775 | }
776 |
777 | /**
778 | * Get posts for a given cell
779 | *
780 | * @since 0.1.0
781 | *
782 | * @param int $iterator
783 | *
784 | * @return string
785 | */
786 | protected function get_posts_for_cell( $iterator = 1, $type = 'items' ) {
787 |
788 | // Get posts and bail if none
789 | $posts = $this->get_queried_items( $iterator, $type );
790 | if ( empty( $posts ) ) {
791 | return '';
792 | }
793 |
794 | // Start an output buffer
795 | ob_start();
796 |
797 | // Loop through today's posts
798 | foreach ( $posts as $post ) :
799 |
800 | // Setup the pointer ID
801 | $ponter_id = "{$post->ID}-{$iterator}";
802 |
803 | // Get the post link
804 | $post_link = get_edit_post_link( $post->ID );
805 |
806 | // Handle empty titles
807 | $post_title = get_the_title( $post->ID );
808 | if ( empty( $post_title ) ) {
809 | $post_title = esc_html__( '(No title)', 'wp-event-calendar' );
810 | } ?>
811 |
812 |
813 |
814 | get_event_classes( $post->ID ) . '">' . $this->get_pointer_title( $post ) . '';
870 | $pointer_content[] = '' . implode( ' ', $this->get_pointer_text( $post ) ) . '
';
871 |
872 | // Filter pointer content specifically
873 | $pointer_content = apply_filters( 'wp_event_calendar_pointer_content', $pointer_content, $post );
874 |
875 | // Filter the entire pointer array
876 | $pointer = apply_filters( 'wp_event_calendar_pointer', array(
877 | 'content' => implode( '', $pointer_content ),
878 | 'anchor_id' => "#event-pointer-{$post->ID}-{$day}",
879 | 'edge' => 'top',
880 | 'align' => 'left'
881 | ), $post );
882 |
883 | // Add pointer to pointers array
884 | $this->pointers[] = $pointer;
885 | }
886 |
887 | /**
888 | * Return the pointer title text
889 | *
890 | * @since 0.1.1
891 | *
892 | * @param object $post
893 | * @return string
894 | */
895 | protected function get_pointer_title( $post = false ) {
896 |
897 | // Get post type object
898 | $post_type_object = get_post_type_object( $post->post_type );
899 |
900 | // Handle empty titles
901 | $title = ! empty( $post->post_title )
902 | ? $post->post_title
903 | : esc_html__( '(No title)', 'wp-event-calendar' );
904 |
905 | // Title links to edit
906 | if ( current_user_can( $post_type_object->cap->edit_post, $post->ID ) ) {
907 | $retval = '' . esc_js( $title ) . ' ';
908 |
909 | // No title link
910 | } else {
911 | $retval = esc_js( $title );
912 | }
913 |
914 | // Filter & return the pointer title
915 | return apply_filters( 'wp_event_calendar_pointer_title', $retval, $post );
916 | }
917 |
918 | /**
919 | * Return the pointer title text
920 | *
921 | * @since 0.1.1
922 | *
923 | * @param object $post
924 | *
925 | * @return string
926 | */
927 | protected function get_pointer_text( $post = false ) {
928 | $pointer_text = $this->get_pointer_metadata( $post );
929 |
930 | // Append with new-line if metadata exists
931 | $new_line = ! empty( $pointer_text )
932 | ? ' '
933 | : '';
934 |
935 | // Special case for password protected posts
936 | if ( ! empty( $post->post_password ) ) {
937 | $pointer_text[] = $new_line . esc_html__( 'Password required.', 'wp-event-calendar' );
938 |
939 | // Post is not protected
940 | } else {
941 |
942 | // No content
943 | if ( empty( $post->post_content ) ) {
944 | $pointer_text[] = $new_line . esc_html__( 'No description.', 'wp-event-calendar' );
945 |
946 | // Attempt to sanitize content
947 | } else {
948 |
949 | // Strip new lines & reduce to allowed tags
950 | $the_content = wptexturize( $post->post_content );
951 | $the_content = wpautop( $the_content, true );
952 | $the_content = wp_kses( $the_content, $this->get_allowed_pointer_tags() );
953 | $the_content = preg_replace( '#\r|\n#', ' ', $the_content );
954 |
955 | // Texturize
956 | $pointer_text[] = $new_line . $the_content;
957 | }
958 | }
959 |
960 | // Filter & return the pointer title
961 | return apply_filters( 'wp_event_calendar_pointer_text', $pointer_text, $post );
962 | }
963 |
964 | /**
965 | * Get event metadata for display in a pointer
966 | *
967 | * @since 0.1.0
968 | *
969 | * @param object $post
970 | *
971 | * @return array
972 | */
973 | protected function get_pointer_metadata( $post = false ) {
974 | $pointer_metadata = array();
975 |
976 | // All day event
977 | if ( ( true === $this->item_all_day ) ) {
978 | $pointer_metadata[] = '' . esc_html__( 'All Day', 'wp-event-calendar' ) . ' ';
979 |
980 | } else {
981 |
982 | // Date & Time
983 | if ( ! empty( $this->item_start ) ) {
984 | $pointer_metadata[] = '' . esc_html__( 'Start', 'wp-event-calendar' ) . ' ';
985 | $pointer_metadata[] = sprintf( esc_html__( '%s on %s', 'wp-event-calendar' ), $this->get_event_time( $post, $this->item_start ), $this->get_event_date( $post, $this->item_start ) );
986 | }
987 |
988 | // Date & Time
989 | if ( ! empty( $this->item_end ) ) {
990 |
991 | // Extra padding
992 | if ( ! empty( $this->item_start ) ) {
993 | $pointer_metadata[] = '';
994 | }
995 |
996 | $pointer_metadata[] = '' . esc_html__( 'End', 'wp-event-calendar' ) . ' ';
997 | $pointer_metadata[] = sprintf( esc_html__( '%s on %s', 'wp-event-calendar' ), $this->get_event_time( $post, $this->item_end ), $this->get_event_date( $post, $this->item_end ) );
998 | }
999 | }
1000 |
1001 | // Filter & return the pointer title
1002 | return apply_filters( 'wp_event_calendar_pointer_metadata', $pointer_metadata, $post );
1003 | }
1004 |
1005 | /**
1006 | * Return array of allowed HTML tags to use in admin pointers
1007 | *
1008 | * @since 0.1.1
1009 | *
1010 | * @return allay Allowed HTML tags
1011 | */
1012 | protected function get_allowed_pointer_tags() {
1013 | return apply_filters( 'wp_event_calendar_get_allowed_pointer_tags', array(
1014 | 'a' => array(),
1015 | 'strong' => array(),
1016 | 'em' => array(),
1017 | 'img' => array()
1018 | ) );
1019 | }
1020 |
1021 | /**
1022 | * Output the pointers for each event
1023 | *
1024 | * This is a pretty horrible way to accomplish this, but it's currently the
1025 | * way WordPress's pointer API expects to work, so be it.
1026 | *
1027 | * @since 0.1.1
1028 | */
1029 | public function admin_pointers_footer() {
1030 | ?>
1031 |
1032 |
1033 |
1058 |
1059 |
1060 | display_tablenav( 'top' ); ?>
1079 |
1080 |
1081 |
1082 |
1083 | print_column_headers(); ?>
1084 |
1085 |
1086 |
1087 | '>
1088 | display_mode(); ?>
1089 |
1090 |
1091 |
1092 |
1093 | print_column_headers( false ); ?>
1094 |
1095 |
1096 |
1097 |
1098 | display_tablenav( 'bottom' );
1102 |
1103 | // End and flush the buffer
1104 | ob_end_flush();
1105 | }
1106 |
1107 | /**
1108 | * Message to be displayed when there are no items
1109 | */
1110 | public function no_items() {
1111 | // Do nothing; calendars always have rows
1112 | }
1113 |
1114 | /**
1115 | * Get classes for post in day
1116 | *
1117 | * @since 0.1.0
1118 | *
1119 | * @param int $post_id
1120 | */
1121 | protected function get_event_classes( $post_id = 0 ) {
1122 |
1123 | // Empty classes array
1124 | $classes = array();
1125 |
1126 | // Is the event all day?
1127 | $classes[] = get_post_meta( $post_id, 'wp_event_calendar_all_day' )
1128 | ? 'all-day'
1129 | : '';
1130 |
1131 | // Is the event all day?
1132 | $classes[] = get_post_meta( $post_id, 'wp_event_calendar_location' )
1133 | ? 'has-location'
1134 | : '';
1135 |
1136 | // Get event terms
1137 | $terms = wp_get_object_terms( $post_id, get_object_taxonomies( 'event' ) );
1138 | foreach ( $terms as $term ) {
1139 | $classes[] = "tax-{$term->taxonomy}";
1140 | $classes[] = "term-{$term->slug}";
1141 | }
1142 |
1143 | // Remove any empties
1144 | $classes = get_post_class( $classes, $post_id );
1145 |
1146 | // Join & return
1147 | return join( ' ', $classes );
1148 | }
1149 |
1150 | /**
1151 | * Is the current calendar view today
1152 | *
1153 | * @since 0.1.0
1154 | *
1155 | * @return bool
1156 | */
1157 | protected function is_today( $month, $day, $year ) {
1158 | $_month = (bool) ( $month == date_i18n( 'n' ) );
1159 | $_day = (bool) ( $day == date_i18n( 'j' ) );
1160 | $_year = (bool) ( $year == date_i18n( 'Y' ) );
1161 |
1162 | return (bool) ( true === $_month && true === $_day && true === $_year );
1163 | }
1164 |
1165 | /**
1166 | * Get classes for table cell
1167 | *
1168 | * @since 0.1.0
1169 | *
1170 | * @param type $iterator
1171 | * @param type $start_day
1172 | *
1173 | * @return type
1174 | */
1175 | protected function get_day_classes( $iterator = 1, $start_day = 1 ) {
1176 | $dow = ( $iterator % 7 );
1177 | $day_key = sanitize_key( $GLOBALS['wp_locale']->get_weekday( $dow ) );
1178 | $offset = ( $iterator - $start_day ) + 1;
1179 |
1180 | // Position & day info
1181 | $position = "position-{$dow}";
1182 | $day_number = "day-{$offset}";
1183 | $month_number = "month-{$this->month}";
1184 | $year_number = "year-{$this->year}";
1185 |
1186 | $is_today = $this->is_today( $this->month, $offset, $this->year )
1187 | ? 'today'
1188 | : '';
1189 |
1190 | // Assemble classes
1191 | $classes = array(
1192 | $day_key,
1193 | $is_today,
1194 | $position,
1195 | $day_number,
1196 | $month_number,
1197 | $year_number
1198 | );
1199 |
1200 | return implode( ' ', $classes );
1201 | }
1202 |
1203 | /**
1204 | * Display a calendar by month and year
1205 | *
1206 | * @since 0.1.0
1207 | */
1208 | protected function display_mode() {
1209 | // Performed by subclass
1210 | }
1211 |
1212 | /**
1213 | * Generate the table navigation above or below the table
1214 | *
1215 | * @since 0.1.0
1216 | *
1217 | * @access protected
1218 | * @param string $which
1219 | */
1220 | protected function display_tablenav( $which ) {
1221 | ?>
1222 |
1223 |
1224 |
1225 | extra_tablenav( $which );
1229 |
1230 | // Output year/month pagination
1231 | echo $this->pagination( $which );
1232 |
1233 | // Output month/week/day switcher
1234 | echo $this->view_switcher( $which ); ?>
1235 |
1236 |
1237 |
1238 |
1239 |
1258 |
1259 |
1260 |
1261 |
1262 |
1263 |
1264 | month ); ?>>get_month( $month_index ); ?>
1265 |
1266 |
1267 |
1268 |
1269 |
1270 |
1271 |
1272 |
1273 | 'doaction' ) );
1280 |
1281 | // Filter & return
1282 | return apply_filters( 'wp_event_calendar_get_extra_tablenav', ob_get_clean() );
1283 | }
1284 |
1285 | /**
1286 | * Paginate through months & years
1287 | *
1288 | * @since 0.1.0
1289 | *
1290 | * @param array $args
1291 | */
1292 | protected function pagination( $args = array() ) {
1293 |
1294 | // Parse args
1295 | $r = wp_parse_args( $args, array(
1296 | 'which' => 'top',
1297 | 'small' => '1 month',
1298 | 'large' => '1 year',
1299 | 'labels' => array(
1300 | 'today' => esc_html__( 'Today', 'wp-event-calendar' ),
1301 | 'next_small' => esc_html__( 'Next', 'wp-event-calendar' ),
1302 | 'next_large' => esc_html__( 'Next', 'wp-event-calendar' ),
1303 | 'prev_small' => esc_html__( 'Previous', 'wp-event-calendar' ),
1304 | 'prev_large' => esc_html__( 'Previous', 'wp-event-calendar' )
1305 | )
1306 | ) );
1307 |
1308 | // No botton pagination
1309 | if ( 'top' !== $r['which'] ) {
1310 | return;
1311 | }
1312 |
1313 | // Base URLs
1314 | $today = $this->get_base_url();
1315 |
1316 | // Calculate previous & next weeks & months
1317 | $prev_small = strtotime( "-{$r['small']}", $this->today );
1318 | $next_small = strtotime( "+{$r['small']}", $this->today );
1319 | $prev_large = strtotime( "-{$r['large']}", $this->today );
1320 | $next_large = strtotime( "+{$r['large']}", $this->today );
1321 |
1322 | // Week
1323 | $prev_small_d = date_i18n( 'j', $prev_small );
1324 | $prev_small_m = date_i18n( 'n', $prev_small );
1325 | $prev_small_y = date_i18n( 'Y', $prev_small );
1326 | $next_small_d = date_i18n( 'j', $next_small );
1327 | $next_small_m = date_i18n( 'n', $next_small );
1328 | $next_small_y = date_i18n( 'Y', $next_small );
1329 |
1330 | // Month
1331 | $prev_large_d = date_i18n( 'j', $prev_large );
1332 | $prev_large_m = date_i18n( 'n', $prev_large );
1333 | $prev_large_y = date_i18n( 'Y', $prev_large );
1334 | $next_large_d = date_i18n( 'j', $next_large );
1335 | $next_large_m = date_i18n( 'n', $next_large );
1336 | $next_large_y = date_i18n( 'Y', $next_large );
1337 |
1338 | // Setup month args
1339 | $prev_small_args = array( 'cy' => $prev_small_y, 'cm' => $prev_small_m, 'cd' => $prev_small_d );
1340 | $prev_large_args = array( 'cy' => $prev_large_y, 'cm' => $prev_large_m, 'cd' => $prev_large_d );
1341 | $next_small_args = array( 'cy' => $next_small_y, 'cm' => $next_small_m, 'cd' => $next_small_d );
1342 | $next_large_args = array( 'cy' => $next_large_y, 'cm' => $next_large_m, 'cd' => $next_large_d );
1343 |
1344 | // Setup links
1345 | $prev_small_link = add_query_arg( $prev_small_args, $today );
1346 | $next_small_link = add_query_arg( $next_small_args, $today );
1347 | $prev_large_link = add_query_arg( $prev_large_args, $today );
1348 | $next_large_link = add_query_arg( $next_large_args, $today );
1349 |
1350 | // Start an output buffer
1351 | ob_start(); ?>
1352 |
1353 |
1378 |
1379 |
1401 |
1402 |
1403 |
1404 |
1405 | modes as $mode => $title ) :
1409 |
1410 | $url = add_query_arg( 'mode', $mode );
1411 |
1412 | // Setup classes
1413 | $classes = array( 'view-' . $mode );
1414 | if ( $this->mode === $mode ) {
1415 | $classes[] = 'current';
1416 | } ?>
1417 |
1418 |
1419 |
1420 |
1421 |
1422 |
1423 |
1424 |
1425 |
1426 |
1427 |