Lawtee Blog

Just 2 Simple Steps to Permanently Add Social Feed Features Like 'Moments' to Your Static Blog

Just 2 Simple Steps to Permanently Add Social Feed Features Like 'Moments' to Your Static Blog

Adding a “Moments” or social feed page to a static blog is a long-discussed topic. Previous solutions were either cumbersome to set up or inconvenient to use. To solve this problem definitively, I recently experimented with using GitHub Issues – requiring just two simple steps to create a dynamically updatable feed page.


Core Concept

Use GitHub Issues as a publishing platform for feed content, then reference those issues on a new static blog page. GitHub Actions monitors issue changes to trigger blog updates automatically.

Advantages:

  1. Simple setup and maintenance – Built on GitHub. Any issues can be resolved with AI assistance.
  2. Mobile-friendly – GitHub’s mobile app allows pinning issues to the home screen for quick posting, similar to WeChat Moments.
  3. Secure and scalable – Fully controlled content with unlimited capacity and easy migration.

Disadvantages: None identified yet.

Implementation Guide

Step 1: Create a Feed Page in Your Blog Template

For Hugo, create a file like moments.html in the layouts folder, using resources.GetRemote to fetch content from a GitHub Issue (e.g., https://api.github.com/repos/microsoft/vscode/issues/519/comments).

Adapt a static page template with your theme settings.

Example:

 1{{ define "main" }}  
 2<article class="main-article">  
 3    {{ $url := "https://api.github.com/repos/microsoft/vscode/issues/519/comments" }}  
 4    {{ $opts := dict  
 5        "headers" (dict "User-Agent" "Hugo Static Site Generator")  
 6    }}  
 7    {{ with resources.GetRemote $url $opts }}  
 8        {{ if and .Content (ne .Content "") }}  
 9            {{ $comments := .Content | transform.Unmarshal (dict "format" "json") }}  
10            <div class="moments-feed">  
11                {{ range $comments }}  
12                    <article class="moment-article">  
13                        <header class="article-header">  
14                            <div class="article-details">  
15                                <footer class="article-time">  
16                                    <div>  
17                                        {{ .created_at | time.Format "2006-01-02 15:04" }}</time>  
18                                    </div>  
19                                </footer>  
20                            </div>  
21                        </header>  
22                        <section class="article-content">  
23                            <div class="moment-content">  
24                                {{ .body | markdownify }}  
25                            </div>  
26                        </section>  
27                    </article>  
28                {{ else }}  
29                    <p>No updates yet</p>  
30                {{ end }}  
31            </div>  
32        {{ else }}  
33            <p class="no-content">Empty content</p>  
34        {{ end }}  
35    {{ else }}  
36        <p class="error">⚠️ Failed to load comments</p>  
37    {{ end }}  
38</article>  

Step 2: Set Up an Update Trigger

Note: Private repositories block external image access in issues. Use a public repository.

Option A: Blog and Feed in the Same Repo

Add this to your deployment workflow:

1on:  
2  issue_comment:  
3    types: [created, edited]  

Option B: Separate Repositories

  1. Create a public repository dedicated to feed content.
  2. Add an issue.yml file under .github/workflows as a trigger.
  3. Generate a Personal access token with repo permissions in GitHub settings, then add it to the feed repo’s Secrets as PAT.
 1name: Trigger Empty Commit on Issue Update  
 2
 3on:  
 4  issue_comment:  
 5    types: [created, edited]  
 6
 7jobs:  
 8  trigger-empty-commit:  
 9    runs-on: ubuntu-latest  
10    steps:  
11      - name: Check if the comment is on the target issue  
12        id: check-issue  
13        run: |  
14          if [ "${{ github.event.issue.number }}" != "1" ]; then  
15            echo "should_trigger=false" >> $GITHUB_OUTPUT  
16          else  
17            echo "should_trigger=true" >> $GITHUB_OUTPUT  
18          fi  
19
20      - name: Trigger empty commit in user.github.io  
21        if: steps.check-issue.outputs.should_trigger == 'true'  
22        uses: actions/github-script@v6  
23        env:  
24          PAT: ${{ secrets.PAT }}  
25        with:  
26          script: |  
27            const { execSync } = require('child_process');  
28            const repo = 'user/user.github.io';  // Replace with your Hugo repo  
29            const token = process.env.PAT;  
30
31            try {  
32              const repoUrl = `https://x-access-token:${token}@github.com/${repo}.git`;  
33              console.log(`Cloning ${repo}...`);  
34
35              execSync(`git clone ${repoUrl}`);  
36              process.chdir('user.github.io'); // Replace with your Hugo repo  
37
38              execSync('git config user.name "github-actions[bot]"');  
39              execSync('git config user.email "4189+github-actions[bot]@users.noreply.github.com"');  
40
41              execSync('git commit --allow-empty -m "Trigger update from moments/issues/1"');  
42              execSync(`git push ${repoUrl} master`);  
43              console.log('✅ Empty commit pushed successfully!');  
44            } catch (error) {  
45              console.error('❌ Error:', error.message);  
46              process.exit(1);  
47            }  

#moments #static blog

Comments