Embed GitHub Gist in Hugo posts
Embed GitHub Gist in Hugo posts
I was approached by Divya Akula with a suggestion to use a link to GitHub for my script and I really bought in the idea because I used to do it on Wordpress. I started googling and trying out solutions which did not work and messed up my blog repo. Fortunately being MVP I have access to GitHub Copilot and asked Copilot with a simple prompt which gave me a simple straight forward looking solution.
Notes: This section is generated by GitHub Copilot using the prompt “how to embed github gist within hugo site” and I amended it with caveats and examples I used.
To create a custom shortcode in Hugo, follow these steps:
In your Hugo site’s directory, navigate to the layouts/shortcodes directory. If it doesn’t exist, create it.
Inside the shortcodes directory, create a new file with the name of your shortcode. For example, if you want to create a shortcode named gist, you would create a file named gist.html.
In this file, write the HTML that you want the shortcode to output. For a gist shortcode, you might write something like this:
<script src="https://gist.github.com/{{ .Get 0 }}/{{ .Get 1 }}.js"></script>
This code will create a script tag that links to the Gist specified by the parameters passed to the shortcode.
- Save the file. You can now use your custom shortcode in your markdown files like this: Replace username with your GitHub username and gist_id with the ID of the Gist you want to embed.
Example for gist url https://gist.github.com/reshmee011/c23123e5f1abedd1085876279ac17b7f
| Clear-Host | |
| $properties=@{SiteUrl='';SiteTitle='';ListTitle='';SensitivityLabel='';Type='';RelativeUrl='';ParentGroup='';MemberType='';MemberName='';MemberLoginName='';Roles='';}; | |
| $dateTime = (Get-Date).toString("dd-MM-yyyy-hh-ss") | |
| $invocation = (Get-Variable MyInvocation).Value | |
| $directorypath = (Split-Path $invocation.MyCommand.Path) + "\Logs\" | |
| $excludeLimitedAccess = $true; | |
| $includeListsItems = $true; | |
| $SiteCollectionUrl = Read-Host -Prompt "Enter site collection URL "; | |
| $global:siteTitle= ""; | |
| #Exclude certain libraries | |
| $ExcludedLibraries = @("Form Templates", "Preservation Hold Library", "Site Assets", "Images", "Pages", "Settings", "Videos","Timesheet" | |
| "Site Collection Documents", "Site Collection Images", "Style Library", "AppPages", "Apps for SharePoint", "Apps for Office") | |
| $global:permissions =@(); | |
| $global:sharingLinks = @(); | |
| function Get-ListItems_WithUniquePermissions{ | |
| param( | |
| [Parameter(Mandatory)] | |
| [Microsoft.SharePoint.Client.List]$List | |
| ) | |
| $selectFields = "ID,HasUniqueRoleAssignments,FileRef,FileLeafRef,FileSystemObjectType" | |
| $Url = $siteUrl + '/_api/web/lists/getbytitle(''' + $($list.Title) + ''')/items?$select=' + $($selectFields) | |
| $nextLink = $Url | |
| $listItems = @() | |
| $Stoploop =$true | |
| while($nextLink){ | |
| do{ | |
| try { | |
| $response = invoke-pnpsprestmethod -Url $nextLink -Method Get | |
| $Stoploop =$true | |
| } | |
| catch { | |
| write-host "An error occured: $_ : Retrying" -ForegroundColor Red | |
| $Stoploop =$true | |
| Start-Sleep -Seconds 30 | |
| } | |
| } | |
| While ($Stoploop -eq $false) | |
| $listItems += $response.value | where-object{$_.HasUniqueRoleAssignments -eq $true} | |
| if($response.'odata.nextlink'){ | |
| $nextLink = $response.'odata.nextlink' | |
| } else{ | |
| $nextLink = $null | |
| } | |
| } | |
| return $listItems | |
| } | |
| Function PermissionObject($_object,$_type,$_relativeUrl,$_siteUrl,$_siteTitle,$_listTitle,$_memberType,$_parentGroup,$_memberName,$_memberLoginName,$_roleDefinitionBindings,$_sensitivityLabel) | |
| { | |
| $permission = New-Object -TypeName PSObject -Property $properties; | |
| $permission.SiteUrl =$_siteUrl; | |
| $permission.SiteTitle = $_siteTitle; | |
| $permission.ListTitle = $_listTitle; | |
| $permission.SensitivityLabel = $_sensitivityLabel; | |
| $permission.Type = $_Type -eq 1 ? "Folder" : $_Type -eq 0 ? "File" : $_Type; | |
| $permission.RelativeUrl = $_relativeUrl; | |
| $permission.MemberType = $_memberType; | |
| $permission.ParentGroup = $_parentGroup; | |
| $permission.MemberName = $_memberName; | |
| $permission.MemberLoginName = $_memberLoginName; | |
| $permission.Roles = $_roleDefinitionBindings -join ","; | |
| $global:permissions += $permission; | |
| } | |
| Function Extract-Guid ($inputString) { | |
| $splitString = $inputString -split '\|' | |
| return $splitString[2].TrimEnd('_o') | |
| } | |
| Function QueryUniquePermissionsByObject($_ctx,$_object,$_Type,$_RelativeUrl,$_siteUrl,$_siteTitle,$_listTitle) | |
| { | |
| $roleAssignments = Get-PnPProperty -ClientObject $_object -Property RoleAssignments | |
| switch ($_Type) { | |
| 0 { $sensitivityLabel = $_object.FieldValues["_DisplayName"] } | |
| 1 { $sensitivityLabel = $_object.FieldValues["_DisplayName"] } | |
| "Site" { $sensitivityLabel = (Get-PnPSiteSensitivityLabel).displayname } | |
| default { " " } | |
| } | |
| foreach($roleAssign in $roleAssignments){ | |
| Get-PnPProperty -ClientObject $roleAssign -Property RoleDefinitionBindings,Member; | |
| $PermissionLevels = $roleAssign.RoleDefinitionBindings | Select -ExpandProperty Name; | |
| #Get all permission levels assigned (Excluding:Limited Access) | |
| if($excludeLimitedAccess -eq $true){ | |
| $PermissionLevels = ($PermissionLevels | Where { $_ -ne "Limited Access"}) -join "," | |
| } | |
| $Users = Get-PnPProperty -ClientObject ($roleAssign.Member) -Property Users -ErrorAction SilentlyContinue | |
| #Get Access type | |
| $AccessType = $roleAssign.RoleDefinitionBindings.Name | |
| $MemberType = $roleAssign.Member.GetType().Name; | |
| #Get the Principal Type: User, SP Group, AD Group | |
| $PermissionType = $roleAssign.Member.PrincipalType | |
| if( $_Type -eq 0){ | |
| $sharingLinks = Get-PnPFileSharingLink -Identity $_object.FieldValues["FileRef"] | |
| } | |
| if( $_Type -eq 1){ | |
| $sharingLinks = Get-PnPFolderSharingLink -Folder $_object.FieldValues["FileRef"] | |
| } | |
| If($PermissionLevels.Length -gt 0) { | |
| $MemberType = $roleAssign.Member.GetType().Name; | |
| #Sharing link is in the format SharingLinks.03012675-2057-4d1d-91e0-8e3b176edd94.OrganizationView.20d346d3-d359-453b-900c-633c1551ccaa | |
| If ($roleAssign.Member.Title -like "SharingLinks*") | |
| { | |
| if($sharingLinks){ | |
| $sharingLinks | where-object {$roleAssign.Member.Title -match $_.Id } | ForEach-Object{ | |
| If ($Users.Count -gt 0) | |
| { | |
| ForEach ($User in $Users) | |
| { | |
| PermissionObject $_object $_Type $_RelativeUrl $_siteUrl $_siteTitle $_listTitle "Sharing Links" $roleAssign.Member.LoginName $user.Title $User.LoginName $_.Link.Type $sensitivityLabel; | |
| } | |
| } | |
| else { | |
| PermissionObject $_object $_Type $_RelativeUrl $_siteUrl $_siteTitle $_listTitle "Sharing Links" $roleAssign.Member.LoginName $_.Link.Scope "" $_.Link.Type $sensitivityLabel; | |
| } | |
| } | |
| } | |
| } | |
| ElseIf($MemberType -eq "Group" -or $MemberType -eq "User") | |
| { | |
| $MemberName = $roleAssign.Member.Title; | |
| $MemberLoginName = $roleAssign.Member.LoginName; | |
| if($MemberType -eq "User") | |
| { | |
| $ParentGroup = "NA"; | |
| } | |
| else | |
| { | |
| $ParentGroup = $MemberName; | |
| } | |
| (PermissionObject $_object $_Type $_RelativeUrl $_siteUrl $_siteTitle $_listTitle $MemberType $ParentGroup $MemberName $MemberLoginName $PermissionLevels $sensitivityLabel); | |
| } | |
| if($_Type -eq "Site" -and $MemberType -eq "Group") | |
| { | |
| $sensitivityLabel = (Get-PnPSiteSensitivityLabel).DisplayName | |
| If($PermissionType -eq "SharePointGroup") { | |
| #Get Group Members | |
| $groupUsers = Get-PnPGroupMember -Identity $roleAssign.Member.LoginName | |
| $groupUsers|foreach-object{ | |
| if ($_.LoginName.StartsWith("c:0o.c|federateddirectoryclaimprovider|") -and $_.LoginName.EndsWith("_0")) { | |
| $guid = Extract-Guid $_.LoginName | |
| Get-PnPMicrosoft365GroupOwners -Identity $guid | ForEach-Object { | |
| $user = $_ | |
| (PermissionObject $_object "Site" $_RelativeUrl $_siteUrl $_siteTitle "" "GroupMember" $roleAssign.Member.LoginName $user.DisplayName $user.UserPrincipalName $PermissionLevels $sensitivityLabel); | |
| } | |
| } | |
| elseif ($_.LoginName.StartsWith("c:0o.c|federateddirectoryclaimprovider|")) { | |
| $guid = Extract-Guid $_.LoginName | |
| Get-PnPMicrosoft365GroupMembers -Identity $guid | ForEach-Object { | |
| $user = $_ | |
| (PermissionObject $_object "Site" $_RelativeUrl $_siteUrl $_siteTitle "" "GroupMember" $roleAssign.Member.LoginName $user.DisplayName $user.UserPrincipalName $PermissionLevels $sensitivityLabel); | |
| } | |
| } | |
| (PermissionObject $_object "Site" $_RelativeUrl $_siteUrl $_siteTitle "" "GroupMember" $roleAssign.Member.LoginName $_.Title $_.LoginName $PermissionLevels $sensitivityLabel); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| Function QueryUniquePermissions($_web) | |
| { | |
| ##query list, files and items unique permissions | |
| Write-Host "Querying web $($_web.Title)"; | |
| $siteUrl = $_web.Url; | |
| Write-Host $siteUrl -Foregroundcolor "Red"; | |
| $global:siteTitle = $_web.Title; | |
| $ll = Get-PnPList -Includes BaseType, Hidden, Title,HasUniqueRoleAssignments,RootFolder -Connection $siteconn | Where-Object {$_.Hidden -eq $False -and $_.Title -notin $ExcludedLibraries } #$_.BaseType -eq "DocumentLibrary" | |
| Write-Host "Number of lists $($ll.Count)"; | |
| QueryUniquePermissionsByObject $_web $_web "Site" "" $siteUrl $siteTitle ""; | |
| foreach($list in $ll) | |
| { | |
| $listUrl = $list.RootFolder.ServerRelativeUrl; | |
| #Exclude internal system lists and check if it has unique permissions | |
| if($list.Hidden -ne $True) | |
| { | |
| Write-Host $list.Title -Foregroundcolor "Yellow"; | |
| $listTitle = $list.Title; | |
| #Check List Permissions | |
| if($list.HasUniqueRoleAssignments -eq $True) | |
| { | |
| $Type = $list.BaseType.ToString(); | |
| QueryUniquePermissionsByObject $_web $list $Type $listUrl $siteUrl $siteTitle $listTitle; | |
| } | |
| if($includeListsItems){ | |
| $collListItem = Get-ListItems_WithUniquePermissions -List $list | |
| $count = $collListItem.Count | |
| Write-Host "Number of items with unique permissions: $count within list $listTitle" | |
| foreach($item in $collListItem) | |
| { | |
| $Type = $item.FileSystemObjectType; | |
| $fileUrl = $item.FileRef; | |
| $i = Get-PnPListItem -List $list -Id $item.ID | |
| QueryUniquePermissionsByObject $_web $i $Type $fileUrl $siteUrl $siteTitle $listTitle; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| if(Test-Path $directorypath){ | |
| Connect-PnPOnline -Url $SiteCollectionUrl -Interactive | |
| #array storing permissions | |
| $web = Get-PnPWeb | |
| #root web , i.e. site collection level | |
| QueryUniquePermissions($web); | |
| Write-Host "Permission count: $($global:permissions.Count)"; | |
| $exportFilePath = Join-Path -Path $directorypath -ChildPath $([string]::Concat($siteTitle,"-Permissions_",$dateTime,".csv")); | |
| Write-Host "Export File Path is:" $exportFilePath | |
| Write-Host "Number of lines exported is :" $global:permissions.Count | |
| $global:permissions | Select-Object SiteUrl,SiteTitle,Type,SensitivityLabel,RelativeUrl,ListTitle,MemberType,MemberName,MemberLoginName,ParentGroup,Roles|Export-CSV -Path $exportFilePath -NoTypeInformation; | |
| } | |
| else{ | |
| Write-Host "Invalid directory path:" $directorypath -ForegroundColor "Red"; | |
| } |
When you build your Hugo site, the shortcode will be replaced with the HTML you specified in the shortcode file.
Caveats
Don’t update the theme layouts section
I did that and broke my theme.
11:51:20 PM: Starting to prepare the repo for build
11:51:21 PM: Failed during stage 'preparing repo': From https://github.com/reshmee011/m365blogs
* branch main -> FETCH_HEAD
12c52c1..89bd13c main -> origin/main
Fetching submodule Hugo/sites/M365Blog/themes/ananke
From https://github.com/theNewDynamic/gohugo-theme-ananke
a1a99cf..f34c219 master -> origin/master
fatal: remote error: upload-pack: not our ref a6af9573bf68429ff0eb1e66a0d9dd53d54654db
Errors during submodule fetch:
Hugo/sites/M365Blog/themes/ananke
: exit status 1
11:51:21 PM: Preparing Git Reference refs/heads/main
11:51:21 PM: Error pulling repository: From https://github.com/reshmee011/m365blogs
* branch main -> FETCH_HEAD
12c52c1..89bd13c main -> origin/main
Fetching submodule Hugo/sites/M365Blog/themes/ananke
From https://github.com/theNewDynamic/gohugo-theme-ananke
a1a99cf..f34c219 master -> origin/master
fatal: remote error: upload-pack: not our ref a6af9573bf68429ff0eb1e66a0d9dd53d54654db
Errors during submodule fetch:
Hugo/sites/M365Blog/themes/ananke
: exit status 1
11:51:21 PM: Failing build: Failed to prepare repo
I deleted and readded the theme to fix using
$ git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke.git themes/ananke
However still had some issues building my site.
Potential errors
1:26:46 AM: Error: Error building site: failed to render pages: render of "home" failed: "/opt/build/repo/Hugo/sites/M365Blog/themes/ananke/layouts/index.html:48:23": execute of template failed: template: index.html:48:23: executing "main" at <.Site.GetPage>: can't evaluate field Site in type string
Total in 423 ms
1:26:46 AM:
1:26:46 AM: "build.command" failed
1:26:46 AM: ────────────────────────────────────────────────────────────────
1:26:46 AM:
1:26:46 AM: Error message
1:26:46 AM: Command failed with exit code 255: hugo --gc --minify -b $URL (https://ntl.fyi/exit-code-255)
1:26:46 AM:
1:26:46 AM: Error location
1:26:46 AM: In build.command from netlify.toml:
1:26:46 AM: hugo --gc --minify -b $URL
1:26:46 AM:
1:26:46 AM: Resolved config
1:26:46 AM: build:
1:26:46 AM: base: /opt/build/repo/Hugo/sites/M365Blog
1:26:46 AM: command: hugo --gc --minify -b $URL
1:26:46 AM: commandOrigin: config
1:26:46 AM: environment:
1:26:46 AM: - NODE_ENV
1:26:46 AM: - TZ
1:26:46 AM: - HUGO_VERSION
1:26:46 AM: - HUGO_ENV
1:26:46 AM: publish: /opt/build/repo/Hugo/sites/M365Blog/public
1:26:46 AM: publishOrigin: config
1:26:46 AM: Build failed due to a user error: Build script returned non-zero exit code: 2
1:26:46 AM: Failing build: Failed to build site
1:26:46 AM: Finished processing build request in 26.545s
Resolutions
Ultimately I reverted to a commit which worked using the git reset
git reset 12c52c1e031abf9fab7cdf077dd088644eb1e294
git push
I followed the instructions provided by github copilot under my site folder creating the layouts > shortcodes folder before creating the gist.html file and it worked.