Create users in WordPress using the REST API

For a current project, we use WordPress as the backend for a native mobile app. The app is developed by another company. I’m responsible for the WordPress part. The content for the app is being created using multiple custom post types and custom taxonomies, as well as some special blocks for a better editing experience. The app can be used without any registration. But some features need a registration, such as synchronizing results on multiple devices or comparing results with other users.

Preparing the server to accept requests

In order to make requests to the server, some response headers have to be set, especially for the iOS version. I first tried to set them using the server configuration, just to realize, that WordPress sets some response headers as well, which resulted in some duplicate headers with the same key, but different values. After some debugging I’ve found some hooks I could use:

function app_rest_headers_allowed_cors_headers( $allow_headers ) {
	return array(
		'Origin',
		'Content-Type',
		'X-Auth-Token',
		'Accept',
		'Authorization',
		'X-Request-With',
		'Access-Control-Request-Method',
		'Access-Control-Request-Headers',
	);
}
add_filter( 'rest_allowed_cors_headers', 'app_rest_headers_allowed_cors_headers' );

For another hook there was no filter, so I had to explicitly call the PHP header() function for this one:

function app_rest_headers_pre_serve_request( $value ) {
	header( 'Access-Control-Allow-Origin: *', true );
	return $value;
}
add_filter( 'rest_pre_serve_request', 'app_rest_headers_pre_serve_request', 11 );

After this small preparation, we can try to create a user with the users endpoint, but this is not going to work. Why not? Well, simply because you cannot create a user for a WordPress site using the REST API without authorization. If that would be possible, that wouldn’t really be good, because otherwise anyone could register a user on an WordPress site.

Authenticate a user with the REST API

So how to we authenticate against the REST API? There are different ways. A very new one is just around the corner and it’s going to be the first one to be integrated into Core: Application Passwords.

There is currently a proposol to integrate the feature project into the upcoming WordPress 5.6. If you want to use it already, you can install the plugin Application Passwords.

Create an app user for the user management

By default, only admin users can manager users. But you probably don’t want to allow an app to have every capability an admin has on a WordPress site. Therefore it’s better to create a special user that only has those capabilitites managing users. You can do that by using a plugin like Members, create a role and a user with PHP code or you use the WP-CLI:

wp role create app App --clone=subscriber
wp cap add app create_users
wp user create app-rest-user app-rest-user@example.com --role=app

The user needs to have at least the create_users capability to manage users and you should also add the read capability, so you can login with the new user and set the application password (this is why we clone the “subscriber” role in the example above). Alternatively you can set the application password for a user with an admin user.

Get the application password for the new user

After you have created the user, login with that user and navigate to the profile settings (or edit it’s profile with an admin user). Here you find a new profile field to create application passwords. Choose a name and hit “Add new”:

This will open a modal with the generated password. You have to copy that password from the modal, as you cannot get it’s plain text after closing the modal.

Now we have everything we need for your API call to create users.

Create your first user

Depending on which system you use to make calls against the WordPress REST API, you workflow looks different. I’ll just use a plain curl call from the terminal to demonstrate the request:

curl --user "app-rest-user:younfj4FX6nnDGuv9EwRkDrK" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"username":"jane","password":"secret","email":"jane@example.com"}' \
     http://example.com/wp-json/wp/v2/users

If you have set up everything correct, you should get a JSON response with the data of the new user.

Conclusion

Managing users is possible without some setup work and (currently) some external authentication plugins, but with the new applications password feature it will become a lot easier. In a similar way you can make any other call to the REST API that needs an authorized user. For better security, it’s best to create a specific user for such calls (unless you want to create content assigned to a specific user).

Deactivate individual block styles

In my last blog post I’ve showed you how to deactivate page templates in a child theme and this week I have another tip on how to deactivate some of the things that might come with a parent theme or a plugin. Today I will write about block styles. They are normally defined by Core or the theme, but sometimes they are introduced by plugins.

Deactivate them using a dequeue hook

Block styles are defined using a JavsScript file. That file must be enqueued into the page. This is where we can use a hook to dequeue that file. It could look like this:

function dibs_dequeue_assets() {
	wp_dequeue_script( 'editorskit-editor' );
}
add_action( 'enqueue_block_editor_assets', 'dibs_dequeue_assets', 11 );

This example would remove the main editor JavaScript file, which will not only disable block styles, but all JavaScript code of that plugin. So this is only a good solution, if there is a separate file just with the registrations of block styles.

