ThemeFuse / Unyson

A WordPress framework that facilitates the development of WP themes
http://unyson.io
922 stars 218 forks source link

How to properly use fw_backend_options_render in ajax? #913

Closed danyj closed 9 years ago

danyj commented 9 years ago

OK this is becoming ridiculous and I refuse to believe that this is the way this should be done.
Please help me out here.

I have in theme/options file topmenu.php that contains $options array of 20 options for top menu.

Than I have topmenu current options serialized and saved to a file , just an example

fw_options%5Bmenupreset%5D=style1&f.......

Id rather use JSON but according to this way of doing things it needs to be serialized https://github.com/ThemeFuse/Unyson/blob/bdc4f3ab1ed59e2c0b1ded227eb093cd1f556b4a/framework/static/js/fw.js#L933

Now in order for me to re-render my saved options , I need to :

run ajax to get options default array   by looking in to topmenu.php ( why? ) 
run ajax to get my saved serialized preset
run ajax  to  get the values  with  fw_backend_options_get_values ( why? ) 
run ajax to render and return html with  fw_backend_options_render

is there any way to shorten this madness?

can I use just max 2 ajax calls ?

run ajax to get my preset 
run ajax to rerender  
ghost commented 9 years ago

Id rather use JSON but according to this way of doing things it needs to be serialized

jQuery.ajax.data accepts 2 formats:

can I use just max 2 ajax calls ?

What stops you from doing that?

danyj commented 9 years ago

ok , thnx for the info about JSON,
but

What stops you from doing that?

well seems like I must run this in the way I described above

First ajax is to get the default array structure so that it can be compared to the option value Second one is to get my serialized options that are saved in a file

third is to get options from values required for render https://github.com/ThemeFuse/Unyson-Framework/blob/master/core/components/backend.php#L659-L666

fourth is to render

https://github.com/ThemeFuse/Unyson-Framework/blob/master/core/components/backend.php#L578-L585

or am I missing the point here in those actions ?

danyj commented 9 years ago

so basically question is can I use my saved serialized directly with render

https://github.com/ThemeFuse/Unyson-Framework/blob/master/core/components/backend.php#L578-L585

and skip the other 2 and If so how ?

danyj commented 9 years ago

to make it very short , the whole point of all this is to render my saved preset , no matter what format I have saved , JSON , serialized data , I need to render this properly the shortest way possible.

ghost commented 9 years ago

First ajax is to get the default array structure so that it can be compared to the option value Second one is to get my serialized options that are saved in a file

Why you can't put that data in html on render?

third is to get options from values required for render

Maybe this step also can be done on render? Or all the above steps in one ajax?

and If so how ?

on render put all those in data-...="..." attributes?


Sorry, now I am focused on Backup and I am asking this by fast looking. I am feeling that I don't have enough "brain RAM" too keep track of all the details that you are trying to explain (looks complicated, or maybe because we are chatting/writing, not talking)

danyj commented 9 years ago

lol >"brain RAM" nice one

it looks complicated I admit but it is simple concept.

Why you can't put that data in html on render?

because render requires 2 things , default options JSON string and object with

ID:value  

and serialize comes as

NAME:value 

how would you do this

  1. how would you save data in a file ( I am rewrtiitng and thinking of , form.serializeArray() save it in presetname.json )

2 . how would you render that saved data

ghost commented 9 years ago

on render put all those in data-...="..." attributes?

Or to prevent making the html too big. On _enqueue_static() to wp_localize_script() the data you need.

danyj commented 9 years ago

on render put all those in data-...="..." attributes?

I had it originally like that , but it does get big , and if you have lets say 5 or more presets it gets to much for html

danyj commented 9 years ago

Simple concept being , save preset in to a file , on button click render preset

ghost commented 9 years ago

save preset in to a file

in wp-content/uploads ? because in other directory you will need FTP details from user (a form should be displayed)

how would you save data?

In DB.

how would you render that saved data?

  • On option static enqueue, localize the data in javascript
  • On preset save, in ajax response send the new data and update the javascript value (so it will be used on next render, instead of doing an ajax on next render to get the data)
danyj commented 9 years ago

because in other directory you will need FTP details

no way , please dont tell me this , in order to save anything to a file in let say

themes/themename/presets 

I need FTP credentials?

I need presets in files so that they can be transferable from theme to theme

danyj commented 9 years ago

ok just tested on live server , saving presets to a file works ok , unless you know something that will mess this up

ghost commented 9 years ago

On regular/default server installations php can't write anywhere (because all files are owned by your_user and php scripts are executed by www-data user), it can write only in directories with write permissions for all 777. wp-content/uploads is required to be 777 because WordPress will not be able to upload images (asking FTP details on every image upload is too much).

This is the reason why WP_Filesystem exists.

