<?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/"
	xmlns:media="http://search.yahoo.com/mrss/"
>

<channel>
	<title>Programmering &#8211; Squazz.dk</title>
	<atom:link href="https://squazz.dk/tag/programmering/feed/" rel="self" type="application/rss+xml" />
	<link>https://squazz.dk/tag/programmering/</link>
	<description>IT, rejser &#38; økonomi - lidt af det hele</description>
	<lastBuildDate>Thu, 26 Jan 2023 12:43:17 +0000</lastBuildDate>
	<language>da-DK</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://squazz.dk/wp-content/uploads/2019/03/cropped-favicon-512x512-2-80x80.jpg</url>
	<title>Programmering &#8211; Squazz.dk</title>
	<link>https://squazz.dk/tag/programmering/</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">70087090</site>	<item>
		<title>Entity Framework og nullable variable</title>
		<link>https://squazz.dk/teknologi/entity-framework-og-nullable-variable/</link>
					<comments>https://squazz.dk/teknologi/entity-framework-og-nullable-variable/#respond</comments>
		
		<dc:creator><![CDATA[Kasper Plougmann]]></dc:creator>
		<pubDate>Mon, 12 Dec 2022 13:32:36 +0000</pubDate>
				<category><![CDATA[Programmering]]></category>
		<guid isPermaLink="false">http://squazz.dk/?p=4020</guid>

					<description><![CDATA[Hos en kunde havde de problemer med at det tog rigtigt lang tid når de forsøgte at hente data ud af deres views gennem Entity Framework. Det viste sig at de flere steder brugte&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[ <p> Hos en kunde havde de problemer med at det tog rigtigt lang tid når de forsøgte at hente data ud af deres views gennem Entity Framework. </p> 
 <p> <span id="more-4020"></span> </p> 
 <p> Det viste sig at de flere steder brugte OR i deres WHERE clauses. Hvilket var det første problem. <br /> 
Mens en OR i en SELECT eller CASE clause ikke er noget stort problem, er det generelt ikke en god idé at have OR i din WHERE clause. Dette fordi en OR resulterer i at der laves et fuldt tablescan. </p> 
 <a class="deep-link" href="#or-vs-union"><h2 id="or-vs-union">OR vs UNION</h2></a>
 <p> Lad os prøve at se på det konkrete eksempel jeg havde ude hos kunden, for at se hvordan vi kan gøre det bedre. </p> 
 <p> Nedenstående rå SQL query tager mig over 30 sekunder at eksekvere på min database gennem SQL Server Management Studio (SSMS): </p> 
<pre class="c-mrkdwn__pre" data-stringify-type="pre">SELECT *
FROM GetCustomerPurchases_View
WHERE (
         CardIdentification IN ('ABC', 'DEF', 'JKL', 'ASD')
         OR CustomerId = 123
      )
      AND PurchaseTime &gt; '2021-11-17 00:00:00'
      AND CardIdentification IS NOT NULL</pre>
 <p> Ændrer jeg koden til at bruge UNION i stedet for OR, vil den resulterende SQL query komme til at se således ud: </p> 
<pre class="c-mrkdwn__pre" data-stringify-type="pre">SELECT *
FROM GetCustomerPurchases_View
WHERE CardIdentification IN ('ABC', 'DEF', 'JKL', 'ASD')
      AND PurchaseTime &gt; '2021-11-17 00:00:00'
UNION
SELECT *
FROM GetCustomerPurchases_View
WHERE CustomerId = 123
      AND PurchaseTime &gt; '2021-11-17 00:00:00'
      AND CardIdentification IS NOT NULL</pre>
 <p> Når jeg har lavet query om til at bruge UNION i stedet for OR, tager det mig under et sekund at eksekvere min query, og jeg får det samme datasæt tilbage. </p> 
 <a class="deep-link" href="#or-vs-union"><h2 id="or-vs-union">OR vs UNION</h2></a>
 <p> Hvorfor er querien med UNION hurtigere end OR? </p> 
 <p> Som nævnt tidligere, resulterer en OR i vores WHERE clause, at der bliver lavet et fuldt tablescan. Men med UNION får SQL Server i stedet lov til at lave en eksekutionplan hvor den vælger den optimale strategi for de enkelte subqueries, inden der bliver lavet UNION på datasættene fra vores subqueries. Dette kan resultere i nogle meget hurtigere subqueries, og af hvad jeg har erfaret, er det konsekvent hurtigere end et fuldt tablescan. </p> 
 <a class="deep-link" href="#at-faa-det-lavet-i-linq"><h2 id="at-faa-det-lavet-i-linq">At få det lavet i LINQ</h2></a>
 <p> Da kunden kører med EntityFramework skulle vi have implenteret vores query som </p> 
 <p> At få det implementeret i rå SQL som LINQ var dog straks sværere. </p> 
 <p> Et intuitivt første forsøg ville være at gøre som herunder, hvor vi blot omskriver vores SQL query til LINQ: </p> 
<pre>var listWithCustomerPurchases = context.GetCustomerPurchases_View
   .Where(x =&gt;
      cardIdentificationList.Contains(x.CardIdentification)
      &amp;&amp; x.PurchaseTime &gt;= cutOffDate)
   .Union(
      context.GetCustomerPurchases_View
      .Where(x =&gt;
         x.CustomerId == Customer_Id 
         &amp;&amp; x.PurchaseTime &gt;= cutOffDate
         &amp;&amp; x.CardIdentification != null)
      )
   .ToList();</pre>
 <p> Men i det konkrete eksempel ude hos kunden, resulterede det i at vi nu stadig fik et uønsket OR i vores SQL statement fra LINQ: </p> 
<pre>SELECT *
FROM [GetCustomerPurchases_View] AS [Extent1]
WHERE (
   ([Extent1].[CustomerId] = @p__linq__0) 
   OR (([Extent1].[CustomerId] IS NULL) AND (@p__linq__0 IS NULL))
) 
AND ([Extent1].[PurchaseTime] &gt;= @p__linq__1) 
AND ([Extent1].[CardIdentification] IS NOT NULL)
@p__linq__0=13213;@p__linq__1=65465</pre>
 <p> Dette uønskede OR kom fra at LINQ kunne se at vores Customer_Id kunne være NULL. </p> 
 <p> Så, for at fjerne vores uønskede OR, skal vi sikre os at Customer_Id ikke kan være NULL. Ude hos kudnen gjorde vi det helt konkret ved at tjekke for om Customer_Id er NULL, og hvis ikke, tage value fra denne over i en variable som ikke er nullable. </p> 
 <p> Denne løsning ses implementeret herunder </p> 
<pre>var query = context.GetCustomerPurchases_View
   .Where(x =&gt;
      cardIdentificationList.Contains(x.CardIdentification)
      &amp;&amp; x.PurchaseTime &gt;= cutOffDate);

if(Customer_Id .HasValue){
   var customerIdLong = Customer_Id.Value;

   var queryWithCustomerIds = context.GetCustomerPurchases_View
      .Where(x =&gt;
         x.CustomerId== customerIdLong 
         &amp;&amp; x.PurchaseTime &gt;= cutOffDate
         &amp;&amp; x.CardIdentification != null);
      )
   query = query.Union(queryWithCustomerIds);
}

var listWithCustomerPurchases = query.ToList();</pre>
 <p> Nu hvor jeg kun laver union når jeg ved at Customer_Id ikke er null, kommer den resulterende SQL til at se ud om vi ønsker den. </p> 
<pre>SELECT *
FROM [GetCustomerPurchases_View] AS [Extent1]
WHERE ([Extent1].[CustomerId] = @p__linq__0) 
AND ([Extent1].[PurchaseTime] &gt;= @p__linq__1) 
AND ([Extent1].[CardIdentification] IS NOT NULL)
@p__linq__0=13213;@p__linq__1=65465</pre>
 <p> Det har også den øgede bonus at querien er endnu hurtigere hvis Customer_Id rent faktisk er NULL, da der så er lidt mindre at checke for vores WHERE clause. </p> 
<pre>SELECT *
FROM [GetCustomerPurchases_View] AS [Extent1]
WHERE ([Extent1].[PurchaseTime] &gt;= @p__linq__0)
AND ([Extent1].[CardIdentification] IS NOT NULL)
@p__linq__0=65465</pre>
 <p> &nbsp; </p> 
]]></content:encoded>
					
					<wfw:commentRss>https://squazz.dk/teknologi/entity-framework-og-nullable-variable/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			<media:content url="https://squazz.dk/wp-content/uploads/2022/12/computer-number-environment-pattern-line-coding-1172040-pxhere.com-1-760x507.jpg" medium="image" />