Deactivate specific block styles

If you just want to remove specific block styles from the backend, you have to use some JavaScript code yourself. So first we have to enqueue a JavaScript file we can then use:

function dibs_enqueue_assets() {
	wp_enqueue_script(
		'dibs-remove-block-styles',
		plugins_url( 'remove-block-styles.js', __FILE__ ),
		array( 'wp-blocks', 'wp-dom-ready', 'wp-edit-post' ),
		filemtime( plugin_dir_path( __FILE__ ) . 'remove-block-styles.js' ),
		true
	);
}
add_action( 'enqueue_block_editor_assets', 'dibs_enqueue_assets', 11 );

The enqueued file need the dependencies wp-blocks, wp-dom-ready and wp-edit-post to work properly. After we have enqueued the file, we can use it to unregister some block styles:

wp.domReady( function() {
	wp.blocks.unregisterBlockStyle(
		'core/image',
		'editorskit-diagonal'
	);
	wp.blocks.unregisterBlockStyle(
		'core/image',
		'editorskit-inverted-diagonal'
	);
	wp.blocks.unregisterBlockStyle(
		'core/cover',
		'editorskit-diagonal'
	);
	wp.blocks.unregisterBlockStyle(
		'core/cover',
		'editorskit-inverted-diagonal'
	);
} );

After the editor has loaded, we will use wp.blocks.unregisterBlockStyle() with the first parameter set to the slug of the block we want to unregister a block style for. The second parameter is the slug of the block style. In this example we would remove the same two block styles from the core/image and from the core/cover block.

This approach is likely the one you want to use, as you don’t want to remove the complete JavaScript as in the first snippet, but only the block styles. And of those you might want to remove only a few.

Conclusion

If a theme or plugin introduces block styles, you don’t want to use, you can use a small JavaScript file to remove them. You just have to be aware, that even if you remove the block styles from being selected for new blocks, the previously selected block styles are still attached to block with the corresponding CSS file. So if you want to remove the block styles from the front end as well, you either have to remove the CSS classes on the old blocks or remove/overwrite the CSS parts in your (child) theme.

Deactivate or replace a page templates in a child theme

This week one of my colleagues was working on a new project, where a page template in the parent theme was broken. There was a better similar page template to use instead, but there might still be the chance that someone would use this broken page template, when creating a new page. So I had the idea to find out, how to deactivate a page template from the dropdown.

Deactivate a page template

In a child theme, it is quite easy to create a new page template or to overwrite a page template, by copying it over from the parent theme. But how can you prevent a page template from showing up in the dropdown? Fortunately, there is almost always a hook for that. If you want to deactivate a page template, use this filter:

function child_theme_disable_page_template( $post_templates, $theme, $post, $post_type ) {
	unset( $post_templates['page-templates/tpl-hero-light.php'] );
	return $post_templates;
}
add_filter( 'theme_templates', 'child_theme_disable_page_template', 10, 4 );

The filter theme_templates will get an array with all templates, using the relative path as the key and the (translated) name as a value. It could look like this:

$post_templates = array(
	'page-templates/tpl-fullscreen-light.php'  => 'Fullscreen, light header',
	'page-templates/tpl-fullscreen.php'        => 'Fullscreen',
	'page-templates/tpl-fullwidth-notitle.php' => 'Full Width, no page title',
	'page-templates/tpl-fullwidth.php'         => 'Full Width',
	'page-templates/tpl-hero-light.php'        => 'Hero, light header',
	'page-templates/tpl-hero.php'              => 'Hero',
);

The array contains page templates from both the parent theme and the child theme. If both have a page template with the same path, only one of it will be included in the array.

Replace a page template

So now you know how to avoid someone from using a page template you don’t want them to use. But what about all the pages that already have that page template selected? You could do a search/replace in the database, replacing all postmeta with the key _wp_page_template and replace it with a new value. But maybe you want to keep the information in the database intakt. Then you can use a variety of hooks to overwrite the path. This is one of the filters you can use:

function child_theme_overwrite_page_template( $template ) {
	if ( get_parent_theme_file_path( '/page-templates/tpl-hero-light.php' ) === $template ) {
		return get_theme_file_path( '/page-templates/tpl-hero.php' );
	}
	return $template;
}
add_filter( 'template_include', 'child_theme_overwrite_page_template' );

