tbenyon
Forum Replies Created
-
Forum: Reviews
In reply to: [External Login] Works like a charmReally appreciate you taking the time to write a review!
Thank you 🙂
Forum: Plugins
In reply to: [External Login] Redirect to another page after loginHey @icola007,
Glad you got it working 😊
I know that feeling of something suddenly working and you don’t know why?!
Would you minding writing a review for the plugin?
I’d be SUPER grateful!
Thanks,
Tom
Forum: Plugins
In reply to: [External Login] Redirect to another page after loginHey @icola007,
Reeally glad the plugin is working for you.
I will have a look into this tongiht to see how easy this is. I initially think this should be a very straightforward feature.
However, I’m also surprised using those other plugins are not working as I’m sticking closely to how WordPress handles login. But this is why I’ll need to look into it.
If you haven’t heard from me tomorrow, please feel free to chase me as I hope to at least update you by then.
Tom 🙂
Forum: Plugins
In reply to: [External Login] Change Username, Email in External DBHey @rjjacob,
I think the thing that feels initially strange about this flow is that WordPress uses the Username as the unique identifier. For this reason I am doing the same.
By setting the username to the e-mail and then wanting this to be able to be updated, as a unique identifier, doesn’t make sense.
I welcome your opinion on the way this would be solved but my current thought is:
- You set the username in WordPress to be the primary key of the external Users table (assuming this is what that system uses to uniquely identify users. This would need testing as I don’t know how grumpy WordPress will get if your primary key is an integer.
- This would still require that external login would support e-mail as a (as well as username) when logging in.
Again your opinion is welcomed.
Tom
Forum: Plugins
In reply to: [External Login] Can’t log in | Password HashingI’m presuming this is resolved as I haven’t heard back so I’m going to mark this as so.
If this is not the case, please feel free to get back to me and we’ll continue to look into this for you.
Thanks,
Tom 🙂
Forum: Plugins
In reply to: [External Login] Active/Inactive UsersHey @xprojectsx,
Sincere apologies for the delay.
New thing to try.
1) Replace all the code in
options/wpconfig_options.phpwith the below:<?php //If a constant is defined for an option, make that take president function exlog_get_option($option_name) { $constant_option_name = strtoupper($option_name); if (defined($constant_option_name)) { return constant($constant_option_name); } else { $option_data = get_option($option_name); $decoded_option_data = json_decode(base64_decode($option_data), true); if ($decoded_option_data) { return exlog_modify_repeater_data_for_view_use($decoded_option_data); // If data was JSON return PHP array (for repeater fields) } return $option_data; } } function exlog_is_wpconfig_option_set($option_name) { return defined(strtoupper($option_name)); } function exlog_modify_repeater_data_for_view_use($repeater_data) { $formatted_data = array(); if (is_array($repeater_data)) { foreach ($repeater_data as $repeater_item_data) { $formatted_repeater_items_data = array(); foreach ($repeater_item_data as $repeater_item_datum) { if ($repeater_item_datum['repeater_field']) { $value = exlog_modify_repeater_data_for_view_use($repeater_item_datum['value']); } else { $value = $repeater_item_datum['value']; } $formatted_repeater_items_data[$repeater_item_datum['name']] = $value; } array_push($formatted_data, $formatted_repeater_items_data); } return $formatted_data; } else { return $repeater_data; } }2) Replace all the code in
js/exlog_repeater_field_handler.jswith this:// Possible data structure var possible_repeater_data_master = [ { "field_name": "title", "id": "12345678", "repeater_field": false, "field_data": "this is some text" }, { "field_name": "Names Repeater", "id": "12345678", "repeater_field": true, "field_data": [ // Repeater items [ // Repeater Item { "field_name": "title in repeater", "id": "12345678", "repeater_field": false, "field_data": "this is some textoooo" }, { "field_name": "title in repeater222", "id": "12345678", "repeater_field": false, "field_data": "this is some textoooo222" }, { "field_name": "inner_repeater", "id": "12345678", "repeater_field": true, "field_data": [ // Repeater Items [ // Repater Item { "field_name": "title in repeater333", "id": "12345678", "repeater_field": false, "field_data": "this is some textoooo3333" }, { "field_name": "title in repeater3331", "id": "12345678", "repeater_field": false, "field_data": "this is some textoooo3332" } ], [ // Repater Item 2 { "field_name": "title in repeater333", "id": "12345678", "repeater_field": false, "field_data": "this is some textoooo3333" }, { "field_name": "title in repeater3331", "id": "12345678", "repeater_field": false, "field_data": "this is some textoooo3332" } ] ] } ] ] } ]; (function ($) { $(function () { var $parent_repeater_fields = $(".option-container.repeater.exlog-repeater-master"); var repeater_buttons_selector = ".exlog_repeater_add_button"; var repeater_item_selector = ".repeater_item"; var repeater_data_attr = 'data-exlog-repeater-id'; var master_markup_item_selector = repeater_item_selector + '[' + repeater_data_attr + '="0"]'; var click_event_name = 'click'; var change_events = ['keyup', 'paste', 'change']; var repeater_data_store_selector = '.exlog_repeater_data_store'; function object_to_string_if_object(data) { if (typeof data === 'object') { try { data = JSON.stringify(data); } catch (error) { // Leave data in current format } } return data } function place_data_from_db() { function place_specific_repeater_values($parent_element, data) { try { data = JSON.parse(data); } catch(e) { // } // Put all data in the name value var $data_store = $parent_element.children(repeater_data_store_selector); var data_string; try { data_string = JSON.stringify(data); } catch(e) { console.log('EXLOG: Failed to parse some data from the database.\nIncorrect data:', data); data_string = false; } $data_store.val(btoa(data_string)); // Of that data, put each value in the correct input if (data && data != 'false') { data.forEach(function (repeater_item, i) { var $repeater_item; if (i > 0) { // If not the first repeater item - create a new one in the DOM and store the jQuery object $repeater_item = create_new_item($parent_element, i, false); } else { // If the first repeater item, get the one repeater jQuery object $repeater_item = $parent_element.find('> .repeater_item'); } repeater_item.forEach(function (repeater_item_option) { var input_data = object_to_string_if_object(repeater_item_option['value']); var input_selector = '> .repeater_item_input_container > .option-container > [name="' + repeater_item_option['name'] + '"]'; var $input_item = $repeater_item.find(input_selector); // Add DB value into the input if ($input_item.attr('type') === 'checkbox') { $input_item.prop('checked', input_data); } else { $input_item.val(input_data); } // If the input data is a repeater field, call this function again with the relevant data and $parent element if (repeater_item_option['repeater_field']) { var $next_repeater = $input_item.closest('.option-container'); place_specific_repeater_values($next_repeater, repeater_item_option['value']); } }); }); } } // Put the master data into the repeater master component and then start placing specific values $parent_repeater_fields.each(function () { var $parent_repeater_field = $(this); var base_64_string = $parent_repeater_field.children(repeater_data_store_selector).val(); var parent_repeater_data; try { parent_repeater_data = JSON.parse(atob(atob(base_64_string))); // Once for storing from server, once for data store } catch (e) { parent_repeater_data = false; } place_specific_repeater_values($parent_repeater_field, parent_repeater_data) }); } function create_new_item($repeater_option_container, item_id) { // Get the markup to copy from looking at first item var markup = $repeater_option_container.children(master_markup_item_selector).html(); var $markup = $('<section class="repeater_item">' + markup + '</section>'); // Clean out any repeater ids that are not the first one from the generated markup $(repeater_item_selector, $markup).each(function () { var $repeater_item = $(this); if ($repeater_item.attr(repeater_data_attr) !== "0") { $repeater_item.remove(); } }); // Store the new id in the attr of the repeater item $markup.attr('data-exlog-repeater-id', item_id); var $markup_inputs = $markup.children('.repeater_item_input_container').find('.option-container input:not([type=button])'); $markup_inputs.each(function () { var $markup_input = $(this); $markup_input.val(''); }); // Place the new markup on the page $repeater_option_container.children('.add_more').before($markup); reset_watchers(); return $markup; } function reselect_add_buttons() { $(repeater_buttons_selector).off(click_event_name).on(click_event_name, on_add_button_click); } function on_add_button_click() { var $button = $(this); var $add_more_container = $button.closest(".add_more"); var used_ids = []; // Store all used ids $add_more_container.siblings(repeater_item_selector).each(function () { var $repeater_item = $(this); var repeater_item_id = $repeater_item.attr(repeater_data_attr); used_ids.push(repeater_item_id) }); // Get a unique id for the new repeater item var new_id = 1; while (used_ids.indexOf(new_id.toString()) > -1 ) { // While new_id is in used_ids new_id += 1; } var $repeater_option_container = $add_more_container.closest('.option-container.repeater'); create_new_item($repeater_option_container, new_id, false); } function monitorRepeaterInputs() { var change_events_string = change_events.join(' '); var $repeater_data_stores = $(repeater_data_store_selector); // For every repeater data store $repeater_data_stores.each(function () { var $repeater_data_store = $(this); // Get just the inputs for that data store var $inputs = $repeater_data_store.siblings('.repeater_item').children('.repeater_item_input_container').children('.option-container').children('input, textarea'); // Clear previous change events on inputs $inputs.off(change_events_string); // For each input, if there is a change in the data, update the data in the repeater data store $inputs.on(change_events_string, (function () { update_repeater_data($repeater_data_store, $inputs); // After the data store data is updated, trigger an event change on the store so that parent stores will update their data $repeater_data_store.trigger(change_events[0]); })); }); } function update_repeater_data($repeater_data_store) { var data_for_store = []; // Object to be populated by first child inputs of repeater var repeater_items = $repeater_data_store.siblings('.repeater_item'); repeater_items.each(function () { var repeater_item = []; var $inputs = $(this).children('.repeater_item_input_container').children('.option-container').children('input, textarea'); $inputs.each(function () { var $input = $(this); var value; if ($input.attr('type') === 'text') { value = $input.val(); } else if ($input.attr('type') === 'checkbox') { value = $input.prop('checked'); } else { value = null; } var repeater_field = false; if ($input.hasClass('exlog_repeater_data_store')) { repeater_field = true; try { value = JSON.parse(atob(value)); // If the data can be interpreted as JSON convert it to an object } catch (error) { console.log("EXLOG: Error storing repeater data for '" + $input.attr('name') + "'", "Value:", value); } } repeater_item.push({ "name": $input.attr('name'), "repeater_field": repeater_field, "value": value }); }); data_for_store.push(repeater_item); }); $repeater_data_store.val(btoa(JSON.stringify(data_for_store))); } function on_delete_item_click() { $('.delete_repeater_item').off(click_event_name).on(click_event_name, function () { var $delete_button = $(this); var $repeater_item = $delete_button.closest(repeater_item_selector); // var $repeater_item_name = $repeater_item.attr('name'); var $first_item = $repeater_item.siblings(master_markup_item_selector).find('input'); // Remove the repeater item from the DOM $repeater_item.remove(); // Ensure elements no longer in the DOM are no longer selected as otherwise data is kept reset_watchers(); // Make first repeater item trigger change to remove deleted items data $first_item.trigger(change_events[0]); }) } // All the selectors that need updating on DOM change function reset_watchers() { monitorRepeaterInputs(); reselect_add_buttons(); on_delete_item_click(); } place_data_from_db(); reset_watchers(); }) }(jQuery));Let me know if this works.
Tom
Forum: Plugins
In reply to: [External Login] Send you “a beer” problem with PaypalHey @xprojectsx,
I really appreciate you going to all this effort. I think it seems to be working for other people.
Your efforts trying is enough of a reward for me 🙂
Thank you very much! 🙂 🙂 🙂
I’ll mark this as resolved for now.
Thanks,
Tom
Forum: Plugins
In reply to: [External Login] Didn’t workSorry for the delay.
So are you telling me that on a local copy the test button works AND you can login with the external database?
However, on your live website, the test button works but the password is wrong?
Have you definitely got the same password hashing settings on your live environment?
If what I have said above is correct, and you’ve double checked the hashing settings then could you please send me your php logs that happen when you click the login button.
Thanks,
Tom
Forum: Plugins
In reply to: [External Login] Can’t log in | Password HashingForum: Plugins
In reply to: [External Login] Didn’t workHi @rohail1122,
We are not allowed to share personal contact details with each other in this forum. It breaks WordPress’ code of conduct.
I imagine the issue you are having is with your connection to the database on the live service.
Does the “Test” button work?
If not, can you tell me the error you received on screen.
Thanks,
Tom
Forum: Plugins
In reply to: [External Login] TablesHey Americo,
I’m sorry to say that this functionality isn’t currently supported.
I can add this in the future but I have a backlog of feature requests. With my main job and private work this isn’t likely to get done any time soon. This is a hobby for me.
My recommendation would be to get someone to do this integration for you as private work as it seems like a relatively unique issue.
Although some people have found me on Facebook and Linked In, I am not allowed to give out my details as it breaks the WordPress code of practice. For this reason I’d recommend looking for a developer who would be willing to take on this work for you.
Sorry I can’t be of more help but I will add this to the backlog as I may get round to it one day.
I’ll mark it as resolved on the basis that the answer is “it is not supported” and it is on the backlog for a potential future feature.
If you have any more questions however get back to me as I’d be happy to help.
Sorry I can’t be more helpful.
Thanks,
Tom
Forum: Plugins
In reply to: [External Login] Active/Inactive UsersAnd just to double check, with the new JS (with the base 64 conversion) does this work without setting the input type to text?
I’d be surprised if once you’ve updated the field on the front end then hit save that it doesn’t get stored in the database.
Forum: Plugins
In reply to: [External Login] Active/Inactive UsersI expect that on page load, but when you have changed type to be text, and then typed in some boxes, do you see a base 64 encoded value, and does it save to the database when you click save?
Forum: Plugins
In reply to: [External Login] Active/Inactive UsersTo clarify:
- You updated the JS with the code I gave you above
- You modified a field
- In there find the INPUT with the class “exlog_repeater_data_store” you can see a base 64 encoded string (a jumble of characters that ends with an equal sign = )
- When you click save the only thing you see in the database is “false”
When we did this by manually modifying the “FUNKY MONKEY” string previously the data did get saved in the database. This is so weird to me. I don’t know why Funky Monkey would get saved but the base64 string wouldn’t.
The only other differences I can think of is that:
- The input field was not hidden
- We manually typed it into the field
Let’s see which one of these makes a differences.
Firstly let’s just try making the hidden input non hidden.
In “wp-content/plugins/external-login/views/form_elements/repeater_field.php”Let’s modify the below code so it no longer says hidden as the type like this:
<input style="background-color: red;" class="exlog_repeater_data_store" type="hidden" name="<?php echo $form_field["field_slug"]; ?>" <?php if (!$exlog_parent_repeater_slug) : ?> value="<?php echo base64_encode(get_option($form_field["field_slug"])); ?>" <?php endif; ?> >. . . and change it to say text like this:
<input style="background-color: red;" class="exlog_repeater_data_store" type="text" name="<?php echo $form_field["field_slug"]; ?>" <?php if (!$exlog_parent_repeater_slug) : ?> value="<?php echo base64_encode(get_option($form_field["field_slug"])); ?>" <?php endif; ?> >After this let’s go through the process of:
- Reloading the page
- Typing something in the input fields
- make sure we can see the base 64 data appearing in that red field
- Hit save
- Check if anything saved to the database (Don’t forget to refresh 😛 )
Thanks,
Tom
Forum: Plugins
In reply to: [External Login] Active/Inactive UsersBrilliant news! I think we’re close to solving this one!
Still confused why it works in mine and not in yours.
Let’s try base64 encoding all data going to the database.
Could you replace everything in ‘wp-content/plugins/external-login/js/exlog_repeater_field_handler.js’ with the following code:
(function ($) { $(function () { var $parent_repeater_fields = $(".option-container.repeater.exlog-repeater-master"); var repeater_buttons_selector = ".exlog_repeater_add_button"; var repeater_item_selector = ".repeater_item"; var repeater_data_attr = 'data-exlog-repeater-id'; var master_markup_item_selector = repeater_item_selector + '[' + repeater_data_attr + '="0"]'; var click_event_name = 'click'; var change_events = ['keyup', 'paste']; var repeater_data_store_selector = '.exlog_repeater_data_store'; function object_to_string_if_object(data) { if (typeof data === 'object') { try { data = JSON.stringify(data); } catch (error) { // Leave data in current format } } return data } function place_data_from_db() { function place_specific_repeater_values($parent_element, data) { // Put all data in the name value var $data_store = $parent_element.children(repeater_data_store_selector); var data_string; try { data_string = JSON.stringify(data); } catch(e) { console.log('EXLOG: Failed to parse some data from the database.\nIncorrect data:', data); data_string = false; } $data_store.val(data_string); // Of that data, put each value in the correct input if (data) { data.forEach(function (repeater_item, i) { var $repeater_item; if (i > 0) { // If not the first repeater item - create a new one in the DOM and store the jQuery object $repeater_item = create_new_item($parent_element, i, false); } else { // If the first repeater item, get the one repeater jQuery object $repeater_item = $parent_element.find('> .repeater_item'); } repeater_item.forEach(function (repeater_item_option) { var input_data = object_to_string_if_object(repeater_item_option['value']); var input_selector = '> .repeater_item_input_container > .option-container > [name="' + repeater_item_option['name'] + '"]'; // Add DB value into the input var $input_element = $repeater_item.find(input_selector).val(input_data); // If the input data is a repeater field, call this function again with the relevant data and $parent element if (repeater_item_option['repeater_field']) { place_specific_repeater_values($input_element.closest('.option-container'), repeater_item_option['value']); } }); }); } } // Put the master data into the repeater master component and then start placing specific values $parent_repeater_fields.each(function () { var $parent_repeater_field = $(this); var base_64_string = $parent_repeater_field.children(repeater_data_store_selector).val(); var parent_repeater_data; try { parent_repeater_data = JSON.parse(atob(atob(base_64_string))); // Once for storing from server, once for data store } catch (e) { parent_repeater_data = false; } place_specific_repeater_values($parent_repeater_field, parent_repeater_data) }); } function create_new_item($repeater_option_container, item_id) { // Get the markup to copy from looking at first item var markup = $repeater_option_container.children(master_markup_item_selector).html(); var $markup = $('<section class="repeater_item">' + markup + '</section>'); // Clean out any repeater ids that are not the first one from the generated markup $(repeater_item_selector, $markup).each(function () { var $repeater_item = $(this); if ($repeater_item.attr(repeater_data_attr) !== "0") { $repeater_item.remove(); } }); // Store the new id in the attr of the repeater item $markup.attr('data-exlog-repeater-id', item_id); var $markup_inputs = $markup.children('.repeater_item_input_container').find('.option-container input:not([type=button])'); $markup_inputs.each(function () { var $markup_input = $(this); $markup_input.val(''); }); // Place the new markup on the page $repeater_option_container.children('.add_more').before($markup); reset_watchers(); return $markup; } function reselect_add_buttons() { $(repeater_buttons_selector).off(click_event_name).on(click_event_name, on_add_button_click); } function on_add_button_click() { var $button = $(this); var $add_more_container = $button.closest(".add_more"); var used_ids = []; // Store all used ids $add_more_container.siblings(repeater_item_selector).each(function () { var $repeater_item = $(this); var repeater_item_id = $repeater_item.attr(repeater_data_attr); used_ids.push(repeater_item_id) }); // Get a unique id for the new repeater item var new_id = 1; while (used_ids.indexOf(new_id.toString()) > -1 ) { // While new_id is in used_ids new_id += 1; } var $repeater_option_container = $add_more_container.closest('.option-container.repeater'); create_new_item($repeater_option_container, new_id, false); } function monitorRepeaterInputs() { var change_events_string = change_events.join(' '); var $repeater_data_stores = $(repeater_data_store_selector); $repeater_data_stores.each(function () { var $repeater_data_store = $(this); var $inputs = $repeater_data_store.siblings('.repeater_item').children('.repeater_item_input_container').children('.option-container').children('input, textarea'); // Clear previous events $inputs.off(change_events_string); $inputs.on(change_events_string, (function () { update_repeater_data($repeater_data_store, $inputs); $repeater_data_store.trigger(change_events[0]); })); }); } function update_repeater_data($repeater_data_store) { var data_for_store = []; // Object to be populated by first child inputs of repeater var repeater_items = $repeater_data_store.siblings('.repeater_item'); repeater_items.each(function () { var repeater_item = []; var $inputs = $(this).children('.repeater_item_input_container').children('.option-container').children('input, textarea'); $inputs.each(function () { var $input = $(this); var value = $input.val(); var repeater_field = false; if ($input.hasClass('exlog_repeater_data_store')) { repeater_field = true; try { value = JSON.parse(atob(value)); // If the data can be interpreted as JSON convert it to an object } catch (error) { console.log("EXLOG: Error storing repeater data for '" + $input.attr('name') + "'", "Value:", value); } } repeater_item.push({ "name": $input.attr('name'), "repeater_field": repeater_field, "value": value }); }); data_for_store.push(repeater_item); }); $repeater_data_store.val(btoa(JSON.stringify(data_for_store))); } function on_delete_item_click() { $('.delete_repeater_item').off(click_event_name).on(click_event_name, function () { var $delete_button = $(this); var $repeater_item = $delete_button.closest(repeater_item_selector); // var $repeater_item_name = $repeater_item.attr('name'); var $first_item = $repeater_item.siblings(master_markup_item_selector).find('input'); // Remove the repeater item from the DOM $repeater_item.remove(); // Ensure elements no longer in the DOM are no longer selected as otherwise data is kept reset_watchers(); // Make first repeater item trigger change to remove deleted items data $first_item.trigger(change_events[0]); }) } // All the selectors that need updating on DOM change function reset_watchers() { monitorRepeaterInputs(); reselect_add_buttons(); on_delete_item_click(); } place_data_from_db(); reset_watchers(); }) }(jQuery));