Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions benchmarks/HugoImporterBench.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

declare(strict_types=1);

namespace YiiPress\Benchmarks;

use PhpBench\Attributes\AfterMethods;
use PhpBench\Attributes\BeforeMethods;
use PhpBench\Attributes\Iterations;
use PhpBench\Attributes\Revs;
use PhpBench\Attributes\Warmup;
use YiiPress\Import\Hugo\HugoContentImporter;

#[BeforeMethods('setUp')]
#[AfterMethods('tearDown')]
final class HugoImporterBench
{
private string $sourceDir;
private string $targetDir;
private HugoContentImporter $importer;

public function setUp(): void
{
$this->sourceDir = sys_get_temp_dir() . '/yiipress-hugo-bench-source-' . uniqid();
$this->targetDir = sys_get_temp_dir() . '/yiipress-hugo-bench-target-' . uniqid();
mkdir($this->sourceDir . '/content/posts', 0o755, true);
mkdir($this->targetDir, 0o755, true);

for ($i = 1; $i <= 100; $i++) {
file_put_contents(
$this->sourceDir . '/content/posts/post-' . $i . '.md',
"+++\ntitle = \"Post $i\"\ndate = \"2024-03-15T10:30:00Z\"\ntags = [\"php\", \"yii\"]\n+++\n\nBody $i.\n",
);
}

$this->importer = new HugoContentImporter();
}

public function tearDown(): void
{
$this->removeDir($this->sourceDir);
$this->removeDir($this->targetDir);
}

#[Revs(10)]
#[Iterations(3)]
#[Warmup(1)]
public function benchImportPosts(): void
{
$this->removeDir($this->targetDir);
mkdir($this->targetDir, 0o755, true);

$this->importer->import(['directory' => $this->sourceDir], $this->targetDir, 'blog');
}

private function removeDir(string $path): void
{
if (!is_dir($path)) {
return;
}

$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST,
);
foreach ($iterator as $item) {
if ($item->isDir()) {
rmdir($item->getPathname());
} else {
unlink($item->getPathname());
}
}

rmdir($path);
}
}
2 changes: 2 additions & 0 deletions config/common/di/importer.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
declare(strict_types=1);

use YiiPress\Console\ImportCommand;
use YiiPress\Import\Hugo\HugoContentImporter;
use YiiPress\Import\Telegram\TelegramContentImporter;

$workingDirectory = getcwd() ?: dirname(__DIR__, 3);
Expand All @@ -12,6 +13,7 @@
'__construct()' => [
'rootPath' => $workingDirectory,
'importers' => [
'hugo' => new HugoContentImporter(),
'telegram' => new TelegramContentImporter(),
],
],
Expand Down
28 changes: 27 additions & 1 deletion docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ Imports content from external sources into a YiiPress collection.

**Arguments:**

- `source` — source type to import from (required). Currently supported: `telegram`.
- `source` — source type to import from (required). Currently supported: `hugo`, `telegram`.

**Common options:**

Expand Down Expand Up @@ -191,6 +191,32 @@ Supports both single-chat exports (`result.json` with `messages` array) and full
./yiipress import telegram --directory=./telegram-data --content-dir=content
```

### Hugo import

Imports Markdown content from a Hugo site directory. The importer scans `content/posts/`, then `content/post/`, then `content/`, reads `.md` files recursively, and writes YiiPress markdown files into the target collection.

**Importer options:**

- `--directory` — path to the Hugo site directory (required). Absolute or relative to project root.

The importer supports YAML (`---`) and simple TOML (`+++`) front matter and preserves:

- `title`
- `date`
- `url` / `permalink`
- `draft`
- `tags`
- `categories`

If `title` is missing, it is inferred from the first `# Heading` in the post body and then from the filename slug. If `date` is missing, filenames starting with `YYYY-MM-DD-` provide the date.

**Examples:**

```bash
./yiipress import hugo --directory=/path/to/hugo-site
./yiipress import hugo --directory=../old-hugo-site --collection=blog
```

### Adding custom importers

Importers implement `YiiPress\Import\ContentImporterInterface` and are registered via [Yii3 DI](https://yiisoft.github.io/docs/guide/concept/di-container.html) in `config/common/di/importer.php`. Each importer declares its own options via the `options()` method. See [Importing content](importing-content.md) for details.
Expand Down
12 changes: 12 additions & 0 deletions docs/importing-content.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ Imports messages from a Telegram Desktop channel export (JSON format).

See [commands.md](commands.md#yii-import) for usage details.

### HugoContentImporter

Imports Markdown content from a Hugo site.

**Options:**

- `--directory` — Path to the Hugo site directory (required)

The importer scans `content/posts/`, then `content/post/`, then `content/`, accepts `.md` files, supports YAML (`---`) and simple TOML (`+++`) front matter, preserves common fields (`title`, `date`, `url` / `permalink`, `draft`, `tags`, `categories`), and creates a default collection config when one does not exist.

See [commands.md](commands.md#hugo-import) for usage details.

## Writing a custom importer

Create a class implementing `ContentImporterInterface`. Each importer declares its own options — a file-based importer might need a `directory`, while an API-based importer might need `url` and `api-key`.
Expand Down
2 changes: 1 addition & 1 deletion roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@

- [ ] WordPress
- [ ] Jekyll
- [ ] Hugo
- [x] Hugo
- [ ] Medium exported Markdown
- [ ] Ghost
- [x] Telegram export
Loading