The Fulcrum
banner
thefulcrum.thefulcrum.dev.ap.brid.gy
The Fulcrum
@thefulcrum.thefulcrum.dev.ap.brid.gy
The Programmer's Fulcrum (aka Reuben Walker - Journalist, Philosopher, Techno Anarchist): Developers defending democracy, developing the Open Media Network. #fediverse […]

🌉 bridged from ⁂ https://www.thefulcrum.dev/, follow @ap.brid.gy to interact
The Programmer's Fulcrum: 13 December, 2025
Here we feature the latest Symfony Station Communiqué and Battalion "Destroying Autocracy" Post along with their featured articles. Original 'The Fulcrum' content updates will start in January when I sunset Symfony Station and Battalion. Posts with original content will start next month. # Symfony Station Communiqué - Stardate: ✦ 12 December 2025 ✦ Get the latest from the Symfony Universe and PHP development communities. Explore! ## Featured Item DerEuroMark writes: Djot is a lightweight markup language by the author of Commonmark (Markdown) and Pandoc. It takes the best ideas from Markdown while addressing many of its ambiguities and limitations. The syntax is familiar yet more predictable, making it an excellent choice for content-heavy applications. You could call it somewhat a possible successor. The php-collective/djot composer package brings full Djot support to PHP 8.2+, with 100% compatibility with the official djot test suite. Djot PHP: A Modern Markup Parser **This is the type of PHP item we will cover on The Fulcrum. Trés cool.** ## * * * # Destroying Autocracy – December 04, 2025 Welcome to this week's "Destroying Autocracy". It’s your source for curated news affecting democracy in the cyber arena with a focus on protecting it. Destroy! ## Featured Item(s) Deutche Welle writes: DW Access is a lightweight app designed to ensure access to independent information in regions where digital freedom is under threat. It provides users with a secure way to reach DW content even under severe censorship. DW Access: New app counters global censorship And Ben Werdmuller writes: When people think about RSS, they most often associate it with the long-departed Google Reader — but it’s far from dead. From direct subscriptions to syndication into apps that aggregate and re-present content, RSS remains the standard for feeds. It’s the glue that holds the timely web together. Most people know RSS powers blogs and podcasts. But it powers popular news apps too, from aggregated headlines on MSN or in SmartNews to up-to-date headlines in business services like Lexis Nexis or Bloomberg. It’s also widely used to keep track of status updates of all kinds: weather, software updates, infrastructure uptime, and so on. Most of this activity happens behind the scenes. Publishers often think of feeds as an afterthought, but entire industries rely on them. It’s a workhorse that's become essential infrastructure for the web. Why RSS matters Share on Open Social Media ### Follow us on the Fediverse Follow us on Bluesky although FYI, we won't be active on it. The Fulcrum (@thefulcrum.thefulcrum.dev.ap.brid.gy)Developers defending democracy! 🌉 bridged from https://www.thefulcrum.dev/ on the fediverse by https://fed.brid.gy/Bluesky Social
www.thefulcrum.dev
December 13, 2025 at 3:27 PM
Reposted by The Fulcrum
🎉 Joplin at FOSDEM 2026 in Brussels!
What’s in store: live demos, goodies, and great conversations.
We can’t wait to see you there!

📅 When? January 31st and 1st, 2026 📍 Where? Booth 4, K Level Université Libre de Bruxelles, Brussels
December 11, 2025 at 4:02 PM
Cryptpad has its November 2025 status update. https://blog.cryptpad.org/2025/12/10/status-2025-11/ #cryptPad
November 2025 status
2 new NLNet projects, End-of-year funding campaign, In the news, and more
blog.cryptpad.org
December 11, 2025 at 5:29 PM
Reposted by The Fulcrum
#xwiki 16.10.15 has been #released! Check it out: https://www.xwiki.org/xwiki/bin/view/ReleaseNotes/Data/XWiki/16.10.15

