From 2ea45c81c49575fddb87a1ee462c3c67d36d9bd0 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Thu, 7 Jul 2022 20:37:54 +0100 Subject: [PATCH 01/50] Console log errors --- assets/js/ssi-wpjm-admin.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/assets/js/ssi-wpjm-admin.js b/assets/js/ssi-wpjm-admin.js index 835314e..bcd9d53 100644 --- a/assets/js/ssi-wpjm-admin.js +++ b/assets/js/ssi-wpjm-admin.js @@ -24,6 +24,9 @@ // what happens on success. success: function( response, status, request ) { + console.log( 'Success' ); + console.log( response ); + // set the image src to the response. $( '.ssi-image' ).attr( 'src', response.url ); @@ -83,6 +86,9 @@ // what happens on success. success: function( response, status, request ) { + console.log( 'Success' ); + console.log( response ); + // set the image src to the response. $( '.ssi-image' ).attr( 'src', placeholderImag ); From 292ae91ecd0ae1a515a1f897f326711e91b4de12 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 11 Jul 2022 22:31:17 +0100 Subject: [PATCH 02/50] New settings page --- assets/css/1.php | 31 -- assets/css/2.php | 67 ---- assets/css/3.php | 45 --- assets/css/4.php | 45 --- assets/css/5.php | 44 --- assets/css/global.php | 75 ----- assets/css/ssi-wpjm-admin.css | 45 +++ assets/img/no-image.jpg | Bin 0 -> 2687 bytes assets/js/ssi-wpjm-admin.js | 203 +++++++----- assets/js/ssi-wpjm-editor.js | 121 +++++++ endpoints/generate.php | 68 ++-- inc/admin-menu.php | 147 +++++++++ inc/enqueue.php | 69 ++++ inc/functions.php | 281 ++++++++++++++++ inc/meta-box.php | 4 +- inc/setttings.php | 606 ++++++++++++++++++++++++++++++---- simple-social-images-wpjm.php | 123 ------- templates/1.php | 3 + templates/2.php | 3 + templates/3.php | 3 + templates/4.php | 3 + templates/5.php | 3 + 22 files changed, 1379 insertions(+), 610 deletions(-) delete mode 100644 assets/css/1.php delete mode 100644 assets/css/2.php delete mode 100644 assets/css/3.php delete mode 100644 assets/css/4.php delete mode 100644 assets/css/5.php delete mode 100644 assets/css/global.php create mode 100644 assets/img/no-image.jpg create mode 100644 assets/js/ssi-wpjm-editor.js create mode 100644 inc/admin-menu.php create mode 100644 inc/enqueue.php create mode 100644 inc/functions.php diff --git a/assets/css/1.php b/assets/css/1.php deleted file mode 100644 index fefd77e..0000000 --- a/assets/css/1.php +++ /dev/null @@ -1,31 +0,0 @@ - \ No newline at end of file diff --git a/assets/css/2.php b/assets/css/2.php deleted file mode 100644 index 77a4fec..0000000 --- a/assets/css/2.php +++ /dev/null @@ -1,67 +0,0 @@ - \ No newline at end of file diff --git a/assets/css/3.php b/assets/css/3.php deleted file mode 100644 index fb5f418..0000000 --- a/assets/css/3.php +++ /dev/null @@ -1,45 +0,0 @@ - \ No newline at end of file diff --git a/assets/css/4.php b/assets/css/4.php deleted file mode 100644 index 1a6aa7e..0000000 --- a/assets/css/4.php +++ /dev/null @@ -1,45 +0,0 @@ - \ No newline at end of file diff --git a/assets/css/5.php b/assets/css/5.php deleted file mode 100644 index a9272a7..0000000 --- a/assets/css/5.php +++ /dev/null @@ -1,44 +0,0 @@ - \ No newline at end of file diff --git a/assets/css/global.php b/assets/css/global.php deleted file mode 100644 index 60e7bc2..0000000 --- a/assets/css/global.php +++ /dev/null @@ -1,75 +0,0 @@ - \ No newline at end of file diff --git a/assets/css/ssi-wpjm-admin.css b/assets/css/ssi-wpjm-admin.css index 70b6810..d73e708 100644 --- a/assets/css/ssi-wpjm-admin.css +++ b/assets/css/ssi-wpjm-admin.css @@ -9,4 +9,49 @@ img.ssi-image { } .wp-core-ui .ssi-hidden { display: none; +} +.ssi-wpjm-input--image, +.ssi-wpjm-input--gallery { + display: none; +} +.ssi-wpjm-image, +.ssi-wpjm-gallery-image{ + border: 4px solid #CCCCCC; + padding: 4px; + margin-top: 20px; + margin-bottom: 20px; +} +.ssi-wpjm-image-wrapper { + position: relative; + width: 166px; +} +.ssi-wpjm-image--remove, +.ssi-wpjm-gallery--remove { + position: absolute; + font-size: 28px; + cursor: pointer; +} + +.ssi-wpjm-gallery-item { + display: inline-block; + margin: 0; + margin-right: 32px; +} +.ssi-wpjm-input-description { + font-style: italic; +} +.form-table .ssi-wpjm-gallery-button, +.form-table .ssi-wpjm-image-button { + margin-bottom: 8px; +} + +.setting-type--section { + border-top: 1px solid #CCCCCC; +} +.setting-type--section th { + font-size: 130%; + font-weight: bold; +} +.ssi-wpjm-settings-form .form-table th { + width: 300px; } \ No newline at end of file diff --git a/assets/img/no-image.jpg b/assets/img/no-image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d2fcabda21686e9528171a3e32f388593f6e5c26 GIT binary patch literal 2687 zcmbW2c{tSDAIHyZ4B5sq){wE4EnAkPB3rmOB`HNj#;%MEcgB{KN}7a=M}&S-;m24i zDI!afromXU?_A4}F)^7t)YE;Q-(T17{e8~)exC1nf6wQ6eZJ>>54)Q^1cZ)S+E@Yz z1ORK!1=z#D&I0dq5deF8um=Eu1d!`K0M3ax79hoG0Kjq}0LHmPHlO7{e~qT*!2XFh zjqEvKcnlka3ktyo1{@_A zf>e+SgD3zf3Ianx*bP9AlM?~i($;I74g!V25nS9z9^M@sLxm84LSQf`9ELz_rhyPS z;{c9A2=CH9%q8OB&aH4sR40b?5Q#A>trI&=Sya^ZxE#yFix!uVlu}YwQQf^qPk*0* zp^>rq5erKzYn!7d98Wr(az1_Lf~VI-Z>*1R2rl$W7(P7WYTUK>>o*c^-b=oplA88s zdPZ(u{-ggCJT81vMlP?Yta|?9<=gs(ca2TWE$=^5J36~)-95d-Bco&E6O&WZGxVk9 zuPcmI=C`#?E>1mvU~&2%WdFm3;&4IXa2T9>lM4b3+XP3!5xcaxgbzD#yI&Gf(1}5c znvous*70C;k1vXOT&D1%74?Rd=$mL;Wd9B<_WvUL1@;eDA20{dEy1BsI2Rla=R$IE zgycnTikFXfOME{iuqB~Q3I7tCGYRK|!Vqu-5)Ma-@bBOk*|ymIoMp+&?ge}>2xl?D zP~af=UYmPU75s|^V}II)m$D7-=WTeYKfEPrky0C!OZcZFRX0q(Ah2Sjmt(g;_<;$(eqWXU6Q(WP@UsZM-K{n2T<$e#Gm0z(2;{wreB zQpFW{Q%-LJX_~|2tA@)eqziUyfgT8gmoC0R8X8?TXE}D0PIwnCG}Y`#VfW8DZEcd-Hvx5 zJ@e9Ko?0Npr3#ys<~OT%EVuoxgP%X2oN`ZDAn~i0qSUfrLX=SG?+CvQkKr7$x_1rJB8-w=bX|>LKuWkUo z9n?JB{LyftfZT~|Gi&yZAbvQ}ha#y5K8q7rkHN?#62gW`;$NfbO>;Zw(kJLyPkd9m z3^MRlh4rnXb=~PW*u6TOMETo)3v7GHeV&1h)Z?IN3{op z^5s7(l;C}LX0IcO#N^E-v3Al{>^)ZBX7d*l&P@*dmKKqG*hlg52bpJ2WoXNJWqHsX zOOw*uT1Ub9?$hVYA2yrBswq$#T;<->B-@w1uF9B@TOnEP(Jfei&x4_tw9UcJbQPP* z_7aq|!t$`IuZ^ECvPxUzmxri~Z*N=MED30hacD7qNJeUn`tA+b5OT&FPuTCUCVvXV zbt`7j9LNdhpI72L{(ILh+Ne>dE`d)+LI?{R&7_}=#NU2AV-B@E zuPX~P61WZL(`ZZLo&_wZL)cJ)V zy>;aTS9;OeaEBKe&W;VY`}z%7-DhJF5t9jDU77=NY#_{1W_lOmLtLrFyRefndVSbO zmCK^P2N}jsEhLWgM?0pR&-aKno&5P*fw4P&Zd+Yu(BkZd*w+Dt%(-m8jlr%!eL{Go zTgqg<-#BrizpC})LYmQfp4jyLW8BdM_wU(+{dB)`pIFW`?%z6bwvR80BQsf33U`m5 zCxvM`mcuR z2@Y|cwE%cp^lOo`%&>+N%;mU`ik$O|%tc&SE zW+)r*e5@EQx-ggR#RhR<$ED)iwW6|a3>--RQf;~s=Kc~_VwW3j()U(QFltzgUUJjK zozZ@9L)i9KI4fH#D4Bsr%LIN2oA0YOJd2ww5_c1fq|$xcN7DNCeNVQ{v|ras%Np=6 z)JmTS9F^9t^7$C@pmSR97JJ|m zG9{)$nzDQjauK42s3CcrYDF3CuMin zFdc%1B`4@A@1#r6J~oo;`|fDYDcxH-WNPiTuIFd6o{jCbmKz+^U!_3e1?6c5-b3x& z(`!kLn)qaIL=PLJQtG5y*noJAf9(@@`v4CU9TbURn%75kkbPw3KNaOY=wk4NGr}}= z6>g88w)VJ(@p2CS1J#So7T8d$BzqG_gJf)?e7xlEyEyk)d8l|zsRS>PRaQw?3Kv|* bEr6)Qj~2!5+{S6rwGA(A8{X}lls$g~)AW*) literal 0 HcmV?d00001 diff --git a/assets/js/ssi-wpjm-admin.js b/assets/js/ssi-wpjm-admin.js index bcd9d53..4035694 100644 --- a/assets/js/ssi-wpjm-admin.js +++ b/assets/js/ssi-wpjm-admin.js @@ -1,121 +1,144 @@ -( function( $ ) { +(function( $ ) { - // hide the deploy spinner. - $( '.ssi-wpjm-spinner' ).hide(); - - // when the deploy button is clicked. - $( document ).on( 'click', '.generate-ssi-image-button', function(e) { - - // prevent the button taking its normal action. - e.preventDefault(); - - // show the deploy spinner. - $( '.ssi-wpjm-spinner' ).show(); - - // get the deploy endpoint url. - var generateEndpointUrl = $( this ).data( 'endpoint-url' ); - - // do the ajax request for job search. - $.ajax({ - - type: 'get', - url: generateEndpointUrl, - - // what happens on success. - success: function( response, status, request ) { - - console.log( 'Success' ); - console.log( response ); - - // set the image src to the response. - $( '.ssi-image' ).attr( 'src', response.url ); - - // change the media id in the delete button. - $( '.delete-ssi-image-button' ).data( 'media-id', response.id ); - - // remove the hidden class for the delete button. - $( '.delete-ssi-image-button' ).removeClass( 'ssi-hidden' ); - - // add the hidden class for the add button. - $( '.generate-ssi-image-button' ).addClass( 'ssi-hidden' ); + // Add Color Picker to all inputs that have .ssi-wpjm-input--color-picker + $( function() { + $( '.ssi-wpjm-input--color-picker' ).wpColorPicker(); + }); - // hide the deploy spinner. - $( '.ssi-wpjm-spinner' ).hide(); + $('body').on('click', '.ssi-wpjm-image-button', function(e) { + e.preventDefault(); + + // get the previous input. + var inputID = $( this ).prev(); + var imgID = $( inputID ).prev().children('img')[0]; + + ssi_wpjm_image_uploader = wp.media({ + title: 'Image', + button: { + text: 'Use this image' + }, + multiple: false + }).on('select', function() { + + var attachment = ssi_wpjm_image_uploader.state().get('selection').first().toJSON(); + console.log( attachment ); + $( inputID ).val(attachment.id); + $( imgID ).attr( 'src', attachment.sizes.thumbnail.url ); + }) + .open(); + }); + + $('body').on('click', '.ssi-wpjm-image--remove', function(e) { + + // get the previous input. + var img = $( this ).prev(); + + $( img ).attr( 'src', $( this ).data( 'placeholder' ) ); + $( '#' + $( this ).data( 'input-id' ) ).val(''); - }, + }); - /* what happens on success */ - error: function( response ) { + $('body').on('click', '.ssi-wpjm-gallery-button', function(e) { - console.log( 'Error' ); - console.log( response ); + e.preventDefault(); - } + // get the current values. + currentValue = $( this ).prev().val(); - }); + // if current value is currently empty. + if ( currentValue === '' ) { + currentValues = []; + } else { + currentValues = currentValue.split( ',' ); + } - }); + // get the current gallery images stored. + var galleryImageIds = $( this ).prev(); - // when the deploy button is clicked. - $( document ).on( 'click', '.delete-ssi-image-button', function(e) { + // get the gallery wrapper element. + var galleryWrapper = galleryImageIds.prev(); - // prevent the button taking its normal action. - e.preventDefault(); + ssi_wpjm_gallery_uploader = wp.media({ + title: 'Image', + button: { + text: 'Use this image' + }, + multiple: true + }).on('select', function() { + + var attachments = ssi_wpjm_gallery_uploader.state().get('selection').toJSON(); - // show the deploy spinner. - $( '.ssi-wpjm-spinner' ).show(); + // loop through each of the attachments selected. + $.each( attachments , function( index, val ) { + console.log( currentValues ); + // if this attachment id is not already in the current values array. + if ( currentValues.indexOf( val.id + '' ) !== 0 ) { - // get the deploy endpoint url. - var deleteEndpoint = $( this ).data( 'endpoint-url' ); + // add attachment ID to the array. + currentValues.push( val.id ); - // get the attachment to delete. - var deleteMediaId = $( this ).data( 'media-id' ); + // output a new figure and image element on the page. - // get the placeholder image url. - var placeholderImag = $( this ).data( 'placeholder-img' ); + // create a new figure element. + imageFigure = $( '' ); + + // create the removal span. + removeSpan = $( '' ); + removeSpan.attr( 'data-image-id', val.id ); + + // add the span for removing. + $( imageFigure ).prepend( removeSpan ); + + imageEl = $( '' ) + imageEl.attr( 'src', val.sizes.thumbnail.url ); - // do the ajax request for job search. - $.ajax({ + // add a new image to the figure. + $( imageFigure ).prepend( imageEl ); - url: deleteEndpoint + deleteMediaId + '/?force=true', - method: 'DELETE', - beforeSend: function ( xhr ) { - xhr.setRequestHeader( 'X-WP-Nonce', wpApiSettings.nonce ); - }, + // append to the gallery wrapper. + $( galleryWrapper ).prepend( imageFigure ); - // what happens on success. - success: function( response, status, request ) { - console.log( 'Success' ); - console.log( response ); + } - // set the image src to the response. - $( '.ssi-image' ).attr( 'src', placeholderImag ); + }); - // set the media id data. - $( '.ssi-image' ).data( 'media-id', deleteMediaId ); + // convert the current values array to a new values string. + newValues = currentValues.toString(); - // remove the hidden class for the delete button. - $( '.delete-ssi-image-button' ).addClass( 'ssi-hidden' ); + // set the input to the new current values. + $( galleryImageIds ).val( newValues ); + + }) + .open(); - // remove the hidden class for the generate button. - $( '.generate-ssi-image-button' ).removeClass( 'ssi-hidden' ); + }); - // hide the deploy spinner. - $( '.ssi-wpjm-spinner' ).hide(); + $('body').on('click', '.ssi-wpjm-gallery--remove', function(e) { + + // get the previous input. + var img = $( this ).prev(); + var figure = $( img ).parent(); - }, + // remove this image. + figure.remove(); - /* what happens on success */ - error: function( response ) { + // get the current value of the background images input. + // NEED TO FIND THIS DYNAMICALLY BASED ON WHERE WE ARE ON CLICK! + var currentImages = $( '#ssi_wpjm_background_images-input').val(); + var currentImagesArray = currentImages.split( ',' ); - console.log( 'Error' ); - console.log( response ); + var imageID = $( this ).data( 'image-id' ); - } + // find the key of this image id in the current images array. + var key = currentImagesArray.indexOf( imageID + '' ); + + // remove the imageID from the current images array. + currentImagesArray.splice( key, 1 ); - }); + // NEED TO FIND THIS DYNAMICALLY BASED ON WHERE WE ARE ON CLICK! + $( '.ssi-wpjm-input--gallery' ).val( currentImagesArray ); }); -} )( jQuery ); \ No newline at end of file +})( jQuery ); \ No newline at end of file diff --git a/assets/js/ssi-wpjm-editor.js b/assets/js/ssi-wpjm-editor.js new file mode 100644 index 0000000..bcd9d53 --- /dev/null +++ b/assets/js/ssi-wpjm-editor.js @@ -0,0 +1,121 @@ +( function( $ ) { + + // hide the deploy spinner. + $( '.ssi-wpjm-spinner' ).hide(); + + // when the deploy button is clicked. + $( document ).on( 'click', '.generate-ssi-image-button', function(e) { + + // prevent the button taking its normal action. + e.preventDefault(); + + // show the deploy spinner. + $( '.ssi-wpjm-spinner' ).show(); + + // get the deploy endpoint url. + var generateEndpointUrl = $( this ).data( 'endpoint-url' ); + + // do the ajax request for job search. + $.ajax({ + + type: 'get', + url: generateEndpointUrl, + + // what happens on success. + success: function( response, status, request ) { + + console.log( 'Success' ); + console.log( response ); + + // set the image src to the response. + $( '.ssi-image' ).attr( 'src', response.url ); + + // change the media id in the delete button. + $( '.delete-ssi-image-button' ).data( 'media-id', response.id ); + + // remove the hidden class for the delete button. + $( '.delete-ssi-image-button' ).removeClass( 'ssi-hidden' ); + + // add the hidden class for the add button. + $( '.generate-ssi-image-button' ).addClass( 'ssi-hidden' ); + + // hide the deploy spinner. + $( '.ssi-wpjm-spinner' ).hide(); + + }, + + /* what happens on success */ + error: function( response ) { + + console.log( 'Error' ); + console.log( response ); + + } + + }); + + }); + + // when the deploy button is clicked. + $( document ).on( 'click', '.delete-ssi-image-button', function(e) { + + // prevent the button taking its normal action. + e.preventDefault(); + + // show the deploy spinner. + $( '.ssi-wpjm-spinner' ).show(); + + // get the deploy endpoint url. + var deleteEndpoint = $( this ).data( 'endpoint-url' ); + + // get the attachment to delete. + var deleteMediaId = $( this ).data( 'media-id' ); + + // get the placeholder image url. + var placeholderImag = $( this ).data( 'placeholder-img' ); + + // do the ajax request for job search. + $.ajax({ + + url: deleteEndpoint + deleteMediaId + '/?force=true', + method: 'DELETE', + beforeSend: function ( xhr ) { + xhr.setRequestHeader( 'X-WP-Nonce', wpApiSettings.nonce ); + }, + + // what happens on success. + success: function( response, status, request ) { + + console.log( 'Success' ); + console.log( response ); + + // set the image src to the response. + $( '.ssi-image' ).attr( 'src', placeholderImag ); + + // set the media id data. + $( '.ssi-image' ).data( 'media-id', deleteMediaId ); + + // remove the hidden class for the delete button. + $( '.delete-ssi-image-button' ).addClass( 'ssi-hidden' ); + + // remove the hidden class for the generate button. + $( '.generate-ssi-image-button' ).removeClass( 'ssi-hidden' ); + + // hide the deploy spinner. + $( '.ssi-wpjm-spinner' ).hide(); + + }, + + /* what happens on success */ + error: function( response ) { + + console.log( 'Error' ); + console.log( response ); + + } + + }); + + }); + +} )( jQuery ); \ No newline at end of file diff --git a/endpoints/generate.php b/endpoints/generate.php index 82b6173..228bc8b 100644 --- a/endpoints/generate.php +++ b/endpoints/generate.php @@ -1,44 +1,68 @@ get_option( 'ssi_wpjm_template' ), - 'job_post' => $job_post, - 'bg_color' => get_option( 'ssi_wpjm_bg_color' ), - 'bg_text_color' => get_option( 'ssi_wpjm_text_bg_color' ), - 'text_color' => get_option( 'ssi_wpjm_text_color' ), - 'image' => wp_get_attachment_image_url( ssi_wpjm_get_random_image_id(), 'full' ), - 'logo' => wp_get_attachment_image_url( get_option( 'ssi_wpjm_logo_id' ), 'full' ), + 'template' => ssi_wpjm_get_template(), + 'post_id' => $post_id, + 'bg_color' => ssi_wpjm_get_bg_color(), + 'bg_text_color' => ssi_wpjm_get_text_bg_color(), + 'text_color' => ssi_wpjm_get_text_color(), + 'title_size' => ssi_wpjm_get_title_font_size(), + 'location_size' => ssi_wpjm_get_location_font_size(), + 'salary_size' => ssi_wpjm_get_salary_font_size(), + 'google_font_url' => ssi_wpjm_get_google_font_url(), + 'google_font_family' => ssi_wpjm_get_google_font_family(), + 'logo_size' => ssi_wpjm_get_logo_size(), + 'image' => wp_get_attachment_image_url( ssi_wpjm_get_random_image_id(), 'full' ), + 'logo' => wp_get_attachment_image_url( get_option( 'ssi_wpjm_logo_id' ), 'full' ), ); // allow the args to be filtered. $args = apply_filters( 'ssi_wpjm_endpoint_generate_args', $args ); // set the location of the template file, making it filterable. -$template_location = apply_filters( 'ssi_wpjm_generate_template_location', SSI_WPJM_LOCATION . '/templates/', $args ); -$template_css_location = apply_filters( 'ssi_wpjm_generate_template_css_location', SSI_WPJM_LOCATION . '/assets/css/', $args ); +$template_location = apply_filters( 'ssi_wpjm_endpoint_generate_template_location', SSI_WPJM_LOCATION . '/templates/', $args ); // start output buffering. ob_start(); -// load the template markup, passing our args. -load_template( SSI_WPJM_LOCATION . '/assets/css/global.php', true, $args ); +?> + + + + + + + + + +
+ +

