Yet Another Free Publish Alternative (YAFPA)

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

Also, on mobile, you need to run the script plus a git commit/push methods. See after to get shortcuts for IOS.
You need a python interpreter (see pyto, pythonista or a-shell) to do so.

Before Started

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


Get Started

The best way is to fork the original template and delete files in _notes (which are the original files).
Otherwise, just copy script and use it for your template.
Beware that some settings use the CSS (and javascript) so, you need to adjust it.


The script uses :

You can install all with pip install -r requirements.txt


You need a .env file in root containing the path to your obsidian vault and the link to your blog. The file looks like this :



Usage: [-h] [--Preserve | --update] [--filepath FILEPATH] [--Git]

Create file in _notes, 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 : Don’t delete file if already exist
  • --update, --U : Force update : delete all file and reform.
  • --filepath FILEPATH, --F FILEPATH : Filepath of the file you want to
  • --Git, --G : No commit and no push to git (work for github, gitlab…)

Checking differences

The script will convert all file with share:true and check if the contents are differents with the version in _notes. The only things that are ignored is the contents of the metadata.

If you want absolutely change the metadata, you can:

  • Use share --file <filepath> directly
  • Use --u to force update all file
  • Continue to work on the file before pushing it.
  • Add a newline with $~$ or <br> (it will be not converted and displayed on page / obsidian so…)
  • Manually delete the file
  • Add or edit the metadata keys (unless date/title/created/update).

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

  • In different folder
  • With different sharing status
    The script will bug because I don’t check folder (It’s voluntary). In this unique case, you need to rename one of the files.


Share all

By adding, in the yaml of your file, the key share: true, you allow the script to publish the file. In fact, the script will read all the files in your vault before selecting the ones meeting the condition.

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 file to be shared does not need to contain share: true in its YAML.

How it works

The script :

  • Moves file (with share: true frontmatter or specific file) in the _notes folder or in the _private folder if private: true
  • 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 existant 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)
  • 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 front matter of original file with link ; update share status for solo sharing file.
  • Delete file if they are deleted from the vault

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

Note : The clipboard maybe 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.
I can’t testing on these 3 OS, so I can’t create a clipboard option on my own.

Also, paperclip doesn’t work on a-shell and it exists no alternative for the moment, so clipboard doesn’t work on a-shell.

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.
  • current: false : Don’t update the date
  • folder : Specify the collection-folder of your note. The “private” folder will create a “secret” page on the blog (you can only access it with adding /private to your link)

Some “CSS” / “blogs” option :

  • flux: false : remove the file from the feed
  • category : Add a category for the category page ; category: false remove it from this page too.
  • resume : Add a resume of the file in the feed.


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 niced all things.

: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.

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*

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!

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

Pyto shortcuts

To use the shortcuts, you need :

:warning: You need to install YAFPA via pip, and configure it with yafpa --config (in module run) or, using repl :

from YAFPA import blog

The config file is stored in the pyto folder. You can directly change the file using textastic or a-shell.

The main shortcut is on RoutineHub (more practical for version update) : share one file
(it’s equivalent to share <filepath>)

There are another shortcut to “share all” files : Share all true file in vault
(it’s equivalent to share without arguments)


:warning: For the moment, I can’t update this shortcuts, because of a bug.

To use the shortcuts, you need :

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

pip install yafpa

For the moment I can’t create a shortcut to share only one file, BUT! You can use a-shell as you do in a normal terminal, aka :

jump <vault>
yafpa --f <file>

To run the script for all your file, run yafpa.

Note : Compared to pyto, the script cannot work with $HOME, so the .YAFPA-env will be created in the folder you use to run it. It is also possible to use multiple folder, but you need to create the file for each. The better is to have one in the vault ; and one in the default folder of a-shell.


→ 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.