Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
Experience Sitecore! | All posts tagged 'SXA'

Experience Sitecore!

Martin Miles on Sitecore

How to make a link to downloadable media item from within SXA rendering variant?

This is just a quick tip about the way you can create a downloadable link to some media item from within a rendering variant. Given, that you have a template with a field of type File, and an item of that template has a downloadable resource, let's say PDF. Trying to use that field worn't work normally.

What you should do instead is create a reference variant field to that media item, attached within a File field. And from within a context of that reference variant field, you address to a field called File path. The image below describes that trick in action:


Hope that trick helps!

Creating custom SXA components with rendering variants and (almost) no codebehind on an example of social share buttons

Introduction. Initially, I was going to implement social share buttons on my page. The first thing coming into my mind was to use existing share components coming OOB with SXA. That's what I did and it looked well.. until I viewed generated source. It looks quite monstrous, includes iframes, inline JavaScripts and in general brought customization issues for my front-end developers. Here's how 2 of 3 buttons look like when rendered (3-rd is collapsed):


In general, that looks sort of over-engineering for given requirements. The code suggested by my front end developers looked more-less elegant like this:

<div class="social-block">
	<span class="social-block__label">share this</span>
	<ul class="social-block__list">
		<li class="social-block__item">
			<a href="#" class="social-block__link social-block__link_facebook"></a>
		</li>
		<li class="social-block__item">
			<a href="#" class="social-block__link social-block__link_twitter"></a>
		</li>
		<li class="social-block__item">
			<a href="#" class="social-block__link social-block__link_linkedin"></a>
		</li>
		<li class="social-block__item">
			<a href="#" class="social-block__link social-block__link_mail"></a>
		</li>
	</ul>
</div>

Definitely much nicer and cleaner, given that sharing functionality provided by many social platforms can be implemented just in a form of a link (ie. //www.facebook.com/sharer/sharer.php?u=https://your-site/page-to-share), so that can be simply passed with href attribute of anchor tag. 


Implementation. Based on that, I decided to implement my own Share buttons component. Of course, unwilling to create a new component from a scratch, I decided to take a look on existing with a purpose of cloning it. There were 2 requirements while picking the right component to clone: 1) it should support rendering variants and 2) it should work with datasource template, so that those are also cloned. It looks that Promo component fits the purpose well, so here we go, by using an SXA built-in clone script available from a context menu:



By that moment, I already have my custom module named Components, sitting outside of Experience Accelerator folder, that will likely be overridden by next version update, and where I separate my custom controls. So, in the following dialog, name the component, state where you want to put it and also give the name to CSS class to be used with it. 

I called my new component Social buttons, so that I will make two rendering variant as the part of it: one for sharing current page over social networs, and another will be called Social presense simply leading to my company's social network accounts. I also named CSS class social-buttons:

Also, in order to be able to provide some defaults, I also make a copy of Promo's rendering parameters under a new name, so that I could adjust it later according to my requirements:

And also copying datasource:

And finally, to make my new component even more isolated from its donor, I copy the rendering view file as well:


It is not mandatory, you may keep using existing control rendering. However, In my case I do want to modify HTML structure, to get rid of nested <div class="component-content"> elements, so I select "Copy MVC view file (specify path below)" option. 

Note 1: before you start cloning component, make sure ~/Views/SocialButtons target folder exists, otherwise script errors out. Also, once done don't forget to copy cloned rendering into your working folder so that you include it into solution and add to the source control (somewhere similar to src/Feature/Components/code/Views/SocialButtons/SocialButtons.cshtml as in my case).

Note 2: just to remind, that rendering view, CSS class name for the component and other settings can be adjusted later at the Experience Accelerator section of rendering item:

Click Proceed and when complete, you see successful result confirmation:


Once clone script finished, we may also want to add new component into the toolbox. To do so, navigate to Presentation - Available Renderings, find the desired module and add a new component into it:

I made few more changes - renamed Social buttons into Social buttons group as it makes more sense, and made item and folder templates for buttons. 

Here's what I got under feature templates for Social buttons group:


and for Social button:

