首先在任何页面上使用@Darren给出的代码。为了简单起见,我将PHP和JS代码组合在一个块中:
<?php $heading_picture = esc_attr(get_option( \'heading_picture\' )); ?>
<input type="hidden" name="heading_picture" id="heading_picture" value="<?php echo $heading_picture; ?>" />
<img id="heading_picture_preview" class="heading-picture" src="<?php echo $heading_picture; ?>" />
<button id="btn_heading_picture" name="btn_heading_picture" class="button default">Choose Picture</button>
<script>
jQuery(function($) {
function myTheme_calculateImageSelectOptions(attachment, controller) {
var control = controller.get( \'control\' );
var flexWidth = !! parseInt( control.params.flex_width, 10 );
var flexHeight = !! parseInt( control.params.flex_height, 10 );
var realWidth = attachment.get( \'width\' );
var realHeight = attachment.get( \'height\' );
var xInit = parseInt(control.params.width, 10);
var yInit = parseInt(control.params.height, 10);
var ratio = xInit / yInit;
controller.set( \'canSkipCrop\', ! control.mustBeCropped( flexWidth, flexHeight, xInit, yInit, realWidth, realHeight ) );
var xImg = xInit;
var yImg = yInit;
if ( realWidth / realHeight > ratio ) {
yInit = realHeight;
xInit = yInit * ratio;
} else {
xInit = realWidth;
yInit = xInit / ratio;
}
var x1 = ( realWidth - xInit ) / 2;
var y1 = ( realHeight - yInit ) / 2;
var imgSelectOptions = {
handles: true,
keys: true,
instance: true,
persistent: true,
imageWidth: realWidth,
imageHeight: realHeight,
minWidth: xImg > xInit ? xInit : xImg,
minHeight: yImg > yInit ? yInit : yImg,
x1: x1,
y1: y1,
x2: xInit + x1,
y2: yInit + y1
};
return imgSelectOptions;
}
function myTheme_setImageFromURL(url, attachmentId, width, height) {
var choice, data = {};
data.url = url;
data.thumbnail_url = url;
data.timestamp = _.now();
if (attachmentId) {
data.attachment_id = attachmentId;
}
if (width) {
data.width = width;
}
if (height) {
data.height = height;
}
$("#heading_picture").val( url );
$("#heading_picture_preview").prop("src", url);
}
function myTheme_setImageFromAttachment(attachment) {
$("#heading_picture").val( attachment.url );
$("#heading_picture_preview").prop("src", attachment.url);
}
var mediaUploader;
$("#btn_heading_picture").on("click", function(e) {
e.preventDefault();
/* We need to setup a Crop control that contains a few parameters
and a method to indicate if the CropController can skip cropping the image.
In this example I am just creating a control on the fly with the expected properties.
However, the controls used by WordPress Admin are api.CroppedImageControl and api.SiteIconControl
*/
var cropControl = {
id: "control-id",
params : {
flex_width : false, // set to true if the width of the cropped image can be different to the width defined here
flex_height : true, // set to true if the height of the cropped image can be different to the height defined here
width : 300, // set the desired width of the destination image here
height : 200, // set the desired height of the destination image here
}
};
cropControl.mustBeCropped = function(flexW, flexH, dstW, dstH, imgW, imgH) {
// If the width and height are both flexible
// then the user does not need to crop the image.
if ( true === flexW && true === flexH ) {
return false;
}
// If the width is flexible and the cropped image height matches the current image height,
// then the user does not need to crop the image.
if ( true === flexW && dstH === imgH ) {
return false;
}
// If the height is flexible and the cropped image width matches the current image width,
// then the user does not need to crop the image.
if ( true === flexH && dstW === imgW ) {
return false;
}
// If the cropped image width matches the current image width,
// and the cropped image height matches the current image height
// then the user does not need to crop the image.
if ( dstW === imgW && dstH === imgH ) {
return false;
}
// If the destination width is equal to or greater than the cropped image width
// then the user does not need to crop the image...
if ( imgW <= dstW ) {
return false;
}
return true;
};
/* NOTE: Need to set this up every time instead of reusing if already there
as the toolbar button does not get reset when doing the following:
mediaUploader.setState(\'library\');
mediaUploader.open();
*/
mediaUploader = wp.media({
button: {
text: \'Select and Crop\', // l10n.selectAndCrop,
close: false
},
states: [
new wp.media.controller.Library({
title: \'Select and Crop\', // l10n.chooseImage,
library: wp.media.query({ type: \'image\' }),
multiple: false,
date: false,
priority: 20,
suggestedWidth: 300,
suggestedHeight: 200
}),
new wp.media.controller.CustomizeImageCropper({
imgSelectOptions: myTheme_calculateImageSelectOptions,
control: cropControl
})
]
});
mediaUploader.on(\'cropped\', function(croppedImage) {
var url = croppedImage.url,
attachmentId = croppedImage.attachment_id,
w = croppedImage.width,
h = croppedImage.height;
myTheme_setImageFromURL(url, attachmentId, w, h);
});
mediaUploader.on(\'skippedcrop\', function(selection) {
var url = selection.get(\'url\'),
w = selection.get(\'width\'),
h = selection.get(\'height\');
myTheme_setImageFromURL(url, selection.id, w, h);
});
mediaUploader.on("select", function() {
var attachment = mediaUploader.state().get( \'selection\' ).first().toJSON();
if ( cropControl.params.width === attachment.width
&& cropControl.params.height === attachment.height
&& ! cropControl.params.flex_width
&& ! cropControl.params.flex_height ) {
myTheme_setImageFromAttachment( attachment );
mediaUploader.close();
} else {
mediaUploader.setState( \'cropper\' );
}
});
mediaUploader.open();
});
});
</script>
然后在一些
plugin 使用以下代码:
add_action( \'wp_enqueue_scripts\', \'vna_wp_enqueue_scripts\' );
function vna_wp_enqueue_scripts() {
wp_enqueue_media();
wp_enqueue_script( \'imgareaselect\', get_bloginfo(\'url\') . \'/wp-includes/js/imgareaselect/jquery.imgareaselect.js\', array( \'jquery\' ), \'1\', true );
wp_enqueue_style( \'imgareaselect\', get_bloginfo(\'url\') . \'/wp-includes/js/imgareaselect/imgareaselect.css\', array(), \'0.9.8\' );
}
add_action( \'setup_theme\',\'vna_wp_ajax_crop_image\', 1 );
function vna_wp_ajax_crop_image() {
global $wp_customize;
if(isset($_REQUEST[\'action\']) && $_REQUEST[\'action\'] == \'crop-image\') {
$post = new WP_Post(new stdClass());
$post->ID = $_REQUEST[\'id\'];
$post->post_type = \'customize_changeset\';
$post->filter = \'raw\';
wp_cache_set($wp_customize->changeset_uuid(), $post, \'customize_changeset_post\');
}
}
Notes:
<有很多依赖于管理JS文件。早些时候,我试图根据测试期间遇到的JS错误,一个接一个地添加这些文件。然后我发现
wp_enqueue_media()
它完成了大部分工作。它仍然无法加载
imgareaselect
JS和CSS,所以我们必须显式地加载它们上述代码必须位于
plugin. 我在一个主题中尝试代码,但它不起作用,因为
setup_theme
在预期事件之后调用主题中的操作(解释如下)。为了避免它,我不得不把它放在插件中只有当用户登录并且
edit_post 对图像的权限。如果没有,您将
0
作为来自
admin-ajax.php
当操作是
crop-image
.黑客之路:在
setup_theme
优先级设置为的操作
1
. 这是因为
class WP_Customize_Manager
有一个
setup_theme
方法,并检查是否存在类型为的post id/post
customize_changeset
. 此外,后过滤器需要
raw
否则,它会尝试从DB为给定的post ID加载post(在本例中,我们将图像ID设置为post ID),这会导致post type设置为
attachment
. 如果检查失败(找不到给定ID类型的post
customize_changeset
) 然后你得到
-1
作为来自
admin-ajax.php
当操作是
crop-image
. 我没有在DB中创建有效的变更集post,而是创建了一个伪post对象并将其添加到缓存中代码看起来不多,但正如我前面提到的
my comment 发现这些情况真的很痛苦。我很高兴我终于成功了。