Upload files to "ansico-some-plugin"

This commit is contained in:
Andreas Andersen 2026-04-13 18:55:00 +00:00
parent bc4caa4379
commit 02a3c109ea
4 changed files with 322 additions and 0 deletions

View file

@ -0,0 +1,19 @@
jQuery(document).ready(function($){
var mediaUploader;
$('#ansico-upload-button').click(function(e) {
e.preventDefault();
if (mediaUploader) { mediaUploader.open(); return; }
mediaUploader = wp.media({ title: 'Choose Avatar', button: { text: 'Set as Profile Picture' }, multiple: false });
mediaUploader.on('select', function() {
var attachment = mediaUploader.state().get('selection').first().toJSON();
$('#ansico-avatar-url').val(attachment.url);
$('#ansico-avatar-preview').attr('src', attachment.url).show();
});
mediaUploader.open();
});
$('#ansico-remove-button').click(function(e){
e.preventDefault();
$('#ansico-avatar-url').val('');
$('#ansico-avatar-preview').hide().attr('src', '');
});
});

View file

@ -0,0 +1,176 @@
<?php
/**
* Plugin Name: Ansico SoMe plugin
* Description: Adds a custom avatar upload to user profiles and provides two blocks: an Author Profile and a SoMe Comment block.
* Version: 1.0.0
* Author: Ansico
* Text Domain: ansico-some-plugin
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
add_action( 'show_user_profile', 'ansico_some_avatar_field' );
add_action( 'edit_user_profile', 'ansico_some_avatar_field' );
function ansico_some_avatar_field( $user ) {
$avatar_url = get_user_meta( $user->ID, 'ansico_avatar_url', true );
?>
<h3>Ansico Avatar</h3>
<table class="form-table">
<tr>
<th><label for="ansico-avatar-url">Profile Picture</label></th>
<td>
<img id="ansico-avatar-preview" src="<?php echo esc_url( $avatar_url ); ?>" style="max-width: 150px; display: <?php echo $avatar_url ? 'block' : 'none'; ?>; border-radius: 50%; margin-bottom: 10px;" />
<input type="hidden" name="ansico_avatar_url" id="ansico-avatar-url" value="<?php echo esc_url( $avatar_url ); ?>" class="regular-text" />
<button type="button" class="button" id="ansico-upload-button">Upload / Select Image</button>
<button type="button" class="button" id="ansico-remove-button" style="color: #a00;">Remove</button>
<p class="description">Upload a custom profile picture. This will override Gravatar. If empty, Gravatar or standard logo will be used.</p>
</td>
</tr>
</table>
<?php
}
add_action( 'personal_options_update', 'ansico_some_save_avatar' );
add_action( 'edit_user_profile_update', 'ansico_some_save_avatar' );
function ansico_some_save_avatar( $user_id ) {
if ( ! current_user_can( 'edit_user', $user_id ) ) { return false; }
if ( isset( $_POST['ansico_avatar_url'] ) ) { update_user_meta( $user_id, 'ansico_avatar_url', esc_url_raw( $_POST['ansico_avatar_url'] ) ); }
}
add_action( 'admin_enqueue_scripts', 'ansico_some_admin_scripts' );
function ansico_some_admin_scripts( $hook ) {
if ( $hook === 'profile.php' || $hook === 'user-edit.php' ) {
wp_enqueue_media();
wp_enqueue_script( 'ansico-some-admin-script', plugins_url( 'admin-script.js', __FILE__ ), array( 'jquery' ), '1.0.0', true );
}
}
add_filter( 'get_avatar_url', 'ansico_some_custom_avatar_url', 10, 3 );
function ansico_some_custom_avatar_url( $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; }
elseif ( is_string( $id_or_email ) ) { $user = get_user_by( 'email', $id_or_email ); if ( $user ) { $user_id = $user->ID; } }
if ( $user_id ) {
$custom_avatar = get_user_meta( $user_id, 'ansico_avatar_url', true );
if ( ! empty( $custom_avatar ) ) { return $custom_avatar; }
}
return $url;
}
add_action( 'init', 'ansico_some_register_blocks' );
function ansico_some_register_blocks() {
wp_register_script(
'ansico-some-blocks-script',
plugins_url( 'block.js', __FILE__ ),
array( 'wp-blocks', 'wp-element', 'wp-block-editor', 'wp-data', 'wp-components' ),
'1.0.0'
);
wp_register_style(
'ansico-some-blocks-style',
plugins_url( 'style.css', __FILE__ ),
array(),
'1.0.0'
);
register_block_type( 'ansico/some-author', array(
'editor_script' => 'ansico-some-blocks-script',
'editor_style' => 'ansico-some-blocks-style',
'style' => 'ansico-some-blocks-style',
'render_callback' => 'ansico_some_render_author_block'
) );
register_block_type( 'ansico/some-comment', array(
'editor_script' => 'ansico-some-blocks-script',
'editor_style' => 'ansico-some-blocks-style',
'style' => 'ansico-some-blocks-style',
'render_callback' => 'ansico_some_render_comment_block'
) );
}
function ansico_some_render_author_block( $attributes, $content, $block ) {
$post_id = get_the_ID();
$author_id = get_post_field( 'post_author', $post_id ) ?: get_current_user_id();
$name = get_the_author_meta( 'display_name', $author_id );
$bio = get_the_author_meta( 'description', $author_id );
$avatar_url = get_avatar_url( $author_id, array( 'size' => 100 ) );
ob_start();
?>
<div <?php echo get_block_wrapper_attributes( array( 'class' => 'ansico-compact-author' ) ); ?>>
<div class="ansico-some-author-box">
<img src="<?php echo esc_url( $avatar_url ); ?>" alt="Avatar" class="ansico-some-avatar" />
<div class="ansico-some-info">
<h3 class="ansico-some-name"><?php echo esc_html( $name ); ?></h3>
<div class="ansico-some-bio"><?php echo wp_kses_post( wpautop( $bio ) ); ?></div>
<div class="ansico-some-social-links"><?php echo $content; ?></div>
</div>
</div>
</div>
<?php
return ob_get_clean();
}
function ansico_some_render_comment_block( $attributes ) {
$text = isset( $attributes['text'] ) ? $attributes['text'] : '';
$url = isset( $attributes['url'] ) ? $attributes['url'] : '';
$time = isset( $attributes['time'] ) ? $attributes['time'] : '';
$author_id = get_post_field( 'post_author', get_the_ID() ) ?: get_current_user_id();
$name = get_the_author_meta( 'display_name', $author_id );
$avatar_url = get_avatar_url( $author_id, array( 'size' => 50 ) );
$domain = '';
if ( ! empty( $url ) ) {
$domain = parse_url( $url, PHP_URL_HOST );
$domain = str_replace( 'www.', '', $domain );
}
$time_display = $time;
if ( ! empty( $time ) ) {
$timestamp = strtotime( $time );
if ( $timestamp ) {
$date_format = get_option( 'date_format' );
$time_format = get_option( 'time_format' );
$formatted_time = wp_date( $time_format, $timestamp );
$formatted_date = wp_date( $date_format, $timestamp );
$time_display = $formatted_time . ' &middot; ' . $formatted_date;
}
}
$source_label = __( 'Source:', 'ansico-some-plugin' );
if ( $source_label === 'Source:' ) {
$locale = get_locale();
if ( strpos( $locale, 'da' ) === 0 ) { $source_label = 'Kilde:'; }
elseif ( strpos( $locale, 'sv' ) === 0 ) { $source_label = 'Källa:'; }
elseif ( strpos( $locale, 'no' ) === 0 || strpos( $locale, 'nb' ) === 0 || strpos( $locale, 'nn' ) === 0 ) { $source_label = 'Kilde:'; }
elseif ( strpos( $locale, 'de' ) === 0 ) { $source_label = 'Quelle:'; }
}
ob_start();
?>
<div <?php echo get_block_wrapper_attributes( array( 'class' => 'ansico-some-tweet' ) ); ?>>
<img src="<?php echo esc_url( $avatar_url ); ?>" alt="Avatar" class="ansico-tweet-avatar" />
<div class="ansico-tweet-content">
<div class="ansico-tweet-header">
<span class="ansico-tweet-name"><?php echo esc_html( $name ); ?></span>
<?php if ( $time_display ) : ?><span class="ansico-tweet-time"><?php echo wp_kses_post( $time_display ); ?></span><?php endif; ?>
</div>
<div class="ansico-tweet-text"><?php echo wp_kses_post( wpautop( $text ) ); ?></div>
<?php if ( $domain ) : ?>
<div class="ansico-tweet-footer">
<?php echo esc_html( $source_label ); ?> <a href="<?php echo esc_url( $url ); ?>" target="_blank" rel="nofollow noreferrer"><?php echo esc_html( $domain ); ?></a>
</div>
<?php endif; ?>
</div>
</div>
<?php
return ob_get_clean();
}
?>

View file

@ -0,0 +1,73 @@
( function( blocks, element, blockEditor, data, components ) {
var el = element.createElement;
var useBlockProps = blockEditor.useBlockProps;
var InnerBlocks = blockEditor.InnerBlocks;
var TextControl = components.TextControl;
var TextareaControl = components.TextareaControl;
var useSelect = data.useSelect;
var Spinner = components.Spinner;
blocks.registerBlockType( 'ansico/some-author', {
title: 'Ansico Author Profile', icon: 'admin-users', category: 'widgets', supports: { html: false },
edit: function( props ) {
var blockProps = useBlockProps();
var authorDetails = useSelect( function( select ) {
var core = select( 'core' ); var editor = select( 'core/editor' );
var authorId = editor ? editor.getCurrentPostAttribute( 'author' ) : null;
if ( ! authorId ) { var currentUser = core.getCurrentUser(); authorId = currentUser ? currentUser.id : null; }
return authorId ? core.getUser( authorId ) : null;
}, [] );
if ( ! authorDetails ) { return el( 'div', blockProps, el( Spinner ) ); }
var avatarUrl = authorDetails.avatar_urls ? authorDetails.avatar_urls['96'] : '';
return el( 'div', blockProps,
el( 'div', { className: 'ansico-some-author-box' },
el( 'img', { src: avatarUrl, className: 'ansico-some-avatar', alt: 'Avatar' } ),
el( 'div', { className: 'ansico-some-info' },
el( 'h3', { className: 'ansico-some-name' }, authorDetails.name || 'Author Name' ),
el( 'p', { className: 'ansico-some-bio' }, authorDetails.description || '...' ),
el( 'div', { className: 'ansico-some-social-links' },
el( InnerBlocks, { allowedBlocks: [ 'core/social-links' ], template: [ [ 'core/social-links', {}, [] ] ] } )
)
)
)
);
},
save: function() { return el( 'div', useBlockProps.save(), el( InnerBlocks.Content ) ); }
} );
blocks.registerBlockType( 'ansico/some-comment', {
title: 'Ansico SoMe Comment', icon: 'format-status', category: 'widgets', supports: { html: false },
attributes: { text: { type: 'string', default: '' }, url: { type: 'string', default: '' }, time: { type: 'string', default: '' } },
edit: function( props ) {
var attributes = props.attributes; var setAttributes = props.setAttributes; var blockProps = useBlockProps();
var authorDetails = useSelect( function( select ) {
var core = select( 'core' ); var editor = select( 'core/editor' );
var authorId = editor ? editor.getCurrentPostAttribute( 'author' ) : null;
if ( ! authorId ) { var currentUser = core.getCurrentUser(); authorId = currentUser ? currentUser.id : null; }
return authorId ? core.getUser( authorId ) : null;
}, [] );
if ( ! authorDetails ) { return el( 'div', blockProps, el( Spinner ) ); }
var avatarUrl = authorDetails.avatar_urls ? authorDetails.avatar_urls['48'] : '';
return el( 'div', blockProps,
el( 'div', { className: 'ansico-some-tweet' },
el( 'img', { src: avatarUrl, className: 'ansico-tweet-avatar', alt: 'Avatar' } ),
el( 'div', { className: 'ansico-tweet-content' },
el( 'div', { className: 'ansico-tweet-header' },
el( 'span', { className: 'ansico-tweet-name' }, authorDetails.name || 'Author' ),
el( 'span', { className: 'ansico-tweet-time' }, attributes.time || 'Time' )
),
el( 'div', { className: 'ansico-tweet-text' }, attributes.text || 'Message text...' )
)
),
el( 'div', { style: { marginTop: '10px', borderTop: '1px solid #ddd', paddingTop: '10px' } },
el( TextareaControl, { label: 'Comment Text', value: attributes.text, onChange: function( v ) { setAttributes( { text: v } ); } } ),
el( TextControl, { label: 'Source URL', value: attributes.url, onChange: function( v ) { setAttributes( { url: v } ); } } ),
el( TextControl, { label: 'Time (e.g. 2026-04-12 19:43)', value: attributes.time, onChange: function( v ) { setAttributes( { time: v } ); } } )
)
);
},
save: function() { return null; }
} );
} )( window.wp.blocks, window.wp.element, window.wp.blockEditor, window.wp.data, window.wp.components );

View file

@ -0,0 +1,54 @@
/* Author Profile - Compact */
.ansico-some-author-box { display: flex; gap: 20px; align-items: flex-start; background: #ffffff; padding: 15px; border-radius: 8px; border: 1px solid #eaeaea; }
.ansico-some-avatar { width: 80px; height: 80px; min-width: 80px; border-radius: 50%; object-fit: cover; border: 2px solid #f0f0f0; margin: 0 !important; }
.ansico-some-name { margin: 0 0 5px 0 !important; font-size: 18px; font-weight: 700; }
.ansico-some-bio { margin: 0 0 10px 0 !important; font-size: 14px; color: #444; line-height: 1.5; }
/* SoMe Comment (Tweet Style) - FORCED LAYOUT */
.ansico-some-tweet {
display: flex !important;
flex-direction: row !important;
gap: 12px !important;
align-items: flex-start !important;
padding: 12px;
border: 1px solid #eff3f4;
border-radius: 12px;
background: #ffffff;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
margin-bottom: 24px;
box-sizing: border-box;
}
.ansico-tweet-avatar {
width: 48px !important;
height: 48px !important;
min-width: 48px !important;
border-radius: 50% !important;
object-fit: cover !important;
margin: 0 !important;
display: block !important;
}
.ansico-tweet-content {
flex: 1 1 auto !important;
width: 100%;
}
.ansico-tweet-header {
display: flex !important;
align-items: baseline !important;
flex-wrap: wrap;
gap: 8px !important;
margin-bottom: 2px !important;
}
.ansico-tweet-name { font-weight: 700 !important; color: #0f1419 !important; font-size: 15px !important; }
.ansico-tweet-time { color: #536471 !important; font-size: 14px !important; }
.ansico-tweet-text { font-size: 15px !important; line-height: 1.4 !important; color: #0f1419 !important; }
.ansico-tweet-text p { margin-top: 0; }
.ansico-tweet-footer { font-size: 11px !important; color: #536471 !important; margin-top: 8px !important; }
.ansico-tweet-footer a { color: #1d9bf0 !important; text-decoration: none !important; }
.ansico-tweet-footer a:hover { text-decoration: underline !important; }
.wp-block-ansico-some-author .ansico-some-bio { font-size: 14px; }
.wp-block-ansico-some-author { margin-bottom: 24px; }