+ +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ + + +

+ +

+ + + +
+ +
+ + esc_url_raw( rest_url() ), + 'nonce' => wp_create_nonce( 'wp_rest' ) + ) + ); + + // register the js. + wp_enqueue_script( + 'ssi_wpjm_editor_js', + SSI_WPJM_LOCATION_URL . '/assets/js/ssi-wpjm-editor.js', + array( 'jquery' ), + SSI_WPJM_VERSION, + true + ); + + } + + // register the admin css. + wp_enqueue_style( + 'ssi_wpjm_admin_css', + SSI_WPJM_LOCATION_URL . '/assets/css/ssi-wpjm-admin.css', + array(), + SSI_WPJM_VERSION + ); + + // if this is the ssi settings page. + if ( $hook === 'job_listing_page_ssi-wpjm-settings' ) { + + // add the color picker css file + wp_enqueue_style( 'wp-color-picker' ); + + // include our custom jQuery file with WordPress Color Picker dependency + wp_enqueue_script( + 'ssi_wpjm_admin_js', + SSI_WPJM_LOCATION_URL . '/assets/js/ssi-wpjm-admin.js', + array( 'wp-color-picker' ), + false, + true + ); + + if ( ! did_action( 'wp_enqueue_media' ) ) { + wp_enqueue_media(); + } + + } + +} + +add_action( 'admin_enqueue_scripts', 'ssi_wpjm_enqueue_scripts' ); diff --git a/inc/functions.php b/inc/functions.php new file mode 100644 index 0000000..8f5d9d8 --- /dev/null +++ b/inc/functions.php @@ -0,0 +1,281 @@ +ID; + + } + + // get the image id stored as meta. + $image_id = get_post_meta( $post_id, '', true ); + + // if we have no image id. + if ( empty( $image_id ) ) { + return 0; + } + + // get the image url for the associated meta. + $image_url = wp_get_attachment_image_url( $image_id, 'ssi_image' ); + + // if we have no image url. + if ( $image_url === false ) { + return 0; + } + + // go this far, we must have an image. + return apply_filters( 'ssi_wpjm_has_image', $image_id, $post_id ); + +} + +/** + * Sorts an array by the order paramter. + */ +function ssi_wpjm_array_sort_by_order_key( $a, $b ) { + + // if no order paramter is provided. + if ( ! isset( $a['order'] ) ) { + + // set the order to 10. + $a['order'] = 10; + + } + + // if no order paramter is provided. + if ( ! isset( $b['order'] ) ) { + + // set the order to 10. + $b['order'] = 10; + + } + + // if the first array element is the same as the next. + if ( $a['order'] === $b['order'] ) { + return 0; + } + + // return -1 is the first array element is less than the second, otherwise return 1. + return ( $a['order'] < $b['order'] ) ? -1 : 1; + +} + +/** + * Returns an array of all the registered settings. + */ +function ssi_wpjm_get_settings() { + + $settings = apply_filters( + 'ssi_wpjm_settings', + array() + ); + + // sort the settings based on the order parameter. + uasort( $settings, 'ssi_wpjm_array_sort_by_order_key' ); + + // return the settings. + return $settings; + +} + +/** + * Gets the current active template selected. + * + * @return string The template name. + */ +function ssi_wpjm_get_template() { + + return apply_filters( + 'ssi_wpjm_template', + get_option( 'ssi_wpjm_template' ) + ); + +} + +/** + * Gets the current active text color. + */ +function ssi_wpjm_get_text_color() { + + return apply_filters( + 'ssi_wpjm_text_color', + get_option( 'ssi_wpjm_text_color' ) + ); + +} + +/** + * Gets the current active text background color. + */ +function ssi_wpjm_get_text_bg_color() { + + return apply_filters( + 'ssi_wpjm_text_bg_color', + get_option( 'ssi_wpjm_text_bg_color' ) + ); + +} + +/** + * Gets the current active background color. + */ +function ssi_wpjm_get_bg_color() { + + return apply_filters( + 'ssi_wpjm_bg_color', + get_option( 'ssi_wpjm_bg_color' ) + ); + +} + +/** + * Gets the currently uploaded logo attachment ID. + */ +function ssi_wpjm_get_logo_id() { + + return apply_filters( + 'ssi_wpjm_logo_id', + get_option( 'ssi_wpjm_logo' ) + ); + +} + +/** + * Gets the currently set logo size. + */ +function ssi_wpjm_get_logo_size() { + + return apply_filters( + 'ssi_wpjm_logo_size', + get_option( 'ssi_wpjm_logo_size' ) + ); + +} + +/** + * Gets the currently uploaded logo attachment ID. + */ +function ssi_wpjm_get_background_images() { + + // get the background images. + $bg_images = get_option( 'ssi_wpjm_background_images' ); + + // if we have no bg images. + if ( empty( $bg_images ) ) { + return array(); + } + + return apply_filters( + 'ssi_wpjm_background_images', + explode( ',', $bg_images ) + ); + +} + +/** + * Gets the current title font size. + */ +function ssi_wpjm_get_title_font_size() { + + return apply_filters( + 'ssi_wpjm_title_font_size', + get_option( 'ssi_wpjm_title_size' ) + ); + +} + +/** + * Gets the current location font size. + */ +function ssi_wpjm_get_location_font_size() { + + return apply_filters( + 'ssi_wpjm_location_font_size', + get_option( 'ssi_wpjm_location_size' ) + ); + +} + +/** + * Gets the current salary font size. + */ +function ssi_wpjm_get_salary_font_size() { + + return apply_filters( + 'ssi_wpjm_salary_font_size', + get_option( 'ssi_wpjm_salary_size' ) + ); + +} + +/** + * Gets the current Google font URL. + */ +function ssi_wpjm_get_google_font_url() { + + return apply_filters( + 'ssi_wpjm_google_font_url', + get_option( 'ssi_wpjm_google_font_url' ) + ); + +} + +/** + * Gets the current Google font family. + */ +function ssi_wpjm_get_google_font_family() { + + return apply_filters( + 'ssi_wpjm_google_font_family', + get_option( 'ssi_wpjm_google_font_family' ) + ); + +} + +/** + * Grabs a random image ID from those added to the settings page. + */ +function ssi_wpjm_get_random_image_id() { + + // get the image ids from options. + $images = ssi_wpjm_get_background_images(); + + $image_id_key = array_rand( $images, 1 ); + $image_id = $images[ $image_id_key ]; + + return absint( $image_id ); + +} + +/** + * Returns the URL of the SSI API to generate an image. + */ +function ssi_wpjm_generate_api_url() { + + return apply_filters( + 'ssi_wpjm_generate_api_url', + 'https://simplesocialimages.com/ssi-api/v1/generate/' + ); + +} + +/** + * Add the og:image size in WP. + * Allows images to be cropped to og:image size. + */ +function ssi_wpjm_add_image_size() { + + // add the og:image size. + add_image_size( 'ssi_image', 1200, 630, true ); + +} + +add_action( 'after_setup_theme', 'ssi_wpjm_add_image_size' ); diff --git a/inc/meta-box.php b/inc/meta-box.php index f16599f..1090fc2 100644 --- a/inc/meta-box.php +++ b/inc/meta-box.php @@ -45,10 +45,10 @@ function ssi_wpjm_jobs_meta_box_output( $post ) { } ?> -

+

ID ) ) . '">preview it first if you like.', 'simpe-social-images-wpjm' ); ?>

'ssi_wpjm_license_key', - 'label' => __( 'License Key', 'simple-social-images-wpjm' ), - 'desc' => __( 'Enter your license key for the Simple Social Images service. You can signup for a license here.', 'simple-social-images-wpjm' ), - 'type' => 'text', - 'attributes' => array(), - ), - array( - 'name' => 'ssi_wpjm_template', - 'std' => '', - 'label' => __( 'Template', 'simple-social-images-wpjm' ), - 'desc' => __( 'Choose your template for the social sharing images that are generated.', 'simple-social-images-wpjm' ), - 'type' => 'select', - 'options' => array( - '1' => __( 'Template 1', 'simple-social-images-wpjm' ), - '2' => __( 'Template 2', 'simple-social-images-wpjm' ), - '3' => __( 'Template 3', 'simple-social-images-wpjm' ), - '4' => __( 'Template 4', 'simple-social-images-wpjm' ), - '5' => __( 'Template 5', 'simple-social-images-wpjm' ), - ), - 'attributes' => array(), - ), - array( - 'name' => 'ssi_wpjm_text_color', - 'label' => __( 'Text Colour', 'simple-social-images-wpjm' ), - 'desc' => __( 'Enter the hex code of your text colour. The text on your image will be this colour.', 'simple-social-images-wpjm' ), - 'type' => 'text', - 'attributes' => array(), - ), - array( - 'name' => 'ssi_wpjm_text_bg_color', - 'label' => __( 'Text Background Colour', 'simple-social-images-wpjm' ), - 'desc' => __( 'Enter the hex code of your text background colour. The colour behind your text on your image will be this colour.', 'simple-social-images-wpjm' ), - 'type' => 'text', - 'attributes' => array(), - ), - array( - 'name' => 'ssi_wpjm_bg_color', - 'label' => __( 'Background Colour', 'simple-social-images-wpjm' ), - 'desc' => __( 'Enter the hex code of your background colour.', 'simple-social-images-wpjm' ), - 'type' => 'text', - 'attributes' => array(), - ), - array( - 'name' => 'ssi_wpjm_images', - 'label' => __( 'Image IDs', 'simple-social-images-wpjm' ), - 'desc' => __( 'Enter a comma seperated list of WordPress attachment IDs of the images you want to be randomly used when your image is generated.', 'simple-social-images-wpjm' ), - 'type' => 'text', - 'attributes' => array(), - ), + // get the registered settings. + $settings = ssi_wpjm_get_settings(); + + // if we have no settings. + if ( empty( $settings ) ) { + return; + } + + // set up default option args. + $defaults = array( + 'label' => '', + 'option_name' => '', + 'input_type' => 'text', + 'type' => 'string', + 'description' => '', + 'sanitize_callback' => null, + 'show_in_rest' => false, + 'order' => 10, + ); + + // loop through each setting. + foreach ( $settings as $setting ) { + + // merge the args with defaults. + $args = wp_parse_args( $setting, $defaults ); + + // if no setting key is set. + if ( '' === $args['option_name'] ) { + + // don't register the setting. + continue; + + } + + // register this setting. + register_setting( + 'ssi_wpjm_settings', // setting group name. + $args['option_name'], // setting name - the option key. array( - 'name' => 'ssi_wpjm_logo_id', - 'label' => __( 'Logo Attachment ID', 'simple-social-images-wpjm' ), - 'desc' => __( 'Enter the attachment IDs of the image you want to use as the logo.', 'simple-social-images-wpjm' ), - 'type' => 'text', - 'attributes' => array(), - ), - ), - array( - 'before' => __( 'Simple Social Images generates a automatic, beautiful and branded image for each job which, if the job is shared on social media, for example LinkedIn, shows as the preview image for the job. This really makes your jobs stand out from the crowd in social media feeds. Enter your settings below.', 'simple-social-image-wpjm' ), + 'type' => $args['type'], + 'group' => 'ssi_wpjm_settings', + 'description' => $args['description'], + 'sanitize_callback' => $args['sanitize_callback'], + 'show_in_rest' => $args['show_in_rest'], + ) + ); + + } + +} + +add_action( 'admin_init', 'ssi_wpjm_register_settings' ); + +/** + * Registers the plugins default settings. + * + * @param array $settings The current array of settings. + * @return array $settings The modified array of settings. + */ +function ssi_wpjm_register_default_settings( $settings ) { + + $settings['license_key'] = array( + 'option_name' => 'ssi_wpjm_license_key', + 'label' => __( 'License Key', 'simple-social-images-wpjm' ), + 'description' => __( 'Enter your license key.', 'simple-social-images-wpjm' ), + 'input_type' => 'text', + 'order' => 10, + ); + + $settings['template'] = array( + 'option_name' => 'ssi_wpjm_template', + 'label' => __( 'Select a Template', 'simple-social-images-wpjm' ), + 'description' => __( 'Choose which template to use.', 'simple-social-images-wpjm' ), + 'input_type' => 'select', + 'options' => array( + '1' => __( 'Template 1', 'simple-social-images-wpjm' ), + '2' => __( 'Template 2', 'simple-social-images-wpjm' ), + '3' => __( 'Template 3', 'simple-social-images-wpjm' ), + '4' => __( 'Template 4', 'simple-social-images-wpjm' ), + '5' => __( 'Template 5', 'simple-social-images-wpjm' ), + 'custom' => __( 'Custom Template', 'simple-social-images-wpjm' ), ), + 'order' => 10, + ); + + $settings['colors_section'] = array( + 'option_name' => 'ssi_wpjm_colors_section', + 'label' => __( 'Colour Settings', 'simple-social-images-wpjm' ), + 'input_type' => 'section', + 'order' => 20, + ); + + $settings['text_color'] = array( + 'option_name' => 'ssi_wpjm_text_color', + 'label' => __( 'Text Colour', 'simple-social-images-wpjm' ), + 'description' => __( 'Enter or choose the text colour.', 'simple-social-images-wpjm' ), + 'input_type' => 'color_picker', + 'order' => 30, + ); + + $settings['text_bg_color'] = array( + 'option_name' => 'ssi_wpjm_text_bg_color', + 'label' => __( 'Text Background Colour', 'simple-social-images-wpjm' ), + 'description' => __( 'Enter or choose the text background colour.', 'simple-social-images-wpjm' ), + 'input_type' => 'color_picker', + 'order' => 40, + ); + + $settings['bg_color'] = array( + 'option_name' => 'ssi_wpjm_bg_color', + 'label' => __( 'Background Colour', 'simple-social-images-wpjm' ), + 'description' => __( 'Enter or choose the background colour.', 'simple-social-images-wpjm' ), + 'input_type' => 'color_picker', + 'order' => 50, ); - // return the settings array. + $settings['logo_section'] = array( + 'option_name' => 'ssi_wpjm_logo_section', + 'label' => __( 'Logo Settings', 'simple-social-images-wpjm' ), + 'input_type' => 'section', + 'order' => 60, + ); + + $settings['logo'] = array( + 'option_name' => 'ssi_wpjm_logo', + 'label' => __( 'Image', 'simple-social-images-wpjm' ), + 'description' => __( 'Upload your logo to display on your images.', 'simple-social-images-wpjm' ), + 'input_type' => 'image', + 'order' => 70, + ); + + $settings['logo_size'] = array( + 'option_name' => 'ssi_wpjm_logo_size', + 'label' => __( 'Size', 'simple-social-images-wpjm' ), + 'description' => __( 'Select a size for the logo.', 'simple-social-images-wpjm' ), + 'input_type' => 'range', + 'min' => '4', + 'max' => '12', + 'step' => '0.1', + 'order' => 80, + ); + + $settings['background_images_section'] = array( + 'option_name' => 'ssi_wpjm_background_images_section', + 'label' => __( 'Background Images Settings', 'simple-social-images-wpjm' ), + 'input_type' => 'section', + 'order' => 90, + ); + + $settings['background_images'] = array( + 'option_name' => 'ssi_wpjm_background_images', + 'label' => __( 'Add Images', 'simple-social-images-wpjm' ), + 'description' => __( 'Upload background images to use on your social media images.', 'simple-social-images-wpjm' ), + 'input_type' => 'gallery', + 'order' => 100, + ); + + $settings['fonts_section'] = array( + 'option_name' => 'ssi_wpjm_font_sizes_section', + 'label' => __( 'Font Settings', 'simple-social-images-wpjm' ), + 'input_type' => 'section', + 'order' => 110, + ); + + $settings['title_size'] = array( + 'option_name' => 'ssi_wpjm_title_size', + 'label' => __( 'Title Size', 'simple-social-images-wpjm' ), + 'description' => __( 'Select a size for the title.', 'simple-social-images-wpjm' ), + 'input_type' => 'range', + 'min' => '2', + 'max' => '12', + 'step' => '0.1', + 'order' => 120, + ); + + $settings['location_size'] = array( + 'option_name' => 'ssi_wpjm_location_size', + 'label' => __( 'Location Size', 'simple-social-images-wpjm' ), + 'description' => __( 'Select a size for the location.', 'simple-social-images-wpjm' ), + 'input_type' => 'range', + 'min' => '2', + 'max' => '6', + 'step' => '0.1', + 'order' => 130, + ); + + $settings['salary_size'] = array( + 'option_name' => 'ssi_wpjm_salary_size', + 'label' => __( 'Salary Size', 'simple-social-images-wpjm' ), + 'description' => __( 'Select a size for the salary.', 'simple-social-images-wpjm' ), + 'input_type' => 'range', + 'min' => '2', + 'max' => '6', + 'step' => '0.1', + 'order' => 140, + ); + + $settings['google_font_url'] = array( + 'option_name' => 'ssi_wpjm_google_font_url', + 'label' => __( 'Google Font URL', 'simple-social-images-wpjm' ), + 'description' => __( 'Enter the URL of the Google font you wish to use.', 'simple-social-images-wpjm' ), + 'input_type' => 'text', + 'sanitize_callback' => 'sanitize_url', + 'order' => 150, + ); + + $settings['google_font_family'] = array( + 'option_name' => 'ssi_wpjm_google_font_family', + 'label' => __( 'Google Font Family', 'simple-social-images-wpjm' ), + 'description' => __( 'Enter the name of the Google font family.', 'simple-social-images-wpjm' ), + 'input_type' => 'text', + 'order' => 160, + ); + + // return the registered settings array. return $settings; } -add_filter( 'job_manager_settings', 'ssi_wpjm_register_settings', 10, 1 ); +add_filter( 'ssi_wpjm_settings', 'ssi_wpjm_register_default_settings' ); + +/** + * Controls the output of text input setting. + * + * @param array $setting an array of the current setting. + * @param mixed $value the current value of this setting saved in the database. + */ +function ssi_wpjm_setting_input_type_text( $setting, $value ) { + + // handle output for a text input. + ?> + + + + + + + + + + + + + + + + + + + + + +
+ + 'ssi-wpjm-image', + 'id' => $setting['option_name'] . 'image', + ) + ); + + } else { + + ?> + + + + + +
+ + + + + + + + + + + + + + + + + + +

+ +

+ esc_url_raw( rest_url() ), - 'nonce' => wp_create_nonce( 'wp_rest' ) - ) - ); - - // register the js. - wp_enqueue_script( - 'ssi_wpjm_admin_js', - SSI_WPJM_LOCATION_URL . '/assets/js/ssi-wpjm-admin.js', - array( 'jquery' ), - SSI_WPJM_VERSION, - true - ); - - // register the admin css. - wp_enqueue_style( - 'ssi_wpjm_admin_css', - SSI_WPJM_LOCATION_URL . '/assets/css/ssi-wpjm-admin.css', - array(), - SSI_WPJM_VERSION - ); - -} - -add_action( 'admin_enqueue_scripts', 'ssi_wpjm_enqueue_scripts' ); - -/** - * Add the og:image size in WP. - * Allows images to be cropped to og:image size. - */ -function ssi_wpjm_add_image_size() { - - // add the og:image size. - add_image_size( 'ssi_image', 1200, 630, true ); - -} - -add_action( 'after_setup_theme', 'ssi_wpjm_add_image_size' ); - -function ssi_wpjm_has_image( $post_id = 0 ) { - - // if we have no post id to check. - if ( $post_id === 0 ) { - - // use current global post id. - global $post; - $post_id = $post->ID; - - } - - // get the image id stored as meta. - $image_id = get_post_meta( $post_id, '', true ); - - // if we have no image id. - if ( empty( $image_id ) ) { - return 0; - } - - // get the image url for the associated meta. - $image_url = wp_get_attachment_image_url( $image_id, 'ssi_image' ); - - // if we have no image url. - if ( $image_url === false ) { - return 0; - } - - // go this far, we must have an image. - return apply_filters( 'ssi_wpjm_has_image', $image_id, $post_id ); - -} diff --git a/templates/1.php b/templates/1.php index bd24861..5322ae6 100644 --- a/templates/1.php +++ b/templates/1.php @@ -1,3 +1,6 @@ +
diff --git a/templates/2.php b/templates/2.php index bd24861..a31a97e 100644 --- a/templates/2.php +++ b/templates/2.php @@ -1,3 +1,6 @@ +
diff --git a/templates/3.php b/templates/3.php index bd24861..c5b270e 100644 --- a/templates/3.php +++ b/templates/3.php @@ -1,3 +1,6 @@ +
diff --git a/templates/4.php b/templates/4.php index bd24861..81006f8 100644 --- a/templates/4.php +++ b/templates/4.php @@ -1,3 +1,6 @@ +
diff --git a/templates/5.php b/templates/5.php index bd24861..f509c5d 100644 --- a/templates/5.php +++ b/templates/5.php @@ -1,3 +1,6 @@ +
From 0f25fadb8815f75ce76173e10fbff3439d62c935 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Tue, 12 Jul 2022 10:19:53 +0100 Subject: [PATCH 03/50] Correct comment --- endpoints/generate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/endpoints/generate.php b/endpoints/generate.php index 228bc8b..e713ef5 100644 --- a/endpoints/generate.php +++ b/endpoints/generate.php @@ -173,7 +173,7 @@ } - // if we have a template. + // if we have no template. if ( empty( $args['template'] ) ) { // default the template. From b64f57b958dd01c9fdfda6882ad3a56ede9d584e Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 18 Jul 2022 12:56:56 +0100 Subject: [PATCH 04/50] Rename generate endpoint --- endpoints/{generate.php => generate-html.php} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename endpoints/{generate.php => generate-html.php} (99%) diff --git a/endpoints/generate.php b/endpoints/generate-html.php similarity index 99% rename from endpoints/generate.php rename to endpoints/generate-html.php index e713ef5..51c982d 100644 --- a/endpoints/generate.php +++ b/endpoints/generate-html.php @@ -95,7 +95,7 @@ // remove the meta: string $match_key = str_replace( 'meta:', '', $match_value ); - + // get the value of this meta. $match_value = get_post_meta( $args['post_id'], $match_key, true ); From 7292e8652422128bb7065fdf72eff56dcf39794d Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 18 Jul 2022 12:57:14 +0100 Subject: [PATCH 05/50] Rename the endpoint slug for generating images --- inc/endpoints.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/inc/endpoints.php b/inc/endpoints.php index 8caf49d..1508991 100644 --- a/inc/endpoints.php +++ b/inc/endpoints.php @@ -56,15 +56,15 @@ function ssi_wpjm_load_jobfeed_endpoint_template( $template ) { } // check for a app push template file in the theme folder. - if ( file_exists( STYLESHEETPATH . '/ssi-wpjm/generate.php' ) ) { + if ( file_exists( STYLESHEETPATH . '/ssi-wpjm/generate-html.php' ) ) { // load the file from the theme folder. - return STYLESHEETPATH . '/ssi-wpjm/generate.php'; + return STYLESHEETPATH . '/ssi-wpjm/generate-html.php'; } else { // file not in theme folder. // load the timetables file from the plugin. - return SSI_WPJM_LOCATION . '/endpoints/generate.php'; + return SSI_WPJM_LOCATION . '/endpoints/generate-html.php'; } @@ -127,7 +127,7 @@ function ssi_wpjm_generate_endpoint_output( \WP_REST_Request $request ) { $social_image_html_url = home_url( '/ssi-wpjm/v1/generate-html/' ); $social_image_html_url = add_query_arg( array( - 'job_id' => absint( $request['post_id'] ), + 'post_id' => absint( $request['post_id'] ), 'timestamp' => time(), ), $social_image_html_url @@ -165,7 +165,8 @@ function ssi_wpjm_generate_endpoint_output( \WP_REST_Request $request ) { // output error. return array( 'success' => false, - 'error' => __( 'Request returned an error.', 'simple-social-image-wpjm' ), + //'error' => __( 'Request returned an error.', 'simple-social-image-wpjm' ), + 'error' => $response->get_error_message() ); } From dadd149c7ff697f6f0df72c7082e0ffb756f007f Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 18 Jul 2022 12:57:27 +0100 Subject: [PATCH 06/50] Correct conditional function for checking image --- inc/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/functions.php b/inc/functions.php index 8f5d9d8..9d5262f 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -17,7 +17,7 @@ function ssi_wpjm_has_image( $post_id = 0 ) { } // get the image id stored as meta. - $image_id = get_post_meta( $post_id, '', true ); + $image_id = get_post_meta( $post_id, 'ssi_wpjm_image_id', true ); // if we have no image id. if ( empty( $image_id ) ) { From 72b133b54543c1064c216c77e50ce195d0829097 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 18 Jul 2022 12:57:37 +0100 Subject: [PATCH 07/50] Meta box work for using a nonce --- inc/meta-box.php | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/inc/meta-box.php b/inc/meta-box.php index 1090fc2..b25b28b 100644 --- a/inc/meta-box.php +++ b/inc/meta-box.php @@ -44,10 +44,38 @@ function ssi_wpjm_jobs_meta_box_output( $post ) { } + // build the rest endpoint url. + $endpoint_url = get_rest_url( null, 'ssi-wpjm/v1/getimage' ); + $endpoint_url = add_query_arg( + array( + 'post_id' => $post->ID, + '_wpnonce' => wp_create_nonce( 'wp_rest' ), + ), + $endpoint_url + ); + + ?> +

