From af57ed4871467dfb50dfea9a1edc8299f89dda09 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Sun, 17 Aug 2025 09:35:02 -0500 Subject: [PATCH] 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 --- docs/_docs/configuration/default.md | 1 + docs/_docs/deployment.md | 1 + docs/_docs/deployment/multiple-sites.md | 44 +++++++++++++++++++++++++ lib/jekyll/collection.rb | 7 ++-- lib/jekyll/configuration.rb | 1 + lib/jekyll/document.rb | 9 +++-- lib/jekyll/drops/document_drop.rb | 2 +- lib/jekyll/page.rb | 2 +- lib/jekyll/site.rb | 6 ++-- 9 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 docs/_docs/deployment/multiple-sites.md diff --git a/docs/_docs/configuration/default.md b/docs/_docs/configuration/default.md index e96c5071..bda69e8e 100644 --- a/docs/_docs/configuration/default.md +++ b/docs/_docs/configuration/default.md @@ -43,6 +43,7 @@ show_drafts : null limit_posts : 0 future : false unpublished : false +target : "default" # Plugins whitelist : [] diff --git a/docs/_docs/deployment.md b/docs/_docs/deployment.md index 45722e4e..9e69d909 100644 --- a/docs/_docs/deployment.md +++ b/docs/_docs/deployment.md @@ -9,3 +9,4 @@ Sites built using Jekyll can be deployed in a large number of ways due to the st * [Manually]({{ '/docs/deployment/manual/' | relative_url }}) * [Automated]({{ '/docs/deployment/automated/' | relative_url }}) * [Third Party]({{ '/docs/deployment/third-party/' | relative_url }}) +* [Multiple Sites and Target]({{ '/docs/deployment/multiple-sites' | relative_url }}) diff --git a/docs/_docs/deployment/multiple-sites.md b/docs/_docs/deployment/multiple-sites.md new file mode 100644 index 00000000..1b994794 --- /dev/null +++ b/docs/_docs/deployment/multiple-sites.md @@ -0,0 +1,44 @@ +--- +title: Multiple Sites and Target +permalink: /docs/deployment/multiple-sites/ +--- + +The `target` setting in `_config.yml` and frontmatter in conjunction with config stacking allows multiple sites with varitation to be built from one codebase. + +## Use Case + +You may have multiple access paths to your site, and want to offer unique content on some of them, for examples you may have a open web version of your site at `https://foo.com` and you may also have an [onion service](https://community.torproject.org/onion-services/setup/) version of your site accesible via `http://foo000...abc.onion`. Alternately you may have a public facing version of the site, and an internal network or VPN accessible version that you want additional content to be included on. + +## Method + +By default the `target` config option is set to "default" in `_site_config.yml` and when comparing with frontmatter of content, if none is set, it inherit's the site's value. So by default all content will be published. To make content only appear on a specific version of a site, in frontmatter add `target: xVersion` where "xVersion" will be a `target` option set in a second `_site_x.yml`. + +You generate the normal site the same + +`bundle exec jekyll build` + +For the second site, you create a mini site specific config, like + +```yml +url: https://altDomain.com +destination: _site_xVersion +target: xVersion + +``` + +and build it with + +`bundle exec jekyll build --config "_config.yml,_config_xversion.yml"` + +Jekyll configs stack, and overrides from additional configs override earlier ones, so this will get all the default site config options and then just change `url`, `destination` and `target` + + +Then any content with a frontmatter `target` of "xVersion" will be included in this build which will be output to the new `_site_xVersion`. + +If there is any content you want on the default version of the site but not any alternative ones, just add `target: default` to it's frontmatter. + +Then configure your webserver with a second site config with the alternative access path and pointing to `_site_xVersion` directory. + +### Potential Cons + +This does result in multiple builds, which is potentially the one negative of this method if you are very constrained for space or your jekyll site is very large. diff --git a/lib/jekyll/collection.rb b/lib/jekyll/collection.rb index 1ce33bf2..81bc2392 100644 --- a/lib/jekyll/collection.rb +++ b/lib/jekyll/collection.rb @@ -183,9 +183,12 @@ module Jekyll # Whether the collection's documents ought to be written as individual # files in the output. # - # Returns true if the 'write' metadata is true, false otherwise. + # Returns true if the 'write' metadata is true and + # if the collection's target matches the site's target, + # false otherwise. def write? - !!metadata.fetch("output", false) + !!metadata.fetch("output", false) && + (site.target == metadata.fetch("target", site.target)) end # The URL template to render collection's documents at. diff --git a/lib/jekyll/configuration.rb b/lib/jekyll/configuration.rb index 9b2fbffc..ad19b2e7 100644 --- a/lib/jekyll/configuration.rb +++ b/lib/jekyll/configuration.rb @@ -30,6 +30,7 @@ module Jekyll "limit_posts" => 0, "future" => false, "unpublished" => false, + "target" => "default", # Plugins "whitelist" => [], diff --git a/lib/jekyll/document.rb b/lib/jekyll/document.rb index 2e39024e..4f03cec8 100644 --- a/lib/jekyll/document.rb +++ b/lib/jekyll/document.rb @@ -348,17 +348,20 @@ module Jekyll end # 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? - # 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. # # rubocop:disable Naming/MemoizedInstanceVariableName def write? 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 # rubocop:enable Naming/MemoizedInstanceVariableName diff --git a/lib/jekyll/drops/document_drop.rb b/lib/jekyll/drops/document_drop.rb index 0cff3741..b1bf3ed0 100644 --- a/lib/jekyll/drops/document_drop.rb +++ b/lib/jekyll/drops/document_drop.rb @@ -15,7 +15,7 @@ module Jekyll private delegate_method_as :data, :fallback_data delegate_methods :id, :output, :content, :to_s, :relative_path, :url, :date - data_delegators "title", "categories", "tags" + data_delegators "title", "categories", "tags", :target def collection @obj.collection.label diff --git a/lib/jekyll/page.rb b/lib/jekyll/page.rb index 64821a82..c94767cb 100644 --- a/lib/jekyll/page.rb +++ b/lib/jekyll/page.rb @@ -180,7 +180,7 @@ module Jekyll end def write? - true + site.config["target"] == data.fetch("target", site.config["target"]) end def excerpt_separator diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index adec4cc0..f531878e 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -6,7 +6,7 @@ module Jekyll :file_read_opts, :future, :gems, :generators, :highlighter, :include, :inclusions, :keep_files, :layouts, :limit_posts, :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 attr_reader :cache_dir, :config, :dest, :filter_cache, :includes_load_paths, @@ -47,7 +47,7 @@ module Jekyll def config=(config) @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| send(:"#{opt}=", config[opt]) end @@ -360,7 +360,7 @@ module Jekyll end 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? } collections.each_value { |coll| coll.docs.each { |doc| yield(doc) if doc.write? } } end