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 ) . ' · ' . 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 ) . ' · ' . 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' => '« Forrige' ,
'next_text' => __ ( 'Next »' , '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 ) . ' · ' . 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' => '« Forrige' ,
'next_text' => __ ( 'Next »' , '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 : 8 px ;
margin : 20 px 0 24 px ;
border - bottom : 1 px solid #dcdcde;
padding - bottom : 0 ;
}
. ansico - profile - tabs - nav . ansico - profile - tab - button {
border : 1 px solid #dcdcde;
border - bottom : none ;
background : #f6f7f7;
color : #1d2327;
padding : 10 px 14 px ;
margin : 0 ;
border - radius : 6 px 6 px 0 0 ;
cursor : pointer ;
font - weight : 600 ;
}
. ansico - profile - tabs - nav . ansico - profile - tab - button . is - active {
background : #fff;
position : relative ;
top : 1 px ;
}
. 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 : 96 px ;
}
. ansico - profile - card {
background : #fff;
border : 1 px solid #dcdcde;
border - radius : 16 px ;
padding : 18 px 22 px ;
margin : 0 0 18 px ;
box - shadow : 0 1 px 2 px rgba ( 0 , 0 , 0 , . 04 );
}
. ansico - profile - card > h2 ,
. ansico - profile - card > h3 {
margin - top : 0 ;
margin - bottom : 16 px ;
}
. ansico - profile - card . form - table th {
width : 220 px ;
}
. ansico - profile - subheading - row th {
width : auto ! important ;
font - size : 12 px ;
text - transform : uppercase ;
letter - spacing : . 04 em ;
color : #50575e;
padding - top : 18 px ;
padding - bottom : 8 px ;
}
. ansico - profile - inline - grid {
display : grid ;
grid - template - columns : repeat ( 2 , minmax ( 0 , 1 fr ));
gap : 16 px ;
margin - bottom : 10 px ;
}
. ansico - profile - inline - label {
display : block ;
font - weight : 600 ;
margin : 0 0 6 px ;
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 : 18 px ;
padding - left : 22 px ;
padding - right : 22 px ;
margin - bottom : 12 px ;
}
. ansico - profile - cover - table {
width : min ( 100 % , 820 px );
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 12 px ! important ;
}
. ansico - profile - cover - row img {
width : 100 % ;
max - width : none ;
height : 180 px ;
object - fit : cover ;
display : block ;
border - radius : 16 px ;
}
. ansico - header - trigger {
width : 100 % ;
min - height : 180 px ;
border : 0 ;
background : #f6f7f7;
padding : 0 ;
display : block ;
cursor : pointer ;
overflow : hidden ;
border - radius : 16 px ;
}
. ansico - header - trigger img {
width : 100 % ;
max - width : none ;
height : 180 px ;
object - fit : cover ;
display : block ;
border - radius : 16 px ;
}
. ansico - header - placeholder {
min - height : 180 px ;
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 : 8 px ;
margin - top : 10 px ;
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 : - 58 px ;
margin - left : 48 px ;
position : relative ;
z - index : 2 ;
}
. ansico - profile - hero - card . has - cover . ansico - avatar - remove - button {
margin - left : 48 px ;
}
. ansico - avatar - cell {
display : flex ;
flex - direction : column ;
align - items : flex - start ;
gap : 12 px ;
}
. ansico - avatar - trigger {
width : 120 px ;
height : 120 px ;
border - radius : 999 px ;
border : 1 px 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 : 999 px ;
}
. 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 : 24 px ;
padding : 16 px 0 0 ;
border - top : 1 px 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
}