In this example, any page that would use the page-templates/tpl-hero-light.php page template from the parent theme will now be using the page-templates/tpl-hero.php page template from the child theme.

Conclusion

While it’s very easy to add or overwrite page templates in a child theme, deactivating one in a child theme is not as easy. But as WordPress usually has a hook for anything you want to customize, even this task is not that hard.

Manually update or downgrade plugins and themes with WordPress 5.5

The lastest WordPress major release 5.5 was released mid August. There have been some nice new features. But one of these new features has not been mentioned in many posts about the new release. It’s the possibility to replace an installed plugin or theme using a zip file.

Some previous ways to replace an installed plugin or theme

In WordPress, it’s really easy to update a plugin or theme to the newest version (at least for all plugins available on WordPress.org). But downgrading a plugin or theme to an old version or updating premium versions is not that easy.

Using the WP-CLI

If you use the WP-CLI, you can use the install command for plugins or themes to install a specific version. If that plugin or theme is already installed, you simply force install it:

wp plugin install gutenberg --version=8.9.0 --force

This will overwrite the current version with the given version. This is only possible if that version is available through the WordPress.org plugin or theme directory.

Uploading the old version using SFTP/FTPS/FTP

If you don’t have access to the server though SSH and/or can’t use the WP-CLI on the server, you can use a file transfer client to delete the old version and replace it with a different one. This approach has the bis drawback, that you first have to manually delete the old version and then upload the new one. Depending on how large the plugin is and how many files it has, this can take some time and your site might be broken while you are replacing the plugin. You could minimize that time by uploading the old version to a different folder and then rename the current version (or delete it) and rename the old version to the correct folder name. But still this way is not really ideal.

Deactivate and uninstalling the current version

Some of you might think that you can simply deactivate and uninstall the current version and then you install the old version. This can be really risky. Many plugins delete their settings when they are deactivated/uninstalled, some even the data created by those plugins. So this way should really be avoided.

Replace the current version with the new WordPress 5.5 feature

When you’ve updated to WordPress 5.5, you have a very new way. To use it, you simply have to upload the old version as a zip file. You can get an old version either from you backup or from the WordPress.org plugin or theme directory.

Download an old version of a plugin

For a plugin that’s very easy. Just navigate to the plugin page on the WordPress.org plugin directory and click on the “Advanched View” link on the right:

Here you scroll all the way to the bottom, where you can find a dropdown with previous version. These are all versions the plugin authors have tagged/released:

Select the version you want to have and click on the download button. This should get you a zip file with that specific version. If you can’t find that dropdown, then unfortunately the developers have never tagged a specific version.

Upload the old version and replace the current version

Now you can upload that version. This works just as installing a plugin or theme for the first time. So in your dashboard you navigate to “Plugins | Add New” and then click on the “Upload Plugin” button next to the headline. Then you use the file upload form and click “Install Now” to upload the zip file. This will then show you a screen like this:

You will be presented with a page showing you the current version of the plugin and the uploaded version. For both you will see which version of WordPress and PHP they require. If you want to continue, click on the blue “Replace current with uploaded” button.

Conclusion

Sometimes even the smaller features of a release can make a huge difference for users. Downgrading plugins or themes was not an easy task in the past. But when your site crashed after an update, there is a big need to get back to an old version. This new feature will come in very handy for those cases. But it will also help you if the premium plugins or theme you are using does not integrate into the update mechanism of WordPress.

Order post type navigation by name

On many client projects, there is a need to create custom post types. I usually create them using the wp scaffold post-type command from the WP-CLI. This will create the necessary PHP functions with the most common definitions and a large array where you can set nice labels. But in the most basic way, registering a post type could looks like this:

function optn_register_post_type() {
	register_post_type(
		'sponsor',
		array(
			'label'       => __( 'Sponsor', 'optn' ),
			'public'      => true,
			'has_archive' => true,
			'show_ui'     => true,
		)
	);
}
add_action( 'init', 'optn_register_post_type' );
Read more →

Organizing WordCamps in times of a world wide pandemic

Around two weeks ago, the Global Leads, the Local Lead and the Mentor of WordCamp Europe 2021 took the hard decision to postpone the in-person event in 2021 in Porto for another year and organize the next edition of WCEU online again. After the great success of this year’s event, the new organizing team will have the chance to organize an even bigger event in 2021, giving them more time focusing on the special needs for an online event. The Call for organizers ended just around a week ago. I’m wishing the new organizing team all the best – which I will not be a part of.

