0

I have a new theme I'm working on and I really need 3 image upload options which trigger the popup media upload box.

I know the customizer is recommended now but it only really makes sense to me to use that for styles (ie. colours and fonts) and still have a theme settings section which is what I have done.

After trying many solutions, Rushabh Dave's solution here works a treat, nearly perfect but not quite...

My issue is I get the popup box, select the image and I then have the URL to that image but when I hit save, the page refreshes but my image isn't saved, the URL disappears therefore I can't pick it up the front end.

I'm not sure what I may be doing wrong.

In functions.php

<?php
// jQuery
wp_enqueue_script('jquery');
// This will enqueue the Media Uploader script  
wp_enqueue_media();
?>
<div>
<label for="image_url">Image</label>
<input type="text" name="image_url" id="image_url" class="regular-text" />
<input type="button" name="upload-btn" id="upload-btn" class="button-secondary" value="Upload Image">

</div>
<script type="text/javascript">
jQuery(document).ready(function($){
$('#upload-btn').click(function(e) {
    e.preventDefault();
    var image = wp.media({ 
        title: 'Upload Image',
        // mutiple: true if you want to upload multiple files at once
        multiple: false
    }).open()
    .on('select', function(e){
        // This will return the selected image from the Media Uploader, the result is an object
        var uploaded_image = image.state().get('selection').first();
        // We convert uploaded_image to a JSON object to make accessing it easier
        // Output to the console uploaded_image
        console.log(uploaded_image);
        var image_url = uploaded_image.toJSON().url;
        // Let's assign the url value to the input field
        $('#image_url').val(image_url);
    });
});
});
</script>

On the front-end

<div><img src="<?php echo $options['image_url']; ?>" /></div>
Community
  • 1
  • 1
