Answers.Body: <p>For anyone wanting to do this in Craft 3 there are a couple changes to the code you need to add to getSettingsHtml().</p>
  
  <pre><code>'myImageSelectConfig' =&gt; array(
              'id'                 =&gt; 'myImage',
              'name'               =&gt; 'myImage',
              'jsClass'            =&gt; 'Craft.AssetSelectInput',
              'elementType'        =&gt; 'craft\\elements\\Asset',
              'elements'           =&gt; $this-&gt;getSettings()['myImage'] &amp;&amp; count($this-&gt;getSettings()['myImage']) ? [Craft::$app-&gt;getElements()-&gt;getElementById($this-&gt;getSettings()['myImage'][0])] : null,
              'sources'            =&gt; array('folder:2'),
              'criteria'           =&gt; array('kind' =&gt; array('image'), 'localeEnabled' =&gt; null),
              'limit'              =&gt; 1,
              'viewMode'           =&gt; 'table',
              'selectionLabel'     =&gt; Craft::t('app','Add image'),
          )
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-05-24T21:05:26.230Z
Answers.LastActivityDate: 2018-05-24T21:05:26.230Z
Answers.UserDisplayName: Bradlay Law
Answers.Body: <p>Unfortunately, a simple HTML file input on its own isn't enough to upload an image (in Craft or anywhere else) – the input simply exposes the file on your local filesystem to the browser/server. In other words, with your current setup, you're not actually uploading anything.</p>
  
  <p>In my opinion, you have two choices:</p>
  
  <ol>
  <li>Use Assets and Craft's built-in Assets ElementSelect input (easy)</li>
  <li>Don't use Assets; upload the image natively using a file input (harder)</li>
  </ol>
  
  <p>Personally, I'd recommend that unless you <em>can't</em> have the image be an Asset file for some reason, you should definitely go with the Assets approach. It's way easier to set up, offers a familiar user experience and you can even use image transforms and whatnot since your <code>myImage</code> file will be a bona fide Asset.</p>
  
  <p>Either way, here's how option 1 could look:</p>
  
  <p>In your plugin's <code>settings.html</code> file, replace your current call to the <code>forms.file()</code> macro with this:</p>
  
  <pre><code>{{ forms.field({
    label: "My Image"
  }, include('_includes/forms/elementSelect', myImageSelectConfig)) }}
  </code></pre>
  
  <p>Then, fire up your plugin's primary class. Revise your <code>getSettingsHtml()</code> method to include the <code>myImageSelectConfig</code> attribute referenced in <code>settings.html</code> above, so the method looks something like this:</p>
  
  <pre><code>public function getSettingsHtml()
  {
      return craft()-&gt;templates-&gt;render('yourpluginhandle/settings', array(
          'settings' =&gt; $this-&gt;getSettings(),
          'myImageSelectConfig' =&gt; array(
              'id'                 =&gt; 'myImage',
              'name'               =&gt; 'myImage',
              'jsClass'            =&gt; 'Craft.AssetSelectInput',
              'elementType'        =&gt; new ElementTypeVariable(craft()-&gt;elements-&gt;getElementType(ElementType::Asset)),
              'elements'           =&gt; $this-&gt;getSettings()['myImage'] ? craft()-&gt;elements-&gt;getCriteria(ElementType::Asset, array('id' =&gt; $this-&gt;getSettings()['myImage'])) : null,
              'sources'            =&gt; array('folder:2'),
              'criteria'           =&gt; array('kind' =&gt; array('image'), 'localeEnabled' =&gt; null),
              'limit'              =&gt; 1,
              'viewMode'           =&gt; 'table',
              'selectionLabel'     =&gt; Craft::t('Add image'),
          ),
      ));
  }
  </code></pre>
  
  <p>Note: The <code>sources</code> attribute refers to the ID(s) for the Asset folder the admin should upload images to (and choose images from). You can look at the <code>craft_assetfolders</code> database table to figure out which ID(s) you want. Alternatively you can remove the <code>sources</code> property entirely, to enable all folders – which is probably the best option if this is going to be a publicly available plugin.</p>
  
  <p>And that's it. The actual <code>myImage</code> setting value stored will be an array with the ID to the selected Asset file, e.g. <code>{"myImage":["42"]}</code>. If you need to pull the Asset in a template, you'll need to add a <a href="http://buildwithcraft.com/docs/plugins/variables" rel="noreferrer">Variable</a> class to your plugin, exposing the plugin settings:</p>
  
  <pre><code>class MyPluginVariable
  {
      public function settings()
      {
          return craft()-&gt;plugins-&gt;getPlugin('myPlugin')-&gt;getSettings();
      }
  }
  </code></pre>
  
  <p>...and in your template:</p>
  
  <pre><code>{% set assetId = craft.myPlugin.settings.myImage %}
  {% set asset = craft.assets.id(assetId).first() %}
  </code></pre>
  
  <p><strong>If you don't want to go with the Assets approach</strong>, you can keep your <code>forms.file()</code> macro in <code>settings.html</code>. However, there's a few more things you'll need to handle to get the upload working.</p>
  
  <p>First, in order to actually upload a file from a file input, the enclosing form needs to have an <code>enctype="multipart/form-data"</code> attribute. Unfortunately, plugin settings forms don't, and there's no real way to add it. However, you can use jQuery to hack it in – add this to your plugin's <code>settings.html</code> file:</p>
  
  <pre><code>{% includeJs '$("form:first").attr("enctype", "multipart/form-data");' %}
  </code></pre>
  
  <p>Second, you'll need some server side code to actually handle the upload. Add the following to your plugin's primary class:</p>
  
  <pre><code>public function prepSettings($settings)
  {
  
      $imageFile = UploadedFile::getInstanceByName('settings.myImage');
  
      if ($imageFile) {
  
          // Where should the image be stored?
          $basePath = $_SERVER['DOCUMENT_ROOT'];
          $uploadFolder = '/uploads/yourpluginhandle/';
          $filePath = $basePath.$uploadFolder.$imageFile-&gt;name;
  
          // Make sure the upload folder exists
          IOHelper::ensureFolderExists($basePath.$uploadFolder);
  
          // Attempt to upload the file
          if ($imageFile-&gt;saveAs($filePath)) {
              // File uploaded successfully – store the relative filepath in the plugin settings
              $settings['myImage'] = str_replace($basePath, '', $filePath);
          } else {
              // Aw.
              craft()-&gt;userSession-&gt;setError(Craft::t('Unable to upload image {filename}', array(
                  'filename' =&gt; $imageFile-&gt;name,
              )));
          }
      }
  
      return $settings;
  
  }
  </code></pre>
  
  <p>The above example is pretty much the bare minimum you'd need in order to upload a file from your plugin's settings page, to an arbitrary folder on your server's file system. The example <code>prepSettings()</code> script will upload the file to a folder called <code>/uploads/yourpluginhandle</code> in the public webroot (i.e. <code>$_SERVER['DOCUMENT_ROOT']</code>), before storing the <em>relative</em> path to the file in the settings, if the upload was successful.</p>
  
  <p>Keep in mind that file uploading is actually fairly complex (lots of things can go wrong), and also a potential security risk. You should probably consider adding some code to ensure that the file's mime type (<code>$imageFile-&gt;type</code>), size (<code>$imageFile-&gt;size</code>) and other properties are legit, before calling <code>$file-&gt;saveAs()</code>. You might also need to create a UI for displaying and deleting the current image, and making sure old and no longer selected files are deleted from the server.</p>
  
  <p>Finally, I'd posit that a vanilla browser file input is a pretty terrible user experience, compared to the Assets select input in Craft proper. There's all sorts of JavaScript libraries to help out with that, of course – in any case the above is hopefully a good starting point if you go down this road.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-08-14T02:03:14.333Z
