WebOrbiton

Code

Publisium

A modern, fast CMS for building article and blog websites.

Version history

Version 1.0.0.6 2026-10-01

Browse files
Files changed9
Lines added+58
Lines removed-3
article.php Modified +11 -1
⋮ 125 unchanged lines ⋮
          exit('You do not have permission to preview this article.');
      }
  } else {
-     $updateViews = $db->prepare('UPDATE articles SET views_count = views_count + 1 WHERE id = :id');
+     $updateViews = $db->prepare('UPDATE articles SET views_count = views_count + 1, updated_at = updated_at WHERE id = :id');
      $updateViews->execute(['id' => $article['id']]);
  }
  
⋮ 30 unchanged lines ⋮
  $ogImagePath = !empty($article['cover_image_path']) ? $article['cover_image_path'] : null;
  $pageType = 'article';
  $authorPage = AuthorProfile::isEnabled() ? AuthorProfile::publicSummary((int) $article['author_id']) : null;
+ $authorPageUrl = $authorPage !== null ? SiteFront::authorUrl((string) $authorPage['slug']) : null;
+ $ogArticleMeta = [
+     'published' => $article['published_at'] ?? null,
+     'modified' => $article['updated_at'] ?? null,
+     'author' => $authorPageUrl !== null ? SiteFront::absoluteUrl($authorPageUrl) : (string) $article['author_name'],
+     'section' => (string) ($article['category_name'] ?? ''),
+ ];
+ $pageSchema = !$isPreview && $settings['seo_article_schema_enabled'] === '1'
+     ? SiteFront::renderArticleSchema($article, AuthorProfile::schemaType((int) $article['author_id']), $authorPageUrl)
+     : '';
  $pageTitle = $isPreview ? 'Preview - ' . $pageTitle : $pageTitle;
  
  require __DIR__ . '/includes/front-header.php';
⋮ 217 unchanged lines ⋮
dashboard-actions/save-settings.php Modified +3 -0
⋮ 222 unchanged lines ⋮
          'seo_robots_index' => isset($_POST['seo_robots_index']) ? '1' : '0',
          'seo_robots_follow' => isset($_POST['seo_robots_follow']) ? '1' : '0',
          'seo_og_article_image_enabled' => isset($_POST['seo_og_article_image_enabled']) ? '1' : '0',
+         'seo_social_tags_enabled' => isset($_POST['seo_social_tags_enabled']) ? '1' : '0',
+         'seo_twitter_handle' => preg_match('/^@?([A-Za-z0-9_]{1,15})$/', trim((string) ($_POST['seo_twitter_handle'] ?? '')), $twitterHandle) === 1 ? '@' . $twitterHandle[1] : '',
+         'seo_article_schema_enabled' => isset($_POST['seo_article_schema_enabled']) ? '1' : '0',
          'clean_article_urls' => isset($_POST['clean_article_urls']) ? '1' : '0',
          'clean_page_urls' => isset($_POST['clean_page_urls']) ? '1' : '0',
          'clean_author_urls' => isset($_POST['clean_author_urls']) ? '1' : '0',
⋮ 9 unchanged lines ⋮
dashboard-views/profile.php Modified +12 -0
⋮ 25 unchanged lines ⋮
      : AuthorProfile::formValues($profile);
  $publishDirectly = Auth::canPublishDirectly();
  $status = $profile['status'] ?? 'draft';
+ $showSchemaType = SiteFront::settings()['seo_article_schema_enabled'] === '1';
+ $schemaType = $wasPosted ? (string) ($_POST['schema_type'] ?? '') : (string) ($profile['schema_type'] ?? '');
+ $schemaType = in_array($schemaType, AuthorProfile::SCHEMA_TYPES, true) ? $schemaType : 'Person';
  
  ?>
  <div class="dash-header-row">
⋮ 31 unchanged lines ⋮
  
  <label>Website (optional)</label>
  <input type="url" name="website_url" maxlength="<?= AuthorProfile::URL_MAX ?>" value="<?= htmlspecialchars($form['website_url']) ?>" placeholder="https://">
+ 
+ <?php if ($showSchemaType): ?>
+ <label>For search engines, this author is</label>
+ <select name="schema_type">
+ <option value="Person" <?= $schemaType === 'Person' ? 'selected' : '' ?>>A person (Person)</option>
+ <option value="Organization" <?= $schemaType === 'Organization' ? 'selected' : '' ?>>An organization, e.g. an editorial team or agency (Organization)</option>
+ </select>
+ <p style="font-size:12px;color:var(--muted);margin-top:6px;">Used in the article data Google reads. It changes right away, without review.</p>
+ <?php endif; ?>
  
  <p style="font-size:12px;color:var(--muted);margin-top:10px;">Your profile photo is set by an administrator in Team.</p>
  