jfar_2020
  • 161
  • 4
  • 23
  • Where are you uploading these images? On the front end, back end? – dingo_d Nov 07 '16 at 12:28
  • That's where I am bit confused. I (stupidly) assumed that the user can click 'add media', choose their image which would then upload to the server and save. Then I can call this on the front end to display it. – jfar_2020 Nov 07 '16 at 12:32
  • But sorry, maybe you meant where is the 'add media' option. It is on the backend in the admin in the 'theme settings' section. – jfar_2020 Nov 07 '16 at 12:32
  • Well if you want the user to upload the image to your WordPress, I wouldn't advise using media uploader for that. They will be able to see all the images in your media library ([you could restrict it](http://wordpress.stackexchange.com/questions/1482/restricting-users-to-view-only-media-library-items-they-have-uploaded)). I'd use simple file upload input and load the image using [media_handle_sideload](https://codex.wordpress.org/Function_Reference/media_handle_sideload) – dingo_d Nov 07 '16 at 12:41
  • Sorry, there is some confusion here. I don't want the user to upload to my media library. This is a theme they will use, not mine. I develop themes for clients but don't often use theme settings so I'm having a go adding a whole lot of options so they can update all the options themselves so there is no problem with them seeing their own media library. – jfar_2020 Nov 07 '16 at 12:44
  • Ok, so it's a back end. Where in the admin area do you need the extra image fields? Post page, pages page, taxonomy page, settings? – dingo_d Nov 07 '16 at 12:46
  • I have created a custom 'theme settings' area that contains lots of settings so they can insert their own social media links, text in the footer, analytics code etc. so it's a new settings area, not in the page or post settings. – jfar_2020 Nov 07 '16 at 12:47
  • I'm sure I could use a standard image upload option but wanted to use the media library given people are used to using that already. – jfar_2020 Nov 07 '16 at 12:48

2 Answers2

1

First you want to enqueue your scripts on the backend only. In functions.php add

add_action( 'after_setup_theme', 'yourthemeslug_theme_setup' );
if ( ! function_exists( 'yourthemeslug_theme_setup' ) ) {
    /**
     * Sets up theme defaults and registers support for various WordPress features.
     *
     * Note that this function is hooked into the after_setup_theme hook, which
     * runs before the init hook. The init hook is too late for some features, such
     * as indicating support for post thumbnails.
     *
     * @since  1.0.0
     */
    function yourthemeslug_theme_setup() {

        add_action( 'admin_enqueue_scripts', 'yourthemeslug_backend_scripts' );
    }
}

if ( ! function_exists( 'yourthemeslug_backend_scripts' ) ) {
    /**
     * Enqueue back end scripts and styles.
     *
     * @param  string $hook Hook string to check the page, so that not all scripts are loaded
     *                      unnecessarily on every page.
     * @since 1.0.0
     */
    function yourthemeslug_backend_scripts( $hook ) {
        if ( 'your_subpage_slug' === $hook ) {
            wp_enqueue_media();
            wp_enqueue_script( 'yourthemeslug_image_upload', get_template_directory_uri(). '/js/admin.js', array('jquery') );
        }
    }
}

Or just add to existing after_setup_theme hook, and function that hooks to admin_enqueue_scripts.

The your_subpage_slug in the yourthemeslug_backend_scripts function has to be replaced by the the string that describes your custom built subpage. The best way to see what it is is to do a print_r($hook); before the if condition and see what the string will be (in the inspector it should be right under the body tag).

In your page you should have

<div>
    <label for="image_url">Image</label>
    <div class="image"><img src="<?php echo esc_url( $image ); ?>" /></div>
    <input type="text" name="image_url" id="image_url" class="regular-text" />
    <input type="button" name="upload-btn" id="upload-btn" class="button-secondary" value="Upload Image">
</div>

Where $image is

$image = ( isset( $options['image_url'] ) && '' !== $options['image_url'] ) ? $options['image_url'] : '';

The value you need to fetch from the database.

So when one click on #upload-btn the media uploader has to open.

In the admin.js file that we enqueued add

jQuery( document ).ready(function( $) {
    "use strict";

    $(document).on('click', '#upload-btn', upload_image_button);

    function upload_image_button(e) {
        e.preventDefault();
        var $input_field = $('#image_url');
        var $image = $('.image');
        var custom_uploader = wp.media.frames.file_frame = wp.media({
            title: 'Add Image',
            button: {
                text: 'Add Image'
            },
            multiple: false
        });
        custom_uploader.on('select', function() {
            var attachment = custom_uploader.state().get('selection').first().toJSON();
            $input_field.val(attachment.url);
            $image.html('').html('<img width="254" src="'+attachment.url+'" />');
        });
        custom_uploader.open();
    }

});

This triggers the media upload. But you still need to save it.

In the page where you are saving the options, you need to check if the input field with the image url is set, is not empty and then you can save that to your options (I'd include a nonce check for a safe measure)

if ( isset($_POST['image_url'] ) && '' !== $_POST['image_url'] ) {
    update_option( $_POST['image_url'], 'image_url' );
}

Now I don't know how you are saving these options, since you haven't specified that, but there should be some kind of hook you're using when saving them. Just place this in there, and it should do it.

dingo_d
  • 11,160
  • 11
  • 73
  • 132
  • You could add a remove image button as well that will remove the `img` element and clear the input field on click as well. I haven't tested this but it should work. – dingo_d Nov 07 '16 at 13:18
  • Thanks a lot for this dingo_d, I'm not there yet as currently when I click 'Upload Image', nothing happens, I dont get the media library popup. I have the script in the admin.js which is uploaded to /js/admin.js and the code I ave now is below. I'm sure I've missed something somewhere. – jfar_2020 Nov 07 '16 at 13:57
  • Is the script loaded? Inspect your page and see if the script is loaded. – dingo_d Nov 07 '16 at 14:00
  • No, its not. Should all the references to yourthemeslug_ be changed? – jfar_2020 Nov 07 '16 at 14:13
  • Well yeah, this should be your theme slug. Plus be sure that the condition with the `$hook` checks out ;) – dingo_d Nov 07 '16 at 14:19
  • Sorry, you'll need to bare with me :) So I added print_r($hook); right underneath if ( 'theme_settings' === $hook ) { and all references to yourthemeslug have been changed to the theme name. Now when inspecting the page, all that is underneath the body tag is a script so it looks like this – jfar_2020 Nov 07 '16 at 14:29
  • document.body.className = document.body.className.replace('no-js','js'); – jfar_2020 Nov 07 '16 at 14:29
  • The print_r should go before the if condition but inside the function, so that you could see the name of the hook of your settings page. Once you have that string put it in the if condition instead of 'your_subpage_slug'. Then renove the print_r. – dingo_d Nov 07 '16 at 14:33
  • I've changed that now, where should I be seeing the name of the hook? There is nothing appearing on the settings page – jfar_2020 Nov 07 '16 at 14:36
  • It's usually hidden behind the menu in the admin page. That' why I suggested that you check the inspector. You can add print_r('blaaaaaaaaaa') and try to search it. If that doesn't work for some odd reason, just remove the if condition (but that will enqueue the script in the admin allways, which I generally avoid) – dingo_d Nov 07 '16 at 14:40
  • I did check the inspector but still I just have the body tag then a script, I'm at a loss here as also tried print_r('blaaaaaaaaaa') but there is no sign of blaaaaaaaa in the source either – jfar_2020 Nov 07 '16 at 14:47
  • Even completely removing the if condition doesn't display any hook, should it? – jfar_2020 Nov 07 '16 at 14:48
  • Ok did you just pasted that code in your functions.php? With the after setup theme hook? – dingo_d Nov 07 '16 at 15:08
  • Everything you gave me I pasted into functions.php (other than the admin.js stuff) and the current print_r($hook); is just under 'if ( 'theme_settings' === $hook ) {' – jfar_2020 Nov 07 '16 at 15:10
  • I think the hook name is theme_settings looking at the other code which is why this was there but changed to r($hook); if ('hook name' === $hook ) and still nothing. I appreciate your help with this but hope you don't feel I'm wasting your time, I'm in a bit deep here as don't know WordPress to this level. – jfar_2020 Nov 07 '16 at 15:24
  • Do you have 'after_setup_theme' anywhere in your functions.php? If you do just add the add_action( 'admin_enqueue_scripts', 'yourthemeslug_backend_scripts' ); Inside it and the the second function should go after that. This is the standard procedure :/ I don't know what could be wrong... – dingo_d Nov 07 '16 at 15:29
  • The only reference to after_setup is from your code, I am not using it anywhere else. It's not often I give up but I'm at a loss, do you do freelance work? :) – jfar_2020 Nov 07 '16 at 15:36
  • Yeah check my profile, the contact should be there. This is a minor thing to fix. I'll do it for free. I'll be at my computer in 5+ hours so if you contact me I can look at it then :) – dingo_d Nov 07 '16 at 15:39
  • Dropping you an email now, thanks a lot :) I'll mark your answer as correct as I'm sure it is, it is more my setup that is failing. – jfar_2020 Nov 07 '16 at 15:45
  • Fair enough, I think its too early to mark an answer yet anyway as I dont have the option. – jfar_2020 Nov 07 '16 at 15:47
