Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DO NOT MERGE | new calendar endpoints #831

Closed
wants to merge 65 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
230fe93
95% working PoC for add-to-calendar endpoints
carstingaxion Aug 29, 2024
a1abe95
Validate & fix generated .ics against RFC standard
carstingaxion Aug 29, 2024
3a7a873
Fixes for CS
carstingaxion Aug 30, 2024
55c7501
Prepare for custom event rewrite base
carstingaxion Aug 30, 2024
c0db9ac
Abstract endpoints-idea into files
carstingaxion Sep 8, 2024
a0ac728
Add dashes to endpoints
carstingaxion Sep 8, 2024
21e348e
Refactor single ical endpoints
carstingaxion Sep 8, 2024
79bef2d
Introduce (WIP) ical-feed endpoints
carstingaxion Sep 8, 2024
c9bbdbe
Fix for CS
carstingaxion Sep 8, 2024
395f282
DRY out activation of Endpoint_types
carstingaxion Sep 10, 2024
5fedfe5
DRY out object types
carstingaxion Sep 10, 2024
1ab7870
Add alternate-links to <head>
carstingaxion Sep 10, 2024
d312f5e
DRY out feed template loading
carstingaxion Sep 10, 2024
4c2da83
TRY-TO DRY out rewrite attributes
carstingaxion Sep 10, 2024
60d6ff4
DRY out blogititle in feed titles
carstingaxion Sep 10, 2024
dba6f74
An Online-Event will have no Venue; prevent error on non-existent obj…
carstingaxion Sep 10, 2024
9efe58b
Send the Content-Length headers for files
carstingaxion Sep 10, 2024
ccc4273
Flush rewrite rules automatically when needed
carstingaxion Sep 10, 2024
9c9cbca
DRY out query_var (as it seems to work with just one)
carstingaxion Sep 10, 2024
5ade127
Check if tax is vieweable before creating endpoints
carstingaxion Sep 10, 2024
500f988
Revert having the query_var as static default for all Endpoint_Classes
carstingaxion Sep 10, 2024
7922947
Adjust some inline-docs
carstingaxion Sep 10, 2024
58af251
Fix for CS
carstingaxion Sep 10, 2024
278b3bd
Run on current_filter and prio +1
carstingaxion Sep 10, 2024
8d62c76
Remove call_user_func calls
carstingaxion Sep 10, 2024
65fa644
Adjust some inline-docs
carstingaxion Sep 10, 2024
56e6a6d
TRY different header params to try to fix the FF :bug:
carstingaxion Sep 10, 2024
e44f7af
Add missing use statement
carstingaxion Sep 10, 2024
ac00347
NEW docs about unit tests
carstingaxion Sep 12, 2024
a23a008
SoC for maintainability & testing
carstingaxion Sep 12, 2024
07d0976
Fix error
carstingaxion Sep 12, 2024
5b61419
Add 1st test
carstingaxion Sep 12, 2024
d4711de
Add Resources about pmc-unit-test to docs
carstingaxion Sep 12, 2024
d102280
NEW docs about endpoints (WIP)
carstingaxion Sep 13, 2024
05fa0fe
NEW "Export to & subscribe with..." features in main plugin README
carstingaxion Sep 13, 2024
fa3560e
Rename class to be more general
carstingaxion Sep 13, 2024
615a7d4
NEW static getter for endpoint URLs, similar to get_post_embed_url()
carstingaxion Sep 13, 2024
42b30a4
Rename folder to match headline
carstingaxion Sep 13, 2024
25f563c
Update example in docs
carstingaxion Sep 13, 2024
7df9372
Fix for CS
carstingaxion Sep 13, 2024
9f1bcee
Add Screenshot from the 'Rewrite Analyzer' plugin page with a matchin…
carstingaxion Sep 13, 2024
c3f84c0
Fix typo
carstingaxion Sep 13, 2024
786cd5f
Minor fix: Add full-stops.
carstingaxion Sep 13, 2024
0cb66a3
Prefix overrideable template file-names with 'gatherpress_'
carstingaxion Sep 13, 2024
c37112f
Rename files and integrate methods from Event()
carstingaxion Sep 15, 2024
e72d25c
Additional check on the rewrite URL to test if rewrites needs to be f…
carstingaxion Sep 15, 2024
bc2b246
WIP ical feed rendering
carstingaxion Sep 15, 2024
6a2a57e
Fix line breaks
carstingaxion Sep 15, 2024
213904f
Fix props author name
carstingaxion Sep 15, 2024
b7b5538
NEW docs/developer/theme-customizations
carstingaxion Sep 15, 2024
01c066f
fix typo
carstingaxion Sep 15, 2024
a6c6853
fix typos
carstingaxion Sep 16, 2024
38cb0b4
DRY out ical methods
carstingaxion Sep 16, 2024
ec12153
Fix for CS
carstingaxion Sep 16, 2024
fa3e35b
Query all (upcoming & past) events for ical feeds
carstingaxion Sep 16, 2024
9a8be7e
Rename methods
carstingaxion Sep 16, 2024
cdea924
Fix syntax errors (in php 7.4)
carstingaxion Sep 16, 2024
bacb2e9
DRY out sending the ics to the browser (for files and feeds)
carstingaxion Sep 16, 2024
dc696b4
Fix for CS
carstingaxion Sep 17, 2024
91960ca
Update 'covers'
carstingaxion Sep 17, 2024
8c2bd81
WIP updating tests
carstingaxion Sep 17, 2024
3146cf4
Fix for CS
carstingaxion Sep 17, 2024
4ad39a6
Update docs about theme_supports
carstingaxion Sep 17, 2024
ae0e3f5
Replace xcal with ical (as it is not xcal)
carstingaxion Sep 17, 2024
f6530c5
Remove the union return type declarations to become compatible with P…
carstingaxion Sep 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions docs/contributor/unit-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# PHP Unit tests

