Yet Another Free Publish Alternative (YAFPA) [No longer maintened]

Hello everyone!
I will showcase, here, my final solution to recreate a free publish blog using :

Difference with other Free Publish

The main difference with a lot of free publish : My script will only publish the file you want. Aka, the file where you set share: true in the front matter.
(PS : There are another methods with Hugo/Jekyll and GitHub actions here).

Compared to them, my methods directly push using git with the script. The “Hugo” method is the opposite: the push will cause the action of the script.

You are welcome to adapt the script to GitHub actions.
I try to do that, but the submodule way is not the best way and I want to avoid sharing all my vault on GitHub

Before Started

Use the template on my fork to get started. After, follow the ffirst Readme (wrote by @Maxence)


Get Started

Get Started

  • You first need to create a template using YAFPA-blog
  • After, do pip install YAFPA

The first time you use the script, it will ask you three things :

  • Your vault path (absolute path !)
  • The path of the blog (absolute too !)
  • The link of your blog, as

You can reconfigure the path with yafpa --config
The file will be created in your site_package folder (you can get it with pip show YAFPA)


Usage: yafpa [-h] [--preserve | --update] [--filepath FILEPATH] [--git] [--keep] [--config]

Create file in folder, move image in assets, convert to relative path, add share support, and push to git

Optional arguments:

  • -h, --help : show this help message and exit
  • --preserve, --p, --P : Don’t delete file if already exist
  • --update, --u, --U : force update : delete all file and reform.
  • --filepath FILEPATH, --f FILEPATH, --F FILEPATH : Filepath of the file you want to convert
  • --git, --g, --G : No commit and no push to git
  • --keep, --k : Keep deleted file from vault and removed shared file
  • --config, --c : Edit the config file

Checking differences

The script will convert all file with share:true and check if the contents
are different to the versions in _notes. The only things that are
ignored is the contents of the metadata. If you want absolutely change the
metadata you can:

  • Use yafpa --file <filepath> directly
  • Use --u to force update all file
  • Continue to work on the file before pushing it.
  • Add a newline
  • Manually delete the file
  • Add or edit the metadata keys (unless date/title/created/update/link).

:warning: As always with git, you can repost the exact same file that already exists on the server.


:warning: In case you have two files with the same name but :

  • In different folder

  • With different sharing status or folder
    The script will bug because The folder is not checked (It’s not required). In this unique case, you need to rename one of the files.

  • In the same way, in case you change the folder key in the metadata, you will have two identic file in different folder.


Share all

yafpa and all yafpa option without --F FILEPATH will automatically read all file in your vault to check the share: true key in metadata (frontmatter YAML).

By default, the script will check the difference between line (cf checking difference), and convert only the file with difference. You can use --u to force update.

Share only a file

The command will be : yafpa --F filepath

The file to be shared does not need to contain share: true in its YAML, and will be updated no matter what.

How it works

