]> git.bts.cx Git - cx.git/blob - cx/lib/posts.php
Better paths for images and editor links
[cx.git] / cx / lib / posts.php
1 <?php
2
3 cx_require('lib', 'db.php');
4 cx_require('lib', 'setup.php');
5 cx_require('lib', 'markdown.php');
6
7 class PostMetadata {
8         public $hero_image;
9         public $hero_image_alt;
10
11         public function __construct($dict) {
12                 $this->hero_image = isset($dict['post_hero_image']) ? $dict['post_hero_image'] : null;
13                 $this->hero_image_alt = isset($dict['post_hero_image_alt']) ? $dict['post_hero_image_alt'] : null;
14         }
15 }
16
17 class Post {
18         public $id;
19         public $title;
20         public $slug;
21         public $date;
22         public $is_page;
23         public $is_draft;
24         public $nav_index;
25         public $data;
26         public $html_content;
27         public $html_excerpt;
28
29         public function __construct($dict) {
30                 $this->id = $dict['post_id']; // FIXME, hide when not used?
31                 $this->title = $dict['post_title'];
32                 $this->slug = $dict['post_slug'];
33                 $this->date = $dict['post_date'];
34                 $this->is_page = $dict['post_is_page'];
35                 $this->is_draft = $dict['post_is_draft'];
36                 $this->nav_index = $dict['post_navigation_index'];
37                 $this->data = $dict['post_data'];
38                 $this->html_content = cx_markdown_generate_html($this->data);
39                 $this->html_excerpt = null;
40
41                 // Read more...
42                 $segments = explode('---', $this->data, 2);
43                 if (count($segments) > 1) {
44                         $this->html_excerpt = cx_markdown_generate_html($segments[0]);
45                 }
46         }
47
48         public function get_permalink_path() {
49                 $permalink = '/' . $this->slug;
50                 if ($this->is_page == false) {
51                         $permalink = '/' . date('Y', $this->date) . '/' . date('m', $this->date) . '/' . $this->slug;
52                 }
53                 return $permalink;
54         }
55
56         public function get_metadata() {
57                 $data = [];
58
59                 $doc = new DOMDocument();
60                 $doc->loadHTML($this->html_content);
61
62                 $image_tag = $doc->getElementsByTagName('img')[0];
63
64                 if ($image_tag != null) {
65                         $data['post_hero_image'] = $image_tag->getAttribute('src');
66                         $data['post_hero_image_alt'] = htmlspecialchars($image_tag->getAttribute('alt'));
67                 }
68
69                 return new PostMetadata($data);
70         }
71 }
72
73 function cx_post_make_slug($title) {
74         $alnum_title = preg_replace('/[^A-Za-z0-9 ]?/', '', $title);
75         
76         $slug_components = explode(' ', $alnum_title, 10);
77         $slug_components = array_filter($slug_components);
78         $slug_components = array_values($slug_components); // re-index
79
80         $slug = join('-', $slug_components);
81         $slug = strtolower($slug);
82
83         return $slug;
84 }
85
86 function cx_posts_add_post($site_id, $title, $slug, $date, $page, $draft, $nav_index, $data) {
87         $creation_time = $update_time = time();
88         
89         if ($slug == null) {
90                 $slug = cx_post_make_slug($title);
91         }
92
93         if ($date == null) {
94                 $date = $update_time;
95         }
96
97         $sql = 'INSERT INTO posts (
98                         post_site_id,
99                         post_creation_time,
100                         post_update_time,
101                         post_slug,
102                         post_date,
103                         post_is_page,
104                         post_is_draft,
105                         post_navigation_index,
106                         post_title,
107                         post_data,
108                         post_data_version)
109                 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);';
110         $id = cx_db_exec($sql, $site_id, $creation_time, $update_time, $slug, $date, $page, $draft, $nav_index, $title, $data, 1);
111         return $id;
112 }
113
114 function cx_posts_update_post($post_id, $title, $slug, $date, $page, $draft, $nav_index, $data) {
115         $update_time = time();
116         
117         if ($slug == null) {
118                 $slug = cx_post_make_slug($title);
119         }
120
121         if ($date == null) {
122                 $date = $update_time;
123         }
124
125         $sql = 'UPDATE posts
126                 SET post_update_time = ?,
127                 post_slug = ?,
128                 post_date = ?,
129                 post_is_page = ?,
130                 post_is_draft = ?,
131                 post_navigation_index = ?,
132                 post_title = ?,
133                 post_data = ?
134                 WHERE post_id == ?;';
135                 //LIMIT 1;';
136         cx_db_exec($sql, $update_time, $slug, $date, $page, $draft, $nav_index, $title, $data, $post_id);
137 }
138
139 function cx_posts_delete_post($post_id) {
140         $sql = 'DELETE FROM posts
141                 WHERE post_id == ?;';
142                 //LIMIT 1;';
143         cx_db_exec($sql, $post_id);
144 }
145
146 function cx_posts_get(int $limit = 0, int $offset = 0, bool $include_drafts = false) {
147         $sql = 'SELECT
148                 post_id,
149                 post_slug,
150                 post_date,
151                 post_is_page,
152                 post_is_draft,
153                 post_navigation_index,
154                 post_title,
155                 post_data
156                 FROM posts
157                 WHERE post_is_page == FALSE';
158         
159         if ($include_drafts == false) {
160                 $sql .= ' AND post_is_draft == FALSE';
161         }
162
163         $sql .= ' ORDER BY post_date DESC';
164         
165         if ($limit > 0) {
166                 $sql .= ' LIMIT ' . $limit;
167         }
168         
169         if ($offset > 0) {
170                 $sql .= ' OFFSET ' . $offset;
171         }
172
173         $sql .= ';';
174
175         foreach (cx_db_query($sql) as $post) {
176                 $p = new Post($post);
177                 yield $p;
178         }
179 }
180
181 function cx_posts_count(bool $include_drafts = false) {
182         $sql = 'SELECT
183                 COUNT(post_id) AS _count
184                 FROM posts
185                 WHERE post_is_page == FALSE';
186         
187         if ($include_drafts == false) {
188                 $sql .= ' AND post_is_draft == FALSE';
189         }
190
191         $sql .= ';';
192
193
194         foreach (cx_db_query($sql) as $count_details) {
195                 return $count_details['_count'];
196         }
197
198         return 0;
199 }
200
201 function cx_posts_find_post($post_id) {
202         $sql = 'SELECT
203                 post_id,
204                 post_slug,
205                 post_date,
206                 post_is_page,
207                 post_is_draft,
208                 post_navigation_index,
209                 post_title,
210                 post_data
211                 FROM posts
212                 WHERE post_id == ?
213                 LIMIT 1;';
214
215         foreach (cx_db_query($sql, $post_id) as $post) {
216                 $p = new Post($post);
217                 return $p;
218         }
219
220         return null;
221 }
222
223 function cx_posts_find_article_id($post_slug, bool $include_drafts = false) {
224         $sql = 'SELECT
225                 post_id
226                 FROM posts
227                 WHERE post_slug == ?
228                 AND post_is_page == FALSE';
229
230         if ($include_drafts == false) {
231                 $sql .= ' AND post_is_draft == FALSE';
232         }
233
234         $sql .= ' LIMIT 1';
235
236         $sql .= ';';
237
238         foreach (cx_db_query($sql, $post_slug) as $post) {
239                 return $post['post_id'];
240         }
241
242         return null;
243
244 }
245
246 function cx_posts_find_page_id($post_slug, bool $include_drafts = false) {
247         $sql = 'SELECT
248                 post_id
249                 FROM posts
250                 WHERE post_slug == ?
251                 AND post_is_page == TRUE';
252
253         if ($include_drafts == false) {
254                 $sql .= ' AND post_is_draft == FALSE';
255         }
256
257         $sql .= ' LIMIT 1';
258
259         $sql .= ';';
260
261         foreach (cx_db_query($sql, $post_slug) as $post) {
262                 return $post['post_id'];
263         }
264
265         return null;
266 }
267
268 function cx_pages_get(bool $navigation_only = true, bool $include_drafts = false) {
269         $sql = 'SELECT
270                 post_id,
271                 post_slug,
272                 post_date,
273                 post_is_page,
274                 post_is_draft,
275                 post_navigation_index,
276                 post_title,
277                 post_data
278                 FROM posts
279                 WHERE post_is_page == TRUE';
280
281         if ($navigation_only) {
282                 $sql .= ' AND post_navigation_index != ""';
283         }
284
285         if ($include_drafts == false) {
286                 $sql .= ' AND post_is_draft == FALSE';
287         }
288
289         $sql .= ' ORDER BY post_navigation_index ASC, post_date DESC';
290
291         $sql .= ';';
292
293         foreach (cx_db_query($sql) as $post) {
294                 $p = new Post($post);
295                 yield $p;
296         }
297 }
298
299 cx_setup_register(1, function() {
300         cx_db_exec('CREATE TABLE posts (
301                         post_id INTEGER PRIMARY KEY,
302                         post_site_id INTEGER,
303                         post_creation_time INTEGER,
304                         post_update_time INTEGER,
305                         post_slug STRING,
306                         post_date INTEGER,
307                         post_is_page BOOLEAN,
308                         post_is_draft BOOLEAN,
309                         post_navigation_index INTEGER,
310                         post_title STRING,
311                         post_data BLOB,
312                         post_data_version INTEGER,
313
314                         FOREIGN KEY(post_site_id) REFERENCES sites(site_id)
315                 );');
316 });