]> git.bts.cx Git - cx.git/blob - cx/lib/posts.php
allow html in body of posts
[cx.git] / cx / lib / posts.php
1 <?php
2
3 cx_require('lib', 'db.php');
4 cx_require('lib', 'setup.php');
5 cx_require('third_party', 'parsedown', 'Parsedown.php');
6
7 function mk_markdown($markdown) {
8 static $Parsedown = new Parsedown();
9
10 return $Parsedown->text($markdown);
11 }
12
13 class PostMetadata {
14 public $hero_image;
15 public $hero_image_alt;
16
17 public function __construct($dict) {
18 $this->hero_image = isset($dict['post_hero_image']) ? $dict['post_hero_image'] : null;
19 $this->hero_image_alt = isset($dict['post_hero_image_alt']) ? $dict['post_hero_image_alt'] : null;
20 }
21 }
22
23 class Post {
24 public $id;
25 public $title;
26 public $slug;
27 public $date;
28 public $is_draft;
29 public $data;
30 public $html_content;
31 public $html_excerpt;
32
33 public function __construct($dict) {
34 $this->id = $dict['post_id']; // FIXME, hide when not used?
35 $this->title = $dict['post_title'];
36 $this->slug = $dict['post_slug'];
37 $this->date = $dict['post_date'];
38 $this->is_draft = $dict['post_is_draft'];
39 $this->data = $dict['post_data'];
40 $this->html_content = mk_markdown($this->data);
41 $this->html_excerpt = null;
42
43 // Read more...
44 $segments = explode('---', $this->data, 2);
45 if (count($segments) > 1) {
46 $this->html_excerpt = mk_markdown($segments[0]);
47 }
48 }
49
50 public function get_metadata() {
51 $data = [];
52
53 $doc = new DOMDocument();
54 $doc->loadHTML($this->html_content);
55
56 $image_tag = $doc->getElementsByTagName('img')[0];
57
58 if ($image_tag != null) {
59 $data['post_hero_image'] = $image_tag->getAttribute('src');
60 $data['post_hero_image_alt'] = htmlspecialchars($image_tag->getAttribute('alt'));
61 }
62
63 return new PostMetadata($data);
64 }
65 }
66
67 function cx_post_make_slug($title) {
68 $alnum_title = preg_replace('/[^A-Za-z0-9 ]?/', '', $title);
69
70 $slug_components = explode(' ', $alnum_title, 10);
71 $slug_components = array_filter($slug_components);
72 $slug_components = array_values($slug_components); // re-index
73
74 $slug = join('-', $slug_components);
75 $slug = strtolower($slug);
76
77 return $slug;
78 }
79
80 function cx_posts_add_post($site_id, $title, $slug, $date, $draft, $data) {
81 $creation_time = $update_time = time();
82
83 if ($slug == null) {
84 $slug = cx_post_make_slug($title);
85 }
86
87 if ($date == null) {
88 $date = $update_time;
89 }
90
91 $sql = 'INSERT INTO posts (
92 post_site_id,
93 post_creation_time,
94 post_update_time,
95 post_slug,
96 post_date,
97 post_is_page,
98 post_is_draft,
99 post_title,
100 post_data,
101 post_data_version)
102 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);';
103 cx_db_exec($sql, $site_id, $creation_time, $update_time, $slug, $date, false, $draft, $title, $data, 1);
104 }
105
106 function cx_posts_update_post($post_id, $title, $slug, $date, $draft, $data) {
107 $update_time = time();
108
109 if ($slug == null) {
110 $slug = cx_post_make_slug($title);
111 }
112
113 if ($date == null) {
114 $date = $update_time;
115 }
116
117 $sql = 'UPDATE posts
118 SET post_update_time = ?,
119 post_slug = ?,
120 post_date = ?,
121 post_is_draft = ?,
122 post_title = ?,
123 post_data = ?
124 WHERE post_id == ?;';
125 //LIMIT 1;';
126 cx_db_exec($sql, $update_time, $slug, $date, $draft, $title, $data, $post_id);
127 }
128
129 function cx_posts_delete_post($post_id) {
130 $sql = 'DELETE FROM posts
131 WHERE post_id == ?;';
132 //LIMIT 1;';
133 cx_db_exec($sql, $post_id);
134 }
135
136 function cx_posts_get(int $limit = 0, bool $include_drafts = false) {
137 $sql = 'SELECT
138 post_id,
139 post_slug,
140 post_date,
141 post_is_draft,
142 post_title,
143 post_data
144 FROM posts
145 WHERE post_is_page == FALSE';
146
147 if ($include_drafts == false) {
148 $sql .= ' AND post_is_draft == FALSE';
149 }
150
151 $sql .= ' ORDER BY post_date DESC';
152
153 if ($limit > 0) {
154 $sql .= ' LIMIT ' . $limit;
155 }
156
157 $sql .= ';';
158
159 foreach (cx_db_query($sql) as $post) {
160 $p = new Post($post);
161 yield $p;
162 }
163 }
164
165 function cx_posts_find_post($post_id) {
166 $sql = 'SELECT
167 post_id,
168 post_slug,
169 post_date,
170 post_is_draft,
171 post_title,
172 post_data
173 FROM posts
174 WHERE post_is_page == FALSE
175 AND post_id == ?
176 LIMIT 1;';
177
178 foreach (cx_db_query($sql, $post_id) as $post) {
179 $p = new Post($post);
180 return $p;
181 }
182
183 return null;
184 }
185
186 function cx_posts_find_post_id($post_slug) {
187 $sql = 'SELECT
188 post_id
189 FROM posts
190 WHERE post_slug == ?
191 LIMIT 1;';
192
193 foreach (cx_db_query($sql, $post_slug) as $post) {
194 return $post['post_id'];
195 }
196
197 return null;
198 }
199
200 function cx_pages_get() {
201 $sql = 'SELECT
202 post_id,
203 post_slug,
204 post_date,
205 post_is_draft,
206 post_title,
207 post_data
208 FROM posts
209 WHERE post_is_page == TRUE
210 AND post_is_draft == FALSE
211 ORDER BY post_creation_time DESC;';
212
213 foreach (cx_db_query($sql) as $post) {
214 $p = new Post($post);
215 yield $p;
216 }
217 }
218
219 cx_setup_register(1, function() {
220 cx_db_exec('CREATE TABLE posts (
221 post_id INTEGER PRIMARY KEY,
222 post_site_id INTEGER,
223 post_creation_time INTEGER,
224 post_update_time INTEGER,
225 post_slug STRING,
226 post_date INTEGER,
227 post_is_page BOOLEAN,
228 post_is_draft BOOLEAN,
229 post_title STRING,
230 post_data BLOB,
231 post_data_version INTEGER,
232
233 FOREIGN KEY(post_site_id) REFERENCES sites(site_id)
234 );');
235 });