ID ) ) . '">preview it first if you like.', 'simpe-social-images-wpjm' ); ?>

+ + -

ID ) ) . '">preview it first if you like.', 'simpe-social-images-wpjm' ); ?>

- @@ -60,11 +88,11 @@ function ssi_wpjm_jobs_meta_box_output( $post ) { 'ssi-hidden', ); - // if the is a current social image set. + // if there is a current social image set. if ( $social_image_id !== 0 ) { // we should be showing the button so remove the hide class. - $key = array_search( 'delete-ssi-image-button--hidden', $delete_button_class, true ); + $key = array_search( 'ssi-hidden', $delete_button_class, true ); // if we have found the class. if ( $key !== false ) { From 3880d6c8696ca8890a1c61c035553722215fe1a5 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 18 Jul 2022 13:27:38 +0100 Subject: [PATCH 08/50] Rename templates as html ending --- templates/{1.php => 1.html} | 3 --- templates/2.html | 11 +++++++++++ templates/2.php | 14 -------------- templates/3.html | 11 +++++++++++ templates/3.php | 14 -------------- templates/4.html | 11 +++++++++++ templates/4.php | 14 -------------- templates/5.html | 11 +++++++++++ templates/5.php | 14 -------------- 9 files changed, 44 insertions(+), 59 deletions(-) rename templates/{1.php => 1.html} (51%) create mode 100644 templates/2.html delete mode 100644 templates/2.php create mode 100644 templates/3.html delete mode 100644 templates/3.php create mode 100644 templates/4.html delete mode 100644 templates/4.php create mode 100644 templates/5.html delete mode 100644 templates/5.php diff --git a/templates/1.php b/templates/1.html similarity index 51% rename from templates/1.php rename to templates/1.html index 5322ae6..bd24861 100644 --- a/templates/1.php +++ b/templates/1.html @@ -1,6 +1,3 @@ -
diff --git a/templates/2.html b/templates/2.html new file mode 100644 index 0000000..bd24861 --- /dev/null +++ b/templates/2.html @@ -0,0 +1,11 @@ +
+
+
+ [post:post_title] + [meta:_job_location] + [meta:_job_salary] +
+ + +
+
\ No newline at end of file diff --git a/templates/2.php b/templates/2.php deleted file mode 100644 index a31a97e..0000000 --- a/templates/2.php +++ /dev/null @@ -1,14 +0,0 @@ - -
-
-
- [post:post_title] - [meta:_job_location] - [meta:_job_salary] -
- - -
-
\ No newline at end of file diff --git a/templates/3.html b/templates/3.html new file mode 100644 index 0000000..bd24861 --- /dev/null +++ b/templates/3.html @@ -0,0 +1,11 @@ +
+
+
+ [post:post_title] + [meta:_job_location] + [meta:_job_salary] +
+ + +
+
\ No newline at end of file diff --git a/templates/3.php b/templates/3.php deleted file mode 100644 index c5b270e..0000000 --- a/templates/3.php +++ /dev/null @@ -1,14 +0,0 @@ - -
-
-
- [post:post_title] - [meta:_job_location] - [meta:_job_salary] -
- - -
-
\ No newline at end of file diff --git a/templates/4.html b/templates/4.html new file mode 100644 index 0000000..bd24861 --- /dev/null +++ b/templates/4.html @@ -0,0 +1,11 @@ +
+
+
+ [post:post_title] + [meta:_job_location] + [meta:_job_salary] +
+ + +
+
\ No newline at end of file diff --git a/templates/4.php b/templates/4.php deleted file mode 100644 index 81006f8..0000000 --- a/templates/4.php +++ /dev/null @@ -1,14 +0,0 @@ - -
-
-
- [post:post_title] - [meta:_job_location] - [meta:_job_salary] -
- - -
-
\ No newline at end of file diff --git a/templates/5.html b/templates/5.html new file mode 100644 index 0000000..bd24861 --- /dev/null +++ b/templates/5.html @@ -0,0 +1,11 @@ +
+
+
+ [post:post_title] + [meta:_job_location] + [meta:_job_salary] +
+ + +
+
\ No newline at end of file diff --git a/templates/5.php b/templates/5.php deleted file mode 100644 index f509c5d..0000000 --- a/templates/5.php +++ /dev/null @@ -1,14 +0,0 @@ - -
-
-
- [post:post_title] - [meta:_job_location] - [meta:_job_salary] -
- - -
-
\ No newline at end of file From 04c875f69fcd99d0c3a2c0d0c0cd61cc3f72b766 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 18 Jul 2022 13:27:52 +0100 Subject: [PATCH 09/50] Create single CSS file to load on generate endpoint --- assets/css/ssi-wpjm-generate.css | 276 +++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 assets/css/ssi-wpjm-generate.css diff --git a/assets/css/ssi-wpjm-generate.css b/assets/css/ssi-wpjm-generate.css new file mode 100644 index 0000000..991e5f2 --- /dev/null +++ b/assets/css/ssi-wpjm-generate.css @@ -0,0 +1,276 @@ +/** + * CSS rules that apply to all templates. + */ +:root { + --hdsmi--text--color: white; + --hdsmi--text--background-color: rgb(91, 212, 218); + --hdsmi--background-color: rgb(23, 139, 145); + --hdsmi--font-family: sans-serif; + --hdsmi--font-size: 6vw; + --hdsmi--title--font-size: 6vw; + --hdsmi--title--font-weight: inherit; + --hdsmi--title--text-transform: inherit; + --hdsmi--location--font-size: 4vw; + --hdsmi--location--font-weight: inherit; + --hdsmi--location--text-transform: inherit; + --hdsmi--salary--font-size: 3vw; + --hdsmi--salary--font-weight: inherit; + --hdsmi--salary--text-transform: inherit; + --hdsmi--image--background-blend-mode: none; + --hdsmi--logo--height: 4vw; + --hdsmi--logo--width: auto +} +body { + margin: 0; + padding: 0 +} +.hdsmi-template { + width: 100vw; + aspect-ratio: 120/63; + display: grid; + place-items: center; + background-color: var(--hdsmi--background-color) +} +.hdsmi-template__inner { + position: relative; + aspect-ratio: 120/63; + width: 100% +} +.hdsmi-template__text { + font-size: var(--hdsmi--font-size); + font-family: var(--hdsmi--font-family); + color: var(--hdsmi--text--color) +} +.hdsmi-template__title { + color: var(--hdsmi--title--color,var(--hdsmi--text--color)); + font-size: var(--hdsmi--title--font-size, var(--hdsmi--font-size)); + font-weight: var(--hdsmi--title--font-weight); + text-transform: var(--hdsmi--title--text-transform) +} +.hdsmi-template__location { + color: var(--hdsmi--location--color,var(--hdsmi--text--color)); + font-size: var(--hdsmi--location--font-size, var(--hdsmi--font-size)); + font-weight: var(--hdsmi--location--font-weight); + text-transform: var(--hdsmi--location--text-transform) +} +.hdsmi-template__salary { + color: var(--hdsmi--salary--color,var(--hdsmi--text--color)); + font-size: var(--hdsmi--salary--font-size, var(--hdsmi--font-size)); + font-weight: var(--hdsmi--salary--font-weight); + text-transform: var(--hdsmi--salary--text-transform) +} +.hdsmi-template__logo { + height: var(--hdsmi--logo--height); + width: var(--hdsmi--logo--width) +} + +/* Template 1 */ + +.hdsmi-template--1 { + --hdsmi--title--font-weight: bold +} +.hdsmi-template--1 .hdsmi-template__inner { + display: flex; + align-items: center; + width: 100% +} +.hdsmi-template--1 .hdsmi-template__text { + display: flex; + flex-direction: column; + gap: 3vw; + padding: 3vw +} +.hdsmi-template--1 .hdsmi-template__image { + align-self: stretch; + width: 33%; + height: auto; + object-fit: cover +} +.hdsmi-template--1 .hdsmi-template__logo { + position: absolute; + top: 3vw; + right: 3vw +} + +/* Template 2 */ + +.hdsmi-template--2 { + --hdsmi--location--font-size: 2.5vw +} +.hdsmi-template--2 { + --hdsmi--location--font-size: 2.5vw +} +.hdsmi-template--2 .hdsmi-template__inner { + display: flex; + flex-direction: column; + justify-content: flex-end +} +.hdsmi-template--2 .hdsmi-template__image { + position: absolute; + z-index: 0; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100%; + height: 100%; + object-fit: cover +} +.hdsmi-template--2 .hdsmi-template__text { + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + gap: 2vw; + padding: 0 6vw 4vw +} +.hdsmi-template--2 .hdsmi-template__text:after { + content: ''; + position: absolute; + z-index: -1; + top: -10vw; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(#00000000,var(--hdsmi--text--background-color) 70%,var(--hdsmi--text--background-color)) +} +.hdsmi-template--2 .hdsmi-template__title { + order: 2 +} +.hdsmi-template--2 .hdsmi-template__location { + text-transform: uppercase; + order: 1; + margin-top: auto +} +.hdsmi-template--2 .hdsmi-template__salary { + order: 3; + font-weight: 700 +} +.hdsmi-template--2 .hdsmi-template__logo { + position: absolute; + top: 3vw; + left: 6vw +} + +/* Template 3 */ + +.hdsmi-template--3 { + --hdsmi--title--font-weight: bold +} +.hdsmi-template--3 { + --hdsmi--title--font-size: 4vw; + --hdsmi--location--font-size: 3vw; + --hdsmi--logo--height: 6vw +} +.hdsmi-template--3 .hdsmi-template__text { + width: 66.66vw; + z-index: 2; + position: absolute; + bottom: 4vw; + left: 4vw; + background-color: var(--hdsmi--text--background-color); + padding: 2vw; + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 2vw +} +.hdsmi-template--3 .hdsmi-template__salary { + margin-left: auto +} +.hdsmi-template--3 .hdsmi-template__image { + width: 66.66vw; + height: 40vw; + position: absolute; + z-index: 1; + top: 5vw; + right: 0; + bottom: 5vw; + object-fit: cover +} +.hdsmi-template--3 .hdsmi-template__logo { + position: absolute; + top: 3vw; + left: 3vw +} + +/* Template 4 */ + +.hdsmi-template--4 { + --hdsmi--title--font-size: 4vw; + --hdsmi--location--font-size: 2.5vw; + --hdsmi--salary--font-size: 2.5vw; + --hdsmi--logo--height: 5vw +} +.hdsmi-template--4 .hdsmi-template__inner { + display: grid; + align-items: end; + justify-items: center +} +.hdsmi-template--4 .hdsmi-template__image { + width: 100%; + height: 100%; + position: absolute; + z-index: 0; + top: 0; + bottom: 0; + left: 0; + right: 0; + object-fit: cover; + mix-blend-mode: screen +} +.hdsmi-template--4 .hdsmi-template__text { + position: relative; + z-index: 1; + background-color: var(--hdsmi--text--background-color); + padding: 2vw; + margin: 4vw 15vw; + text-align: center; + display: flex; + flex-direction: column; + gap: 2vw +} +.hdsmi-template--4 .hdsmi-template__logo { + position: absolute; + top: 3vw; + z-index: 0 +} + +/* Template 5 */ + +.hdsmi-template--5 { + --hdsmi--title--font-size: 5vw; + --hdsmi--location--font-size: 3vw; + --hdsmi--logo--height: 3vw +} +.hdsmi-template--5 .hdsmi-template__text { + width: 50vw; + position: absolute; + top: 50%; + left: calc(50% - 4vw); + transform: translateY(-50%) +} +.hdsmi-template--5 .hdsmi-template__text > * { + display: inline; + padding: 1vw 2vw; + background-color: var(--hdsmi--text--background-color); + -webkit-box-decoration-break: clone; + box-decoration-break: clone +} +.hdsmi-template--5 .hdsmi-template__text > :after { + content: "\A"; + white-space: pre-line +} +.hdsmi-template--5 .hdsmi-template__title { + line-height: 1 +} +.hdsmi-template--5 .hdsmi-template__image { + width: 50vw; + height: 100%; + object-fit: cover +} +.hdsmi-template--5 .hdsmi-template__logo { + position: absolute; + top: 3vw; + right: 3vw +} From a5b8d27a92fb8f33e8e32319b401e1ee19af3934 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 18 Jul 2022 13:29:08 +0100 Subject: [PATCH 10/50] Use HTML markup Also: * Check for post thumbnail and use if present as the background image * Coreect Google font URL output * Check taxonomy exists before attempting to replace with term values --- endpoints/generate-html.php | 102 +++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 36 deletions(-) diff --git a/endpoints/generate-html.php b/endpoints/generate-html.php index 51c982d..fb51c73 100644 --- a/endpoints/generate-html.php +++ b/endpoints/generate-html.php @@ -27,6 +27,14 @@ 'logo' => wp_get_attachment_image_url( get_option( 'ssi_wpjm_logo_id' ), 'full' ), ); +// if the current post has a featured image. +if ( has_post_thumbnail( $args['post_id'] ) ) { + + // set the image url to that of the featured image. + $args['image'] = get_the_post_thumbnail_url( $args['post_id'], 'full' ); + +} + // allow the args to be filtered. $args = apply_filters( 'ssi_wpjm_endpoint_generate_args', $args ); @@ -37,40 +45,52 @@ ob_start(); ?> - - + + + + + + + + + // output the link elements to load the font. + ?> - - - + + + - + + + +'; From 249fd3a84ce5881d7ad4593bbedb4a6c00fc875d Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 18 Jul 2022 13:33:43 +0100 Subject: [PATCH 11/50] Output template preview div --- inc/admin-menu.php | 18 ++++++++++++++++-- inc/functions.php | 13 +++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/inc/admin-menu.php b/inc/admin-menu.php index 98f0020..39b01b4 100644 --- a/inc/admin-menu.php +++ b/inc/admin-menu.php @@ -24,6 +24,13 @@ function ssi_wpjm_settings_page_output() {

+ +
@@ -140,8 +147,15 @@ function ssi_wpjm_settings_page_output() {
+ +
+
+ Date: Mon, 18 Jul 2022 13:35:16 +0100 Subject: [PATCH 12/50] Rename admin js to settings js Only loaded on the settings page --- assets/js/{ssi-wpjm-admin.js => ssi-wpjm-settings.js} | 0 inc/enqueue.php | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename assets/js/{ssi-wpjm-admin.js => ssi-wpjm-settings.js} (100%) diff --git a/assets/js/ssi-wpjm-admin.js b/assets/js/ssi-wpjm-settings.js similarity index 100% rename from assets/js/ssi-wpjm-admin.js rename to assets/js/ssi-wpjm-settings.js diff --git a/inc/enqueue.php b/inc/enqueue.php index bdac123..868e625 100644 --- a/inc/enqueue.php +++ b/inc/enqueue.php @@ -52,7 +52,7 @@ function ssi_wpjm_enqueue_scripts( $hook ) { // include our custom jQuery file with WordPress Color Picker dependency wp_enqueue_script( 'ssi_wpjm_admin_js', - SSI_WPJM_LOCATION_URL . '/assets/js/ssi-wpjm-admin.js', + SSI_WPJM_LOCATION_URL . '/assets/js/ssi-wpjm-settings.js', array( 'wp-color-picker' ), false, true From b0aefab41379d37ba7bc8a653215ee3ab8faf83e Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 18 Jul 2022 13:50:36 +0100 Subject: [PATCH 13/50] Load template CSS and variables on settings page --- endpoints/generate-html.php | 4 ++-- inc/enqueue.php | 6 ++++++ inc/functions.php | 39 ++++++++++++++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/endpoints/generate-html.php b/endpoints/generate-html.php index fb51c73..a1ccff9 100644 --- a/endpoints/generate-html.php +++ b/endpoints/generate-html.php @@ -60,14 +60,14 @@ --hdsmi--location--font-size: vw; --hdsmi--salary--font-size: vw; --hdsmi--logo--height: vw; - --hdsmi--font-family: ; + --hdsmi--font-family: ; } diff --git a/inc/enqueue.php b/inc/enqueue.php index 868e625..481168b 100644 --- a/inc/enqueue.php +++ b/inc/enqueue.php @@ -45,6 +45,12 @@ function ssi_wpjm_enqueue_scripts( $hook ) { // if this is the ssi settings page. if ( $hook === 'job_listing_page_ssi-wpjm-settings' ) { + + // enqueue the template css for the preview to work. + wp_enqueue_style( + 'ssi_wpjm_template_css', + SSI_WPJM_LOCATION_URL . '/assets/css/ssi-wpjm-generate.css', + ); // add the color picker css file wp_enqueue_style( 'wp-color-picker' ); diff --git a/inc/functions.php b/inc/functions.php index dca8850..91aa107 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -233,9 +233,20 @@ function ssi_wpjm_get_google_font_url() { */ function ssi_wpjm_get_google_font_family() { + // get the font family from settings. + $font_family = get_option( 'ssi_wpjm_google_font_family' ); + + // if the font family is empty. + if ( empty( $font_family ) ) { + + // set to default system family for sans serif. + $font_family = 'sans-serif;'; + + } + return apply_filters( 'ssi_wpjm_google_font_family', - get_option( 'ssi_wpjm_google_font_family' ) + $font_family ); } @@ -280,6 +291,32 @@ function ssi_wpjm_add_image_size() { add_action( 'after_setup_theme', 'ssi_wpjm_add_image_size' ); +/** + * Outputs the custom variables on the settings page for the template preview. + */ +function ssi_wpjm_add_template_custom_properties() { + + ?> + + + + Date: Mon, 18 Jul 2022 15:55:47 +0100 Subject: [PATCH 14/50] Add generate social image to its own function This can then be re-used. --- inc/functions.php | 132 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/inc/functions.php b/inc/functions.php index 91aa107..018239b 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -329,3 +329,135 @@ function ssi_wpjm_add_preview_markup_to_settings_page() { } add_action( 'ssi_wpjm_after_settings_form_output', 'ssi_wpjm_add_preview_markup_to_settings_page' ); + +/** + * Generates the social media sharing image for a post. + * Also saves the image to the media library and attaches it to the post. + * + * @param integer $post_id The ID of the post to generate an image for. + * @return array An array of image id and url on success + * An error array with error message on failure. + */ +function ssi_wpjm_generate_social_image( $post_id = 0 ) { + + // if no post id then use the global post ID. + if ( $post_id = 0 ) { + global $post; + $post_id = $post->ID; + } + + // get the license key. + $license_key = get_option( 'ssi_wpjm_license_key' ); + + // if we have no license key. + if ( empty( $license_key ) ) { + + // output error. + return array( + 'success' => false, + 'error' => __( 'No license key provided.', 'simple-social-image-wpjm' ), + ); + + } + + $social_image_html_url = home_url( '/ssi-wpjm/v1/generate-html/' ); + $social_image_html_url = add_query_arg( + array( + 'post_id' => absint( $request['post_id'] ), + 'timestamp' => time(), + ), + $social_image_html_url + ); + + // set the URL of the simple social images api. + $api_url = ssi_wpjm_generate_api_url(); + + // add the paramters to the api_url. + $api_url = add_query_arg( + apply_filters( + 'ssi_wpjm_api_url_query_args', + array( + 'license_key' => sanitize_text_field( $license_key ), + 'site_url' => home_url(), + 'url' => urlencode( $social_image_html_url ), + 'element' => '.hdsmi-template', + 'ttl' => 300, + ), + ), + $api_url + ); + + // send the request to the api. + $response = wp_remote_get( + $api_url, + array( + 'sslverify' => false, + ) + ); + + // if there was an error. + if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) { + + // output error. + return array( + 'success' => false, + 'error' => $response->get_error_message() + ); + + } + + // get the body of the request, decoded as an array. + $response = json_decode( wp_remote_retrieve_body( $response ), true ); + + // if we have no url returned. + if ( empty( $response['url'] ) ) { + + // output error. + return array( + 'success' => false, + 'error' => __( 'No image was generated.', 'simple-social-image-wpjm' ), + ); + + } + + // we are outside of WP Admin so need to include these files. + require_once( ABSPATH . 'wp-admin/includes/media.php' ); + require_once( ABSPATH . 'wp-admin/includes/file.php' ); + require_once( ABSPATH . 'wp-admin/includes/image.php' ); + + // grab the image and store in the media library. + $image_id = media_sideload_image( $response['url'], absint( $request['post_id'] ), '', 'id' ); + + // if we have an image set. + if ( ! is_wp_error( $image_id ) ) { + + // save meta data indicating this is image generated by hd og images. + update_post_meta( $image_id, 'ssi_wpjm_image', true ); + + // get the current image id for the og:image. + $current_image_id = get_post_meta( absint( $request['post_id'] ), 'ssi_wpjm_image_id', true ); + + // if we have a current image. + if ( ! empty( $current_image_id ) ) { + + // delete the attachment. + wp_delete_attachment( $current_image_id ); + + } + + // store the image ID as meta against the job. + update_post_meta( absint( $request['post_id'] ), 'ssi_wpjm_image_id', $image_id ); + + } + + return apply_filters( + 'ssi_wpjm_generated_social_image', + array( + 'success' => true, + 'id' => $image_id, + 'url' => wp_get_attachment_image_url( $image_id, 'ssi_image' ), + ), + $request + ); + +} From 8c022457c0abd49b36900e89bf4cf80db5154045 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 18 Jul 2022 15:56:01 +0100 Subject: [PATCH 15/50] Use new generate image function in endpoint --- inc/endpoints.php | 114 +--------------------------------------------- 1 file changed, 1 insertion(+), 113 deletions(-) diff --git a/inc/endpoints.php b/inc/endpoints.php index 1508991..6df7858 100644 --- a/inc/endpoints.php +++ b/inc/endpoints.php @@ -110,118 +110,6 @@ function ssi_wpjm_generate_endpoint_output( \WP_REST_Request $request ) { } - // get the license key. - $license_key = get_option( 'ssi_wpjm_license_key' ); - - // if we have no license key. - if ( empty( $license_key ) ) { - - // output error. - return array( - 'success' => false, - 'error' => __( 'No license key provided.', 'simple-social-image-wpjm' ), - ); - - } - - $social_image_html_url = home_url( '/ssi-wpjm/v1/generate-html/' ); - $social_image_html_url = add_query_arg( - array( - 'post_id' => absint( $request['post_id'] ), - 'timestamp' => time(), - ), - $social_image_html_url - ); - - // set the URL of the simple social images api. - $api_url = ssi_wpjm_generate_api_url(); - - // add the paramters to the api_url. - $api_url = add_query_arg( - apply_filters( - 'ssi_wpjm_api_url_query_args', - array( - 'license_key' => sanitize_text_field( $license_key ), - 'site_url' => home_url(), - 'url' => urlencode( $social_image_html_url ), - 'element' => '.hdsmi-template', - 'ttl' => 300, - ), - ), - $api_url - ); - - // send the request to the api. - $response = wp_remote_get( - $api_url, - array( - 'sslverify' => false, - ) - ); - - // if there was an error. - if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) { - - // output error. - return array( - 'success' => false, - //'error' => __( 'Request returned an error.', 'simple-social-image-wpjm' ), - 'error' => $response->get_error_message() - ); - - } - - // get the body of the request, decoded as an array. - $response = json_decode( wp_remote_retrieve_body( $response ), true ); - - // if we have no url returned. - if ( empty( $response['url'] ) ) { - - // output error. - return array( - 'success' => false, - 'error' => __( 'No image was generated.', 'simple-social-image-wpjm' ), - ); - - } - - // we are outside of WP Admin so need to include these files. - require_once( ABSPATH . 'wp-admin/includes/media.php' ); - require_once( ABSPATH . 'wp-admin/includes/file.php' ); - require_once( ABSPATH . 'wp-admin/includes/image.php' ); - - // grab the image and store in the media library. - $image_id = media_sideload_image( $response['url'], absint( $request['post_id'] ), '', 'id' ); - - // if we have an image set. - if ( ! is_wp_error( $image_id ) ) { - - // save meta data indicating this is image generated by hd og images. - update_post_meta( $image_id, 'ssi_wpjm_image', true ); - - // get the current image id for the og:image. - $current_image_id = get_post_meta( absint( $request['post_id'] ), 'ssi_wpjm_image_id', true ); - - // if we have a current image. - if ( ! empty( $current_image_id ) ) { - - // delete the attachment. - wp_delete_attachment( $current_image_id ); - - } - - // store the image ID as meta against the job. - update_post_meta( absint( $request['post_id'] ), 'ssi_wpjm_image_id', $image_id ); - - } - - return apply_filters( - 'ssi_wpjm_generated_social_image', - array( - 'id' => $image_id, - 'url' => wp_get_attachment_image_url( $image_id, 'ssi_image' ), - ), - $request - ); + return ssi_wpjm_generate_social_image( $request['post_id'] ); } From 9985f7844caa8d744dc2cfff30e1452ec957a19c Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 18 Jul 2022 18:01:34 +0100 Subject: [PATCH 16/50] Only show meta box content when post published --- inc/meta-box.php | 145 +++++++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 67 deletions(-) diff --git a/inc/meta-box.php b/inc/meta-box.php index b25b28b..7592c7f 100644 --- a/inc/meta-box.php +++ b/inc/meta-box.php @@ -27,102 +27,113 @@ function ssi_wpjm_add_ssi_jobs_meta_box() { */ function ssi_wpjm_jobs_meta_box_output( $post ) { - // default social image id. - $social_image_id = 0; + // if this is not a published post. + if ( $post->post_status !== 'publish' ) { + + ?> +

+ ID ); + } else { - // get the URL for the current social image. - $social_image_url = wp_get_attachment_image_url( $social_image_id, 'ssi_image' ); + // default social image id. + $social_image_id = 0; - // if we don't have a social image URL. - if ( empty ( $social_image_url ) ) { + // get the current social image for this post. + $social_image_id = ssi_wpjm_has_image( $post->ID ); - // set the url of the image to the placeholder. - $social_image_url = SSI_WPJM_LOCATION_URL . '/assets/img/social-placeholder.jpg'; + // get the URL for the current social image. + $social_image_url = wp_get_attachment_image_url( $social_image_id, 'ssi_image' ); - } + // if we don't have a social image URL. + if ( empty ( $social_image_url ) ) { - // build the rest endpoint url. - $endpoint_url = get_rest_url( null, 'ssi-wpjm/v1/getimage' ); - $endpoint_url = add_query_arg( - array( - 'post_id' => $post->ID, - '_wpnonce' => wp_create_nonce( 'wp_rest' ), - ), - $endpoint_url - ); + // set the url of the image to the placeholder. + $social_image_url = SSI_WPJM_LOCATION_URL . '/assets/img/social-placeholder.jpg'; - ?> -

ID ) ) . '">preview it first if you like.', 'simpe-social-images-wpjm' ); ?>