Read more →

Use startup tasks as a replacement for file watchers in PhpStorm

Last week I started with a new project and developed a theme using Underscores as the base theme. I always use the “sassified” version and create it with the WP-CLI scaffold command. When I inspected the files, I could see some new files in the directory. But one of the files that is included for quite some time is the package.json file, defining various npm tasks, of which some are responsible to compile Sass files or watch for file changes on those files.

Using file watchers from PhpStorm

In the past I have usually used the file watchers from PhpStorm. In a blog post from January 2018, I’ve explained how to set such a file watcher up to compile Sass files. This is a good way when you don’t have any other mechanism to compile those files bundled with the software/theme/plugin. But if you develop something that has a compilation task defined in the projects, things can get more complicated, especially when you work in a team with members of that team using different operation systems and default Sass compilers. In the past a Ruby compiler was the recommended option, but as of March 2019, this option has been depecated. Now it’s recommended to use either Dart Sass or Lib Sass to compile your files. I’ve tried out Dart Sass, as it was the only compiler that was producing the exact same CSS files on Windows, Linux and Mac in my tests.

So why not just use one of the new compilers in combination with a PhpStorm file watcher? There are two reasons. First, those file watchers are not easy to set up, especially when the folder structure is different to the default structure. This is the case for Underscores, where the style.scss files it stored in the sass sub folder, but the compiled style.css file is in the root folder. The seconds reason is the possibility of additional compilation tasks defined in the package.json file. A common example for that is a PostCSS plugin like the Autoprefixer. Those compilers would not run on the Sass file watcher in PhpStorm.

Running a watcher from the package.json file

You can run an npm (or similar) task in PhpStorm in two ways. You either start a terminal and run the command there (which will exit, as soon as you close the terminal) or you run it using “Task | Run Gulp/Grunt/npm Task” from the menu bar.

Screenshot of the "Run npm Task" window

From here you simply double click one of the tasks and it will run in a new task window in PhpStorm. But every time you develop on that project, you have remember to start that task manually, while the file watcher was “starting” automatically. So isn’t there a better way?

Using a startup task to run the watcher

Fortunately there is a very easy way I’ve found some weeks ago. You can define startup tasks that would run every time you open a project in PhpStorm. In the settings at “Tools|Starup Tasks” you can choose from a wide variety of tasks to run. One of them is npm. So first, you just add such a startup task:

Screenshot of the "Settings | Tools | Startup Tasks" window with "npm" selected as the new type of task to add

If you have ran the npm task manually before, as described above, you can simply select it on the left. If you haven’t you simply create a new task giving it a name, selecting the package.json file and the command and script to run on startup:

Screenshot of the npm run configuration setting

Once you’ve set the startup task, simply restart PhpStorm or close and reopen the project to test the startup task. You should see the same run window opening as in the manual run.

Conslusion

The file watchers in PhpStorm are really useful when you work on a project that is not using any task runner. But it’s limited and the setup can be more complicated. Using the startup tasks makes it a lot easier to use the tasks bundled in a projects and ensures that you and your team are all using the same tasks. This can dramatically reduce issues like merge conflict on differently complied files and similar issues.

Cleaning up space on your development environment

Even the largest hard drive has a limit. From time to time, you have to clean up some file to be able to work on some new projects. Working on multiple WordPress projects, old and new ones, can use up a lot of storage. In a previous blog post from earlier this year, I’ve showed you how to save storage by loading images from a live website. As images and other files in the uploads folder are usually the largest parts of a WordPress website, this already helps a lot. But there is another type of files, that can easily fill up you hard drive in now time: database dumps.

Finding large database dumps

When you work on projects that have already gone live, you probably want to get the latest database from the live website and import it locally. But you might also have done some settings in your local environment, so you make a backup of the local database before replacing it with the live one. That’s already two dumps. Then you play around a bit with the content and just in case make some more backups. And as some WordPress databases easily have some hundred megabytes, your free disk space is reduced quite fast. So the first step you should take is to find all those large database dumps on your local disk. For that, you can simply run this command in the main local development folder:

find . -type f -size +10M -name "*.sql"

This command will find any SQL dump that is larger then 10 MB. You might even want to search for smaller files, if you have lots of them which sums up to some hundred megabytes in total. If you wand to see how large all of these files are, you simply extend the command and run it through the du command:

find . -type f -size +10M -name "*.sql" -exec du -h "{}" \;

Now that you have found all of these files, you can delete those you really don’t need anymore. But what about files you still might need?

Compressing all database dumps

Well, you can simply use another command and compress all of them in one go. You just have to run this command:

find . -type f -size +10M -name "*.sql" -exec gzip "{}" \;

This will compress all database dumps larger than 10 MB using the gzip command. I’ve run that command on my work laptop some days ago and was able to save more than 3.5 GB on my drive. It only took about 90 seconds to run. If I need to restore any of the compressed dumps, I would use ungzip them before and then import the dump into the database.

Find other large files

Once you’ve done with compressing all database dumps, why not search for other types of large files that can easily be compress or deleted? Some other good candidates are logfiles, like the debug.log you will find in the wp-content folder, when you’ve activated the WP_DEBUG_LOG in an installation. To find those files, either replace the search pattern or just remove it completely, to find all large files:

find . -type f -size +10M -exec du -h "{}" \;

Searching without a file extension will probably also show you a lot of media files, that are easily large as well. But then you might use the trick mentioned earlier to load those from a remote server.

Another type of files you may find are XML files. They may come from the WordPress XML Exporter, but they could also some other type of files, that needes to be left uncompressed.

Caveat

Some of you may think now “Why not just compress all .sql files?”, but this can cause some issues. If you search without the size filter, you will find some files within plugins. Those files are usually used to create the necessary database tables, when installing/activating the plugin. If you compress them, the plugin can probably now longer use them. So don’t use a to low file size in the filter. On my system 1 MB was even small enough to catch all real database dump but not those special files. The same is true for some XML files mentioned earlier. And you can’t compress logfiles, if you still want to write to them. So don’t just compress every text file that is too large.

Conclusion

Having a lot of projects on needs a lot of disk space. Knowing how to save some of this valuable space is crucial, especially when you can’t simply upgrade the hard drive in your hardware. Compressing all those database dump quickly cleanup up a lot of disk space for me in no time and without the need to decide on every file, weather I still need it or not.

Fixing the Markdown editor in PhpStorm

I’ve probably wrote in earlier blog posts, that I usually use PhpStorm when developing websites. Some weeks ago, every time when I have tried to open a Markdown file, I got the following error:

PhpStorm error message: "Tried to use preview panel provider (JavaFX WebView), but it is unavailable. Reverting to default."

As I’m quite familiar with writing Markdown in normal text editors and don’t need syntax highlighting or the preview, I simply disabled the Markdown plugin.

Today I was working on a WordPress plugin and wanted to separate some text into multiple lines. To do this, you have to add two space to the end of every line. But as soon as I wanted to commit the file, the PhpStorm file cleanup routines removed those “unnecessary whitespaces” at the end of the lines. So I’ve reactivated the Markdown plugin, just to find out, that the issue still exists.

Solving the issue

A quick search for the error message brought me to a support ticket and here I found the hint, that it might have to do with the JRE PhpStorm is using to run. If you have multiple JRE versions installed, you can use a plugin to choose from those. Jetbrains, the company behind PhpStorm recommends to use a special JRE version provided by Jetbrains.

I currenlty run Manjaro Linux on my work laptop, so I searched in the program repositories for that special version and found the following:

Installation dialog for "phpstorm-jre 2020", the patched JRE for PhpStorm

After installing the patched JRE version and restarting PhpStorm, I was able to open Markdown files again. When trying to commit the Markdown file, the additional two spaces at the end of the lines were not delete anymore.

Conclusion

Sometimes a quick fix like disabling a plugin for a software seems to solve an issue. But there might be some side effects with that. Trying to dig deeper into the real issue and finding a solution might sometimes take more time, but it’s usually the better solution.

WordCamp Europe 2020 – An unexpected journey

Yesterday, the 8th edition of WordCamp Europe had it’s final day. And it was an amazing experience. I had the pleasure to take part as an organizer, but the result was quite different, that I would have expected.

WordCamp Europe Porto 2020

The journey began 12 month ago in Berlin. At the closing remarks of the WCEU 2019 we announced that we would go to Porto. I commited myself to continue a fourth year in a row as an organizer, taking the role as a Global Lead. But I was not going to do that alone. I was joines by Tess and Jonas. For the first time in WCEU history, we started with three Global Leads. But the team would not be complete without José Freitas the Local Team Lead for Porto.