GatherPress allows to run **automated & manual php unit tests**, while sharing the same, `wp-env` based, setup.

## Automated tests

Check the results of the [*phpunit-tests action workflow*](https://github.com/GatherPress/gatherpress/actions/workflows/phpunit-tests.yml) at `https://github.com/GatherPress/gatherpress/actions/workflows/phpunit-tests.yml`.

## Manual tests

The unittest-setup can also be used to manually run the test suite. In general, only a `wp-env` instance is needed.

### Install dependencies

To run the unit tests you will have to install the requirements using the following commands:

```bash
composer install
```

> [!NOTE]
> You also need to use Node.js 20 or later

Install the dependencies to create the Playground testing instance, using the following command:

```bash
npm ci --legacy-peer-deps
```

### Start the Environment

A call to `npm run test:unit:php` will automatically setup a `wp-env` powered WordPress instance, already prepared to mount GatherPress from the current directory.

So while there is no technical need to start `wp-env` manually on its own, you might want to do so for any reason. If the environment is already running, the unit tests will run against that existing instance. You might want to start it with this command:


```bash
npm run wp-env -- start
```

The testing website is reachable at `http://127.0.0.1:8889`, the user is `admin` and the password is `password`.

### Run the unit tests

To run the full suite with all unit tests, use the command:

```bash
npm run test:unit:php
```

To run only specific tests, you can call `npm run test:unit:php`:

- with the `--filter` argument,
to execute all tests in `test/unit/php/includes/core/classes/class-test-event-query.php` for example:

```bash
npm run test:unit:php -- --filter 'Test_Event_Query'
```

- with the `--group` argument, to execute all tests which share the same `@group` declaration, for example all tests related to `/ical` and `/feed/ical` endpoints of events & venues:

```bash
npm run test:unit:php -- --group endpoints
```

- or with any other of [phpunit's command-line options](https://docs.phpunit.de/en/10.5/textui.html#command-line-options).

## Resources

### PMC Unit Test Framework

GatherPress uses the *PMC Unit Test Framework* because it:

> [...] provide[s] common utilities and data mocking for unit tests in a WordPress environment.

> This plugin was originally written for internal use at Penske Media [...] Our hope is that other teams find this plugin as useful as we do when writing unit tests in WordPress.
>
> https://github.com/penske-media-corp/pmc-unit-test

* [Installation](https://github.com/penske-media-corp/pmc-unit-test/tree/main?tab=readme-ov-file#installation)
* [Usage](https://github.com/penske-media-corp/pmc-unit-test/tree/main?tab=readme-ov-file#usage)
* [Data Mocking Overview](https://github.com/penske-media-corp/pmc-unit-test/blob/main/src/mocks/README.md)
* [$this->mock->http()](https://github.com/penske-media-corp/pmc-unit-test/blob/main/docs/mock-http.md)
* [$this->mock->input()](https://github.com/penske-media-corp/pmc-unit-test/blob/main/docs/mock-input.md)
* [$this->mock->mail()](https://github.com/penske-media-corp/pmc-unit-test/blob/main/docs/mock-mail.md)
* [$this->mock->post()](https://github.com/penske-media-corp/pmc-unit-test/blob/main/docs/mock-post.md)
* [$this->mock->post()->is_amp()](https://github.com/penske-media-corp/pmc-unit-test/blob/main/docs/mock-post.md)
* [$this->mock->user()](https://github.com/penske-media-corp/pmc-unit-test/blob/main/docs/mock-user.md)
* [$this->mock->wp()](https://github.com/penske-media-corp/pmc-unit-test/blob/main/docs/mock-wp.md)
2 changes: 1 addition & 1 deletion docs/developer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ cd gatherpress
wp-env start
```

You should then see that a development site has been configured for you on localhost port 2003
You should then see that a development site has been configured for you on localhost port 8889

![Development Site Login](../media/wp-env.json-startup.png)

Expand Down
224 changes: 224 additions & 0 deletions docs/developer/custom-url-endpoints/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
# Custom URL Endpoints

GatherPress provides some different and custom URL endpoints, for example `/ical` and `/feed/ical`.

**Existing custom endpoints:**

- `example.org/event/my-sample-event/ical`

provides a download-able .ics file in ical format.

- `example.org/event/my-sample-event/outlook`

provides the same download-able file as an alias.

- `example.org/event/my-sample-event/google-calendar`

redirects to create a new event in *Google Calendar*.

- `example.org/event/my-sample-event/yahoo-calendar`

redirects to create a new event in *Yahoo Calendar*.

- `example.org/event/feed/ical`

provides a subscribe-able event feed in ical format with all events of the site.

- `example.org/venue/my-sample-venue/feed/ical`

provides a subscribe-able event feed in ical format with all events at that venue.

- `example.org/topic/my-sample-topic/feed/ical`

provides a subscribe-able event feed in ical format with all events grouped into that topic.

The most obvious functions to create such within WordPress seem to be [`add_feed()`](https://developer.wordpress.org/reference/functions/add_feed/) and [`add_rewrite_endpoint()`](https://developer.wordpress.org/reference/functions/add_rewrite_endpoint/) for this purpose.

Unfortunately both functions share a common pitfall, they are not restricitive to any post type at all. That would result in having a `/feed/ical` endpoint for all posts AND every other non-hierarchical, custom post type which seemed to be the wrong way to go. A lot of code would have had to be written, to patch this behavior and remove those superfluous endpoints.

That's why GatherPress created its own Endpoint ~~API~~ helper and tries to fix the mentioned problems before they appear.

## GatherPress' own Endpoint API

In opposite to the former mentioned WordPress core functions GatherPress Endpoint API is flexible enough to not *only* provide endpoints for GatherPress. You can utilize its classes to create a plenty of different endpoints for your post types and taxonomies as well.

In general, one endpoint can be created ...

- for individual posts
- for post type archives
- for taxonomy archives

It can be either ...

- a redirect

*or*

- a template to load


### Setup new endpoints

To create a new endpoint you will want to create a new instance of the *pure* [`Endpoint()`](https://github.com/GatherPress/gatherpress/tree/main/includes/core/classes/endpoints/class-endpoint.php) class or one of its sub-classes:

- [`Posttype_Single_Endpoint()`](https://github.com/GatherPress/gatherpress/tree/main/includes/core/classes/endpoints/class-posttype-single-endpoint.php)

for endpoints like `example.org/cpt/my-custom-post-type/new-endpoint`

- [`Posttype_Single_Feed_Endpoint()`](https://github.com/GatherPress/gatherpress/tree/main/includes/core/classes/endpoints/class-posttype-single-feed-endpoint.php)

for endpoints like `example.org/cpt/my-custom-post-type/feed/new-endpoint`

- [`Posttype_Feed_Endpoint()`](https://github.com/GatherPress/gatherpress/tree/main/includes/core/classes/endpoints/class-posttype-feed-endpoint.php)

for endpoints like `example.org/cpt/feed/new-endpoint`

- [`Taxonomy_Feed_Endpoint()`](https://github.com/GatherPress/gatherpress/tree/main/includes/core/classes/endpoints/class-taxonomy-feed-endpoint.php)

for endpoints like `example.org/ctax/feed/new-endpoint`

These classes help to select *where* an endpoint should run.

To become properly callable as URL, the endpoints needs to know *what* to do when some URL is requested. Therefore each `Endpoint()` needs to have at least one of either:

- [`Endpoint_Redirect()`](https://github.com/GatherPress/gatherpress/tree/main/includes/core/classes/endpoints/class-endpoint-redirect.php)

*or*

- [`Endpoint_Template()`](https://github.com/GatherPress/gatherpress/tree/main/includes/core/classes/endpoints/class-endpoint-template.php)

## Example 1 | Add events to *Office365 Calendar*

Example for a new redirection endpoint like `example.org/event/my-sample-event/office365-calendar`

- ### 1. Setup a new endpoint

Let's create an endpoint to immediately add an event to a *Office365 Calendar*, similar to the existing for *Google* and *Yahoo*.

![Screenshot from the 'Rewrite Analyzer' plugin page with a matching rewrite for office365-endpoint from this example.](./custom-url-endpoints__office365-calendar.png)

To set up a new endpoint for single events, use the [`Posttype_Single_Endpoint()`](https://github.com/GatherPress/gatherpress/tree/main/includes/core/classes/endpoints/class-posttype-single-endpoint.php) class.

```php
use GatherPress\Core\Endpoints\Posttype_Single_Endpoint;
use GatherPress\Core\Endpoints\Endpoint_Redirect;
```
```php
new Posttype_Single_Endpoint(
array(
new Endpoint_Redirect(
'office365-calendar',
array( $this, 'get_office365_calendar_link' )
),
),
'gatherpress_awesome_calendar',
);
```

> [!TIP]
> Run this on the `registered_post_type_{post_type}` action, to ensure that custom endpoints are registered after their post type is initialized. GatherPress will trigger php warnings if called too early or or with unsupported arguments.

- ### 2. Define the callback for the endpoint

```php
use GatherPress\Core\Event;
```
```php

/**
* Returns the office365 calendar URL for the current event.
*
* This method generates the appropriate URL for Office 365 Calendar.
* It uses the `Event` class to retrieve the necessary data for the event.
*
* @since 1.0.0
*
* @return string The URL to redirect the user to the appropriate calendar service.
*/
public function get_office365_calendar_link(): string {

$event = new Event( get_queried_object_id() );
$date_start = $event->get_formatted_datetime( 'Ymd', 'start', false );
$time_start = $event->get_formatted_datetime( 'His', 'start', false );
$date_end = $event->get_formatted_datetime( 'Ymd', 'end', false );
$time_end = $event->get_formatted_datetime( 'His', 'end', false );

// Format the start and end datetime in the required format
$startdt = sprintf('%sT%sZ', $date_start, $time_start);
$enddt = sprintf('%sT%sZ', $date_end, $time_end);

$venue = $event->get_venue_information();
$location = $venue['name'];
$description = $event->get_calendar_description();

if ( ! empty( $venue['full_address'] ) ) {
$location .= sprintf( ', %s', $venue['full_address'] );
}

$params = array(
'subject' => sanitize_text_field( $event->event->post_title ),
'body' => sanitize_text_field( $description ),
'startdt' => $startdt,
'enddt' => $enddt,
'location' => sanitize_text_field( $location ),
'path' => '/calendar/action/compose',
'rru' => 'addevent',
);

return add_query_arg(
rawurlencode_deep( $params ),
'https://outlook.office.com/calendar/0/deeplink/compose'
);
}
```

- ### 3. Use & retrieve the endpoint

To use the newly created endpoints, you can use `Endpoints::get_url()` and rely on the used WordPress core functions internally:

```php
use GatherPress\Core\Endpoints;
```
```php
Endpoints::get_url(
'office365-calendar'
get_queried_object_id(),
'gatherpress_awesome_calendar',
);
```




## Resources

- Full, working code from all examples as part of **GatherPress Awesome**.

Within [your GatherPress Awesome plugin](https://github.com/GatherPress/gatherpress-awesome), just enable it in `gatherpress-awesome/includes/classes/class-setup.php`

```php
// ENABLE or DISABLE
// Test adding some awesome endpoints!
// Awesome_Endpoints::get_instance(); // <-- Un-Comment to ENABLE
```

```php
// ENABLED
// Test adding some awesome endpoints!
Awesome_Endpoints::get_instance(); // <-- :tada:
```

### Testing & Validating

- [iCalendar Validator](https://icalendar.org/validator.html)
- [Monkeyman Rewrite Analyzer – WordPress plugin | WordPress.org](https://wordpress.org/plugins/monkeyman-rewrite-analyzer/)

### used & related from WordPress

-

#### *explicitly not used*, but related from WordPress

- [`add_feed()`](https://developer.wordpress.org/reference/functions/add_feed/)
- [`add_rewrite_endpoint()`](https://developer.wordpress.org/reference/functions/add_rewrite_endpoint/)

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 65 additions & 0 deletions docs/developer/theme-customizations/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Theme customizations

1. [Template overrides](#template-overrides)
2. [Theme supports](#theme-supports)

## Template overrides

GatherPress provides different ways to customize its output via theme files. Some of this customization opportunities come from GatherPress, but the most are just pure WordPress. A site could provide one or more of the following templates from one of:

- a child theme’s `/templates` folder (if child theme is active).
- the theme’s `/templates` folder.

### Default template overrides

Following the [default WordPress template hierarchy](https://developer.wordpress.org/themes/templates/template-hierarchy).

#### Events

- `archive-gatherpress_event.(html|php)`
- `single-gatherpress_event.(html|php)`
- `single-gatherpress_event-{post_name}.(html|php)`
- `embed-gatherpress_event.php`

Due to [a known issue](https://developer.wordpress.org/themes/templates/template-hierarchy/#embed-hierarchy) embed templates can only be created as `.php` files.

#### Venues

- `single-gatherpress_venue.(html|php)`
- `single-gatherpress_venue-{post_name}.(html|php)`
- `embed-gatherpress_venue.php`

#### Topics

- `taxonomy-gatherpress_topic.(html|php)`
- `taxonomy-gatherpress_topic-{term_slug}.(html|php)`

### Overriding plugin template

In addition to the default theme files, a theme author could add the following templates to override special templates, normally provided by the GatherPress plugin:

- `gatherpress_ical-download.php`
- `gatherpress_ical-feed.php`

## Theme supports

GatherPress does respect [theme_supports](https://developer.wordpress.org/reference/functions/current_theme_supports/) definitions and will output the following pieces only if the current theme supports it.

- When **`automatic-feed-links`** are supported, GatherPress will add `rel="alternate"` links to the `<head>` of each view, with the URLs to the relevant iCal feed links. This will be:

- For all requests (`example.org/*`):
- `example.org/event/feed/ical`

- For singular event requests (`example.org/event/my-sample-event`):
- `example.org/event/feed/ical`
- `example.org/event/my-sample-event/ical`
- `example.org/venue/my-sample-venue/feed/ical` (if its not an Online-Event)
- `example.org/topic/my-sample-topic/feed/ical` (if a topic is selected)

- For singular venue requests (`example.org/venue/my-sample-venue`):
- `example.org/event/feed/ical`
- `example.org/venue/my-sample-venue/feed/ical`

- For topic term requests (`example.org/topic/my-sample-topic`):
- `example.org/event/feed/ical`
- `example.org/topic/my-sample-topic/feed/ical`
1 change: 1 addition & 0 deletions includes/core/classes/class-autoloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ static function ( string $class_string = '' ): void {

switch ( $class_type ) {
case 'commands':
case 'endpoints':
case 'settings':
case 'traits':
array_pop( $structure );
Expand Down
Loading
Loading