Compare commits

...

28 Commits

Author SHA1 Message Date
Dan Ballard 176fd9425c Add target config setting and front matter variables so one could create multiple outputs from a single site codebase with various target site included files 2025-08-17 12:25:46 -05:00
jekyllbot 40ac06ed3e Update history to reflect merge of #9850 [ci skip] 2025-07-11 05:07:19 -07:00
fauno 76982c73c0
Do not treat colons in `url_placeholders` as URI delimiters (#9850)
Merge pull request 9850
2025-07-11 05:07:17 -07:00
jekyllbot 55024b37ae Update history to reflect merge of #9832 [ci skip] 2025-06-05 08:30:47 -07:00
Sam Cole 59d5d9ae62
Add ruby-erb prerequisite for Arch Linux installations (#9832)
Merge pull request 9832
2025-06-05 08:30:45 -07:00
jekyllbot a2330bb3b3 Update history to reflect merge of #9776 [ci skip] 2025-06-05 07:51:06 -07:00
Jefferson Quesado 79a8e16f22
feat: Allowing post_url tag to receive liquid variables (#9776)
Merge pull request 9776
2025-06-05 07:51:04 -07:00
jekyllbot e2e1ee8eaa Update history to reflect merge of #9829 [ci skip] 2025-06-02 08:07:04 -07:00
Ashwin Maroli 2a37caac83
Improve readability of `post_url` tag (#9829)
Merge pull request 9829
2025-06-02 08:07:02 -07:00
jekyllbot 84437a5052 Update history to reflect merge of #9813 [ci skip] 2025-04-24 05:08:01 -07:00
printfn 01781355ef
Fix logs containing IPv6 URLs (#9813)
Merge pull request 9813
2025-04-24 05:08:00 -07:00
Ashwin Maroli fa5575c806 Configure spell-check to allow `azion` 2025-04-23 19:02:11 +05:30
jekyllbot cc583c218c Update history to reflect merge of #9811 [ci skip] 2025-04-22 07:32:19 -07:00
Bruno Germano 5f877c347b
Add Azion to the 3rd party deployment docs (#9811)
Merge pull request 9811
2025-04-22 07:32:17 -07:00
Ashwin Maroli dfbd86db50
Edit History doc to reflect updated pull request titles [skip ci] 2025-04-09 18:04:48 +05:30
Molly Exten 1b617d7281
Updated note on Gemfiles in 10-deployment.md (#9805)
This is a 🔦 documentation change.

I've adjusted the documentation to include a note that Gemfile is
already installed if the reader has completed step 1 in this tutorial. I
thought it was kind of confusing to see instructions on adding a Gemfile
when I had already done that step in the first part of the tutorial.

---------

Co-authored-by: Matt Rogers <mattr-@github.com>
2025-04-08 11:15:23 -05:00
Matt Rogers f6d9f86e04
Update spelling allow list after merging 9786 [ci skip] 2025-04-08 10:58:01 -05:00
jekyllbot 148c1d395c Update history to reflect merge of #9784 [ci skip] 2025-04-08 08:09:47 -07:00
Ashwin Maroli 07a01b0bc9
Avoid caching resource when called via `include_relative` tag (#9784)
Merge pull request 9784
2025-04-08 08:09:45 -07:00
jekyllbot 82efcc4c51 Update history to reflect merge of #9786 [ci skip] 2025-04-08 08:08:28 -07:00
Fernando Tapia Rico 1e4696457d
Add Supranode to third-party deployment guide (#9786)
Merge pull request 9786
2025-04-08 08:08:26 -07:00
jekyllbot f320d0d5d7 Update history to reflect merge of #9802 [ci skip] 2025-04-08 08:07:48 -07:00
Reinhard Söllradl 193d2eca7f
Update resources.md (#9802)
Merge pull request 9802
2025-04-08 08:07:46 -07:00
jekyllbot 0db8443b41 Update history to reflect merge of #9803 [ci skip] 2025-04-08 08:06:47 -07:00
Molly Exten e4f0c58395
Small documentation update for 09-collections.md (#9803)
Merge pull request 9803
2025-04-08 08:06:45 -07:00
Ashwin Maroli 1f319fb273 Release 💎 v4.4.1 2025-01-29 18:16:50 +05:30
Ashwin Maroli c5cd1fb04f
Restore globbed path behavior in front matter defaults (#9762)
Restore existing behavior in v4.3.x wherein a scope with path
`_*/**/index.md` matches `_label/index.md` as well instead of just
`_label/dir/index.md`.
2025-01-29 18:01:40 +05:30
Ashwin Maroli 33e8a84a00
Add unrecognized words to expected spelling data [skip ci] 2025-01-29 17:39:01 +05:30
34 changed files with 271 additions and 96 deletions

View File

@ -1,3 +1,4 @@
azion
builtins builtins
github github
hakiri hakiri
@ -7,6 +8,7 @@ Microsoft
ssh ssh
Statictastic Statictastic
statictastic statictastic
supranode
ubuntu ubuntu
Wikipedia Wikipedia
workaround workaround

View File

@ -83,6 +83,7 @@ DCEU
Debian Debian
defunkt defunkt
delegators delegators
devcontainer
digitalocean digitalocean
disqus disqus
ditaa ditaa
@ -360,7 +361,7 @@ shingo
shopify shopify
shortlinks shortlinks
shortlog shortlog
Shoulda shoulda
sieversii sieversii
sigpipe sigpipe
Singhaniya Singhaniya
@ -446,6 +447,7 @@ vnd
vohedge vohedge
vps vps
vwochnik vwochnik
WAI
wdm wdm
We'd We'd
webfonts webfonts

View File

@ -1,3 +1,34 @@
## HEAD
### Bug Fixes
* Avoid caching resource when called via `include_relative` tag (#9784)
* Fix logs containing IPv6 URLs (#9813)
* Do not treat colons in `url_placeholders` as URI delimiters (#9850)
### Documentation
* Improve documentation on collections in step-by-step walkthrough (#9803)
* Add `https://form.taxi` as a third-party resource for forms (#9802)
* Add Supranode to third-party deployment guide (#9786)
* Document the need for a `Gemfile` in deployment step of step-by-step walkthrough (#9805)
* Add Azion to the 3rd party deployment docs (#9811)
* Add ruby-erb prerequisite for Arch Linux installations (#9832)
### Development Fixes
* Improve readability of `post_url` tag (#9829)
### Minor Enhancements
* feat: Allowing post_url tag to receive liquid variables (#9776)
## 4.4.1 / 2025-01-29
### Bug Fixes
* Restore globbed path behavior in front matter defaults (#9762)
## 4.4.0 / 2025-01-27 ## 4.4.0 / 2025-01-27
### Minor Enhancements ### Minor Enhancements

View File

@ -1,5 +1,5 @@
--- ---
version: 4.4.0 version: 4.4.1
name: Jekyll • Simple, blog-aware, static sites name: Jekyll • Simple, blog-aware, static sites
description: Transform your plain text into static websites and blogs description: Transform your plain text into static websites and blogs
url: https://jekyllrb.com url: https://jekyllrb.com

View File

@ -47,9 +47,9 @@ Read this [Jekyll step-by-step guide](https://www.netlify.com/blog/2020/04/02/a-
[Render](https://render.com) provides zero config continuous deployment for static sites. The service is free under 100GB monthly bandwidth. [Render](https://render.com) provides zero config continuous deployment for static sites. The service is free under 100GB monthly bandwidth.
## Hostman ## Hostman
[Hostman](https://hostman.com) allows you to host websites for free with no configurations. Read [this guide](https://hostman.com/docs/jekyll) to deploy your Jekyll site on Hostman. [Hostman](https://hostman.com) allows you to host websites for free with no configurations. Read [this guide](https://hostman.com/docs/jekyll) to deploy your Jekyll site on Hostman.
## Static Publisher ## Static Publisher
@ -70,7 +70,17 @@ Read this [Jekyll step-by-step guide](https://www.21yunbox.com/docs/#/deploy-jek
[Layer0](https://www.layer0.co) is an all-in-one platform to develop, deploy, preview, experiment on, monitor, and run your headless frontend. It is focused on large, dynamic websites and best-in-class performance through EdgeJS (a JavaScript-based Content Delivery Network), predictive prefetching, and performance monitoring. Layer0 offers a free tier. Get started in just a few minutes by following [Layer0's guide to deploying Jekyll](https://docs.layer0.co/guides/jekyll). [Layer0](https://www.layer0.co) is an all-in-one platform to develop, deploy, preview, experiment on, monitor, and run your headless frontend. It is focused on large, dynamic websites and best-in-class performance through EdgeJS (a JavaScript-based Content Delivery Network), predictive prefetching, and performance monitoring. Layer0 offers a free tier. Get started in just a few minutes by following [Layer0's guide to deploying Jekyll](https://docs.layer0.co/guides/jekyll).
## Kinsta Application Hosting ## Kinsta Application Hosting
[Kinsta Application Hosting](https://kinsta.com/application-hosting) is a Cloud Platform designed to help your company and dev teams ship web projects faster and more efficiently. You can host your apps, databases, and sites all in one place. Easily connect with GitHub and automate deployments and get 24/7 support for all your favorite languages and frameworks. [Kinsta Application Hosting](https://kinsta.com/application-hosting) is a Cloud Platform designed to help your company and dev teams ship web projects faster and more efficiently. You can host your apps, databases, and sites all in one place. Easily connect with GitHub and automate deployments and get 24/7 support for all your favorite languages and frameworks.
Read [this guide](https://kinsta.com/docs/jekyll-static-site-example/) to learn how to deploy Jekyll site on Kinsta. Read [this guide](https://kinsta.com/docs/jekyll-static-site-example/) to learn how to deploy Jekyll site on Kinsta.
## Supranode
[Supranode](https://supranode.com) offers customizable continuous deployment for static websites, featuring automatic HTTPS, a high-performance CDN, secret management, deployment previews, password protection, and more.
## Azion
[Azion](https://www.azion.com/en/) is an web platform that provides a wide range of services. It allows you to host static sites, including Jekyll-powered websites, with features like automatic HTTPS, custom domains, and real-time analytics. Azion's platform is designed for performance and scalability, making it an excellent choice for hosting global websites.
In [this guide](https://www.azion.com/en/documentation/products/guides/jekyll-boilerplate/) you can learn how to deploy a Jekyll site on Azion.

View File

@ -4,6 +4,15 @@ permalink: "/docs/history/"
note: This file is autogenerated. Edit /History.markdown instead. note: This file is autogenerated. Edit /History.markdown instead.
--- ---
## 4.4.1 / 2025-01-29
{: #v4-4-1}
### Bug Fixes
{: #bug-fixes-v4-4-1}
- Restore globbed path behavior in front matter defaults ([#9762]({{ site.repository }}/issues/9762))
## 4.4.0 / 2025-01-27 ## 4.4.0 / 2025-01-27
{: #v4-4-0} {: #v4-4-0}

View File

@ -40,7 +40,7 @@ sudo emerge --ask --verbose jekyll
### ArchLinux ### ArchLinux
```sh ```sh
sudo pacman -S ruby base-devel sudo pacman -S ruby base-devel ruby-erb
``` ```
### OpenSUSE ### OpenSUSE

View File

@ -188,3 +188,25 @@ You can also use this tag to create a link to a post in Markdown as follows:
[Name of Link]({% post_url 2010-07-21-name-of-post %}) [Name of Link]({% post_url 2010-07-21-name-of-post %})
``` ```
{% endraw %} {% endraw %}
Now lets say you have a [datafile]({{ '/docs/datafiles/' | relative_url }}) `_data/cool_posts.yaml` used to keep track
of certain posts that you intend to be listed as say *Cool Posts*:
```yaml
- title: "An Awesome Post"
slug: "2010-07-21-name-of-post"
- title: "Another Awesome Post"
slug: "2016-07-26-name-of-post"
```
You may list such posts using the `post_url` tag as well (from {%- include docs_version_badge.html version="4.5.0" -%}):
{% raw %}
```liquid
Cool posts:
{%- for cool_post in site.data.cool_posts %}
- [{{ cool_post.title }}]({% post_url {{ cool_post.slug }} %})
{%- endfor %}
```
{% endraw %}

View File

@ -57,7 +57,7 @@ Ted has been eating fruit since he was baby.
Let's add a page which lists all the authors on the site. Jekyll makes the Let's add a page which lists all the authors on the site. Jekyll makes the
collection available at `site.authors`. collection available at `site.authors`.
Create `staff.html` and iterate over `site.authors` to output all the staff: Create `staff.html` in the root directory and iterate over `site.authors` to output all the staff:
{% raw %} {% raw %}
```liquid ```liquid

View File

@ -11,7 +11,7 @@ It's good practice to have a [Gemfile](/docs/ruby-101/#gemfile) for your site.
This ensures the version of Jekyll and other gems remains consistent across This ensures the version of Jekyll and other gems remains consistent across
different environments. different environments.
Create a `Gemfile` in the root. If you completed step one in this tutorial, you have already created a Gemfile. If you skipped step one, create a `Gemfile` in the root.
The file should be called 'Gemfile' and should *not* have any extension. The file should be called 'Gemfile' and should *not* have any extension.
You can create a Gemfile with Bundler and then add the `jekyll` gem: You can create a Gemfile with Bundler and then add the `jekyll` gem:
@ -20,7 +20,7 @@ bundle init
bundle add jekyll bundle add jekyll
``` ```
Your file should look something like: Your `Gemfile` should look something like:
```ruby ```ruby
# frozen_string_literal: true # frozen_string_literal: true

View File

@ -0,0 +1,10 @@
---
title: 'Jekyll 4.4.1 Released'
date: 2025-01-29 18:15:32 +0530
author: ashmaroli
version: 4.4.1
category: release
---
Publishing a patch release to restore existing behavior around defining front matter defaults
where a scope with path containing glob patterns are lax in matching paths on disk.

View File

@ -1 +1 @@
4.4.0 4.4.1

View File

@ -62,6 +62,7 @@ Use a SaaS service as a backend for functionality on your Jekyll site
- [Formspark](https://formspark.io/) - [Formspark](https://formspark.io/)
- [Formspree (open source)](https://formspree.io/) - [Formspree (open source)](https://formspree.io/)
- [formX](https://formx.stream) - [formX](https://formx.stream)
- [Form.taxi](https://form.taxi/en/backend)
- [Simple Form](https://getsimpleform.com/) - [Simple Form](https://getsimpleform.com/)
- [SmartForms](https://smartforms.dev/) - [SmartForms](https://smartforms.dev/)
- [Typeform](https://www.typeform.com/templates/c/forms/) - [Typeform](https://www.typeform.com/templates/c/forms/)

View File

@ -58,3 +58,22 @@ Feature: include_relative Tag
Then I should get a zero exit status Then I should get a zero exit status
And the _site directory should exist And the _site directory should exist
And I should see "Welcome back Dear Reader!" in "_site/index.html" And I should see "Welcome back Dear Reader!" in "_site/index.html"
Scenario: Include multiple files relative to a page at root
Given I have an "apple.md" page with foo "bar" that contains "{{ page.path }}, {{ page.foo }}"
And I have an "banana.md" page with content:
"""
{% include_relative apple.md %}
{% include_relative cherry.md %}
{{ page.path }}
"""
And I have an "cherry.md" page with foo "lipsum" that contains "{{ page.path }}, {{ page.foo }}"
When I run jekyll build
Then I should get a zero exit status
And the _site directory should exist
And I should see "<p>apple.md, bar</p>" in "_site/apple.html"
And I should see "<hr />\n<p>foo: bar" in "_site/banana.html"
And I should see "<hr />\n<p>foo: lipsum" in "_site/banana.html"
And I should see "<p>cherry.md, lipsum</p>" in "_site/cherry.html"
But I should not see "foo: lipsum" in "_site/cherry.html"

View File

@ -157,3 +157,37 @@ Feature: PostUrl Tag
But the _site directory should exist But the _site directory should exist
And I should see "<p><a href=\"/cats%20and%20dogs/2019/02/04/hello-world.html\">Post 1</a></p>" in "_site/index.html" And I should see "<p><a href=\"/cats%20and%20dogs/2019/02/04/hello-world.html\">Post 1</a></p>" in "_site/index.html"
And I should see "<p><a href=\"/2019/02/05/hello-again.html\">Post 2</a></p>" in "_site/index.html" And I should see "<p><a href=\"/2019/02/05/hello-again.html\">Post 2</a></p>" in "_site/index.html"
Scenario: Calling for a post via a liquid variable
Given I have a _posts directory
And I have the following post:
| title | date | content |
| Hello World | 2019-02-04 | Lorem ipsum dolor |
And I have an "index.md" page with content:
"""
{% assign value='2019-02-04-hello-world' %}
[Welcome]({% post_url {{ value }} %})
"""
When I run jekyll build
Then I should get a zero exit status
And the _site directory should exist
And I should see "<p><a href=\"/2019/02/04/hello-world.html\">Welcome</a></p>" in "_site/index.html"
Scenario: Calling for posts via a liquid variable in a for tag
Given I have a _posts directory
And I have the following post:
| title | date | content |
| Hello World | 2019-02-04 | Lorem ipsum dolor |
| We Meet Again | 2019-02-05 | Alpha beta gamma |
And I have an "index.md" page with content:
"""
{% assign posts = '2019-02-04-hello-world;2019-02-05-we-meet-again' | split: ';' %}
{%- for slug in posts -%}
[{{ slug }}]({% post_url {{ slug }} %})
{%- endfor %}
"""
When I run jekyll build
Then I should get a zero exit status
And the _site directory should exist
And I should see "<a href=\"/2019/02/04/hello-world.html\">2019-02-04-hello-world</a>" in "_site/index.html"
And I should see "<a href=\"/2019/02/05/we-meet-again.html\">2019-02-05-we-meet-again</a>" in "_site/index.html"

View File

@ -185,7 +185,8 @@ module Jekyll
# #
# Returns true if the 'write' metadata is true, false otherwise. # Returns true if the 'write' metadata is true, false otherwise.
def write? def write?
!!metadata.fetch("output", false) !!metadata.fetch("output", false) &&
(site.target == metadata.fetch("target", site.target))
end end
# The URL template to render collection's documents at. # The URL template to render collection's documents at.

View File

@ -243,7 +243,7 @@ module Jekyll
def format_url(ssl_enabled, address, port, baseurl = nil) def format_url(ssl_enabled, address, port, baseurl = nil)
format("%<prefix>s://%<address>s:%<port>i%<baseurl>s", format("%<prefix>s://%<address>s:%<port>i%<baseurl>s",
:prefix => ssl_enabled ? "https" : "http", :prefix => ssl_enabled ? "https" : "http",
:address => address, :address => address.include?(":") ? "[#{address}]" : address,
:port => port, :port => port,
:baseurl => baseurl ? "#{baseurl}/" : "") :baseurl => baseurl ? "#{baseurl}/" : "")
end end

View File

@ -55,8 +55,9 @@ module Jekyll
EM.schedule { @started_event.set } EM.schedule { @started_event.set }
EM.add_shutdown_hook { @stopped_event.set } EM.add_shutdown_hook { @stopped_event.set }
host = opts["host"].include?(":") ? "[#{opts["host"]}]" : opts["host"]
Jekyll.logger.info "LiveReload address:", Jekyll.logger.info "LiveReload address:",
"http://#{opts["host"]}:#{opts["livereload_port"]}" "http://#{host}:#{opts["livereload_port"]}"
end end
end end
@thread.abort_on_exception = true @thread.abort_on_exception = true

View File

@ -30,6 +30,7 @@ module Jekyll
"limit_posts" => 0, "limit_posts" => 0,
"future" => false, "future" => false,
"unpublished" => false, "unpublished" => false,
"target" => "default",
# Plugins # Plugins
"whitelist" => [], "whitelist" => [],

View File

@ -348,17 +348,20 @@ module Jekyll
end end
# Determine whether this document should be written. # Determine whether this document should be written.
# Based on the Collection to which it belongs. # Based on the Collection to which it belongs
# and site and document target.
# #
# True if the document has a collection and if that collection's #write? # True if the document has a collection and if that collection's #write?
# method returns true, and if the site's Publisher will publish the document. # method returns true, and if the site's Publisher will publish the document,
# and if the document's target matches the site target or is undefined.
# False otherwise. # False otherwise.
# #
# rubocop:disable Naming/MemoizedInstanceVariableName # rubocop:disable Naming/MemoizedInstanceVariableName
def write? def write?
return @write_p if defined?(@write_p) return @write_p if defined?(@write_p)
@write_p = collection&.write? && site.publisher.publish?(self) @write_p = collection&.write? && site.publisher.publish?(self) &&
(site.target == data.fetch("target", site.target))
end end
# rubocop:enable Naming/MemoizedInstanceVariableName # rubocop:enable Naming/MemoizedInstanceVariableName

View File

@ -15,7 +15,7 @@ module Jekyll
private delegate_method_as :data, :fallback_data private delegate_method_as :data, :fallback_data
delegate_methods :id, :output, :content, :to_s, :relative_path, :url, :date delegate_methods :id, :output, :content, :to_s, :relative_path, :url, :date
data_delegators "title", "categories", "tags" data_delegators "title", "categories", "tags", :target
def collection def collection
@obj.collection.label @obj.collection.label

View File

@ -109,7 +109,7 @@ module Jekyll
sanitized_path = sanitize_path(path) sanitized_path = sanitize_path(path)
if rel_scope_path.include?("*") if rel_scope_path.include?("*")
File.fnmatch?(strip_collections_dir(rel_scope_path), sanitized_path) glob_scope(sanitized_path, rel_scope_path)
else else
path_is_subpath?(sanitized_path, strip_collections_dir(rel_scope_path)) path_is_subpath?(sanitized_path, strip_collections_dir(rel_scope_path))
end end

View File

@ -180,7 +180,7 @@ module Jekyll
end end
def write? def write?
true site.config["target"] == data.fetch("target", site.config["target"])
end end
def excerpt_separator def excerpt_separator

View File

@ -6,7 +6,7 @@ module Jekyll
:file_read_opts, :future, :gems, :generators, :highlighter, :file_read_opts, :future, :gems, :generators, :highlighter,
:include, :inclusions, :keep_files, :layouts, :limit_posts, :include, :inclusions, :keep_files, :layouts, :limit_posts,
:lsi, :pages, :permalink_style, :plugin_manager, :plugins, :lsi, :pages, :permalink_style, :plugin_manager, :plugins,
:reader, :safe, :show_drafts, :static_files, :theme, :time, :reader, :safe, :target, :show_drafts, :static_files, :theme, :time,
:unpublished :unpublished
attr_reader :cache_dir, :config, :dest, :filter_cache, :includes_load_paths, attr_reader :cache_dir, :config, :dest, :filter_cache, :includes_load_paths,
@ -47,7 +47,7 @@ module Jekyll
def config=(config) def config=(config)
@config = config.clone @config = config.clone
%w(safe lsi highlighter baseurl exclude include future unpublished %w(safe lsi highlighter baseurl exclude include future unpublished target
show_drafts limit_posts keep_files).each do |opt| show_drafts limit_posts keep_files).each do |opt|
send(:"#{opt}=", config[opt]) send(:"#{opt}=", config[opt])
end end
@ -360,7 +360,7 @@ module Jekyll
end end
def each_site_file def each_site_file
pages.each { |page| yield page } pages.each { |page| yield (page) if page.write? }
static_files.each { |file| yield(file) if file.write? } static_files.each { |file| yield(file) if file.write? }
collections.each_value { |coll| coll.docs.each { |doc| yield(doc) if doc.write? } } collections.each_value { |coll| coll.docs.each { |doc| yield(doc) if doc.write? } }
end end

View File

@ -249,6 +249,11 @@ module Jekyll
end end
class IncludeRelativeTag < IncludeTag class IncludeRelativeTag < IncludeTag
def load_cached_partial(path, context)
context.registers[:cached_partials] ||= {}
context.registers[:cached_partials][path] ||= parse_partial(path, context)
end
def tag_includes_dirs(context) def tag_includes_dirs(context)
Array(page_path(context)).freeze Array(page_path(context)).freeze
end end
@ -267,6 +272,17 @@ module Jekyll
path = File.join(site.config["collections_dir"], path) if page["collection"] path = File.join(site.config["collections_dir"], path) if page["collection"]
path.delete_suffix("/#excerpt") path.delete_suffix("/#excerpt")
end end
# Since Jekyll 4 caches convertibles based on their path within the only instance of
# `LiquidRenderer`, initialize a new LiquidRenderer instance on every render of this
# tag to bypass caching rendered output of page / document.
def parse_partial(path, context)
LiquidRenderer.new(context.registers[:site]).file(path).parse(read_file(path, context))
rescue Liquid::Error => e
e.template_name = path
e.markup_context = "included " if e.markup_context.nil?
raise e
end
end end
end end
end end

View File

@ -3,34 +3,39 @@
module Jekyll module Jekyll
module Tags module Tags
class PostComparer class PostComparer
# Deprecated (soft; No interpreter warnings).
# To be removed in v5.0.
# Use private constant `POST_PATH_MATCHER` instead.
MATCHER = %r!^(.+/)*(\d+-\d+-\d+)-(.*)$!.freeze MATCHER = %r!^(.+/)*(\d+-\d+-\d+)-(.*)$!.freeze
POST_PATH_MATCHER = %r!\A(.+/)*?(\d{2,4}-\d{1,2}-\d{1,2})-([^/]*)\z!.freeze
private_constant :POST_PATH_MATCHER
attr_reader :path, :date, :slug, :name attr_reader :path, :date, :slug, :name
def initialize(name) def initialize(name)
@name = name @name = name
all, @path, @date, @slug = *name.sub(%r!^/!, "").match(MATCHER) all, @path, @date, @slug = *name.delete_prefix("/").match(POST_PATH_MATCHER)
unless all unless all
raise Jekyll::Errors::InvalidPostNameError, raise Jekyll::Errors::InvalidPostNameError,
"'#{name}' does not contain valid date and/or title." "'#{name}' does not contain valid date and/or title."
end end
basename_pattern = "#{date}-#{Regexp.escape(slug)}\\.[^.]+" basename_pattern = "#{date}-#{Regexp.escape(slug)}\\.[^.]+"
@name_regex = %r!^_posts/#{path}#{basename_pattern}|^#{path}_posts/?#{basename_pattern}! @name_regex = %r!\A_posts/#{path}#{basename_pattern}|\A#{path}_posts/?#{basename_pattern}!
end end
def post_date def post_date
@post_date ||= Utils.parse_date( @post_date ||= Utils.parse_date(date, "Path '#{name}' does not contain valid date.")
date,
"'#{date}' does not contain valid date and/or title."
)
end end
# Returns `MatchData` or `nil`.
def ==(other) def ==(other)
other.relative_path.match(@name_regex) other.relative_path.match(@name_regex)
end end
# Deprecated. To be removed in v5.0.
def deprecated_equality(other) def deprecated_equality(other)
slug == post_slug(other) && slug == post_slug(other) &&
post_date.year == other.date.year && post_date.year == other.date.year &&
@ -40,9 +45,9 @@ module Jekyll
private private
# Construct the directory-aware post slug for a Jekyll::Post # Construct the directory-aware post slug for a Jekyll::Document object.
# #
# other - the Jekyll::Post # other - the Jekyll::Document object.
# #
# Returns the post slug with the subdirectory (relative to _posts) # Returns the post slug with the subdirectory (relative to _posts)
def post_slug(other) def post_slug(other)
@ -58,47 +63,71 @@ module Jekyll
class PostUrl < Liquid::Tag class PostUrl < Liquid::Tag
include Jekyll::Filters::URLFilters include Jekyll::Filters::URLFilters
def initialize(tag_name, post, tokens) def initialize(tag_name, markup, tokens)
super super
@orig_post = post.strip @markup = markup.strip
begin @template = Liquid::Template.parse(@markup) if @markup.include?("{{")
@post = PostComparer.new(@orig_post)
rescue StandardError => e # Deprecated instance_variables.
raise Jekyll::Errors::PostURLError, <<~MSG # To be removed in Jekyll v5.0.
Could not parse name of post "#{@orig_post}" in tag 'post_url'. @orig_post = @markup
Make sure the post exists and the name is correct. @post = nil
#{e.class}: #{e.message}
MSG
end
end end
def render(context) def render(context)
@context = context @context = context
@resolved_markup = @template&.render(@context) || @markup
site = context.registers[:site] site = context.registers[:site]
site.posts.docs.each do |document| begin
return relative_url(document) if @post == document @post_comparer = PostComparer.new(@resolved_markup)
rescue StandardError
raise_markup_parse_error
end
# For backwards compatibility only; deprecated instance_variable.
# To be removed in Jekyll v5.0.
@post = @post_comparer
# First pass-through.
site.posts.docs.each do |post|
return relative_url(post) if @post_comparer == post
end end
# New matching method did not match, fall back to old method # First pass-through did not yield the requested post. Search again using legacy matching
# with deprecation warning if this matches # method. Log deprecation warning if a post is detected via this round.
site.posts.docs.each do |post|
next unless @post_comparer.deprecated_equality(post)
site.posts.docs.each do |document| log_legacy_usage_deprecation
next unless @post.deprecated_equality document return relative_url(post)
Jekyll::Deprecator.deprecation_message(
"A call to '{% post_url #{@post.name} %}' did not match a post using the new " \
"matching method of checking name (path-date-slug) equality. Please make sure " \
"that you change this tag to match the post's name exactly."
)
return relative_url(document)
end end
raise_post_not_found_error
end
private
def raise_markup_parse_error
raise Jekyll::Errors::PostURLError, <<~MSG raise Jekyll::Errors::PostURLError, <<~MSG
Could not find post "#{@orig_post}" in tag 'post_url'. Could not parse name of post #{@resolved_markup.inspect} in tag 'post_url'.
Make sure the post exists and the name is correct. Make sure the correct name is given to the tag.
MSG MSG
end end
def raise_post_not_found_error
raise Jekyll::Errors::PostURLError, <<~MSG
Could not find post #{@resolved_markup.inspect} in tag 'post_url'.
Make sure the post exists and the correct name is given to the tag.
MSG
end
def log_legacy_usage_deprecation
Jekyll::Deprecator.deprecation_message(
"A call to '{% post_url #{@resolved_markup} %}' did not match a post using the new " \
"matching method of checking name (path-date-slug) equality. Please make sure that " \
"you change this tag to match the post's name exactly."
)
end
end end
end end
end end

View File

@ -144,7 +144,13 @@ module Jekyll
# pct-encoded = "%" HEXDIG HEXDIG # pct-encoded = "%" HEXDIG HEXDIG
# sub-delims = "!" / "$" / "&" / "'" / "(" / ")" # sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
# / "*" / "+" / "," / ";" / "=" # / "*" / "+" / "," / ";" / "="
Addressable::URI.encode(path).encode("utf-8").sub("#", "%23") #
# `Addressable::URI::CharacterClassesRegexps::PATH` is used to encode
# non-alphanumeric characters such as "[", "]", etc.
Addressable::URI.encode_component(
path,
Addressable::URI::CharacterClassesRegexps::PATH
).encode("utf-8").sub("#", "%23")
end end
# Unescapes a URL path segment # Unescapes a URL path segment

View File

@ -1,5 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Jekyll module Jekyll
VERSION = "4.4.0" VERSION = "4.4.1"
end end

View File

@ -1 +0,0 @@
<svg></svg>

Before

Width:  |  Height:  |  Size: 13 B

View File

@ -1,3 +0,0 @@
---
speciality: Ruby
---

View File

@ -1 +0,0 @@
<svg></svg>

Before

Width:  |  Height:  |  Size: 13 B

View File

@ -1,3 +0,0 @@
---
speciality: JS Frameworks
---

View File

@ -25,6 +25,10 @@ class TestFrontMatterDefaults < JekyllUnitTest
assert_equal "val", @affected.data["key"] assert_equal "val", @affected.data["key"]
assert_nil @not_affected.data["key"] assert_nil @not_affected.data["key"]
end end
should "not call Dir.glob block" do
refute_includes @output, "Globbed Scope Path:"
end
end end
context "A site with full front matter defaults (glob)" do context "A site with full front matter defaults (glob)" do
@ -49,38 +53,9 @@ class TestFrontMatterDefaults < JekyllUnitTest
assert_equal "val", @affected.data["key"] assert_equal "val", @affected.data["key"]
assert_nil @not_affected.data["key"] assert_nil @not_affected.data["key"]
end end
end
context "A site with collections and front matter defaults with glob patterns" do should "call Dir.glob block" do
setup do assert_includes @output, "Globbed Scope Path:"
site = fixture_site(
"collections_dir" => "gathering",
"collections" => { "staff" => { "output" => true } },
"defaults" => [
{
"scope" => { "path" => "_staff/**/*.md", "type" => "staff" },
"values" => { "layout" => "simple" },
},
{
"scope" => { "path" => "_staff/**/*.svg" },
"values" => { "css_class" => "epilson" },
},
]
)
site.read
@staff = site.collections["staff"]
end
should "affect the appropriate items only" do
@staff.docs.each do |item|
assert_equal "simple", item.data["layout"]
assert_nil item.data["css_class"]
end
@staff.files.each do |item|
assert_equal "epilson", item.data["css_class"]
assert_nil item.data["layout"]
end
end end
end end

View File

@ -80,5 +80,16 @@ class TestURL < JekyllUnitTest
).to_s ).to_s
end end
end end
should "not treat colons in placeholders as uri delimiters" do
assert_equal "/foo/foo%20bar:foobar/", URL.new(
:template => "/:x/:y/",
:placeholders => { :x => "foo", :y => "foo bar:foobar" }
).to_s
end
should "unescape urls with colons" do
assert_equal "/foo/foo bar:foobar/", Jekyll::URL.unescape_path("/foo/foo%20bar:foobar/")
end
end end
end end