0

I have a basic plugin that pulls tileset data from mapbox in json. I then want to send the json data to my custom javascript to display it. If I pass the data using wp_add_inline_script I can receive the data (proof is by console.loggging the passed data), however, instead of the 12 rows of data, I get 5256 rows of unset data.

Here is my plugin script:

function fs_tilesets_get(){
    $url = 'https://api.mapbox.com/tilesets/v1/username?access_token=sk.[snip]';
    $arg= [
        'headers'   => [
            'Content-Type' => 'application/json'
        ],
        'body'      => []
        ];
    $response = wp_remote_get($url, $args);
    //$response_code = wp-wp_remote_retrieve_response_code($response);
    $fs_tileset_data = wp_remote_retrieve_body($response);

   return $fs_tileset_data;
}

function fs_tilesets_index_html(){
    ?>
        <div class="container">
        
        <div class="box box-primary">
        
            <div class="box-body">
        
                <table width="100%" class="table table-hover" id="fs_tileset_index">
        
                    <thead>
                        <tr>
                            <th>Type</th>
                            <th>ID</th>
                            <th>Name</th>
                            <th>Center</th>
                            <th>Created</th>
                            <th>Modified</th>
                            <th>Visibility</th>
                            <th>Description</th>
                            <th>Filesize</th>
                            <th>Status</th>
                            <th>tileset_precisions </th>
                            <th>created_by_client</th>
                        </tr>
                    </thead>

                </table>

            </div>

        </div>

    </div>
    <?php
}

function fs_tileset_settings_admin_callback(){
    fs_tilesets_index_html();
}



function fs_api_enqueue_script() {   
    wp_enqueue_style('datatables-bootstrap5', '//cdn.datatables.net/1.13.3/css/dataTables.bootstrap5.min.css' );
    wp_enqueue_style('datatables-responsive', '//cdn.datatables.net/responsive/2.4.0/css/responsive.dataTables.min.css' );
    wp_enqueue_script('datatablesjs', '//cdn.datatables.net/1.13.3/js/jquery.dataTables.min.js', array('jquery'), '1.0', TRUE );
    wp_enqueue_script('datatablesjsbs', '//cdn.datatables.net/1.13.3/js/dataTables.bootstrap5.min.js', array('jquery'), '1.0', TRUE );
    wp_enqueue_script('datatables-responsive', '//cdn.datatables.net/responsive/2.4.0/js/dataTables.responsive.min.js', array('jquery'), '1.0', TRUE );
    $fs_plugin_params = array(
        'fs_tileset_data' => fs_tilesets_get(),
    );
    wp_enqueue_script( 'fs_tileset_settings_datatable', plugin_dir_url( __FILE__ ) . 'js/fs_tileset_settings_datatable.js', array('jquery'), '1.0' );
    wp_add_inline_script( 'fs_tileset_settings_datatable', 'var fs_plugin_params = ' . wp_json_encode( $fs_plugin_params ), 'before' );
}
add_action('admin_enqueue_scripts', 'fs_api_enqueue_script');

And then in my fs_tileset_settings_datatable.js I have the following;

jQuery( document ).ready(function($) {

    console.log(fs_plugin_params.fs_tileset_data);
  
    xxx =  
    [
  {
    "type": "vector",
    "id": "username.6z20mb78",
    "name": "somename-8t9d58",
    "center": [
      137.18893815,
      39.08704805,
      0
    ],
    "created": "2023-07-30T02:30:15.315Z",
    "modified": "2023-07-30T02:30:15.028Z",
    "visibility": "private",
    "description": "",
    "filesize": 843391,
    "status": "available",
    "tileset_precisions": {
      "10m": 1426540.488293752
    },
    "created_by_client": "studio"
  },
  [snip the reset of the records]
];

    jQuery('#fs_tileset_index').DataTable({
       // data:           xxx,
        data: fs_plugin_params.fs_tileset_data,
        "columns": [
            //0
            {
                data:       "type",
                 "defaultContent": "<i>Not set</i>"
            },
            //1
            {
                data: "id",
                "defaultContent": "<i>Not set</i>"
            },
            //2
            [snip rest]

If I use xxx it works. If I use fs_plugin_params.fs_tileset_data I get 5236 records instead of 12. The json is passed over as I console log it and it is there (12 of them).

4
  • So the problem is that the data is being mangled by wp_add_inline_script()? What does the var fs_plugin_params = block look like in the page source? Does that look OK? I wonder if it needs a trailing ;. Commented Aug 14, 2023 at 11:07
  • 1
    You might also want to cache the mapbox data in WordPress e.g. using transients, depending on how often you serve the same data. Or if it's global maybe that wouldn't generate many cache hits. Commented Aug 14, 2023 at 11:10
  • are you sure the problem is at the WP end and not int he usage of the mapbox API? You mentioned you get 5k+ rows of unset data but never explain what you meant by unset data, and it's unclear how you're debugging this since there are no points in the code where the output from mapbox is logged so that it can be inspected. This looks like a mapbox API problem, and not something that can be solved with WordPress knowledge Commented Aug 14, 2023 at 11:22
  • 1
    a quick look at the mapbox API documentation suggests that the API you're using is docs.mapbox.com/api/maps/mapbox-tiling-service, specifically docs.mapbox.com/api/maps/mapbox-tiling-service/#list-tilesets could it actually be that your response from mapbox is ` 5256` characters long and that you've JSON encoded a string containing JSON? Eitherway this looks like a mapbox issue not a PHP/WP issue, more information is needed. I also see no error handling is present, so there's no way to know if your request succeeded or not Commented Aug 14, 2023 at 11:29

1 Answer 1

3

This is because the response from MapBox's API is a string, which is then passed to wp_json_encode.

e.g.

echo wp_json_encode( [ 'fs_tileset_data' =>  'this is already a JSON string' ] );

This is the cause of the problem, it's not 5256 rows of unset data, it's a double JSON encoded string that's 5256 characters long, it's the same as echo json_encode( json_encode( excerpt the inner json_encode is happening on MapBox' server.

There are two solutions:

  • decode the JSON from mapbox before returning it in fs_tilesets_get
  • print it directly and don't use wp_json_encode

The first is the best.

Other notes:

  • using the CDNs for bootstrap etc will slow your site down, shared CDNs worked well for older browsers, but modern browsers use independent caches per domain to prevent cross-site tracking and improve security so it's going to request it again anyway even if it's already loaded on another site.
    • to make things worse, because they're on a different server no http2 optimisations can occur so it can't send the files alongside the HTML in the same compression stream, reducing performance
  • fs_tileset_settings_admin_callback as a callback is pointless because it just calls another function. Best to remove it completely and use fs_tilesets_index_html as the callback instead
  • caching! HTTP requests are one of the heaviest slowest things you can do, and if mapbox goes down for maintenance your settings page breaks! Store it in a transient with an hours timeout and the page will be significantly faster and more reliable
  • error handling, there is nothing to handle errors, e.g. if their API changed, or your token expired, everything would stop working without explanation
1
  • Tom J Nowell, that is extremely helpful info. Will need to read some more. Also, really appreciate the bonus comments about speed/performance. I will certainly change the code around. I have some other code in fs_tileset_settings_admin_callback which is why its there. Great info about transients which I did not know existed (just move to WP). Yes, well noted about error handling. Was just trying to get it working first. Thank you Tom J Nowell! Commented Aug 15, 2023 at 0:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.