This is a bug fix release that fixes important bugs and upgrades or removes dependencies with security vulnerabilities.
November 27, 2025 at 10:25 AM
Reposted by The Fulcrum
Topics are now on the Explore page. Browse by Technology, Business, News, Culture, and more to find publishers writing about what you care about.
December 11, 2025 at 9:08 AM
New Workspace Tools Released — Manage Your Nextcloud With One Click. #nextcloud https://cp.tab.digital/announcements/145/New-Workspace-Tools-Released--Manage-Your-Nextcloud-With-One-Click.html
Announcements - TAB.DIGITAL | Nextcloud Hosting | Managed Nextcloud
cp.tab.digital
December 10, 2025 at 9:01 PM
Reposted by The Fulcrum
The EC hit X with a 120M fine for DSA transparency violations. But as the European politicians cannot get themselves to leave the platform, it shows the underlying issues with how the politicians (dont) understand how power works on social platforms […]
Original post on mastodon.social
mastodon.social
December 10, 2025 at 7:19 PM
Reposted by The Fulcrum
How do I get push notifications to work with the official @Mastodon iOS app? I have enabled them in the OS settings for the app, checked each type on and off multiple times in the in-app settings, ensured background app refresh is enabled.. still nothing is coming through. I had no problem […]
Original post on mastodon.social
mastodon.social
December 10, 2025 at 6:48 PM
AAC audio: Kdenlive beats DaVinci Resolve (Studio) on Linux… #kDenLive #videoEditing https://www.provideocoalition.com/aac-audio-kdenlive-beats-davinci-resolve-studio-on-linux/
AAC audio: Kdenlive beats DaVinci Resolve (Studio) on Linux…
Support ProVideo Coalition Shop with ### Filmtools Filmmakers go-to destination for pre-production, production & post production equipment! Shop Now An unusual situation with AAC audio decoding makes Kdenlive surprisingly more attractive than DaVinci Resolve (Studio), specifically on Linux. Allan Tépper November 12, 2025 __Comment Although I have covered the wonderful AAC códec (the one that essentially replaced MP3 back in 1997, even though many people still don’t know it), I usually cover AAC in an audio final distribution context. Today, I’m talking about AAC in a video recording and editing context. I’ll explain about an unusual licensing situation which was privately resolved in the past on both macOS and Windows, but not with Linux distributions. Most of Linux «distros» are FOSS (free and open source software). Although there is no public record of the transaction, it appears that sometime in the past Apple and Microsoft privately negotiated with the predecessor of what is now Via-LA (Via Licensing Corp) to receive a license for _decoding_ AAC audio on its platforms, be it from audio-only files or AAC audio embedded within H.264 and H.265 video files. Even though the DaVinci Resolve (free) and DaVinci Resolve Studio (paid, currently US$295) programs exist for Linux, macOS and Windows (and the licensing of AAC decoding was already taken care of by Apple and Microsoft _on a system level)_ , the situation is quite different on Linux. As a result of this weird situation, H.264 and H.265 video files with embedded AAC audio (the most common way audio is embedded there) are initially silent when played within DaVinci Resolve (Studio) on Linux. The suggested workaround is to use a free third-party tool to extract and transcode those AAC recordings into separate audio files, either WAV or separate FLAC (compressed yet lossless) and import them into DaVinci Resolve (Studio) to accompany the essentially «muted» H.264 or H.265 files. This means extra steps before editing this H.264 or H.265 footage, which is very common in many camcorders and mobile phone recordings. Kdenlive (a competing product which is also available for the same three operating systems) solved this on Linux. Kdenlive is FOSS (free and open source software) on all platforms. Kdenlive decodes AAC on-the-fly on Linux by leveraging the FFmpeg libraries, which are a core part of Kdenlive0s functionality. FFmpeg handles the decoding of AAC audio, allowing Kdenlive to use the audio directly without needing separate conversion steps for most standard AAC-encoded files. FFmpeg is also FOSS (Free and Open-Source Software). As a result, when using Kdenlive on Linux, you just import the file and go, without any prior transcoding required. Online forums are filled with DaVinci Resolve (Studio) users on Linux who are complaining about this situation. For editors who must frequently receive material from H.264 and H.265 video files with embedded AAC audio (the most common way with those files) this makes Kdenlive a hassle free solution, which is also cash-free, unless they decide to donate to Kdenlive’s develepors. There are certainly stronger features in DaVinci Resolve (Studio), but that goes beyond this targeted article about decoding AAC audio on Linux. I will also comment that AAC decoding comes with most modern Linux distributions nowadays, although it may require installing extra packages depending on the specific distribution. Ubuntu, Linux Mint, Fedora, and Arch Linux are among those that provide easy access to the necessary códecs through their repositories. In the case of Linux Mint (which I have installed and tested recently), an option is offered during setup to include additional multimedia códecs, where I always say ****Yes**** (or _****Sí****_). Then I visit my most active audio podcast page using the included or any other browser on Linux at CapicúaFM.com and make sure that the AAC audio from my show plays, which it does 🙂 ## If Blackmagic is listening/reading… If Blackmagic is listening or reading, please consider improving your Linux versions of DaVinci Resolve Studio by leveraging the FFmpeg libraries at least for AAC decoding. This is something which has been done by Kdenlive and all of the web browsers and media players I have tested on Linux so far, so it should be feasible for Blackmagic’s programmers to do with the Linux versions of DaVinci Resolve. I know you have heard this before, but we will keep reminding you about it until it’s solved, one way or another. Offering a premium program for Linux for US$295 without feature parity (when so many browsers, editors and media players on Linux have solved it) isn’t right. ## Lee este artículo en buen castellano ****Audio AAC: Kdenlive le gana a DaVinci Resolve en Linux…**** ## **(Re-)Subscribe for upcoming articles, reviews, radio shows, books and seminars/webinars** Stand by for upcoming articles, reviews, books and courses by subscribing to my bulletins. In English: * Email bulletins, bulletins.AllanTepper.com * In Telegram, t.me/TecnoTurBulletins * Twitter (bilingual), AllanLTepper En castellano: * Boletines por correo electrónico, boletines.AllanTepper.com * En Telegram, t.me/boletinesdeAllan * Twitter (bilingüe), AllanLTepper Most of my current books are at books.AllanTepper.com, and also visit AllanTepper.com and radio.AllanTepper.com. ## **FTC disclosure** None of the organizations mentioned above have paid for this article. Some of the manufacturers listed above have contracted Tépper and/or TecnoTur LLC to carry out consulting and/or translations/localizations/transcreations. So far, none of the manufacturers listed above is/are sponsors of the _TecnoTur_ , _BeyondPodcasting_ , _CapicúaFM_ or _TuSaludSecreta_ programs, although they are welcome to do so, and some are, may be (or may have been) sponsors of _ProVideo Coalition_ magazine. Some links to third parties listed in this article and/or on this web page may indirectly benefit TecnoTur LLC via affiliate programs. Allan Tépper’s opinions are his own. Allan Tépper is not liable for misuse or misunderstanding of information he shares. AAC codec DaVinci Resolve Kdenlive ### What Do You Think? Let Us Know. __ Subscribe __ __Login Notify of new follow-up comments new replies to my comments Label __ Name* __ Email* __ Website ____ Label __ Name* __ Email* __ Website ____ 1 Comment __ __ Oldest __ Newest Most Voted __Inline Feedbacks View all comments Paul __26 days ago __ Or, you know, just start recommending Kdenlive instead of some proprietary walled garden crap.. 0 Reply
www.provideocoalition.com
December 10, 2025 at 4:16 AM
Adjacent Post Navigation Changes in WordPress 6.9 and Compatibility Issues. #wordPress https://make.wordpress.org/core/2025/12/10/adjacent-post-navigation-changes-in-wordpress-6-9-and-compatibility-issues/
Adjacent Post Navigation Changes in WordPress 6.9 and Compatibility Issues
## TL;DR WordPress 6.9 introduced a fix for adjacent post navigation when posts have identical publication dates. While this resolved a long-standing bugbug A bug is an error or unexpected result. Performance improvements, code optimization, and are considered enhancements, not defects. After feature freeze, only bugs are dealt with, with regressions (adverse changes from the previous version) being the highest priority., it inadvertently caused infinite loops in some extensions that modify the `get_adjacent_post()` `WHERE` clause. ## What Changed in WordPress 6.9 In WordPress 6.9 (Trac #8107), a bug fix landed where next/previous post navigation failed when multiple posts shared identical `post_date` values. This commonly occurred when bulk-publishing draft posts. ### The Technical Change The `get_adjacent_post()` function’s `WHERE` clause was modified to include ID-based comparison as a tiebreaker: **Before (WordPress 6.8 and earlier):** WHERE p.post_date > '2024-01-01 12:00:00' AND p.post_type = 'post' **After (WordPress 6.9):** WHERE ( p.post_date > '2024-01-01 12:00:00' OR ( p.post_date = '2024-01-01 12:00:00' AND p.ID > 123 ) ) AND p.post_type = 'post' This ensures deterministic ordering when posts have identical dates, using the post ID as a secondary sort criterion. Additionally, the `ORDER BY` clause was updated: -- Before ORDER BY p.post_date DESC LIMIT 1 -- After ORDER BY p.post_date DESC, p.ID DESC LIMIT 1 ## The Problem: Infinite Loops in Some Themes/Plugins As Trac ticket #64390 documents, some plugins and themes modify adjacent post navigation to change behavior. For example, WooCommerce’s Storefront theme navigates between products instead of regular posts. These plugins use the `get_{$adjacent}_post_where` filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. to replace the current post’s date with a different post’s date. Here’s what was happening: 1. PluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party hooksHooks In WordPress theme and development, hooks are functions that can be applied to an action or a Filter in WordPress. Actions are functions performed when a certain event occurs in WordPress. Filters allow you to modify certain functions. Arguments used to hook both filters and actions look the same. into `get_previous_post_where` filter. 2. Plugin does string replacement: replaces `$current_post->post_date` with `$target_product->post_date`. 3. **Problem** : The new `WHERE` clause structure includes the post date in TWO places (date comparison `AND ID` comparison). 4. Simple string replacement modified the date comparison but left the ID comparison unchanged. 5. Query returns the same post repeatedly → infinite loopLoop The Loop is PHP code used by WordPress to display posts. Using The Loop, WordPress processes each post to be displayed on the current page, and formats it according to how it matches specified criteria within The Loop tags. Any HTML or PHP code in the Loop will be processed on each post. https://codex.wordpress.org/The_Loop.. ### Real-World Example: Storefront Theme The fix to the WooCommerce Storefront theme illustrates this issue. They had to add special handling for the ID comparison: // Replace the post date (works as before) $where = str_replace( $post->post_date, $new->post_date, $where ); // NEW: Also need to replace the ID comparison (WordPress 6.9+) if ( strpos( $where, 'AND p.ID ' ) !== false ) { $search = sprintf( 'AND p.ID %s ', $this->previous ? '<' : '>' ); $target = $search . $post->ID; $replace = $search . $new->ID; $where = str_replace( $target, $replace, $where ); } ## For Plugin Developers: Detecting and Fixing the Issue ### How to Detect If Your Plugin Is Affected Your plugin is likely affected if it: 1. Uses the `get_{$adjacent}_post_where` filter. 2. Performs string replacement on post dates in the `WHERE` clause. 3. Changes which post is considered “adjacent” (like navigating between custom post types instead). To test if your plugin works correctly with WordPress 6.9: 1. Create 3-4 posts with identical publication dates (bulk publish drafts). 2. Navigate between them using your plugin’s adjacent post functionality. 3. Verify that navigation moves to different posts (not the same post repeatedly). 4. Check for infinite loops or performance issues. ### Quick Fix: Handle the ID Comparison If you’re doing date replacement in the `WHERE` clause, you also need to handle the ID comparison. There are numerous ways to tie a knot, but the following example is loosely inspired by Storefront’s recent fix. add_filter( 'get_next_post_where', 'example_custom_adjacent_post_where', 10, 5 ); add_filter( 'get_previous_post_where', 'example_custom_adjacent_post_where', 10, 5 ); function example_custom_adjacent_post_where( $where, $in_same_term, $excluded_terms, $taxonomy, $post ) { // IMPORTANT: Replace this with your logic to find the desired adjacent post. $adjacent_post = example_find_adjacent_post_function( $post ); if ( $adjacent_post instanceof WP_Post ) { // Replace the date comparison. $where = str_replace( $post->post_date, $adjacent_post->post_date, $where ); // Replace the post ID in the comparison. $where = preg_replace( "/AND p\.ID (<|>) {$post->ID}\)/", "AND p.ID $1 {$adjacent_post->ID})", $where ); } return $where; } You could also add a `version_compare( $wp_version, '6.9', '>=' )` test if you’d like to support multiple versions. **_Important_** : don’t forget to first test any code on your site, and customize it according to your needs. ## Next time At the time, this was not a known breaking change, and was classed as a bug fix. However as @jmdodd points out in the ticket, changes to `WP_Query`, especially SQL changes should be, by default, communicated more widely. Going forward: 1. Reach out to known plugins using the `get_{$adjacent}_post_where` filter. 2. Include a migrationMigration Moving the code, database and media files for a website site from one server to another. Most typically done when changing hosting companies. guidance in the 6.9 field guideField guide The field guide is a type of blogpost published on Make/Core during the release candidate phase of the WordPress release cycle. The field guide generally lists all the dev notes published during the beta cycle. This guide is linked in the about page of the corresponding version of WordPress, in the release post and in the HelpHub version page. (as applicable). 3. Test against any known, popular plugins that modify adjacent post queries. ## What’s Next and Getting Help Discussions have started on the ticket about ways to make this more robust in future WordPress versions. If you’re experiencing issues related to this change: 1. Check Trac ticket #64390 for the latest updates. 2. Ask questions in the #core channel on WordPress SlackSlack Slack is a Collaborative Group Chat Platform https://slack.com/. The WordPress community has its own Slack Channel at https://make.wordpress.org/chat/.. 3. Review the original fix PR #10394. Thank you for your patience and understanding. If you maintain a plugin affected by this change, please update it using the guidance above, and don’t hesitate to reach out if you need assistance. Thanks to @westonruter @isabel_brison @andrewserong @jmdodd for helping to prepare this post. #6-9, #dev-notes ### Share this: * Click to share on Threads (Opens in new window) Threads * Click to share on Mastodon (Opens in new window) Mastodon * Click to share on Bluesky (Opens in new window) Bluesky * Click to share on X (Opens in new window) X * Click to share on Facebook (Opens in new window) Facebook * Click to share on LinkedIn (Opens in new window) LinkedIn * * Login to Reply
make.wordpress.org
December 10, 2025 at 3:26 AM
Reposted by The Fulcrum
«Of course, Musk could get out of paying these fines by moving all his businesses out of the EU, which, frankly, would be a major result for Europe.» - @pluralistic