0
     <?php
 add_action( 'after_setup_theme', 'yourthemeslug_theme_setup' );
 if ( ! function_exists( 'yourthemeslug_theme_setup' ) ) {
 /**
 * Sets up theme defaults and registers support for various WordPress features.
 *
 * Note that this function is hooked into the after_setup_theme hook, which
 * runs before the init hook. The init hook is too late for some features, such
 * as indicating support for post thumbnails.
 *
 * @since  1.0.0
 */
 function yourthemeslug_theme_setup() {

    add_action( 'admin_enqueue_scripts', 'yourthemeslug_backend_scripts' );
 }
 }

 if ( ! function_exists( 'yourthemeslug_backend_scripts' ) ) {
 /**
 * Enqueue back end scripts and styles.
 *
 * @param  string $hook Hook string to check the page, so that not all scripts are loaded
 *                      unnecessarily on every page.
 * @since 1.0.0
 */
 function yourthemeslug_backend_scripts( $hook ) {
    if ( 'theme_settings' === $hook ) {
        wp_enqueue_media();
        wp_enqueue_script( 'yourthemeslug_image_upload', UTTER_TEMPPATH . '/js/admin.js', array('jquery') );
    }
 }
 }
 ?>
 <div>
 <label for="image_url">Image</label>
 <div class="image"><img src="<?php echo esc_url( $image ); ?>" /></div>
 <input type="text" name="image_url" id="image_url" class="regular-text" />
 <input type="button" name="upload-btn" id="upload-btn" class="button-secondary" value="Upload Image">
 </div>

 <?php
 if ( isset($_POST['image_url'] ) && '' !== $_POST['image_url'] ) {
 update_option( $_POST['image_url'], 'image_url' );
 }
 ?>
jfar_2020
  • 161
  • 4
  • 23