<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ivo Bathke | Nerdpress.org</title>
	<atom:link href="https://nerdpress.org/author/ivo-bathke/feed/" rel="self" type="application/rss+xml" />
	<link>https://nerdpress.org</link>
	<description>...dev, tech problems and solutions.</description>
	<lastBuildDate>Thu, 16 Apr 2026 14:19:33 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>PHP&#8217;s serialize_precision hidden danger</title>
		<link>https://nerdpress.org/2026/04/16/phps-serialize_precision-hidden-danger/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Thu, 16 Apr 2026 14:19:02 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[JSON]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3477</guid>

					<description><![CDATA[<p>The PHP configuration directive serialize_precision can cause hard to debug issues. When deviated from its default value, it can lead to inexpected behavior in common functions like json_encode() and serialize(). The Problem If you change the serialize_precision setting from its default value of -1, the float precision will be more digits than 2 decimal places.If &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2026/04/16/phps-serialize_precision-hidden-danger/" class="more-link">Continue reading<span class="screen-reader-text"> "PHP&#8217;s serialize_precision hidden danger"</span></a></p>
The post <a href="https://nerdpress.org/2026/04/16/phps-serialize_precision-hidden-danger/">PHP’s serialize_precision hidden danger</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>The PHP configuration directive <code>serialize_precision</code> can cause hard to debug issues.</p>



<p>When deviated from its default value, it can lead to inexpected behavior in common functions like <code>json_encode()</code> and <code>serialize()</code>.</p>



<span id="more-3477"></span>



<h2 class="wp-block-heading"><strong>The Problem</strong></h2>



<p>If you change the <code>serialize_precision</code> setting from its default value of <strong>-1</strong>, the float precision will be more digits than 2 decimal places.<br />If you are not aware of this setting, it can lead to hard-to-debug issues in your application.</p>



<p>This behavior can silently break payload validation, API responses, or any logic that relies on exact string comparisons of numeric values or which assumes that float values come with 2 decimal places.</p>



<h2 class="wp-block-heading"><strong>Impact on Functions</strong></h2>



<p>When <code>serialize_precision</code> is set to something other than <strong>-1</strong>, the following functions are affected:</p>



<ul class="wp-block-list">
<li>json_encode()</li>



<li>json_decode()</li>



<li>serialize()</li>



<li>unserialize()</li>
</ul>



<p>Consider the following example.<br />Setting a high precision changes the number in the JSON output:</p>


<pre class="wp-block-code"><span><code class="hljs language-xml"><span class="php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-comment">// High precision</span>
ini_set(<span class="hljs-string">"serialize_precision"</span>, <span class="hljs-number">100</span>);
<span class="hljs-keyword">echo</span> json_encode(<span class="hljs-number">12.12</span>);
<span class="hljs-comment">// Output: 12.1199999999999992184029906638897955417633056640625</span>

<span class="hljs-comment">// Default (recommended) precision</span>
ini_set(<span class="hljs-string">"serialize_precision"</span>, <span class="hljs-number">-1</span>);
<span class="hljs-keyword">echo</span> json_encode(<span class="hljs-number">12.12</span>);
<span class="hljs-comment">// Output: 12.12</span></span></code></span></pre>


<h2 class="wp-block-heading"><strong>How to Check Your Configuration</strong></h2>



<p>So better verify your current setting, especially when dealing with mysterious floating-point issues in legacy environments.<br />When on shared hosting, you might even not know that the setting was changed.</p>



<p>You can check it via code:</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-keyword">echo</span> ini_get(<span class="hljs-string">"serialize_precision"</span>);</code></span></pre>


<p>Or, if you are using PHP 8.5 or newer, you can conveniently check for configuration differences using the CLI:</p>


<pre class="wp-block-code"><span><code class="hljs">php --ini=diff</code></span></pre>


<p>This will highlight any settings that differ from the PHP defaults, making it much easier to spot such dangerous configurations.</p>



<h2 class="wp-block-heading"><strong>Conclusion</strong></h2>



<p>If you encounter unexpected floating-point behavior in your PHP application, check the <code>serialize_precision</code> setting first. It&#8217;s a simple fix that can save you hours of debugging.</p>



<p></p>The post <a href="https://nerdpress.org/2026/04/16/phps-serialize_precision-hidden-danger/">PHP’s serialize_precision hidden danger</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>A WordPress-like More Tag in Astro</title>
		<link>https://nerdpress.org/2026/02/28/a-wordpress-like-more-tag-in-astro/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Sat, 28 Feb 2026 14:46:49 +0000</pubDate>
				<category><![CDATA[Astro]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Wordpress]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3470</guid>

					<description><![CDATA[<p>When migrating from WordPress to Astro, one encounters various challenges.One is handling the WordPress &#8220;More&#8221; tag, which originates from the More Element in the WordPress Block Editor. After converting the WordPress export to Markdown, you will find `&#60;!&#8211; more &#8211;>` tags in your content. These tags serve as delimiters in WordPress, allowing you to define &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2026/02/28/a-wordpress-like-more-tag-in-astro/" class="more-link">Continue reading<span class="screen-reader-text"> "A WordPress-like More Tag in Astro"</span></a></p>
The post <a href="https://nerdpress.org/2026/02/28/a-wordpress-like-more-tag-in-astro/">A WordPress-like More Tag in Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>When migrating from WordPress to Astro, one encounters various challenges.<br />One is handling the WordPress &#8220;More&#8221; tag, which originates from the More Element in the WordPress Block Editor.</p>



<p>After converting the WordPress export to Markdown, you will find `&lt;!&#8211; more &#8211;>` tags in your content. These tags serve as delimiters in WordPress, allowing you to define where the excerpt ends on listing pages.</p>



<span id="more-3470"></span>



<h2 class="wp-block-heading"><strong>The Challenge</strong></h2>



<p>Astro does not provide a built-in mechanism to handle these tags. I also could not find a suitable plugin that would manage this functionality.</p>



<p>My first approach was to use a Remark plugin like <a href="https://www.npmjs.com/package/remark-excerpt" target="_blank" rel="noopener" title="">remark-excerpt</a>. However, this did not work as expected. Instead of adding an Excerpt property to the frontmatter or to the data object of the content collection, it simply replaced the Content with the Excerpt.</p>



<p>Writing a custom Remark plugin proved challenging as well. While extracting the excerpt markdown is straightforward, rendering it to HTML is not. Since Astro does not expose its renderer (yet*), you would need to create your own renderer or use Astro&#8217;s internal `astrojs/markdown-remark`. Both approaches are rather hacky and not really recommended.</p>



<p>* <em>There are ongoing discussions about making the renderer API public: <a href="https://github.com/withastro/roadmap/discussions/1094" target="_blank" rel="noopener" title="">Astro Roadmap Discussion #1094.</a></em></p>



<h2 class="wp-block-heading"><strong>The Solution</strong></h2>



<p>The current best way to handle the WordPress More Tag in Astro is to split the rendered HTML content directly.</p>



<p>On the list page where you want to display the excerpt, you can map over the entries, split the rendered HTML at the <code>&lt;!--more--></code> tag, and add the excerpt to the return object:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">const</span> previewPosts = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(
	posts.map(<span class="hljs-keyword">async</span> (post) =&gt; {
		<span class="hljs-keyword">const</span> fullHtml = post.rendered?.html || <span class="hljs-string">''</span>;
		<span class="hljs-keyword">const</span> moreIndex = fullHtml.indexOf(<span class="hljs-string">'&lt;!--more--&gt;'</span>);
		<span class="hljs-keyword">const</span> excerptHtml = moreIndex !== <span class="hljs-number">-1</span> ? fullHtml.slice(<span class="hljs-number">0</span>, moreIndex) : fullHtml;
		<span class="hljs-keyword">const</span> hasMore = moreIndex !== <span class="hljs-number">-1</span>;
		<span class="hljs-keyword">return</span> { post, hasMore, excerptHtml };
	}),
);

{previewPosts.map(<span class="hljs-function">(<span class="hljs-params">{ post, hasMore, Content }</span>) =&gt;</span> (
	<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"preview-content"</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">Content</span> /&gt;</span>
	<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
	{hasMore &amp;&amp; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"read-more"</span>&gt;</span>Read more...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>}
))}</code></span></pre>


<p>Straightforward and effective :)</p>



<p></p>The post <a href="https://nerdpress.org/2026/02/28/a-wordpress-like-more-tag-in-astro/">A WordPress-like More Tag in Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Dynamic OpenGraph Images in Astro</title>
		<link>https://nerdpress.org/2025/12/23/dynamic-opengraph-images-in-astro/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Tue, 23 Dec 2025 13:13:06 +0000</pubDate>
				<category><![CDATA[Astro]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[OpenGraph]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3457</guid>

					<description><![CDATA[<p>If you&#8217;ve ever shared a link on social media, you know how critical OpenGraph (OG) images are. They&#8217;re the first thing people see &#8211; often before they even click.Static OG images are fine as a start, but what if you want custom images for every blog post or content collection item? For Astro there is &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2025/12/23/dynamic-opengraph-images-in-astro/" class="more-link">Continue reading<span class="screen-reader-text"> "Dynamic OpenGraph Images in Astro"</span></a></p>
The post <a href="https://nerdpress.org/2025/12/23/dynamic-opengraph-images-in-astro/">Dynamic OpenGraph Images in Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>If you&#8217;ve ever shared a link on social media, you know how critical OpenGraph (OG) images are. They&#8217;re the first thing people see &#8211; often before they even click.<br />Static OG images are fine as a start, but what if you want <strong>custom images for every blog post or content collection item</strong>?</p>



<p>For Astro there is <a href="https://github.com/delucis/astro-og-canvas" target="_blank" rel="noopener" title="">astro-og-canvas</a>, a nice and useful Astro plugin that utilizes Canvas to create dynamic OG images.</p>



<p>In this post, I&#8217;ll walk you through how to generate dynamic OG images for your Astro site, inspired by <a href="https://aidankinzett.com/blog/astro-open-graph-image/" target="_blank" rel="noopener" title="">Aidan Kinzett&#8217;s excellent post</a>.<br />I&#8217;ll also share some odds and learned lessons.</p>



<span id="more-3457"></span>



<p><strong>Step 1: Set Up `astro-og-canvas`</strong></p>



<p>First, install the package:</p>



<p><code>npm install astro-og-canvas</code></p>



<p>Create a new file at <code>src/pages/og/[...routes].ts</code>.<br />This will dynamically generate images for your content.<br />Here&#8217;s how I set it up for my newsletter collection:</p>


<pre class="wp-block-code"><span><code class="hljs language-typescript"><span class="hljs-keyword">import</span> { OGImageRoute } <span class="hljs-keyword">from</span> <span class="hljs-string">"astro-og-canvas"</span>;
<span class="hljs-keyword">import</span> { getCollection } <span class="hljs-keyword">from</span> <span class="hljs-string">"astro:content"</span>;

<span class="hljs-comment">// Fetch all newsletter entries</span>
<span class="hljs-keyword">const</span> newsletters = <span class="hljs-keyword">await</span> getCollection(<span class="hljs-string">"newsletter"</span>);

<span class="hljs-comment">// Map newsletters to OG image configurations</span>
<span class="hljs-keyword">const</span> pages = {
  ...Object.fromEntries(
    newsletters.map(<span class="hljs-function">(<span class="hljs-params"><span class="hljs-params">newsletter</span></span>) =&gt;</span> &#91;
      newsletter.data.slug,
      {
        data: {
          title: newsletter.data.title,
          description: newsletter.data.newsletter.parts
            .map(<span class="hljs-function">(<span class="hljs-params"><span class="hljs-params">part</span></span>) =&gt;</span> <span class="hljs-string">`<span class="hljs-subst">${part.emoji.icon}</span> <span class="hljs-subst">${part.title}</span>`</span>)
            .join(<span class="hljs-string">" • "</span>),
        },
        slug: newsletter.data.slug,
      },
    ])
  ),
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> { getStaticPaths, GET } = OGImageRoute({
  param: <span class="hljs-string">"route"</span>,
  pages,
  getImageOptions: <span class="hljs-keyword">async</span> (_, { data, slug }) =&gt; ({
    title: <span class="hljs-string">`Ivo's Ecotainment Newsletter: <span class="hljs-subst">${data.title}</span>`</span>,
    description: data.description,
    bgGradient: &#91;
      &#91;<span class="hljs-number">255</span>, <span class="hljs-number">221</span>, <span class="hljs-number">0</span>], <span class="hljs-comment">// Yellow (from logo)</span>
      &#91;<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>], <span class="hljs-comment">// White</span>
    ],
    logo: {
      path: <span class="hljs-string">"./public/Ivos-Ecotainment-Newsletter_Salamander.png"</span>,
      size: &#91;<span class="hljs-number">1080</span>],
    },
    border: {
      color: &#91;<span class="hljs-number">83</span>, <span class="hljs-number">174</span>, <span class="hljs-number">90</span>], <span class="hljs-comment">// Green accent</span>
      width: <span class="hljs-number">2</span>,
      side: <span class="hljs-string">"inline-start"</span>,
    },
    font: {
      title: {
        size: <span class="hljs-number">42</span>,
        weight: <span class="hljs-string">"Bold"</span>,
        families: &#91;<span class="hljs-string">"Noto Sans"</span>, <span class="hljs-string">"Noto Color Emoji"</span>],
        color: &#91;<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>],
      },
      description: {
        size: <span class="hljs-number">20</span>,
        weight: <span class="hljs-string">"Normal"</span>,
        families: &#91;<span class="hljs-string">"Noto Sans"</span>, <span class="hljs-string">"Noto Color Emoji"</span>],
        color: &#91;<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>],
        lineHeight: <span class="hljs-number">1.4</span>,
      },
    },
    fonts: &#91;
      <span class="hljs-string">"./public/fonts/Noto_Sans/NotoSans-VariableFont_wdth,wght.ttf"</span>,
      <span class="hljs-string">"./public/fonts/Noto_Color_Emoji/NotoColorEmoji-Regular.ttf"</span>,
    ],
    padding: <span class="hljs-number">50</span>,
  }),
});</code></span></pre>


<p><br /><strong>Some learned lessons:</strong><br />1. Logos: SVGs won&#8217;t work here. Use PNGs instead.<br />2. Fonts: Add font files, if you use fonts.<br />3. Emojis: If you use emojis in your content, include an emoji font (like &#8220;Noto Color Emoji&#8221;) to ensure they render correctly.</p>



<p><strong>Step 2: Integrate with astro-seo</strong></p>



<p>I use the <a href="https://github.com/jonasmerlin/astro-seo" target="_blank" rel="noopener" title="">astro-seo</a> component in my main Layout component to handle SEO metadata.</p>



<p>For the OG image I add a prop to be passed from the respective page:</p>


<pre class="wp-block-code"><span><code class="hljs language-typescript"><span class="hljs-keyword">const</span> { title, description, ogImage } = Astro.props;

&lt;SEO
  title={title}
  description={description}
  openGraph={{
    basic: {
      title,
      <span class="hljs-keyword">type</span>: <span class="hljs-string">"website"</span>,
      image: ogImage || <span class="hljs-string">`<span class="hljs-subst">${Astro.site}</span>Ivos-Ecotainment-Newsletter_big.png`</span>, <span class="hljs-comment">// Fallback</span>
    },
  }}
/&gt;</code></span></pre>


<p><strong>In Your Content Pages</strong>:<br />Construct the OG image path and pass it to your layout:</p>


<pre class="wp-block-code"><span><code class="hljs language-typescript"><span class="hljs-keyword">const</span> ogImage = <span class="hljs-string">`<span class="hljs-subst">${Astro.site?.href || <span class="hljs-string">""</span>}</span>og/<span class="hljs-subst">${entry.data.slug}</span>.png`</span>;

&lt;Layout title={entry.data.title} description={description} ogImage={ogImage}&gt;
  {<span class="hljs-comment">/* Post content */</span>}
&lt;<span class="hljs-regexp">/Layout&gt;</span></code></span></pre>


<p><strong>Astro Odds</strong>:</p>



<p>A bit odd is if your <code>astro.config.mjs</code> has <code>trailingSlash: "always"</code>, you&#8217;ll need to add a trailing slash to OG image URLs <strong>in development</strong>:<br /><code>http://localhost:4321/og/${entry.data.slug}.png/</code></p>



<p>In prod (no trailing slash needed) so you can just pass it as: <code>http://localhost:4321/og/${entry.data.slug}.png</code></p>



<p></p>



<p><strong>3. Testing OG Images</strong></p>



<p>As recommend in the Blog post of Aidan Kinzett: Use <a href="https://www.opengraph.xyz" target="_blank" rel="noopener" title="">opengraph.xyz</a>  to preview your OG images before sharing links.<br />Very good tool!</p>



<p>Here is how the OG image looks like with logo, title and description with emojis:</p>



<figure class="wp-block-image size-large"><a href="https://ivos-ecotainment-newsletter.info/archiv/pt58-party-parrot/"><img fetchpriority="high" decoding="async" width="1024" height="538" src="https://nerdpress.org/wp-content/uploads/2025/12/pt58-party-parrot-1024x538.png" alt="" class="wp-image-3462" srcset="https://nerdpress.org/wp-content/uploads/2025/12/pt58-party-parrot-1024x538.png 1024w, https://nerdpress.org/wp-content/uploads/2025/12/pt58-party-parrot-300x158.png 300w, https://nerdpress.org/wp-content/uploads/2025/12/pt58-party-parrot-768x403.png 768w, https://nerdpress.org/wp-content/uploads/2025/12/pt58-party-parrot.png 1200w" sizes="(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" /></a></figure>



<p>Happy hacking!</p>



<p></p>The post <a href="https://nerdpress.org/2025/12/23/dynamic-opengraph-images-in-astro/">Dynamic OpenGraph Images in Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>5 Essential Plugins for Yazi File Manager</title>
		<link>https://nerdpress.org/2025/11/08/5-essential-plugins-for-yazi-file-manager/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Sat, 08 Nov 2025 10:35:27 +0000</pubDate>
				<category><![CDATA[TUI]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[tui]]></category>
		<category><![CDATA[yazi]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3442</guid>

					<description><![CDATA[<p>Yazi is my preferred terminal file manager, and these are my five essential plugins that improve my workflow. The Yazi package manager ya will be used to install the plugins mentioned below, which is shipped with Yazi. For the installation of necessary terminal tools, I will use brew, since I am currently on OSX. For &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2025/11/08/5-essential-plugins-for-yazi-file-manager/" class="more-link">Continue reading<span class="screen-reader-text"> "5 Essential Plugins for Yazi File Manager"</span></a></p>
The post <a href="https://nerdpress.org/2025/11/08/5-essential-plugins-for-yazi-file-manager/">5 Essential Plugins for Yazi File Manager</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>Yazi is my preferred terminal file manager, and these are my five essential plugins that improve my workflow.</p>



<p>The Yazi package manager <strong>ya</strong> will be used to install the plugins mentioned below, which is shipped with Yazi.</p>



<p>For the installation of necessary terminal tools, I will use <strong>brew</strong>, since I am currently on OSX. For Linux use the equivalents like <strong>apt</strong>.</p>



<span id="more-3442"></span>



<p><strong> 1. <a href="https://github.com/boydaihungst/mediainfo.yazi" target="_blank" rel="noopener" title="">MediaInfo</a></strong></p>



<p>The MediaInfo plugin adds detailed information to the preview of media files such as JPG, PNG, and other media formats.</p>



<p>Especially Width, Height and Size is very useful.</p>



<figure class="wp-block-image size-large"><a href="https://nerdpress.org/wp-content/uploads/2025/11/yazi-mediainfo-preview-scaled.png"><img decoding="async" width="1024" height="665" src="https://nerdpress.org/wp-content/uploads/2025/11/yazi-mediainfo-preview-1024x665.png" alt="Terminal view of MediaInfo plugin for Yazi rendering a png file" class="wp-image-3443" srcset="https://nerdpress.org/wp-content/uploads/2025/11/yazi-mediainfo-preview-1024x665.png 1024w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-mediainfo-preview-300x195.png 300w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-mediainfo-preview-768x499.png 768w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-mediainfo-preview-1536x998.png 1536w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-mediainfo-preview-2048x1330.png 2048w" sizes="(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" /></a></figure>



<p>Installation:</p>



<ol class="wp-block-list">
<li>Install MediaInfo terminal tool using Brew:<code> brew install mediainfo</code></li>



<li>Add the plugin to Yazi: <code>ya pack -a boydaihungst/mediainfo</code></li>



<li>Add the necessary configuration to your <strong>yazi.toml</strong> file.</li>
</ol>



<p><strong>2. <a href="https://github.com/wylie102/duckdb.yazi" target="_blank" rel="noopener" title="">DuckDB</a></strong></p>



<p>DuckDB.yazi is a plugin for handling CSV, TSV and Parquet files. <br />It uses <a href="https://duckdb.org/" target="_blank" rel="noopener" title="">DuckDB</a> under the hood for adhoc rendering of the data files.</p>



<p>It can also render JSON files as tables, but I have not enabled this, because I want json files preview to just render json as is.<br />So I just added the viewers for tsv and csv in yazi.toml:</p>



<p><code>{ name = "*.csv", run = "duckdb" },<br />{ name = "*.tsv", run = "duckdb" },</code></p>



<figure class="wp-block-image size-large"><a href="https://nerdpress.org/wp-content/uploads/2025/11/yazi-duckdb-csv_preview-scaled.png"><img decoding="async" width="1024" height="665" src="https://nerdpress.org/wp-content/uploads/2025/11/yazi-duckdb-csv_preview-1024x665.png" alt="Terminal view of DuckDB plugin for Yazi rendering a csv file" class="wp-image-3445" srcset="https://nerdpress.org/wp-content/uploads/2025/11/yazi-duckdb-csv_preview-1024x665.png 1024w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-duckdb-csv_preview-300x195.png 300w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-duckdb-csv_preview-768x499.png 768w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-duckdb-csv_preview-1536x998.png 1536w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-duckdb-csv_preview-2048x1330.png 2048w" sizes="(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" /></a></figure>



<p><strong>3. <a href="https://github.com/Reledia/glow.yazi" target="_blank" rel="noopener" title="">Glow</a></strong></p>



<p>Glow.yazi is a plugin for previewing Markdown files.<br />I uses terminal markdown renderer <a href="https://github.com/charmbracelet/glow" target="_blank" rel="noopener" title="">Glow</a>.</p>



<figure class="wp-block-image size-large"><a href="https://nerdpress.org/wp-content/uploads/2025/11/yazi-glow-md-preview-scaled.png"><img decoding="async" width="1024" height="665" src="https://nerdpress.org/wp-content/uploads/2025/11/yazi-glow-md-preview-1024x665.png" alt="Terminal view of Glow plugin for Yazi rendering a markdown file" class="wp-image-3447" srcset="https://nerdpress.org/wp-content/uploads/2025/11/yazi-glow-md-preview-1024x665.png 1024w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-glow-md-preview-300x195.png 300w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-glow-md-preview-768x499.png 768w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-glow-md-preview-1536x998.png 1536w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-glow-md-preview-2048x1330.png 2048w" sizes="(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" /></a></figure>



<p>Installation: </p>



<ol class="wp-block-list">
<li>Install Glow: <code>brew install glow</code></li>



<li> Add the plugin to Yazi: <code>ya pack -a Reledia/glow.yazi</code></li>
</ol>



<p><strong>Note</strong>: the plugin is deprecated by now in favour of the new <a href="https://github.com/yazi-rs/plugins/tree/main/piper.yazi#piperyazi" target="_blank" rel="noopener" title="">Piper</a> plugin, a general-purpose previewer.<br />I might check this out as well in the near future.</p>



<p><strong>4. <a href="https://github.com/ndtoan96/ouch.yazi" target="_blank" rel="noopener" title="">Ouch.yazi</a></strong></p>



<p>This plugin uses <a href="https://github.com/ouch-org/ouch" target="_blank" rel="noopener" title="">Ouch</a> for handling zip, tar, and other archive formats.</p>



<figure class="wp-block-image size-large"><a href="https://nerdpress.org/wp-content/uploads/2025/11/yazi-ouch-zip-preview-scaled.png"><img decoding="async" width="1024" height="665" src="https://nerdpress.org/wp-content/uploads/2025/11/yazi-ouch-zip-preview-1024x665.png" alt="Terminal view of Ouch plugin for Yazi rendering a zip file" class="wp-image-3449" srcset="https://nerdpress.org/wp-content/uploads/2025/11/yazi-ouch-zip-preview-1024x665.png 1024w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-ouch-zip-preview-300x195.png 300w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-ouch-zip-preview-768x499.png 768w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-ouch-zip-preview-1536x998.png 1536w, https://nerdpress.org/wp-content/uploads/2025/11/yazi-ouch-zip-preview-2048x1330.png 2048w" sizes="(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" /></a></figure>



<p>Installation:</p>



<ol class="wp-block-list">
<li>Install Ouch and 7-zip using Brew: <code>brew install ouch 7-zip</code></li>



<li>Add the plugin to Yazi: <code>ya pack -a ndtoan96/ouch</code></li>



<li>Add the &#8220;C&#8221; to your `keymap.toml` file to compress files:<br /><code>[[mgr.prepend_keymap]]<br />on = ["C"]<br />run = "plugin ouch"<br />desc = "Compress with ouch"</code></li>
</ol>



<p>Simply press &#8220;Enter&#8221; on an archive file should uncompress the archive.</p>



<p><strong>5. <a href="https://github.com/Ape/open-with-cmd.yazi" target="_blank" rel="noopener" title="">OpenWithCmd</a></strong></p>



<p>OpenWithCmd is a plugin for opening files with specific commands, such as opening a file in LibreOffice. In Finder one would usually use right click &#8220;Open with&#8221; dialog.</p>



<p>Installation:</p>



<ol class="wp-block-list">
<li>Add the plugin to Yazi: <code>ya pack -a Ape/open-with-cmd.yazi</code></li>



<li>Add the &#8220;o&#8221; and &#8220;O&#8221; to your `keymap.toml` file to open the OpenWith dialog:<br /><code>[[mgr.prepend_keymap]]<br />on = "o"<br />run = "plugin open-with-cmd --args=block"<br />desc = "Open with command in the terminal"<br />[[mgr.prepend_keymap]]<br />on = "O"<br />run = "plugin open-with-cmd"<br />desc = "Open with command</code>&#8220;</li>
</ol>



<p>To open a file in LibreOffice from Yazi, type &#8220;o&#8221; and enter <code>calc type:soffice --calc</code> in the dialog.</p>



<p>Note that the window might not focus directly, and you may need to check if it is opened in the background.</p>



<p>This plugin overrides the `o/O` keymap, but you can still use `Enter` or `Shift+Enter` to open files directly in the default app.</p>The post <a href="https://nerdpress.org/2025/11/08/5-essential-plugins-for-yazi-file-manager/">5 Essential Plugins for Yazi File Manager</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Symfony HTTP Client default timeout</title>
		<link>https://nerdpress.org/2025/08/06/symfony-http-client-default-timeout/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Wed, 06 Aug 2025 07:02:56 +0000</pubDate>
				<category><![CDATA[Symfony]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3428</guid>

					<description><![CDATA[<p>Small Service Post: The default timeout of the Symfony HTTP Client is 60s (seconds)! Sure, it is mentioned in the Symfony HTTP Client docs, that PHP&#8217;s default_socket_timeout is taken as default value.So what is the default_socket_timeout then, you might wonder? One click away in PHP Runtime Configuration docs you will find that in the php.ini &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2025/08/06/symfony-http-client-default-timeout/" class="more-link">Continue reading<span class="screen-reader-text"> "Symfony HTTP Client default timeout"</span></a></p>
The post <a href="https://nerdpress.org/2025/08/06/symfony-http-client-default-timeout/">Symfony HTTP Client default timeout</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p><br />Small Service Post:<br /><br />The default timeout of the Symfony HTTP Client is <strong>60s</strong> (seconds)!<br /><br />Sure, it is mentioned in the <a href="https://symfony.com/doc/current/reference/configuration/framework.html#timeout" title="">Symfony HTTP Client docs</a>, that PHP&#8217;s <em>default_socket_timeout</em> is taken as default value.<br />So what is the default_socket_timeout then, you might wonder?</p>



<p>One click away in <a href="https://www.php.net/manual/en/filesystem.configuration.php" target="_blank" rel="noopener" title="">PHP Runtime Configuration docs</a> you will find that in the php.ini the default value is &#8220;60&#8221;. <br />In case you wonder what unit these &#8220;60&#8221; is, you will find <em>(in seconds)</em> a bit down below the config table. <br />&#8211; Yeah, seconds was my first guess, but I need to assure it is not microseconds by any chance. &#8211;</p>



<p>And thats it! Thats the post.</p>



<p>P.S: It is funny how scattered information sometimes is, although is all there. <br />AI did know, but did not name a source. <br />And since AI is not to trust, I still had to look it up via Search.</p>The post <a href="https://nerdpress.org/2025/08/06/symfony-http-client-default-timeout/">Symfony HTTP Client default timeout</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>From Xubuntu to Lubuntu</title>
		<link>https://nerdpress.org/2025/07/26/from-xubuntu-to-lubuntu/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Sat, 26 Jul 2025 15:38:25 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[permacomputing]]></category>
		<category><![CDATA[ubuntu]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3423</guid>

					<description><![CDATA[<p>I have this old, super-cheap laptop: Lenovo E145, which I use as my travel and breakfast laptop. It has 8GB of RAM and a very weak CPU (AMD E1-2500 APU). Any modern mobile phone probably has more resources these days. For surfing the web, checking mails, editing and uploading some fotos it is sufficient and &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2025/07/26/from-xubuntu-to-lubuntu/" class="more-link">Continue reading<span class="screen-reader-text"> "From Xubuntu to Lubuntu"</span></a></p>
The post <a href="https://nerdpress.org/2025/07/26/from-xubuntu-to-lubuntu/">From Xubuntu to Lubuntu</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>I have this old, super-cheap laptop: Lenovo E145, which I use as my travel and breakfast laptop. It has 8GB of RAM and a very weak CPU (AMD E1-2500 APU). Any modern mobile phone probably has more resources these days.</p>



<p>For surfing the web, checking mails, editing and uploading some fotos it is sufficient and I prefer using a laptop for this.</p>



<p>I used to run <a href="https://xubuntu.org/" target="_blank" rel="noopener" title="">Xubuntu</a> on it, but lately it had performance issues and all programs and actions were lagging very significantly. So I decided to reinstall the OS and try <a href="https://lubuntu.me/" target="_blank" rel="noopener" title="">Lubuntu</a>, since it should be even more lean.</p>



<p>I grabbed the current Lubuntu image (25.04 Plucky Puffin), created a bootable USB stick, and installed Lubuntu. So far, so good. And indeed, everything felt much smoother and faster.</p>



<p>But, as usual, there are some post-installation hiccups which needed a bit more tuning.</p>



<span id="more-3423"></span>



<ol class="wp-block-list">
<li>Wifi<br />WiFi was not working out of the box. <br />The E145 ships with a Broadcom WiFi chip (BCM43142), and the drivers are proprietary and need to be installed separately. After some Googling and trying this and that, this finally worked for me: <br /><code>sudo apt install broadcom-sta-dkms <br />reboot</code> <br />And WiFi worked. :)</li>



<li>Encryption<br />Another change is the encryption strategy: <br />before I had only my home directory encrypted, but this option wasn&#8217;t available anymore in the Lubuntu installer. <br />Apparently, encoding only the home directory is discouraged nowadays since it has some security flaws. (&#8220;Encrypting only the home directory leaves swap, temp files, and system logs unprotected, exposing sensitive data.&#8221;) <br />So this time I encrypted the whole disk, as offered in the installer. However, now I would have to enter the passphrase to decrypt the disk and then I would also have to enter user credentials to log in. This felt a bit cumbersome, so I enabled auto-login since I will be the only user using this laptop. And now I only have to enter the passphrase and can immediately use it.</li>



<li>Browsers<br />There are more and more browsers to choose from, so picking the right one becomes a task.<br />I used to use Chromium, but since I have had rather bad experiences with the Snap install and there is no easy other way to install Chromium, I simply turned to Chrome. <br />Not the best choice in privacy regards, admittedly. But I will be using my Google account on this browser anyway, and then it is the full package. <br />For more privacy-focused browsing, I will use <a href="https://librewolf.net/" target="_blank" rel="noopener" title="">Librewolf</a>, a Firefox clone with privacy and security focus.</li>
</ol>



<p>Librewolf recommends installation on Ubuntu/Debian via the <a href="https://manpages.ubuntu.com/manpages/focal/man1/extrepo.1p.html" target="_blank" rel="noopener" title="">Extrepo</a> tool.<br />Extrepo is a neat tool that takes care of adding external repositories and installing software from there in one command.</p>



<p>Turned out Extrepo can also install Chrome, so I installed both browsers with it.<br />First install Extrepo:<br /><code>sudo apt update &amp;&amp; sudo apt install extrepo -y</code><br />Then install Librewolf &amp; Chrome:<br /><code>sudo extrepo enable librewolf<br />sudo extrepo enable google-chrome</code></p>



<ol class="wp-block-list"></ol>



<p>That&#8217;s it so far. Ready to use my old travel laptop for some more years with newest software. <br />Keep using old hardware!</p>The post <a href="https://nerdpress.org/2025/07/26/from-xubuntu-to-lubuntu/">From Xubuntu to Lubuntu</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Yazi PDF preview not working</title>
		<link>https://nerdpress.org/2025/05/31/yazi-pdf-preview-not-working/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Sat, 31 May 2025 10:25:43 +0000</pubDate>
				<category><![CDATA[TUI]]></category>
		<category><![CDATA[pdf]]></category>
		<category><![CDATA[tui]]></category>
		<category><![CDATA[yazi]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3415</guid>

					<description><![CDATA[<p>Yazi is a terminal-based file manager (TUI) that I use heavily because it&#8217;s fast and lets me navigate files and folders without needing a mouse. (&#8230;and I really dislike the OSX Finder) Yazi can render previews for images and PDF files, but in my case, PDF previews weren&#8217;t showing up. Yazi requires Poppler for PDF &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2025/05/31/yazi-pdf-preview-not-working/" class="more-link">Continue reading<span class="screen-reader-text"> "Yazi PDF preview not working"</span></a></p>
The post <a href="https://nerdpress.org/2025/05/31/yazi-pdf-preview-not-working/">Yazi PDF preview not working</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p><a href="https://yazi-rs.github.io/" target="_blank" rel="noopener" title="">Yazi</a> is a terminal-based file manager (TUI) that I use heavily because it&#8217;s fast and lets me navigate files and folders without needing a mouse. (&#8230;and I really dislike the OSX Finder)</p>



<p>Yazi can render previews for images and PDF files, but in my case, PDF previews weren&#8217;t showing up. Yazi requires Poppler for PDF previewing&#8211;and it was already installed on my system&#8211;the previews still didn&#8217;t work.</p>



<p>So I began debugging by running <code>yazi --debug</code>, which provides detailed information about your Yazi installation. Under the Dependencies section, I noticed a suspicious message:</p>



<pre class="wp-block-preformatted">pdftoppm      : ExitStatus(unix_wait_status(25344)),"pdftoppm version 4.0...</pre>



<span id="more-3415"></span>



<p><br />This should actually just render the version of <strong>pdftoppm</strong> by poppler like:</p>



<pre class="wp-block-preformatted">pdftoppm      : 25.04.0</pre>



<p>So there was clearly some issue with <strong>Poppler</strong> and <strong>pdftoppm</strong> here.<br />Then I ran <strong>Yazi</strong> with a debug log enabled: <code>YAZI_LOG=debug yazi</code><br />and checked the log file in <code>~/.local/state/yazi/yazi.log</code></p>



<p>And there was also an error:</p>



<pre class="wp-block-preformatted">ERROR yazi_scheduler::prework::prework: Error when running preloader pdf:<br />Failed to convert PDF to image, stderr: pdftoppm version 4.05 [www.xpdfreader.com]</pre>



<p>It turns out that Xpdf was conflicting with the actual <code>pdftoppm</code> utility from Poppler. I had previously installed Xpdf for some reason, and it was now preventing Poppler from being installed properly. The error message confirmed the conflict:</p>



<pre class="wp-block-preformatted">Error: Cannot install poppler because conflicting formulae are installed.<br />xpdf: because poppler, pdftohtml, pdf2image, and xpdf install conflicting executables</pre>



<p>So I uninstalled Xpdf via brew: <code>brew unlink xpdf</code><br />Reinstalled <strong>Poppler</strong> via brew and now everything works nice:</p>



<figure class="wp-block-image size-large"><a href="https://nerdpress.org/wp-content/uploads/2025/05/yazi-pdf-preview.png"><img decoding="async" width="1024" height="167" src="https://nerdpress.org/wp-content/uploads/2025/05/yazi-pdf-preview-1024x167.png" alt="" class="wp-image-3416" srcset="https://nerdpress.org/wp-content/uploads/2025/05/yazi-pdf-preview-1024x167.png 1024w, https://nerdpress.org/wp-content/uploads/2025/05/yazi-pdf-preview-300x49.png 300w, https://nerdpress.org/wp-content/uploads/2025/05/yazi-pdf-preview-768x125.png 768w, https://nerdpress.org/wp-content/uploads/2025/05/yazi-pdf-preview.png 1286w" sizes="(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" /></a><figcaption class="wp-element-caption">Yazi terminal file manager PDF preview</figcaption></figure>



<p></p>The post <a href="https://nerdpress.org/2025/05/31/yazi-pdf-preview-not-working/">Yazi PDF preview not working</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Patch dependencies with composer-patches</title>
		<link>https://nerdpress.org/2025/04/11/patch-dependencies-with-composer-patches/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Fri, 11 Apr 2025 10:10:56 +0000</pubDate>
				<category><![CDATA[Composer]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[composer]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3406</guid>

					<description><![CDATA[<p>Sometimes, you may encounter a bug or an unwanted functionality in a PHP vendor dependency, and forking the package and maintaining upstream changes can be too cumbersome. In such cases, using composer-patches is a good solution. Composer-patches is a handy Composer plugin that applies diff patches to specific packages during installation. Basically, you store a &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2025/04/11/patch-dependencies-with-composer-patches/" class="more-link">Continue reading<span class="screen-reader-text"> "Patch dependencies with composer-patches"</span></a></p>
The post <a href="https://nerdpress.org/2025/04/11/patch-dependencies-with-composer-patches/">Patch dependencies with composer-patches</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>Sometimes, you may encounter a bug or an unwanted functionality in a PHP vendor dependency, and forking the package and maintaining upstream changes can be too cumbersome. In such cases, using <strong><a href="https://github.com/cweagans/composer-patches" target="_blank" rel="noopener" title="">composer-patches</a></strong> is a good solution.</p>



<p><strong>Composer-patches</strong> is a handy Composer plugin that applies diff patches to specific packages during installation.</p>



<p>Basically, you store a diff patch in your project, specify which vendor package it should be applied to in your <code>composer.json</code>, and the plugin will apply the patch to the original code of the vendor package after it got installed by composer.</p>



<span id="more-3406"></span>



<p>The <a href="https://docs.cweagans.net/composer-patches/" target="_blank" rel="noopener" title="">documentation</a> provides detailed instructions on how to set up the plugin.<br />In short, you need:</p>



<ul class="wp-block-list">
<li>Install the plugin (we&#8217;re using the v2 beta) with:<br /><code>composer require cweagans/composer-patches:^2.0.0-beta2</code></li>



<li>Create a patch. The plugin relies on Git as the patcher, so you can use Git to generate the patch file. (See below)<br />However, I recommend using another package to create the patch file:<br /><a class="" href="https://github.com/symplify/vendor-patches">https://github.com/symplify/vendor-patches</a><br />This package provides an opinionated but reasonable way to create and store your patches. <strong>vendor-patches</strong> takes care of the correct paths in the patch file, which might not be immediately obvious: Pathes should be relative to the vendor package root and not relative to your projects root dir.</li>



<li>Add the patch instructions to your <code>composer.json</code> by including a <code>patches</code> section under <code>extra</code>. For example:</li>
</ul>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-string">"extra"</span>: {
  <span class="hljs-string">"patches"</span>: {
    <span class="hljs-string">"oxid-esales/oxideshop-ce"</span>: {
      <span class="hljs-string">"Disable user registration due to spam attacks"</span>: <span class="hljs-string">"./patches/disable-registerUser.patch"</span>
    }
  }
}</code></span></pre>


<p>On your next <code>composer install</code> the vendor package will be patched and the vendor&#8217;s <br />code will be altered according the patch.</p>



<p>Some notes: If you encounter the error:</p>



<pre class="wp-block-preformatted">Could not apply patch! Skipping. The error was: Cannot apply patch disable-registerUser.patch</pre>



<p>You might have incorrect paths in your patch file. As mentioned above, the paths need to be relative to the vendor root directory, not your project&#8217;s root directory.<br />So to manually create the diff patches, run this command:</p>



<pre class="wp-block-preformatted">diff --git a/source/Application/Component/UserComponent.php b/source/Application/Component/UserComponent.php</pre>



<p><br />This is <strong>wrong</strong> usage from project root dir:</p>



<pre class="wp-block-preformatted">diff --git a/vendor/oxid-esales/oxideshop-ce/source/Application/Component/UserComponent.php b/vendor/oxid-esales/oxideshop-ce/source/Application/Component/UserComponent.php</pre>



<p>Happy patching! :)</p>The post <a href="https://nerdpress.org/2025/04/11/patch-dependencies-with-composer-patches/">Patch dependencies with composer-patches</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ObfuscateLink Web Component in Astro</title>
		<link>https://nerdpress.org/2025/02/07/obfuscatelink-web-component-in-astro/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Fri, 07 Feb 2025 09:36:02 +0000</pubDate>
				<category><![CDATA[Astro]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Web components]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3393</guid>

					<description><![CDATA[<p>Using Web Components in Astro wasn&#8217;t as straightforward as expected. Here&#8217;s an example showing how to integrate the obfuscate-link web component into an Astro project.&#160; First, add the Obfuscate-Link web component to the project: Now register ObfuscateLink with customElements:&#160; This occurs in the Layout.astro component, making it available across all pages. The registration happens within &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2025/02/07/obfuscatelink-web-component-in-astro/" class="more-link">Continue reading<span class="screen-reader-text"> "ObfuscateLink Web Component in Astro"</span></a></p>
The post <a href="https://nerdpress.org/2025/02/07/obfuscatelink-web-component-in-astro/">ObfuscateLink Web Component in Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>Using Web Components in <a href="https://astro.build/" title="">Astro</a> wasn&#8217;t as straightforward as expected. Here&#8217;s an example showing how to integrate the <a href="https://github.com/ivoba/obfuscate-wc" title="">obfuscate-link</a> web component into an Astro project.&nbsp;</p>



<p>First, add the Obfuscate-Link web component to the project:</p>


<pre class="wp-block-code"><span><code class="hljs">npm install obfuscate-link-web-component</code></span></pre>


<span id="more-3393"></span>



<p>Now register ObfuscateLink with customElements:&nbsp;</p>


<pre class="wp-block-code"><span><code class="hljs language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">slot</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
      <span class="hljs-keyword">import</span> { ObfuscateLink } <span class="hljs-keyword">from</span> <span class="hljs-string">'obfuscate-link-web-component'</span>;
      <span class="hljs-comment">// Only define the custom element if it hasn't been defined yet</span>
      <span class="hljs-keyword">if</span> (!customElements.get(<span class="hljs-string">'obfuscate-link'</span>)) {
        customElements.define(<span class="hljs-string">'obfuscate-link'</span>, ObfuscateLink);
      }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span></code></span></pre>


<p>This occurs in the Layout.astro component, making it available across all pages. The registration happens within a script tag in the HTML to execute only on the client side, avoiding it execution while SSR rendering performed by Astro beforehand.</p>



<p>Next, create an Astro component that wraps the web-component and handles the obfuscation by encoding the passed prop.</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">---
type BaseProps = {
  id?: string;
}
type EmailProps = BaseProps &amp; {
  <span class="hljs-attr">email</span>: string;
  tel?: never;
  sms?: never;
  facetime?: never;
  href?: never;
}
type TelProps = BaseProps &amp; {
  email?: never;
  tel: string;
  sms?: never;
  facetime?: never;
  href?: never;
}
type SmsProps = BaseProps &amp; {
  email?: never;
  tel?: never;
  sms: string;
  facetime?: never;
  href?: never;
}
type FacetimeProps = BaseProps &amp; {
  email?: never;
  tel?: never;
  sms?: never;
  facetime: string;
  href?: never;
}
type HrefProps = BaseProps &amp; {
  email?: never;
  tel?: never;
  sms?: never;
  facetime?: never;
  href: string;
}
<span class="hljs-keyword">export</span> type Props = EmailProps | TelProps | SmsProps | FacetimeProps | HrefProps;
<span class="hljs-keyword">const</span> props = Astro.props;
<span class="hljs-keyword">const</span> { id } = props;
<span class="hljs-comment">// Find the active prop (email, tel, sms, facetime, or href)</span>
<span class="hljs-keyword">const</span> activeProp = <span class="hljs-built_in">Object</span>.entries(props).find(<span class="hljs-function">(<span class="hljs-params">&#91;key, value]</span>) =&gt;</span> 
  key !== <span class="hljs-string">'id'</span> &amp;&amp; value !== <span class="hljs-literal">undefined</span>
);
<span class="hljs-keyword">let</span> attribute = <span class="hljs-string">''</span>;
<span class="hljs-keyword">let</span> value = <span class="hljs-string">''</span>;
<span class="hljs-keyword">if</span> (activeProp) {
  &#91;attribute, value] = activeProp;
  <span class="hljs-keyword">const</span> orgValue = value;
  value = Buffer.from(value).toString(<span class="hljs-string">'base64'</span>);
}
---

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">obfuscate-link</span>
  <span class="hljs-attr">id</span>=<span class="hljs-string">{id}</span>
  {<span class="hljs-attr">...</span>{&#91;<span class="hljs-attr">attribute</span>]<span class="hljs-attr">:</span> <span class="hljs-attr">value</span>}}
&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">slot</span> /&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">obfuscate-link</span>&gt;</span></span></code></span></pre>


<p>Finally, you can utilize both the Astro component and the Web component throughout your Astro project.</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">
---
<span class="hljs-keyword">import</span> ObfuscateLink <span class="hljs-keyword">from</span> <span class="hljs-string">'./ObfuscateLink.astro'</span>;
---

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
    Email: <span class="hljs-tag">&lt;<span class="hljs-name">ObfuscateLink</span> <span class="hljs-attr">email</span>=<span class="hljs-string">"info@example.com"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span></code></span></pre>


<p>The complete code can be seen in this Gist: </p>



<p><a href="https://gist.github.com/ivoba/222d5a49ad4542392772195c5e5ad032" target="_blank" rel="noopener" title="">https://gist.github.com/ivoba/222d5a49ad4542392772195c5e5ad032</a></p>The post <a href="https://nerdpress.org/2025/02/07/obfuscatelink-web-component-in-astro/">ObfuscateLink Web Component in Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Doctrine: WHERE IN with array of integers</title>
		<link>https://nerdpress.org/2025/01/17/doctrine-where-in-with-array-of-integers/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Fri, 17 Jan 2025 16:34:32 +0000</pubDate>
				<category><![CDATA[Doctrine ORM]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[Sql]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3381</guid>

					<description><![CDATA[<p>Since I stumbled across this the other day, here&#8217;s how you build an SQL query with a WHERE IN condition for an array of integers. This is surprisingly not intuitive, as you cannot simply pass an array of integers to a prepared statement. Instead, you need to add special binding types to inform Doctrine that &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2025/01/17/doctrine-where-in-with-array-of-integers/" class="more-link">Continue reading<span class="screen-reader-text"> "Doctrine: WHERE IN with array of integers"</span></a></p>
The post <a href="https://nerdpress.org/2025/01/17/doctrine-where-in-with-array-of-integers/">Doctrine: WHERE IN with array of integers</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>Since I stumbled across this the other day, here&#8217;s how you build an SQL query with a <code>WHERE IN</code> condition for an array of integers.</p>



<p>This is surprisingly not intuitive, as you cannot simply pass an array of integers to a prepared statement. Instead, you need to add special binding types to inform Doctrine that this is indeed an array of integers.</p>



<p>It&#8217;s very well explained in the documentation under the Parameters Conversion section:<br /><a href="https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion">https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion</a><br />But it is rather hard to find and it took me a while.</p>



<p>The trick is to add the array binding types to the the types parameters to the query method. In the case of integers, it is<code> \Doctrine\DBAL\ArrayParameterType::INTEGER</code>. <br />Now Doctrine knows how to handle the types in the array while binding the values.</p>



<span id="more-3381"></span>



<p>Example:</p>


<pre class="wp-block-code"><span><code class="hljs language-php">$sql = <span class="hljs-string">'SELECT * FROM items WHERE id IN (?)'</span>; 
$numbersAsStrings = <span class="hljs-string">"1,2,3"</span>;
$numbers = array_map(<span class="hljs-string">'intval'</span>, explode(<span class="hljs-string">','</span>, $numbersAsStrings));
$users = $con-&gt;fetchAllAssociative(
  $sql, 
  &#91;$numbers], 
  &#91;ArrayParameterType::INTEGER]
);</code></span></pre>


<p>If you omit the types, Doctrine will simply try to bind the array as string, which will fail and you get this error:<br /><em>Array to string conversion</em></p>



<p>If you try to pass it as a comma-separated string yourself and omit the types like <kbd><code>$numbers = implode(',',array_map('intval', explode(',', $numbersAsStrings)));</code></kbd> You will get an error because Doctrine expects an array of values for the <kbd>IN</kbd> clause and not a string.<br />Error: <br /><em>count(): Argument #1 ($value) must be of type Countable|array, string given</em></p>



<p>I hope this helps someone finding out how to make <kbd>WHERE IN</kbd> SQL queries with Doctrine more quickly than me next time.</p>



<p></p>The post <a href="https://nerdpress.org/2025/01/17/doctrine-where-in-with-array-of-integers/">Doctrine: WHERE IN with array of integers</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
