Posts::site_name(), 'bio' => (string) get_option( 'stubli_bio', '' ), 'pronouns' => (string) get_option( 'stubli_pronouns', '' ), 'tagline' => Posts::site_tagline(), 'url' => home_url( '/' ), 'avatar' => $icon ? self::media( $icon ) : null, 'smiley' => Avatar::look(), 'accent' => Setup::accent(), 'mode' => Setup::mode(), 'links' => (string) get_option( 'stubli_links', '' ), 'favourites' => Links::data(), 'interests' => array_column( Setup::interests(), 'name' ), 'prompts' => Prompts::get(), ); } /** * Settings worth keeping when moving. * * @return array */ public static function settings() { $s = Settings::get(); return array( 'who_can_comment' => $s['who_can_comment'], 'on_break' => $s['on_break'], 'search_engines' => $s['search_engines'], 'block_ai' => $s['block_ai'], 'credit' => $s['credit'], 'digest_time' => $s['digest_time'], 'digest_email' => $s['digest_email'], 'blocked' => array_values( (array) get_option( 'stubli_blocked', array() ) ), ); } /** * The people you follow. * * @return array */ public static function follows() { return array_map( static fn( $f ) => array( 'url' => (string) $f['site_url'], 'name' => (string) $f['name'], 'interest' => (string) $f['list_name'], 'is_public' => (bool) $f['is_public'], 'muted' => (bool) $f['muted'], 'since' => (string) $f['created'], ), Follows::all() ); } /** * IDs of all photo posts and journal entries, oldest first. * * @return int[] */ public static function post_ids() { $q = new \WP_Query( array( 'post_type' => 'post', 'post_status' => array( 'publish', 'private' ), 'posts_per_page' => -1, 'orderby' => 'date', 'order' => 'ASC', 'fields' => 'ids', 'no_found_rows' => true, ) ); return array_map( 'intval', $q->posts ); } /** * One photo, video or image file: where it is and what it is. * * @param int $id Attachment ID. * @return array|null */ public static function media( $id ) { $id = (int) $id; if ( ! $id || 'attachment' !== get_post_type( $id ) ) { return null; } $path = function_exists( 'wp_get_original_image_path' ) ? wp_get_original_image_path( $id ) : false; if ( ! $path || ! file_exists( $path ) ) { $path = get_attached_file( $id ); } $url = function_exists( 'wp_get_original_image_url' ) ? wp_get_original_image_url( $id ) : false; return array( 'id' => $id, 'url' => $url ? (string) $url : (string) wp_get_attachment_url( $id ), 'path' => $path ? (string) $path : '', 'mime' => (string) get_post_mime_type( $id ), 'alt' => (string) get_post_meta( $id, '_wp_attachment_image_alt', true ), 'name' => $path ? wp_basename( $path ) : '', ); } /** * Comments on a post or the guest book, oldest first. * * @param int $post_id Post ID. * @return array */ public static function comments( $post_id ) { $out = array(); foreach ( get_comments( array( 'post_id' => (int) $post_id, 'status' => 'approve', 'orderby' => 'comment_date_gmt', 'order' => 'ASC', ) ) as $c ) { $meta = array(); foreach ( (array) get_comment_meta( $c->comment_ID ) as $k => $v ) { if ( '_' !== substr( (string) $k, 0, 1 ) ) { $meta[ $k ] = maybe_unserialize( $v[0] ); } } $out[] = array( 'id' => (int) $c->comment_ID, 'parent' => (int) $c->comment_parent, 'name' => (string) $c->comment_author, 'url' => (string) $c->comment_author_url, 'mine' => (int) $c->user_id > 0 && user_can( (int) $c->user_id, 'manage_options' ), 'avatar' => (string) get_avatar_url( $c ), 'text' => wp_strip_all_tags( $c->comment_content ), 'date' => gmdate( 'c', (int) strtotime( $c->comment_date_gmt . ' UTC' ) ), 'type' => (string) $c->comment_type, 'meta' => $meta, ); } return $out; } /** * One photo post or journal entry. * * @param int $id Post ID. * @return array|null */ public static function post( $id ) { $post = get_post( (int) $id ); if ( ! $post || 'post' !== $post->post_type || ! in_array( $post->post_status, array( 'publish', 'private' ), true ) ) { return null; } $format = get_post_format( $post ); $type = 'status' === $format ? 'journal' : ( in_array( $format, array( 'image', 'gallery' ), true ) ? 'photo' : 'other' ); $out = array( 'id' => (int) $post->ID, 'type' => $type, 'format' => $format ? $format : 'standard', 'date' => get_post_time( 'c', true, $post ), 'status' => $post->post_status, 'audience' => Friends::audience( $post ), 'title' => $post->post_title, 'own_title' => 'journal' === $type ? Journal::title( $post->ID ) : '', 'url' => (string) get_permalink( $post ), 'collection' => '', 'note' => (string) get_post_meta( $post->ID, '_stubli_content_note', true ), 'caption' => 'photo' === $type ? Mine::caption_text( $post ) : '', 'html' => 'photo' === $type ? '' : (string) $post->post_content, 'photos' => array(), 'comments' => self::comments( $post->ID ), ); $def = (int) get_option( 'default_category' ); foreach ( get_the_category( $post->ID ) as $c ) { if ( (int) $c->term_id !== $def ) { $out['collection'] = $c->name; break; } } if ( 'photo' === $type ) { foreach ( Posts::photo_ids( $post->ID ) as $aid ) { $m = self::media( $aid ); if ( $m ) { $v = Posts::video_for( $aid ); $m['video'] = $v ? self::media( $v ) : null; $out['photos'][] = $m; } } } else { foreach ( get_children( array( 'post_parent' => $post->ID, 'post_type' => 'attachment', 'post_mime_type' => 'image', 'orderby' => 'menu_order ID', 'order' => 'ASC', ) ) as $att ) { $m = self::media( $att->ID ); if ( $m ) { $m['video'] = null; $out['photos'][] = $m; } } } return $out; } /** * Swap the of one photo inside journal HTML for something else. * Matches by file name, including WordPress's resized copies * (photo-1024x768.jpg, photo-scaled.jpg). * * @param string $html Journal HTML. * @param array $m Media (with name). * @param string $with Replacement HTML. * @return string */ public static function replace_img( $html, array $m, $with ) { $name = (string) ( $m['name'] ?? '' ); if ( '' === $name ) { return $html; } $dot = strrpos( $name, '.' ); $stem = preg_quote( false === $dot ? $name : substr( $name, 0, $dot ), '#' ); $ext = preg_quote( false === $dot ? '' : substr( $name, $dot ), '#' ); $stem = preg_replace( '#\\-scaled$#', '', $stem ); return (string) preg_replace_callback( '#]*\bsrc="[^"]*/' . $stem . '(?:-scaled|-\d+x\d+)*' . $ext . '"[^>]*>#i', static fn() => $with, $html ); } /** * The guest book. * * @return array */ public static function guestbook() { $id = Guestbook::page_id(); if ( ! $id ) { return array(); } $out = self::comments( $id ); foreach ( $out as &$e ) { $e['pinned'] = ! empty( $e['meta']['stubli_pinned'] ); } return $out; } }