You may also notice two correspondent folder templates to create folders for storing items of these new types.

These were feature-layer templates, but there's one more project-layer interface template to be appended to page types inheritance:


So now, under Data folder I can create social buttons and a social share group based on (some of) these buttons. I made just one and called it Default


From this moment, adding _Social share groups interface template into an inheritance of some page templates adds a section with an option of selecting a social group for all pages of these type. You may also customize label (and if) shown next to social buttons.


Usage. Here we carry on. After adjusting placeholder settings, you added a new component to a page, then selected appropriate datasource but nothing appears as the result. This comes due to a component supporting rendering variants, does not have any single variant availability. How comes that? 

Note 3: the clone script does not clone rendering variants (at least per SXA version 1.8), so you need to create at least one. Remember that when creating new Variants item (or duplicating an existing one), the name should be the same, as the name of the corresponding rendering:


Insert at least one Variant Definition. 

Note 4: the way rendering variants work it the first Variant Definition in the list becomes default one, if not set explicitly. I called variant Share buttons and added Info field so that it becomes visible on partial design in Experience Editor straight away (I explain Info field trick in more details in this article).


At least component shows up in Experience Editor as:


Now being aware that right component with right rendering variant presents on a page, I can carry on implementing that variant according to my desired output. 

Note 5: these buttons are not subjects to changes by content editors from within EE, rather they are configured by the site setup. That's why links should not be editable so I can use template variant field in order to render anchor tag precisely as per our requirements.


Creating rendering variant. This is how I implemented Share buttons rendering variant:


Few things I'd like to explain about the way it is structured and how it works. 

1. Naming conventions. instead of giving sections generic names, I am following "Element - Class" approach. Of course, it would make much sense from interpreting the point of view to name them "Element.Class" as CSS selectors normally do, however using dot is not allowed to be used for Sitecore item names by default while explicit setting that value for display name is an exhaustive waste of time. In any case, it is clear what element renders to.

2. You may notice, that I am having two reference variant fields, one nested into another. The way it works is that it contains the name of a field from a context item, that has a link to another item (or items). Thus, it switched context so that all nested field will be executed in the context of that "proxied" item.

3. NVelocity template (pictured above) is the very powerful way to extend rendering variants functionality far beyond out-of-the-box variant fields, employing the power of custom C# code, pre-built tools or creating your own. In one of my previous posts, I mentioned SXA built-in token tools to be used with rendering variant templates, so I am using the one already have in my solution, but if you haven't - these 2 snippets would be the only piece of your C# code to implement. Link Tool:

public class LinkTool
{
    public static string GetItemLink(Item item, bool includeServerUrl = false)
    {
        var options = UrlOptions.DefaultOptions.Clone() as UrlOptions;

        if (includeServerUrl)
        {
            options.AlwaysIncludeServerUrl = true;
        }

        return LinkManager.GetItemUrl(item, options);
    }
    public static string GetCurrent(bool includeServerUrl = false)
    {
        var item = Sitecore.Context.Item;
        return item == null ? String.Empty : GetItemLink(item, includeServerUrl);
    }
}
and ItemFieldTool below:
public class ItemFieldTool
{
    public static string GetField(Item item, string fieldName)
    {
        ReferenceField field = item.Fields[fieldName];
        return field?.Value ?? String.Empty;
    }
}

The payload, however, is lack of ability to edit anchor tag, as I mentioned in Note 5 above. But, that should not surprise, given that you see that it is being calculated on a fly from different sources. GetFieldTool reads field value of a context item, where context has been changed twice already, in this case, a variant is iterating through the list of Social buttons and $item relates to Social button item.

#set($title = $itemFieldTool.GetField($item, "Title"))
#set($suffix = $itemFieldTool.GetField($item, "Style suffix"))
#set($prefix = $itemFieldTool.GetField($item, "Url prefix"))
But how do I get a something from the context of an initial item, before "tunnelling" two times through references? The code behind tools is being still executed in Sitecore.Context which means access to page item, so I implemented GetCurrent() method that returns full URL of context page. I use it for appending to URL prefix of a social button.
$linkTool.GetCurrent(true)


