As per
#19
✨
Add a helper function: drupal_get_now()
Active
and
#20
✨
Add a helper function: drupal_get_now()
Active
I give up.
I will not spend any more time trying to port this enhancement correctly to Drupal core. It's just not worth the effort.
May all your potential upcoming rewriting, pushing and requesting be met with success, @sourav_paul and @shalini_jha.
Solved by v1.2.1 → .
Added a crucial tip: remember to check "Allow the user to override the default view mode" in the text format.
Yes. We should do our utmost to help the users using our modules.
Migrate Wizard is probably a great module. But the documentation (I think it was mostly the documentation, but cannot be completely sure) made me opt for another solution.
@chi, your concers addressed
The implementation is hardcoded to one specific date format (Y-m-d\TH:i:s).
Yeah. It looks shoddy but
a) There is no core time format just like this
b) That is the time format that all datetime fields expect.
Can you improve it?
It overlaps with PSR 20 where now() is supposed to return DateTimeImmutable object.
Let's call this useful function getNow then.
It does not use core time service. So no way to mock the date in tests.
Hm. Is that a necessity?
Can you point to (or have ChatGPT create) the specific tests @smustgrave wishes for?
I'm so sorry for
a) Not seeing this until now
b) Making such a shoddy error message
The utf8mb4 check in the install file has now been vastly improved.
Is it still useful?
My guess is that 99% of people running Drupal 10, 11 do it on a database using utf8mb4.
Yet, I made a utf8mb4 check in the install file in order to save the few poor souls not using utf8mb4 from a White Screen of Death upon installation.
Phpstan should not choke on version 1.2.1. My apologies for the old, shoddy version.
You may want to make
drush ms
drush mim id_migration
part of the documentation for the module.
A chapter called "Running the migrations" in the README.md would be well received, I think.
I hear you, brother @sourav_paul. So I asked Claude to do it:
I'll create a PHPUnit test for this static method from the DrupalDateTime class.
This test class provides comprehensive coverage for the now() method with several test cases:
testNowDefaultFormat(): Tests the default ISO 8601 format and verifies the timestamp is current
testNowCustomFormat(): Tests various custom format strings using a data provider
testNowTimezone(): Verifies that the method always uses UTC regardless of system timezone
Key features of the tests:
- Uses PHPUnit's data provider pattern to test multiple format strings
- Includes regex pattern validation for different date formats
- Handles timezone testing safely by restoring the original timezone
- Includes proper PHPDoc blocks and type hints
- Follows Drupal coding standards and testing conventions
You can run these tests using PHPUnit from your Drupal root directory:
./vendor/bin/phpunit core/tests/Drupal/Tests/Core/Datetime/DrupalDateTimeTest.php
And here's the test. I hope you can suss out where to put it:
<?php
namespace Drupal\Tests\Core\Datetime;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Datetime\DrupalDateTime
* @group DateTime
*/
class DrupalDateTimeTest extends UnitTestCase {
/**
* Tests the default format of the now() method.
*
* @covers ::now
*/
public function testNowDefaultFormat(): void {
$datetime = DrupalDateTime::now();
// Validate the format matches ISO 8601
$this->assertMatchesRegularExpression(
'/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/',
$datetime,
'Default format should match ISO 8601 format (Y-m-d\TH:i:s)'
);
// Validate the timestamp is within 1 second of current time
$now = time();
$test_time = strtotime($datetime);
$this->assertLessThanOrEqual(1, abs($now - $test_time),
'Generated timestamp should be within 1 second of current time'
);
}
/**
* Tests the now() method with custom formats.
*
* @covers ::now
* @dataProvider provideTimeFormats
*/
public function testNowCustomFormat(string $format, string $pattern): void {
$datetime = DrupalDateTime::now($format);
$this->assertMatchesRegularExpression(
$pattern,
$datetime,
sprintf('Format %s should match pattern %s', $format, $pattern)
);
}
/**
* Data provider for testNowCustomFormat.
*
* @return array
* Test cases with format strings and their corresponding regex patterns.
*/
public function provideTimeFormats(): array {
return [
'Year only' => [
'Y',
'/^\d{4}$/',
],
'Date only' => [
'Y-m-d',
'/^\d{4}-\d{2}-\d{2}$/',
],
'Time only' => [
'H:i:s',
'/^\d{2}:\d{2}:\d{2}$/',
],
'Custom format' => [
'd/m/Y H:i',
'/^\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}$/',
],
'Unix timestamp' => [
'U',
'/^\d+$/',
],
];
}
/**
* Tests that the now() method uses UTC timezone.
*
* @covers ::now
*/
public function testNowTimezone(): void {
// Store current timezone
$current_timezone = date_default_timezone_get();
try {
// Set system timezone to something other than UTC
date_default_timezone_set('America/New_York');
// Get timestamp in both timezones
$utc_time = strtotime(DrupalDateTime::now('Y-m-d H:i:s'));
$ny_time = strtotime((new \DateTime('now', new \DateTimeZone('America/New_York')))->format('Y-m-d H:i:s'));
// Calculate the offset (should be 4 or 5 hours depending on daylight savings)
$offset = abs($ny_time - $utc_time);
$this->assertTrue(
$offset >= 14400 && $offset <= 18000,
'UTC time should differ from New York time by 4-5 hours'
);
}
finally {
// Restore original timezone
date_default_timezone_set($current_timezone);
}
}
}
That's a rejection then.
I accept that.
My guess is, that you'll gradually change your mind on the "Modules should work AND be solely written by a person".
Not much skin off my back.
Here's the breakdown from my work log:
1 hour: have Claude make a very useful module and test it
1 hour: try to get better and more obvious maintainers to make or adopt it.
2 hours: security applications and related discussions.
6 hours: make (to us: very limited value) phpcs, phpcbd work company wide.
2 hours: git work
Disregarding the community is by far the path of least resistance.
Making your own great modules locally may be the future for Drupal.
@vishal.kadam: It was a one-minute job with Claude "Turn this into a correctly formatted Drupal module README.md file, render it as markdown: [readme.txt]". And it just works.
@avpaderno I too had my doubts about modules written by AI. So I asked an adult for guidance.
She said (paraphrased): If it works and isn't riddled with back doors, go for it. I see a bright future for Drupal with more and better features made significantly faster than in the old days.
So.
Does it work? Yes.
Is it riddled with back doors? No.
I have it running in production.
I vouch for the quality. But that's not very interesting yet, as I'm a small fry in the middle of a Drupal.org security advisory coverage application. Although, I have been publishing working modules on Drupal.org since 2006 → . I will admit to possessing an adequate amount of Drupal knowledge.
Smart programmers will use Drush, IDE extensions and LLMs to get the work done fast and well.
Looks very fine to me. Short, elegant and to the point.
Sadly I have no idea why we get "Merge request pipeline #339722 failed" at PHPUnit Functional 7/8 or how to get out of this regrettable situation.
A module page emerged. Entityqueue buttons → .
steven snedker → created an issue.
steven snedker → created an issue.
Well, my preference is
- drupal_get_now() (global function, not the modern Drupal way, will probably not make it into core)
- \Drupal\Core\Datetime\DrupalDateTime::now() (You'll almost be able to remember this one)
- \Drupal::service('datetime.service')->now() (harder to remember)
Naming
now is short and easy to remember. It's not as distinct as getNowUTC, but your IDE would probably tell you that now returned the date+time as UTC.
Make a patch @nikhil_110 and set the ball in motion!
I had Claude make the great Entityqueue Buttons module. You can find it at https://vertikal.dk/entityqueue_buttons.zip.
My hope is that @amateescu, @quicksketch or @jojonaloha will try it out and make it a submodule of Entityqueue. Or maybe publish it as a distinct project and link to it from the Entityqueue project page.
What makes the Entityqueue Buttons module useful? You only have to click once to add or remove a node. It'll also cut down on the confusion a very junior editor may feel.
Drawbacks? You'll get an add/remove button on your nodes, that only editors can see. Shouldn't be that ugly or confusing.
Claude is pretty keen on the idea:
That's a great idea to simplify this common operation! Let me think through the architectural considerations:
Public static method vs. global function:
- Given Drupal's move away from global functions, a static method would indeed be more aligned with modern best practices
- It would maintain better encapsulation and namespace organization
- It follows object-oriented principles better than adding to the global namespace
- It makes the functionality more discoverable through IDE tooling
A static method could look something like:
public static function nowUtc(string $format = 'Y-m-d\TH:i:s'): string { return (new static('now', new \DateTimeZone('UTC')))->format($format); }
Then you could use it as:
$now = \Drupal\Core\Datetime\DrupalDateTime::nowUtc();
This gives you:
- A cleaner, more maintainable API
- The ability to easily extend with additional formats or timezones if needed
- Better consistency with modern PHP practices
- Clear indication that this is Drupal-specific datetime functionality
Would you like me to explore other potential approaches or elaborate on any aspects of this solution?
Trading
$now = (new \Drupal\Core\Datetime\DrupalDateTime('now', new \DateTimeZone('UTC')))->format('Y-m-d\TH:i:s');
for
$now = \Drupal\Core\Datetime\DrupalDateTime::nowUtc();
is slightly better. You do not have to remember hyperspecific stuff like 'Y-m-d\TH:i:s'.
Having it as a better service
# Create a new service class
class DateTimeService {
public function getNowUtc(string $format = 'Y-m-d\TH:i:s'): string {
return (new DrupalDateTime('now', new \DateTimeZone('UTC')))->format($format);
}
}
would also trade very specific and human-unfriendly
$now = \Drupal::service('date.formatter')->format(time(), 'custom', 'Y-m-d\TH:i:s', 'UTC');
for better
$now = \Drupal::service('datetime.service')->getNowUtc();
I'm not sure if which of the public static function or the service will play nicest with IDE tooling. Which one would require the least remembering aand typing?
My VS Code, filled to the brim with the right extensions → still makes me pine for simple, global functions.
$user = user_load(42);
is still way easier than
$user = \Drupal::entityTypeManager()->getStorage('user')->load(42);
steven snedker → created an issue.
Added a paragraph about saving datetimes, dateranges and timestamps programmatically. Updated the tags.
Cool! I look forward to trying it.
Are you on track to having the high priests bestow a vetted role upon you → ? (Sadly, I'm not).
That would give the module the coveted "Stable releases for this project are covered by the security advisory policy.
Look for the shield icon below." badge.
(Which my modules on Drupal.org has - but only because they've been grandfathered into the security coverage.)
The generic description is very brief and does mention Buzzsprout in passing:
Configuration & Use
Install this module as usual.
Create a new Media Type, select "Remote Media URL" as Media source
Important: Configure the display, selecting as formatter in the URL field your desired provider. For example, if you are creating a "Buzzsprout" media type, select "Remote Media - Buzzsprout" as formatter for the URL field in the "Manage display" tab.
My proposed resolution is guaranteed to show newbies the ropes by
a) providing them with an actual working example (that's Drupal Module Gold)
b) taking them through all 7 steps in the correct sequence.
The smart ones can probably write something other than Buzzsprout on their first run. The less smart ones can get a working example and change bits and pieces until it works with another provider. Or make a new one in the vein of Buzzsprout.
A generic Configuration & Use where Buzzsprout is changed to [PROVIDERNAME] and [PROVIDERURL] is less readable. And won't necessarily work.
I also like the bit in step 6:
Click "Add" (clicking "Save" will make stuff explode). Click "Save". Click "Insert selected". (Scroll to the bottom and) click "Save".
It's probably still correct (but I haven't tested since June, so who knows).
My conclusion: this patch is useful for everyone and a great improvement.
steven snedker → created an issue.
steven snedker → created an issue.
steven snedker → created an issue.
steven snedker → created an issue.
A solution has been found in #14 🐛 Unable to save text format config form in 10.3 Fixed .
I'm very impressed with the solution in #14. Repaired the upcoming version of Wayback Filter → as well. Thank you, Julien.
Steven Snedker → created an issue.
"If you want to use a different font you can just load them via CSS?"
Perhaps. In the example, I use the Oliviero theme and use the cwl custom module to alter/replace the entity-print.css.
It's a rather complicated way of doing things, I admit. But I found no simpler module-centric way that actually worked IRL.
I seemingly had to follow all these very complicated steps to have cwl-print.css load at the right time and actually work.
As for storing fonts locally, it's just a GDPR thing.
Thank you. Matt B, for your efforts regarding better documentation.
It took quite a few steps to route around entity-print.css and use my own module supplied css. I gifted this actually working example to the newbies.
Great. Though it looks to me as if the numbered list has only 1s and no 2,3,4...
I'd love to write a patch, but as you can see I'm not sufficiently fluent in English, I have no useful git.drupalcode.org access and I can't even target the correct version of the splendid Flysystem module. Also I have only an hours experience with the module.
Looking at the flysystem 2.2.x-dev DEV readme I can see I would have missed quite a few important points. I'd say people were better off if the Flysystem module page linked to the flysystem 2.2.x-dev DEV readme instead of the faulty/less stellar 8.x-1.x readme.
I'm also happy that useful documentation is now a task and not a bug.
I was misled by this ChatGPT answer:
Is faulty documentation of a Drupal module a bug?
Yes, faulty documentation of a Drupal module can be considered a bug. Documentation is an integral part of software development, as it helps users understand how to use the module correctly. If the documentation is incorrect, incomplete, or misleading, it can cause users to misuse the module or struggle to implement it effectively. This can be as disruptive as a functional bug in the code itself. Therefore, reporting and addressing documentation issues is crucial for maintaining the overall quality and usability of the module.
Thank you for improving he Flysystem module - and the documentation!
Having the video(url) show up in the media library added no benefits to my project, I found.
So I ended up with a simpler solution than installing, patching, tweaking and setting up the Media Remote module:
function mymodule_preprocess_node(&$variables) {
if (!empty($variables['node']->get('field_video')->value)) {
$video_link = $variables['node']->get('field_video')->value;
$variables['content']['field_video'] = [
'#type' => 'inline_template',
'#title' => 'Video',
'#template' => '<video controls><source src="{{ url }}" type="video/mp4"></video>',
'#context' => ['url' => $video_link],
];
}
If you have a text field called video in a node, and you type in a remote video url, when editing the node, a video player will appear when viewing the node, instead of the text.
Video urls should be https://. Otherwise your browser might not play the video and might give you a strange error message
I hope someone will save some hours.
Steven Snedker → created an issue.
Thank you!
I can confirm it works with a short URL like https://vertikal.dk/sites/default/files/keys.mp4
On URLs longer than 245 chars it breaks. Because the name of the video is supposed to fit in 255 chars.
In the MediaRemoteVideoFormatter.php I changed
public static function deriveMediaDefaultNameFromUrl($url) {
$pattern = static::getUrlRegexPattern();
if (preg_match($pattern, $url)) {
return t('Video from @url', [
'@url' => $url,
]);
}
return parent::deriveMediaDefaultNameFromUrl($url);
}
to
public static function deriveMediaDefaultNameFromUrl($url) {
$pattern = static::getUrlRegexPattern();
if (preg_match($pattern, $url)) {
return t('Video from @url', [
'@url' => substr($url, 0, 200),
]);
}
return parent::deriveMediaDefaultNameFromUrl($url);
}
to make it work.
I also had to relax getUrlRegexPattern() in order to make videos like
http://mywonderfulNAS.myds.me:8764/share.cgi/Homevideo%20U-Matic/1061.mp...
almost work.
In the MediaRemoteVideoFormatter.php I changed
public static function getUrlRegexPattern() {
return '/^https?.*?\.mp4/';
}
to
public static function getUrlRegexPattern() {
return '/^http?.*/';
}
The player is still adamant that "No video with supported format and MIME type found" - but this is probably not related to this module or this formatter.
At least the player will get the correct url this way.
Steven Snedker → created an issue.
The current documentation is clearly inadequate. It has not been updated for four years.
I wish I could update it on https://git.drupalcode.org, but I'm not allowed to neither edit nor fork over there.
So here's an error ridden, but hopefully useful, stab at some better documentation:
1. The Flysystem module page links to
http://cgit.drupalcode.org/flysystem/plain/README.md?h=8.x-1.x
This page look pretty ugly in a browser. Link to
https://git.drupalcode.org/project/flysystem/-/blob/2.0.x/README.md?ref_...
or some such instead.
Better yet. Include most of the documentation (100+ lines?) on the module page. It's a great place for documentation! People will probably be more likely to install it, if they get the full picture up front.
2. "Reducing technical debt and risk of vendor lock-in." is slightly better than the current "Reducing technical debt and chance of vendor lock-in."
3. Requirements and Installation boilerplate should be removed. This is definitely not the first module a novice Drupal user will choose to install. Spend your time on the important details.
4. "Stream wrappers are configured in settings.php (usually found in /sites/default/settings.php or /web/sites/default/settings.php".
There are two settings.php in a typical D10 installation (the other one is at /core/lib/Drupal/Core/Site). And nearly 20 *settings.php files. We'd hate to confuse people.
5. Troubleshooting. Fine. But place it after the Configuration bit, where people need it.
6. Configuration. The example does not work.
This example will work
$schemes = [
'local-example' => [ // The name of the stream wrapper.
'driver' => 'local', // The plugin key.
'config' => [
'root' => '/../../', // Path to directory outside Drupal. Maybe /var/www/html/storage or ../ works better, who knows? 'sites/default/files/flysystem' would be a part of the public file system.
'public' => TRUE, // In order for the public setting to work,
// the path must be relative to the root
// of the Drupal install.
// Optional settings that apply to all adapters.
'name' => 'local-example', // Optional. Defaults to something secret.
'description' => 'An example of a local flyssystem file system', // // Optional. Defaults to something secret.
'cache' => TRUE, // Cache filesystem metadata. Not necessary for
// the local driver.
'replicate' => 'ftp-example', // 'replicate' writes to both filesystems, but
// reads from this one. Functions as a backup.
'serve_js' => TRUE, // Serve Javascript or CSS via this stream wrapper.
'serve_css' => TRUE, // This is useful for adapters that function as
// CDNs like the S3 adapter.
],
],
'ftp-example' => [
'driver' => 'ftp',
'config' => [
'host' => 'ftp.storaro.it', // or whatever the name of your ftp host is
'username' => 'storaro', // use a better username
'password' => 'cin3matograph3r', // use a better password
// Optional config settings.
'port' => 21,
'root' => '/var/www/html/storage',
'passive' => true,
'ssl' => false,
'timeout' => 90,
'permPrivate' => 0700,
'permPublic' => 0700,
'transferMode' => FTP_BINARY,
],
],
];
// Don't forget this!
$settings['flysystem'] = $schemes;
6) Troubleshooting. Have a look at the status report (admin/reports/status) to see if it works.
And on the status page, you should never write "ftp returned an error". That's close to useless. What error did it return? Should the user have a closer look at the hostname, port, username or password?
7) How to use the module.
"Now whenever you add a NEW file field to a node type/entiity type, you can decide which file system to use. You cannot change the file system for existing fields, though. Only new fields get the benefit of the module.
I, too, made a small module to mitigate this error.
Back Button Disable Module →
.
I won't upload it as a proper Drupal module. Drupal 7 is soon end of life and uploading modules to drupal.org is a time-consuming chore.
I, too, made a small module to mitigate this error.
Back Button Disable Module →
.
I won't upload it as a proper Drupal module. Drupal 7 is soon end of life and uploading modules to drupal.org is a hideous and time-consuming chore.
Steven Snedker → created an issue.
Fixed and committed.
Steven Snedker → created an issue.
Steven Snedker → created an issue.
Updated. Do keep me posted as to how it works in a real life situation.
Verdammt! I hope to have a new CKEditor 5 compatible version up sometime next week. In the meantime, you can try with CKEditor 4 and see if you miss a feature: I might be able to fix it.
I expect to spend a pleasant hour makeing the module work with CKEditor 5 and two savagely bitter hours getting the new and improved version placed correctly on Drupal.org.
Steven Snedker → created an issue.
On the module page here at drupal.org, I think you should change
Installation and Setup
See the README.md for detailed instructions.
to
Installation and Setup
IMPORTANT! You most likely need to fiddle with .htaccess and composer.json in order to make this module work. See the README.md for detailed instructions.
This more effectively warns people that this installation is not business as usual.
The README.md is fine now, by the way.
Joachim is absolutely correct regarding docblocks (#29). They are easier to read when only 80 chars wide. "Make your docblocks easier to read by aiming for a width of 80 chars" is a clearly a sensible recommendation.
But, using the exact same example, everyone is way happier with the 96 char line at
https://git.drupalcode.org/project/drupal/-/blob/11.x/core/lib/Drupal/Co...
than with some chopped up, harder to read, 80 char monstrosity. And also already allowed per "Control structure conditions may exceed 80 characters, if they are simple to read and understand". But you
The same goes for mherchels 130 char line in #9. Way better than any chopped up 80 or 120 char monstrosity.
Also already allowed per "Control structure conditions may exceed 80 characters, if they are simple to read and understand".
Let's be pragmatic thinkers and doers and extend "may exceed 80 characters, if they are simple to read and understand" to everything.
No hard or soft limits. Just (modern) common sense recommendations on legibility.
Removed an invalid example. A tag named 1.0.0-beta1 will show up as an option when you "Add new release".
@hansfn
I keenly followed the steps provided on the
Version control tab →
for my module.
This ends with:
Creating releases
See the naming conventions → for a complete description of how to name branches and tags so you can create releases.
Branch for a dev release
This creates and checks out a new branch in one command, then pushes it to Drupal.org
git checkout -b 1.0.x
git push -u origin 1.0.x
Tag for a stable release
git tag [tag name]
git push origin tag [tag name]Once you’ve pushed the properly-formed tag or branch, see Creating a project release → for directions to actually create the release node.
Unguided fool that I am, I chose a tag name that was not 1.0.1 or 1.1.0. And became none the wiser reading Creating a project release → (that did not, at that point, link to Release naming conventions → ).
I think I have now improved Creating a project release → and Release naming conventions → by making it clear what a tag should look like in order for the Add new release → bit to work.
I would love for the "Tag for a stable release" bit of the Version control tab → to sport a specific and useful recommendation. But I hope other beginners will find the nearby links to the newly improved Creating a project release → and Release naming conventions → useful when deciding on a (useful) name for the tag.
Linked to the strict naming conventions → for branches and tags that you need to adhere to in order to make a release that you will actually be able to add and administer.
Made it clear that a tag should be three numbers separated by full stops (i.e. 1.0.0) in order for the release to be added and administered on the module page.
Explained the conventions on branch and tag naming in more detail in order to make it easier for beginners (like me) to branch and tag stable releases that'll actually show up on the module page at Drupal.org.
Disclaimer: I'm an impatient man of average intelligence. Thus, I need better documentation than most other module maintainers.
I would like this page, Creating a Project Release, to solve this problem:
I've managed to
- create af Drupal 10 version of my module https://www.drupal.org/project/wayback_filter →
- placing it at https://git.drupalcode.org/project/wayback_filter/-/tree/1.1.x?ref_type=... using the git instructions at https://www.drupal.org/project/wayback_filter/git-instructions →
- Having it show up on the "View all releases page", https://www.drupal.org/project/wayback_filter/releases → , as "wayback_filter 1.1.x-dev"
On "Administer releases", https://www.drupal.org/node/2210155/edit/releases → , I've filled out the checkboxes "Supported" and "Recommended".
But it does not show up as recommended at https://www.drupal.org/project/wayback_filter →
Also I'm unable to make another release at https://www.drupal.org/node/add/project-release/2210155 → (reading Release naming conventions at https://www.drupal.org/node/1015226 → offered no useful solutions).
Second disclaimer:
"If you are looking for help with your Drupal site, please visit the support page".
I will.
But I think this very page Creating a Project Release should enable me, an impatient man of average intelligence, to do such a simple thing. I think this page (or some other nearby documentation page) should be improved to the point where I'm able to actually create a project release and have it show up correctly on the relevant pages.
I can't find a good source telling me that embedding external images in my site is a GDPR no-go. Do you have one?
But I can find several fresh sources telling me that embedding external fonts in my site is a no-go.
That's about the same.
So embedding external images in my site is probably a GDPR no-go.
I've augmented a local version the External Link Preview module with caching. However, if you're caching, you risk running into a speculative invoicing businesses. All over the world representatives of right holders will send you letters demanding 500 EUR per image you cache!
It happened to me in Denmark and your browser can probably translate most of I linked to a newspaper and received af 500 EUR invoice for you.
So. The External Link Preview module is
no caching: horribly slow, probably violating GDPR, safe from most speculative invoicing businesses
caching the external HTML locally: way faster, still violating GDPR, safe from most speculative invoicing businesses
caching the external HTML and images locally: way faster, GDPR compliant, exposed to speculative invoicing businesses
Sites like Facebook are caching 100% of the external images used for link previews. As they should. But they have a way bigger budget and way bigger legal department than the average user of the Drupal CMS.
I've thought about merging the caching version of the External Link Preview module into the more modern Link Field Preview → .
But I do not want for anyone to break GDPR or open themselves to extortion from speculative invoicing businesses. So I have done exactly nothing for a couple of years (other than writing a few articles about the nasty, time wasting speculative invoicing businesses).
It's hard to see how we can fix GDRP compliance without exposing the users to huge financial risks.
Steven Snedker → created an issue.
I can expand a little on the troubles Potassiumchloride is experiencing.
Having Fullcalendar View display a (day) calendar based on a daterange field with multiple values works like a charm. Until you add filters.
Some filters work well
i.e node type == appointment, published== yes.
You get single entries in the calendar, and they're wonderfully draggable and editable.
Others filters carry penalties
date_range_field == not empty will result in those undraggable, duplicate entries we see in
#2
💬
Duplicates of node with multiple date values
Closed: outdated
.
field_car_term == 3 will make entries based on nodes with a changed date different from today invisible. I have not finished investigating this strange error. Can only say it apparently does not matter if the Default date source of the view is Current date, Date of first view result or Fixed value.
Changing or adding view filters programmatically → offers no escape. The troubles caused by filtering persists.
So the best advice for now is: Are you getting no or duplicate entries? Try removing the filters one by one until there are no errors.
When Drupal has very, very convoluted syntax and very little useful documentation, ChatGPT is usually awesome.
Asking Google or Drupal → for "How do I add a tooltip (title) to the summary of a Drupal 9 details render array?" is a waste of time. Asking ChatGPT elicits a perfect answer in seconds.
ChatGPT does struggle though in places where the required Drupal syntax is very unintuitive. An example
$view->display_handler->options['filters']['field_car_term_target_id']['value'] = $term->tid;
will not in any way alter the filter of a view you have loaded in Drupal 9. You'll just get the predominantly useless error message ✨ Improve error messages, by including the source Active :
Argument #1 ($array) must be of type array, string given inarray_filter() (line 136 of core/modules/views/src/Plugin/views/filter/ManyToOne.php
I tried to coax a better answer out of ChatGPT. But the correct answers came from rote trial and error:
$view->display_handler->options['filters']['field_car_term_target_id']['value'][$term->tid] = $term->tid;
$view->display_handler->options['filters']['field_car_term_target_id']['value'][3] = $term->tid;
$view->display_handler->options['filters']['field_car_term_target_id']['value']['forsomereasonyoucanwritewhateveryouwant'] = $term->tid;
But usually ChatGPT is a very, very good ally against the many time sinks.
I highly recommend it.
This bug/sad state of affairs reminds of an old Drupal 7 bug:
format_date blows up with an unintelligible error message if it gets NULL or thinks the numbers it gets are strings.
Fixing this now been discussed for 10 years (!).
Bright and friendly people have made format_date more robust with a few lines of additional code → .
Result?
They have been asked to:
A) to follow Drupal's syntax to the letter
B) not to actually make the format_date function more robust. Or spew a useful error, when fed, say, a NULL value.
After 10 years of discussion and great fixes, it's a "Won't fix!"
Oh well. Still I will try to be a charitable developer and at least try to make my own modules as robust as possible and provide useful error messages. I wouldn't like for Drupal to turn inscruteable and unforgiving everywhere.
This bewildering Drupal core bug is now reported as Invisible and wrong error message when flood controlled users ask for a password reset mail 🐛 Invisible and wrong error message when flood controlled users ask for a password reset mail Active .
The bug hunts in Drupal 4-7 were shorter. The simpler architecture meant that you could usually locate the bug in minutes instead of hours. You only had to spend minutes on trial&error, not hours.
Sadly neither I can see a path ahead toward better error reporting in (soon to be obsolete) Drupal 8 and 9.
We might collectively make Drupal 10 a little bit more robust by making our code more robust, using way more is_string(), !empty(), isset(), get_class() etc. But the error reporting will be stuck at suck, I'm afraid. It's way above my technical and social skills to affect useful change here.
I still haven't enjoyed a Drupal week with less than two hours of wild goose chases. So The Wayback Filter module has not yet been updated to D10.
I'm also waiting for a peeve to get resolved: the 2½ year old Increase line length limit coding standards issue → . Updating The Wayback Filter Module I also need to brace myself for some convoluted git and version workflows, I fear. Not today, Drupal.
But you are right. A tired and despondent tone is not at all helpful.
A few hours ago I helped a contrib developer, I think. I showed him how to spend more hours on the module in order for updates to break in fewer places 🐛 Updating from 1.0.2 to 1.04 breaks the site Active . I hope a few people will find it and find it useful. Using ChatGPT instead of Drupal.org to get useful documentation and working examples is generally also an idea worth promoting everywhere.
I see absolutely no reason for a 40, 80 or 120 characters hard limit.
If a visually impaired developer chooses to develop on a 14" laptop using a huge font-size, this fine human will just have to make his editor wrap the code.
Paqualle pointed to this response from Linus:
So the fact is, many of us have long long since skipped the whole "80-column terminal" model, for the same reason that we have many more lines than 25 lines visible at a time.
And honestly, I don't want to see patches that make the kernel reading experience worse for me and likely for the vast majority of people,
based on the argument that some odd people have small terminal windows.If you or Christoph have 80 character lines, you'll get possibly ugly wrapped output. Tough. That's _your_ choice. Your hardware limitations
shouldn't be a pain for the rest of us.Longer lines are fundamentally useful. My monitor is not only a lot wider than it is tall, my fonts are universally narrower than they are
tall. Long lines are natural.
[...]So no. I do not care about somebody with a 80x25 terminal window getting line wrapping.
For exactly the same reason I find it completely irrelevant if somebody says that their kernel compile takes 10 hours because they are doing kernel development on a Raspberry PI with 4GB of RAM.
People with restrictive hardware shouldn't make it more inconvenient for people who have better resources. Yes, we'll accommodate things to within reasonable limits. But no, 80-column terminals in 2020 isn't "reasonable" any more as far as I'm concerned. People commonly used
132-column terminals even back in the 80's, for chrissake, don't try to make 80 columns some immovable standard.If you choose to use a 80-column terminal, you can live with the line wrapping. It's just that simple.
So I'm +1 for no hard limits and +1 for no soft limits. PHPCS unable to do soft limits? Not our problem.
Just ditch the ancient character limits.
I'm sure this will lead to happier developers and more legible code for +97% of the developers.
I've set up xdebug to work with VS Code following these instructions → (here's a video). I hope Sublime Text works more or less the same way.
Xdebug It shaves a few minutes off debugging as you do not have to print or log as many values. But it's not a silver bullet.
I'm afraid Jaypan's fine explanation is correct in most cases.
In this particular case:
Warning: Array to string conversion in Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::castValue() (line 2579 of core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php).
Drupal Core could probably try to var_dump Array in order to help the blameless Drupal webmasters. That might sometimes give someone a clue as to where the bug might be located. But sometimes the arrays are so huge, that trying to var_dump them will just give you a memory error on the server and/or kill your browser.
In this particular case var_dumping the array held no clue whatsoever as to where the bug was located.
And the verbose backtrace consisted of:
- 32 Drupal\Core\
- 3 Symfony\Component\HttpKernel
- 2 Drupal\page_cache\
- 1 Stack\StackedHttpKernel
All of them clearly correct, but not particularly helpful. Red herrings.
The core architecture of Drupal 8+ will have to change significantly for errors like these to be solveable in a reasonable amount of time by a reasonably experienced developer or webmaster.
Do you know if there's a correct way to remove submodules from your module?
ChatGPT has this suggestion which to me sounds right on:
If another user has not uninstalled one of your submodules and updates to the new version of your module that no longer includes that submodule, they will indeed get a fatal "submodule not found" error.
To prevent this error from occurring, you can add an update hook to your module that checks for the presence of the submodule and uninstalls it if it's found.
Here's an example of how you can do this:
Create a new file in your main module's directory called my_module.post_update.php.
In this file, create a function that checks if the submodule exists, and if it does, uninstalls it. Here's an example:
function my_module_remove_submodule() { $submodule_name = 'submodule_to_remove'; if (\Drupal::moduleHandler()->moduleExists($submodule_name)) { \Drupal::service('module_installer')->uninstall([$submodule_name]); } }
In this example, replace submodule_to_remove with the actual name of the submodule that you're removing.
In your main module's .info.yml file, add the following line:
post_update: my_module_remove_submodule
This tells Drupal to run the my_module_remove_submodule function when the module is updated.
Now, when a user updates to the new version of your module, Drupal will automatically check for the presence of the removed submodule and uninstall it if it's found, preventing the fatal "submodule not found" error.
God bless ChatGPT!
The core developers have been discussing how to make the module system less fickle for years and years 🐛 Moving modules breaks system Active .
But until they make the system more robust, I fear it's up to us to jump through these hoops in order not to break stuff.
Thank you for your work on the Threejs field 3d Object module.
I can see you asked nicely over at #3351526 ✨ Improve error messages, by including the source Active and someone dismissed it - or at least tried to - very fast. I hope someone working on that part of the system will at some point show up. Sadly my experience is that even bona fide bugs 🐛 Invisible and wrong error message when flood controlled users ask for a password reset mail Active elicit little interest. Often you'll just get an quick, unhelpful message from a guy venturing that the problem actually isn't a problem.
But well. I'll try to keep my parts of Drupal working well, in the hope that the core devs will do the same. I promise to update Wayback Filter → to D10 when I've enjoyed a Drupal week with less than two hours of wild goose chases.
You have encouraged me to "create an issue or two about [the bugs], in order to get them looked at and solved. This is Open Source after all, so we all need to chip in, to improve this great free software."
So today I have made this bug report Updating from 1.0.2 to 1.04 breaks the site 🐛 Updating from 1.0.2 to 1.04 breaks the site Active . It looks like a small, local problem. But it really is part of a severe core problem.
Steven Snedker → created an issue.
Well @ressa, it's easy to get the useless error messages.
There are three steps to reproduce at the bug report 🐛 Fails on Drupal 9.5+ Fixed and @clarksquared provided some nice screenshots of it 🐛 Fails on Drupal 9.5+ Fixed .
What should the title of your core issue be?
"Outlaw useless error messages and make Drupal more robust." or some variation, I think.
On my wish list, the stuff that's slowing down my work horribly, I find.
1. Useless error messages (the Field HTML example is a great example, even the best experts have no idea where the error is situated and have no way of finding out.... Other than time consuming trial and error)
2. Small errors that turn into fatal errors (the Field HTML example is a great example, a field does not provide a value (by design) - but suddenly you cannot save a node any more (one of Drupals most cherished features))
Expanding on this:
3. Errors messages should be easy to see for admins, but should also be easy to hide from average users.
4. Symphony errors should not brick the whole site.
And, straying even further from the focus, but I need to get this off my chest
5. Consistency and simplicity.
->title, ->getTitle() or ->get('title')?
->label, get('label') or ->field_label?
->label->value, label[0]->value, label[0]['value'], ['label']?
->value, ->target_id or ->email?
Making simple functions (like this one altering a node alias) often takes twice as much code as you'd expect.
6. You should be able to disable ALL caches and caching in one checkbox. Then you can add caching and refine as your site matures. Having to code just to avoid caching is the wrong way round.
7. Composer errors should be less useless. If you accidentally run composer in the wrong directory (i.e. ROOT instead of ROOT/web these days) it'll offer up three wrong explanations as to why you cannot composer require 'drupal/readonly_html_field:^1.0'
I don't have any good experiences adding Drupal Core Issues.
My last one is just sitting there 🐛 Invisible and wrong error message when flood controlled users ask for a password reset mail Active .
I, and every other user of the Readonly HTML Field module are grateful for your solution.
I've been writing Drupal modules (and a few field types) for 15 years. I'm stunned - on a daily basis - of just how much trial and error I have to go through to hunt down bugs (which I somehow feel arre getting more numerous across the board).
[Saving a node]
Warning: Array to string conversion in Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::castValue() (line 2579 of core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php).
did not offer me any clue whatsoever as to the origin of the, in real money, fatal error. At least in the old days of Drupal 4-7 you get a bit of a clue as to where a bug was situated.
Oh well. There's no magic tool or bullet. Just trial and error to deal with problems like this.
Once more: thank you for your help and your patch.
I proabaly should have used the Markup module → .
Great solution!
But how did you get to it?
If I were as smart as you, how would I get from
Warning: Array to string conversion in Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::castValue() (line 2579 of core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php)
to
Readonly HTML Field
to
implementing the isEmpty() method and always return TRUE
?
Yes, I want to become better at wrangling Drupal.
The Multiple fields remove button → module does what we wish for. No need to update this module.
My tools were no match for this error message. Reading all 28 lines did not give me or my tools any clue as to what the problem was and where to actually find bug:
Warning: Array to string conversion in Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::castValue() (line 2579 of core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php).
Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::castValue(Array, Array) (Line: 1375)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->saveToDedicatedTables(Object, , Array) (Line: 969)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->doSaveFieldItems(Object) (Line: 721)
Drupal\Core\Entity\ContentEntityStorageBase->doSave(NULL, Object) (Line: 520)
Drupal\Core\Entity\EntityStorageBase->save(Object) (Line: 804)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->save(Object) (Line: 339)
Drupal\Core\Entity\EntityBase->save() (Line: 270)
Drupal\node\NodeForm->save(Array, Object)
call_user_func_array(Array, Array) (Line: 114)
Drupal\Core\Form\FormSubmitter->executeSubmitHandlers(Array, Object) (Line: 52)
Drupal\Core\Form\FormSubmitter->doSubmitForm(Array, Object) (Line: 595)
Drupal\Core\Form\FormBuilder->processForm('node_testcontenttype_form', Array, Object) (Line: 323)
Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 73)
Drupal\Core\Controller\FormController->getContentResult(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 169)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 718)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
Steven Snedker → created an issue.
Steven Snedker → created an issue.
You are absolutely correct. I added a boolean field to an existing content type and pretty soon had
"NULL" in 5000 nodes
"0" in 200 nodes
"1" in 150 nodes
Loading all nodes without "1" took two fairly long entityqueries.
That sucks.
Thank you for pointing me to Field Defaults →
That is the fastest, most robust and least sucky solution to this unfortunate problem.
Base property is a novel solution and creative. Well spotted. But knowing how Drupal is increasingly creaking under it's own weight I'll go with the simpler Field Defaults → solution.
Thanks a lot for the answer.
Boolean field can have 2 states:
- NULL - the entity was never saved with the field, the field is empty
- 0/1 - the field has a value
A boolean with three values (NULL, 0, 1) has no upside whatsoever. At least I cannot imagine a single example where it's nice or convenient to use a boolean field to find out if a user has saved his/her user profile, webform or some node.
Booleans with three values (or two states and two values) makes a routine entityQuery awfully complex.
Here's an example:
$query = \Drupal::entityQuery('node')
->condition('type', 'measurement_result')
->condition('has_been_processed.value', 1, '!=')
->sort('changed', 'DESC')
->range(0, 20)
->accessCheck(FALSE)
->execute();
will not give me the 0 and NULL nodes. Only the has_been_processed=0 nodes.
So I have to make an additional
$query = \Drupal::entityQuery('node')
->condition('type', 'measurement_result')
->notExists('has_been_processed.value')
->sort('changed', 'DESC')
->range(0, 20)
->accessCheck(FALSE)
->execute();
"Ah," you may say. "You can make that more compact. Try:
$orGroup = $query->orConditionGroup()
->condition('field_saved_as_single.value', 1, '!=')
->notExists('field_saved_as_single.value');
But no. That does not work. notExists's and isEmpty's are not welcome in orConditionGroup's.
Is there a simpler way to find out if a checkbox has been checked?
And if not, can we make it?
Well, SomebodySysop. I'm sorry that noone gave you a good answer in time and that the documentation for Drupal 9 is so awful. I try do document my own modules well, at least.
Anyway, here how I solved programmatically adding a filter to a view in Drupal 9.5. It may solve a problem for you in the future or bring some help to all the other lost developers looking for useful documentation and working examples.
I made
a view →
(the format is Full Calender Display, but that doesn't matter) showing the jobs assigned to a specific car on a specific day.
My wish was to programmatically load and show a view block 10 times - once for each car on that day.
So in the views UI I added a filter for field_car_term set to 11.
Then I made this code:
function home() {
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree('cars'); // Get all terms from vocabulary
foreach ($terms as $term) { // Loop through them
$view = Views::getView('job_calendar');
$view->setDisplay('block_1');
unset($view->display_handler->options['filters']['field_car_term_target_id']['value']['11']); // Unset the hardcoded value
$view->display_handler->options['filters']['field_car_term_target_id']['value'][$term->tid] = $term->tid; // Set the dynamic value
$ret[$term->tid]['cal'] = $view->buildRenderable(); // Add the render array of the view to an array
}
return $ret; // Return render array
}
The filter has to exist in the view. Otherwise the above code will not work.
The filter should be hardcoded to something that you later unset. Here it's term id 11.
Setting the filter, you have a surprising amount of freedom
$view->display_handler->options['filters']['field_car_term_target_id']['value'][$term->tid] = $term->tid;
$view->display_handler->options['filters']['field_car_term_target_id']['value'][3] = $term->tid;
$view->display_handler->options['filters']['field_car_term_target_id']['value']['drupalisawfullydocmented'] = $term->tid;
all work well.
The saner looking
$view->display_handler->options['filters']['field_car_term_target_id']['value'] = $term->tid;
does not work whatsoever. So avoid that.
I'd be thrilled if there was a better place to read about how to programatically add filters to a view. A place with more and better examples. But alas. Looking for hours I did not find such a place.
Patch #18 works: https://www.drupal.org/project/autologout/issues/3301642#comment-14764507 🐛 Throws Notice on Login when destination is set Needs work
Easily reproduced the error putting a destination on link to a form. Patch in #18 solved the problem. RTBC +1