+ } - $post->ID, + '_wpnonce' => wp_create_nonce( 'wp_rest' ), + ), + $endpoint_url + ); - // set class for the gernate button. - $generate_button_class = array( - 'button-secondary', - 'generate-ssi-image-button', - ); + ?> +

ID ) ) . '">preview it first if you like.', 'simpe-social-images-wpjm' ); ?>

- // if there is a current social image set. - if ( $social_image_id !== 0 ) { + - - + // add the hidden class. + $generate_button_class[] = 'ssi-hidden'; - + + - // if there is a current social image set. - if ( $social_image_id !== 0 ) { + - // output the delete button. - ?> + - + - ?> + - + - ?> + - + Date: Mon, 18 Jul 2022 18:01:51 +0100 Subject: [PATCH 17/50] Fix post ID in generate image request function --- inc/functions.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index 018239b..b5883e1 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -341,7 +341,7 @@ function ssi_wpjm_add_preview_markup_to_settings_page() { function ssi_wpjm_generate_social_image( $post_id = 0 ) { // if no post id then use the global post ID. - if ( $post_id = 0 ) { + if ( $post_id === 0 ) { global $post; $post_id = $post->ID; } @@ -363,7 +363,7 @@ function ssi_wpjm_generate_social_image( $post_id = 0 ) { $social_image_html_url = home_url( '/ssi-wpjm/v1/generate-html/' ); $social_image_html_url = add_query_arg( array( - 'post_id' => absint( $request['post_id'] ), + 'post_id' => absint( $post_id ), 'timestamp' => time(), ), $social_image_html_url @@ -426,7 +426,7 @@ function ssi_wpjm_generate_social_image( $post_id = 0 ) { require_once( ABSPATH . 'wp-admin/includes/image.php' ); // grab the image and store in the media library. - $image_id = media_sideload_image( $response['url'], absint( $request['post_id'] ), '', 'id' ); + $image_id = media_sideload_image( $response['url'], absint( $post_id ), '', 'id' ); // if we have an image set. if ( ! is_wp_error( $image_id ) ) { @@ -435,7 +435,7 @@ function ssi_wpjm_generate_social_image( $post_id = 0 ) { update_post_meta( $image_id, 'ssi_wpjm_image', true ); // get the current image id for the og:image. - $current_image_id = get_post_meta( absint( $request['post_id'] ), 'ssi_wpjm_image_id', true ); + $current_image_id = get_post_meta( absint( $post_id ), 'ssi_wpjm_image_id', true ); // if we have a current image. if ( ! empty( $current_image_id ) ) { @@ -446,7 +446,7 @@ function ssi_wpjm_generate_social_image( $post_id = 0 ) { } // store the image ID as meta against the job. - update_post_meta( absint( $request['post_id'] ), 'ssi_wpjm_image_id', $image_id ); + $result = update_post_meta( absint( $post_id ), 'ssi_wpjm_image_id', $image_id ); } @@ -457,7 +457,7 @@ function ssi_wpjm_generate_social_image( $post_id = 0 ) { 'id' => $image_id, 'url' => wp_get_attachment_image_url( $image_id, 'ssi_image' ), ), - $request + $post_id ); } From 726cc09ddf7463f241011766ff791867e86916fd Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 18 Jul 2022 18:03:00 +0100 Subject: [PATCH 18/50] Comment functions --- inc/endpoints.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/inc/endpoints.php b/inc/endpoints.php index 6df7858..2918bf9 100644 --- a/inc/endpoints.php +++ b/inc/endpoints.php @@ -74,6 +74,9 @@ function ssi_wpjm_load_jobfeed_endpoint_template( $template ) { add_filter( 'template_include', 'ssi_wpjm_load_jobfeed_endpoint_template' ); +/** + * Registers a custom rest endpoint which gets the image for a post. + */ function ssi_wpjm_register_rest_endpoint() { // register a new rest route or endpoint for getting slot posts. From 5307b762cabeb10f899ccce0ff86753f6cf0fe13 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 18 Jul 2022 18:19:30 +0100 Subject: [PATCH 19/50] Settings page improvements --- assets/img/google-font-family-example.jpg | Bin 0 -> 19633 bytes assets/img/google-font-url-example.jpg | Bin 0 -> 71421 bytes inc/setttings.php | 10 +++++----- 3 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 assets/img/google-font-family-example.jpg create mode 100644 assets/img/google-font-url-example.jpg diff --git a/assets/img/google-font-family-example.jpg b/assets/img/google-font-family-example.jpg new file mode 100644 index 0000000000000000000000000000000000000000..03d3840d2989d4e0d38281cbbe2aefc4ee4559f5 GIT binary patch literal 19633 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 Ef9Kjl82|tP literal 0 HcmV?d00001 diff --git a/assets/img/google-font-url-example.jpg b/assets/img/google-font-url-example.jpg new file mode 100644 index 0000000000000000000000000000000000000000..096daf6c8deb54f8036fb96c531455f655ae6912 GIT binary patch literal 71421 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 R<0Av;>l#V@#rS*d{{b28 'ssi_wpjm_license_key', 'label' => __( 'License Key', 'simple-social-images-wpjm' ), - 'description' => __( 'Enter your license key.', 'simple-social-images-wpjm' ), + 'description' => sprintf( __( 'Enter your %1$sSimple Social Images%2$s license key. This is required in order to generate your social sharing images.', 'simple-social-images-wpjm' ), '', '' ), 'input_type' => 'text', 'order' => 10, ); @@ -88,7 +88,6 @@ function ssi_wpjm_register_default_settings( $settings ) { '3' => __( 'Template 3', 'simple-social-images-wpjm' ), '4' => __( 'Template 4', 'simple-social-images-wpjm' ), '5' => __( 'Template 5', 'simple-social-images-wpjm' ), - 'custom' => __( 'Custom Template', 'simple-social-images-wpjm' ), ), 'order' => 10, ); @@ -160,7 +159,7 @@ function ssi_wpjm_register_default_settings( $settings ) { $settings['background_images'] = array( 'option_name' => 'ssi_wpjm_background_images', 'label' => __( 'Add Images', 'simple-social-images-wpjm' ), - 'description' => __( 'Upload background images to use on your social media images.', 'simple-social-images-wpjm' ), + 'description' => __( 'Upload background images to use on your template. Each template uses the background image slightly differently. Images are chosen at random from the images uploaded here, assuming your job does not have a featured image.', 'simple-social-images-wpjm' ), 'input_type' => 'gallery', 'order' => 100, ); @@ -209,6 +208,7 @@ function ssi_wpjm_register_default_settings( $settings ) { 'option_name' => 'ssi_wpjm_google_font_url', 'label' => __( 'Google Font URL', 'simple-social-images-wpjm' ), 'description' => __( 'Enter the URL of the Google font you wish to use.', 'simple-social-images-wpjm' ), + 'description' => sprintf( __( 'Enter the URL of the Google font. %1$sSee an example of what is required%2$s (the highlighted text).', 'simple-social-images-wpjm' ), '', '' ), 'input_type' => 'text', 'sanitize_callback' => 'sanitize_url', 'order' => 150, @@ -217,7 +217,7 @@ function ssi_wpjm_register_default_settings( $settings ) { $settings['google_font_family'] = array( 'option_name' => 'ssi_wpjm_google_font_family', 'label' => __( 'Google Font Family', 'simple-social-images-wpjm' ), - 'description' => __( 'Enter the name of the Google font family.', 'simple-social-images-wpjm' ), + 'description' => sprintf( __( 'Enter the name of the Google font family. %1$sSee an example of what is required%2$s (the highlighted text).', 'simple-social-images-wpjm' ), '', '' ), 'input_type' => 'text', 'order' => 160, ); @@ -546,7 +546,7 @@ function ssi_wpjm_output_setting_descriptions( $setting, $value ) { // output the description. ?> -