⋮ 7 unchanged lines ⋮
includes/author-profile.php Modified +23 -0
⋮ 10 unchanged lines ⋮
      public const BIO_MAX = 2000;
      public const URL_MAX = 255;
      public const REASON_MAX = 500;
+     public const SCHEMA_TYPES = ['Person', 'Organization'];
  
      private static ?bool $enabled = null;
  
⋮ 57 unchanged lines ⋮
          }
      }
  
+     public static function schemaType(int $accountId): string
+     {
+         if ($accountId <= 0) {
+             return 'Person';
+         }
+ 
+         try {
+             $statement = Database::site()->prepare('SELECT schema_type FROM author_profiles WHERE account_id = :account LIMIT 1');
+             $statement->execute(['account' => $accountId]);
+             $type = (string) $statement->fetchColumn();
+         } catch (PDOException $e) {
+             return 'Person';
+         }
+ 
+         return in_array($type, self::SCHEMA_TYPES, true) ? $type : 'Person';
+     }
+ 
      public static function pendingCount(): int
      {
          try {
⋮ 95 unchanged lines ⋮
          }
  
          $db = Database::site();
+ 
+         if (in_array($input['schema_type'] ?? null, self::SCHEMA_TYPES, true)) {
+             $db->prepare('UPDATE author_profiles SET schema_type = :type WHERE account_id = :account')
+                 ->execute(['type' => $input['schema_type'], 'account' => $accountId]);
+         }
  
          if ($intent === 'submit' && $publishDirectly) {
              $db->prepare(
⋮ 147 unchanged lines ⋮
includes/database.php Modified +4 -0
⋮ 112 unchanged lines ⋮
                  'article_comments' => [
                      'author_email' => "ALTER TABLE article_comments ADD COLUMN author_email VARCHAR(190) NULL AFTER author_name",
                  ],
+                 'author_profiles' => [
+                     'schema_type' => "ALTER TABLE author_profiles ADD COLUMN schema_type VARCHAR(12) NOT NULL DEFAULT 'Person' AFTER website_url",
+                 ],
                  'nav_items' => [
                      'icon_key' => "ALTER TABLE nav_items ADD COLUMN icon_key VARCHAR(30) NULL AFTER target",
                      'icon_svg' => "ALTER TABLE nav_items ADD COLUMN icon_svg MEDIUMTEXT NULL AFTER icon_key",
⋮ 59 unchanged lines ⋮
                      headline VARCHAR(160) NOT NULL DEFAULT '',
                      bio TEXT NULL,
                      website_url VARCHAR(255) NOT NULL DEFAULT '',
+                     schema_type VARCHAR(12) NOT NULL DEFAULT 'Person',
                      draft_headline VARCHAR(160) NULL,
                      draft_bio TEXT NULL,
                      draft_website_url VARCHAR(255) NULL,
⋮ 181 unchanged lines ⋮
includes/front-header.php Modified +4 -1
⋮ 29 unchanged lines ⋮
      <?php endif; ?>
      <?= SiteFront::renderSeoMeta() ?>
      <?= Languages::renderAlternates() ?>
-     <?= SiteFront::renderOpenGraph($resolvedPageTitle, $resolvedPageDescription, $ogType ?? 'website', $ogImagePath ?? null) ?>
+     <?= SiteFront::renderOpenGraph($resolvedPageTitle, $resolvedPageDescription, $ogType ?? 'website', $ogImagePath ?? null, $ogArticleMeta ?? null) ?>
      <?php if ($isHomepage): ?>
          <?= SiteFront::renderOrganizationSchema() ?>
+     <?php endif; ?>
+     <?php if (!empty($pageSchema)): ?>
+         <?= $pageSchema ?>
      <?php endif; ?>
      <?= Asset::favicon() ?>
      <?php if (($settings['pwa_enabled'] ?? '0') === '1'): ?>
⋮ 130 unchanged lines ⋮
includes/site-front.php Modified

Not shown (binary file or too large to diff).

settings.php Modified

Not shown (binary file or too large to diff).

version.txt Modified +1 -1
- 1.0.0.5
+ 1.0.0.6