diff --git a/a/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php b/b/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php index 8409969..522bb36 100644 --- a/a/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php +++ b/b/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php @@ -888,11 +888,15 @@ if (!empty($geofield_names) && (!empty($this->view->result) || !$this->options['hide_empty_map'])) { // Group the rows according to the grouping instructions, if specified. - $view_results_groups = $this->renderGrouping( - $this->view->result, - $this->options['grouping'], - TRUE - ); + // Avoid StylePluginBase::renderGrouping()'s unconditional renderFields() + // call when nothing is actually grouped: it renders every configured + // field for every row through the full Render API, a large and + // needless cost with hundreds/thousands of map features. Fields are + // still rendered lazily, on demand, by whichever option actually + // needs them (see ensureRenderedFields()). + $view_results_groups = !empty($this->options['grouping']) + ? $this->renderGrouping($this->view->result, $this->options['grouping'], TRUE) + : ['' => ['group' => '', 'rows' => $this->view->result]]; asort($view_results_groups); // Process results and create features. @@ -1204,6 +1208,24 @@ } /** + * Ensures fields have been rendered, lazily, only when actually needed. + * + * StylePluginBase::renderFields() renders every configured field for + * every row through the full Render API - expensive with hundreds/ + * thousands of map features. Most per-feature options (weight, icon, + * className, ajax popups) only need raw field values and use + * getFieldValue() instead (cheap, no Render API). This is called only by + * the few remaining consumers (legacy popup/tooltip/marker-cluster- + * exclude options) that genuinely need the rendered/formatted output, so + * views that don't use those options never pay the renderFields() cost. + */ + protected function ensureRenderedFields(): void { + if (!isset($this->rendered_fields)) { + $this->renderFields($this->view->result); + } + } + + /** * Applies Views token replacement only when the text actually has tokens. * * PluginBase::viewsTokenReplace() always renders the text through the @@ -1303,6 +1325,9 @@ default: // Row rendering of single specified field value (without labels). + if (!empty($popup_source)) { + $this->ensureRenderedFields(); + } $popup_content = !empty($popup_source) ? $this->rendered_fields[$result->index][$popup_source] : ''; } @@ -1342,8 +1367,9 @@ */ protected function prepareTokens(mixed $result): array { $tokens = []; - foreach ($this->rendered_fields[$result->index] as $field_name => $field_value) { - $tokens[$field_name] = $field_value; + foreach (array_keys($this->view->field) as $field_name) { + $values = $this->getFieldValue($result->index, $field_name); + $tokens[$field_name] = is_array($values) ? reset($values) : $values; } return $tokens; } @@ -1434,6 +1460,7 @@ if ($this->options['leaflet_markercluster'] && $this->options['leaflet_markercluster']['control'] && !empty($this->options['leaflet_markercluster']['excluded'])) { + $this->ensureRenderedFields(); $excluded_from_markercluster_option = $this->rendered_fields[$result->index][$this->options['leaflet_markercluster']['excluded']] ?? NULL; $feature['markercluster_excluded'] = !empty(str_replace( ["\n", "\r"], @@ -1482,6 +1509,7 @@ default: // Decode every entity because JS will encode them again, // and we don't want double encoding. + $this->ensureRenderedFields(); $feature['tooltip']['value'] = array_key_exists($this->options['leaflet_tooltip']['value'], $this->rendered_fields[$result->index]) ? Html::decodeEntities((string) $this->rendered_fields[$result->index][$this->options['leaflet_tooltip']['value']]) : ''; } @@ -1499,8 +1527,10 @@ elseif ($this->options['name_field']) { // Decode every entity because JS will encode them again, // and we don't want double encoding. - $feature['title'] = !empty($this->options['name_field']) ? - Html::decodeEntities((string) $this->rendered_fields[$result->index][$this->options['name_field']]) : ''; + $name_field_values = !empty($this->options['name_field']) ? + $this->getFieldValue($result->index, $this->options['name_field']) : NULL; + $feature['title'] = !empty($name_field_values) ? + Html::decodeEntities((string) reset($name_field_values)) : ''; } }