Getting result. Finally, after opening exact item in Experience Editor (and not the partial design edited previously that does not wire to actual data), I am getting expected share links rendered, with correct URL:


and after applying CSS styles on a published site, Info Field scaffolding is not shown and we see nicely applied social share buttons:


This is a flexible approach allowing to configure individual buttons set per each page template by standard values with an option of overriding the default for specific page individually.

That was a walkthrough of creating new components with (almost) no new backend code written. You learned how to create custom components by cloning existing, how to create rendering variants, how to use reference fields to "proxy" the context and NVelocity templates from within rendering variant.

Hope it helps!

SXA tip: use information scaffolding fields to get more visibility over your components in Experience Editor

When working in Experience Editor, by default you see empty fields of components, that allows you editing these fields, selecting hierarchy and thus modifying components. However not always that happens...

Scenario: creating a rendering variant that has VariantReference (for switching context of related item) while editing partial design in Experience Editor. 

Symptoms: what actually happens is that partial designs are edited in their own context, all presentation data you create is stored in Final Renderings for that particular Partial Design, and not the page item. It will pull data from page item only once applied that item or (more likely) associated with its page template. But when using VariantReference field, it won't be wired to any data, thus not proxying the context to anything, leading to all the fields underneath VariantReference field item not rendered in EE. If there are not any other visuals within given rendering variant - entire component becomes non-selectable in EE.

Suggestion: to create some information field to be shown in Experience Editor, so that you may select given component and adjust its settings, as you normally do. At the same time we don't want this field to present outside of Experience Editor since its only purpose is make editors aware about this component.

Solution: that's the case where we can use personalization with a custom "where the Experience Editor is in editing mode" condition I recently wrote about. Having it in scope trick goes very simple - simply create a text variant field and enter component and rendering variant info: 


And once done, create a personalization rule for that info field to be shown only in Experience Editor, using newly created condition:


Finally, instead of unclickable whitespace, you'll see the component:


Hope this basic trick helps improving your productivity while working with SXA!

Quick tip: using rules engine for SXA rendering variants

I working on a rendering variant in order to implement a component similar to the one below:


The component should display a heading title, followed by a list of promo blocks leading to the other pages. What is important here, is that different page types can be assigned into given component, of course they all do implement _Promotable interface template that has fields allowing them being promoted through this component. So far, so good.

But notice, each promo block has its type in left top corner painted into appropriate color. The values of it (article, topic, blog) are actually types of the pages, they do not present in generic _Promotable interface template, but do match template names, so why not to expose template names for these fields?

The easiest way of doing that is to create a label for each of the page type and assign it corresponding CSS class to display in appropriate color. 


Then we may use built in Rules Engine in order to create a rules for each of these page type labels to be shown only if the item template matches given page type. Here's how it looks in Content Editor:


Note! If you cannot access your condition through SXA built-in Rule Engine, you need to assign tag to Conditional Renderings tags (/sitecore/system/Settings/Rules/Conditional Renderings):


Also, there is another way of achieving the same goat - using NVelocity templates: create a Variant Template field and expose current template name:


That will also work since type badge matches name of page template in our case, but will need some extra work to wire up CSS class, that should derive from template name in this or that way.

SXA tokens for datasource queries

Just a cheat sheet for myself to have them here all in one place so that I bookmark this URL and don't waste time digging out all sorts of documentation in order to find the right one. Taken out from here and here.

Available tokens:

  • $compatibleThemes - path to all themes
  • $theme - currently used theme
  • $pageDesigns - root of page designs
  • $partialDesigns - root of partial designs
  • $currenttemplate - name of the current template
  • $tenant - path to the current tenant
  • $site - path to the current site
  • $home - path to the current site start item (Home)
  • $templates - path to the current sitetemplates
  • $siteMedia - path to Virtual Media folder located under site
  • $sharedSites - for multiroot fields, resovles shared site for current tenant.
Custom tokens can be defined by adding an additional processor to resolveTokens pipeline.


