├── .editorconfig ├── .github ├── FUNDING.yml └── workflows │ ├── php-cs-fixer.yml │ ├── run-tests.yml │ └── update-changelog.yml ├── .php-cs-fixer.dist.php ├── CHANGELOG.md ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml └── src ├── Arr.php ├── ComplexMarkdownParser.php ├── Document.php └── YamlFrontMatter.php /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_size = 4 9 | indent_style = space 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: spatie 2 | custom: https://spatie.be/open-source/support-us 3 | -------------------------------------------------------------------------------- /.github/workflows/php-cs-fixer.yml: -------------------------------------------------------------------------------- 1 | name: Check & fix styling 2 | 3 | on: [ push ] 4 | 5 | jobs: 6 | php-cs-fixer: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout code 11 | uses: actions/checkout@v2 12 | with: 13 | ref: ${{ github.head_ref }} 14 | 15 | - name: Run PHP CS Fixer 16 | uses: docker://oskarstark/php-cs-fixer-ga 17 | with: 18 | args: --config=.php-cs-fixer.dist.php --allow-risky=yes 19 | 20 | - name: Commit changes 21 | uses: stefanzweifel/git-auto-commit-action@v4 22 | with: 23 | commit_message: Fix styling 24 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: run-tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | os: [ubuntu-latest, windows-latest] 12 | php: [8.4, 8.3, 8.2, 8.1, 8.0] 13 | dependency-version: [prefer-lowest, prefer-stable] 14 | 15 | name: P${{ matrix.php }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} 16 | 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@v2 20 | 21 | - name: Setup PHP 22 | uses: shivammathur/setup-php@v2 23 | with: 24 | php-version: ${{ matrix.php }} 25 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo 26 | coverage: none 27 | 28 | - name: Install dependencies 29 | run: composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction 30 | 31 | - name: Execute tests 32 | run: vendor/bin/phpunit 33 | -------------------------------------------------------------------------------- /.github/workflows/update-changelog.yml: -------------------------------------------------------------------------------- 1 | name: "Update Changelog" 2 | 3 | on: 4 | release: 5 | types: [released] 6 | 7 | jobs: 8 | update: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v2 14 | with: 15 | ref: main 16 | 17 | - name: Update Changelog 18 | uses: stefanzweifel/changelog-updater-action@v1 19 | with: 20 | latest-version: ${{ github.event.release.name }} 21 | release-notes: ${{ github.event.release.body }} 22 | 23 | - name: Commit updated CHANGELOG 24 | uses: stefanzweifel/git-auto-commit-action@v4 25 | with: 26 | branch: main 27 | commit_message: Update CHANGELOG 28 | file_pattern: CHANGELOG.md 29 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | notPath('bootstrap/*') 5 | ->notPath('storage/*') 6 | ->notPath('resources/view/mail/*') 7 | ->in([ 8 | __DIR__ . '/src', 9 | __DIR__ . '/tests', 10 | ]) 11 | ->name('*.php') 12 | ->notName('*.blade.php') 13 | ->ignoreDotFiles(true) 14 | ->ignoreVCS(true); 15 | 16 | return (new PhpCsFixer\Config) 17 | ->setRules([ 18 | '@PSR2' => true, 19 | 'array_syntax' => ['syntax' => 'short'], 20 | 'ordered_imports' => ['sort_algorithm' => 'alpha'], 21 | 'no_unused_imports' => true, 22 | 'not_operator_with_successor_space' => true, 23 | 'trailing_comma_in_multiline' => true, 24 | 'phpdoc_scalar' => true, 25 | 'unary_operator_spaces' => true, 26 | 'binary_operator_spaces' => true, 27 | 'blank_line_before_statement' => [ 28 | 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], 29 | ], 30 | 'phpdoc_single_line_var_spacing' => true, 31 | 'phpdoc_var_without_name' => true, 32 | 'method_argument_space' => [ 33 | 'on_multiline' => 'ensure_fully_multiline', 34 | 'keep_multiple_spaces_after_comma' => true, 35 | ] 36 | ]) 37 | ->setFinder($finder); 38 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All Notable changes to `yaml-front-matter` will be documented in this file 4 | 5 | ## 2.1.0 - 2024-12-02 6 | 7 | ### What's Changed 8 | 9 | * PHP 8.4 support by @brendt in https://github.com/spatie/yaml-front-matter/pull/42 10 | * Drop PHP 7 support 11 | 12 | ### New Contributors 13 | 14 | * @brendt made their first contribution in https://github.com/spatie/yaml-front-matter/pull/42 15 | 16 | **Full Changelog**: https://github.com/spatie/yaml-front-matter/compare/2.0.9...2.1.0 17 | 18 | ## 2.0.9 - 2024-06-13 19 | 20 | ### What's Changed 21 | 22 | * Check if the array key is set before trying to trim it by @caendesilva in https://github.com/spatie/yaml-front-matter/pull/41 23 | 24 | **Full Changelog**: https://github.com/spatie/yaml-front-matter/compare/2.0.8...2.0.9 25 | 26 | ## 2.0.8 - 2023-12-04 27 | 28 | ### What's Changed 29 | 30 | * Add PHP 8.2 Support by @patinthehat in https://github.com/spatie/yaml-front-matter/pull/39 31 | * Support Symfony 7 by @RobinDev in https://github.com/spatie/yaml-front-matter/pull/40 32 | 33 | ### New Contributors 34 | 35 | * @RobinDev made their first contribution in https://github.com/spatie/yaml-front-matter/pull/40 36 | 37 | **Full Changelog**: https://github.com/spatie/yaml-front-matter/compare/2.0.7...2.0.8 38 | 39 | ## 2.0.7 - 2022-04-06 40 | 41 | ## What's Changed 42 | 43 | - Fix #30, bug where the package cannot properly parse a file that contains Markdown code blocks with front matter in them by @caendesilva in https://github.com/spatie/yaml-front-matter/pull/38 44 | 45 | ## New Contributors 46 | 47 | - @caendesilva made their first contribution in https://github.com/spatie/yaml-front-matter/pull/38 48 | 49 | **Full Changelog**: https://github.com/spatie/yaml-front-matter/compare/2.0.6...2.0.7 50 | 51 | ## 2.0.6 - 2021-12-22 52 | 53 | - Support Symfony 6 54 | 55 | **Full Changelog**: https://github.com/spatie/yaml-front-matter/compare/2.0.5...2.0.6 56 | 57 | ## 2.0.6 - 2021-12-22 58 | 59 | - Support Symfony 6 60 | 61 | ## 2.0.5 - 2019-12-02 62 | 63 | - Allow Symfony 5 (#20) 64 | 65 | ## 2.0.4 - 2019-09-12 66 | 67 | - Remove `illuminate/support` dependency 68 | 69 | ## 2.0.3 - 2019-09-04 70 | 71 | - Allow `illuminate/support:^6.0` 72 | 73 | ## 2.0.2 - 2018-02-23 74 | 75 | - Fix for documents with no newline after front matter 76 | 77 | ## 2.0.1 - 2017-09-04 78 | 79 | - Fix for documents with empty front matter 80 | 81 | ## 2.0.0 - 2017-08-21 82 | 83 | - Renamed `Parser` class to `YamlFrontMatter` 84 | - `parse` and `parseFile` are now static methods 85 | - `Document` now has a `__get` implementation for retrieving front matter 86 | 87 | ## 1.1.0 - 2017-07-12 88 | 89 | - Added `parseFile` 90 | 91 | ## 1.0.1 - 2016-01-27 92 | 93 | - Parser regex improvements 94 | 95 | ## 1.0.0 - 2016-01-14 96 | 97 | - First release 98 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Spatie bvba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [](https://supportukrainenow.org) 3 | 4 | # yaml-front-matter 5 | 6 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/yaml-front-matter.svg?style=flat-square)](https://packagist.org/packages/spatie/yaml-front-matter) 7 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 8 | [![Build Status](https://img.shields.io/travis/spatie/yaml-front-matter/master.svg?style=flat-square)](https://travis-ci.org/spatie/yaml-front-matter) 9 | [![Quality Score](https://img.shields.io/scrutinizer/g/spatie/yaml-front-matter.svg?style=flat-square)](https://scrutinizer-ci.com/g/spatie/yaml-front-matter) 10 | [![Total Downloads](https://img.shields.io/packagist/dt/spatie/yaml-front-matter.svg?style=flat-square)](https://packagist.org/packages/spatie/yaml-front-matter) 11 | 12 | A to the point front matter parser. Front matter is metadata written in yaml, located at the top of a file wrapped in `---`'s. 13 | 14 | ```md 15 | --- 16 | title: Example 17 | --- 18 | 19 | Lorem ipsum. 20 | ``` 21 | 22 | ```php 23 | use Spatie\YamlFrontMatter\YamlFrontMatter; 24 | 25 | $object = YamlFrontMatter::parse(file_get_contents(__DIR__.'/example.md')); 26 | 27 | $object->matter('title'); // => 'Example'; 28 | $object->body(); // => 'Lorem ipsum.' 29 | 30 | // Or retrieve front matter with a property call... 31 | 32 | $object->title; // => 'Example'; 33 | ``` 34 | 35 | Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects [on our website](https://spatie.be/opensource). 36 | 37 | ## Support us 38 | 39 | [](https://spatie.be/github-ad-click/yaml-front-matter) 40 | 41 | We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). 42 | 43 | We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). 44 | 45 | ## Install 46 | 47 | You can install the `yaml-front-matter` via composer: 48 | 49 | ``` bash 50 | $ composer require spatie/yaml-front-matter 51 | ``` 52 | 53 | ## Usage 54 | 55 | Consider the `example.md` file from above. First you'll need to parse the contents: 56 | 57 | ```php 58 | use Spatie\YamlFrontMatter\YamlFrontMatter; 59 | $object = YamlFrontMatter::parse(file_get_contents('example.md')); 60 | ``` 61 | 62 | The parser will return a `YamlFrontMatterObject`, which can be queried for front matter or it's body. 63 | 64 | ```php 65 | $object->matter(); // => ['title' => 'Example'] 66 | $object->matter('title'); // => 'Example' 67 | $object->body(); // => 'Lorem ipsum.' 68 | $object->title; // => 'Example' 69 | ``` 70 | 71 | **Protip**: The `matter` function also accepts dot notation for nested fields, e.g. `matter('meta.keywords')`. 72 | 73 | ## Changelog 74 | 75 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. 76 | 77 | ## Testing 78 | 79 | ``` bash 80 | $ vendor/bin/phpunit 81 | ``` 82 | 83 | ## Contributing 84 | 85 | Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details. 86 | 87 | ## Security 88 | 89 | If you've found a bug regarding security please mail [security@spatie.be](mailto:security@spatie.be) instead of using the issue tracker. 90 | 91 | ## Postcardware 92 | 93 | You're free to use this package, but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. 94 | 95 | Our address is: Spatie, Kruikstraat 22, 2018 Antwerp, Belgium. 96 | 97 | We publish all received postcards [on our company website](https://spatie.be/en/opensource/postcards). 98 | 99 | ## Credits 100 | 101 | - [Sebastian De Deyne](https://github.com/:author_username) 102 | - [All Contributors](../../contributors) 103 | 104 | ## License 105 | 106 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 107 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spatie/yaml-front-matter", 3 | "description": "A to the point yaml front matter parser", 4 | "keywords": [ 5 | "spatie", 6 | "yaml", 7 | "front matter", 8 | "jekyll" 9 | ], 10 | "homepage": "https://github.com/sebastiandedeyne/yaml-front-matter", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Sebastian De Deyne", 15 | "email": "sebastian@spatie.be", 16 | "homepage": "https://spatie.be", 17 | "role": "Developer" 18 | } 19 | ], 20 | "require": { 21 | "php": "^8.0", 22 | "symfony/yaml": "^6.0|^7.0" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "^9.0" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Spatie\\YamlFrontMatter\\": "src" 30 | } 31 | }, 32 | "autoload-dev": { 33 | "psr-4": { 34 | "Spatie\\YamlFrontMatter\\Tests\\": "tests" 35 | } 36 | }, 37 | "scripts": { 38 | "test": "vendor/bin/phpunit" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | tests/ 22 | 23 | 24 | tests/DocumentTest.php 25 | 26 | 27 | tests/YamlFrontMatterTest.php 28 | 29 | 30 | 31 | 32 | ./src 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/Arr.php: -------------------------------------------------------------------------------- 1 | offsetExists($key); 84 | } 85 | 86 | return array_key_exists($key, $array); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/ComplexMarkdownParser.php: -------------------------------------------------------------------------------- 1 | content = $content; 18 | $this->lines = explode("\n", $this->content); 19 | } 20 | 21 | public function parse(): Document 22 | { 23 | $this->findFrontMatterStartAndEndLineNumbers(); 24 | 25 | if (! $this->hasFrontMatter()) { 26 | return new Document([], $this->content); 27 | } 28 | 29 | $matter = $this->getFrontMatter(); 30 | $body = $this->getBody(); 31 | 32 | $matter = Yaml::parse($matter); 33 | 34 | return new Document($matter, $body); 35 | } 36 | 37 | protected function findFrontMatterStartAndEndLineNumbers() 38 | { 39 | foreach ($this->lines as $lineNumber => $lineContents) { 40 | if ($this->isFrontMatterControlBlock($lineContents)) { 41 | $this->setFrontMatterLineNumber($lineNumber); 42 | } 43 | } 44 | } 45 | 46 | protected function setFrontMatterLineNumber(int $lineNumber) 47 | { 48 | if (! isset($this->frontMatterStartLine)) { 49 | $this->frontMatterStartLine = $lineNumber; 50 | 51 | return; 52 | } 53 | 54 | if (! isset($this->frontMatterEndLine)) { 55 | $this->frontMatterEndLine = $lineNumber; 56 | } 57 | } 58 | 59 | protected function getFrontMatter(): string 60 | { 61 | $matter = []; 62 | foreach ($this->lines as $lineNumber => $lineContents) { 63 | if ($lineNumber <= $this->frontMatterEndLine) { 64 | if (! $this->isFrontMatterControlBlock($lineContents)) { 65 | $matter[] = $lineContents; 66 | } 67 | } 68 | } 69 | 70 | return implode("\n", $matter); 71 | } 72 | 73 | protected function getBody(): string 74 | { 75 | $body = []; 76 | foreach ($this->lines as $lineNumber => $lineContents) { 77 | if ($lineNumber > $this->frontMatterEndLine) { 78 | $body[] = $lineContents; 79 | } 80 | } 81 | 82 | return implode("\n", $this->trimBody($body)); 83 | } 84 | 85 | protected function trimBody(array $body): array 86 | { 87 | if (isset($body[0]) && trim($body[0]) === '') { 88 | unset($body[0]); 89 | } 90 | 91 | return $body; 92 | } 93 | 94 | protected function hasFrontMatter(): bool 95 | { 96 | return ($this->frontMatterStartLine !== null) && ($this->frontMatterEndLine !== null); 97 | } 98 | 99 | protected function isFrontMatterControlBlock(string $line): bool 100 | { 101 | return substr($line, 0, 3) === '---'; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Document.php: -------------------------------------------------------------------------------- 1 | matter = is_array($matter) ? $matter : []; 13 | $this->body = $body; 14 | } 15 | 16 | public function matter(?string $key = null, mixed $default = null) 17 | { 18 | if ($key) { 19 | return Arr::get($this->matter, $key, $default); 20 | } 21 | 22 | return $this->matter; 23 | } 24 | 25 | public function body(): string 26 | { 27 | return $this->body; 28 | } 29 | 30 | public function __get($key) 31 | { 32 | return $this->matter($key); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/YamlFrontMatter.php: -------------------------------------------------------------------------------- 1 | parse(); 32 | } 33 | 34 | public static function parseFile(string $path): Document 35 | { 36 | return static::parse( 37 | file_get_contents($path) 38 | ); 39 | } 40 | } 41 | --------------------------------------------------------------------------------