The script :

  • Moves file (with share: true frontmatter or specific file) in the _notes folder
  • Moves image in assets/img and convert (with alt support)
  • Converts highlight (==mark== to [[mark::highlight]])
  • Converts “normal” writing to GFM markdown (adding \n each \n)
  • Supports non existent file (adding a css for that :wink:)
  • Supports image flags css (Lithou snippet :pray:)
  • Support normal and external files (convert “normal markdown link” to
  • Edit link to support transluction (if not embed: False)
  • Remove block id (no support)
  • Add CSS settings for inline tags (no link support) ; Tags are : class = .hash ; id = #tag_name (so you can style each tags you use)
  • Frontmatter : Update the date. If there is already a date key, save it to created and update date.
  • Frontmatter : In absence of title, add the file’s title.
  • Copy the link to your clipboard if one file is edited.
  • :star: Admonition conversion to “callout inspired notion”
  • Update the frontmatter in the original file, adding the link and change share to true if one file is shared.

Finally, the plugin will add, commit and push if supported.

Note : The clipboard may not work in your configuration. I have (and can) only test the script on IOS and Windows, so I use pyperclip and pasteboard to do that. If you are on MacOS, Linux, Android, please, check your configuration on your python and open an issue if it doesn’t work.
Note : I can’t test on these 3 OSes, so I can’t create a clipboard option on my own.

Custom CSS

You can add CSS using the file custom.css. The plugin Markdown Attribute allow to use the creation of inline css.
Some information about this :

  • You need to add : after the first {
  • The inline IAL work only if there is stylized markdown. In absence, the text will be bolded.
  • It won’t work with highlight (removed automatically by the script)

:warning: As I use CodeMirror Options and Contextual Typography, I warn you : the use of #tags to stylize the text before it doesn’t work with my build. So, as an option to don’t have a random tag in a text, you can use custom.css to remove it with display: none (you can have an example with #left).

Frontmatter settings

  • share: true : Share the file
  • embed: false : remove the transluction (convert to normal wikilinks)
  • update: false : Don’t update the file at all after the first push
  • current: false : Don’t update the date
  • folder : Use a different folder than _note (here some more information)


As admonition is very tricky, I choose to convert all admonition to a “callout Notion”.
The script will :

  • Remove codeblock for admonition codeblocks
  • Convert ```ad-``` to !!!ad-
  • Bold title and add a IAL {: .title}

JavaScript will make all things nice.

:warning: As always with markdown, you will see some problem with new paragraph inside admonition. You can use $~$ to fake line. The script will automatically add this.
Also, you can add emoji on title to add some nice formatting.

The script will add an emoji to “copy” the icons used by Admonition.

**🍎 Title**{:.title}  
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi faucibus at ex in ultricies. Etiam ac sodales mi, non aliquam lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Integer ac lectus quam. Proin sed velit eget dui aliquet sodales. Duis sed urna eleifend, dictum neque eu, elementum neque. Quisque efficitur, justo ut malesuada faucibus, magna libero tempor elit, at fermentum libero mauris aliquam magna. Quisque ultrices tortor nec enim bibendum sodales.
It supports latex : $1+1$ and *markdown*

Custom Admonition

The file custom_admonition allow you to create custom admonition for the script.
The template is :

- admonition_type: #Admonition plugin, same name
    - logo #emoji, ASCII...
    - admonition_title #As in admonition plugin

A reference of logo used in the original script :

  • Note, seelaso : :pen:
  • Abstract, summary, tldr: :memo:
  • info, todo: :information_source:
  • tip, hint, important: :fire:
  • success, check, done: :sparkles:
  • question, help, faq: :question:
  • warning, caution, attention: :warning:
  • failure, fail, missing: :x:
  • danger, error: :zap:
  • bug: :bug:
  • example, exemple: :pushpin:
  • quote, cite: :left_speech_bubble:

You need to create multiple key and value for each different synonym you use (as in admonition…)

IOS Shortcuts

You need to found the path of your vault and the blog in your phone. To achieve that, I use a-shell.

First, in a-shell, run pickFolder and choose the folder of your vault, and rerun pickFolder to choose the folder where are the blog data (you need to clone with Working Copy)
After, do showmarks and copy the two path in any note app. Check if the path is not broken because of the paste!

You can also do :

showmarks > bookmark
vim bookmark

Here is a blank sheet to help you if you want to manually write / edit it :


With :

  • vault: Vault Absolute Path
  • blog_path : Blog repository absolute path
  • blog : Blog link


To use the shortcuts, you need :

Before running the shortcuts, you need to install all requirements, aka :

pip install yafpa
yafpa --C



→ Please use Wikilinks with “short links” (I BEG YOU)
You can integrate the script within obsidian using the nice plugin Obsidian ShellCommands.

You could create two commands :

  1. share all : yafpa
  2. share one : yafpa --F {{file_path:absolute}}

You can use :

To have a button to share your file directly in Obsidian !

Template frontmatter

→ The • indicate that this value is optional

title: My files•
date: 12-11-2021•
embed: true•
update: true•
current: true•
folder: notes•
flux: true•
share: false 
category: Notes
description: my awesome file

You can use MetaEdit / Supercharged links to quickly update the front matter.

Here is my blog showcase

On blog

On Obsidian


Little update to add a new feature : Clipboard !
If you share one file ; it will add the link in your clipboard.

For MacOS/Windows/Linux, I use pyperclip to do that.

On IOS, I use :

  • Pasteboard module on Pyto
  • Clipboard module on pythonista.

So, I can’t try to find a clipboard package for Android because I don’t have one. If you have one, please, create an issue or PR, and we will check that !

Also, you need to add, in your .env another line with blog=""


:star: I updated the repository to add Admonition support.
I take the icons from Material Icons and use the official color from Material Docs.

It uses : {: .type} and {: .ad-title-type}.
The script will add **title**{: .ad-title-type} if found title: in the admonition block.

It doesn’t support :

  • Collapse
  • Color
  • Icon
  • Custom admonition (convert to note by default)
    Collapse, color, and icon are just removed in the conversion.

The final admonition part will be :

{: .admonition-type}
> **title**{: .ad-title-type}
> Word
> Word

If no title is found, the admonition will be one line, as that :

{: .admonition-type}
> Admonition content

It also supports markdown and latex.

You can view all admonition here : Owlly House

Hello everyone !

I updated the shortcuts and add a tutorial using a-shell to get the vault path in IOS !

:warning: New Update

  • I change the “check diff file” to be more accurate, you don’t need to add a new line now to push change!

  • Admonition “non block” are now supported.

  • Using parsearg to be more practical to use.

  • Added a update and current front matter :

    • update : false : Prevent the file to update, but if the file doesn’t exist, convert and create it on the blog.
    • current: false prevent the date to be updated

I also correct the image for excalidraw (convert to excalidraw.png)

:star: To have a more cool way to use it in obsidian, the plugin Shell Commands works very well!

With [customizable sidebar] you can add the commands in directly obsidian :slight_smile:

Hello everyone!
I choose to remove the admonition support for the site because It will cause bug when conversion with python.

So, I convert ‘admonition’ to some ‘callout’, inspired by the Joshua’s publish website.

Moreover, the script normally break less things, and now, tags in page are just rendered as tag (not clickable).

If anyone know JS/liquid, I think it’s largely possible to support natively Admonition.

Title had a little rendering. Icon, collapse, are removed. You can add "pseudo-icon’ with emoji.

Also, my website become larger and larger each day. Some days ago, I add a “menu” configuration with category :

The script will now allow creating css special for each tags you use :
So, now, each tag are : <strong id="tags_name" class="hash">

Don’t forgot that the plugin Markdown Attribute allow to use the creation of inline css. Just some information :

  • You need to add : after the first {
  • You need to add the CSS to your blog. To accomplish that, you can use the css “style.css” or “custom.css” in asset/css
  • The inline IAL work only if there is stylized markdown. In absence, the text will be bolded.
  • It won’t work with highlight (removed automatically by the script)

:warning: As I use CodeMirror Options and Contextual Typography, I warn you : the use of #tags to stylize the text before it doesn’t work with my build. So, as an option to don’t have a random tag in a text, you can use custom.css to remove it with display: none (you can have an example with #left).

I can’t convert these tags to IAL because … You will lose your inline tags, so I prefer to remove this little feature to prevent breaking things.

I added a new function to the script / website : You can now use the folder key in frontmatter to specify a folder (it’s a jekyll collection).
There is several steps before you can use this functionality :

  1. Create a new folder with the name you want, prefixed with _ (as _notes or _private)
  2. Add to the _config.yml :
    1. collection :
        output: true
        permalink: /folder_name/:title
    1. defaults
         - scope: 
            path: ""
            type: folder_name
           layout: post
           content-type: notes
  3. Duplicate the and rename it with the folder name you want.
    1. In this new file, change the line {%- if page.permalink == "/private/" -%} for {%- if page.permalink == "/folder_name/" -%}
    2. Change the permalink key with permalink: /folder_name/
    3. Change {% assign mydocs = site.folder_name | group_by: 'category' %}

And there it is!

Notes about Private folder : the private folder doesn’t have a page, and doesn’t appear in the feed or in search. The only way to access it is with the link (adding /private at the end).

1 Like

Do you remember that ?
Because Python, now, the script will read the custom.css and add id according to the ID in!
So, how it is work?

Imagine, you have a custom tag to right align a text, as it doesn’t in Contextual Typography and CodeMirror Options. You use the tag #right
First, add the css to your custom.css (in asset/css) with :

#right {
 float: right

After, the script will convert all #right tags to : **your text**{: #right} in place of your text #right

Also, by default, the stylized text will be bolded, so you can add font-weight: normal !important; in the CSS ID.

:warning: Breaking change !
To be add a better setup, I separate the blog jekyll and the script !
You can found the script on pip : YAFPA · PyPI and here : GitHub - Mara-Li/YAFPA-python: The script in python for YAFPA website

To install it : pip install yafpa
and use ? yafpa
The script will ask for the .YAFPA-env at the start, and you can reconfig it with yafpa --config
Note : The file will be created by default in $HOME (or ~). In case you don’t have the writing authorization for this folder, the file will be created in the folder you use the script. So, in this case, run yafpa in always the same folder, as Documents, your vault…

Hello everyone !
I try to recreate the shortcuts, but :

  • With Pyto, I can’t run shortcuts from pip module. So, I need to rewrite a script that import all things and use variable to run the good option.
  • With a-shell, I can’t create shortcuts, because the app crash each time I add a command.

So, for the moment, I will keep with Pyto and a little script.

Hello everyone !
Some update here :slight_smile:

First : I added custom admonition ! You need to use the yaml file “custom_admonition” in the blog repository ;
I also removed the shortcuts with pyto. The app keeps crashing every time I use it, and I can’t make it to work with the new update.

I updated the shortcuts with a-shell, and add a shortcut to share one file.

Note : I also moved the env file in the site_package folder.

New update with some breaking change I moved the custom_admonition file to assets/script. For the moment, the script keep to working with the original path.

Also, I added a way to disable share in some excluded folder. You just need to add the folder name in exclude_folder.

1 Like

Hello !
I created a little script in the YAFPA BLOG repository (not the python script) to simplify the creation of folder/collection.
You need to update your repo (or download the file) and run python3 folder folder_name. The script will do the rest for you !

Does this work well?
I should be trying this in a separate backup ,right?

Well, I use it for my main vault and I saw two bug on my file :

  • Probably bug around some specific Admonition I didn’t found
  • File with emoji in name, I need to update the script for that but I was too bored.

For little file (I use it for my roleplay) it’s pretty okay and I don’t have problem.

In case you want to try, you can completely test in a test vault or make a copy of your actual vault.

Sure, Thanks!

For the moment, I work a new version of YAFPA, using Material Docs instead of because :

  • Mkdocs have a lot of good plugin (Admonition / Wikilinks)
  • Notenote is really difficult to maintain and edit.
  • My personal knowledge is more a wiki based than a blog based (as Jekyll is)
  • Jekyll liquid is difficult to use/edit.

The script will be cleared and :

  • category will be a path for folder in material/docs
  • The script will continue to convert admonition code blocks to Mkdocs but will be simplified a lot


As I said before, I stop using YAFPA because :

  • Mkdocs have a lot of good plugin (Admonition / Wikilinks)
  • Notenote is really difficult to maintain and edit.
  • My personal knowledge is more a wiki based than a blog based (as Jekyll is)
  • Jekyll liquid is difficult to use/edit.

So, I write a new template and new script (using 90% of YAPFA) to create a better experience for me.
You can totally fork YAFPA and maintains our, but in some days, I will archive the two repository.

1 Like