Update docs + sandbox files
This commit is contained in:
parent
0975b674c5
commit
1bf5cd7bf8
|
@ -6,14 +6,19 @@
|
||||||
|
|
||||||
- Newlines are now required after the closing `+++` of front-matter
|
- Newlines are now required after the closing `+++` of front-matter
|
||||||
- `resize_image` now returns an object: `{url, static_path}` instead of just the URL so you can follow up with other functions on the new file if needed
|
- `resize_image` now returns an object: `{url, static_path}` instead of just the URL so you can follow up with other functions on the new file if needed
|
||||||
- `get_file_hash` now has the `base64` option set to `true` by default (from `false`) since it's mainly used for integrity hashes which are base64
|
- `get_file_hash` now has the `base64` option set to `true` by default (from `false`) since it's mainly used for integrity hashes which are base64
|
||||||
- `get_url` does not automatically strip leading `/` from paths anymore
|
|
||||||
- i18n rework: languages now have their sections in `config.toml` to set up all their options
|
- i18n rework: languages now have their sections in `config.toml` to set up all their options
|
||||||
1. taxonomies don't have a `lang` anymore in the config, you need to declare them in their respective language section
|
1. taxonomies don't have a `lang` anymore in the config, you need to declare them in their respective language section
|
||||||
2. the `config` variable in templates has been changed and is now a stripped down language aware version of the previous `config`
|
2. the `config` variable in templates has been changed and is now a stripped down language aware version of the previous `config`
|
||||||
object
|
object
|
||||||
3. Search settings are now language specific
|
3. Search settings are now language specific
|
||||||
4. Translations are now nested in the languages table
|
4. Translations are now nested in the languages table
|
||||||
|
- Paths unification:
|
||||||
|
1. `get_url` does not load automatically from the `static` folder anymore
|
||||||
|
2. New path resolving logic for all on-disk files: replace `@/` by `content/`, trim leading `/` and
|
||||||
|
search in $BASE_DIR + $path, $BASE_DIR + static + $path and $BASE_DIR + content + $path
|
||||||
|
3. `get_file_hash` now returns base64 encoded hash by default
|
||||||
|
4. all functions working on files can now only load files in the Zola directory
|
||||||
|
|
||||||
### Other
|
### Other
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ where
|
||||||
{
|
{
|
||||||
let mut hasher = D::new();
|
let mut hasher = D::new();
|
||||||
io::copy(&mut file, &mut hasher)?;
|
io::copy(&mut file, &mut hasher)?;
|
||||||
println!("base64: {}", as_base64);
|
|
||||||
if as_base64 {
|
if as_base64 {
|
||||||
Ok(encode_b64(hasher.finalize()))
|
Ok(encode_b64(hasher.finalize()))
|
||||||
} else {
|
} else {
|
||||||
|
@ -79,9 +78,6 @@ impl TeraFn for GetUrl {
|
||||||
let lang = optional_arg!(String, args.get("lang"), "`get_url`: `lang` must be a string.")
|
let lang = optional_arg!(String, args.get("lang"), "`get_url`: `lang` must be a string.")
|
||||||
.unwrap_or_else(|| self.config.default_language.clone());
|
.unwrap_or_else(|| self.config.default_language.clone());
|
||||||
|
|
||||||
// TODO: handle rss files with langs
|
|
||||||
// https://zola.discourse.group/t/rss-and-languages-do-not-work/878
|
|
||||||
// TODO: clean up everything
|
|
||||||
// if it starts with @/, resolve it as an internal link
|
// if it starts with @/, resolve it as an internal link
|
||||||
if path.starts_with("@/") {
|
if path.starts_with("@/") {
|
||||||
let path_with_lang = match make_path_with_lang(path, &lang, &self.config) {
|
let path_with_lang = match make_path_with_lang(path, &lang, &self.config) {
|
||||||
|
@ -91,10 +87,11 @@ impl TeraFn for GetUrl {
|
||||||
|
|
||||||
match resolve_internal_link(&path_with_lang, &self.permalinks) {
|
match resolve_internal_link(&path_with_lang, &self.permalinks) {
|
||||||
Ok(resolved) => Ok(to_value(resolved.permalink).unwrap()),
|
Ok(resolved) => Ok(to_value(resolved.permalink).unwrap()),
|
||||||
Err(_) => {
|
Err(_) => Err(format!(
|
||||||
Err(format!("Could not resolve URL for link `{}` not found.", path_with_lang)
|
"`get_url`: could not resolve URL for link `{}` not found.",
|
||||||
.into())
|
path_with_lang
|
||||||
}
|
)
|
||||||
|
.into()),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// anything else
|
// anything else
|
||||||
|
@ -115,6 +112,7 @@ impl TeraFn for GetUrl {
|
||||||
|
|
||||||
if cachebust {
|
if cachebust {
|
||||||
match search_for_file(&self.base_path, &path_with_lang)
|
match search_for_file(&self.base_path, &path_with_lang)
|
||||||
|
.map_err(|e| format!("`get_url`: {}", e))?
|
||||||
.and_then(|(p, _)| fs::File::open(&p).ok())
|
.and_then(|(p, _)| fs::File::open(&p).ok())
|
||||||
.and_then(|f| compute_file_hash::<Sha256>(f, false).ok())
|
.and_then(|f| compute_file_hash::<Sha256>(f, false).ok())
|
||||||
{
|
{
|
||||||
|
@ -122,7 +120,11 @@ impl TeraFn for GetUrl {
|
||||||
permalink = format!("{}?h={}", permalink, hash);
|
permalink = format!("{}?h={}", permalink, hash);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return Err(format!("Could not find or open file {}", path_with_lang).into())
|
return Err(format!(
|
||||||
|
"`get_url`: Could not find or open file {}",
|
||||||
|
path_with_lang
|
||||||
|
)
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -166,7 +168,9 @@ impl TeraFn for GetFileHash {
|
||||||
)
|
)
|
||||||
.unwrap_or(true);
|
.unwrap_or(true);
|
||||||
|
|
||||||
let file_path = match search_for_file(&self.base_path, &path) {
|
let file_path = match search_for_file(&self.base_path, &path)
|
||||||
|
.map_err(|e| format!("`get_file_hash`: {}", e))?
|
||||||
|
{
|
||||||
Some((f, _)) => f,
|
Some((f, _)) => f,
|
||||||
None => {
|
None => {
|
||||||
return Err(format!("`get_file_hash`: Cannot find file: {}", path).into());
|
return Err(format!("`get_file_hash`: Cannot find file: {}", path).into());
|
||||||
|
@ -262,6 +266,10 @@ title = "A title"
|
||||||
let mut args = HashMap::new();
|
let mut args = HashMap::new();
|
||||||
args.insert("path".to_string(), to_value("app.css").unwrap());
|
args.insert("path".to_string(), to_value("app.css").unwrap());
|
||||||
assert_eq!(static_fn.call(&args).unwrap(), "http://a-website.com/app.css");
|
assert_eq!(static_fn.call(&args).unwrap(), "http://a-website.com/app.css");
|
||||||
|
|
||||||
|
let mut args = HashMap::new();
|
||||||
|
args.insert("path".to_string(), to_value("/app.css").unwrap());
|
||||||
|
assert_eq!(static_fn.call(&args).unwrap(), "http://a-website.com/app.css");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -431,7 +439,6 @@ title = "A title"
|
||||||
let mut args = HashMap::new();
|
let mut args = HashMap::new();
|
||||||
args.insert("path".to_string(), to_value("doesnt-exist").unwrap());
|
args.insert("path".to_string(), to_value("doesnt-exist").unwrap());
|
||||||
let err = format!("{}", static_fn.call(&args).unwrap_err());
|
let err = format!("{}", static_fn.call(&args).unwrap_err());
|
||||||
println!("{:?}", err);
|
|
||||||
|
|
||||||
assert!(err.contains("Cannot find file"));
|
assert!(err.contains("Cannot find file"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use errors::{bail, Result};
|
||||||
|
use utils::fs::is_path_in_directory;
|
||||||
|
|
||||||
/// This is used by a few Tera functions to search for files on the filesystem.
|
/// This is used by a few Tera functions to search for files on the filesystem.
|
||||||
/// This does try to find the file in 3 different spots:
|
/// This does try to find the file in 3 different spots:
|
||||||
/// 1. base_path + path
|
/// 1. base_path + path
|
||||||
|
@ -9,16 +12,22 @@ use std::path::{Path, PathBuf};
|
||||||
/// A path starting with @/ will replace it with `content/` and a path starting with `/` will have
|
/// A path starting with @/ will replace it with `content/` and a path starting with `/` will have
|
||||||
/// it removed.
|
/// it removed.
|
||||||
/// It also returns the unified path so it can be used as unique hash for a given file.
|
/// It also returns the unified path so it can be used as unique hash for a given file.
|
||||||
pub fn search_for_file(base_path: &Path, path: &str) -> Option<(PathBuf, String)> {
|
/// It will error if the file is not contained in the Zola directory.
|
||||||
|
pub fn search_for_file(base_path: &Path, path: &str) -> Result<Option<(PathBuf, String)>> {
|
||||||
let search_paths = [base_path.join("static"), base_path.join("content")];
|
let search_paths = [base_path.join("static"), base_path.join("content")];
|
||||||
let actual_path = if path.starts_with("@/") {
|
let actual_path = if path.starts_with("@/") {
|
||||||
Cow::Owned(path.replace("@/", "content/"))
|
Cow::Owned(path.replace("@/", "content/"))
|
||||||
} else {
|
} else {
|
||||||
Cow::Borrowed(path.trim_start_matches('/'))
|
Cow::Borrowed(path.trim_start_matches('/'))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut file_path = base_path.join(&*actual_path);
|
let mut file_path = base_path.join(&*actual_path);
|
||||||
let mut file_exists = file_path.exists();
|
let mut file_exists = file_path.exists();
|
||||||
|
|
||||||
|
if file_exists && !is_path_in_directory(base_path, &file_path)? {
|
||||||
|
bail!("{:?} is not inside the base site directory {:?}", path, base_path);
|
||||||
|
}
|
||||||
|
|
||||||
if !file_exists {
|
if !file_exists {
|
||||||
// we need to search in both search folders now
|
// we need to search in both search folders now
|
||||||
for dir in &search_paths {
|
for dir in &search_paths {
|
||||||
|
@ -32,8 +41,8 @@ pub fn search_for_file(base_path: &Path, path: &str) -> Option<(PathBuf, String)
|
||||||
}
|
}
|
||||||
|
|
||||||
if file_exists {
|
if file_exists {
|
||||||
Some((file_path, actual_path.into_owned()))
|
Ok(Some((file_path, actual_path.into_owned())))
|
||||||
} else {
|
} else {
|
||||||
None
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,9 @@ impl TeraFn for ResizeImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut imageproc = self.imageproc.lock().unwrap();
|
let mut imageproc = self.imageproc.lock().unwrap();
|
||||||
let (file_path, unified_path) = match search_for_file(&self.base_path, &path) {
|
let (file_path, unified_path) = match search_for_file(&self.base_path, &path)
|
||||||
|
.map_err(|e| format!("`resize_image`: {}", e))?
|
||||||
|
{
|
||||||
Some(f) => f,
|
Some(f) => f,
|
||||||
None => {
|
None => {
|
||||||
return Err(format!("`resize_image`: Cannot find file: {}", path).into());
|
return Err(format!("`resize_image`: Cannot find file: {}", path).into());
|
||||||
|
@ -95,14 +97,15 @@ impl TeraFn for GetImageMetadata {
|
||||||
"`get_image_metadata`: `allow_missing` must be a boolean (true or false)"
|
"`get_image_metadata`: `allow_missing` must be a boolean (true or false)"
|
||||||
)
|
)
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
let (src_path, _) = match search_for_file(&self.base_path, &path) {
|
let (src_path, _) = match search_for_file(&self.base_path, &path)
|
||||||
|
.map_err(|e| format!("`get_image_metadata`: {}", e))?
|
||||||
|
{
|
||||||
Some((f, p)) => (f, p),
|
Some((f, p)) => (f, p),
|
||||||
None => {
|
None => {
|
||||||
if allow_missing {
|
if allow_missing {
|
||||||
println!("Image at path {} could not be found or loaded", path);
|
|
||||||
return Ok(Value::Null);
|
return Ok(Value::Null);
|
||||||
}
|
}
|
||||||
return Err(format!("`resize_image`: Cannot find path: {}", path).into());
|
return Err(format!("`get_image_metadata`: Cannot find path: {}", path).into());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use reqwest::{blocking::Client, header};
|
||||||
use tera::{from_value, to_value, Error, Function as TeraFn, Map, Result, Value};
|
use tera::{from_value, to_value, Error, Function as TeraFn, Map, Result, Value};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use utils::de::fix_toml_dates;
|
use utils::de::fix_toml_dates;
|
||||||
use utils::fs::{get_file_time, is_path_in_directory, read_file};
|
use utils::fs::{get_file_time, read_file};
|
||||||
|
|
||||||
use crate::global_fns::helpers::search_for_file;
|
use crate::global_fns::helpers::search_for_file;
|
||||||
|
|
||||||
|
@ -94,7 +94,9 @@ impl DataSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(path) = path_arg {
|
if let Some(path) = path_arg {
|
||||||
return match search_for_file(&base_path, &path) {
|
return match search_for_file(&base_path, &path)
|
||||||
|
.map_err(|e| format!("`load_data`: {}", e))?
|
||||||
|
{
|
||||||
Some((f, _)) => Ok(Some(DataSource::Path(f))),
|
Some((f, _)) => Ok(Some(DataSource::Path(f))),
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
};
|
};
|
||||||
|
@ -104,7 +106,7 @@ impl DataSource {
|
||||||
return Url::parse(&url)
|
return Url::parse(&url)
|
||||||
.map(DataSource::Url)
|
.map(DataSource::Url)
|
||||||
.map(Some)
|
.map(Some)
|
||||||
.map_err(|e| format!("Failed to parse {} as url: {}", url, e).into());
|
.map_err(|e| format!("`load_data`: Failed to parse {} as url: {}", url, e).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(GET_DATA_ARGUMENT_ERROR_MESSAGE.into())
|
Err(GET_DATA_ARGUMENT_ERROR_MESSAGE.into())
|
||||||
|
@ -139,21 +141,6 @@ impl Hash for DataSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_local_data_file(base_path: &Path, full_path: PathBuf) -> Result<String> {
|
|
||||||
if !is_path_in_directory(&base_path, &full_path)
|
|
||||||
.map_err(|e| format!("Failed to read data file {}: {}", full_path.display(), e))?
|
|
||||||
{
|
|
||||||
return Err(format!(
|
|
||||||
"{:?} is not inside the base site directory {:?}",
|
|
||||||
full_path, base_path
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
read_file(&full_path)
|
|
||||||
.map_err(|e| format!("`load_data`: error reading file {:?}: {}", full_path, e).into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_output_format_from_args(
|
fn get_output_format_from_args(
|
||||||
format_arg: Option<String>,
|
format_arg: Option<String>,
|
||||||
data_source: &DataSource,
|
data_source: &DataSource,
|
||||||
|
@ -235,21 +222,24 @@ impl TeraFn for LoadData {
|
||||||
|
|
||||||
// If the file doesn't exist, source is None
|
// If the file doesn't exist, source is None
|
||||||
let data_source =
|
let data_source =
|
||||||
match (DataSource::from_args(path_arg.clone(), url_arg, &self.base_path)?, required) {
|
match (DataSource::from_args(path_arg.clone(), url_arg, &self.base_path), required) {
|
||||||
// If the file was not required, return a Null value to the template
|
// If the file was not required, return a Null value to the template
|
||||||
(None, false) => {
|
(Ok(None), false) | (Err(_), false) => {
|
||||||
return Ok(Value::Null);
|
return Ok(Value::Null);
|
||||||
}
|
}
|
||||||
|
(Err(e), true) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
// If the file was required, error
|
// If the file was required, error
|
||||||
(None, true) => {
|
(Ok(None), true) => {
|
||||||
// source is None only with path_arg (not URL), so path_arg is safely unwrap
|
// source is None only with path_arg (not URL), so path_arg is safely unwrap
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"{} doesn't exist",
|
"`load_data`: {} doesn't exist",
|
||||||
&self.base_path.join(path_arg.unwrap()).display()
|
&self.base_path.join(path_arg.unwrap()).display()
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
(Some(data_source), _) => data_source,
|
(Ok(Some(data_source)), _) => data_source,
|
||||||
};
|
};
|
||||||
|
|
||||||
let file_format = get_output_format_from_args(format_arg, &data_source)?;
|
let file_format = get_output_format_from_args(format_arg, &data_source)?;
|
||||||
|
@ -262,7 +252,8 @@ impl TeraFn for LoadData {
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = match data_source {
|
let data = match data_source {
|
||||||
DataSource::Path(path) => read_local_data_file(&self.base_path, path),
|
DataSource::Path(path) => read_file(&path)
|
||||||
|
.map_err(|e| format!("`load_data`: error reading file {:?}: {}", path, e)),
|
||||||
DataSource::Url(url) => {
|
DataSource::Url(url) => {
|
||||||
let response_client = self.client.lock().expect("response client lock");
|
let response_client = self.client.lock().expect("response client lock");
|
||||||
let req = match method {
|
let req = match method {
|
||||||
|
@ -280,7 +271,7 @@ impl TeraFn for LoadData {
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"{} is an illegal content type",
|
"`load_data`: {} is an illegal content type",
|
||||||
&content_type
|
&content_type
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
|
@ -296,7 +287,7 @@ impl TeraFn for LoadData {
|
||||||
|
|
||||||
match req.send().and_then(|res| res.error_for_status()) {
|
match req.send().and_then(|res| res.error_for_status()) {
|
||||||
Ok(r) => r.text().map_err(|e| {
|
Ok(r) => r.text().map_err(|e| {
|
||||||
format!("Failed to parse response from {}: {:?}", url, e).into()
|
format!("`load_data`: Failed to parse response from {}: {:?}", url, e)
|
||||||
}),
|
}),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if !required {
|
if !required {
|
||||||
|
@ -305,10 +296,14 @@ impl TeraFn for LoadData {
|
||||||
return Ok(Value::Null);
|
return Ok(Value::Null);
|
||||||
}
|
}
|
||||||
Err(match e.status() {
|
Err(match e.status() {
|
||||||
Some(status) => format!("Failed to request {}: {}", url, status),
|
Some(status) => {
|
||||||
None => format!("Could not get response status for url: {}", url),
|
format!("`load_data`: Failed to request {}: {}", url, status)
|
||||||
}
|
}
|
||||||
.into())
|
None => format!(
|
||||||
|
"`load_data`: Could not get response status for url: {}",
|
||||||
|
url
|
||||||
|
),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -634,13 +629,14 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cannot_load_outside_content_dir() {
|
fn cannot_load_outside_base_dir() {
|
||||||
let static_fn = LoadData::new(PathBuf::from(PathBuf::from("../utils")));
|
let static_fn = LoadData::new(PathBuf::from(PathBuf::from("../utils")));
|
||||||
let mut args = HashMap::new();
|
let mut args = HashMap::new();
|
||||||
args.insert("path".to_string(), to_value("../../README.md").unwrap());
|
args.insert("path".to_string(), to_value("../../README.md").unwrap());
|
||||||
args.insert("format".to_string(), to_value("plain").unwrap());
|
args.insert("format".to_string(), to_value("plain").unwrap());
|
||||||
let result = static_fn.call(&args);
|
let result = static_fn.call(&args);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
println!("{:?} {:?}", std::env::current_dir(), result);
|
||||||
assert!(result.unwrap_err().to_string().contains("is not inside the base site directory"));
|
assert!(result.unwrap_err().to_string().contains("is not inside the base site directory"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -736,7 +732,7 @@ mod tests {
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().to_string(),
|
result.unwrap_err().to_string(),
|
||||||
format!("Failed to request {}: 404 Not Found", url)
|
format!("`load_data`: Failed to request {}: 404 Not Found", url)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,21 +82,36 @@ Encode the variable to base64.
|
||||||
Decode the variable from base64.
|
Decode the variable from base64.
|
||||||
|
|
||||||
|
|
||||||
## Built-in global functions
|
## Built-in functions
|
||||||
|
|
||||||
Zola adds a few global functions to [those in Tera](https://tera.netlify.com/docs#built-in-functions)
|
Zola adds a few Tera functions to [those built-in in Tera](https://tera.netlify.com/docs#built-in-functions)
|
||||||
to make it easier to develop complex sites.
|
to make it easier to develop complex sites.
|
||||||
|
|
||||||
|
### File searching logic
|
||||||
|
For functions that are searching for a file on disk other than through `get_page` and `get_section`, the following
|
||||||
|
logic applies.
|
||||||
|
|
||||||
|
1. The base directory is the Zola root directory, where the `config.toml` is
|
||||||
|
2. For the given path: if it starts with `@/`, replace that with `content/` instead and trim any leading `/`
|
||||||
|
3. Search in the following 3 locations in this order, returning the first where the file exists:
|
||||||
|
a. $base_directory + $path
|
||||||
|
b. $base_directory + "static/" + $path
|
||||||
|
c. $base_directory + "content/" + $path
|
||||||
|
|
||||||
|
In practice this means that `@/some/image.jpg`, `/content/some/image.jpg` and `content/some/image.jpg` will point to the
|
||||||
|
same thing.
|
||||||
|
|
||||||
|
It will error if the path is outside the Zola directory.
|
||||||
|
|
||||||
### `get_page`
|
### `get_page`
|
||||||
Takes a path to an `.md` file and returns the associated page.
|
Takes a path to an `.md` file and returns the associated page. The base path is the `content` directory.
|
||||||
|
|
||||||
```jinja2
|
```jinja2
|
||||||
{% set page = get_page(path="blog/page2.md") %}
|
{% set page = get_page(path="blog/page2.md") %}
|
||||||
```
|
```
|
||||||
|
|
||||||
### `get_section`
|
### `get_section`
|
||||||
Takes a path to an `_index.md` file and returns the associated section.
|
Takes a path to an `_index.md` file and returns the associated section. The base path is the `content` directory.
|
||||||
|
|
||||||
```jinja2
|
```jinja2
|
||||||
{% set section = get_section(path="blog/_index.md") %}
|
{% set section = get_section(path="blog/_index.md") %}
|
||||||
|
@ -108,78 +123,6 @@ If you only need the metadata of the section, you can pass `metadata_only=true`
|
||||||
{% set section = get_section(path="blog/_index.md", metadata_only=true) %}
|
{% set section = get_section(path="blog/_index.md", metadata_only=true) %}
|
||||||
```
|
```
|
||||||
|
|
||||||
### `get_url`
|
|
||||||
Gets the permalink for the given path.
|
|
||||||
If the path starts with `@/`, it will be treated as an internal
|
|
||||||
link like the ones used in Markdown, starting from the root `content` directory.
|
|
||||||
|
|
||||||
```jinja2
|
|
||||||
{% set url = get_url(path="@/blog/_index.md") %}
|
|
||||||
```
|
|
||||||
|
|
||||||
It accepts an optional parameter `lang` in order to compute a *language-aware URL* in multilingual websites. Assuming `config.base_url` is `"http://example.com"`, the following snippet will:
|
|
||||||
|
|
||||||
- return `"http://example.com/blog/"` if `config.default_language` is `"en"`
|
|
||||||
- return `"http://example.com/en/blog/"` if `config.default_language` is **not** `"en"` and `"en"` appears in `config.languages`
|
|
||||||
- fail otherwise, with the error message `"'en' is not an authorized language (check config.languages)."`
|
|
||||||
|
|
||||||
```jinja2
|
|
||||||
{% set url = get_url(path="@/blog/_index.md", lang="en") %}
|
|
||||||
```
|
|
||||||
|
|
||||||
This can also be used to get the permalinks for static assets, for example if
|
|
||||||
we want to link to the file that is located at `static/css/app.css`:
|
|
||||||
|
|
||||||
```jinja2
|
|
||||||
{{/* get_url(path="css/app.css") */}}
|
|
||||||
```
|
|
||||||
|
|
||||||
By default, assets will not have a trailing slash. You can force one by passing `trailing_slash=true` to the `get_url` function.
|
|
||||||
An example is:
|
|
||||||
|
|
||||||
```jinja2
|
|
||||||
{{/* get_url(path="css/app.css", trailing_slash=true) */}}
|
|
||||||
```
|
|
||||||
|
|
||||||
In the case of non-internal links, you can also add a cachebust of the format `?h=<sha256>` at the end of a URL
|
|
||||||
by passing `cachebust=true` to the `get_url` function.
|
|
||||||
|
|
||||||
### `get_file_hash`
|
|
||||||
|
|
||||||
Returns the hash digest of a static file. Supported hashing algorithms are
|
|
||||||
SHA-256, SHA-384 (default) and SHA-512. Requires `path`. The `sha_type`
|
|
||||||
parameter is optional and must be one of 256, 384 or 512.
|
|
||||||
|
|
||||||
```jinja2
|
|
||||||
{{/* get_file_hash(path="js/app.js", sha_type=256) */}}
|
|
||||||
```
|
|
||||||
|
|
||||||
The function can also output a base64-encoded hash value when its `base64`
|
|
||||||
parameter is set to `true`. This can be used to implement [subresource
|
|
||||||
integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity).
|
|
||||||
|
|
||||||
```jinja2
|
|
||||||
<script src="{{/* get_url(path="js/app.js") */}}"
|
|
||||||
integrity="sha384-{{ get_file_hash(path="js/app.js", sha_type=384, base64=true) | safe }}"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
Do note that subresource integrity is typically used when using external
|
|
||||||
scripts, which `get_file_hash` does not support.
|
|
||||||
|
|
||||||
Whenever hashing files, whether using `get_file_hash` or `get_url(...,
|
|
||||||
cachebust=true)`, the file is searched for in three places: `static/`,
|
|
||||||
`content/` and the output path (so e.g. compiled SASS can be hashed, too.)
|
|
||||||
|
|
||||||
### `get_image_metadata`
|
|
||||||
|
|
||||||
Gets metadata for an image. This supports common formats like JPEG, PNG, as well as SVG.
|
|
||||||
Currently, the only supported keys are `width` and `height`.
|
|
||||||
|
|
||||||
```jinja2
|
|
||||||
{% set meta = get_image_metadata(path="...") %}
|
|
||||||
Our image is {{ meta.width }}x{{ meta.height }}
|
|
||||||
```
|
|
||||||
|
|
||||||
### `get_taxonomy_url`
|
### `get_taxonomy_url`
|
||||||
Gets the permalink for the taxonomy item found.
|
Gets the permalink for the taxonomy item found.
|
||||||
|
|
||||||
|
@ -208,12 +151,88 @@ items: Array<TaxonomyTerm>;
|
||||||
|
|
||||||
See the [Taxonomies documentation](@/documentation/templates/taxonomies.md) for a full documentation of those types.
|
See the [Taxonomies documentation](@/documentation/templates/taxonomies.md) for a full documentation of those types.
|
||||||
|
|
||||||
|
### `get_url`
|
||||||
|
Gets the permalink for the given path.
|
||||||
|
If the path starts with `@/`, it will be treated as an internal link like the ones used in Markdown,
|
||||||
|
starting from the root `content` directory as well as validated.
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% set url = get_url(path="@/blog/_index.md") %}
|
||||||
|
```
|
||||||
|
|
||||||
|
It accepts an optional parameter `lang` in order to compute a *language-aware URL* in multilingual websites. Assuming `config.base_url` is `"http://example.com"`, the following snippet will:
|
||||||
|
|
||||||
|
- return `"http://example.com/blog/"` if `config.default_language` is `"en"`
|
||||||
|
- return `"http://example.com/en/blog/"` if `config.default_language` is **not** `"en"` and `"en"` appears in `config.languages`
|
||||||
|
- fail otherwise, with the error message `"'en' is not an authorized language (check config.languages)."`
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% set url = get_url(path="@/blog/_index.md", lang="en") %}
|
||||||
|
```
|
||||||
|
|
||||||
|
This can also be used to get the permalinks for static assets, for example if
|
||||||
|
we want to link to the file that is located at `static/css/app.css`:
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{{/* get_url(path="static/css/app.css") */}}
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, assets will not have a trailing slash. You can force one by passing `trailing_slash=true` to the `get_url` function.
|
||||||
|
An example is:
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{{/* get_url(path="static/css/app.css", trailing_slash=true) */}}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the case of non-internal links, you can also add a cachebust of the format `?h=<sha256>` at the end of a URL
|
||||||
|
by passing `cachebust=true` to the `get_url` function. In this case, the path will need to resolve to an actual file.
|
||||||
|
See [File Searching Logic](@/documentation/templates/overview.md#file-searching-logic) for details.
|
||||||
|
|
||||||
|
### `get_file_hash`
|
||||||
|
|
||||||
|
Returns the hash digest (SHA-256, SHA-384 or SHA-512) of a file.
|
||||||
|
|
||||||
|
It can take the following arguments:
|
||||||
|
- `path`: mandatory, see [File Searching Logic](@/documentation/templates/overview.md#file-searching-logic) for details
|
||||||
|
- `sha_type`: optional, one of `256`, `384` or `512`, defaults to `384`
|
||||||
|
- `base64`: optional, `true` or `false`, defaults to `true`. Whether to encode the hash as base64
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{{/* get_file_hash(path="static/js/app.js", sha_type=256) */}}
|
||||||
|
```
|
||||||
|
|
||||||
|
The function can also output a base64-encoded hash value when its `base64`
|
||||||
|
parameter is set to `true`. This can be used to implement [subresource
|
||||||
|
integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity).
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
<script src="{{/* get_url(path="static/js/app.js") */}}"
|
||||||
|
integrity="sha384-{{ get_file_hash(path="static/js/app.js", sha_type=384, base64=true) | safe }}"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
Do note that subresource integrity is typically used when using external scripts, which `get_file_hash` does not support.
|
||||||
|
|
||||||
|
### `get_image_metadata`
|
||||||
|
|
||||||
|
Gets metadata for an image. This supports common formats like JPEG, PNG, WebP, BMP, GIF as well as SVG.
|
||||||
|
|
||||||
|
It can take the following arguments:
|
||||||
|
|
||||||
|
- `path`: mandatory, see [File Searching Logic](@/documentation/templates/overview.md#file-searching-logic) for details
|
||||||
|
- `allow_missing`: optional, `true` or `false`, defaults to `false`. Whether a missing file should raise an error or not.
|
||||||
|
|
||||||
|
The method returns a map containing `width`, `height` and `format` (the lowercased value as string).
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% set meta = get_image_metadata(path="...") %}
|
||||||
|
Our image (.{{meta.format}}) has format is {{ meta.width }}x{{ meta.height }}
|
||||||
|
```
|
||||||
|
|
||||||
### `load_data`
|
### `load_data`
|
||||||
Loads data from a file or URL. Supported file types include *toml*, *json*, *csv* and *bibtex*.
|
Loads data from a file or URL. Supported file types include *toml*, *json*, *csv* and *bibtex*.
|
||||||
Any other file type will be loaded as plain text.
|
Any other file type will be loaded as plain text.
|
||||||
|
|
||||||
The `path` argument specifies the path to the data file relative to your base directory, where your `config.toml` is.
|
The `path` argument specifies the path to the data file, according to the [File Searching Logic](@/documentation/templates/overview.md#file-searching-logic).
|
||||||
As a security precaution, if this file is outside the main site directory, your site will fail to build.
|
|
||||||
|
|
||||||
```jinja2
|
```jinja2
|
||||||
{% set data = load_data(path="content/blog/story/data.toml") %}
|
{% set data = load_data(path="content/blog/story/data.toml") %}
|
||||||
|
|
Loading…
Reference in a new issue