Answers.Text: Seriously, though... I want to fly to Norway just to buy you a beer.
Answers.UserDisplayName: Brad Bell
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-08-14T05:54:10.850Z
Answers.Text: @BradBell That's fortunate - I love beer!
Answers.UserDisplayName: Mats Mikkel Rummelhoff
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-08-14T14:32:03.307Z
Answers.Text: No worries, @BillyMedia – hope it helps you out.
Answers.UserDisplayName: Mats Mikkel Rummelhoff
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-08-13T18:41:09.100Z
Answers.LastActivityDate: 2016-08-13T18:46:34.880Z
Answers.LastEditDate: 2016-08-13T18:46:34.880Z
Answers.UserDisplayName: Mats Mikkel Rummelhoff
Body: <p>My plugin needs to allow admin to upload an image. I have the field setup and saving ok. But i cant seem to control the upload location. </p>
  
  <p>This is what i have so far in my settings:</p>
  
  <pre><code>{{ forms.file({
      label: "My Image"|t,
      instructions: ""|t,
      name: 'myImage',
      value: settings.myImage
  }) }}
  </code></pre>
  
  <p>When I output the <code>settings.myImage</code>, I get the file name on its own and no path. I would like it to upload to my <code>/uploads</code> folder.
  So for example, the image I uploaded was "test.jpg". When I output the result of <code>settings.myImage</code>, I get "test.jpg" and no path.</p>
  
