I found the following excellent library for copying files to and fro from my AlphasSync Neo2. However, I had to build it in Xcode from a specific pull request to get it working on Catalina. Knowing that this is beyond the ability of most folks, I am uploading the app, so that other can benefit. I have simply repackaged it. You can read about it here. Distributed under this license, no warranty expressed or implied. Download the dmg file here…
Read more about AlphaSync MacOS Catalina: Download and Install App/DMG◆
Doesn't seem like there's a hook for this. According to people in the forum, this can't be controlled. Flexbox to the rescue! Stick this in functions.php. Make sure to use your dev tools to make sure the classes are right. But basically, you use flexbox order property to rearrange items in the left admin sidebar. add_action('admin_head', 'mytheme_custom_admin_css'); function mytheme_custom_admin_css() { echo ' html .edit-post-meta-boxes-area { order: -1; } html .components-panel { display: flex; flex-direction: column; } '; }…
Read more about Re-Order Sidebar Widgets in Wordpress Admin Left Sidebar◆
NodeBB uses custom themes, but expects them to be installed as an npm dependency. And here we have a problem. Who wants to make a npm package for some client's one-off theme? I prefer to version the theme directly in the repo, less confusing for future developers. But only you, reader, may truly judge if this process is preferable. In for a penny, in for a pound. And so it goes…
Read more about How to Fork and Deploy a NodeBB Custom Theme to Heroku◆
If you're running a cron job as root, and you're running a homebrew command, you'll need to add homebrew to the root user's path. sudo su cat ~/.bash_profile Do you see this? ? If not, run echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bash_profile Test it source ~/.bash_profile which mycommand…
Read more about Failed crontab for root on OSX◆
When a dev first adds typescript to a project, they often complain that it slows them down. Why install something whose only job is to complain about perfectly good software? Typescript, like a linter and an IDE, can help you catch mistakes before you break production or solicit annoyed comments from senior devs. So I'm going to give you some advice below that's... controversial. But I believe in dipping your toe into the water before diving into the deep end…
Read more about Solving Typescript "Problems" in React: How to Argue with Typescript and Win, Even When You're Wrong◆
Wix has a Show More tutorial, but it only allows you to replace the text of content, and does not allow you to use HTML in your Show More expanded or collapsed content. There would be a million ways to solve this, but Wix likes to lock you down in their scripts and prevent you from modifying the DOM. For a developer used to being able to accomplish whatever is needed, this is frustrating. Here's the solution I came up with for a friend: Here's the code. Read the instructions in the comments…
Read more about Make a Wix Show-More with HTML content◆
NodeJS scripts from the CLI can be difficult to debug. Often, one doesn't want to modify the core processes. I found the easiest way to hit a breakpoint was to create a shell wrapper. But I was worried... would my code have access to stdin and stdout? The answer is yes, scripts called from within scripts have access to stdin and stdout. Call your script from within a shell script. Here's the wrapper script: exec node --inspect-brk=9229 ./myscript.js. You can use whatever port you like…
Read more about Debugging a nodejs cli script with --inspect◆
I used to love Scrivener, but eventually, my 7-year-old novel started to take 5-10 minutes to sync, among other problems. All of Scrivener's fancy export options turned out to be totally useless--so useless that I wrote my own nodejs conversion utility to ease the pain of converting my MS from Scrivener to standard MS format. Ulysses is simple and works great. I did have a few problems importing my with filenames. Here’s what to do if you don’t care about filenames. But if you do, read on. Select all the files in scrivener you wish to export…
Read more about Export From Scrivener to Ulysses, Preserving Filenames◆
I ran into a problem with a composer script timing out on my machine because I had xdebug installed on the cli. Now, I sometimes actually use xdebug on the cli, so I wanted a cli config that allowed xdebug to be switched on and off, but defaults to off. The solution uses the PHP_INI_SCAN_DIR variable. Create a separate conf.d directory that symlinks everything except ext-xdebug.ini, then point PHP_INI_SCAN_DIR to it…
Read more about PHP Cli With Optional Xdebug: Separate Cli Ini File◆
My HTML, or what I thought was HTML, was actually generating an object of type Twig_Markup rather than a string, and therefore wasn't passing json validation. Hmm. raw didn't work. But Twig_Markup has a magic method, __toString() which is called, magically, when Twig_Markup is printed. So, I just had to invoke that directly. Which was as easy as: {% set buttonHtml = buttonHtml.__toString(buttonHtml) %) Happy coding! References: Twig_Markup API docs…
Read more about Casting Twig_Markup to string in Twig◆
I had to do a little RTFMing today, and so I thought I'd post about it. First of all, this is how you set up PhpStorm to use ES6 eslint settings. You may find it useful Is the linter getting in your way? The first way to override an eslint setting is inline, disabling it on a one-off basis. If you truly need a new .eslintrc.json file, then you should probably extend the one from Drupal core. Here's how the linter looks for eslint files. TL;DR: like .gitignore files. Finally, here's how the extends property of eslintrc.json…
Read more about Overriding Drupal 8's .eslintrc.json File in Your Theme With Extends◆
You may not know this, but support for ES6 was added in Drupal 8.4. It wasn't in the release notes, but I was delighted to learn of it. You have probably landed here because you have gotten the error: Cannot find module 'eslint-config-airbnb'. If you want to see ES6 linting in PHPStorm, you'll need to do a couple of things. (In order to actually use ES6 in your theme, you'll have to configure your own build transpiling task, which is out of scope here…
Read more about Drupal ES6 Linting in PhpStorm. Or, PhpStorm Drupal Error: Cannot find module 'eslint-config-airbnb'◆
I recently had to move a bunch of Wordpress sites. Wordpress, generally, is terribly insecure. Here are my notes for configuring and hardening Wordpress. Certainly these measures are incomplete. I gathered them from several sources. I write them here, for posterity, and so I don't forget in the future. Steps include setting file permissions (644 for files, 755 for directories), disabling PHP execution in uploads, and adding .htaccess rules to deny direct access to sensitive files…
Read more about Hardening Wordpress File Permissions◆
It can be hard to tell why a mixin fails in a sass file. After all, if the mixin isn't included in your dependencies automatically as it was before, grepping for it in the files won't turn up anything. I was using a child theme of Classy, running Drupal 8. It turns out that this particular generically-named mixin comes from susy 2.x, having been removed in susy 3.x. I fixed this by pinning the susy version number in package.json…
Read more about Error: no mixin named container or border-box-sizing◆
I had a very strange problem wherein I was not able to affect variables being passed to views-view-grid--my_view.html.twig. function mytheme_preprocess_views_view(&$vars) { if ($vars['view']->id() == 'myview') { $vars['amaaaazingVar'] = '!'; } } Yet, sadly, there was no amaaaazingVar to be found in views-view-grid--my_view.html.twig when I did {{ kint() }}. What did I do? I set a breakpoint in the twig template using this methodology and then looked back through to see what preprocess functions were being called by the theme. And yes... my preprocess function was called. But the variables weren't getting saved. Strange. Why were my variables clobbered…
Read more about D8: Variables in template_preprocess_views_view not passed to twig◆
On the method of disabling a block without recourse to path…
Read more about D8: Disable Block Programmatically on Just One View or Node◆
On the method of creating custom breadcrumbs: simply crumble stale bread and dip battered eggs into your bowl. But in Drupal…
Read more about Drupal 8.3: Create Programmatic Custom Breadrumb◆
I had a devil of a time figuring out where captioning was coming from on my entity embeds. Another team member had set it up, and I was just kind of baffled as to why captions were being offered on my entity embed forms. It turns out that if you turn on captioning, you just get it for free on all of your embeds, and it's not configurable. But... I don't want it for free! Bah. Humbug. Here's how you turn off captioning using hook_form_alter()…
Read more about 8: Disable Caption on Specific Entity Embed Types in CkEditor◆
All of a sudden, on a commit which had nothing to do with drush as far as I can tell, drush stopped working on platform.sh. I got an error like this: env: drush: No such file or directory Which is to say, "no drush here." But why? It's added in composer. Nothing changed. I ran platform drush-aliases and refreshed them. Stop asking why. Here's how I fixed it. Turns out that drush still exists on the server, even though which drush led to nothing. Not in the path? Unclear. Here's how I fixed it. Or worked around it…
Read more about Platform.sh drush alias stops working◆
Sometimes, you've got a Drupal twig function that doesn't exist in PatternLab, and it prevents PatternLab from building. You get an "Unknown filter" error. What you need to do is create a Twig stub that does either what you need it to, or nothing at all. In emulsify, twig functions exist at emulsify/components/_twig-components/filters. For example, to create a typogrify filter, create a file called typogrify.filter.php…
Read more about Add a New Twig Function in Patternlab◆
Views has a setting to exclude the current nid from the URL from the listing one is currently viewing. This is essential when you have, say, a list of related nodes that are are defined by a category that includes the current node. If you don't exclude the current node, your current node will be listed in the "related content" block on itself. Well, obviously one is related to oneself, one thinks. First, I tired to accomplish this through the UI with these steps, below. Add contextual filter: Get content ID from URL: Exclude results: Perfect! Except, wait…
Read more about 8: Programatically Filter Current Nid from Views Block Listing◆
So, your debug output isn't working. You checked to make sure you followed all the steps here. But still... no theme debug output. WTF? Try turning on and off twig caching. For me, it seemed something was stuck or whatever. First turn it on: twig.config: debug: true auto_reload: true cache: true Then do drush cr. Then turn it off: twig.config: debug: true auto_reload: true cache: false Then do drush cr. Sometimes the code that makes Drupal run can kind of pile up and get stuck, like a logjam in a river. This just clears the blockage. Just kidding…
Read more about Twig/Theme Debug Not Working Even Though Set◆
It turns out that image style tokens are an easter egg of the regular Token module, ported in from the Imagecache Token module on this ticket. Image style tokens don't show up in the media browser, and so you sort of have to guess at how to use them. I figured it out by studying the merged commit that added the functionality…
Read more about Drupal 8: How to Get Image Style Tokens for Metatags◆
Pluralizing and singularizing words got very easy with the inclusion of the Doctrine Inflector class in Drupal 8 core. use Doctrine\Common\Inflector\Inflector; $pluralized = Inflector::pluralize($bundle_singular); $singularized = Inflector::singularize($bundle_singular); You can read more about the Doctrine Inflector class here…
Read more about How to Pluralize and Singularize a Word in Drupal 8◆
The task at hand here is to allow the client to create a classed wrapper around multiple elements using CKEditor in Drupal 8. The fundamental problem here is the CKEditor's built in "Styles" dropdown classes each individually, while we need a class wrapping them. You could probably make or install your own CKEditor plugin, but that's not what I did. I did this with Javascript…
Read more about Add Multi-Element Wrapper Class With CKEditor in Drupal 8◆
Client has a bunch of static landing pages that are mobile-friendly and need to remain that way. But what is to be done about srcset? Read on, oh reader, for the solution. First, I created a gulp build task which makes a bunch of different sizes. Install dependencies like this: npm install -D gulp-load-plugins gulp-responsive sharp. The task uses gulp-responsive to generate multiple image sizes from a source directory…
Read more about Drupal srcset in static HTML pages: gulp asset build pipeline◆
There're a lot of really complicated descriptions of srcset out there. As a result, I thought srcset was more complicated than it actually is. Here's the all-purpose srcset code I used in my static HTML. This covers 1x, 1.5x, 2x, and mobile optimization in a fine-grained way: Explanation In srcset, you're telling the browser the sizes of the images that you have to fill the hole. /images/myimage-100w.png 100w, describes the width of the image myimage-100w.png as 100px. In sizes, you're specifying the size of the image hole to fill based on media queries…
Read more about Srcset Example and Explanation in Static HTML◆
You never know when you're going to encounter data ravaged by clients, cast aside and mauled, an antelope passed by lions to jackals. But fortunately, data is much easier to repair than a gaping wound. Here's the SQL query I'd use to replace non-breaking spaces with regular spaces. You'll need to replace it with whatever your search term is. The queries target both node_revision__body and node__body tables using SQL REPLACE and LIKE…
Read more about SQL Search and Replace in Drupal 8 Body Field◆
Here's the controlling issue for adding timezone support to Drupal core. As of now, August 1st, 2017, it doesn't appear to be ready. Instead, I just added a timezone field to the node using the Timezone module, then appended it to the date range on field preprocess. This won't work for you if you have multiple dates on an entity with different timezones (you might want to try the patch linked above), but it will fit most use cases…
Read more about Drupal 8.4x: Add Timezone to Date or DateRange Field◆
Over the last several days, I've railed in my head against the matroshka structure of Drupal entities. But when I tried to break out some helper functions, and when I realized what each of the different properties each entity had, I realized the complexities of entities were warranted. Life is complex, and thus Drupal is complex. Entity references load a Media Entity, which load an Image from an image field, which load a File. The alt and title are on the Image, while the file URI is on the file…
Read more about Drupal 8: Get URI, Title, and Alt from Media Entity Reference Item◆
This is pretty simple, but it took me a minute, because I kept trying to use the base Entity class, like an angry baby trying to remove a clenched fist from a bottle. use Drupal\media_entity\entity\Media; Media::load($media_id)…
Read more about Get Drupal 8 Media Entity Object from ID◆
This function gets all the Media ID's from the database whose names begins with a specific string. I'm using this for an array of default images. You can see I'm using both drupal_static() and \Drupal::cache(). Necessary? I would bet \Drupal::cache() goes to the database to ask for information (unless you're using Memcache or Redis, that is), and thus in a view with multiple content listings calling this function drupal_static() will be faster, because that saves to a PHP variable. Overkill for a little query like this? OK, sue me. I love performance. Here's the code…
Read more about Drupal EntityFieldQuery, drupal_static(), \Drupal::cache() Example◆
It can take a minute to figure out what method to use to get the file URL from the file URI. Here's what I did: file_create_url($file_entity->get('uri')->getString()) Now, mind you, this requires a file entity. Function doc here. For details on getting that, see this…
Read more about Drupal 8: How to Get a File URL from a File URI like public://filename Suitable for img src◆
Zebras. (I just wanted to use my "z" illumination.) In general, it's not necessary to add a timezone to both start and end dates. But if you modify the date format, that's exactly what will happen. So how do we add the site timezone just to the end of the DateTimeRange? The solution uses mytheme_preprocess_field() to append the timezone abbreviation to the end date, producing output like: 8/2/17 5:15 PM - 8/2/17 10:15 PM EDT…
Read more about Append Site Timezone to End Date in DateRange in Drupal 8◆
Another day learning Drupal 8, but today is troubling. Here's where I'm at. I'm theming search results, and I need to load field values to pass to twig templates—specifically a styled url for img src. Entities values are not loaded on search results, only little snippets, so I have to load them the hard way, because we want images and nice theming on our search results…
Read more about Get File URI from Media Entity Reference Item in Drupal 8 OR Wrong File Loaded◆
Well, that's because you can't. For whatever reason. I can't modify the variables in search-result.html.twig like so: function mytheme_preprocess_search_result(&$variables) { $variables['result']['testvar'] = 'beeeg test!'; $variables['result']['title'] = 'AMAAAAZING NEW TITLE!!!'; } Hmm. Okay. But I can access testvar like so in the twig file: {{ result.testvar }} And if I really want to change the title of my search results, I can do this: function mytheme_preprocess_item_list(&$vars) { foreach ($vars['items'] as &$item) { $res =& $item['value']['#result']; $res['title'] = 'bleaaargh!' ; } } And now all titles are set to 'bleaaargh!' as they should be…
Read more about Can't modify title in search-result.html.twig with template_preprocess_search_result()◆
Sometimes, I've had a rule that fails continually, because data on it is bad. Maybe it was created in development, maybe it's just gone rogue—data with a broken-off arrowhead lodged in its side, tearing through trees until, foam crusting its lips, it lays down to die. Here's what I would do. First, poke around in the queue table in the db. You can also get valuable info from the rules_scheduler table. I would set a breakpoint in common.inc in drupal_cron_run() right where $queue->claimItem() happens…
Read more about Deleted Undead Scheduler Queue Entries◆
Quite the problem—Drupal config management on local and prod. Drupal 8 can be punctilious: it will simply refuse to work if there's a mismatch between database and config objects on the filesystem. So... how do we manage two sets of configurations—one for local, and one for production? The Problem I have modules like varnish installed on production that shouldn't be enabled on local, and modules that are enabled on local that shouldn't be enabled on production. I have uninstalled varnish_purger on local…
Read more about Config Management Roundup◆
So you found this post because you just updated or installed PHPUnit, you're running PHP 5.6, and you get this error: "This version of PHPUnit is supported on PHP 7.0 and PHP 7.1. You are using PHP 5.6.30 (/usr/local/Cellar/php56/5.6.30_6/bin/php)." Maybe, like me, you're cranky about virtualization and you're using a PHP switcher to switch between PHP 5.6 and 7.1. The solution? brew install phpunit@5.7 Then you can run: phpunitat57 mytest…
Read more about Install PHPUnit for PHP 5.6 and PHP 7.1 on Homebrew◆
Nobody likes iframes. That's because you can't style their innards, and they aren't responsive... or are they?!?! The first thing to know about here is the padding height hack. This allows you to set the height of an object relative to the width, because while height is always as a percentage of the container, padding height is as a percentage of width. So all you have to know is the ratio of height to width and you can make a thing that responsively scales. My first attempt was to use javascript to get the viewport height from the iframe…
Read more about Responsive iframe in Drupal 8 from Client Embed Code◆
Often one finds oneself needing to parse HTML. Back in the day, we used regexes, and smoked inside. We didn't even know about caveman coders back then. Later, we'd use SimpleHtmlDom and mostly just swore when things didn't quite work as expected. But now, we can use PHP's DomDocument, and in Drupal we create them using Drupal's HTML utility. At the top of your file place: use Drupal\Component\Utility\Html; Now, I'm looking for an iframe embed in my HTML, and I want the src, width, and height…
Read more about Parse HTML in Drupal 8 to Get Attributes◆
Have you ever wanted to .gitignore a file by branch? The classic example for me here is versioning the generated styles.css file on master (which is deployed to production) but not on develop (which is used for pull requests). Versioning the styles.css file can result in merge conflicts or PRs that are just messy. Here's the script I wrote. Read the comments for installation notes…
Read more about .gitignore by branch◆
Personally, I feel overwhelmed looking at the ocean of metatags presented on the node edit page when the metatag module is installed. How much more overwhelmed would a regular ol' user feel? I created a small modules to hide the extra form elements from the metatag module: metatag_limit.module…
Read more about Remove Extra Metatags on Node Form, Drupal 8◆
There are many suggestions for how to go about theming field collections and several confusing problems. The most important problem is that there appears to be no preprocess hook for field-collection-item--my-field-collection-name.tpl.php (if someone knows otherwise please correct me in the comments, my tests did not work). Next, using field--my-field-collection-name.tpl.php cascades down to all the fields on the field collection, which results in confusing behavior. There is a very long thread on this subject which would take you time to digest…
Read more about Theming Field Collections With Preprocess Hooks in Drupal 7◆
The view relationship for Flag module only allows you to set a single flag type as a target, which means only one flag type is available on a views row. My specific use case is adding flag/unflag links to the /admin/content page which I've replaced by a view with the Admin Views module. I ended up digging around quite a bit through Flag module's source code to pop this one out. The heart of it is in a views field template--one of your choosing…
Read more about Add Drupal 7 Flag/Unflag Links to View for All Available Actions◆
Edited 8-27-2018 I love PHPStorm. However, the clipboard history function mainly just gets in my way. After a long survey of various clipboard history applications on the Mac, I chose Clipboard History. And I'm quite happy with it. Click Help -> Edit Custom Properties Paste in this property: ide.mac.useNativeClipboard=True Next, you have to turn off the keyboard shortcut that brings up the history, which conflicted with the button mapping for Clipboard History, Ctrl + Shift + V. Search for "clipboard" under PHPStorm -> Preferences, then click Keymap, and remap the "Paste from History" button to nothing…
Read more about How to Turn off PHPStorm's Clipboard History◆
The admin toolbar is a user's first look at Drupal. A complex, cluttered toolbar gives the n00b a sense that things in this site are too much to handle. A clean, well-curated interface that presents content tasks first gives the n00b a sense that Drupal is easy to use. Drupal 8 promises a simplified toolbar that gives the user this cozy sense of belonging. Default Drupal Toolbar The toolbar module is a big improvement over no toolbar at all…
Read more about Drupal 7 Administration Toolbar Roundup◆
Ever have wanted to import data into your Drupal site from JSON or a big ol' PHP array? You don't need to sweat all the gory details of matching up nodes and fields and coding massive for loops. Let the Drupal Feeds module do that for you. We're going to be uisng the Feeds Extensible Parsers module which provides a JSONpath expression analyzer…
Read more about Feeds Extensible Parsers JSONPath Tutorial: Map JSON to Drupal Fields◆
The landscape of paid OCR solutions is, well, expensive. And the unbiased folks from the tesseract homepage say, "Tesseract is probably the most accurate open source OCR engine available." Tesseract OCR's images, but pypdfocr uses tesseract as an engine to convert whole PDFs. With a few crafty command-line utilities, we can create a watched folder that will automatically OCR any PDF copied into it, and create a nice OCR'ed PDF which you can cut-and-paste text from or search happily. This tutorial is partially based on the one at the pypdfocr page, and I owe much to this launchd tutorial…
Read more about PDF to PDF OCR launchd Daemon: Setting a Watched Folder to Create OCR'ed, Searchable PDFs on Mac OSX