I know a person, his site was regularly hacked, then he set 755 on wp-content/uploads, so no bad plugin or any php script can create or modify files. Only when he wants to upload some images, he sets 777 on wp-content/uploads then sets back 755.

I know that on most of hosting providers, there are scripts that automatically install WP and set the owner for all files to www-data, this is convenient but not secure.

On my localhost I install apache + php manually and from php I can't change/create files. If I will set the owner to www-data for everything, I will not be able to edit the files from IDE. The only way is to set 777 but, when I will create a new file from IDE it will be owned by current user, and it will be a mess with files owned by different users and different permissions (also permission denied errors on extensions or WordPress update). I always install an ftp server so I can enter current user and password in WP FTP details form, and PHP will connect to FTP and create/edit files as that user.

On your localhost you have MAMP executed as super-user?

danyj commented 9 years ago

I am on WAMP local and have no permission issue , just tested this concept on live cPanel apache + litespeed where by default max folder permission is 755 and it works.

http://prntscr.com/8oba8c

http://prntscr.com/8obaqk http://prntscr.com/8obath

I have been doing same concept on Joomla since about 5 years now , and customers had no issues with files modification/creation via php . Sure proper POST checks are required and I do use

WP_Filesystem

in this case. Just hope that in WP is not much different than Joomla when it comes to folder permission issues.

ghost commented 9 years ago

This is on my localhost

s

http://prntscr.com/8oba8c http://prntscr.com/8obath

Can you show the column Owner in that table?

ghost commented 9 years ago

I am on WAMP

In Windows there is not such thing multiple users, so you will never have an issue with permission denied because the file owner is another user.

On Linux can be many users (and groups), each can set permissions to files they own.

danyj commented 9 years ago

in cPanel I dont know how to show the owner column but I am sure that in this case is the user ,

danyj commented 9 years ago

I mean this relies on user permission for the folder and as long as read and write are set for the user on server it should work. I mean it did work for me for 5 years now. 100K members and few cases where their theme folder was blocked due to wrong things , but if they cant see the theme css file or run theme index.php than there is a problem , as long as those 2 work the creation /modification of files via ajax should be ok.

You really got me thinking now

ghost commented 9 years ago

To confirm what I said https://codex.wordpress.org/Changing_File_Permissions

danyj commented 9 years ago

OK , please tell me how to test bad case scenario in WP. I am on live server, what should I do , create some admin user and change permissions or ?

ghost commented 9 years ago

Find the owner of directories within wp-content/uploads/

Somehow, make sure the the owner of your theme directories (and files) is another user. For e.g. try to connect with your FTP user (if it's another user) and upload your theme via FTP (instead of WP admin upload form), so the files will be created as FTP user.

danyj commented 9 years ago

ah , ok , on it

danyj commented 9 years ago

no issue bud , created ftp user , loged in , FTP complete theme folder , ( not zip /unzip ) , activated theme and no issues. Could be my server setup that files are always owned by the user.

ghost commented 9 years ago

Which is owner of themes/themename/presets directory and the files in it? Why php was able to create files inside the presets directory?

danyj commented 9 years ago

I cant see it bud , I think I setup cPanel trough WHM for all files in user accounts to be owned by that user , so if you ftp anything by any user , let say cPanel owned by user1 , all files inside are owned by user1 ,

I have no environment to check this except MAMP on macbook PRO ,

if you know how I should set this up on MAMP it would be great .

On the other hand it is strange to me that WP can run n this way , 1 WP install multiple file owners

ghost commented 9 years ago

FileZilla has the Owner column

danyj commented 9 years ago

ok give me min

danyj commented 9 years ago

http://prntscr.com/8oc91u http://prntscr.com/8oc96x

danyj commented 9 years ago

same owner for everything in that wp folder , i think this is lightspeed thing

danyj commented 9 years ago

Here is why it is doing it ,

WP_Filesystem

http://ottopress.com/2011/tutorial-using-the-wp_filesystem/

The WP_Filesystem basically support five different ways of writing files to the system and they all ensure that ownership of those files remains firmly in the hands of the same person that owns the WordPress files. In other words, it writes files using your user account and not as the webserver user.

and that is exactly what I used , I did not use

fopen()

or

fwrite()

directly , but used the wp file system instead

ghost commented 9 years ago

I know that. But in your case it is able to do that without FTP details (I don't know why), in my case it can't and it asks FTP details.

danyj commented 9 years ago

in my case it can't and it asks FTP details

strange , I would really like to test this in some way

so you are saying that if you do an ajax action that does

WP_Filesystem::put_contents(file_path,content);

you are asked for FTP credentials ?

danyj commented 9 years ago

I dug this up from Otto's comments

If you are on shared hosting, and see WordPress ask for FTP credentials, then it’s not running setuid methods, and it’s asking for FTP credentials as a form of protection, because it does not want to write files and have them owned by the webserver user.

ghost commented 9 years ago

WP_Filesystem::put_contents(...); will fail.

First we make sure we have filesystem access/connection then we do actions on files.

danyj commented 9 years ago

yes I do that to , checing the wp_filesystem

 /**
 * Return wp_filesystem, initiate if not there
 */
public static function thz_preset_file_system(){

    global $wp_filesystem;
    if (empty($wp_filesystem)) {
        require_once (ABSPATH . '/wp-admin/includes/file.php');
        WP_Filesystem();
    }

    return  $wp_filesystem;
}

but this is a big thing and I need to do it right

ghost commented 9 years ago

I added this code in {theme}/functions.php

add_action('admin_head', function(){
    fw_print(
        get_filesystem_method()
    );
});

and it shows 'ftpext'.

What it shows on your server?

danyj commented 9 years ago

in wamp and live cPanel

'direct'
danyj commented 9 years ago

I just forced the config via

define('FS_METHOD', 'ftpext');

and see what you mean. This is bad news, can you do me a favor and test on your end with this in config

define('FS_METHOD', 'ftpext');
define('FTP_BASE', 'PATH_TO_YOUR_BASE');
define('FTP_USER', 'username');
define('FTP_PASS', 'password');
define('FTP_HOST', 'host');
define('FTP_SSL', false);

and see if your ajax would now ask you for credentials

ghost commented 9 years ago

I'll try later. Recently I reinstalled my OS and I don't have configured the FTP server.

danyj commented 9 years ago

for time being until we find suitable solution I did this http://prntscr.com/8oe6y7 when you get to it please do let me know about ajax + FTP user info in config. If that works we might be ok

ghost commented 9 years ago

Your WordPress installation -> Current Theme :)

danyj commented 9 years ago

lol :) no man is WP fault , don't you know that :)