Tags: <plugin-development><plugins><settings>
Title: Plugin settings - file field upload location
ThreadText: # Plugin settings - file field upload location
  
  (Asked by: username_0 on 2016-06-09)
  
  My plugin needs to allow admin to upload an image. I have the field setup and saving ok. But i cant seem to control the upload location.
  
  This is what i have so far in my settings:
  
  ```
  {{ forms.file({
      label: "My Image"|t,
      instructions: ""|t,
      name: 'myImage',
      value: settings.myImage
  }) }}
  
  ```
  
  When I output the `settings.myImage`, I get the file name on its own and no path. I would like it to upload to my `/uploads` folder.
  So for example, the image I uploaded was "test.jpg". When I output the result of `settings.myImage`, I get "test.jpg" and no path.
  
  **Tags:** plugin-development, plugins, settings
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_2 on 2016-08-13. Score: 10 | Accepted answer
  
  Unfortunately, a simple HTML file input on its own isn't enough to upload an image (in Craft or anywhere else) – the input simply exposes the file on your local filesystem to the browser/server. In other words, with your current setup, you're not actually uploading anything.
  
  In my opinion, you have two choices:
  
  1. Use Assets and Craft's built-in Assets ElementSelect input (easy)
  2. Don't use Assets; upload the image natively using a file input (harder)
  
  Personally, I'd recommend that unless you *can't* have the image be an Asset file for some reason, you should definitely go with the Assets approach. It's way easier to set up, offers a familiar user experience and you can even use image transforms and whatnot since your `myImage` file will be a bona fide Asset.
  
  Either way, here's how option 1 could look:
  
  In your plugin's `settings.html` file, replace your current call to the `forms.file()` macro with this:
  
  ```
  {{ forms.field({
    label: "My Image"
  }, include('_includes/forms/elementSelect', myImageSelectConfig)) }}
  
  ```
  
  Then, fire up your plugin's primary class. Revise your `getSettingsHtml()` method to include the `myImageSelectConfig` attribute referenced in `settings.html` above, so the method looks something like this:
  
  ```
  public function getSettingsHtml()
  {
      return craft()->templates->render('yourpluginhandle/settings', array(
          'settings' => $this->getSettings(),
          'myImageSelectConfig' => array(
              'id'                 => 'myImage',
              'name'               => 'myImage',
              'jsClass'            => 'Craft.AssetSelectInput',
              'elementType'        => new ElementTypeVariable(craft()->elements->getElementType(ElementType::Asset)),
              'elements'           => $this->getSettings()['myImage'] ? craft()->elements->getCriteria(ElementType::Asset, array('id' => $this->getSettings()['myImage'])) : null,
              'sources'            => array('folder:2'),
              'criteria'           => array('kind' => array('image'), 'localeEnabled' => null),
              'limit'              => 1,
              'viewMode'           => 'table',
              'selectionLabel'     => Craft::t('Add image'),
          ),
      ));
  }
  
  ```
  
  Note: The `sources` attribute refers to the ID(s) for the Asset folder the admin should upload images to (and choose images from). You can look at the `craft_assetfolders` database table to figure out which ID(s) you want. Alternatively you can remove the `sources` property entirely, to enable all folders – which is probably the best option if this is going to be a publicly available plugin.
  
  And that's it. The actual `myImage` setting value stored will be an array with the ID to the selected Asset file, e.g. `{"myImage":["42"]}`. If you need to pull the Asset in a template, you'll need to add a [Variable](http://buildwithcraft.com/docs/plugins/variables) class to your plugin, exposing the plugin settings:
  
  ```
  class MyPluginVariable
  {
      public function settings()
      {
          return craft()->plugins->getPlugin('myPlugin')->getSettings();
      }
  }
  
  ```
  
  ...and in your template:
  
  ```
  {% set assetId = craft.myPlugin.settings.myImage %}
  {% set asset = craft.assets.id(assetId).first() %}
  
  ```
  
  **If you don't want to go with the Assets approach**, you can keep your `forms.file()` macro in `settings.html`. However, there's a few more things you'll need to handle to get the upload working.
  
  First, in order to actually upload a file from a file input, the enclosing form needs to have an `enctype="multipart/form-data"` attribute. Unfortunately, plugin settings forms don't, and there's no real way to add it. However, you can use jQuery to hack it in – add this to your plugin's `settings.html` file:
  
  ```
  {% includeJs '$("form:first").attr("enctype", "multipart/form-data");' %}
  
  ```
  
  Second, you'll need some server side code to actually handle the upload. Add the following to your plugin's primary class:
  
  ```
  public function prepSettings($settings)
  {
  
      $imageFile = UploadedFile::getInstanceByName('settings.myImage');
  
      if ($imageFile) {
  
          // Where should the image be stored?
          $basePath = $_SERVER['DOCUMENT_ROOT'];
          $uploadFolder = '/uploads/yourpluginhandle/';
          $filePath = $basePath.$uploadFolder.$imageFile->name;
  
          // Make sure the upload folder exists
          IOHelper::ensureFolderExists($basePath.$uploadFolder);
  
          // Attempt to upload the file
          if ($imageFile->saveAs($filePath)) {
              // File uploaded successfully – store the relative filepath in the plugin settings
              $settings['myImage'] = str_replace($basePath, '', $filePath);
          } else {
              // Aw.
              craft()->userSession->setError(Craft::t('Unable to upload image {filename}', array(
                  'filename' => $imageFile->name,
              )));
          }
      }
  
      return $settings;
  
  }
  
  ```
  
  The above example is pretty much the bare minimum you'd need in order to upload a file from your plugin's settings page, to an arbitrary folder on your server's file system. The example `prepSettings()` script will upload the file to a folder called `/uploads/yourpluginhandle` in the public webroot (i.e. `$_SERVER['DOCUMENT_ROOT']`), before storing the *relative* path to the file in the settings, if the upload was successful.
  
  Keep in mind that file uploading is actually fairly complex (lots of things can go wrong), and also a potential security risk. You should probably consider adding some code to ensure that the file's mime type (`$imageFile->type`), size (`$imageFile->size`) and other properties are legit, before calling `$file->saveAs()`. You might also need to create a UI for displaying and deleting the current image, and making sure old and no longer selected files are deleted from the server.
  
  Finally, I'd posit that a vanilla browser file input is a pretty terrible user experience, compared to the Assets select input in Craft proper. There's all sorts of JavaScript libraries to help out with that, of course – in any case the above is hopefully a good starting point if you go down this road.
  
  > **Comments:**
  > **username_3**: Seriously, though... I want to fly to Norway just to buy you a beer.  
  > **username_2**: @username_3 That's fortunate - I love beer!  
  > **username_2**: No worries, @username_0 – hope it helps you out.  
  
  ---
  
  ### Answer by username_1 on 2018-05-24. Score: 1
  
  For anyone wanting to do this in Craft 3 there are a couple changes to the code you need to add to getSettingsHtml().
  
  ```
  'myImageSelectConfig' => array(
              'id'                 => 'myImage',
              'name'               => 'myImage',
              'jsClass'            => 'Craft.AssetSelectInput',
              'elementType'        => 'craft\\elements\\Asset',
              'elements'           => $this->getSettings()['myImage'] && count($this->getSettings()['myImage']) ? [Craft::$app->getElements()->getElementById($this->getSettings()['myImage'][0])] : null,
              'sources'            => array('folder:2'),
              'criteria'           => array('kind' => array('image'), 'localeEnabled' => null),
              'limit'              => 1,
              'viewMode'           => 'table',
              'selectionLabel'     => Craft::t('app','Add image'),
          )
  
  ```
  
  
  ---
  
  