<post-id xmlns="com-wordpress:feed-additions:1">4020</post-id>	</item>
		<item>
		<title>Blazor for skeptikere</title>
		<link>https://squazz.dk/teknologi/blazor-for-skeptikere/</link>
					<comments>https://squazz.dk/teknologi/blazor-for-skeptikere/#respond</comments>
		
		<dc:creator><![CDATA[Kasper Plougmann]]></dc:creator>
		<pubDate>Wed, 18 Aug 2021 13:57:43 +0000</pubDate>
				<category><![CDATA[Programmering]]></category>
		<category><![CDATA[Personlig udvikling]]></category>
		<guid isPermaLink="false">http://squazz.dk/?p=3896</guid>

					<description><![CDATA[I lang tid så jeg ikke meningen bag Blazor. Hvad skal vi bruge det til, og er det ikke bare ligesom Razor, WPF og andre lignende frameworks? Siden 2018 har mine kollegaer, især de&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I lang tid så jeg ikke meningen bag Blazor. Hvad skal vi bruge det til, og er det ikke bare ligesom Razor, WPF og andre lignende frameworks? </p> 
 <p> <span id="more-3896"></span> </p> 



<p class="wp-block-paragraph">Siden 2018 har mine kollegaer, især de der har deres primære fokus på C#, snakket meget om <a href="https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor" target="_blank" rel="noopener external">Blazor</a>, hvor vildt det var og at det skulle være fremtiden for frontend-udvikling. </p> 
 <p> Jeg må indrømme, at jeg altid har været skeptisk. Da jeg først hørte om det var alle mine associationer knyttet til <a href="https://docs.microsoft.com/en-us/aspnet/core/razor-pages/" target="_blank" rel="noopener external">Razor pages fra ASP.NET</a>, som jeg ikke havde de bedste erfaringer med. Hvis man gerne ville have den typestærke tilgang, hvorfor ikke bare bruge <a href="https://www.typescriptlang.org/" target="_blank" rel="noopener external">Typescript</a>. Hvad er problemet i at snakke med et <a href="https://graphql.org/" target="_blank" rel="noopener external">GraphQL API</a> gennem en JS klient? </p> 
 <p> Hvis du har det som jeg, er du kommet til det rette sted. I det følgende vil jeg forsøge at redegøre for hvilke dele af Blazor hypen der kan retfærdiggøres, og hvor jeg tror evangelisterne tager fejl, samt hvor vi som skeptikere måske har misforstået Blazor. </p> 
 <p> Det bliver ikke en lang gennemgang, men jeg linker løbende videre til en del kilder hvis du er interesseret i at lære mere. </p> 
 <a class="deep-link" href="#hvad-er-blazor"><h2 id="hvad-er-blazor">Hvad er Blazor?</h2></a>
 <p> Blazor udnytter introduktionen af WebAssembly (WASM) i 2015, til at muliggøre eksekvering af C# på klient-siden af en webapplikation. </p> 
 <p> Blazor er et frontend framework for SPA (Single-Page Applikation), som bruger C# som fullstack. Blazor gør det dermed muligt at skrive klient-side applikations-kode i C#, uden at skulle gøre brug af JavaScript, som du ellers ville gøre det med <a href="https://jquery.com/" target="_blank" rel="noopener external">jQuery</a>, <a href="https://angular.io/" target="_blank" rel="noopener external">Angular</a>, <a href="https://reactjs.org/" target="_blank" rel="noopener external">React</a> og lignende. Tanken er at Blazor i din webapplikation skal erstatte disse JS-frameworks. </p> 
 <p> Kombineret med en .NET Core backend, muliggør det at have .NET kode end-to-end. En .NET backend udvikler bliver pludselig en fullstack udvikler, i stand til også at skrive klient-koden i webapplikationen. </p> 
 <a class="deep-link" href="#hvordan-virker-blazor"><h2 id="hvordan-virker-blazor">Hvordan virker Blazor?</h2></a>
 <p> Der er som udgangspunkt to udgaver af Blazor. Der er den server-side renderede udgave, og så er der den klient-side renderede. Hver har sine fordele og ulemper, men fordelen ved dem begge er at det er samme kode, der bruges begge steder. </p> 
 <p> Ved server-side rendering sendes alle UI ændringer fra serveren til browseren via SignalR. På den klient-renderede udgave, sendes DLL&#8217;er til klienten, som så renderes af <a href="https://github.com/dotnet/runtime/tree/main/src/mono/wasm" target="_blank" rel="noopener external">dotnet.wasm</a>. Klientudgaven (WebAssembly udgaven) er hvad vi bedst kan sammenligne med moderne JS frameworks så som Angular &amp; React. </p> 
 <a class="deep-link" href="#debugging-oplevelsen"><h2 id="debugging-oplevelsen">Debugging oplevelsen</h2></a>
 <p> Debugging af koden kan ofte være en stor del af arbejdet. Derfor er det også meget relevant for os at se på hvordan den oplevelse egentligt vil være i <a href="https://blexin.com/en/blog-en/blazor-vs-angular-which-to-choose-part-one/" target="_blank" rel="noopener external">Blazor i forhold til traditionel frontend</a> (JavaScript). </p> 
 <p> Med frameworks som Angular &amp; React vil en stor del af debugging oplevelsen foregå direkte i browseren med de indbyggede værktøjer der er at finde her. Det er også muligt at <a href="https://www.hanselman.com/blog/compiling-c-to-wasm-with-mono-and-blazor-then-debugging-net-source-with-remote-debugging-in-chrome-devtools" target="_blank" rel="noopener external">debugge direkte i browseren med Blazor</a>, men <a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/debug#debug-in-the-browser-1" target="_blank" rel="noopener external">det kræver lidt ekstra opsætning</a>, og er ikke en lige så lækker oplevelse som det er det for JavaScript/TypeScript. En uddybende gennemgang af hvordan debugging af Blazor fungerer kan <a href="https://stackoverflow.com/a/58851109/1955317" target="_blank" rel="noopener external">findes på StackOverflow</a>. </p> 
 <a class="deep-link" href="#fordelene-ved-blazor"><h2 id="fordelene-ved-blazor">Fordelene ved Blazor</h2></a>
 <p> Blazor introducerer, sammen med WebAssembly, et nyt paradigmeskifte for den måde vi tænker frontendudvikling. </p> 
<ul>
<li>Gør det muligt at eksekvere C# i din frontend
<ul>
<li>Bryder JS monopolet på frontend</li>
<li>Hvis du allerede kender C# har du lynhurtigt også en frontend, uden at du behøver være programmerings <a href="https://da.wikipedia.org/wiki/Polyglot" target="_blank" rel="noopener external">polyglot</a></li>
</ul>
</li>
<li>Hurtig udvikling, kort Time To Market
<ul>
<li>Det er nemt for en enkelt udvikler at producere både frontend og backend, og sende begge dele til produktionsserveren </li>
</ul>
</li>
<li>Baseret på WebAssembly
<ul>
<li>Muligt at dele forretningslogik &amp; validering i både front og backend</li>
</ul>
</li>
<li>.NET IL har potentialet for at være hurtigere end JavaScript kode. Dette kan gøre Blazor til det foretrukne værktøj ved udvikling af spil og andre performance-afhængige applikationer</li>
<li>Hvis du ikke er glad for WPF, kan du forholdsvist nemt <a href="https://www.telerik.com/blogs/blazor-wpf#toc_4" target="_blank" rel="noopener external">bruge Blazor sammen med WPF i .NET6</a></li>
<li><a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/state-management" target="_blank" rel="noopener external">Blazor applikationer er natively stateful</a></li>
<li>Samme kodebase for <a href="https://visualstudiomagazine.com/articles/2019/09/26/blazor-future.aspx" target="_blank" rel="noopener external">web, desktop &amp; mobil</a></li>
<li>Samme kodebase for <a href="https://visualstudiomagazine.com/articles/2019/09/26/blazor-future.aspx" target="_blank" rel="noopener external">WPA, native &amp; hybride cross-platform apps</a></li>
</ul>
 <a class="deep-link" href="#ulemperne-ved-blazor"><h2 id="ulemperne-ved-blazor">Ulemperne ved Blazor</h2></a>
 <p> Desværre kommer Blazor ikke uden sine egne udfordringer.  </p> 
<ul>
<li>Blazor kan ikke arbejde med DOM elementerne direkte. Derfor vil der fra tid til anden være brug for JavaScript Interop, til at udfylde de huller denne manglende funktionalitet resulterer i. Det er derfor i mange tilfælde ikke muligt helt at droppe javascript.</li>
<li>Blazor er i øjeblikket (2021) langsommere end JavaScript. Microsoft har dog en god track record i forhold til performance optimeringer, så dette skulle gerne være et mindre problem på længere sigt</li>
<li>Debugging er ikke en lige så god oplevelse som  den er det ved etablerede JS frameworks.</li>
</ul>
 <a class="deep-link" href="#renderingsspecifikt"><h3 id="renderingsspecifikt">Renderingsspecifikt</h3></a>
 <p> Alt efter hvilken renderings-tilgang du bruger, har de også hver deres ulemper. </p> 
 <a class="deep-link" href="#wasm-renderer"><h4 id="wasm-renderer">WASM renderer:</h4></a>
<ul>
<li>Stor payload.
<ul>
<li>Ud over at skulle downloade applikationens WASM og .NET biblioteker til browseren, skal Mono.wasm også hentes ned. </li>
<li>En &#8220;Hello World&#8221; applikation har en <a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/#size" target="_blank" rel="noopener external">payload på ca. 1Mb i .NET 6</a>, men det løber efter sigende hurtigt op i <a href="https://www.reddit.com/r/Blazor/comments/i4t1dw/blazor_app_sizes_not_that_bad_really/g0keo2e/?utm_source=reddit&amp;utm_medium=web2x&amp;context=3" target="_blank" rel="noopener external">5-6Mb når man først har en færdig applikation</a>. <a href="https://itnext.io/blazor-switching-server-and-webassembly-at-runtime-d65c25fd4d8" target="_blank" rel="noopener external">Nogle melder om +10Mb</a>.</li>
<li>1Mb for en &#8220;Hello World&#8221; applikation er meget når man sammenligner med størrelsen på andre frontend frameworks: <a href="https://medium.com/dailyjs/a-realworld-comparison-of-front-end-frameworks-2020-4e50655fe4c1#31f0" target="_blank" rel="noopener external">https://medium.com/dailyjs/a-realworld-comparison-of-front-end-frameworks-2020-4e50655fe4c1</a></li>
<li><a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/webassembly-lazy-load-assemblies" target="_blank" rel="noopener external">Lazy loading </a>kan løse lidt af disse problemer, <a href="https://blexin.com/en/blog-en/blazor-vs-angular-which-to-choose-part-two/" target="_blank" rel="noopener external">men det er stadig noget begrænset og omstændigt</a></li>
</ul>
</li>
</ul>
 <a class="deep-link" href="#serverside-renderer"><h4 id="serverside-renderer">Serverside renderer:</h4></a>
<ul>
<li>Kræver konstant adgang til backend.
<ul>
<li>Hvis forbindelsen brydes, stopper applikationen med at virke, indtil forbindelse kan genetableres</li>
<li>Hvis serveren genstartes, vil applikationen stoppe med at virke og state tabes </li>
</ul>
</li>
<li>Svært at skalere, klienten vil kun fungere med den server som gemmer dens state. <a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/hosting-models?view=aspnetcore-3.1#connection-to-the-server-2" target="_blank" rel="noopener external">Kan løses med Sticky Sessions i SignalR</a></li>
<li>Ikke muligt at lave til en PWA</li>
<li>Introducerer en del crosstalk frem og tilbage mellem klient og server. Kan give store problemer hvis responstid er høj / hvis du er en mobil-bruger</li>
</ul>
 <a class="deep-link" href="#kombinering-af-serverside-wasm"><h2 id="kombinering-af-serverside-wasm">Kombinering af serverside &amp; WASM</h2></a>
 <p> Med ulemperne ved henholdsvis klient-rendering og serverside-rendering, kan det være svært at finde det oplagte sted at bruge Blazor. Især hvis man er afhængig af at applikationen starter hurtigt op. </p> 
 <p> Det er dog muligt at køre en hybrid af de to renderinger, ved at køre en hybrid løsning. <a class="ck cl at au av aw ax ay az ba fj bd fk fl" href="https://medium.com/@zaikinsr" target="_blank" rel="noopener external">Sergey Zaikin</a> har lavet en gennemgang af hvordan han formåede at løse denne <a href="https://itnext.io/blazor-switching-server-and-webassembly-at-runtime-d65c25fd4d8" target="_blank" rel="noopener external">hybrid Blazor opsætning</a> i et demoprojekt. </p> 
 <a class="deep-link" href="#konklusion"><h2 id="konklusion">Konklusion</h2></a>
 <p> Blazor er et stærkt værktøj, i den rette usecase. </p> 
 <p> Som landskabet for Blazor ser ud lige nu, er Blazor rigtigt stærkt hvis du laver enterprise applikationer, hvor du er sikker på at dine brugere altid tilgår applikationen med en computer. Hvis dine brugere bruger mobile enheder, skal du være villig enten til at: </p> 
<ul>
<li>Lade dine brugere vente et stykke tid på at applikationen er indlæst (WASM)</li>
<li>Acceptere at applikationen ikke kan virke offline (ServerSide)</li>
</ul>
 <p> Blazor viser rigtigt sine styrker når der er tale om at størstedelen af applikationen består af CRUD operationer mod en .NET backend. Især fordi man så har muligheden for at dele forretningslogik mellem backend og frontend gennem webassembly. Denne centralisering af fx valideringslogik gør det noget nemmere at vedligeholde komplekse forretningsgange. </p> 
 <p> I fremtiden vil payload på download af mono.wasm, .NET DLL&#8217;er samt applikationens DLL&#8217;s blive mindre og mindre. Vi har allerede set dette da vi gik fra .NET core til .NET5. Og <a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/#blazor-and-mono" target="_blank" rel="noopener external">.NET6 ser også ud til at give massive performance forbedringer.</a> </p> 
 <p> Hvis  Blazor skal blive bredt accepteret som en platform for webudvikling, er der dog stadig et behov for <span class="match">nedbringelse</span> af payload. Det er en hård konkurrence at skulle kæmpe med JavaScript, når JavaScript eksekverer direkte i browseren, uden at være afhængige af at skulle køre ovenpå en runtime skrevet i WebAssembly (som skal hentes ned som det allerførste i applikationens levetid). </p> 
 <p> Jeg kan ikke forestille mig en fremtid hvor Blazor erstatter JavaScript. Blazor vil derimod sikkert blive som så mange andre frameworks, biblioteker og værktøjer. Nogle vil undgå det, andre vil omfavne det. Uagtet vil internettet forsætte sin vante udvikling, præcis som vi har set det med udviklingen af de forskellige JavaScript frameworks. </p> 
 <a class="deep-link" href="#hvordan-kommer-jeg-videre"><h2 id="hvordan-kommer-jeg-videre">Hvordan kommer jeg videre?</h2></a>
 <p> Hvis du ønsker at lære mere om Blazor, kan du finde links til yderligere læsning samt referencer til demoprojekter på <a href="https://github.com/AdrienTorris/awesome-blazor?WT.mc_id=dotnet-35129-website" target="_blank" rel="noopener external">Awesome Blazor</a>&#8216;s git repo. </p> 
]]></content:encoded>
					
					<wfw:commentRss>https://squazz.dk/teknologi/blazor-for-skeptikere/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			<media:content url="https://squazz.dk/wp-content/uploads/2021/08/Blazor-760x413.png" medium="image" />