Which incidentally seems to be close to being the only path for many EU institutions, politicians and journalists to finally get […]
Original post on scholar.social
scholar.social
December 9, 2025 at 1:04 PM
Reposted by The Fulcrum
Good day all!

Quick heads up! While https://video.firesidefedi.live still exists, and will for the immediate future, the show will be moving to a new location!

https://tubefree.org/@firesidefedi

To hook Fireside Fedi into the non-profit I have moved all old videos of Fireside Fedi to […]
Original post on social.firesidefedi.live
social.firesidefedi.live
December 10, 2025 at 1:51 AM
Reposted by The Fulcrum
Let's Encrypt is ten years old. It's changed the web for the better. #technology https://werd.io/10-years-of-lets-encrypt-certificates/
December 10, 2025 at 1:45 AM
OWS.EU Partner in Focus: Open Search Foundation. #search
Welcome - OpenWebSearch.eu – Promoting Europe‘s Independence in Web Search
OWS.EU
December 9, 2025 at 10:37 PM
PeerTube 8.0 Brings a Modern Video Player and Team Channel Management. #peerTube https://linuxiac.com/peertube-8-0-brings-a-modern-video-player-and-team-channel-management/
Three months after the 7.3 release, PeerTube, a decentralized video hosting platform developed as a free and open-source alternative to centralized services, rolled out version 8.0. The new Lucide player theme introduces a cleaner, more modern look, replacing bold icons with lighter, unobtrusive elements that highlight the video itself. On top of that, peer-to-peer details now sit inside the “Stats for nerds” menu, and the volume controls have been simplified. For those who prefer the classic interface, the old player theme remains available at the platform, channel, or video level. The new PeerTube’s Lucide player theme. Alongside the visual overhaul, PeerTube 8 finally introduces shared channel management. Platform members can now be assigned as editors, enabling them to upload, modify, or delete videos and playlists, manage synchronizations, update channel information, and oversee comments. Editors cannot add or remove other editors or delete the channel, but the new role meets a longstanding need for organizations that rely on team-based publishing workflows. Moreover, failed imports can now be retried manually, and channel synchronizations automatically attempt reruns at the next verification interval. Status information for each import is now clearly displayed in the video management page, giving administrators better visibility into ongoing operations. Recent releases also added a configuration wizard for administrators, a redesigned “About” page, improved batch management tools, a new moderation feature for tracking specific words, and a complete overhaul of sensitive content handling. The team’s future plans include delivering promised features for the mobile app—background playback, live streaming, and TV apps—starting in early 2026. A “video maker” mode is expected to arrive within days. For more information, see the announcement. _Image credits: PeerTube_
linuxiac.com
December 9, 2025 at 10:07 PM
xWiki November Pro Apps updates. #xWiki https://xwiki.com/en/Blog/pro-apps-updates-november-2025/
Written by **The XWiki Team** The highlights of our November updates include important enhancements to the **Confluence Migrator (Pro)** , **Calendar Application (Pro)** , and **Pro Macros** , along with the exciting **launch of the new Open Project Integration (Pro)**. We’ve also rolled out a series of smaller improvements throughout the Pro Apps suite to make your experience even smoother. * * * ## **#1 Open Project Integration (Pro)** 🎉 We’re thrilled to announce that we've just launched the **Open Project Integration (Pro)** , a new project management tool that connects your OpenProject instance directly to XWiki. This new application allows you to pull filtered work packages straight into your wiki pages. It provides project managers and team leads with a simple way to keep everything aligned in a single open-source workspace. Thinking about stepping away from Confluence and Jira? This integration makes the move effortless. 💡 For more details on the new app, you can read the release notes. **👉Try the app for free and let us know what you think! Share your feedback in the dedicated form or open a GitHub ticket in the extension's repository**. ## **#2 Confluence Migrator (Pro)** With this release, we've brought multiple improvements to reports and added a warning when overwriting app pages. If you're an advanced user or an admin, these enhancements will significantly improve your experience with the migrator. 💡 For more details on these updates, you can check out the release notes. 👉 **Try out the latest version and let us know how these improvements are helping your workflow. Share your feedback in thededicated form or open a GitHub ticket in the extension's repository.** ## **#3 Calendar Application (Pro)** The November release comes with a fresh round of UI improvements and bug fixes to the **Calendar Application (Pro)**. More specifically, we've fixed the issue about the Calendar field missing from the Event prompt editing menu. We've also solved a bug that prevented the colors of the calendar events from being saved. These updates ensure a more stable, reliable, and user-friendly experience, so planning team meetings and tracking project deadlines will work better for everyone using the app. 💡 For more details on these updates, you can read the release notes. **👉 Update to the latest version and take advantage of these fixes and improvements. Share your feedback in thededicated form or open a GitHub ticket in the extension's repository.** ## **#4 Pro Macros** The latest update delivers faster performance for the **View File macro** , along with several stability improvements throughout the macros. These optimizations ensure that the View File macro works more quickly for you, while overall usage becomes more reliable. 💡 For more details on these updates, you can see the release notes. **👉 Update to the latest version and let us know if you have any feedback. Share your comments in thededicated form or open a GitHub ticket in the extension's repository.** ## **#5 Stability and UX improvements** We've addressed several minor issues and introduced small enhancements to stability and user experience across all Pro Applications. These updates provide a more reliable and consistent environment, helping you carry out everyday tasks more smoothly and stay focused on your work. **👉 Update all Pro Apps that you use** **to the latest version to benefit from these improvements, and please share your feedback if you notice any new issues.** ## ✨ **What's next** In the upcoming version 3.10.0, we're revamping the **Task Manager Application (Pro)** to make it more performant and flexible. You'll be able to assign multiple users to a single task, enjoy enhanced inline task functionalities, and benefit from various bug fixes and other improvements. This way, managing tasks becomes more efficient and collaborative. * * * ## **Before you go...** ## **Stay in the loop! 👀** Subscribe to our newsletter and stay up-to-date with all XWiki SAS news.
xwiki.com
December 9, 2025 at 10:00 PM
The world needs social sovereignty
Elon Musk’s X platform has blocked the European Commission from making advertisements, presumably in response to the €120 million fine for its misleading verification system and overall lack of transparency. We’re grateful to Elon Musk for proving once again why the world needs to log off corporate-owned, centrally-controlled social media platforms and log on to a better way of being online. The world needs an open social web through the fediverse and Mastodon. Calls for public institutions to invest in digital sovereignty are increasing across civil society. The term digital sovereignty means that an institution has autonomy and control over the critical digital infrastructure, data, and services that make up their online presence. Up until this point, social media has not been a part of this conversation. We think it is time to change that. In any free society, it is the right of every citizen to access and comment on the news, decisions, and reasonings of their government. We believe it is a government’s responsibility to ensure this right for its constituents. Public institutions should communicate with their citizens on open platforms, not ones that require creating an account and sending personal data to a self-serving tech company. Today, institutions often communicate through the censorious filter of corporations that do not have the best interests of people or society at heart. They let their message be governed by the whims of out-of-touch and overpaid people who believe they should have unchecked power. We cannot let this stand. Mastodon offers a path forward for any institution that wants to take control of their communications, and we can help you get started today. One of the tools these corporate social media platforms use to control an institution’s communications is the algorithm. Platforms strategically tune their algorithms to make it difficult, if not impossible, for institutions to reach their people without paying the platform ad money. Musk’s move to turn off the European Commission’s advertising capabilities feels like a perverse power play over a legitimate fine, one that effectively silences a crucial avenue for public discourse. We should be horrified that any single individual can wield such influence over the relationship between governments and the people they represent. We should be especially concerned when that individual doesn’t think our governments should exist in the first place. Mastodon’s chronological timeline means that no institution needs to game an algorithm to keep their people informed. By using hashtags, it’s easy for people who care about the topics you discuss to find you. What’s more, your constituents don’t need to be on Mastodon to follow your posts. They can subscribe via open protocols like RSS and soon via email. When it comes to the source of the fine in the first place—X’s infamous blue checks, a.k.a. verification—Mastodon also offers a better way. We empower people to verify themselves by linking their social profile to their official (or personal) website. This allows for greater transparency and trust than relying on the often less-than-reputable verification practices of a single corporate entity, especially one that is willing to sell reputation for a low monthly fee. (Meanwhile, another corporate social media platform made $16 billion, 10% of their 2024 revenue, from advertisements for scams and banned goods.) In an era where information is power, it’s disheartening to see our institutions yield so much to the whims of industry and individuals. In contrast, the European Commission is leading the way in taking ownership of social sovereignty on behalf of their people. They own a Mastodon instance, ec.social-network.europa.eu, to reach Europeans directly and keep them well informed. Mastodon is proud to help them manage the technical side of things. If you are someone on the fediverse who would like to see their government own their social sovereignty, we encourage you to get in touch with your local representative and tell them why you think they should start using open social media networks like the fediverse. We’re starting a thread on Mastodon of resources to help you get in touch with your local representative here. By making the news and truth contingent on advertising budgets we’ve created an environment where any narrative can win, as long as the storyteller is willing to pay. If we allow these conditions to continue, we will leave behind the voices that truly matter; the people and their public institutions. It is critical that those voices not be silenced forever. The promise of the fediverse is the promise of a better way forward: free from ads and manipulative algorithms, a place built by and for people like you, where our sovereignty is a right and not a privilege. It will take all of us working together to build a better way of being online. If you want to start an instance or have ideas about how we can encourage more institutions to take control of their social sovereignty, get in touch us at hello@joinmastodon.org.
blog.joinmastodon.org
December 9, 2025 at 6:52 PM
Trunk & Tidbits, November 2025
Hello, friends! Last month was momentous and exciting: we announced a new organisation structure; Eugen changed roles; and, we also announced a new path for donors to support us in Europe, thanks to fiscal sponsorship from WE AID. Alongside these changes, we’ve also started a series of social posts to encourage folks to visit the new donation portal. You may see these posts, with a #SupportMastodon hashtag - feel free to boost them, to spread the word about our mission 🙏🏻 Oh, and also, this happened… 🎉 > Post by @shlee@aus.social > > View on Mastodon ## Events in November, and ahead Andy was at Decidim Fest in Barcelona, as part of the panel “Can Decentralization Fix Social Media?”. There were some lively conversations about digital sovereignty and technical standards, but the core of the event itself was participatory technology for democracy. The concept that civic institutions should own their own social channels, aligns strongly with Mastodon’s own vision and values. Felix joined the in-person Fediforum track at SFSCon in Bolzano, Italy. It was great to connect with a number of our friends from around the Fediverse. Last month also saw the European Digital Sovereignty Summit held in Berlin. Our new Executive Director Felix, and our Chief of Staff, Philip, were able to attend, and connect with other organisations that share a similar mission to Mastodon. Looking ahead into early 2026, we will have a stand at FOSDEM. We’re excited to be heading back to Brussels, where we will also be present in the Social Web Devroom. ## Releases The current stable release of Mastodon is **4.5.3**, released yesterday (alongside 4.4.10, 4.3.16 and 4.2.28): > Post by @MastodonEngineering@mastodon.social > > View on Mastodon During November, we shipped two fixes for the 4.5 release (4.5.1, 4.5.2), and backported equivalent updates for the 4.4 and 4.3 branches: version 4.4.9 and version 4.3.15. We recommend that all Mastodon server owners should be running the latest point version for their release branch, and ideally, to upgrade to the newest stable version of Mastodon. > Please pay attention to the upcoming end-of-life dates. The 4.2 branch will no longer receive updates after **January 8, 2026** , and the 4.3 branch will reach EOL on **May 6, 2026**. ## Backend and Web In November 2025 we reviewed and merged 237 Pull Requests (159 with translation and dependency updates removed) from 20 contributors. This was huge. We appreciate the contributions! * interface The experimental `theme_tokens` feature flag as well as our legacy styles have been removed from our codebase, and our new theme tokens (based on CSS variables) are now live on mastodon.social and mastodon.online (and any other servers using our nightly builds). If you are maintaining a third-party theme or a server with custom CSS, now is a good time to ensure your styling tweaks play well with this update. — PR #37056 (by diondiondion) * new feature Implementation of “Collections” (our take on Starter Packs) has begun. We are slowly laying foundations, so nothing to see yet, but we are getting there! — PR #37049 (by oneiros) — PR #37020 (by oneiros) — PR #37005 (by oneiros) — PR #36977 (by oneiros) * interface Added notifications about interactions between quote posts and Direct Messages — PR #36696 (by ChaosExAnima) * interface Updated the media modal with smoother scrolling experience — PR #36673 (by ChaosExAnima) (and multiple others) * interface Fixed issues with emoji caching and web worker — PR #36808 (by ChaosExAnima) — PR #36897 (by ChaosExAnima) * interface Fix post and keyboard navigation issues — PR #37052 (by diondiondion) (and multiple others) * interface Move “Privacy and reach” from “Public profile” to top-level navigation in settings — PR #27294 (by ChaelCodes) * interface Fix duplicated counters in some languages — PR #32614 (by xatier) — PR #36844 (by ChaoxExAnima) * interface Improve viewing non-public hashtag pages when not logged in — PR #36961 (by diondiondion) * interface Prevent vertical videos from overflowing the viewport — PR #36966 (by diondiondion) * developer Fix Accept headers when fetching ActivityPub objects to match spec (AP integrity/interoperability) — PR #30354 (by TheOneric) * api Fix `/api/v1/statuses/:id/context` sometimes returning Mastodon-Async-Refresh without result_count — PR #36779 (by ClearlyClaire) * admin Increase HTTP read timeout for expensive S3 batch delete operations — PR #37004 (by ClearlyClaire) — PR #36971 (by ClearlyClaire) — PR #36996 (by ClearlyClaire) * admin Increase nginx proxy_read_timeout to avoid long-request failures — PR #30599 (by shleeable) * admin Optimize nginx location blocks — PR #19644 (by Izorkin) * admin Fix `tootctl status remove` removing quoted posts and remote quotes of local posts — PR #37009 (by ClearlyClaire) * admin Separate remote thumbnails into cache/ directory — PR #36911 (by shugo) * admin Add systemd service file for Prometheus exporter — PR #35130 (by ThisIsMissEm) * admin Rely on Puma default environment and remove legacy AR connection boot from Puma config — PR #36760 (by mjankowski) — PR #36757 (by mjankowski) ## Android We released an update that adds loading all replies, and several smaller updates that improve the stability of the app. ## iOS We shipped version 2025.08 on December 1st, with better loading and scrolling performance, an all-new audio player, and improvements to video playback. Major work on rewriting/refactoring is starting to pay off as more areas of the app are replaced with new multi-purpose code and old code files are deleted. This version also saw us replace our complex and outdated localization system with modern `.xcstrings` format files, which will be much easier for developers and translators moving forward. ## DevOps If you have an interest in our Helm charts to deploy Mastodon, we would like to hear from you. > Post by @MastodonEngineering@mastodon.social > > View on Mastodon ## Documentation Shout-out to Matt Jankowski for a huge effort on issue triage & merge support, closing 81 issues in total (most of which merged fixes and updates), backed by 13 contributors in total. ## Translations We’ve posted a call for proofreaders for translations across our apps and website. If you are already translating our apps and would like to coordinate the work for your language, see this discussion post. If you would like to help translating Mastodon into your language, you can join the many volunteers who already do so on Crowdin: for the web app, the iOS app and the Android app. ## Community * Version 3.2.0 of Pachli for Android was released just over a week ago; it includes support for Quote Posts, and makes lots of useful search options available. * Version 7 of Mona for iOS will be available soon. Reminder that if you’re building on the Mastodon API, we’d love to hear about your project. ## Thanks That’s it for another month of behind-the-scenes updates. We’re grateful for your support for our mission. Please donate to help us if you are able. ### Thank you for supporting Mastodon We develop and maintain the free and open source software that powers the social web. There is no capital behind this — we rely entirely on your support. Donate to the project View our sponsors
blog.joinmastodon.org
December 9, 2025 at 6:34 PM
Djot PHP: A Modern Markup Parser. #markdown #PHP https://www.dereuromark.de/2025/12/09/djot-php-a-modern-markup-parser/
Djot PHP: A Modern Markup Parser
If you’ve ever wished Markdown was a bit more consistent and feature-rich, you’ll want to hear about ****Djot**** – and now there’s a complete PHP implementation available. ## What is Djot? Djot is a lightweight markup language by the author of Commonmark (Markdown) and Pandoc. It takes the best ideas from Markdown while addressing many of its ambiguities and limitations. The syntax is familiar yet more predictable, making it an excellent choice for content-heavy applications. You could call it somewhat a possible successor. The `php-collective/djot` composer package brings full Djot support to PHP 8.2+, with ****100% compatibility**** with the official djot test suite. ## Use Cases Let’s talk about common cases where such a markup language would be beneficial: * Blog engines and CMS platforms * Documentation systems * Technical writing applications * User-generated content (comments, forums) with Profile-based restrictions * Any project requiring lightweight markup with advanced formatting * Customizable to specific (business relevant) markup/constructs * Secure by design Let’s see if Djot fits these needs. ## Feature Highlights ### Rich Text Formatting Djot supports the familiar emphasis and strong formatting, plus several extras: Syntax | Result | Description ---|---|--- `*Strong*` | **Strong** | Bold text `_Emphasized_` | _Emphasized_ | Italic text `{=Highlighted=}` | Highlighted | Highlighted text `{+Inserted+}` | Inserted | Inserted text `{-Deleted-}` | ~~Deleted~~ | Deleted text ``code`` | `code` | Inline code `E=mc^2^` | E=mc2 | Superscript `H~2~O` | H2O | Subscript ### Smart Typography Smart quotes, em-dashes, en-dashes, and ellipsis are handled automatically: * `"Hello"` becomes “Hello” with curved quotes * `---` becomes an em-dash (—) * `--` becomes an en-dash (–) * `...` becomes an ellipsis (…) ### Tables with Alignment Full table support with column alignment: | Feature | Status | Notes | |:------------|:------:|--------:| | Left-align | Center | Right | ## Task Lists Native checkbox support for task lists: - [x] Create parser - [x] Create renderer - [ ] World domination Since this post is written in Djot, here’s the actual rendered output: * Create parser * Create renderer * World domination ## Divs with Classes Create styled containers with the triple-colon syntax: ::: warning This is a warning message. ::: Renders as: <div class="warning"> <p>This is a warning message.</p> </div> Live demo: ****Note:**** This is a note block. Use it for tips, hints, or additional information that complements the main content. ****Warning:**** This is a warning block. Use it to highlight important cautions or potential issues that readers should be aware of. ## Spans with Attributes Add classes, IDs, or custom attributes to inline content: This is [important]{.highlight #key-point} ## Code Blocks Fenced code blocks with syntax highlighting hints: ```php $converter = new DjotConverter(); echo $converter->convert($text); ``` ### Captions (Images, Blockquotes & Tables) The `^` prefix adds a caption to the block immediately above it: Block Type | HTML Output ---|--- Image | `<figure>` + `<figcaption>` Table | `<caption>` inside `<table>` Blockquote | `<figure>` + `<figcaption>` > To be or not to be, > that is the question. ^ William Shakespeare Renders as: > To be or not to be, that is the question. William Shakespeare ## The Markdown Elephant in the Room Let’s be honest: Markdown has quirks. Ever spent 20 minutes debugging why your nested list won’t render correctly? Or wondered why `_this_works_` but `_this_doesn't_` in some parsers? Djot was designed by someone who knows these pain points intimately – John MacFarlane literally wrote the CommonMark spec. With Djot, he started fresh with lessons learned from years of Markdown edge cases. The result? A syntax that feels familiar but actually behaves predictably. Your users write content, not workarounds. ## Why Djot Over Markdown? * ****More consistent syntax**** – Fewer edge cases and ambiguities * ****Better nesting**** – Clear rules for nested emphasis and containers * ****Built-in features**** – Highlights, insertions, deletions, and spans without extensions * ****Smart typography**** – Automatic without additional plugins * ****Cleaner specification**** – Easier to implement correctly * ****Easier to extend**** – AST makes adding new features straightforward * ****Secure by design**** – Random unfenced HTML like `<b>...</b>` shouldn’t be treated as such blindly ## Djot vs Markdown: Quick Comparison Feature | Markdown | Djot ---|---|--- Strong | `**text**` or `__text__` | `*text*` Emphasis | `*text*` or `_text_` | `_text_` Highlight | ❌ (needs extension) | `{=text=}` Insert/Delete | ❌ (needs extension) | `{+text+}` / `{-text-}` Attributes | ❌ (non-standard) | `[text]{.class #id}` Divs | ❌ | `::: classname` Smart quotes | Depends on parser | Always on Nested emphasis | Inconsistent | Predictable Hard line breaks | Two trailing spaces | Visible `\` (backslash) Trailing spaces are problematic since most IDEs and editors auto-trim whitespace. Using a visible `\` character is much cleaner. Auto-HTML is also problematic for user-generated content. Djot treats everything as text by default – you must explicitly enable raw HTML (see below). ## Basic Usage Converting Djot to HTML is straightforward: use Djot\DjotConverter; $converter = new DjotConverter(); $html = $converter->convert($djotText); Need XHTML output? Just pass a flag: $converter = new DjotConverter(xhtml: true); ## Advanced Usage For more control, you can work with the AST directly: $converter = new DjotConverter(); // Parse to AST $document = $converter->parse($djotText); // Manipulate the AST if needed... // Render to HTML $html = $converter->render($document); ## Markdown compatibility modes Note: This is specific to this library and not yet officially in the specs. Using this in your apps means, your users get the best out of both concepts, but it also means you need to clarify and document this and cannot “just” link to djot specs. ### Soft break mode Configure soft breaks as per context and user needs: Mode | HTML Output | Browser Display ---|---|--- Newline | `\n` | No visible break (whitespace collapsed) Space | ` ` | No visible break (whitespace collapsed) Break | `<br>` | Visible line break $renderer = $converter->getRenderer(); // HtmlRenderer // Default - newline in source, invisible in browser $renderer->setSoftBreakMode(SoftBreakMode::Newline); // Space - same visual result, slightly smaller HTML $renderer->setSoftBreakMode(SoftBreakMode::Space); // Break - every source line break becomes visible <br> $renderer->setSoftBreakMode(SoftBreakMode::Break); This actually allows a certain compatibility with users that are used to Markdown line breaking within normal text. So this is useful for chats or simple text inputs. As this only affects the rendering, but not the parsing, this is still fully spec-compliant in that way. ### Significant Newlines Mode (Markdown-Like) This mode is for users accustomed to Markdown’s “human” behavior where newlines intuitively interrupt blocks. The Djot specification states: “Paragraphs can never be interrupted by other block-level elements.” In standard Djot, this means lists and other elements require blank lines before them – more “spaced” than what Markdown users expect. There’s an easy solution to get the best of both worlds: $converter = new DjotConverter(significantNewlines: true); $result = $converter->convert("Here's a list: - Item one - Item two"); // Output: <p>Here's a list:</p>\n<ul><li>Item one</li><li>Item two</li></ul> If you need a marker character (-, *, +, >) at the start of a line without triggering a block, use escaping: // Without escaping - creates a list $result = $converter->convert("Price: - 10 dollars"); // Output: <p>Price:</p><ul><li>10 dollars</li></ul> // With escaping - literal text $result = $converter->convert("Price: \\- 10 dollars"); // Output: <p>Price:<br>- 10 dollars</p> This returns you to standard Djot behavior for that line. This mode is useful when migrating existing systems where users expect Markdown-like behavior – most content works without changes, and the rare edge cases can be escaped. For offline docs and anything needed to be more agnostic one should still use the default spec compliant way. ## Customization ### Custom Rendering with Events Want to customize how specific elements render? Use the event system: use Djot\Renderer\Event\RenderEvent; $renderer = $converter->getRenderer(); // Convert :emoji: symbols to actual emoji $renderer->addEventListener('render.symbol', function (RenderEvent $event) { $node = $event->getNode(); $emoji = match ($node->getName()) { 'smile' => '😊', 'heart' => '❤️', 'rocket' => '🚀', default => ':' . $node->getName() . ':', }; $event->setHtml($emoji); }); // Add target="_blank" to external links $renderer->addEventListener('render.link', function (RenderEvent $event) { $link = $event->getNode(); $url = $link->getDestination(); if (str_starts_with($url, 'http')) { $link->setAttribute('target', '_blank'); $link->setAttribute('rel', 'noopener noreferrer'); } }); ### Extensibility: Custom Patterns Need `@mentions`, `#hashtags`, or wiki-style links? The parser supports custom inline patterns: use Djot\Node\Inline\Link; use Djot\Node\Inline\Text; $parser = $converter->getParser()->getInlineParser(); // @mentions → profile links $parser->addInlinePattern('/@([a-zA-Z0-9_]+)/', function ($match, $groups, $p) { $link = new Link('/users/' . $groups[1]); $link->appendChild(new Text('@' . $groups[1])); return $link; }); // #hashtags → tag pages $parser->addInlinePattern('/#([a-zA-Z][a-zA-Z0-9_]*)/', function ($match, $groups, $p) { $link = new Link('/tags/' . strtolower($groups[1])); $link->appendChild(new Text('#' . $groups[1])); return $link; }); echo $converter->convert('Hey @john, check out #PHP!'); // <p>Hey <a href="/users/john">@john</a>, check out <a href="/tags/php">#PHP</a>!</p> Custom block patterns are also supported for admonitions, tab containers, and more. See the Cookbook for recipes including ToC generation, math rendering, and image processing. ## Feature Restriction: Profiles SafeMode prevents XSS attacks, but what about controlling **which** markup features users can access? A comment section probably shouldn’t allow headings, tables, or raw HTML – not because they’re dangerous, but because they’re inappropriate for that context. That’s where Profiles come in. They complement SafeMode by restricting available features based on context: use Djot\Profile; // Comment sections: basic formatting only $converter = new DjotConverter(profile: Profile::comment()); // Blog posts: rich formatting, but no raw HTML $converter = new DjotConverter(profile: Profile::article()); // Chat messages: text, bold, italic - that's it $converter = new DjotConverter(profile: Profile::minimal()); ### SafeMode vs Profile Concern | SafeMode | Profile ---|---|--- Purpose | Security (XSS prevention) | Feature restriction Blocks | `javascript:` URLs, event handlers | Headings, tables, raw HTML Target | Malicious input | Inappropriate formatting Use both together for user-generated content: $converter = new DjotConverter( safeMode: true, profile: Profile::comment() ); ### Built-in Profiles Each profile is designed for specific use cases: * ****`Profile::full()`**** – Everything enabled (admin/trusted content) * ****`Profile::article()`**** – Blog posts: no raw HTML, allows headings/tables * ****`Profile::comment()`**** – User comments: no headings/tables, adds `rel="nofollow ugc"` to links * ****`Profile::minimal()`**** – Chat: text, bold, italic only ### Understanding Restrictions Profiles can explain **why** features are restricted: $profile = Profile::comment(); echo $profile->getReasonDisallowed('heading'); // "Headings would disrupt page hierarchy in user comments" echo $profile->getReasonDisallowed('raw_block'); // "Raw HTML could bypass template styling and security measures" ### Link Policies Control where users can link to: use Djot\LinkPolicy; // Only allow links to your own domain $profile = Profile::comment() ->setLinkPolicy(LinkPolicy::internalOnly()); // Or whitelist specific domains $profile = Profile::comment() ->setLinkPolicy( LinkPolicy::allowlist(['docs.php.net', 'github.com']) ->withRelAttributes(['nofollow', 'ugc']) ); ### Graceful Degradation When users try restricted features, content converts to plain text by default – nothing is lost: $converter = new DjotConverter(profile: Profile::minimal()); $html = $converter->convert('# Heading attempt'); // Renders: <p>Heading attempt</p> (text preserved, heading stripped) For stricter handling, you can strip content entirely or throw exceptions: $profile = Profile::minimal()->setDefaultAction(Profile::ACTION_STRIP); // Or for APIs: $profile = Profile::minimal()->setDefaultAction(Profile::ACTION_ERROR); ## Architecture The package uses a clean separation of concerns: * ****BlockParser**** – Parses block-level elements (headings, lists, tables, code blocks, etc.) * ****InlineParser**** – Processes inline elements within blocks (emphasis, links, code spans) * ****HtmlRenderer**** – Converts the AST to HTML output This AST-based approach makes the codebase maintainable and opens possibilities for alternative output formats. There are also other compatibility renderers available, as well as converters to convert existing markup to Djot. ## WordPress Plugin: Djot Markup for WP Want to use Djot in your WordPress site? There’s now a dedicated plugin that brings full Djot support to WordPress. ### Features * ****Full Content Processing**** – Write entire posts in Djot syntax * ****Shortcode Support**** – Use `[djot]...[/djot]` for mixed content * ****Syntax Highlighting**** – Built-in highlight.js with 12+ themes * ****Profiles**** – Limit functionality per post/page/comment type, disable raw HTML * ****Admin Settings**** – Easy configuration via Settings → WP Djot * ****Markdown compatibility**** mode and soft-break settings if coming from MD Fun fact: I just migrated this blog from custom markdown-hacks to Djot (and wrote this post with it). For that I used the built in migrator of that WP plugin as well as a bit of custom migration tooling. I needed to migrate posts, articles and comments – all in all quite straightforward though. The new interface with quick markdown-paste and other useful gimmicks helps to speed up technical blogging actually. It is both safe (comments use the right profile) and reliable. The plugin also comes with useful semantic customization right away: Djot Syntax | HTML Output | Output | Use Case ---|---|---|--- `[CSS]{abbr="Cascading Style Sheets"}` | `<abbr title="...">CSS</abbr>` | CSS | Abbreviations `[Ctrl+C]{kbd=""}` | `<kbd>Ctrl+C</kbd>` | `Ctrl+C` | Keyboard input `[term]{dfn=""}` | `<dfn>term</dfn>` | term | Definition term On top, it has some gotchas as extensions: * `![Alt text](https://www.youtube.com/watch?v=aVx-zJPEF2c){video}` renders videos from all WP supported sources right away, customize the attributes as always: `{video width=300 height=200}` * Import from HTML or markdown You can extend the customizations also on your own. ## IDE Support: IntelliJ Plugin For developers using PhpStorm, IntelliJ IDEA, or other JetBrains IDEs, there’s now an official Djot plugin available. ### Features * ****Syntax Highlighting**** – Full TextMate grammar support for `.djot` files * ****Live Preview**** – Split-view editor with real-time rendered output * ****Theme Sync**** – Preview follows your IDE’s dark/light mode * ****Code Block Highlighting**** – Syntax highlighting within fenced code blocks * ****HTML Export**** – Save documents as rendered HTML files * ****Live Templates**** – Code snippets for common Djot patterns The plugin requires JetBrains IDE 2024.1+ and Java 17+. ## Performance How fast is it? We benchmarked djot-php against Djot implementations in other languages: Implementation | ~56 KB Doc | Throughput | vs PHP ---|---|---|--- Rust (jotdown) | ~1-2 ms | ~30+ MB/s | ~10x faster Go (godjot) | ~2-4 ms | ~15+ MB/s | ~5x faster JS (@djot/djot) | ~8 ms | ~7 MB/s | ~2x faster ****PHP (djot-php)**** | ~18 ms | ~3 MB/s | baseline Python (markdown-it) | ~37 ms | ~1.5 MB/s | ~2x slower* *Python comparison uses Markdown parsers since no Djot implementation exists for Python. ****Key observations:**** – PHP processes ~2-3 MB/s of Djot content consistently – Performance scales linearly O(n) with document size – Safe mode and Profiles have negligible performance impact – Comparable to Python, ~2x slower than JavaScript reference implementation For typical blog posts and comments (1-10 KB), parsing takes under 5 ms. A 1 MB document converts in ~530 ms using ~44 MB RAM. The performance documentation includes detailed benchmarks, memory profiling, and stress test results. ## Enhancements & Extensions The library and the WP plugin already have some useful and powerful extensions, notably: * Full attribute support * Boolean Attribute Shorthand * Fenced Comment Blocks * Multiple Definition Terms and Definition Descriptions * Captions for Images, Tables, and Block Quotes * Markdown compatibility mode (Significant Newlines) These extend beyond the current spec but are documented as such. Keep this in mind if you need cross-application compatibility. There is also a `highlight.js` extension available to also code highlight `djot` content. ## Importing and Migration You can often with a boolean flag just continue to support the current markup, and with new content add djot based content. For those that want to migrate, there is some built in tooling and converters: * HtmlToDjot * MarkdownToDjot * BbcodeToDjot Fun fact: They also serve as a nice round-trip validation, to check if the transformation from and to is loss-free. Send a doc into it and reverse it, and the content should still “match” without loss of supported structures. ## What’s Next? The library is actively maintained with plans for: * Additional renderers (convert Djot back for interoperability) * More converters * More markup supported (not contradicting the specs) * Maybe some framework specific plugins or integrations Contributions welcome! ## Some personal notes I would have liked URLs and images to have a bit more friendly syntax as well, e.g. `[link: url "text"]` style for links and `[image: src "alt"]` style for images. The `![](url)` style still feels a bit too much like code syntax to me. If I were ever to invent a new markup language, I would probably take a similar approach, but try to keep it even simpler by default. The `{}` braces seem a bit heavy for these common use cases, and for non-technical users. One of the quirks I had to get used to, was the automated flow (line breaks are ignored) and the need for the visible (hard) line break if really desired. But in the end it usually helps to keep clear paragraphs. And I added compatibility options as opt-in for upgrading or usability ease. Overall, Djot strikes a great balance between familiarity and consistency. And at least topics like URL/image can be easily added as extension if desired. The PHP implementation with `djot-php` library is the most complete implementation of the standard available. It is perfectly suited for web-based usage. Make sure to check out the live sandbox and play around with the complex examples! ## Links * Live Sandbox – Try it in your browser * GitHub Repository * Djot Official Site * * * Give Djot PHP a try in your next project. The familiar syntax with improved consistency and a lot more out of the box might just win you over. *[CSS]: Cascading Style Sheets
www.dereuromark.de
December 9, 2025 at 4:14 PM