+

Date: Tue, 19 Jul 2022 09:47:28 +0100 Subject: [PATCH 20/50] Settings screen preview --- assets/css/ssi-wpjm-admin.css | 48 ++++++++++- assets/css/ssi-wpjm-generate.css | 138 ++++++++++++++++--------------- assets/js/ssi-wpjm-settings.js | 103 ++++++++++++++++++++++- endpoints/generate-html.php | 42 ++++++++-- inc/enqueue.php | 9 ++ inc/functions.php | 59 +++++++++++-- inc/setttings.php | 2 +- 7 files changed, 312 insertions(+), 89 deletions(-) diff --git a/assets/css/ssi-wpjm-admin.css b/assets/css/ssi-wpjm-admin.css index d73e708..7494ca4 100644 --- a/assets/css/ssi-wpjm-admin.css +++ b/assets/css/ssi-wpjm-admin.css @@ -23,7 +23,12 @@ img.ssi-image { } .ssi-wpjm-image-wrapper { position: relative; - width: 166px; + width: 25em; +} +.ssi-wpjm-image-wrapper img { + max-width: 100%; + height: auto; + box-sizing: border-box; } .ssi-wpjm-image--remove, .ssi-wpjm-gallery--remove { @@ -52,6 +57,43 @@ img.ssi-image { font-size: 130%; font-weight: bold; } -.ssi-wpjm-settings-form .form-table th { - width: 300px; + +.ssi-wpjm-settings-form tr { + display: flex; + flex-wrap: wrap; + gap: 2em; +} +.ssi-wpjm-settings-form th { + padding: 20px 0; +} +.ssi-wpjm-settings-form td { + padding: 15px 0; +} +.ssi-wpjm-settings-form .form-table { + width: calc(100% - 520px - 4em); +} +.ssi-wpjm-template-preview { + + position: fixed; + bottom: 3em; + right: 2em; + max-width: var(--hdsmi-template--width); + box-shadow: 20px 20px 40px rgba(0,0,0,0.2); + +} + +.ssi-wpjm-template-preview .ssi-wpjm-template-preview__toggle { + + position: absolute; + top: -1em; + right: 0; + transform: translateY(-100%); + box-shadow: 20px 20px 40px rgba(0,0,0,0.2); + +} + +.ssi-wpjm-template-preview .hdsmi-template { + + --hdsmi-template--width: 520px; + } \ No newline at end of file diff --git a/assets/css/ssi-wpjm-generate.css b/assets/css/ssi-wpjm-generate.css index 991e5f2..57543a3 100644 --- a/assets/css/ssi-wpjm-generate.css +++ b/assets/css/ssi-wpjm-generate.css @@ -1,73 +1,79 @@ /** * CSS rules that apply to all templates. */ -:root { +body { + margin: 0; + padding: 0 +} + + .hdsmi-template { + + --hdsmi-template--width: 100vw; + --hdsmi-template--unit: calc(var(--hdsmi-template--width) / 100); --hdsmi--text--color: white; --hdsmi--text--background-color: rgb(91, 212, 218); --hdsmi--background-color: rgb(23, 139, 145); --hdsmi--font-family: sans-serif; - --hdsmi--font-size: 6vw; - --hdsmi--title--font-size: 6vw; + --hdsmi--font-size: 6; + --hdsmi--title--font-size: 6; --hdsmi--title--font-weight: inherit; --hdsmi--title--text-transform: inherit; - --hdsmi--location--font-size: 4vw; + --hdsmi--location--font-size: 4; --hdsmi--location--font-weight: inherit; --hdsmi--location--text-transform: inherit; - --hdsmi--salary--font-size: 3vw; + --hdsmi--salary--font-size: 3; --hdsmi--salary--font-weight: inherit; --hdsmi--salary--text-transform: inherit; --hdsmi--image--background-blend-mode: none; - --hdsmi--logo--height: 4vw; - --hdsmi--logo--width: auto -} -body { - margin: 0; - padding: 0 -} -.hdsmi-template { - width: 100vw; + --hdsmi--logo--height: 4; + --hdsmi--logo--width: auto; + + width: var(--hdsmi-template--width); aspect-ratio: 120/63; display: grid; place-items: center; - background-color: var(--hdsmi--background-color) + background-color: var(--hdsmi--background-color); + } + .hdsmi-template__inner { position: relative; aspect-ratio: 120/63; width: 100% } .hdsmi-template__text { - font-size: var(--hdsmi--font-size); + font-size: calc(var(--hdsmi--font-size) * var(--hdsmi-template--unit)); + line-height: 1.25; font-family: var(--hdsmi--font-family); color: var(--hdsmi--text--color) } .hdsmi-template__title { color: var(--hdsmi--title--color,var(--hdsmi--text--color)); - font-size: var(--hdsmi--title--font-size, var(--hdsmi--font-size)); + font-size: calc(var(--hdsmi--title--font-size, var(--hdsmi--font-size)) * var(--hdsmi-template--unit)); font-weight: var(--hdsmi--title--font-weight); text-transform: var(--hdsmi--title--text-transform) } .hdsmi-template__location { color: var(--hdsmi--location--color,var(--hdsmi--text--color)); - font-size: var(--hdsmi--location--font-size, var(--hdsmi--font-size)); + font-size: calc(var(--hdsmi--location--font-size, var(--hdsmi--font-size)) * var(--hdsmi-template--unit)); font-weight: var(--hdsmi--location--font-weight); text-transform: var(--hdsmi--location--text-transform) } .hdsmi-template__salary { color: var(--hdsmi--salary--color,var(--hdsmi--text--color)); - font-size: var(--hdsmi--salary--font-size, var(--hdsmi--font-size)); + font-size: calc(var(--hdsmi--salary--font-size, var(--hdsmi--font-size)) * var(--hdsmi-template--unit)); font-weight: var(--hdsmi--salary--font-weight); text-transform: var(--hdsmi--salary--text-transform) } .hdsmi-template__logo { - height: var(--hdsmi--logo--height); + height: calc(var(--hdsmi--logo--height) * var(--hdsmi-template--unit)); width: var(--hdsmi--logo--width) } /* Template 1 */ .hdsmi-template--1 { - --hdsmi--title--font-weight: bold + --hdsmi--template--font-weight: bold } .hdsmi-template--1 .hdsmi-template__inner { display: flex; @@ -75,10 +81,12 @@ body { width: 100% } .hdsmi-template--1 .hdsmi-template__text { + + width: 66.66%; display: flex; flex-direction: column; - gap: 3vw; - padding: 3vw + gap: calc(3 * var(--hdsmi-template--unit)); + padding: calc(3 * var(--hdsmi-template--unit)) } .hdsmi-template--1 .hdsmi-template__image { align-self: stretch; @@ -88,17 +96,14 @@ body { } .hdsmi-template--1 .hdsmi-template__logo { position: absolute; - top: 3vw; - right: 3vw + top: calc(3 * var(--hdsmi-template--unit)); + right: calc(3 * var(--hdsmi-template--unit)) } /* Template 2 */ .hdsmi-template--2 { - --hdsmi--location--font-size: 2.5vw -} -.hdsmi-template--2 { - --hdsmi--location--font-size: 2.5vw + --hdsmi--location--font-size: 2.5; } .hdsmi-template--2 .hdsmi-template__inner { display: flex; @@ -121,14 +126,14 @@ body { z-index: 1; display: flex; flex-direction: column; - gap: 2vw; - padding: 0 6vw 4vw + gap: calc(2 * var(--hdsmi-template--unit)); + padding: 0 calc(6 * var(--hdsmi-template--unit)) calc(4 * var(--hdsmi-template--unit)) } .hdsmi-template--2 .hdsmi-template__text:after { content: ''; position: absolute; z-index: -1; - top: -10vw; + top: calc(-10 * var(--hdsmi-template--unit)); left: 0; right: 0; bottom: 0; @@ -148,8 +153,8 @@ body { } .hdsmi-template--2 .hdsmi-template__logo { position: absolute; - top: 3vw; - left: 6vw + top: calc(3 * var(--hdsmi-template--unit)); + left: calc(6 * var(--hdsmi-template--unit)) } /* Template 3 */ @@ -158,49 +163,49 @@ body { --hdsmi--title--font-weight: bold } .hdsmi-template--3 { - --hdsmi--title--font-size: 4vw; - --hdsmi--location--font-size: 3vw; - --hdsmi--logo--height: 6vw + --hdsmi--title--font-size: 4; + --hdsmi--location--font-size: 3; + --hdsmi--logo--height: 6; } .hdsmi-template--3 .hdsmi-template__text { - width: 66.66vw; + width: calc(66.6 * var(--hdsmi-template--unit)); z-index: 2; position: absolute; - bottom: 4vw; - left: 4vw; + bottom: calc(4 * var(--hdsmi-template--unit)); + left: calc(4 * var(--hdsmi-template--unit)); background-color: var(--hdsmi--text--background-color); - padding: 2vw; + padding: calc(2 * var(--hdsmi-template--unit)); display: flex; flex-wrap: wrap; align-items: center; - gap: 2vw + gap: calc(2 * var(--hdsmi-template--unit)) } .hdsmi-template--3 .hdsmi-template__salary { margin-left: auto } .hdsmi-template--3 .hdsmi-template__image { - width: 66.66vw; - height: 40vw; + width: calc(66.6 * var(--hdsmi-template--unit)); + height: calc(40 * var(--hdsmi-template--unit)); position: absolute; z-index: 1; - top: 5vw; + top: calc(5 * var(--hdsmi-template--unit)); right: 0; - bottom: 5vw; + bottom: calc(5 * var(--hdsmi-template--unit)); object-fit: cover } .hdsmi-template--3 .hdsmi-template__logo { position: absolute; - top: 3vw; - left: 3vw + top: calc(3 * var(--hdsmi-template--unit)); + left: calc(3 * var(--hdsmi-template--unit)) } /* Template 4 */ .hdsmi-template--4 { - --hdsmi--title--font-size: 4vw; - --hdsmi--location--font-size: 2.5vw; - --hdsmi--salary--font-size: 2.5vw; - --hdsmi--logo--height: 5vw + --hdsmi--title--font-size: 4; + --hdsmi--location--font-size: 2.5; + --hdsmi--salary--font-size: 2.5; + --hdsmi--logo--height: 5; } .hdsmi-template--4 .hdsmi-template__inner { display: grid; @@ -222,37 +227,38 @@ body { .hdsmi-template--4 .hdsmi-template__text { position: relative; z-index: 1; + max-width: 66.66%; background-color: var(--hdsmi--text--background-color); - padding: 2vw; - margin: 4vw 15vw; + padding: calc(4 * var(--hdsmi-template--unit)); + margin: calc(4 * var(--hdsmi-template--unit)) 1calc(5 * var(--hdsmi-template--unit)); text-align: center; display: flex; flex-direction: column; - gap: 2vw + gap: calc(2 * var(--hdsmi-template--unit)) } .hdsmi-template--4 .hdsmi-template__logo { position: absolute; - top: 3vw; + top: calc(3 * var(--hdsmi-template--unit)); z-index: 0 } /* Template 5 */ .hdsmi-template--5 { - --hdsmi--title--font-size: 5vw; - --hdsmi--location--font-size: 3vw; - --hdsmi--logo--height: 3vw + --hdsmi--title--font-size: 5; + --hdsmi--location--font-size: 3; + --hdsmi--logo--height: 3 } .hdsmi-template--5 .hdsmi-template__text { - width: 50vw; + width: calc(50 * var(--hdsmi-template--unit)); position: absolute; top: 50%; - left: calc(50% - 4vw); + left: calc(50% - calc(4 * var(--hdsmi-template--unit))); transform: translateY(-50%) } .hdsmi-template--5 .hdsmi-template__text > * { - display: inline; - padding: 1vw 2vw; + display: inline-block; + padding: calc(1 * var(--hdsmi-template--unit)) calc(2 * var(--hdsmi-template--unit)); background-color: var(--hdsmi--text--background-color); -webkit-box-decoration-break: clone; box-decoration-break: clone @@ -265,12 +271,12 @@ body { line-height: 1 } .hdsmi-template--5 .hdsmi-template__image { - width: 50vw; + width: calc(50 * var(--hdsmi-template--unit)); height: 100%; object-fit: cover } .hdsmi-template--5 .hdsmi-template__logo { position: absolute; - top: 3vw; - right: 3vw + top: calc(3 * var(--hdsmi-template--unit)); + right: calc(3 * var(--hdsmi-template--unit)) } diff --git a/assets/js/ssi-wpjm-settings.js b/assets/js/ssi-wpjm-settings.js index 4035694..0637100 100644 --- a/assets/js/ssi-wpjm-settings.js +++ b/assets/js/ssi-wpjm-settings.js @@ -21,9 +21,8 @@ }).on('select', function() { var attachment = ssi_wpjm_image_uploader.state().get('selection').first().toJSON(); - console.log( attachment ); $( inputID ).val(attachment.id); - $( imgID ).attr( 'src', attachment.sizes.thumbnail.url ); + $( imgID ).attr( 'src', attachment.sizes.full.url ); }) .open(); }); @@ -141,4 +140,104 @@ }); + + + + + + /* Live preview settings */ + + /* Logo size */ + var logoSize = document.querySelector("#ssi_wpjm_logo_size"); + + logoSize.addEventListener("change", function() { + document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--logo--height", this.value); + }); + + /* Text color */ + $('#ssi_wpjm_text_color').iris({ + //hide: false, + change: function(event, ui) { + // event = standard jQuery event, produced by whichever control was changed. + // ui = standard jQuery UI object, with a color member containing a Color.js object + + document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--text--color", ui.color.toString()); + + } + }); + + /* Text background color */ + $('#ssi_wpjm_text_bg_color').iris({ + //hide: false, + change: function(event, ui) { + // event = standard jQuery event, produced by whichever control was changed. + // ui = standard jQuery UI object, with a color member containing a Color.js object + + document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--text--background-color", ui.color.toString()); + + } + }); + + + /* Background color */ + $('#ssi_wpjm_bg_color').iris({ + //hide: false, + change: function(event, ui) { + // event = standard jQuery event, produced by whichever control was changed. + // ui = standard jQuery UI object, with a color member containing a Color.js object + + document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--background-color", ui.color.toString()); + + } + }); + + /* Title font size */ + var titleFontSize = document.querySelector("#ssi_wpjm_title_size"); + + titleFontSize.addEventListener("change", function() { + document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--title--font-size", this.value); + }); + + /* Location font size */ + var locationFontSize = document.querySelector("#ssi_wpjm_location_size"); + + locationFontSize.addEventListener("change", function() { + document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--location--font-size", this.value); + }); + + /* Salary font size */ + var salaryFontSize = document.querySelector("#ssi_wpjm_salary_size"); + + salaryFontSize.addEventListener("change", function() { + var newFontSize = this.value; + document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--salary--font-size", newFontSize); + }); + + /* Template choice */ + var templateChoice = document.querySelector("#ssi_wpjm_template"); + + templateChoice.addEventListener("change", function() { + + var template = document.querySelector(".hdsmi-template"); + + template.classList.remove('hdsmi-template--1', 'hdsmi-template--2', 'hdsmi-template--3', 'hdsmi-template--4', 'hdsmi-template--5'); + + template.classList.add("hdsmi-template--" + this.value); + + }); + + /* Logo file */ + $('img.ssi-wpjm-image').on('load', function () { + $('.hdsmi-template__logo').attr('src', $('img.ssi-wpjm-image').attr('src')); + }); + + /* Background images */ + $('img.ssi-wpjm-gallery-image').on('load', function () { + + imgSrc = $('img.ssi-wpjm-gallery-image').attr('src'); + fullImgSrc = imgSrc.replace("-150x150", ""); + $('.hdsmi-template__image').attr('src', fullImgSrc); + + }); + })( jQuery ); \ No newline at end of file diff --git a/endpoints/generate-html.php b/endpoints/generate-html.php index a1ccff9..776d5ad 100644 --- a/endpoints/generate-html.php +++ b/endpoints/generate-html.php @@ -53,14 +53,40 @@ diff --git a/inc/enqueue.php b/inc/enqueue.php index 481168b..635048e 100644 --- a/inc/enqueue.php +++ b/inc/enqueue.php @@ -46,6 +46,15 @@ function ssi_wpjm_enqueue_scripts( $hook ) { // if this is the ssi settings page. if ( $hook === 'job_listing_page_ssi-wpjm-settings' ) { + if ( ! empty ( ssi_wpjm_get_google_font_url() ) ) { + + wp_enqueue_style( + 'ssi_wpjm_google_font_url', + ssi_wpjm_get_google_font_url(), + ); + + } + // enqueue the template css for the preview to work. wp_enqueue_style( 'ssi_wpjm_template_css', diff --git a/inc/functions.php b/inc/functions.php index 91aa107..81e20c2 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -300,14 +300,39 @@ function ssi_wpjm_add_template_custom_properties() { @@ -323,7 +348,23 @@ function ssi_wpjm_add_template_custom_properties() { function ssi_wpjm_add_preview_markup_to_settings_page() { ?> -
+
+ + + +
+
+
+ Test job title + London, UK + £30,000 per annum +
+ + +
+
+ +
'ssi-wpjm-image', From 45dc3b5edd740da71e91e39e5d831d5903f011b2 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Tue, 19 Jul 2022 10:45:18 +0100 Subject: [PATCH 21/50] Correct endpoint variables output --- endpoints/generate-html.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/endpoints/generate-html.php b/endpoints/generate-html.php index 776d5ad..bd8b6d4 100644 --- a/endpoints/generate-html.php +++ b/endpoints/generate-html.php @@ -55,35 +55,35 @@ .hdsmi-template{ From 91c4783bcbf8e4388ee9cae926f3b99744ba588a Mon Sep 17 00:00:00 2001 From: Keith Devon Date: Tue, 19 Jul 2022 10:54:40 +0100 Subject: [PATCH 22/50] Fix row spacing --- assets/js/ssi-wpjm-settings.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/assets/js/ssi-wpjm-settings.js b/assets/js/ssi-wpjm-settings.js index 0637100..b3045b8 100644 --- a/assets/js/ssi-wpjm-settings.js +++ b/assets/js/ssi-wpjm-settings.js @@ -161,7 +161,11 @@ // event = standard jQuery event, produced by whichever control was changed. // ui = standard jQuery UI object, with a color member containing a Color.js object + // update the custom property. document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--text--color", ui.color.toString()); + + // update the color preview background color. + $(this).parents('.wp-picker-container').find('.button.wp-color-result').css('background-color', ui.color.toString()); } }); @@ -173,7 +177,11 @@ // event = standard jQuery event, produced by whichever control was changed. // ui = standard jQuery UI object, with a color member containing a Color.js object + // update the custom property. document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--text--background-color", ui.color.toString()); + + // update the color preview background color. + $(this).parents('.wp-picker-container').find('.button.wp-color-result').css('background-color', ui.color.toString()); } }); @@ -186,8 +194,12 @@ // event = standard jQuery event, produced by whichever control was changed. // ui = standard jQuery UI object, with a color member containing a Color.js object + // update the custom property. document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--background-color", ui.color.toString()); + // update the color preview background color. + $(this).parents('.wp-picker-container').find('.button.wp-color-result').css('background-color', ui.color.toString()); + } }); @@ -237,7 +249,7 @@ imgSrc = $('img.ssi-wpjm-gallery-image').attr('src'); fullImgSrc = imgSrc.replace("-150x150", ""); $('.hdsmi-template__image').attr('src', fullImgSrc); - + }); })( jQuery ); \ No newline at end of file From af913293f2b4635260b462310416e9e72408cbcb Mon Sep 17 00:00:00 2001 From: Keith Devon Date: Tue, 19 Jul 2022 10:55:05 +0100 Subject: [PATCH 23/50] Remove row gap --- assets/css/ssi-wpjm-admin.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/css/ssi-wpjm-admin.css b/assets/css/ssi-wpjm-admin.css index 7494ca4..7145139 100644 --- a/assets/css/ssi-wpjm-admin.css +++ b/assets/css/ssi-wpjm-admin.css @@ -61,7 +61,7 @@ img.ssi-image { .ssi-wpjm-settings-form tr { display: flex; flex-wrap: wrap; - gap: 2em; + column-gap: 2em; } .ssi-wpjm-settings-form th { padding: 20px 0; From 0fc97b872a025e347a7d8d13bce6cb1894cff3f6 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Tue, 19 Jul 2022 10:58:43 +0100 Subject: [PATCH 24/50] Increase timeout on posting to ssi service --- inc/functions.php | 1 + 1 file changed, 1 insertion(+) diff --git a/inc/functions.php b/inc/functions.php index 8be8aea..5091678 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -433,6 +433,7 @@ function ssi_wpjm_generate_social_image( $post_id = 0 ) { $api_url, array( 'sslverify' => false, + 'timeout' => 30, ) ); From 6da1041593ff0e3c73c970c74ebf794597d8d3ce Mon Sep 17 00:00:00 2001 From: Keith Devon Date: Tue, 19 Jul 2022 11:23:18 +0100 Subject: [PATCH 25/50] Settings page updates --- assets/css/ssi-wpjm-admin.css | 52 +++++++++++++++++++++++--------- assets/css/ssi-wpjm-generate.css | 3 ++ inc/functions.php | 2 -- inc/setttings.php | 12 ++++---- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/assets/css/ssi-wpjm-admin.css b/assets/css/ssi-wpjm-admin.css index 7145139..7b1a2d5 100644 --- a/assets/css/ssi-wpjm-admin.css +++ b/assets/css/ssi-wpjm-admin.css @@ -53,10 +53,14 @@ img.ssi-image { .setting-type--section { border-top: 1px solid #CCCCCC; } -.setting-type--section th { +.ssi-wpjm-settings-form .setting-type--section th { + flex-basis: 100%; font-size: 130%; font-weight: bold; } +.ssi-wpjm-settings-form .setting-type--section { + gap: 0; +} .ssi-wpjm-settings-form tr { display: flex; @@ -64,36 +68,54 @@ img.ssi-image { column-gap: 2em; } .ssi-wpjm-settings-form th { - padding: 20px 0; + padding: 20px 0 0; + flex-basis: 25%; } .ssi-wpjm-settings-form td { padding: 15px 0; } .ssi-wpjm-settings-form .form-table { - width: calc(100% - 520px - 4em); + width: 100%; +} + +@media screen and (min-width: 1000px) { + .ssi-wpjm-settings-form .form-table { + width: calc(100% - 520px - 4em); + } } -.ssi-wpjm-template-preview { - position: fixed; - bottom: 3em; - right: 2em; + +.ssi-wpjm-template-preview { + max-width: var(--hdsmi-template--width); - box-shadow: 20px 20px 40px rgba(0,0,0,0.2); } -.ssi-wpjm-template-preview .ssi-wpjm-template-preview__toggle { +@media screen and (min-width: 1000px) { - position: absolute; - top: -1em; - right: 0; - transform: translateY(-100%); - box-shadow: 20px 20px 40px rgba(0,0,0,0.2); + .ssi-wpjm-template-preview { + + position: fixed; + bottom: 3em; + right: 2em; + + } } .ssi-wpjm-template-preview .hdsmi-template { - --hdsmi-template--width: 520px; + --hdsmi-template--width: 80vw; + box-shadow: 20px 20px 40px rgba(0,0,0,0.2); + +} + +@media screen and (min-width: 600px) { + + .ssi-wpjm-template-preview .hdsmi-template { + + --hdsmi-template--width: 520px; + + } } \ No newline at end of file diff --git a/assets/css/ssi-wpjm-generate.css b/assets/css/ssi-wpjm-generate.css index 57543a3..04576ab 100644 --- a/assets/css/ssi-wpjm-generate.css +++ b/assets/css/ssi-wpjm-generate.css @@ -180,6 +180,9 @@ body { align-items: center; gap: calc(2 * var(--hdsmi-template--unit)) } +.hdsmi-template--3 .hdsmi-template__title { + width: 100% +} .hdsmi-template--3 .hdsmi-template__salary { margin-left: auto } diff --git a/inc/functions.php b/inc/functions.php index 8be8aea..dc47fca 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -350,8 +350,6 @@ function ssi_wpjm_add_preview_markup_to_settings_page() { ?>
- -
diff --git a/inc/setttings.php b/inc/setttings.php index e70dce6..ccae1d2 100644 --- a/inc/setttings.php +++ b/inc/setttings.php @@ -177,8 +177,8 @@ function ssi_wpjm_register_default_settings( $settings ) { 'description' => __( 'Select a size for the title.', 'simple-social-images-wpjm' ), 'input_type' => 'range', 'min' => '2', - 'max' => '12', - 'step' => '0.1', + 'max' => '10', + 'step' => '0.5', 'order' => 120, ); @@ -188,8 +188,8 @@ function ssi_wpjm_register_default_settings( $settings ) { 'description' => __( 'Select a size for the location.', 'simple-social-images-wpjm' ), 'input_type' => 'range', 'min' => '2', - 'max' => '6', - 'step' => '0.1', + 'max' => '10', + 'step' => '0.5', 'order' => 130, ); @@ -199,8 +199,8 @@ function ssi_wpjm_register_default_settings( $settings ) { 'description' => __( 'Select a size for the salary.', 'simple-social-images-wpjm' ), 'input_type' => 'range', 'min' => '2', - 'max' => '6', - 'step' => '0.1', + 'max' => '10', + 'step' => '0.5', 'order' => 140, ); From 8b187d2cf52fef640f1d8bd3696572ad5a68bb9a Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Tue, 19 Jul 2022 14:26:50 +0100 Subject: [PATCH 26/50] Use correct function to output logo URL --- endpoints/generate-html.php | 2 +- readme.txt | 54 +++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/endpoints/generate-html.php b/endpoints/generate-html.php index bd8b6d4..d613eee 100644 --- a/endpoints/generate-html.php +++ b/endpoints/generate-html.php @@ -24,7 +24,7 @@ 'google_font_family' => ssi_wpjm_get_google_font_family(), 'logo_size' => ssi_wpjm_get_logo_size(), 'image' => wp_get_attachment_image_url( ssi_wpjm_get_random_image_id(), 'full' ), - 'logo' => wp_get_attachment_image_url( get_option( 'ssi_wpjm_logo_id' ), 'full' ), + 'logo' => wp_get_attachment_image_url( ssi_wpjm_get_logo_id(), 'full' ), ); // if the current post has a featured image. diff --git a/readme.txt b/readme.txt index 6b50448..a340ece 100644 --- a/readme.txt +++ b/readme.txt @@ -1,35 +1,24 @@ === Simple Social Images for WP Job Manager === -Contributors: wpmarkuk, keithdevon, highrisedigital -Tags: social sharing, jobs, open graph -Requires at least: 6.0 -Tested up to: 6.0 +Contributors: highrisedigital, wpmarkuk, keithdevon +Tags: social sharing, jobs, open graph, social images, twitter, facebook, linkedin +Requires at least: 6.0.1 +Tested up to: 6.0.1 Stable tag: 1.0 -Requires PHP: 7.0 +Requires PHP: 7.4 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html -This plugin when combined with a Simple Social Images license, automatically generates beautiful and branded images which are displayed in social media feeds when a job, written in WP Job Manager is shared on social media platforms. +This plugin automatically generates beautiful and branded images which are displayed in social media feeds when a job is shared on social media. == Description == -This is the long description. No limit, and you can use Markdown (as well as in the following sections). +Simple Social Images for WP job Manager is a plugin which automates the creation of branded, beautiful social images for your WP Job Manager jobs. Our clients have told us that jobs which are shared on social media and show a branded image, containing the job title, location and salary, have improved engagement. -For backwards compatibility, if this section is missing, the full length of the short description will be used, and -Markdown parsed. +**Important** - _for this plugin to work, it requires a paid Simple Social Images license in order to generate the images. [Purchase a license here](https://simplesocialimages.com)_. -A few notes about the sections above: +When you share a job URL from your website on social networks, a preview image can be shown in order to preview the content. If this isn't customised, it can often look unprofessional. Many WP Job Manager users will create their own images, uploading them to WordPress. However, this is time consumuing and prone to errors. This plugin automates the creation of these images and makes sure they are set as the image to use in the social network preview. -* "Contributors" is a comma separated list of wordpress.org usernames -* "Tags" is a comma separated list of tags that apply to the plugin -* "Requires at least" is the lowest version that the plugin will work on -* "Tested up to" is the highest version that you've *successfully used to test the plugin* -* Stable tag must indicate the Subversion "tag" of the latest stable version - -Note that the `readme.txt` value of stable tag is the one that is the defining one for the plugin. If the `/trunk/readme.txt` file says that the stable tag is `4.3`, then it is `/tags/4.3/readme.txt` that'll be used for displaying information about the plugin. - -If you develop in trunk, you can update the trunk `readme.txt` to reflect changes in your in-development version, without having that information incorrectly disclosed about the current stable version that lacks those changes -- as long as the trunk's `readme.txt` points to the correct stable tag. - -If no stable tag is provided, your users may not get the correct version of your code. +The images that are generated can be customised to suit your brand. In fact, you have control over which template you would like to use (currently there is a choice of 5, with more to come soon!), which colours should be used in the template, adding your logo to each image as well as choosing suitable background images. Our simple preview tool allows you to preview what you images will look like in the plugins settings page. == Frequently Asked Questions == @@ -39,18 +28,31 @@ Yes, the plugin requires a paid license for [Simple Social Images](https://simpl = Will all the generated images not look the same? = -No, you can select which template you want to use, and then each image that is generated can have a random background image (which you can also provide) and will also include the job title, salary and location. +No, you can select which template you want to use, and then each image that is generated can have a random background image (which you can also provide), or it will use the featured image of the job itself as the background, and will also include the job title, salary and location. + += How do I test which image is used by the social networks? = + +For LinkedIn: + +1. Open the LinkedIn Post Inspector +2. Enter the URL of a job from your website +3. Click ‘Inspect’ + +You can also test how your jobs look on [Facebook](https://developers.facebook.com/tools/debug/) and [Twitter](https://cards-dev.twitter.com/validator). == Screenshots == -1. This screen shot description corresponds to screenshot-1.(png|jpg|jpeg|gif). Screenshots are stored in the /assets directory. -2. This is the second screen shot +1. Template 2 preview +2. Template 3 preview +3. Template 4 preview +4. Template 5 preview +5. The Simple Social Images for WP Job Manager settings screen +6. The Simple Social Images for WP Job Manager meta box, used to generate the images for each job == Changelog == = 1.0 = -* A change since the previous version. -* Another change. +* Initial plugin launch. == Upgrade Notice == From cd5e4c1a5736b7b30a311c4daccacac22f443445 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Tue, 19 Jul 2022 20:16:33 +0100 Subject: [PATCH 27/50] Readme updates --- readme.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index a340ece..ee6dacb 100644 --- a/readme.txt +++ b/readme.txt @@ -14,12 +14,21 @@ This plugin automatically generates beautiful and branded images which are displ Simple Social Images for WP job Manager is a plugin which automates the creation of branded, beautiful social images for your WP Job Manager jobs. Our clients have told us that jobs which are shared on social media and show a branded image, containing the job title, location and salary, have improved engagement. -**Important** - _for this plugin to work, it requires a paid Simple Social Images license in order to generate the images. [Purchase a license here](https://simplesocialimages.com)_. +⚠️**Important** - _for this plugin to work, it requires a paid Simple Social Images license in order to generate the images. [Purchase a license here](https://simplesocialimages.com)_. When you share a job URL from your website on social networks, a preview image can be shown in order to preview the content. If this isn't customised, it can often look unprofessional. Many WP Job Manager users will create their own images, uploading them to WordPress. However, this is time consumuing and prone to errors. This plugin automates the creation of these images and makes sure they are set as the image to use in the social network preview. The images that are generated can be customised to suit your brand. In fact, you have control over which template you would like to use (currently there is a choice of 5, with more to come soon!), which colours should be used in the template, adding your logo to each image as well as choosing suitable background images. Our simple preview tool allows you to preview what you images will look like in the plugins settings page. +== Installation == + +1. Log into WordPress +2. Go to Plugins, Add New +3. Search for Simple Social Images for WP Job Manager +4. Click Install Now, then Activate +5. Go to Job Listings, the Simple Social Images +6. Enter your license key for [Simple Social Images](https://simplesocialimages.com) and complete the settings to setup your images. + == Frequently Asked Questions == = Does this plugin require a paid license? = From 34a22918e17e0627190e200a200a207900c601bb Mon Sep 17 00:00:00 2001 From: Keith Devon Date: Wed, 20 Jul 2022 09:31:15 +0100 Subject: [PATCH 28/50] Settings page updates --- assets/css/ssi-wpjm-generate.css | 22 ++++++++++----- assets/js/ssi-wpjm-settings.js | 48 ++++++++++++++++++++++++++++++-- inc/setttings.php | 9 +++++- 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/assets/css/ssi-wpjm-generate.css b/assets/css/ssi-wpjm-generate.css index 04576ab..f9c5d62 100644 --- a/assets/css/ssi-wpjm-generate.css +++ b/assets/css/ssi-wpjm-generate.css @@ -11,7 +11,7 @@ body { --hdsmi-template--width: 100vw; --hdsmi-template--unit: calc(var(--hdsmi-template--width) / 100); --hdsmi--text--color: white; - --hdsmi--text--background-color: rgb(91, 212, 218); + --hdsmi--text--background-color: transparent; --hdsmi--background-color: rgb(23, 139, 145); --hdsmi--font-family: sans-serif; --hdsmi--font-size: 6; @@ -72,8 +72,8 @@ body { /* Template 1 */ -.hdsmi-template--1 { - --hdsmi--template--font-weight: bold +.hdsmi-template.hdsmi-template--1 { + --hdsmi--template--font-weight: bold; } .hdsmi-template--1 .hdsmi-template__inner { display: flex; @@ -81,13 +81,20 @@ body { width: 100% } .hdsmi-template--1 .hdsmi-template__text { - width: 66.66%; display: flex; flex-direction: column; - gap: calc(3 * var(--hdsmi-template--unit)); + align-items: flex-start; + gap: calc(2 * var(--hdsmi-template--unit)); padding: calc(3 * var(--hdsmi-template--unit)) } +.hdsmi-template--1 .hdsmi-template__text > * { + display: inline; + padding: calc(1 * var(--hdsmi-template--unit)) calc(2 * var(--hdsmi-template--unit)); + background-color: var(--hdsmi--text--background-color); + -webkit-box-decoration-break: clone; + box-decoration-break: clone +} .hdsmi-template--1 .hdsmi-template__image { align-self: stretch; width: 33%; @@ -160,7 +167,7 @@ body { /* Template 3 */ .hdsmi-template--3 { - --hdsmi--title--font-weight: bold + --hdsmi--title--font-weight: bold; } .hdsmi-template--3 { --hdsmi--title--font-size: 4; @@ -178,13 +185,14 @@ body { display: flex; flex-wrap: wrap; align-items: center; + justify-content: space-between; gap: calc(2 * var(--hdsmi-template--unit)) } .hdsmi-template--3 .hdsmi-template__title { width: 100% } .hdsmi-template--3 .hdsmi-template__salary { - margin-left: auto + /* margin-left: auto */ } .hdsmi-template--3 .hdsmi-template__image { width: calc(66.6 * var(--hdsmi-template--unit)); diff --git a/assets/js/ssi-wpjm-settings.js b/assets/js/ssi-wpjm-settings.js index b3045b8..5cb4b9e 100644 --- a/assets/js/ssi-wpjm-settings.js +++ b/assets/js/ssi-wpjm-settings.js @@ -69,7 +69,7 @@ // loop through each of the attachments selected. $.each( attachments , function( index, val ) { - console.log( currentValues ); + // if this attachment id is not already in the current values array. if ( currentValues.indexOf( val.id + '' ) !== 0 ) { @@ -161,6 +161,14 @@ // event = standard jQuery event, produced by whichever control was changed. // ui = standard jQuery UI object, with a color member containing a Color.js object + // update customproperty on 'Clear' button press. + $('.wp-picker-clear').on('click', function(){ + + // update the custom property. + document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--text--background-color", 'transparent'); + + }); + // update the custom property. document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--text--color", ui.color.toString()); @@ -171,12 +179,21 @@ }); /* Text background color */ + //var added_clearer = false; $('#ssi_wpjm_text_bg_color').iris({ //hide: false, change: function(event, ui) { // event = standard jQuery event, produced by whichever control was changed. // ui = standard jQuery UI object, with a color member containing a Color.js object + // update customproperty on 'Clear' button press. + $('.wp-picker-clear').on('click', function(){ + + // update the custom property. + document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--text--background-color", 'transparent'); + + }); + // update the custom property. document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--text--background-color", ui.color.toString()); @@ -194,6 +211,14 @@ // event = standard jQuery event, produced by whichever control was changed. // ui = standard jQuery UI object, with a color member containing a Color.js object + // update customproperty on 'Clear' button press. + $('.wp-picker-clear').on('click', function(){ + + // update the custom property. + document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--text--background-color", 'transparent'); + + }); + // update the custom property. document.querySelector(".hdsmi-template").style.setProperty("--hdsmi--background-color", ui.color.toString()); @@ -244,12 +269,31 @@ }); /* Background images */ + $('img.ssi-wpjm-gallery-image').on('load', function () { - imgSrc = $('img.ssi-wpjm-gallery-image').attr('src'); + console.log('Image loaded'); + + imgSrc = $(this).attr('src'); fullImgSrc = imgSrc.replace("-150x150", ""); $('.hdsmi-template__image').attr('src', fullImgSrc); }); + $(document).on('click', $('.ssi-wpjm-gallery-image'), function () { + + console.log('clicked'); + + console.log( $(this) ); + + // get the image source. + var imgSrc = $(this).attr('src'); + + console.log('imgSrc = ' + imgSrc); + + // set template image source. + $('.hdsmi-template__image').attr('src', imgSrc); + + }); + })( jQuery ); \ No newline at end of file diff --git a/inc/setttings.php b/inc/setttings.php index ccae1d2..d688666 100644 --- a/inc/setttings.php +++ b/inc/setttings.php @@ -77,6 +77,13 @@ function ssi_wpjm_register_default_settings( $settings ) { 'order' => 10, ); + $settings['template_section'] = array( + 'option_name' => 'ssi_wpjm_template_section', + 'label' => __( 'Template Settings', 'simple-social-images-wpjm' ), + 'input_type' => 'section', + 'order' => 12, + ); + $settings['template'] = array( 'option_name' => 'ssi_wpjm_template', 'label' => __( 'Select a Template', 'simple-social-images-wpjm' ), @@ -89,7 +96,7 @@ function ssi_wpjm_register_default_settings( $settings ) { '4' => __( 'Template 4', 'simple-social-images-wpjm' ), '5' => __( 'Template 5', 'simple-social-images-wpjm' ), ), - 'order' => 10, + 'order' => 15, ); $settings['colors_section'] = array( From d28bce873d135556716805582d2c2fa14f40fdeb Mon Sep 17 00:00:00 2001 From: Keith Devon Date: Wed, 20 Jul 2022 09:33:23 +0100 Subject: [PATCH 29/50] Click to preview background images --- assets/js/ssi-wpjm-settings.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/assets/js/ssi-wpjm-settings.js b/assets/js/ssi-wpjm-settings.js index 5cb4b9e..f109839 100644 --- a/assets/js/ssi-wpjm-settings.js +++ b/assets/js/ssi-wpjm-settings.js @@ -280,17 +280,11 @@ }); - $(document).on('click', $('.ssi-wpjm-gallery-image'), function () { - - console.log('clicked'); - - console.log( $(this) ); + $(document).on('click', '.ssi-wpjm-gallery-image', function () { // get the image source. var imgSrc = $(this).attr('src'); - console.log('imgSrc = ' + imgSrc); - // set template image source. $('.hdsmi-template__image').attr('src', imgSrc); From 1113272cfae31423d057983b49fe1004f846258f Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Wed, 20 Jul 2022 09:34:32 +0100 Subject: [PATCH 30/50] Sanitize font family output --- endpoints/generate-html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/endpoints/generate-html.php b/endpoints/generate-html.php index d613eee..c35e8c3 100644 --- a/endpoints/generate-html.php +++ b/endpoints/generate-html.php @@ -83,7 +83,7 @@ } if ( ! empty( $args['google_font_family'] ) ) { - echo "--hdsmi--font-family:" . esc_attr( $args['google_font_family'] ) . ";"; + echo "--hdsmi--font-family:" . wp_kses_post( $args['google_font_family'] ) . ";"; } ?> From ea3499c256a7990b1855a34f771759c830e11e1c Mon Sep 17 00:00:00 2001 From: Keith Devon Date: Wed, 20 Jul 2022 09:34:38 +0100 Subject: [PATCH 31/50] =?UTF-8?q?Use=20=E2=80=98full=E2=80=99=20image=20so?= =?UTF-8?q?urce=20for=20background=20preview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/js/ssi-wpjm-settings.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/assets/js/ssi-wpjm-settings.js b/assets/js/ssi-wpjm-settings.js index f109839..e2e629d 100644 --- a/assets/js/ssi-wpjm-settings.js +++ b/assets/js/ssi-wpjm-settings.js @@ -283,10 +283,11 @@ $(document).on('click', '.ssi-wpjm-gallery-image', function () { // get the image source. - var imgSrc = $(this).attr('src'); + imgSrc = $(this).attr('src'); + fullImgSrc = imgSrc.replace("-150x150", ""); // set template image source. - $('.hdsmi-template__image').attr('src', imgSrc); + $('.hdsmi-template__image').attr('src', fullImgSrc); }); From 1de1986f1c7d1e7318942334a30c8d2a779526c1 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Wed, 20 Jul 2022 09:39:58 +0100 Subject: [PATCH 32/50] Correct transparent image when none provided --- endpoints/generate-html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/endpoints/generate-html.php b/endpoints/generate-html.php index c35e8c3..66135b1 100644 --- a/endpoints/generate-html.php +++ b/endpoints/generate-html.php @@ -225,7 +225,7 @@ if ( empty( $args['image'] ) ) { // set the image to a transparent image. - $args['logo'] = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; + $args['image'] = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; } From b597e6d6169d0eb883c737d5ee3f22c26ef55a3a Mon Sep 17 00:00:00 2001 From: Keith Devon Date: Wed, 20 Jul 2022 09:52:02 +0100 Subject: [PATCH 33/50] Placeholder image fixes --- inc/functions.php | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index 760a7b6..3231d6f 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -357,8 +357,25 @@ function ssi_wpjm_add_preview_markup_to_settings_page() { London, UK £30,000 per annum
- - + + + +
From 7864fcecae5f81b8c41b829f3176fe8c80874234 Mon Sep 17 00:00:00 2001 From: Keith Devon Date: Wed, 20 Jul 2022 09:52:41 +0100 Subject: [PATCH 34/50] Remove console logs --- assets/js/ssi-wpjm-settings.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/assets/js/ssi-wpjm-settings.js b/assets/js/ssi-wpjm-settings.js index e2e629d..f784739 100644 --- a/assets/js/ssi-wpjm-settings.js +++ b/assets/js/ssi-wpjm-settings.js @@ -272,8 +272,6 @@ $('img.ssi-wpjm-gallery-image').on('load', function () { - console.log('Image loaded'); - imgSrc = $(this).attr('src'); fullImgSrc = imgSrc.replace("-150x150", ""); $('.hdsmi-template__image').attr('src', fullImgSrc); From a378252ce45f320d908fcabf4e177da8a3b2135c Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Wed, 20 Jul 2022 09:55:16 +0100 Subject: [PATCH 35/50] Neaten up some code with comments! --- inc/functions.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index 3231d6f..881119b 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -360,17 +360,27 @@ function ssi_wpjm_add_preview_markup_to_settings_page() { From 8675ebf89011a0c0a754a7586226ada6ce98b24f Mon Sep 17 00:00:00 2001 From: Keith Devon Date: Wed, 20 Jul 2022 10:27:42 +0100 Subject: [PATCH 36/50] Readme updates --- readme.txt | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/readme.txt b/readme.txt index ee6dacb..39990e2 100644 --- a/readme.txt +++ b/readme.txt @@ -8,17 +8,40 @@ Requires PHP: 7.4 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html -This plugin automatically generates beautiful and branded images which are displayed in social media feeds when a job is shared on social media. +Automatically generate beautiful and branded social sharing images for your WP Job Manager jobs. == Description == -Simple Social Images for WP job Manager is a plugin which automates the creation of branded, beautiful social images for your WP Job Manager jobs. Our clients have told us that jobs which are shared on social media and show a branded image, containing the job title, location and salary, have improved engagement. +Simple Social Images for WP Job Manager automates the creation of branded, beautiful social images for your WP Job Manager jobs. ⚠️**Important** - _for this plugin to work, it requires a paid Simple Social Images license in order to generate the images. [Purchase a license here](https://simplesocialimages.com)_. -When you share a job URL from your website on social networks, a preview image can be shown in order to preview the content. If this isn't customised, it can often look unprofessional. Many WP Job Manager users will create their own images, uploading them to WordPress. However, this is time consumuing and prone to errors. This plugin automates the creation of these images and makes sure they are set as the image to use in the social network preview. +When you share a job URL from your website on social networks, they will look for an image to display. Sometimes no image can be found. Sometimes the image is generic, irrelevant, unprofessional or just embarrasing! -The images that are generated can be customised to suit your brand. In fact, you have control over which template you would like to use (currently there is a choice of 5, with more to come soon!), which colours should be used in the template, adding your logo to each image as well as choosing suitable background images. Our simple preview tool allows you to preview what you images will look like in the plugins settings page. +Custom sharing images **increase engagement** when you, or others, share your jobs online. + +To solve this, many WP Job Manager users will create their own images and upload them to WordPress. But this can be very time consuming to produce (e.g. using Canva) and difficult to maintain consistency. + +With Simple Social Images for WP Job Manager you can automate this process, getting the engagement that you want while saving 50+ hours per year. + +How it works: + +1. Choose your template and customise it to your brand +2. Create and publish a job +3. The plugin will create an image and save it to your WordPress Media Library +4. The plugin will set the og:image tag to the URL of the custom image +5. Share your job online and see your custom sharing image + +The images that are generated can be customised to suit your brand. You have control over: + +* Template choice +* Fonts +* Text sizes +* Colors +* Company logo and size +* Background images + +Our simple preview tool allows you to preview what you images will look like in the plugins settings page. == Installation == From df795ddcb2d8545bec247444d82f860318298dd8 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Wed, 20 Jul 2022 10:47:23 +0100 Subject: [PATCH 37/50] Separate our helper functions --- inc/functions.php | 267 --------------------------------------------- inc/helpers.php | 271 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 271 insertions(+), 267 deletions(-) create mode 100644 inc/helpers.php diff --git a/inc/functions.php b/inc/functions.php index 881119b..8acc06f 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1,271 +1,4 @@ ID; - - } - - // get the image id stored as meta. - $image_id = get_post_meta( $post_id, 'ssi_wpjm_image_id', true ); - - // if we have no image id. - if ( empty( $image_id ) ) { - return 0; - } - - // get the image url for the associated meta. - $image_url = wp_get_attachment_image_url( $image_id, 'ssi_image' ); - - // if we have no image url. - if ( $image_url === false ) { - return 0; - } - - // go this far, we must have an image. - return apply_filters( 'ssi_wpjm_has_image', $image_id, $post_id ); - -} - -/** - * Sorts an array by the order paramter. - */ -function ssi_wpjm_array_sort_by_order_key( $a, $b ) { - - // if no order paramter is provided. - if ( ! isset( $a['order'] ) ) { - - // set the order to 10. - $a['order'] = 10; - - } - - // if no order paramter is provided. - if ( ! isset( $b['order'] ) ) { - - // set the order to 10. - $b['order'] = 10; - - } - - // if the first array element is the same as the next. - if ( $a['order'] === $b['order'] ) { - return 0; - } - - // return -1 is the first array element is less than the second, otherwise return 1. - return ( $a['order'] < $b['order'] ) ? -1 : 1; - -} - -/** - * Returns an array of all the registered settings. - */ -function ssi_wpjm_get_settings() { - - $settings = apply_filters( - 'ssi_wpjm_settings', - array() - ); - - // sort the settings based on the order parameter. - uasort( $settings, 'ssi_wpjm_array_sort_by_order_key' ); - - // return the settings. - return $settings; - -} - -/** - * Gets the current active template selected. - * - * @return string The template name. - */ -function ssi_wpjm_get_template() { - - return apply_filters( - 'ssi_wpjm_template', - get_option( 'ssi_wpjm_template' ) - ); - -} - -/** - * Gets the current active text color. - */ -function ssi_wpjm_get_text_color() { - - return apply_filters( - 'ssi_wpjm_text_color', - get_option( 'ssi_wpjm_text_color' ) - ); - -} - -/** - * Gets the current active text background color. - */ -function ssi_wpjm_get_text_bg_color() { - - return apply_filters( - 'ssi_wpjm_text_bg_color', - get_option( 'ssi_wpjm_text_bg_color' ) - ); - -} - -/** - * Gets the current active background color. - */ -function ssi_wpjm_get_bg_color() { - - return apply_filters( - 'ssi_wpjm_bg_color', - get_option( 'ssi_wpjm_bg_color' ) - ); - -} - -/** - * Gets the currently uploaded logo attachment ID. - */ -function ssi_wpjm_get_logo_id() { - - return apply_filters( - 'ssi_wpjm_logo_id', - get_option( 'ssi_wpjm_logo' ) - ); - -} - -/** - * Gets the currently set logo size. - */ -function ssi_wpjm_get_logo_size() { - - return apply_filters( - 'ssi_wpjm_logo_size', - get_option( 'ssi_wpjm_logo_size' ) - ); - -} - -/** - * Gets the currently uploaded logo attachment ID. - */ -function ssi_wpjm_get_background_images() { - - // get the background images. - $bg_images = get_option( 'ssi_wpjm_background_images' ); - - // if we have no bg images. - if ( empty( $bg_images ) ) { - return array(); - } - - return apply_filters( - 'ssi_wpjm_background_images', - explode( ',', $bg_images ) - ); - -} - -/** - * Gets the current title font size. - */ -function ssi_wpjm_get_title_font_size() { - - return apply_filters( - 'ssi_wpjm_title_font_size', - get_option( 'ssi_wpjm_title_size' ) - ); - -} - -/** - * Gets the current location font size. - */ -function ssi_wpjm_get_location_font_size() { - - return apply_filters( - 'ssi_wpjm_location_font_size', - get_option( 'ssi_wpjm_location_size' ) - ); - -} - -/** - * Gets the current salary font size. - */ -function ssi_wpjm_get_salary_font_size() { - - return apply_filters( - 'ssi_wpjm_salary_font_size', - get_option( 'ssi_wpjm_salary_size' ) - ); - -} - -/** - * Gets the current Google font URL. - */ -function ssi_wpjm_get_google_font_url() { - - return apply_filters( - 'ssi_wpjm_google_font_url', - get_option( 'ssi_wpjm_google_font_url' ) - ); - -} - -/** - * Gets the current Google font family. - */ -function ssi_wpjm_get_google_font_family() { - - // get the font family from settings. - $font_family = get_option( 'ssi_wpjm_google_font_family' ); - - // if the font family is empty. - if ( empty( $font_family ) ) { - - // set to default system family for sans serif. - $font_family = 'sans-serif;'; - - } - - return apply_filters( - 'ssi_wpjm_google_font_family', - $font_family - ); - -} - -/** - * Grabs a random image ID from those added to the settings page. - */ -function ssi_wpjm_get_random_image_id() { - - // get the image ids from options. - $images = ssi_wpjm_get_background_images(); - - $image_id_key = array_rand( $images, 1 ); - $image_id = $images[ $image_id_key ]; - - return absint( $image_id ); - -} - /** * Returns the URL of the SSI API to generate an image. */ diff --git a/inc/helpers.php b/inc/helpers.php new file mode 100644 index 0000000..f275a42 --- /dev/null +++ b/inc/helpers.php @@ -0,0 +1,271 @@ +ID; + + } + + // get the image id stored as meta. + $image_id = get_post_meta( $post_id, 'ssi_wpjm_image_id', true ); + + // if we have no image id. + if ( empty( $image_id ) ) { + return 0; + } + + // get the image url for the associated meta. + $image_url = wp_get_attachment_image_url( $image_id, 'ssi_image' ); + + // if we have no image url. + if ( $image_url === false ) { + return 0; + } + + // go this far, we must have an image. + return apply_filters( 'ssi_wpjm_has_image', $image_id, $post_id ); + +} + +/** + * Sorts an array by the order paramter. + */ +function ssi_wpjm_array_sort_by_order_key( $a, $b ) { + + // if no order paramter is provided. + if ( ! isset( $a['order'] ) ) { + + // set the order to 10. + $a['order'] = 10; + + } + + // if no order paramter is provided. + if ( ! isset( $b['order'] ) ) { + + // set the order to 10. + $b['order'] = 10; + + } + + // if the first array element is the same as the next. + if ( $a['order'] === $b['order'] ) { + return 0; + } + + // return -1 is the first array element is less than the second, otherwise return 1. + return ( $a['order'] < $b['order'] ) ? -1 : 1; + +} + +/** + * Returns an array of all the registered settings. + */ +function ssi_wpjm_get_settings() { + + $settings = apply_filters( + 'ssi_wpjm_settings', + array() + ); + + // sort the settings based on the order parameter. + uasort( $settings, 'ssi_wpjm_array_sort_by_order_key' ); + + // return the settings. + return $settings; + +} + +/** + * Gets the current active template selected. + * + * @return string The template name. + */ +function ssi_wpjm_get_template() { + + return apply_filters( + 'ssi_wpjm_template', + get_option( 'ssi_wpjm_template' ) + ); + +} + +/** + * Gets the current active text color. + */ +function ssi_wpjm_get_text_color() { + + return apply_filters( + 'ssi_wpjm_text_color', + get_option( 'ssi_wpjm_text_color' ) + ); + +} + +/** + * Gets the current active text background color. + */ +function ssi_wpjm_get_text_bg_color() { + + return apply_filters( + 'ssi_wpjm_text_bg_color', + get_option( 'ssi_wpjm_text_bg_color' ) + ); + +} + +/** + * Gets the current active background color. + */ +function ssi_wpjm_get_bg_color() { + + return apply_filters( + 'ssi_wpjm_bg_color', + get_option( 'ssi_wpjm_bg_color' ) + ); + +} + +/** + * Gets the currently uploaded logo attachment ID. + */ +function ssi_wpjm_get_logo_id() { + + return apply_filters( + 'ssi_wpjm_logo_id', + get_option( 'ssi_wpjm_logo' ) + ); + +} + +/** + * Gets the currently set logo size. + */ +function ssi_wpjm_get_logo_size() { + + return apply_filters( + 'ssi_wpjm_logo_size', + get_option( 'ssi_wpjm_logo_size' ) + ); + +} + +/** + * Gets the currently uploaded logo attachment ID. + */ +function ssi_wpjm_get_background_images() { + + // get the background images. + $bg_images = get_option( 'ssi_wpjm_background_images' ); + + // if we have no bg images. + if ( empty( $bg_images ) ) { + return array(); + } + + return apply_filters( + 'ssi_wpjm_background_images', + explode( ',', $bg_images ) + ); + +} + +/** + * Gets the current title font size. + */ +function ssi_wpjm_get_title_font_size() { + + return apply_filters( + 'ssi_wpjm_title_font_size', + get_option( 'ssi_wpjm_title_size' ) + ); + +} + +/** + * Gets the current location font size. + */ +function ssi_wpjm_get_location_font_size() { + + return apply_filters( + 'ssi_wpjm_location_font_size', + get_option( 'ssi_wpjm_location_size' ) + ); + +} + +/** + * Gets the current salary font size. + */ +function ssi_wpjm_get_salary_font_size() { + + return apply_filters( + 'ssi_wpjm_salary_font_size', + get_option( 'ssi_wpjm_salary_size' ) + ); + +} + +/** + * Gets the current Google font URL. + */ +function ssi_wpjm_get_google_font_url() { + + return apply_filters( + 'ssi_wpjm_google_font_url', + get_option( 'ssi_wpjm_google_font_url' ) + ); + +} + +/** + * Gets the current Google font family. + */ +function ssi_wpjm_get_google_font_family() { + + // get the font family from settings. + $font_family = get_option( 'ssi_wpjm_google_font_family' ); + + // if the font family is empty. + if ( empty( $font_family ) ) { + + // set to default system family for sans serif. + $font_family = 'sans-serif;'; + + } + + return apply_filters( + 'ssi_wpjm_google_font_family', + $font_family + ); + +} + +/** + * Grabs a random image ID from those added to the settings page. + */ +function ssi_wpjm_get_random_image_id() { + + // get the image ids from options. + $images = ssi_wpjm_get_background_images(); + + $image_id_key = array_rand( $images, 1 ); + $image_id = $images[ $image_id_key ]; + + return absint( $image_id ); + +} From 19b4696f287fb2dec5f6aea8398a48fb12edd0de Mon Sep 17 00:00:00 2001 From: Keith Devon Date: Wed, 20 Jul 2022 10:47:50 +0100 Subject: [PATCH 38/50] Reduce maximum font size --- inc/setttings.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inc/setttings.php b/inc/setttings.php index d688666..232e053 100644 --- a/inc/setttings.php +++ b/inc/setttings.php @@ -184,7 +184,7 @@ function ssi_wpjm_register_default_settings( $settings ) { 'description' => __( 'Select a size for the title.', 'simple-social-images-wpjm' ), 'input_type' => 'range', 'min' => '2', - 'max' => '10', + 'max' => '8', 'step' => '0.5', 'order' => 120, ); @@ -195,7 +195,7 @@ function ssi_wpjm_register_default_settings( $settings ) { 'description' => __( 'Select a size for the location.', 'simple-social-images-wpjm' ), 'input_type' => 'range', 'min' => '2', - 'max' => '10', + 'max' => '8', 'step' => '0.5', 'order' => 130, ); @@ -206,7 +206,7 @@ function ssi_wpjm_register_default_settings( $settings ) { 'description' => __( 'Select a size for the salary.', 'simple-social-images-wpjm' ), 'input_type' => 'range', 'min' => '2', - 'max' => '10', + 'max' => '8', 'step' => '0.5', 'order' => 140, ); From 0aca86adc774427b4f991f9fa325af9df360e0d2 Mon Sep 17 00:00:00 2001 From: Keith Devon Date: Wed, 20 Jul 2022 10:48:00 +0100 Subject: [PATCH 39/50] Template 5 spacing tweaks --- assets/css/ssi-wpjm-generate.css | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/css/ssi-wpjm-generate.css b/assets/css/ssi-wpjm-generate.css index f9c5d62..e6861c0 100644 --- a/assets/css/ssi-wpjm-generate.css +++ b/assets/css/ssi-wpjm-generate.css @@ -270,6 +270,7 @@ body { .hdsmi-template--5 .hdsmi-template__text > * { display: inline-block; padding: calc(1 * var(--hdsmi-template--unit)) calc(2 * var(--hdsmi-template--unit)); + margin: calc(.5 * var(--hdsmi-template--unit)) 0; background-color: var(--hdsmi--text--background-color); -webkit-box-decoration-break: clone; box-decoration-break: clone From 8c0285664e181f4d0edbf405c83b11a562308e40 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Wed, 20 Jul 2022 12:59:12 +0100 Subject: [PATCH 40/50] Output the social sharing image As open graph and twitter tags in the head of the page, taking into account whether the user has Yoast SEO installed and active or not. --- inc/functions.php | 90 +++++++++++++++++++++++++++++++++++++ inc/helpers.php | 30 +++++++++++++ inc/loader.php | 17 ++++++- inc/plugins/yoast-seo.php | 95 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 inc/plugins/yoast-seo.php diff --git a/inc/functions.php b/inc/functions.php index 8acc06f..a5bd74e 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -261,3 +261,93 @@ function ssi_wpjm_generate_social_image( $post_id = 0 ) { ); } + +/** + * Outputs the meta tags in the head for open graph and twitter images. + */ +function ssi_wpjm_render_tags() { + + // if this is not a single job. + if ( ! is_singular( 'job_listing' ) ) { + return; + } + + // get the social sharing image url. + $ssi_image_url = ssi_wpjm_ssi_get_image_url(); + + // if we have no URL. + if ( '' === $ssi_image_url ) { + return; + } + + // set an array of tags to render. + $tags = array(); + + // if we are rendering open graph tags. + if ( apply_filters( 'ssi_wpjm_render_og_image_tags', true ) === true ) { + + // merge the current tags with our tags array. + $tags = array_merge( + $tags, + array( + 'og:image' => $ssi_image_url, + 'og:image:width' => 1200, + 'og:image:height' => 630, + ) + ); + + } + + // if we are rendering twitter tags. + if ( apply_filters( 'ssi_wpjm_render_twitter_image_tags', true ) === true ) { + + // merge the current tags with our tags array. + $tags = array_merge( + $tags, + array( + 'twitter:image' => $ssi_image_url, + 'twitter:card' => 'summary_large_image', + ) + ); + + } + + // if we don't have any tags to output. + if ( empty( $tags ) ) { + return; + } + + echo '' . PHP_EOL; + + // loop through each tag. + foreach ( $tags as $property => $content ) { + + // create a filter name for this tag. + $filter = 'ssi_wpjm_meta_' . str_replace( ':', '_', $property ); + + // filter the tag + $content = apply_filters( $filter, $content ); + + // set the meta tag to name for twitter and property for open graph. + $label = strpos( $property, 'twitter' ) === false ? 'property' : 'name'; + + // if we have any content. + if ( $content ) { + + // print the tag screen. + printf( + '' . PHP_EOL, + esc_attr( $label ), + esc_attr( $property ), + esc_attr( $content ) + ); + + } + + } + + echo '' . PHP_EOL; + +} + +add_action( 'wp_head', 'ssi_wpjm_render_tags' ); diff --git a/inc/helpers.php b/inc/helpers.php index f275a42..56a6c10 100644 --- a/inc/helpers.php +++ b/inc/helpers.php @@ -41,6 +41,36 @@ function ssi_wpjm_has_image( $post_id = 0 ) { } +/** + * Returns the image url of a posts social image. + * + * @param integer $post_id The ID of the post to return the image of. Defaults to current post. + * @return string The image URL or an empty string if the post does not have an image. + */ +function ssi_wpjm_ssi_get_image_url( $post_id = 0 ) { + + // if no post ID is provided. + if ( 0 === $post_id ) { + $post_id = get_the_ID(); + } + + // if this post does not have an image. + if ( 0 === ssi_wpjm_has_image( $post_id ) ) { + return ''; + } + + // return the image url. + return apply_filters( + 'ssi_wpjm_ssi_image_url', + wp_get_attachment_image_url( + get_post_meta( $post_id, 'ssi_wpjm_image_id', true ), + 'ssi_image' + ), + $post_id + ); + +} + /** * Sorts an array by the order paramter. */ diff --git a/inc/loader.php b/inc/loader.php index daeb735..c5dbc63 100644 --- a/inc/loader.php +++ b/inc/loader.php @@ -17,4 +17,19 @@ require_once( $includes_file ); } -} \ No newline at end of file +} + +// load in all the required plugin files. +$plugins_fies = glob( plugin_dir_path( __FILE__ ) . '/plugins/*.php' ); + +// if we have any plugin files. +if ( ! empty( $plugins_fies ) ) { + + // loop through each file. + foreach ( $plugins_fies as $plugin_file ) { + + // require this file in the plugin. + require_once( $plugin_file ); + + } +} diff --git a/inc/plugins/yoast-seo.php b/inc/plugins/yoast-seo.php new file mode 100644 index 0000000..43d9965 --- /dev/null +++ b/inc/plugins/yoast-seo.php @@ -0,0 +1,95 @@ + Date: Wed, 20 Jul 2022 13:45:35 +0100 Subject: [PATCH 41/50] Compatability with Rank Math and AIOSEO --- inc/plugins/all-in-one-seo.php | 62 +++++++++++++++++++++++ inc/plugins/rank-math-seo.php | 89 ++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 inc/plugins/all-in-one-seo.php create mode 100644 inc/plugins/rank-math-seo.php diff --git a/inc/plugins/all-in-one-seo.php b/inc/plugins/all-in-one-seo.php new file mode 100644 index 0000000..d8dd449 --- /dev/null +++ b/inc/plugins/all-in-one-seo.php @@ -0,0 +1,62 @@ +social->facebook->getImage(); + + // if we have a custom open graph image set. + if ( ! empty( $custom_og_image ) ) { + + // prevent this plugin outputting an og image. + add_filter( 'ssi_wpjm_render_og_image_tags', '__return_false' ); + + } + + // return the meta tags. + return $facebook_tags; +} + +add_filter( 'aioseo_facebook_tags', 'ssi_wpjm_aioseo_change_open_graph_tags' ); + +/** + * Change Twitter image output with All in one SEO if necessary. + * + * @param string $url URL of the image. + */ +function ssi_wpjm_aioseo_change_twitter_tags( $twitter_tags ) { + + // if this is not a single job. + if ( ! is_singular( 'job_listing') ) { + return $twitter_tags; + } + + // get custom twitter images. + $custom_twitter_image = \aioseo()->social->twitter->getImage(); + + // if we have a custom twitter image set. + if ( ! empty( $custom_twitter_image ) ) { + + // prevent this plugin outputting a twitter image. + add_filter( 'ssi_wpjm_render_twitter_image_tags', '__return_false' ); + + } + + // return the meta tags. + return $twitter_tags; +} + +add_filter( 'aioseo_twitter_tags', 'ssi_wpjm_aioseo_change_twitter_tags' ); diff --git a/inc/plugins/rank-math-seo.php b/inc/plugins/rank-math-seo.php new file mode 100644 index 0000000..6e36415 --- /dev/null +++ b/inc/plugins/rank-math-seo.php @@ -0,0 +1,89 @@ + Date: Wed, 20 Jul 2022 16:05:23 +0100 Subject: [PATCH 42/50] Readme updates Included the requirement for using WP Job Manager --- readme.txt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/readme.txt b/readme.txt index 39990e2..9f16674 100644 --- a/readme.txt +++ b/readme.txt @@ -14,7 +14,7 @@ Automatically generate beautiful and branded social sharing images for your WP J Simple Social Images for WP Job Manager automates the creation of branded, beautiful social images for your WP Job Manager jobs. -⚠️**Important** - _for this plugin to work, it requires a paid Simple Social Images license in order to generate the images. [Purchase a license here](https://simplesocialimages.com)_. +⚠️**Important** - _for this plugin to work, it requires a paid Simple Social Images license in order to generate the images. [Purchase a license here](https://simplesocialimages.com)_. It also requires you to have the [WP Job Manager](https://wordpress.org/plugins/wp-job-manager/) plugin installed and activated. When you share a job URL from your website on social networks, they will look for an image to display. Sometimes no image can be found. Sometimes the image is generic, irrelevant, unprofessional or just embarrasing! @@ -74,12 +74,13 @@ You can also test how your jobs look on [Facebook](https://developers.facebook.c == Screenshots == -1. Template 2 preview -2. Template 3 preview -3. Template 4 preview -4. Template 5 preview -5. The Simple Social Images for WP Job Manager settings screen -6. The Simple Social Images for WP Job Manager meta box, used to generate the images for each job +1. Template 1 preview +2. Template 2 preview +3. Template 3 preview +4. Template 4 preview +5. Template 5 preview +6. The Simple Social Images for WP Job Manager settings screen +7. The Simple Social Images for WP Job Manager meta box, used to generate the images for each job == Changelog == From e53a3845d221475205ceae6068e6e3bf28bc4918 Mon Sep 17 00:00:00 2001 From: Keith Devon Date: Wed, 20 Jul 2022 22:10:30 +0100 Subject: [PATCH 43/50] Settings page improvements --- assets/css/ssi-wpjm-admin.css | 4 ++ assets/css/ssi-wpjm-generate.css | 47 +++++++++++++++----- assets/js/ssi-wpjm-settings.js | 21 +++++++++ inc/functions.php | 74 ++++++++++++++++++++++++++++++-- inc/setttings.php | 49 ++++++++++++++++++--- 5 files changed, 175 insertions(+), 20 deletions(-) diff --git a/assets/css/ssi-wpjm-admin.css b/assets/css/ssi-wpjm-admin.css index 7b1a2d5..d33bde4 100644 --- a/assets/css/ssi-wpjm-admin.css +++ b/assets/css/ssi-wpjm-admin.css @@ -62,6 +62,10 @@ img.ssi-image { gap: 0; } +.ssi-wpjm-settings-form .setting-type--hidden { + display: none; +} + .ssi-wpjm-settings-form tr { display: flex; flex-wrap: wrap; diff --git a/assets/css/ssi-wpjm-generate.css b/assets/css/ssi-wpjm-generate.css index e6861c0..d18f27c 100644 --- a/assets/css/ssi-wpjm-generate.css +++ b/assets/css/ssi-wpjm-generate.css @@ -43,7 +43,7 @@ body { } .hdsmi-template__text { font-size: calc(var(--hdsmi--font-size) * var(--hdsmi-template--unit)); - line-height: 1.25; + line-height: var(--hdsmi--line-height); font-family: var(--hdsmi--font-family); color: var(--hdsmi--text--color) } @@ -69,11 +69,16 @@ body { height: calc(var(--hdsmi--logo--height) * var(--hdsmi-template--unit)); width: var(--hdsmi--logo--width) } +.hdsmi-template__image { + display: block; +} /* Template 1 */ .hdsmi-template.hdsmi-template--1 { --hdsmi--template--font-weight: bold; + --hdsmi--line-height: 1.5; + --hdsmi--line-gap: .1em; } .hdsmi-template--1 .hdsmi-template__inner { display: flex; @@ -88,13 +93,20 @@ body { gap: calc(2 * var(--hdsmi-template--unit)); padding: calc(3 * var(--hdsmi-template--unit)) } + .hdsmi-template--1 .hdsmi-template__text > * { + display: block; +} + +.hdsmi-template--1 .hdsmi-template__text > * > [class*="__inner"] { display: inline; - padding: calc(1 * var(--hdsmi-template--unit)) calc(2 * var(--hdsmi-template--unit)); + line-height: var(--hdsmi--line-height); + padding: calc( ( ( (1em * var(--hdsmi--line-height)) - 1em) / 2) - (var(--hdsmi--line-gap) / 2) ) calc(2 * var(--hdsmi-template--unit)); background-color: var(--hdsmi--text--background-color); -webkit-box-decoration-break: clone; box-decoration-break: clone } + .hdsmi-template--1 .hdsmi-template__image { align-self: stretch; width: 33%; @@ -111,6 +123,7 @@ body { .hdsmi-template--2 { --hdsmi--location--font-size: 2.5; + --hdsmi--line-height: 1.25; } .hdsmi-template--2 .hdsmi-template__inner { display: flex; @@ -168,6 +181,7 @@ body { .hdsmi-template--3 { --hdsmi--title--font-weight: bold; + --hdsmi--line-height: 1.25; } .hdsmi-template--3 { --hdsmi--title--font-size: 4; @@ -217,6 +231,7 @@ body { --hdsmi--location--font-size: 2.5; --hdsmi--salary--font-size: 2.5; --hdsmi--logo--height: 5; + --hdsmi--line-height: 1.25; } .hdsmi-template--4 .hdsmi-template__inner { display: grid; @@ -233,7 +248,6 @@ body { left: 0; right: 0; object-fit: cover; - mix-blend-mode: screen } .hdsmi-template--4 .hdsmi-template__text { position: relative; @@ -256,21 +270,32 @@ body { /* Template 5 */ .hdsmi-template--5 { + --hdsmi--line-height: 1.5; + --hdsmi--line-gap: .1em; --hdsmi--title--font-size: 5; --hdsmi--location--font-size: 3; - --hdsmi--logo--height: 3 + --hdsmi--logo--height: 3; } .hdsmi-template--5 .hdsmi-template__text { - width: calc(50 * var(--hdsmi-template--unit)); + line-height: calc(.1 * var(--hdsmi-template--unit)); + width: calc( (50 * var(--hdsmi-template--unit)) + (8 * var(--hdsmi-template--unit))); position: absolute; top: 50%; - left: calc(50% - calc(4 * var(--hdsmi-template--unit))); - transform: translateY(-50%) + left: calc(50% - calc(10 * var(--hdsmi-template--unit))); + transform: translateY(-50%); + padding-top: calc(var(--hdsmi--logo--height) * var(--hdsmi-template--unit)); } + .hdsmi-template--5 .hdsmi-template__text > * { - display: inline-block; - padding: calc(1 * var(--hdsmi-template--unit)) calc(2 * var(--hdsmi-template--unit)); - margin: calc(.5 * var(--hdsmi-template--unit)) 0; + display: block; + margin: .5em 0; +} + +.hdsmi-template--5 .hdsmi-template__text > * > [class*="__inner"] { + display: inline; + line-height: var(--hdsmi--line-height); + padding: calc( ( ( (1em * var(--hdsmi--line-height)) - 1em) / 2) - (var(--hdsmi--line-gap) / 2) ) calc(2 * var(--hdsmi-template--unit)); + background-color: var(--hdsmi--text--background-color); -webkit-box-decoration-break: clone; box-decoration-break: clone @@ -280,7 +305,7 @@ body { white-space: pre-line } .hdsmi-template--5 .hdsmi-template__title { - line-height: 1 + } .hdsmi-template--5 .hdsmi-template__image { width: calc(50 * var(--hdsmi-template--unit)); diff --git a/assets/js/ssi-wpjm-settings.js b/assets/js/ssi-wpjm-settings.js index f784739..d218360 100644 --- a/assets/js/ssi-wpjm-settings.js +++ b/assets/js/ssi-wpjm-settings.js @@ -289,4 +289,25 @@ }); + /* Placeholder text fields */ + $('.hdsmi-template__text > * ').on('focusout', function () { + + console.log('Focusout'); + + // find the inner element + editableText = $(this).find('[contenteditable="true"]'); + + // get the content. + thisContent = editableText.text(); + console.log(thisContent); + + // get the data-input value. + dataInputValue = editableText.data('input'); + console.log(dataInputValue); + + // set the input value. + $('#' + dataInputValue).val(thisContent); + + }); + })( jQuery ); \ No newline at end of file diff --git a/inc/functions.php b/inc/functions.php index 881119b..8d44137 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -251,6 +251,42 @@ function ssi_wpjm_get_google_font_family() { } +/** + * Gets the title placeholder text. + */ +function ssi_wpjm_get_title_placeholder_text() { + + return apply_filters( + 'ssi_wpjm_title_placeholder_text', + get_option( 'ssi_wpjm_title_placeholder_text' ) + ); + +} + +/** + * Gets the location placeholder text. + */ +function ssi_wpjm_get_location_placeholder_text() { + + return apply_filters( + 'ssi_wpjm_location_placeholder_text', + get_option( 'ssi_wpjm_location_placeholder_text' ) + ); + +} + +/** + * Gets the salary placeholder text. + */ +function ssi_wpjm_get_salary_placeholder_text() { + + return apply_filters( + 'ssi_wpjm_salary_placeholder_text', + get_option( 'ssi_wpjm_salary_placeholder_text' ) + ); + +} + /** * Grabs a random image ID from those added to the settings page. */ @@ -353,9 +389,41 @@ function ssi_wpjm_add_preview_markup_to_settings_page() {
- Test job title - London, UK - £30,000 per annum + + + + + + + + +
160, ); + $settings['title_placeholder_text'] = array( + 'option_name' => 'ssi_wpjm_title_placeholder_text', + 'input_type' => 'hidden', + 'order' => 170, + ); + + $settings['salary_placeholder_text'] = array( + 'option_name' => 'ssi_wpjm_salary_placeholder_text', + 'input_type' => 'hidden', + 'order' => 170, + ); + + $settings['location_placeholder_text'] = array( + 'option_name' => 'ssi_wpjm_location_placeholder_text', + 'input_type' => 'hidden', + 'order' => 170, + ); + // return the registered settings array. return $settings; @@ -274,6 +292,25 @@ function ssi_wpjm_setting_input_type_textarea( $setting, $value ) { add_action( 'ssi_wpjm_setting_type_textarea', 'ssi_wpjm_setting_input_type_textarea', 10, 2 ); +/** + * Controls the output of hidden input setting. + * + * @param array $setting an array of the current setting. + * @param mixed $value the current value of this setting saved in the database. + */ +function ssi_wpjm_setting_input_type_hidden( $setting, $value ) { + + // handle output for a hidden input. + ?> + + + +