Add installer functionality for WordPress with FTP and database configuration

- Create SQL migration for prompt templates used in article and image generation.
- Add migration to change publish interval from days to hours in the sites table.
- Implement InstallerController to handle installation requests and validation.
- Develop FtpService for FTP connections and file uploads.
- Create InstallerService to manage the WordPress installation process, including downloading, extracting, and configuring WordPress.
- Add index view for the installer with form inputs for FTP, database, and WordPress admin settings.
- Implement progress tracking for the installation process with AJAX polling.
This commit is contained in:
2026-02-16 21:55:24 +01:00
parent 884ee9cc88
commit b653cea252
37 changed files with 2899 additions and 204 deletions

View File

@@ -49,6 +49,24 @@ class WordPressService
}
}
public function createCategory(array $site, string $name, int $parent = 0): ?array
{
try {
$response = $this->client->post($site['url'] . '/wp-json/wp/v2/categories', [
'auth' => [$site['api_user'], $site['api_token']],
'json' => [
'name' => $name,
'parent' => $parent,
],
]);
return json_decode($response->getBody()->getContents(), true);
} catch (GuzzleException $e) {
Logger::error("WP createCategory failed for {$site['url']}: " . $e->getMessage(), 'wordpress');
return null;
}
}
public function uploadMedia(array $site, string $imageData, string $filename): ?int
{
try {
@@ -104,6 +122,51 @@ class WordPressService
}
}
public function getPostFeaturedMedia(array $site, int $wpPostId): ?int
{
try {
$response = $this->client->get($site['url'] . '/wp-json/wp/v2/posts/' . $wpPostId, [
'auth' => [$site['api_user'], $site['api_token']],
'query' => ['_fields' => 'featured_media'],
]);
$data = json_decode($response->getBody()->getContents(), true);
$mediaId = $data['featured_media'] ?? 0;
return $mediaId > 0 ? $mediaId : null;
} catch (GuzzleException $e) {
Logger::error("WP getPostFeaturedMedia failed: " . $e->getMessage(), 'wordpress');
return null;
}
}
public function updatePostFeaturedMedia(array $site, int $wpPostId, int $mediaId): bool
{
try {
$this->client->post($site['url'] . '/wp-json/wp/v2/posts/' . $wpPostId, [
'auth' => [$site['api_user'], $site['api_token']],
'json' => ['featured_media' => $mediaId],
]);
return true;
} catch (GuzzleException $e) {
Logger::error("WP updatePostFeaturedMedia failed: " . $e->getMessage(), 'wordpress');
return false;
}
}
public function deleteMedia(array $site, int $mediaId): bool
{
try {
$this->client->delete($site['url'] . '/wp-json/wp/v2/media/' . $mediaId, [
'auth' => [$site['api_user'], $site['api_token']],
'query' => ['force' => true],
]);
return true;
} catch (GuzzleException $e) {
Logger::error("WP deleteMedia failed: " . $e->getMessage(), 'wordpress');
return false;
}
}
private function getMimeType(string $filename): string
{
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));