danyj commented 9 years ago

I think best fallback is to check if we can save /load to file and if not save in DB

danyj commented 9 years ago

Now lets say I cant use a file and must go to DB , can I do a blank , none existing file option save vi ajax like

  fw_set_db_settings_option('menu_presets, ''{presetname:"presetdata....."")

and keep on adding to it ? ( this is the tricky one )

ghost commented 9 years ago

It will be wiped on next Theme Settings save.

I recommend to use a separate wp option, because presets data can grow and to prevent mysql error when update sql is too big.

update_option(
    'thz-presets:'. fw()->theme->manifest->get_id(),
    $presets, 
    false // https://codex.wordpress.org/Function_Reference/update_option#Parameters
);
danyj commented 9 years ago

was just busting on it , thnx much

danyj commented 9 years ago

OK how is this,

on theme install run this for example

$thz_options_presets_option = 'thz_options_presets:'. fw()->theme->manifest->get_id();
add_option($thz_options_presets_option,array(

    'topmenupreset' => array(
        'style1'  => array(
            'label' => 'Style 1',
            'canremove'=> false,
            'data'  => '{style1data}'

        ),
        'style2'=> array(
            'label' => 'Style 2',
            'canremove'=> false,
            'data'  => '{style2data}'

        ),
    ),

    'iconboxespreset' => array(
        'style1'  => array(
            'label' => 'Style 1',
            'canremove'=> false,
            'data'  => '{style1data}',

        ),
        'style2'  => array(
            'label' => 'Style 2',
            'canremove'=> false,
            'data'  => '{style2data}'

        ),

        'stylebyuser'  => array(
            'label' => 'User custom style',
            'canremove'=> true,
            'data'  => '{stylebyuserdata}'

        ),
    )

));

than use those to populate defaults , on create/update/delete new preset add/remove to that option , you think this can fly ?

danyj commented 9 years ago

I think this is hand in replacement for files option and we still have presets , I can add hidden admin option to update the file with new presets, if permissions are right , otherwise tell admin to do direct update if he/she wants more default presets

ghost commented 9 years ago
$presets = array_merge(
    load_predefined_presets_from_theme_file(),
    $user_presets_from_db
);

?

danyj commented 9 years ago

they will all endup in DB option , no reason to merge , on user preset save il do update_option combined with

fw_akg() 

to add to it

you see i forgot about one big thing and that is theme updates , so looks like I must stay away from files creation/edits and use DB instead , since everything is deleted on theme update and I dont want to create folder outside , check permissions and all the funny stuff.

here better picture of what I mean ,

on fw_init , I do this

http://prntscr.com/8ohzj5

so now by default we have 2 predefined styles for the menu , user has option to save new preset , when he does that , I just update DB option

thz_options_presets:'. fw()->theme->manifest->get_id()

makes sense?