In September, our Call for Organizers was done, our organizing team of 72 volunteers from the WordPress community was selected and we started organizing an event for around 3500 attendees. This trip to Porto would have also been my first trip Portugal. But then things changed.

The cancelation of WordCamp Asia

The COVID-19 outbreach had just started, but on 12 Februrary, only around a week before the event, WordCamp Asia was postponed to 2021. This was not only a shock for the global WordPress community, but also for us as organizers of WordCamp Europe. Having an event only three and a half months later, we could not see, if we would be able to let it happen. The next weeks were quite intense. Other events were postponed as well, and it was getting clear, that we had to do something, Finally on 12 March, one month after WordCamp Asia, we also had to postpone WordCamp Europe in Porto to 2021. It was one of the hardest decision any organizer of a WordCamp Europe probably ever had to make. But the WordPress community was amazing in supporting our decision.

Starting from stratch

When we decided to postpone the in-person event, we also decided to have an online event insted. Up to this day, no other WordCamp that had been canceled went online. So there was no experience in the community on how to best do an event of our size online. We basically had to stop with the local event and start all over again organizing a very different event.

Although the decision was made by the whole organizing team, not all of us were able to continue helping with the online event for various reasons. While Tess and Jonas couldn’t continue as Global Leads, I was joined by Rocío Valdivia who was previously our mentor. We were joined by another 31 organizers who re-grouped in different teams.

Group photo of the WCEU 2020 Online organising team
The WordCamp Europe 2020 Online Organizing Team

This was the start of the first ever WordCamo Europe Online and a new milestone for the community and many of us.

Three months of passion and hard work

Organizing a WordCamp Europe in nine month is a lot of work. Organizing an online event that size in less then three month, is incredibly harder. With the passion, dedication, hard work and amazing team work, we managed to deliver an event, that can hopefully be an inspiration for other online WordCamps to come.

We have received so much help from other WordCamp organizers along the way. The WordCamp Asia team showed us how to deal with postponing an event, the WordCamp Spain team organized a real community event, that made us change some of our plans, to copy some of the great ideas they came up with. And also other WordCamps around the world had some unique things, we were inspired by.

The biggest Wor(l)dCamp ever

Any organizer who ever had contact with vendors probably experienced, that the name is sometimes misspelled as “WorldCamp”. And this time, it can’t be more true. Although our focus is the European community, we wanted to allow anyone from around the world to participate. So have chosen a time from 15:00 to 20:00 CEST on the three days, allowing Europeans to join in their afternoon, so they don’t necessarily have to take a day of to participate. But this times also allowed many attendees on both sides of the Pacific to attend, either in the early morning or late evening.

The WordCamp in Porto was expecting 3500 tickets to be sold and more than 3000 attending. Last year we have sold more than 3300 tickets, welcomed around 2700 attendees from 90+ different countries. This year we sold 8600 tickets for our live stream and had more than 9000 views to the track 1 session of Friday in the first 24h, with some attendees watching the replay of the stream. But the number that was most impressive: we had signups from 140 different countries, so truely a “WorldCamp”:

World map of all attendees of WordCamp Europe 2020 Online

An experience I would never had imagined

I’ve attendeed every WordCamp Europe and have been involved in the organizing team since 2017. When we had the event in Berlin last year, it felt quite different. This year it was even more different. Usually I traveled to a foreign country some days before the event and met old and new friends. This year, we all had to attend and organzier from our homes. Everyone was missing the personal contact to other attendees. But the feedback from the community was overwhelming!

A huge thanks to the community!

I cannot put into words how I’m feeling right now. The experineces of this week is still so fresh, that it’s hard to describe. But more than anything else, I’m feeling thankful. For my fellow co-organizers, for the community who attended the talks, participated at the Contributor Day, for the speakers, the emceees and other volunteers, for the sponsors helping the event financially and any other person or organization helping with this event. Even though we didn’t had the chance to meet with friends, we gave so many more people the chance to participate.

See you all in Porto in 2021!

I hope many of you joined us this weekend at WCEU 2020 Online. Next year, we hopefully have the opportunity to finally meet in Porto. I will again take part in the organizing team as one of four Global Leads, joined by Lesley, Taeke and Moncho. If you want to help as an organizer yourself, please apply at our Call for Organizers. And if you just want to attend, you can already grab your ticket.

See you all in Porto in June 2021!