Ansico-SoMe-plugin/ansico-some-plugin/ansico-some-plugin.php

1851 lines
80 KiB
PHP
Raw Normal View History

2026-04-13 18:55:00 +00:00
<?php
/**
2026-04-16 16:59:23 +00:00
* Plugin Name: Ansico SoMe Plugin
* Plugin URI: https://ansico.dk/Ansico/Ansico-SoMe-plugin
* Description: Turn WordPress into your own microblog with comments and likes. Lots of blocks.
* Version: 1.2.0
* Author: Andreas Andersen (Ansico)
* Author URI: https://ansico.dk
* License: GPL-3.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-3.0.html
2026-04-13 18:55:00 +00:00
* Text Domain: ansico-some-plugin
2026-04-16 16:59:23 +00:00
* Requires at least: 6.4
* Requires PHP: 7.4
2026-04-13 18:55:00 +00:00
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
2026-04-16 16:59:23 +00:00
if ( ! defined( 'ANSICO_SOME_PLUGIN_VERSION' ) ) {
define( 'ANSICO_SOME_PLUGIN_VERSION', '1.2.0' );
}
add_filter( 'block_categories_all', 'ansico_register_block_category', 10, 2 );
function ansico_register_block_category( $categories, $post ) {
foreach ( $categories as $category ) {
if ( isset( $category['slug'] ) && 'ansico' === $category['slug'] ) {
return $categories;
}
}
array_unshift(
$categories,
array(
'slug' => 'ansico',
'title' => __( 'Ansico Blocks', 'ansico-some-plugin' ),
'icon' => null,
)
);
return $categories;
}
function ansico_get_micropost_max_chars() {
$value = get_option( 'ansico_micropost_max_chars', 500 );
$value = intval( $value );
return $value > 0 ? $value : 500;
}
add_action( 'admin_menu', 'ansico_register_settings_page' );
function ansico_register_settings_page() {
add_options_page(
'Ansico SoMe Plugin',
'Ansico SoMe Plugin',
'manage_options',
'ansico-some-plugin-settings',
'ansico_render_settings_page'
);
}
add_action( 'admin_init', 'ansico_register_settings' );
function ansico_register_settings() {
register_setting(
'ansico_some_plugin_settings',
'ansico_micropost_max_chars',
array(
'type' => 'integer',
'sanitize_callback' => 'ansico_sanitize_micropost_max_chars',
'default' => 500,
)
);
register_setting(
'ansico_some_plugin_settings',
'ansico_clean_up_profile_settings',
array(
'type' => 'boolean',
'sanitize_callback' => 'ansico_sanitize_checkbox_setting',
'default' => false,
)
);
add_settings_section(
'ansico_some_plugin_main',
__( 'Micropost settings', 'ansico-some-plugin' ),
function() {
echo '<p>' . esc_html__( 'Settings for Ansico SoMe Plugin.', 'ansico-some-plugin' ) . '</p>';
},
'ansico-some-plugin-settings'
);
add_settings_field(
'ansico_micropost_max_chars',
__( 'Maximum characters in Micropost Form', 'ansico-some-plugin' ),
'ansico_render_micropost_max_chars_field',
'ansico-some-plugin-settings',
'ansico_some_plugin_main'
);
add_settings_field(
'ansico_clean_up_profile_settings',
__( 'Clean up profile settings', 'ansico-some-plugin' ),
'ansico_render_clean_up_profile_settings_field',
'ansico-some-plugin-settings',
'ansico_some_plugin_main'
);
}
function ansico_sanitize_checkbox_setting( $value ) {
return ! empty( $value ) ? '1' : '';
}
function ansico_sanitize_micropost_max_chars( $value ) {
$value = intval( $value );
if ( $value < 1 ) {
$value = 500;
}
return $value;
}
function ansico_render_micropost_max_chars_field() {
$value = ansico_get_micropost_max_chars();
echo '<input type="number" min="1" step="1" name="ansico_micropost_max_chars" value="' . esc_attr( $value ) . '" class="small-text" />';
echo '<p class="description">' . esc_html__( 'Default is 500 characters.', 'ansico-some-plugin' ) . '</p>';
}
2026-04-13 18:55:00 +00:00
2026-04-16 16:59:23 +00:00
function ansico_render_clean_up_profile_settings_field() {
$enabled = ! empty( get_option( 'ansico_clean_up_profile_settings', '' ) );
echo '<label for="ansico-clean-up-profile-settings">';
echo '<input type="checkbox" id="ansico-clean-up-profile-settings" name="ansico_clean_up_profile_settings" value="1" ' . checked( $enabled, true, false ) . ' /> ';
echo esc_html__( 'Organize the WordPress profile page into tabs: Profile, Federation, and Other settings.', 'ansico-some-plugin' );
echo '</label>';
}
function ansico_render_settings_page() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
2026-04-13 18:55:00 +00:00
?>
2026-04-16 16:59:23 +00:00
<div class="wrap">
<h1><?php echo esc_html__( 'Ansico SoMe Plugin', 'ansico-some-plugin' ); ?></h1>
<form method="post" action="options.php">
<?php
settings_fields( 'ansico_some_plugin_settings' );
do_settings_sections( 'ansico-some-plugin-settings' );
submit_button();
?>
</form>
</div>
2026-04-13 18:55:00 +00:00
<?php
}
2026-04-16 16:59:23 +00:00
/* ==========================================================================
1. MICROPOST POST TYPE & TAXONOMY
========================================================================== */
2026-04-13 18:55:00 +00:00
2026-04-16 16:59:23 +00:00
/* ==========================================================================
1.5. INKLUDER MICROPOSTS I FORFATTER ARKIV (TIL QUERY LOOP)
========================================================================== */
add_action( 'pre_get_posts', 'ansico_include_microposts_in_author_archive' );
function ansico_include_microposts_in_author_archive( $query ) {
if ( ! is_admin() && $query->is_main_query() && $query->is_author() ) {
$types = $query->get('post_type');
if (empty($types) || $types === 'post') {
$query->set( 'post_type', array( 'post', 'micropost' ) );
} elseif (is_array($types) && !in_array('micropost', $types)) {
$types[] = 'micropost';
$query->set('post_type', $types);
}
}
2026-04-13 18:55:00 +00:00
}
2026-04-16 16:59:23 +00:00
/* ==========================================================================
1.6. FORCE COMMENTS OPEN FOR MICROPOSTS
========================================================================== */
add_filter( 'comments_open', 'ansico_force_micropost_comments_open', 10, 2 );
function ansico_force_micropost_comments_open( $open, $post_id ) {
if ( get_post_type( $post_id ) === 'micropost' ) {
return true;
2026-04-13 18:55:00 +00:00
}
2026-04-16 16:59:23 +00:00
return $open;
2026-04-13 18:55:00 +00:00
}
2026-04-16 16:59:23 +00:00
/* ==========================================================================
1.7. FORMAT MICROPOST COMMENTS (Mastodon & Embeds)
========================================================================== */
add_filter( 'comment_text', 'ansico_format_comment_text', 10, 2 );
function ansico_format_comment_text( $text, $comment = null ) {
if ( ! is_object( $comment ) || get_post_type( $comment->comment_post_ID ) !== 'micropost' ) {
return $text;
2026-04-13 18:55:00 +00:00
}
2026-04-16 16:59:23 +00:00
return ansico_get_formatted_comment_html( $comment, true );
2026-04-13 18:55:00 +00:00
}
2026-04-16 16:59:23 +00:00
function ansico_apply_micropost_text_formatting( $text ) {
$text = (string) $text;
$text = preg_replace('/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/i', '<a href="$2" target="_blank" rel="nofollow ugc noopener">$1</a>', $text);
$text = preg_replace('/(?<!["\w@])@([a-zA-Z0-9_]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})(?!\S)/u', '<a href="https://$2/@$1" target="_blank" rel="nofollow ugc noopener">@$1@$2</a>', $text);
$text = preg_replace_callback('/(?<=^|\s|>|>)#([\p{L}\p{N}_]+)/u', function($m) {
$link = get_term_link($m[1], 'micropost_tag');
if ( is_wp_error($link) ) {
$link = home_url('/micropost-tag/' . sanitize_title($m[1]) . '/');
}
return '<a href="' . esc_url( $link ) . '" class="ansico-hashtag">#' . esc_html($m[1]) . '</a>';
}, $text);
$text = make_clickable($text);
$text = preg_replace('/\*\*(.+?)\*\*/s', '<strong>$1</strong>', $text);
$text = preg_replace('/\*([^\*]+)\*/s', '<em>$1</em>', $text);
$text = preg_replace('/`([^`]+)`/s', '<code>$1</code>', $text);
$text = preg_replace('/^>\s+(.*)/m', '<blockquote>$1</blockquote>', $text);
return $text;
}
function ansico_get_formatted_comment_html( $comment, $already_filtered = false ) {
if ( ! is_object( $comment ) ) {
return '';
}
$raw_text = isset( $comment->comment_content ) ? (string) $comment->comment_content : '';
if ( $raw_text === '' ) {
return '';
}
preg_match( '/(https?:\/\/[^\s()<>{}\[\]]+)/i', $raw_text, $url_matches );
$first_url = ! empty( $url_matches[1] ) ? $url_matches[1] : '';
$text = esc_html( $raw_text );
2026-04-13 18:55:00 +00:00
2026-04-16 16:59:23 +00:00
$text = ansico_apply_micropost_text_formatting( $text );
$text = wpautop( $text );
if ( $first_url ) {
$embed_data = ansico_fetch_metadata_internal( $first_url );
if ( $embed_data && ! empty( $embed_data['title'] ) ) {
$img_html = ! empty( $embed_data['image'] ) ? '<img src="' . esc_url( $embed_data['image'] ) . '" class="ansico-tweet-embed-image" />' : '';
$text .= '<div class="ansico-tweet-embed"><a href="' . esc_url( $first_url ) . '" target="_blank" rel="nofollow noreferrer noopener" style="text-decoration:none; color:inherit; display:block;">' . $img_html . '<div class="ansico-tweet-embed-content"><span class="ansico-tweet-embed-domain">' . esc_html( $embed_data['domain'] ) . '</span><h3 class="ansico-tweet-embed-title">' . esc_html( $embed_data['title'] ) . '</h3></div></a></div>';
}
}
return ansico_prepare_comment_display_html( $text );
}
function ansico_prepare_comment_display_html( $html ) {
$html = (string) $html;
if ( $html === '' ) {
return '';
}
// Normaliser WordPress-kommentar HTML uden at skabe ekstra luft omkring embeds.
$html = shortcode_unautop( $html );
// Fjern tomme afsnit og linjeskift rundt om embed-kort.
$patterns = array(
'#<p>\s*(<div class="ansico-tweet-embed"[^>]*>)#i',
'#(</div>)\s*</p>#i',
'#<p>\s*(<a [^>]*>\s*<img[^>]*class="ansico-tweet-embed-image"[^>]*>\s*</a>)\s*</p>#i',
'#<p>\s*(<img[^>]*class="ansico-tweet-embed-image"[^>]*>)\s*</p>#i',
'#<p>\s*(<blockquote[^>]*>.*?</blockquote>)\s*</p>#is',
'#<p>\s*</p>#i',
2026-04-13 18:55:00 +00:00
);
2026-04-16 16:59:23 +00:00
$replacements = array('$1', '$1', '$1', '$1', '$1', '');
$html = preg_replace( $patterns, $replacements, $html );
return trim( $html );
}
/* ==========================================================================
1.8. CUSTOM COMMENT MARKUP (Design uden "siger" og med ny opstilling)
========================================================================== */
function ansico_custom_comment_markup($comment, $args, $depth) {
$GLOBALS['comment'] = $comment;
$avatar = get_avatar($comment, 40, '', '', array('class' => 'ansico-tweet-avatar'));
$author_link = get_comment_author_link($comment);
$author_url = '';
if ( is_object( $comment ) && ! empty( $comment->user_id ) ) {
$author_url = get_author_posts_url( (int) $comment->user_id );
} elseif ( is_object( $comment ) && ! empty( $comment->comment_author_url ) ) {
$author_url = $comment->comment_author_url;
}
$avatar_html = $author_url ? '<a class="ansico-comment-avatar-link" href="' . esc_url( $author_url ) . '">' . $avatar . '</a>' : $avatar;
$time_display = get_comment_date( get_option('date_format'), $comment ) . ' &middot; ' . get_comment_time( get_option('time_format'), false, false, $comment );
$like_button = ansico_render_like_button( 'comment', $comment->comment_ID );
?>
<li <?php comment_class('ansico-isolated-comment'); ?> id="comment-<?php comment_ID(); ?>" style="position: relative; display: block !important; list-style: none; margin-bottom: 20px;">
<button class="ansico-copy-btn-comment" onclick="navigator.clipboard.writeText('<?php echo esc_js(get_comment_link($comment)); ?>'); var el=this; el.classList.add('copied'); setTimeout(function(){el.classList.remove('copied');}, 2000);" title="<?php echo esc_attr__( 'Copy link', 'ansico-some-plugin' ); ?>">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</button>
<div class="ansico-comment-inner-wrap" style="display: flex; gap: 12px; width: 100%;">
<div class="ansico-comment-avatar-wrap"><?php echo $avatar_html; ?></div>
<div class="ansico-comment-content-wrap" style="flex: 1; min-width: 0;">
<div class="ansico-comment-header-row" style="display: flex; align-items: baseline; gap: 8px; margin-bottom: 2px;">
<div class="ansico-tweet-name" style="font-weight: 700; font-size: 15px; color: #0f1419;"><?php echo $author_link; ?></div>
<div class="ansico-tweet-time" style="font-size: 13px; color: #536471;"><?php echo $time_display; ?></div>
</div>
<div class="ansico-comment-text-body" style="font-size: 15px; color: #0f1419; line-height: 1.4; word-wrap: break-word;">
<?php echo wp_kses_post( ansico_get_formatted_comment_html( $comment ) ); ?>
</div>
<div class="reply-action-wrap ansico-tweet-actions-bottom" style="margin-top: 6px;">
<?php if ( $like_button ) echo $like_button; ?>
<?php
$reply_icon = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align: middle;"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path></svg>';
comment_reply_link(array_merge($args, array(
'depth' => $depth,
'max_depth' => $args['max_depth'],
'reply_text' => $reply_icon
)));
?>
</div>
</div>
</div>
<?php
}
add_action( 'init', 'ansico_register_micropost_type' );
function ansico_register_micropost_type() {
register_post_type( 'micropost', array(
'labels' => array(
'name' => 'Microposts',
'singular_name' => 'Micropost',
),
'public' => true,
'has_archive' => true,
'supports' => array( 'editor', 'author', 'custom-fields', 'comments' ),
'menu_icon' => 'dashicons-edit-page',
'show_in_rest' => true,
'rewrite' => array('slug' => 'micropost'),
));
register_taxonomy( 'micropost_tag', 'micropost', array(
'labels' => array(
'name' => 'Tags',
'singular_name' => 'Tag',
),
'public' => true,
'rewrite' => array( 'slug' => 'micropost-tag' ),
'hierarchical' => false,
'show_in_rest' => true,
'show_admin_column' => true,
));
}
add_filter( 'wp_insert_post_data', function( $data, $postarr ) {
if ( $data['post_type'] === 'micropost' && $data['post_status'] !== 'trash' ) {
if ( empty( $postarr['post_title'] ) || $postarr['post_title'] === 'Auto Draft' || $postarr['post_title'] === '' ) {
$clean_content = strip_tags( $data['post_content'] );
$data['post_title'] = mb_substr( $clean_content, 0, 50 );
}
if ( empty( $data['post_name'] ) ) {
$data['post_name'] = date('YmdHis') . rand(100, 999);
}
}
return $data;
}, 10, 2 );
add_action('save_post_micropost', function($post_id, $post, $update) {
if ( wp_is_post_revision( $post_id ) ) return;
preg_match_all('/#([\p{L}\p{N}_]+)/u', $post->post_content, $matches);
if (!empty($matches[1])) {
wp_set_object_terms( $post_id, $matches[1], 'micropost_tag', false );
}
}, 10, 3);
/* ==========================================================================
2. TEMPLATE STYRING
========================================================================== */
function ansico_get_micropost_ids_matching_search( $search_query ) {
global $wpdb;
$search_query = trim( (string) $search_query );
if ( $search_query === '' ) {
return array();
}
$like = '%' . $wpdb->esc_like( $search_query ) . '%';
2026-04-13 18:55:00 +00:00
2026-04-16 16:59:23 +00:00
$post_ids = $wpdb->get_col( $wpdb->prepare(
"SELECT ID FROM {$wpdb->posts}
WHERE post_type = %s
AND post_status = 'publish'
AND (post_title LIKE %s OR post_content LIKE %s)",
'micropost',
$like,
$like
2026-04-13 18:55:00 +00:00
) );
2026-04-16 16:59:23 +00:00
$comment_post_ids = $wpdb->get_col( $wpdb->prepare(
"SELECT DISTINCT c.comment_post_ID
FROM {$wpdb->comments} c
INNER JOIN {$wpdb->posts} p ON p.ID = c.comment_post_ID
WHERE p.post_type = %s
AND p.post_status = 'publish'
AND c.comment_approved = '1'
AND (c.comment_type = '' OR c.comment_type = 'comment')
AND c.comment_content LIKE %s",
'micropost',
$like
2026-04-13 18:55:00 +00:00
) );
2026-04-16 16:59:23 +00:00
$all_ids = array_unique( array_map( 'intval', array_merge( $post_ids, $comment_post_ids ) ) );
rsort( $all_ids );
return $all_ids;
2026-04-13 18:55:00 +00:00
}
2026-04-16 16:59:23 +00:00
add_action( 'pre_get_posts', 'ansico_apply_micropost_archive_search' );
function ansico_apply_micropost_archive_search( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
2026-04-13 18:55:00 +00:00
2026-04-16 16:59:23 +00:00
if ( $query->is_post_type_archive( 'micropost' ) ) {
$search_query = '';
if ( isset( $_GET['ms'] ) ) {
$search_query = sanitize_text_field( wp_unslash( $_GET['ms'] ) );
} elseif ( isset( $_GET['s'] ) ) {
$search_query = sanitize_text_field( wp_unslash( $_GET['s'] ) );
}
if ( $search_query !== '' ) {
$matching_ids = ansico_get_micropost_ids_matching_search( $search_query );
$query->set( 'post_type', 'micropost' );
$query->set( 's', '' );
$query->set( 'post__in', ! empty( $matching_ids ) ? $matching_ids : array( 0 ) );
$query->set( 'orderby', 'date' );
$query->set( 'order', 'DESC' );
}
}
}
add_filter('template_include', 'ansico_micropost_templates');
function ansico_micropost_templates( $template ) {
// Deaktiveret for enkelte microposts, så din Site Editor skabelon kan bruges.
/* if ( is_singular('micropost') ) {
$plugin_template = plugin_dir_path(__FILE__) . 'templates/single-micropost.php';
if ( file_exists($plugin_template) ) return $plugin_template;
} */
// Brug kun pluginets simple archive-template på det normale micropost-arkiv.
// Ved søgning skal temaets eget layout bruges, så sidebar og globalt site-design bevares.
if ( is_post_type_archive('micropost') ) {
$has_search = false;
if ( isset( $_GET['ms'] ) ) {
$has_search = trim( (string) wp_unslash( $_GET['ms'] ) ) !== '';
} elseif ( isset( $_GET['s'] ) ) {
$has_search = trim( (string) wp_unslash( $_GET['s'] ) ) !== '';
}
if ( ! $has_search ) {
$plugin_template = plugin_dir_path(__FILE__) . 'templates/archive-micropost.php';
if ( file_exists($plugin_template) ) return $plugin_template;
}
}
// Deaktiveret for tags, så din egen Site Editor skabelon kan træde i kraft.
/* if ( is_tax('micropost_tag') ) {
$plugin_template = plugin_dir_path(__FILE__) . 'templates/taxonomy-micropost_tag.php';
if ( file_exists($plugin_template) ) return $plugin_template;
} */
/* if ( is_author() ) {
$plugin_template = plugin_dir_path(__FILE__) . 'templates/author-micropost.php';
if ( file_exists($plugin_template) ) return $plugin_template;
} */
return $template;
}
add_action( 'add_meta_boxes', function() {
add_meta_box( 'ansico_micropost_meta', 'Micropost Details', 'ansico_micropost_meta_html', 'micropost', 'normal', 'high' );
});
function ansico_micropost_meta_html( $post ) {
$url = get_post_meta( $post->ID, 'ansico_micropost_url', true );
$time = get_post_meta( $post->ID, 'ansico_micropost_time', true );
$is_federated = ansico_is_micropost_federated( $post->ID );
wp_nonce_field( 'ansico_micropost_save', 'ansico_micropost_nonce' );
2026-04-13 18:55:00 +00:00
?>
2026-04-16 16:59:23 +00:00
<p><label><strong>Permalink/URL:</strong></label><br><input type="text" name="ansico_micropost_url" value="<?php echo esc_attr($url); ?>" style="width:100%;" /></p>
<p><label><strong>Time:</strong></label><br><input type="text" name="ansico_micropost_time" value="<?php echo esc_attr($time); ?>" style="width:100%;" /></p>
<p>
<label style="display:flex; align-items:center; gap:8px;">
<input type="checkbox" <?php checked( $is_federated ); ?> disabled="disabled" />
<strong><?php echo esc_html__( 'Has been federated', 'ansico-some-plugin' ); ?></strong>
</label>
</p>
<?php
}
add_action( 'save_post', function( $post_id ) {
if ( !isset($_POST['ansico_micropost_nonce']) || !wp_verify_nonce($_POST['ansico_micropost_nonce'], 'ansico_micropost_save') ) return;
if ( isset($_POST['ansico_micropost_url']) ) update_post_meta( $post_id, 'ansico_micropost_url', sanitize_text_field( $_POST['ansico_micropost_url'] ) );
if ( isset($_POST['ansico_micropost_time']) ) update_post_meta( $post_id, 'ansico_micropost_time', sanitize_text_field( $_POST['ansico_micropost_time'] ) );
});
function ansico_get_activitypub_visibility_meta_key() {
return 'activitypub_content_visibility';
}
function ansico_get_activitypub_status_meta_key() {
return 'activitypub_status';
}
function ansico_is_micropost_federated( $post_id ) {
$post_id = intval( $post_id );
if ( $post_id < 1 || get_post_type( $post_id ) !== 'micropost' ) {
return false;
}
if ( '1' === (string) get_post_meta( $post_id, '_ansico_has_been_federated', true ) ) {
return true;
}
$visibility = strtolower( (string) get_post_meta( $post_id, ansico_get_activitypub_visibility_meta_key(), true ) );
$status = strtolower( (string) get_post_meta( $post_id, ansico_get_activitypub_status_meta_key(), true ) );
if ( $visibility === 'public' && in_array( $status, array( 'federated', 'scheduled', 'processing', 'sent', 'success', 'done' ), true ) ) {
return true;
}
return false;
}
function ansico_sync_micropost_federation_meta( $post_id ) {
$post_id = intval( $post_id );
if ( $post_id < 1 || get_post_type( $post_id ) !== 'micropost' ) {
return;
}
if ( ansico_is_micropost_federated( $post_id ) ) {
update_post_meta( $post_id, '_ansico_has_been_federated', '1' );
}
}
add_action( 'save_post_micropost', 'ansico_sync_micropost_federation_meta', 20 );
function ansico_mark_micropost_as_federated( $wp_object ) {
if ( is_object( $wp_object ) && isset( $wp_object->ID ) && get_post_type( $wp_object->ID ) === 'micropost' ) {
update_post_meta( intval( $wp_object->ID ), '_ansico_has_been_federated', '1' );
}
}
add_action( 'activitypub_mark_wp_object_as_federated', 'ansico_mark_micropost_as_federated' );
/* ==========================================================================
3. RENDERING ENGINE
========================================================================== */
function ansico_get_like_count( $object_type, $object_id ) {
$object_id = intval( $object_id );
if ( $object_id < 1 ) {
return 0;
}
if ( $object_type === 'comment' ) {
return max( 0, intval( get_comment_meta( $object_id, '_ansico_like_count', true ) ) );
}
return max( 0, intval( get_post_meta( $object_id, '_ansico_like_count', true ) ) );
}
function ansico_get_user_liked_items( $user_id, $object_type ) {
$meta_key = $object_type === 'comment' ? '_ansico_liked_comments' : '_ansico_liked_posts';
$liked = get_user_meta( intval( $user_id ), $meta_key, true );
return is_array( $liked ) ? array_values( array_unique( array_map( 'intval', $liked ) ) ) : array();
}
function ansico_user_has_liked( $object_type, $object_id, $user_id = 0 ) {
$user_id = $user_id ? intval( $user_id ) : get_current_user_id();
$object_id = intval( $object_id );
if ( $user_id < 1 || $object_id < 1 ) {
return false;
}
return in_array( $object_id, ansico_get_user_liked_items( $user_id, $object_type ), true );
}
function ansico_toggle_like( $object_type, $object_id, $user_id = 0 ) {
$user_id = $user_id ? intval( $user_id ) : get_current_user_id();
$object_id = intval( $object_id );
if ( $user_id < 1 || $object_id < 1 ) {
return new WP_Error( 'ansico_like_forbidden', 'Kun loggede brugere kan like.', array( 'status' => 403 ) );
}
if ( $object_type === 'comment' ) {
$comment = get_comment( $object_id );
if ( ! $comment || intval( $comment->comment_approved ) !== 1 ) {
return new WP_Error( 'ansico_like_invalid_comment', 'Kommentaren findes ikke.', array( 'status' => 404 ) );
}
$liked = ansico_get_user_liked_items( $user_id, 'comment' );
$has_liked = in_array( $object_id, $liked, true );
if ( $has_liked ) {
$liked = array_values( array_diff( $liked, array( $object_id ) ) );
update_user_meta( $user_id, '_ansico_liked_comments', $liked );
$count = max( 0, ansico_get_like_count( 'comment', $object_id ) - 1 );
update_comment_meta( $object_id, '_ansico_like_count', $count );
return array( 'liked' => false, 'count' => $count );
}
$liked[] = $object_id;
update_user_meta( $user_id, '_ansico_liked_comments', array_values( array_unique( array_map( 'intval', $liked ) ) ) );
$count = ansico_get_like_count( 'comment', $object_id ) + 1;
update_comment_meta( $object_id, '_ansico_like_count', $count );
return array( 'liked' => true, 'count' => $count );
}
$post = get_post( $object_id );
if ( ! $post || $post->post_status !== 'publish' || $post->post_type !== 'micropost' ) {
return new WP_Error( 'ansico_like_invalid_post', 'Microposten findes ikke.', array( 'status' => 404 ) );
}
$liked = ansico_get_user_liked_items( $user_id, 'post' );
$has_liked = in_array( $object_id, $liked, true );
if ( $has_liked ) {
$liked = array_values( array_diff( $liked, array( $object_id ) ) );
update_user_meta( $user_id, '_ansico_liked_posts', $liked );
$count = max( 0, ansico_get_like_count( 'post', $object_id ) - 1 );
update_post_meta( $object_id, '_ansico_like_count', $count );
return array( 'liked' => false, 'count' => $count );
}
$liked[] = $object_id;
update_user_meta( $user_id, '_ansico_liked_posts', array_values( array_unique( array_map( 'intval', $liked ) ) ) );
$count = ansico_get_like_count( 'post', $object_id ) + 1;
update_post_meta( $object_id, '_ansico_like_count', $count );
return array( 'liked' => true, 'count' => $count );
}
function ansico_render_like_button( $object_type, $object_id, $extra_classes = '' ) {
$object_id = intval( $object_id );
if ( $object_id < 1 ) {
return '';
}
$count = ansico_get_like_count( $object_type, $object_id );
$is_logged_in = is_user_logged_in();
$has_liked = $is_logged_in ? ansico_user_has_liked( $object_type, $object_id ) : false;
$classes = trim( 'ansico-action-btn ansico-like-btn ' . $extra_classes . ( $has_liked ? ' is-liked' : '' ) );
$disabled_attr = $is_logged_in ? '' : ' disabled aria-disabled="true" tabindex="-1"';
$title = $is_logged_in ? ( $has_liked ? 'Fjern like' : 'Like' ) : 'Log ind for at like';
return '<button class="' . esc_attr( $classes ) . '" type="button" data-ansico-like data-object-type="' . esc_attr( $object_type ) . '" data-object-id="' . intval( $object_id ) . '" title="' . esc_attr( $title ) . '" aria-label="' . esc_attr( $title ) . '"' . $disabled_attr . '><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 21s-6.7-4.35-9.33-8.28C.9 10.13 1.29 6.5 4.35 4.77c2.03-1.15 4.53-.73 6.15.96 1.62-1.69 4.12-2.11 6.15-.96 3.06 1.73 3.45 5.36 1.68 7.95C18.7 16.65 12 21 12 21z"></path></svg><span class="ansico-like-count">' . intval( $count ) . '</span></button>';
}
function ansico_get_tweet_html($author_id, $text, $time_str, $source_url, $embed_data = null, $post_id = 0) {
$name = get_the_author_meta( 'display_name', $author_id );
$avatar = get_avatar_url( $author_id, array( 'size' => 50 ) );
if (!$embed_data) {
preg_match('/(?<!href=")(?<!src=")((https?:\/\/[^\s()<>{}\[\]]+))/i', $text, $matches);
if ($matches) { $embed_data = ansico_fetch_metadata_internal($matches[0]); }
}
$time_display = $time_str;
if ( strtotime($time_str) ) {
$ts = strtotime($time_str);
$time_display = wp_date(get_option('date_format'), $ts) . ' &middot; ' . wp_date(get_option('time_format'), $ts);
}
$text = ansico_apply_micropost_text_formatting( $text );
$comment_count = $post_id ? get_comments_number($post_id) : 0;
$permalink = $post_id ? get_permalink($post_id) : $source_url;
$like_button = $post_id ? ansico_render_like_button( 'post', $post_id ) : '';
$is_federated = $post_id ? ansico_is_micropost_federated( $post_id ) : false;
ob_start(); ?>
<div class="ansico-micropost-wrapper">
<div class="ansico-some-tweet" id="micropost-<?php echo $post_id; ?>">
<?php if ( $is_federated || $permalink ) : ?>
<div class="ansico-top-right-icons" style="position:absolute; top:12px; right:12px; display:flex; align-items:center; gap:8px; z-index:10;">
<?php if ( $is_federated ) : ?>
<span class="ansico-federated-icon-top" title="<?php echo esc_attr__( 'Federated', 'ansico-some-plugin' ); ?>" aria-label="<?php echo esc_attr__( 'Federated', 'ansico-some-plugin' ); ?>" style="display:flex; align-items:center; justify-content:center; width:32px; height:32px; color:#536471;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"></circle><path d="M3 12h18"></path><path d="M12 3a14.5 14.5 0 0 1 4 9 14.5 14.5 0 0 1-4 9 14.5 14.5 0 0 1-4-9 14.5 14.5 0 0 1 4-9Z"></path></svg>
</span>
<?php endif; ?>
<?php if ($permalink) : ?>
<button class="ansico-copy-btn-top" style="position:static !important; top:auto !important; right:auto !important; margin:0 !important;" onclick="navigator.clipboard.writeText('<?php echo esc_js($permalink); ?>'); var el=this; el.classList.add('copied'); setTimeout(function(){el.classList.remove('copied');}, 2000);" title="<?php echo esc_attr__( 'Copy link', 'ansico-some-plugin' ); ?>">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</button>
<?php endif; ?>
</div>
<?php endif; ?>
<a href="<?php echo esc_url(get_author_posts_url($author_id)); ?>" class="ansico-tweet-avatar-link">
<img src="<?php echo esc_url($avatar); ?>" class="ansico-tweet-avatar" alt="" />
</a>
<div class="ansico-tweet-content">
<div class="ansico-tweet-header">
<a href="<?php echo esc_url(get_author_posts_url($author_id)); ?>" class="ansico-tweet-name-link">
<span class="ansico-tweet-name"><?php echo esc_html($name); ?></span>
</a>
<span class="ansico-tweet-time"><?php echo wp_kses_post($time_display); ?></span>
</div>
<div class="ansico-tweet-text"><?php echo wp_kses_post(wpautop($text)); ?></div>
<?php if ($embed_data && !empty($embed_data['title'])) : ?>
<div class="ansico-tweet-embed">
<a href="<?php echo esc_url($matches[0] ?? $source_url); ?>" target="_blank" rel="nofollow noreferrer" style="text-decoration:none; color:inherit; display:block;">
<?php if (!empty($embed_data['image'])) : ?><img src="<?php echo esc_url($embed_data['image']); ?>" class="ansico-tweet-embed-image" /><?php endif; ?>
<div class="ansico-tweet-embed-content">
<span class="ansico-tweet-embed-domain"><?php echo esc_html($embed_data['domain']); ?></span>
<h3 class="ansico-tweet-embed-title"><?php echo esc_html($embed_data['title']); ?></h3>
</div>
</a>
</div>
<?php endif; ?>
<div class="ansico-tweet-actions-bottom">
<?php if ( $like_button ) echo $like_button; ?>
<a href="<?php echo esc_url($permalink); ?>#respond" class="ansico-action-btn ansico-comment-btn" title="<?php echo esc_attr__( 'Reply', 'ansico-some-plugin' ); ?>">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path></svg>
<span class="ansico-comment-count"><?php echo intval($comment_count); ?></span>
</a>
</div>
</div>
</div>
<?php
// Inkluder kommentarspor på enkelt-visning
if ( is_singular('micropost') && get_queried_object_id() == $post_id ) : ?>
<div class="ansico-comments-area">
<?php
$comments = get_comments(array('post_id' => $post_id, 'status' => 'approve', 'order' => 'ASC'));
if ($comments) {
echo '<h3 class="ansico-comments-title">' . esc_html__( 'Replies', 'ansico-some-plugin' ) . '</h3>';
echo '<ul class="ansico-comment-list">';
wp_list_comments(array(
'style' => 'ul',
'short_ping' => true,
'callback' => 'ansico_custom_comment_markup',
), $comments);
echo '</ul>';
}
if ( is_user_logged_in() ) {
comment_form(array(
'title_reply' => '',
'title_reply_to' => '',
'comment_notes_before' => '',
'class_submit' => 'ansico-twitter-reply-btn',
'label_submit' => __( 'Reply', 'ansico-some-plugin' ),
'class_form' => 'ansico-twitter-reply-form',
'logged_in_as' => '',
'must_log_in' => '',
'comment_field' => '<div class="ansico-reply-field-container"><img class="ansico-reply-user-avatar" src="' . get_avatar_url(get_current_user_id(), array('size' => 48)) . '" alt="" /><textarea id="comment" name="comment" placeholder="' . esc_attr__( 'Write your reply...', 'ansico-some-plugin' ) . '" required></textarea></div>',
), $post_id);
}
?>
</div>
<?php endif; ?>
</div>
<?php return ob_get_clean();
}
add_filter( 'preprocess_comment', 'ansico_set_logged_in_comment_author_url' );
function ansico_set_logged_in_comment_author_url( $commentdata ) {
if ( empty( $commentdata['comment_post_ID'] ) ) {
return $commentdata;
}
$post_id = intval( $commentdata['comment_post_ID'] );
if ( $post_id < 1 || get_post_type( $post_id ) !== 'micropost' || ! is_user_logged_in() ) {
return $commentdata;
}
$user_id = get_current_user_id();
if ( $user_id > 0 ) {
$commentdata['comment_author_url'] = get_author_posts_url( $user_id );
}
return $commentdata;
}
/* ==========================================================================
4. BLOCKS & API
========================================================================== */
add_action( 'init', 'ansico_some_register_all' );
function ansico_some_register_all() {
wp_register_script(
'ansico-blocks-js',
plugins_url( 'block.js', __FILE__ ),
array( 'wp-blocks', 'wp-element', 'wp-block-editor', 'wp-data', 'wp-components', 'wp-core-data' ),
ANSICO_SOME_PLUGIN_VERSION
);
wp_register_style( 'ansico-style', plugins_url( 'style.css', __FILE__ ), array(), ANSICO_SOME_PLUGIN_VERSION );
register_block_type( 'ansico/some-author', array( 'editor_script' => 'ansico-blocks-js', 'style' => 'ansico-style', 'render_callback' => 'ansico_render_author' ) );
register_block_type( 'ansico/some-comment', array( 'editor_script' => 'ansico-blocks-js', 'style' => 'ansico-style', 'render_callback' => 'ansico_render_comment' ) );
register_block_type( 'ansico/embed-url', array( 'editor_script' => 'ansico-blocks-js', 'style' => 'ansico-style' ) );
register_block_type( 'ansico/micropost-form', array(
'editor_script' => 'ansico-blocks-js',
'style' => 'ansico-style',
'render_callback' => 'ansico_render_micropost_form'
) );
register_block_type( 'ansico/micropost-search', array( 'editor_script' => 'ansico-blocks-js', 'style' => 'ansico-style', 'render_callback' => 'ansico_render_micropost_search' ) );
register_block_type( 'ansico/micropost-list', array(
'editor_script' => 'ansico-blocks-js',
'style' => 'ansico-style',
'render_callback' => 'ansico_render_micropost_list',
'attributes' => array(
'postsPerPage' => array(
'type' => 'number',
'default' => 20,
),
'tagFilter' => array(
'type' => 'string',
'default' => '',
),
),
) );
register_block_type( 'ansico/micropost-comments', array(
'editor_script' => 'ansico-blocks-js',
'style' => 'ansico-style',
'render_callback' => 'ansico_render_micropost_comments',
'attributes' => array(
'commentsToShow' => array(
'type' => 'number',
'default' => 5,
),
),
) );
register_block_type( 'ansico/micropost-top-tags', array(
'editor_script' => 'ansico-blocks-js',
'style' => 'ansico-style',
'render_callback' => 'ansico_render_micropost_top_tags',
'attributes' => array(
'tagsToShow' => array(
'type' => 'number',
'default' => 10,
),
),
) );
register_block_type( 'ansico/micropost-activity', array(
'editor_script' => 'ansico-blocks-js',
'style' => 'ansico-style',
'render_callback' => 'ansico_render_micropost_activity',
'attributes' => array(
'itemsPerPage' => array(
'type' => 'number',
'default' => 10,
),
),
) );
}
function ansico_get_author_micropost_comment_count( $author_id ) {
$author_id = intval( $author_id );
if ( $author_id < 1 ) {
return 0;
}
return (int) get_comments( array(
'user_id' => $author_id,
'status' => 'approve',
'post_type' => 'micropost',
'type' => 'comment',
'count' => true,
) );
}
function ansico_get_social_profile_fields() {
return array(
'facebook' => array( 'label' => 'Facebook', 'abbr' => 'f' ),
'twitter' => array( 'label' => 'Twitter/X', 'abbr' => 'X' ),
'bluesky' => array( 'label' => 'Bluesky', 'abbr' => 'B' ),
'threads' => array( 'label' => 'Threads', 'abbr' => '@' ),
'mastodon' => array( 'label' => 'Mastodon', 'abbr' => 'M' ),
'instagram' => array( 'label' => 'Instagram', 'abbr' => 'I' ),
'linkedin' => array( 'label' => 'LinkedIn', 'abbr' => 'in' ),
'friendica' => array( 'label' => 'Friendica', 'abbr' => 'F' ),
'pixelfed' => array( 'label' => 'Pixelfed', 'abbr' => 'P' ),
);
}
function ansico_get_visible_social_profiles( $user_id ) {
$profiles = array();
foreach ( ansico_get_social_profile_fields() as $key => $field ) {
$url = trim( (string) get_user_meta( $user_id, 'ansico_social_' . $key . '_url', true ) );
$show = ! empty( get_user_meta( $user_id, 'ansico_social_' . $key . '_show', true ) );
if ( $show && ! empty( $url ) ) {
$profiles[ $key ] = array(
'label' => $field['label'],
'abbr' => $field['abbr'],
'url' => esc_url( $url ),
);
}
}
return $profiles;
}
function ansico_render_social_profile_links( $user_id ) {
$profiles = ansico_get_visible_social_profiles( $user_id );
if ( empty( $profiles ) ) {
return '';
}
$html = '<div class="ansico-author-social-links" aria-label="' . esc_attr__( 'Social profiles', 'ansico-some-plugin' ) . '">';
foreach ( $profiles as $key => $profile ) {
$html .= '<a class="ansico-social-link ansico-social-link-' . esc_attr( $key ) . '" href="' . esc_url( $profile['url'] ) . '" target="_blank" rel="nofollow noopener" title="' . esc_attr( $profile['label'] ) . '" aria-label="' . esc_attr( $profile['label'] ) . '"><span class="ansico-social-link-abbr">' . esc_html( $profile['abbr'] ) . '</span></a>';
}
$html .= '</div>';
return $html;
}
function ansico_render_author_intro_html( $author_id ) {
$author_name = get_the_author_meta('display_name', $author_id);
$author_avatar = get_avatar_url($author_id, array('size' => 120));
$post_count = count_user_posts($author_id, 'micropost');
$comment_count = ansico_get_author_micropost_comment_count( $author_id );
$author_bio = get_the_author_meta('description', $author_id);
$author_website = get_the_author_meta('user_url', $author_id);
$social_links = ansico_render_social_profile_links( $author_id );
if ($author_bio) {
$author_bio = esc_html($author_bio);
$author_bio = preg_replace('/(?<=^|\s|>|>)@([a-zA-Z0-9_]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/i', '<a href="https://$2/@$1" target="_blank" rel="nofollow">@$1@$2</a>', $author_bio);
$author_bio = make_clickable($author_bio);
$author_bio = preg_replace('/>https?:\/\/(www\.)?([^<]+)<\/a>/i', '>$2</a>', $author_bio);
$author_bio = wpautop($author_bio);
}
ob_start(); ?>
<div class="ansico-author-intro" style="margin-bottom: 30px;">
<img src="<?php echo esc_url($author_avatar); ?>" class="ansico-author-intro-avatar" />
<div class="ansico-author-intro-content">
<h2 class="ansico-author-intro-name"><?php echo esc_html($author_name); ?></h2>
<?php if ($author_bio) : ?><div class="ansico-author-intro-bio"><?php echo wp_kses_post($author_bio); ?></div><?php endif; ?>
<?php if (!empty($author_website)) : ?>
<div class="ansico-author-intro-website">
<a href="<?php echo esc_url($author_website); ?>" target="_blank" rel="nofollow noopener">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#536471" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align: text-bottom; margin-right: 4px;"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
<?php echo esc_html(preg_replace('#^https?://(www\.)?#', '', $author_website)); ?>
</a>
</div>
<?php endif; ?>
<?php if ( ! empty( $social_links ) ) : ?>
<?php echo $social_links; ?>
<?php endif; ?>
<div class="ansico-author-intro-stats" style="display:flex; gap:16px; flex-wrap:wrap; align-items:center;">
<span><strong><?php echo intval($post_count); ?></strong> <?php echo esc_html__( 'Microposts', 'ansico-some-plugin' ); ?></span>
<span><strong><?php echo intval($comment_count); ?></strong> <?php echo esc_html__( 'Comments', 'ansico-some-plugin' ); ?></span>
2026-04-13 18:55:00 +00:00
</div>
</div>
</div>
<?php
return ob_get_clean();
}
2026-04-16 16:59:23 +00:00
function ansico_render_author() {
if ( is_author() ) {
$author_id = get_queried_object_id();
} else {
$author_id = get_post_field( 'post_author', get_the_ID() ) ?: get_current_user_id();
}
return ansico_render_author_intro_html( $author_id );
}
function ansico_render_comment($attributes) {
2026-04-13 18:55:00 +00:00
$author_id = get_post_field( 'post_author', get_the_ID() ) ?: get_current_user_id();
2026-04-16 16:59:23 +00:00
return ansico_get_tweet_html($author_id, $attributes['text'] ?? '', $attributes['time'] ?? '', $attributes['url'] ?? '', null, get_the_ID());
}
function ansico_render_micropost_form() {
if ( !is_user_logged_in() ) return '';
$max_chars = ansico_get_micropost_max_chars();
ob_start(); ?>
<div class="ansico-micropost-form-wrap">
<textarea id="ansico-micropost-text" placeholder="<?php echo esc_attr__( "What's happening?", 'ansico-some-plugin' ); ?>" maxlength="<?php echo esc_attr( $max_chars ); ?>"></textarea>
<div class="ansico-form-bottom">
<span id="ansico-char-counter">0 / <?php echo esc_html( $max_chars ); ?></span>
<button id="ansico-post-btn" class="wp-element-button"><?php echo esc_html__( 'Post', 'ansico-some-plugin' ); ?></button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const area = document.getElementById('ansico-micropost-text');
const count = document.getElementById('ansico-char-counter');
const btn = document.getElementById('ansico-post-btn');
const maxChars = <?php echo (int) $max_chars; ?>;
if(!area) return;
area.addEventListener('input', () => {
let len = area.value.length;
count.innerText = len + ' / ' + maxChars;
count.style.color = len > maxChars ? '#e0245e' : '#536471';
});
btn.addEventListener('click', () => {
if(!area.value.trim()) return;
if(area.value.length > maxChars) return;
btn.disabled = true;
fetch('<?php echo esc_url(rest_url("ansico/v1/create-micropost")); ?>', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': '<?php echo wp_create_nonce("wp_rest"); ?>' },
body: JSON.stringify({ text: area.value })
}).then(r => r.json()).then(data => {
if(data.success) { area.value = ''; window.location.reload(); } else { btn.disabled = false; }
}).catch(() => {
btn.disabled = false;
});
});
});
</script>
<?php return ob_get_clean();
}
function ansico_render_micropost_list($attributes) {
if ( is_front_page() ) { $paged = ( get_query_var( 'page' ) ) ? get_query_var( 'page' ) : 1; }
else { $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1; }
$search_query = isset($_GET['ms']) ? sanitize_text_field($_GET['ms']) : '';
$is_single_micropost = is_singular('micropost');
$tag_filter = isset($attributes['tagFilter']) ? sanitize_text_field($attributes['tagFilter']) : '';
if ( empty($tag_filter) && is_tax('micropost_tag') ) {
$current_term = get_queried_object();
if ( $current_term && isset($current_term->slug) ) $tag_filter = $current_term->slug;
}
2026-04-13 18:55:00 +00:00
2026-04-16 16:59:23 +00:00
$author_filter = is_author() ? get_queried_object_id() : 0;
$ppp = isset($attributes['postsPerPage']) ? intval($attributes['postsPerPage']) : 20;
$query_args = array(
'post_type' => 'micropost',
'posts_per_page' => $is_single_micropost ? 1 : $ppp,
'paged' => $paged,
'orderby' => 'date',
'order' => 'DESC'
);
if (!empty($search_query)) {
$matching_ids = ansico_get_micropost_ids_matching_search( $search_query );
$query_args['post__in'] = !empty($matching_ids) ? $matching_ids : array(0);
}
if ($is_single_micropost) $query_args['p'] = get_the_ID();
if ($author_filter) $query_args['author'] = $author_filter;
if (!empty($tag_filter)) {
$tag_filter = ltrim($tag_filter, '#');
$query_args['tax_query'] = array(array('taxonomy' => 'micropost_tag', 'field' => 'slug', 'terms' => $tag_filter));
}
$query = new WP_Query($query_args);
ob_start();
// Vis forfatter intro hvis vi er på en forfatter side
if ( is_author() && $paged == 1 && empty($search_query) ) {
$author_id = get_queried_object_id();
echo ansico_render_author_intro_html( $author_id );
}
echo '<div class="ansico-micropost-list">';
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
$url = get_post_meta(get_the_ID(), 'ansico_micropost_url', true);
$time = get_post_meta(get_the_ID(), 'ansico_micropost_time', true);
echo ansico_get_tweet_html(get_the_author_meta('ID'), get_the_content(), $time, $url, null, get_the_ID());
}
if ( !$is_single_micropost ) {
$big = 999999999;
echo '<div class="ansico-pagination">';
echo paginate_links(array(
'base' => str_replace($big, '%#%', esc_url(get_pagenum_link($big))),
'format' => '?paged=%#%',
'current' => max(1, $paged),
'total' => $query->max_num_pages,
'prev_text' => '&laquo; Forrige',
'next_text' => __( 'Next &raquo;', 'ansico-some-plugin' ),
));
echo '</div>';
}
wp_reset_postdata();
}
echo '</div>';
return ob_get_clean();
}
function ansico_render_micropost_top_tags($attributes) {
$tags_to_show = isset($attributes['tagsToShow']) ? intval($attributes['tagsToShow']) : 10;
if ($tags_to_show < 1) {
$tags_to_show = 1;
}
$terms = get_terms(array(
'taxonomy' => 'micropost_tag',
'hide_empty' => true,
'number' => $tags_to_show,
'orderby' => 'count',
'order' => 'DESC',
));
if (is_wp_error($terms) || empty($terms)) {
return '';
2026-04-13 18:55:00 +00:00
}
2026-04-16 16:59:23 +00:00
ob_start();
echo '<div class="ansico-micropost-top-tags-block">';
echo '<div class="ansico-micropost-top-tags-list">';
foreach ($terms as $term) {
$term_link = get_term_link($term);
if (is_wp_error($term_link)) {
continue;
2026-04-13 18:55:00 +00:00
}
2026-04-16 16:59:23 +00:00
echo '<a class="ansico-micropost-tag-pill" href="' . esc_url($term_link) . '">';
echo '<span class="ansico-micropost-tag-name">#' . esc_html($term->name) . '</span>';
echo '<span class="ansico-micropost-tag-count">' . intval($term->count) . '</span>';
echo '</a>';
}
echo '</div>';
echo '</div>';
return ob_get_clean();
}
function ansico_render_micropost_comments($attributes) {
$comments_to_show = isset($attributes['commentsToShow']) ? intval($attributes['commentsToShow']) : 5;
if ($comments_to_show < 1) {
$comments_to_show = 1;
}
$comments = get_comments(array(
'status' => 'approve',
'number' => $comments_to_show,
'orderby' => 'comment_date_gmt',
'order' => 'DESC',
'post_type' => 'micropost',
'type__in' => array('', 'comment'),
));
if (empty($comments)) {
return '';
}
ob_start();
echo '<div class="ansico-micropost-comments-block">';
foreach ($comments as $comment) {
echo ansico_render_activity_comment_item($comment);
}
echo '</div>';
return ob_get_clean();
}
function ansico_render_activity_comment_item( $comment ) {
$post_id = isset($comment->comment_post_ID) ? intval($comment->comment_post_ID) : 0;
if (!$post_id || get_post_type($post_id) !== 'micropost') {
return '';
}
$micropost_permalink = get_permalink($post_id);
$comment_permalink = get_comment_link($comment);
$reply_permalink = $micropost_permalink ? add_query_arg( 'replytocom', intval( $comment->comment_ID ), $micropost_permalink ) . '#respond' : '';
$author_url = '';
if ( is_object( $comment ) && ! empty( $comment->user_id ) ) {
$author_url = get_author_posts_url( (int) $comment->user_id );
} elseif ( is_object( $comment ) && ! empty( $comment->comment_author_url ) ) {
$author_url = $comment->comment_author_url;
}
$author_name = get_comment_author($comment);
$avatar = get_avatar($comment, 40, '', '', array('class' => 'ansico-tweet-avatar'));
$avatar_html = $author_url ? '<a class="ansico-comment-avatar-link" href="' . esc_url( $author_url ) . '">' . $avatar . '</a>' : $avatar;
$time_display = get_comment_date( get_option('date_format'), $comment ) . ' &middot; ' . get_comment_time( get_option('time_format'), false, false, $comment );
$comment_text = ansico_get_formatted_comment_html( $comment );
$reply_count = get_comments(array(
'post_id' => $post_id,
'parent' => intval($comment->comment_ID),
'status' => 'approve',
'count' => true,
'type__in' => array('', 'comment'),
));
$like_button = ansico_render_like_button( 'comment', $comment->comment_ID );
ob_start();
echo '<article class="ansico-activity-item ansico-activity-item-comment ansico-micropost-wrapper">';
echo '<div class="ansico-some-tweet ansico-some-tweet-comment">';
echo '<div class="ansico-activity-comment-top-actions">';
if ($micropost_permalink) {
echo '<a class="ansico-action-btn ansico-activity-comment-top-action" href="' . esc_url($micropost_permalink) . '" title="' . esc_attr__( 'Go to micropost', 'ansico-some-plugin' ) . '" aria-label="' . esc_attr__( 'Go to micropost', 'ansico-some-plugin' ) . '">';
echo '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"></path><path d="M12 5l7 7-7 7"></path></svg>';
echo '</a>';
}
echo "<button class=\"ansico-action-btn ansico-activity-comment-top-action ansico-activity-copy-btn\" type=\"button\" onclick=\"navigator.clipboard.writeText('" . esc_js( $comment_permalink ) . "'); var el=this; el.classList.add('copied'); setTimeout(function(){el.classList.remove('copied');}, 2000);\" title=\"" . esc_attr__( 'Copy comment link', 'ansico-some-plugin' ) . "\" aria-label=\"" . esc_attr__( 'Copy comment link', 'ansico-some-plugin' ) . "\">";
echo '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>';
echo '</button>';
echo '</div>';
echo '<div class="ansico-comment-avatar-wrap">' . $avatar_html . '</div>';
echo '<div class="ansico-tweet-content ansico-comment-content-wrap">';
echo '<div class="ansico-tweet-header ansico-comment-header-row">';
if (!empty($author_url)) {
echo '<a class="ansico-tweet-name-link" href="' . esc_url($author_url) . '" rel="nofollow ugc"><span class="ansico-tweet-name">' . esc_html($author_name) . '</span></a>';
} else {
echo '<span class="ansico-tweet-name">' . esc_html($author_name) . '</span>';
}
echo '<span class="ansico-tweet-time">' . esc_html( wp_strip_all_tags( $time_display ) ) . '</span>';
echo '</div>';
echo '<div class="ansico-tweet-text ansico-comment-text-body">' . wp_kses_post( $comment_text ) . '</div>';
echo '<div class="ansico-tweet-actions-bottom ansico-activity-comment-actions">';
if ($like_button) {
echo $like_button;
}
if ($reply_permalink) {
echo '<a class="ansico-action-btn ansico-comment-btn ansico-activity-reply-btn" href="' . esc_url($reply_permalink) . '" title="' . esc_attr__( 'Reply to this comment', 'ansico-some-plugin' ) . '" aria-label="' . esc_attr__( 'Reply to this comment', 'ansico-some-plugin' ) . '">';
echo '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path></svg>';
echo '<span class="ansico-comment-count">' . intval($reply_count) . '</span>';
echo '</a>';
}
echo '</div>';
echo '</div>';
echo '</div>';
echo '</article>';
return ob_get_clean();
}
function ansico_render_micropost_activity($attributes) {
global $wpdb;
$items_per_page = isset($attributes['itemsPerPage']) ? intval($attributes['itemsPerPage']) : 10;
if ($items_per_page < 1) {
$items_per_page = 1;
}
$current_page = isset($_GET['ansico_activity_page']) ? intval($_GET['ansico_activity_page']) : 1;
if ($current_page < 1) {
$current_page = 1;
}
$offset = ($current_page - 1) * $items_per_page;
$posts_table = $wpdb->posts;
$comments_table = $wpdb->comments;
$total_posts = (int) $wpdb->get_var(
"SELECT COUNT(ID) FROM {$posts_table} WHERE post_type = 'micropost' AND post_status = 'publish'"
);
$total_comments = (int) $wpdb->get_var(
"SELECT COUNT(c.comment_ID)
FROM {$comments_table} c
INNER JOIN {$posts_table} p ON c.comment_post_ID = p.ID
WHERE c.comment_approved = '1'
AND (c.comment_type = '' OR c.comment_type = 'comment')
AND p.post_type = 'micropost'
AND p.post_status = 'publish'"
);
$total_items = $total_posts + $total_comments;
if ($total_items < 1) {
return '';
2026-04-13 18:55:00 +00:00
}
2026-04-16 16:59:23 +00:00
$query = $wpdb->prepare(
"(SELECT ID AS object_id, post_date_gmt AS event_date_gmt, 'post' AS event_type
FROM {$posts_table}
WHERE post_type = 'micropost' AND post_status = 'publish')
UNION ALL
(SELECT c.comment_ID AS object_id, c.comment_date_gmt AS event_date_gmt, 'comment' AS event_type
FROM {$comments_table} c
INNER JOIN {$posts_table} p ON c.comment_post_ID = p.ID
WHERE c.comment_approved = '1'
AND (c.comment_type = '' OR c.comment_type = 'comment')
AND p.post_type = 'micropost'
AND p.post_status = 'publish')
ORDER BY event_date_gmt DESC
LIMIT %d OFFSET %d",
$items_per_page,
$offset
);
$rows = $wpdb->get_results($query);
if (empty($rows)) {
return '';
2026-04-13 18:55:00 +00:00
}
ob_start();
2026-04-16 16:59:23 +00:00
echo '<div class="ansico-micropost-activity-block">';
foreach ($rows as $row) {
if ($row->event_type === 'post') {
$post = get_post((int) $row->object_id);
if (!$post || $post->post_status !== 'publish' || $post->post_type !== 'micropost') {
continue;
}
$url = get_post_meta($post->ID, 'ansico_micropost_url', true);
$time = get_post_meta($post->ID, 'ansico_micropost_time', true);
echo '<div class="ansico-activity-item ansico-activity-item-post">';
echo ansico_get_tweet_html($post->post_author, $post->post_content, $time, $url, null, $post->ID);
echo '</div>';
} else {
$comment = get_comment((int) $row->object_id);
if (!$comment) {
continue;
}
echo ansico_render_activity_comment_item($comment);
}
}
$total_pages = (int) ceil($total_items / $items_per_page);
if ($total_pages > 1) {
$pagination = paginate_links(array(
'base' => esc_url_raw(add_query_arg('ansico_activity_page', '%#%')),
'format' => '',
'current' => $current_page,
'total' => $total_pages,
'type' => 'list',
'prev_text' => '&laquo; Forrige',
'next_text' => __( 'Next &raquo;', 'ansico-some-plugin' ),
));
if ($pagination) {
echo '<nav class="ansico-activity-pagination" aria-label="Micropost aktivitet sider">' . wp_kses_post($pagination) . '</nav>';
}
}
echo '</div>';
return ob_get_clean();
}
add_action( 'rest_api_init', function () {
register_rest_route( 'ansico/v1', '/create-micropost', array( 'methods' => 'POST', 'callback' => 'ansico_rest_create', 'permission_callback' => function() { return is_user_logged_in(); } ) );
register_rest_route( 'ansico/v1', '/toggle-like', array(
'methods' => 'POST',
'callback' => 'ansico_rest_toggle_like',
'permission_callback' => function() { return is_user_logged_in(); },
) );
});
function ansico_rest_create($req) {
$text = sanitize_textarea_field($req['text']);
$max_chars = ansico_get_micropost_max_chars();
if (empty($text)) {
return array('success' => false, 'message' => 'Tom micropost.');
}
if ( function_exists( 'mb_strlen' ) ? mb_strlen( $text ) > $max_chars : strlen( $text ) > $max_chars ) {
return array('success' => false, 'message' => __( 'Micropost is too long.', 'ansico-some-plugin' ));
}
$post_id = wp_insert_post(array('post_type' => 'micropost', 'post_content' => $text, 'post_status' => 'publish', 'comment_status' => 'open'));
if ($post_id) {
update_post_meta($post_id, 'ansico_micropost_time', current_time('mysql'));
update_post_meta($post_id, 'ansico_micropost_url', get_permalink($post_id));
return array('success' => true);
}
return array('success' => false, 'message' => __( 'Could not create micropost.', 'ansico-some-plugin' ));
}
function ansico_fetch_metadata_internal($url) {
$response = wp_remote_get( $url );
if ( is_wp_error( $response ) ) return null;
$html = wp_remote_retrieve_body( $response );
libxml_use_internal_errors(true);
$doc = new DOMDocument();
@$doc->loadHTML( mb_convert_encoding( $html, 'HTML-ENTITIES', 'UTF-8' ) );
libxml_clear_errors();
$res = array('title' => '', 'image' => '', 'domain' => str_replace('www.', '', wp_parse_url($url, PHP_URL_HOST)));
$tags = $doc->getElementsByTagName('meta');
foreach ($tags as $tag) {
if ($tag->getAttribute('property') === 'og:title') $res['title'] = $tag->getAttribute('content');
if ($tag->getAttribute('property') === 'og:image') $res['image'] = $tag->getAttribute('content');
}
if(empty($res['title'])) { $t = $doc->getElementsByTagName('title'); if($t->length > 0) $res['title'] = $t->item(0)->nodeValue; }
return $res;
}
/* ==========================================================================
5. AVATAR FILTERS
========================================================================== */
add_filter( 'get_avatar_url', function( $url, $id_or_email, $args ) {
$user_id = null;
if ( is_numeric( $id_or_email ) ) { $user_id = $id_or_email; }
elseif ( is_object( $id_or_email ) && isset( $id_or_email->user_id ) ) { $user_id = $id_or_email->user_id; }
if ( $user_id ) {
$custom = get_user_meta( $user_id, 'ansico_avatar_url', true );
if ( $custom ) return $custom;
}
return $url;
}, 10, 3 );
add_action( 'show_user_profile', 'ansico_avatar_field' );
add_action( 'edit_user_profile', 'ansico_avatar_field' );
function ansico_avatar_field($user) {
$url = get_user_meta($user->ID, 'ansico_avatar_url', true);
echo '<h3>' . esc_html__( 'Profilbillede', 'ansico-some-plugin' ) . '</h3><table class="form-table"><tr><th>Profilbillede</th><td><img id="ansico-avatar-preview" src="'.esc_url($url).'" style="width:120px; height:120px; object-fit:cover; display:'.($url?'block':'none').'; border-radius:50%;"/><input type="hidden" name="ansico_avatar_url" id="ansico-avatar-url" value="'.esc_attr($url).'"/><button class="button" id="ansico-upload-button" style="margin-top:10px;">Upload</button> <button class="button" id="ansico-remove-button" style="margin-top:10px;">Remove</button></td></tr></table>';
echo '<h3>' . esc_html__( 'Social profiles', 'ansico-some-plugin' ) . '</h3>';
echo '<table class="form-table" role="presentation">';
foreach ( ansico_get_social_profile_fields() as $key => $field ) {
$profile_url = get_user_meta( $user->ID, 'ansico_social_' . $key . '_url', true );
$show_on_profile = ! empty( get_user_meta( $user->ID, 'ansico_social_' . $key . '_show', true ) );
echo '<tr>';
echo '<th><label for="ansico-social-' . esc_attr( $key ) . '">' . esc_html( $field['label'] ) . '</label></th>';
echo '<td>';
echo '<div style="display:flex; gap:12px; align-items:center; flex-wrap:wrap;">';
echo '<input type="url" class="regular-text" id="ansico-social-' . esc_attr( $key ) . '" name="ansico_social[' . esc_attr( $key ) . '][url]" value="' . esc_attr( $profile_url ) . '" placeholder="https://" />';
echo '<label style="display:inline-flex; align-items:center; gap:6px;"><input type="checkbox" name="ansico_social[' . esc_attr( $key ) . '][show]" value="1" ' . checked( $show_on_profile, true, false ) . ' /> ' . esc_html__( 'Show on profile', 'ansico-some-plugin' ) . '</label>';
echo '</div>';
echo '</td>';
echo '</tr>';
}
echo '</table>';
}
function ansico_rest_toggle_like( WP_REST_Request $request ) {
$object_type = sanitize_key( (string) $request->get_param( 'object_type' ) );
$object_id = intval( $request->get_param( 'object_id' ) );
if ( ! in_array( $object_type, array( 'post', 'comment' ), true ) ) {
return new WP_Error( 'ansico_like_invalid_type', __( 'Invalid like type.', 'ansico-some-plugin' ), array( 'status' => 400 ) );
}
$result = ansico_toggle_like( $object_type, $object_id, get_current_user_id() );
if ( is_wp_error( $result ) ) {
return $result;
}
return rest_ensure_response( array(
'liked' => ! empty( $result['liked'] ),
'count' => intval( $result['count'] ),
) );
}
add_action( 'personal_options_update', 'ansico_save_avatar' );
add_action( 'edit_user_profile_update', 'ansico_save_avatar' );
function ansico_save_avatar($user_id) {
if(isset($_POST['ansico_avatar_url'])) update_user_meta($user_id, 'ansico_avatar_url', esc_url_raw($_POST['ansico_avatar_url']));
$social_input = isset( $_POST['ansico_social'] ) && is_array( $_POST['ansico_social'] ) ? $_POST['ansico_social'] : array();
foreach ( ansico_get_social_profile_fields() as $key => $field ) {
$row = isset( $social_input[ $key ] ) && is_array( $social_input[ $key ] ) ? $social_input[ $key ] : array();
$url = isset( $row['url'] ) ? esc_url_raw( trim( wp_unslash( $row['url'] ) ) ) : '';
$show = ! empty( $row['show'] ) ? '1' : '';
update_user_meta( $user_id, 'ansico_social_' . $key . '_url', $url );
update_user_meta( $user_id, 'ansico_social_' . $key . '_show', $show );
}
}
add_action( 'admin_enqueue_scripts', function( $hook ) {
if ( 'profile.php' === $hook || 'user-edit.php' === $hook ) {
wp_enqueue_media();
wp_enqueue_script( 'ansico-admin', plugins_url( 'admin-script.js', __FILE__ ), array( 'jquery' ), ANSICO_SOME_PLUGIN_VERSION, true );
wp_localize_script(
'ansico-admin',
'ansicoAdminSettings',
array(
'cleanUpProfileSettings' => ! empty( get_option( 'ansico_clean_up_profile_settings', '' ) ),
'labels' => array(
'profile' => __( 'Profile', 'ansico-some-plugin' ),
'federation' => __( 'Federation', 'ansico-some-plugin' ),
'otherSettings' => __( 'Other settings', 'ansico-some-plugin' ),
),
)
);
}
} );
add_action( 'admin_head-profile.php', 'ansico_render_profile_cleanup_admin_css' );
add_action( 'admin_head-user-edit.php', 'ansico_render_profile_cleanup_admin_css' );
function ansico_render_profile_cleanup_admin_css() {
if ( empty( get_option( 'ansico_clean_up_profile_settings', '' ) ) ) {
return;
}
2026-04-13 18:55:00 +00:00
?>
2026-04-16 16:59:23 +00:00
<style>
.ansico-profile-tabs-nav {
display: flex;
gap: 8px;
margin: 20px 0 24px;
border-bottom: 1px solid #dcdcde;
padding-bottom: 0;
}
.ansico-profile-tabs-nav .ansico-profile-tab-button {
border: 1px solid #dcdcde;
border-bottom: none;
background: #f6f7f7;
color: #1d2327;
padding: 10px 14px;
margin: 0;
border-radius: 6px 6px 0 0;
cursor: pointer;
font-weight: 600;
}
.ansico-profile-tabs-nav .ansico-profile-tab-button.is-active {
background: #fff;
position: relative;
top: 1px;
}
.ansico-profile-tab-panel {
display: none;
}
.ansico-profile-tab-panel.is-active {
display: block;
}
.ansico-profile-tab-panel h2:first-child,
.ansico-profile-tab-panel h3:first-child {
margin-top: 0;
}
.ansico-profile-tab-panel {
padding-bottom: 96px;
}
.ansico-profile-card {
background: #fff;
border: 1px solid #dcdcde;
border-radius: 16px;
padding: 18px 22px;
margin: 0 0 18px;
box-shadow: 0 1px 2px rgba(0,0,0,.04);
}
.ansico-profile-card > h2,
.ansico-profile-card > h3 {
margin-top: 0;
margin-bottom: 16px;
}
.ansico-profile-card .form-table th {
width: 220px;
}
.ansico-profile-subheading-row th {
width: auto !important;
font-size: 12px;
text-transform: uppercase;
letter-spacing: .04em;
color: #50575e;
padding-top: 18px;
padding-bottom: 8px;
}
.ansico-profile-inline-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
margin-bottom: 10px;
}
.ansico-profile-inline-label {
display: block;
font-weight: 600;
margin: 0 0 6px;
color: #1d2327;
}
.ansico-profile-inline-control input[type="text"],
.ansico-profile-inline-control input[type="email"],
.ansico-profile-inline-control input[type="url"] {
width: 100%;
}
.ansico-profile-card-avatar .form-table th {
display: none;
}
.ansico-profile-card-avatar .form-table td {
padding-left: 0;
}
.ansico-profile-hero-card {
overflow: hidden;
padding-top: 0;
}
.ansico-profile-hero-card > h2,
.ansico-profile-hero-card > h3 {
padding-top: 18px;
padding-left: 22px;
padding-right: 22px;
margin-bottom: 12px;
}
.ansico-profile-cover-table {
width: min(100%, 820px);
margin: 0 auto 0;
border-collapse: separate;
border-spacing: 0;
}
.ansico-profile-cover-row th {
display: none;
}
.ansico-profile-cover-row td {
padding: 0 0 12px !important;
}
.ansico-profile-cover-row img {
width: 100%;
max-width: none;
height: 180px;
object-fit: cover;
display: block;
border-radius: 16px;
}
.ansico-header-trigger {
width: 100%;
min-height: 180px;
border: 0;
background: #f6f7f7;
padding: 0;
display: block;
cursor: pointer;
overflow: hidden;
border-radius: 16px;
}
.ansico-header-trigger img {
width: 100%;
max-width: none;
height: 180px;
object-fit: cover;
display: block;
border-radius: 16px;
}
.ansico-header-placeholder {
min-height: 180px;
display: flex;
align-items: center;
justify-content: center;
color: #50575e;
font-weight: 600;
}
.ansico-header-hidden-button {
display: none !important;
}
.ansico-header-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-top: 10px;
flex-wrap: wrap;
}
.ansico-header-actions .button,
.ansico-header-actions button,
.ansico-header-actions input[type="button"],
.ansico-header-actions input[type="submit"] {
margin: 0 !important;
}
.ansico-header-remove-button {
margin-top: 0 !important;
}
.ansico-profile-hero-card.has-cover .ansico-avatar-cell {
margin-top: -58px;
margin-left: 48px;
position: relative;
z-index: 2;
}
.ansico-profile-hero-card.has-cover .ansico-avatar-remove-button {
margin-left: 48px;
}
.ansico-avatar-cell {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.ansico-avatar-trigger {
width: 120px;
height: 120px;
border-radius: 999px;
border: 1px solid #dcdcde;
background: #f6f7f7;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
overflow: hidden;
padding: 0;
}
.ansico-avatar-trigger img {
width: 100%;
height: 100%;
object-fit: cover;
display: block !important;
border-radius: 999px;
}
.ansico-avatar-placeholder {
color: #50575e;
font-weight: 600;
}
.ansico-avatar-hidden-button {
display: none !important;
}
.ansico-avatar-remove-button {
margin-top: 0 !important;
}
.ansico-profile-submit-wrap {
margin-top: 24px;
padding: 16px 0 0;
border-top: 1px solid #dcdcde;
display: block;
position: sticky;
bottom: 0;
background: #fff;
z-index: 5;
}
.ansico-profile-submit-wrap .submit,
.ansico-profile-submit-wrap p.submit {
margin: 0;
padding: 0;
}
</style>
<?php
}
function ansico_render_micropost_search() {
$val = '';
if ( isset( $_GET['ms'] ) ) {
$val = esc_attr( wp_unslash( $_GET['ms'] ) );
} elseif ( isset( $_GET['s'] ) ) {
$val = esc_attr( wp_unslash( $_GET['s'] ) );
}
$search_url = get_post_type_archive_link( 'micropost' );
if ( ! $search_url ) {
$search_url = home_url( '/micropost/' );
}
ob_start(); ?>
<div class="ansico-micropost-search-wrap" style="margin-bottom: 20px;">
<form method="get" action="<?php echo esc_url( $search_url ); ?>" style="display: flex; gap: 8px;">
<input type="text" name="ms" value="<?php echo $val; ?>" placeholder="<?php echo esc_attr__( 'Search microposts...', 'ansico-some-plugin' ); ?>" style="flex: 1; border: 1px solid #eff3f4; border-radius: 9999px; padding: 8px 15px;" />
<button type="submit" class="wp-element-button" style="background: #1d9bf0; color: #fff; border: none; border-radius: 9999px; padding: 8px 20px; cursor: pointer; font-weight: bold;"><?php echo esc_html__( 'Search', 'ansico-some-plugin' ); ?></button>
</form>
2026-04-13 18:55:00 +00:00
</div>
2026-04-16 16:59:23 +00:00
<?php return ob_get_clean();
}
/* ==========================================================================
6. FSE / SITE EDITOR OVERRIDES
========================================================================== */
add_filter( 'render_block', 'ansico_force_fse_micropost_layout', 10, 2 );
function ansico_force_fse_micropost_layout( $block_content, $block ) {
if ( is_admin() ) return $block_content;
// Find ud af hvilket indlæg blokken forsøger at vise
$post_id = isset($block['context']['postId']) ? $block['context']['postId'] : get_the_ID();
// Tjek om vi rent faktisk kigger på et micropost
if ( $post_id && get_post_type($post_id) === 'micropost' ) {
// FSE standard-blokke vi VIL skjule, fordi vores tweet-html allerede indeholder denne data
$hidden_blocks = array( 'core/post-title', 'core/post-date', 'core/post-author', 'core/post-author-name', 'core/post-terms', 'core/post-featured-image', 'core/read-more', 'core/avatar', 'core/post-author-biography', 'core/comment-author-name' );
if ( in_array( $block['blockName'], $hidden_blocks ) ) {
return ''; // Skjul blokken
}
// Hvis WordPress forsøger at vise indholdet, overskriver vi det med vores fulde tweet-design
if ( in_array( $block['blockName'], array( 'core/post-content', 'core/post-excerpt' ) ) ) {
wp_enqueue_style('ansico-style'); // Sørg for at plugin CSS indlæses, når standardblokken overskrives
$author_id = get_post_field( 'post_author', $post_id );
$url = get_post_meta($post_id, 'ansico_micropost_url', true);
$time = get_post_meta($post_id, 'ansico_micropost_time', true);
$raw_content = get_post_field( 'post_content', $post_id );
return ansico_get_tweet_html($author_id, $raw_content, $time, $url, null, $post_id);
}
}
return $block_content;
}
add_action( 'wp_footer', 'ansico_focus_script_v2' );
function ansico_focus_script_v2() {
?>
<script>
document.addEventListener('DOMContentLoaded', function() {
function focusComment() {
setTimeout(function() {
var input = document.getElementById('comment');
if (input) {
input.focus();
var val = input.value; input.value = ''; input.value = val;
}
}, 300);
}
if (window.location.hash === '#respond') { focusComment(); }
document.body.addEventListener('click', function(e) {
var replyTrigger = e.target.closest('.comment-reply-link') || e.target.closest('.ansico-comment-btn');
if (replyTrigger) { focusComment(); }
var likeButton = e.target.closest('[data-ansico-like]');
if (!likeButton) {
return;
}
if (likeButton.disabled || likeButton.getAttribute('aria-disabled') === 'true') {
e.preventDefault();
return;
}
e.preventDefault();
if (likeButton.classList.contains('is-busy')) {
return;
}
likeButton.classList.add('is-busy');
fetch('<?php echo esc_url( rest_url( 'ansico/v1/toggle-like' ) ); ?>', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': '<?php echo esc_js( wp_create_nonce( 'wp_rest' ) ); ?>'
},
body: JSON.stringify({
object_type: likeButton.getAttribute('data-object-type'),
object_id: likeButton.getAttribute('data-object-id')
})
}).then(function(response) {
return response.json().then(function(data) {
return { ok: response.ok, data: data };
});
}).then(function(result) {
if (!result.ok) {
throw new Error((result.data && result.data.message) ? result.data.message : __( 'Could not register like.', 'ansico-some-plugin' ));
}
likeButton.classList.toggle('is-liked', !!result.data.liked);
likeButton.setAttribute('title', result.data.liked ? 'Fjern like' : 'Like');
likeButton.setAttribute('aria-label', result.data.liked ? 'Fjern like' : 'Like');
var count = likeButton.querySelector('.ansico-like-count');
if (count) {
count.textContent = parseInt(result.data.count || 0, 10);
}
}).catch(function(error) {
window.alert(error && error.message ? error.message : __( 'Could not register like.', 'ansico-some-plugin' ));
}).finally(function() {
likeButton.classList.remove('is-busy');
});
});
});
</script>
2026-04-13 18:55:00 +00:00
<?php
}