<post-id xmlns="com-wordpress:feed-additions:1">3896</post-id>	</item>
		<item>
		<title>Tips til at gøre WordPress hurtigere</title>
		<link>https://squazz.dk/teknologi/tips-til-at-goere-wordpress-hurtigere/</link>
					<comments>https://squazz.dk/teknologi/tips-til-at-goere-wordpress-hurtigere/#respond</comments>
		
		<dc:creator><![CDATA[Kasper Plougmann]]></dc:creator>
		<pubDate>Sun, 17 Mar 2019 15:17:52 +0000</pubDate>
				<category><![CDATA[Programmering]]></category>
		<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[PHP magic]]></category>
		<guid isPermaLink="false">http://squazz.dk/?p=1869</guid>

					<description><![CDATA[Jeg bøvlede selv meget med en langsom WordPress hjemmeside. Meget er blevet prøvet, så her er min opsamling på hvordan du kan gøre WordPress hurtigere. Det er først vigtigt at sige, at en af&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[ <p> Jeg bøvlede selv meget med en langsom WordPress hjemmeside. Meget er blevet prøvet, så her er min opsamling på hvordan du kan gøre WordPress hurtigere. </p> 
 <p> <span id="more-1869"></span> </p> 
 <p> Det er først vigtigt at sige, at en af de største syndere i forhold til en langsomt WordPress hjemmeside, er det brugte tema. Du kan gøre mange ting i forhold til optimering og forskellige plugins, men hvis dit tema generelt er langsomt og/eller er meget afhængigt af javascript for bare at vise de mest simple ting, er der desværre lang vej til en hurtig hjemmeside. Mit tema er ikke det hurtigste, og der er ting som kunne optimeres fra forfatterens side. Men dette skal ikke stoppe os i at gøre det så godt som vi nu engang kan. </p> 
 <p> Der findes mange muligheder for at tilkøbe sig optimering af ens hjemmeside. Især ved optimering og levering af billeder er der mange muligheder for at betale for en færdig løsning. Jeg har i det følgende gjort en dyd ud af kun at finde gratis løsninger. <br /> 
 <a class="deep-link" href="#de-vigtigste-plugins"> </p> 
<h2 id="de-vigtigste-plugins">De vigtigste plugins</h2>
 <p> </a> <br /> 
Med blot 2 plugins kan du komme UTROLIGT langt i forhold til at optimere din hjemmeside. Om ikke andet, så vil jeg på det kraftigste anbefale at du får installeret de to følgende plugins. </p> 
<h3><a href="https://wordpress.org/plugins/w3-total-cache/" target="_blank" rel="noopener external">W3 Total Cache</a></h3>
 <p> Den første her er W3 Total Cahce, det nok vigtigste plugin. Pluginnet kan en masse, men de vigtigste funktioner er for mig at se de følgende: </p> 
<h4><strong>Page Cache</strong></h4>
 <p> Denne funktion er den nok vigtigste funktion i dette plugin. Det forsøger at lave alle dine sider om til statiske sider. Dette betyder at i stedet for at skulle spørge databasen om hvilket indhold der skal vises, og derefter begynde at &#8220;tegne&#8221; den enkelte side, gemmes en forud genereret side på serveren. Når en bruger så skal se en side på din hjemmeside, hentes denne forud-genererede side frem. Markant bedre end at hjemmesiden skal på arbejde for at genere siden forfra. Dette plugin alene kan spare oceaner af tid for dine brugere, og ressourcer på din server. Mindre arbejde til serveren = hurtigere svartider, samt at serveren kan håndtere flere samtidige brugere. </p> 
 <p> <div id="attachment_1917" style="width: 815px" class="wp-caption alignnone"><a href="https://squazz.dk/wp-content/uploads/2019/03/W3-Total-Cache-page-cache.png?x62182"><img fetchpriority="high" decoding="async" aria-describedby="caption-attachment-1917" class="wp-image-1917 size-full" src="https://squazz.dk/wp-content/uploads/2019/03/W3-Total-Cache-page-cache.png?x62182" alt="W3 Total Cache - page cache" width="805" height="303" srcset="https://squazz.dk/wp-content/uploads/2019/03/W3-Total-Cache-page-cache.png 805w, https://squazz.dk/wp-content/uploads/2019/03/W3-Total-Cache-page-cache-300x113.png 300w, https://squazz.dk/wp-content/uploads/2019/03/W3-Total-Cache-page-cache-760x286.png 760w, https://squazz.dk/wp-content/uploads/2019/03/W3-Total-Cache-page-cache-768x289.png 768w, https://squazz.dk/wp-content/uploads/2019/03/W3-Total-Cache-page-cache-600x226.png 600w" sizes="(max-width: 805px) 100vw, 805px" /></a><p id="caption-attachment-1917" class="wp-caption-text">W3 Total Cache &#8211; page cache </p> </div> </p> 
<h4><strong>Browser Cache</strong></h4>
 <p> Browser cache sørger for at din hjemmesides ressourcer gemmes lokalt i den enkelte brugers browser. Dette sikrer at dine brugere henter så lidt data fra serveren som muligt, og i stedet hele tiden tjekker browserens cahce for om data allerede er hentet og ligger lokalt. </p> 
 <p> <div id="attachment_1916" style="width: 680px" class="wp-caption alignnone"><a href="https://squazz.dk/wp-content/uploads/2019/03/W3-Total-Cache-browser-cache.png?x62182"><img decoding="async" aria-describedby="caption-attachment-1916" class="size-full wp-image-1916" src="https://squazz.dk/wp-content/uploads/2019/03/W3-Total-Cache-browser-cache.png?x62182" alt="W3 Total Cache - browser cache" width="670" height="226" srcset="https://squazz.dk/wp-content/uploads/2019/03/W3-Total-Cache-browser-cache.png 670w, https://squazz.dk/wp-content/uploads/2019/03/W3-Total-Cache-browser-cache-300x101.png 300w, https://squazz.dk/wp-content/uploads/2019/03/W3-Total-Cache-browser-cache-600x202.png 600w" sizes="(max-width: 670px) 100vw, 670px" /></a><p id="caption-attachment-1916" class="wp-caption-text">W3 Total Cache &#8211; browser cache </p> </div> </p> 
 <p> Der er mange andre ting man kan sætte op i W3 Total Cache, men disse to funktioner er de to jeg har fundet altid virker, og har en stor indvirkning på hjemmesiden. <a href="https://premium.wpmudev.org/blog/w3-total-cache-settings/" target="_blank" rel="noopener external">Et dybere dyk i alle de indstillinger der er for W3 Total Cache, kan findes hos premium.wpmudev.org</a>. Her går de virkeligt i dybden med de enkelte dele. </p> 
<h3><a href="https://wordpress.org/plugins/autoptimize/" target="_blank" rel="noopener external">Autoptimize</a></h3>
 <p> Hjemmesider er bygget op af en masse henvisninger. Hvert billede kræver fx. et ny forespørgsel til serveren. En stor del af ventetiden på hjemmesiderne, er de mange forespørgsler til serveren, men det er ikke kun de tunge billeder der er problemet her. Hvis din hjemmeside gør brug af flere forskellige stylesheets og javascript filer, skal disse hentes hver for sig. Det tager tid. Auoptimize hjælper på dette problem. Den gennemløber din hjemmesider og finder henholdsvis alle javascript filerne og alle stylesheet (CSS) filerne. Når disse er fundet, samler den alle javascript filerne i én fil, komprimerer denne fil (minimize), og udstiller denne. Det samme sker for CSS filerne. I stedet for en masse refernecer, er der kun kun 2 små tilbage. Dette hjælper også en del på hastigheden. </p> 
 <p> W3 Total Cache er i princippet i stand til at komprimere (minimize) javascript og stylesheets. Men jeg har personligt ikke gode erfaringer W3 Total Cache her, og Autoptimize lade til (for mig) at virker bedre og generelt gøre et bedre job. <br /> 
 <a class="deep-link" href="#optimering-af-billeder"> </p> 
<h2 id="optimering-af-billeder">Optimering af billeder</h2>
 <p> </a> <br /> 
Op imod <a href="https://youtu.be/SRdJ1mQiqTg?t=155" target="_blank" rel="noopener external">75% af de data</a> bliver leveret fra hjemmesider verden over er billeder. Det er en meget stor del af din hjemmeside, så kan vi optimere hvor hurtigt billederne bliver leveret til brugerne, kan vi drastisk optimere på hastigheden af vores hjemmesider. <br /> 
 <a class="deep-link" href="#goer-billederne-mindre"> </p> 
<h3 id="goer-billederne-mindre">Gør billederne mindre</h3>
 <p> </a> <br /> 
Det første step du kan gøre for at optimere leveringen af dine billeder, er at gøre dem mindre. Dette kan både gøres ved at ændre på størrelsen af billederne, så du ikke leverer et billede der er 1200px bredt hvis browseren bagefter gør billedet mindre så det kun fylder 600px. En halvering af bredden kan give dig et billede der kun fylder 25% af originalen. </p> 
 <p> Ud over at ændre på størrelsen af dine billeder kan du også ændre lidt på kvaliteten. Som det ses på billedet herunder kan der være mange KB data at hente ved blot at reducere størrelsen på et billede en smule. </p> 
 <p> <div id="attachment_3256" style="width: 1010px" class="wp-caption alignnone"><a href="https://squazz.dk/wp-content/uploads/2019/03/lossy-compression-ratios.jpg?x62182"><img decoding="async" aria-describedby="caption-attachment-3256" class="size-full wp-image-3256" src="https://squazz.dk/wp-content/uploads/2019/03/lossy-compression-ratios.jpg?x62182" alt="Lossy Compression Ratios" width="1000" height="287" srcset="https://squazz.dk/wp-content/uploads/2019/03/lossy-compression-ratios.jpg 1000w, https://squazz.dk/wp-content/uploads/2019/03/lossy-compression-ratios-300x86.jpg 300w, https://squazz.dk/wp-content/uploads/2019/03/lossy-compression-ratios-760x218.jpg 760w, https://squazz.dk/wp-content/uploads/2019/03/lossy-compression-ratios-768x220.jpg 768w, https://squazz.dk/wp-content/uploads/2019/03/lossy-compression-ratios-600x172.jpg 600w" sizes="(max-width: 1000px) 100vw, 1000px" /></a><p id="caption-attachment-3256" class="wp-caption-text">Lossy Compression Ratios </p> </div> </p> 
 <p> Til at gøre mine billeder mindre bruger jeg <a href="https://da.wordpress.org/plugins/ewww-image-optimizer/" target="_blank" rel="noopener external">EWWW Image Optimizer</a>. Det er dejligt fleksibelt, relativt overskueligt, og har meget funktionalitet med sig. Dertil er deres Pixel Perfect komprimering virkeligt god til at fjerne data fra billederne uden at man rigtigt kan se det på det endelige resultat. <br /> 
 <a class="deep-link" href="#konverter-billederne"> </p> 
<h3 id="konverter-billederne">Konverter billederne</h3>
 <p> </a> <br /> 
Nogle gange kan du også få en del ud af at skifte billedformat. Fx kunne du konvertere dine JPG/JPEG billeder over til PNG formatet. Dette giver rigtigt god mening hvis der er tale om fotografier eller lignende, men har du tekst på dine billeder vil jeg klart anbefale dig at holde dig til PNG. </p> 
 <p> Til dette plugin bruger jeg <a href="https://da.wordpress.org/plugins/png-to-jpg/" target="_blank" rel="noopener external">PNG to JPG</a>. Jeg konverterer billederne enkeltvist, da det som tidligere nævnt ikke er i alle tilfælde du ville ønske at bruge JPG billeder. </p> 
 <p> <a href="https://images.guide/#what-is-webp" target="_blank" rel="noopener external">WebP</a> er et billedformat der er meget på vej frem, og har været det <a href="https://en.wikipedia.org/wiki/WebP" target="_blank" rel="noopener external">siden 2010</a>. WebP billeder har vist sig at være i gennemsnit <a href="https://developers.google.com/speed/webp/docs/webp_study" target="_blank" rel="noopener external">25-35%</a> mindre end JPG billeder, personligt har jeg set besparelser op imod 70% af den oprindelige billedstørrelse, uden at jeg har kunnet se forskel på de to billeder. </p> 
 <p> Når det omhandler generering af webp billeder, er <a href="https://da.wordpress.org/plugins/ewww-image-optimizer/" target="_blank" rel="noopener external">EWWW Image Optimizer</a> det bedste plugin jeg har fundet indtil videre. <br /> 
 <a class="deep-link" href="#brug-af-webp-i-praksis"> </p> 
<h4 id="brug-af-webp-i-praksis">Brug af WebP i praksis.</h4>
 <p> </a> <br /> 
Desværre kan du ikke bare konvertere alle dine billeder over til WebP. Det er nemlig ikke alle browsers, der i skrivende stund (marts 2020) understøtter WebP. Apple enheder (og det døde Internet Explorer) understøtter endnu ikke WebP. </p> 
 <p> Herunder kan du se de browsers som i øjeblikket understøtter WebP<a href="https://caniuse.com/#feat=webp"><picture><img decoding="async" src="https://caniuse.bitsofco.de/image/webp.png" alt="Data on support for the webp feature across the major browsers from caniuse.com" /></picture> </a> <br /> 
 <a class="deep-link" href="#caching-webp"> </p> 
<h5 id="caching-webp">Caching &amp; WebP</h5>
 <p> </a> <br /> 
EWWW har indbygget en funktionalitet til at kunne levere det rigtige til de enkelte browsers. Desværre er denne funktionalitet baseret på at EWWW læser hvilken browser du besøger hjemmesiden med, og så leverer det billede du kan bruge. Dette virker dog ikke sammen med cache løsninger så som CloudFlare. Ikke med mindre at man betaler sig til funktionaliteten hos CloudFlare. Alternativt stiller EWWW  noget javascript til rådighed som kan håndtere det. Men dette tilføjer blot mere data som skal indlæses af vores klienter, hvilket heller ikke er ønskværdigt. </p> 
 <p> Derfor bruger jeg <a href="https://da.wordpress.org/plugins/webp-express/" target="_blank" rel="noopener external">WebP Express</a> til at generere den nødvendige HTML så både Apple enheder og alle andre enheder får leveret et billede når de besøger min hjemmeside. WebP tilbyder nemlig muligheden for at kunne omskrive HTML&#8217;en så der i stedet for bare at være et &lt;img&gt; tag på hjemmesiden, nu kommer et &lt;picture&gt; tag som indeholder både WebP og JPG eller PNG billeder. Det tillader at HTML&#8217;en kan caches af CloudFlare, og lægger ansvaret over til browseren om at downloade det billede den kan forstå. </p> 
 <p> Det skal dog siges at EWWW har givet udtryk for at de arbejder på en lignende funktionalitet, og det kan ske vi derfor engang i fremtiden kan undvære WebP Express. <br /> 
 <a class="deep-link" href="#webp-express-indstillinger"> </p> 
<h5 id="webp-express-indstillinger">WebP Express indstillinger</h5>
 <p> </a> <br /> 
Du kan se de indstilligner jeg har valgt til WebP Express her: </p> 
 <p> <div id="attachment_3249" style="width: 806px" class="wp-caption alignnone"><a href="https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-CDN-Friendly.png?x62182"><img decoding="async" aria-describedby="caption-attachment-3249" class="size-full wp-image-3249" src="https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-CDN-Friendly.png?x62182" alt="WebP Express - CDN Friendly" width="796" height="189" srcset="https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-CDN-Friendly.png 796w, https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-CDN-Friendly-300x71.png 300w, https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-CDN-Friendly-760x180.png 760w, https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-CDN-Friendly-768x182.png 768w, https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-CDN-Friendly-600x142.png 600w" sizes="(max-width: 796px) 100vw, 796px" /></a><p id="caption-attachment-3249" class="wp-caption-text">WebP Express &#8211; CDN Friendly </p> </div> </p> 
 <p> <div id="attachment_3252" style="width: 584px" class="wp-caption alignnone"><a href="https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Generelle-Indstillinger.png?x62182"><img decoding="async" aria-describedby="caption-attachment-3252" class="size-full wp-image-3252" src="https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Generelle-Indstillinger.png?x62182" alt="WebP Express - Generelle Indstillinger" width="574" height="273" srcset="https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Generelle-Indstillinger.png 574w, https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Generelle-Indstillinger-300x143.png 300w" sizes="(max-width: 574px) 100vw, 574px" /></a><p id="caption-attachment-3252" class="wp-caption-text">WebP Express &#8211; Generelle Indstillinger </p> </div> </p> 
 <p> <div id="attachment_3251" style="width: 498px" class="wp-caption alignnone"><a href="https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Ingen-Live-Conversion.png?x62182"><img decoding="async" aria-describedby="caption-attachment-3251" class="size-full wp-image-3251" src="https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Ingen-Live-Conversion.png?x62182" alt="WebP Express - Ingen Live Conversion" width="488" height="141" srcset="https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Ingen-Live-Conversion.png 488w, https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Ingen-Live-Conversion-300x87.png 300w" sizes="(max-width: 488px) 100vw, 488px" /></a><p id="caption-attachment-3251" class="wp-caption-text">WebP Express &#8211; Ingen Live Conversion </p> </div> </p> 
 <p> <div id="attachment_3250" style="width: 807px" class="wp-caption alignnone"><a href="https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Rediger-HTML.png?x62182"><img decoding="async" aria-describedby="caption-attachment-3250" class="size-full wp-image-3250" src="https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Rediger-HTML.png?x62182" alt="WebP Express - Rediger HTML" width="797" height="586" srcset="https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Rediger-HTML.png 797w, https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Rediger-HTML-300x221.png 300w, https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Rediger-HTML-760x559.png 760w, https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Rediger-HTML-768x565.png 768w, https://squazz.dk/wp-content/uploads/2019/03/WebP-Express-Rediger-HTML-600x441.png 600w" sizes="(max-width: 797px) 100vw, 797px" /></a><p id="caption-attachment-3250" class="wp-caption-text">WebP Express &#8211; Rediger HTML </p> </div> </p> 
 <p> Vær opmærksom på at jeg har valgt ikke at refererer WebP billeder som ikke er genereret. Meningen med denne funktion er at man kan slå den til, sammen med live conversion, og så få genereret de WebP billeder man har brug for. Desværre har jeg oplevet at konverteringen nogle gange kan tage MEGET lang tid, og endda nogle gange gå helt i stå. Det ønsker jeg ikke at mine brugere skal opleve, så derfor konverterer jeg billederne på forhånd. <br /> 
Dertil er det ikke altid fordelagtigt at konvertere til WebP, nogle gange bliver billederne større end hvis man leverede dem i JPG. Derfor sparer vi også noget data for brugerne ved kun at konvertere og vise de WebP billeder som rent faktisk er mindre end hvis vi havde leveret dem et JPG billede. </p> 
 <p> På denne måde kan vi levere de mindre WebP billeder til de browsers der understøtter det, og have en fallback til &#8220;normale&#8221; billeder til de browsers der ikke understøtter det nye format. <br /> 
 <a class="deep-link" href="#laes-mere"> </p> 
<h3 id="laes-mere">Læs mere</h3>
 <p> </a> <br /> 
Hvis du vi dykke dybt i optimering af billeder på hjemmesider, og især dykke ned i den tekniske del, kan jeg klart anbefale e-bogen &#8220;<a href="https://images.guide/" target="_blank" rel="noopener external">Essential Image Optimization</a>&#8221; af <a href="https://addyosmani.com/" target="_blank" rel="noopener external">Addy Osmani</a>. Det er en &#8220;lang&#8221; artikel, men den kan klart anbefales hvis du vil vide mere dybdegående information om emnet. <br /> 
 <a class="deep-link" href="#generel-optimering"> </p> 
<h2 id="generel-optimering">Generel optimering</h2>
 <p> </a> <br /> 
 <a class="deep-link" href="#lazy-loading"> </p> 
<h3 id="lazy-loading">Lazy loading</h3>
 <p> </a> <br /> 
Lazy loading er et udtryk for at alle elementer på hjemmesiden ikke hentes på én gang, men derimod først når de rent faktisk skal bruges. </p> 
 <p> I dag bruger jeg <a href="https://da.wordpress.org/plugins/lazy-loading-responsive-images/" target="_blank" rel="noopener external">Lazy Loader</a> til at klare denne opgave. Tidligere brugte jeg <a href="https://wordpress.org/plugins/bj-lazy-load/" target="_blank" rel="noopener external">BJ Lazy Load</a>, som også er et rigtigt fint letvægts plugin. Desværre virker BJ Lazy Load dog ikke for AMP, og den kan heller ikke håndtere &lt;picture&gt; &amp; det dertilhørende &lt;source&gt; tag, hvilket betyder at indlæsningen af webp billeder ikke kan gøres med Lazy Load. </p> 
 <p> Hvis dit site skal være <span class="removed_link" title="https://ampready.com/">AMP ready</span>, kan du ikke bruge BJ Lazy Load. Til gengæld kan du bruge det lazy load der følger med Jetpack, hvilket er hvad jeg er skiftet over til de steder hvor AMP er vigtigt. <br /> 
 <a class="deep-link" href="#progessiv-web-app-pwa"> </p> 
<h3 id="progessiv-web-app-pwa">Progessiv Web App &#8211; PWA</h3>
 <p> </a> <br /> 
<a href="https://squazz.dk/wp-content/uploads/2019/03/Super-Progressive-Web-Apps-Banner.png?x62182"><img decoding="async" class="alignnone wp-image-1919 size-full" src="https://squazz.dk/wp-content/uploads/2019/03/Super-Progressive-Web-Apps-Banner.png?x62182" alt="Super Progressive Web Apps Banner" width="772" height="250" srcset="https://squazz.dk/wp-content/uploads/2019/03/Super-Progressive-Web-Apps-Banner.png 772w, https://squazz.dk/wp-content/uploads/2019/03/Super-Progressive-Web-Apps-Banner-300x97.png 300w, https://squazz.dk/wp-content/uploads/2019/03/Super-Progressive-Web-Apps-Banner-760x246.png 760w, https://squazz.dk/wp-content/uploads/2019/03/Super-Progressive-Web-Apps-Banner-768x249.png 768w, https://squazz.dk/wp-content/uploads/2019/03/Super-Progressive-Web-Apps-Banner-600x194.png 600w" sizes="(max-width: 772px) 100vw, 772px" /></a> </p> 
 <p> Et andet plugin jeg har fundet, som jeg synes er en skam flere ikke kender til, er <a href="https://wordpress.org/plugins/super-progressive-web-apps/" target="_blank" rel="noopener external">Super Progressive Web Apps</a>. Min erfaring er dette plugin hjælper med at cache de besøgte sider på den enkelte bruger telefon. Sidder brugeren og navigerer rundt, og kommer forbi de samme sider igen, er disse sider allerede gemt lokalt på telefonen. Dét er en stor fordel, og giver en utroligt god brugeroplevelse. Pluginnet kan også komme op med en notifikation om at man kan tilføje hjemmesiden som et bogmærke på startskærmen. Gøres dette bliver der oprettet en Progressiv Web App (PWA), som er endnu bedre til at cache indholdet på telefonen. <br /> 
Hvis du har en hjemmeside som ofte besøges af de samme brugere igen og igen, og især hvis disse brugere bruger de samme sider igen og igen, er dette plugin et must have i min bog. </p> 
<h3><a href="https://wordpress.org/plugins/jetpack/" target="_blank" rel="noopener external">Jetpack</a></h3>
 <p> <a href="https://squazz.dk/wp-content/uploads/2019/03/Wordpress-Jetpack.png?x62182"><img decoding="async" class="alignnone wp-image-1920 size-full" src="https://squazz.dk/wp-content/uploads/2019/03/Wordpress-Jetpack.png?x62182" alt="Wordpress Jetpack" width="788" height="295" srcset="https://squazz.dk/wp-content/uploads/2019/03/Wordpress-Jetpack.png 788w, https://squazz.dk/wp-content/uploads/2019/03/Wordpress-Jetpack-300x112.png 300w, https://squazz.dk/wp-content/uploads/2019/03/Wordpress-Jetpack-760x285.png 760w, https://squazz.dk/wp-content/uploads/2019/03/Wordpress-Jetpack-768x288.png 768w, https://squazz.dk/wp-content/uploads/2019/03/Wordpress-Jetpack-600x225.png 600w" sizes="(max-width: 788px) 100vw, 788px" /></a> </p> 
 <p> <span style="text-decoration: line-through;">Jetpack er et stort plugin. Det kan UTROLIGT meget!</span> </p> 
 <p> <span style="text-decoration: line-through;">I forhold til at gøre WordPress hurtigere, er der dog kun en enkelt funktionalitet jeg bruger;  <a href="https://jetpack.com/support/site-accelerator/" target="_blank" rel="noopener external">Site accelerator</a>. Site accelerator består af to komponenter, et der håndterer billeder, og et der håndterer de statiske filer så som javascript &amp; CSS som hyppigst bruges i WordPress regi.</span> </p> 
 <p> <span style="text-decoration: line-through;">Det at Jetpack tilbyder at hente alle dine billeder over til dem, og sørge for at de bliver leveret så hurtigt som muligt til brugeren, betyder at din hjemmesides server ikke skal stå for at finde og sende billederne til brugerne. Min erfaring er at dette gør en kæmpe forskel.</span> </p> 
 <p> Jeg bruger ikke længere Jetpack til dette, da det viste sig at et korrekt konfigureret Cloudflare løste disse problematikker markant bedre end Jetpack, samtidig med at det resulterede i mindre Javascript til frontenden / brugere + potentielt bedre SEO da billede-URLs nu er fra mit eget domæne og ikke fra Jetpacks domæne. </p> 
<h3><a href="https://wordpress.org/plugins/redirection/" target="_blank" rel="noopener external">Redirection</a> &amp; håndtering af 404 fejl</h3>
 <p> Noget der også kan gøre WordPress langsomt, er hvis dine brugere bliver videresendt / redirected fra side til side. Der kan være mange grunde til at dette sker, både tilsigtede og utilsigtede. Endvidere kan brugerne forsøge at tilgå ressourcer som ikke findes, sker dette vil de blive mødt af en 404 fejl. Dette kan være en viderestilling som ikke virker, og det kan være billeder som af den ene eller anden grund, ikke længere findes på hjemmesiden. </p> 
 <p> Et plugin jeg er blevet rigtigt glad for når jeg skal lede efter og håndtere disse fejl, er pluginnet <a href="https://wordpress.org/plugins/redirection/" target="_blank" rel="noopener external">Redirection</a>. Herunder ser du et eksempel på et billede som jeg stadig linker til et sted, men som ikke længere findes i min uploads mappe på serveren. </p> 
 <p> <div id="attachment_1915" style="width: 582px" class="wp-caption alignnone"><a href="https://squazz.dk/wp-content/uploads/2019/03/Redirects-404s.png?x62182"><img decoding="async" aria-describedby="caption-attachment-1915" class="size-full wp-image-1915" src="https://squazz.dk/wp-content/uploads/2019/03/Redirects-404s.png?x62182" alt="Redirects - 404s" width="572" height="237" srcset="https://squazz.dk/wp-content/uploads/2019/03/Redirects-404s.png 572w, https://squazz.dk/wp-content/uploads/2019/03/Redirects-404s-300x124.png 300w" sizes="(max-width: 572px) 100vw, 572px" /></a><p id="caption-attachment-1915" class="wp-caption-text">Redirects &#8211; 404s </p> </div> </p> 
 <p> Håndtering af disse redirects kan hjælpe med at gøre WordPress hurtigere, da browseren så ikke skal håndtere og vente på ressourcer som ikke findes. </p> 
<h2>Offsite cache &#8211; <a href="https://www.cloudflare.com/" target="_blank" rel="noopener external">Cloudflare</a></h2>
 <p> Du har fået lavet en lokal cache på din server med W3, dine scripts og stylesheets er komprimeret og er samlet i én fil for hver type. Dine billeder har fået lazy load. Generelt har du gjort hvad du umiddelbart tænker du kan for at optimere din hjemmeside. </p> 
 <p> Men vent! Der er mere du kan gøre for at gøre WordPress hurtigere. Men nu begynder vi at bevæge os ind på den mere tekniske del af optimeringerne. </p> 
 <p> Når brugerne besøger din hjemmeside, er det dit webhotel som skal levere disse data. I langt de fleste tilfælde, er denne server langsom, fordi du (ligesom mig) har sparet på serveren til din hjemmeside. Derfor kunne det da være lækkert hvis vi kunne få en super hurtig webserver til at agere cache for vores hjemmeside. Og netop dette kan Cloudflare hjælpe os med. <a href="https://thehackernews.com/2018/04/fastest-dns-service.html" target="_blank" rel="noopener external">De er blandt andet kendt for at have verdens hurtigste DNS</a>. </p> 
 <p> At få sat Cloudflare op som caching server er desværre så nemt som bare at downloade et plugin og trykke &#8220;aktiver&#8221;, her skal der lidt mere til da det er et mere teknisk setup. Vi skal nemlig have fortal dine besøgendes browser at den ikke skal lede efter din hjemmeside på din webserver, men i stedet skal lede efter den hos Cloudflare. <br /> 
 <a class="deep-link" href="#hvor-stor-er-effekten-saa-af-cloudflare"> </p> 
<h3 id="hvor-stor-er-effekten-saa-af-cloudflare">Hvor stor er effekten så af Cloudflare?</h3>
 <p> </a> <br /> 
Heldigvis har <a href="https://support.cloudflare.com/hc/en-us/articles/227634427-Using-Cloudflare-with-WordPress" target="_blank" rel="noopener external">Cloudflare selv lavet en guide til hvordan du får sat Cloudflare op for din hjemmeside</a>, så jeg vil lade dem forklare den tekniske del, og i stedet vil jeg vise jer nogle før og efter billeder for min hjemmesides forside. </p> 
 <p> <div id="attachment_1903" style="width: 865px" class="wp-caption alignnone"><a href="https://squazz.dk/wp-content/uploads/2019/03/Før-Cloudflare.png?x62182"><img decoding="async" aria-describedby="caption-attachment-1903" class="size-full wp-image-1903" src="https://squazz.dk/wp-content/uploads/2019/03/Før-Cloudflare.png?x62182" alt="Før Cloudflare" width="855" height="378" srcset="https://squazz.dk/wp-content/uploads/2019/03/Før-Cloudflare.png 855w, https://squazz.dk/wp-content/uploads/2019/03/Før-Cloudflare-300x133.png 300w, https://squazz.dk/wp-content/uploads/2019/03/Før-Cloudflare-760x336.png 760w, https://squazz.dk/wp-content/uploads/2019/03/Før-Cloudflare-768x340.png 768w, https://squazz.dk/wp-content/uploads/2019/03/Før-Cloudflare-600x265.png 600w" sizes="(max-width: 855px) 100vw, 855px" /></a><p id="caption-attachment-1903" class="wp-caption-text">Mobil &#8211; før Cloudflare </p> </div> </p> 
 <p> Læg især mærke til billederne under tallene. Her er det tydeligt at vi nu allerede fra starten har menuen, topbaren &amp; overskriften af artiklen klar. Vi får også ret hurtigt vist et billede og den vigtigste tekst så brugeren kan komme igang med at læse indholdet. </p> 
 <p> <div id="attachment_1902" style="width: 846px" class="wp-caption alignnone"><a href="https://squazz.dk/wp-content/uploads/2019/03/Efter-Cloudflare.png?x62182"><img decoding="async" aria-describedby="caption-attachment-1902" class="wp-image-1902 size-full" src="https://squazz.dk/wp-content/uploads/2019/03/Efter-Cloudflare.png?x62182" alt="Efter Cloudflare" width="836" height="370" srcset="https://squazz.dk/wp-content/uploads/2019/03/Efter-Cloudflare.png 836w, https://squazz.dk/wp-content/uploads/2019/03/Efter-Cloudflare-300x133.png 300w, https://squazz.dk/wp-content/uploads/2019/03/Efter-Cloudflare-760x336.png 760w, https://squazz.dk/wp-content/uploads/2019/03/Efter-Cloudflare-768x340.png 768w, https://squazz.dk/wp-content/uploads/2019/03/Efter-Cloudflare-600x266.png 600w" sizes="(max-width: 836px) 100vw, 836px" /></a><p id="caption-attachment-1902" class="wp-caption-text">Mobil &#8211; Efter Cloudflare </p> </div> </p> 
 <p> På stationære &amp; bærbare computere er resultatet et helt andet. Her er der snart ikke meget at komme efter længere. </p> 
 <p> <div id="attachment_1904" style="width: 865px" class="wp-caption alignnone"><a href="https://squazz.dk/wp-content/uploads/2019/03/Desktop-efter-CloudFlare.png?x62182"><img decoding="async" aria-describedby="caption-attachment-1904" class="size-full wp-image-1904" src="https://squazz.dk/wp-content/uploads/2019/03/Desktop-efter-CloudFlare.png?x62182" alt="Desktop efter CloudFlare" width="855" height="327" srcset="https://squazz.dk/wp-content/uploads/2019/03/Desktop-efter-CloudFlare.png 855w, https://squazz.dk/wp-content/uploads/2019/03/Desktop-efter-CloudFlare-300x115.png 300w, https://squazz.dk/wp-content/uploads/2019/03/Desktop-efter-CloudFlare-760x291.png 760w, https://squazz.dk/wp-content/uploads/2019/03/Desktop-efter-CloudFlare-768x294.png 768w, https://squazz.dk/wp-content/uploads/2019/03/Desktop-efter-CloudFlare-600x229.png 600w" sizes="(max-width: 855px) 100vw, 855px" /></a><p id="caption-attachment-1904" class="wp-caption-text">Desktop / bærbar efter CloudFlare </p> </div> </p> 
 <p> Såfremt du ønsker at bruge Cloudflare kan det varmt anbefales at bruge<a href="https://wordpress.org/plugins/cloudflare/" target="_blank" rel="noopener external"> Cloudflare pluginnet</a>. Det kan sørge for at din off-location cache bliver purged hver gang du laver ændringer til dit layout. Dertil den har en fin handy knap til at sætte de mest normale indstillinger op for Cloudflare når man bruger WordPress. <br /> 
 <a class="deep-link" href="#pagerules"> </p> 
<h3 id="pagerules">Pagerules</h3>
 <p> </a> <br /> 
Jeg kan på det varmeste anbefale at du får lavet de følgende &#8220;Page Rules&#8221; i Cloudflare. Formålet med disse regler er følgende: </p> 
<ol>
<li>Undgå al caching på dine preview sider. Dette er de sider du får vist når du bruger forhåndsvisningen for dine indlæg.</li>
<li>Fjernelse af hård cache (cache everything) på wp-admin delen af WordPress, men samtidig bibeholde caching af det <a href="https://developers.cloudflare.com/cache/about/default-cache-behavior">statiske indhold</a> du har i wp-content (fx dine billeder)</li>
<li>&#8220;<a href="https://developers.cloudflare.com/cache/about/default-cache-behavior">Cache everything</a>&#8221; = hård cache / &#8220;fang alt&#8221; for resten af dit site. Alting bliver gemt her, også dynamisk indhold, hvilket også inkluderer søgeresultater på din side, widgets i din sidebar, og kommentarer. Dette er en ret stor hammer, og synes du den rammer for hårdt kan du med fordel ændre &#8220;Cache Everything&#8221; til &#8220;Standard&#8221;.</li>
</ol>
 <p> <div id="attachment_3463" style="width: 770px" class="wp-caption alignnone"><a href="https://squazz.dk/wp-content/uploads/2019/03/Cloudflare-PageRules.png?x62182"><img decoding="async" aria-describedby="caption-attachment-3463" class="size-large wp-image-3463" src="https://squazz.dk/wp-content/uploads/2019/03/Cloudflare-PageRules-760x200.png?x62182" alt="Cloudflare PageRules" width="760" height="200" srcset="https://squazz.dk/wp-content/uploads/2019/03/Cloudflare-PageRules-760x200.png 760w, https://squazz.dk/wp-content/uploads/2019/03/Cloudflare-PageRules-300x79.png 300w, https://squazz.dk/wp-content/uploads/2019/03/Cloudflare-PageRules-768x202.png 768w, https://squazz.dk/wp-content/uploads/2019/03/Cloudflare-PageRules-600x158.png 600w, https://squazz.dk/wp-content/uploads/2019/03/Cloudflare-PageRules.png 1045w" sizes="(max-width: 760px) 100vw, 760px" /></a><p id="caption-attachment-3463" class="wp-caption-text">Cloudflare PageRules </p> </div> <br /> 
 <a class="deep-link" href="#ekstra-mine-egne-funktioner"> </p> 
<h2 id="ekstra-mine-egne-funktioner">Ekstra: Mine egne funktioner</h2>
 <p> </a> <br /> 
Her rammer vi den tekniske del. Følgende vil kræve at du kan håndtere at navigere rundt på en FTP server, og at du ved hvordan du håndterer at tilføje nye PHP funktioner til dit site. <br /> 
 <a class="deep-link" href="#justeringer-af-billedkvalitet"> </p> 
<h3 id="justeringer-af-billedkvalitet">Justeringer af billedkvalitet</h3>
 <p> </a> <br /> 
Til EWWW har jeg tilføjet disse to overrides i <a href="https://www.wpbeginner.com/glossary/wp-config-php" target="_blank" rel="noopener external">wp-config.php</a>. Disse to overrides sørger for at mine originale uploads holdes så originale som muligt. Derfor beholder jeg metadata / <a href="https://en.wikipedia.org/wiki/Exif" target="_blank" rel="noopener external">EXIF</a> data på disse billeder, samt skipper billederne hvis der køres en lozzy optimering af billederne. </p> 
<div>
<pre>define( 'EWWW_IMAGE_OPTIMIZER_METADATA_SKIP_FULL', true );
define( 'EWWW_IMAGE_OPTIMIZER_LOSSY_SKIP_FULL', true );
</pre>
 <p> Da jeg bruger EWWW til at optimere størrelsen på mine billeder, har jeg valgt at sætte WordPress&#8217; komprimerings kvalitet på et højt niveau. Dette gøres ved at tilføje nedenstående linjer til <a href="https://codex.wordpress.org/Functions_File_Explained" target="_blank" rel="noopener external">functions.php</a>. WordPress bruger som standard en kvalitet op 82, og det synes jeg personligt er synligt på de færdige billeder. </p> 
<div>
<pre>// Lock Image Quality
add_filter( 'jpeg_quality', function($arg){return 90;} );
add_filter( 'wp_editor_set_quality', function($arg){return 90;} );</pre>
</div>
 <p>  <a class="deep-link" href="#for-store-billeder-paa-relaterede-opslag"> </p> 
<h3 id="for-store-billeder-paa-relaterede-opslag">For store billeder på relaterede opslag</h3>
 <p> </a> <br /> 
Hvis du bruger Jetpack og dennes &#8220;relaterede opslag&#8221; funktion, kan billederne godt være lidt for store i forhold til hvordan de vises på din hjemmeside, det var de i mit tilfælde. Jeg har lavet følgende script som kan bruges til at justere dette. Hvis du ved præcis hvor høje og brede du ønsker billederne, brug da med fordel nedenstående til at justere disse billeder til. Så hentes der ikke for store billeder ned til dine brugere. </p> 
<div>
<pre>// change thumbnail size
function jetpackchange_image_size ( $thumbnail_size ) {
    $thumbnail_size['width'] = 240;
    $thumbnail_size['height'] = 137;
    return $thumbnail_size;
}
add_filter( 'jetpack_relatedposts_filter_thumbnail_size', 'jetpackchange_image_size' );</pre>
</div>
 <p>  <a class="deep-link" href="#brug-den-seneste-version-af-jquery"> </p> 
<h3 id="brug-den-seneste-version-af-jquery">Brug den seneste version af jQuery</h3>
 <p> </a> <br /> 
Rigtigt mange funktioner og plugins i WordPress bruger jQuery. WordPress kommer med jQuery forudinstalleret, men den version WordPress tilbyder er version 1.12.4. <a href="https://www.measurethat.net/Benchmarks/Show/2838/0/jquery-version-speed-test" target="_blank" rel="noopener external">Denne version er langsommere end den nyeste version 3.4.1</a>, <a href="https://snyk.io/test/npm/jquery/1.12.4" target="_blank" rel="noopener external">og så er den også kendt for at indeholde sikkerhedshuller</a>. <a href="https://snyk.io/test/npm/jquery/3.4.1" target="_blank" rel="noopener external">JQuery version 3.4.1 har i øjeblikket ikke kendte sikkerhedshuller</a>. </p> 
 <p> Vær dog opmærksom på at det ikke er alle temaer &amp; plugins der fungerer med den seneste version af jQuery. De er alle skrevet med tanke på at WordPress som standard leverer version 1.12.4, så hvis de bruger funktionalitet specifik til denne version, vil din hjemmeside ikke fungere bagefter. Test scriptet andensteds først om muligt. </p> 
<pre>/* Replace the default WordPress jQuery script */
function squazz_modify_jquery() {
    wp_deregister_script('jquery');
    if(wp_is_mobile()) {
        wp_enqueue_script('jquery', 'https://code.jquery.com/jquery-3.4.1.min.js', array(), null, true);
    } else {
        wp_enqueue_script('jquery', 'https://code.jquery.com/jquery-3.4.1.min.js', array(), null, true);         
    }
}
add_action('wp_enqueue_scripts', 'squazz_modify_jquery');</pre>
 <p>  <a class="deep-link" href="#udskyd-indlaesning-af-javascript"> </p> 
<h3 id="udskyd-indlaesning-af-javascript">Udskyd indlæsning af javascript</h3>
 <p> </a> <br /> 
<a href="https://developers.google.com/speed/pagespeed/insights/" target="_blank" rel="noopener external">Google PageSpeed</a> (Og <a href="https://developers.google.com/web/tools/lighthouse/" target="_blank" rel="noopener external">Google Lighthouse</a>) er ikke glade for at man indlæser javascript inden man skal bruge det. Og det er dine brugere heller ikke. Jo senere du indlæser tunge filer som jQuery, jo bedre. </p> 
 <p> Derfor har jeg ledt efter en måde hvorpå jeg kunne sikre mig at jQuery blev indlæst så sent som muligt. Nogle gange kan jeg nøjes med en defer (de fleste gange), men andre gange er man nødt til at indlæse data async så det kommer på siden lidt hurtigere. <a href="https://stackoverflow.com/questions/44827134/wordpress-script-with-integrity-and-crossorigin" target="_blank" rel="noopener external">På stackoverflow fandt jeg en rigtig fin måde at udsætte loading af scripts</a>. Samtidig fandt jeg også en måde hvorpå jeg kunne tilføje <em>integrity</em> og <em>crossorigin</em> tags til mit jQuery script, hvilket sikrer mig mod XSS (Cross Site Scripting). </p> 
<pre>// https://stackoverflow.com/questions/44827134/wordpress-script-with-integrity-and-crossorigin
add_filter( 'script_loader_tag', 'add_attribs_to_scripts', 10, 3 );
function add_attribs_to_scripts( $tag, $handle, $src ) {
    // The handles of the enqueued scripts we want to defer
    $async_scripts = array(
        'jquery-migrate',
        'sharethis',
    );
    $defer_scripts = array( 
        'contact-form-7',
        'jquery-ui',
        'jquery-form',
        'wpdm-bootstrap',
        'frontjs',
        'jquery-choosen',
        'fancybox',
        'jquery-colorbox',  
        'search'
    );        
    $jquery = array(
        'jquery'
    );

    if ( in_array( $handle, $defer_scripts ) ) {
        return '&lt;script src="' . $src . '" defer="defer" type="text/javascript"&gt;&lt;/script&gt;' . "\n";
    }
    if ( in_array( $handle, $async_scripts ) ) {
        return '&lt;script src="' . $src . '" async="async" type="text/javascript"&gt;&lt;/script&gt;' . "\n";
    }
    if ( in_array( $handle, $jquery ) ) {
        return '&lt;script src="' . $src . '" defer integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous" type="text/javascript"&gt;&lt;/script&gt;' . "\n";
    }
    return $tag;
}</pre>
 <p>  <a class="deep-link" href="#kommentarer"> </p> 
<h2 id="kommentarer">Kommentarer?</h2>
 <p> </a> <br /> 
Hvad har du erfaringer med? Er der noget jeg har overset? Eller kender du et bedre alternativ til de plugins og løsninger jeg har valgt? <br /> 
Hold dig endelig ikke tilbage, og fortæl mig om det i kommentarsporet. </p> 
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://squazz.dk/teknologi/tips-til-at-goere-wordpress-hurtigere/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			<media:content url="https://squazz.dk/wp-content/uploads/2019/03/Stopur-i-haand-760x507.jpg" medium="image" />
<post-id xmlns="com-wordpress:feed-additions:1">1869</post-id>	</item>
		<item>
		<title>Det at hente en samling af strenge fra app.config</title>
		<link>https://squazz.dk/teknologi/det-at-hente-en-samling-af-strenge-fra-app-config/</link>
					<comments>https://squazz.dk/teknologi/det-at-hente-en-samling-af-strenge-fra-app-config/#respond</comments>
		
		<dc:creator><![CDATA[Kasper Plougmann]]></dc:creator>
		<pubDate>Thu, 19 Nov 2015 20:44:14 +0000</pubDate>
				<category><![CDATA[Programmering]]></category>
		<category><![CDATA[StackOverflow]]></category>
		<guid isPermaLink="false">http://squazz.dk/?p=1503</guid>

					<description><![CDATA[Det hænder til tider at man har brug for en samling af strenge, tal eller andet som man ønsker at definere i sin app.config. Dette er fx også tilfældet i dette StackOverflow post som inspirerede&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[ <p> Det hænder til tider at man har brug for en samling af strenge, tal eller andet som man ønsker at definere i sin app.config. Dette er fx også tilfældet i <a href="https://stackoverflow.com/questions/1779117/how-to-get-a-liststring-collection-of-values-from-app-config-in-wpf/33544322" target="_blank" rel="noopener external">dette StackOverflow post</a> som inspirerede mig til at <a href="https://stackoverflow.com/questions/1779117/how-to-get-a-liststring-collection-of-values-from-app-config-in-wpf#33544322" target="_blank" rel="noopener external">smide dette kodestykke live</a>. </p> 
 <p> <span id="more-1503"></span> </p> 
 <p> Mange af de løsninger jeg ser til at løse lignende problematikker, gør det ved at definere en semikolon (eller lignende) separeret liste på et enkelt key i app.config. Det er en fin løsning, og den kan bruges, men det er ikke en særligt pæn løsning. Den stiller også lidt flere krav til de steder hvor den definerede liste skal bruges. <br /> 
 <a class="deep-link" href="#min-loesning"> </p> 
<h2 id="min-loesning">Min løsning</h2>
 <p> </a> <br /> 
I dette tilfælde ønsker jeg at oprette en velkomst widget som har brug for at vide hvilke muligheder den har for at sige &#8220;hej&#8221; til brugeren. </p> 
 <p> <strong>Eksempel på den XML kode vi ender med at kunne indsætte i app.config</strong> </p> 
<pre class="lang-cs prettyprint prettyprinted">&lt;?xml version="1.0" encoding="utf-8" /&gt;
&lt;configuration&gt;
 &lt;widgets&gt;
  &lt;greetingWidget&gt;
   &lt;add greeting="Hej" /&gt;
   &lt;add greeting="Goddag" /&gt;
   &lt;add greeting="Hello" /&gt;
   ...
   &lt;add greeting="Konnichiwa" /&gt;
   &lt;add greeting="Namaskaar" /&gt;
  &lt;/greetingWidget&gt;
 &lt;/widgets&gt;
&lt;/configuration&gt;
</pre>
 <p> <strong>Først starter jeg med at oprette det egentlige greeting-element</strong> </p> 
 <p> Det er vigtigt at vi får nedarvet fra <a href="https://docs.microsoft.com/en-us/dotnet/api/system.configuration.configurationelement?redirectedfrom=MSDN&amp;view=netframework-4.7.2" target="_blank" rel="noopener external">ConfigurationElement</a> da vi bruger den programmatiske tilgang til at implementere vores <a href="https://docs.microsoft.com/en-us/dotnet/api/system.configuration.configurationelementcollection?redirectedfrom=MSDN&amp;view=netframework-4.7.2" target="_blank" rel="noopener external">ConfigurationElementCollection</a> senere. </p> 
<pre class="lang-cs prettyprint prettyprinted">public interface IGreeting
{
    string Greeting { get; set; }
}


public class GreetingElement : ConfigurationElement, IGreeting
{
    [ConfigurationProperty("greeting", IsRequired = true)]
    public string Greeting
    {
        get { return (string)this["greeting"]; }
        set { this["greeting"] = value; }
    }
}</pre>
 <p> <strong>Derefter opretter jeg min samling som skal håndtere de forskellige hilsner.</strong> </p> 
<pre class="lang-cs prettyprint prettyprinted">public class GreetingElementsCollection : System.Configuration.ConfigurationElementCollection
{
    public List&lt;IGreeting&gt; All { 
        get { return this.Cast&lt;IGreeting&gt;().ToList(); }
    }

    public GreetingElement this[int index]
    {
        get
        {
            return base.BaseGet(index) as GreetingElement;
        }
        set
        {
            if (base.BaseGet(index) != null)
            {
                base.BaseRemoveAt(index);
            }
            this.BaseAdd(index, value);
        }
    }

    protected override ConfigurationElement CreateNewElement()
    {
        return new GreetingElement();
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((GreetingElement)element).Greeting;
    }
}</pre>
 <p> <strong>Vi har også brug for en greetingWidget property så vores app.config forstår den nyoprettede samling</strong> </p> 
<pre class="lang-cs prettyprint prettyprinted">public class Widgets : System.Configuration.ConfigurationSection
{
    public static Widgets Widget =&gt; ConfigurationManager.GetSection("greetingWidget") as Widgets;

    [ConfigurationProperty("greetingWidget", IsRequired = true)]
    public GreetingElementsCollection GreetingWidget
    {
        get { return (GreetingElementsCollection)this["greetingWidget"]; }
        set { this["greetingWidget"] = value; }
    }
}</pre>
 <p> <strong>Når vi skal have fat i data fra vores config gør vi det således</strong> </p> 
<pre class="lang-cs prettyprint prettyprinted"><code><span class="typ">List</span><span class="pun">&lt;</span><span class="typ">GreetingElement</span><span class="pun">&gt;</span><span class="pln"> greetings </span><span class="pun">=</span> <span class="typ">Widgets</span><span class="pun">.</span><span class="typ">Widget</span><span class="pun">.</span><span class="typ">GreetingWidget</span><span class="pun">.</span><span class="typ">All</span><span class="pun">;</span></code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://squazz.dk/teknologi/det-at-hente-en-samling-af-strenge-fra-app-config/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1503</post-id>	</item>
		<item>
		<title>Redigering af labels i The Events Calendar</title>
		<link>https://squazz.dk/teknologi/redigering-af-labels-i-the-events-calendar/</link>
					<comments>https://squazz.dk/teknologi/redigering-af-labels-i-the-events-calendar/#respond</comments>
		
		<dc:creator><![CDATA[Kasper Plougmann]]></dc:creator>
		<pubDate>Wed, 17 Dec 2014 21:20:28 +0000</pubDate>
				<category><![CDATA[Programmering]]></category>
		<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[PHP magic]]></category>
		<guid isPermaLink="false">http://squazz.dk/?p=1295</guid>

					<description><![CDATA[Det hænder at man ønsker at ændre på standard udtrykkene i et plugin. Navngivningen i The Events Calendar fra fødslen passer sjældent til alle. Der er flere løsninger til problemet, men ikke ret mange&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[ <p> Det hænder at man ønsker at ændre på standard udtrykkene i et plugin. Navngivningen i The Events Calendar fra fødslen passer sjældent til alle. Der er flere løsninger til problemet, men ikke ret mange der er holdbare. </p> 
 <p> <span id="more-1295"></span> </p> 
 <p> <a title="The Events Calendar" href="https://wordpress.org/plugins/the-events-calendar/" target="_blank" rel="noopener external">The Events Calendar</a> er et lækkert plugin når man har en masse events man hurtigt vil have oprettet og fremstillet på en flot måde. Desværre løb jeg ind i at en klient ønskede at få ændret en label med værdien &#8220;Organizer&#8221; til at få værdien &#8220;Coordinator&#8221;. </p> 
 <p> Jeg kunne have valgt at redigere labels direkte i pluginnets kode. Men så ville jeg enten være låst til den nuværende version af pluginnet fremover, eller også ville jeg skulle huske at opdatere mine egne rettelser hver gang. Alternativt kunne jeg også have brugt et oversættelsesprogram som <a title="WPML.org" href="https://wpml.org/" target="_blank" rel="noopener external">WPML</a>, som ville kunne oversætte den enkelte streng. Men at hente et oversættelses plugin ned, bare for at ændre et par labels, virker som noget af et overkill. </p> 
 <p> I stedet endte jeg med at hægte mig på The Events Calendar&#8217;s filtre, og overskrive disse. I den nedenstående kode ændrer jeg først organizer labellen til at være Coordinator. Dernæst <a title="Obfuscate emails" href="https://squazz.dk/teknologi/obfuscate-emails/">obfuskerer jeg mailadressen</a> og gør den klikbar. </p> 
<pre>// Edit Organizer Label Singular &amp; Plural
add_filter('tribe_organizer_label_singular', 'tribe_organizer_label_singular_edit');
   function tribe_organizer_label_singular_edit() {
   return __( 'Coordinator', 'tribe-events-calendar' );
}
add_filter('tribe_organizer_label_plural', 'tribe_organizer_label_plural_edit');
   function tribe_organizer_label_plural_edit() {
   return __( 'Coordinators', 'tribe-events-calendar' );
}
// Make Organizer Label clickable
$mail = tribe_get_organizer_email();
add_filter('tribe_get_organizer_email', 'tribe_get_organizer_email_edit');
function tribe_get_organizer_email_edit($mail) {
   $output = mailto($mail);
   return $output;
}</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://squazz.dk/teknologi/redigering-af-labels-i-the-events-calendar/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			<media:content url="https://squazz.dk/wp-content/uploads/2014/12/the-events-calendar-logo-1.png" medium="image" />
<post-id xmlns="com-wordpress:feed-additions:1">1295</post-id>	</item>
		<item>
		<title>Rediger Ninja Forms Capabilities</title>
		<link>https://squazz.dk/teknologi/ninja-forms-capabilities/</link>
					<comments>https://squazz.dk/teknologi/ninja-forms-capabilities/#respond</comments>
		
		<dc:creator><![CDATA[Kasper Plougmann]]></dc:creator>
		<pubDate>Wed, 17 Dec 2014 20:38:50 +0000</pubDate>
				<category><![CDATA[Programmering]]></category>
		<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[PHP magic]]></category>
		<guid isPermaLink="false">http://squazz.dk/?p=1307</guid>

					<description><![CDATA[Ninja Forms er gratis, intuitivt og hurtigt. desværre, er det også ret låst angående hvilke WordPress roller der kan oprette og vedligeholde forms. Om det er grundet marketing så Ninja Forms kan få solgt&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[ <p> <a title="Ninja Forms" href="https://ninjaforms.com/" target="_blank" rel="noopener external">Ninja Forms</a> er gratis, intuitivt og hurtigt. desværre, er det også ret låst angående hvilke WordPress roller der kan oprette og vedligeholde forms. </p> 
 <p> <span id="more-1307"></span> </p> 
 <p> Om det er grundet marketing så Ninja Forms kan få solgt deres &#8220;<a title="Front-End Posting - Ninja Forms" href="https://ninjaforms.com/extensions/front-end-posting/" target="_blank" rel="noopener external">Front-End Posting</a>&#8221; plugin skal jeg ikke kunne sige (men jeg mistænker dem for det). Men som det ser ud i øjeblikket er det kun administratorer der har adgang til at oprette og redigere Ninja Forms i WordPress&#8217; backend. Et problem, da jeg ikke ønsker at alle mine brugere, som skal kunne oprette forms, skal være administratorer. </p> 
 <p> Da jeg ledte efter en måde hvorpå man kunne ændre hvilke brugere der havde adgang til hvad i deres plugin, fandt jeg ud af at det i skrivende stund kun er muligt ved at hægte sig på filtrene i WordPress. Så det måtte jeg jo gøre. </p> 
 <p> I mit tilfælde ønskede jeg at editors og admins kunne oprette og vedligeholde forms. Skal jeg ramme begge, skal jeg finde en egenskab som disse to roller har til fælles. &#8220;edit_others_posts&#8221; er en sådan egenskab som kun Editors og Admins deler. Det er derfor en fin egenskab at sortere efter. Se evt. <a title="Capability vs. Role table" href="https://codex.wordpress.org/Roles_and_Capabilities#Capability_vs._Role_Table" target="_blank" rel="noopener external">Capability vs. Role table</a> for andre egenskaber at sorter efter. </p> 
 <p> Min endelige løsning blev de følgende linjers kode. Disse filtre tillader mine editors at oprette nye forms. Dertil har jeg tilføjet tilladelser til nogle af de undermenuer vi i vores tilfælde havde brug for at editors havde adgang til. </p> 
<pre>function squazz_change_ninja_forms_capabilities_filter( ) {
   return 'edit_others_posts';
}
add_filter( 'ninja_forms_admin_menu_capabilities', 'squazz_change_ninja_forms_capabilities_filter' ); // Show Ninja Forms menu
add_filter( 'ninja_forms_admin_add_new_capabilities', 'squazz_change_ninja_forms_capabilities_filter' ); // Show "Add New" submenu
add_filter( 'ninja_forms_admin_all_forms_capabilities', 'squazz_change_ninja_forms_capabilities_filter' ); // Show "All Forms" submenu
add_filter( 'ninja_forms_admin_submissions_capabilities', 'squazz_change_ninja_forms_capabilities_filter' ); // Show "Submissions" submenu
add_filter( 'ninja_forms_admin_import_export_capabilities', 'squazz_change_ninja_forms_capabilities_filter' ); // Show "Import / Export" submenu</pre>
 <p> Det hele kan laves til et plugin. I så fald skal vores funktion omskrives lidt: </p> 
<pre>function squazz_change_ninja_forms_capabilities_filter( $capabilities ) {
   $capabilities = 'edit_others_posts';
   return $capabilities;
}</pre>
 <p> Filtrene skal da omskrives på følgende måde: </p> 
<pre>add_filter( 'ninja_forms_admin_menu_capabilities', 'squazz_change_ninja_forms_capabilities_filter' ); // Show Ninja Forms menu</pre>
 <p> Tjek <a title="Writing a Plugin" href="https://codex.wordpress.org/Writing_a_Plugin" target="_blank" rel="noopener external">Writing a Plugin</a> hvis du ikke har helt styr på hvordan du laver et plugin. </p> 
]]></content:encoded>
					
					<wfw:commentRss>https://squazz.dk/teknologi/ninja-forms-capabilities/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			<media:content url="https://squazz.dk/wp-content/uploads/2014/12/ninja-forms-logo-1.png" medium="image" />
<post-id xmlns="com-wordpress:feed-additions:1">1307</post-id>	</item>
		<item>
		<title>Obfuscate emails</title>
		<link>https://squazz.dk/teknologi/obfuscate-emails/</link>
					<comments>https://squazz.dk/teknologi/obfuscate-emails/#respond</comments>
		
		<dc:creator><![CDATA[Kasper Plougmann]]></dc:creator>
		<pubDate>Wed, 17 Dec 2014 20:23:18 +0000</pubDate>
				<category><![CDATA[Teknologi]]></category>
		<category><![CDATA[PHP magic]]></category>
		<category><![CDATA[Programmering]]></category>
		<guid isPermaLink="false">http://squazz.dk/?p=1297</guid>

					<description><![CDATA[Vores besøgnende skal kunne læse og klikke på vores mailadresse. Men vi må huske at obfuscate mails hvis ikke at spam-robotterne skal læse email-linket og sende os spam. Nedenstående kode er i store dele&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[ <p> Vores besøgnende skal kunne læse og klikke på vores mailadresse. Men vi må huske at obfuscate mails hvis ikke at spam-robotterne skal læse email-linket og sende os spam. </p> 
 <p> <span id="more-1297"></span> </p> 
 <p> Nedenstående kode er i store dele taget fra <a href="https://zackperdue.com/" target="_blank" rel="noopener external">Zack Perdue</a>&#8216;s fine blogpost &#8220;<span class="removed_link" title="http://zackperdue.com/tutorials/protect-your-email-from-spammers">3 Clever Ways To Protect Your Email From Spammers</span>&#8220;, men jeg har rettet koden lidt til da jeg fik nogle fejl med koden hvis ikke funktionerne blev fodret med en mailadresse. </p> 
<pre>/*
 * Obfuscate emails / use with "echo mailto($email)"
 */
function obfuscate($string) {
   $safe = '';
   foreach (str_split($string) as $letter) {
      switch (rand(1, 3)) {
         // HTML entity code
         case 1:
         $safe .= '&amp;#'.ord($letter).';';
         break;
         // Hex character code
         case 2:
         $safe .= '&amp;#x'.dechex(ord($letter)).';';
         break;
         // Raw (no) encoding
         case 3:
         $safe .= $letter;
      }
   }
   return $safe;
}

function email($email) {
   // Make sure the at sign is always obfuscated
   return str_replace('@', '&amp;#64;', obfuscate($email));
}

function mailto($email, $title = NULL) {
   // Obfuscate email address
   if($email) {
      $email = email($email);
      if ($title === NULL) {
         // Use the email address as the title
         $title = $email;
      }
      return '&lt;a href="&amp;#109;&amp;#097;&amp;#105;&amp;#108;&amp;#116;&amp;#111;&amp;#058;'.$email.'"&gt;'.$title.'&lt;/a&gt;';
      } else {
      return '';
   }
}
</pre>
 <p> Ovenstående implementation bruger jeg flittigt i kombination med WordPress Plugins der ikke håndterer dette af sig selv. <a href="https://squazz.dk/teknologi/redigering-af-labels-i-the-events-calendar/">Dette er fx tilfældet med &#8220;The Events Calendar&#8221;.</a> </p> 
]]></content:encoded>
					
					<wfw:commentRss>https://squazz.dk/teknologi/obfuscate-emails/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1297</post-id>	</item>
		<item>
		<title>Gør NextGen Gallerys styles responsive</title>
		<link>https://squazz.dk/teknologi/goer-nextgen-gallerys-styles-responsive/</link>
					<comments>https://squazz.dk/teknologi/goer-nextgen-gallerys-styles-responsive/#respond</comments>
		
		<dc:creator><![CDATA[Kasper Plougmann]]></dc:creator>
		<pubDate>Wed, 17 Dec 2014 19:57:08 +0000</pubDate>
				<category><![CDATA[Programmering]]></category>
		<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[PHP magic]]></category>
		<guid isPermaLink="false">http://squazz.dk/?p=1299</guid>

					<description><![CDATA[Med sine næsten 11,5 millioner downloads (pr. 17/12/2014), skulle man næsten tro at NextGen gallery var vedligeholdt og opdateret til moderne standarder. Langt fra, desværre. Når jeg udvikler temaer til WordPress, forsøger jeg altid&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[ <p> Med sine næsten 11,5 millioner downloads (pr. 17/12/2014), skulle man næsten tro at <a href="https://wordpress.org/plugins/nextgen-gallery/" target="_blank" rel="noopener nofollow noreferrer external">NextGen gallery</a> var vedligeholdt og opdateret til moderne standarder. Langt fra, desværre. </p> 
 <p> <span id="more-1299"></span> </p> 
 <p> Når jeg udvikler temaer til WordPress, forsøger jeg altid så vidt muligt at gøre temaet responsivt. Derfor skar det mig også i hjertet da jeg opdagede hvor låst NextGen Gallerys styles var. Det er ikke meget kode der skal til for at gøre det meste responsivt dog, hvilket den kommende CSS vil vise. </p> 
<pre>/*
 * CSS Name: Responsive NextGen Styles
 * Description: NextGEN Gallery Responsive Stylesheet
 * Author: Late Night Productions / Squazz
 * Version: 1.1
 */

.ngg-galleryoverview {
   display: flex !important;
   flex-wrap: wrap;
}
.ngg-album-compact,
.ngg-gallery-thumbnail-box {
   width: 98%;
   padding:0 1% 5px 1% !important;
   margin: 0 !important;
}
.ngg-album-compactbox {
   line-height: 1;
}
.ngg-album-compactbox .Thumb,
.ngg-gallery-thumbnail img {
   width: 100%;
   height: auto;
   margin: 0 !important;
   padding: 0 !important;
}
.ngg-album-compact h4 .ngg-album-desc,
.ngg-gallery-thumbnail {
   height: auto !important;
   width: 100% !important;
}
.ngg-album-compact p {
   line-height: 1;
}
.slideshowlink {
 width: 100%;
}
/* iPhone / Droid – Landscape */
@media screen and (min-width: 480px) {
   .ngg-album-compact,
   .ngg-gallery-thumbnail-box {
      width: 48%;
   }
}
/* Small Tablets – 640px wide */
@media screen and (min-width: 640px) {
   .ngg-album-compact,
   .ngg-gallery-thumbnail-box {
      width: 31%;
   }
}
</pre>
 <p> Husk at loade disse styles afhængigt af NextGens styles. Både fordi det er god practice, og fordi det er nødvendigt grundet den måde NextGen har skrevet deres styles fra start. Indsæt følgende kode i functions.php (og ret til så det passer til din opbygning af kode) </p> 
<pre>// NextGen gallery fix
function NextGen_styles_fix() {
   wp_enqueue_style( 'NextGen-Responsive', get_stylesheet_directory_uri() . '/styles/nggallery.css', array('nextgen_basic_thumbnails_style'), '1.1' );
}
add_action( 'wp_enqueue_scripts', 'NextGen_styles_fix' );</pre>
 <p> Der er dog nogle problemer med dette setup. Grundet at NextGen er så fastlåst i sine styles fra start af, har udvikleren også valgt at køre med meget små thumbnails. Med ovenstående styles strækker vi disse styles ret meget, og thumbnails vil komme til at se forfærdelige ud nu. Det er derfor vigtigt at vi sikrer os at vores thumbnails er store nok til worst-cases. I mit tilfælde var det 450px i bredden (Det er næsten 3x den størrelse NextGen bruger som standard). </p> 
 <p> Vi kan ændre de generelle indstillinger for thumbnails under &#8220;Gallery Settings&#8221;, hvor vi i hver af de faner vi bliver præsenteret for vælger &#8220;Override thumbnail settings&#8221; og indtaster de værdier der passer til vores tema. </p> 
 <p> Da NextGen Gallery er bygget op som den er, er det ikke nok at ændre den generelle thumbnail værdi for gamle albums. Denne værdi skal ændres for samtlige albums, hvilket kan være en del albums hvis man er en aktiv fotograf. Men det er arbejdet værd i det lange løb. </p> 
]]></content:encoded>
					
					<wfw:commentRss>https://squazz.dk/teknologi/goer-nextgen-gallerys-styles-responsive/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			<media:content url="https://squazz.dk/wp-content/uploads/2014/12/nextgen-gallery-logo-1.png" medium="image" />
<post-id xmlns="com-wordpress:feed-additions:1">1299</post-id>	</item>
		<item>
		<title>jQuery Accordion i WordPress</title>
		<link>https://squazz.dk/teknologi/jquery-accordion-i-wordpress/</link>
					<comments>https://squazz.dk/teknologi/jquery-accordion-i-wordpress/#respond</comments>
		
		<dc:creator><![CDATA[Kasper Plougmann]]></dc:creator>
		<pubDate>Thu, 04 Dec 2014 16:53:30 +0000</pubDate>
				<category><![CDATA[Programmering]]></category>
		<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[PHP magic]]></category>
		<category><![CDATA[StackOverflow]]></category>
		<guid isPermaLink="false">http://squazz.dk/?p=858</guid>

					<description><![CDATA[Hos Musalaha, ønskede vi at lave vores Q&#38;A liste mere overskuelig, og vores endelige løsning blev jQuery&#8217;s Accordion samt lidt ekstra JavaScript til at styre hvad vores brugere så. jQuerys Accordion er utroligt let at&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[ <p> Hos <a href="https://musalaha.org/" target="_blank" rel="noopener external">Musalaha</a>, ønskede vi at lave <span class="removed_link" title="https://www.musalaha.org/about-us/q-and-a/">vores Q&amp;A liste mere overskuelig</span>, og vores endelige løsning blev <a title="jQuery Accordion" href="https://jqueryui.com/accordion/" target="_blank" rel="noopener noreferrer external">jQuery&#8217;s Accordion</a> samt lidt ekstra JavaScript til at styre hvad vores brugere så. </p> 
 <p> <span id="more-858"></span> </p> 
 <p> jQuerys Accordion er utroligt let at bruge, alt hvad man behøver at gøre er at indsætte et par links i bunden af ens website (JavaScript bør altid ende i bunden af dit site). I Wordpres er det endnu nemmere, her tilføjer vi blot den følgende kode til vores functions.php fil. </p> 
<pre>function enqueued_scripts() {
   if ( !is_admin() ) {
      wp_enqueue_script('jquery-ui-accordion');
   }
}
add_action( 'wp_enqueue_scripts', 'enqueued_scripts' );</pre>
 <p> For at styre hvordan vores accordion skal fungere, opretter jeg filen accordion.js med følgende indhold: </p> 
<pre>jQuery(document).ready(function($) {
   $( "#accordion" ).accordion({
      heightStyle: "content",
      collapsible: true,
      active: false
   });
});</pre>
 <p> Og tilføjer den til wordpress på følgende måde: </p> 
<pre>function enqueued_scripts() {
   if ( !is_admin() ) {
      wp_enqueue_script('jquery-ui-accordion');
      wp_enqueue_script(
         'custom-accordion',
         get_stylesheet_directory_uri() . '/js/accordion.js',
         array('jquery')
      );
   }
}
add_action( 'wp_enqueue_scripts', 'enqueued_scripts' );</pre>
 <p> Slutteligt skal vi have opdateret vores Q&amp;A så den udnytter jQuery&#8217;s Accordion. Dette gøres i tekst-editoren for din WordPress side: </p> 
<pre>&lt;div id="accordion"&gt;
   &lt;h3&gt;Section 1&lt;/h3&gt;
   &lt;div&gt; Mauris mauris ante, blandit et, ultrices a,...&lt;/div&gt;
   &lt;h3&gt;Section 2&lt;/h3&gt;
   &lt;div&gt; Sed non urna. Donec et ante. Phasellus eu ligula...&lt;/div&gt;
&lt;/div&gt;</pre>
 <p>  <a class="deep-link" href="#de-sidste-rettelser"> </p> 
<h2 id="de-sidste-rettelser">De sidste rettelser</h2>
 <p> </a> <br /> 
Så er vi faktisk færdige, men accordion kan hurtigt gå hen og blive uoverskueligt, især når man er en mobilbruger. I vores tilfælde, ønskede vi at have det således at når man klikkede på en ny overskrift for at åbne den, lukkede den tidligere fane sig automatisk sammen. Dette fungerede fantastisk på desktop computere, men på mobile enheder blev det hurtigt rodet. Man endte med at scrolle frem og tilbage for at kunne læse indholdet af vores Q&amp;A. </p> 
 <p> For at løse dette problem vendte jeg snuden mod <a href="https://stackoverflow.com/" target="_blank" rel="noopener noreferrer external">StackOverflow</a>. Som så ofte før, viste det sig at der var andre der havde haft <a title="jQuery Accordion - will it scroll to the top of the open item? - StackOverflow" href="https://stackoverflow.com/questions/3621161/jquery-accordion-will-it-scroll-to-the-top-of-the-open-item" target="_blank" rel="noopener noreferrer external">samme problem som jeg</a>. Her fandt jeg frem til denne løsning, som virkede præcist som jeg ønskede den skulle: </p> 
<pre>activate: function( event, ui ) {
   if(!$.isEmptyObject(ui.newHeader.offset())) {
      $('html:not(:animated), body:not(:animated)').animate({ scrollTop: ui.newHeader.offset().top }, 'slow');
   }
}</pre>
 <p> Efter en opdatering af accordion.js med denne kode ender vi slutteligt ud med dette </p> 
<pre>jQuery(document).ready(function($) {
   $( "#accordion" ).accordion({
      heightStyle: "content",
      collapsible: true,
      active: false,
      activate: function( event, ui ) {
         if(!$.isEmptyObject(ui.newHeader.offset())) {
            $('html:not(:animated), body:not(:animated)').animate({ scrollTop: ui.newHeader.offset().top }, 'slow');
         }
      }
   });
});</pre>
 <p>  <a class="deep-link" href="#aendringer-specifikt-for-mobile-enheder"> </p> 
<h3 id="aendringer-specifikt-for-mobile-enheder">Ændringer specifikt for mobile enheder</h3>
 <p> </a> <br /> 
Hvis man ikke ønsker at siden automatisk skal flytte fokus til toppen af overskriften når man er på en desktop computer, kan man tjekke hvorvidt brugeren er på en mobil eller stationær enhed. Der er mange måder at gøre dette på. Min personlige favorit er at bruge så simpelt JavaScript som muligt, både fordi simpel kode er nemmest at læse, og fordi man så ikke skal huske at importere en masse biblioteker. Denne følgende kode (<a title="What is the best way to detect a handheld device in jQuery? - StackOverflow" href="https://stackoverflow.com/questions/3514784/what-is-the-best-way-to-detect-a-mobile-device-in-jquery" target="_blank" rel="noopener noreferrer external">fundet på StackOverflow</a>) kan bruges til at tjekke om din bruger er på en mobil platform: </p> 
<pre><span class="kwd">if</span><span class="pun">(</span> <span class="str">/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/</span><span class="pln">i</span><span class="pun">.</span><span class="pln">test</span><span class="pun">(</span><span class="pln">navigator</span><span class="pun">.</span><span class="pln">userAgent</span><span class="pun">)</span> <span class="pun">)</span> <span class="pun">{</span>
<span class="com">   // some code..</span>
<span class="pun">}</span></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://squazz.dk/teknologi/jquery-accordion-i-wordpress/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			<media:content url="https://squazz.dk/wp-content/uploads/2014/12/jquery-black-1-760x502.jpg" medium="image" />
<post-id xmlns="com-wordpress:feed-additions:1">858</post-id>	</item>
		<item>
		<title>Find alle PDF filer matchende et keyword</title>
		<link>https://squazz.dk/teknologi/find-alle-pdf-filer-indeholdende-et-keyword/</link>
					<comments>https://squazz.dk/teknologi/find-alle-pdf-filer-indeholdende-et-keyword/#respond</comments>
		
		<dc:creator><![CDATA[Kasper Plougmann]]></dc:creator>
		<pubDate>Thu, 04 Dec 2014 16:37:01 +0000</pubDate>
				<category><![CDATA[Programmering]]></category>
		<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[PHP magic]]></category>
		<category><![CDATA[StackOverflow]]></category>
		<guid isPermaLink="false">http://squazz.dk/?p=1238</guid>

					<description><![CDATA[I forbindelse med mit arbejde i WordPress for Musalaha, fik vi behov for at vise det nyeste nyhedsbrev på forsiden. Lad os finde PDF filerne En løsning var at oprette en side, og så importere&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[ <p> I forbindelse med <a href="https://squazz.dk/alt-om-israel/omkring-opholdet-i-israel/">mit arbejde i WordPress for Musalaha</a>, fik vi behov for at vise det nyeste nyhedsbrev på forsiden. </p> 
 <p> <span id="more-1238"></span> <br /> 
 <a class="deep-link" href="#lad-os-finde-pdf-filerne"> </p> 
<h2 id="lad-os-finde-pdf-filerne">Lad os finde PDF filerne</h2>
 <p> </a> <br /> 
En løsning var at oprette en side, og så importere denne side på forsiden via min forbedrede side inkludering. Dette er ikke en optimal løsning. Det ville betyde at skribenten på Musalaha så både skal: </p> 
<ol>
<li>Uploade nyhedsbrevet</li>
<li>Indsætte det på siden med vores nyhedsbreve</li>
<li>Huske at opdatere siden indeholdende det seneste nyhedsbrev</li>
</ol>
 <p> I stedet ønskede vi at automatisere denne proces.  Det gælder trods alt om at give skribenterne så få muligheder for at lave fejl som muligt <span class="wp-font-emots-emo-tongue"></span> </p> 
 <p> Efter at have søgt vidt og bredt efter et plugin, der kunne hjælpe mig med opgaven, endte jeg hos Stray Bits hvor <a title="Besøg Chris Cummings’s hjemmeside" href="http://www.iwdonline.com/" target="_blank" rel="author external noopener noreferrer">Chris Cummings</a> havde siddet med <a title="WordPress: List all PDFs, with a word filter" href="http://www.integritywebdevelopment.com/wordpress/wordpress-list-pdf-files-with-a-keyword-in-the-name/" target="_blank" rel="noopener external">samme problematik</a>. Min løsning er baseret meget på hans arbejde, men dog med nogle modifikationer for at kunne bruge koden mere bredt i fremtiden. Der er trods alt ingen grund til at låse sig selv fast fra begyndelsen. </p> 
<pre>function squazz_get_PDF($targetword, $limit = '-1') {
   // Setup what we are searching for
   $args = array(
      'post_type' =&gt; 'attachment',
      'post_mime_type' =&gt; 'application/pdf',
      'numberposts' =&gt; -1,
      'post_status' =&gt; null,
      'post_parent' =&gt; null,
      'orderby' =&gt; 'post_date',
      'order' =&gt; 'DESC'
   );
 
   // Get the initial results
   $attachments = get_posts($args);
   // If there are results, sort them
   if ($attachments) {
      $i = 1;
      foreach ($attachments as $post) {
         // Get the post title 
         $title = $post-&gt;post_title;
         // Only show results matching our keyword
         if (stripos($title,$targetword) !== false) {
            $files[$i]['ID'] = $post-&gt;ID;
            $files[$i]['title'] = $title;
            ...
            if($i == $limit) { break; }
            ++$i;
         }
      }
   } else {
      _e('Nothing to see here', 'SquazzFunctions')
   }
   return $files;
}</pre>
 <p> Med vores funktion kan vi nu vælge hvilket nøgleord vi vil søge efter, og hvor mange resultater vi ønsker at få. <br /> 
 <a class="deep-link" href="#naesten-i-maal"> </p> 
<h2 id="naesten-i-maal">Næsten i mål</h2>
 <p> </a> <br /> 
Med ovenstående løsning fik jeg hvad jeg ønskede, næsten i hvert fald. Funktionen søger efter PDF filer hvis titel indeholder vores keyword. I vores tilfælde skulle vi kun bruge ét dokument, det seneste, som er på engelsk. Og netop her opstår problematikken: &#8220;&#8230; <em>på engelsk</em>&#8220;. </p> 
 <p> Arbejdsrutinen omkring upload af vores nyhedsbreve er som oftest, at det første nyhedsbrev vi uploader, er det engelske nyhedsbrev. Herefter kommer så det tyske og derefter det franske. Hvilket også betyder at jeg i første forsøg fik præsenteret det franske nyhedsbrev da jeg kørte min funktion. Én løsning er at fortælle alle skribenterne at de skal uploade det engelske nyhedsbrev til sidst, men hele grunden til at vi lavede denne funktion var jo at vi ønskede at minimere mængden af ting vore skribenter skulle huske på. Hvem ved, måske kommer der i fremtiden andre processer, eller flere sprog til. <br /> 
 <a class="deep-link" href="#tid-til-flere-rettelser"> </p> 
<h3 id="tid-til-flere-rettelser">Tid til flere rettelser</h3>
 <p> </a> <br /> 
Det vores funktion har brug for, er en opgradering. Ud over at vælge hvad vi vil søge efter, og hvor mange resultater vi ønsker at modtage, vil vi også kunne vælge hvilke ting vi <em>ikke</em> ønsker at få med i resultaterne. Dette viste sig at være nemmere sagt end gjort. </p> 
 <p> Heldigvis har vi på Musalaha en arbejdsrutine hvor nyhedsbreve navngives &#8220;newsletter-<em>LANGUAGE</em>&#8211;<em>YEAR</em>&#8220;. Dette er vigtig information, da vi så &#8220;bare&#8221; skal fortælle vores mini PDF-søgemaskine hvilke ting vi <em>ikke</em> ønsker at blive præsenteret for. </p> 
 <p> PHP tilbyder os finde strenge ved hjælpe af strpos(), men desværre tilbyder PHP os ikke at søge efter et array af strenge i samme streng. Heldigvis er der andre der har haft dette problem, og som så mange gange før kunne <a href="https://stackoverflow.com/" target="_blank" rel="noopener noreferrer external">StackOwerflow</a> hjælpe mig videre med <a title="Using an array as needles in strpos - StackOwerflow" href="https://stackoverflow.com/questions/6284553/using-an-array-as-needles-in-strpos/9220624#9220624" target="_blank" rel="noopener noreferrer external">en super god løsning</a>. For at skabe overblik har vi koden herunder: </p> 
<pre>function strposa($haystack, $needle, $offset=0) {
   if(!is_array($needle)) $needle = array($needle);
   foreach($needle as $query) {
      // stop on first true result
      if(strpos($haystack, $query, $offset) !== false) return true; 
   }
   return false;
}</pre>
 <p> Note: <a title="PHP: strpos - Manual" href="https://www.php.net/manual/en/function.strpos.php" target="_blank" rel="noopener noreferrer external">strpos()</a> er case-sensitive, brug <a title="PHP: stripos - Manual" href="https://www.php.net/manual/en/function.stripos.php" target="_blank" rel="noopener noreferrer external">stripos()</a> hvis du leder efter en case-insensitive løsning. </p> 
 <p> Med min nye funktion, som kan søge efter flere keywords i en streng, har jeg nu det perfekte våben i kampen mod uønskede fraser i titlen på vores nyhedsbrev. Vi tilføjer et nyt parameter til vores funktion og nogle få linjer i koden af funktionen. Og så er vi faktisk klar til at frasortere alle de elementer vi ikke ønsker at se. </p> 
<pre>function squazz_get_PDF($targetword, $limit = '-1'<strong>, $remove = array()</strong>) {
   ...
   if ($attachments) {
      ...
         if (stripos($title,$targetword) !== false) {
            <strong>if(!strposa($title,$remove))</strong> {
               ...
            }
         }
      }
   }
   ...
}</pre>
 <p> Den endelige funktion kan ses herunder i sin fulde form: </p> 
<pre>function squazz_get_PDF($targetword, $limit = '-1', $remove = array()) {
   // Setup what we are searching for
   $args = array(
      'post_type' =&gt; 'attachment',
      'post_mime_type' =&gt; 'application/pdf',
      'numberposts' =&gt; -1,
      'post_status' =&gt; null,
      'post_parent' =&gt; null,
      'orderby' =&gt; 'post_date',
      'order' =&gt; 'DESC'
   );
 
   // Get the initial results
   $attachments = get_posts($args);
   // If there are results, sort them
   if ($attachments) {
      $i = 1;
      foreach ($attachments as $post) {
         // Get the post title 
         $title = $post-&gt;post_title;
         // Only show results matching our keyword
         if (stripos($title,$targetword) !== false) {
            if(!strposa($title,$remove)) {
               $files[$i]['ID'] = $post-&gt;ID;
               $files[$i]['title'] = $title;
               ...
               if($i == $limit) { break; }
               ++$i;
            }
         }
      }
   } else {
      _e('Nothing to see here', 'SquazzFunctions')
   }
   return $files;
}</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://squazz.dk/teknologi/find-alle-pdf-filer-indeholdende-et-keyword/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			<media:content url="https://squazz.dk/wp-content/uploads/2014/12/PHP-kode-760x507.jpg" medium="image" />
<post-id xmlns="com-wordpress:feed-additions:1">1238</post-id>	</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: squazz.dk @ 2026-09-22 08:51:08 by W3 Total Cache
-->