Some samples
Children of the current pagequery:.//*
Home item of the current sitequery:$home
Parent item of the current pagequery:..
Parent of the parent item of the current pagequery:../..
Every item under site home pagequery:$home//*
Every item under site home page with additional sorting appliedquery:$home//*[@@name='News']
All items of the Page template under the current itemquery:..//*[@@templatename='Page']
All items of the Page template under the Home item of the current site       query:$site/*[@@name='Home']//*[@@templatename='Page']

Other examples met in projects per field types

Droptree
query:$site
query:$site/Data/Authors
query:$site/*[@@templatename='Presentation']/*[@@templatename='Partial Designs']
Datasource=/sitecore/system/Marketing Control Panel/Outcomes&IncludeTemplatesForSelection=outcome definition&AllowMultipleSelection=no
DataSource=/sitecore/system/Settings/Security/Profiles/Habitat/UserProfile&DatabaseName=core

Droplink
query:$site
code:Sitecore.XA.Foundation.Variants.Abstractions.DataSource.AvailableRenderingVariants, Sitecore.XA.Foundation.Variants.Abstractions
query:$compatibleThemes
query:$site/Settings/Scopes//*[@@templateid='{8B649372-CC12-4F31-802A-8C3B3D09BB3F}']|$sharedSites/Settings/Scopes//*[@@templateid='{8B649372-CC12-4F31-802A-8C3B3D09BB3F}']
query:$pageDesigns//*[@@templatename='Page Design']
query:/sitecore/system/Settings/Foundation/Experience Accelerator/Rendering Variants/Rendering Variants/*[@@templatename='Variants Grouping']/POI//*[@@templatename='Variant Definition']|$site/*[@@name='Presentation']/*[@@templatename='Variants Grouping']/POI//*[@@templatename='Variant Definition']|$sharedSites/*[@@name='Presentation']/*[@@templatename='Variants Grouping']/POI//*[@@templatename='Variant Definition']
query:$site/*[@@name='Presentation']/*[@@templatename='PoiTypes']//*[@@templatename='POI Type']|$sharedSites/*[@@name='Presentation']/*[@@templatename='PoiTypes']//*[@@templatename='POI Type']

Droplist
databasename=core&datasource=/sitecore/content/Applications/WebEdit/Edit Frame Buttons        (edit frame select buttons)

Multilist
query:/sitecore/system/Marketing Control Panel/Profiles//*[@@templatename='Profile']
query:/sitecore/system/Marketing Control Panel/Profiles//*[@@templatename='Profile']
query:/sitecore/system/Marketing Control Panel/Profiles//*[@@templatename='Profile']
query:$templates

Treelist
datasource=/sitecore/media library&IncludeTemplatesForDisplay=Media Folder,Base Theme,Theme
query:$site/*[@@name='Data']/*[@@templatename='Tag Folder']
DataSource=/sitecore/media library&IncludeTemplatesForSelection=Theme
DataSource=query:$site/Data/Links
DataSource=/sitecore/system/Settings&IncludeTemplatesForSelection=EditTenantTemplate,AddItem,ExecuteScript
DataSource=query:$tenant&IncludeTemplatesForSelection=Site
Datasource=/sitecore/media library&ExcludeTemplatesForSelection=Main section
datasource=/sitecore/layout/renderings&excludetemplatesforselection=Folder,Rendering Folder,Node
query:$tenant

TreelistEx
DataSource=/sitecore/layout&ExcludeItemsForDisplay={E18F4BC6-46A2-4842-898B-B6613733F06F},{75CC5CE4-8979-4008-9D3C-806477D57619},{1CE3B36C-9B0C-4EB5-A996-BFCB4EAA5287},{B4A0FB13-9758-427C-A7EB-1A406C045192}&ExcludeTemplatesForSelection={239F9CF4-E5A0-44E0-B342-0F32CD4C6D8B},{A87A00B1-E6DB-45AB-8B54-636FEC3B5523}
DataSource=/sitecore/layout&ExcludeItemsForDisplay={E18F4BC6-46A2-4842-898B-B6613733F06F},{75CC5CE4-8979-4008-9D3C-806477D57619},{1CE3B36C-9B0C-4EB5-A996-BFCB4EAA5287},{B4A0FB13-9758-427C-A7EB-1A406C045192},{75D27C2B-5F88-4CC8-B1DE-8412A1628408},{B87CD5F0-4E72-429D-90A3-B285F1D038CA},{39522E9A-9B6E-4CB4-850C-23D0D3ADFD0C}&ExcludeTemplatesForSelection={239F9CF4-E5A0-44E0-B342-0F32CD4C6D8B},{A87A00B1-E6DB-45AB-8B54-636FEC3B5523}
IncludeTemplatesForSelection=Site

Multiroot Treelist
DataSource=query:$partialDesigns&IncludeTemplatesForSelection=Partial Design,Metadata Partial Design&IncludeTemplatesForDisplay=Partial Design,Metadata Partial Design,Partial Designs,Partial Design Folder

Image
query:$siteMedia

General Link
query:$home

Rich text
/sitecore/system/Settings/Html Editor Profiles/Rich Text XA

Rules
rulespath=/sitecore/system/Settings/Foundation/Experience Accelerator/Variants/Rules Context&hideactions=true&allowmultiple=true
rulespath=/sitecore/system/Settings/Foundation/Experience Accelerator/Search/Item Query Rules Context&hideactions=true&allowmultiple=true

Lookup name lookup value list
query:/sitecore/layout/Devices//*[@@templatename='Device']||query:$compatibleThemes
query:/sitecore/system/Settings/Foundation/#Experience Accelerator#/Theming/Enums/Placeholders/*||query:/sitecore/templates/Foundation/#Experience Accelerator#/Grid/#Grid Definition#/#Placeholder Styles#/*
query:$templates||query:$pageDesigns//*[@@templatename='Page Design']
query:/sitecore/layout/Devices//*[@@templatename='Device']||query:/sitecore/system/Settings/*//*[@@templatename='Grid Definition']

Tag treelist
query:$site/*[@@name='Data']/*[@@templatename='Tag Folder']

Styling parameters

code:Sitecore.XA.Foundation.Presentation.CodeDataSource.RenderingStyles, Sitecore.XA.Foundation.Presentation


Mythical SXA body-top placeholder shown in Experience Editor

Recently I came into a weird situation. So, to start with ...

I got Sitecore 9.0 update 2, installed SXA 1.8 for 9.0 on top of it. Created a tenant and a site, also made few pages for test and some initial settings as we usually do as per documentation, so far so good. 

Then I made a solution, configuration and serialized everything I made on the previous step, then reinstalled an instance in order to test my solution, configuration and serialization deploys well on top of clean Sitecore and to confirm everything works as expected.

Build process went fine, deployment worked well, Unicorn ran and created the site with all my pages and all relevant items - all good, except for one issue. Before Sitecore reinstallation, a new page in Experience Editor looked that way:


After the deployment on top of the new clean instance, running Experience Editor brought the following layout:


Clearly, there was something missing from either my configuration or serialization. So I started troubleshooting and comparing.

In both scenarios, I had instances sites of the same version and both with SXA 1.8. Since this issue was reproducible, next time I made git init just within webroot in order to get a version diff with a post-deployment state, so that I could see all modified files and see the diff as I usually do with git tools. However, nothing suspicious found at bin and within App_config folder. Deployment went as expected so that should be something in Sitecore then.

First of all, I compared templates and standard values, but they were the same for both cases. Next, I ensured presentation details are also identical, even ensured Layout files and binary equal.  Yes, it contains body-top placeholder, but in one scenario it is presented for some reason.

Then I went to the actual page items in order to compare those, but they were also the same. View options have same parameters checked. No idea then...

Finally, after spending plenty of time I figured out that something was wrong with SXA themes. Unfortunately, did not identify what exactly causes the problem, but after re-creating it at serialization config and re-serializing items the issue has gone. So, the outcome is: if you see unexpected placeholders - please make sure your SXA theme is in the correct state and serialized properly.

Fixing issues preventing one having solution with SXA 1.8 along with Sitecore XP 9.0 update 2

I was very anticipating to upgrade my solution to recently released XP 9.1 with SXA 1.8 and all its great features, however, I got a dependency on Sitecore Commerce, which hasn't (yet) updated to 9.1. Got nothing to do with that, but just wait for a month or so until XC 9.1 is out...

But wait, why not just update at least SXA to version 1.8 meanwhile? SXA 1.8 comes for both versions for 9.1 and 9.0 which means - in two runtimes .NET 4.7.1 and .NET 4.6.2 correspondingly. Done, upgraded. SXA 1.8 works well on top of clean Sitecore 9.0 update 2 instance for me.

But when it came to updating NuGet packages in my solution, I was unable to do so because NuGet packages for my version for some reason demand .NET 4.7.1:


And that is my error:

Package Sitecore.XA.Feature.CreativeExchange 3.8.0 is not compatible with net462 (.NETFramework,Version=v4.6.2) / win-x86. Package Sitecore.XA.Feature.CreativeExchange 3.8.0 supports: net471 (.NETFramework,Version=v4.7.1)


Version 3.8.0 is the correct version of SXA 1.8 for 9.0 and it should support .NET 4.6.2, not 4.7.2. Version of SXA 1.8 for 9.1 has number 4.8.0 and that one indeed supports 4.7.1 runtime.

Since I cannot do anything about NuGet feeds, I turned back to the old lib\LocalRepository folder in my solution, simply copying all the required SXA 1.8 libraries from instance webroot (where I have SXA 1.8 working with clean 9.0 update instance) and referencing them instead from affected projects. 


That did me a job for the moment. I will either update to the NuGets once it is fixed with the correct version or upgrade the entire solution to 9.1 when XC 9.1 is out, whatever comes earlier.

How to use Install-SitecoreConfiguration from SIF with your custom configuration on example of installing SPE and SXA along with Sitecore

This is an exercise resulting from a blog post by Rob Ahnemann and I will cover Install-SitecoreConfiguration in more details on an example of installing Sitecore modules SPE and SXA as a part of a Sitecore installation by SIF.

Install-SitecoreConfiguration is one of the most what actually SIF is. In my Sitecore installation script I have created a step called Install-Packages. Let's look at how it works:

function Install-Packages {
    Unblock-File .\build\PostInstall\Invoke-InstallPackageTask.psm1 
    Install-SitecoreConfiguration -Path .\build\PostInstall\install-sitecore-package.json -SiteName "$SolutionPrefix.$SitePostFix"
}

This installs a configuration called install-sitecore-package.json Opening it looks like below:

{
    "Parameters": {
         "SiteName": {
            "Type": "string",
            "DefaultValue": "Sitecore",
            "Description": "The name of the site to be deployed."
        },
        "InstallDirectory": {
            "Type": "string",
            "DefaultValue": "c:\\inetpub\\wwwroot",
            "Description": "Base folder to where website is deployed."
        }
    },
    "Variables": {
        // The sites full path on disk
        "Site.PhysicalPath": "[joinpath(parameter('InstallDirectory'), parameter('SiteName'))]",
		"Site.Url": "[concat('http://', parameter('SiteName'))]"

    },
    "Tasks": {
		"InstallPackages":{
			"Type": "InstallPackage",
            "Params": [
                {
                    "SiteFolder": "[variable('Site.PhysicalPath')]",
                    "SiteUrl": "[variable('Site.Url')]",
                    "PackagePath": ".\\build\\assets\\Modules\\Sitecore PowerShell Extensions-4.7.2 for Sitecore 8.zip"
                },
                {
                    "SiteFolder": "[variable('Site.PhysicalPath')]",
                    "SiteUrl": "[variable('Site.Url')]",
                    "PackagePath": ".\\build\\assets\\Modules\\Sitecore Experience Accelerator 1.6 rev. 180103 for 9.0.zip"
                }
            ]
		}
    },
	"Modules":[
		".\\build\\PostInstall\\Invoke-InstallPackageTask.psm1"
	]
}

Parameters are values that may be passed when Install-SitecoreConfiguration is called. Parameters must declare a Type and may declare a DefaultValue and Description. Parameters with no DefaultValue are required when Install-SitecoreConfiguration is called.

Variables are values calculated in a configuration. They can reference Parameters, other Variables, and config functions.

Tasks are separate units of work in a configuration. Each task is an action that will be completed when Install-SitecoreConfiguration is called. By default, tasks are applied in the order they are declared. Tasks may reference Parameters, Variables, and config functions.

Finally, the last line is actually referencing the actual task - a PowerShell module script (Invoke-InstallPackageTask.psm1) that will be run with given parameters:

Set-StrictMode -Version 2.0

Function Invoke-InstallPackageTask {
    [CmdletBinding(SupportsShouldProcess=$true)]
    param(
        [Parameter(Mandatory=$true)]
        [string]$SiteFolder,
		[Parameter(Mandatory=$true)]
        [string]$SiteUrl,
		[Parameter(Mandatory=$true)]
        [string]$PackagePath
    )

    Write-TaskInfo "Installing Package $PackagePath" -Tag 'PackageInstall'

    #Generate a random 10 digit folder name. For security 
	$folderKey = -join ((97..122) | Get-Random -Count 10 | % {[char]$_})
	
	#Generate a Access Key (hi there TDS)
	$accessKey = New-Guid
	
	Write-TaskInfo "Folder Key = $folderKey" -Tag 'PackageInstall'
	Write-TaskInfo "Access Guid = $accessKey" -Tag 'PackageInstall'

	#The path to the source Agent.  Should be in the same folder as I'm running
	$sourceAgentPath = Resolve-Path "PackageInstaller.asmx"
	
	#The folder on the Server where the Sitecore PackageInstaller folder is to be created
	$packageInstallPath = [IO.Path]::Combine($SiteFolder, 'sitecore', 'PackageInstaller')
	
	#The folder where the actuall install happens
	$destPath = [IO.Path]::Combine($SiteFolder, 'sitecore', 'PackageInstaller', $folderKey)

	#Full path including the installer name
	$fullFileDestPath = Join-Path $destPath "PackageInstaller.asmx"
	
	Write-TaskInfo "Source Agent [$sourceAgentPath]" -Tag 'PackageInstall'
	Write-TaskInfo "Dest AgentPath [$destPath]" -Tag 'PackageInstall'

	#Forcibly cread the folder 
	New-Item -ItemType Directory -Force -Path $destPath

	#Read contents of the file, and embed the security token
	(Get-Content $sourceAgentPath).replace('[TOKEN]', $accessKey) | Set-Content $fullFileDestPath

	#How do we get to Sitecore? This URL!
	$webURI= "$siteURL/sitecore/PackageInstaller/$folderKey/packageinstaller.asmx?WSDL"
	 
	Write-TaskInfo "Url $webURI" -Tag 'PackageInstall'
	
	#Do the install here
	$proxy = New-WebServiceProxy -uri $webURI
	$proxy.Timeout = 1800000

	#Invoke our proxy
	$proxy.InstallZipPackage($PackagePath, $accessKey)

	#Remove the folderKey
	Remove-Item $packageInstallPath -Recurse
}
Register-SitecoreInstallExtension -Command Invoke-InstallPackageTask -As InstallPackage -Type Task

What this task does is locates ASMX file, which is an actual handler and copies it into temp random folder within your Sitecore instance allowing you to execute package installer APIs that itself does require Sitecore context. 

Obviously, before running .\install-xp0.ps1 please make sure you have both installers for modules by their paths as per configuration parameters in PackagePath (from example above, they are):
    .\build\assets\Modules\Sitecore PowerShell Extensions-4.7.2 for Sitecore 8.zip
    .\build\assets\Modules\Sitecore Experience Accelerator 1.6 rev. 180103 for 9.0.zip

So, that's how we added new SitecoreConfiguration in order to achieve automated package installation of SPE and SXA by SIF. Since now new locally installed Sitecore instance already has both SPE and SXA pre-installed and ready to use. This approach also allows installing any other modules as you may need them pre-installed.

Finally, would highly recommend watching a great video by Thomas Eldblom about using SIF configurations:

UPDATE: there is another way of doing this by new built-in SIF functionality, please read the blog post here.